// Copyright Microsoft Corporation.
// This source file is subject to the Microsoft Permissive License.
// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
// All other rights reserved.
using System;
#if FxCop
using Win32ResourceListMicrosoft.Cci.Win32ResourceCollection;
using TypeNodeListMicrosoft.Cci.TypeNodeCollection;
#endif
#if CCINamespace
using Microsoft.Cci;
#else
using System.Compiler;
#endif
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.Serialization;
//^ using Microsoft.Contracts;
/* These classes help with parsing and producing PE files. They are best understood in conjunction with the ECMA 335 Specification
* (Common Language Infrastructure), particularly Partition II. Also see "Inside Microsoft .NET IL Assembler" by Serge Lidin. */
#if CCINamespace
namespace Microsoft.Cci.Metadata{
#else
namespace System.Compiler.Metadata
{
#endif
internal struct AssemblyRow
{
internal int HashAlgId;
internal int MajorVersion;
internal int MinorVersion;
internal int BuildNumber;
internal int RevisionNumber;
internal int Flags;
internal int PublicKey;
internal int Name;
internal int Culture;
}
internal struct AssemblyRefRow
{
internal int MajorVersion;
internal int MinorVersion;
internal int BuildNumber;
internal int RevisionNumber;
internal int Flags;
internal int PublicKeyOrToken;
internal int Name;
internal int Culture;
internal int HashValue;
internal AssemblyReference AssemblyReference;
}
internal struct ClassLayoutRow
{
internal int PackingSize;
internal int ClassSize;
internal int Parent;
}
internal struct ConstantRow
{
internal int Type;
internal int Parent;
internal int Value;
}
internal struct CustomAttributeRow
{
internal int Parent;
internal int Constructor;
internal int Value;
}
internal struct DeclSecurityRow
{
internal int Action;
internal int Parent;
internal int PermissionSet;
}
internal struct EventMapRow
{
internal int Parent;
internal int EventList;
}
internal struct EventPtrRow
{
internal int Event;
}
internal struct EventRow
{
internal int Flags;
internal int Name;
internal int EventType;
}
internal struct ExportedTypeRow
{
internal int Flags;
internal int TypeDefId;
internal int TypeName;
internal int TypeNamespace;
internal int Implementation;
}
internal struct FieldRow
{
internal int Flags;
internal int Name;
internal int Signature;
internal Field Field;
}
internal struct FieldLayoutRow
{
internal int Offset;
internal int Field;
}
internal struct FieldMarshalRow
{
internal int Parent;
internal int NativeType;
}
internal struct FieldPtrRow
{
internal int Field;
}
internal struct FieldRvaRow
{
internal int RVA;
internal int Field;
internal PESection TargetSection;
}
internal struct FileRow
{
internal int Flags;
internal int Name;
internal int HashValue;
}
internal struct GenericParamRow
{
internal int Number;
internal int Flags;
internal int Owner;
internal int Name;
internal Member GenericParameter;
}
internal struct GenericParamConstraintRow
{
internal int Param;
internal int Constraint;
}
internal struct ImplMapRow
{
internal int MappingFlags;
internal int MemberForwarded;
internal int ImportName;
internal int ImportScope;
}
internal struct InterfaceImplRow
{
internal int Class;
internal int Interface;
}
internal struct ManifestResourceRow
{
internal int Offset;
internal int Flags;
internal int Name;
internal int Implementation;
}
internal struct MemberRefRow
{
internal int Class;
internal int Name;
internal int Signature;
internal Member Member;
internal TypeNodeList VarargTypes;
}
internal struct MethodRow
{
internal int RVA;
internal int ImplFlags;
internal int Flags;
internal int Name;
internal int Signature;
internal int ParamList;
internal Method Method;
}
internal struct MethodImplRow
{
internal int Class;
internal int MethodBody;
internal int MethodDeclaration;
}
internal struct MethodPtrRow
{
internal int Method;
}
internal struct MethodSemanticsRow
{
internal int Semantics;
internal int Method;
internal int Association;
}
internal struct MethodSpecRow
{
internal int Method;
internal int Instantiation;
internal Method InstantiatedMethod;
}
internal struct ModuleRow
{
internal int Generation;
internal int Name;
internal int Mvid;
internal int EncId;
internal int EncBaseId;
}
internal struct ModuleRefRow
{
internal int Name;
#if FxCop
internal ModuleNode Module;
#else
internal Module Module;
#endif
}
internal struct NestedClassRow
{
internal int NestedClass;
internal int EnclosingClass;
}
internal struct ParamRow
{
internal int Flags;
internal int Sequence;
internal int Name;
}
internal struct ParamPtrRow
{
internal int Param;
}
internal struct PropertyRow
{
internal int Flags;
internal int Name;
internal int Signature;
}
internal struct PropertyPtrRow
{
internal int Property;
}
internal struct PropertyMapRow
{
internal int Parent;
internal int PropertyList;
}
internal struct StandAloneSigRow
{
internal int Signature;
}
internal struct TypeDefRow
{
internal int Flags;
internal int Name;
internal int Namespace;
internal int Extends;
internal int FieldList;
internal int MethodList;
internal TypeNode Type;
internal Identifier NamespaceId;
internal int NamespaceKey;
internal int NameKey;
}
internal struct TypeRefRow
{
internal int ResolutionScope;
internal int Name;
internal int Namespace;
internal TypeNode Type;
}
internal struct TypeSpecRow
{
internal int Signature;
internal TypeNode Type;
}
[Serializable]
public sealed class InvalidMetadataException : System.Exception
{
public InvalidMetadataException() { }
public InvalidMetadataException(string message)
: base(message)
{
}
public InvalidMetadataException(string message, Exception innerException)
: base(message, innerException)
{
}
private InvalidMetadataException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
internal class CLIHeader
{
internal int cb;
internal ushort majorRuntimeVersion;
internal ushort minorRuntimeVersion;
internal DirectoryEntry metaData;
internal int flags;
internal int entryPointToken;
internal DirectoryEntry resources;
internal DirectoryEntry strongNameSignature;
internal DirectoryEntry codeManagerTable;
internal DirectoryEntry vtableFixups;
internal DirectoryEntry exportAddressTableJumps;
internal CLIHeader()
{
this.cb = 72;
this.majorRuntimeVersion = 2;
this.minorRuntimeVersion = 5;
// initialization provided by runtime
//this.flags = 0;
//this.entryPointToken = 0;
}
}
internal struct DirectoryEntry
{
internal int virtualAddress;
internal int size;
}
internal class MetadataHeader
{
internal int signature;
internal ushort majorVersion;
internal ushort minorVersion;
internal int reserved;
internal string versionString;
internal int flags;
internal StreamHeader[] streamHeaders;
}
internal class NTHeader
{
internal int signature;
internal ushort machine;
internal ushort numberOfSections;
internal int timeDateStamp;
internal int pointerToSymbolTable;
internal int numberOfSymbols;
internal ushort sizeOfOptionalHeader;
internal ushort characteristics;
internal ushort magic;
internal byte majorLinkerVersion;
internal byte minorLinkerVersion;
internal int sizeOfCode;
internal int sizeOfInitializedData;
internal int sizeOfUninitializedData;
internal int addressOfEntryPoint;
internal int baseOfCode;
internal int baseOfData;
internal long imageBase;
internal int sectionAlignment;
internal int fileAlignment;
internal ushort majorOperatingSystemVersion;
internal ushort minorOperatingSystemVersion;
internal ushort majorImageVersion;
internal ushort minorImageVersion;
internal ushort majorSubsystemVersion;
internal ushort minorSubsystemVersion;
internal int win32VersionValue;
internal int sizeOfImage;
internal int sizeOfHeaders;
internal int checkSum;
internal ushort subsystem;
internal ushort dllCharacteristics;
internal long sizeOfStackReserve;
internal long sizeOfStackCommit;
internal long sizeOfHeapReserve;
internal long sizeOfHeapCommit;
internal int loaderFlags;
internal int numberOfDataDirectories;
internal DirectoryEntry exportTable;
internal DirectoryEntry importTable;
internal DirectoryEntry resourceTable;
internal DirectoryEntry exceptionTable;
internal DirectoryEntry certificateTable;
internal DirectoryEntry baseRelocationTable;
internal DirectoryEntry debugTable;
internal DirectoryEntry copyrightTable;
internal DirectoryEntry globalPointerTable;
internal DirectoryEntry threadLocalStorageTable;
internal DirectoryEntry loadConfigTable;
internal DirectoryEntry boundImportTable;
internal DirectoryEntry importAddressTable;
internal DirectoryEntry delayImportTable;
internal DirectoryEntry cliHeaderTable;
internal DirectoryEntry reserved;
internal NTHeader()
{
this.signature = 0x00004550; /* "PE\0\0" */
this.machine = 0x14c;
this.sizeOfOptionalHeader = 224;
this.characteristics = 0x0002 | 0x0004 | 0x008 | 0x0100;
this.magic = 0x10B;
this.majorLinkerVersion = 6;
this.baseOfCode = 0x2000;
this.imageBase = 0x400000; //TODO: make this settable
this.sectionAlignment = 8192;
this.fileAlignment = 512;
this.majorOperatingSystemVersion = 4;
this.majorSubsystemVersion = 4;
this.dllCharacteristics = 0x400;
this.sizeOfStackReserve = 1048576;
this.sizeOfStackCommit = 4096;
this.sizeOfHeapReserve = 1048576;
this.sizeOfHeapCommit = 4096;
this.numberOfDataDirectories = 16;
// initialization provided by runtime
//this.numberOfSections = 0;
//this.timeDateStamp = 0;
//this.pointerToSymbolTable = 0;
//this.numberOfSymbols = 0;
//this.minorLinkerVersion = 0;
//this.sizeOfCode = 0;
//this.sizeOfInitializedData = 0;
//this.sizeOfUninitializedData = 0;
//this.addressOfEntryPoint = 0;
//this.baseOfData = 0;
//this.minorOperatingSystemVersion = 0;
//this.majorImageVersion = 0;
//this.minorImageVersion = 0;
//this.minorSubsystemVersion = 0;
//this.win32VersionValue = 0;
//this.sizeOfImage = 0;
//this.sizeOfHeaders = 0;
//this.checkSum = 0;
//this.subsystem = 0;
//this.loaderFlags = 0x0;
}
}
internal struct SectionHeader
{
internal string name;
internal int virtualSize;
internal int virtualAddress;
internal int sizeOfRawData;
internal int pointerToRawData;
internal int pointerToRelocations;
internal int pointerToLinenumbers;
internal ushort numberOfRelocations;
internal ushort numberOfLinenumbers;
internal int characteristics;
}
internal class StreamHeader
{
internal int offset;
internal int size;
internal String name;
}
internal class TablesHeader
{
internal int reserved;
internal byte majorVersion;
internal byte minorVersion;
internal byte heapSizes;
internal byte rowId;
internal long maskValid;
internal long maskSorted;
internal int[] countArray;
}
internal enum TableIndices
{
Module = 0x00,
TypeRef = 0x01,
TypeDef = 0x02,
FieldPtr = 0x03,
Field = 0x04,
MethodPtr = 0x05,
Method = 0x06,
ParamPtr = 0x07,
Param = 0x08,
InterfaceImpl = 0x09,
MemberRef = 0x0A,
Constant = 0x0B,
CustomAttribute = 0x0C,
FieldMarshal = 0x0D,
DeclSecurity = 0x0E,
ClassLayout = 0x0F,
FieldLayout = 0x10,
StandAloneSig = 0x11,
EventMap = 0x12,
EventPtr = 0x13,
Event = 0x14,
PropertyMap = 0x15,
PropertyPtr = 0x16,
Property = 0x17,
MethodSemantics = 0x18,
MethodImpl = 0x19,
ModuleRef = 0x1A,
TypeSpec = 0x1B,
ImplMap = 0x1C,
FieldRva = 0x1D,
EncLog = 0x1E,
EncMap = 0x1F,
Assembly = 0x20,
AssemblyProcessor = 0x21,
AssemblyOS = 0x22,
AssemblyRef = 0x23,
AssemblyRefProcessor = 0x24,
AssemblyRefOS = 0x25,
File = 0x26,
ExportedType = 0x27,
ManifestResource = 0x28,
NestedClass = 0x29,
GenericParam = 0x2a,
MethodSpec = 0x2b,
GenericParamConstraint = 0x2c,
Count
}
internal enum ElementType
{
End = 0x00,
Void = 0x01,
Boolean = 0x02,
Char = 0x03,
Int8 = 0x04,
UInt8 = 0x05,
Int16 = 0x06,
UInt16 = 0x07,
Int32 = 0x08,
UInt32 = 0x09,
Int64 = 0x0a,
UInt64 = 0x0b,
Single = 0x0c,
Double = 0x0d,
String = 0x0e,
Pointer = 0x0f,
Reference = 0x10,
ValueType = 0x11,
Class = 0x12,
TypeParameter = 0x13,
Array = 0x14,
GenericTypeInstance = 0x15,
DynamicallyTypedReference = 0x16,
IntPtr = 0x18,
UIntPtr = 0x19,
FunctionPointer = 0x1b,
Object = 0x1c,
SzArray = 0x1d,
MethodParameter = 0x1e,
RequiredModifier = 0x1f,
OptionalModifier = 0x20,
Internal = 0x21,
Modifier = 0x40,
Sentinel = 0x41,
Pinned = 0x45,
Type = 0x50,
BoxedEnum = 0x51,
Enum = 0x55
}
unsafe internal class MetadataReader : IDisposable
{
#if !ROTOR
private MemoryMappedFile memmap;
#endif
private MemoryCursor/*!*/ cursor;
internal int entryPointToken;
internal int fileAlignment;
internal ModuleKindFlags moduleKind;
internal PEKindFlags peKind;
internal bool TrackDebugData;
private int mdOffset;
private int resourcesOffset;
private int win32ResourcesOffset;
private SectionHeader[] sectionHeaders;
//^ [SpecPublic]
private StreamHeader identifierStringHeap;
//^ [SpecPublic]
private StreamHeader generalStringHeap;
private StreamHeader blobHeap;
//^ [SpecPublic]
private StreamHeader guidHeap;
private StreamHeader tables;
internal TablesHeader tablesHeader;
internal string targetRuntimeVersion;
internal int linkerMajorVersion;
internal int linkerMinorVersion;
internal int metadataFormatMajorVersion;
internal int metadataFormatMinorVersion;
private int blobRefSize;
private int constantParentRefSize;
private int customAttributeParentRefSize;
private int customAttributeConstructorRefSize;
private int declSecurityParentRefSize;
private int fieldMarshalParentRefSize;
private int guidRefSize;
private int hasSemanticRefSize;
private int implementationRefSize;
private int methodDefOrRefSize;
private int memberRefParentSize;
private int memberForwardedRefSize;
private int typeDefOrRefOrSpecSize;
private int typeDefOrMethodDefSize;
private int resolutionScopeRefSize;
private int stringRefSize;
private int[] tableSize;
private int[] tableRefSize;
private int[] tableOffset;
internal byte[] HashValue;
#if !ROTOR
internal MetadataReader(string path)
{
MemoryMappedFile memmap = this.memmap = new MemoryMappedFile(path);
try
{
this.cursor = new MemoryCursor(memmap);
//^ base();
ReadHeader();
}
catch
{
this.Dispose();
throw;
}
}
#endif
internal MetadataReader(byte* buffer, int length)
{
this.cursor = new MemoryCursor(buffer, length);
//^ base();
ReadHeader();
}
public void Dispose()
{
#if !ROTOR
if (this.memmap != null) this.memmap.Dispose();
this.memmap = null;
#endif
//this.cursor = null;
this.sectionHeaders = null;
this.identifierStringHeap = null;
this.generalStringHeap = null;
this.blobHeap = null;
this.guidHeap = null;
this.tables = null;
this.tablesHeader = null;
this.targetRuntimeVersion = null;
this.tableSize = null;
this.tableRefSize = null;
this.tableOffset = null;
this.HashValue = null;
}
private AssemblyRow[] assemblyTable;
private AssemblyRefRow[] assemblyRefTable;
private ClassLayoutRow[] classLayoutTable;
private ConstantRow[] constantTable;
private CustomAttributeRow[] customAttributeTable;
private DeclSecurityRow[] declSecurityTable;
private EventMapRow[] eventMapTable;
private EventPtrRow[] eventPtrTable;
private EventRow[] eventTable;
private ExportedTypeRow[] exportedTypeTable;
private FieldRow[] fieldTable;
private FieldLayoutRow[] fieldLayoutTable;
private FieldMarshalRow[] fieldMarshalTable;
private FieldPtrRow[] fieldPtrTable;
private FieldRvaRow[] fieldRvaTable;
private FileRow[] fileTable;
private GenericParamRow[] genericParamTable;
private GenericParamConstraintRow[] genericParamConstraintTable;
private ImplMapRow[] implMapTable;
private InterfaceImplRow[] interfaceImplTable;
private ManifestResourceRow[] manifestResourceTable;
private MemberRefRow[] memberRefTable;
private MethodRow[] methodTable;
private MethodPtrRow[] methodPtrTable;
private MethodImplRow[] methodImplTable;
private MethodSemanticsRow[] methodSemanticsTable;
private MethodSpecRow[] methodSpecTable;
private ModuleRow[] moduleTable;
private ModuleRefRow[] moduleRefTable;
private NestedClassRow[] nestedClassTable;
private ParamRow[] paramTable;
private ParamPtrRow[] paramPtrTable;
private PropertyRow[] propertyTable;
private PropertyMapRow[] propertyMapTable;
private PropertyPtrRow[] propertyPtrTable;
private StandAloneSigRow[] standAloneSigTable;
private TypeDefRow[] typeDefTable;
private TypeRefRow[] typeRefTable;
private TypeSpecRow[] typeSpecTable;
internal AssemblyRow[]/*!*/ AssemblyTable
{
get { if (this.assemblyTable == null) this.ReadAssemblyTable(); return this.assemblyTable; }
}
internal AssemblyRefRow[]/*!*/ AssemblyRefTable
{
get { if (this.assemblyRefTable == null) this.ReadAssemblyRefTable(); return this.assemblyRefTable; }
}
internal ClassLayoutRow[]/*!*/ ClassLayoutTable
{
get { if (this.classLayoutTable == null) this.ReadClassLayoutTable(); return this.classLayoutTable; }
}
internal ConstantRow[]/*!*/ ConstantTable
{
get { if (this.constantTable == null) this.ReadConstantTable(); return this.constantTable; }
}
internal CustomAttributeRow[]/*!*/ CustomAttributeTable
{
get { if (this.customAttributeTable == null) this.ReadCustomAttributeTable(); return this.customAttributeTable; }
}
internal DeclSecurityRow[]/*!*/ DeclSecurityTable
{
get { if (this.declSecurityTable == null) this.ReadDeclSecurityTable(); return this.declSecurityTable; }
}
internal EventMapRow[]/*!*/ EventMapTable
{
get { if (this.eventMapTable == null) this.ReadEventMapTable(); return this.eventMapTable; }
}
internal EventPtrRow[]/*!*/ EventPtrTable
{
get { if (this.eventPtrTable == null) this.ReadEventPtrTable(); return this.eventPtrTable; }
}
internal EventRow[]/*!*/ EventTable
{
get { if (this.eventTable == null) this.ReadEventTable(); return this.eventTable; }
}
internal ExportedTypeRow[]/*!*/ ExportedTypeTable
{
get { if (this.exportedTypeTable == null) this.ReadExportedTypeTable(); return this.exportedTypeTable; }
}
internal FieldRow[]/*!*/ FieldTable
{
get { if (this.fieldTable == null) this.ReadFieldTable(); return this.fieldTable; }
}
internal FieldLayoutRow[]/*!*/ FieldLayoutTable
{
get { if (this.fieldLayoutTable == null) this.ReadFieldLayoutTable(); return this.fieldLayoutTable; }
}
internal FieldMarshalRow[]/*!*/ FieldMarshalTable
{
get { if (this.fieldMarshalTable == null) this.ReadFieldMarshalTable(); return this.fieldMarshalTable; }
}
internal FieldPtrRow[]/*!*/ FieldPtrTable
{
get { if (this.fieldPtrTable == null) this.ReadFieldPtrTable(); return this.fieldPtrTable; }
}
internal FieldRvaRow[]/*!*/ FieldRvaTable
{
get { if (this.fieldRvaTable == null) this.ReadFieldRvaTable(); return this.fieldRvaTable; }
}
internal FileRow[]/*!*/ FileTable
{
get { if (this.fileTable == null) this.ReadFileTable(); return this.fileTable; }
}
internal GenericParamRow[]/*!*/ GenericParamTable
{
get { if (this.genericParamTable == null) this.ReadGenericParamTable(); return this.genericParamTable; }
}
internal GenericParamConstraintRow[]/*!*/ GenericParamConstraintTable
{
get { if (this.genericParamConstraintTable == null) this.ReadGenericParamConstraintTable(); return this.genericParamConstraintTable; }
}
internal ImplMapRow[]/*!*/ ImplMapTable
{
get { if (this.implMapTable == null) this.ReadImplMapTable(); return this.implMapTable; }
}
internal InterfaceImplRow[]/*!*/ InterfaceImplTable
{
get { if (this.interfaceImplTable == null) this.ReadInterfaceImplTable(); return this.interfaceImplTable; }
}
internal ManifestResourceRow[]/*!*/ ManifestResourceTable
{
get { if (this.manifestResourceTable == null) this.ReadManifestResourceTable(); return this.manifestResourceTable; }
}
internal MemberRefRow[]/*!*/ MemberRefTable
{
get { if (this.memberRefTable == null) this.ReadMemberRefTable(); return this.memberRefTable; }
}
internal MethodRow[]/*!*/ MethodTable
{
get { if (this.methodTable == null) this.ReadMethodTable(); return this.methodTable; }
}
internal MethodImplRow[]/*!*/ MethodImplTable
{
get { if (this.methodImplTable == null) this.ReadMethodImplTable(); return this.methodImplTable; }
}
internal MethodPtrRow[]/*!*/ MethodPtrTable
{
get { if (this.methodPtrTable == null) this.ReadMethodPtrTable(); return this.methodPtrTable; }
}
internal MethodSemanticsRow[]/*!*/ MethodSemanticsTable
{
get { if (this.methodSemanticsTable == null) this.ReadMethodSemanticsTable(); return this.methodSemanticsTable; }
}
internal MethodSpecRow[]/*!*/ MethodSpecTable
{
get { if (this.methodSpecTable == null) this.ReadMethodSpecTable(); return this.methodSpecTable; }
}
internal ModuleRow[]/*!*/ ModuleTable
{
get { if (this.moduleTable == null) this.ReadModuleTable(); return this.moduleTable; }
}
internal ModuleRefRow[]/*!*/ ModuleRefTable
{
get { if (this.moduleRefTable == null) this.ReadModuleRefTable(); return this.moduleRefTable; }
}
internal NestedClassRow[]/*!*/ NestedClassTable
{
get { if (this.nestedClassTable == null) this.ReadNestedClassTable(); return this.nestedClassTable; }
}
internal ParamRow[]/*!*/ ParamTable
{
get { if (this.paramTable == null) this.ReadParamTable(); return this.paramTable; }
}
internal ParamPtrRow[]/*!*/ ParamPtrTable
{
get { if (this.paramPtrTable == null) this.ReadParamPtrTable(); return this.paramPtrTable; }
}
internal PropertyRow[]/*!*/ PropertyTable
{
get { if (this.propertyTable == null) this.ReadPropertyTable(); return this.propertyTable; }
}
internal PropertyMapRow[]/*!*/ PropertyMapTable
{
get { if (this.propertyMapTable == null) this.ReadPropertyMapTable(); return this.propertyMapTable; }
}
internal PropertyPtrRow[]/*!*/ PropertyPtrTable
{
get { if (this.propertyPtrTable == null) this.ReadPropertyPtrTable(); return this.propertyPtrTable; }
}
internal StandAloneSigRow[]/*!*/ StandAloneSigTable
{
get { if (this.standAloneSigTable == null) this.ReadStandAloneSigTable(); return this.standAloneSigTable; }
}
internal TypeDefRow[]/*!*/ TypeDefTable
{
get { if (this.typeDefTable == null) this.ReadTypeDefTable(); return this.typeDefTable; }
}
internal TypeRefRow[]/*!*/ TypeRefTable
{
get { if (this.typeRefTable == null) this.ReadTypeRefTable(); return this.typeRefTable; }
}
internal TypeSpecRow[]/*!*/ TypeSpecTable
{
get { if (this.typeSpecTable == null) this.ReadTypeSpecTable(); return this.typeSpecTable; }
}
internal void SetCurrentPosition(int pos)
{
this.cursor.Position = pos;
}
internal void AlignTo32BitBoundary()
{
this.cursor.Align(4);
}
internal void Skip(int bytes)
{
this.cursor.SkipByte(bytes);
}
internal byte[]/*!*/ GetBlob(int blobIndex)
{
MemoryCursor c = this.cursor;
c.Position = PositionOfBlob(blobIndex);
return c.ReadBytes(c.ReadCompressedInt());
}
internal MemoryCursor/*!*/ GetBlobCursor(int blobIndex)
{
MemoryCursor c = this.cursor;
c.Position = PositionOfBlob(blobIndex);
c.ReadCompressedInt();
return new MemoryCursor(c);
}
internal MemoryCursor/*!*/ GetBlobCursor(int blobIndex, out int blobLength)
{
MemoryCursor c = this.cursor;
c.Position = PositionOfBlob(blobIndex);
blobLength = c.ReadCompressedInt();
return new MemoryCursor(c);
}
internal System.Guid GetGuid(int guidIndex)
//^ requires this.guidHeap != null;
{
int guidOffset = guidIndex * 16;
if (guidOffset < 16 || this.guidHeap.size < guidOffset)
throw new System.ArgumentOutOfRangeException("guidIndex", ExceptionStrings.BadGuidHeapIndex);
MemoryCursor c = this.cursor;
c.Position = this.mdOffset + this.guidHeap.offset + guidOffset - 16;
return new System.Guid(c.ReadBytes(16));
}
internal Identifier/*!*/ GetIdentifier(int stringHeapIndex)
//^ requires this.identifierStringHeap != null;
{
int position = this.mdOffset + this.identifierStringHeap.offset + stringHeapIndex;
MemoryCursor c = this.cursor;
return Identifier.For(c.GetBuffer(), position/*, c.KeepAlive*/);
}
internal byte GetMethodBodyHeaderByte(int RVA)
{
MemoryCursor c = this.cursor;
c.Position = this.RvaToOffset(RVA);
return c.ReadByte();
}
internal MemoryCursor/*!*/ GetNewCursor()
{
return new MemoryCursor(this.cursor);
}
internal MemoryCursor/*!*/ GetNewCursor(int RVA, out PESection targetSection)
{
MemoryCursor c = new MemoryCursor(this.cursor);
c.Position = this.RvaToOffset(RVA, out targetSection);
return c;
}
internal byte GetByte()
{
MemoryCursor c = this.cursor;
return c.ReadByte();
}
internal int GetCurrentPosition()
{
return this.cursor.Position;
}
internal int GetInt32()
{
MemoryCursor c = this.cursor;
return c.ReadInt32();
}
internal short GetInt16()
{
MemoryCursor c = this.cursor;
return c.ReadInt16();
}
internal ushort GetUInt16()
{
MemoryCursor c = this.cursor;
return c.ReadUInt16();
}
internal int GetSignatureLength(int blobIndex)
{
MemoryCursor c = this.cursor;
c.Position = this.PositionOfBlob(blobIndex);
return c.ReadCompressedInt();
}
internal string/*!*/ GetString(int stringHeapIndex)
//^ requires this.identifierStringHeap != null;
{
if (stringHeapIndex < 0 || this.identifierStringHeap.size <= stringHeapIndex)
throw new System.ArgumentOutOfRangeException("stringHeapIndex", ExceptionStrings.BadStringHeapIndex);
MemoryCursor c = this.cursor;
c.Position = this.mdOffset + this.identifierStringHeap.offset + stringHeapIndex;
return c.ReadUTF8();
}
internal string/*!*/ GetUserString(int stringHeapIndex)
//^ requires this.generalStringHeap != null;
{
if (stringHeapIndex < 0 || this.generalStringHeap.size <= stringHeapIndex)
throw new System.ArgumentOutOfRangeException("stringHeapIndex", ExceptionStrings.BadUserStringHeapIndex);
MemoryCursor c = this.cursor;
c.Position = this.mdOffset + this.generalStringHeap.offset + stringHeapIndex;
int strLength = c.ReadCompressedInt();
return c.ReadUTF16(strLength / 2);
}
internal string/*!*/ GetBlobString(int blobIndex)
{
MemoryCursor c = this.cursor;
c.Position = this.PositionOfBlob(blobIndex);
int blobLength = c.ReadCompressedInt();
return c.ReadUTF16(blobLength / 2);
}
internal object GetValueFromBlob(int type, int blobIndex)
{
MemoryCursor c = this.cursor;
c.Position = this.PositionOfBlob(blobIndex);
int blobLength = c.ReadCompressedInt();
switch ((ElementType)type)
{
case ElementType.Boolean: return c.ReadBoolean();
case ElementType.Char: return (char)c.ReadUInt16();
case ElementType.Double: return c.ReadDouble();
case ElementType.Single: return c.ReadSingle();
case ElementType.Int16: return c.ReadInt16();
case ElementType.Int32: return c.ReadInt32();
case ElementType.Int64: return c.ReadInt64();
case ElementType.Int8: return c.ReadSByte();
case ElementType.UInt16: return c.ReadUInt16();
case ElementType.UInt32: return c.ReadUInt32();
case ElementType.UInt64: return c.ReadUInt64();
case ElementType.UInt8: return c.ReadByte();
case ElementType.Class: return null;
case ElementType.String: return c.ReadUTF16(blobLength / 2);
}
throw new InvalidMetadataException(ExceptionStrings.UnknownConstantType);
}
internal byte[] GetResourceData(int resourceOffset)
{
this.cursor.Position = this.resourcesOffset + resourceOffset;
int length = this.cursor.ReadInt32();
return this.cursor.ReadBytes(length);
}
private int PositionOfBlob(int blobIndex)
//^ requires this.blobHeap != null;
{
if (blobIndex < 0 || this.blobHeap.size <= blobIndex)
throw new System.ArgumentOutOfRangeException("blobIndex", ExceptionStrings.BadBlobHeapIndex);
return this.mdOffset + this.blobHeap.offset + blobIndex;
}
private void ReadHeader()
{ //TODO: break up this method
MemoryCursor c = this.cursor;
c.Position = 0;
ReadDOSHeader(c);
NTHeader ntHeader = ReadNTHeader(c);
this.linkerMajorVersion = ntHeader.majorLinkerVersion;
this.linkerMinorVersion = ntHeader.minorLinkerVersion;
this.fileAlignment = ntHeader.fileAlignment;
if ((ntHeader.characteristics & 0x2000) != 0)
this.moduleKind = ModuleKindFlags.DynamicallyLinkedLibrary;
else
this.moduleKind = ntHeader.subsystem == 0x3 ? ModuleKindFlags.ConsoleApplication : ModuleKindFlags.WindowsApplication;
int sectionCount = ntHeader.numberOfSections;
SectionHeader[] sectionHeaders = this.sectionHeaders = new SectionHeader[sectionCount];
int resourceSectionIndex = -1;
for (int i = 0; i < sectionCount; i++)
{
sectionHeaders[i] = ReadSectionHeader(c);
if (sectionHeaders[i].name == ".rsrc") resourceSectionIndex = i;
}
if (resourceSectionIndex >= 0)
this.win32ResourcesOffset = sectionHeaders[resourceSectionIndex].pointerToRawData;
else
this.win32ResourcesOffset = -1;
DirectoryEntry de = ntHeader.cliHeaderTable;
int cliHeaderOffset = this.RvaToOffset(de.virtualAddress);
c.Position = cliHeaderOffset;
CLIHeader cliHeader = ReadCLIHeader(c);
this.entryPointToken = cliHeader.entryPointToken;
if ((cliHeader.flags & 1) != 0)
this.peKind = PEKindFlags.ILonly;
if ((cliHeader.flags & 0x10) != 0)
this.entryPointToken = 0; //Native entry point. Ignore.
switch (ntHeader.machine)
{
case 0x0200:
this.peKind |= PEKindFlags.Requires64bits;
break;
case 0x8664:
this.peKind |= PEKindFlags.Requires64bits | PEKindFlags.AMD;
break;
default:
if (ntHeader.magic == 0x20B) //Optional header magic for PE32+
this.peKind |= PEKindFlags.Requires64bits;
else if ((cliHeader.flags & 2) != 0)
this.peKind |= PEKindFlags.Requires32bits;
break;
}
this.TrackDebugData = (cliHeader.flags & 0x10000) != 0;
if (cliHeader.resources.size > 0)
this.resourcesOffset = this.RvaToOffset(cliHeader.resources.virtualAddress);
int snSize = cliHeader.strongNameSignature.size;
if (snSize > 0)
{
long hashOffset = this.RvaToOffset(cliHeader.strongNameSignature.virtualAddress);
c.Position = (int)hashOffset;
this.HashValue = c.ReadBytes(snSize);
bool zeroHash = true;
for (int i = 0; i < snSize; i++) if (this.HashValue[i] != 0) zeroHash = false;
if (zeroHash) this.HashValue = null; //partially signed assembly
}
long mdOffset = this.mdOffset = this.RvaToOffset(cliHeader.metaData.virtualAddress);
c.Position = (int)mdOffset;
MetadataHeader mdHeader = ReadMetadataHeader(c);
this.targetRuntimeVersion = mdHeader.versionString;
foreach (StreamHeader sheader in mdHeader.streamHeaders)
{
//^ assume sheader != null;
switch (sheader.name)
{
case "#Strings": this.identifierStringHeap = sheader; continue;
case "#US": this.generalStringHeap = sheader; continue;
case "#Blob": this.blobHeap = sheader; continue;
case "#GUID": this.guidHeap = sheader; continue;
case "#~": this.tables = sheader; continue;
case "#-": this.tables = sheader; continue;
default: continue;
}
}
if (this.tables == null) throw new InvalidMetadataException(ExceptionStrings.NoMetadataStream);
c.Position = (int)(mdOffset + this.tables.offset);
TablesHeader tablesHeader = this.tablesHeader = ReadTablesHeader(c);
this.metadataFormatMajorVersion = tablesHeader.majorVersion;
this.metadataFormatMinorVersion = tablesHeader.minorVersion;
int[] tableSize = this.tableSize = new int[(int)TableIndices.Count];
int[] tableRefSize = this.tableRefSize = new int[(int)TableIndices.Count];
long valid = tablesHeader.maskValid;
int[] countArray = tablesHeader.countArray;
//^ assume countArray != null;
for (int i = 0, j = 0; i < (int)TableIndices.Count; i++)
{
if (valid % 2 == 1)
{
int m = tableSize[i] = countArray[j++];
tableRefSize[i] = m < 0x10000 ? 2 : 4;
}
else
tableRefSize[i] = 2;
valid /= 2;
}
int blobRefSize = this.blobRefSize = ((tablesHeader.heapSizes & 0x04) == 0 ? 2 : 4);
int constantParentRefSize = this.constantParentRefSize =
tableSize[(int)TableIndices.Param] < 0x4000 &&
tableSize[(int)TableIndices.Field] < 0x4000 &&
tableSize[(int)TableIndices.Property] < 0x4000 ? 2 : 4;
int customAttributeParentRefSize = 0;
if (this.metadataFormatMajorVersion > 1 || this.metadataFormatMinorVersion > 0)
{
customAttributeParentRefSize = this.customAttributeParentRefSize =
tableSize[(int)TableIndices.Method] < 0x0800 &&
tableSize[(int)TableIndices.Field] < 0x0800 &&
tableSize[(int)TableIndices.TypeRef] < 0x0800 &&
tableSize[(int)TableIndices.TypeDef] < 0x0800 &&
tableSize[(int)TableIndices.Param] < 0x0800 &&
tableSize[(int)TableIndices.InterfaceImpl] < 0x0800 &&
tableSize[(int)TableIndices.MemberRef] < 0x0800 &&
tableSize[(int)TableIndices.Module] < 0x0800 &&
tableSize[(int)TableIndices.DeclSecurity] < 0x0800 &&
tableSize[(int)TableIndices.Property] < 0x0800 &&
tableSize[(int)TableIndices.Event] < 0x0800 &&
tableSize[(int)TableIndices.StandAloneSig] < 0x0800 &&
tableSize[(int)TableIndices.ModuleRef] < 0x0800 &&
tableSize[(int)TableIndices.TypeSpec] < 0x0800 &&
tableSize[(int)TableIndices.Assembly] < 0x0800 &&
tableSize[(int)TableIndices.File] < 0x0800 &&
tableSize[(int)TableIndices.ExportedType] < 0x0800 &&
tableSize[(int)TableIndices.ManifestResource] < 0x0800 &&
tableSize[(int)TableIndices.GenericParam] < 0x0800 &&
tableSize[(int)TableIndices.MethodSpec] < 0x0800 &&
tableSize[(int)TableIndices.GenericParamConstraint] < 0x0800 ? 2 : 4;
}
else
{
customAttributeParentRefSize = this.customAttributeParentRefSize =
tableSize[(int)TableIndices.Method] < 0x0800 &&
tableSize[(int)TableIndices.Field] < 0x0800 &&
tableSize[(int)TableIndices.TypeRef] < 0x0800 &&
tableSize[(int)TableIndices.TypeDef] < 0x0800 &&
tableSize[(int)TableIndices.Param] < 0x0800 &&
tableSize[(int)TableIndices.InterfaceImpl] < 0x0800 &&
tableSize[(int)TableIndices.MemberRef] < 0x0800 &&
tableSize[(int)TableIndices.Module] < 0x0800 &&
tableSize[(int)TableIndices.DeclSecurity] < 0x0800 &&
tableSize[(int)TableIndices.Property] < 0x0800 &&
tableSize[(int)TableIndices.Event] < 0x0800 &&
tableSize[(int)TableIndices.StandAloneSig] < 0x0800 &&
tableSize[(int)TableIndices.ModuleRef] < 0x0800 &&
tableSize[(int)TableIndices.TypeSpec] < 0x0800 &&
tableSize[(int)TableIndices.Assembly] < 0x0800 &&
tableSize[(int)TableIndices.File] < 0x0800 &&
tableSize[(int)TableIndices.ExportedType] < 0x0800 &&
tableSize[(int)TableIndices.ManifestResource] < 0x0800 ? 2 : 4;
}
int customAttributeConstructorRefSize = this.customAttributeConstructorRefSize =
tableSize[(int)TableIndices.Method] < 0x2000 &&
tableSize[(int)TableIndices.MemberRef] < 0x2000 ? 2 : 4;
int declSecurityParentRefSize = this.declSecurityParentRefSize =
tableSize[(int)TableIndices.TypeDef] < 0x4000 &&
tableSize[(int)TableIndices.Method] < 0x4000 &&
tableSize[(int)TableIndices.Assembly] < 0x4000 ? 2 : 4;
int fieldMarshalParentRefSize = this.fieldMarshalParentRefSize =
tableSize[(int)TableIndices.Field] < 0x8000 &&
tableSize[(int)TableIndices.Param] < 0x8000 ? 2 : 4;
int guidRefSize = this.guidRefSize = ((tablesHeader.heapSizes & 0x02) == 0 ? 2 : 4);
int hasSemanticRefSize = this.hasSemanticRefSize =
tableSize[(int)TableIndices.Event] < 0x8000 &&
tableSize[(int)TableIndices.Property] < 0x8000 ? 2 : 4;
int implementationRefSize = this.implementationRefSize =
tableSize[(int)TableIndices.File] < 0x4000 &&
tableSize[(int)TableIndices.AssemblyRef] < 0x4000 &&
tableSize[(int)TableIndices.ExportedType] < 0x4000 ? 2 : 4;
int methodDefOrRefSize = this.methodDefOrRefSize =
tableSize[(int)TableIndices.Method] < 0x8000 &&
tableSize[(int)TableIndices.MemberRef] < 0x8000 ? 2 : 4;
int memberRefParentSize = this.memberRefParentSize =
tableSize[(int)TableIndices.TypeDef] < 0x2000 &&
tableSize[(int)TableIndices.TypeRef] < 0x2000 &&
tableSize[(int)TableIndices.ModuleRef] < 0x2000 &&
tableSize[(int)TableIndices.Method] < 0x2000 &&
tableSize[(int)TableIndices.TypeSpec] < 0x2000 ? 2 : 4;
int memberForwardedRefSize = this.memberForwardedRefSize =
tableSize[(int)TableIndices.Field] < 0x8000 &&
tableSize[(int)TableIndices.Method] < 0x8000 ? 2 : 4;
int typeDefOrMethodDefSize = this.typeDefOrMethodDefSize =
tableSize[(int)TableIndices.TypeDef] < 0x8000 &&
tableSize[(int)TableIndices.Method] < 0x8000 ? 2 : 4;
int typeDefOrRefOrSpecSize = this.typeDefOrRefOrSpecSize =
tableSize[(int)TableIndices.TypeDef] < 0x4000 &&
tableSize[(int)TableIndices.TypeRef] < 0x4000 &&
tableSize[(int)TableIndices.TypeSpec] < 0x4000 ? 2 : 4;
int resolutionScopeRefSize = this.resolutionScopeRefSize =
tableSize[(int)TableIndices.Module] < 0x4000 &&
tableSize[(int)TableIndices.ModuleRef] < 0x4000 &&
tableSize[(int)TableIndices.AssemblyRef] < 0x4000 &&
tableSize[(int)TableIndices.TypeRef] < 0x4000 ? 2 : 4;
int stringRefSize = this.stringRefSize = ((tablesHeader.heapSizes & 0x01) == 0 ? 2 : 4);
int[] tableOffset = this.tableOffset = new int[(int)TableIndices.Count];
int offset = this.mdOffset + this.tables.offset + 24 + countArray.Length * 4;
for (int i = 0; i < (int)TableIndices.Count; i++)
{
int m = tableSize[i];
if (m == 0) continue;
tableOffset[i] = offset;
switch ((TableIndices)i)
{
case TableIndices.Module: offset += m * (2 + stringRefSize + 3 * guidRefSize); break;
case TableIndices.TypeRef: offset += m * (resolutionScopeRefSize + 2 * stringRefSize); break;
case TableIndices.TypeDef: offset += m * (4 + 2 * stringRefSize + typeDefOrRefOrSpecSize + tableRefSize[(int)TableIndices.Field] + tableRefSize[(int)TableIndices.Method]); break;
case TableIndices.FieldPtr: offset += m * (tableRefSize[(int)TableIndices.Field]); break;
case TableIndices.Field: offset += m * (2 + stringRefSize + blobRefSize); break;
case TableIndices.MethodPtr: offset += m * (tableRefSize[(int)TableIndices.Method]); break;
case TableIndices.Method: offset += m * (8 + stringRefSize + blobRefSize + tableRefSize[(int)TableIndices.Param]); break;
case TableIndices.ParamPtr: offset += m * (tableRefSize[(int)TableIndices.Param]); break;
case TableIndices.Param: offset += m * (4 + stringRefSize); break;
case TableIndices.InterfaceImpl: offset += m * (tableRefSize[(int)TableIndices.TypeDef] + typeDefOrRefOrSpecSize); break;
case TableIndices.MemberRef: offset += m * (memberRefParentSize + stringRefSize + blobRefSize); break;
case TableIndices.Constant: offset += m * (2 + constantParentRefSize + blobRefSize); break;
case TableIndices.CustomAttribute: offset += m * (customAttributeParentRefSize + customAttributeConstructorRefSize + blobRefSize); break;
case TableIndices.FieldMarshal: offset += m * (fieldMarshalParentRefSize + blobRefSize); break;
case TableIndices.DeclSecurity: offset += m * (2 + declSecurityParentRefSize + blobRefSize); break;
case TableIndices.ClassLayout: offset += m * (6 + tableRefSize[(int)TableIndices.TypeDef]); break;
case TableIndices.FieldLayout: offset += m * (4 + tableRefSize[(int)TableIndices.Field]); break;
case TableIndices.StandAloneSig: offset += m * (blobRefSize); break;
case TableIndices.EventMap: offset += m * (tableRefSize[(int)TableIndices.TypeDef] + tableRefSize[(int)TableIndices.Event]); break;
case TableIndices.EventPtr: offset += m * (tableRefSize[(int)TableIndices.Event]); break;
case TableIndices.Event: offset += m * (2 + stringRefSize + typeDefOrRefOrSpecSize); break;
case TableIndices.PropertyMap: offset += m * (tableRefSize[(int)TableIndices.TypeDef] + tableRefSize[(int)TableIndices.Property]); break;
case TableIndices.PropertyPtr: offset += m * (tableRefSize[(int)TableIndices.Property]); break;
case TableIndices.Property: offset += m * (2 + stringRefSize + blobRefSize); break;
case TableIndices.MethodSemantics: offset += m * (2 + tableRefSize[(int)TableIndices.Method] + hasSemanticRefSize); break;
case TableIndices.MethodImpl: offset += m * (tableRefSize[(int)TableIndices.TypeDef] + 2 * methodDefOrRefSize); break;
case TableIndices.ModuleRef: offset += m * (stringRefSize); break;
case TableIndices.TypeSpec: offset += m * (blobRefSize); break;
case TableIndices.ImplMap: offset += m * (2 + memberForwardedRefSize + stringRefSize + tableRefSize[(int)TableIndices.ModuleRef]); break;
case TableIndices.FieldRva: offset += m * (4 + tableRefSize[(int)TableIndices.Field]); break;
case TableIndices.EncLog: throw new InvalidMetadataException(ExceptionStrings.ENCLogTableEncountered);
case TableIndices.EncMap: throw new InvalidMetadataException(ExceptionStrings.ENCMapTableEncountered);
case TableIndices.Assembly: offset += m * (16 + blobRefSize + 2 * stringRefSize); break;
case TableIndices.AssemblyProcessor: offset += m * (4); break;
case TableIndices.AssemblyOS: offset += m * (12); break;
case TableIndices.AssemblyRef: offset += m * (12 + 2 * blobRefSize + 2 * stringRefSize); break;
case TableIndices.AssemblyRefProcessor: offset += m * (4 + tableRefSize[(int)TableIndices.AssemblyRef]); break;
case TableIndices.AssemblyRefOS: offset += m * (12 + tableRefSize[(int)TableIndices.AssemblyRef]); break;
case TableIndices.File: offset += m * (4 + stringRefSize + blobRefSize); break;
case TableIndices.ExportedType: offset += m * (8 + 2 * stringRefSize + implementationRefSize); break;
case TableIndices.ManifestResource: offset += m * (8 + stringRefSize + implementationRefSize); break;
case TableIndices.NestedClass: offset += m * (2 * tableRefSize[(int)TableIndices.TypeDef]); break;
case TableIndices.GenericParam:
if (this.metadataFormatMajorVersion == 1 && this.metadataFormatMinorVersion == 0)
offset += m * (6 + typeDefOrMethodDefSize + stringRefSize + typeDefOrRefOrSpecSize);
else if (this.metadataFormatMajorVersion == 1 && this.metadataFormatMinorVersion == 1)
offset += m * (4 + typeDefOrMethodDefSize + stringRefSize + typeDefOrRefOrSpecSize);
else
offset += m * (4 + typeDefOrMethodDefSize + stringRefSize);
break;
case TableIndices.MethodSpec: offset += m * (methodDefOrRefSize + blobRefSize); break;
case TableIndices.GenericParamConstraint: offset += m * (tableRefSize[(int)TableIndices.GenericParam] + typeDefOrRefOrSpecSize); break;
default: throw new InvalidMetadataException(ExceptionStrings.UnsupportedTableEncountered);
}
}
}
internal Win32ResourceList ReadWin32Resources()
{
Win32ResourceList rs = new Win32ResourceList();
int startPos = this.win32ResourcesOffset;
if (startPos < 0) return rs;
MemoryCursor c = this.cursor;
c.Position = startPos;
int sizeOfTypeDirectory = ReadWin32ResourceDirectoryHeader(c);
for (int i = 0; i < sizeOfTypeDirectory; i++)
{
string TypeName = null;
int TypeID = c.ReadInt32();
if (TypeID < 0)
{
MemoryCursor nac = new MemoryCursor(c);
nac.Position = startPos + (TypeID & 0x7FFFFFFF);
int strLength = nac.ReadUInt16();
TypeName = nac.ReadUTF16(strLength);
}
int offset = c.ReadInt32();
if (offset >= 0)
rs.Add(this.ReadWin32ResourceDataEntry(c, startPos + offset, TypeName, TypeID, null, 0, 0));
else
{
MemoryCursor nc = new MemoryCursor(c);
nc.Position = startPos + (offset & 0x7FFFFFFF);
int sizeOfNameDirectory = ReadWin32ResourceDirectoryHeader(nc);
for (int j = 0; j < sizeOfNameDirectory; j++)
{
string Name = null;
int ID = nc.ReadInt32();
if (ID < 0)
{
MemoryCursor nac = new MemoryCursor(c);
int strLength = nac.ReadUInt16();
Name = nac.ReadUTF16(strLength);
}
offset = nc.ReadInt32();
if (offset >= 0)
rs.Add(this.ReadWin32ResourceDataEntry(c, startPos + offset, TypeName, TypeID, Name, ID, 0));
else
{
MemoryCursor lc = new MemoryCursor(c);
lc.Position = startPos + (offset & 0x7FFFFFFF);
int sizeOfLanguageDirectory = ReadWin32ResourceDirectoryHeader(lc);
for (int k = 0; k < sizeOfLanguageDirectory; k++)
{
int LanguageID = lc.ReadInt32();
offset = lc.ReadInt32();
rs.Add(this.ReadWin32ResourceDataEntry(c, startPos + offset, TypeName, TypeID, Name, ID, LanguageID));
}
}
}
}
}
return rs;
}
private static int ReadWin32ResourceDirectoryHeader(MemoryCursor/*!*/ c)
{
c.ReadInt32(); //Characteristics
c.ReadInt32(); //TimeDate stamp
c.ReadInt32(); //Version
int numberOfNamedEntries = c.ReadUInt16();
int numberOfIdEntries = c.ReadUInt16();
return numberOfNamedEntries + numberOfIdEntries;
}
private Win32Resource ReadWin32ResourceDataEntry(MemoryCursor/*!*/ c, int position,
string TypeName, int TypeID, string Name, int ID, int LanguageID)
{
Win32Resource rsrc = new Win32Resource();
rsrc.TypeName = TypeName;
rsrc.TypeId = TypeID;
rsrc.Name = Name;
rsrc.Id = ID;
rsrc.LanguageId = LanguageID;
c = new MemoryCursor(c);
c.Position = position;
int dataRVA = c.ReadInt32();
int dataSize = c.ReadInt32();
rsrc.CodePage = c.ReadInt32();
c.Position = this.RvaToOffset(dataRVA);
rsrc.Data = c.ReadBytes(dataSize);
return rsrc;
}
private void ReadAssemblyTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
{
int n = this.tableSize[(int)TableIndices.Assembly];
AssemblyRow[] result = this.assemblyTable = new AssemblyRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.Assembly];
for (int i = 0; i < n; i++)
{
AssemblyRow row;
row.HashAlgId = c.ReadInt32();
row.MajorVersion = c.ReadUInt16();
row.MinorVersion = c.ReadUInt16();
row.BuildNumber = c.ReadUInt16();
row.RevisionNumber = c.ReadUInt16();
row.Flags = c.ReadInt32();
row.PublicKey = c.ReadReference(this.blobRefSize);
row.Name = c.ReadReference(this.stringRefSize);
row.Culture = c.ReadReference(this.stringRefSize);
result[i] = row;
}
}
private void ReadAssemblyRefTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
{
int n = this.tableSize[(int)TableIndices.AssemblyRef];
AssemblyRefRow[] result = this.assemblyRefTable = new AssemblyRefRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.AssemblyRef];
for (int i = 0; i < n; i++)
{
AssemblyRefRow row;
row.MajorVersion = c.ReadUInt16();
row.MinorVersion = c.ReadUInt16();
row.BuildNumber = c.ReadUInt16();
row.RevisionNumber = c.ReadUInt16();
row.Flags = c.ReadInt32();
row.PublicKeyOrToken = c.ReadReference(this.blobRefSize);
row.Name = c.ReadReference(this.stringRefSize);
row.Culture = c.ReadReference(this.stringRefSize);
row.HashValue = c.ReadReference(this.blobRefSize);
row.AssemblyReference = null;
result[i] = row;
}
}
private void ReadClassLayoutTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.ClassLayout];
ClassLayoutRow[] result = this.classLayoutTable = new ClassLayoutRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.ClassLayout];
for (int i = 0; i < n; i++)
{
ClassLayoutRow row;
row.PackingSize = c.ReadUInt16();
row.ClassSize = c.ReadInt32();
row.Parent = c.ReadReference(this.tableRefSize[(int)TableIndices.TypeDef]);
result[i] = row;
}
}
private void ReadConstantTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
{
int n = this.tableSize[(int)TableIndices.Constant];
ConstantRow[] result = this.constantTable = new ConstantRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.Constant];
for (int i = 0; i < n; i++)
{
ConstantRow row;
row.Type = c.ReadByte();
c.ReadByte();
row.Parent = c.ReadReference(this.constantParentRefSize);
row.Value = c.ReadReference(this.blobRefSize);
result[i] = row;
}
}
private void ReadCustomAttributeTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
{
int n = this.tableSize[(int)TableIndices.CustomAttribute];
CustomAttributeRow[] result = this.customAttributeTable = new CustomAttributeRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.CustomAttribute];
for (int i = 0; i < n; i++)
{
CustomAttributeRow row;
row.Parent = c.ReadReference(this.customAttributeParentRefSize);
row.Constructor = c.ReadReference(this.customAttributeConstructorRefSize);
row.Value = c.ReadReference(this.blobRefSize);
result[i] = row;
}
}
private void ReadDeclSecurityTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
{
int n = this.tableSize[(int)TableIndices.DeclSecurity];
DeclSecurityRow[] result = this.declSecurityTable = new DeclSecurityRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.DeclSecurity];
for (int i = 0; i < n; i++)
{
DeclSecurityRow row;
row.Action = c.ReadUInt16();
row.Parent = c.ReadReference(this.declSecurityParentRefSize);
row.PermissionSet = c.ReadReference(this.blobRefSize);
result[i] = row;
}
}
private void ReadEventMapTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.EventMap];
EventMapRow[] result = this.eventMapTable = new EventMapRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.EventMap];
for (int i = 0; i < n; i++)
{
EventMapRow row;
row.Parent = c.ReadReference(this.tableRefSize[(int)TableIndices.TypeDef]);
row.EventList = c.ReadReference(this.tableRefSize[(int)TableIndices.Event]);
result[i] = row;
}
}
private void ReadEventPtrTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.EventPtr];
EventPtrRow[] result = this.eventPtrTable = new EventPtrRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.EventPtr];
for (int i = 0; i < n; i++)
{
EventPtrRow row;
row.Event = c.ReadReference(this.tableRefSize[(int)TableIndices.Event]);
result[i] = row;
}
}
private void ReadEventTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
{
int n = this.tableSize[(int)TableIndices.Event];
EventRow[] result = this.eventTable = new EventRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.Event];
for (int i = 0; i < n; i++)
{
EventRow row;
row.Flags = c.ReadUInt16();
row.Name = c.ReadReference(this.stringRefSize);
row.EventType = c.ReadReference(this.typeDefOrRefOrSpecSize);
result[i] = row;
}
}
private void ReadExportedTypeTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
{
int n = this.tableSize[(int)TableIndices.ExportedType];
ExportedTypeRow[] result = this.exportedTypeTable = new ExportedTypeRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.ExportedType];
for (int i = 0; i < n; i++)
{
ExportedTypeRow row;
row.Flags = c.ReadInt32();
row.TypeDefId = c.ReadInt32();
row.TypeName = c.ReadReference(this.stringRefSize);
row.TypeNamespace = c.ReadReference(this.stringRefSize);
row.Implementation = c.ReadReference(this.implementationRefSize);
result[i] = row;
}
}
private void ReadFieldTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
{
int n = this.tableSize[(int)TableIndices.Field];
FieldRow[] result = this.fieldTable = new FieldRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.Field];
for (int i = 0; i < n; i++)
{
FieldRow row;
row.Flags = c.ReadUInt16();
row.Name = c.ReadReference(this.stringRefSize);
row.Signature = c.ReadReference(this.blobRefSize);
row.Field = null;
result[i] = row;
}
}
private void ReadFieldLayoutTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.FieldLayout];
FieldLayoutRow[] result = this.fieldLayoutTable = new FieldLayoutRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.FieldLayout];
for (int i = 0; i < n; i++)
{
FieldLayoutRow row;
row.Offset = c.ReadInt32();
row.Field = c.ReadReference(this.tableRefSize[(int)TableIndices.Field]);
result[i] = row;
}
}
private void ReadFieldMarshalTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
{
int n = this.tableSize[(int)TableIndices.FieldMarshal];
FieldMarshalRow[] result = this.fieldMarshalTable = new FieldMarshalRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.FieldMarshal];
for (int i = 0; i < n; i++)
{
FieldMarshalRow row;
row.Parent = c.ReadReference(this.fieldMarshalParentRefSize);
row.NativeType = c.ReadReference(this.blobRefSize);
result[i] = row;
}
}
private void ReadFieldPtrTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.FieldPtr];
FieldPtrRow[] result = this.fieldPtrTable = new FieldPtrRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.FieldPtr];
for (int i = 0; i < n; i++)
{
FieldPtrRow row;
row.Field = c.ReadReference(this.tableRefSize[(int)TableIndices.Field]);
result[i] = row;
}
}
private void ReadFieldRvaTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.FieldRva];
FieldRvaRow[] result = this.fieldRvaTable = new FieldRvaRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.FieldRva];
for (int i = 0; i < n; i++)
{
FieldRvaRow row;
row.RVA = c.ReadInt32();
row.Field = c.ReadReference(this.tableRefSize[(int)TableIndices.Field]);
row.TargetSection = 0; //Ignored on reading
result[i] = row;
}
}
private void ReadFileTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
{
int n = this.tableSize[(int)TableIndices.File];
FileRow[] result = this.fileTable = new FileRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.File];
for (int i = 0; i < n; i++)
{
FileRow row;
row.Flags = c.ReadInt32();
row.Name = c.ReadReference(this.stringRefSize);
row.HashValue = c.ReadReference(this.blobRefSize);
result[i] = row;
}
}
private void ReadGenericParamTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.GenericParam];
GenericParamRow[] result = this.genericParamTable = new GenericParamRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.GenericParam];
bool reallyOldGenericsFileFormat = this.metadataFormatMajorVersion == 1 && this.metadataFormatMinorVersion == 0;
bool oldGenericsFileFormat = this.metadataFormatMajorVersion == 1 && this.metadataFormatMinorVersion == 1;
for (int i = 0; i < n; i++)
{
GenericParamRow row;
row.Number = c.ReadUInt16();
row.Flags = c.ReadUInt16();
row.Owner = c.ReadReference(this.typeDefOrMethodDefSize);
row.Name = c.ReadReference(this.stringRefSize);
row.GenericParameter = null;
if (oldGenericsFileFormat) c.ReadReference(this.typeDefOrRefOrSpecSize);
if (reallyOldGenericsFileFormat) c.ReadInt16();
result[i] = row;
}
}
private void ReadGenericParamConstraintTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.GenericParamConstraint];
GenericParamConstraintRow[] result = this.genericParamConstraintTable = new GenericParamConstraintRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.GenericParamConstraint];
for (int i = 0; i < n; i++)
{
GenericParamConstraintRow row;
row.Param = c.ReadReference(this.tableRefSize[(int)TableIndices.GenericParam]);
row.Constraint = c.ReadReference(this.typeDefOrRefOrSpecSize);
result[i] = row;
}
}
private void ReadImplMapTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.ImplMap];
ImplMapRow[] result = this.implMapTable = new ImplMapRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.ImplMap];
for (int i = 0; i < n; i++)
{
ImplMapRow row;
row.MappingFlags = c.ReadUInt16();
row.MemberForwarded = c.ReadReference(this.memberForwardedRefSize);
row.ImportName = c.ReadReference(this.stringRefSize);
row.ImportScope = c.ReadReference(this.tableRefSize[(int)TableIndices.ModuleRef]);
result[i] = row;
}
}
private void ReadInterfaceImplTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.InterfaceImpl];
InterfaceImplRow[] result = this.interfaceImplTable = new InterfaceImplRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.InterfaceImpl];
for (int i = 0; i < n; i++)
{
InterfaceImplRow row;
row.Class = c.ReadReference(this.tableRefSize[(int)TableIndices.TypeDef]);
row.Interface = c.ReadReference(this.typeDefOrRefOrSpecSize);
result[i] = row;
}
}
private void ReadManifestResourceTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
{
int n = this.tableSize[(int)TableIndices.ManifestResource];
ManifestResourceRow[] result = this.manifestResourceTable = new ManifestResourceRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.ManifestResource];
for (int i = 0; i < n; i++)
{
ManifestResourceRow row;
row.Offset = c.ReadInt32();
row.Flags = c.ReadInt32();
row.Name = c.ReadReference(this.stringRefSize);
row.Implementation = c.ReadReference(this.implementationRefSize);
result[i] = row;
}
}
private void ReadMemberRefTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
{
int n = this.tableSize[(int)TableIndices.MemberRef];
MemberRefRow[] result = this.memberRefTable = new MemberRefRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.MemberRef];
for (int i = 0; i < n; i++)
{
MemberRefRow row;
row.Class = c.ReadReference(this.memberRefParentSize);
row.Name = c.ReadReference(this.stringRefSize);
row.Signature = c.ReadReference(this.blobRefSize);
row.Member = null;
row.VarargTypes = null;
result[i] = row;
}
}
private void ReadMethodTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.Method];
MethodRow[] result = this.methodTable = new MethodRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.Method];
for (int i = 0; i < n; i++)
{
MethodRow row;
row.RVA = c.ReadInt32();
row.ImplFlags = c.ReadUInt16();
row.Flags = c.ReadUInt16();
row.Name = c.ReadReference(this.stringRefSize);
row.Signature = c.ReadReference(this.blobRefSize);
row.ParamList = c.ReadReference(this.tableRefSize[(int)TableIndices.Param]);
row.Method = null;
result[i] = row;
}
}
private void ReadMethodImplTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.MethodImpl];
MethodImplRow[] result = this.methodImplTable = new MethodImplRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.MethodImpl];
for (int i = 0; i < n; i++)
{
MethodImplRow row;
row.Class = c.ReadReference(this.tableRefSize[(int)TableIndices.TypeDef]);
row.MethodBody = c.ReadReference(this.methodDefOrRefSize);
row.MethodDeclaration = c.ReadReference(this.methodDefOrRefSize);
result[i] = row;
}
}
private void ReadMethodPtrTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.MethodPtr];
MethodPtrRow[] result = this.methodPtrTable = new MethodPtrRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.MethodPtr];
for (int i = 0; i < n; i++)
{
MethodPtrRow row;
row.Method = c.ReadReference(this.tableRefSize[(int)TableIndices.Method]);
result[i] = row;
}
}
private void ReadMethodSemanticsTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.MethodSemantics];
MethodSemanticsRow[] result = this.methodSemanticsTable = new MethodSemanticsRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.MethodSemantics];
for (int i = 0; i < n; i++)
{
MethodSemanticsRow row;
row.Semantics = c.ReadUInt16();
row.Method = c.ReadReference(this.tableRefSize[(int)TableIndices.Method]);
row.Association = c.ReadReference(this.hasSemanticRefSize);
result[i] = row;
}
}
private void ReadMethodSpecTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
{
int n = this.tableSize[(int)TableIndices.MethodSpec];
MethodSpecRow[] result = this.methodSpecTable = new MethodSpecRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.MethodSpec];
for (int i = 0; i < n; i++)
{
MethodSpecRow row;
row.Method = c.ReadReference(this.methodDefOrRefSize);
row.Instantiation = c.ReadReference(this.blobRefSize);
row.InstantiatedMethod = null;
result[i] = row;
}
}
private void ReadModuleTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
{
int n = this.tableSize[(int)TableIndices.Module];
ModuleRow[] result = this.moduleTable = new ModuleRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.Module];
for (int i = 0; i < n; i++)
{
ModuleRow row;
row.Generation = c.ReadUInt16();
row.Name = c.ReadReference(this.stringRefSize);
row.Mvid = c.ReadReference(this.guidRefSize);
row.EncId = c.ReadReference(this.guidRefSize);
row.EncBaseId = c.ReadReference(this.guidRefSize);
result[i] = row;
}
}
private void ReadModuleRefTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
{
int n = this.tableSize[(int)TableIndices.ModuleRef];
ModuleRefRow[] result = this.moduleRefTable = new ModuleRefRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.ModuleRef];
for (int i = 0; i < n; i++)
{
ModuleRefRow row;
row.Name = c.ReadReference(this.stringRefSize);
row.Module = null;
result[i] = row;
}
}
private void ReadNestedClassTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.NestedClass];
NestedClassRow[] result = this.nestedClassTable = new NestedClassRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.NestedClass];
for (int i = 0; i < n; i++)
{
NestedClassRow row;
row.NestedClass = c.ReadReference(this.tableRefSize[(int)TableIndices.TypeDef]);
row.EnclosingClass = c.ReadReference(this.tableRefSize[(int)TableIndices.TypeDef]);
result[i] = row;
}
}
private void ReadParamTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
{
int n = this.tableSize[(int)TableIndices.Param];
ParamRow[] result = this.paramTable = new ParamRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.Param];
for (int i = 0; i < n; i++)
{
ParamRow row;
row.Flags = c.ReadUInt16();
row.Sequence = c.ReadUInt16();
row.Name = c.ReadReference(this.stringRefSize);
result[i] = row;
}
}
private void ReadParamPtrTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.ParamPtr];
ParamPtrRow[] result = this.paramPtrTable = new ParamPtrRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.ParamPtr];
for (int i = 0; i < n; i++)
{
ParamPtrRow row;
row.Param = c.ReadReference(this.tableRefSize[(int)TableIndices.Param]);
result[i] = row;
}
}
private void ReadPropertyTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
{
int n = this.tableSize[(int)TableIndices.Property];
PropertyRow[] result = this.propertyTable = new PropertyRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.Property];
for (int i = 0; i < n; i++)
{
PropertyRow row;
row.Flags = c.ReadUInt16();
row.Name = c.ReadReference(this.stringRefSize);
row.Signature = c.ReadReference(this.blobRefSize);
result[i] = row;
}
}
private void ReadPropertyMapTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.PropertyMap];
PropertyMapRow[] result = this.propertyMapTable = new PropertyMapRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.PropertyMap];
for (int i = 0; i < n; i++)
{
PropertyMapRow row;
row.Parent = c.ReadReference(this.tableRefSize[(int)TableIndices.TypeDef]);
row.PropertyList = c.ReadReference(this.tableRefSize[(int)TableIndices.Property]);
result[i] = row;
}
}
private void ReadPropertyPtrTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.PropertyPtr];
PropertyPtrRow[] result = this.propertyPtrTable = new PropertyPtrRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.PropertyPtr];
for (int i = 0; i < n; i++)
{
PropertyPtrRow row;
row.Property = c.ReadReference(this.tableRefSize[(int)TableIndices.Property]);
result[i] = row;
}
}
private void ReadStandAloneSigTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
{
int n = this.tableSize[(int)TableIndices.StandAloneSig];
StandAloneSigRow[] result = this.standAloneSigTable = new StandAloneSigRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.StandAloneSig];
for (int i = 0; i < n; i++)
{
StandAloneSigRow row;
row.Signature = c.ReadReference(this.blobRefSize);
result[i] = row;
}
}
private void ReadTypeDefTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.TypeDef];
TypeDefRow[] result = this.typeDefTable = new TypeDefRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.TypeDef];
for (int i = 0; i < n; i++)
{
TypeDefRow row;
row.Flags = c.ReadInt32();
row.Name = c.ReadReference(this.stringRefSize);
row.Namespace = c.ReadReference(this.stringRefSize);
row.Extends = c.ReadReference(this.typeDefOrRefOrSpecSize);
row.FieldList = c.ReadReference(this.tableRefSize[(int)TableIndices.Field]);
row.MethodList = c.ReadReference(this.tableRefSize[(int)TableIndices.Method]);
row.Type = null;
row.NameKey = 0;
row.NamespaceId = null;
row.NamespaceKey = 0;
result[i] = row;
}
for (int i = 0; i < n; i++)
{
result[i].NameKey = this.GetIdentifier(result[i].Name).UniqueIdKey;
result[i].NamespaceId = this.GetIdentifier(result[i].Namespace);
//^ assume result[i].NamespaceId != null;
result[i].NamespaceKey = result[i].NamespaceId.UniqueIdKey;
}
}
private void ReadTypeRefTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
{
int n = this.tableSize[(int)TableIndices.TypeRef];
TypeRefRow[] result = this.typeRefTable = new TypeRefRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.TypeRef];
for (int i = 0; i < n; i++)
{
TypeRefRow row;
row.ResolutionScope = c.ReadReference(this.resolutionScopeRefSize);
row.Name = c.ReadReference(this.stringRefSize);
row.Namespace = c.ReadReference(this.stringRefSize);
row.Type = null;
result[i] = row;
}
}
private void ReadTypeSpecTable()
//^ requires this.tableSize != null;
//^ requires this.tableOffset != null;
{
int n = this.tableSize[(int)TableIndices.TypeSpec];
TypeSpecRow[] result = this.typeSpecTable = new TypeSpecRow[n];
if (n == 0) return;
MemoryCursor c = this.cursor;
c.Position = this.tableOffset[(int)TableIndices.TypeSpec];
for (int i = 0; i < n; i++)
{
TypeSpecRow row;
row.Signature = c.ReadReference(this.blobRefSize);
row.Type = null;
result[i] = row;
}
}
internal int GetOffsetToEndOfSection(int virtualAddress)
{
foreach (SectionHeader section in this.sectionHeaders)
if (virtualAddress >= section.virtualAddress && virtualAddress < section.virtualAddress + section.sizeOfRawData)
return (section.sizeOfRawData - (virtualAddress - section.virtualAddress));
return -1;
}
internal bool NoOffsetFor(int virtualAddress)
{
foreach (SectionHeader section in this.sectionHeaders)
if (virtualAddress >= section.virtualAddress && virtualAddress < section.virtualAddress + section.sizeOfRawData)
return false;
return true;
}
private int RvaToOffset(int virtualAddress)
{
foreach (SectionHeader section in this.sectionHeaders)
if (virtualAddress >= section.virtualAddress && virtualAddress < section.virtualAddress + section.sizeOfRawData)
return (virtualAddress - section.virtualAddress + section.pointerToRawData);
throw new InvalidMetadataException(String.Format(CultureInfo.CurrentCulture,
ExceptionStrings.UnknownVirtualAddress, virtualAddress));
}
private int RvaToOffset(int virtualAddress, out PESection targetSection)
{
foreach (SectionHeader section in this.sectionHeaders)
if (virtualAddress >= section.virtualAddress && virtualAddress < section.virtualAddress + section.sizeOfRawData)
{
if (section.name == ".tls") targetSection = PESection.TLS;
else if (section.name == ".sdata") targetSection = PESection.SData;
else targetSection = PESection.Text;
return (virtualAddress - section.virtualAddress + section.pointerToRawData);
}
throw new InvalidMetadataException(String.Format(
CultureInfo.CurrentCulture, ExceptionStrings.UnknownVirtualAddress, +virtualAddress));
}
private static CLIHeader/*!*/ ReadCLIHeader(MemoryCursor/*!*/ c)
{
CLIHeader header = new CLIHeader();
header.cb = c.Int32(0); c.SkipInt32(1);
header.majorRuntimeVersion = c.UInt16(0);
header.minorRuntimeVersion = c.UInt16(1); c.SkipUInt16(2);
header.metaData = ReadDirectoryEntry(c);
header.flags = c.Int32(0);
header.entryPointToken = c.Int32(1); c.SkipInt32(2);
header.resources = ReadDirectoryEntry(c);
header.strongNameSignature = ReadDirectoryEntry(c);
header.codeManagerTable = ReadDirectoryEntry(c);
header.vtableFixups = ReadDirectoryEntry(c);
header.exportAddressTableJumps = ReadDirectoryEntry(c);
if (header.majorRuntimeVersion < 2)
throw new InvalidMetadataException(ExceptionStrings.BadCLIHeader);
return header;
}
private static DirectoryEntry ReadDirectoryEntry(MemoryCursor/*!*/ c)
{
DirectoryEntry entry = new DirectoryEntry();
entry.virtualAddress = c.Int32(0);
entry.size = c.Int32(1); c.SkipInt32(2);
return entry;
}
internal static void ReadDOSHeader(MemoryCursor/*!*/ c)
{
c.Position = 0;
int magicNumber = c.UInt16(0);
if (magicNumber != 0x5a4d) throw new InvalidMetadataException(ExceptionStrings.BadMagicNumber);
c.Position = 0x3c;
int ntHeaderOffset = c.Int32(0);
c.Position = ntHeaderOffset;
}
private static MetadataHeader/*!*/ ReadMetadataHeader(MemoryCursor/*!*/ c)
{
MetadataHeader header = new MetadataHeader();
header.signature = c.ReadInt32();
if (header.signature != 0x424a5342)
throw new InvalidMetadataException(ExceptionStrings.BadMetadataHeaderSignature);
header.majorVersion = c.ReadUInt16();
header.minorVersion = c.ReadUInt16();
header.reserved = c.ReadInt32();
int len = c.ReadInt32();
header.versionString = c.ReadASCII(len);
while (len++ % 4 != 0) c.ReadByte();
header.flags = c.ReadUInt16();
int n = c.ReadUInt16();
StreamHeader[] streamHeaders = header.streamHeaders = new StreamHeader[n];
for (int i = 0; i < n; i++)
streamHeaders[i] = ReadStreamHeader(c);
return header;
}
internal static NTHeader/*!*/ ReadNTHeader(MemoryCursor/*!*/ c)
{
NTHeader header = new NTHeader();
header.signature = c.ReadInt32();
header.machine = c.ReadUInt16();
header.numberOfSections = c.ReadUInt16();
header.timeDateStamp = c.ReadInt32();
header.pointerToSymbolTable = c.ReadInt32();
header.numberOfSymbols = c.ReadInt32();
header.sizeOfOptionalHeader = c.ReadUInt16();
header.characteristics = c.ReadUInt16();
header.magic = c.ReadUInt16();
header.majorLinkerVersion = c.ReadByte();
header.minorLinkerVersion = c.ReadByte();
header.sizeOfCode = c.ReadInt32();
header.sizeOfInitializedData = c.ReadInt32();
header.sizeOfUninitializedData = c.ReadInt32();
header.addressOfEntryPoint = c.ReadInt32();
header.baseOfCode = c.ReadInt32();
if (header.magic == 0x10B)
{
header.baseOfData = c.ReadInt32();
header.imageBase = c.ReadInt32();
}
else
{
header.baseOfData = 0;
header.imageBase = c.ReadInt64();
}
header.sectionAlignment = c.ReadInt32();
header.fileAlignment = c.ReadInt32();
header.majorOperatingSystemVersion = c.ReadUInt16();
header.minorOperatingSystemVersion = c.ReadUInt16();
header.majorImageVersion = c.ReadUInt16();
header.minorImageVersion = c.ReadUInt16();
header.majorSubsystemVersion = c.ReadUInt16();
header.minorSubsystemVersion = c.ReadUInt16();
header.win32VersionValue = c.ReadInt32();
header.sizeOfImage = c.ReadInt32();
header.sizeOfHeaders = c.ReadInt32();
header.checkSum = c.ReadInt32();
header.subsystem = c.ReadUInt16();
header.dllCharacteristics = c.ReadUInt16();
if (header.magic == 0x10B)
{
header.sizeOfStackReserve = c.ReadInt32();
header.sizeOfStackCommit = c.ReadInt32();
header.sizeOfHeapReserve = c.ReadInt32();
header.sizeOfHeapCommit = c.ReadInt32();
}
else
{
header.sizeOfStackReserve = c.ReadInt64();
header.sizeOfStackCommit = c.ReadInt64();
header.sizeOfHeapReserve = c.ReadInt64();
header.sizeOfHeapCommit = c.ReadInt64();
}
header.loaderFlags = c.ReadInt32();
header.numberOfDataDirectories = c.ReadInt32();
// Verify that the header signature and magic number are valid
if (header.signature != 0x00004550 /* "PE\0\0" */)
throw new InvalidMetadataException(ExceptionStrings.BadCOFFHeaderSignature);
if (header.magic != 0x010B && header.magic != 0x020B)
throw new InvalidMetadataException(ExceptionStrings.BadPEHeaderMagicNumber);
//Read the data directories
header.exportTable = ReadDirectoryEntry(c);
header.importTable = ReadDirectoryEntry(c);
header.resourceTable = ReadDirectoryEntry(c);
header.exceptionTable = ReadDirectoryEntry(c);
header.certificateTable = ReadDirectoryEntry(c);
header.baseRelocationTable = ReadDirectoryEntry(c);
header.debugTable = ReadDirectoryEntry(c);
header.copyrightTable = ReadDirectoryEntry(c);
header.globalPointerTable = ReadDirectoryEntry(c);
header.threadLocalStorageTable = ReadDirectoryEntry(c);
header.loadConfigTable = ReadDirectoryEntry(c);
header.boundImportTable = ReadDirectoryEntry(c);
header.importAddressTable = ReadDirectoryEntry(c);
header.delayImportTable = ReadDirectoryEntry(c);
header.cliHeaderTable = ReadDirectoryEntry(c);
header.reserved = ReadDirectoryEntry(c);
return header;
}
internal static SectionHeader ReadSectionHeader(MemoryCursor/*!*/ c)
{
SectionHeader header = new SectionHeader();
header.name = c.ReadASCII(8);
header.virtualSize = c.Int32(0);
header.virtualAddress = c.Int32(1);
header.sizeOfRawData = c.Int32(2);
header.pointerToRawData = c.Int32(3);
header.pointerToRelocations = c.Int32(4);
header.pointerToLinenumbers = c.Int32(5); c.SkipInt32(6);
header.numberOfRelocations = c.UInt16(0);
header.numberOfLinenumbers = c.UInt16(1); c.SkipInt16(2);
header.characteristics = c.Int32(0); c.SkipInt32(1);
return header;
}
private static StreamHeader ReadStreamHeader(MemoryCursor/*!*/ c)
{
StreamHeader header = new StreamHeader();
header.offset = c.ReadInt32();
header.size = c.ReadInt32();
header.name = c.ReadASCII();
int n = header.name.Length + 1;
c.Position += (4 - (n % 4)) % 4;
return header;
}
private static TablesHeader/*!*/ ReadTablesHeader(MemoryCursor/*!*/ c)
{
TablesHeader header = new TablesHeader();
header.reserved = c.ReadInt32(); // Must be zero
header.majorVersion = c.ReadByte(); // Must be one
header.minorVersion = c.ReadByte(); // Must be zero
header.heapSizes = c.ReadByte(); // Bits for heap sizes
header.rowId = c.ReadByte(); // log-base-2 of largest rowId
header.maskValid = c.ReadInt64(); // Present table counts
header.maskSorted = c.ReadInt64(); // Sorted tables
int n = 0;
ulong mask = (ulong)header.maskValid;
while (mask != 0)
{
if (mask % 2 == 1) n++;
mask /= 2;
}
int[] countArray = header.countArray = new int[n];
for (int i = 0; i < n; i++)
countArray[i] = c.ReadInt32();
return header;
}
}
#if !NoWriter
internal class MetadataWriter
{
internal MemoryStream StringHeap;
internal MemoryStream BlobHeap;
internal MemoryStream UserstringHeap;
internal MemoryStream ResourceDataHeap;
internal MemoryStream SdataHeap;
internal MemoryStream TlsHeap;
internal Guid[] GuidHeap;
internal MemoryStream MethodBodiesHeap;
internal Win32ResourceList Win32Resources;
internal AssemblyRow[] assemblyTable;
internal AssemblyRefRow[] assemblyRefTable;
internal ClassLayoutRow[] classLayoutTable;
internal ConstantRow[] constantTable;
internal CustomAttributeRow[] customAttributeTable;
internal DeclSecurityRow[] declSecurityTable;
internal EventMapRow[] eventMapTable;
internal EventRow[] eventTable;
internal ExportedTypeRow[] exportedTypeTable = null;
internal FieldRow[] fieldTable;
internal FieldLayoutRow[] fieldLayoutTable;
internal FieldMarshalRow[] fieldMarshalTable = null;
internal FieldRvaRow[] fieldRvaTable = null;
internal FileRow[] fileTable;
internal GenericParamRow[] genericParamTable;
internal GenericParamConstraintRow[] genericParamConstraintTable;
internal ImplMapRow[] implMapTable;
internal InterfaceImplRow[] interfaceImplTable;
internal ManifestResourceRow[] manifestResourceTable = null;
internal MemberRefRow[] memberRefTable;
internal MethodRow[] methodTable;
internal MethodImplRow[] methodImplTable;
internal MethodSemanticsRow[] methodSemanticsTable;
internal MethodSpecRow[] methodSpecTable;
internal ModuleRow[] moduleTable;
internal ModuleRefRow[] moduleRefTable;
internal NestedClassRow[] nestedClassTable;
internal ParamRow[] paramTable;
internal PropertyRow[] propertyTable;
internal PropertyMapRow[] propertyMapTable;
internal StandAloneSigRow[] standAloneSigTable;
internal TypeDefRow[] typeDefTable;
internal TypeRefRow[] typeRefTable;
internal TypeSpecRow[] typeSpecTable;
internal int entryPointToken;
internal int fileAlignment;
internal ModuleKindFlags moduleKind;
internal PEKindFlags peKind;
internal bool TrackDebugData;
internal bool UseGenerics = false;
internal byte[] PublicKey;
private int blobRefSize;
private int constantParentRefSize;
private int customAttributeParentRefSize;
private int customAttributeConstructorRefSize;
private int declSecurityParentRefSize;
private int fieldMarshalParentRefSize;
private int guidRefSize;
private int hasSemanticRefSize;
private int implementationRefSize;
private int methodDefOrRefSize;
private int memberRefParentSize;
private int memberForwardedRefSize;
private int typeDefOrMethodDefSize;
private int typeDefOrRefOrSpecSize;
private int resolutionScopeRefSize;
private int stringRefSize;
#if !ROTOR
private ISymUnmanagedWriter symWriter;
#endif
private int[] tableRefSize;
private int[] tableSize;
private long validMask;
#if !ROTOR
internal MetadataWriter(ISymUnmanagedWriter symWriter)
{
this.symWriter = symWriter;
}
#else
internal MetadataWriter(){
}
#endif
private void SerializeMetadata(BinaryWriter/*!*/ writer, int virtualAddressBase, Fixup/*!*/ sdataFixup, Fixup/*!*/ tlsFixup)
//^ requires this.MethodBodiesHeap != null;
//^ requires this.ResourceDataHeap != null;
//^ requires this.StringHeap != null;
//^ requires this.UserstringHeap != null;
//^ requires this.BlobHeap != null;
//^ requires this.GuidHeap != null;
//^ requires TargetPlatform.TargetRuntimeVersion != null;
{
int tableOffset = 0;
tableOffset += (int)this.MethodBodiesHeap.Length;
this.MethodBodiesHeap.WriteTo(writer.BaseStream);
while (tableOffset % 4 != 0) { writer.Write((byte)0); tableOffset++; }
if (this.PublicKey != null && 0 < this.PublicKey.Length)
{
this.cliHeader.strongNameSignature.virtualAddress = virtualAddressBase + 72 + tableOffset;
int keysize = this.PublicKey.Length - 32;
if (keysize < 128) keysize = 128;
this.cliHeader.strongNameSignature.size = keysize;
tableOffset += keysize;
writer.BaseStream.Position += keysize;
}
if (this.ResourceDataHeap.Length > 0)
{
this.cliHeader.resources.virtualAddress = virtualAddressBase + 72 + tableOffset;
this.ResourceDataHeap.WriteTo(writer.BaseStream);
int sizeOfResources = (int)this.ResourceDataHeap.Length;
while (sizeOfResources % 4 != 0) { writer.Write((byte)0); sizeOfResources++; }
this.cliHeader.resources.size = sizeOfResources;
tableOffset += sizeOfResources;
}
this.cliHeader.metaData.virtualAddress = virtualAddressBase + 72 + tableOffset;
int startPos = (int)writer.BaseStream.Position;
writer.Write((int)0x424a5342); //Magic signature
writer.Write((short)1); //Major version
writer.Write((short)1); //Minor version
writer.Write((int)0); //Reserved
writer.Write((int)12); // version must be 12 chars
char[] version = new char[12];
char[] aversion = TargetPlatform.TargetRuntimeVersion.ToCharArray();
Array.Copy(aversion, 0, version, 0, Math.Min(12, aversion.Length));
writer.Write(version);
writer.Write((short)0); //flags
writer.Write((short)5); //number of streams
int offsetFromStartOfMetadata = 108;
writer.Write((int)offsetFromStartOfMetadata);
int cbStringHeapPad = 0;
offsetFromStartOfMetadata += (int)this.StringHeap.Length;
while (offsetFromStartOfMetadata % 4 != 0)
{
offsetFromStartOfMetadata++;
cbStringHeapPad++;
}
writer.Write((int)this.StringHeap.Length + cbStringHeapPad);
writer.Write(new char[] { '#', 'S', 't', 'r', 'i', 'n', 'g', 's', '\0', '\0', '\0', '\0' });
writer.Write((int)offsetFromStartOfMetadata);
offsetFromStartOfMetadata += (int)this.UserstringHeap.Length;
int cbUserStringHeapPad = 0;
while (offsetFromStartOfMetadata % 4 != 0)
{
offsetFromStartOfMetadata++;
cbUserStringHeapPad++;
}
writer.Write((int)this.UserstringHeap.Length + cbUserStringHeapPad);
writer.Write(new char[] { '#', 'U', 'S', '\0' });
writer.Write((int)offsetFromStartOfMetadata);
writer.Write((int)this.BlobHeap.Length);
writer.Write(new char[] { '#', 'B', 'l', 'o', 'b', '\0', '\0', '\0' });
offsetFromStartOfMetadata += (int)this.BlobHeap.Length;
while (offsetFromStartOfMetadata % 4 != 0) offsetFromStartOfMetadata++;
writer.Write((int)offsetFromStartOfMetadata);
writer.Write((int)this.GuidHeap.Length * 16);
writer.Write(new char[] { '#', 'G', 'U', 'I', 'D', '\0', '\0', '\0' });
offsetFromStartOfMetadata += this.GuidHeap.Length * 16;
writer.Write((int)offsetFromStartOfMetadata);
int tabsL = this.TablesLength();
writer.Write((int)tabsL);
writer.Write(new char[] { '#', '~', '\0', '\0' });
this.StringHeap.WriteTo(writer.BaseStream);
int p = (int)this.StringHeap.Length;// +cbStringHeapPad;
while (p % 4 != 0) { writer.Write((byte)0); p++; }
this.UserstringHeap.WriteTo(writer.BaseStream);
p = (int)this.UserstringHeap.Length;// +cbUserStringHeapPad;
while (p % 4 != 0) { writer.Write((byte)0); p++; }
this.BlobHeap.WriteTo(writer.BaseStream);
p = (int)this.BlobHeap.Length;
while (p % 4 != 0) { writer.Write((byte)0); p++; }
for (int i = 0, n = this.GuidHeap.Length; i < n; i++)
writer.Write(this.GuidHeap[i].ToByteArray());
this.SerializeTables(writer, virtualAddressBase + 72, sdataFixup, tlsFixup);
this.cliHeader.metaData.size = ((int)writer.BaseStream.Position) - startPos;
}
#if !ROTOR
private unsafe void WriteReferenceToPDBFile(BinaryWriter/*!*/ writer, int virtualAddressBase, int fileBase)
//^ requires this.symWriter != null;
{
int startPos = writer.BaseStream.Position;
this.ntHeader.debugTable.virtualAddress = startPos - fileBase + virtualAddressBase;
this.ntHeader.debugTable.size = 28;
ImageDebugDirectory debugDir = new ImageDebugDirectory(true);
uint pcData = 0;
this.symWriter.GetDebugInfo(ref debugDir, 0, out pcData, IntPtr.Zero);
byte[] data = new byte[pcData];
fixed (byte* pb = data)
{
this.symWriter.GetDebugInfo(ref debugDir, pcData, out pcData, (IntPtr)pb);
}
writer.Write((int)debugDir.Characteristics);
writer.Write(this.ntHeader.timeDateStamp);
writer.Write((ushort)debugDir.MajorVersion);
writer.Write((ushort)debugDir.MinorVersion);
writer.Write((int)debugDir.Type);
writer.Write((int)debugDir.SizeOfData);
writer.Write((int)startPos + 28 - fileBase + virtualAddressBase); //AddressOfRawData
writer.Write((int)startPos + 28); //PointerToRawData
writer.Write((byte[])data);
}
#endif
private void SerializeTables(BinaryWriter/*!*/ writer, int mbRVAOffset, Fixup/*!*/ sdataFixup, Fixup/*!*/ tlsFixup)
//^ requires this.StringHeap != null;
//^ requires this.GuidHeap != null;
//^ requires this.BlobHeap != null;
//^ requires this.tableSize != null;
//^ requires this.tableRefSize != null;
{
writer.Write((int)0); //Reserved
writer.Write((byte)TargetPlatform.MajorVersion);
writer.Write((byte)TargetPlatform.MinorVersion);
byte heapSizes = 0;
if (this.StringHeap.Length >= 0x10000) heapSizes |= 0x01;
if (this.GuidHeap.Length >= 0x10000) heapSizes |= 0x02;
if (this.BlobHeap.Length >= 0x10000) heapSizes |= 0x04;
writer.Write(heapSizes);
writer.Write((byte)0); //Reserved
writer.Write(this.validMask); //Tables that are present
if (this.UseGenerics)
writer.Write((long)0x16003301fa00); //Tables that are sorted
else
writer.Write((long)0x02003301fa00); //Tables that are sorted
int[] tableSize = this.tableSize;
for (int i = 0, n = 0; i < (int)TableIndices.Count; i++)
if ((n = tableSize[i]) > 0) writer.Write(n);
if (this.moduleTable != null) this.SerializeModuleTable(writer);
if (this.typeRefTable != null) this.SerializeTypeRefTable(writer);
if (this.typeDefTable != null) this.SerializeTypeDefTable(writer);
if (this.fieldTable != null) this.SerializeFieldTable(writer);
if (this.methodTable != null) this.SerializeMethodTable(writer, mbRVAOffset);
if (this.paramTable != null) this.SerializeParamTable(writer);
if (this.interfaceImplTable != null) this.SerializeInterfaceImplTable(writer);
if (this.memberRefTable != null) this.SerializeMemberRefTable(writer);
if (this.constantTable != null) this.SerializeConstantTable(writer);
if (this.customAttributeTable != null) this.SerializeCustomAttributeTable(writer);
if (this.fieldMarshalTable != null) this.SerializeFieldMarshalTable(writer);
if (this.declSecurityTable != null) this.SerializeDeclSecurityTable(writer);
if (this.classLayoutTable != null) this.SerializeClassLayoutTable(writer);
if (this.fieldLayoutTable != null) this.SerializeFieldLayoutTable(writer);
if (this.standAloneSigTable != null) this.SerializeStandAloneSigTable(writer);
if (this.eventMapTable != null) this.SerializeEventMapTable(writer);
if (this.eventTable != null) this.SerializeEventTable(writer);
if (this.propertyMapTable != null) this.SerializePropertyMapTable(writer);
if (this.propertyTable != null) this.SerializePropertyTable(writer);
if (this.methodSemanticsTable != null) this.SerializeMethodSemanticsTable(writer);
if (this.methodImplTable != null) this.SerializeMethodImplTable(writer);
if (this.moduleRefTable != null) this.SerializeModuleRefTable(writer);
if (this.typeSpecTable != null) this.SerializeTypeSpecTable(writer);
if (this.implMapTable != null) this.SerializeImplMapTable(writer);
if (this.fieldRvaTable != null) this.SerializeFieldRvaTable(writer, mbRVAOffset, sdataFixup, tlsFixup);
if (this.assemblyTable != null) this.SerializeAssemblyTable(writer);
if (this.assemblyRefTable != null) this.SerializeAssemblyRefTable(writer);
if (this.fileTable != null) this.SerializeFileTable(writer);
if (this.exportedTypeTable != null) this.SerializeExportedTypeTable(writer);
if (this.manifestResourceTable != null) this.SerializeManifestResourceTable(writer);
if (this.nestedClassTable != null) this.SerializeNestedClassTable(writer);
if (this.genericParamTable != null) this.SerializeGenericParamTable(writer);
if (this.methodSpecTable != null) this.SerializeMethodSpecTable(writer);
if (this.genericParamConstraintTable != null) this.SerializeGenericParamConstraintTable(writer);
}
private void SerializeAssemblyTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.assemblyTable != null;
{
int n = this.tableSize[(int)TableIndices.Assembly];
for (int i = 0; i < n; i++)
{
AssemblyRow row = this.assemblyTable[i];
writer.Write((int)row.HashAlgId);
writer.Write((short)row.MajorVersion);
writer.Write((short)row.MinorVersion);
writer.Write((short)row.BuildNumber);
writer.Write((short)row.RevisionNumber);
writer.Write((int)row.Flags);
this.WriteReference(writer, row.PublicKey, this.blobRefSize);
this.WriteReference(writer, row.Name, this.stringRefSize);
this.WriteReference(writer, row.Culture, this.stringRefSize);
}
}
private void SerializeAssemblyRefTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.assemblyRefTable != null;
{
int n = this.tableSize[(int)TableIndices.AssemblyRef];
for (int i = 0; i < n; i++)
{
AssemblyRefRow row = this.assemblyRefTable[i];
writer.Write((short)row.MajorVersion);
writer.Write((short)row.MinorVersion);
writer.Write((short)row.BuildNumber);
writer.Write((short)row.RevisionNumber);
writer.Write((int)row.Flags);
this.WriteReference(writer, row.PublicKeyOrToken, this.blobRefSize);
this.WriteReference(writer, row.Name, this.stringRefSize);
this.WriteReference(writer, row.Culture, this.stringRefSize);
this.WriteReference(writer, row.HashValue, this.blobRefSize);
}
}
private void SerializeClassLayoutTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.classLayoutTable != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.ClassLayout];
for (int i = 0; i < n; i++)
{
ClassLayoutRow row = this.classLayoutTable[i];
writer.Write((short)row.PackingSize);
writer.Write((int)row.ClassSize);
this.WriteReference(writer, row.Parent, this.tableRefSize[(int)TableIndices.TypeDef]);
}
}
private void SerializeConstantTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.constantTable != null;
{
int n = this.tableSize[(int)TableIndices.Constant];
for (int i = 0; i < n; i++)
{
ConstantRow row = this.constantTable[i];
writer.Write((byte)row.Type);
writer.Write((byte)0);
this.WriteReference(writer, row.Parent, this.constantParentRefSize);
this.WriteReference(writer, row.Value, this.blobRefSize);
}
}
private void SerializeCustomAttributeTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.customAttributeTable != null;
{
int n = this.tableSize[(int)TableIndices.CustomAttribute];
for (int i = 0; i < n; i++)
{
CustomAttributeRow row = this.customAttributeTable[i];
this.WriteReference(writer, row.Parent, this.customAttributeParentRefSize);
this.WriteReference(writer, row.Constructor, this.customAttributeConstructorRefSize);
this.WriteReference(writer, row.Value, this.blobRefSize);
}
}
private void SerializeDeclSecurityTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.declSecurityTable != null;
{
int n = this.tableSize[(int)TableIndices.DeclSecurity];
for (int i = 0; i < n; i++)
{
DeclSecurityRow row = this.declSecurityTable[i];
writer.Write((short)row.Action);
this.WriteReference(writer, row.Parent, this.declSecurityParentRefSize);
this.WriteReference(writer, row.PermissionSet, this.blobRefSize);
}
}
private void SerializeEventMapTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.eventMapTable != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.EventMap];
for (int i = 0; i < n; i++)
{
EventMapRow row = this.eventMapTable[i];
this.WriteReference(writer, row.Parent, this.tableRefSize[(int)TableIndices.TypeDef]);
this.WriteReference(writer, row.EventList, this.tableRefSize[(int)TableIndices.Event]);
}
}
private void SerializeEventTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.eventTable != null;
{
int n = this.tableSize[(int)TableIndices.Event];
for (int i = 0; i < n; i++)
{
EventRow row = this.eventTable[i];
writer.Write((short)row.Flags);
this.WriteReference(writer, row.Name, this.stringRefSize);
this.WriteReference(writer, row.EventType, this.typeDefOrRefOrSpecSize);
}
}
private void SerializeExportedTypeTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.exportedTypeTable != null;
{
int n = this.tableSize[(int)TableIndices.ExportedType];
for (int i = 0; i < n; i++)
{
ExportedTypeRow row = this.exportedTypeTable[i];
writer.Write((int)row.Flags);
writer.Write((int)row.TypeDefId);
this.WriteReference(writer, row.TypeName, this.stringRefSize);
this.WriteReference(writer, row.TypeNamespace, this.stringRefSize);
this.WriteReference(writer, row.Implementation, this.implementationRefSize);
}
}
private void SerializeFieldTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.fieldTable != null;
{
int n = this.tableSize[(int)TableIndices.Field];
for (int i = 0; i < n; i++)
{
FieldRow row = this.fieldTable[i];
writer.Write((short)row.Flags);
this.WriteReference(writer, row.Name, this.stringRefSize);
this.WriteReference(writer, row.Signature, this.blobRefSize);
}
}
private void SerializeFieldLayoutTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.fieldLayoutTable != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.FieldLayout];
for (int i = 0; i < n; i++)
{
FieldLayoutRow row = this.fieldLayoutTable[i];
writer.Write((int)row.Offset);
this.WriteReference(writer, row.Field, this.tableRefSize[(int)TableIndices.Field]);
}
}
private void SerializeFieldMarshalTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.fieldMarshalTable != null;
{
int n = this.tableSize[(int)TableIndices.FieldMarshal];
for (int i = 0; i < n; i++)
{
FieldMarshalRow row = this.fieldMarshalTable[i];
this.WriteReference(writer, row.Parent, this.fieldMarshalParentRefSize);
this.WriteReference(writer, row.NativeType, this.blobRefSize);
}
}
private void SerializeFieldRvaTable(BinaryWriter/*!*/ writer, int mbRVAOffset, Fixup/*!*/ sdataFixup, Fixup/*!*/ tlsFixup)
//^ requires this.tableSize != null;
//^ requires this.fieldRvaTable != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.FieldRva];
for (int i = 0; i < n; i++)
{
FieldRvaRow row = this.fieldRvaTable[i];
switch (row.TargetSection)
{
case PESection.SData:
case PESection.TLS:
Fixup fixup = new Fixup();
fixup.fixupLocation = writer.BaseStream.Position;
fixup.addressOfNextInstruction = row.RVA;
if (row.TargetSection == PESection.SData)
{
sdataFixup.nextFixUp = fixup;
sdataFixup = fixup;
}
else
{
sdataFixup.nextFixUp = fixup;
sdataFixup = fixup;
}
writer.Write((int)0);
break;
case PESection.Text:
writer.Write((int)row.RVA + mbRVAOffset);
break;
}
this.WriteReference(writer, row.Field, this.tableRefSize[(int)TableIndices.Field]);
}
}
private void SerializeFileTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.fileTable != null;
{
int n = this.tableSize[(int)TableIndices.File];
for (int i = 0; i < n; i++)
{
FileRow row = this.fileTable[i];
writer.Write((int)row.Flags);
this.WriteReference(writer, row.Name, this.stringRefSize);
this.WriteReference(writer, row.HashValue, this.blobRefSize);
}
}
private void SerializeGenericParamTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.genericParamTable != null;
{
int n = this.tableSize[(int)TableIndices.GenericParam];
bool reallyOldGenericsFileFormat = TargetPlatform.MajorVersion == 1 && TargetPlatform.MinorVersion == 0;
bool oldGenericsFileFormat = TargetPlatform.MajorVersion == 1 && TargetPlatform.MinorVersion == 1;
for (int i = 0; i < n; i++)
{
GenericParamRow row = this.genericParamTable[i];
writer.Write((short)row.Number);
writer.Write((short)row.Flags);
this.WriteReference(writer, row.Owner, this.typeDefOrMethodDefSize);
this.WriteReference(writer, row.Name, this.stringRefSize);
if (oldGenericsFileFormat) this.WriteReference(writer, 0, this.typeDefOrRefOrSpecSize);
if (reallyOldGenericsFileFormat) writer.Write((short)0);
}
}
private void SerializeGenericParamConstraintTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.genericParamConstraintTable != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.GenericParamConstraint];
for (int i = 0; i < n; i++)
{
GenericParamConstraintRow row = this.genericParamConstraintTable[i];
this.WriteReference(writer, row.Param, this.tableRefSize[(int)TableIndices.GenericParam]);
this.WriteReference(writer, row.Constraint, this.typeDefOrRefOrSpecSize);
}
}
private void SerializeImplMapTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.implMapTable != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.ImplMap];
for (int i = 0; i < n; i++)
{
ImplMapRow row = this.implMapTable[i];
writer.Write((short)row.MappingFlags);
this.WriteReference(writer, row.MemberForwarded, this.memberForwardedRefSize);
this.WriteReference(writer, row.ImportName, this.stringRefSize);
this.WriteReference(writer, row.ImportScope, this.tableRefSize[(int)TableIndices.ModuleRef]);
}
}
private void SerializeInterfaceImplTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.interfaceImplTable != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.InterfaceImpl];
for (int i = 0; i < n; i++)
{
InterfaceImplRow row = this.interfaceImplTable[i];
this.WriteReference(writer, row.Class, this.tableRefSize[(int)TableIndices.TypeDef]);
this.WriteReference(writer, row.Interface, this.typeDefOrRefOrSpecSize);
}
}
private void SerializeManifestResourceTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.manifestResourceTable != null;
{
int n = this.tableSize[(int)TableIndices.ManifestResource];
for (int i = 0; i < n; i++)
{
ManifestResourceRow row = this.manifestResourceTable[i];
writer.Write((int)row.Offset);
writer.Write((int)row.Flags);
this.WriteReference(writer, row.Name, this.stringRefSize);
this.WriteReference(writer, row.Implementation, this.implementationRefSize);
}
}
private void SerializeMemberRefTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.memberRefTable != null;
{
int n = this.tableSize[(int)TableIndices.MemberRef];
for (int i = 0; i < n; i++)
{
MemberRefRow row = this.memberRefTable[i];
this.WriteReference(writer, row.Class, this.memberRefParentSize);
this.WriteReference(writer, row.Name, this.stringRefSize);
this.WriteReference(writer, row.Signature, this.blobRefSize);
}
}
private void SerializeMethodTable(BinaryWriter/*!*/ writer, int mbRVAOffset)
//^ requires this.tableSize != null;
//^ requires this.methodTable != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.Method];
int pn = this.paramTable == null ? 1 : this.paramTable.Length + 1;
for (int i = n - 1; i >= 0; i--)
{
MethodRow row = this.methodTable[i];
if (row.ParamList != 0) pn = row.ParamList; else this.methodTable[i].ParamList = pn;
}
for (int i = 0; i < n; i++)
{
MethodRow row = this.methodTable[i];
if (row.RVA < 0)
writer.Write((int)0);
else
writer.Write((int)row.RVA + mbRVAOffset);
writer.Write((short)row.ImplFlags);
writer.Write((short)row.Flags);
this.WriteReference(writer, row.Name, this.stringRefSize);
this.WriteReference(writer, row.Signature, this.blobRefSize);
this.WriteReference(writer, row.ParamList, this.tableRefSize[(int)TableIndices.Param]);
}
}
private void SerializeMethodImplTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.methodImplTable != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.MethodImpl];
for (int i = 0; i < n; i++)
{
MethodImplRow row = this.methodImplTable[i];
this.WriteReference(writer, row.Class, this.tableRefSize[(int)TableIndices.TypeDef]);
this.WriteReference(writer, row.MethodBody, this.methodDefOrRefSize);
this.WriteReference(writer, row.MethodDeclaration, this.methodDefOrRefSize);
}
}
private void SerializeMethodSemanticsTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.methodSemanticsTable != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.MethodSemantics];
for (int i = 0; i < n; i++)
{
MethodSemanticsRow row = this.methodSemanticsTable[i];
writer.Write((short)row.Semantics);
this.WriteReference(writer, row.Method, this.tableRefSize[(int)TableIndices.Method]);
this.WriteReference(writer, row.Association, this.hasSemanticRefSize);
}
}
private void SerializeMethodSpecTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.assemblyTable != null;
//^ requires this.methodSpecTable != null;
{
int n = this.tableSize[(int)TableIndices.MethodSpec];
for (int i = 0; i < n; i++)
{
MethodSpecRow row = this.methodSpecTable[i];
this.WriteReference(writer, row.Method, this.methodDefOrRefSize);
this.WriteReference(writer, row.Instantiation, this.blobRefSize);
}
}
private void SerializeModuleTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.moduleTable != null;
{
int n = this.tableSize[(int)TableIndices.Module];
for (int i = 0; i < n; i++)
{
ModuleRow row = this.moduleTable[i];
writer.Write((short)row.Generation);
this.WriteReference(writer, row.Name, this.stringRefSize);
this.WriteReference(writer, row.Mvid, this.guidRefSize);
this.WriteReference(writer, row.EncId, this.guidRefSize);
this.WriteReference(writer, row.EncBaseId, this.guidRefSize);
}
}
private void SerializeModuleRefTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.moduleRefTable != null;
{
int n = this.tableSize[(int)TableIndices.ModuleRef];
for (int i = 0; i < n; i++)
{
ModuleRefRow row = this.moduleRefTable[i];
this.WriteReference(writer, row.Name, this.stringRefSize);
}
}
private void SerializeNestedClassTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.nestedClassTable != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.NestedClass];
for (int i = 0; i < n; i++)
{
NestedClassRow row = this.nestedClassTable[i];
this.WriteReference(writer, row.NestedClass, this.tableRefSize[(int)TableIndices.TypeDef]);
this.WriteReference(writer, row.EnclosingClass, this.tableRefSize[(int)TableIndices.TypeDef]);
}
}
private void SerializeParamTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.paramTable != null;
{
int n = this.tableSize[(int)TableIndices.Param];
for (int i = 0; i < n; i++)
{
ParamRow row = this.paramTable[i];
writer.Write((short)row.Flags);
writer.Write((short)row.Sequence);
this.WriteReference(writer, row.Name, this.stringRefSize);
}
}
private void SerializePropertyTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.propertyTable != null;
{
int n = this.tableSize[(int)TableIndices.Property];
for (int i = 0; i < n; i++)
{
PropertyRow row = this.propertyTable[i];
writer.Write((short)row.Flags);
this.WriteReference(writer, row.Name, this.stringRefSize);
this.WriteReference(writer, row.Signature, this.blobRefSize);
}
}
private void SerializePropertyMapTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.propertyMapTable != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.PropertyMap];
for (int i = 0; i < n; i++)
{
PropertyMapRow row = this.propertyMapTable[i];
this.WriteReference(writer, row.Parent, this.tableRefSize[(int)TableIndices.TypeDef]);
this.WriteReference(writer, row.PropertyList, this.tableRefSize[(int)TableIndices.Property]);
}
}
private void SerializeStandAloneSigTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.assemblyTable != null;
//^ requires this.standAloneSigTable != null;
{
int n = this.tableSize[(int)TableIndices.StandAloneSig];
for (int i = 0; i < n; i++)
{
StandAloneSigRow row = this.standAloneSigTable[i];
this.WriteReference(writer, row.Signature, this.blobRefSize);
}
}
private void SerializeTypeDefTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.typeDefTable != null;
//^ requires this.tableRefSize != null;
{
int n = this.tableSize[(int)TableIndices.TypeDef];
int fn = this.fieldTable == null ? 1 : this.fieldTable.Length + 1;
int mn = this.methodTable == null ? 1 : this.methodTable.Length + 1;
for (int i = n - 1; i >= 0; i--)
{
TypeDefRow row = this.typeDefTable[i];
if (row.FieldList != 0) fn = row.FieldList; else this.typeDefTable[i].FieldList = fn;
if (row.MethodList != 0) mn = row.MethodList; else this.typeDefTable[i].MethodList = mn;
}
for (int i = 0; i < n; i++)
{
TypeDefRow row = this.typeDefTable[i];
writer.Write((int)row.Flags);
this.WriteReference(writer, row.Name, this.stringRefSize);
this.WriteReference(writer, row.Namespace, this.stringRefSize);
this.WriteReference(writer, row.Extends, this.typeDefOrRefOrSpecSize);
this.WriteReference(writer, row.FieldList, this.tableRefSize[(int)TableIndices.Field]);
this.WriteReference(writer, row.MethodList, this.tableRefSize[(int)TableIndices.Method]);
}
}
private void SerializeTypeRefTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.typeRefTable != null;
{
int n = this.tableSize[(int)TableIndices.TypeRef];
for (int i = 0; i < n; i++)
{
TypeRefRow row = this.typeRefTable[i];
this.WriteReference(writer, row.ResolutionScope, this.resolutionScopeRefSize);
this.WriteReference(writer, row.Name, this.stringRefSize);
this.WriteReference(writer, row.Namespace, this.stringRefSize);
}
}
private void SerializeTypeSpecTable(BinaryWriter/*!*/ writer)
//^ requires this.tableSize != null;
//^ requires this.typeSpecTable != null;
{
int n = this.tableSize[(int)TableIndices.TypeSpec];
for (int i = 0; i < n; i++)
{
TypeSpecRow row = this.typeSpecTable[i];
this.WriteReference(writer, row.Signature, this.blobRefSize);
}
}
private int TablesLength()
//^ requires this.BlobHeap != null;
//^ requires this.GuidHeap != null;
//^ requires this.StringHeap != null;
{
int[] tableSize = this.tableSize = new int[(int)TableIndices.Count];
int[] tableRefSize = this.tableRefSize = new int[(int)TableIndices.Count];
int tableCount = 0;
long validMask = 0;
for (int i = 0; i < (int)TableIndices.Count; i++)
{
int j = 0;
switch ((TableIndices)i)
{
case TableIndices.Module: if (this.moduleTable != null) j = this.moduleTable.Length; break;
case TableIndices.TypeRef: if (this.typeRefTable != null) j = this.typeRefTable.Length; break;
case TableIndices.TypeDef: if (this.typeDefTable != null) j = this.typeDefTable.Length; break;
case TableIndices.Field: if (this.fieldTable != null) j = this.fieldTable.Length; break;
case TableIndices.Method: if (this.methodTable != null) j = this.methodTable.Length; break;
case TableIndices.Param: if (this.paramTable != null) j = this.paramTable.Length; break;
case TableIndices.InterfaceImpl: if (this.interfaceImplTable != null) j = this.interfaceImplTable.Length; break;
case TableIndices.MemberRef: if (this.memberRefTable != null) j = this.memberRefTable.Length; break;
case TableIndices.Constant: if (this.constantTable != null) j = this.constantTable.Length; break;
case TableIndices.CustomAttribute: if (this.customAttributeTable != null) j = this.customAttributeTable.Length; break;
case TableIndices.FieldMarshal: if (this.fieldMarshalTable != null) j = this.fieldMarshalTable.Length; break;
case TableIndices.DeclSecurity: if (this.declSecurityTable != null) j = this.declSecurityTable.Length; break;
case TableIndices.ClassLayout: if (this.classLayoutTable != null) j = this.classLayoutTable.Length; break;
case TableIndices.FieldLayout: if (this.fieldLayoutTable != null) j = this.fieldLayoutTable.Length; break;
case TableIndices.StandAloneSig: if (this.standAloneSigTable != null) j = this.standAloneSigTable.Length; break;
case TableIndices.EventMap: if (this.eventMapTable != null) j = this.eventMapTable.Length; break;
case TableIndices.Event: if (this.eventTable != null) j = this.eventTable.Length; break;
case TableIndices.PropertyMap: if (this.propertyMapTable != null) j = this.propertyMapTable.Length; break;
case TableIndices.Property: if (this.propertyTable != null) j = this.propertyTable.Length; break;
case TableIndices.MethodSemantics: if (this.methodSemanticsTable != null) j = this.methodSemanticsTable.Length; break;
case TableIndices.MethodImpl: if (this.methodImplTable != null) j = this.methodImplTable.Length; break;
case TableIndices.ModuleRef: if (this.moduleRefTable != null) j = this.moduleRefTable.Length; break;
case TableIndices.TypeSpec: if (this.typeSpecTable != null) j = this.typeSpecTable.Length; break;
case TableIndices.ImplMap: if (this.implMapTable != null) j = this.implMapTable.Length; break;
case TableIndices.FieldRva: if (this.fieldRvaTable != null) j = this.fieldRvaTable.Length; break;
case TableIndices.Assembly: if (this.assemblyTable != null) j = this.assemblyTable.Length; break;
case TableIndices.AssemblyRef: if (this.assemblyRefTable != null) j = this.assemblyRefTable.Length; break;
case TableIndices.File: if (this.fileTable != null) j = this.fileTable.Length; break;
case TableIndices.ExportedType: if (this.exportedTypeTable != null) j = this.exportedTypeTable.Length; break;
case TableIndices.ManifestResource: if (this.manifestResourceTable != null) j = this.manifestResourceTable.Length; break;
case TableIndices.NestedClass: if (this.nestedClassTable != null) j = this.nestedClassTable.Length; break;
case TableIndices.GenericParam: if (this.genericParamTable != null) j = this.genericParamTable.Length; break;
case TableIndices.MethodSpec: if (this.methodSpecTable != null) j = this.methodSpecTable.Length; break;
case TableIndices.GenericParamConstraint: if (this.genericParamConstraintTable != null) j = this.genericParamConstraintTable.Length; break;
}
tableSize[i] = j;
if (j > 0)
{
tableCount++;
validMask |= 1L << i;
}
}
this.validMask = validMask;
for (int i = 0; i < (int)TableIndices.Count; i++)
tableRefSize[i] = tableSize[i] < 0x10000 ? 2 : 4;
int blobRefSize = this.blobRefSize = this.BlobHeap.Length < 0x10000 ? 2 : 4;
int constantParentRefSize = this.constantParentRefSize =
tableSize[(int)TableIndices.Param] < 0x4000 &&
tableSize[(int)TableIndices.Field] < 0x4000 &&
tableSize[(int)TableIndices.Property] < 0x4000 ? 2 : 4;
int customAttributeParentRefSize = this.customAttributeParentRefSize =
tableSize[(int)TableIndices.Method] < 0x0800 &&
tableSize[(int)TableIndices.Field] < 0x0800 &&
tableSize[(int)TableIndices.TypeRef] < 0x0800 &&
tableSize[(int)TableIndices.TypeDef] < 0x0800 &&
tableSize[(int)TableIndices.Param] < 0x0800 &&
tableSize[(int)TableIndices.InterfaceImpl] < 0x0800 &&
tableSize[(int)TableIndices.MemberRef] < 0x0800 &&
tableSize[(int)TableIndices.Module] < 0x0800 &&
tableSize[(int)TableIndices.DeclSecurity] < 0x0800 &&
tableSize[(int)TableIndices.Property] < 0x0800 &&
tableSize[(int)TableIndices.Event] < 0x0800 &&
tableSize[(int)TableIndices.StandAloneSig] < 0x0800 &&
tableSize[(int)TableIndices.ModuleRef] < 0x0800 &&
tableSize[(int)TableIndices.TypeSpec] < 0x0800 &&
tableSize[(int)TableIndices.Assembly] < 0x0800 &&
tableSize[(int)TableIndices.File] < 0x0800 &&
tableSize[(int)TableIndices.ExportedType] < 0x0800 &&
tableSize[(int)TableIndices.ManifestResource] < 0x0800 &&
tableSize[(int)TableIndices.GenericParam] < 0x0800 &&
tableSize[(int)TableIndices.MethodSpec] < 0x0800 &&
tableSize[(int)TableIndices.GenericParamConstraint] < 0x0800 ? 2 : 4;
int customAttributeConstructorRefSize = this.customAttributeConstructorRefSize =
tableSize[(int)TableIndices.Method] < 0x2000 &&
tableSize[(int)TableIndices.MemberRef] < 0x2000 ? 2 : 4;
int declSecurityParentRefSize = this.declSecurityParentRefSize =
tableSize[(int)TableIndices.TypeDef] < 0x4000 &&
tableSize[(int)TableIndices.Method] < 0x4000 &&
tableSize[(int)TableIndices.Assembly] < 0x4000 ? 2 : 4;
int fieldMarshalParentRefSize = this.fieldMarshalParentRefSize =
tableSize[(int)TableIndices.Field] < 0x8000 &&
tableSize[(int)TableIndices.Param] < 0x8000 ? 2 : 4;
int guidRefSize = this.guidRefSize = this.GuidHeap.Length < 0x10000 ? 2 : 4;
int hasSemanticRefSize = this.hasSemanticRefSize =
tableSize[(int)TableIndices.Event] < 0x8000 &&
tableSize[(int)TableIndices.Property] < 0x8000 ? 2 : 4;
int implementationRefSize = this.implementationRefSize =
tableSize[(int)TableIndices.File] < 0x4000 &&
tableSize[(int)TableIndices.AssemblyRef] < 0x4000 &&
tableSize[(int)TableIndices.ExportedType] < 0x4000 ? 2 : 4;
int methodDefOrRefSize = this.methodDefOrRefSize =
tableSize[(int)TableIndices.Method] < 0x8000 &&
tableSize[(int)TableIndices.MemberRef] < 0x8000 ? 2 : 4;
int memberRefParentSize = this.memberRefParentSize =
tableSize[(int)TableIndices.TypeDef] < 0x2000 &&
tableSize[(int)TableIndices.TypeRef] < 0x2000 &&
tableSize[(int)TableIndices.ModuleRef] < 0x2000 &&
tableSize[(int)TableIndices.Method] < 0x2000 &&
tableSize[(int)TableIndices.TypeSpec] < 0x2000 ? 2 : 4;
int memberForwardedRefSize = this.memberForwardedRefSize =
tableSize[(int)TableIndices.Field] < 0x8000 &&
tableSize[(int)TableIndices.Method] < 0x8000 ? 2 : 4;
int typeDefOrMethodDefSize = this.typeDefOrMethodDefSize =
tableSize[(int)TableIndices.TypeDef] < 0x8000 &&
tableSize[(int)TableIndices.Method] < 0x8000 ? 2 : 4;
int typeDefOrRefOrSpecSize = this.typeDefOrRefOrSpecSize =
tableSize[(int)TableIndices.TypeDef] < 0x4000 &&
tableSize[(int)TableIndices.TypeRef] < 0x4000 &&
tableSize[(int)TableIndices.TypeSpec] < 0x4000 ? 2 : 4;
int resolutionScopeRefSize = this.resolutionScopeRefSize =
tableSize[(int)TableIndices.Module] < 0x4000 &&
tableSize[(int)TableIndices.ModuleRef] < 0x4000 &&
tableSize[(int)TableIndices.AssemblyRef] < 0x4000 &&
tableSize[(int)TableIndices.TypeRef] < 0x4000 ? 2 : 4;
int stringRefSize = this.stringRefSize = this.StringHeap.Length < 0x10000 ? 2 : 4;
int length = 0;
for (int i = 0; i < (int)TableIndices.Count; i++)
{
int m = tableSize[i];
if (m == 0) continue;
switch ((TableIndices)i)
{
case TableIndices.Module: length += m * (2 + stringRefSize + 3 * guidRefSize); break;
case TableIndices.TypeRef: length += m * (resolutionScopeRefSize + 2 * stringRefSize); break;
case TableIndices.TypeDef: length += m * (4 + 2 * stringRefSize + typeDefOrRefOrSpecSize + tableRefSize[(int)TableIndices.Field] + tableRefSize[(int)TableIndices.Method]); break;
case TableIndices.Field: length += m * (2 + stringRefSize + blobRefSize); break;
case TableIndices.Method: length += m * (8 + stringRefSize + blobRefSize + tableRefSize[(int)TableIndices.Param]); break;
case TableIndices.Param: length += m * (4 + stringRefSize); break;
case TableIndices.InterfaceImpl: length += m * (tableRefSize[(int)TableIndices.TypeDef] + typeDefOrRefOrSpecSize); break;
case TableIndices.MemberRef: length += m * (memberRefParentSize + stringRefSize + blobRefSize); break;
case TableIndices.Constant: length += m * (2 + constantParentRefSize + blobRefSize); break;
case TableIndices.CustomAttribute: length += m * (customAttributeParentRefSize + customAttributeConstructorRefSize + blobRefSize); break;
case TableIndices.FieldMarshal: length += m * (fieldMarshalParentRefSize + blobRefSize); break;
case TableIndices.DeclSecurity: length += m * (2 + declSecurityParentRefSize + blobRefSize); break;
case TableIndices.ClassLayout: length += m * (6 + tableRefSize[(int)TableIndices.TypeDef]); break;
case TableIndices.FieldLayout: length += m * (4 + tableRefSize[(int)TableIndices.Field]); break;
case TableIndices.StandAloneSig: length += m * (blobRefSize); break;
case TableIndices.EventMap: length += m * (tableRefSize[(int)TableIndices.TypeDef] + tableRefSize[(int)TableIndices.Event]); break;
case TableIndices.Event: length += m * (2 + stringRefSize + typeDefOrRefOrSpecSize); break;
case TableIndices.PropertyMap: length += m * (tableRefSize[(int)TableIndices.TypeDef] + tableRefSize[(int)TableIndices.Property]); break;
case TableIndices.Property: length += m * (2 + stringRefSize + blobRefSize); break;
case TableIndices.MethodSemantics: length += m * (2 + tableRefSize[(int)TableIndices.Method] + hasSemanticRefSize); break;
case TableIndices.MethodImpl: length += m * (tableRefSize[(int)TableIndices.TypeDef] + 2 * methodDefOrRefSize); break;
case TableIndices.ModuleRef: length += m * (stringRefSize); break;
case TableIndices.TypeSpec: length += m * (blobRefSize); break;
case TableIndices.ImplMap: length += m * (2 + memberForwardedRefSize + stringRefSize + tableRefSize[(int)TableIndices.ModuleRef]); break;
case TableIndices.FieldRva: length += m * (4 + tableRefSize[(int)TableIndices.Field]); break;
case TableIndices.EncLog: throw new InvalidMetadataException(ExceptionStrings.ENCLogTableEncountered);
case TableIndices.EncMap: throw new InvalidMetadataException(ExceptionStrings.ENCMapTableEncountered);
case TableIndices.Assembly: length += m * (16 + blobRefSize + 2 * stringRefSize); break;
case TableIndices.AssemblyRef: length += m * (12 + 2 * blobRefSize + 2 * stringRefSize); break;
case TableIndices.File: length += m * (4 + stringRefSize + blobRefSize); break;
case TableIndices.ExportedType: length += m * (8 + 2 * stringRefSize + implementationRefSize); break;
case TableIndices.ManifestResource: length += m * (8 + stringRefSize + implementationRefSize); break;
case TableIndices.NestedClass: length += m * (2 * tableRefSize[(int)TableIndices.TypeDef]); break;
case TableIndices.GenericParam:
if (TargetPlatform.MajorVersion == 1 && TargetPlatform.MinorVersion == 0)
length += m * (6 + typeDefOrMethodDefSize + stringRefSize + typeDefOrRefOrSpecSize);
else if (TargetPlatform.MajorVersion == 1 && TargetPlatform.MinorVersion == 1)
length += m * (4 + typeDefOrMethodDefSize + stringRefSize + typeDefOrRefOrSpecSize);
else
length += m * (4 + typeDefOrMethodDefSize + stringRefSize);
break;
case TableIndices.MethodSpec: length += m * (methodDefOrRefSize + blobRefSize); break;
case TableIndices.GenericParamConstraint: length += m * (tableRefSize[(int)TableIndices.GenericParam] + typeDefOrRefOrSpecSize); break;
}
}
length += 24 + (tableCount * 4);
return length;
}
private NTHeader/*!*/ ntHeader = new NTHeader();
private CLIHeader/*!*/ cliHeader = new CLIHeader();
private SectionHeader[] sectionHeaders;
internal void WritePE(BinaryWriter/*!*/ writer)
//^ requires this.SdataHeap != null;
//^ requires this.TlsHeap != null;
{
this.cliHeader.entryPointToken = this.entryPointToken;
switch (this.moduleKind)
{
case ModuleKindFlags.ConsoleApplication:
this.ntHeader.subsystem = 3;
break;
case ModuleKindFlags.DynamicallyLinkedLibrary:
this.ntHeader.characteristics |= 0x2000;
this.ntHeader.subsystem = 3;
break;
case ModuleKindFlags.WindowsApplication:
this.ntHeader.subsystem = 2;
break;
}
int numSectionHeaders = 2;
if (this.SdataHeap.Length > 0) numSectionHeaders++;
if (this.TlsHeap.Length > 0) numSectionHeaders++;
if (this.Win32Resources != null && this.Win32Resources.Count > 0) numSectionHeaders++;
this.sectionHeaders = new SectionHeader[numSectionHeaders];
this.ntHeader.numberOfSections = (ushort)numSectionHeaders;
this.ntHeader.timeDateStamp = (int)((DateTime.Now.ToUniversalTime() - NineteenSeventy).TotalSeconds);
//Write out .text section for meta data tables, method bodies, address tables and entry point stub
Fixup sdataFixup = new Fixup();
Fixup tlsFixup = new Fixup();
SectionHeader textSection = new SectionHeader();
textSection.name = ".text";
textSection.virtualAddress = 8192;
int sizeOfPeHeaders = 376 + 40 * numSectionHeaders;
textSection.pointerToRawData = ((int)Math.Ceiling(sizeOfPeHeaders / (double)this.fileAlignment)) * this.fileAlignment;
textSection.characteristics = 0x60000020;
writer.BaseStream.Position = textSection.pointerToRawData + 72; //Leave 72 bytes for CLI header
this.SerializeMetadata(writer, textSection.virtualAddress, sdataFixup, tlsFixup);
int RVAofEntryPointJumpTarget = this.WriteImportTableAndEntryPointStub(writer, ref textSection);
#if !ROTOR
if (this.symWriter != null) this.WriteReferenceToPDBFile(writer, textSection.virtualAddress, textSection.pointerToRawData);
#endif
int len = textSection.virtualSize = ((int)writer.BaseStream.Position) - textSection.pointerToRawData;
textSection.sizeOfRawData = ((int)Math.Ceiling(len / (double)this.fileAlignment)) * this.fileAlignment;
this.sectionHeaders[0] = textSection;
writer.BaseStream.Position = textSection.pointerToRawData;
this.ntHeader.cliHeaderTable.virtualAddress = textSection.virtualAddress;
this.ntHeader.cliHeaderTable.size = 72;
WriteCLIHeader(writer); //Write CLI header last so that forward pointers can be filled in first
int sectionHeaderIndex = 1;
SectionHeader previousSection = textSection;
int n = this.ntHeader.sectionAlignment;
int m = this.fileAlignment;
if (this.SdataHeap.Length > 0)
{
SectionHeader sdataSection = new SectionHeader();
sdataSection.name = ".sdata";
int vaddr = sdataSection.virtualAddress = previousSection.virtualAddress + n * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)n);
sdataSection.virtualSize = this.SdataHeap.Length;
sdataSection.pointerToRawData = previousSection.pointerToRawData + m * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)m);
sdataSection.characteristics = unchecked((int)0xC0000040);
writer.BaseStream.Position = sdataSection.pointerToRawData;
this.SdataHeap.WriteTo(writer.BaseStream);
len = sdataSection.virtualSize = ((int)writer.BaseStream.Position) - sdataSection.pointerToRawData;
writer.BaseStream.Position += m - (len % this.fileAlignment) - 1;
writer.Write((byte)0);
sdataSection.sizeOfRawData = ((int)Math.Ceiling(len / (double)this.fileAlignment)) * this.fileAlignment;
sdataFixup = sdataFixup.nextFixUp; //Skip over dummy header
while (sdataFixup != null)
{
writer.BaseStream.Position = sdataFixup.fixupLocation;
writer.Write((int)(vaddr + sdataFixup.addressOfNextInstruction));
sdataFixup = sdataFixup.nextFixUp;
}
this.sectionHeaders[sectionHeaderIndex++] = sdataSection;
previousSection = sdataSection;
}
if (this.TlsHeap.Length > 0)
{
SectionHeader tlsSection = new SectionHeader();
tlsSection.name = ".tls";
int vaddr = tlsSection.virtualAddress = previousSection.virtualAddress + n * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)n);
tlsSection.virtualSize = this.SdataHeap.Length;
tlsSection.pointerToRawData = previousSection.pointerToRawData + m * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)m);
tlsSection.characteristics = unchecked((int)0xC0000040);
writer.BaseStream.Position = tlsSection.pointerToRawData;
this.TlsHeap.WriteTo(writer.BaseStream);
len = tlsSection.virtualSize = ((int)writer.BaseStream.Position) - tlsSection.pointerToRawData;
writer.BaseStream.Position += m - (len % this.fileAlignment) - 1;
writer.Write((byte)0);
tlsSection.sizeOfRawData = ((int)Math.Ceiling(len / (double)this.fileAlignment)) * this.fileAlignment;
tlsFixup = tlsFixup.nextFixUp; //Skip over dummy header
while (tlsFixup != null)
{
writer.BaseStream.Position = tlsFixup.fixupLocation;
writer.Write((int)(vaddr + tlsFixup.addressOfNextInstruction));
tlsFixup = tlsFixup.nextFixUp;
}
this.sectionHeaders[sectionHeaderIndex++] = tlsSection;
previousSection = tlsSection;
}
if (this.Win32Resources != null && this.Win32Resources.Count > 0)
{
SectionHeader rsrcSection = new SectionHeader();
rsrcSection.name = ".rsrc";
rsrcSection.virtualAddress = previousSection.virtualAddress + n * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)n);
rsrcSection.pointerToRawData = previousSection.pointerToRawData + m * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)m);
rsrcSection.characteristics = 0x40000040;
writer.BaseStream.Position = rsrcSection.pointerToRawData;
this.WriteWin32Resources(writer, rsrcSection.virtualAddress);
len = rsrcSection.virtualSize = ((int)writer.BaseStream.Position) - rsrcSection.pointerToRawData;
writer.BaseStream.Position += m - (len % this.fileAlignment) - 1;
writer.Write((byte)0);
rsrcSection.sizeOfRawData = ((int)Math.Ceiling(len / (double)this.fileAlignment)) * this.fileAlignment;
this.sectionHeaders[sectionHeaderIndex++] = rsrcSection;
this.ntHeader.resourceTable.virtualAddress = rsrcSection.virtualAddress;
this.ntHeader.resourceTable.size = rsrcSection.virtualSize;
this.ntHeader.sizeOfInitializedData += rsrcSection.sizeOfRawData;
previousSection = rsrcSection;
}
//Write out .reloc section for entry point stub relocation table
SectionHeader relocSection = new SectionHeader();
relocSection.name = ".reloc";
relocSection.virtualAddress = previousSection.virtualAddress + n * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)n);
relocSection.virtualSize = 12;
relocSection.pointerToRawData = previousSection.pointerToRawData + m * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)m);
relocSection.sizeOfRawData = m;
relocSection.characteristics = 0x42000040;
writer.BaseStream.Position = relocSection.pointerToRawData;
writer.Write((int)((RVAofEntryPointJumpTarget / 4096) * 4096)); //Page RVA
writer.Write((int)12);
int offsetWithinPage = RVAofEntryPointJumpTarget % 4096;
short s = (short)(3 << 12 | offsetWithinPage);
writer.Write(s);
writer.Write((short)0); //next chunk's RVA
writer.BaseStream.Position += m - 13;
writer.Write((byte)0);
this.sectionHeaders[sectionHeaderIndex] = relocSection;
this.ntHeader.baseRelocationTable.virtualAddress = relocSection.virtualAddress;
this.ntHeader.baseRelocationTable.size = relocSection.virtualSize;
this.ntHeader.sizeOfInitializedData += relocSection.sizeOfRawData;
//Write PE headers. Do this last because forward pointers are filled in by preceding code
writer.BaseStream.Position = 0;
writer.Write(dosHeader);
WriteNTHeader(writer);
WriteSectionHeaders(writer);
}
private class Directory
{
internal string Name;
internal int ID;
internal int NumberOfNamedEntries;
internal int NumberOfIdEntries;
internal ArrayList/*!*/ Entries;
internal Directory(string Name, int ID)
{
this.Name = Name;
this.ID = ID;
this.Entries = new ArrayList();
//^ base();
}
}
private void WriteWin32Resources(BinaryWriter/*!*/ writer, int virtualAddressBase)
//^ requires this.Win32Resources != null;
{
Win32ResourceList rsrcs = this.Win32Resources;
BinaryWriter dataHeap = new BinaryWriter(new MemoryStream(), System.Text.Encoding.Unicode);
//Construct a tree of array lists to represent the directory and make it easier to compute offsets
Directory TypeDirectory = new Directory("", 0);
Directory NameDirectory = null;
Directory LanguageDirectory = null;
int lastTypeID = int.MinValue;
string lastTypeName = null;
int lastID = int.MinValue;
string lastName = null;
int sizeOfDirectoryTree = 16;
for (int i = 0, n = rsrcs.Count; i < n; i++)
{
Win32Resource r = rsrcs[i];
bool typeDifferent = (r.TypeId < 0 && r.TypeName != lastTypeName) || r.TypeId > lastTypeID;
if (typeDifferent)
{
lastTypeID = r.TypeId;
lastTypeName = r.TypeName;
if (lastTypeID < 0) TypeDirectory.NumberOfNamedEntries++; else TypeDirectory.NumberOfIdEntries++;
sizeOfDirectoryTree += 24;
TypeDirectory.Entries.Add(NameDirectory = new Directory(lastTypeName, lastTypeID));
}
//^ assume NameDirectory != null;
if (typeDifferent || (r.Id < 0 && r.Name != lastName) || r.Id > lastID)
{
lastID = r.Id;
lastName = r.Name;
if (lastID < 0) NameDirectory.NumberOfNamedEntries++; else NameDirectory.NumberOfIdEntries++;
sizeOfDirectoryTree += 24;
NameDirectory.Entries.Add(LanguageDirectory = new Directory(lastName, lastID));
}
//^ assume LanguageDirectory != null;
LanguageDirectory.NumberOfIdEntries++;
sizeOfDirectoryTree += 8;
LanguageDirectory.Entries.Add(r);
continue;
}
this.WriteDirectory(TypeDirectory, writer, 0, 0, sizeOfDirectoryTree, virtualAddressBase, dataHeap);
dataHeap.BaseStream.WriteTo(writer.BaseStream);
}
private void WriteDirectory(Directory/*!*/ directory, BinaryWriter/*!*/ writer, int offset, int level, int sizeOfDirectoryTree,
int virtualAddressBase, BinaryWriter/*!*/ dataHeap)
{
writer.Write((int)0); //Characteristics
writer.Write((int)0); //Timestamp
writer.Write((int)0); //Version
writer.Write((short)directory.NumberOfNamedEntries);
writer.Write((short)directory.NumberOfIdEntries);
int n = directory.Entries.Count;
int k = offset + 16 + n * 8;
for (int i = 0; i < n; i++)
{
int id = int.MinValue;
string name = null;
int nOff = dataHeap.BaseStream.Position + sizeOfDirectoryTree;
int dOff = k;
Directory subDir = directory.Entries[i] as Directory;
if (subDir != null)
{
id = subDir.ID;
name = subDir.Name;
if (level == 0)
k += this.SizeOfDirectory(subDir);
else
k += 16 + 8 * subDir.Entries.Count;
}
else
{
Win32Resource r = (Win32Resource)directory.Entries[i];
id = level == 0 ? r.TypeId : level == 1 ? r.Id : r.LanguageId;
name = level == 0 ? r.TypeName : level == 1 ? r.Name : null;
dataHeap.Write((int)(virtualAddressBase + sizeOfDirectoryTree + 16 + dataHeap.BaseStream.Position));
dataHeap.Write((int)r.Data.Length);
dataHeap.Write((int)r.CodePage);
dataHeap.Write((int)0);
dataHeap.Write(r.Data);
}
if (id >= 0)
writer.Write(id);
else
{
if (name == null) name = "";
writer.Write(((uint)nOff) | 0x80000000);
dataHeap.Write((ushort)name.Length);
dataHeap.Write(name.ToCharArray()); //REVIEW: what happens if the name contains chars that do not fit into a single utf8 code point?
}
if (subDir != null)
writer.Write(((uint)dOff) | 0x80000000);
else
writer.Write(nOff);
}
k = offset + 16 + n * 8;
for (int i = 0; i < n; i++)
{
Directory subDir = directory.Entries[i] as Directory;
if (subDir != null)
{
this.WriteDirectory(subDir, writer, k, level + 1, sizeOfDirectoryTree, virtualAddressBase, dataHeap);
if (level == 0)
k += this.SizeOfDirectory(subDir);
else
k += 16 + 8 * subDir.Entries.Count;
}
}
}
private int SizeOfDirectory(Directory/*!*/ directory)
{
int n = directory.Entries.Count;
int size = 16 + 8 * n;
for (int i = 0; i < n; i++)
{
Directory subDir = directory.Entries[i] as Directory;
if (subDir != null)
size += 16 + 8 * subDir.Entries.Count;
}
return size;
}
private static readonly byte[] dosHeader = new byte[]{
0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd,
0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,
0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e,
0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a,
0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static readonly DateTime NineteenSeventy = new DateTime(1970, 1, 1).ToUniversalTime();
private void WriteNTHeader(BinaryWriter/*!*/ writer)
//^ requires this.sectionHeaders != null;
{
NTHeader ntHeader = this.ntHeader;
writer.Write(ntHeader.signature);
if ((this.peKind & PEKindFlags.Requires64bits) == 0)
{
ntHeader.magic = 0x10B; //PE32
ntHeader.machine = 0x014c; //I386
}
else
{
ntHeader.characteristics &= 0xFEFF; //Not 32-bit
ntHeader.characteristics |= 0x0020; //Can handle >2gb addresses
ntHeader.magic = 0x20B; //PE32+
if ((this.peKind & PEKindFlags.AMD) != 0)
ntHeader.machine = 0x8664; //AMD64
else
ntHeader.machine = 0x0200; //IA64
ntHeader.sizeOfOptionalHeader += 16;
}
writer.Write(ntHeader.machine);
writer.Write(ntHeader.numberOfSections);
writer.Write(ntHeader.timeDateStamp);
writer.Write(ntHeader.pointerToSymbolTable);
writer.Write(ntHeader.numberOfSymbols);
writer.Write(ntHeader.sizeOfOptionalHeader);
writer.Write(ntHeader.characteristics);
writer.Write(ntHeader.magic);
writer.Write((byte)TargetPlatform.LinkerMajorVersion);
writer.Write((byte)TargetPlatform.LinkerMinorVersion);
writer.Write(this.sectionHeaders[0].sizeOfRawData); //sizeOfCode
writer.Write(ntHeader.sizeOfInitializedData);
writer.Write(ntHeader.sizeOfUninitializedData);
writer.Write(ntHeader.addressOfEntryPoint);
writer.Write(this.sectionHeaders[0].virtualAddress); //baseOfCode
if (ntHeader.magic == 0x10B)
{
if (this.sectionHeaders.Length > 1)
writer.Write(this.sectionHeaders[1].virtualAddress); //baseOfData
else
writer.Write((int)0);
writer.Write((int)ntHeader.imageBase);
}
else
{
writer.Write(ntHeader.imageBase);
}
writer.Write(ntHeader.sectionAlignment);
writer.Write(this.fileAlignment);
writer.Write(ntHeader.majorOperatingSystemVersion);
writer.Write(ntHeader.minorOperatingSystemVersion);
writer.Write(ntHeader.majorImageVersion);
writer.Write(ntHeader.minorImageVersion);
writer.Write(ntHeader.majorSubsystemVersion);
writer.Write(ntHeader.minorSubsystemVersion);
writer.Write(ntHeader.win32VersionValue);
int sectionPages = (int)(Math.Ceiling(this.sectionHeaders[this.sectionHeaders.Length - 1].virtualSize /
(double)ntHeader.sectionAlignment) * ntHeader.sectionAlignment);
writer.Write(this.sectionHeaders[this.sectionHeaders.Length - 1].virtualAddress + sectionPages); //sizeOfImage
writer.Write(this.sectionHeaders[0].pointerToRawData); //sizeOfHeaders
writer.Write(ntHeader.checkSum);
writer.Write(ntHeader.subsystem);
writer.Write(ntHeader.dllCharacteristics);
if (ntHeader.magic == 0x10B)
{
writer.Write((int)ntHeader.sizeOfStackReserve);
writer.Write((int)ntHeader.sizeOfStackCommit);
writer.Write((int)ntHeader.sizeOfHeapReserve);
writer.Write((int)ntHeader.sizeOfHeapCommit);
}
else
{
writer.Write(ntHeader.sizeOfStackReserve);
writer.Write(ntHeader.sizeOfStackCommit);
writer.Write(ntHeader.sizeOfHeapReserve);
writer.Write(ntHeader.sizeOfHeapCommit);
}
writer.Write(ntHeader.loaderFlags);
writer.Write(ntHeader.numberOfDataDirectories);
writer.Write(ntHeader.exportTable.virtualAddress);
writer.Write(ntHeader.exportTable.size);
writer.Write(ntHeader.importTable.virtualAddress);
writer.Write(ntHeader.importTable.size);
writer.Write(ntHeader.resourceTable.virtualAddress);
writer.Write(ntHeader.resourceTable.size);
writer.Write(ntHeader.exceptionTable.virtualAddress);
writer.Write(ntHeader.exceptionTable.size);
writer.Write(ntHeader.certificateTable.virtualAddress);
writer.Write(ntHeader.certificateTable.size);
writer.Write(ntHeader.baseRelocationTable.virtualAddress);
writer.Write(ntHeader.baseRelocationTable.size);
writer.Write(ntHeader.debugTable.virtualAddress);
writer.Write(ntHeader.debugTable.size);
writer.Write(ntHeader.copyrightTable.virtualAddress);
writer.Write(ntHeader.copyrightTable.size);
writer.Write(ntHeader.globalPointerTable.virtualAddress);
writer.Write(ntHeader.globalPointerTable.size);
writer.Write(ntHeader.threadLocalStorageTable.virtualAddress);
writer.Write(ntHeader.threadLocalStorageTable.size);
writer.Write(ntHeader.loadConfigTable.virtualAddress);
writer.Write(ntHeader.loadConfigTable.size);
writer.Write(ntHeader.boundImportTable.virtualAddress);
writer.Write(ntHeader.boundImportTable.size);
writer.Write(ntHeader.importAddressTable.virtualAddress);
writer.Write(ntHeader.importAddressTable.size);
writer.Write(ntHeader.delayImportTable.virtualAddress);
writer.Write(ntHeader.delayImportTable.size);
writer.Write(ntHeader.cliHeaderTable.virtualAddress);
writer.Write(ntHeader.cliHeaderTable.size);
writer.Write((long)0);
}
private void WriteSectionHeaders(BinaryWriter/*!*/ writer)
//^ requires this.sectionHeaders != null;
{
SectionHeader[] sectionHeaders = this.sectionHeaders;
for (int i = 0, n = this.sectionHeaders.Length; i < n; i++)
{
SectionHeader hdr = sectionHeaders[i];
//^ assume hdr.name != null;
for (int j = 0, m = hdr.name.Length; j < 8; j++)
if (j < m) writer.Write(hdr.name[j]); else writer.Write((byte)0);
writer.Write(hdr.virtualSize);
writer.Write(hdr.virtualAddress);
writer.Write(hdr.sizeOfRawData);
writer.Write(hdr.pointerToRawData);
writer.Write(hdr.pointerToRelocations);
writer.Write(hdr.pointerToLinenumbers);
writer.Write(hdr.numberOfRelocations);
writer.Write(hdr.numberOfLinenumbers);
writer.Write(hdr.characteristics);
}
}
private void WriteCLIHeader(BinaryWriter/*!*/ writer)
{
CLIHeader hdr = this.cliHeader;
writer.Write(hdr.cb);
writer.Write((ushort)2);
if (this.UseGenerics)
writer.Write((ushort)5); //Violates the ECMA standard (25.3.3 of Partition II), but apparently necessary
else
writer.Write((ushort)0);
writer.Write(hdr.metaData.virtualAddress);
writer.Write(hdr.metaData.size);
if ((this.peKind & PEKindFlags.Requires32bits) != 0) hdr.flags |= 2;
if ((this.peKind & PEKindFlags.ILonly) != 0) hdr.flags |= 1;
if (this.TrackDebugData) hdr.flags |= 0x10000;
writer.Write(hdr.flags);
writer.Write(hdr.entryPointToken);
writer.Write(hdr.resources.virtualAddress);
writer.Write(hdr.resources.size);
writer.Write(hdr.strongNameSignature.virtualAddress);
writer.Write(hdr.strongNameSignature.size);
writer.Write(hdr.codeManagerTable.virtualAddress);
writer.Write(hdr.codeManagerTable.size);
writer.Write(hdr.vtableFixups.virtualAddress);
writer.Write(hdr.vtableFixups.size);
}
private int WriteImportTableAndEntryPointStub(BinaryWriter/*!*/ writer, ref SectionHeader textSection)
{
bool use32bitAddresses = (this.peKind & PEKindFlags.Requires64bits) == 0;
int pos = (int)writer.BaseStream.Position;
while (pos % 4 != 0) { pos++; writer.Write((byte)0); }
int ITrva = textSection.virtualAddress + pos - textSection.pointerToRawData;
int ITLrva = ITrva + 40;
int rvasize = 12; // size of relocation sections
int hintRva = ITLrva + (use32bitAddresses ? 8 : 16); //position of name of entry point in runtime dll
int nameRva = hintRva + 14; // position of name of runtime dll
int ITArva = nameRva + 14 + // size of name of runtime dll
4 + // size of entry point code 0000ff25
rvasize; // size of relocation fixup
this.ntHeader.addressOfEntryPoint = ITArva - rvasize - 2;
this.ntHeader.importTable.virtualAddress = ITrva;
this.ntHeader.importTable.size = this.ntHeader.addressOfEntryPoint - ITrva - 2;
this.ntHeader.importAddressTable.virtualAddress = ITArva;
this.ntHeader.importAddressTable.size = 8;
//Import table
writer.Write((int)ITLrva);
writer.Write((int)0);
writer.Write((int)0);
writer.Write((int)nameRva);
writer.Write((int)ITArva);
writer.BaseStream.Position += 20;
//Import Lookup table
if (use32bitAddresses)
{
writer.Write((int)hintRva);
writer.Write((int)0);
}
else
{
writer.Write((long)hintRva);
writer.Write((long)0);
}
//Hint table
writer.Write((short)0); //Hint
string entryPointName = this.moduleKind == ModuleKindFlags.DynamicallyLinkedLibrary ? "_CorDllMain" : "_CorExeMain";
foreach (char ch in entryPointName.ToCharArray()) writer.Write((byte)ch);
writer.Write((byte)0);
//name of CLR runtime dll
foreach (char ch in "mscoree.dll".ToCharArray()) writer.Write((byte)ch);
writer.Write((byte)0);
writer.Write((short)0);
//entry point code, consisting of a jump indirect to _CorXXXMain
writer.Write((short)0); //padding so that address to replace is on a word boundary
writer.Write((byte)0xff);
writer.Write((byte)0x25);
writer.Write((int)ITArva + (int)this.ntHeader.imageBase); //REVIEW: is this OK for 64 bit?
writer.Write((int)0); // relocation fixup must be 12 bytes.
writer.Write((int)0);
//Import Address Table
if (use32bitAddresses)
{
writer.Write((int)hintRva);
writer.Write((int)0);
}
else
{
writer.Write((long)hintRva);
writer.Write((long)0);
}
//Return RVA of the target address of the indirect jump at the entry point
return ITArva - rvasize;
}
private void WriteReference(BinaryWriter/*!*/ writer, int index, int refSize)
{
if (refSize == 2) writer.Write((short)index); else writer.Write(index);
}
}
#endif
}
|