Metadata.cs :  » Development » Sandcastle » Microsoft » Cci » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Development » Sandcastle 
Sandcastle » Microsoft » Cci » Metadata.cs
// 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
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.