// // Author: // Jb Evain (jbevain@gmail.com) // // Copyright (c) 2008 - 2015 Jb Evain // Copyright (c) 2008 - 2011 Novell, Inc. // // Licensed under the MIT/X11 license. // using MonoFN.Cecil.Cil; using MonoFN.Cecil.Metadata; using MonoFN.Cecil.PE; using MonoFN.Collections.Generic; using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Text; using BlobIndex = System.UInt32; using CodedRID = System.UInt32; using GuidIndex = System.UInt32; using RID = System.UInt32; using RVA = System.UInt32; using StringIndex = System.UInt32; namespace MonoFN.Cecil { using AssemblyRefRow = Row; using AssemblyRow = Row; using ClassLayoutRow = Row; using ConstantRow = Row; using CustomAttributeRow = Row; using CustomDebugInformationRow = Row; using DeclSecurityRow = Row; using DocumentRow = Row; using EventMapRow = Row; using EventRow = Row; using ExportedTypeRow = Row; using FieldLayoutRow = Row; using FieldMarshalRow = Row; using FieldRow = Row; using FieldRVARow = Row; using FileRow = Row; using GenericParamConstraintRow = Row; using GenericParamRow = Row; using ImplMapRow = Row; using ImportScopeRow = Row; using InterfaceImplRow = Row; using LocalConstantRow = Row; using LocalScopeRow = Row; using LocalVariableRow = Row; using ManifestResourceRow = Row; using MemberRefRow = Row; using MethodDebugInformationRow = Row; using MethodImplRow = Row; using MethodRow = Row; using MethodSemanticsRow = Row; using MethodSpecRow = Row; using ModuleRow = Row; using NestedClassRow = Row; using ParamRow = Row; using PropertyMapRow = Row; using PropertyRow = Row; using StateMachineMethodRow = Row; using TypeDefRow = Row; using TypeRefRow = Row; internal static class ModuleWriter { public static void WriteModule(ModuleDefinition module, Disposable stream, WriterParameters parameters) { using (stream) { Write(module, stream, parameters); } } private static void Write(ModuleDefinition module, Disposable stream, WriterParameters parameters) { if ((module.Attributes & ModuleAttributes.ILOnly) == 0) throw new NotSupportedException("Writing mixed-mode assemblies is not supported"); if (module.HasImage && module.ReadingMode == ReadingMode.Deferred) { ImmediateModuleReader immediate_reader = new(module.Image); immediate_reader.ReadModule(module, resolve_attributes: false); immediate_reader.ReadSymbols(module); } module.MetadataSystem.Clear(); if (module.symbol_reader != null) module.symbol_reader.Dispose(); AssemblyNameDefinition name = module.assembly != null && module.kind != ModuleKind.NetModule ? module.assembly.Name : null; string fq_name = stream.value.GetFileName(); uint timestamp = parameters.Timestamp ?? module.timestamp; ISymbolWriterProvider symbol_writer_provider = parameters.SymbolWriterProvider; if (symbol_writer_provider == null && parameters.WriteSymbols) symbol_writer_provider = new DefaultSymbolWriterProvider(); if (parameters.HasStrongNameKey && name != null) { name.PublicKey = CryptoService.GetPublicKey(parameters); module.Attributes |= ModuleAttributes.StrongNameSigned; } if (parameters.DeterministicMvid) module.Mvid = Guid.Empty; MetadataBuilder metadata = new(module, fq_name, timestamp, symbol_writer_provider); try { module.metadata_builder = metadata; using (ISymbolWriter symbol_writer = GetSymbolWriter(module, fq_name, symbol_writer_provider, parameters)) { metadata.SetSymbolWriter(symbol_writer); BuildMetadata(module, metadata); if (parameters.DeterministicMvid) metadata.ComputeDeterministicMvid(); ImageWriter writer = ImageWriter.CreateWriter(module, metadata, stream); stream.value.SetLength(0); writer.WriteImage(); if (parameters.HasStrongNameKey) CryptoService.StrongName(stream.value, writer, parameters); } } finally { module.metadata_builder = null; } } private static void BuildMetadata(ModuleDefinition module, MetadataBuilder metadata) { if (!module.HasImage) { metadata.BuildMetadata(); return; } module.Read(metadata, (builder, _) => { builder.BuildMetadata(); return builder; }); } private static ISymbolWriter GetSymbolWriter(ModuleDefinition module, string fq_name, ISymbolWriterProvider symbol_writer_provider, WriterParameters parameters) { if (symbol_writer_provider == null) return null; if (parameters.SymbolStream != null) return symbol_writer_provider.GetSymbolWriter(module, parameters.SymbolStream); return symbol_writer_provider.GetSymbolWriter(module, fq_name); } } internal abstract class MetadataTable { public abstract int Length { get; } public bool IsLarge { get { return Length > ushort.MaxValue; } } public abstract void Write(TableHeapBuffer buffer); public abstract void Sort(); } internal abstract class OneRowTable : MetadataTable where TRow : struct { internal TRow row; public sealed override int Length { get { return 1; } } public sealed override void Sort() { } } internal abstract class MetadataTable : MetadataTable where TRow : struct { internal TRow[] rows = new TRow [2]; internal int length; public sealed override int Length { get { return length; } } public int AddRow(TRow row) { if (rows.Length == length) Grow(); rows[length++] = row; return length; } private void Grow() { TRow[] rows = new TRow [this.rows.Length * 2]; Array.Copy(this.rows, rows, this.rows.Length); this.rows = rows; } public override void Sort() { } } internal abstract class SortedTable : MetadataTable, IComparer where TRow : struct { public sealed override void Sort() { MergeSort.Sort(rows, 0, length, this); } protected static int Compare(uint x, uint y) { return x == y ? 0 : x > y ? 1 : -1; } public abstract int Compare(TRow x, TRow y); } internal sealed class ModuleTable : OneRowTable { public override void Write(TableHeapBuffer buffer) { buffer.WriteUInt16(0); // Generation buffer.WriteString(row.Col1); // Name buffer.WriteGuid(row.Col2); // Mvid buffer.WriteUInt16(0); // EncId buffer.WriteUInt16(0); // EncBaseId } } internal sealed class TypeRefTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteCodedRID(rows[i].Col1, CodedIndex.ResolutionScope); // Scope buffer.WriteString(rows[i].Col2); // Name buffer.WriteString(rows[i].Col3); // Namespace } } } internal sealed class TypeDefTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteUInt32((uint)rows[i].Col1); // Attributes buffer.WriteString(rows[i].Col2); // Name buffer.WriteString(rows[i].Col3); // Namespace buffer.WriteCodedRID(rows[i].Col4, CodedIndex.TypeDefOrRef); // Extends buffer.WriteRID(rows[i].Col5, Table.Field); // FieldList buffer.WriteRID(rows[i].Col6, Table.Method); // MethodList } } } internal sealed class FieldTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteUInt16((ushort)rows[i].Col1); // Attributes buffer.WriteString(rows[i].Col2); // Name buffer.WriteBlob(rows[i].Col3); // Signature } } } internal sealed class MethodTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteUInt32(rows[i].Col1); // RVA buffer.WriteUInt16((ushort)rows[i].Col2); // ImplFlags buffer.WriteUInt16((ushort)rows[i].Col3); // Flags buffer.WriteString(rows[i].Col4); // Name buffer.WriteBlob(rows[i].Col5); // Signature buffer.WriteRID(rows[i].Col6, Table.Param); // ParamList } } } internal sealed class ParamTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteUInt16((ushort)rows[i].Col1); // Attributes buffer.WriteUInt16(rows[i].Col2); // Sequence buffer.WriteString(rows[i].Col3); // Name } } } internal sealed class InterfaceImplTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteRID(rows[i].Col1, Table.TypeDef); // Class buffer.WriteCodedRID(rows[i].Col2, CodedIndex.TypeDefOrRef); // Interface } } /*public override int Compare (InterfaceImplRow x, InterfaceImplRow y) { return (int) (x.Col1 == y.Col1 ? y.Col2 - x.Col2 : x.Col1 - y.Col1); }*/ } internal sealed class MemberRefTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteCodedRID(rows[i].Col1, CodedIndex.MemberRefParent); buffer.WriteString(rows[i].Col2); buffer.WriteBlob(rows[i].Col3); } } } internal sealed class ConstantTable : SortedTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteUInt16((ushort)rows[i].Col1); buffer.WriteCodedRID(rows[i].Col2, CodedIndex.HasConstant); buffer.WriteBlob(rows[i].Col3); } } public override int Compare(ConstantRow x, ConstantRow y) { return Compare(x.Col2, y.Col2); } } internal sealed class CustomAttributeTable : SortedTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteCodedRID(rows[i].Col1, CodedIndex.HasCustomAttribute); // Parent buffer.WriteCodedRID(rows[i].Col2, CodedIndex.CustomAttributeType); // Type buffer.WriteBlob(rows[i].Col3); } } public override int Compare(CustomAttributeRow x, CustomAttributeRow y) { return Compare(x.Col1, y.Col1); } } internal sealed class FieldMarshalTable : SortedTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteCodedRID(rows[i].Col1, CodedIndex.HasFieldMarshal); buffer.WriteBlob(rows[i].Col2); } } public override int Compare(FieldMarshalRow x, FieldMarshalRow y) { return Compare(x.Col1, y.Col1); } } internal sealed class DeclSecurityTable : SortedTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteUInt16((ushort)rows[i].Col1); buffer.WriteCodedRID(rows[i].Col2, CodedIndex.HasDeclSecurity); buffer.WriteBlob(rows[i].Col3); } } public override int Compare(DeclSecurityRow x, DeclSecurityRow y) { return Compare(x.Col2, y.Col2); } } internal sealed class ClassLayoutTable : SortedTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteUInt16(rows[i].Col1); // PackingSize buffer.WriteUInt32(rows[i].Col2); // ClassSize buffer.WriteRID(rows[i].Col3, Table.TypeDef); // Parent } } public override int Compare(ClassLayoutRow x, ClassLayoutRow y) { return Compare(x.Col3, y.Col3); } } internal sealed class FieldLayoutTable : SortedTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteUInt32(rows[i].Col1); // Offset buffer.WriteRID(rows[i].Col2, Table.Field); // Parent } } public override int Compare(FieldLayoutRow x, FieldLayoutRow y) { return Compare(x.Col2, y.Col2); } } internal sealed class StandAloneSigTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) buffer.WriteBlob(rows[i]); } } internal sealed class EventMapTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteRID(rows[i].Col1, Table.TypeDef); // Parent buffer.WriteRID(rows[i].Col2, Table.Event); // EventList } } } internal sealed class EventTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteUInt16((ushort)rows[i].Col1); // Flags buffer.WriteString(rows[i].Col2); // Name buffer.WriteCodedRID(rows[i].Col3, CodedIndex.TypeDefOrRef); // EventType } } } internal sealed class PropertyMapTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteRID(rows[i].Col1, Table.TypeDef); // Parent buffer.WriteRID(rows[i].Col2, Table.Property); // PropertyList } } } internal sealed class PropertyTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteUInt16((ushort)rows[i].Col1); // Flags buffer.WriteString(rows[i].Col2); // Name buffer.WriteBlob(rows[i].Col3); // Type } } } internal sealed class MethodSemanticsTable : SortedTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteUInt16((ushort)rows[i].Col1); // Flags buffer.WriteRID(rows[i].Col2, Table.Method); // Method buffer.WriteCodedRID(rows[i].Col3, CodedIndex.HasSemantics); // Association } } public override int Compare(MethodSemanticsRow x, MethodSemanticsRow y) { return Compare(x.Col3, y.Col3); } } internal sealed class MethodImplTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteRID(rows[i].Col1, Table.TypeDef); // Class buffer.WriteCodedRID(rows[i].Col2, CodedIndex.MethodDefOrRef); // MethodBody buffer.WriteCodedRID(rows[i].Col3, CodedIndex.MethodDefOrRef); // MethodDeclaration } } } internal sealed class ModuleRefTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) buffer.WriteString(rows[i]); // Name } } internal sealed class TypeSpecTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) buffer.WriteBlob(rows[i]); // Signature } } internal sealed class ImplMapTable : SortedTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteUInt16((ushort)rows[i].Col1); // Flags buffer.WriteCodedRID(rows[i].Col2, CodedIndex.MemberForwarded); // MemberForwarded buffer.WriteString(rows[i].Col3); // ImportName buffer.WriteRID(rows[i].Col4, Table.ModuleRef); // ImportScope } } public override int Compare(ImplMapRow x, ImplMapRow y) { return Compare(x.Col2, y.Col2); } } internal sealed class FieldRVATable : SortedTable { internal int position; public override void Write(TableHeapBuffer buffer) { position = buffer.position; for (int i = 0; i < length; i++) { buffer.WriteUInt32(rows[i].Col1); // RVA buffer.WriteRID(rows[i].Col2, Table.Field); // Field } } public override int Compare(FieldRVARow x, FieldRVARow y) { return Compare(x.Col2, y.Col2); } } internal sealed class AssemblyTable : OneRowTable { public override void Write(TableHeapBuffer buffer) { buffer.WriteUInt32((uint)row.Col1); // AssemblyHashAlgorithm buffer.WriteUInt16(row.Col2); // MajorVersion buffer.WriteUInt16(row.Col3); // MinorVersion buffer.WriteUInt16(row.Col4); // Build buffer.WriteUInt16(row.Col5); // Revision buffer.WriteUInt32((uint)row.Col6); // Flags buffer.WriteBlob(row.Col7); // PublicKey buffer.WriteString(row.Col8); // Name buffer.WriteString(row.Col9); // Culture } } internal sealed class AssemblyRefTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteUInt16(rows[i].Col1); // MajorVersion buffer.WriteUInt16(rows[i].Col2); // MinorVersion buffer.WriteUInt16(rows[i].Col3); // Build buffer.WriteUInt16(rows[i].Col4); // Revision buffer.WriteUInt32((uint)rows[i].Col5); // Flags buffer.WriteBlob(rows[i].Col6); // PublicKeyOrToken buffer.WriteString(rows[i].Col7); // Name buffer.WriteString(rows[i].Col8); // Culture buffer.WriteBlob(rows[i].Col9); // Hash } } } internal sealed class FileTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteUInt32((uint)rows[i].Col1); buffer.WriteString(rows[i].Col2); buffer.WriteBlob(rows[i].Col3); } } } internal sealed class ExportedTypeTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteUInt32((uint)rows[i].Col1); buffer.WriteUInt32(rows[i].Col2); buffer.WriteString(rows[i].Col3); buffer.WriteString(rows[i].Col4); buffer.WriteCodedRID(rows[i].Col5, CodedIndex.Implementation); } } } internal sealed class ManifestResourceTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteUInt32(rows[i].Col1); buffer.WriteUInt32((uint)rows[i].Col2); buffer.WriteString(rows[i].Col3); buffer.WriteCodedRID(rows[i].Col4, CodedIndex.Implementation); } } } internal sealed class NestedClassTable : SortedTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteRID(rows[i].Col1, Table.TypeDef); // NestedClass buffer.WriteRID(rows[i].Col2, Table.TypeDef); // EnclosingClass } } public override int Compare(NestedClassRow x, NestedClassRow y) { return Compare(x.Col1, y.Col1); } } internal sealed class GenericParamTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteUInt16(rows[i].Col1); // Number buffer.WriteUInt16((ushort)rows[i].Col2); // Flags buffer.WriteCodedRID(rows[i].Col3, CodedIndex.TypeOrMethodDef); // Owner buffer.WriteString(rows[i].Col4); // Name } } } internal sealed class MethodSpecTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteCodedRID(rows[i].Col1, CodedIndex.MethodDefOrRef); // Method buffer.WriteBlob(rows[i].Col2); // Instantiation } } } internal sealed class GenericParamConstraintTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteRID(rows[i].Col1, Table.GenericParam); // Owner buffer.WriteCodedRID(rows[i].Col2, CodedIndex.TypeDefOrRef); // Constraint } } } internal sealed class DocumentTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteBlob(rows[i].Col1); // Name buffer.WriteGuid(rows[i].Col2); // HashAlgorithm buffer.WriteBlob(rows[i].Col3); // Hash buffer.WriteGuid(rows[i].Col4); // Language } } } internal sealed class MethodDebugInformationTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteRID(rows[i].Col1, Table.Document); // Document buffer.WriteBlob(rows[i].Col2); // SequencePoints } } } internal sealed class LocalScopeTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteRID(rows[i].Col1, Table.Method); // Method buffer.WriteRID(rows[i].Col2, Table.ImportScope); // ImportScope buffer.WriteRID(rows[i].Col3, Table.LocalVariable); // VariableList buffer.WriteRID(rows[i].Col4, Table.LocalConstant); // ConstantList buffer.WriteUInt32(rows[i].Col5); // StartOffset buffer.WriteUInt32(rows[i].Col6); // Length } } } internal sealed class LocalVariableTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteUInt16((ushort)rows[i].Col1); // Attributes buffer.WriteUInt16(rows[i].Col2); // Index buffer.WriteString(rows[i].Col3); // Name } } } internal sealed class LocalConstantTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteString(rows[i].Col1); // Name buffer.WriteBlob(rows[i].Col2); // Signature } } } internal sealed class ImportScopeTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteRID(rows[i].Col1, Table.ImportScope); // Parent buffer.WriteBlob(rows[i].Col2); // Imports } } } internal sealed class StateMachineMethodTable : MetadataTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteRID(rows[i].Col1, Table.Method); // MoveNextMethod buffer.WriteRID(rows[i].Col2, Table.Method); // KickoffMethod } } } internal sealed class CustomDebugInformationTable : SortedTable { public override void Write(TableHeapBuffer buffer) { for (int i = 0; i < length; i++) { buffer.WriteCodedRID(rows[i].Col1, CodedIndex.HasCustomDebugInformation); // Parent buffer.WriteGuid(rows[i].Col2); // Kind buffer.WriteBlob(rows[i].Col3); // Value } } public override int Compare(CustomDebugInformationRow x, CustomDebugInformationRow y) { return Compare(x.Col1, y.Col1); } } internal sealed class MetadataBuilder { internal readonly ModuleDefinition module; internal readonly ISymbolWriterProvider symbol_writer_provider; internal ISymbolWriter symbol_writer; internal readonly TextMap text_map; internal readonly string fq_name; internal readonly uint timestamp; private readonly Dictionary type_ref_map; private readonly Dictionary type_spec_map; private readonly Dictionary member_ref_map; private readonly Dictionary method_spec_map; private readonly Collection generic_parameters; internal readonly CodeWriter code; internal readonly DataBuffer data; internal readonly ResourceBuffer resources; internal readonly StringHeapBuffer string_heap; internal readonly GuidHeapBuffer guid_heap; internal readonly UserStringHeapBuffer user_string_heap; internal readonly BlobHeapBuffer blob_heap; internal readonly TableHeapBuffer table_heap; internal readonly PdbHeapBuffer pdb_heap; internal MetadataToken entry_point; internal RID type_rid = 1; internal RID field_rid = 1; internal RID method_rid = 1; internal RID param_rid = 1; internal RID property_rid = 1; internal RID event_rid = 1; internal RID local_variable_rid = 1; internal RID local_constant_rid = 1; private readonly TypeRefTable type_ref_table; private readonly TypeDefTable type_def_table; private readonly FieldTable field_table; private readonly MethodTable method_table; private readonly ParamTable param_table; private readonly InterfaceImplTable iface_impl_table; private readonly MemberRefTable member_ref_table; private readonly ConstantTable constant_table; private readonly CustomAttributeTable custom_attribute_table; private readonly DeclSecurityTable declsec_table; private readonly StandAloneSigTable standalone_sig_table; private readonly EventMapTable event_map_table; private readonly EventTable event_table; private readonly PropertyMapTable property_map_table; private readonly PropertyTable property_table; private readonly TypeSpecTable typespec_table; private readonly MethodSpecTable method_spec_table; internal MetadataBuilder metadata_builder; private readonly DocumentTable document_table; private readonly MethodDebugInformationTable method_debug_information_table; private readonly LocalScopeTable local_scope_table; private readonly LocalVariableTable local_variable_table; private readonly LocalConstantTable local_constant_table; private readonly ImportScopeTable import_scope_table; private readonly StateMachineMethodTable state_machine_method_table; private readonly CustomDebugInformationTable custom_debug_information_table; private readonly Dictionary import_scope_map; private readonly Dictionary document_map; public MetadataBuilder(ModuleDefinition module, string fq_name, uint timestamp, ISymbolWriterProvider symbol_writer_provider) { this.module = module; text_map = CreateTextMap(); this.fq_name = fq_name; this.timestamp = timestamp; this.symbol_writer_provider = symbol_writer_provider; code = new(this); data = new(); resources = new(); string_heap = new(); guid_heap = new(); user_string_heap = new(); blob_heap = new(); table_heap = new(module, this); type_ref_table = GetTable(Table.TypeRef); type_def_table = GetTable(Table.TypeDef); field_table = GetTable(Table.Field); method_table = GetTable(Table.Method); param_table = GetTable(Table.Param); iface_impl_table = GetTable(Table.InterfaceImpl); member_ref_table = GetTable(Table.MemberRef); constant_table = GetTable(Table.Constant); custom_attribute_table = GetTable(Table.CustomAttribute); declsec_table = GetTable(Table.DeclSecurity); standalone_sig_table = GetTable(Table.StandAloneSig); event_map_table = GetTable(Table.EventMap); event_table = GetTable(Table.Event); property_map_table = GetTable(Table.PropertyMap); property_table = GetTable(Table.Property); typespec_table = GetTable(Table.TypeSpec); method_spec_table = GetTable(Table.MethodSpec); RowEqualityComparer row_equality_comparer = new(); type_ref_map = new(row_equality_comparer); type_spec_map = new(); member_ref_map = new(row_equality_comparer); method_spec_map = new(row_equality_comparer); generic_parameters = new(); document_table = GetTable(Table.Document); method_debug_information_table = GetTable(Table.MethodDebugInformation); local_scope_table = GetTable(Table.LocalScope); local_variable_table = GetTable(Table.LocalVariable); local_constant_table = GetTable(Table.LocalConstant); import_scope_table = GetTable(Table.ImportScope); state_machine_method_table = GetTable(Table.StateMachineMethod); custom_debug_information_table = GetTable(Table.CustomDebugInformation); document_map = new(StringComparer.Ordinal); import_scope_map = new(row_equality_comparer); } public MetadataBuilder(ModuleDefinition module, PortablePdbWriterProvider writer_provider) { this.module = module; text_map = new(); symbol_writer_provider = writer_provider; string_heap = new(); guid_heap = new(); user_string_heap = new(); blob_heap = new(); table_heap = new(module, this); pdb_heap = new(); document_table = GetTable(Table.Document); method_debug_information_table = GetTable(Table.MethodDebugInformation); local_scope_table = GetTable(Table.LocalScope); local_variable_table = GetTable(Table.LocalVariable); local_constant_table = GetTable(Table.LocalConstant); import_scope_table = GetTable(Table.ImportScope); state_machine_method_table = GetTable(Table.StateMachineMethod); custom_debug_information_table = GetTable(Table.CustomDebugInformation); RowEqualityComparer row_equality_comparer = new(); document_map = new(); import_scope_map = new(row_equality_comparer); } public void SetSymbolWriter(ISymbolWriter writer) { symbol_writer = writer; if (symbol_writer == null && module.HasImage && module.Image.HasDebugTables()) symbol_writer = new PortablePdbWriter(this, module); } private TextMap CreateTextMap() { TextMap map = new(); map.AddMap(TextSegment.ImportAddressTable, module.Architecture == TargetArchitecture.I386 ? 8 : 0); map.AddMap(TextSegment.CLIHeader, 0x48, 8); return map; } private TTable GetTable(Table table) where TTable : MetadataTable, new() { return table_heap.GetTable(table); } private uint GetStringIndex(string @string) { if (string.IsNullOrEmpty(@string)) return 0; return string_heap.GetStringIndex(@string); } private uint GetGuidIndex(Guid guid) { return guid_heap.GetGuidIndex(guid); } private uint GetBlobIndex(ByteBuffer blob) { if (blob.length == 0) return 0; return blob_heap.GetBlobIndex(blob); } private uint GetBlobIndex(byte[] blob) { if (blob.IsNullOrEmpty()) return 0; return GetBlobIndex(new ByteBuffer(blob)); } public void BuildMetadata() { BuildModule(); table_heap.string_offsets = string_heap.WriteStrings(); table_heap.ComputeTableInformations(); table_heap.WriteTableHeap(); } private void BuildModule() { ModuleTable table = GetTable(Table.Module); table.row.Col1 = GetStringIndex(module.Name); table.row.Col2 = GetGuidIndex(module.Mvid); AssemblyDefinition assembly = module.Assembly; if (module.kind != ModuleKind.NetModule && assembly != null) BuildAssembly(); if (module.HasAssemblyReferences) AddAssemblyReferences(); if (module.HasModuleReferences) AddModuleReferences(); if (module.HasResources) AddResources(); if (module.HasExportedTypes) AddExportedTypes(); BuildTypes(); if (module.kind != ModuleKind.NetModule && assembly != null) { if (assembly.HasCustomAttributes) AddCustomAttributes(assembly); if (assembly.HasSecurityDeclarations) AddSecurityDeclarations(assembly); } if (module.HasCustomAttributes) AddCustomAttributes(module); if (module.EntryPoint != null) entry_point = LookupToken(module.EntryPoint); } private void BuildAssembly() { AssemblyDefinition assembly = module.Assembly; AssemblyNameDefinition name = assembly.Name; AssemblyTable table = GetTable(Table.Assembly); table.row = new(name.HashAlgorithm, (ushort)name.Version.Major, (ushort)name.Version.Minor, (ushort)name.Version.Build, (ushort)name.Version.Revision, name.Attributes, GetBlobIndex(name.PublicKey), GetStringIndex(name.Name), GetStringIndex(name.Culture)); if (assembly.Modules.Count > 1) BuildModules(); } private void BuildModules() { Collection modules = this.module.Assembly.Modules; FileTable table = GetTable(Table.File); for (int i = 0; i < modules.Count; i++) { ModuleDefinition module = modules[i]; if (module.IsMain) continue; #if NET_CORE throw new NotSupportedException(); #else WriterParameters parameters = new() { SymbolWriterProvider = symbol_writer_provider }; string file_name = GetModuleFileName(module.Name); module.Write(file_name, parameters); byte[] hash = CryptoService.ComputeHash(file_name); table.AddRow(new(FileAttributes.ContainsMetaData, GetStringIndex(module.Name), GetBlobIndex(hash))); #endif } } #if !NET_CORE private string GetModuleFileName(string name) { if (string.IsNullOrEmpty(name)) throw new NotSupportedException(); string path = Path.GetDirectoryName(fq_name); return Path.Combine(path, name); } #endif private void AddAssemblyReferences() { Collection references = module.AssemblyReferences; AssemblyRefTable table = GetTable(Table.AssemblyRef); if (module.IsWindowsMetadata()) module.Projections.RemoveVirtualReferences(references); for (int i = 0; i < references.Count; i++) { AssemblyNameReference reference = references[i]; byte[] key_or_token = reference.PublicKey.IsNullOrEmpty() ? reference.PublicKeyToken : reference.PublicKey; Version version = reference.Version; int rid = table.AddRow(new((ushort)version.Major, (ushort)version.Minor, (ushort)version.Build, (ushort)version.Revision, reference.Attributes, GetBlobIndex(key_or_token), GetStringIndex(reference.Name), GetStringIndex(reference.Culture), GetBlobIndex(reference.Hash))); reference.token = new(TokenType.AssemblyRef, rid); } if (module.IsWindowsMetadata()) module.Projections.AddVirtualReferences(references); } private void AddModuleReferences() { Collection references = module.ModuleReferences; ModuleRefTable table = GetTable(Table.ModuleRef); for (int i = 0; i < references.Count; i++) { ModuleReference reference = references[i]; reference.token = new(TokenType.ModuleRef, table.AddRow(GetStringIndex(reference.Name))); } } private void AddResources() { Collection resources = module.Resources; ManifestResourceTable table = GetTable(Table.ManifestResource); for (int i = 0; i < resources.Count; i++) { Resource resource = resources[i]; ManifestResourceRow row = new(0, resource.Attributes, GetStringIndex(resource.Name), 0); switch (resource.ResourceType) { case ResourceType.Embedded: row.Col1 = AddEmbeddedResource((EmbeddedResource)resource); break; case ResourceType.Linked: row.Col4 = CodedIndex.Implementation.CompressMetadataToken(new(TokenType.File, AddLinkedResource((LinkedResource)resource))); break; case ResourceType.AssemblyLinked: row.Col4 = CodedIndex.Implementation.CompressMetadataToken(((AssemblyLinkedResource)resource).Assembly.MetadataToken); break; default: throw new NotSupportedException(); } table.AddRow(row); } } private uint AddLinkedResource(LinkedResource resource) { FileTable table = GetTable(Table.File); byte[] hash = resource.Hash; if (hash.IsNullOrEmpty()) hash = CryptoService.ComputeHash(resource.File); return (uint)table.AddRow(new(FileAttributes.ContainsNoMetaData, GetStringIndex(resource.File), GetBlobIndex(hash))); } private uint AddEmbeddedResource(EmbeddedResource resource) { return resources.AddResource(resource.GetResourceData()); } private void AddExportedTypes() { Collection exported_types = module.ExportedTypes; ExportedTypeTable table = GetTable(Table.ExportedType); for (int i = 0; i < exported_types.Count; i++) { ExportedType exported_type = exported_types[i]; int rid = table.AddRow(new(exported_type.Attributes, (uint)exported_type.Identifier, GetStringIndex(exported_type.Name), GetStringIndex(exported_type.Namespace), MakeCodedRID(GetExportedTypeScope(exported_type), CodedIndex.Implementation))); exported_type.token = new(TokenType.ExportedType, rid); } } private MetadataToken GetExportedTypeScope(ExportedType exported_type) { if (exported_type.DeclaringType != null) return exported_type.DeclaringType.MetadataToken; IMetadataScope scope = exported_type.Scope; switch (scope.MetadataToken.TokenType) { case TokenType.AssemblyRef: return scope.MetadataToken; case TokenType.ModuleRef: FileTable file_table = GetTable(Table.File); for (int i = 0; i < file_table.length; i++) if (file_table.rows[i].Col2 == GetStringIndex(scope.Name)) return new(TokenType.File, i + 1); break; } throw new NotSupportedException(); } private void BuildTypes() { if (!module.HasTypes) return; AttachTokens(); AddTypes(); AddGenericParameters(); } private void AttachTokens() { Collection types = module.Types; for (int i = 0; i < types.Count; i++) AttachTypeToken(types[i]); } private void AttachTypeToken(TypeDefinition type) { TypeDefinitionProjection treatment = WindowsRuntimeProjections.RemoveProjection(type); type.token = new(TokenType.TypeDef, type_rid++); type.fields_range.Start = field_rid; type.methods_range.Start = method_rid; if (type.HasFields) AttachFieldsToken(type); if (type.HasMethods) AttachMethodsToken(type); if (type.HasNestedTypes) AttachNestedTypesToken(type); WindowsRuntimeProjections.ApplyProjection(type, treatment); } private void AttachNestedTypesToken(TypeDefinition type) { Collection nested_types = type.NestedTypes; for (int i = 0; i < nested_types.Count; i++) AttachTypeToken(nested_types[i]); } private void AttachFieldsToken(TypeDefinition type) { Collection fields = type.Fields; type.fields_range.Length = (uint)fields.Count; for (int i = 0; i < fields.Count; i++) fields[i].token = new(TokenType.Field, field_rid++); } private void AttachMethodsToken(TypeDefinition type) { Collection methods = type.Methods; type.methods_range.Length = (uint)methods.Count; for (int i = 0; i < methods.Count; i++) methods[i].token = new(TokenType.Method, method_rid++); } private MetadataToken GetTypeToken(TypeReference type) { if (type == null) return MetadataToken.Zero; if (type.IsDefinition) return type.token; if (type.IsTypeSpecification()) return GetTypeSpecToken(type); return GetTypeRefToken(type); } private MetadataToken GetTypeSpecToken(TypeReference type) { uint row = GetBlobIndex(GetTypeSpecSignature(type)); MetadataToken token; if (type_spec_map.TryGetValue(row, out token)) return token; return AddTypeSpecification(type, row); } private MetadataToken AddTypeSpecification(TypeReference type, uint row) { type.token = new(TokenType.TypeSpec, typespec_table.AddRow(row)); MetadataToken token = type.token; type_spec_map.Add(row, token); return token; } private MetadataToken GetTypeRefToken(TypeReference type) { TypeReferenceProjection projection = WindowsRuntimeProjections.RemoveProjection(type); TypeRefRow row = CreateTypeRefRow(type); MetadataToken token; if (!type_ref_map.TryGetValue(row, out token)) token = AddTypeReference(type, row); WindowsRuntimeProjections.ApplyProjection(type, projection); return token; } private TypeRefRow CreateTypeRefRow(TypeReference type) { MetadataToken scope_token = GetScopeToken(type); return new(MakeCodedRID(scope_token, CodedIndex.ResolutionScope), GetStringIndex(type.Name), GetStringIndex(type.Namespace)); } private MetadataToken GetScopeToken(TypeReference type) { if (type.IsNested) return GetTypeRefToken(type.DeclaringType); IMetadataScope scope = type.Scope; if (scope == null) return MetadataToken.Zero; return scope.MetadataToken; } private static CodedRID MakeCodedRID(IMetadataTokenProvider provider, CodedIndex index) { return MakeCodedRID(provider.MetadataToken, index); } private static CodedRID MakeCodedRID(MetadataToken token, CodedIndex index) { return index.CompressMetadataToken(token); } private MetadataToken AddTypeReference(TypeReference type, TypeRefRow row) { type.token = new(TokenType.TypeRef, type_ref_table.AddRow(row)); MetadataToken token = type.token; type_ref_map.Add(row, token); return token; } private void AddTypes() { Collection types = module.Types; for (int i = 0; i < types.Count; i++) AddType(types[i]); } private void AddType(TypeDefinition type) { TypeDefinitionProjection treatment = WindowsRuntimeProjections.RemoveProjection(type); type_def_table.AddRow(new(type.Attributes, GetStringIndex(type.Name), GetStringIndex(type.Namespace), MakeCodedRID(GetTypeToken(type.BaseType), CodedIndex.TypeDefOrRef), type.fields_range.Start, type.methods_range.Start)); if (type.HasGenericParameters) AddGenericParameters(type); if (type.HasInterfaces) AddInterfaces(type); if (type.HasLayoutInfo) AddLayoutInfo(type); if (type.HasFields) AddFields(type); if (type.HasMethods) AddMethods(type); if (type.HasProperties) AddProperties(type); if (type.HasEvents) AddEvents(type); if (type.HasCustomAttributes) AddCustomAttributes(type); if (type.HasSecurityDeclarations) AddSecurityDeclarations(type); if (type.HasNestedTypes) AddNestedTypes(type); WindowsRuntimeProjections.ApplyProjection(type, treatment); } private void AddGenericParameters(IGenericParameterProvider owner) { Collection parameters = owner.GenericParameters; for (int i = 0; i < parameters.Count; i++) generic_parameters.Add(parameters[i]); } private sealed class GenericParameterComparer : IComparer { public int Compare(GenericParameter a, GenericParameter b) { CodedRID a_owner = MakeCodedRID(a.Owner, CodedIndex.TypeOrMethodDef); CodedRID b_owner = MakeCodedRID(b.Owner, CodedIndex.TypeOrMethodDef); if (a_owner == b_owner) { int a_pos = a.Position; int b_pos = b.Position; return a_pos == b_pos ? 0 : a_pos > b_pos ? 1 : -1; } return a_owner > b_owner ? 1 : -1; } } private void AddGenericParameters() { GenericParameter[] items = generic_parameters.items; int size = generic_parameters.size; Array.Sort(items, 0, size, new GenericParameterComparer()); GenericParamTable generic_param_table = GetTable(Table.GenericParam); GenericParamConstraintTable generic_param_constraint_table = GetTable(Table.GenericParamConstraint); for (int i = 0; i < size; i++) { GenericParameter generic_parameter = items[i]; int rid = generic_param_table.AddRow(new((ushort)generic_parameter.Position, generic_parameter.Attributes, MakeCodedRID(generic_parameter.Owner, CodedIndex.TypeOrMethodDef), GetStringIndex(generic_parameter.Name))); generic_parameter.token = new(TokenType.GenericParam, rid); if (generic_parameter.HasConstraints) AddConstraints(generic_parameter, generic_param_constraint_table); if (generic_parameter.HasCustomAttributes) AddCustomAttributes(generic_parameter); } } private void AddConstraints(GenericParameter generic_parameter, GenericParamConstraintTable table) { Collection constraints = generic_parameter.Constraints; uint gp_rid = generic_parameter.token.RID; for (int i = 0; i < constraints.Count; i++) { GenericParameterConstraint constraint = constraints[i]; int rid = table.AddRow(new(gp_rid, MakeCodedRID(GetTypeToken(constraint.ConstraintType), CodedIndex.TypeDefOrRef))); constraint.token = new(TokenType.GenericParamConstraint, rid); if (constraint.HasCustomAttributes) AddCustomAttributes(constraint); } } private void AddInterfaces(TypeDefinition type) { Collection interfaces = type.Interfaces; uint type_rid = type.token.RID; for (int i = 0; i < interfaces.Count; i++) { InterfaceImplementation iface_impl = interfaces[i]; int rid = iface_impl_table.AddRow(new(type_rid, MakeCodedRID(GetTypeToken(iface_impl.InterfaceType), CodedIndex.TypeDefOrRef))); iface_impl.token = new(TokenType.InterfaceImpl, rid); if (iface_impl.HasCustomAttributes) AddCustomAttributes(iface_impl); } } private void AddLayoutInfo(TypeDefinition type) { ClassLayoutTable table = GetTable(Table.ClassLayout); table.AddRow(new((ushort)type.PackingSize, (uint)type.ClassSize, type.token.RID)); } private void AddNestedTypes(TypeDefinition type) { Collection nested_types = type.NestedTypes; NestedClassTable nested_table = GetTable(Table.NestedClass); for (int i = 0; i < nested_types.Count; i++) { TypeDefinition nested = nested_types[i]; AddType(nested); nested_table.AddRow(new(nested.token.RID, type.token.RID)); } } private void AddFields(TypeDefinition type) { Collection fields = type.Fields; for (int i = 0; i < fields.Count; i++) AddField(fields[i]); } private void AddField(FieldDefinition field) { FieldDefinitionProjection projection = WindowsRuntimeProjections.RemoveProjection(field); field_table.AddRow(new(field.Attributes, GetStringIndex(field.Name), GetBlobIndex(GetFieldSignature(field)))); if (!field.InitialValue.IsNullOrEmpty()) AddFieldRVA(field); if (field.HasLayoutInfo) AddFieldLayout(field); if (field.HasCustomAttributes) AddCustomAttributes(field); if (field.HasConstant) AddConstant(field, field.FieldType); if (field.HasMarshalInfo) AddMarshalInfo(field); WindowsRuntimeProjections.ApplyProjection(field, projection); } private void AddFieldRVA(FieldDefinition field) { FieldRVATable table = GetTable(Table.FieldRVA); table.AddRow(new(data.AddData(field.InitialValue), field.token.RID)); } private void AddFieldLayout(FieldDefinition field) { FieldLayoutTable table = GetTable(Table.FieldLayout); table.AddRow(new((uint)field.Offset, field.token.RID)); } private void AddMethods(TypeDefinition type) { Collection methods = type.Methods; for (int i = 0; i < methods.Count; i++) AddMethod(methods[i]); } private void AddMethod(MethodDefinition method) { MethodDefinitionProjection projection = WindowsRuntimeProjections.RemoveProjection(method); method_table.AddRow(new(method.HasBody ? code.WriteMethodBody(method) : 0, method.ImplAttributes, method.Attributes, GetStringIndex(method.Name), GetBlobIndex(GetMethodSignature(method)), param_rid)); AddParameters(method); if (method.HasGenericParameters) AddGenericParameters(method); if (method.IsPInvokeImpl) AddPInvokeInfo(method); if (method.HasCustomAttributes) AddCustomAttributes(method); if (method.HasSecurityDeclarations) AddSecurityDeclarations(method); if (method.HasOverrides) AddOverrides(method); WindowsRuntimeProjections.ApplyProjection(method, projection); } private void AddParameters(MethodDefinition method) { ParameterDefinition return_parameter = method.MethodReturnType.parameter; if (return_parameter != null && RequiresParameterRow(return_parameter)) AddParameter(0, return_parameter, param_table); if (!method.HasParameters) return; Collection parameters = method.Parameters; for (int i = 0; i < parameters.Count; i++) { ParameterDefinition parameter = parameters[i]; if (!RequiresParameterRow(parameter)) continue; AddParameter((ushort)(i + 1), parameter, param_table); } } private void AddPInvokeInfo(MethodDefinition method) { PInvokeInfo pinvoke = method.PInvokeInfo; if (pinvoke == null) return; ImplMapTable table = GetTable(Table.ImplMap); table.AddRow(new(pinvoke.Attributes, MakeCodedRID(method, CodedIndex.MemberForwarded), GetStringIndex(pinvoke.EntryPoint), pinvoke.Module.MetadataToken.RID)); } private void AddOverrides(MethodDefinition method) { Collection overrides = method.Overrides; MethodImplTable table = GetTable(Table.MethodImpl); for (int i = 0; i < overrides.Count; i++) { table.AddRow(new(method.DeclaringType.token.RID, MakeCodedRID(method, CodedIndex.MethodDefOrRef), MakeCodedRID(LookupToken(overrides[i]), CodedIndex.MethodDefOrRef))); } } private static bool RequiresParameterRow(ParameterDefinition parameter) { return !string.IsNullOrEmpty(parameter.Name) || parameter.Attributes != ParameterAttributes.None || parameter.HasMarshalInfo || parameter.HasConstant || parameter.HasCustomAttributes; } private void AddParameter(ushort sequence, ParameterDefinition parameter, ParamTable table) { table.AddRow(new(parameter.Attributes, sequence, GetStringIndex(parameter.Name))); parameter.token = new(TokenType.Param, param_rid++); if (parameter.HasCustomAttributes) AddCustomAttributes(parameter); if (parameter.HasConstant) AddConstant(parameter, parameter.ParameterType); if (parameter.HasMarshalInfo) AddMarshalInfo(parameter); } private void AddMarshalInfo(IMarshalInfoProvider owner) { FieldMarshalTable table = GetTable(Table.FieldMarshal); table.AddRow(new(MakeCodedRID(owner, CodedIndex.HasFieldMarshal), GetBlobIndex(GetMarshalInfoSignature(owner)))); } private void AddProperties(TypeDefinition type) { Collection properties = type.Properties; property_map_table.AddRow(new(type.token.RID, property_rid)); for (int i = 0; i < properties.Count; i++) AddProperty(properties[i]); } private void AddProperty(PropertyDefinition property) { property_table.AddRow(new(property.Attributes, GetStringIndex(property.Name), GetBlobIndex(GetPropertySignature(property)))); property.token = new(TokenType.Property, property_rid++); MethodDefinition method = property.GetMethod; if (method != null) AddSemantic(MethodSemanticsAttributes.Getter, property, method); method = property.SetMethod; if (method != null) AddSemantic(MethodSemanticsAttributes.Setter, property, method); if (property.HasOtherMethods) AddOtherSemantic(property, property.OtherMethods); if (property.HasCustomAttributes) AddCustomAttributes(property); if (property.HasConstant) AddConstant(property, property.PropertyType); } private void AddOtherSemantic(IMetadataTokenProvider owner, Collection others) { for (int i = 0; i < others.Count; i++) AddSemantic(MethodSemanticsAttributes.Other, owner, others[i]); } private void AddEvents(TypeDefinition type) { Collection events = type.Events; event_map_table.AddRow(new(type.token.RID, event_rid)); for (int i = 0; i < events.Count; i++) AddEvent(events[i]); } private void AddEvent(EventDefinition @event) { event_table.AddRow(new(@event.Attributes, GetStringIndex(@event.Name), MakeCodedRID(GetTypeToken(@event.EventType), CodedIndex.TypeDefOrRef))); @event.token = new(TokenType.Event, event_rid++); MethodDefinition method = @event.AddMethod; if (method != null) AddSemantic(MethodSemanticsAttributes.AddOn, @event, method); method = @event.InvokeMethod; if (method != null) AddSemantic(MethodSemanticsAttributes.Fire, @event, method); method = @event.RemoveMethod; if (method != null) AddSemantic(MethodSemanticsAttributes.RemoveOn, @event, method); if (@event.HasOtherMethods) AddOtherSemantic(@event, @event.OtherMethods); if (@event.HasCustomAttributes) AddCustomAttributes(@event); } private void AddSemantic(MethodSemanticsAttributes semantics, IMetadataTokenProvider provider, MethodDefinition method) { method.SemanticsAttributes = semantics; MethodSemanticsTable table = GetTable(Table.MethodSemantics); table.AddRow(new(semantics, method.token.RID, MakeCodedRID(provider, CodedIndex.HasSemantics))); } private void AddConstant(IConstantProvider owner, TypeReference type) { object constant = owner.Constant; ElementType etype = GetConstantType(type, constant); constant_table.AddRow(new(etype, MakeCodedRID(owner.MetadataToken, CodedIndex.HasConstant), GetBlobIndex(GetConstantSignature(etype, constant)))); } private static ElementType GetConstantType(TypeReference constant_type, object constant) { if (constant == null) return ElementType.Class; ElementType etype = constant_type.etype; switch (etype) { case ElementType.None: TypeDefinition type = constant_type.CheckedResolve(); if (type.IsEnum) return GetConstantType(type.GetEnumUnderlyingType(), constant); return ElementType.Class; case ElementType.String: return ElementType.String; case ElementType.Object: return GetConstantType(constant.GetType()); case ElementType.Array: case ElementType.SzArray: case ElementType.MVar: case ElementType.Var: return ElementType.Class; case ElementType.GenericInst: GenericInstanceType generic_instance = (GenericInstanceType)constant_type; if (generic_instance.ElementType.IsTypeOf("System", "Nullable`1")) return GetConstantType(generic_instance.GenericArguments[0], constant); return GetConstantType(((TypeSpecification)constant_type).ElementType, constant); case ElementType.CModOpt: case ElementType.CModReqD: case ElementType.ByRef: case ElementType.Sentinel: return GetConstantType(((TypeSpecification)constant_type).ElementType, constant); case ElementType.Boolean: case ElementType.Char: case ElementType.I: case ElementType.I1: case ElementType.I2: case ElementType.I4: case ElementType.I8: case ElementType.U: case ElementType.U1: case ElementType.U2: case ElementType.U4: case ElementType.U8: case ElementType.R4: case ElementType.R8: return GetConstantType(constant.GetType()); default: return etype; } } private static ElementType GetConstantType(Type type) { switch (Type.GetTypeCode(type)) { case TypeCode.Boolean: return ElementType.Boolean; case TypeCode.Byte: return ElementType.U1; case TypeCode.SByte: return ElementType.I1; case TypeCode.Char: return ElementType.Char; case TypeCode.Int16: return ElementType.I2; case TypeCode.UInt16: return ElementType.U2; case TypeCode.Int32: return ElementType.I4; case TypeCode.UInt32: return ElementType.U4; case TypeCode.Int64: return ElementType.I8; case TypeCode.UInt64: return ElementType.U8; case TypeCode.Single: return ElementType.R4; case TypeCode.Double: return ElementType.R8; case TypeCode.String: return ElementType.String; default: throw new NotSupportedException(type.FullName); } } private void AddCustomAttributes(ICustomAttributeProvider owner) { Collection custom_attributes = owner.CustomAttributes; for (int i = 0; i < custom_attributes.Count; i++) { CustomAttribute attribute = custom_attributes[i]; CustomAttributeValueProjection projection = WindowsRuntimeProjections.RemoveProjection(attribute); custom_attribute_table.AddRow(new(MakeCodedRID(owner, CodedIndex.HasCustomAttribute), MakeCodedRID(LookupToken(attribute.Constructor), CodedIndex.CustomAttributeType), GetBlobIndex(GetCustomAttributeSignature(attribute)))); WindowsRuntimeProjections.ApplyProjection(attribute, projection); } } private void AddSecurityDeclarations(ISecurityDeclarationProvider owner) { Collection declarations = owner.SecurityDeclarations; for (int i = 0; i < declarations.Count; i++) { SecurityDeclaration declaration = declarations[i]; declsec_table.AddRow(new(declaration.Action, MakeCodedRID(owner, CodedIndex.HasDeclSecurity), GetBlobIndex(GetSecurityDeclarationSignature(declaration)))); } } private MetadataToken GetMemberRefToken(MemberReference member) { MemberRefRow row = CreateMemberRefRow(member); MetadataToken token; if (!member_ref_map.TryGetValue(row, out token)) token = AddMemberReference(member, row); return token; } private MemberRefRow CreateMemberRefRow(MemberReference member) { return new(MakeCodedRID(GetTypeToken(member.DeclaringType), CodedIndex.MemberRefParent), GetStringIndex(member.Name), GetBlobIndex(GetMemberRefSignature(member))); } private MetadataToken AddMemberReference(MemberReference member, MemberRefRow row) { member.token = new(TokenType.MemberRef, member_ref_table.AddRow(row)); MetadataToken token = member.token; member_ref_map.Add(row, token); return token; } private MetadataToken GetMethodSpecToken(MethodSpecification method_spec) { MethodSpecRow row = CreateMethodSpecRow(method_spec); MetadataToken token; if (method_spec_map.TryGetValue(row, out token)) return token; AddMethodSpecification(method_spec, row); return method_spec.token; } private void AddMethodSpecification(MethodSpecification method_spec, MethodSpecRow row) { method_spec.token = new(TokenType.MethodSpec, method_spec_table.AddRow(row)); method_spec_map.Add(row, method_spec.token); } private MethodSpecRow CreateMethodSpecRow(MethodSpecification method_spec) { return new(MakeCodedRID(LookupToken(method_spec.ElementMethod), CodedIndex.MethodDefOrRef), GetBlobIndex(GetMethodSpecSignature(method_spec))); } private SignatureWriter CreateSignatureWriter() { return new(this); } private SignatureWriter GetMethodSpecSignature(MethodSpecification method_spec) { if (!method_spec.IsGenericInstance) throw new NotSupportedException(); GenericInstanceMethod generic_instance = (GenericInstanceMethod)method_spec; SignatureWriter signature = CreateSignatureWriter(); signature.WriteByte(0x0a); signature.WriteGenericInstanceSignature(generic_instance); return signature; } public uint AddStandAloneSignature(uint signature) { return (uint)standalone_sig_table.AddRow(signature); } public uint GetLocalVariableBlobIndex(Collection variables) { return GetBlobIndex(GetVariablesSignature(variables)); } public uint GetCallSiteBlobIndex(CallSite call_site) { return GetBlobIndex(GetMethodSignature(call_site)); } public uint GetConstantTypeBlobIndex(TypeReference constant_type) { return GetBlobIndex(GetConstantTypeSignature(constant_type)); } private SignatureWriter GetVariablesSignature(Collection variables) { SignatureWriter signature = CreateSignatureWriter(); signature.WriteByte(0x7); signature.WriteCompressedUInt32((uint)variables.Count); for (int i = 0; i < variables.Count; i++) signature.WriteTypeSignature(variables[i].VariableType); return signature; } private SignatureWriter GetConstantTypeSignature(TypeReference constant_type) { SignatureWriter signature = CreateSignatureWriter(); signature.WriteByte(0x6); signature.WriteTypeSignature(constant_type); return signature; } private SignatureWriter GetFieldSignature(FieldReference field) { SignatureWriter signature = CreateSignatureWriter(); signature.WriteByte(0x6); signature.WriteTypeSignature(field.FieldType); return signature; } private SignatureWriter GetMethodSignature(IMethodSignature method) { SignatureWriter signature = CreateSignatureWriter(); signature.WriteMethodSignature(method); return signature; } private SignatureWriter GetMemberRefSignature(MemberReference member) { FieldReference field = member as FieldReference; if (field != null) return GetFieldSignature(field); MethodReference method = member as MethodReference; if (method != null) return GetMethodSignature(method); throw new NotSupportedException(); } private SignatureWriter GetPropertySignature(PropertyDefinition property) { SignatureWriter signature = CreateSignatureWriter(); byte calling_convention = 0x8; if (property.HasThis) calling_convention |= 0x20; uint param_count = 0; Collection parameters = null; if (property.HasParameters) { parameters = property.Parameters; param_count = (uint)parameters.Count; } signature.WriteByte(calling_convention); signature.WriteCompressedUInt32(param_count); signature.WriteTypeSignature(property.PropertyType); if (param_count == 0) return signature; for (int i = 0; i < param_count; i++) signature.WriteTypeSignature(parameters[i].ParameterType); return signature; } private SignatureWriter GetTypeSpecSignature(TypeReference type) { SignatureWriter signature = CreateSignatureWriter(); signature.WriteTypeSignature(type); return signature; } private SignatureWriter GetConstantSignature(ElementType type, object value) { SignatureWriter signature = CreateSignatureWriter(); switch (type) { case ElementType.Array: case ElementType.SzArray: case ElementType.Class: case ElementType.Object: case ElementType.None: case ElementType.Var: case ElementType.MVar: signature.WriteInt32(0); break; case ElementType.String: signature.WriteConstantString((string)value); break; default: signature.WriteConstantPrimitive(value); break; } return signature; } private SignatureWriter GetCustomAttributeSignature(CustomAttribute attribute) { SignatureWriter signature = CreateSignatureWriter(); if (!attribute.resolved) { signature.WriteBytes(attribute.GetBlob()); return signature; } signature.WriteUInt16(0x0001); signature.WriteCustomAttributeConstructorArguments(attribute); signature.WriteCustomAttributeNamedArguments(attribute); return signature; } private SignatureWriter GetSecurityDeclarationSignature(SecurityDeclaration declaration) { SignatureWriter signature = CreateSignatureWriter(); if (!declaration.resolved) signature.WriteBytes(declaration.GetBlob()); else if (module.Runtime < TargetRuntime.Net_2_0) signature.WriteXmlSecurityDeclaration(declaration); else signature.WriteSecurityDeclaration(declaration); return signature; } private SignatureWriter GetMarshalInfoSignature(IMarshalInfoProvider owner) { SignatureWriter signature = CreateSignatureWriter(); signature.WriteMarshalInfo(owner.MarshalInfo); return signature; } private static Exception CreateForeignMemberException(MemberReference member) { return new ArgumentException(string.Format("Member '{0}' is declared in another module and needs to be imported", member)); } public MetadataToken LookupToken(IMetadataTokenProvider provider) { if (provider == null) throw new ArgumentNullException(); if (metadata_builder != null) return metadata_builder.LookupToken(provider); MemberReference member = provider as MemberReference; if (member == null || member.Module != module) throw CreateForeignMemberException(member); MetadataToken token = provider.MetadataToken; switch (token.TokenType) { case TokenType.TypeDef: case TokenType.Method: case TokenType.Field: case TokenType.Event: case TokenType.Property: return token; case TokenType.TypeRef: case TokenType.TypeSpec: case TokenType.GenericParam: return GetTypeToken((TypeReference)provider); case TokenType.MethodSpec: return GetMethodSpecToken((MethodSpecification)provider); case TokenType.MemberRef: return GetMemberRefToken(member); default: throw new NotSupportedException(); } } public void AddMethodDebugInformation(MethodDebugInformation method_info) { if (method_info.HasSequencePoints) AddSequencePoints(method_info); if (method_info.Scope != null) AddLocalScope(method_info, method_info.Scope); if (method_info.StateMachineKickOffMethod != null) AddStateMachineMethod(method_info); AddCustomDebugInformations(method_info.Method); } private void AddStateMachineMethod(MethodDebugInformation method_info) { state_machine_method_table.AddRow(new(method_info.Method.MetadataToken.RID, method_info.StateMachineKickOffMethod.MetadataToken.RID)); } private void AddLocalScope(MethodDebugInformation method_info, ScopeDebugInformation scope) { int rid = local_scope_table.AddRow(new(method_info.Method.MetadataToken.RID, scope.import != null ? AddImportScope(scope.import) : 0, local_variable_rid, local_constant_rid, (uint)scope.Start.Offset, (uint)((scope.End.IsEndOfMethod ? method_info.code_size : scope.End.Offset) - scope.Start.Offset))); scope.token = new(TokenType.LocalScope, rid); AddCustomDebugInformations(scope); if (scope.HasVariables) AddLocalVariables(scope); if (scope.HasConstants) AddLocalConstants(scope); for (int i = 0; i < scope.Scopes.Count; i++) AddLocalScope(method_info, scope.Scopes[i]); } private void AddLocalVariables(ScopeDebugInformation scope) { for (int i = 0; i < scope.Variables.Count; i++) { VariableDebugInformation variable = scope.Variables[i]; local_variable_table.AddRow(new(variable.Attributes, (ushort)variable.Index, GetStringIndex(variable.Name))); variable.token = new(TokenType.LocalVariable, local_variable_rid); local_variable_rid++; AddCustomDebugInformations(variable); } } private void AddLocalConstants(ScopeDebugInformation scope) { for (int i = 0; i < scope.Constants.Count; i++) { ConstantDebugInformation constant = scope.Constants[i]; local_constant_table.AddRow(new(GetStringIndex(constant.Name), GetBlobIndex(GetConstantSignature(constant)))); constant.token = new(TokenType.LocalConstant, local_constant_rid); local_constant_rid++; } } private SignatureWriter GetConstantSignature(ConstantDebugInformation constant) { TypeReference type = constant.ConstantType; SignatureWriter signature = CreateSignatureWriter(); signature.WriteTypeSignature(type); if (type.IsTypeOf("System", "Decimal")) { int[] bits = decimal.GetBits((decimal)constant.Value); uint low = (uint)bits[0]; uint mid = (uint)bits[1]; uint high = (uint)bits[2]; byte scale = (byte)(bits[3] >> 16); bool negative = (bits[3] & 0x80000000) != 0; signature.WriteByte((byte)(scale | (negative ? 0x80 : 0x00))); signature.WriteUInt32(low); signature.WriteUInt32(mid); signature.WriteUInt32(high); return signature; } if (type.IsTypeOf("System", "DateTime")) { DateTime date = (DateTime)constant.Value; signature.WriteInt64(date.Ticks); return signature; } signature.WriteBytes(GetConstantSignature(type.etype, constant.Value)); return signature; } public void AddCustomDebugInformations(ICustomDebugInformationProvider provider) { if (!provider.HasCustomDebugInformations) return; Collection custom_infos = provider.CustomDebugInformations; for (int i = 0; i < custom_infos.Count; i++) { CustomDebugInformation custom_info = custom_infos[i]; switch (custom_info.Kind) { case CustomDebugInformationKind.Binary: BinaryCustomDebugInformation binary_info = (BinaryCustomDebugInformation)custom_info; AddCustomDebugInformation(provider, binary_info, GetBlobIndex(binary_info.Data)); break; case CustomDebugInformationKind.AsyncMethodBody: AddAsyncMethodBodyDebugInformation(provider, (AsyncMethodBodyDebugInformation)custom_info); break; case CustomDebugInformationKind.StateMachineScope: AddStateMachineScopeDebugInformation(provider, (StateMachineScopeDebugInformation)custom_info); break; case CustomDebugInformationKind.EmbeddedSource: AddEmbeddedSourceDebugInformation(provider, (EmbeddedSourceDebugInformation)custom_info); break; case CustomDebugInformationKind.SourceLink: AddSourceLinkDebugInformation(provider, (SourceLinkDebugInformation)custom_info); break; default: throw new NotImplementedException(); } } } private void AddStateMachineScopeDebugInformation(ICustomDebugInformationProvider provider, StateMachineScopeDebugInformation state_machine_scope) { MethodDebugInformation method_info = ((MethodDefinition)provider).DebugInformation; SignatureWriter signature = CreateSignatureWriter(); Collection scopes = state_machine_scope.Scopes; for (int i = 0; i < scopes.Count; i++) { StateMachineScope scope = scopes[i]; signature.WriteUInt32((uint)scope.Start.Offset); int end_offset = scope.End.IsEndOfMethod ? method_info.code_size : scope.End.Offset; signature.WriteUInt32((uint)(end_offset - scope.Start.Offset)); } AddCustomDebugInformation(provider, state_machine_scope, signature); } private void AddAsyncMethodBodyDebugInformation(ICustomDebugInformationProvider provider, AsyncMethodBodyDebugInformation async_method) { SignatureWriter signature = CreateSignatureWriter(); signature.WriteUInt32((uint)async_method.catch_handler.Offset + 1); if (!async_method.yields.IsNullOrEmpty()) { for (int i = 0; i < async_method.yields.Count; i++) { signature.WriteUInt32((uint)async_method.yields[i].Offset); signature.WriteUInt32((uint)async_method.resumes[i].Offset); signature.WriteCompressedUInt32(async_method.resume_methods[i].MetadataToken.RID); } } AddCustomDebugInformation(provider, async_method, signature); } private void AddEmbeddedSourceDebugInformation(ICustomDebugInformationProvider provider, EmbeddedSourceDebugInformation embedded_source) { SignatureWriter signature = CreateSignatureWriter(); if (!embedded_source.resolved) { signature.WriteBytes(embedded_source.ReadRawEmbeddedSourceDebugInformation()); AddCustomDebugInformation(provider, embedded_source, signature); return; } byte[] content = embedded_source.content ?? Empty.Array; if (embedded_source.compress) { signature.WriteInt32(content.Length); MemoryStream decompressed_stream = new(content); MemoryStream content_stream = new(); using (DeflateStream compress_stream = new(content_stream, CompressionMode.Compress, leaveOpen: true)) { decompressed_stream.CopyTo(compress_stream); } signature.WriteBytes(content_stream.ToArray()); } else { signature.WriteInt32(0); signature.WriteBytes(content); } AddCustomDebugInformation(provider, embedded_source, signature); } private void AddSourceLinkDebugInformation(ICustomDebugInformationProvider provider, SourceLinkDebugInformation source_link) { SignatureWriter signature = CreateSignatureWriter(); signature.WriteBytes(Encoding.UTF8.GetBytes(source_link.content)); AddCustomDebugInformation(provider, source_link, signature); } private void AddCustomDebugInformation(ICustomDebugInformationProvider provider, CustomDebugInformation custom_info, SignatureWriter signature) { AddCustomDebugInformation(provider, custom_info, GetBlobIndex(signature)); } private void AddCustomDebugInformation(ICustomDebugInformationProvider provider, CustomDebugInformation custom_info, uint blob_index) { int rid = custom_debug_information_table.AddRow(new(MakeCodedRID(provider.MetadataToken, CodedIndex.HasCustomDebugInformation), GetGuidIndex(custom_info.Identifier), blob_index)); custom_info.token = new(TokenType.CustomDebugInformation, rid); } private uint AddImportScope(ImportDebugInformation import) { uint parent = 0; if (import.Parent != null) parent = AddImportScope(import.Parent); uint targets_index = 0; if (import.HasTargets) { SignatureWriter signature = CreateSignatureWriter(); for (int i = 0; i < import.Targets.Count; i++) AddImportTarget(import.Targets[i], signature); targets_index = GetBlobIndex(signature); } ImportScopeRow row = new(parent, targets_index); MetadataToken import_token; if (import_scope_map.TryGetValue(row, out import_token)) return import_token.RID; import_token = new(TokenType.ImportScope, import_scope_table.AddRow(row)); import_scope_map.Add(row, import_token); return import_token.RID; } private void AddImportTarget(ImportTarget target, SignatureWriter signature) { signature.WriteCompressedUInt32((uint)target.kind); switch (target.kind) { case ImportTargetKind.ImportNamespace: signature.WriteCompressedUInt32(GetUTF8StringBlobIndex(target.@namespace)); break; case ImportTargetKind.ImportNamespaceInAssembly: signature.WriteCompressedUInt32(target.reference.MetadataToken.RID); signature.WriteCompressedUInt32(GetUTF8StringBlobIndex(target.@namespace)); break; case ImportTargetKind.ImportType: signature.WriteTypeToken(target.type); break; case ImportTargetKind.ImportXmlNamespaceWithAlias: signature.WriteCompressedUInt32(GetUTF8StringBlobIndex(target.alias)); signature.WriteCompressedUInt32(GetUTF8StringBlobIndex(target.@namespace)); break; case ImportTargetKind.ImportAlias: signature.WriteCompressedUInt32(GetUTF8StringBlobIndex(target.alias)); break; case ImportTargetKind.DefineAssemblyAlias: signature.WriteCompressedUInt32(GetUTF8StringBlobIndex(target.alias)); signature.WriteCompressedUInt32(target.reference.MetadataToken.RID); break; case ImportTargetKind.DefineNamespaceAlias: signature.WriteCompressedUInt32(GetUTF8StringBlobIndex(target.alias)); signature.WriteCompressedUInt32(GetUTF8StringBlobIndex(target.@namespace)); break; case ImportTargetKind.DefineNamespaceInAssemblyAlias: signature.WriteCompressedUInt32(GetUTF8StringBlobIndex(target.alias)); signature.WriteCompressedUInt32(target.reference.MetadataToken.RID); signature.WriteCompressedUInt32(GetUTF8StringBlobIndex(target.@namespace)); break; case ImportTargetKind.DefineTypeAlias: signature.WriteCompressedUInt32(GetUTF8StringBlobIndex(target.alias)); signature.WriteTypeToken(target.type); break; } } private uint GetUTF8StringBlobIndex(string s) { return GetBlobIndex(Encoding.UTF8.GetBytes(s)); } public MetadataToken GetDocumentToken(Document document) { MetadataToken token; if (document_map.TryGetValue(document.Url, out token)) return token; token = new(TokenType.Document, document_table.AddRow(new(GetBlobIndex(GetDocumentNameSignature(document)), GetGuidIndex(document.HashAlgorithm.ToGuid()), GetBlobIndex(document.Hash), GetGuidIndex(document.Language.ToGuid())))); document.token = token; AddCustomDebugInformations(document); document_map.Add(document.Url, token); return token; } private SignatureWriter GetDocumentNameSignature(Document document) { string name = document.Url; SignatureWriter signature = CreateSignatureWriter(); char separator; if (!TryGetDocumentNameSeparator(name, out separator)) { signature.WriteByte(0); signature.WriteCompressedUInt32(GetUTF8StringBlobIndex(name)); return signature; } signature.WriteByte((byte)separator); string[] parts = name.Split(new[] { separator }); for (int i = 0; i < parts.Length; i++) { if (parts[i] == String.Empty) signature.WriteCompressedUInt32(0); else signature.WriteCompressedUInt32(GetUTF8StringBlobIndex(parts[i])); } return signature; } private static bool TryGetDocumentNameSeparator(string path, out char separator) { const char unix = '/'; const char win = '\\'; const char zero = (char)0; separator = zero; if (string.IsNullOrEmpty(path)) return false; int unix_count = 0; int win_count = 0; for (int i = 0; i < path.Length; i++) { if (path[i] == unix) unix_count++; else if (path[i] == win) win_count++; } if (unix_count == 0 && win_count == 0) return false; if (unix_count >= win_count) { separator = unix; return true; } separator = win; return true; } private void AddSequencePoints(MethodDebugInformation info) { uint rid = info.Method.MetadataToken.RID; Document document; if (info.TryGetUniqueDocument(out document)) method_debug_information_table.rows[rid - 1].Col1 = GetDocumentToken(document).RID; SignatureWriter signature = CreateSignatureWriter(); signature.WriteSequencePoints(info); method_debug_information_table.rows[rid - 1].Col2 = GetBlobIndex(signature); } public void ComputeDeterministicMvid() { Guid guid = CryptoService.ComputeGuid(CryptoService.ComputeHash(data, resources, string_heap, user_string_heap, blob_heap, table_heap, code)); int position = guid_heap.position; guid_heap.position = 0; guid_heap.WriteBytes(guid.ToByteArray()); guid_heap.position = position; module.Mvid = guid; } } internal sealed class SignatureWriter : ByteBuffer { private readonly MetadataBuilder metadata; public SignatureWriter(MetadataBuilder metadata) : base(6) { this.metadata = metadata; } public void WriteElementType(ElementType element_type) { WriteByte((byte)element_type); } public void WriteUTF8String(string @string) { if (@string == null) { WriteByte(0xff); return; } byte[] bytes = Encoding.UTF8.GetBytes(@string); WriteCompressedUInt32((uint)bytes.Length); WriteBytes(bytes); } public void WriteMethodSignature(IMethodSignature method) { byte calling_convention = (byte)method.CallingConvention; if (method.HasThis) calling_convention |= 0x20; if (method.ExplicitThis) calling_convention |= 0x40; IGenericParameterProvider generic_provider = method as IGenericParameterProvider; int generic_arity = generic_provider != null && generic_provider.HasGenericParameters ? generic_provider.GenericParameters.Count : 0; if (generic_arity > 0) calling_convention |= 0x10; int param_count = method.HasParameters ? method.Parameters.Count : 0; WriteByte(calling_convention); if (generic_arity > 0) WriteCompressedUInt32((uint)generic_arity); WriteCompressedUInt32((uint)param_count); WriteTypeSignature(method.ReturnType); if (param_count == 0) return; Collection parameters = method.Parameters; for (int i = 0; i < param_count; i++) WriteTypeSignature(parameters[i].ParameterType); } private uint MakeTypeDefOrRefCodedRID(TypeReference type) { return CodedIndex.TypeDefOrRef.CompressMetadataToken(metadata.LookupToken(type)); } public void WriteTypeToken(TypeReference type) { WriteCompressedUInt32(MakeTypeDefOrRefCodedRID(type)); } public void WriteTypeSignature(TypeReference type) { if (type == null) throw new ArgumentNullException(); ElementType etype = type.etype; switch (etype) { case ElementType.MVar: case ElementType.Var: { GenericParameter generic_parameter = (GenericParameter)type; WriteElementType(etype); int position = generic_parameter.Position; if (position == -1) throw new NotSupportedException(); WriteCompressedUInt32((uint)position); break; } case ElementType.GenericInst: { GenericInstanceType generic_instance = (GenericInstanceType)type; WriteElementType(ElementType.GenericInst); WriteElementType(generic_instance.IsValueType ? ElementType.ValueType : ElementType.Class); WriteCompressedUInt32(MakeTypeDefOrRefCodedRID(generic_instance.ElementType)); WriteGenericInstanceSignature(generic_instance); break; } case ElementType.Ptr: case ElementType.ByRef: case ElementType.Pinned: case ElementType.Sentinel: { TypeSpecification type_spec = (TypeSpecification)type; WriteElementType(etype); WriteTypeSignature(type_spec.ElementType); break; } case ElementType.FnPtr: { FunctionPointerType fptr = (FunctionPointerType)type; WriteElementType(ElementType.FnPtr); WriteMethodSignature(fptr); break; } case ElementType.CModOpt: case ElementType.CModReqD: { IModifierType modifier = (IModifierType)type; WriteModifierSignature(etype, modifier); break; } case ElementType.Array: { ArrayType array = (ArrayType)type; if (!array.IsVector) { WriteArrayTypeSignature(array); break; } WriteElementType(ElementType.SzArray); WriteTypeSignature(array.ElementType); break; } case ElementType.None: { WriteElementType(type.IsValueType ? ElementType.ValueType : ElementType.Class); WriteCompressedUInt32(MakeTypeDefOrRefCodedRID(type)); break; } default: if (!TryWriteElementType(type)) throw new NotSupportedException(); break; } } private void WriteArrayTypeSignature(ArrayType array) { WriteElementType(ElementType.Array); WriteTypeSignature(array.ElementType); Collection dimensions = array.Dimensions; int rank = dimensions.Count; WriteCompressedUInt32((uint)rank); int sized = 0; int lbounds = 0; for (int i = 0; i < rank; i++) { ArrayDimension dimension = dimensions[i]; if (dimension.UpperBound.HasValue) { sized++; lbounds++; } else if (dimension.LowerBound.HasValue) { lbounds++; } } int[] sizes = new int [sized]; int[] low_bounds = new int [lbounds]; for (int i = 0; i < lbounds; i++) { ArrayDimension dimension = dimensions[i]; low_bounds[i] = dimension.LowerBound.GetValueOrDefault(); if (dimension.UpperBound.HasValue) sizes[i] = dimension.UpperBound.Value - low_bounds[i] + 1; } WriteCompressedUInt32((uint)sized); for (int i = 0; i < sized; i++) WriteCompressedUInt32((uint)sizes[i]); WriteCompressedUInt32((uint)lbounds); for (int i = 0; i < lbounds; i++) WriteCompressedInt32(low_bounds[i]); } public void WriteGenericInstanceSignature(IGenericInstance instance) { Collection generic_arguments = instance.GenericArguments; int arity = generic_arguments.Count; WriteCompressedUInt32((uint)arity); for (int i = 0; i < arity; i++) WriteTypeSignature(generic_arguments[i]); } private void WriteModifierSignature(ElementType element_type, IModifierType type) { WriteElementType(element_type); WriteCompressedUInt32(MakeTypeDefOrRefCodedRID(type.ModifierType)); WriteTypeSignature(type.ElementType); } private bool TryWriteElementType(TypeReference type) { ElementType element = type.etype; if (element == ElementType.None) return false; WriteElementType(element); return true; } public void WriteConstantString(string value) { if (value != null) WriteBytes(Encoding.Unicode.GetBytes(value)); else WriteByte(0xff); } public void WriteConstantPrimitive(object value) { WritePrimitiveValue(value); } public void WriteCustomAttributeConstructorArguments(CustomAttribute attribute) { if (!attribute.HasConstructorArguments) return; Collection arguments = attribute.ConstructorArguments; Collection parameters = attribute.Constructor.Parameters; if (parameters.Count != arguments.Count) throw new InvalidOperationException(); for (int i = 0; i < arguments.Count; i++) WriteCustomAttributeFixedArgument(parameters[i].ParameterType, arguments[i]); } private void WriteCustomAttributeFixedArgument(TypeReference type, CustomAttributeArgument argument) { if (type.IsArray) { WriteCustomAttributeFixedArrayArgument((ArrayType)type, argument); return; } WriteCustomAttributeElement(type, argument); } private void WriteCustomAttributeFixedArrayArgument(ArrayType type, CustomAttributeArgument argument) { CustomAttributeArgument[] values = argument.Value as CustomAttributeArgument[]; if (values == null) { WriteUInt32(0xffffffff); return; } WriteInt32(values.Length); if (values.Length == 0) return; TypeReference element_type = type.ElementType; for (int i = 0; i < values.Length; i++) WriteCustomAttributeElement(element_type, values[i]); } private void WriteCustomAttributeElement(TypeReference type, CustomAttributeArgument argument) { if (type.IsArray) { WriteCustomAttributeFixedArrayArgument((ArrayType)type, argument); return; } if (type.etype == ElementType.Object) { argument = (CustomAttributeArgument)argument.Value; type = argument.Type; WriteCustomAttributeFieldOrPropType(type); WriteCustomAttributeElement(type, argument); return; } WriteCustomAttributeValue(type, argument.Value); } private void WriteCustomAttributeValue(TypeReference type, object value) { ElementType etype = type.etype; switch (etype) { case ElementType.String: string @string = (string)value; if (@string == null) WriteByte(0xff); else WriteUTF8String(@string); break; case ElementType.None: if (type.IsTypeOf("System", "Type")) WriteCustomAttributeTypeValue((TypeReference)value); else WriteCustomAttributeEnumValue(type, value); break; default: WritePrimitiveValue(value); break; } } private void WriteCustomAttributeTypeValue(TypeReference value) { TypeDefinition typeDefinition = value as TypeDefinition; if (typeDefinition != null) { TypeDefinition outermostDeclaringType = typeDefinition; while (outermostDeclaringType.DeclaringType != null) outermostDeclaringType = outermostDeclaringType.DeclaringType; // In CLR .winmd files, custom attribute arguments reference unmangled type names (rather than Name) if (WindowsRuntimeProjections.IsClrImplementationType(outermostDeclaringType)) { WindowsRuntimeProjections.Project(outermostDeclaringType); WriteTypeReference(value); WindowsRuntimeProjections.RemoveProjection(outermostDeclaringType); return; } } WriteTypeReference(value); } private void WritePrimitiveValue(object value) { if (value == null) throw new ArgumentNullException(); switch (Type.GetTypeCode(value.GetType())) { case TypeCode.Boolean: WriteByte((byte)((bool)value ? 1 : 0)); break; case TypeCode.Byte: WriteByte((byte)value); break; case TypeCode.SByte: WriteSByte((sbyte)value); break; case TypeCode.Int16: WriteInt16((short)value); break; case TypeCode.UInt16: WriteUInt16((ushort)value); break; case TypeCode.Char: WriteInt16((short)(char)value); break; case TypeCode.Int32: WriteInt32((int)value); break; case TypeCode.UInt32: WriteUInt32((uint)value); break; case TypeCode.Single: WriteSingle((float)value); break; case TypeCode.Int64: WriteInt64((long)value); break; case TypeCode.UInt64: WriteUInt64((ulong)value); break; case TypeCode.Double: WriteDouble((double)value); break; default: throw new NotSupportedException(value.GetType().FullName); } } private void WriteCustomAttributeEnumValue(TypeReference enum_type, object value) { TypeDefinition type = enum_type.CheckedResolve(); if (!type.IsEnum) throw new ArgumentException(); WriteCustomAttributeValue(type.GetEnumUnderlyingType(), value); } private void WriteCustomAttributeFieldOrPropType(TypeReference type) { if (type.IsArray) { ArrayType array = (ArrayType)type; WriteElementType(ElementType.SzArray); WriteCustomAttributeFieldOrPropType(array.ElementType); return; } ElementType etype = type.etype; switch (etype) { case ElementType.Object: WriteElementType(ElementType.Boxed); return; case ElementType.None: if (type.IsTypeOf("System", "Type")) { WriteElementType(ElementType.Type); } else { WriteElementType(ElementType.Enum); WriteTypeReference(type); } return; default: WriteElementType(etype); return; } } public void WriteCustomAttributeNamedArguments(CustomAttribute attribute) { int count = GetNamedArgumentCount(attribute); WriteUInt16((ushort)count); if (count == 0) return; WriteICustomAttributeNamedArguments(attribute); } private static int GetNamedArgumentCount(ICustomAttribute attribute) { int count = 0; if (attribute.HasFields) count += attribute.Fields.Count; if (attribute.HasProperties) count += attribute.Properties.Count; return count; } private void WriteICustomAttributeNamedArguments(ICustomAttribute attribute) { if (attribute.HasFields) WriteCustomAttributeNamedArguments(0x53, attribute.Fields); if (attribute.HasProperties) WriteCustomAttributeNamedArguments(0x54, attribute.Properties); } private void WriteCustomAttributeNamedArguments(byte kind, Collection named_arguments) { for (int i = 0; i < named_arguments.Count; i++) WriteCustomAttributeNamedArgument(kind, named_arguments[i]); } private void WriteCustomAttributeNamedArgument(byte kind, CustomAttributeNamedArgument named_argument) { CustomAttributeArgument argument = named_argument.Argument; WriteByte(kind); WriteCustomAttributeFieldOrPropType(argument.Type); WriteUTF8String(named_argument.Name); WriteCustomAttributeFixedArgument(argument.Type, argument); } private void WriteSecurityAttribute(SecurityAttribute attribute) { WriteTypeReference(attribute.AttributeType); int count = GetNamedArgumentCount(attribute); if (count == 0) { WriteCompressedUInt32(1); // length WriteCompressedUInt32(0); // count return; } SignatureWriter buffer = new(metadata); buffer.WriteCompressedUInt32((uint)count); buffer.WriteICustomAttributeNamedArguments(attribute); WriteCompressedUInt32((uint)buffer.length); WriteBytes(buffer); } public void WriteSecurityDeclaration(SecurityDeclaration declaration) { WriteByte((byte)'.'); Collection attributes = declaration.security_attributes; if (attributes == null) throw new NotSupportedException(); WriteCompressedUInt32((uint)attributes.Count); for (int i = 0; i < attributes.Count; i++) WriteSecurityAttribute(attributes[i]); } public void WriteXmlSecurityDeclaration(SecurityDeclaration declaration) { string xml = GetXmlSecurityDeclaration(declaration); if (xml == null) throw new NotSupportedException(); WriteBytes(Encoding.Unicode.GetBytes(xml)); } private static string GetXmlSecurityDeclaration(SecurityDeclaration declaration) { if (declaration.security_attributes == null || declaration.security_attributes.Count != 1) return null; SecurityAttribute attribute = declaration.security_attributes[0]; if (!attribute.AttributeType.IsTypeOf("System.Security.Permissions", "PermissionSetAttribute")) return null; if (attribute.properties == null || attribute.properties.Count != 1) return null; CustomAttributeNamedArgument property = attribute.properties[0]; if (property.Name != "XML") return null; return (string)property.Argument.Value; } private void WriteTypeReference(TypeReference type) { WriteUTF8String(TypeParser.ToParseable(type, top_level: false)); } public void WriteMarshalInfo(MarshalInfo marshal_info) { WriteNativeType(marshal_info.native); switch (marshal_info.native) { case NativeType.Array: { ArrayMarshalInfo array = (ArrayMarshalInfo)marshal_info; if (array.element_type != NativeType.None) WriteNativeType(array.element_type); if (array.size_parameter_index > -1) WriteCompressedUInt32((uint)array.size_parameter_index); if (array.size > -1) WriteCompressedUInt32((uint)array.size); if (array.size_parameter_multiplier > -1) WriteCompressedUInt32((uint)array.size_parameter_multiplier); return; } case NativeType.SafeArray: { SafeArrayMarshalInfo array = (SafeArrayMarshalInfo)marshal_info; if (array.element_type != VariantType.None) WriteVariantType(array.element_type); return; } case NativeType.FixedArray: { FixedArrayMarshalInfo array = (FixedArrayMarshalInfo)marshal_info; if (array.size > -1) WriteCompressedUInt32((uint)array.size); if (array.element_type != NativeType.None) WriteNativeType(array.element_type); return; } case NativeType.FixedSysString: FixedSysStringMarshalInfo sys_string = (FixedSysStringMarshalInfo)marshal_info; if (sys_string.size > -1) WriteCompressedUInt32((uint)sys_string.size); return; case NativeType.CustomMarshaler: CustomMarshalInfo marshaler = (CustomMarshalInfo)marshal_info; WriteUTF8String(marshaler.guid != Guid.Empty ? marshaler.guid.ToString() : string.Empty); WriteUTF8String(marshaler.unmanaged_type); WriteTypeReference(marshaler.managed_type); WriteUTF8String(marshaler.cookie); return; } } private void WriteNativeType(NativeType native) { WriteByte((byte)native); } private void WriteVariantType(VariantType variant) { WriteByte((byte)variant); } public void WriteSequencePoints(MethodDebugInformation info) { int start_line = -1; int start_column = -1; WriteCompressedUInt32(info.local_var_token.RID); Document previous_document; if (!info.TryGetUniqueDocument(out previous_document)) previous_document = null; for (int i = 0; i < info.SequencePoints.Count; i++) { SequencePoint sequence_point = info.SequencePoints[i]; Document document = sequence_point.Document; if (previous_document != document) { MetadataToken document_token = metadata.GetDocumentToken(document); if (previous_document != null) WriteCompressedUInt32(0); WriteCompressedUInt32(document_token.RID); previous_document = document; } if (i > 0) WriteCompressedUInt32((uint)(sequence_point.Offset - info.SequencePoints[i - 1].Offset)); else WriteCompressedUInt32((uint)sequence_point.Offset); if (sequence_point.IsHidden) { WriteInt16(0); continue; } int delta_lines = sequence_point.EndLine - sequence_point.StartLine; int delta_columns = sequence_point.EndColumn - sequence_point.StartColumn; WriteCompressedUInt32((uint)delta_lines); if (delta_lines == 0) WriteCompressedUInt32((uint)delta_columns); else WriteCompressedInt32(delta_columns); if (start_line < 0) { WriteCompressedUInt32((uint)sequence_point.StartLine); WriteCompressedUInt32((uint)sequence_point.StartColumn); } else { WriteCompressedInt32(sequence_point.StartLine - start_line); WriteCompressedInt32(sequence_point.StartColumn - start_column); } start_line = sequence_point.StartLine; start_column = sequence_point.StartColumn; } } } internal static partial class Mixin { public static bool TryGetUniqueDocument(this MethodDebugInformation info, out Document document) { document = info.SequencePoints[0].Document; for (int i = 1; i < info.SequencePoints.Count; i++) { SequencePoint sequence_point = info.SequencePoints[i]; if (sequence_point.Document != document) return false; } return true; } } }