| File: System\Reflection\Metadata\Ecma335\MetadataRootBuilder.cs | Web Access |
| Project: src\runtime\src\libraries\System.Reflection.Metadata\src\System.Reflection.Metadata.csproj (System.Reflection.Metadata) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Immutable; using System.Diagnostics; using System.Text; namespace System.Reflection.Metadata.Ecma335 { /// <summary> /// Builder of a Metadata Root to be embedded in a Portable Executable image. /// </summary> /// <remarks> /// Metadata root constitutes of a metadata header followed by metadata streams (#~, #Strings, #US, #Guid and #Blob). /// </remarks> public sealed class MetadataRootBuilder { private const string DefaultMetadataVersionString = "v4.0.30319"; // internal for testing internal static readonly ImmutableArray<int> EmptyRowCounts = ImmutableArray.Create(new int[MetadataTokens.TableCount]); private readonly MetadataBuilder _tablesAndHeaps; private readonly SerializedMetadata _serializedMetadata; /// <summary> /// Metadata version string. /// </summary> public string MetadataVersion { get; } /// <summary> /// True to suppresses basic validation of metadata tables. /// The validation verifies that entries in the tables were added in order required by the ECMA specification. /// It does not enforce all specification requirements on metadata tables. /// </summary> public bool SuppressValidation { get; } /// <summary> /// Creates a builder of a metadata root. /// </summary> /// <param name="tablesAndHeaps"> /// Builder populated with metadata entities stored in tables and values stored in heaps. /// The entities and values will be enumerated when serializing the metadata root. /// </param> /// <param name="metadataVersion"> /// The version string written to the metadata header. The default value is "v4.0.30319". /// </param> /// <param name="suppressValidation"> /// True to suppresses basic validation of metadata tables during serialization. /// The validation verifies that entries in the tables were added in order required by the ECMA specification. /// It does not enforce all specification requirements on metadata tables. /// </param> /// <exception cref="ArgumentNullException"><paramref name="tablesAndHeaps"/> is null.</exception> /// <exception cref="ArgumentException"><paramref name="metadataVersion"/> is too long (the number of bytes when UTF-8 encoded must be less than 255).</exception> public MetadataRootBuilder(MetadataBuilder tablesAndHeaps, string? metadataVersion = null, bool suppressValidation = false) { if (tablesAndHeaps is null) { Throw.ArgumentNull(nameof(tablesAndHeaps)); } Debug.Assert(Encoding.UTF8.GetByteCount(DefaultMetadataVersionString) == DefaultMetadataVersionString.Length); int metadataVersionByteCount = metadataVersion != null ? Encoding.UTF8.GetByteCount(metadataVersion) : DefaultMetadataVersionString.Length; if (metadataVersionByteCount > MetadataSizes.MaxMetadataVersionByteCount) { Throw.InvalidArgument(SR.MetadataVersionTooLong, nameof(metadataVersion)); } _tablesAndHeaps = tablesAndHeaps; MetadataVersion = metadataVersion ?? DefaultMetadataVersionString; SuppressValidation = suppressValidation; _serializedMetadata = tablesAndHeaps.GetSerializedMetadata(EmptyRowCounts, metadataVersionByteCount, isStandaloneDebugMetadata: false); } /// <summary> /// Returns sizes of various metadata structures. /// </summary> public MetadataSizes Sizes => _serializedMetadata.Sizes; /// <summary> /// Serializes metadata root content into the given <see cref="BlobBuilder"/>. /// </summary> /// <param name="builder">Builder to write to.</param> /// <param name="methodBodyStreamRva"> /// The relative virtual address of the start of the method body stream. /// Used to calculate the final value of RVA fields of MethodDef table. /// </param> /// <param name="mappedFieldDataStreamRva"> /// The relative virtual address of the start of the field init data stream. /// Used to calculate the final value of RVA fields of FieldRVA table. /// </param> /// <exception cref="ArgumentNullException"><paramref name="builder"/> is null.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="methodBodyStreamRva"/> or <paramref name="mappedFieldDataStreamRva"/> is negative.</exception> /// <exception cref="InvalidOperationException"> /// A metadata table is not ordered as required by the specification and <see cref="SuppressValidation"/> is false. /// </exception> public void Serialize(BlobBuilder builder, int methodBodyStreamRva, int mappedFieldDataStreamRva) { if (builder is null) { Throw.ArgumentNull(nameof(builder)); } if (methodBodyStreamRva < 0) { Throw.ArgumentOutOfRange(nameof(methodBodyStreamRva)); } if (mappedFieldDataStreamRva < 0) { Throw.ArgumentOutOfRange(nameof(mappedFieldDataStreamRva)); } if (!SuppressValidation) { _tablesAndHeaps.ValidateOrder(); } // header: MetadataBuilder.SerializeMetadataHeader(builder, MetadataVersion, _serializedMetadata.Sizes); // #~ or #- stream: _tablesAndHeaps.SerializeMetadataTables(builder, _serializedMetadata.Sizes, _serializedMetadata.StringMap, methodBodyStreamRva, mappedFieldDataStreamRva); // #Strings, #US, #Guid and #Blob streams: _tablesAndHeaps.WriteHeapsTo(builder, _serializedMetadata.StringHeap); } } }