3315 lines
120 KiB
C#
3315 lines
120 KiB
C#
//
|
|
// 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<ushort, ushort, ushort, ushort, AssemblyAttributes, uint, uint, uint, uint>;
|
|
using AssemblyRow = Row<AssemblyHashAlgorithm, ushort, ushort, ushort, ushort, AssemblyAttributes, uint, uint, uint>;
|
|
using ClassLayoutRow = Row<ushort, uint, RID>;
|
|
using ConstantRow = Row<ElementType, CodedRID, BlobIndex>;
|
|
using CustomAttributeRow = Row<CodedRID, CodedRID, BlobIndex>;
|
|
using CustomDebugInformationRow = Row<CodedRID, GuidIndex, BlobIndex>;
|
|
using DeclSecurityRow = Row<SecurityAction, CodedRID, BlobIndex>;
|
|
using DocumentRow = Row<BlobIndex, GuidIndex, BlobIndex, GuidIndex>;
|
|
using EventMapRow = Row<RID, RID>;
|
|
using EventRow = Row<EventAttributes, StringIndex, CodedRID>;
|
|
using ExportedTypeRow = Row<TypeAttributes, uint, StringIndex, StringIndex, CodedRID>;
|
|
using FieldLayoutRow = Row<uint, RID>;
|
|
using FieldMarshalRow = Row<CodedRID, BlobIndex>;
|
|
using FieldRow = Row<FieldAttributes, StringIndex, BlobIndex>;
|
|
using FieldRVARow = Row<RVA, RID>;
|
|
using FileRow = Row<FileAttributes, StringIndex, BlobIndex>;
|
|
using GenericParamConstraintRow = Row<RID, CodedRID>;
|
|
using GenericParamRow = Row<ushort, GenericParameterAttributes, CodedRID, StringIndex>;
|
|
using ImplMapRow = Row<PInvokeAttributes, CodedRID, StringIndex, RID>;
|
|
using ImportScopeRow = Row<RID, BlobIndex>;
|
|
using InterfaceImplRow = Row<uint, CodedRID>;
|
|
using LocalConstantRow = Row<StringIndex, BlobIndex>;
|
|
using LocalScopeRow = Row<RID, RID, RID, RID, uint, uint>;
|
|
using LocalVariableRow = Row<VariableAttributes, ushort, StringIndex>;
|
|
using ManifestResourceRow = Row<uint, ManifestResourceAttributes, StringIndex, CodedRID>;
|
|
using MemberRefRow = Row<CodedRID, StringIndex, BlobIndex>;
|
|
using MethodDebugInformationRow = Row<RID, BlobIndex>;
|
|
using MethodImplRow = Row<RID, CodedRID, CodedRID>;
|
|
using MethodRow = Row<RVA, MethodImplAttributes, MethodAttributes, StringIndex, BlobIndex, RID>;
|
|
using MethodSemanticsRow = Row<MethodSemanticsAttributes, RID, CodedRID>;
|
|
using MethodSpecRow = Row<CodedRID, BlobIndex>;
|
|
using ModuleRow = Row<StringIndex, GuidIndex>;
|
|
using NestedClassRow = Row<RID, RID>;
|
|
using ParamRow = Row<ParameterAttributes, ushort, StringIndex>;
|
|
using PropertyMapRow = Row<RID, RID>;
|
|
using PropertyRow = Row<PropertyAttributes, StringIndex, BlobIndex>;
|
|
using StateMachineMethodRow = Row<RID, RID>;
|
|
using TypeDefRow = Row<TypeAttributes, StringIndex, StringIndex, CodedRID, RID, RID>;
|
|
using TypeRefRow = Row<CodedRID, StringIndex, StringIndex>;
|
|
|
|
internal static class ModuleWriter
|
|
{
|
|
public static void WriteModule(ModuleDefinition module, Disposable<Stream> stream, WriterParameters parameters)
|
|
{
|
|
using (stream)
|
|
{
|
|
Write(module, stream, parameters);
|
|
}
|
|
}
|
|
|
|
private static void Write(ModuleDefinition module, Disposable<Stream> 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<TRow> : MetadataTable where TRow : struct
|
|
{
|
|
internal TRow row;
|
|
public sealed override int Length
|
|
{
|
|
get { return 1; }
|
|
}
|
|
public sealed override void Sort() { }
|
|
}
|
|
|
|
internal abstract class MetadataTable<TRow> : 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<TRow> : MetadataTable<TRow>, IComparer<TRow> where TRow : struct
|
|
{
|
|
public sealed override void Sort()
|
|
{
|
|
MergeSort<TRow>.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<ModuleRow>
|
|
{
|
|
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<TypeRefRow>
|
|
{
|
|
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<TypeDefRow>
|
|
{
|
|
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<FieldRow>
|
|
{
|
|
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<MethodRow>
|
|
{
|
|
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<ParamRow>
|
|
{
|
|
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<InterfaceImplRow>
|
|
{
|
|
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<MemberRefRow>
|
|
{
|
|
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<ConstantRow>
|
|
{
|
|
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<CustomAttributeRow>
|
|
{
|
|
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<FieldMarshalRow>
|
|
{
|
|
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<DeclSecurityRow>
|
|
{
|
|
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<ClassLayoutRow>
|
|
{
|
|
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<FieldLayoutRow>
|
|
{
|
|
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<uint>
|
|
{
|
|
public override void Write(TableHeapBuffer buffer)
|
|
{
|
|
for (int i = 0; i < length; i++)
|
|
buffer.WriteBlob(rows[i]);
|
|
}
|
|
}
|
|
|
|
internal sealed class EventMapTable : MetadataTable<EventMapRow>
|
|
{
|
|
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<EventRow>
|
|
{
|
|
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<PropertyMapRow>
|
|
{
|
|
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<PropertyRow>
|
|
{
|
|
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<MethodSemanticsRow>
|
|
{
|
|
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<MethodImplRow>
|
|
{
|
|
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<uint>
|
|
{
|
|
public override void Write(TableHeapBuffer buffer)
|
|
{
|
|
for (int i = 0; i < length; i++)
|
|
buffer.WriteString(rows[i]); // Name
|
|
}
|
|
}
|
|
|
|
internal sealed class TypeSpecTable : MetadataTable<uint>
|
|
{
|
|
public override void Write(TableHeapBuffer buffer)
|
|
{
|
|
for (int i = 0; i < length; i++)
|
|
buffer.WriteBlob(rows[i]); // Signature
|
|
}
|
|
}
|
|
|
|
internal sealed class ImplMapTable : SortedTable<ImplMapRow>
|
|
{
|
|
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<FieldRVARow>
|
|
{
|
|
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<AssemblyRow>
|
|
{
|
|
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<AssemblyRefRow>
|
|
{
|
|
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<FileRow>
|
|
{
|
|
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<ExportedTypeRow>
|
|
{
|
|
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<ManifestResourceRow>
|
|
{
|
|
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<NestedClassRow>
|
|
{
|
|
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<GenericParamRow>
|
|
{
|
|
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<MethodSpecRow>
|
|
{
|
|
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<GenericParamConstraintRow>
|
|
{
|
|
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<DocumentRow>
|
|
{
|
|
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<MethodDebugInformationRow>
|
|
{
|
|
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<LocalScopeRow>
|
|
{
|
|
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<LocalVariableRow>
|
|
{
|
|
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<LocalConstantRow>
|
|
{
|
|
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<ImportScopeRow>
|
|
{
|
|
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<StateMachineMethodRow>
|
|
{
|
|
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<CustomDebugInformationRow>
|
|
{
|
|
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<TypeRefRow, MetadataToken> type_ref_map;
|
|
private readonly Dictionary<uint, MetadataToken> type_spec_map;
|
|
private readonly Dictionary<MemberRefRow, MetadataToken> member_ref_map;
|
|
private readonly Dictionary<MethodSpecRow, MetadataToken> method_spec_map;
|
|
private readonly Collection<GenericParameter> 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<ImportScopeRow, MetadataToken> import_scope_map;
|
|
private readonly Dictionary<string, MetadataToken> 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<TypeRefTable>(Table.TypeRef);
|
|
type_def_table = GetTable<TypeDefTable>(Table.TypeDef);
|
|
field_table = GetTable<FieldTable>(Table.Field);
|
|
method_table = GetTable<MethodTable>(Table.Method);
|
|
param_table = GetTable<ParamTable>(Table.Param);
|
|
iface_impl_table = GetTable<InterfaceImplTable>(Table.InterfaceImpl);
|
|
member_ref_table = GetTable<MemberRefTable>(Table.MemberRef);
|
|
constant_table = GetTable<ConstantTable>(Table.Constant);
|
|
custom_attribute_table = GetTable<CustomAttributeTable>(Table.CustomAttribute);
|
|
declsec_table = GetTable<DeclSecurityTable>(Table.DeclSecurity);
|
|
standalone_sig_table = GetTable<StandAloneSigTable>(Table.StandAloneSig);
|
|
event_map_table = GetTable<EventMapTable>(Table.EventMap);
|
|
event_table = GetTable<EventTable>(Table.Event);
|
|
property_map_table = GetTable<PropertyMapTable>(Table.PropertyMap);
|
|
property_table = GetTable<PropertyTable>(Table.Property);
|
|
typespec_table = GetTable<TypeSpecTable>(Table.TypeSpec);
|
|
method_spec_table = GetTable<MethodSpecTable>(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<DocumentTable>(Table.Document);
|
|
method_debug_information_table = GetTable<MethodDebugInformationTable>(Table.MethodDebugInformation);
|
|
local_scope_table = GetTable<LocalScopeTable>(Table.LocalScope);
|
|
local_variable_table = GetTable<LocalVariableTable>(Table.LocalVariable);
|
|
local_constant_table = GetTable<LocalConstantTable>(Table.LocalConstant);
|
|
import_scope_table = GetTable<ImportScopeTable>(Table.ImportScope);
|
|
state_machine_method_table = GetTable<StateMachineMethodTable>(Table.StateMachineMethod);
|
|
custom_debug_information_table = GetTable<CustomDebugInformationTable>(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<DocumentTable>(Table.Document);
|
|
method_debug_information_table = GetTable<MethodDebugInformationTable>(Table.MethodDebugInformation);
|
|
local_scope_table = GetTable<LocalScopeTable>(Table.LocalScope);
|
|
local_variable_table = GetTable<LocalVariableTable>(Table.LocalVariable);
|
|
local_constant_table = GetTable<LocalConstantTable>(Table.LocalConstant);
|
|
import_scope_table = GetTable<ImportScopeTable>(Table.ImportScope);
|
|
state_machine_method_table = GetTable<StateMachineMethodTable>(Table.StateMachineMethod);
|
|
custom_debug_information_table = GetTable<CustomDebugInformationTable>(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<TTable>(Table table) where TTable : MetadataTable, new()
|
|
{
|
|
return table_heap.GetTable<TTable>(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<ModuleTable>(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<AssemblyTable>(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<ModuleDefinition> modules = this.module.Assembly.Modules;
|
|
FileTable table = GetTable<FileTable>(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<AssemblyNameReference> references = module.AssemblyReferences;
|
|
AssemblyRefTable table = GetTable<AssemblyRefTable>(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<ModuleReference> references = module.ModuleReferences;
|
|
ModuleRefTable table = GetTable<ModuleRefTable>(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<Resource> resources = module.Resources;
|
|
ManifestResourceTable table = GetTable<ManifestResourceTable>(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<FileTable>(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<ExportedType> exported_types = module.ExportedTypes;
|
|
ExportedTypeTable table = GetTable<ExportedTypeTable>(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<FileTable>(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<TypeDefinition> 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<TypeDefinition> nested_types = type.NestedTypes;
|
|
for (int i = 0; i < nested_types.Count; i++)
|
|
AttachTypeToken(nested_types[i]);
|
|
}
|
|
|
|
private void AttachFieldsToken(TypeDefinition type)
|
|
{
|
|
Collection<FieldDefinition> 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<MethodDefinition> 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<TypeDefinition> 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<GenericParameter> parameters = owner.GenericParameters;
|
|
|
|
for (int i = 0; i < parameters.Count; i++)
|
|
generic_parameters.Add(parameters[i]);
|
|
}
|
|
|
|
private sealed class GenericParameterComparer : IComparer<GenericParameter>
|
|
{
|
|
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<GenericParamTable>(Table.GenericParam);
|
|
GenericParamConstraintTable generic_param_constraint_table = GetTable<GenericParamConstraintTable>(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<GenericParameterConstraint> 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<InterfaceImplementation> 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<ClassLayoutTable>(Table.ClassLayout);
|
|
|
|
table.AddRow(new((ushort)type.PackingSize, (uint)type.ClassSize, type.token.RID));
|
|
}
|
|
|
|
private void AddNestedTypes(TypeDefinition type)
|
|
{
|
|
Collection<TypeDefinition> nested_types = type.NestedTypes;
|
|
NestedClassTable nested_table = GetTable<NestedClassTable>(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<FieldDefinition> 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<FieldRVATable>(Table.FieldRVA);
|
|
table.AddRow(new(data.AddData(field.InitialValue), field.token.RID));
|
|
}
|
|
|
|
private void AddFieldLayout(FieldDefinition field)
|
|
{
|
|
FieldLayoutTable table = GetTable<FieldLayoutTable>(Table.FieldLayout);
|
|
table.AddRow(new((uint)field.Offset, field.token.RID));
|
|
}
|
|
|
|
private void AddMethods(TypeDefinition type)
|
|
{
|
|
Collection<MethodDefinition> 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<ParameterDefinition> 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<ImplMapTable>(Table.ImplMap);
|
|
table.AddRow(new(pinvoke.Attributes, MakeCodedRID(method, CodedIndex.MemberForwarded), GetStringIndex(pinvoke.EntryPoint), pinvoke.Module.MetadataToken.RID));
|
|
}
|
|
|
|
private void AddOverrides(MethodDefinition method)
|
|
{
|
|
Collection<MethodReference> overrides = method.Overrides;
|
|
MethodImplTable table = GetTable<MethodImplTable>(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<FieldMarshalTable>(Table.FieldMarshal);
|
|
|
|
table.AddRow(new(MakeCodedRID(owner, CodedIndex.HasFieldMarshal), GetBlobIndex(GetMarshalInfoSignature(owner))));
|
|
}
|
|
|
|
private void AddProperties(TypeDefinition type)
|
|
{
|
|
Collection<PropertyDefinition> 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<MethodDefinition> others)
|
|
{
|
|
for (int i = 0; i < others.Count; i++)
|
|
AddSemantic(MethodSemanticsAttributes.Other, owner, others[i]);
|
|
}
|
|
|
|
private void AddEvents(TypeDefinition type)
|
|
{
|
|
Collection<EventDefinition> 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<MethodSemanticsTable>(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<CustomAttribute> 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<SecurityDeclaration> 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<VariableDefinition> 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<VariableDefinition> 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<ParameterDefinition> 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<CustomDebugInformation> 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<StateMachineScope> 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<byte>.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<ParameterDefinition> 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<ArrayDimension> 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<TypeReference> 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<CustomAttributeArgument> arguments = attribute.ConstructorArguments;
|
|
Collection<ParameterDefinition> 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 <CLR>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<CustomAttributeNamedArgument> 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<SecurityAttribute> 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;
|
|
}
|
|
}
|
|
} |