diff options
Diffstat (limited to 'mcs/class/PEAPI/Metadata.cs')
-rw-r--r-- | mcs/class/PEAPI/Metadata.cs | 5659 |
1 files changed, 5659 insertions, 0 deletions
diff --git a/mcs/class/PEAPI/Metadata.cs b/mcs/class/PEAPI/Metadata.cs new file mode 100644 index 00000000000..c77ae5d9b65 --- /dev/null +++ b/mcs/class/PEAPI/Metadata.cs @@ -0,0 +1,5659 @@ +using System; +using System.IO; +using System.Collections; +using System.Text; + +namespace PEAPI { + + #region Enums + + /// <summary> + /// flags for the assembly (.corflags) + /// </summary> + public enum CorFlags {CF_IL_ONLY = 1, CF_32_BITREQUIRED = 2, + CF_STRONGNAMESIGNED = 8, CF_TRACKDEBUGDATA = 0x10000 } + + /// <summary> + /// subsystem for the assembly (.subsystem) + /// </summary> + public enum SubSystem { Native = 1, Windows_GUI = 2, + Windows_CUI = 3, OS2_CUI = 5, POSIX_CUI = 7, Native_Windows = 8, + Windows_CE_GUI = 9} + + /// <summary> + /// Hash algorithms for the assembly + /// </summary> + public enum HashAlgorithm { None, SHA1 } + + /// <summary> + /// Attributes for this assembly + /// </summary> + public enum AssemAttr { EnableJITCompileTracking = 0x8000, + DisableJITCompileOptimizer = 0x4000} + + /// <summary> + /// Method call conventions + /// </summary> + [Flags] + public enum CallConv { Default, Cdecl, Stdcall, Thiscall, + Fastcall, Vararg, Instance = 0x20, Generic = 0x10, InstanceExplicit = 0x60 } + + /// <summary> + /// Type custom modifier + /// </summary> + public enum CustomModifier { modreq = 0x1F, modopt }; + + /// <summary> + /// Attibutes for a class + /// </summary> + [Flags] + public enum TypeAttr {Private, Public, NestedPublic, NestedPrivate, + NestedFamily, NestedAssembly, NestedFamAndAssem, NestedFamOrAssem, + SequentialLayout, ExplicitLayout = 0x10, Interface = 0x20, + Abstract = 0x80, PublicAbstract = 0x81, Sealed = 0x100, + PublicSealed = 0x101, SpecialName = 0x400, RTSpecialName = 0x800, + Import = 0x1000, Serializable = 0x2000, UnicodeClass = 0x10000, + AutoClass = 0x20000, HasSecurity = 0x40000, BeforeFieldInit = 0x100000, + VisibilityMask = 0x07 } + + /// <summary> + /// Attributes for a field + /// </summary> + public enum FieldAttr {Default, Private, FamAndAssem, Assembly, + Family, FamOrAssem, Public, Static = 0x10, PublicStatic = 0x16, + Initonly = 0x20, Literal = 0x40, Notserialized = 0x80, + SpecialName = 0x200, RTSpecialName = 0x400, HasFieldMarshal = 0x1000 } + + /// <summary> + /// Attributes for a method + /// </summary> + public enum MethAttr { Default, Private, FamAndAssem, Assembly, + Family, FamOrAssem, Public, Static = 0x0010, PublicStatic = 0x16, + Final = 0x0020, PublicStaticFinal = 0x36, Virtual = 0x0040, + PrivateVirtual, PublicVirtual = 0x0046, HideBySig = 0x0080, + NewSlot = 0x0100, Abstract = 0x0400, SpecialName = 0x0800, + RTSpecialName = 0x1000, SpecialRTSpecialName = 0x1800, + HasSecurity = 0x4000, RequireSecObject = 0x8000} + + /// <summary> + /// Attributes for .pinvokeimpl method declarations + /// </summary> + public enum PInvokeAttr { nomangle = 1, ansi = 2, unicode = 4, autochar = 6, + bestfit_on = 0x0010, bestfit_off = 0x0020, bestfit_mask = 0x0030, + lasterr = 0x0040, winapi = 0x0100, cdecl = 0x0200, + stdcall = 0x0300, thiscall = 0x0400, fastcall = 0x0500, + charmaperror_on = 0x1000, charmaperror_off = 0x2000 + } + + /// <summary> + /// Implementation attributes for a method + /// </summary> + public enum ImplAttr { IL, Native, Runtime = 0x03, Unmanaged = 0x04, + ForwardRef = 0x10, PreserveSig = 0x0080, InternalCall = 0x1000, + Synchronised = 0x0020, Synchronized = 0x0020, NoInLining = 0x0008, Optil = 0x0002} + + /// <summary> + /// Modes for a parameter + /// </summary> + public enum ParamAttr { Default, In, Out, Opt = 16, HasDefault = 0x1000, HasFieldMarshal = 0x2000 } + + /// <summary> + /// CIL instructions + /// </summary> + public enum Op { nop, breakOp, ldarg_0, ldarg_1, ldarg_2, ldarg_3, + ldloc_0, ldloc_1, ldloc_2, ldloc_3, stloc_0, stloc_1, stloc_2, stloc_3, + ldnull = 0x14, ldc_i4_m1, ldc_i4_0, ldc_i4_1, ldc_i4_2, ldc_i4_3, + ldc_i4_4, ldc_i4_5, ldc_i4_6, ldc_i4_7, ldc_i4_8, dup = 0x25, pop, + ret = 0x2A, ldind_i1 = 0x46, ldind_u1, ldind_i2, ldind_u2, ldind_i4, + ldind_u4, ldind_i8, ldind_i, ldind_r4, ldind_r8, ldind_ref, stind_ref, + stind_i1, stind_i2, stind_i4, stind_i8, stind_r4, stind_r8, add, sub, mul, + div, div_un, rem, rem_un, and, or, xor, shl, shr, shr_un, neg, not, + conv_i1, conv_i2, conv_i4, conv_i8, conv_r4, conv_r8, conv_u4, conv_u8, + conv_r_un = 0x76, throwOp = 0x7A, conv_ovf_i1_un = 0x82, conv_ovf_i2_un, + conv_ovf_i4_un, conv_ovf_i8_un, conf_ovf_u1_un, conv_ovf_u2_un, + conv_ovf_u4_un, conv_ovf_u8_un, conv_ovf_i_un, conv_ovf_u_un, + ldlen = 0x8E, ldelem_i1 = 0x90, ldelem_u1, ldelem_i2, ldelem_u2, + ldelem_i4, ldelem_u4, ldelem_i8, ldelem_i, ldelem_r4, ldelem_r8, + ldelem_ref, stelem_i, stelem_i1, stelem_i2, stelem_i4, stelem_i8, stelem_r4 = 0xA0, stelem_r8, + stelem_ref, conv_ovf_i1 = 0xb3, conv_ovf_u1, conv_ovf_i2, conv_ovf_u2, + conv_ovf_i4, conv_ovf_u4, conv_ovf_i8, conv_ovf_u8, ckfinite = 0xC3, + conv_u2 = 0xD1, conv_u1, conv_i, conv_ovf_i, conv_ovf_u, add_ovf, + add_ovf_un, mul_ovf, mul_ovf_un, sub_ovf, sub_ovf_un, endfinally, + stind_i = 0xDF, conv_u, arglist = 0xFE00, ceq, cgt, cgt_un, clt, clt_un, + localloc = 0xFE0F, endfilter = 0xFE11, volatile_ = 0xFE13, tail_, + cpblk = 0xFE17, initblk, rethrow = 0xFE1A, refanytype = 0xFE1D, readonly_ = 0xFE1E } + + /// <summary> + /// CIL instructions requiring an integer parameter + /// </summary> + public enum IntOp {ldarg_s = 0x0E, ldarga_s, starg_s, ldloc_s, ldloca_s, + stloc_s, ldc_i4_s = 0x1F, ldc_i4, ldarg = 0xFE09, + ldarga, starg, ldloc, ldloca, stloc, unaligned = 0xFE12 } + + /// <summary> + /// CIL instructions requiring a field parameter + /// </summary> + public enum FieldOp {ldfld = 0x7B, ldflda, stfld, ldsfld, ldsflda, + stsfld, ldtoken = 0xD0 } + + /// <summary> + /// CIL instructions requiring a method parameter + /// </summary> + public enum MethodOp {jmp = 0x27, call, callvirt = 0x6F, newobj = 0x73, + ldtoken = 0xD0, ldftn = 0xFE06, ldvirtfn } + + /// <summary> + /// CIL instructions requiring a type parameter + /// </summary> + public enum TypeOp {cpobj = 0x70, ldobj, castclass = 0x74, isinst, + unbox = 0x79, stobj = 0x81, box = 0x8C, newarr, + ldelema = 0x8F, refanyval = 0xC2, mkrefany = 0xC6, + ldtoken = 0xD0, initobj = 0xFE15, constrained = 0xFE16, + sizeOf = 0xFE1C, ldelem = 0xA3, stelem = 0xA4, unbox_any } + + /// <summary> + /// CIL branch instructions + /// </summary> + public enum BranchOp { + // short branches + br_s = 0x2B, brfalse_s, brtrue_s, beq_s, bge_s, bgt_s, + ble_s, blt_s, bne_un_s, bge_un_s, bgt_un_s, ble_un_s, blt_un_s, + // long branches + br = 0x38, brfalse, brtrue, beq, bge, bgt, ble, blt, + bne_un, bge_un, bgt_un, ble_un, blt_un, + + leave = 0xDD, leave_s } + + /// <summary> + /// Index for all the tables in the meta data + /// </summary> + public enum MDTable { Module, TypeRef, TypeDef, Field = 0x04, Method = 0x06, + Param = 0x08, InterfaceImpl, MemberRef, Constant, CustomAttribute, + FieldMarshal, DeclSecurity, ClassLayout, FieldLayout, StandAloneSig, + EventMap, Event = 0x14, PropertyMap, Property = 0x17, MethodSemantics, + MethodImpl, ModuleRef, TypeSpec, ImplMap, FieldRVA, Assembly = 0x20, + AssemblyProcessor, AssemblyOS, AssemblyRef, AssemblyRefProcessor, + AssemblyRefOS, File, ExportedType, ManifestResource, NestedClass, + GenericParam, MethodSpec, GenericParamConstraint } + + public enum SafeArrayType { int16 = 2, int32, float32, float64, + currency, date, bstr, dispatch, error, boolean, variant, unknown, + Decimal, int8 = 16, uint8, uint16, uint32, Int = 22, UInt } + + internal enum CIx { TypeDefOrRef, HasConst, HasCustomAttr, HasFieldMarshal, + HasDeclSecurity, MemberRefParent, HasSemantics, MethodDefOrRef, + MemberForwarded, Implementation, CustomAttributeType, ResolutionScope, + TypeOrMethodDef, MaxCIx } + + internal enum MapType { eventMap, propertyMap, nestedClass } + + public enum ValueClass { ValueType, Enum } + + public enum GenParamType : byte { + Var = 0x13, MVar = 0x1E + } + + [Flags] + public enum GenericParamAttributes : ushort { + VarianceMask = 0x0003, + NonVariant = 0x0000, + Covariant = 0x0001, + Contravariant = 0x0002, + + SpecialConstraintMask = 0x001c, + ReferenceTypeConstraint = 0x0004, + NotNullableValueTypeConstraint = 0x0008, + DefaultConstructorConstrait = 0x0010 + } + + /* Taken from Mono.Cecil */ + public enum SecurityAction : short { + Request = 1, + Demand = 2, + Assert = 3, + Deny = 4, + PermitOnly = 5, + LinkDemand = 6, + InheritDemand = 7, + RequestMinimum = 8, + RequestOptional = 9, + RequestRefuse = 10, + PreJitGrant = 11, + PreJitDeny = 12, + NonCasDemand = 13, + NonCasLinkDemand = 14, + NonCasInheritance = 15, + LinkDemandChoice = 16, + InheritDemandChoice = 17, + DemandChoice = 18 + } + + #endregion + + /**************************************************************************/ + /// <summary> + /// Base class for all Meta Data table elements + /// </summary> + + public abstract class MetaDataElement: IComparable { + protected ArrayList customAttributes; + private uint row = 0; + protected bool done = false; + protected MDTable tabIx; + protected bool sortTable = false; + + internal MetaDataElement() { } + + public uint Row { + get { + return row; + } + set { + row = value; + } + } + + internal virtual uint GetCodedIx(CIx code) { return 0; } + + /// <summary> + /// Add a custom attribute to this item + /// </summary> + /// <param name="ctorMeth">the constructor method for this attribute</param> + /// <param name="val">the byte value of the parameters</param> + public void AddCustomAttribute(Method ctorMeth, byte[] val) + { + if (customAttributes == null) { + customAttributes = new ArrayList(); + } + customAttributes.Add(new CustomAttribute(this,ctorMeth,val)); + } + + /// <summary> + /// Add a custom attribute to this item + /// </summary> + /// <param name="ctorMeth">the constructor method for this attribute</param> + /// <param name="val">the constant values of the parameters</param> + public void AddCustomAttribute(Method ctorMeth, Constant[] cVals) + { + if (customAttributes == null) { + customAttributes = new ArrayList(); + } + // customAttributes.Add(new CustomAttribute(this,ctorMeth,cVals)); + } + + internal uint Token() + { + return (((uint)tabIx << 24) | row); + } + + internal virtual void BuildTables(MetaData md) + { + done = true; + } + + internal virtual uint Size(MetaData md) + { + return 0; + } + + internal virtual void Write(FileImage output) { } + + internal virtual uint SortKey() + { + throw new PEFileException("Trying to sort table of " + this); + //return 0; + } + + internal virtual uint SortKey2() + { + return 0; + } + + public int CompareTo(object obj) + { + uint otherKey = ((MetaDataElement)obj).SortKey(); + uint thisKey = SortKey(); + + if (thisKey == otherKey) { + + otherKey = ((MetaDataElement)obj).SortKey2(); + thisKey = SortKey2(); + if (thisKey == otherKey) + return 0; + if (thisKey < otherKey) + return -1; + return 1; + } + if (thisKey < otherKey) return -1; + + return 1; + } + + } + + /**************************************************************************/ + /// <summary> + /// Layout information for a class (.class [sequential | explicit]) + /// </summary> + internal class ClassLayout : MetaDataElement { + + ClassDef parent; + ushort packSize = 0; + uint classSize = 0; + + internal ClassLayout(int pack, int cSize, ClassDef par) + { + packSize = (ushort)pack; + classSize = (uint)cSize; + parent = par; + tabIx = MDTable.ClassLayout; + } + + internal sealed override uint Size(MetaData md) + { + return 6 + md.TableIndexSize(MDTable.TypeDef); + } + + internal sealed override void Write(FileImage output) + { + output.Write(packSize); + output.Write(classSize); + output.WriteIndex(MDTable.TypeDef,parent.Row); + } + + } + + /**************************************************************************/ + /// <summary> + /// Summary description for ConstantElem. + /// </summary> + internal class ConstantElem : MetaDataElement { + + MetaDataElement parent; + Constant cValue; + uint valIx = 0; + + internal ConstantElem(MetaDataElement parent, Constant val) + { + this.parent = parent; + cValue = val; + tabIx = MDTable.Constant; + sortTable = true; + } + + internal override uint SortKey() + { + return (parent.Row << MetaData.CIxShiftMap[(uint)CIx.HasConst]) + | parent.GetCodedIx(CIx.HasConst); + } + + internal sealed override void BuildTables(MetaData md) + { + if (done) return; + valIx = cValue.GetBlobIndex(md); + done = true; + } + + internal void AddToBlob(BinaryWriter bw) + { + cValue.Write(bw); + } + + internal sealed override uint Size(MetaData md) + { + return 2 + md.CodedIndexSize(CIx.HasConst) + md.BlobIndexSize(); + } + + internal sealed override void Write(FileImage output) + { + output.Write(cValue.GetTypeIndex()); + output.Write((byte)0); + output.WriteCodedIndex(CIx.HasConst,parent); + output.BlobIndex(valIx); + } + + } + /**************************************************************************/ + /// <summary> + /// Descriptor for a Custom Attribute (.custom) + /// </summary> + + public class CustomAttribute : MetaDataElement { + + private static readonly ushort prolog = 0x0001; + MetaDataElement parent; + Method type; + uint valIx; + Constant cVal; + byte[] byteVal; + ushort numNamed = 0; + ArrayList names, vals; + + internal CustomAttribute(MetaDataElement paren, Method constrType, + Constant val) { + parent = paren; + type = constrType; + cVal = val; + tabIx = MDTable.CustomAttribute; + } + + internal CustomAttribute(MetaDataElement paren, Method constrType, + byte[] val) { + parent = paren; + type = constrType; + tabIx = MDTable.CustomAttribute; + byteVal = val; + } + + internal override uint SortKey() + { + return (parent.Row << MetaData.CIxShiftMap[(uint)CIx.HasCustomAttr]) + | parent.GetCodedIx(CIx.HasCustomAttr); + } + + public void AddFieldOrProp(string name, Constant val) + { + if (numNamed == 0) { + names = new ArrayList(); + vals = new ArrayList(); + } + names.Add(name); + vals.Add(val); + } + + internal sealed override void BuildTables(MetaData md) + { + BinaryWriter bw = new BinaryWriter(new MemoryStream()); + bw.Write(byteVal); + md.AddToTable(MDTable.CustomAttribute, this); + MemoryStream str = (MemoryStream)bw.BaseStream; + valIx = md.AddToBlobHeap(str.ToArray()); + } + + internal sealed override uint Size(MetaData md) + { + return md.CodedIndexSize(CIx.HasCustomAttr) + md.CodedIndexSize(CIx.CustomAttributeType) + md.BlobIndexSize(); + } + + internal sealed override void Write(FileImage output) + { + output.WriteCodedIndex(CIx.HasCustomAttr,parent); + output.WriteCodedIndex(CIx.CustomAttributeType,type); + output.BlobIndex(valIx); + } + + } + + /**************************************************************************/ + /// <summary> + /// Descriptor for security permissions for a class or a method + /// </summary> + + public class DeclSecurity : MetaDataElement { + + ushort action; + MetaDataElement parent; + uint permissionIx; + byte [] byteVal; + + internal DeclSecurity(MetaDataElement paren, ushort act, byte [] val) + { + parent = paren; + action = act; + tabIx = MDTable.DeclSecurity; + byteVal = val; + } + + internal override uint SortKey() + { + return (parent.Row << MetaData.CIxShiftMap[(uint)CIx.HasDeclSecurity]) + | parent.GetCodedIx(CIx.HasDeclSecurity); + } + + internal sealed override uint Size(MetaData md) + { + return 2 + md.CodedIndexSize(CIx.HasDeclSecurity) + md.BlobIndexSize(); + } + + internal sealed override void BuildTables(MetaData md) + { + if (done) return; + BinaryWriter bw = new BinaryWriter (new MemoryStream ()); + bw.Write (byteVal); + md.AddToTable (MDTable.DeclSecurity, this); + MemoryStream str = (MemoryStream)bw.BaseStream; + permissionIx = md.AddToBlobHeap(str.ToArray()); + + done = true; + } + + internal sealed override void Write(FileImage output) + { + output.Write(action); + output.WriteCodedIndex(CIx.HasDeclSecurity,parent); + output.BlobIndex(permissionIx); + } + + } + + /**************************************************************************/ + /// <summary> + /// Descriptor for layout information for a field + /// </summary> + + public class FieldLayout : MetaDataElement { + + Field field; + uint offset; + + internal FieldLayout(Field field, uint offset) + { + this.field = field; + this.offset = offset; + tabIx = MDTable.FieldLayout; + } + + internal sealed override uint Size(MetaData md) + { + return 4 + md.TableIndexSize(MDTable.Field); + } + + internal sealed override void Write(FileImage output) + { + output.Write(offset); + output.WriteIndex(MDTable.Field,field.Row); + } + + } + + /*****************************************************************************/ + /// <summary> + /// Marshalling information for a field or param + /// </summary> + public class FieldMarshal : MetaDataElement { + + MetaDataElement field; + NativeType nt; + uint ntIx; + + internal FieldMarshal(MetaDataElement field, NativeType nType) + { + this.field = field; + this.nt = nType; + tabIx = MDTable.FieldMarshal; + } + + internal override uint SortKey() + { + return (field.Row << MetaData.CIxShiftMap[(uint)CIx.HasFieldMarshal]) + | field.GetCodedIx(CIx.HasFieldMarshal); + } + + internal sealed override void BuildTables(MetaData md) + { + if (done) return; + ntIx = md.AddToBlobHeap(nt.ToBlob()); + done = true; + } + + internal sealed override uint Size(MetaData md) + { + return md.CodedIndexSize(CIx.HasFieldMarshal) + md.BlobIndexSize(); + } + + internal sealed override void Write(FileImage output) + { + output.WriteCodedIndex(CIx.HasFieldMarshal,field); + output.BlobIndex(ntIx); + } + + } + + /**************************************************************************/ + /// <summary> + /// Descriptor for the address of a field's value in the PE file + /// </summary> + public class FieldRVA : MetaDataElement { + + Field field; + DataConstant data; + + internal FieldRVA(Field field, DataConstant data) + { + this.field = field; + this.data = data; + tabIx = MDTable.FieldRVA; + } + + internal sealed override void BuildTables(MetaData md) + { + if (done) return; + md.AddData(data); + done = true; + } + + internal sealed override uint Size(MetaData md) + { + return 4 + md.TableIndexSize(MDTable.Field); + } + + internal sealed override void Write(FileImage output) + { + output.WriteDataRVA(data.DataOffset); + output.WriteIndex(MDTable.Field,field.Row); + } + + } + + /**************************************************************************/ + /// <summary> + /// Descriptor for a file referenced in THIS assembly/module (.file) + /// </summary> + public class FileRef : MetaDataElement { + + private static readonly uint NoMetaData = 0x1; + uint nameIx = 0, hashIx = 0; + uint flags = 0; + protected string name; + + internal FileRef(string name, byte[] hashBytes, bool metaData, + bool entryPoint, MetaData md) { + if (!metaData) flags = NoMetaData; + if (entryPoint) md.SetEntryPoint(this); + this.name = name; + nameIx = md.AddToStringsHeap(name); + hashIx = md.AddToBlobHeap(hashBytes); + tabIx = MDTable.File; + } + + internal FileRef(uint nameIx, byte[] hashBytes, bool metaData, + bool entryPoint, MetaData md) { + if (!metaData) flags = NoMetaData; + if (entryPoint) md.SetEntryPoint(this); + this.nameIx = nameIx; + hashIx = md.AddToBlobHeap(hashBytes); + tabIx = MDTable.File; + } + + internal sealed override uint Size(MetaData md) + { + return 4 + md.StringsIndexSize() + md.BlobIndexSize(); + } + + internal sealed override void BuildTables(MetaData md) + { + md.AddToTable(MDTable.File,this); + } + + internal sealed override void Write(FileImage output) + { + output.Write(flags); + output.StringsIndex(nameIx); + output.BlobIndex(hashIx); + } + + internal sealed override uint GetCodedIx(CIx code) + { + switch (code) { + case (CIx.HasCustomAttr) : return 16; + case (CIx.Implementation) : return 0; + } + return 0; + } + + } + /**************************************************************************/ + /// <summary> + /// Descriptor for pinvoke information for a method NOT YET IMPLEMENTED + /// </summary> + public class ImplMap : MetaDataElement { + + private static readonly ushort NoMangle = 0x01; + ushort flags; + Method meth; + string importName; + uint iNameIx; + ModuleRef importScope; + + internal ImplMap(ushort flag, Method implMeth, string iName, ModuleRef mScope) + { + flags = flag; + meth = implMeth; + importName = iName; + importScope = mScope; + tabIx = MDTable.ImplMap; + if (iName == null) flags |= NoMangle; + //throw(new NotYetImplementedException("PInvoke ")); + } + + internal override uint SortKey() + { + return (meth.Row << MetaData.CIxShiftMap[(uint)CIx.MemberForwarded]) + | meth.GetCodedIx(CIx.MemberForwarded); + } + + internal sealed override void BuildTables(MetaData md) + { + if (done) return; + iNameIx = md.AddToStringsHeap(importName); + done = true; + } + + internal sealed override uint Size(MetaData md) + { + return 2+ md.CodedIndexSize(CIx.MemberForwarded) + + md.StringsIndexSize() + md.TableIndexSize(MDTable.ModuleRef); + } + + internal sealed override void Write(FileImage output) + { + output.Write(flags); + output.WriteCodedIndex(CIx.MemberForwarded,meth); + output.StringsIndex(iNameIx); + output.WriteIndex(MDTable.ModuleRef,importScope.Row); + } + + } + + /**************************************************************************/ + + public class GenericParameter : MetaDataElement { + + MetaDataElement owner; + MetaData metadata; + public string name; + uint nameIx; + short index; + GenericParamAttributes attr; + + internal GenericParameter (ClassDef owner, MetaData metadata, + short index, string name, GenericParamAttributes attr) : this (owner, metadata, index, name, attr, true) + { + } + + internal GenericParameter (MethodDef owner, MetaData metadata, + short index, string name, GenericParamAttributes attr) : this (owner, metadata, index, name, attr, true) + { + } + + private GenericParameter (MetaDataElement owner, MetaData metadata, + short index, string name, GenericParamAttributes attr, bool nadda) { + this.owner = owner; + this.metadata = metadata; + this.index = index; + tabIx = MDTable.GenericParam; + this.name = name; + this.attr = attr; + } + + internal override uint SortKey() + { + return (owner.Row << MetaData.CIxShiftMap[(uint)CIx.TypeOrMethodDef]) + | owner.GetCodedIx(CIx.TypeOrMethodDef); + } + + internal override uint SortKey2 () + { + return (uint) index; + } + + public void AddConstraint (Type constraint) + { + metadata.AddToTable (MDTable.GenericParamConstraint, + new GenericParamConstraint (this, constraint)); + } + + internal sealed override uint Size(MetaData md) + { + return (uint) (4 + + md.CodedIndexSize(CIx.TypeOrMethodDef) + + md.StringsIndexSize ()); + } + + internal sealed override void BuildTables(MetaData md) + { + if (done) return; + nameIx = md.AddToStringsHeap(name); + done = true; + } + + internal sealed override void Write(FileImage output) + { + output.Write ((short) index); + output.Write ((short) attr); + output.WriteCodedIndex(CIx.TypeOrMethodDef, owner); + output.StringsIndex (nameIx); + } + + internal sealed override uint GetCodedIx(CIx code) + { + switch (code) { + case (CIx.HasCustomAttr) : return 19; + } + return 0; + } + + } + + internal class GenericParamConstraint : MetaDataElement { + + GenericParameter param; + Type type; + + public GenericParamConstraint (GenericParameter param, Type type) + { + this.param = param; + this.type = type; + tabIx = MDTable.GenericParamConstraint; + } + + internal override uint SortKey() + { + return param.Row; + } + + internal sealed override uint Size(MetaData md) + { + return (uint) (md.TableIndexSize(MDTable.GenericParam) + + md.CodedIndexSize(CIx.TypeDefOrRef)); + } + + internal sealed override void Write(FileImage output) + { + output.WriteIndex(MDTable.GenericParam, param.Row); + output.WriteCodedIndex(CIx.TypeDefOrRef, type); + } + + } + + internal class MethodSpec : Method { + + Method meth; + GenericMethodSig g_sig; + uint sidx; + + internal MethodSpec (Method meth, GenericMethodSig g_sig) : base ("") + { + this.meth = meth; + this.g_sig = g_sig; + tabIx = MDTable.MethodSpec; + } + + internal override uint GetSigIx (MetaData md) + { + throw new Exception ("Should not be used."); + } + + public override void AddCallConv (CallConv cconv) + { + throw new Exception ("Should not be used."); + } + + internal sealed override void BuildTables (MetaData md) + { + if (done) return; + sidx = g_sig.GetSigIx (md); + done = true; + } + + internal sealed override uint Size (MetaData md) + { + return (uint) (md.CodedIndexSize(CIx.MethodDefOrRef) + + md.BlobIndexSize ()); + } + + internal sealed override void Write (FileImage output) + { + output.WriteCodedIndex (CIx.MethodDefOrRef, meth); + output.BlobIndex (sidx); + } + + internal sealed override void TypeSig (MemoryStream sig) + { + throw new Exception ("Should not be used."); + } + } + + /**************************************************************************/ + /// <summary> + /// Descriptor for interface implemented by a class + /// </summary> + public class InterfaceImpl: MetaDataElement { + + ClassDef theClass; + Class theInterface; + + internal InterfaceImpl(ClassDef theClass, Class theInterface) + { + this.theClass = theClass; + this.theInterface = theInterface; + tabIx = MDTable.InterfaceImpl; + } + + internal sealed override uint Size(MetaData md) + { + return md.TableIndexSize(MDTable.TypeDef) + + md.CodedIndexSize(CIx.TypeDefOrRef); + } + + internal sealed override void Write(FileImage output) + { + output.WriteIndex(MDTable.TypeDef,theClass.Row); + output.WriteCodedIndex(CIx.TypeDefOrRef,theInterface); + } + + internal sealed override uint GetCodedIx(CIx code) { return 5; } + + internal override uint SortKey () + { + return (theClass.Row << MetaData.CIxShiftMap[(uint)CIx.TypeDefOrRef]) + | theClass.GetCodedIx (CIx.TypeDefOrRef); + } + + } + + /**************************************************************************/ + /// <summary> + /// Descriptor for resources used in this PE file + /// </summary> + + public class ManifestResource : MetaDataElement { + + public static readonly uint PublicResource = 0x1; + public static readonly uint PrivateResource = 0x2; + + string mrName; + MetaDataElement rRef; + uint fileOffset; + uint nameIx = 0; + uint flags = 0; + byte [] resourceBytes; + + public ManifestResource (string name, byte[] resBytes, uint flags) + { + InitResource (name, flags); + this.resourceBytes = resBytes; + } + + public ManifestResource(string name, uint flags, FileRef fileRef) + { + InitResource (name, flags); + rRef = fileRef; + } + + public ManifestResource(string name, uint flags, FileRef fileRef, + uint fileIx) { + InitResource (name, flags); + rRef = fileRef; + fileOffset = fileIx; + } + + public ManifestResource(string name, uint flags, AssemblyRef assemRef) + { + InitResource (name, flags); + rRef = assemRef; + } + + internal ManifestResource (ManifestResource mres) + { + mrName = mres.mrName; + flags = mres.flags; + rRef = mres.rRef; + fileOffset = mres.fileOffset; + resourceBytes = mres.resourceBytes; + } + + private void InitResource (string name, uint flags) + { + mrName = name; + this.flags = flags; + tabIx = MDTable.ManifestResource; + } + + internal sealed override void BuildTables(MetaData md) + { + if (done) return; + md.AddToTable (MDTable.ManifestResource, this); + nameIx = md.AddToStringsHeap(mrName); + if (resourceBytes != null) { + if (rRef != null) + throw new PEFileException ("Manifest Resource has byte value and file reference"); + fileOffset = md.AddResource(resourceBytes); + } else { + if (rRef == null) + throw new PEFileException ("Manifest Resource has no implementation or value"); + rRef.BuildTables (md); + } + + done = true; + } + + internal sealed override uint Size(MetaData md) + { + return 8 + md.StringsIndexSize() + + md.CodedIndexSize(CIx.Implementation); + } + + internal sealed override void Write(FileImage output) + { + output.Write(fileOffset); + output.Write(flags); + output.StringsIndex(nameIx); + output.WriteCodedIndex(CIx.Implementation,rRef); + } + + internal sealed override uint GetCodedIx(CIx code) { return 18; } + + public string Name { + get { return mrName; } + set { mrName = value; } + } + + } + /**************************************************************************/ + /// <summary> + /// Base class for elements in the PropertyMap, EventMap and + /// NestedClass MetaData tables + /// </summary> + public class MapElem : MetaDataElement { + + ClassDef parent; + uint elemIx; + MDTable elemTable; + + internal MapElem(ClassDef par, uint elIx, MDTable elemTab) + { + parent = par; + elemIx = elIx; + elemTable = elemTab; + } + + internal sealed override uint Size(MetaData md) + { + return md.TableIndexSize(MDTable.TypeDef) + md.TableIndexSize(elemTable); + } + + internal sealed override void Write(FileImage output) + { + output.WriteIndex(MDTable.TypeDef,parent.Row); + output.WriteIndex(elemTable,elemIx); + } + } + + /**************************************************************************/ + /// <summary> + /// Descriptor for an overriding method (.override) + /// </summary> + public class MethodImpl : MetaDataElement { + + ClassDef parent; + Method header, body; + + internal MethodImpl(ClassDef par, Method decl, Method bod) + { + parent = par; + header = decl; + body = bod; + tabIx = MDTable.MethodImpl; + } + + internal sealed override uint Size(MetaData md) + { + return md.TableIndexSize(MDTable.TypeDef) + 2 * md.CodedIndexSize(CIx.MethodDefOrRef); + } + + internal sealed override void Write(FileImage output) + { + output.WriteIndex(MDTable.TypeDef,parent.Row); + output.WriteCodedIndex(CIx.MethodDefOrRef,body); + output.WriteCodedIndex(CIx.MethodDefOrRef,header); + } + + } + + /**************************************************************************/ + /// <summary> + /// Descriptor for Property and Event methods + /// </summary> + public class MethodSemantics : MetaDataElement { + + Feature.MethodType type; + MethodDef meth; + Feature eventOrProp; + + internal MethodSemantics(Feature.MethodType mType, MethodDef method, Feature feature) + { + type = mType; + meth = method; + eventOrProp = feature; + tabIx = MDTable.MethodSemantics; + } + + internal override uint SortKey() + { + return (eventOrProp.Row << MetaData.CIxShiftMap [(uint)CIx.HasSemantics]) + | eventOrProp.GetCodedIx (CIx.HasSemantics); + } + + internal sealed override uint Size(MetaData md) + { + return 2 + md.TableIndexSize(MDTable.Method) + md.CodedIndexSize(CIx.HasSemantics); + } + + internal sealed override void Write(FileImage output) + { + output.Write((ushort)type); + output.WriteIndex(MDTable.Method,meth.Row); + output.WriteCodedIndex(CIx.HasSemantics,eventOrProp); + } + + } + + /**************************************************************************/ + /// <summary> + /// Descriptor for a parameter of a method defined in this assembly/module + /// </summary> + public class Param : MetaDataElement { + + + Type pType; + string pName; + internal ushort seqNo = 0; + ushort parMode; + ConstantElem defaultVal; + uint nameIx = 0; + FieldMarshal marshalInfo; + + /// <summary> + /// Create a new parameter for a method + /// </summary> + /// <param name="mode">param mode (in, out, opt)</param> + /// <param name="parName">parameter name</param> + /// <param name="parType">parameter type</param> + public Param(ParamAttr mode, string parName, Type parType) + { + pName = parName; + pType = parType; + parMode = (ushort)mode; + tabIx = MDTable.Param; + } + + /// <summary> + /// Add a default value to this parameter + /// </summary> + /// <param name="c">the default value for the parameter</param> + public void AddDefaultValue(Constant cVal) + { + defaultVal = new ConstantElem(this,cVal); + parMode |= (ushort) ParamAttr.HasDefault; + } + + /// <summary> + /// Add marshalling information about this parameter + /// </summary> + public void AddMarshallInfo(NativeType marshallType) + { + parMode |= (ushort) ParamAttr.HasFieldMarshal; + marshalInfo = new FieldMarshal(this,marshallType); + } + + internal Type GetParType() { return pType; } + + internal sealed override void BuildTables(MetaData md) + { + if (done) return; + nameIx = md.AddToStringsHeap(pName); + if (defaultVal != null) { + md.AddToTable(MDTable.Constant,defaultVal); + defaultVal.BuildTables(md); + } + if (marshalInfo != null) { + md.AddToTable(MDTable.FieldMarshal,marshalInfo); + marshalInfo.BuildTables(md); + } + done = true; + } + + internal void TypeSig(MemoryStream str) + { + pType.TypeSig(str); + } + + internal sealed override uint Size(MetaData md) + { + return 4 + md.StringsIndexSize(); + } + + internal sealed override void Write(FileImage output) + { + output.Write(parMode); + output.Write(seqNo); + output.StringsIndex(nameIx); + } + + internal sealed override uint GetCodedIx(CIx code) + { + switch (code) { + case (CIx.HasCustomAttr) : return 4; + case (CIx.HasConst) : return 1; + case (CIx.HasFieldMarshal) : return 1; + } + return 0; + } + + } + + /**************************************************************************/ + public abstract class Signature : MetaDataElement { + + protected uint sigIx; + + internal Signature() + { + tabIx = MDTable.StandAloneSig; + } + + internal sealed override uint Size(MetaData md) + { + return md.BlobIndexSize(); + } + + internal sealed override void Write(FileImage output) + { + output.BlobIndex(sigIx); + } + + internal sealed override uint GetCodedIx(CIx code) { return (uint)tabIx; } + + } + + /**************************************************************************/ + public class TypeSpec : MetaDataElement { + uint sigIx = 0; + + internal TypeSpec(Type aType, MetaData md) + { + MemoryStream sig = new MemoryStream(); + aType.TypeSig(sig); + sigIx = md.AddToBlobHeap(sig.ToArray()); + tabIx = MDTable.TypeSpec; + } + + internal sealed override uint GetCodedIx(CIx code) + { + switch (code) { + case (CIx.TypeDefOrRef) : return 2; + case (CIx.HasCustomAttr) : return 13; + case (CIx.MemberRefParent) : return 4; + } + return 0; + } + + internal override uint Size(MetaData md) + { + return md.BlobIndexSize(); + } + + internal sealed override void Write(FileImage output) + { + //Console.WriteLine("Writing the blob index for a TypeSpec"); + output.BlobIndex(sigIx); + } + } + + + /**************************************************************************/ + /// <summary> + /// Base class for all IL types + /// </summary> + public abstract class Type : MetaDataElement { + protected byte typeIndex; + protected TypeSpec typeSpec; + + internal Type(byte tyIx) { typeIndex = tyIx; } + + internal byte GetTypeIndex() { return typeIndex; } + internal void SetTypeIndex (byte b) { typeIndex = b; } + + internal virtual MetaDataElement GetTypeSpec(MetaData md) + { + if (typeSpec == null) { + typeSpec = new TypeSpec(this,md); + md.AddToTable(MDTable.TypeSpec,typeSpec); + } + return typeSpec; + } + + internal virtual void TypeSig(MemoryStream str) + { + throw(new TypeSignatureException(this.GetType().AssemblyQualifiedName + + " doesn't have a type signature!!")); + } + } + + public class ClassRefInst : Type { + + private Type type; + private bool is_value; + + public ClassRefInst (Type type, bool is_value) : base (PrimitiveType.Class.GetTypeIndex ()) + { + this.type = type; + this.is_value = is_value; + if (is_value) + typeIndex = PrimitiveType.ValueType.GetTypeIndex (); + tabIx = MDTable.TypeSpec; + } + + internal sealed override void TypeSig(MemoryStream str) + { + type.TypeSig (str); + } + } + + /**************************************************************************/ + /// <summary> + /// The base descriptor for a class + /// </summary> + public abstract class Class : Type { + + protected int row = 0; + public string name, nameSpace; + protected uint nameIx, nameSpaceIx; + protected MetaData _metaData; + internal Class(string nameSpaceName, string className, MetaData md) + : base(PrimitiveType.Class.GetTypeIndex ()) + { + nameSpace = nameSpaceName; + name = className; + nameIx = md.AddToStringsHeap(name); + nameSpaceIx = md.AddToStringsHeap(nameSpace); + _metaData = md; + } + + internal Class(uint nsIx, uint nIx) : base(PrimitiveType.Class.GetTypeIndex ()) + { + nameSpaceIx = nsIx; + nameIx = nIx; + } + + internal Class (byte typeIndex) : base (typeIndex) + { + nameSpace = "Should not be used"; + name = "Should not be used"; + } + + internal virtual uint TypeDefOrRefToken() { return 0; } + + internal virtual void MakeValueClass(ValueClass vClass) + { + typeIndex = PrimitiveType.ValueType.GetTypeIndex (); + } + + internal virtual string TypeName() + { + return (nameSpace + "." + name); + } + + internal override MetaDataElement GetTypeSpec(MetaData md) + { + return this; + } + } + + /**************************************************************************/ + // This Class produces entries in the TypeDef table of the MetaData + // in the PE meta data. + + // NOTE: Entry 0 in TypeDef table is always the pseudo class <module> + // which is the parent for functions and variables declared a module level + + /// <summary> + /// The descriptor for a class defined in the IL (.class) in the current assembly/module + /// </summary> + /// + public class ClassDef : Class { + + private static readonly byte ElementType_Class = 0x12; + + Class superType; + ArrayList fields = new ArrayList(); + ArrayList methods = new ArrayList(); + ArrayList events; + ArrayList properties; + bool typeIndexChecked = true; + uint fieldIx = 0, methodIx = 0; + byte[] securityActions; + uint flags; + ClassLayout layout; + ClassDef parentClass; + MetaData metaData; + + internal ClassDef(TypeAttr attrSet, string nsName, string name, + MetaData md) : base(nsName, name, md) + { + metaData = md; + if (! ((nsName == "" && name == "<Module>") || (nsName == "System" && name == "Object")) ) { + superType = metaData.mscorlib.GetSpecialSystemClass(PrimitiveType.Object); + } + flags = (uint)attrSet; + tabIx = MDTable.TypeDef; + } + + internal void SetSuper(Class sClass) + { + superType = sClass; + if (! (sClass is GenericTypeInst)) + typeIndexChecked = false; + } + + internal override void MakeValueClass(ValueClass vClass) + { + if (vClass == ValueClass.Enum) + superType = metaData.mscorlib.EnumType(); + else + superType = metaData.mscorlib.ValueType(); + + typeIndex = PrimitiveType.ValueType.GetTypeIndex (); + } + + public void SpecialNoSuper() + { + superType = null; + } + + /// <summary> + /// Add an attribute to this class + /// </summary> + /// <param name="ta">the attribute to be added</param> + public void AddAttribute(TypeAttr ta) + { + flags |= (uint)ta; + } + + /// <summary> + /// Add an interface that is implemented by this class + /// </summary> + /// <param name="iFace">the interface that is implemented</param> + public void AddImplementedInterface(Class iFace) + { + metaData.AddToTable(MDTable.InterfaceImpl,new InterfaceImpl(this,iFace)); + } + + /// <summary> + /// Add a named generic type parameter + /// </summary> + public GenericParameter AddGenericParameter (short index, string name) + { + return AddGenericParameter (index, name, 0); + } + + /// <summary> + /// Add a named generic type parameter with attributes + /// </summary> + public GenericParameter AddGenericParameter (short index, string name, GenericParamAttributes attr) + { + GenericParameter gp = new GenericParameter (this, metaData, index, name, attr); + metaData.AddToTable (MDTable.GenericParam, gp); + return gp; + } + + /// <summary> + /// Add a field to this class + /// </summary> + /// <param name="name">field name</param> + /// <param name="fType">field type</param> + /// <returns>a descriptor for this new field</returns> + public FieldDef AddField(string name, Type fType) + { + FieldDef field = new FieldDef(name,fType); + fields.Add(field); + return field; + } + + /// <summary> + /// Add a field to this class + /// </summary> + /// <param name="fAtts">attributes for this field</param> + /// <param name="name">field name</param> + /// <param name="fType">field type</param> + /// <returns>a descriptor for this new field</returns> + public FieldDef AddField(FieldAttr fAtts, string name, Type fType) + { + FieldDef field = new FieldDef(fAtts,name,fType); + fields.Add(field); + return field; + } + + public void SetFieldOrder (ArrayList fields) + { + this.fields = fields; + } + + /// <summary> + /// Add a method to this class + /// </summary> + /// <param name="name">method name</param> + /// <param name="retType">return type</param> + /// <param name="pars">parameters</param> + /// <returns>a descriptor for this new method</returns> + public MethodDef AddMethod(string name, Type retType, Param[] pars) + { + // Console.WriteLine("Adding method " + name + " to class " + this.name); + MethodDef meth = new MethodDef(metaData,name,retType, pars); + methods.Add(meth); + return meth; + } + + /// <summary> + /// Add a method to this class + /// </summary> + /// <param name="mAtts">attributes for this method</param> + /// <param name="iAtts">implementation attributes for this method</param> + /// <param name="name">method name</param> + /// <param name="retType">return type</param> + /// <param name="pars">parameters</param> + /// <returns>a descriptor for this new method</returns> + public MethodDef AddMethod(MethAttr mAtts, ImplAttr iAtts, string name, + Type retType, Param[] pars) { + // Console.WriteLine("Adding method " + name + " to class " + this.name); + MethodDef meth = new MethodDef(metaData,mAtts,iAtts,name,retType,pars); + methods.Add(meth); + return meth; + } + + /// <summary> + /// Add an event to this class + /// </summary> + /// <param name="name">event name</param> + /// <param name="eType">event type</param> + /// <returns>a descriptor for this new event</returns> + public Event AddEvent(string name, Type eType) + { + Event e = new Event(name,eType,this); + if (events == null) events = new ArrayList(); + events.Add(e); + return e; + } + + /// <summary> + /// Add a property to this class + /// </summary> + /// <param name="name">property name</param> + /// <param name="propType">property type</param> + /// <returns>a descriptor for this new property</returns> + public Property AddProperty(string name, Type retType, Type[] pars) + { + Property p = new Property(name, retType, pars, this); + if (properties == null) properties = new ArrayList(); + properties.Add(p); + return p; + } + + /// <summary> + /// Add a nested class to this class + /// </summary> + /// <param name="attrSet">attributes for this nested class</param> + /// <param name="nsName">nested name space name</param> + /// <param name="name">nested class name</param> + /// <returns>a descriptor for this new nested class</returns> + public ClassDef AddNestedClass(TypeAttr attrSet, string nsName, + string name) { + ClassDef nClass = new ClassDef(attrSet,"",name,metaData); + metaData.AddToTable(MDTable.TypeDef,nClass); + metaData.AddToTable(MDTable.NestedClass,new MapElem(nClass,Row,MDTable.TypeDef)); + nClass.parentClass = this; + return (nClass); + } + + public static bool IsValueType (Class type) + { + return IsValueType (type.nameSpace, type.name); + } + + public static bool IsEnum (Class type) + { + return IsEnum (type.nameSpace, type.name); + } + + public static bool IsValueType (string nsName, string name) + { + return (nsName == "System" && name == "ValueType"); + } + + public static bool IsEnum (string nsName, string name) + { + return (nsName == "System" && name == "Enum"); + } + + /// <summary> + /// Add a nested class to this class + /// </summary> + /// <param name="attrSet">attributes for this nested class</param> + /// <param name="nsName">nested name space name</param> + /// <param name="name">nested class name</param> + /// <param name="sType">super type of this nested class</param> + /// <returns>a descriptor for this new nested class</returns> + public ClassDef AddNestedClass(TypeAttr attrSet, string nsName, + string name, Class sType) { + ClassDef nClass = AddNestedClass (attrSet, nsName, name); + nClass.SetSuper(sType); + if (ClassDef.IsValueType (sType)) + nClass.MakeValueClass (ValueClass.ValueType); + else + if (ClassDef.IsEnum (sType)) + nClass.MakeValueClass (ValueClass.Enum); + + if (ClassDef.IsValueType (sType) || ClassDef.IsEnum (sType)) + nClass.SetTypeIndex (PrimitiveType.ValueType.GetTypeIndex ()); + + nClass.typeIndexChecked = true; + return (nClass); + } + + /// <summary> + /// Add layout information for this class. This class must have the + /// sequential or explicit attribute. + /// </summary> + /// <param name="packSize">packing size (.pack)</param> + /// <param name="classSize">class size (.size)</param> + public void AddLayoutInfo (int packSize, int classSize) + { + layout = new ClassLayout(packSize,classSize,this); + } + + /// <summary> + /// Use a method as the implementation for another method (.override) + /// </summary> + /// <param name="decl">the method to be overridden</param> + /// <param name="body">the implementation to be used</param> + public void AddMethodOverride(Method decl, Method body) + { + metaData.AddToTable(MDTable.MethodImpl,new MethodImpl(this,decl,body)); + } + + /// <summary> + /// Add security to this class NOT YET IMPLEMENTED + /// </summary> + /// <param name="permissionSet"></param> + public void AddSecurity(byte[] permissionSet) + { + throw(new NotYetImplementedException("Class security ")); + //flags |= HasSecurity; + // securityActions = permissionSet; + } + + //public void AddLineInfo(int row, int col) { } + + internal void CheckTypeIndex() + { + if (typeIndexChecked) return; + if (superType is ClassDef) + ((ClassDef)superType).CheckTypeIndex(); + typeIndex = superType.GetTypeIndex(); + typeIndexChecked = true; + } + + internal sealed override void BuildTables(MetaData md) + { + if (done) return; + if ((flags & (uint)TypeAttr.Interface) != 0) { superType = null; } + // Console.WriteLine("Building tables for " + name); + if (layout != null) md.AddToTable(MDTable.ClassLayout,layout); + // Console.WriteLine("adding methods " + methods.Count); + methodIx = md.TableIndex(MDTable.Method); + for (int i=0; i < methods.Count; i++) { + md.AddToTable(MDTable.Method,(MetaDataElement)methods[i]); + ((MethodDef)methods[i]).BuildTables(md); + } + // Console.WriteLine("adding fields"); + fieldIx = md.TableIndex(MDTable.Field); + for (int i=0; i < fields.Count; i++) { + md.AddToTable(MDTable.Field,(MetaDataElement)fields[i]); + ((FieldDef)fields[i]).BuildTables(md); + } + // Console.WriteLine("adding events and properties"); + if (events != null) { + for (int i=0; i < events.Count; i++) { + md.AddToTable(MDTable.Event,(Event)events[i]); + ((Event)events[i]).BuildTables(md); + } + md.AddToTable(MDTable.EventMap, + new MapElem(this,((Event)events[0]).Row,MDTable.Event)); + } + if (properties != null) { + for (int i=0; i < properties.Count; i++) { + md.AddToTable(MDTable.Property,(Property)properties[i]); + ((Property)properties[i]).BuildTables(md); + } + md.AddToTable(MDTable.PropertyMap,new MapElem(this, + ((Property)properties[0]).Row,MDTable.Property)); + } + // Console.WriteLine("End of building tables"); + done = true; + } + + internal sealed override uint Size(MetaData md) + { + return 4 + 2 * md.StringsIndexSize() + + md.CodedIndexSize(CIx.TypeDefOrRef) + + md.TableIndexSize(MDTable.Field) + + md.TableIndexSize(MDTable.Method); + } + + internal sealed override void Write(FileImage output) + { + output.Write(flags); + output.StringsIndex(nameIx); + output.StringsIndex(nameSpaceIx); + //if (superType != null) + // Console.WriteLine("getting coded index for superType of " + name + " = " + superType.GetCodedIx(CIx.TypeDefOrRef)); + output.WriteCodedIndex(CIx.TypeDefOrRef,superType); + output.WriteIndex(MDTable.Field,fieldIx); + output.WriteIndex(MDTable.Method,methodIx); + } + + internal sealed override uint TypeDefOrRefToken() + { + uint cIx = Row; + cIx = cIx << 2; + return cIx; + } + + internal sealed override void TypeSig(MemoryStream sig) + { + if (!typeIndexChecked) CheckTypeIndex(); + sig.WriteByte(GetTypeIndex()); + MetaData.CompressNum(TypeDefOrRefToken(),sig); + } + + internal sealed override uint GetCodedIx(CIx code) + { + switch (code) { + case (CIx.TypeDefOrRef) : return 0; + case (CIx.HasCustomAttr) : return 3; + case (CIx.HasDeclSecurity) : return 0; + case (CIx.TypeOrMethodDef) : return 0; + } + return 0; + } + + } + + /**************************************************************************/ + /// <summary> + /// Descriptor for a class/interface declared in another module of THIS + /// assembly, or in another assembly. + /// </summary> + public class ClassRef : Class, IExternRef, IResolutionScope { + + protected IResolutionScope parent; + ExternClass externClass; + protected MetaData metaData; + + internal ClassRef(string nsName, string name, MetaData md) : base(nsName, name, md) + { + metaData = md; + tabIx = MDTable.TypeRef; + } + + /// <summary> + /// Add a method to this class + /// </summary> + /// <param name="name">method name</param> + /// <param name="retType">return type</param> + /// <param name="pars">parameter types</param> + /// <returns>a descriptor for this method</returns> + public MethodRef AddMethod(string name, Type retType, Type[] pars) + { + return AddMethod (name, retType, pars, 0); + } + + /// <summary> + /// Add a method to this class + /// </summary> + /// <param name="name">method name</param> + /// <param name="retType">return type</param> + /// <param name="pars">parameter types</param> + /// <param name="gen_param_count">num of generic parameters</param> + /// <returns>a descriptor for this method</returns> + public MethodRef AddMethod (string name, Type retType, Type[] pars, int gen_param_count) + { + MethodRef meth = new MethodRef (this, name, retType, pars, false, null, gen_param_count); + metaData.AddToTable(MDTable.MemberRef,meth); + return meth; + } + + /// <summary> + /// Add a method to this class + /// </summary> + /// <param name="name">method name</param> + /// <param name="retType">return type</param> + /// <param name="pars">parameter types</param> + /// <returns>a descriptor for this method</returns> + public MethodRef AddVarArgMethod(string name, Type retType, + Type[] pars, Type[] optPars) + { + MethodRef meth = new MethodRef(this,name,retType,pars,true,optPars, 0); + metaData.AddToTable(MDTable.MemberRef,meth); + return meth; + } + + /// <summary> + /// Add a field to this class + /// </summary> + /// <param name="name">field name</param> + /// <param name="fType">field type</param> + /// <returns>a descriptor for this field</returns> + public FieldRef AddField(string name, Type fType) + { + FieldRef field = new FieldRef(this,name,fType); + metaData.AddToTable(MDTable.MemberRef,field); + return field; + } + + public ClassRef AddClass (string nsName, string name) + { + ClassRef aClass = new ClassRef(nsName,name,metaData); + metaData.AddToTable(MDTable.TypeRef,aClass); + aClass.SetParent(this); + return aClass; + } + + public ClassRef AddValueClass (string nsName, string name) + { + ClassRef aClass = AddClass (nsName, name); + aClass.MakeValueClass (ValueClass.ValueType); + return aClass; + } + + internal void SetParent(IResolutionScope par) + { + parent = par; + } + + internal override string TypeName() + { + if ((parent != null) && (parent is AssemblyRef)) + return (nameSpace + "." + name + ", " + ((AssemblyRef)parent).TypeName()); + else + return (nameSpace + name); + } + + internal sealed override uint Size(MetaData md) + { + return md.CodedIndexSize(CIx.ResolutionScope) + 2 * + md.StringsIndexSize(); + } + + internal sealed override void Write(FileImage output) + { + output.WriteCodedIndex(CIx.ResolutionScope,(MetaDataElement) parent); + output.StringsIndex(nameIx); + output.StringsIndex(nameSpaceIx); + } + + internal override sealed uint TypeDefOrRefToken() + { + uint cIx = Row; + cIx = (cIx << 2) | 0x1; + return cIx; + } + + internal override void TypeSig(MemoryStream sig) + { + sig.WriteByte(GetTypeIndex()); + MetaData.CompressNum(TypeDefOrRefToken(),sig); + } + + internal sealed override uint GetCodedIx(CIx code) + { + switch (code) { + case (CIx.TypeDefOrRef) : return 1; + case (CIx.HasCustomAttr) : return 2; + case (CIx.MemberRefParent) : return 1; + case (CIx.ResolutionScope) : return 3; + } + return 0; + } + + } + + /**************************************************************************/ + public class ExternClassRef : ClassRef { + + ExternClass externClass; + + internal ExternClassRef(TypeAttr attrs, string nsName, string name, + FileRef declFile, MetaData md) : base(nsName,name,md) + { + externClass = new ExternClass(attrs,nameSpaceIx,nameIx,declFile); + metaData.AddToTable(MDTable.ExportedType,externClass); + } + + internal ExternClassRef(string name, MetaData md) : base(null,name,md) + { + } + + public ClassRef AddNestedClass(TypeAttr attrs, string name) + { + ExternClassRef nestedClass = new ExternClassRef(name,metaData); + externClass = new ExternClass(attrs,0,nameIx,this.externClass); + metaData.AddToTable(MDTable.ExportedType,externClass); + return nestedClass; + } + + } + + /**************************************************************************/ + /// <summary> + /// Descriptor for a class defined in another module of THIS assembly + /// and exported (.class extern) + /// </summary> + + internal class ExternClass : Class { + + MetaDataElement parent; + uint flags; + + internal ExternClass(TypeAttr attr, uint nsIx, uint nIx, + MetaDataElement paren) : base(nsIx,nIx) + { + flags = (uint)attr; + parent = paren; + tabIx = MDTable.ExportedType; + } + + internal sealed override uint Size(MetaData md) + { + return 8 + 2* md.StringsIndexSize() + md.CodedIndexSize(CIx.Implementation); + } + + internal sealed override void Write(FileImage output) + { + output.Write(flags); + output.Write(0); + output.StringsIndex(nameIx); + output.StringsIndex(nameSpaceIx); + output.WriteCodedIndex(CIx.Implementation,parent); + } + + internal sealed override uint GetCodedIx(CIx code) + { + switch (code) { + case (CIx.HasCustomAttr) : return 17; + case (CIx.Implementation) : return 2; + } + return 0; + } + + } + + public class GenParam : Class { + + private int index; + private string param_name; + private uint sigIx = 0; + + public GenParam (int index, string name, GenParamType ptype) : base ((byte) ptype) + { + this.index = index; + this.param_name = name; + tabIx = MDTable.TypeSpec; + } + + public int Index { + get { return index; } + set { index = value; } + } + + public string Name { + get { return param_name; } + set { param_name = value; } + } + + public GenParamType Type { + get { return (GenParamType) GetTypeIndex (); } + } + + internal sealed override void BuildTables (MetaData md) + { + if (done) + return; + MemoryStream str = new MemoryStream (); + TypeSig (str); + sigIx = md.AddToBlobHeap (str.ToArray ()); + + done = true; + } + + internal sealed override void TypeSig(MemoryStream str) + { + if (index < 0) + throw new PEFileException (String.Format ("Unresolved {0} - {1}", (GenParamType) GetTypeIndex (), param_name)); + str.WriteByte(typeIndex); + MetaData.CompressNum ((uint) index, str); + } + + internal override uint Size(MetaData md) + { + return md.BlobIndexSize(); + } + + internal sealed override void Write (FileImage output) + { + output.BlobIndex (sigIx); + } + + internal sealed override uint GetCodedIx(CIx code) + { + switch (code) { + case (CIx.TypeDefOrRef) : return 2; + case (CIx.HasCustomAttr) : return 13; + case (CIx.MemberRefParent) : return 4; + } + return 0; + } + } + + public class GenericTypeInst : Class { + + private Type gen_type; + private Type[] gen_param; + bool inTable = false; + uint sigIx = 0; + + public GenericTypeInst (Type gen_type, Type[] gen_param) + : base ((byte) PrimitiveType.GenericInst.GetTypeIndex ()) + { + this.gen_type = gen_type; + this.gen_param = gen_param; + tabIx = MDTable.TypeSpec; + } + + internal override MetaDataElement GetTypeSpec (MetaData md) + { + if (!inTable) { + md.AddToTable (MDTable.TypeSpec, this); + inTable = true; + } + + return this; + } + + internal sealed override void TypeSig(MemoryStream str) + { + str.WriteByte(typeIndex); + gen_type.TypeSig (str); + MetaData.CompressNum ((uint) gen_param.Length, str); + foreach (Type param in gen_param) + param.TypeSig (str); + } + + internal sealed override void BuildTables (MetaData md) + { + if (done) + return; + MemoryStream str = new MemoryStream (); + TypeSig (str); + sigIx = md.AddToBlobHeap (str.ToArray ()); + + done = true; + } + + internal sealed override uint Size (MetaData md) + { + return md.BlobIndexSize (); + } + + internal sealed override void Write (FileImage output) + { + output.BlobIndex (sigIx); + } + + internal sealed override uint GetCodedIx (CIx code) + { + switch (code) { + case (CIx.TypeDefOrRef): return 2; + case (CIx.MemberRefParent): return 4; + case (CIx.HasCustomAttr): return 13; + } + return 0; + } + } + + public class GenericMethodSig { + + private Type[] gen_param; + private bool done; + private uint sigIx = 0; + + public GenericMethodSig (Type[] gen_param) + { + this.gen_param = gen_param; + done = false; + } + + internal void TypeSig (MemoryStream str) + { + str.WriteByte (0x0A); /* GENERIC_INST */ + MetaData.CompressNum ((uint) gen_param.Length, str); + foreach (Type param in gen_param) + param.TypeSig (str); + } + + internal uint GetSigIx (MetaData md) + { + if (done) + return sigIx; + + MemoryStream sig = new MemoryStream(); + TypeSig (sig); + sigIx = md.AddToBlobHeap (sig.ToArray()); + done = true; + return sigIx; + } + } + + public class Sentinel : Type { + + public Sentinel () : base (0x41) { } + + internal sealed override void TypeSig(MemoryStream str) + { + str.WriteByte(typeIndex); + } + } + + /**************************************************************************/ + /// <summary> + /// Descriptor for a FunctionPointer type + /// </summary> + /// + public class MethPtrType : Type { + + bool varArgMeth; + Type retType; + Type [] parList; + Type [] optParList; + CallConv callConv; + uint numPars; + uint numOptPars; + uint sigIx = 0; + + /// <summary> + /// Create a new function pointer type + /// </summary> + /// <param name="meth">the function to be referenced</param> + public MethPtrType (CallConv callconv, Type retType, Type[] pars, + bool varArgMeth, Type[] optPars) : base(0x1B) + { + this.retType = retType; + callConv = callconv; + parList = pars; + this.varArgMeth = varArgMeth; + if (parList != null) numPars = (uint)parList.Length; + if (varArgMeth) { + optParList = optPars; + if (optParList != null) numOptPars = (uint)optParList.Length; + callConv |= CallConv.Vararg; + } + tabIx = MDTable.TypeSpec; + } + + internal sealed override void TypeSig(MemoryStream sig) + { + sig.WriteByte(typeIndex); + // Bootlegged from method ref + sig.WriteByte((byte)callConv); + MetaData.CompressNum (numPars + numOptPars, sig); + retType.TypeSig (sig); + for (int i=0; i < numPars; i++) { + parList[i].TypeSig (sig); + } + if (varArgMeth) { + sig.WriteByte (0x41); // Write the sentinel + for (int i=0; i < numOptPars; i++) { + optParList[i].TypeSig (sig); + } + } + } + + internal sealed override void BuildTables(MetaData md) + { + if (done) return; + MemoryStream sig = new MemoryStream(); + TypeSig(sig); + sigIx = md.AddToBlobHeap(sig.ToArray()); + done = true; + } + + internal sealed override uint Size(MetaData md) + { + return md.BlobIndexSize(); + } + + internal sealed override void Write(FileImage output) + { + output.BlobIndex(sigIx); + } + + internal sealed override uint GetCodedIx(CIx code) { return 0x1B; } + + } + + #region Array Types + /* Classes for Arrays */ + + /// <summary> + /// The IL Array type + /// </summary> + public abstract class Array : Type { + + protected Type elemType; + protected MetaData metaData; + protected string cnameSpace, cname; + + internal Array(Type eType, byte TypeId) : base(TypeId) + { + elemType = eType; + tabIx = MDTable.TypeSpec; + } + } + + /// <summary> + /// Single dimensional array with zero lower bound + /// </summary> + public class ZeroBasedArray : Array { + + /// <summary> + /// Create a new array - elementType[] + /// </summary> + /// <param name="elementType">the type of the array elements</param> + public ZeroBasedArray(Type elementType) : base (elementType, PrimitiveType.SZArray.GetTypeIndex ()) { } + + internal sealed override void TypeSig(MemoryStream str) + { + str.WriteByte(typeIndex); + elemType.TypeSig(str); + } + + } + + /// <summary> + /// Multi dimensional array with explicit bounds + /// </summary> + public class BoundArray : Array { + int[] lowerBounds; + int[] sizes; + uint numDims; + + /// <summary> + /// Create a new multi dimensional array type + /// eg. elemType[1..5,3..10,5,,] would be + /// new BoundArray(elemType,5,[1,3,0],[5,10,4]) + /// </summary> + /// <param name="elementType">the type of the elements</param> + /// <param name="dimensions">the number of dimensions</param> + /// <param name="loBounds">lower bounds of dimensions</param> + /// <param name="sizes">sizes for the dimensions</param> + public BoundArray(Type elementType, uint dimensions, int[] loBounds, + int[] sizes) : base (elementType,0x14) + { + numDims = dimensions; + lowerBounds = loBounds; + this.sizes = sizes; + } + + /// <summary> + /// Create a new multi dimensional array type + /// eg. elemType[5,10,20] would be new BoundArray(elemType,3,[5,10,20]) + /// </summary> + /// <param name="elementType">the type of the elements</param> + /// <param name="dimensions">the number of dimensions</param> + /// <param name="size">the sizes of the dimensions</param> + public BoundArray(Type elementType, uint dimensions, int[] size) + : base (elementType,0x14) + { + numDims = dimensions; + sizes = size; + } + + /// <summary> + /// Create a new multi dimensional array type + /// eg. elemType[,,] would be new BoundArray(elemType,3) + /// </summary> + /// <param name="elementType">the type of the elements</param> + /// <param name="dimensions">the number of dimensions</param> + public BoundArray(Type elementType, uint dimensions) + : base (elementType,0x14) + { + numDims = dimensions; + } + + internal sealed override void TypeSig(MemoryStream str) + { + str.WriteByte(typeIndex); + elemType.TypeSig(str); + MetaData.CompressNum(numDims,str); + if ((sizes != null) && (sizes.Length > 0)) { + + MetaData.CompressNum((uint)sizes.Length,str); + for (int i=0; i < sizes.Length; i++) { + MetaData.CompressNum((uint)sizes[i],str); + } + } else str.WriteByte(0); + if ((lowerBounds != null) && (lowerBounds.Length > 0)) { + MetaData.CompressNum((uint)lowerBounds.Length,str); + for (int i=0; i < lowerBounds.Length; i++) { + CompressSignedNum (lowerBounds[i],str); + } + } else str.WriteByte(0); + } + private void CompressSignedNum (int val, MemoryStream str) + { + uint uval = (uint) val; + byte sign = 0; + if (val < 0) { + val = -val; + sign = 1; + } + + /* Map the signed number to an unsigned number in two ways. + + fval: left-rotated 2's complement representation + sval: map the signed number to unsigned as follows: 0 -> 0, -1 -> 1, 1 -> 2, -2 -> 3, 2 -> 4, .... + the mapping is: x -> 2*|x| - signbit(x) + */ + uint fval = (uval << 1) | sign; + int sval = (val << 1) - sign; + + /* An overly clever transformation: + + a. sval is used to determine the number of bytes in the compressed representation. + b. fval is truncated to the appropriate number of bits and output using the + normal unsigned-int compressor. + + However, or certain values, the truncated fval doesn't carry enough information to round trip. + + (fval & 0x3FFF) <= 0x7F => compressor emits 1 byte, not 2 => there is aliasing of values + + So, we use full 4 bytes to encode such values. + + LAMESPEC: The Microsoft implementation doesn't appear to handle this subtle case. + e.g., it ends up encoding -8192 as the byte 0x01, which decodes to -64 + */ + if (sval <= 0x7F) + MetaData.CompressNum (fval & 0x7F, str); + else if (sval <= 0x3FFF && (fval & 0x3FFF) > 0x7F) + MetaData.CompressNum (fval & 0x3FFF, str); + else if (sval <= 0x1FFFFFFF && (fval & 0x1FFFFFFF) > 0x3FFF) + MetaData.CompressNum (fval & 0x1FFFFFFF, str); + else + /* FIXME: number cannot be represented. Report a warning. */ + // throw new Exception ("cannot represent signed value" + -val); + MetaData.CompressNum (fval, str); + } + } + + #endregion + + + /* Empty interface for grouping TypeRef's possible ResolutionScope + namely : Module, ModuleRef, AssemblyRef and TypeRef */ + public interface IResolutionScope { + } + + /**************************************************************************/ + /// <summary> + /// Base class for scopes (extended by Module, ModuleRef, Assembly, AssemblyRef) + /// </summary> + public abstract class ResolutionScope : MetaDataElement, IResolutionScope { + + protected uint nameIx = 0; + protected MetaData metaData; + protected string name; + + internal ResolutionScope(string name, MetaData md) + { + metaData = md; + this.name = name; + nameIx = md.AddToStringsHeap(name); + } + + internal string GetName() { return name; } + + } + + /**************************************************************************/ + /// <summary> + /// Descriptor for THIS assembly (.assembly) + /// </summary> + public class Assembly : ResolutionScope { + + ushort majorVer, minorVer, buildNo, revisionNo; + uint flags; + uint hashAlgId; + uint keyIx = 0, cultIx = 0; + bool hasPublicKey = false; + + internal Assembly(string name, MetaData md) : base(name,md) + { + tabIx = MDTable.Assembly; + } + + /// <summary> + /// Add details about THIS assembly + /// </summary> + /// <param name="majVer">Major Version</param> + /// <param name="minVer">Minor Version</param> + /// <param name="bldNo">Build Number</param> + /// <param name="revNo">Revision Number</param> + /// <param name="key">Hash Key</param> + /// <param name="hash">Hash Algorithm</param> + /// <param name="cult">Culture</param> + public void AddAssemblyInfo(int majVer, int minVer, int bldNo, int revNo, + byte[] key, uint hash, string cult) + { + majorVer = (ushort)majVer; + minorVer = (ushort)minVer; + buildNo = (ushort)bldNo; + revisionNo = (ushort)revNo; + hashAlgId = hash; + hasPublicKey = (key != null); + keyIx = metaData.AddToBlobHeap(key); + cultIx = metaData.AddToStringsHeap(cult); + } + + /// <summary> + /// Add an attribute to THIS assembly + /// </summary> + /// <param name="aa">assembly attribute</param> + public void AddAssemblyAttr(AssemAttr aa) + { + flags |= (uint)aa; + } + + internal sealed override uint Size(MetaData md) + { + return 16 + md.BlobIndexSize() + 2 * md.StringsIndexSize(); + } + + internal sealed override void Write(FileImage output) + { + // Console.WriteLine("Writing assembly element with nameIx of " + nameIx + " at file offset " + output.Seek(0,SeekOrigin.Current)); + output.Write((uint)hashAlgId); + output.Write(majorVer); + output.Write(minorVer); + output.Write(buildNo); + output.Write(revisionNo); + output.Write(flags); + output.BlobIndex(keyIx); + output.StringsIndex(nameIx); + output.StringsIndex(cultIx); + } + + internal sealed override uint GetCodedIx(CIx code) + { + switch (code) { + case (CIx.HasCustomAttr) : return 14; + case (CIx.HasDeclSecurity) : return 2; + } + return 0; + } + + internal bool HasPublicKey { + get { return hasPublicKey; } + } + } + + /**************************************************************************/ + /// <summary> + /// Descriptor for THIS module + /// </summary> + public class Module : ResolutionScope, IExternRef { + + Guid mvid; + uint mvidIx = 0; + + internal Module(string name, MetaData md) : base(name,md) + { + mvid = Guid.NewGuid(); + mvidIx = md.AddToGUIDHeap(mvid); + tabIx = MDTable.Module; + } + + public Guid Guid { + get { return mvid; } + } + + public ClassRef AddClass(string nsName, string name) + { + ClassRef aClass = new ClassRef (nsName, name, metaData); + metaData.AddToTable (MDTable.TypeRef, aClass); + aClass.SetParent (this); + return aClass; + } + + public ClassRef AddValueClass(string nsName, string name) + { + ClassRef aClass = AddClass (nsName, name); + aClass.MakeValueClass (ValueClass.ValueType); + return aClass; + } + + internal sealed override uint Size(MetaData md) + { + return 2 + md.StringsIndexSize() + 3 * md.GUIDIndexSize(); + } + + internal sealed override void Write(FileImage output) + { + output.Write((short)0); + output.StringsIndex(nameIx); + output.GUIDIndex(mvidIx); + output.GUIDIndex(0); + output.GUIDIndex(0); + } + + internal sealed override uint GetCodedIx(CIx code) + { + switch (code) { + case (CIx.HasCustomAttr) : return 7; + case (CIx.ResolutionScope) : return 0; + } + return 0; + } + } + /**************************************************************************/ + /// <summary> + /// Descriptor for another module in THIS assembly + /// </summary> + public class ModuleRef : ResolutionScope, IExternRef { + + internal ModuleRef(MetaData md, string name) : base(name,md) + { + tabIx = MDTable.ModuleRef; + } + + /// <summary> + /// Add a class to this external module. This is a class declared in + /// another module of THIS assembly. + /// </summary> + /// <param name="nsName">name space name</param> + /// <param name="name">class name</param> + /// <returns>a descriptor for this class in another module</returns> + public ClassRef AddClass(string nsName, string name) + { + ClassRef aClass = new ClassRef(nsName,name,metaData); + metaData.AddToTable(MDTable.TypeRef,aClass); + aClass.SetParent(this); + return aClass; + } + + /// <summary> + /// Make a file descriptor to correspond to this module. The file + /// descriptor will have the same name as the module descriptor + /// </summary> + /// <param name="hashBytes">the hash of the file</param> + /// <param name="hasMetaData">the file contains metadata</param> + /// <param name="entryPoint">the program entry point is in this file</param> + /// <returns>a descriptor for the file which contains this module</returns> + public FileRef MakeFile(byte[] hashBytes, bool hasMetaData, bool entryPoint) + { + FileRef file = new FileRef(nameIx,hashBytes,hasMetaData,entryPoint,metaData); + metaData.AddToTable(MDTable.File,file); + return file; + } + + /// <summary> + /// Add a value class to this module. This is a class declared in + /// another module of THIS assembly. + /// </summary> + /// <param name="nsName">name space name</param> + /// <param name="name">class name</param> + /// <returns></returns> + public ClassRef AddValueClass(string nsName, string name) + { + ClassRef aClass = new ClassRef(nsName,name,metaData); + metaData.AddToTable(MDTable.TypeRef,aClass); + aClass.SetParent(this); + aClass.MakeValueClass(ValueClass.ValueType); + return aClass; + } + + /// <summary> + /// Add a class which is declared public in this external module of + /// THIS assembly. This class will be exported from this assembly. + /// The ilasm syntax for this is .extern class + /// </summary> + /// <param name="attrSet">attributes of the class to be exported</param> + /// <param name="nsName">name space name</param> + /// <param name="name">external class name</param> + /// <param name="declFile">the file where the class is declared</param> + /// <param name="isValueClass">is this class a value type?</param> + /// <returns>a descriptor for this external class</returns> + public ExternClassRef AddExternClass(TypeAttr attrSet, string nsName, + string name, FileRef declFile, + bool isValueClass) { + ExternClassRef cRef = new ExternClassRef(attrSet,nsName,name,declFile,metaData); + metaData.AddToTable(MDTable.TypeRef,cRef); + cRef.SetParent(this); + if (isValueClass) cRef.MakeValueClass(ValueClass.ValueType); + return cRef; + } + + /// <summary> + /// Add a "global" method in another module + /// </summary> + /// <param name="name">method name</param> + /// <param name="retType">return type</param> + /// <param name="pars">method parameter types</param> + /// <returns>a descriptor for this method in anther module</returns> + public MethodRef AddMethod(string name, Type retType, Type[] pars) + { + MethodRef meth = new MethodRef(this,name,retType,pars,false,null, 0); + metaData.AddToTable(MDTable.MemberRef,meth); + return meth; + } + + /// <summary> + /// Add a vararg method to this class + /// </summary> + /// <param name="name">method name</param> + /// <param name="retType">return type</param> + /// <param name="pars">parameter types</param> + /// <param name="optPars">optional param types for this vararg method</param> + /// <returns>a descriptor for this method</returns> + public MethodRef AddVarArgMethod(string name, Type retType, + Type[] pars, Type[] optPars) { + MethodRef meth = new MethodRef(this,name,retType,pars,true,optPars, 0); + metaData.AddToTable(MDTable.MemberRef,meth); + return meth; + } + + /// <summary> + /// Add a field in another module + /// </summary> + /// <param name="name">field name</param> + /// <param name="fType">field type</param> + /// <returns>a descriptor for this field in another module</returns> + public FieldRef AddField(string name, Type fType) + { + FieldRef field = new FieldRef(this,name,fType); + metaData.AddToTable(MDTable.MemberRef,field); + return field; + } + + internal sealed override uint Size(MetaData md) + { + return md.StringsIndexSize(); + } + + internal sealed override void Write(FileImage output) + { + output.StringsIndex(nameIx); + } + + internal sealed override uint GetCodedIx(CIx code) + { + switch (code) { + case (CIx.HasCustomAttr) : return 12; + case (CIx.MemberRefParent) : return 2; + case (CIx.ResolutionScope) : return 1; + } + return 0; + } + + } + + #region Classes for Constants + /// <summary> + /// Descriptor for a constant value + /// </summary> + public abstract class Constant { + protected uint size = 0; + protected Type type; + protected uint blobIndex; + protected bool addedToBlobHeap = false; + + internal Constant() { } + + internal virtual uint GetBlobIndex(MetaData md) { return 0; } + + internal uint GetSize() { return size; } + + internal byte GetTypeIndex() { return type.GetTypeIndex(); } + + internal virtual void Write(BinaryWriter bw) { } + + } + /// <summary> + /// Descriptor for a constant value + /// </summary> + public abstract class DataConstant : Constant { + private uint dataOffset = 0; + + internal DataConstant() { } + + public uint DataOffset { + get { return dataOffset; } + set { dataOffset = value; } + } + + } + + /// <summary> + /// Boolean constant + /// </summary> + public class BoolConst : Constant { + bool val; + + /// <summary> + /// Create a new boolean constant with the value "val" + /// </summary> + /// <param name="val">value of this boolean constant</param> + public BoolConst(bool val) + { + this.val = val; + size = 1; + type = PrimitiveType.Boolean; + } + + internal sealed override uint GetBlobIndex(MetaData md) + { + if (!addedToBlobHeap) { + if (val) blobIndex = md.AddToBlobHeap((sbyte)1); + else blobIndex = md.AddToBlobHeap((sbyte)0); + addedToBlobHeap = true; + } + return blobIndex; + } + + internal sealed override void Write(BinaryWriter bw) + { + if (val) bw.Write((sbyte)1); + else bw.Write((sbyte)0); + } + + } + + public class ByteArrConst : DataConstant { + byte[] val; + + public ByteArrConst(byte[] val) + { + type = PrimitiveType.String; + this.val = val; + size = (uint)val.Length; + } + + public Type Type { + get { return type; } + set { type = value; } + } + + internal sealed override uint GetBlobIndex(MetaData md) + { + if (!addedToBlobHeap) { + blobIndex = md.AddToBlobHeap(val); + addedToBlobHeap = true; + } + return blobIndex; + } + + internal sealed override void Write(BinaryWriter bw) + { + bw.Write(val); + } + + } + + public class CharConst : Constant { + char val; + + public CharConst(char val) + { + this.val = val; + size = 2; + type = PrimitiveType.Char; + } + + internal sealed override uint GetBlobIndex(MetaData md) + { + if (!addedToBlobHeap) { + blobIndex = md.AddToBlobHeap(val); + addedToBlobHeap = true; + } + return blobIndex; + } + + internal sealed override void Write(BinaryWriter bw) + { + bw.Write(val); + } + + } + + public class FloatConst : DataConstant { + float val; + + public FloatConst(float val) + { + this.val = val; + size = 4; + type = PrimitiveType.Float32; + } + + internal sealed override uint GetBlobIndex(MetaData md) + { + if (!addedToBlobHeap) { + blobIndex = md.AddToBlobHeap(val); + addedToBlobHeap = true; + } + return blobIndex; + } + + internal sealed override void Write(BinaryWriter bw) + { + bw.Write(val); + } + + } + + public class DoubleConst : DataConstant { + double val; + + public DoubleConst(double val) + { + this.val = val; + size = 8; + type = PrimitiveType.Float64; + } + + internal sealed override uint GetBlobIndex(MetaData md) + { + if (!addedToBlobHeap) { + blobIndex = md.AddToBlobHeap(val); + addedToBlobHeap = true; + } + return blobIndex; + } + + internal sealed override void Write(BinaryWriter bw) + { + bw.Write(val); + } + + } + + public class IntConst : DataConstant { + long val; + + public IntConst(sbyte val) + { + this.val = val; + size = 1; + type = PrimitiveType.Int8; + } + + public IntConst(short val) + { + this.val = val; + size = 2; + type = PrimitiveType.Int16; + } + + public IntConst(int val) + { + this.val = val; + size = 4; + type = PrimitiveType.Int32; + } + + public IntConst(long val) + { + this.val = val; + size = 8; + type = PrimitiveType.Int64; + } + + internal sealed override uint GetBlobIndex(MetaData md) + { + if (!addedToBlobHeap) { + switch (size) { + case (1) : blobIndex = md.AddToBlobHeap((sbyte)val); break; + case (2) : blobIndex = md.AddToBlobHeap((short)val); break; + case (4) : blobIndex = md.AddToBlobHeap((int)val); break; + default : blobIndex = md.AddToBlobHeap(val); break; + } + addedToBlobHeap = true; + } + return blobIndex; + } + + internal sealed override void Write(BinaryWriter bw) + { + switch (size) { + case (1) : bw.Write((sbyte)val); break; + case (2) : bw.Write((short)val); break; + case (4) : bw.Write((int)val); break; + default : bw.Write(val); break; + } + } + + } + + public class UIntConst : Constant { + ulong val; + + public UIntConst(byte val) + { + this.val = val; + size = 1; + type = PrimitiveType.UInt8; + } + public UIntConst(ushort val) + { + this.val = val; + size = 2; + type = PrimitiveType.UInt16; + } + public UIntConst(uint val) + { + this.val = val; + size = 4; + type = PrimitiveType.UInt32; + } + public UIntConst(ulong val) + { + this.val = val; + size = 8; + type = PrimitiveType.UInt64; + } + + internal sealed override uint GetBlobIndex(MetaData md) + { + if (!addedToBlobHeap) { + switch (size) { + case (1) : blobIndex = md.AddToBlobHeap((byte)val); break; + case (2) : blobIndex = md.AddToBlobHeap((ushort)val); break; + case (4) : blobIndex = md.AddToBlobHeap((uint)val); break; + default : blobIndex = md.AddToBlobHeap(val); break; + } + addedToBlobHeap = true; + } + return blobIndex; + } + + internal sealed override void Write(BinaryWriter bw) + { + switch (size) { + case (1) : bw.Write((byte)val); break; + case (2) : bw.Write((ushort)val); break; + case (4) : bw.Write((uint)val); break; + default : bw.Write(val); break; + } + } + + } + + public class StringConst : DataConstant { + string val; + + public StringConst(string val) + { + this.val = val; + size = (uint)val.Length; // need to add null ?? + type = PrimitiveType.String; + } + + internal sealed override uint GetBlobIndex(MetaData md) + { + if (!addedToBlobHeap) { + byte [] b = Encoding.Unicode.GetBytes (val); + blobIndex = md.AddToBlobHeap(b); + addedToBlobHeap = true; + } + return blobIndex; + } + + internal sealed override void Write(BinaryWriter bw) + { + bw.Write(val); + } + + } + + public class NullConst : Constant { + + public NullConst() + { + size = 4; + type = PrimitiveType.Class; + } + + internal sealed override uint GetBlobIndex(MetaData md) + { + if (!addedToBlobHeap) { + blobIndex = md.AddToBlobHeap((int)0); + addedToBlobHeap = true; + } + return blobIndex; + } + + internal sealed override void Write(BinaryWriter bw) + { + bw.Write((int)0); + } + + } + + public class AddressConstant : DataConstant { + DataConstant data; + + public AddressConstant(DataConstant dConst) + { + data = dConst; + size = 4; + type = PrimitiveType.TypedRef; + } + + internal sealed override void Write(BinaryWriter bw) + { + ((FileImage)bw).WriteDataRVA(data.DataOffset); + } + + } + + public class RepeatedConstant : DataConstant { + DataConstant data; + uint repCount; + + public RepeatedConstant(DataConstant dConst, int repeatCount) + { + data = dConst; + repCount = (uint)repeatCount; + int[] sizes = new int[1]; + sizes[0] = repeatCount; + type = new BoundArray(type,1,sizes); + size = data.GetSize() * repCount; + } + + internal sealed override void Write(BinaryWriter bw) + { + for (int i=0; i < repCount; i++) { + data.Write(bw); + } + } + + } + + public class ArrayConstant : DataConstant { + DataConstant[] dataVals; + + public ArrayConstant(DataConstant[] dVals) + { + dataVals = dVals; + for (int i=0; i < dataVals.Length; i++) { + size += dataVals[i].GetSize(); + } + } + + internal sealed override void Write(BinaryWriter bw) + { + for (int i=0; i < dataVals.Length; i++) { + dataVals[i].Write(bw); + } + } + + } + + public class ClassType : Constant { + string name; + Class desc; + + public ClassType(string className) + { + name = className; + type = PrimitiveType.ClassType; + } + + public ClassType(Class classDesc) + { + desc = classDesc; + type = PrimitiveType.ClassType; + } + + internal override void Write(BinaryWriter bw) + { + if (name == null) name = desc.TypeName(); + bw.Write(name); + } + + } + + #endregion + + /**************************************************************************/ + /// <summary> + /// Descriptor for a custom modifier of a type (modopt or modreq) + /// </summary> + + public class CustomModifiedType : Type { + + Type type; + Class cmodType; + + /// <summary> + /// Create a new custom modifier for a type + /// </summary> + /// <param name="type">the type to be modified</param> + /// <param name="cmod">the modifier</param> + /// <param name="cmodType">the type reference to be associated with the type</param> + public CustomModifiedType(Type type, CustomModifier cmod, Class cmodType) + : base((byte)cmod) + { + this.type = type; + this.cmodType = cmodType; + } + + internal sealed override void TypeSig(MemoryStream str) + { + str.WriteByte(typeIndex); + MetaData.CompressNum(cmodType.TypeDefOrRefToken(),str); + type.TypeSig(str); + } + + } + + /**************************************************************************/ + /// <summary> + /// Base class for Event and Property descriptors + /// </summary> + + public class Feature : MetaDataElement { + + internal enum MethodType : ushort { Setter = 0x01, Getter, Other = 0x04, AddOn = 0x08, + RemoveOn = 0x10, Fire = 0x20 } + + private static readonly int INITSIZE = 5; + private static readonly ushort specialName = 0x200; + private static readonly ushort rtSpecialName = 0x400; + + protected ClassDef parent; + protected ushort flags = 0; + protected string name; + protected int tide = 0; + protected uint nameIx; + protected MethodSemantics[] methods = new MethodSemantics[INITSIZE]; + + internal Feature(string name, ClassDef par) + { + parent = par; + this.name = name; + } + + internal void AddMethod(MethodDef meth, MethodType mType) + { + if (tide >= methods.Length) { + int len = methods.Length; + MethodSemantics[] mTmp = methods; + methods = new MethodSemantics[len * 2]; + for (int i=0; i < len; i++) { + methods[i] = mTmp[i]; + } + } + methods[tide++] = new MethodSemantics(mType,meth,this); + } + + /// <summary> + /// Set the specialName attribute for this Event or Property + /// </summary> + public void SetSpecialName() + { + flags |= specialName; + } + + /// <summary> + /// Set the RTSpecialName attribute for this Event or Property + /// </summary> + public void SetRTSpecialName() + { + flags |= rtSpecialName; + } + + } + + /**************************************************************************/ + /// <summary> + /// Descriptor for an event + /// </summary> + public class Event : Feature { + + Type eventType; + + internal Event(string name, Type eType, ClassDef parent) + : base(name, parent) + { + eventType = eType; + tabIx = MDTable.Event; + } + + /// <summary> + /// Add the addon method to this event + /// </summary> + /// <param name="addon">the addon method</param> + public void AddAddon(MethodDef addon) + { + AddMethod(addon,MethodType.AddOn); + } + + /// <summary> + /// Add the removeon method to this event + /// </summary> + /// <param name="removeOn">the removeon method</param> + public void AddRemoveOn(MethodDef removeOn) + { + AddMethod(removeOn,MethodType.RemoveOn); + } + + /// <summary> + /// Add the fire method to this event + /// </summary> + /// <param name="fire">the fire method</param> + public void AddFire(MethodDef fire) + { + AddMethod(fire,MethodType.Fire); + } + + /// <summary> + /// Add another method to this event + /// </summary> + /// <param name="other">the method to be added</param> + public void AddOther(MethodDef other) + { + AddMethod(other,MethodType.Other); + } + + internal sealed override void BuildTables(MetaData md) + { + if (done) return; + nameIx = md.AddToStringsHeap(name); + for (int i=0; i < tide; i++) { + md.AddToTable(MDTable.MethodSemantics,methods[i]); + } + done = true; + } + + internal sealed override uint Size(MetaData md) + { + return 2 + md.StringsIndexSize() + md.CodedIndexSize(CIx.TypeDefOrRef); + } + + internal sealed override void Write(FileImage output) + { + output.Write(flags); + output.StringsIndex(nameIx); + output.WriteCodedIndex(CIx.TypeDefOrRef,eventType); + } + + internal sealed override uint GetCodedIx(CIx code) + { + switch (code) { + case (CIx.HasCustomAttr) : return 10; + case (CIx.HasSemantics) : return 0; + } + return 0; + } + + } + + /**************************************************************************/ + /// <summary> + /// Descriptor for the Property of a class + /// </summary> + public class Property : Feature { + + private static readonly byte PropertyTag = 0x8; + private bool instance; + MethodDef getterMeth; + ConstantElem constVal; + uint typeBlobIx = 0; + Type[] parList; + Type returnType; + uint numPars = 0; + + internal Property(string name, Type retType, Type[] pars, ClassDef parent) : base(name, parent) + { + returnType = retType; + parList = pars; + if (pars != null) numPars = (uint)pars.Length; + tabIx = MDTable.Property; + } + + /// <summary> + /// Add a set method to this property + /// </summary> + /// <param name="setter">the set method</param> + public void AddSetter(MethodDef setter) + { + AddMethod(setter,MethodType.Setter); + } + + /// <summary> + /// Add a get method to this property + /// </summary> + /// <param name="getter">the get method</param> + public void AddGetter(MethodDef getter) + { + AddMethod(getter,MethodType.Getter); + getterMeth = getter; + } + + /// <summary> + /// Add another method to this property + /// </summary> + /// <param name="other">the method</param> + public void AddOther(MethodDef other) + { + AddMethod(other,MethodType.Other); + } + + /// <summary> + /// Add an initial value for this property + /// </summary> + /// <param name="constVal">the initial value for this property</param> + public void AddInitValue(Constant constVal) + { + this.constVal = new ConstantElem(this,constVal); + } + + public void SetInstance (bool isInstance) + { + this.instance = isInstance; + } + + internal sealed override void BuildTables(MetaData md) + { + if (done) return; + nameIx = md.AddToStringsHeap(name); + MemoryStream sig = new MemoryStream(); + byte tag = PropertyTag; + if (instance) + tag |= 0x20; + sig.WriteByte(tag); + MetaData.CompressNum(numPars,sig); + returnType.TypeSig(sig); + for (int i=0; i < numPars; i++) { + parList[i].TypeSig(sig); + } + typeBlobIx = md.AddToBlobHeap(sig.ToArray()); + for (int i=0; i < tide; i++) { + md.AddToTable(MDTable.MethodSemantics,methods[i]); + } + if (constVal != null) { + md.AddToTable(MDTable.Constant,constVal); + constVal.BuildTables(md); + } + done = true; + } + + internal sealed override uint Size(MetaData md) + { + return 2 + md.StringsIndexSize() + md.BlobIndexSize(); + } + + internal sealed override void Write(FileImage output) + { + output.Write(flags); + output.StringsIndex(nameIx); + output.BlobIndex(typeBlobIx); + } + + internal sealed override uint GetCodedIx(CIx code) + { + switch (code) { + case (CIx.HasCustomAttr) : return 9; + case (CIx.HasConst) : return 2; + case (CIx.HasSemantics) : return 1; + } + return 0; + } + + } + + /**************************************************************************/ + /// <summary> + /// Base class for field/methods (member of a class) + /// </summary> + public abstract class Member : MetaDataElement { + + protected string name; + protected uint nameIx = 0, sigIx = 0; + + internal Member(string memName) + { + name = memName; + tabIx = MDTable.MemberRef; + } + + } + + /*****************************************************************************/ + /// <summary> + /// Descriptor for a field of a class + /// </summary> + + public abstract class Field : Member { + + protected static readonly byte FieldSig = 0x6; + + protected Type type; + + internal Field(string pfName, Type pfType) : base(pfName) + { + type = pfType; + } + + } + /**************************************************************************/ + /// <summary> + /// Descriptor for a field defined in a class of THIS assembly/module + /// </summary> + public class FieldDef : Field { + + //private static readonly uint PInvokeImpl = 0x2000; + private static readonly ushort HasFieldRVA = 0x100; + private static readonly ushort HasDefault = 0x8000; + + FieldRVA rva; + ConstantElem constVal; + FieldLayout layout; + FieldMarshal marshalInfo; + ushort flags; + + internal FieldDef(string name, Type fType) : base(name,fType) + { + tabIx = MDTable.Field; + } + + internal FieldDef(FieldAttr attrSet, string name, Type fType) : base(name, fType) + { + flags = (ushort)attrSet; + tabIx = MDTable.Field; + } + + /// <summary> + /// Add an attribute(s) to this field + /// </summary> + /// <param name="fa">the attribute(s) to be added</param> + public void AddFieldAttr(FieldAttr fa) + { + flags |= (ushort)fa; + } + + /// <summary> + /// Add a value for this field + /// </summary> + /// <param name="val">the value for the field</param> + public void AddValue(Constant val) + { + constVal = new ConstantElem(this,val); + flags |= HasDefault; + } + + /// <summary> + /// Add an initial value for this field (at dataLabel) (.data) + /// </summary> + /// <param name="val">the value for the field</param> + /// <param name="repeatVal">the number of repetitions of this value</param> + public void AddDataValue(DataConstant val) + { + flags |= HasFieldRVA; + rva = new FieldRVA(this,val); + } + + /// <summary> + /// Set the offset of the field. Used for sequential or explicit classes. + /// (.field [offs]) + /// </summary> + /// <param name="offs">field offset</param> + public void SetOffset(uint offs) + { + layout = new FieldLayout(this,offs); + } + + /// <summary> + /// Set the marshalling info for a field + /// </summary> + /// <param name="mInf"></param> + public void SetMarshalInfo(NativeType marshallType) + { + flags |= (ushort) FieldAttr.HasFieldMarshal; + marshalInfo = new FieldMarshal(this,marshallType); + } + + internal sealed override void BuildTables(MetaData md) + { + if (done) return; + nameIx = md.AddToStringsHeap(name); + MemoryStream sig = new MemoryStream(); + sig.WriteByte(FieldSig); + type.TypeSig(sig); + sigIx = md.AddToBlobHeap(sig.ToArray()); + if (rva != null) { + md.AddToTable(MDTable.FieldRVA,rva); + rva.BuildTables(md); + } else if (constVal != null) { + md.AddToTable(MDTable.Constant,constVal); + constVal.BuildTables(md); + } + if (layout != null) md.AddToTable(MDTable.FieldLayout,layout); + if (marshalInfo != null) { + md.AddToTable(MDTable.FieldMarshal,marshalInfo); + marshalInfo.BuildTables(md); + } + done = true; + } + + internal sealed override uint Size(MetaData md) + { + return 2 + md.StringsIndexSize() + md.BlobIndexSize(); + } + + internal sealed override void Write(FileImage output) + { + output.Write(flags); + output.StringsIndex(nameIx); + output.BlobIndex(sigIx); + } + + internal sealed override uint GetCodedIx(CIx code) + { + switch (code) { + case (CIx.HasConst) : return 0; + case (CIx.HasCustomAttr) : return 1; + case (CIx.HasFieldMarshal) : return 0; + case (CIx.MemberForwarded) : return 0; + } + return 0; + } + + } + + /**************************************************************************/ + /// <summary> + /// Descriptor for a field of a class defined in another assembly/module + /// </summary> + public class FieldRef : Field { + + MetaDataElement parent; + + internal FieldRef(MetaDataElement paren, string name, Type fType) : base(name, fType) + { + parent = paren; + } + + internal sealed override void BuildTables(MetaData md) + { + if (done) return; + nameIx = md.AddToStringsHeap(name); + MemoryStream sig = new MemoryStream(); + sig.WriteByte(FieldSig); + type.TypeSig(sig); + sigIx = md.AddToBlobHeap(sig.ToArray()); + done = true; + } + + internal sealed override uint Size(MetaData md) + { + return md.CodedIndexSize(CIx.MemberRefParent) + md.StringsIndexSize() + md.BlobIndexSize(); + } + + internal sealed override void Write(FileImage output) + { + output.WriteCodedIndex(CIx.MemberRefParent,parent); + output.StringsIndex(nameIx); + output.BlobIndex(sigIx); + } + + internal sealed override uint GetCodedIx(CIx code) { return 6; } + + } + + /**************************************************************************/ + /// <summary> + /// Base class for Method Descriptors + /// </summary> + + public abstract class Method : Member { + + internal Method (string methName) : base (methName) + {} + + public abstract void AddCallConv(CallConv cconv); + internal abstract void TypeSig(MemoryStream sig); + internal abstract uint GetSigIx(MetaData md); + } + + /**************************************************************************/ + /// <summary> + /// Descriptor for a method defined in THIS assembly/module + /// IL .method + /// </summary> + + public class MethodDef : Method { + + private static readonly ushort PInvokeImpl = 0x2000; + //private static readonly uint UnmanagedExport = 0x0008; + // private static readonly byte LocalSigByte = 0x7; + uint parIx = 0, textOffset = 0; + private CallConv callConv = CallConv.Default; + private Type retType; + private int gen_param_count; + + MetaData metaData; + CILInstructions code; + ArrayList securityActions = new ArrayList(); + Param[] parList; + Local[] locals; + bool initLocals; + ushort methFlags = 0, implFlags = 0; + int maxStack = 0, numPars = 0; + bool entryPoint = false; + LocalSig localSig; + ArrayList varArgSigList; + ImplMap pinvokeImpl; + Param ret_param; + + + internal MethodDef(MetaData md, string name, Type retType, Param[] pars) : base (name) + { + this.retType = retType; + metaData = md; + parList = pars; + if (parList != null) numPars = parList.Length; + tabIx = MDTable.Method; + } + + internal MethodDef (MetaData md, MethAttr mAttrSet, ImplAttr iAttrSet, string name, + Type retType, Param [] pars) : this (md, name, retType, pars) + { + methFlags = (ushort)mAttrSet; + implFlags = (ushort)iAttrSet; + } + + internal Param[] GetPars() + { + return parList; + } + + internal override uint GetSigIx(MetaData md) + { + MemoryStream sig = new MemoryStream(); + TypeSig(sig); + return md.AddToBlobHeap(sig.ToArray()); + } + + public override void AddCallConv(CallConv cconv) + { + callConv |= cconv; + } + + /// <summary> + /// Add some attributes to this method descriptor + /// </summary> + /// <param name="ma">the attributes to be added</param> + public void AddMethAttribute(MethAttr ma) + { + methFlags |= (ushort)ma; + } + + /// <summary> + /// Add some implementation attributes to this method descriptor + /// </summary> + /// <param name="ia">the attributes to be added</param> + public void AddImplAttribute(ImplAttr ia) + { + implFlags |= (ushort)ia; + } + + public void AddPInvokeInfo(ModuleRef scope, string methName, + PInvokeAttr callAttr) { + pinvokeImpl = new ImplMap((ushort)callAttr,this,methName,scope); + methFlags |= PInvokeImpl; + } + + /// <summary> + /// Add a named generic type parameter + /// </summary> + public GenericParameter AddGenericParameter (short index, string name) + { + return AddGenericParameter (index, name, 0); + } + + /// <summary> + /// Add a named generic type parameter with attributes + /// </summary> + public GenericParameter AddGenericParameter (short index, string name, GenericParamAttributes attr) + { + GenericParameter gp = new GenericParameter (this, metaData, index, name, attr); + metaData.AddToTable (MDTable.GenericParam, gp); + gen_param_count ++; + return gp; + } + + /// <summary> + /// Set the maximum stack height for this method + /// </summary> + /// <param name="maxStack">the maximum height of the stack</param> + public void SetMaxStack(int maxStack) + { + this.maxStack = maxStack; + } + + /// <summary> + /// Add local variables to this method + /// </summary> + /// <param name="locals">the locals to be added</param> + /// <param name="initLocals">are locals initialised to default values</param> + public void AddLocals(Local[] locals, bool initLocals) + { + this.locals = locals; + this.initLocals = initLocals; + } + + /* Add Marshal info for return type */ + public void AddRetTypeMarshallInfo (NativeType marshallType) + { + ret_param = new Param (ParamAttr.HasFieldMarshal, "", retType); + ret_param.AddMarshallInfo (marshallType); + } + + /// <summary> + /// Mark this method as having an entry point + /// </summary> + public void DeclareEntryPoint() + { + entryPoint = true; + } + + /// <summary> + /// Create a code buffer for this method to add the IL instructions to + /// </summary> + /// <returns>a buffer for this method's IL instructions</returns> + public CILInstructions CreateCodeBuffer() + { + code = new CILInstructions(metaData); + return code; + } + + /// <summary> + /// Make a method reference descriptor for this method to be used + /// as a callsite signature for this vararg method + /// </summary> + /// <param name="optPars">the optional pars for the vararg method call</param> + /// <returns></returns> + public MethodRef MakeVarArgSignature(Type[] optPars) + { + Type[] pars = new Type[numPars]; + MethodRef varArgSig; + for (int i=0; i < numPars; i++) { + pars[i] = parList[i].GetParType(); + } + varArgSig = new MethodRef(this,name,retType,pars,true,optPars, 0); + + if (varArgSigList == null) + varArgSigList = new ArrayList (); + varArgSigList.Add (varArgSig); + return varArgSig; + } + + internal sealed override void TypeSig(MemoryStream sig) + { + sig.WriteByte((byte)callConv); + if ((callConv & CallConv.Generic) == CallConv.Generic) + MetaData.CompressNum ((uint) gen_param_count, sig); + MetaData.CompressNum((uint)numPars,sig); + if (ret_param != null) + ret_param.seqNo = 0; + retType.TypeSig(sig); + for (ushort i=0; i < numPars; i++) { + parList[i].seqNo = (ushort)(i+1); + parList[i].TypeSig(sig); + } + } + + internal sealed override void BuildTables(MetaData md) + { + if (done) return; + if (pinvokeImpl != null) { + md.AddToTable(MDTable.ImplMap,pinvokeImpl); + pinvokeImpl.BuildTables(md); + } + if (entryPoint) md.SetEntryPoint(this); + uint locToken = 0; + if (locals != null) { + localSig = new LocalSig(locals); + md.AddToTable(MDTable.StandAloneSig,localSig); + localSig.BuildTables(md); + locToken = localSig.Token(); + } + if (code != null) { + code.CheckCode(locToken,initLocals,maxStack); + textOffset = md.AddCode(code); + } + nameIx = md.AddToStringsHeap(name); + sigIx = GetSigIx(md); + parIx = md.TableIndex(MDTable.Param); + if (ret_param != null) { + md.AddToTable(MDTable.Param, ret_param); + ret_param.BuildTables(md); + } + for (int i=0; i < numPars; i++) { + md.AddToTable(MDTable.Param,parList[i]); + parList[i].BuildTables(md); + } + if (varArgSigList != null) { + foreach (MethodRef varArgSig in varArgSigList) { + md.AddToTable(MDTable.MemberRef,varArgSig); + varArgSig.BuildTables(md); + } + } + // Console.WriteLine("method has " + numPars + " parameters"); + done = true; + } + + internal sealed override uint Size(MetaData md) + { + return 8 + md.StringsIndexSize() + md.BlobIndexSize() + md.TableIndexSize(MDTable.Param); + } + + internal sealed override void Write(FileImage output) + { + if (ZeroRva ()) output.Write(0); + else output.WriteCodeRVA(textOffset); + output.Write(implFlags); + output.Write(methFlags); + output.StringsIndex(nameIx); + output.BlobIndex(sigIx); + output.WriteIndex(MDTable.Param,parIx); + } + + internal bool ZeroRva () + { + return (((methFlags & (ushort)MethAttr.Abstract) != 0) || + ((implFlags & (ushort)ImplAttr.Runtime) != 0) || + ((implFlags & (ushort)ImplAttr.InternalCall) != 0) || + (pinvokeImpl != null)); // TODO: Not entirely true but works for now + } + + internal sealed override uint GetCodedIx(CIx code) + { + switch (code) { + case (CIx.HasCustomAttr) : return 0; + case (CIx.HasDeclSecurity) : return 1; + case (CIx.MemberRefParent) : return 3; + case (CIx.MethodDefOrRef) : return 0; + case (CIx.MemberForwarded) : return 1; + case (CIx.CustomAttributeType) : return 2; + case (CIx.TypeOrMethodDef) : return 1; + } + return 0; + } + + } + /**************************************************************************/ + /// <summary> + /// Descriptor for a method defined in another assembly/module + /// </summary> + public class MethodRef : Method { + + private static readonly byte Sentinel = 0x41; + Type[] parList, optParList; + MetaDataElement parent; + uint numPars = 0, numOptPars = 0; + CallConv callConv = CallConv.Default; + Type retType; + int gen_param_count; + + internal MethodRef(MetaDataElement paren, string name, Type retType, + Type[] pars, bool varArgMeth, Type[] optPars, int gen_param_count) : base(name) + { + parent = paren; + parList = pars; + this.retType = retType; + if (parList != null) numPars = (uint)parList.Length; + if (varArgMeth) { + optParList = optPars; + if (optParList != null) numOptPars = (uint)optParList.Length; + callConv = CallConv.Vararg; + } + this.gen_param_count = gen_param_count; + } + + internal override uint GetSigIx(MetaData md) + { + MemoryStream sig = new MemoryStream(); + TypeSig(sig); + return md.AddToBlobHeap(sig.ToArray()); + } + + public override void AddCallConv(CallConv cconv) + { + callConv |= cconv; + } + + internal sealed override void TypeSig(MemoryStream sig) + { + sig.WriteByte((byte)callConv); + if ((callConv & CallConv.Generic) == CallConv.Generic) + MetaData.CompressNum ((uint) gen_param_count, sig); + MetaData.CompressNum(numPars+numOptPars,sig); + retType.TypeSig(sig); + for (int i=0; i < numPars; i++) { + parList[i].TypeSig(sig); + } + if (numOptPars > 0) { + sig.WriteByte(Sentinel); + for (int i=0; i < numOptPars; i++) { + optParList[i].TypeSig(sig); + } + } + } + + internal sealed override void BuildTables(MetaData md) + { + if (done) return; + nameIx = md.AddToStringsHeap(name); + sigIx = GetSigIx(md); + done = true; + } + + internal sealed override uint Size(MetaData md) + { + return md.CodedIndexSize(CIx.MemberRefParent) + md.StringsIndexSize() + md.BlobIndexSize(); + } + + internal sealed override void Write(FileImage output) + { + output.WriteCodedIndex(CIx.MemberRefParent,parent); + output.StringsIndex(nameIx); + output.BlobIndex(sigIx); + } + + internal sealed override uint GetCodedIx(CIx code) + { + switch (code) { + case (CIx.HasCustomAttr) : return 6; + case (CIx.MethodDefOrRef) : return 1; + case (CIx.CustomAttributeType) : return 3; + } + return 0; + } + + } + + + /**************************************************************************/ + /// <summary> + /// Descriptors for native types used for marshalling + /// </summary> + public class NativeType { + public static readonly NativeType Void = new NativeType(0x01); + public static readonly NativeType Boolean = new NativeType(0x02); + public static readonly NativeType Int8 = new NativeType(0x03); + public static readonly NativeType UInt8 = new NativeType(0x04); + public static readonly NativeType Int16 = new NativeType(0x05); + public static readonly NativeType UInt16 = new NativeType(0x06); + public static readonly NativeType Int32 = new NativeType(0x07); + public static readonly NativeType UInt32 = new NativeType(0x08); + public static readonly NativeType Int64 = new NativeType(0x09); + public static readonly NativeType UInt64 = new NativeType(0x0A); + public static readonly NativeType Float32 = new NativeType(0x0B); + public static readonly NativeType Float64 = new NativeType(0x0C); + public static readonly NativeType Currency = new NativeType(0x0F); + public static readonly NativeType BStr = new NativeType(0x13); + public static readonly NativeType LPStr = new NativeType(0x14); + public static readonly NativeType LPWStr = new NativeType(0x15); + public static readonly NativeType LPTStr = new NativeType(0x16); + public static readonly NativeType FixedSysString = new NativeType(0x17); + public static readonly NativeType IUnknown = new NativeType(0x19); + public static readonly NativeType IDispatch = new NativeType(0x1A); + public static readonly NativeType Struct = new NativeType(0x1B); + public static readonly NativeType Interface = new NativeType(0x1C); + public static readonly NativeType Int = new NativeType(0x1F); + public static readonly NativeType UInt = new NativeType(0x20); + public static readonly NativeType ByValStr = new NativeType(0x22); + public static readonly NativeType AnsiBStr = new NativeType(0x23); + public static readonly NativeType TBstr = new NativeType(0x24); + public static readonly NativeType VariantBool = new NativeType(0x25); + public static readonly NativeType FuncPtr = new NativeType(0x26); + public static readonly NativeType AsAny = new NativeType(0x28); + + protected byte typeIndex; + + internal NativeType(byte tyIx) { typeIndex = tyIx; } + internal byte GetTypeIndex() { return typeIndex; } + + internal virtual byte[] ToBlob() + { + byte[] bytes = new byte[1]; + bytes[0] = GetTypeIndex(); + return bytes; + } + + } + + public class FixedSysString : NativeType { + + uint size; + + public FixedSysString (uint size) : base (NativeType.FixedSysString.GetTypeIndex ()) + { + this.size = size; + } + + internal override byte [] ToBlob () + { + MemoryStream str = new MemoryStream (); + str.WriteByte (GetTypeIndex ()); + MetaData.CompressNum (size, str); + return str.ToArray (); + } + + } + + public class NativeArray : NativeType { + + NativeType elemType; + int numElem = -1, parNum = -1, elemMult = -1; + + public NativeArray(NativeType elemType) : this (elemType, -1, -1, -1) + { + this.elemType = elemType; + } + + /* public NativeArray(NativeType elemType, int len) : base(0x2A) { + this.elemType = elemType; + this.len = len; + } + */ + + public NativeArray(NativeType elemType, int numElem, int parNumForLen, int elemMult) : base(0x2A) + { + this.elemType = elemType; + this.numElem = numElem; + parNum = parNumForLen; + this.elemMult = elemMult; + } + + public NativeArray(NativeType elemType, int numElem, int parNumForLen) + : this (elemType, numElem, parNumForLen, -1) + { + } + + internal override byte[] ToBlob() + { + MemoryStream str = new MemoryStream(); + str.WriteByte(GetTypeIndex()); + if (elemType == null) str.WriteByte(0x50); // no info (MAX) + else str.WriteByte(elemType.GetTypeIndex()); + + /* see : mono/metadata/metadata.c:mono_metadata_parse_marshal_spec + * LAMESPEC: Older spec versions say elemMult comes before + * len. Newer spec versions don't talk about elemMult at + * all, but csc still emits it, and it is used to distinguish + * between parNum being 0, and parNum being omitted. + */ + + if (parNum == -1) + // <native_type> [] + return str.ToArray (); + + MetaData.CompressNum((uint) parNum,str); + if (numElem != -1) { + MetaData.CompressNum ((uint) numElem, str); + if (elemMult != -1) + // <native_type> [ int32 ] + MetaData.CompressNum((uint) elemMult,str); + //else <native_type> [ int32 + int32 ] + } else if (elemMult != -1) { + // When can this occur ? + MetaData.CompressNum (0, str); + MetaData.CompressNum((uint) elemMult,str); + } + //else <native_type> [ + int32 ] + + return str.ToArray(); + } + + } + + public class SafeArray : NativeType { + + SafeArrayType elemType; + bool hasElemType; + + public SafeArray() : base(0x1D) + { + } + + public SafeArray(SafeArrayType elemType) : base(0x1D) + { + this.elemType = elemType; + hasElemType = true; + } + + internal override byte[] ToBlob() + { + byte[] bytes = new byte[hasElemType ? 2 : 1]; + bytes[0] = GetTypeIndex(); + if (hasElemType) + bytes[1] = (byte)elemType; + return bytes; + } + + } + + public class FixedArray : NativeType { + + NativeType elemType; + uint numElem; + + //public FixedArray(NativeType elemType, int numElems) : base(0x1E) { + public FixedArray(int numElems) : base(0x1E) + { + //this.elemType = elemType; + numElem = (uint)numElems; + } + + internal override byte[] ToBlob() + { + MemoryStream str = new MemoryStream(); + str.WriteByte(GetTypeIndex()); + MetaData.CompressNum(numElem,str); + /* FIXME: + fixed array [5] lpstr [2] + This format is not supported by ilasm 1.1.4322.2032, + but is supported by 2.0.5125.. + ilasm 1.1 only supports "fixed array [5]" + if (elemType == null) str.WriteByte(0x50); // no info (MAX) + else str.WriteByte(elemType.GetTypeIndex());*/ + + return str.ToArray(); + } + + } + + public class CustomMarshaller : NativeType { + + string typeName; + string marshallerName; + string cookie; + + public CustomMarshaller(string typeNameOrGUID, string marshallerName, + string optCookie) : base(0x2C) + { + typeName = typeNameOrGUID; + this.marshallerName = marshallerName; + cookie = optCookie; + } + + public CustomMarshaller(string marshallerName, string optCookie) + :this (null, marshallerName, optCookie) + { + } + + internal override byte[] ToBlob() + { + MemoryStream str = new MemoryStream(); + BinaryWriter bw = new BinaryWriter(str,new UTF8Encoding()); + bw.Write(GetTypeIndex()); + //Native type name & unmanaged type - unused + //See mono/metadata/metadata.c : mono_metadata_parse_marshal_spec + bw.Write ((byte) 0); // Native Type name, unused + bw.Write ((byte) 0); // Unmanaged type, unused + if (marshallerName != null) { + MetaData.CompressNum ((uint)marshallerName.Length, str); + bw.Write(marshallerName.ToCharArray()); + } else { + bw.Write ((byte) 0); + } + if (cookie != null) { + MetaData.CompressNum ((uint)cookie.Length, str); + bw.Write(cookie.ToCharArray()); + } else { + bw.Write ((byte) 0); + } + bw.Flush(); + return str.ToArray(); + } + } + + /**************************************************************************/ + /// <summary> + /// Descriptor for the Primitive types defined in IL + /// </summary> + public class PrimitiveType : Type { + + private string name; + private int systemTypeIndex; + public static int NumSystemTypes = 18; + + public static readonly PrimitiveType Void = new PrimitiveType(0x01,"Void",0); + public static readonly PrimitiveType Boolean = new PrimitiveType(0x02,"Boolean",1); + public static readonly PrimitiveType Char = new PrimitiveType(0x03,"Char",2); + public static readonly PrimitiveType Int8 = new PrimitiveType(0x04,"SByte",3); + public static readonly PrimitiveType UInt8 = new PrimitiveType(0x05,"Byte",4); + public static readonly PrimitiveType Int16 = new PrimitiveType(0x06,"Int16",5); + public static readonly PrimitiveType UInt16 = new PrimitiveType(0x07,"UInt16",6); + public static readonly PrimitiveType Int32 = new PrimitiveType(0x08,"Int32",7); + public static readonly PrimitiveType UInt32 = new PrimitiveType(0x09,"UInt32",8); + public static readonly PrimitiveType Int64 = new PrimitiveType(0x0A,"Int64",9); + public static readonly PrimitiveType UInt64 = new PrimitiveType(0x0B,"UInt64",10); + public static readonly PrimitiveType Float32 = new PrimitiveType(0x0C,"Single",11); + public static readonly PrimitiveType Float64 = new PrimitiveType(0x0D,"Double",12); + public static readonly PrimitiveType String = new PrimitiveType(0x0E,"String",13); + internal static readonly PrimitiveType Class = new PrimitiveType(0x12); + internal static readonly PrimitiveType Var = new PrimitiveType(0x13); + internal static readonly PrimitiveType GenericInst = new PrimitiveType(0x15); + public static readonly PrimitiveType TypedRef = new PrimitiveType(0x16,"TypedReference",14); + public static readonly PrimitiveType IntPtr = new PrimitiveType(0x18,"IntPtr",15); + public static readonly PrimitiveType UIntPtr = new PrimitiveType(0x19,"UIntPtr",16); + public static readonly PrimitiveType Object = new PrimitiveType(0x1C,"Object",17); + internal static readonly PrimitiveType ClassType = new PrimitiveType(0x50); + internal static readonly PrimitiveType SZArray = new PrimitiveType(0x1D); + internal static readonly PrimitiveType MVar = new PrimitiveType(0x1E); + internal static readonly PrimitiveType ValueType = new PrimitiveType(0x11, "ValueType", 18); + public static readonly PrimitiveType NativeInt = IntPtr; + public static readonly PrimitiveType NativeUInt = UIntPtr; + + internal PrimitiveType(byte typeIx) : base(typeIx) { } + + internal PrimitiveType(byte typeIx, string name, int STIx) : base(typeIx) + { + this.name = name; + this.systemTypeIndex = STIx; + } + + internal string GetName() { return name; } + + internal int GetSystemTypeIx() { return systemTypeIndex; } + + internal sealed override void TypeSig(MemoryStream str) + { + str.WriteByte(typeIndex); + } + + internal override MetaDataElement GetTypeSpec(MetaData md) + { + TypeSpec tS = md.GetPrimitiveTypeSpec(systemTypeIndex); + if (tS == null) { + tS = new TypeSpec(this,md); + md.SetPrimitiveTypeSpec(systemTypeIndex,tS); + md.AddToTable(MDTable.TypeSpec,tS); + } + return tS; + } + + } + + /**************************************************************************/ + /// <summary> + /// Descriptor for an pointer (type * or type &) + /// </summary> + public abstract class PtrType : Type { + + Type baseType; + + internal PtrType(Type bType, byte typeIx) : base(typeIx) + { + baseType = bType; + tabIx = MDTable.TypeSpec; + } + + internal sealed override void TypeSig(MemoryStream str) + { + str.WriteByte(typeIndex); + baseType.TypeSig(str); + } + + } + /**************************************************************************/ + /// <summary> + /// Descriptor for a managed pointer (type & or byref) + /// </summary> + + public class ManagedPointer : PtrType { + + /// <summary> + /// Create new managed pointer to baseType + /// </summary> + /// <param name="bType">the base type of the pointer</param> + public ManagedPointer(Type baseType) : base(baseType,0x10) { } + + } + /**************************************************************************/ + /// <summary> + /// Descriptor for an unmanaged pointer (type *) + /// </summary> + public class UnmanagedPointer : PtrType { + + /// <summary> + /// Create a new unmanaged pointer to baseType + /// </summary> + /// <param name="baseType">the base type of the pointer</param> + public UnmanagedPointer(Type baseType) : base(baseType, 0x0F) { } + + } + + /**************************************************************************/ + + public interface IExternRef { + ClassRef AddClass(string nsName, string name); + ClassRef AddValueClass(string nsName, string name); + } + + /// <summary> + /// A reference to an external assembly (.assembly extern) + /// </summary> + public class AssemblyRef : ResolutionScope, IExternRef { + + private ushort major, minor, build, revision; + uint flags, keyIx, hashIx, cultIx; + bool hasVersion = false, isKeyToken = false; + byte[] keyBytes; + string culture; + + internal AssemblyRef(MetaData md, string name) : base(name,md) + { + tabIx = MDTable.AssemblyRef; + } + + /// <summary> + /// Add version information about this external assembly + /// </summary> + /// <param name="majVer">Major Version</param> + /// <param name="minVer">Minor Version</param> + /// <param name="bldNo">Build Number</param> + /// <param name="revNo">Revision Number</param> + public void AddVersionInfo(int majVer, int minVer, int bldNo, int revNo) + { + major = (ushort)majVer; + minor = (ushort)minVer; + build = (ushort)bldNo; + revision = (ushort)revNo; + hasVersion = true; + } + + /// <summary> + /// Add the hash value for this external assembly + /// </summary> + /// <param name="hash">bytes of the hash value</param> + public void AddHash(byte[] hash) + { + hashIx = metaData.AddToBlobHeap(hash); + } + + /// <summary> + /// Set the culture for this external assembly + /// </summary> + /// <param name="cult">the culture string</param> + public void AddCulture(string cult) + { + cultIx = metaData.AddToStringsHeap(cult); + culture = cult; + } + + /// <summary> + /// Add the full public key for this external assembly + /// </summary> + /// <param name="key">bytes of the public key</param> + public void AddKey(byte[] key) + { + flags |= 0x0001; // full public key + keyBytes = key; + keyIx = metaData.AddToBlobHeap(key); + } + + /// <summary> + /// Add the public key token (low 8 bytes of the public key) + /// </summary> + /// <param name="key">low 8 bytes of public key</param> + public void AddKeyToken(byte[] key) + { + keyIx = metaData.AddToBlobHeap(key); + keyBytes = key; + isKeyToken = true; + } + + /// <summary> + /// Add a class to this external assembly + /// </summary> + /// <param name="nsName">name space name</param> + /// <param name="name">class name</param> + /// <returns></returns> + public virtual ClassRef AddClass(string nsName, string name) + { + ClassRef aClass = new ClassRef(nsName,name,metaData); + metaData.AddToTable(MDTable.TypeRef,aClass); + aClass.SetParent(this); + return aClass; + } + + /// <summary> + /// Add a value class to this external assembly + /// </summary> + /// <param name="nsName">name space name</param> + /// <param name="name">class name</param> + /// <returns></returns> + public virtual ClassRef AddValueClass(string nsName, string name) + { + ClassRef aClass = new ClassRef(nsName,name,metaData); + metaData.AddToTable(MDTable.TypeRef,aClass); + aClass.SetParent(this); + aClass.MakeValueClass(ValueClass.ValueType); + return aClass; + } + + internal string TypeName() + { + string result = name; + if (hasVersion) + result = result + ", Version=" + major + "." + minor + "." + + build + "." + revision; + if (keyBytes != null) { + string tokenStr = "="; + if (isKeyToken) tokenStr = "Token="; + result = result + ", PublicKey" + tokenStr; + for (int i=0; i < keyBytes.Length; i++) { + result = result + Hex.Byte(keyBytes[i]); + } + } + if (culture != null) + result = result + ", Culture=" + culture; + return result; + } + + internal sealed override uint Size(MetaData md) + { + return 12 + 2 * md.StringsIndexSize() + 2 * md.BlobIndexSize(); + } + + internal sealed override void Write(FileImage output) + { + output.Write(major); + output.Write(minor); + output.Write(build); + output.Write(revision); + output.Write(flags); + output.BlobIndex(keyIx); + output.StringsIndex(nameIx); + output.StringsIndex(cultIx); + output.BlobIndex(hashIx); + } + + internal sealed override uint GetCodedIx(CIx code) + { + switch (code) { + case (CIx.ResolutionScope) : return 2; + case (CIx.HasCustomAttr) : return 15; + case (CIx.Implementation) : return 1; + } + return 0; + } + + } + + /**************************************************************************/ + /// <summary> + /// Descriptor for a class defined in System (mscorlib) + /// </summary> + internal class SystemClass : ClassRef { + + PrimitiveType elemType; + + internal SystemClass(PrimitiveType eType, AssemblyRef paren, MetaData md) + : base("System",eType.GetName(),md) { + elemType = eType; + parent = paren; + } + + internal override sealed MetaDataElement GetTypeSpec(MetaData md) + { + if (typeSpec == null) typeSpec = (TypeSpec)elemType.GetTypeSpec(md); + return typeSpec; + } + + + internal sealed override void TypeSig(MemoryStream str) + { + str.WriteByte(elemType.GetTypeIndex()); + } + + } + + /**************************************************************************/ + /// <summary> + /// The assembly for mscorlib. + /// </summary> + public sealed class MSCorLib : AssemblyRef { + + private static readonly int valueTypeIx = 18; + private readonly string systemName = "System"; + private Class[] systemClasses = new Class[valueTypeIx+2]; + private PrimitiveType[] systemTypes = new PrimitiveType[valueTypeIx]; + private TypeSpec[] specialTypeSpecs = new TypeSpec[valueTypeIx]; + private static int[] specialNames = { + PrimitiveType.Void.GetName().GetHashCode(), + PrimitiveType.Boolean.GetName().GetHashCode(), + PrimitiveType.Char.GetName().GetHashCode(), + PrimitiveType.Int8.GetName().GetHashCode(), + PrimitiveType.UInt8.GetName().GetHashCode(), + PrimitiveType.Int16.GetName().GetHashCode(), + PrimitiveType.UInt16.GetName().GetHashCode(), + PrimitiveType.Int32.GetName().GetHashCode(), + PrimitiveType.UInt32.GetName().GetHashCode(), + PrimitiveType.Int64.GetName().GetHashCode(), + PrimitiveType.UInt64.GetName().GetHashCode(), + PrimitiveType.Float32.GetName().GetHashCode(), + PrimitiveType.Float64.GetName().GetHashCode(), + PrimitiveType.String.GetName().GetHashCode(), + PrimitiveType.TypedRef.GetName().GetHashCode(), + PrimitiveType.IntPtr.GetName().GetHashCode(), + PrimitiveType.UIntPtr.GetName().GetHashCode(), + PrimitiveType.Object.GetName().GetHashCode(), + PrimitiveType.ValueType.GetName ().GetHashCode(), + "Enum".GetHashCode() + }; + + internal MSCorLib(MetaData md) : base(md,"mscorlib") + { + if (!PEFile.IsMSCorlib) + md.AddToTable(MDTable.AssemblyRef,this); + systemTypes[PrimitiveType.Void.GetSystemTypeIx()] = PrimitiveType.Void; + systemTypes[PrimitiveType.Boolean.GetSystemTypeIx()] = PrimitiveType.Boolean; + systemTypes[PrimitiveType.Char.GetSystemTypeIx()] = PrimitiveType.Char; + systemTypes[PrimitiveType.Int8.GetSystemTypeIx()] = PrimitiveType.Int8; + systemTypes[PrimitiveType.UInt8.GetSystemTypeIx()] = PrimitiveType.UInt8; + systemTypes[PrimitiveType.Int16.GetSystemTypeIx()] = PrimitiveType.Int16; + systemTypes[PrimitiveType.UInt16.GetSystemTypeIx()] = PrimitiveType.UInt16; + systemTypes[PrimitiveType.Int32.GetSystemTypeIx()] = PrimitiveType.Int32; + systemTypes[PrimitiveType.UInt32.GetSystemTypeIx()] = PrimitiveType.UInt32; + systemTypes[PrimitiveType.Int64.GetSystemTypeIx()] = PrimitiveType.Int64; + systemTypes[PrimitiveType.UInt64.GetSystemTypeIx()] = PrimitiveType.UInt64; + systemTypes[PrimitiveType.Float32.GetSystemTypeIx()] = PrimitiveType.Float32; + systemTypes[PrimitiveType.Float64.GetSystemTypeIx()] = PrimitiveType.Float64; + systemTypes[PrimitiveType.IntPtr.GetSystemTypeIx()] = PrimitiveType.IntPtr; + systemTypes[PrimitiveType.UIntPtr.GetSystemTypeIx()] = PrimitiveType.UIntPtr; + systemTypes[PrimitiveType.String.GetSystemTypeIx()] = PrimitiveType.String; + systemTypes[PrimitiveType.Object.GetSystemTypeIx()] = PrimitiveType.Object; + systemTypes[PrimitiveType.TypedRef.GetSystemTypeIx()] = PrimitiveType.TypedRef; + } + + /// <summary> + /// Add a class to the mscorlib assembly + /// </summary> + /// <param name="nsName">name space name</param> + /// <param name="name">class name</param> + /// <returns></returns> + public override ClassRef AddClass(string nsName, string name) + { + /* This gets called by !mscorlib, for adding references INTO mscorlib, so + it should be returning ClassRef ..*/ + Class aClass = GetSpecialClass(nsName,name); + if (aClass == null) { + aClass = new ClassRef(nsName,name,metaData); + metaData.AddToTable(MDTable.TypeRef,aClass); + if (aClass is ClassRef) + ((ClassRef) aClass).SetParent(this); + } + //FIXME: Check for !ClassRef here? + return (ClassRef) aClass; + } + + private Class GetSpecialClass(string nsName,string name) + { + if (nsName.CompareTo(systemName) != 0) return null; + int hash = name.GetHashCode(); + for (int i=0; i < specialNames.Length; i++) { + if (hash != specialNames[i]) + continue; + if (systemClasses[i] == null) { + if (i < valueTypeIx) { + systemClasses[i] = new SystemClass(systemTypes[i],this,metaData); + if ((systemTypes[i] != PrimitiveType.Object) && + (systemTypes[i] != PrimitiveType.String)) { + systemClasses[i].MakeValueClass(ValueClass.ValueType); + } + } else { + systemClasses[i] = new ClassRef(nsName,name,metaData); + ((ClassRef) systemClasses[i]).SetParent(this); + if (!ClassDef.IsValueType (nsName, name) && !ClassDef.IsEnum (nsName, name)) + systemClasses[i].MakeValueClass(ValueClass.ValueType); + } + metaData.AddToTable(MDTable.TypeRef,systemClasses[i]); + } + return systemClasses[i]; + } + return null; + } + + internal void SetSpecialSystemClass (string nsName, string name, Class aClass) + { + if (nsName != systemName) return; + int hash = name.GetHashCode (); + for (int i = 0; i < specialNames.Length; i++) { + if (hash != specialNames [i]) + continue; + if (systemClasses [i] == null) { + systemClasses [i] = aClass; + } + } + } + + internal Class GetSpecialSystemClass(PrimitiveType pType) + { + int ix = pType.GetSystemTypeIx(); + if (systemClasses[ix] == null && !PEFile.IsMSCorlib) { + systemClasses[ix] = new SystemClass(pType,this,metaData); + metaData.AddToTable(MDTable.TypeRef,systemClasses[ix]); + } + return systemClasses[ix]; + } + + private ClassRef GetValueClass(string name, int hash) + { + /* Called by MSCorLib.AddValueClass, which is called by + !mscorlib, for adding ref to value class INTO mscorlib, + so this should be classref */ + int ix = valueTypeIx; + if (hash != specialNames[valueTypeIx]) ix++; + if (systemClasses[ix] == null) { + systemClasses[ix] = new ClassRef(systemName,name,metaData); + ((ClassRef) systemClasses[ix]).SetParent(this); + ((ClassRef) systemClasses[ix]).MakeValueClass(ValueClass.ValueType); + metaData.AddToTable(MDTable.TypeRef,systemClasses[ix]); + } + return (ClassRef) systemClasses[ix]; + } + + internal Class ValueType() + { + if (systemClasses[valueTypeIx] == null && !PEFile.IsMSCorlib) { + ClassRef valType = new ClassRef("System","ValueType",metaData); + valType.SetParent(this); + valType.MakeValueClass(ValueClass.ValueType); + metaData.AddToTable(MDTable.TypeRef,valType); + systemClasses[valueTypeIx] = valType; + } + return systemClasses[valueTypeIx]; + } + + internal Class EnumType() + { + /* Called by both mscorlib & !mscorlib, so can be + either ClassRef or ClassDef */ + //systemClasses [ valueTypeIx + 1] -> System.Enum + if (systemClasses[valueTypeIx + 1] == null && !PEFile.IsMSCorlib) { + ClassRef valType = new ClassRef("System","Enum",metaData); + valType.SetParent(this); + valType.MakeValueClass(ValueClass.Enum); + metaData.AddToTable(MDTable.TypeRef,valType); + systemClasses[valueTypeIx + 1] = valType; + } + return systemClasses[valueTypeIx + 1]; + } + + /// <summary> + /// Add a value class to this external assembly + /// </summary> + /// <param name="nsName">name space name</param> + /// <param name="name">class name</param> + /// <returns></returns> + public override ClassRef AddValueClass(string nsName, string name) + { + if (nsName.CompareTo(systemName) == 0) { + int hash = name.GetHashCode(); + if ((hash == specialNames[valueTypeIx]) || + (hash == specialNames[valueTypeIx+1])) { + return GetValueClass(name,hash); + } + } + ClassRef aClass = new ClassRef(nsName,name,metaData); + metaData.AddToTable(MDTable.TypeRef,aClass); + aClass.SetParent(this); + aClass.MakeValueClass(ValueClass.ValueType); + return aClass; + } + + } + + /**************************************************************************/ + /// <summary> + /// MetaData + /// Root (20 bytes + UTF-8 Version String + quad align padding) + /// StreamHeaders (8 bytes + null terminated name string + quad align padding) + /// Streams + /// #~ (always present - holds metadata tables) + /// #Strings (always present - holds identifier strings) + /// #US (Userstring heap) + /// #Blob (signature blobs) + /// #GUID (guids for assemblies or Modules) + /// </summary> + public class MetaData { + + internal static readonly int[] CIxShiftMap = {2,2,5,1,2,3,1,1,1,2,3,2,1}; + private static readonly byte StringsHeapMask = 0x1; + private static readonly byte GUIDHeapMask = 0x2; + private static readonly byte BlobHeapMask = 0x4; + private static readonly uint MetaDataSignature = 0x424A5342; + private static readonly uint maxSmlIxSize = 0xFFFF; + private static readonly uint max1BitSmlIx = 0x7FFF; + private static readonly uint max2BitSmlIx = 0x3FFF; + private static readonly uint max3BitSmlIx = 0x1FFF; + private static readonly uint max5BitSmlIx = 0x7FF; + // NOTE: version and stream name strings MUST always be quad padded +#if NET_2_0 || BOOTSTRAP_NET_2_0 + private static readonly string version = "v2.0.50727\0\0"; +#else + private static readonly string version = "v1.1.4322\0\0\0"; +#endif + private static readonly char[] tildeName = {'#','~','\0','\0'}; + private static readonly char[] stringsName = {'#','S','t','r','i','n','g','s','\0','\0','\0','\0'}; + private static readonly char[] usName = {'#','U','S','\0'}; + private static readonly char[] guidName = {'#','G','U','I','D','\0','\0','\0'}; + private static readonly char[] blobName = {'#','B','l','o','b','\0','\0','\0'}; + private static readonly uint MetaDataHeaderSize = 20 + (uint)version.Length; + private static readonly uint TildeHeaderSize = 24; + private static readonly uint StreamHeaderSize = 8; + private static readonly uint numMetaDataTables = (int)MDTable.GenericParamConstraint + 1; + private static readonly uint tildeHeaderSize = 8 + (uint)tildeName.Length; + + MetaDataStream strings, us, guid, blob; + + MetaDataStream[] streams = new MetaDataStream[5]; + uint numStreams = 5; + uint tildeTide = 0, tildePadding = 0, tildeStart = 0; + uint numTables = 0, resourcesSize = 0; + ArrayList[] metaDataTables = new ArrayList[numMetaDataTables]; + ArrayList byteCodes = new ArrayList(); + uint codeSize = 0, codeStart, byteCodePadding = 0, metaDataSize = 0; + ulong valid = 0, /*sorted = 0x000002003301FA00;*/ sorted = 0; + bool[] largeIx = new bool[numMetaDataTables]; + bool[] lgeCIx = new bool[(int)CIx.MaxCIx]; + bool largeStrings = false, largeUS = false, largeGUID = false, largeBlob = false; + private FileImage file; + private byte heapSizes = 0; + MetaDataElement entryPoint; + BinaryWriter output; + public MSCorLib mscorlib; + private TypeSpec[] systemTypeSpecs = new TypeSpec[PrimitiveType.NumSystemTypes]; + long mdStart; + private ArrayList cattr_list; + private ArrayList declsec_list; + ArrayList resources; + + internal MetaData(FileImage file) + { + // tilde = new MetaDataStream(tildeName,false,0); + this.file = file; + strings = new MetaDataStream(stringsName,new UTF8Encoding(),true); + us = new MetaDataStream(usName,new UnicodeEncoding(),true); + guid = new MetaDataStream(guidName,false); + blob = new MetaDataStream(blobName,true); + streams[1] = strings; + streams[2] = us; + streams[3] = guid; + streams[4] = blob; + for (int i=0; i < numMetaDataTables; i++) { + largeIx[i] = false; + } + for (int i=0; i < lgeCIx.Length; i++) { + lgeCIx[i] = false; + } + mscorlib = new MSCorLib(this); + } + + internal TypeSpec GetPrimitiveTypeSpec(int ix) + { + return systemTypeSpecs[ix]; + } + + internal void SetPrimitiveTypeSpec(int ix, TypeSpec typeSpec) + { + systemTypeSpecs[ix] = typeSpec; + } + + internal uint Size() + { + return metaDataSize; + } + + private void CalcHeapSizes () + { + if (strings.LargeIx()) { + largeStrings = true; + heapSizes |= StringsHeapMask; + } + if (guid.LargeIx()) { + largeGUID = true; + heapSizes |= GUIDHeapMask; + } + if (blob.LargeIx()) { + largeBlob = true; + heapSizes |= BlobHeapMask; + } + + largeUS = us.LargeIx(); + } + + internal void StreamSize(byte mask) + { + heapSizes |= mask; + } + + internal uint AddToUSHeap(string str) + { + if (str == null) return 0; + return us.Add(str,true); + } + + internal uint AddToUSHeap(byte[] str) + { + if (str == null) return 0; + return us.Add (str, true); + } + + internal uint AddToStringsHeap(string str) + { + if ((str == null) || (str.CompareTo("") == 0)) return 0; + return strings.Add(str,false); + } + + internal uint AddToGUIDHeap(Guid guidNum) + { + return guid.Add(guidNum, false); + } + + internal uint AddToBlobHeap(byte[] blobBytes) + { + if (blobBytes == null) return 0; + return blob.Add(blobBytes, true); + } + + internal uint AddToBlobHeap(byte val) + { + return blob.Add(val, true); + } + + internal uint AddToBlobHeap(sbyte val) + { + return blob.Add(val, true); + } + + internal uint AddToBlobHeap(ushort val) + { + return blob.Add(val, true); + } + + internal uint AddToBlobHeap(short val) + { + return blob.Add(val, true); + } + + internal uint AddToBlobHeap(uint val) + { + return blob.Add(val, true); + } + + internal uint AddToBlobHeap(int val) + { + return blob.Add(val, true); + } + + internal uint AddToBlobHeap(ulong val) + { + return blob.Add(val, true); + } + + internal uint AddToBlobHeap(long val) + { + return blob.Add(val, true); + } + + internal uint AddToBlobHeap(float val) + { + return blob.Add(val, true); + } + + internal uint AddToBlobHeap(double val) + { + return blob.Add(val, true); + } + + internal uint AddToBlobHeap(string val) + { + return blob.Add(val,true); + } + + internal void AddCustomAttribute (CustomAttribute cattr) + { + if (cattr_list == null) + cattr_list = new ArrayList (); + cattr_list.Add (cattr); + } + + internal void AddDeclSecurity (DeclSecurity decl_sec) + { + if (declsec_list == null) + declsec_list = new ArrayList (); + declsec_list.Add (decl_sec); + } + + private ArrayList GetTable(MDTable tableIx) + { + int tabIx = (int)tableIx; + if (metaDataTables[tabIx] == null) { + metaDataTables[tabIx] = new ArrayList(); + valid |= ((ulong)0x1 << tabIx); + // Console.WriteLine("after creating table " + tableIx + "(" + tabIx + ") valid = " + valid); + numTables++; + } + return metaDataTables[tabIx]; + } + + internal void AddToTable(MDTable tableIx, MetaDataElement elem) + { + if (elem.Row > 0) { + // Console.Out.WriteLine("ERROR - element already in table " + tableIx); + return; + } + // updates Row field of the element + // Console.WriteLine("Adding element to table " + (uint)tableIx); + ArrayList table = GetTable(tableIx); + elem.Row = (uint)table.Count + 1; + table.Add(elem); + } + + internal uint TableIndex(MDTable tableIx) + { + if (metaDataTables[(int)tableIx] == null) return 1; + return (uint)metaDataTables[(int)tableIx].Count+1; + } + + internal uint AddCode(CILInstructions byteCode) + { + byteCodes.Add(byteCode); + uint offset = codeSize + codeStart; + codeSize += byteCode.GetCodeSize(); + return offset; + } + + internal void SetEntryPoint(MetaDataElement ep) + { + entryPoint = ep; + } + + internal uint AddResource(byte[] resBytes) + { + if (resources == null) resources = new ArrayList (); + resources.Add (resBytes); + uint offset = resourcesSize; + resourcesSize += (uint)resBytes.Length + 4; + return offset; + } + + internal void AddData(DataConstant cVal) + { + file.AddInitData(cVal); + } + + internal static void CompressNum(uint val, MemoryStream sig) + { + if (val <= 0x7F) { + sig.WriteByte((byte)val); + } else if (val <= 0x3FFF) { + byte b1 = (byte)((val >> 8) | 0x80); + byte b2 = (byte)(val & FileImage.iByteMask[0]); + sig.WriteByte(b1); + sig.WriteByte(b2); + } else { + byte b1 = (byte)((val >> 24) | 0xC0); + byte b2 = (byte)((val & FileImage.iByteMask[2]) >> 16); + byte b3 = (byte)((val & FileImage.iByteMask[1]) >> 8);; + byte b4 = (byte)(val & FileImage.iByteMask[0]); + sig.WriteByte(b1); + sig.WriteByte(b2); + sig.WriteByte(b3); + sig.WriteByte(b4); + } + } + + internal uint CodeSize() + { + return codeSize + byteCodePadding; + } + + internal uint GetResourcesSize() + { + return resourcesSize; + } + + internal uint StringsIndexSize() + { + if (largeStrings) return 4; + return 2; + } + + internal uint GUIDIndexSize() + { + if (largeGUID) return 4; + return 2; + } + + internal uint USIndexSize() + { + if (largeUS) return 4; + return 2; + } + + internal uint BlobIndexSize() + { + if (largeBlob) return 4; + return 2; + } + + internal uint CodedIndexSize(CIx code) + { + if (lgeCIx[(uint)code]) return 4; + return 2; + } + + internal uint TableIndexSize(MDTable tabIx) + { + if (largeIx[(uint)tabIx]) return 4; + return 2; + } + + private void SetIndexSizes() + { + for (int i=0; i < numMetaDataTables; i++) { + if (metaDataTables[i] == null) + continue; + + uint count = (uint)metaDataTables[i].Count; + if (count > maxSmlIxSize) + largeIx[i] = true; + + MDTable tabIx = (MDTable)i; + if (count > max5BitSmlIx) { + lgeCIx[(int)CIx.HasCustomAttr] = true; + } + if (count > max3BitSmlIx) { + if ((tabIx == MDTable.TypeRef) || (tabIx == MDTable.ModuleRef) || (tabIx == MDTable.Method) || (tabIx == MDTable.TypeSpec) || (tabIx == MDTable.Field)) + lgeCIx[(int)CIx.CustomAttributeType] = true; + if ((tabIx == MDTable.Method) || (tabIx == MDTable.MemberRef)) + lgeCIx[(int)CIx.MemberRefParent] = true; + } + if (count > max2BitSmlIx) { + if ((tabIx == MDTable.Field) || (tabIx == MDTable.Param) || (tabIx == MDTable.Property)) + lgeCIx[(int)CIx.HasConst] = true; + if ((tabIx == MDTable.TypeDef) || (tabIx == MDTable.TypeRef) || (tabIx == MDTable.TypeSpec)) + lgeCIx[(int)CIx.TypeDefOrRef] = true; + if ((tabIx == MDTable.TypeDef) || (tabIx == MDTable.Method) || (tabIx == MDTable.Assembly)) + lgeCIx[(int)CIx.HasDeclSecurity] = true; + if ((tabIx == MDTable.File) || (tabIx == MDTable.AssemblyRef) || (tabIx == MDTable.ExportedType)) + lgeCIx[(int)CIx.Implementation] = true; + if ((tabIx == MDTable.Module) || (tabIx == MDTable.ModuleRef) || (tabIx == MDTable.AssemblyRef) || (tabIx == MDTable.TypeRef)) + lgeCIx[(int)CIx.ResolutionScope] = true; + } + if (count > max1BitSmlIx) { + if ((tabIx == MDTable.Field) || (tabIx == MDTable.Param)) + lgeCIx[(int)CIx.HasFieldMarshal] = true; + if ((tabIx == MDTable.Event) || (tabIx == MDTable.Property)) + lgeCIx[(int)CIx.HasSemantics] = true; + if ((tabIx == MDTable.Method) || (tabIx == MDTable.MemberRef)) + lgeCIx[(int)CIx.MethodDefOrRef] = true; + if ((tabIx == MDTable.Field) || (tabIx == MDTable.Method)) + lgeCIx[(int)CIx.MemberForwarded] = true; + if ((tabIx == MDTable.TypeDef) || (tabIx == MDTable.Method)) + lgeCIx[(int)CIx.TypeOrMethodDef] = true; + } + } + } + + private void SetStreamOffsets() + { + uint sizeOfHeaders = StreamHeaderSize + (uint)tildeName.Length; + for (int i=1; i < numStreams; i++) { + sizeOfHeaders += streams[i].headerSize(); + } + metaDataSize = MetaDataHeaderSize + sizeOfHeaders; + tildeStart = metaDataSize; + metaDataSize += tildeTide + tildePadding; + for (int i=1; i < numStreams; i++) { + streams[i].Start = metaDataSize; + metaDataSize += streams[i].Size(); + streams[i].WriteDetails(); + } + } + + internal void CalcTildeStreamSize() + { + CalcHeapSizes (); + //tilde.SetIndexSizes(strings.LargeIx(),us.LargeIx(),guid.LargeIx(),blob.LargeIx()); + tildeTide = TildeHeaderSize; + tildeTide += 4 * numTables; + //Console.WriteLine("Tilde header + sizes = " + tildeTide); + for (int i=0; i < numMetaDataTables; i++) { + if (metaDataTables[i] != null) { + ArrayList table = metaDataTables[i]; + // Console.WriteLine("Meta data table " + i + " at offset " + tildeTide); + tildeTide += (uint)table.Count * ((MetaDataElement)table[0]).Size(this); + // Console.WriteLine("Metadata table " + i + " has size " + table.Count); + // Console.WriteLine("tildeTide = " + tildeTide); + } + } + if ((tildeTide % 4) != 0) tildePadding = 4 - (tildeTide % 4); + //Console.WriteLine("tildePadding = " + tildePadding); + } + + internal void WriteTildeStream(FileImage output) + { + long startTilde = output.Seek(0,SeekOrigin.Current); + output.Write((uint)0); // Reserved +#if NET_2_0 || BOOTSTRAP_NET_2_0 + output.Write((byte)2); // MajorVersion + output.Write((byte)0); // MinorVersion +#else + output.Write((byte)1); // MajorVersion + output.Write((byte)0); // MinorVersion +#endif + output.Write(heapSizes); + output.Write((byte)1); // Reserved + output.Write(valid); + output.Write(sorted); + for (int i=0; i < numMetaDataTables; i++) { + if (metaDataTables[i] != null) { + uint count = (uint)metaDataTables[i].Count; + output.Write(count); + } + } + long tabStart = output.Seek(0,SeekOrigin.Current); + // Console.WriteLine("Starting metaData tables at " + tabStart); + for (int i=0; i < numMetaDataTables; i++) { + if (metaDataTables[i] != null) { + // Console.WriteLine("Starting metaData table " + i + " at " + (output.Seek(0,SeekOrigin.Current) - startTilde)); + ArrayList table = metaDataTables[i]; + for (int j=0; j < table.Count; j++) { + ((MetaDataElement)table[j]).Write(output); + } + } + } + // Console.WriteLine("Writing padding at " + output.Seek(0,SeekOrigin.Current)); + for (int i=0; i < tildePadding; i++) output.Write((byte)0); + } + + private void BuildTable(ArrayList table) + { + if (table == null) return; + for (int j=0; j < table.Count; j++) { + ((MetaDataElement)table[j]).BuildTables(this); + } + } + + private void SortTable (ArrayList mTable) + { + if (mTable == null) return; + mTable.Sort(); + for (int i=0; i < mTable.Count; i++) { + ((MetaDataElement)mTable[i]).Row = (uint)i+1; + } + } + + internal void BuildMetaData(uint codeStartOffset) + { + codeStart = codeStartOffset; + BuildTable(metaDataTables[(int)MDTable.TypeDef]); + BuildTable(metaDataTables[(int)MDTable.TypeSpec]); + BuildTable(metaDataTables[(int)MDTable.MemberRef]); +#if NET_2_0 || BOOTSTRAP_NET_2_0 + BuildTable(metaDataTables[(int)MDTable.GenericParam]); + BuildTable(metaDataTables[(int)MDTable.MethodSpec]); + BuildTable(metaDataTables[(int)MDTable.GenericParamConstraint]); +#endif + BuildTable(metaDataTables[(int)MDTable.ManifestResource]); + + if (cattr_list != null) { + foreach (CustomAttribute cattr in cattr_list) + cattr.BuildTables (this); + } + + if (declsec_list != null) { + foreach (DeclSecurity decl_sec in declsec_list) + decl_sec.BuildTables (this); + } + + /* for (int i=0; i < metaDataTables.Length; i++) { + ArrayList table = metaDataTables[i]; + if (table != null) { + for (int j=0; j < table.Count; j++) { + ((MetaDataElement)table[j]).BuildTables(this); + } + } + } + */ + + SetIndexSizes(); + for (int i=1; i < numStreams; i++) { + streams[i].EndStream(); + } + CalcTildeStreamSize(); + SetStreamOffsets(); + byteCodePadding = NumToAlign(codeSize,4); + if (entryPoint != null) file.SetEntryPoint(entryPoint.Token()); + + // Check ordering of specific tables + // Constant, CustomAttribute, FieldMarshal, DeclSecurity, MethodSemantics + // ImplMap, GenericParam + // Need to load GenericParamConstraint AFTER GenericParam table in correct order + // The tables: + // InterfaceImpl, ClassLayout, FieldLayout, MethodImpl, FieldRVA, NestedClass + // will _ALWAYS_ be in the correct order as embedded in BuildMDTables + + SortTable(metaDataTables[(int)MDTable.Constant]); + SortTable(metaDataTables[(int)MDTable.FieldMarshal]); + SortTable(metaDataTables[(int)MDTable.DeclSecurity]); + SortTable(metaDataTables[(int)MDTable.MethodSemantics]); + SortTable(metaDataTables[(int)MDTable.ImplMap]); +#if NET_2_0 || BOOTSTRAP_NET_2_0 + if (metaDataTables[(int)MDTable.GenericParam] != null) { + SortTable(metaDataTables[(int)MDTable.GenericParam]); + // Now add GenericParamConstraints + /*for (int i=0; i < metaDataTables[(int)MDTable.GenericParam].Count; i++) { + ((GenericParameter)metaDataTables[(int)MDTable.GenericParam][i]).AddConstraints(this); + }*/ + } + SortTable(metaDataTables[(int)MDTable.GenericParamConstraint]); +#endif + SortTable(metaDataTables[(int)MDTable.InterfaceImpl]); + SortTable(metaDataTables[(int)MDTable.CustomAttribute]); + + } + + internal void WriteByteCodes(FileImage output) + { + for (int i=0; i < byteCodes.Count; i++) { + ((CILInstructions)byteCodes[i]).Write(output); + } + for (int i=0; i < byteCodePadding; i++) { + output.Write((byte)0); + } + } + + internal void WriteResources (FileImage output) + { + if (resources == null) return; + for (int i = 0; i < resources.Count; i ++) { + byte [] resBytes = (byte []) resources [i]; + output.Write ((uint) resBytes.Length); + output.Write (resBytes); + } + } + + internal void WriteMetaData(FileImage output) + { + this.output = output; + mdStart = output.Seek(0,SeekOrigin.Current); + // Console.WriteLine("Writing metaData at " + Hex.Long(mdStart)); + output.Write(MetaDataSignature); + output.Write((short)1); // Major Version + output.Write((short)1); // Minor Version ECMA = 0, PEFiles = 1 + output.Write(0); // Reserved + output.Write(version.Length); + output.Write(version.ToCharArray()); // version string is already zero padded + output.Write((short)0); + output.Write((ushort)numStreams); + // write tilde header + output.Write(tildeStart); + output.Write(tildeTide + tildePadding); + output.Write(tildeName); + for (int i=1; i < numStreams; i++) streams[i].WriteHeader(output); + // Console.WriteLine("Writing tilde stream at " + output.Seek(0,SeekOrigin.Current) + " = " + tildeStart); + WriteTildeStream(output); + for (int i=1; i < numStreams; i++) streams[i].Write(output); + // Console.WriteLine("Finished Writing metaData at " + output.Seek(0,SeekOrigin.Current)); + } + + internal bool LargeStringsIndex() { return strings.LargeIx(); } + internal bool LargeGUIDIndex() { return guid.LargeIx(); } + internal bool LargeUSIndex() { return us.LargeIx(); } + internal bool LargeBlobIndex() { return blob.LargeIx(); } + + internal bool LargeIx(MDTable tabIx) { return largeIx[(uint)tabIx]; } + + + private uint NumToAlign(uint val, uint alignVal) + { + if ((val % alignVal) == 0) return 0; + return alignVal - (val % alignVal); + } + + internal void WriteCodedIndex(CIx code, MetaDataElement elem, FileImage output) + { + uint ix = 0; + if (elem != null) { + ix = (elem.Row << CIxShiftMap[(uint)code]) | elem.GetCodedIx(code); + // Console.WriteLine("coded index = " + ix + " row = " + elem.Row); + //} else { + // Console.WriteLine("elem for coded index is null"); + } + if (lgeCIx[(uint)code]) + output.Write(ix); + else + output.Write((ushort)ix); + } + + } + + /**************************************************************************/ + /// <summary> + /// Stream in the Meta Data (#Strings, #US, #Blob and #GUID) + /// </summary> + + internal class MetaDataStream : BinaryWriter { + + private static readonly uint StreamHeaderSize = 8; + private static uint maxSmlIxSize = 0xFFFF; + + private uint start = 0; + uint size = 0, tide = 1; + bool largeIx = false; + uint sizeOfHeader; + char[] name; + Hashtable htable = new Hashtable(); + Hashtable btable = new Hashtable (new ByteArrayHashCodeProvider (), new ByteArrayComparer ()); + + internal MetaDataStream(char[] name, bool addInitByte) : base(new MemoryStream()) + { + if (addInitByte) { Write((byte)0); size = 1; } + this.name = name; + sizeOfHeader = StreamHeaderSize + (uint)name.Length; + } + + internal MetaDataStream(char[] name, System.Text.Encoding enc, bool addInitByte) : base(new MemoryStream(),enc) + { + if (addInitByte) { Write((byte)0); size = 1; } + this.name = name; + sizeOfHeader = StreamHeaderSize + (uint)name.Length; + } + + public uint Start { + get { return start; } + set { start = value; } + } + + internal uint headerSize() + { + // Console.WriteLine(name + " stream has headersize of " + sizeOfHeader); + return sizeOfHeader; + } + + internal void SetSize(uint siz) + { + size = siz; + } + + internal uint Size() + { + return size; + } + + internal bool LargeIx() + { + return largeIx; + } + + internal void WriteDetails() + { + // Console.WriteLine(name + " - size = " + size); + } + + internal uint Add(string str, bool prependSize) + { + Object val = htable[str]; + uint index = 0; + if (val == null) { + index = size; + htable[str] = index; + char[] arr = str.ToCharArray(); + if (prependSize) CompressNum((uint)arr.Length*2+1); + Write(arr); + Write((byte)0); + size = (uint)Seek(0,SeekOrigin.Current); + } else { + index = (uint)val; + } + return index; + } + internal uint Add (byte[] str, bool prependSize) + { + Object val = btable [str]; + uint index = 0; + if (val == null) { + index = size; + btable [str] = index; + if (prependSize) CompressNum ((uint) str.Length); + Write (str); + size = (uint) Seek (0, SeekOrigin.Current); + } else { + index = (uint) val; + } + return index; + } + + + internal uint Add(Guid guid, bool prependSize) + { + byte [] b = guid.ToByteArray (); + if (prependSize) CompressNum ((uint) b.Length); + Write(guid.ToByteArray()); + size =(uint)Seek(0,SeekOrigin.Current); + return tide++; + } + + internal uint Add(byte[] blob) + { + uint ix = size; + CompressNum((uint)blob.Length); + Write(blob); + size = (uint)Seek(0,SeekOrigin.Current); + return ix; + } + + internal uint Add(byte val, bool prependSize) + { + uint ix = size; + if (prependSize) CompressNum (1); + Write(val); + size = (uint)Seek(0,SeekOrigin.Current); + return ix; + } + + internal uint Add(sbyte val, bool prependSize) + { + uint ix = size; + if (prependSize) CompressNum (1); + Write(val); + size = (uint)Seek(0,SeekOrigin.Current); + return ix; + } + + internal uint Add(ushort val, bool prependSize) + { + uint ix = size; + if (prependSize) CompressNum (2); + Write(val); + size = (uint)Seek(0,SeekOrigin.Current); + return ix; + } + + internal uint Add(short val, bool prependSize) + { + uint ix = size; + if (prependSize) CompressNum (2); + Write(val); + size = (uint)Seek(0,SeekOrigin.Current); + return ix; + } + + internal uint Add(uint val, bool prependSize) + { + uint ix = size; + if (prependSize) CompressNum (4); + Write(val); + size = (uint)Seek(0,SeekOrigin.Current); + return ix; + } + + internal uint Add(int val, bool prependSize) + { + uint ix = size; + if (prependSize) CompressNum (4); + Write (val); + size = (uint)Seek(0,SeekOrigin.Current); + return ix; + } + + internal uint Add(ulong val, bool prependSize) + { + uint ix = size; + if (prependSize) CompressNum (8); + Write(val); + size = (uint)Seek(0,SeekOrigin.Current); + return ix; + } + + internal uint Add(long val, bool prependSize) + { + uint ix = size; + if (prependSize) CompressNum (8); + Write(val); + size = (uint)Seek(0,SeekOrigin.Current); + return ix; + } + + internal uint Add(float val, bool prependSize) + { + uint ix = size; + if (prependSize) CompressNum (4); + Write(val); + size = (uint)Seek(0,SeekOrigin.Current); + return ix; + } + + internal uint Add(double val, bool prependSize) + { + uint ix = size; + if (prependSize) CompressNum (8); + Write(val); + size = (uint)Seek(0,SeekOrigin.Current); + return ix; + } + + private void CompressNum(uint val) + { + if (val < 0x7F) { + Write((byte)val); + } else if (val < 0x3FFF) { + byte b1 = (byte)((val >> 8) | 0x80); + byte b2 = (byte)(val & FileImage.iByteMask[0]); + Write(b1); + Write(b2); + } else { + byte b1 = (byte)((val >> 24) | 0xC0); + byte b2 = (byte)((val & FileImage.iByteMask[2]) >> 16); + byte b3 = (byte)((val & FileImage.iByteMask[1]) >> 8);; + byte b4 = (byte)(val & FileImage.iByteMask[0]); + Write(b1); + Write(b2); + Write(b3); + Write(b4); + } + } + + private void QuadAlign() + { + if ((size % 4) != 0) { + uint pad = 4 - (size % 4); + size += pad; + for (int i=0; i < pad; i++) { + Write((byte)0); + } + } + } + + internal void EndStream() + { + QuadAlign(); + if (size > maxSmlIxSize) { + largeIx = true; + } + } + + internal void WriteHeader(BinaryWriter output) + { + output.Write(start); + output.Write(size); + output.Write(name); + } + + internal virtual void Write(BinaryWriter output) + { + // Console.WriteLine("Writing " + name + " stream at " + output.Seek(0,SeekOrigin.Current) + " = " + start); + MemoryStream str = (MemoryStream)BaseStream; + output.Write(str.ToArray()); + } + + } + + /**************************************************************************/ + class ByteArrayComparer : IComparer { + + public int Compare (object x, object y) + { + byte [] a = (byte []) x; + byte [] b = (byte []) y; + int len = a.Length; + + if (b.Length != len) + return 1; + + for (int i = 0; i < len; ++i) + if (a [i] != b [i]) + return 1; + return 0; + } + } + + class ByteArrayHashCodeProvider : IHashCodeProvider { + + public int GetHashCode (Object key) + { + byte [] arr = (byte []) key; + int len = arr.Length; + int h = 0; + + for (int i = 0; i < len; ++i) + h = (h << 5) - h + arr [i]; + + return h; + } + + } + + +} |