94b2861243
Former-commit-id: 5f9c6ae75f295e057a7d2971f3a6df4656fa8850
3234 lines
81 KiB
C#
3234 lines
81 KiB
C#
//
|
|
// AssemblyReader.cs
|
|
//
|
|
// Author:
|
|
// Jb Evain (jbevain@gmail.com)
|
|
//
|
|
// Copyright (c) 2008 - 2011 Jb Evain
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
|
|
using Mono.Collections.Generic;
|
|
using Mono.Cecil.Cil;
|
|
using Mono.Cecil.Metadata;
|
|
using Mono.Cecil.PE;
|
|
|
|
using RVA = System.UInt32;
|
|
|
|
namespace Mono.Cecil {
|
|
|
|
abstract class ModuleReader {
|
|
|
|
readonly protected Image image;
|
|
readonly protected ModuleDefinition module;
|
|
|
|
protected ModuleReader (Image image, ReadingMode mode)
|
|
{
|
|
this.image = image;
|
|
this.module = new ModuleDefinition (image);
|
|
this.module.ReadingMode = mode;
|
|
}
|
|
|
|
protected abstract void ReadModule ();
|
|
|
|
protected void ReadModuleManifest (MetadataReader reader)
|
|
{
|
|
reader.Populate (module);
|
|
|
|
ReadAssembly (reader);
|
|
}
|
|
|
|
void ReadAssembly (MetadataReader reader)
|
|
{
|
|
var name = reader.ReadAssemblyNameDefinition ();
|
|
if (name == null) {
|
|
module.kind = ModuleKind.NetModule;
|
|
return;
|
|
}
|
|
|
|
var assembly = new AssemblyDefinition ();
|
|
assembly.Name = name;
|
|
|
|
module.assembly = assembly;
|
|
assembly.main_module = module;
|
|
}
|
|
|
|
public static ModuleDefinition CreateModuleFrom (Image image, ReaderParameters parameters)
|
|
{
|
|
var module = ReadModule (image, parameters);
|
|
|
|
ReadSymbols (module, parameters);
|
|
|
|
if (parameters.AssemblyResolver != null)
|
|
module.assembly_resolver = parameters.AssemblyResolver;
|
|
|
|
if (parameters.MetadataResolver != null)
|
|
module.metadata_resolver = parameters.MetadataResolver;
|
|
|
|
return module;
|
|
}
|
|
|
|
static void ReadSymbols (ModuleDefinition module, ReaderParameters parameters)
|
|
{
|
|
var symbol_reader_provider = parameters.SymbolReaderProvider;
|
|
|
|
if (symbol_reader_provider == null && parameters.ReadSymbols)
|
|
symbol_reader_provider = SymbolProvider.GetPlatformReaderProvider ();
|
|
|
|
if (symbol_reader_provider != null) {
|
|
module.SymbolReaderProvider = symbol_reader_provider;
|
|
|
|
var reader = parameters.SymbolStream != null
|
|
? symbol_reader_provider.GetSymbolReader (module, parameters.SymbolStream)
|
|
: symbol_reader_provider.GetSymbolReader (module, module.FullyQualifiedName);
|
|
|
|
module.ReadSymbols (reader);
|
|
}
|
|
}
|
|
|
|
static ModuleDefinition ReadModule (Image image, ReaderParameters parameters)
|
|
{
|
|
var reader = CreateModuleReader (image, parameters.ReadingMode);
|
|
reader.ReadModule ();
|
|
return reader.module;
|
|
}
|
|
|
|
static ModuleReader CreateModuleReader (Image image, ReadingMode mode)
|
|
{
|
|
switch (mode) {
|
|
case ReadingMode.Immediate:
|
|
return new ImmediateModuleReader (image);
|
|
case ReadingMode.Deferred:
|
|
return new DeferredModuleReader (image);
|
|
default:
|
|
throw new ArgumentException ();
|
|
}
|
|
}
|
|
}
|
|
|
|
sealed class ImmediateModuleReader : ModuleReader {
|
|
|
|
public ImmediateModuleReader (Image image)
|
|
: base (image, ReadingMode.Immediate)
|
|
{
|
|
}
|
|
|
|
protected override void ReadModule ()
|
|
{
|
|
this.module.Read (this.module, (module, reader) => {
|
|
ReadModuleManifest (reader);
|
|
ReadModule (module);
|
|
return module;
|
|
});
|
|
}
|
|
|
|
public static void ReadModule (ModuleDefinition module)
|
|
{
|
|
if (module.HasAssemblyReferences)
|
|
Read (module.AssemblyReferences);
|
|
if (module.HasResources)
|
|
Read (module.Resources);
|
|
if (module.HasModuleReferences)
|
|
Read (module.ModuleReferences);
|
|
if (module.HasTypes)
|
|
ReadTypes (module.Types);
|
|
if (module.HasExportedTypes)
|
|
Read (module.ExportedTypes);
|
|
if (module.HasCustomAttributes)
|
|
Read (module.CustomAttributes);
|
|
|
|
var assembly = module.Assembly;
|
|
if (assembly == null)
|
|
return;
|
|
|
|
if (assembly.HasCustomAttributes)
|
|
Read (assembly.CustomAttributes);
|
|
if (assembly.HasSecurityDeclarations)
|
|
Read (assembly.SecurityDeclarations);
|
|
}
|
|
|
|
static void ReadTypes (Collection<TypeDefinition> types)
|
|
{
|
|
for (int i = 0; i < types.Count; i++)
|
|
ReadType (types [i]);
|
|
}
|
|
|
|
static void ReadType (TypeDefinition type)
|
|
{
|
|
ReadGenericParameters (type);
|
|
|
|
if (type.HasInterfaces)
|
|
Read (type.Interfaces);
|
|
|
|
if (type.HasNestedTypes)
|
|
ReadTypes (type.NestedTypes);
|
|
|
|
if (type.HasLayoutInfo)
|
|
Read (type.ClassSize);
|
|
|
|
if (type.HasFields)
|
|
ReadFields (type);
|
|
|
|
if (type.HasMethods)
|
|
ReadMethods (type);
|
|
|
|
if (type.HasProperties)
|
|
ReadProperties (type);
|
|
|
|
if (type.HasEvents)
|
|
ReadEvents (type);
|
|
|
|
ReadSecurityDeclarations (type);
|
|
ReadCustomAttributes (type);
|
|
}
|
|
|
|
static void ReadGenericParameters (IGenericParameterProvider provider)
|
|
{
|
|
if (!provider.HasGenericParameters)
|
|
return;
|
|
|
|
var parameters = provider.GenericParameters;
|
|
|
|
for (int i = 0; i < parameters.Count; i++) {
|
|
var parameter = parameters [i];
|
|
|
|
if (parameter.HasConstraints)
|
|
Read (parameter.Constraints);
|
|
|
|
if (parameter.HasCustomAttributes)
|
|
Read (parameter.CustomAttributes);
|
|
}
|
|
}
|
|
|
|
static void ReadSecurityDeclarations (ISecurityDeclarationProvider provider)
|
|
{
|
|
if (provider.HasSecurityDeclarations)
|
|
Read (provider.SecurityDeclarations);
|
|
}
|
|
|
|
static void ReadCustomAttributes (ICustomAttributeProvider provider)
|
|
{
|
|
if (provider.HasCustomAttributes)
|
|
Read (provider.CustomAttributes);
|
|
}
|
|
|
|
static void ReadFields (TypeDefinition type)
|
|
{
|
|
var fields = type.Fields;
|
|
|
|
for (int i = 0; i < fields.Count; i++) {
|
|
var field = fields [i];
|
|
|
|
if (field.HasConstant)
|
|
Read (field.Constant);
|
|
|
|
if (field.HasLayoutInfo)
|
|
Read (field.Offset);
|
|
|
|
if (field.RVA > 0)
|
|
Read (field.InitialValue);
|
|
|
|
if (field.HasMarshalInfo)
|
|
Read (field.MarshalInfo);
|
|
|
|
ReadCustomAttributes (field);
|
|
}
|
|
}
|
|
|
|
static void ReadMethods (TypeDefinition type)
|
|
{
|
|
var methods = type.Methods;
|
|
|
|
for (int i = 0; i < methods.Count; i++) {
|
|
var method = methods [i];
|
|
|
|
ReadGenericParameters (method);
|
|
|
|
if (method.HasParameters)
|
|
ReadParameters (method);
|
|
|
|
if (method.HasOverrides)
|
|
Read (method.Overrides);
|
|
|
|
if (method.IsPInvokeImpl)
|
|
Read (method.PInvokeInfo);
|
|
|
|
ReadSecurityDeclarations (method);
|
|
ReadCustomAttributes (method);
|
|
|
|
var return_type = method.MethodReturnType;
|
|
if (return_type.HasConstant)
|
|
Read (return_type.Constant);
|
|
|
|
if (return_type.HasMarshalInfo)
|
|
Read (return_type.MarshalInfo);
|
|
|
|
ReadCustomAttributes (return_type);
|
|
}
|
|
}
|
|
|
|
static void ReadParameters (MethodDefinition method)
|
|
{
|
|
var parameters = method.Parameters;
|
|
|
|
for (int i = 0; i < parameters.Count; i++) {
|
|
var parameter = parameters [i];
|
|
|
|
if (parameter.HasConstant)
|
|
Read (parameter.Constant);
|
|
|
|
if (parameter.HasMarshalInfo)
|
|
Read (parameter.MarshalInfo);
|
|
|
|
ReadCustomAttributes (parameter);
|
|
}
|
|
}
|
|
|
|
static void ReadProperties (TypeDefinition type)
|
|
{
|
|
var properties = type.Properties;
|
|
|
|
for (int i = 0; i < properties.Count; i++) {
|
|
var property = properties [i];
|
|
|
|
Read (property.GetMethod);
|
|
|
|
if (property.HasConstant)
|
|
Read (property.Constant);
|
|
|
|
ReadCustomAttributes (property);
|
|
}
|
|
}
|
|
|
|
static void ReadEvents (TypeDefinition type)
|
|
{
|
|
var events = type.Events;
|
|
|
|
for (int i = 0; i < events.Count; i++) {
|
|
var @event = events [i];
|
|
|
|
Read (@event.AddMethod);
|
|
|
|
ReadCustomAttributes (@event);
|
|
}
|
|
}
|
|
|
|
static void Read (object collection)
|
|
{
|
|
}
|
|
}
|
|
|
|
sealed class DeferredModuleReader : ModuleReader {
|
|
|
|
public DeferredModuleReader (Image image)
|
|
: base (image, ReadingMode.Deferred)
|
|
{
|
|
}
|
|
|
|
protected override void ReadModule ()
|
|
{
|
|
this.module.Read (this.module, (module, reader) => {
|
|
ReadModuleManifest (reader);
|
|
return module;
|
|
});
|
|
}
|
|
}
|
|
|
|
sealed class MetadataReader : ByteBuffer {
|
|
|
|
readonly internal Image image;
|
|
readonly internal ModuleDefinition module;
|
|
readonly internal MetadataSystem metadata;
|
|
|
|
internal IGenericContext context;
|
|
internal CodeReader code;
|
|
|
|
uint Position {
|
|
get { return (uint) base.position; }
|
|
set { base.position = (int) value; }
|
|
}
|
|
|
|
public MetadataReader (ModuleDefinition module)
|
|
: base (module.Image.MetadataSection.Data)
|
|
{
|
|
this.image = module.Image;
|
|
this.module = module;
|
|
this.metadata = module.MetadataSystem;
|
|
this.code = new CodeReader (image.MetadataSection, this);
|
|
}
|
|
|
|
int GetCodedIndexSize (CodedIndex index)
|
|
{
|
|
return image.GetCodedIndexSize (index);
|
|
}
|
|
|
|
uint ReadByIndexSize (int size)
|
|
{
|
|
if (size == 4)
|
|
return ReadUInt32 ();
|
|
else
|
|
return ReadUInt16 ();
|
|
}
|
|
|
|
byte [] ReadBlob ()
|
|
{
|
|
var blob_heap = image.BlobHeap;
|
|
if (blob_heap == null) {
|
|
position += 2;
|
|
return Empty<byte>.Array;
|
|
}
|
|
|
|
return blob_heap.Read (ReadBlobIndex ());
|
|
}
|
|
|
|
byte [] ReadBlob (uint signature)
|
|
{
|
|
var blob_heap = image.BlobHeap;
|
|
if (blob_heap == null)
|
|
return Empty<byte>.Array;
|
|
|
|
return blob_heap.Read (signature);
|
|
}
|
|
|
|
uint ReadBlobIndex ()
|
|
{
|
|
var blob_heap = image.BlobHeap;
|
|
return ReadByIndexSize (blob_heap != null ? blob_heap.IndexSize : 2);
|
|
}
|
|
|
|
string ReadString ()
|
|
{
|
|
return image.StringHeap.Read (ReadByIndexSize (image.StringHeap.IndexSize));
|
|
}
|
|
|
|
uint ReadStringIndex ()
|
|
{
|
|
return ReadByIndexSize (image.StringHeap.IndexSize);
|
|
}
|
|
|
|
uint ReadTableIndex (Table table)
|
|
{
|
|
return ReadByIndexSize (image.GetTableIndexSize (table));
|
|
}
|
|
|
|
MetadataToken ReadMetadataToken (CodedIndex index)
|
|
{
|
|
return index.GetMetadataToken (ReadByIndexSize (GetCodedIndexSize (index)));
|
|
}
|
|
|
|
int MoveTo (Table table)
|
|
{
|
|
var info = image.TableHeap [table];
|
|
if (info.Length != 0)
|
|
Position = info.Offset;
|
|
|
|
return (int) info.Length;
|
|
}
|
|
|
|
bool MoveTo (Table table, uint row)
|
|
{
|
|
var info = image.TableHeap [table];
|
|
var length = info.Length;
|
|
if (length == 0 || row > length)
|
|
return false;
|
|
|
|
Position = info.Offset + (info.RowSize * (row - 1));
|
|
return true;
|
|
}
|
|
|
|
public AssemblyNameDefinition ReadAssemblyNameDefinition ()
|
|
{
|
|
if (MoveTo (Table.Assembly) == 0)
|
|
return null;
|
|
|
|
var name = new AssemblyNameDefinition ();
|
|
|
|
name.HashAlgorithm = (AssemblyHashAlgorithm) ReadUInt32 ();
|
|
|
|
PopulateVersionAndFlags (name);
|
|
|
|
name.PublicKey = ReadBlob ();
|
|
|
|
PopulateNameAndCulture (name);
|
|
|
|
return name;
|
|
}
|
|
|
|
public ModuleDefinition Populate (ModuleDefinition module)
|
|
{
|
|
if (MoveTo (Table.Module) == 0)
|
|
return module;
|
|
|
|
Advance (2); // Generation
|
|
|
|
module.Name = ReadString ();
|
|
module.Mvid = image.GuidHeap.Read (ReadByIndexSize (image.GuidHeap.IndexSize));
|
|
|
|
return module;
|
|
}
|
|
|
|
void InitializeAssemblyReferences ()
|
|
{
|
|
if (metadata.AssemblyReferences != null)
|
|
return;
|
|
|
|
int length = MoveTo (Table.AssemblyRef);
|
|
var references = metadata.AssemblyReferences = new AssemblyNameReference [length];
|
|
|
|
for (uint i = 0; i < length; i++) {
|
|
var reference = new AssemblyNameReference ();
|
|
reference.token = new MetadataToken (TokenType.AssemblyRef, i + 1);
|
|
|
|
PopulateVersionAndFlags (reference);
|
|
|
|
var key_or_token = ReadBlob ();
|
|
|
|
if (reference.HasPublicKey)
|
|
reference.PublicKey = key_or_token;
|
|
else
|
|
reference.PublicKeyToken = key_or_token;
|
|
|
|
PopulateNameAndCulture (reference);
|
|
|
|
reference.Hash = ReadBlob ();
|
|
|
|
references [i] = reference;
|
|
}
|
|
}
|
|
|
|
public Collection<AssemblyNameReference> ReadAssemblyReferences ()
|
|
{
|
|
InitializeAssemblyReferences ();
|
|
|
|
return new Collection<AssemblyNameReference> (metadata.AssemblyReferences);
|
|
}
|
|
|
|
public MethodDefinition ReadEntryPoint ()
|
|
{
|
|
if (module.Image.EntryPointToken == 0)
|
|
return null;
|
|
|
|
var token = new MetadataToken (module.Image.EntryPointToken);
|
|
return GetMethodDefinition (token.RID);
|
|
}
|
|
|
|
public Collection<ModuleDefinition> ReadModules ()
|
|
{
|
|
var modules = new Collection<ModuleDefinition> (1);
|
|
modules.Add (this.module);
|
|
|
|
int length = MoveTo (Table.File);
|
|
for (uint i = 1; i <= length; i++) {
|
|
var attributes = (FileAttributes) ReadUInt32 ();
|
|
var name = ReadString ();
|
|
ReadBlobIndex ();
|
|
|
|
if (attributes != FileAttributes.ContainsMetaData)
|
|
continue;
|
|
|
|
var parameters = new ReaderParameters {
|
|
ReadingMode = module.ReadingMode,
|
|
SymbolReaderProvider = module.SymbolReaderProvider,
|
|
AssemblyResolver = module.AssemblyResolver
|
|
};
|
|
|
|
modules.Add (ModuleDefinition.ReadModule (
|
|
GetModuleFileName (name), parameters));
|
|
}
|
|
|
|
return modules;
|
|
}
|
|
|
|
string GetModuleFileName (string name)
|
|
{
|
|
if (module.FullyQualifiedName == null)
|
|
throw new NotSupportedException ();
|
|
|
|
var path = Path.GetDirectoryName (module.FullyQualifiedName);
|
|
return Path.Combine (path, name);
|
|
}
|
|
|
|
void InitializeModuleReferences ()
|
|
{
|
|
if (metadata.ModuleReferences != null)
|
|
return;
|
|
|
|
int length = MoveTo (Table.ModuleRef);
|
|
var references = metadata.ModuleReferences = new ModuleReference [length];
|
|
|
|
for (uint i = 0; i < length; i++) {
|
|
var reference = new ModuleReference (ReadString ());
|
|
reference.token = new MetadataToken (TokenType.ModuleRef, i + 1);
|
|
|
|
references [i] = reference;
|
|
}
|
|
}
|
|
|
|
public Collection<ModuleReference> ReadModuleReferences ()
|
|
{
|
|
InitializeModuleReferences ();
|
|
|
|
return new Collection<ModuleReference> (metadata.ModuleReferences);
|
|
}
|
|
|
|
public bool HasFileResource ()
|
|
{
|
|
int length = MoveTo (Table.File);
|
|
if (length == 0)
|
|
return false;
|
|
|
|
for (uint i = 1; i <= length; i++)
|
|
if (ReadFileRecord (i).Col1 == FileAttributes.ContainsNoMetaData)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
public Collection<Resource> ReadResources ()
|
|
{
|
|
int length = MoveTo (Table.ManifestResource);
|
|
var resources = new Collection<Resource> (length);
|
|
|
|
for (int i = 1; i <= length; i++) {
|
|
var offset = ReadUInt32 ();
|
|
var flags = (ManifestResourceAttributes) ReadUInt32 ();
|
|
var name = ReadString ();
|
|
var implementation = ReadMetadataToken (CodedIndex.Implementation);
|
|
|
|
Resource resource;
|
|
|
|
if (implementation.RID == 0) {
|
|
resource = new EmbeddedResource (name, flags, offset, this);
|
|
} else if (implementation.TokenType == TokenType.AssemblyRef) {
|
|
resource = new AssemblyLinkedResource (name, flags) {
|
|
Assembly = (AssemblyNameReference) GetTypeReferenceScope (implementation),
|
|
};
|
|
} else if (implementation.TokenType == TokenType.File) {
|
|
var file_record = ReadFileRecord (implementation.RID);
|
|
|
|
resource = new LinkedResource (name, flags) {
|
|
File = file_record.Col2,
|
|
hash = ReadBlob (file_record.Col3)
|
|
};
|
|
} else
|
|
throw new NotSupportedException ();
|
|
|
|
resources.Add (resource);
|
|
}
|
|
|
|
return resources;
|
|
}
|
|
|
|
Row<FileAttributes, string, uint> ReadFileRecord (uint rid)
|
|
{
|
|
var position = this.position;
|
|
|
|
if (!MoveTo (Table.File, rid))
|
|
throw new ArgumentException ();
|
|
|
|
var record = new Row<FileAttributes, string, uint> (
|
|
(FileAttributes) ReadUInt32 (),
|
|
ReadString (),
|
|
ReadBlobIndex ());
|
|
|
|
this.position = position;
|
|
|
|
return record;
|
|
}
|
|
|
|
public MemoryStream GetManagedResourceStream (uint offset)
|
|
{
|
|
var rva = image.Resources.VirtualAddress;
|
|
var section = image.GetSectionAtVirtualAddress (rva);
|
|
var position = (rva - section.VirtualAddress) + offset;
|
|
var buffer = section.Data;
|
|
|
|
var length = buffer [position]
|
|
| (buffer [position + 1] << 8)
|
|
| (buffer [position + 2] << 16)
|
|
| (buffer [position + 3] << 24);
|
|
|
|
return new MemoryStream (buffer, (int) position + 4, length);
|
|
}
|
|
|
|
void PopulateVersionAndFlags (AssemblyNameReference name)
|
|
{
|
|
name.Version = new Version (
|
|
ReadUInt16 (),
|
|
ReadUInt16 (),
|
|
ReadUInt16 (),
|
|
ReadUInt16 ());
|
|
|
|
name.Attributes = (AssemblyAttributes) ReadUInt32 ();
|
|
}
|
|
|
|
void PopulateNameAndCulture (AssemblyNameReference name)
|
|
{
|
|
name.Name = ReadString ();
|
|
name.Culture = ReadString ();
|
|
}
|
|
|
|
public TypeDefinitionCollection ReadTypes ()
|
|
{
|
|
InitializeTypeDefinitions ();
|
|
var mtypes = metadata.Types;
|
|
var type_count = mtypes.Length - metadata.NestedTypes.Count;
|
|
var types = new TypeDefinitionCollection (module, type_count);
|
|
|
|
for (int i = 0; i < mtypes.Length; i++) {
|
|
var type = mtypes [i];
|
|
if (IsNested (type.Attributes))
|
|
continue;
|
|
|
|
types.Add (type);
|
|
}
|
|
|
|
if (image.HasTable (Table.MethodPtr) || image.HasTable (Table.FieldPtr))
|
|
CompleteTypes ();
|
|
|
|
return types;
|
|
}
|
|
|
|
void CompleteTypes ()
|
|
{
|
|
var types = metadata.Types;
|
|
|
|
for (int i = 0; i < types.Length; i++) {
|
|
var type = types [i];
|
|
|
|
InitializeCollection (type.Fields);
|
|
InitializeCollection (type.Methods);
|
|
}
|
|
}
|
|
|
|
void InitializeTypeDefinitions ()
|
|
{
|
|
if (metadata.Types != null)
|
|
return;
|
|
|
|
InitializeNestedTypes ();
|
|
InitializeFields ();
|
|
InitializeMethods ();
|
|
|
|
int length = MoveTo (Table.TypeDef);
|
|
var types = metadata.Types = new TypeDefinition [length];
|
|
|
|
for (uint i = 0; i < length; i++) {
|
|
if (types [i] != null)
|
|
continue;
|
|
|
|
types [i] = ReadType (i + 1);
|
|
}
|
|
}
|
|
|
|
static bool IsNested (TypeAttributes attributes)
|
|
{
|
|
switch (attributes & TypeAttributes.VisibilityMask) {
|
|
case TypeAttributes.NestedAssembly:
|
|
case TypeAttributes.NestedFamANDAssem:
|
|
case TypeAttributes.NestedFamily:
|
|
case TypeAttributes.NestedFamORAssem:
|
|
case TypeAttributes.NestedPrivate:
|
|
case TypeAttributes.NestedPublic:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public bool HasNestedTypes (TypeDefinition type)
|
|
{
|
|
uint [] mapping;
|
|
InitializeNestedTypes ();
|
|
|
|
if (!metadata.TryGetNestedTypeMapping (type, out mapping))
|
|
return false;
|
|
|
|
return mapping.Length > 0;
|
|
}
|
|
|
|
public Collection<TypeDefinition> ReadNestedTypes (TypeDefinition type)
|
|
{
|
|
InitializeNestedTypes ();
|
|
uint [] mapping;
|
|
if (!metadata.TryGetNestedTypeMapping (type, out mapping))
|
|
return new MemberDefinitionCollection<TypeDefinition> (type);
|
|
|
|
var nested_types = new MemberDefinitionCollection<TypeDefinition> (type, mapping.Length);
|
|
|
|
for (int i = 0; i < mapping.Length; i++) {
|
|
var nested_type = GetTypeDefinition (mapping [i]);
|
|
|
|
if (nested_type != null)
|
|
nested_types.Add (nested_type);
|
|
}
|
|
|
|
metadata.RemoveNestedTypeMapping (type);
|
|
|
|
return nested_types;
|
|
}
|
|
|
|
void InitializeNestedTypes ()
|
|
{
|
|
if (metadata.NestedTypes != null)
|
|
return;
|
|
|
|
var length = MoveTo (Table.NestedClass);
|
|
|
|
metadata.NestedTypes = new Dictionary<uint, uint []> (length);
|
|
metadata.ReverseNestedTypes = new Dictionary<uint, uint> (length);
|
|
|
|
if (length == 0)
|
|
return;
|
|
|
|
for (int i = 1; i <= length; i++) {
|
|
var nested = ReadTableIndex (Table.TypeDef);
|
|
var declaring = ReadTableIndex (Table.TypeDef);
|
|
|
|
AddNestedMapping (declaring, nested);
|
|
}
|
|
}
|
|
|
|
void AddNestedMapping (uint declaring, uint nested)
|
|
{
|
|
metadata.SetNestedTypeMapping (declaring, AddMapping (metadata.NestedTypes, declaring, nested));
|
|
metadata.SetReverseNestedTypeMapping (nested, declaring);
|
|
}
|
|
|
|
static TValue [] AddMapping<TKey, TValue> (Dictionary<TKey, TValue []> cache, TKey key, TValue value)
|
|
{
|
|
TValue [] mapped;
|
|
if (!cache.TryGetValue (key, out mapped)) {
|
|
mapped = new [] { value };
|
|
return mapped;
|
|
}
|
|
|
|
var new_mapped = new TValue [mapped.Length + 1];
|
|
Array.Copy (mapped, new_mapped, mapped.Length);
|
|
new_mapped [mapped.Length] = value;
|
|
return new_mapped;
|
|
}
|
|
|
|
TypeDefinition ReadType (uint rid)
|
|
{
|
|
if (!MoveTo (Table.TypeDef, rid))
|
|
return null;
|
|
|
|
var attributes = (TypeAttributes) ReadUInt32 ();
|
|
var name = ReadString ();
|
|
var @namespace = ReadString ();
|
|
var type = new TypeDefinition (@namespace, name, attributes);
|
|
type.token = new MetadataToken (TokenType.TypeDef, rid);
|
|
type.scope = module;
|
|
type.module = module;
|
|
|
|
metadata.AddTypeDefinition (type);
|
|
|
|
this.context = type;
|
|
|
|
type.BaseType = GetTypeDefOrRef (ReadMetadataToken (CodedIndex.TypeDefOrRef));
|
|
|
|
type.fields_range = ReadFieldsRange (rid);
|
|
type.methods_range = ReadMethodsRange (rid);
|
|
|
|
if (IsNested (attributes))
|
|
type.DeclaringType = GetNestedTypeDeclaringType (type);
|
|
|
|
return type;
|
|
}
|
|
|
|
TypeDefinition GetNestedTypeDeclaringType (TypeDefinition type)
|
|
{
|
|
uint declaring_rid;
|
|
if (!metadata.TryGetReverseNestedTypeMapping (type, out declaring_rid))
|
|
return null;
|
|
|
|
metadata.RemoveReverseNestedTypeMapping (type);
|
|
return GetTypeDefinition (declaring_rid);
|
|
}
|
|
|
|
Range ReadFieldsRange (uint type_index)
|
|
{
|
|
return ReadListRange (type_index, Table.TypeDef, Table.Field);
|
|
}
|
|
|
|
Range ReadMethodsRange (uint type_index)
|
|
{
|
|
return ReadListRange (type_index, Table.TypeDef, Table.Method);
|
|
}
|
|
|
|
Range ReadListRange (uint current_index, Table current, Table target)
|
|
{
|
|
var list = new Range ();
|
|
|
|
list.Start = ReadTableIndex (target);
|
|
|
|
uint next_index;
|
|
var current_table = image.TableHeap [current];
|
|
|
|
if (current_index == current_table.Length)
|
|
next_index = image.TableHeap [target].Length + 1;
|
|
else {
|
|
var position = Position;
|
|
Position += (uint) (current_table.RowSize - image.GetTableIndexSize (target));
|
|
next_index = ReadTableIndex (target);
|
|
Position = position;
|
|
}
|
|
|
|
list.Length = next_index - list.Start;
|
|
|
|
return list;
|
|
}
|
|
|
|
public Row<short, int> ReadTypeLayout (TypeDefinition type)
|
|
{
|
|
InitializeTypeLayouts ();
|
|
Row<ushort, uint> class_layout;
|
|
var rid = type.token.RID;
|
|
if (!metadata.ClassLayouts.TryGetValue (rid, out class_layout))
|
|
return new Row<short, int> (Mixin.NoDataMarker, Mixin.NoDataMarker);
|
|
|
|
type.PackingSize = (short) class_layout.Col1;
|
|
type.ClassSize = (int) class_layout.Col2;
|
|
|
|
metadata.ClassLayouts.Remove (rid);
|
|
|
|
return new Row<short, int> ((short) class_layout.Col1, (int) class_layout.Col2);
|
|
}
|
|
|
|
void InitializeTypeLayouts ()
|
|
{
|
|
if (metadata.ClassLayouts != null)
|
|
return;
|
|
|
|
int length = MoveTo (Table.ClassLayout);
|
|
|
|
var class_layouts = metadata.ClassLayouts = new Dictionary<uint, Row<ushort, uint>> (length);
|
|
|
|
for (uint i = 0; i < length; i++) {
|
|
var packing_size = ReadUInt16 ();
|
|
var class_size = ReadUInt32 ();
|
|
|
|
var parent = ReadTableIndex (Table.TypeDef);
|
|
|
|
class_layouts.Add (parent, new Row<ushort, uint> (packing_size, class_size));
|
|
}
|
|
}
|
|
|
|
public TypeReference GetTypeDefOrRef (MetadataToken token)
|
|
{
|
|
return (TypeReference) LookupToken (token);
|
|
}
|
|
|
|
public TypeDefinition GetTypeDefinition (uint rid)
|
|
{
|
|
InitializeTypeDefinitions ();
|
|
|
|
var type = metadata.GetTypeDefinition (rid);
|
|
if (type != null)
|
|
return type;
|
|
|
|
return ReadTypeDefinition (rid);
|
|
}
|
|
|
|
TypeDefinition ReadTypeDefinition (uint rid)
|
|
{
|
|
if (!MoveTo (Table.TypeDef, rid))
|
|
return null;
|
|
|
|
return ReadType (rid);
|
|
}
|
|
|
|
void InitializeTypeReferences ()
|
|
{
|
|
if (metadata.TypeReferences != null)
|
|
return;
|
|
|
|
metadata.TypeReferences = new TypeReference [image.GetTableLength (Table.TypeRef)];
|
|
}
|
|
|
|
public TypeReference GetTypeReference (string scope, string full_name)
|
|
{
|
|
InitializeTypeReferences ();
|
|
|
|
var length = metadata.TypeReferences.Length;
|
|
|
|
for (uint i = 1; i <= length; i++) {
|
|
var type = GetTypeReference (i);
|
|
|
|
if (type.FullName != full_name)
|
|
continue;
|
|
|
|
if (string.IsNullOrEmpty (scope))
|
|
return type;
|
|
|
|
if (type.Scope.Name == scope)
|
|
return type;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
TypeReference GetTypeReference (uint rid)
|
|
{
|
|
InitializeTypeReferences ();
|
|
|
|
var type = metadata.GetTypeReference (rid);
|
|
if (type != null)
|
|
return type;
|
|
|
|
return ReadTypeReference (rid);
|
|
}
|
|
|
|
TypeReference ReadTypeReference (uint rid)
|
|
{
|
|
if (!MoveTo (Table.TypeRef, rid))
|
|
return null;
|
|
|
|
TypeReference declaring_type = null;
|
|
IMetadataScope scope;
|
|
|
|
var scope_token = ReadMetadataToken (CodedIndex.ResolutionScope);
|
|
|
|
var name = ReadString ();
|
|
var @namespace = ReadString ();
|
|
|
|
var type = new TypeReference (
|
|
@namespace,
|
|
name,
|
|
module,
|
|
null);
|
|
|
|
type.token = new MetadataToken (TokenType.TypeRef, rid);
|
|
|
|
metadata.AddTypeReference (type);
|
|
|
|
if (scope_token.TokenType == TokenType.TypeRef) {
|
|
declaring_type = GetTypeDefOrRef (scope_token);
|
|
|
|
scope = declaring_type != null
|
|
? declaring_type.Scope
|
|
: module;
|
|
} else
|
|
scope = GetTypeReferenceScope (scope_token);
|
|
|
|
type.scope = scope;
|
|
type.DeclaringType = declaring_type;
|
|
|
|
MetadataSystem.TryProcessPrimitiveTypeReference (type);
|
|
|
|
return type;
|
|
}
|
|
|
|
IMetadataScope GetTypeReferenceScope (MetadataToken scope)
|
|
{
|
|
switch (scope.TokenType) {
|
|
case TokenType.AssemblyRef:
|
|
InitializeAssemblyReferences ();
|
|
return metadata.AssemblyReferences [(int) scope.RID - 1];
|
|
case TokenType.ModuleRef:
|
|
InitializeModuleReferences ();
|
|
return metadata.ModuleReferences [(int) scope.RID - 1];
|
|
case TokenType.Module:
|
|
return module;
|
|
default:
|
|
throw new NotSupportedException ();
|
|
}
|
|
}
|
|
|
|
public IEnumerable<TypeReference> GetTypeReferences ()
|
|
{
|
|
InitializeTypeReferences ();
|
|
|
|
var length = image.GetTableLength (Table.TypeRef);
|
|
|
|
var type_references = new TypeReference [length];
|
|
|
|
for (uint i = 1; i <= length; i++)
|
|
type_references [i - 1] = GetTypeReference (i);
|
|
|
|
return type_references;
|
|
}
|
|
|
|
TypeReference GetTypeSpecification (uint rid)
|
|
{
|
|
if (!MoveTo (Table.TypeSpec, rid))
|
|
return null;
|
|
|
|
var reader = ReadSignature (ReadBlobIndex ());
|
|
var type = reader.ReadTypeSignature ();
|
|
if (type.token.RID == 0)
|
|
type.token = new MetadataToken (TokenType.TypeSpec, rid);
|
|
|
|
return type;
|
|
}
|
|
|
|
SignatureReader ReadSignature (uint signature)
|
|
{
|
|
return new SignatureReader (signature, this);
|
|
}
|
|
|
|
public bool HasInterfaces (TypeDefinition type)
|
|
{
|
|
InitializeInterfaces ();
|
|
MetadataToken [] mapping;
|
|
|
|
return metadata.TryGetInterfaceMapping (type, out mapping);
|
|
}
|
|
|
|
public Collection<TypeReference> ReadInterfaces (TypeDefinition type)
|
|
{
|
|
InitializeInterfaces ();
|
|
MetadataToken [] mapping;
|
|
|
|
if (!metadata.TryGetInterfaceMapping (type, out mapping))
|
|
return new Collection<TypeReference> ();
|
|
|
|
var interfaces = new Collection<TypeReference> (mapping.Length);
|
|
|
|
this.context = type;
|
|
|
|
for (int i = 0; i < mapping.Length; i++)
|
|
interfaces.Add (GetTypeDefOrRef (mapping [i]));
|
|
|
|
metadata.RemoveInterfaceMapping (type);
|
|
|
|
return interfaces;
|
|
}
|
|
|
|
void InitializeInterfaces ()
|
|
{
|
|
if (metadata.Interfaces != null)
|
|
return;
|
|
|
|
int length = MoveTo (Table.InterfaceImpl);
|
|
|
|
metadata.Interfaces = new Dictionary<uint, MetadataToken []> (length);
|
|
|
|
for (int i = 0; i < length; i++) {
|
|
var type = ReadTableIndex (Table.TypeDef);
|
|
var @interface = ReadMetadataToken (CodedIndex.TypeDefOrRef);
|
|
|
|
AddInterfaceMapping (type, @interface);
|
|
}
|
|
}
|
|
|
|
void AddInterfaceMapping (uint type, MetadataToken @interface)
|
|
{
|
|
metadata.SetInterfaceMapping (type, AddMapping (metadata.Interfaces, type, @interface));
|
|
}
|
|
|
|
public Collection<FieldDefinition> ReadFields (TypeDefinition type)
|
|
{
|
|
var fields_range = type.fields_range;
|
|
if (fields_range.Length == 0)
|
|
return new MemberDefinitionCollection<FieldDefinition> (type);
|
|
|
|
var fields = new MemberDefinitionCollection<FieldDefinition> (type, (int) fields_range.Length);
|
|
this.context = type;
|
|
|
|
if (!MoveTo (Table.FieldPtr, fields_range.Start)) {
|
|
if (!MoveTo (Table.Field, fields_range.Start))
|
|
return fields;
|
|
|
|
for (uint i = 0; i < fields_range.Length; i++)
|
|
ReadField (fields_range.Start + i, fields);
|
|
} else
|
|
ReadPointers (Table.FieldPtr, Table.Field, fields_range, fields, ReadField);
|
|
|
|
return fields;
|
|
}
|
|
|
|
void ReadField (uint field_rid, Collection<FieldDefinition> fields)
|
|
{
|
|
var attributes = (FieldAttributes) ReadUInt16 ();
|
|
var name = ReadString ();
|
|
var signature = ReadBlobIndex ();
|
|
|
|
var field = new FieldDefinition (name, attributes, ReadFieldType (signature));
|
|
field.token = new MetadataToken (TokenType.Field, field_rid);
|
|
metadata.AddFieldDefinition (field);
|
|
|
|
if (IsDeleted (field))
|
|
return;
|
|
|
|
fields.Add (field);
|
|
}
|
|
|
|
void InitializeFields ()
|
|
{
|
|
if (metadata.Fields != null)
|
|
return;
|
|
|
|
metadata.Fields = new FieldDefinition [image.GetTableLength (Table.Field)];
|
|
}
|
|
|
|
TypeReference ReadFieldType (uint signature)
|
|
{
|
|
var reader = ReadSignature (signature);
|
|
|
|
const byte field_sig = 0x6;
|
|
|
|
if (reader.ReadByte () != field_sig)
|
|
throw new NotSupportedException ();
|
|
|
|
return reader.ReadTypeSignature ();
|
|
}
|
|
|
|
public int ReadFieldRVA (FieldDefinition field)
|
|
{
|
|
InitializeFieldRVAs ();
|
|
var rid = field.token.RID;
|
|
|
|
RVA rva;
|
|
if (!metadata.FieldRVAs.TryGetValue (rid, out rva))
|
|
return 0;
|
|
|
|
var size = GetFieldTypeSize (field.FieldType);
|
|
|
|
if (size == 0 || rva == 0)
|
|
return 0;
|
|
|
|
metadata.FieldRVAs.Remove (rid);
|
|
|
|
field.InitialValue = GetFieldInitializeValue (size, rva);
|
|
|
|
return (int) rva;
|
|
}
|
|
|
|
byte [] GetFieldInitializeValue (int size, RVA rva)
|
|
{
|
|
var section = image.GetSectionAtVirtualAddress (rva);
|
|
if (section == null)
|
|
return Empty<byte>.Array;
|
|
|
|
var value = new byte [size];
|
|
Buffer.BlockCopy (section.Data, (int) (rva - section.VirtualAddress), value, 0, size);
|
|
return value;
|
|
}
|
|
|
|
static int GetFieldTypeSize (TypeReference type)
|
|
{
|
|
int size = 0;
|
|
|
|
switch (type.etype) {
|
|
case ElementType.Boolean:
|
|
case ElementType.U1:
|
|
case ElementType.I1:
|
|
size = 1;
|
|
break;
|
|
case ElementType.U2:
|
|
case ElementType.I2:
|
|
case ElementType.Char:
|
|
size = 2;
|
|
break;
|
|
case ElementType.U4:
|
|
case ElementType.I4:
|
|
case ElementType.R4:
|
|
size = 4;
|
|
break;
|
|
case ElementType.U8:
|
|
case ElementType.I8:
|
|
case ElementType.R8:
|
|
size = 8;
|
|
break;
|
|
case ElementType.Ptr:
|
|
case ElementType.FnPtr:
|
|
size = IntPtr.Size;
|
|
break;
|
|
case ElementType.CModOpt:
|
|
case ElementType.CModReqD:
|
|
return GetFieldTypeSize (((IModifierType) type).ElementType);
|
|
default:
|
|
var field_type = type.CheckedResolve ();
|
|
if (field_type.HasLayoutInfo)
|
|
size = field_type.ClassSize;
|
|
|
|
break;
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
void InitializeFieldRVAs ()
|
|
{
|
|
if (metadata.FieldRVAs != null)
|
|
return;
|
|
|
|
int length = MoveTo (Table.FieldRVA);
|
|
|
|
var field_rvas = metadata.FieldRVAs = new Dictionary<uint, uint> (length);
|
|
|
|
for (int i = 0; i < length; i++) {
|
|
var rva = ReadUInt32 ();
|
|
var field = ReadTableIndex (Table.Field);
|
|
|
|
field_rvas.Add (field, rva);
|
|
}
|
|
}
|
|
|
|
public int ReadFieldLayout (FieldDefinition field)
|
|
{
|
|
InitializeFieldLayouts ();
|
|
var rid = field.token.RID;
|
|
uint offset;
|
|
if (!metadata.FieldLayouts.TryGetValue (rid, out offset))
|
|
return Mixin.NoDataMarker;
|
|
|
|
metadata.FieldLayouts.Remove (rid);
|
|
|
|
return (int) offset;
|
|
}
|
|
|
|
void InitializeFieldLayouts ()
|
|
{
|
|
if (metadata.FieldLayouts != null)
|
|
return;
|
|
|
|
int length = MoveTo (Table.FieldLayout);
|
|
|
|
var field_layouts = metadata.FieldLayouts = new Dictionary<uint, uint> (length);
|
|
|
|
for (int i = 0; i < length; i++) {
|
|
var offset = ReadUInt32 ();
|
|
var field = ReadTableIndex (Table.Field);
|
|
|
|
field_layouts.Add (field, offset);
|
|
}
|
|
}
|
|
|
|
public bool HasEvents (TypeDefinition type)
|
|
{
|
|
InitializeEvents ();
|
|
|
|
Range range;
|
|
if (!metadata.TryGetEventsRange (type, out range))
|
|
return false;
|
|
|
|
return range.Length > 0;
|
|
}
|
|
|
|
public Collection<EventDefinition> ReadEvents (TypeDefinition type)
|
|
{
|
|
InitializeEvents ();
|
|
Range range;
|
|
|
|
if (!metadata.TryGetEventsRange (type, out range))
|
|
return new MemberDefinitionCollection<EventDefinition> (type);
|
|
|
|
var events = new MemberDefinitionCollection<EventDefinition> (type, (int) range.Length);
|
|
|
|
metadata.RemoveEventsRange (type);
|
|
|
|
if (range.Length == 0)
|
|
return events;
|
|
|
|
this.context = type;
|
|
|
|
if (!MoveTo (Table.EventPtr, range.Start)) {
|
|
if (!MoveTo (Table.Event, range.Start))
|
|
return events;
|
|
|
|
for (uint i = 0; i < range.Length; i++)
|
|
ReadEvent (range.Start + i, events);
|
|
} else
|
|
ReadPointers (Table.EventPtr, Table.Event, range, events, ReadEvent);
|
|
|
|
return events;
|
|
}
|
|
|
|
void ReadEvent (uint event_rid, Collection<EventDefinition> events)
|
|
{
|
|
var attributes = (EventAttributes) ReadUInt16 ();
|
|
var name = ReadString ();
|
|
var event_type = GetTypeDefOrRef (ReadMetadataToken (CodedIndex.TypeDefOrRef));
|
|
|
|
var @event = new EventDefinition (name, attributes, event_type);
|
|
@event.token = new MetadataToken (TokenType.Event, event_rid);
|
|
|
|
if (IsDeleted (@event))
|
|
return;
|
|
|
|
events.Add (@event);
|
|
}
|
|
|
|
void InitializeEvents ()
|
|
{
|
|
if (metadata.Events != null)
|
|
return;
|
|
|
|
int length = MoveTo (Table.EventMap);
|
|
|
|
metadata.Events = new Dictionary<uint, Range> (length);
|
|
|
|
for (uint i = 1; i <= length; i++) {
|
|
var type_rid = ReadTableIndex (Table.TypeDef);
|
|
Range events_range = ReadEventsRange (i);
|
|
metadata.AddEventsRange (type_rid, events_range);
|
|
}
|
|
}
|
|
|
|
Range ReadEventsRange (uint rid)
|
|
{
|
|
return ReadListRange (rid, Table.EventMap, Table.Event);
|
|
}
|
|
|
|
public bool HasProperties (TypeDefinition type)
|
|
{
|
|
InitializeProperties ();
|
|
|
|
Range range;
|
|
if (!metadata.TryGetPropertiesRange (type, out range))
|
|
return false;
|
|
|
|
return range.Length > 0;
|
|
}
|
|
|
|
public Collection<PropertyDefinition> ReadProperties (TypeDefinition type)
|
|
{
|
|
InitializeProperties ();
|
|
|
|
Range range;
|
|
|
|
if (!metadata.TryGetPropertiesRange (type, out range))
|
|
return new MemberDefinitionCollection<PropertyDefinition> (type);
|
|
|
|
metadata.RemovePropertiesRange (type);
|
|
|
|
var properties = new MemberDefinitionCollection<PropertyDefinition> (type, (int) range.Length);
|
|
|
|
if (range.Length == 0)
|
|
return properties;
|
|
|
|
this.context = type;
|
|
|
|
if (!MoveTo (Table.PropertyPtr, range.Start)) {
|
|
if (!MoveTo (Table.Property, range.Start))
|
|
return properties;
|
|
for (uint i = 0; i < range.Length; i++)
|
|
ReadProperty (range.Start + i, properties);
|
|
} else
|
|
ReadPointers (Table.PropertyPtr, Table.Property, range, properties, ReadProperty);
|
|
|
|
return properties;
|
|
}
|
|
|
|
void ReadProperty (uint property_rid, Collection<PropertyDefinition> properties)
|
|
{
|
|
var attributes = (PropertyAttributes) ReadUInt16 ();
|
|
var name = ReadString ();
|
|
var signature = ReadBlobIndex ();
|
|
|
|
var reader = ReadSignature (signature);
|
|
const byte property_signature = 0x8;
|
|
|
|
var calling_convention = reader.ReadByte ();
|
|
|
|
if ((calling_convention & property_signature) == 0)
|
|
throw new NotSupportedException ();
|
|
|
|
var has_this = (calling_convention & 0x20) != 0;
|
|
|
|
reader.ReadCompressedUInt32 (); // count
|
|
|
|
var property = new PropertyDefinition (name, attributes, reader.ReadTypeSignature ());
|
|
property.HasThis = has_this;
|
|
property.token = new MetadataToken (TokenType.Property, property_rid);
|
|
|
|
if (IsDeleted (property))
|
|
return;
|
|
|
|
properties.Add (property);
|
|
}
|
|
|
|
void InitializeProperties ()
|
|
{
|
|
if (metadata.Properties != null)
|
|
return;
|
|
|
|
int length = MoveTo (Table.PropertyMap);
|
|
|
|
metadata.Properties = new Dictionary<uint, Range> (length);
|
|
|
|
for (uint i = 1; i <= length; i++) {
|
|
var type_rid = ReadTableIndex (Table.TypeDef);
|
|
var properties_range = ReadPropertiesRange (i);
|
|
metadata.AddPropertiesRange (type_rid, properties_range);
|
|
}
|
|
}
|
|
|
|
Range ReadPropertiesRange (uint rid)
|
|
{
|
|
return ReadListRange (rid, Table.PropertyMap, Table.Property);
|
|
}
|
|
|
|
MethodSemanticsAttributes ReadMethodSemantics (MethodDefinition method)
|
|
{
|
|
InitializeMethodSemantics ();
|
|
Row<MethodSemanticsAttributes, MetadataToken> row;
|
|
if (!metadata.Semantics.TryGetValue (method.token.RID, out row))
|
|
return MethodSemanticsAttributes.None;
|
|
|
|
var type = method.DeclaringType;
|
|
|
|
switch (row.Col1) {
|
|
case MethodSemanticsAttributes.AddOn:
|
|
GetEvent (type, row.Col2).add_method = method;
|
|
break;
|
|
case MethodSemanticsAttributes.Fire:
|
|
GetEvent (type, row.Col2).invoke_method = method;
|
|
break;
|
|
case MethodSemanticsAttributes.RemoveOn:
|
|
GetEvent (type, row.Col2).remove_method = method;
|
|
break;
|
|
case MethodSemanticsAttributes.Getter:
|
|
GetProperty (type, row.Col2).get_method = method;
|
|
break;
|
|
case MethodSemanticsAttributes.Setter:
|
|
GetProperty (type, row.Col2).set_method = method;
|
|
break;
|
|
case MethodSemanticsAttributes.Other:
|
|
switch (row.Col2.TokenType) {
|
|
case TokenType.Event: {
|
|
var @event = GetEvent (type, row.Col2);
|
|
if (@event.other_methods == null)
|
|
@event.other_methods = new Collection<MethodDefinition> ();
|
|
|
|
@event.other_methods.Add (method);
|
|
break;
|
|
}
|
|
case TokenType.Property: {
|
|
var property = GetProperty (type, row.Col2);
|
|
if (property.other_methods == null)
|
|
property.other_methods = new Collection<MethodDefinition> ();
|
|
|
|
property.other_methods.Add (method);
|
|
|
|
break;
|
|
}
|
|
default:
|
|
throw new NotSupportedException ();
|
|
}
|
|
break;
|
|
default:
|
|
throw new NotSupportedException ();
|
|
}
|
|
|
|
metadata.Semantics.Remove (method.token.RID);
|
|
|
|
return row.Col1;
|
|
}
|
|
|
|
static EventDefinition GetEvent (TypeDefinition type, MetadataToken token)
|
|
{
|
|
if (token.TokenType != TokenType.Event)
|
|
throw new ArgumentException ();
|
|
|
|
return GetMember (type.Events, token);
|
|
}
|
|
|
|
static PropertyDefinition GetProperty (TypeDefinition type, MetadataToken token)
|
|
{
|
|
if (token.TokenType != TokenType.Property)
|
|
throw new ArgumentException ();
|
|
|
|
return GetMember (type.Properties, token);
|
|
}
|
|
|
|
static TMember GetMember<TMember> (Collection<TMember> members, MetadataToken token) where TMember : IMemberDefinition
|
|
{
|
|
for (int i = 0; i < members.Count; i++) {
|
|
var member = members [i];
|
|
if (member.MetadataToken == token)
|
|
return member;
|
|
}
|
|
|
|
throw new ArgumentException ();
|
|
}
|
|
|
|
void InitializeMethodSemantics ()
|
|
{
|
|
if (metadata.Semantics != null)
|
|
return;
|
|
|
|
int length = MoveTo (Table.MethodSemantics);
|
|
|
|
var semantics = metadata.Semantics = new Dictionary<uint, Row<MethodSemanticsAttributes, MetadataToken>> (0);
|
|
|
|
for (uint i = 0; i < length; i++) {
|
|
var attributes = (MethodSemanticsAttributes) ReadUInt16 ();
|
|
var method_rid = ReadTableIndex (Table.Method);
|
|
var association = ReadMetadataToken (CodedIndex.HasSemantics);
|
|
|
|
semantics [method_rid] = new Row<MethodSemanticsAttributes, MetadataToken> (attributes, association);
|
|
}
|
|
}
|
|
|
|
public PropertyDefinition ReadMethods (PropertyDefinition property)
|
|
{
|
|
ReadAllSemantics (property.DeclaringType);
|
|
return property;
|
|
}
|
|
|
|
public EventDefinition ReadMethods (EventDefinition @event)
|
|
{
|
|
ReadAllSemantics (@event.DeclaringType);
|
|
return @event;
|
|
}
|
|
|
|
public MethodSemanticsAttributes ReadAllSemantics (MethodDefinition method)
|
|
{
|
|
ReadAllSemantics (method.DeclaringType);
|
|
|
|
return method.SemanticsAttributes;
|
|
}
|
|
|
|
void ReadAllSemantics (TypeDefinition type)
|
|
{
|
|
var methods = type.Methods;
|
|
for (int i = 0; i < methods.Count; i++) {
|
|
var method = methods [i];
|
|
if (method.sem_attrs.HasValue)
|
|
continue;
|
|
|
|
method.sem_attrs = ReadMethodSemantics (method);
|
|
}
|
|
}
|
|
|
|
Range ReadParametersRange (uint method_rid)
|
|
{
|
|
return ReadListRange (method_rid, Table.Method, Table.Param);
|
|
}
|
|
|
|
public Collection<MethodDefinition> ReadMethods (TypeDefinition type)
|
|
{
|
|
var methods_range = type.methods_range;
|
|
if (methods_range.Length == 0)
|
|
return new MemberDefinitionCollection<MethodDefinition> (type);
|
|
|
|
var methods = new MemberDefinitionCollection<MethodDefinition> (type, (int) methods_range.Length);
|
|
if (!MoveTo (Table.MethodPtr, methods_range.Start)) {
|
|
if (!MoveTo (Table.Method, methods_range.Start))
|
|
return methods;
|
|
|
|
for (uint i = 0; i < methods_range.Length; i++)
|
|
ReadMethod (methods_range.Start + i, methods);
|
|
} else
|
|
ReadPointers (Table.MethodPtr, Table.Method, methods_range, methods, ReadMethod);
|
|
|
|
return methods;
|
|
}
|
|
|
|
void ReadPointers<TMember> (Table ptr, Table table, Range range, Collection<TMember> members, Action<uint, Collection<TMember>> reader)
|
|
where TMember : IMemberDefinition
|
|
{
|
|
for (uint i = 0; i < range.Length; i++) {
|
|
MoveTo (ptr, range.Start + i);
|
|
|
|
var rid = ReadTableIndex (table);
|
|
MoveTo (table, rid);
|
|
|
|
reader (rid, members);
|
|
}
|
|
}
|
|
|
|
static bool IsDeleted (IMemberDefinition member)
|
|
{
|
|
return member.IsSpecialName && member.Name == "_Deleted";
|
|
}
|
|
|
|
void InitializeMethods ()
|
|
{
|
|
if (metadata.Methods != null)
|
|
return;
|
|
|
|
metadata.Methods = new MethodDefinition [image.GetTableLength (Table.Method)];
|
|
}
|
|
|
|
void ReadMethod (uint method_rid, Collection<MethodDefinition> methods)
|
|
{
|
|
var method = new MethodDefinition ();
|
|
method.rva = ReadUInt32 ();
|
|
method.ImplAttributes = (MethodImplAttributes) ReadUInt16 ();
|
|
method.Attributes = (MethodAttributes) ReadUInt16 ();
|
|
method.Name = ReadString ();
|
|
method.token = new MetadataToken (TokenType.Method, method_rid);
|
|
|
|
if (IsDeleted (method))
|
|
return;
|
|
|
|
methods.Add (method); // attach method
|
|
|
|
var signature = ReadBlobIndex ();
|
|
var param_range = ReadParametersRange (method_rid);
|
|
|
|
this.context = method;
|
|
|
|
ReadMethodSignature (signature, method);
|
|
metadata.AddMethodDefinition (method);
|
|
|
|
if (param_range.Length == 0)
|
|
return;
|
|
|
|
var position = base.position;
|
|
ReadParameters (method, param_range);
|
|
base.position = position;
|
|
}
|
|
|
|
void ReadParameters (MethodDefinition method, Range param_range)
|
|
{
|
|
if (!MoveTo (Table.ParamPtr, param_range.Start)) {
|
|
if (!MoveTo (Table.Param, param_range.Start))
|
|
return;
|
|
|
|
for (uint i = 0; i < param_range.Length; i++)
|
|
ReadParameter (param_range.Start + i, method);
|
|
} else
|
|
ReadParameterPointers (method, param_range);
|
|
}
|
|
|
|
void ReadParameterPointers (MethodDefinition method, Range range)
|
|
{
|
|
for (uint i = 0; i < range.Length; i++) {
|
|
MoveTo (Table.ParamPtr, range.Start + i);
|
|
|
|
var rid = ReadTableIndex (Table.Param);
|
|
|
|
MoveTo (Table.Param, rid);
|
|
|
|
ReadParameter (rid, method);
|
|
}
|
|
}
|
|
|
|
void ReadParameter (uint param_rid, MethodDefinition method)
|
|
{
|
|
var attributes = (ParameterAttributes) ReadUInt16 ();
|
|
var sequence = ReadUInt16 ();
|
|
var name = ReadString ();
|
|
|
|
var parameter = sequence == 0
|
|
? method.MethodReturnType.Parameter
|
|
: method.Parameters [sequence - 1];
|
|
|
|
parameter.token = new MetadataToken (TokenType.Param, param_rid);
|
|
parameter.Name = name;
|
|
parameter.Attributes = attributes;
|
|
}
|
|
|
|
void ReadMethodSignature (uint signature, IMethodSignature method)
|
|
{
|
|
var reader = ReadSignature (signature);
|
|
reader.ReadMethodSignature (method);
|
|
}
|
|
|
|
public PInvokeInfo ReadPInvokeInfo (MethodDefinition method)
|
|
{
|
|
InitializePInvokes ();
|
|
Row<PInvokeAttributes, uint, uint> row;
|
|
|
|
var rid = method.token.RID;
|
|
|
|
if (!metadata.PInvokes.TryGetValue (rid, out row))
|
|
return null;
|
|
|
|
metadata.PInvokes.Remove (rid);
|
|
|
|
return new PInvokeInfo (
|
|
row.Col1,
|
|
image.StringHeap.Read (row.Col2),
|
|
module.ModuleReferences [(int) row.Col3 - 1]);
|
|
}
|
|
|
|
void InitializePInvokes ()
|
|
{
|
|
if (metadata.PInvokes != null)
|
|
return;
|
|
|
|
int length = MoveTo (Table.ImplMap);
|
|
|
|
var pinvokes = metadata.PInvokes = new Dictionary<uint, Row<PInvokeAttributes, uint, uint>> (length);
|
|
|
|
for (int i = 1; i <= length; i++) {
|
|
var attributes = (PInvokeAttributes) ReadUInt16 ();
|
|
var method = ReadMetadataToken (CodedIndex.MemberForwarded);
|
|
var name = ReadStringIndex ();
|
|
var scope = ReadTableIndex (Table.File);
|
|
|
|
if (method.TokenType != TokenType.Method)
|
|
continue;
|
|
|
|
pinvokes.Add (method.RID, new Row<PInvokeAttributes, uint, uint> (attributes, name, scope));
|
|
}
|
|
}
|
|
|
|
public bool HasGenericParameters (IGenericParameterProvider provider)
|
|
{
|
|
InitializeGenericParameters ();
|
|
|
|
Range [] ranges;
|
|
if (!metadata.TryGetGenericParameterRanges (provider, out ranges))
|
|
return false;
|
|
|
|
return RangesSize (ranges) > 0;
|
|
}
|
|
|
|
public Collection<GenericParameter> ReadGenericParameters (IGenericParameterProvider provider)
|
|
{
|
|
InitializeGenericParameters ();
|
|
|
|
Range [] ranges;
|
|
if (!metadata.TryGetGenericParameterRanges (provider, out ranges))
|
|
return new GenericParameterCollection (provider);
|
|
|
|
metadata.RemoveGenericParameterRange (provider);
|
|
|
|
var generic_parameters = new GenericParameterCollection (provider, RangesSize (ranges));
|
|
|
|
for (int i = 0; i < ranges.Length; i++)
|
|
ReadGenericParametersRange (ranges [i], provider, generic_parameters);
|
|
|
|
return generic_parameters;
|
|
}
|
|
|
|
void ReadGenericParametersRange (Range range, IGenericParameterProvider provider, GenericParameterCollection generic_parameters)
|
|
{
|
|
if (!MoveTo (Table.GenericParam, range.Start))
|
|
return;
|
|
|
|
for (uint i = 0; i < range.Length; i++) {
|
|
ReadUInt16 (); // index
|
|
var flags = (GenericParameterAttributes) ReadUInt16 ();
|
|
ReadMetadataToken (CodedIndex.TypeOrMethodDef);
|
|
var name = ReadString ();
|
|
|
|
var parameter = new GenericParameter (name, provider);
|
|
parameter.token = new MetadataToken (TokenType.GenericParam, range.Start + i);
|
|
parameter.Attributes = flags;
|
|
|
|
generic_parameters.Add (parameter);
|
|
}
|
|
}
|
|
|
|
void InitializeGenericParameters ()
|
|
{
|
|
if (metadata.GenericParameters != null)
|
|
return;
|
|
|
|
metadata.GenericParameters = InitializeRanges (
|
|
Table.GenericParam, () => {
|
|
Advance (4);
|
|
var next = ReadMetadataToken (CodedIndex.TypeOrMethodDef);
|
|
ReadStringIndex ();
|
|
return next;
|
|
});
|
|
}
|
|
|
|
Dictionary<MetadataToken, Range []> InitializeRanges (Table table, Func<MetadataToken> get_next)
|
|
{
|
|
int length = MoveTo (table);
|
|
var ranges = new Dictionary<MetadataToken, Range []> (length);
|
|
|
|
if (length == 0)
|
|
return ranges;
|
|
|
|
MetadataToken owner = MetadataToken.Zero;
|
|
Range range = new Range (1, 0);
|
|
|
|
for (uint i = 1; i <= length; i++) {
|
|
var next = get_next ();
|
|
|
|
if (i == 1) {
|
|
owner = next;
|
|
range.Length++;
|
|
} else if (next != owner) {
|
|
AddRange (ranges, owner, range);
|
|
range = new Range (i, 1);
|
|
owner = next;
|
|
} else
|
|
range.Length++;
|
|
}
|
|
|
|
AddRange (ranges, owner, range);
|
|
|
|
return ranges;
|
|
}
|
|
|
|
static void AddRange (Dictionary<MetadataToken, Range []> ranges, MetadataToken owner, Range range)
|
|
{
|
|
if (owner.RID == 0)
|
|
return;
|
|
|
|
Range [] slots;
|
|
if (!ranges.TryGetValue (owner, out slots)) {
|
|
ranges.Add (owner, new [] { range });
|
|
return;
|
|
}
|
|
|
|
slots = slots.Resize (slots.Length + 1);
|
|
slots [slots.Length - 1] = range;
|
|
ranges [owner] = slots;
|
|
}
|
|
|
|
public bool HasGenericConstraints (GenericParameter generic_parameter)
|
|
{
|
|
InitializeGenericConstraints ();
|
|
|
|
MetadataToken [] mapping;
|
|
if (!metadata.TryGetGenericConstraintMapping (generic_parameter, out mapping))
|
|
return false;
|
|
|
|
return mapping.Length > 0;
|
|
}
|
|
|
|
public Collection<TypeReference> ReadGenericConstraints (GenericParameter generic_parameter)
|
|
{
|
|
InitializeGenericConstraints ();
|
|
|
|
MetadataToken [] mapping;
|
|
if (!metadata.TryGetGenericConstraintMapping (generic_parameter, out mapping))
|
|
return new Collection<TypeReference> ();
|
|
|
|
var constraints = new Collection<TypeReference> (mapping.Length);
|
|
|
|
this.context = (IGenericContext) generic_parameter.Owner;
|
|
|
|
for (int i = 0; i < mapping.Length; i++)
|
|
constraints.Add (GetTypeDefOrRef (mapping [i]));
|
|
|
|
metadata.RemoveGenericConstraintMapping (generic_parameter);
|
|
|
|
return constraints;
|
|
}
|
|
|
|
void InitializeGenericConstraints ()
|
|
{
|
|
if (metadata.GenericConstraints != null)
|
|
return;
|
|
|
|
var length = MoveTo (Table.GenericParamConstraint);
|
|
|
|
metadata.GenericConstraints = new Dictionary<uint, MetadataToken []> (length);
|
|
|
|
for (int i = 1; i <= length; i++)
|
|
AddGenericConstraintMapping (
|
|
ReadTableIndex (Table.GenericParam),
|
|
ReadMetadataToken (CodedIndex.TypeDefOrRef));
|
|
}
|
|
|
|
void AddGenericConstraintMapping (uint generic_parameter, MetadataToken constraint)
|
|
{
|
|
metadata.SetGenericConstraintMapping (
|
|
generic_parameter,
|
|
AddMapping (metadata.GenericConstraints, generic_parameter, constraint));
|
|
}
|
|
|
|
public bool HasOverrides (MethodDefinition method)
|
|
{
|
|
InitializeOverrides ();
|
|
MetadataToken [] mapping;
|
|
|
|
if (!metadata.TryGetOverrideMapping (method, out mapping))
|
|
return false;
|
|
|
|
return mapping.Length > 0;
|
|
}
|
|
|
|
public Collection<MethodReference> ReadOverrides (MethodDefinition method)
|
|
{
|
|
InitializeOverrides ();
|
|
|
|
MetadataToken [] mapping;
|
|
if (!metadata.TryGetOverrideMapping (method, out mapping))
|
|
return new Collection<MethodReference> ();
|
|
|
|
var overrides = new Collection<MethodReference> (mapping.Length);
|
|
|
|
this.context = method;
|
|
|
|
for (int i = 0; i < mapping.Length; i++)
|
|
overrides.Add ((MethodReference) LookupToken (mapping [i]));
|
|
|
|
metadata.RemoveOverrideMapping (method);
|
|
|
|
return overrides;
|
|
}
|
|
|
|
void InitializeOverrides ()
|
|
{
|
|
if (metadata.Overrides != null)
|
|
return;
|
|
|
|
var length = MoveTo (Table.MethodImpl);
|
|
|
|
metadata.Overrides = new Dictionary<uint, MetadataToken []> (length);
|
|
|
|
for (int i = 1; i <= length; i++) {
|
|
ReadTableIndex (Table.TypeDef);
|
|
|
|
var method = ReadMetadataToken (CodedIndex.MethodDefOrRef);
|
|
if (method.TokenType != TokenType.Method)
|
|
throw new NotSupportedException ();
|
|
|
|
var @override = ReadMetadataToken (CodedIndex.MethodDefOrRef);
|
|
|
|
AddOverrideMapping (method.RID, @override);
|
|
}
|
|
}
|
|
|
|
void AddOverrideMapping (uint method_rid, MetadataToken @override)
|
|
{
|
|
metadata.SetOverrideMapping (
|
|
method_rid,
|
|
AddMapping (metadata.Overrides, method_rid, @override));
|
|
}
|
|
|
|
public MethodBody ReadMethodBody (MethodDefinition method)
|
|
{
|
|
return code.ReadMethodBody (method);
|
|
}
|
|
|
|
public CallSite ReadCallSite (MetadataToken token)
|
|
{
|
|
if (!MoveTo (Table.StandAloneSig, token.RID))
|
|
return null;
|
|
|
|
var signature = ReadBlobIndex ();
|
|
|
|
var call_site = new CallSite ();
|
|
|
|
ReadMethodSignature (signature, call_site);
|
|
|
|
call_site.MetadataToken = token;
|
|
|
|
return call_site;
|
|
}
|
|
|
|
public VariableDefinitionCollection ReadVariables (MetadataToken local_var_token)
|
|
{
|
|
if (!MoveTo (Table.StandAloneSig, local_var_token.RID))
|
|
return null;
|
|
|
|
var reader = ReadSignature (ReadBlobIndex ());
|
|
const byte local_sig = 0x7;
|
|
|
|
if (reader.ReadByte () != local_sig)
|
|
throw new NotSupportedException ();
|
|
|
|
var count = reader.ReadCompressedUInt32 ();
|
|
if (count == 0)
|
|
return null;
|
|
|
|
var variables = new VariableDefinitionCollection ((int) count);
|
|
|
|
for (int i = 0; i < count; i++)
|
|
variables.Add (new VariableDefinition (reader.ReadTypeSignature ()));
|
|
|
|
return variables;
|
|
}
|
|
|
|
public IMetadataTokenProvider LookupToken (MetadataToken token)
|
|
{
|
|
var rid = token.RID;
|
|
|
|
if (rid == 0)
|
|
return null;
|
|
|
|
IMetadataTokenProvider element;
|
|
var position = this.position;
|
|
var context = this.context;
|
|
|
|
switch (token.TokenType) {
|
|
case TokenType.TypeDef:
|
|
element = GetTypeDefinition (rid);
|
|
break;
|
|
case TokenType.TypeRef:
|
|
element = GetTypeReference (rid);
|
|
break;
|
|
case TokenType.TypeSpec:
|
|
element = GetTypeSpecification (rid);
|
|
break;
|
|
case TokenType.Field:
|
|
element = GetFieldDefinition (rid);
|
|
break;
|
|
case TokenType.Method:
|
|
element = GetMethodDefinition (rid);
|
|
break;
|
|
case TokenType.MemberRef:
|
|
element = GetMemberReference (rid);
|
|
break;
|
|
case TokenType.MethodSpec:
|
|
element = GetMethodSpecification (rid);
|
|
break;
|
|
default:
|
|
return null;
|
|
}
|
|
|
|
this.position = position;
|
|
this.context = context;
|
|
|
|
return element;
|
|
}
|
|
|
|
public FieldDefinition GetFieldDefinition (uint rid)
|
|
{
|
|
InitializeTypeDefinitions ();
|
|
|
|
var field = metadata.GetFieldDefinition (rid);
|
|
if (field != null)
|
|
return field;
|
|
|
|
return LookupField (rid);
|
|
}
|
|
|
|
FieldDefinition LookupField (uint rid)
|
|
{
|
|
var type = metadata.GetFieldDeclaringType (rid);
|
|
if (type == null)
|
|
return null;
|
|
|
|
InitializeCollection (type.Fields);
|
|
|
|
return metadata.GetFieldDefinition (rid);
|
|
}
|
|
|
|
public MethodDefinition GetMethodDefinition (uint rid)
|
|
{
|
|
InitializeTypeDefinitions ();
|
|
|
|
var method = metadata.GetMethodDefinition (rid);
|
|
if (method != null)
|
|
return method;
|
|
|
|
return LookupMethod (rid);
|
|
}
|
|
|
|
MethodDefinition LookupMethod (uint rid)
|
|
{
|
|
var type = metadata.GetMethodDeclaringType (rid);
|
|
if (type == null)
|
|
return null;
|
|
|
|
InitializeCollection (type.Methods);
|
|
|
|
return metadata.GetMethodDefinition (rid);
|
|
}
|
|
|
|
MethodSpecification GetMethodSpecification (uint rid)
|
|
{
|
|
if (!MoveTo (Table.MethodSpec, rid))
|
|
return null;
|
|
|
|
var element_method = (MethodReference) LookupToken (
|
|
ReadMetadataToken (CodedIndex.MethodDefOrRef));
|
|
var signature = ReadBlobIndex ();
|
|
|
|
var method_spec = ReadMethodSpecSignature (signature, element_method);
|
|
method_spec.token = new MetadataToken (TokenType.MethodSpec, rid);
|
|
return method_spec;
|
|
}
|
|
|
|
MethodSpecification ReadMethodSpecSignature (uint signature, MethodReference method)
|
|
{
|
|
var reader = ReadSignature (signature);
|
|
const byte methodspec_sig = 0x0a;
|
|
|
|
var call_conv = reader.ReadByte ();
|
|
|
|
if (call_conv != methodspec_sig)
|
|
throw new NotSupportedException ();
|
|
|
|
var instance = new GenericInstanceMethod (method);
|
|
|
|
reader.ReadGenericInstanceSignature (method, instance);
|
|
|
|
return instance;
|
|
}
|
|
|
|
MemberReference GetMemberReference (uint rid)
|
|
{
|
|
InitializeMemberReferences ();
|
|
|
|
var member = metadata.GetMemberReference (rid);
|
|
if (member != null)
|
|
return member;
|
|
|
|
member = ReadMemberReference (rid);
|
|
if (member != null && !member.ContainsGenericParameter)
|
|
metadata.AddMemberReference (member);
|
|
return member;
|
|
}
|
|
|
|
MemberReference ReadMemberReference (uint rid)
|
|
{
|
|
if (!MoveTo (Table.MemberRef, rid))
|
|
return null;
|
|
|
|
var token = ReadMetadataToken (CodedIndex.MemberRefParent);
|
|
var name = ReadString ();
|
|
var signature = ReadBlobIndex ();
|
|
|
|
MemberReference member;
|
|
|
|
switch (token.TokenType) {
|
|
case TokenType.TypeDef:
|
|
case TokenType.TypeRef:
|
|
case TokenType.TypeSpec:
|
|
member = ReadTypeMemberReference (token, name, signature);
|
|
break;
|
|
case TokenType.Method:
|
|
member = ReadMethodMemberReference (token, name, signature);
|
|
break;
|
|
default:
|
|
throw new NotSupportedException ();
|
|
}
|
|
|
|
member.token = new MetadataToken (TokenType.MemberRef, rid);
|
|
|
|
return member;
|
|
}
|
|
|
|
MemberReference ReadTypeMemberReference (MetadataToken type, string name, uint signature)
|
|
{
|
|
var declaring_type = GetTypeDefOrRef (type);
|
|
|
|
if (!declaring_type.IsArray)
|
|
this.context = declaring_type;
|
|
|
|
var member = ReadMemberReferenceSignature (signature, declaring_type);
|
|
member.Name = name;
|
|
|
|
return member;
|
|
}
|
|
|
|
MemberReference ReadMemberReferenceSignature (uint signature, TypeReference declaring_type)
|
|
{
|
|
var reader = ReadSignature (signature);
|
|
const byte field_sig = 0x6;
|
|
|
|
if (reader.buffer [reader.position] == field_sig) {
|
|
reader.position++;
|
|
var field = new FieldReference ();
|
|
field.DeclaringType = declaring_type;
|
|
field.FieldType = reader.ReadTypeSignature ();
|
|
return field;
|
|
} else {
|
|
var method = new MethodReference ();
|
|
method.DeclaringType = declaring_type;
|
|
reader.ReadMethodSignature (method);
|
|
return method;
|
|
}
|
|
}
|
|
|
|
MemberReference ReadMethodMemberReference (MetadataToken token, string name, uint signature)
|
|
{
|
|
var method = GetMethodDefinition (token.RID);
|
|
|
|
this.context = method;
|
|
|
|
var member = ReadMemberReferenceSignature (signature, method.DeclaringType);
|
|
member.Name = name;
|
|
|
|
return member;
|
|
}
|
|
|
|
void InitializeMemberReferences ()
|
|
{
|
|
if (metadata.MemberReferences != null)
|
|
return;
|
|
|
|
metadata.MemberReferences = new MemberReference [image.GetTableLength (Table.MemberRef)];
|
|
}
|
|
|
|
public IEnumerable<MemberReference> GetMemberReferences ()
|
|
{
|
|
InitializeMemberReferences ();
|
|
|
|
var length = image.GetTableLength (Table.MemberRef);
|
|
|
|
var type_system = module.TypeSystem;
|
|
|
|
var context = new MethodReference (string.Empty, type_system.Void);
|
|
context.DeclaringType = new TypeReference (string.Empty, string.Empty, module, type_system.Corlib);
|
|
|
|
var member_references = new MemberReference [length];
|
|
|
|
for (uint i = 1; i <= length; i++) {
|
|
this.context = context;
|
|
member_references [i - 1] = GetMemberReference (i);
|
|
}
|
|
|
|
return member_references;
|
|
}
|
|
|
|
void InitializeConstants ()
|
|
{
|
|
if (metadata.Constants != null)
|
|
return;
|
|
|
|
var length = MoveTo (Table.Constant);
|
|
|
|
var constants = metadata.Constants = new Dictionary<MetadataToken, Row<ElementType, uint>> (length);
|
|
|
|
for (uint i = 1; i <= length; i++) {
|
|
var type = (ElementType) ReadUInt16 ();
|
|
var owner = ReadMetadataToken (CodedIndex.HasConstant);
|
|
var signature = ReadBlobIndex ();
|
|
|
|
constants.Add (owner, new Row<ElementType, uint> (type, signature));
|
|
}
|
|
}
|
|
|
|
public object ReadConstant (IConstantProvider owner)
|
|
{
|
|
InitializeConstants ();
|
|
|
|
Row<ElementType, uint> row;
|
|
if (!metadata.Constants.TryGetValue (owner.MetadataToken, out row))
|
|
return Mixin.NoValue;
|
|
|
|
metadata.Constants.Remove (owner.MetadataToken);
|
|
|
|
switch (row.Col1) {
|
|
case ElementType.Class:
|
|
case ElementType.Object:
|
|
return null;
|
|
case ElementType.String:
|
|
return ReadConstantString (ReadBlob (row.Col2));
|
|
default:
|
|
return ReadConstantPrimitive (row.Col1, row.Col2);
|
|
}
|
|
}
|
|
|
|
static string ReadConstantString (byte [] blob)
|
|
{
|
|
var length = blob.Length;
|
|
if ((length & 1) == 1)
|
|
length--;
|
|
|
|
return Encoding.Unicode.GetString (blob, 0, length);
|
|
}
|
|
|
|
object ReadConstantPrimitive (ElementType type, uint signature)
|
|
{
|
|
var reader = ReadSignature (signature);
|
|
return reader.ReadConstantSignature (type);
|
|
}
|
|
|
|
void InitializeCustomAttributes ()
|
|
{
|
|
if (metadata.CustomAttributes != null)
|
|
return;
|
|
|
|
metadata.CustomAttributes = InitializeRanges (
|
|
Table.CustomAttribute, () => {
|
|
var next = ReadMetadataToken (CodedIndex.HasCustomAttribute);
|
|
ReadMetadataToken (CodedIndex.CustomAttributeType);
|
|
ReadBlobIndex ();
|
|
return next;
|
|
});
|
|
}
|
|
|
|
public bool HasCustomAttributes (ICustomAttributeProvider owner)
|
|
{
|
|
InitializeCustomAttributes ();
|
|
|
|
Range [] ranges;
|
|
if (!metadata.TryGetCustomAttributeRanges (owner, out ranges))
|
|
return false;
|
|
|
|
return RangesSize (ranges) > 0;
|
|
}
|
|
|
|
public Collection<CustomAttribute> ReadCustomAttributes (ICustomAttributeProvider owner)
|
|
{
|
|
InitializeCustomAttributes ();
|
|
|
|
Range [] ranges;
|
|
if (!metadata.TryGetCustomAttributeRanges (owner, out ranges))
|
|
return new Collection<CustomAttribute> ();
|
|
|
|
var custom_attributes = new Collection<CustomAttribute> (RangesSize (ranges));
|
|
|
|
for (int i = 0; i < ranges.Length; i++)
|
|
ReadCustomAttributeRange (ranges [i], custom_attributes);
|
|
|
|
metadata.RemoveCustomAttributeRange (owner);
|
|
|
|
return custom_attributes;
|
|
}
|
|
|
|
void ReadCustomAttributeRange (Range range, Collection<CustomAttribute> custom_attributes)
|
|
{
|
|
if (!MoveTo (Table.CustomAttribute, range.Start))
|
|
return;
|
|
|
|
for (int i = 0; i < range.Length; i++) {
|
|
ReadMetadataToken (CodedIndex.HasCustomAttribute);
|
|
|
|
var constructor = (MethodReference) LookupToken (
|
|
ReadMetadataToken (CodedIndex.CustomAttributeType));
|
|
|
|
var signature = ReadBlobIndex ();
|
|
|
|
custom_attributes.Add (new CustomAttribute (signature, constructor));
|
|
}
|
|
}
|
|
|
|
static int RangesSize (Range [] ranges)
|
|
{
|
|
uint size = 0;
|
|
for (int i = 0; i < ranges.Length; i++)
|
|
size += ranges [i].Length;
|
|
|
|
return (int) size;
|
|
}
|
|
|
|
public byte [] ReadCustomAttributeBlob (uint signature)
|
|
{
|
|
return ReadBlob (signature);
|
|
}
|
|
|
|
public void ReadCustomAttributeSignature (CustomAttribute attribute)
|
|
{
|
|
var reader = ReadSignature (attribute.signature);
|
|
|
|
if (!reader.CanReadMore ())
|
|
return;
|
|
|
|
if (reader.ReadUInt16 () != 0x0001)
|
|
throw new InvalidOperationException ();
|
|
|
|
var constructor = attribute.Constructor;
|
|
if (constructor.HasParameters)
|
|
reader.ReadCustomAttributeConstructorArguments (attribute, constructor.Parameters);
|
|
|
|
if (!reader.CanReadMore ())
|
|
return;
|
|
|
|
var named = reader.ReadUInt16 ();
|
|
|
|
if (named == 0)
|
|
return;
|
|
|
|
reader.ReadCustomAttributeNamedArguments (named, ref attribute.fields, ref attribute.properties);
|
|
}
|
|
|
|
void InitializeMarshalInfos ()
|
|
{
|
|
if (metadata.FieldMarshals != null)
|
|
return;
|
|
|
|
var length = MoveTo (Table.FieldMarshal);
|
|
|
|
var marshals = metadata.FieldMarshals = new Dictionary<MetadataToken, uint> (length);
|
|
|
|
for (int i = 0; i < length; i++) {
|
|
var token = ReadMetadataToken (CodedIndex.HasFieldMarshal);
|
|
var signature = ReadBlobIndex ();
|
|
if (token.RID == 0)
|
|
continue;
|
|
|
|
marshals.Add (token, signature);
|
|
}
|
|
}
|
|
|
|
public bool HasMarshalInfo (IMarshalInfoProvider owner)
|
|
{
|
|
InitializeMarshalInfos ();
|
|
|
|
return metadata.FieldMarshals.ContainsKey (owner.MetadataToken);
|
|
}
|
|
|
|
public MarshalInfo ReadMarshalInfo (IMarshalInfoProvider owner)
|
|
{
|
|
InitializeMarshalInfos ();
|
|
|
|
uint signature;
|
|
if (!metadata.FieldMarshals.TryGetValue (owner.MetadataToken, out signature))
|
|
return null;
|
|
|
|
var reader = ReadSignature (signature);
|
|
|
|
metadata.FieldMarshals.Remove (owner.MetadataToken);
|
|
|
|
return reader.ReadMarshalInfo ();
|
|
}
|
|
|
|
void InitializeSecurityDeclarations ()
|
|
{
|
|
if (metadata.SecurityDeclarations != null)
|
|
return;
|
|
|
|
metadata.SecurityDeclarations = InitializeRanges (
|
|
Table.DeclSecurity, () => {
|
|
ReadUInt16 ();
|
|
var next = ReadMetadataToken (CodedIndex.HasDeclSecurity);
|
|
ReadBlobIndex ();
|
|
return next;
|
|
});
|
|
}
|
|
|
|
public bool HasSecurityDeclarations (ISecurityDeclarationProvider owner)
|
|
{
|
|
InitializeSecurityDeclarations ();
|
|
|
|
Range [] ranges;
|
|
if (!metadata.TryGetSecurityDeclarationRanges (owner, out ranges))
|
|
return false;
|
|
|
|
return RangesSize (ranges) > 0;
|
|
}
|
|
|
|
public Collection<SecurityDeclaration> ReadSecurityDeclarations (ISecurityDeclarationProvider owner)
|
|
{
|
|
InitializeSecurityDeclarations ();
|
|
|
|
Range [] ranges;
|
|
if (!metadata.TryGetSecurityDeclarationRanges (owner, out ranges))
|
|
return new Collection<SecurityDeclaration> ();
|
|
|
|
var security_declarations = new Collection<SecurityDeclaration> (RangesSize (ranges));
|
|
|
|
for (int i = 0; i < ranges.Length; i++)
|
|
ReadSecurityDeclarationRange (ranges [i], security_declarations);
|
|
|
|
metadata.RemoveSecurityDeclarationRange (owner);
|
|
|
|
return security_declarations;
|
|
}
|
|
|
|
void ReadSecurityDeclarationRange (Range range, Collection<SecurityDeclaration> security_declarations)
|
|
{
|
|
if (!MoveTo (Table.DeclSecurity, range.Start))
|
|
return;
|
|
|
|
for (int i = 0; i < range.Length; i++) {
|
|
var action = (SecurityAction) ReadUInt16 ();
|
|
ReadMetadataToken (CodedIndex.HasDeclSecurity);
|
|
var signature = ReadBlobIndex ();
|
|
|
|
security_declarations.Add (new SecurityDeclaration (action, signature, module));
|
|
}
|
|
}
|
|
|
|
public byte [] ReadSecurityDeclarationBlob (uint signature)
|
|
{
|
|
return ReadBlob (signature);
|
|
}
|
|
|
|
public void ReadSecurityDeclarationSignature (SecurityDeclaration declaration)
|
|
{
|
|
var signature = declaration.signature;
|
|
var reader = ReadSignature (signature);
|
|
|
|
if (reader.buffer [reader.position] != '.') {
|
|
ReadXmlSecurityDeclaration (signature, declaration);
|
|
return;
|
|
}
|
|
|
|
reader.position++;
|
|
var count = reader.ReadCompressedUInt32 ();
|
|
var attributes = new Collection<SecurityAttribute> ((int) count);
|
|
|
|
for (int i = 0; i < count; i++)
|
|
attributes.Add (reader.ReadSecurityAttribute ());
|
|
|
|
declaration.security_attributes = attributes;
|
|
}
|
|
|
|
void ReadXmlSecurityDeclaration (uint signature, SecurityDeclaration declaration)
|
|
{
|
|
var blob = ReadBlob (signature);
|
|
var attributes = new Collection<SecurityAttribute> (1);
|
|
|
|
var attribute = new SecurityAttribute (
|
|
module.TypeSystem.LookupType ("System.Security.Permissions", "PermissionSetAttribute"));
|
|
|
|
attribute.properties = new Collection<CustomAttributeNamedArgument> (1);
|
|
attribute.properties.Add (
|
|
new CustomAttributeNamedArgument (
|
|
"XML",
|
|
new CustomAttributeArgument (
|
|
module.TypeSystem.String,
|
|
Encoding.Unicode.GetString (blob, 0, blob.Length))));
|
|
|
|
attributes.Add (attribute);
|
|
|
|
declaration.security_attributes = attributes;
|
|
}
|
|
|
|
public Collection<ExportedType> ReadExportedTypes ()
|
|
{
|
|
var length = MoveTo (Table.ExportedType);
|
|
if (length == 0)
|
|
return new Collection<ExportedType> ();
|
|
|
|
var exported_types = new Collection<ExportedType> (length);
|
|
|
|
for (int i = 1; i <= length; i++) {
|
|
var attributes = (TypeAttributes) ReadUInt32 ();
|
|
var identifier = ReadUInt32 ();
|
|
var name = ReadString ();
|
|
var @namespace = ReadString ();
|
|
var implementation = ReadMetadataToken (CodedIndex.Implementation);
|
|
|
|
ExportedType declaring_type = null;
|
|
IMetadataScope scope = null;
|
|
|
|
switch (implementation.TokenType) {
|
|
case TokenType.AssemblyRef:
|
|
case TokenType.File:
|
|
scope = GetExportedTypeScope (implementation);
|
|
break;
|
|
case TokenType.ExportedType:
|
|
// FIXME: if the table is not properly sorted
|
|
declaring_type = exported_types [(int) implementation.RID - 1];
|
|
break;
|
|
}
|
|
|
|
var exported_type = new ExportedType (@namespace, name, module, scope) {
|
|
Attributes = attributes,
|
|
Identifier = (int) identifier,
|
|
DeclaringType = declaring_type,
|
|
};
|
|
exported_type.token = new MetadataToken (TokenType.ExportedType, i);
|
|
|
|
exported_types.Add (exported_type);
|
|
}
|
|
|
|
return exported_types;
|
|
}
|
|
|
|
IMetadataScope GetExportedTypeScope (MetadataToken token)
|
|
{
|
|
var position = this.position;
|
|
IMetadataScope scope;
|
|
|
|
switch (token.TokenType) {
|
|
case TokenType.AssemblyRef:
|
|
InitializeAssemblyReferences ();
|
|
scope = metadata.AssemblyReferences [(int) token.RID - 1];
|
|
break;
|
|
case TokenType.File:
|
|
InitializeModuleReferences ();
|
|
scope = GetModuleReferenceFromFile (token);
|
|
break;
|
|
default:
|
|
throw new NotSupportedException ();
|
|
}
|
|
|
|
this.position = position;
|
|
return scope;
|
|
}
|
|
|
|
ModuleReference GetModuleReferenceFromFile (MetadataToken token)
|
|
{
|
|
if (!MoveTo (Table.File, token.RID))
|
|
return null;
|
|
|
|
ReadUInt32 ();
|
|
var file_name = ReadString ();
|
|
var modules = module.ModuleReferences;
|
|
|
|
ModuleReference reference;
|
|
for (int i = 0; i < modules.Count; i++) {
|
|
reference = modules [i];
|
|
if (reference.Name == file_name)
|
|
return reference;
|
|
}
|
|
|
|
reference = new ModuleReference (file_name);
|
|
modules.Add (reference);
|
|
return reference;
|
|
}
|
|
|
|
static void InitializeCollection (object o)
|
|
{
|
|
}
|
|
}
|
|
|
|
sealed class SignatureReader : ByteBuffer {
|
|
|
|
readonly MetadataReader reader;
|
|
readonly uint start, sig_length;
|
|
|
|
TypeSystem TypeSystem {
|
|
get { return reader.module.TypeSystem; }
|
|
}
|
|
|
|
public SignatureReader (uint blob, MetadataReader reader)
|
|
: base (reader.buffer)
|
|
{
|
|
this.reader = reader;
|
|
|
|
MoveToBlob (blob);
|
|
|
|
this.sig_length = ReadCompressedUInt32 ();
|
|
this.start = (uint) position;
|
|
}
|
|
|
|
void MoveToBlob (uint blob)
|
|
{
|
|
position = (int) (reader.image.BlobHeap.Offset + blob);
|
|
}
|
|
|
|
MetadataToken ReadTypeTokenSignature ()
|
|
{
|
|
return CodedIndex.TypeDefOrRef.GetMetadataToken (ReadCompressedUInt32 ());
|
|
}
|
|
|
|
GenericParameter GetGenericParameter (GenericParameterType type, uint var)
|
|
{
|
|
var context = reader.context;
|
|
int index = (int) var;
|
|
|
|
if (context == null)
|
|
return GetUnboundGenericParameter (type, index);
|
|
|
|
IGenericParameterProvider provider;
|
|
|
|
switch (type) {
|
|
case GenericParameterType.Type:
|
|
provider = context.Type;
|
|
break;
|
|
case GenericParameterType.Method:
|
|
provider = context.Method;
|
|
break;
|
|
default:
|
|
throw new NotSupportedException ();
|
|
}
|
|
|
|
if (!context.IsDefinition)
|
|
CheckGenericContext (provider, index);
|
|
|
|
if (index >= provider.GenericParameters.Count)
|
|
return GetUnboundGenericParameter (type, index);
|
|
|
|
return provider.GenericParameters [index];
|
|
}
|
|
|
|
GenericParameter GetUnboundGenericParameter (GenericParameterType type, int index)
|
|
{
|
|
return new GenericParameter (index, type, reader.module);
|
|
}
|
|
|
|
static void CheckGenericContext (IGenericParameterProvider owner, int index)
|
|
{
|
|
var owner_parameters = owner.GenericParameters;
|
|
|
|
for (int i = owner_parameters.Count; i <= index; i++)
|
|
owner_parameters.Add (new GenericParameter (owner));
|
|
}
|
|
|
|
public void ReadGenericInstanceSignature (IGenericParameterProvider provider, IGenericInstance instance)
|
|
{
|
|
var arity = ReadCompressedUInt32 ();
|
|
|
|
if (!provider.IsDefinition)
|
|
CheckGenericContext (provider, (int) arity - 1);
|
|
|
|
var instance_arguments = instance.GenericArguments;
|
|
|
|
for (int i = 0; i < arity; i++)
|
|
instance_arguments.Add (ReadTypeSignature ());
|
|
}
|
|
|
|
ArrayType ReadArrayTypeSignature ()
|
|
{
|
|
var array = new ArrayType (ReadTypeSignature ());
|
|
|
|
var rank = ReadCompressedUInt32 ();
|
|
|
|
var sizes = new uint [ReadCompressedUInt32 ()];
|
|
for (int i = 0; i < sizes.Length; i++)
|
|
sizes [i] = ReadCompressedUInt32 ();
|
|
|
|
var low_bounds = new int [ReadCompressedUInt32 ()];
|
|
for (int i = 0; i < low_bounds.Length; i++)
|
|
low_bounds [i] = ReadCompressedInt32 ();
|
|
|
|
array.Dimensions.Clear ();
|
|
|
|
for (int i = 0; i < rank; i++) {
|
|
int? lower = null, upper = null;
|
|
|
|
if (i < low_bounds.Length)
|
|
lower = low_bounds [i];
|
|
|
|
if (i < sizes.Length)
|
|
upper = lower + (int) sizes [i] - 1;
|
|
|
|
array.Dimensions.Add (new ArrayDimension (lower, upper));
|
|
}
|
|
|
|
return array;
|
|
}
|
|
|
|
TypeReference GetTypeDefOrRef (MetadataToken token)
|
|
{
|
|
return reader.GetTypeDefOrRef (token);
|
|
}
|
|
|
|
public TypeReference ReadTypeSignature ()
|
|
{
|
|
return ReadTypeSignature ((ElementType) ReadByte ());
|
|
}
|
|
|
|
TypeReference ReadTypeSignature (ElementType etype)
|
|
{
|
|
switch (etype) {
|
|
case ElementType.ValueType: {
|
|
var value_type = GetTypeDefOrRef (ReadTypeTokenSignature ());
|
|
value_type.IsValueType = true;
|
|
return value_type;
|
|
}
|
|
case ElementType.Class:
|
|
return GetTypeDefOrRef (ReadTypeTokenSignature ());
|
|
case ElementType.Ptr:
|
|
return new PointerType (ReadTypeSignature ());
|
|
case ElementType.FnPtr: {
|
|
var fptr = new FunctionPointerType ();
|
|
ReadMethodSignature (fptr);
|
|
return fptr;
|
|
}
|
|
case ElementType.ByRef:
|
|
return new ByReferenceType (ReadTypeSignature ());
|
|
case ElementType.Pinned:
|
|
return new PinnedType (ReadTypeSignature ());
|
|
case ElementType.SzArray:
|
|
return new ArrayType (ReadTypeSignature ());
|
|
case ElementType.Array:
|
|
return ReadArrayTypeSignature ();
|
|
case ElementType.CModOpt:
|
|
return new OptionalModifierType (
|
|
GetTypeDefOrRef (ReadTypeTokenSignature ()), ReadTypeSignature ());
|
|
case ElementType.CModReqD:
|
|
return new RequiredModifierType (
|
|
GetTypeDefOrRef (ReadTypeTokenSignature ()), ReadTypeSignature ());
|
|
case ElementType.Sentinel:
|
|
return new SentinelType (ReadTypeSignature ());
|
|
case ElementType.Var:
|
|
return GetGenericParameter (GenericParameterType.Type, ReadCompressedUInt32 ());
|
|
case ElementType.MVar:
|
|
return GetGenericParameter (GenericParameterType.Method, ReadCompressedUInt32 ());
|
|
case ElementType.GenericInst: {
|
|
var is_value_type = ReadByte () == (byte) ElementType.ValueType;
|
|
var element_type = GetTypeDefOrRef (ReadTypeTokenSignature ());
|
|
var generic_instance = new GenericInstanceType (element_type);
|
|
|
|
ReadGenericInstanceSignature (element_type, generic_instance);
|
|
|
|
if (is_value_type) {
|
|
generic_instance.IsValueType = true;
|
|
element_type.GetElementType ().IsValueType = true;
|
|
}
|
|
|
|
return generic_instance;
|
|
}
|
|
case ElementType.Object: return TypeSystem.Object;
|
|
case ElementType.Void: return TypeSystem.Void;
|
|
case ElementType.TypedByRef: return TypeSystem.TypedReference;
|
|
case ElementType.I: return TypeSystem.IntPtr;
|
|
case ElementType.U: return TypeSystem.UIntPtr;
|
|
default: return GetPrimitiveType (etype);
|
|
}
|
|
}
|
|
|
|
public void ReadMethodSignature (IMethodSignature method)
|
|
{
|
|
var calling_convention = ReadByte ();
|
|
|
|
const byte has_this = 0x20;
|
|
const byte explicit_this = 0x40;
|
|
|
|
if ((calling_convention & has_this) != 0) {
|
|
method.HasThis = true;
|
|
calling_convention = (byte) (calling_convention & ~has_this);
|
|
}
|
|
|
|
if ((calling_convention & explicit_this) != 0) {
|
|
method.ExplicitThis = true;
|
|
calling_convention = (byte) (calling_convention & ~explicit_this);
|
|
}
|
|
|
|
method.CallingConvention = (MethodCallingConvention) calling_convention;
|
|
|
|
var generic_context = method as MethodReference;
|
|
if (generic_context != null && !generic_context.DeclaringType.IsArray)
|
|
reader.context = generic_context;
|
|
|
|
if ((calling_convention & 0x10) != 0) {
|
|
var arity = ReadCompressedUInt32 ();
|
|
|
|
if (generic_context != null && !generic_context.IsDefinition)
|
|
CheckGenericContext (generic_context, (int) arity -1 );
|
|
}
|
|
|
|
var param_count = ReadCompressedUInt32 ();
|
|
|
|
method.MethodReturnType.ReturnType = ReadTypeSignature ();
|
|
|
|
if (param_count == 0)
|
|
return;
|
|
|
|
Collection<ParameterDefinition> parameters;
|
|
|
|
var method_ref = method as MethodReference;
|
|
if (method_ref != null)
|
|
parameters = method_ref.parameters = new ParameterDefinitionCollection (method, (int) param_count);
|
|
else
|
|
parameters = method.Parameters;
|
|
|
|
for (int i = 0; i < param_count; i++)
|
|
parameters.Add (new ParameterDefinition (ReadTypeSignature ()));
|
|
}
|
|
|
|
public object ReadConstantSignature (ElementType type)
|
|
{
|
|
return ReadPrimitiveValue (type);
|
|
}
|
|
|
|
public void ReadCustomAttributeConstructorArguments (CustomAttribute attribute, Collection<ParameterDefinition> parameters)
|
|
{
|
|
var count = parameters.Count;
|
|
if (count == 0)
|
|
return;
|
|
|
|
attribute.arguments = new Collection<CustomAttributeArgument> (count);
|
|
|
|
for (int i = 0; i < count; i++)
|
|
attribute.arguments.Add (
|
|
ReadCustomAttributeFixedArgument (parameters [i].ParameterType));
|
|
}
|
|
|
|
CustomAttributeArgument ReadCustomAttributeFixedArgument (TypeReference type)
|
|
{
|
|
if (type.IsArray)
|
|
return ReadCustomAttributeFixedArrayArgument ((ArrayType) type);
|
|
|
|
return ReadCustomAttributeElement (type);
|
|
}
|
|
|
|
public void ReadCustomAttributeNamedArguments (ushort count, ref Collection<CustomAttributeNamedArgument> fields, ref Collection<CustomAttributeNamedArgument> properties)
|
|
{
|
|
for (int i = 0; i < count; i++)
|
|
ReadCustomAttributeNamedArgument (ref fields, ref properties);
|
|
}
|
|
|
|
void ReadCustomAttributeNamedArgument (ref Collection<CustomAttributeNamedArgument> fields, ref Collection<CustomAttributeNamedArgument> properties)
|
|
{
|
|
var kind = ReadByte ();
|
|
var type = ReadCustomAttributeFieldOrPropType ();
|
|
var name = ReadUTF8String ();
|
|
|
|
Collection<CustomAttributeNamedArgument> container;
|
|
switch (kind) {
|
|
case 0x53:
|
|
container = GetCustomAttributeNamedArgumentCollection (ref fields);
|
|
break;
|
|
case 0x54:
|
|
container = GetCustomAttributeNamedArgumentCollection (ref properties);
|
|
break;
|
|
default:
|
|
throw new NotSupportedException ();
|
|
}
|
|
|
|
container.Add (new CustomAttributeNamedArgument (name, ReadCustomAttributeFixedArgument (type)));
|
|
}
|
|
|
|
static Collection<CustomAttributeNamedArgument> GetCustomAttributeNamedArgumentCollection (ref Collection<CustomAttributeNamedArgument> collection)
|
|
{
|
|
if (collection != null)
|
|
return collection;
|
|
|
|
return collection = new Collection<CustomAttributeNamedArgument> ();
|
|
}
|
|
|
|
CustomAttributeArgument ReadCustomAttributeFixedArrayArgument (ArrayType type)
|
|
{
|
|
var length = ReadUInt32 ();
|
|
|
|
if (length == 0xffffffff)
|
|
return new CustomAttributeArgument (type, null);
|
|
|
|
if (length == 0)
|
|
return new CustomAttributeArgument (type, Empty<CustomAttributeArgument>.Array);
|
|
|
|
var arguments = new CustomAttributeArgument [length];
|
|
var element_type = type.ElementType;
|
|
|
|
for (int i = 0; i < length; i++)
|
|
arguments [i] = ReadCustomAttributeElement (element_type);
|
|
|
|
return new CustomAttributeArgument (type, arguments);
|
|
}
|
|
|
|
CustomAttributeArgument ReadCustomAttributeElement (TypeReference type)
|
|
{
|
|
if (type.IsArray)
|
|
return ReadCustomAttributeFixedArrayArgument ((ArrayType) type);
|
|
|
|
return new CustomAttributeArgument (
|
|
type,
|
|
type.etype == ElementType.Object
|
|
? ReadCustomAttributeElement (ReadCustomAttributeFieldOrPropType ())
|
|
: ReadCustomAttributeElementValue (type));
|
|
}
|
|
|
|
object ReadCustomAttributeElementValue (TypeReference type)
|
|
{
|
|
var etype = type.etype;
|
|
|
|
switch (etype) {
|
|
case ElementType.String:
|
|
return ReadUTF8String ();
|
|
case ElementType.None:
|
|
if (type.IsTypeOf ("System", "Type"))
|
|
return ReadTypeReference ();
|
|
|
|
return ReadCustomAttributeEnum (type);
|
|
default:
|
|
return ReadPrimitiveValue (etype);
|
|
}
|
|
}
|
|
|
|
object ReadPrimitiveValue (ElementType type)
|
|
{
|
|
switch (type) {
|
|
case ElementType.Boolean:
|
|
return ReadByte () == 1;
|
|
case ElementType.I1:
|
|
return (sbyte) ReadByte ();
|
|
case ElementType.U1:
|
|
return ReadByte ();
|
|
case ElementType.Char:
|
|
return (char) ReadUInt16 ();
|
|
case ElementType.I2:
|
|
return ReadInt16 ();
|
|
case ElementType.U2:
|
|
return ReadUInt16 ();
|
|
case ElementType.I4:
|
|
return ReadInt32 ();
|
|
case ElementType.U4:
|
|
return ReadUInt32 ();
|
|
case ElementType.I8:
|
|
return ReadInt64 ();
|
|
case ElementType.U8:
|
|
return ReadUInt64 ();
|
|
case ElementType.R4:
|
|
return ReadSingle ();
|
|
case ElementType.R8:
|
|
return ReadDouble ();
|
|
default:
|
|
throw new NotImplementedException (type.ToString ());
|
|
}
|
|
}
|
|
|
|
TypeReference GetPrimitiveType (ElementType etype)
|
|
{
|
|
switch (etype) {
|
|
case ElementType.Boolean:
|
|
return TypeSystem.Boolean;
|
|
case ElementType.Char:
|
|
return TypeSystem.Char;
|
|
case ElementType.I1:
|
|
return TypeSystem.SByte;
|
|
case ElementType.U1:
|
|
return TypeSystem.Byte;
|
|
case ElementType.I2:
|
|
return TypeSystem.Int16;
|
|
case ElementType.U2:
|
|
return TypeSystem.UInt16;
|
|
case ElementType.I4:
|
|
return TypeSystem.Int32;
|
|
case ElementType.U4:
|
|
return TypeSystem.UInt32;
|
|
case ElementType.I8:
|
|
return TypeSystem.Int64;
|
|
case ElementType.U8:
|
|
return TypeSystem.UInt64;
|
|
case ElementType.R4:
|
|
return TypeSystem.Single;
|
|
case ElementType.R8:
|
|
return TypeSystem.Double;
|
|
case ElementType.String:
|
|
return TypeSystem.String;
|
|
default:
|
|
throw new NotImplementedException (etype.ToString ());
|
|
}
|
|
}
|
|
|
|
TypeReference ReadCustomAttributeFieldOrPropType ()
|
|
{
|
|
var etype = (ElementType) ReadByte ();
|
|
|
|
switch (etype) {
|
|
case ElementType.Boxed:
|
|
return TypeSystem.Object;
|
|
case ElementType.SzArray:
|
|
return new ArrayType (ReadCustomAttributeFieldOrPropType ());
|
|
case ElementType.Enum:
|
|
return ReadTypeReference ();
|
|
case ElementType.Type:
|
|
return TypeSystem.LookupType ("System", "Type");
|
|
default:
|
|
return GetPrimitiveType (etype);
|
|
}
|
|
}
|
|
|
|
string UnescapeTypeName (string name)
|
|
{
|
|
StringBuilder sb = new StringBuilder (name.Length);
|
|
for (int i = 0; i < name.Length; i++) {
|
|
char c = name [i];
|
|
if (name [i] == '\\') {
|
|
if ((i < name.Length - 1) && (name [i + 1] == '\\')) {
|
|
sb.Append (c);
|
|
i++;
|
|
}
|
|
} else {
|
|
sb.Append (c);
|
|
}
|
|
}
|
|
return sb.ToString ();
|
|
}
|
|
|
|
public TypeReference ReadTypeReference ()
|
|
{
|
|
string s = ReadUTF8String ();
|
|
if (s != null && s.IndexOf ('\\') != -1)
|
|
s = UnescapeTypeName (s);
|
|
return TypeParser.ParseType (reader.module, s);
|
|
}
|
|
|
|
object ReadCustomAttributeEnum (TypeReference enum_type)
|
|
{
|
|
var type = enum_type.CheckedResolve ();
|
|
if (!type.IsEnum)
|
|
throw new ArgumentException ();
|
|
|
|
return ReadCustomAttributeElementValue (type.GetEnumUnderlyingType ());
|
|
}
|
|
|
|
public SecurityAttribute ReadSecurityAttribute ()
|
|
{
|
|
var attribute = new SecurityAttribute (ReadTypeReference ());
|
|
|
|
ReadCompressedUInt32 ();
|
|
|
|
ReadCustomAttributeNamedArguments (
|
|
(ushort) ReadCompressedUInt32 (),
|
|
ref attribute.fields,
|
|
ref attribute.properties);
|
|
|
|
return attribute;
|
|
}
|
|
|
|
public MarshalInfo ReadMarshalInfo ()
|
|
{
|
|
var native = ReadNativeType ();
|
|
switch (native) {
|
|
case NativeType.Array: {
|
|
var array = new ArrayMarshalInfo ();
|
|
if (CanReadMore ())
|
|
array.element_type = ReadNativeType ();
|
|
if (CanReadMore ())
|
|
array.size_parameter_index = (int) ReadCompressedUInt32 ();
|
|
if (CanReadMore ())
|
|
array.size = (int) ReadCompressedUInt32 ();
|
|
if (CanReadMore ())
|
|
array.size_parameter_multiplier = (int) ReadCompressedUInt32 ();
|
|
return array;
|
|
}
|
|
case NativeType.SafeArray: {
|
|
var array = new SafeArrayMarshalInfo ();
|
|
if (CanReadMore ())
|
|
array.element_type = ReadVariantType ();
|
|
return array;
|
|
}
|
|
case NativeType.FixedArray: {
|
|
var array = new FixedArrayMarshalInfo ();
|
|
if (CanReadMore ())
|
|
array.size = (int) ReadCompressedUInt32 ();
|
|
if (CanReadMore ())
|
|
array.element_type = ReadNativeType ();
|
|
return array;
|
|
}
|
|
case NativeType.FixedSysString: {
|
|
var sys_string = new FixedSysStringMarshalInfo ();
|
|
if (CanReadMore ())
|
|
sys_string.size = (int) ReadCompressedUInt32 ();
|
|
return sys_string;
|
|
}
|
|
case NativeType.CustomMarshaler: {
|
|
var marshaler = new CustomMarshalInfo ();
|
|
var guid_value = ReadUTF8String ();
|
|
marshaler.guid = !string.IsNullOrEmpty (guid_value) ? new Guid (guid_value) : Guid.Empty;
|
|
marshaler.unmanaged_type = ReadUTF8String ();
|
|
marshaler.managed_type = ReadTypeReference ();
|
|
marshaler.cookie = ReadUTF8String ();
|
|
return marshaler;
|
|
}
|
|
default:
|
|
return new MarshalInfo (native);
|
|
}
|
|
}
|
|
|
|
NativeType ReadNativeType ()
|
|
{
|
|
return (NativeType) ReadByte ();
|
|
}
|
|
|
|
VariantType ReadVariantType ()
|
|
{
|
|
return (VariantType) ReadByte ();
|
|
}
|
|
|
|
string ReadUTF8String ()
|
|
{
|
|
if (buffer [position] == 0xff) {
|
|
position++;
|
|
return null;
|
|
}
|
|
|
|
var length = (int) ReadCompressedUInt32 ();
|
|
if (length == 0)
|
|
return string.Empty;
|
|
|
|
var @string = Encoding.UTF8.GetString (buffer, position,
|
|
buffer [position + length - 1] == 0 ? length - 1 : length);
|
|
|
|
position += length;
|
|
return @string;
|
|
}
|
|
|
|
public bool CanReadMore ()
|
|
{
|
|
return position - start < sig_length;
|
|
}
|
|
}
|
|
}
|