+ /// <summary>
+ /// Add extra calling conventions to this callsite signature
+ /// </summary>
+ /// <param name="cconv"></param>
+ public void AddCallingConv(CallConv cconv) {
+ callConv |= cconv;
+ }
+
+ internal sealed override void BuildTables(MetaData md) {
+ if (done) return;
+ MemoryStream sig = new MemoryStream();
+ sig.WriteByte((byte)callConv);
+ MetaData.CompressNum(numPars+numOptPars,sig);
+ returnType.TypeSig(sig);
+ for (int i=0; i < numPars; i++) {
+ parameters[i].TypeSig(sig);
+ }
+ sigIx = md.AddToBlobHeap(sig.ToArray());
+ if (numOptPars > 0) {
+ sig.WriteByte(Sentinel);
+ for (int i=0; i < numOptPars; i++) {
+ optParams[i].TypeSig(sig);
+ }
+ }
+ done = true;
+ }
+
+ }
+ /**************************************************************************/
+ /// <summary>
+ /// The IL instructions for a method
+ /// </summary>
+ public class CILInstructions
+ {
+
+ private static readonly uint ExHeaderSize = 4;
+ private static readonly uint FatExClauseSize = 24;
+ private static readonly uint SmlExClauseSize = 12;
+ private static readonly sbyte maxByteVal = 127;
+ private static readonly sbyte minByteVal = -128;
+ private static readonly byte maxUByteVal = 255;
+ private static readonly int smallSize = 64;
+ private static readonly ushort TinyFormat = 0x2;
+ private static readonly ushort FatFormat = 0x3003;
+ private static readonly ushort MoreSects = 0x8;
+ private static readonly ushort InitLocals = 0x10;
+ private static readonly uint FatSize = 12;
+ private static readonly uint FatWords = FatSize/4;
+ private static readonly byte FatExceptTable = 0x41;
+ private static readonly byte SmlExceptTable = 0x01;
+
+ private MetaData metaData;
+ private ArrayList exceptions, blockStack;
+ //private bool codeChecked = false;
+ private static readonly int INITSIZE = 5;
+ private CILInstruction[] buffer = new CILInstruction[INITSIZE];
+ private int tide = 0;
+ private uint offset = 0;
+ private ushort headerFlags = 0;
+ private short maxStack;
+ private uint paddingNeeded = 0;
+ private byte exceptHeader = 0;
+ uint localSigIx = 0;
+ uint codeSize = 0, exceptSize = 0;
+ bool tinyFormat, fatExceptionFormat = false;
+
+ public uint Offset {
+ get { return offset; }
+ }
+
+ internal CILInstructions(MetaData md) {
+ metaData = md;
+ }
+
+ private void AddToBuffer(CILInstruction inst) {
+ if (tide >= buffer.Length) {
+ CILInstruction[] tmp = buffer;
+ buffer = new CILInstruction[tmp.Length * 2];
+ for (int i=0; i < tide; i++) {
+ buffer[i] = tmp[i];
+ }
+ }
+ //Console.WriteLine("Adding instruction at offset " + offset + " with size " + inst.size);
+ inst.offset = offset;
+ offset += inst.size;
+ buffer[tide++] = inst;
+ }
+
+ /// <summary>
+ /// Add a simple IL instruction
+ /// </summary>
+ /// <param name="inst">the IL instruction</param>
+ public void Inst(Op inst) {
+ AddToBuffer(new Instr((int)inst));
+ }
+
+ /// <summary>
+ /// Add an IL instruction with an integer parameter
+ /// </summary>
+ /// <param name="inst">the IL instruction</param>
+ /// <param name="val">the integer parameter value</param>
+ public void IntInst(IntOp inst, int val) {
+ int instr = (int)inst;
+ if ((inst == IntOp.ldc_i4_s) || (inst == IntOp.ldc_i4))
+ AddToBuffer(new IntInstr(instr,val,(inst == IntOp.ldc_i4_s)));
+ else
+ AddToBuffer(new UIntInstr(instr,val,((inst < IntOp.ldc_i4_s) ||
+ (inst == IntOp.unaligned))));
+ }
+
+ /// <summary>
+ /// Add the load long instruction
+ /// </summary>
+ /// <param name="cVal">the long value</param>
+ public void ldc_i8(long cVal) {
+ AddToBuffer(new LongInstr(0x21,cVal));
+ }
+
+ /// <summary>
+ /// Add the load float32 instruction
+ /// </summary>
+ /// <param name="cVal">the float value</param>
+ public void ldc_r4(float cVal) {
+ AddToBuffer(new FloatInstr(0x22,cVal));
+ }
+
+ /// <summary>
+ /// Add the load float64 instruction
+ /// </summary>
+ /// <param name="cVal">the float value</param>
+ public void ldc_r8(double cVal) {
+ AddToBuffer(new DoubleInstr(0x23,cVal));
+ }
+
+ /// <summary>
+ /// Add the load string instruction
+ /// </summary>
+ /// <param name="str">the string value</param>
+ public void ldstr(string str) {
+ AddToBuffer(new StringInstr(0x72,str));
+ }
+
+ /// <summary>
+ /// Add the load string instruction
+ /// </summary>
+ public void ldstr (byte[] str) {
+ AddToBuffer (new StringInstr (0x72, str));
+ }
+
+ /// <summary>
+ /// Add the calli instruction
+ /// </summary>
+ /// <param name="sig">the signature for the calli</param>
+ public void calli(CalliSig sig) {
+ AddToBuffer(new SigInstr(0x29,sig));
+ }
+
+ /// <summary>
+ /// Add a label to the CIL instructions
+ /// </summary>
+ /// <param name="lab">the label to be added</param>
+ public void CodeLabel(CILLabel lab) {
+ AddToBuffer(new LabelInstr(lab));
+ }
+
+ /// <summary>
+ /// Add an instruction with a field parameter
+ /// </summary>
+ /// <param name="inst">the CIL instruction</param>
+ /// <param name="f">the field parameter</param>
+ public void FieldInst(FieldOp inst, Field f) {
+ AddToBuffer(new FieldInstr((int)inst,f));
+ }
+
+ /// <summary>
+ /// Add an instruction with a method parameter
+ /// </summary>
+ /// <param name="inst">the CIL instruction</param>
+ /// <param name="m">the method parameter</param>
+ public void MethInst(MethodOp inst, Method m) {
+ AddToBuffer(new MethInstr((int)inst,m));
+ }
+
+ /// <summary>
+ /// Add an instruction with a type parameter
+ /// </summary>
+ /// <param name="inst">the CIL instruction</param>
+ /// <param name="t">the type argument for the CIL instruction</param>
+ public void TypeInst(TypeOp inst, Type aType) {
+ AddToBuffer(new TypeInstr((int)inst,aType,metaData));
+ }
+
+ /// <summary>
+ /// Add a branch instruction
+ /// </summary>
+ /// <param name="inst">the branch instruction</param>
+ /// <param name="lab">the label that is the target of the branch</param>
+ public void Branch(BranchOp inst, CILLabel lab) {
+ AddToBuffer(new BranchInstr((int)inst,lab));
+ }
+
+ /// <summary>
+ /// Add a switch instruction
+ /// </summary>
+ /// <param name="labs">the target labels for the switch</param>
+ public void Switch(CILLabel[] labs) {
+ AddToBuffer(new SwitchInstr(0x45,labs));
+ }
+
+ /// <summary>
+ /// Add a byte to the CIL instructions (.emitbyte)
+ /// </summary>
+ /// <param name="bVal"></param>
+ public void emitbyte(byte bVal) {
+ AddToBuffer(new CILByte(bVal));
+ }
+
+ /// <summary>
+ /// Add an instruction which puts an integer on TOS. This method
+ /// selects the correct instruction based on the value of the integer.
+ /// </summary>
+ /// <param name="i">the integer value</param>
+ public void PushInt(int i) {
+ if (i == -1) {
+ AddToBuffer(new Instr((int)Op.ldc_i4_m1));
+ } else if ((i >= 0) && (i <= 8)) {
+ Op op = (Op)(Op.ldc_i4_0 + i);
+ AddToBuffer(new Instr((int)op));
+ } else if ((i >= minByteVal) && (i <= maxByteVal)) {
+ AddToBuffer(new IntInstr((int)IntOp.ldc_i4_s,i,true));
+ } else {
+ AddToBuffer(new IntInstr((int)IntOp.ldc_i4,i,false));
+ }
+ }
+
+ /// <summary>
+ /// Add the instruction to load a long on TOS
+ /// </summary>
+ /// <param name="l">the long value</param>
+ public void PushLong(long l) {
+ AddToBuffer(new LongInstr(0x21,l));
+ }
+
+ /// <summary>
+ /// Add an instruction to push the boolean value true on TOS
+ /// </summary>
+ public void PushTrue() {
+ AddToBuffer(new Instr((int)Op.ldc_i4_1));
+ }
+
+ /// <summary>
+ /// Add an instruction to push the boolean value false on TOS
+ /// </summary>
+ public void PushFalse() {
+ AddToBuffer(new Instr((int)Op.ldc_i4_0));
+ }
+
+ /// <summary>
+ /// Add the instruction to load an argument on TOS. This method
+ /// selects the correct instruction based on the value of argNo
+ /// </summary>
+ /// <param name="argNo">the number of the argument</param>
+ public void LoadArg(int argNo) {
+ if (argNo < 4) {
+ int op = (int)Op.ldarg_0 + argNo;
+ AddToBuffer(new Instr(op));
+ } else if (argNo <= maxUByteVal) {
+ AddToBuffer(new UIntInstr((int)IntOp.ldarg,argNo,true));
+ } else {
+ AddToBuffer(new UIntInstr(0x09,argNo,false));
+ }
+ }
+
+ /// <summary>
+ /// Add the instruction to load the address of an argument on TOS.
+ /// This method selects the correct instruction based on the value
+ /// of argNo.
+ /// </summary>
+ /// <param name="argNo">the number of the argument</param>
+ public void LoadArgAdr(int argNo) {
+ if (argNo <= maxUByteVal) {
+ AddToBuffer(new UIntInstr((int)IntOp.ldarga,argNo,true));
+ } else {
+ AddToBuffer(new UIntInstr(0x0A,argNo,false));
+ }
+ }
+
+ /// <summary>
+ /// Add the instruction to load a local on TOS. This method selects
+ /// the correct instruction based on the value of locNo.
+ /// </summary>
+ /// <param name="locNo">the number of the local to load</param>
+ public void LoadLocal(int locNo) {
+ if (locNo < 4) {
+ int op = (int)Op.ldloc_0 + locNo;
+ AddToBuffer(new Instr(op));
+ } else if (locNo <= maxUByteVal) {
+ AddToBuffer(new UIntInstr((int)IntOp.ldloc,locNo,true));
+ } else {
+ AddToBuffer(new UIntInstr(0x0C,locNo,false));
+ }
+ }
+
+ /// <summary>
+ /// Add the instruction to load the address of a local on TOS.
+ /// This method selects the correct instruction based on the
+ /// value of locNo.
+ /// </summary>
+ /// <param name="locNo">the number of the local</param>
+ public void LoadLocalAdr(int locNo) {
+ if (locNo <= maxUByteVal) {
+ AddToBuffer(new UIntInstr((int)IntOp.ldloca,locNo,true));
+ } else {
+ AddToBuffer(new UIntInstr(0x0D,locNo,false));
+ }
+ }
+
+ /// <summary>
+ /// Add the instruction to store to an argument. This method
+ /// selects the correct instruction based on the value of argNo.
+ /// </summary>
+ /// <param name="argNo">the argument to be stored to</param>
+ public void StoreArg(int argNo) {
+ if (argNo <= maxUByteVal) {
+ AddToBuffer(new UIntInstr((int)IntOp.starg,argNo,true));
+ } else {
+ AddToBuffer(new UIntInstr(0x0B,argNo,false));
+ }
+ }
+
+ /// <summary>
+ /// Add the instruction to store to a local. This method selects
+ /// the correct instruction based on the value of locNo.
+ /// </summary>
+ /// <param name="locNo">the local to be stored to</param>
+ public void StoreLocal(int locNo) {
+ if (locNo < 4) {
+ int op = (int)Op.stloc_0 + locNo;
+ AddToBuffer(new Instr(op));
+ } else if (locNo <= maxUByteVal) {
+ AddToBuffer(new UIntInstr((int)IntOp.stloc,locNo,true));
+ } else {
+ AddToBuffer(new UIntInstr(0x0E,locNo,false));
+ }
+ }
+
+ /// <summary>
+ /// Create a new CIL label. To place the label in the CIL instruction
+ /// stream use CodeLabel.
+ /// </summary>
+ /// <returns>a new CIL label</returns>
+ public CILLabel NewLabel() {
+ return new CILLabel();
+ }
+
+ public void AddTryBlock(TryBlock tryBlock) {
+ if (exceptions == null)
+ exceptions = new ArrayList();
+ else if (exceptions.Contains(tryBlock)) return;
+ exceptions.Add(tryBlock);
+ }
+
+ /// <summary>
+ /// Create a new label at this position in the code buffer
+ /// </summary>
+ /// <returns>the label at the current position</returns>
+ public CILLabel NewCodedLabel() {
+ CILLabel lab = new CILLabel();
+ AddToBuffer(new LabelInstr(lab));
+ return lab;
+ }
+
+ /// <summary>
+ /// Mark this position as the start of a new block
+ /// (try, catch, filter, finally or fault)
+ /// </summary>
+ public void StartBlock() {
+ if (blockStack == null) blockStack = new ArrayList();
+ blockStack.Insert(0,NewCodedLabel());
+ }
+
+ /// <summary>
+ /// Mark this position as the end of the last started block and
+ /// make it a try block. This try block is added to the current
+ /// instructions (ie do not need to call AddTryBlock)
+ /// </summary>
+ /// <returns>The try block just ended</returns>
+ public TryBlock EndTryBlock() {
+ TryBlock tBlock = new TryBlock((CILLabel)blockStack[0],NewCodedLabel());
+ blockStack.RemoveAt(0);
+ AddTryBlock(tBlock);
+ return tBlock;
+ }
+
+ /// <summary>
+ /// Mark this position as the end of the last started block and
+ /// make it a catch block. This catch block is associated with the
+ /// specified try block.
+ /// </summary>
+ /// <param name="exceptType">the exception type to be caught</param>
+ /// <param name="tryBlock">the try block associated with this catch block</param>
+ public void EndCatchBlock(Class exceptType, TryBlock tryBlock) {
+ Catch catchBlock = new Catch(exceptType,(CILLabel)blockStack[0],
+ NewCodedLabel());
+ tryBlock.AddHandler(catchBlock);
+ }
+
+ /// <summary>
+ /// Mark this position as the end of the last started block and
+ /// make it a filter block. This filter block is associated with the
+ /// specified try block.
+ /// </summary>
+ /// <param name="filterLab">the label where the filter code is</param>
+ /// <param name="tryBlock">the try block associated with this filter block</param>
+ public void EndFilterBlock(CILLabel filterLab, TryBlock tryBlock) {
+ Filter filBlock = new Filter(filterLab,(CILLabel)blockStack[0],NewCodedLabel());
+ tryBlock.AddHandler(filBlock);
+ }
+
+ /// <summary>
+ /// Mark this position as the end of the last started block and
+ /// make it a finally block. This finally block is associated with the
+ /// specified try block.
+ /// </summary>
+ /// <param name="tryBlock">the try block associated with this finally block</param>
+ public void EndFinallyBlock(TryBlock tryBlock) {
+ Finally finBlock= new Finally((CILLabel)blockStack[0],NewCodedLabel());
+ tryBlock.AddHandler(finBlock);
+ }
+
+ /// <summary>
+ /// Mark this position as the end of the last started block and
+ /// make it a fault block. This fault block is associated with the
+ /// specified try block.
+ /// </summary>
+ /// <param name="tryBlock">the try block associated with this fault block</param>
+ public void EndFaultBlock(TryBlock tryBlock) {
+ Fault fBlock= new Fault((CILLabel)blockStack[0],NewCodedLabel());
+ tryBlock.AddHandler(fBlock);
+ }
+
+ internal uint GetCodeSize() {
+ return codeSize + paddingNeeded + exceptSize;
+ }
+
+ internal void CheckCode(uint locSigIx, bool initLocals, int maxStack) {
+ if (tide == 0) return;
+ bool changed = true;
+ while (changed) {
+ changed = false;
+ for (int i=0; i < tide; i++) {
+ changed = buffer[i].Check(metaData) || changed;
+ }
+ if (changed) {
+ for (int i=1; i < tide; i++) {
+ buffer[i].offset = buffer[i-1].offset + buffer[i-1].size;
+ }
+ offset = buffer[tide-1].offset + buffer[tide-1].size;
+ }
+ }
+ codeSize = offset;
+ // Console.WriteLine("codeSize before header added = " + codeSize);
+ if ((offset < smallSize) && (maxStack <= 8) && (locSigIx == 0) && (exceptions == null)) {
+ // can use tiny header
+ //Console.WriteLine("Tiny Header");
+ tinyFormat = true;
+ headerFlags = (ushort)(TinyFormat | ((ushort)codeSize << 2));
+ codeSize++;
+ if ((codeSize % 4) != 0) { paddingNeeded = 4 - (codeSize % 4); }
+ } else {
+ //Console.WriteLine("Fat Header");
+ tinyFormat = false;
+ localSigIx = locSigIx;
+ this.maxStack = (short)maxStack;
+ headerFlags = FatFormat;
+ if (exceptions != null) {
+ // Console.WriteLine("Got exceptions");
+ headerFlags |= MoreSects;
+ uint numExceptClauses = 0;
+ for (int i=0; i < exceptions.Count; i++) {
+ TryBlock tryBlock = (TryBlock)exceptions[i];
+ tryBlock.SetSize();
+ numExceptClauses += (uint)tryBlock.NumHandlers();
+ if (tryBlock.isFat()) fatExceptionFormat = true;
+ }
+
+ uint data_size = ExHeaderSize + numExceptClauses *
+ (fatExceptionFormat ? FatExClauseSize : SmlExClauseSize);
+
+ if (data_size > 256)
+ fatExceptionFormat = true;
+
+ // Console.WriteLine("numexceptclauses = " + numExceptClauses);
+ if (fatExceptionFormat) {
+ // Console.WriteLine("Fat exception format");
+ exceptHeader = FatExceptTable;
+ exceptSize = ExHeaderSize + numExceptClauses * FatExClauseSize;
+ } else {
+ // Console.WriteLine("Tiny exception format");
+ exceptHeader = SmlExceptTable;
+ exceptSize = ExHeaderSize + numExceptClauses * SmlExClauseSize;
+ }
+ // Console.WriteLine("exceptSize = " + exceptSize);
+ }
+ if (initLocals) headerFlags |= InitLocals;
+ if ((offset % 4) != 0) { paddingNeeded = 4 - (offset % 4); }
+ codeSize += FatSize;
+ }
+ // Console.WriteLine("codeSize = " + codeSize + " headerFlags = " +
+ // Hex.Short(headerFlags));
+ }
+
+ internal void Write(FileImage output) {
+ // Console.WriteLine("Writing header flags = " + Hex.Short(headerFlags));
+ if (tinyFormat) {
+ // Console.WriteLine("Writing tiny code");
+ output.Write((byte)headerFlags);
+ } else {
+ // Console.WriteLine("Writing fat code");
+ output.Write(headerFlags);
+ output.Write((ushort)maxStack);
+ output.Write(offset);
+ output.Write(localSigIx);
+ }
+ // Console.WriteLine(Hex.Int(tide) + " CIL instructions");
+ // Console.WriteLine("starting instructions at " + output.Seek(0,SeekOrigin.Current));
+ for (int i=0; i < tide; i++) {
+ buffer[i].Write(output);
+ }
+ // Console.WriteLine("ending instructions at " + output.Seek(0,SeekOrigin.Current));
+ for (int i=0; i < paddingNeeded; i++) { output.Write((byte)0); }
+ if (exceptions != null) {
+ // Console.WriteLine("Writing exceptions");
+ // Console.WriteLine("header = " + Hex.Short(exceptHeader) + " exceptSize = " + Hex.Int(exceptSize));
+ output.Write(exceptHeader);
+ output.Write3Bytes((uint)exceptSize);
+ for (int i=0; i < exceptions.Count; i++) {
+ TryBlock tryBlock = (TryBlock)exceptions[i];
+ tryBlock.Write(output,fatExceptionFormat);
+ }
+ }
+ }
+
+ }
+ /**************************************************************************/
+ /// <summary>
+ /// A label in the IL
+ /// </summary>
+ public class CILLabel
+ {
+ CILInstruction branch;
+ CILInstruction[] multipleBranches;
+ int tide = 0;
+ CILInstruction labInstr;
+ uint offset = 0;
+
+ public CILLabel (uint offset) {
+ this.offset = offset;
+ }
+
+
+ internal CILLabel() {
+ }
+
+ internal void AddBranch(CILInstruction instr) {
+ if (branch == null) {
+ branch = instr;
+ return;
+ }
+ if (multipleBranches == null) {
+ multipleBranches = new CILInstruction[2];
+ } else if (tide >= multipleBranches.Length) {
+ CILInstruction[] tmp = multipleBranches;
+ multipleBranches = new CILInstruction[tmp.Length*2];
+ for (int i=0; i < tide; i++) {
+ multipleBranches[i] = tmp[i];
+ }
+ }
+ multipleBranches[tide++] = instr;
+ }
+
+ internal void AddLabelInstr(LabelInstr lInstr) {
+ labInstr = lInstr;
+ }
+
+ internal uint GetLabelOffset() {
+ if (labInstr == null) return 0;
+ return labInstr.offset + offset;
+ }
+
+ }
+ /**************************************************************************/
+ public abstract class CodeBlock {
+
+ private static readonly int maxCodeSize = 256;
+ protected CILLabel start, end;
+ protected bool small = true;
+
+ public CodeBlock(CILLabel start, CILLabel end) {
+ this.start = start;
+ this.end = end;
+ }
+
+ internal virtual bool isFat() {
+ // Console.WriteLine("block start = " + start.GetLabelOffset() +
+ // " block end = " + end.GetLabelOffset());
+ return (end.GetLabelOffset() - start.GetLabelOffset()) > maxCodeSize;
+ }
+
+ internal virtual void Write(FileImage output, bool fatFormat) {
+ if (fatFormat) output.Write(start.GetLabelOffset());
+ else output.Write((short)start.GetLabelOffset());
+ uint len = end.GetLabelOffset() - start.GetLabelOffset();
+ if (fatFormat) output.Write(len);
+ else output.Write((byte)len);
+ }
+
+ }
+
+ /// <summary>
+ /// The descriptor for a guarded block (.try)
+ /// </summary>
+ public class TryBlock : CodeBlock {
+ protected bool fatFormat = false;
+ protected int flags = 0;
+ ArrayList handlers = new ArrayList();
+
+ /// <summary>
+ /// Create a new try block
+ /// </summary>
+ /// <param name="start">start label for the try block</param>
+ /// <param name="end">end label for the try block</param>
+ public TryBlock(CILLabel start, CILLabel end) : base(start,end) { }
+
+ /// <summary>
+ /// Add a handler to this try block
+ /// </summary>
+ /// <param name="handler">a handler to be added to the try block</param>
+ public void AddHandler(HandlerBlock handler) {
+ flags = handler.GetFlag();
+ handlers.Add(handler);
+ }
+
+ internal void SetSize() {
+ fatFormat = base.isFat();
+ if (fatFormat) return;
+ for (int i=0; i < handlers.Count; i++) {
+ HandlerBlock handler = (HandlerBlock)handlers[i];
+ if (handler.isFat()) {
+ fatFormat = true;
+ return;
+ }
+ }
+ }
+
+ internal int NumHandlers() {
+ return handlers.Count;
+ }
+
+ internal override bool isFat() {
+ return fatFormat;
+ }
+
+ internal override void Write(FileImage output, bool fatFormat) {
+ // Console.WriteLine("writing exception details");
+ for (int i=0; i < handlers.Count; i++) {
+ // Console.WriteLine("Except block " + i);
+ HandlerBlock handler = (HandlerBlock)handlers[i];
+ if (fatFormat) output.Write(flags);
+ else output.Write((short)flags);
+ // Console.WriteLine("flags = " + Hex.Short(flags));
+ base.Write(output,fatFormat);
+ handler.Write(output,fatFormat);
+ }
+ }
+ }
+
+ public abstract class HandlerBlock : CodeBlock
+ {
+ protected static readonly short ExceptionFlag = 0;
+ protected static readonly short FilterFlag = 0x01;
+ protected static readonly short FinallyFlag = 0x02;
+ protected static readonly short FaultFlag = 0x04;
+
+ public HandlerBlock(CILLabel start, CILLabel end) : base(start,end) { }
+
+ internal virtual short GetFlag() { return ExceptionFlag; }
+
+ internal override void Write(FileImage output, bool fatFormat) {
+ base.Write(output,fatFormat);
+ }
+
+ }
+
+ /// <summary>
+ /// The descriptor for a catch clause (.catch)
+ /// </summary>
+ public class Catch : HandlerBlock
+ {
+ Class exceptType;
+
+ /// <summary>
+ /// Create a new catch clause
+ /// </summary>
+ /// <param name="except">the exception to be caught</param>
+ /// <param name="handlerStart">start of the handler code</param>
+ /// <param name="handlerEnd">end of the handler code</param>
+ public Catch(Class except, CILLabel handlerStart, CILLabel handlerEnd)
+ : base(handlerStart,handlerEnd) {
+ exceptType = except;
+ }
+
+ internal override void Write(FileImage output, bool fatFormat) {
+ base.Write(output,fatFormat);
+ output.Write(exceptType.Token());
+ }
+ }
+
+ /// <summary>
+ /// The descriptor for a filter clause (.filter)
+ /// </summary>
+ public class Filter : HandlerBlock
+ {
+ CILLabel filterLabel;
+
+ /// <summary>
+ /// Create a new filter clause
+ /// </summary>
+ /// <param name="filterLabel">the label where the filter code starts</param>
+ /// <param name="handlerStart">the start of the handler code</param>
+ /// <param name="handlerEnd">the end of the handler code</param>
+ public Filter(CILLabel filterLabel, CILLabel handlerStart,
+ CILLabel handlerEnd) : base(handlerStart,handlerEnd) {
+ this.filterLabel = filterLabel;
+ }
+
+ internal override short GetFlag() {
+ return FilterFlag;
+ }
+
+ internal override void Write(FileImage output, bool fatFormat) {
+ base.Write(output,fatFormat);
+ output.Write(filterLabel.GetLabelOffset());
+ }
+
+ }
+
+ /// <summary>
+ /// Descriptor for a finally block (.finally)
+ /// </summary>
+ public class Finally : HandlerBlock
+ {
+ /// <summary>
+ /// Create a new finally clause
+ /// </summary>
+ /// <param name="finallyStart">start of finally code</param>
+ /// <param name="finallyEnd">end of finally code</param>
+ public Finally(CILLabel finallyStart, CILLabel finallyEnd)
+ : base(finallyStart,finallyEnd) { }
+
+ internal override short GetFlag() {
+ return FinallyFlag;
+ }
+
+ internal override void Write(FileImage output, bool fatFormat) {
+ base.Write(output,fatFormat);
+ output.Write((int)0);
+ }
+
+ }
+
+ /// <summary>
+ /// Descriptor for a fault block (.fault)
+ /// </summary>
+ public class Fault : HandlerBlock
+ {
+ /// <summary>
+ /// Create a new fault clause
+ /// </summary>
+ /// <param name="faultStart">start of the fault code</param>
+ /// <param name="faultEnd">end of the fault code</param>
+ public Fault(CILLabel faultStart, CILLabel faultEnd)
+ : base(faultStart,faultEnd) { }
+
+ internal override short GetFlag() {
+ return FaultFlag;
+ }
+
+ internal override void Write(FileImage output, bool fatFormat) {
+ base.Write(output,fatFormat);
+ output.Write((int)0);
+
+ }
+ }
+
+ /**************************************************************************/
+ /// <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 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 uint HasSecurity = 0x00040000;
+ 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;
+ superType = metaData.mscorlib.GetSpecialSystemClass(PrimitiveType.Object);
+ flags = (uint)attrSet;
+ tabIx = MDTable.TypeDef;
+ }
+
+ internal void SetSuper(Class sClass) {
+ superType = sClass;
+ if (sClass is ClassRef)
+ typeIndex = superType.GetTypeIndex();
+ else
+ typeIndexChecked = false;
+ }
+
+ internal override void MakeValueClass(ValueClass vClass) {
+ if (vClass == ValueClass.Enum)
+ superType = metaData.mscorlib.EnumType();
+ else
+ superType = metaData.mscorlib.ValueType();
+
+ typeIndex = superType.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) {
+ GenericParameter gp = new GenericParameter (this, metaData, index, name);
+ 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.CompareTo ("System") == 0) &&
+ (name.CompareTo ("ValueType") == 0));
+ }
+
+ public static bool IsEnum (string nsName, string name)
+ {
+ return ((nsName.CompareTo ("System") == 0) &&
+ (name.CompareTo ("Enum") == 0));
+ }
+
+ /// <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 ());
+
+ 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 ClassRef))
+ ((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>
+ /// 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>
+ /// Descriptor for a class/interface declared in another module of THIS
+ /// assembly, or in another assembly.
+ /// </summary>
+ public class ClassRef : Class
+ {
+ protected ResolutionScope 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) {
+ MethodRef meth = new MethodRef(this,name,retType,pars,false,null);
+ 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);
+ 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;
+ }
+
+ internal void SetParent(ResolutionScope 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,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 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 {
+ long val;
+
+ public UIntConst(sbyte val) {
+ this.val = val;
+ size = 1;
+ type = PrimitiveType.UInt8;
+ }
+ public UIntConst(short val) {
+ this.val = val;
+ size = 2;
+ type = PrimitiveType.UInt16;
+ }
+ public UIntConst(int val) {
+ this.val = val;
+ size = 4;
+ type = PrimitiveType.UInt32;
+ }
+ public UIntConst(long 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((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 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);
+ }
+
+ }
+
+
+
+ /**************************************************************************/
+ /// <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 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>
+ /// Descriptor for security permissions for a class or a method NOT YET IMPLEMENTED
+ /// </summary>
+
+ public class DeclSecurity : MetaDataElement
+ {
+ ushort action;
+ MetaDataElement parent;
+ uint permissionIx;
+
+ internal DeclSecurity(MetaDataElement paren, ushort act) {
+ parent = paren;
+ action = act;
+ tabIx = MDTable.DeclSecurity;
+ throw(new NotYetImplementedException("Security "));
+ }
+
+ 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;
+// add permission to blob heap
+ done = true;
+ }
+
+ internal sealed override void Write(FileImage output) {
+ output.Write(action);
+ output.WriteCodedIndex(CIx.HasDeclSecurity,parent);
+ output.BlobIndex(permissionIx);
+ }
+
+ }
+ /**************************************************************************/
+ /// <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 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;
+ }
+
+ }
+ /**************************************************************************/
+ /// <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 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 HasFieldMarshal = 0x1000;
+ 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 |= 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 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 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>
+ /// 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>
+ /// Image for a PEFile
+ /// File Structure
+ /// DOS Header (128 bytes)
+ /// PE Signature ("PE\0\0")
+ /// PEFileHeader (20 bytes)
+ /// PEOptionalHeader (224 bytes)
+ /// SectionHeaders (40 bytes * NumSections)
+ ///
+ /// Sections .text (always present - contains metadata)
+ /// .sdata (contains any initialised data in the file - may not be present)
+ /// (for ilams /debug this contains the Debug table)
+ /// .reloc (always present - in pure CIL only has one fixup)
+ /// others??? c# produces .rsrc section containing a Resource Table
+ ///
+ /// .text layout
+ /// IAT (single entry 8 bytes for pure CIL)
+ /// CLIHeader (72 bytes)
+ /// CIL instructions for all methods (variable size)
+ /// 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)
+ /// ImportTable (40 bytes)
+ /// ImportLookupTable(8 bytes) (same as IAT for standard CIL files)
+ /// Hint/Name Tables with entry "_CorExeMain" for .exe file and "_CorDllMain" for .dll (14 bytes)
+ /// ASCII string "mscoree.dll" referenced in ImportTable (+ padding = 16 bytes)
+ /// Entry Point (0xFF25 followed by 4 bytes 0x400000 + RVA of .text)
+ ///
+ /// #~ stream structure
+ /// Header (24 bytes)
+ /// Rows (4 bytes * numTables)
+ /// Tables
+ /// </summary>
+ internal class FileImage : BinaryWriter
+ {
+ internal readonly static uint[] iByteMask = {0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000};
+ internal readonly static ulong[] lByteMask = {0x00000000000000FF, 0x000000000000FF00,
+ 0x0000000000FF0000, 0x00000000FF000000,
+ 0x000000FF00000000, 0x0000FF0000000000,
+ 0x00FF000000000000, 0xFF00000000000000 };
+ internal readonly static uint nibble0Mask = 0x0000000F;
+ internal readonly static uint nibble1Mask = 0x000000F0;
+
+ private static readonly byte[] DOSHeader = { 0x4d,0x5a,0x90,0x00,0x03,0x00,0x00,0x00,
+ 0x04,0x00,0x00,0x00,0xff,0xff,0x00,0x00,
+ 0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,
+ 0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd,
+ 0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68,
+ 0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,
+ 0x61,0x6d,0x20,0x63,0x61,0x6e,0x6e,0x6f,
+ 0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,
+ 0x20,0x69,0x6e,0x20,0x44,0x4f,0x53,0x20,
+ 0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0d,0x0a,
+ 0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x50,0x45,0x00,0x00};
+ private static byte[] PEHeader = { 0x4c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xE0, 0x00, 0x0E, 0x01, // PE Header Standard Fields
+ 0x0B, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ private static readonly uint minFileAlign = 0x200;
+ private static readonly uint maxFileAlign = 0x1000;
+ private static readonly uint fileHeaderSize = 0x178;
+ private static readonly uint sectionHeaderSize = 40;
+ private static readonly uint SectionAlignment = 0x2000;
+ private static readonly uint ImageBase = 0x400000;
+ private static readonly uint ImportTableSize = 40;
+ private static readonly uint IATSize = 8;
+ private static readonly uint CLIHeaderSize = 72;
+ private uint runtimeFlags = 0x01; // COMIMAGE_FLAGS_ILONLY
+ // 32BITREQUIRED 0x02, STRONGNAMESIGNED 0x08, TRACKDEBUGDATA 0x10000
+ private static readonly uint StrongNameSignatureSize = 128;
+ private bool reserveStrongNameSignatureSpace = false;
+
+ private static readonly uint relocFlags = 0x42000040;
+ private static readonly ushort exeCharacteristics = 0x010E;
+ private static readonly ushort dllCharacteristics = 0x210E;
+ // section names are all 8 bytes
+ private static readonly string textName = ".text\0\0\0";
+ private static readonly string sdataName = ".sdata\0\0";
+ private static readonly string relocName = ".reloc\0\0";
+ private static readonly string rsrcName = ".rsrc\0\0\0";
+ private static readonly string exeHintNameTable = "\0\0_CorExeMain\0";
+ private static readonly string dllHintNameTable = "\0\0_CorDllMain\0";
+ private static readonly string runtimeEngineName = "mscoree.dll\0\0";
+
+ private Section text, sdata, rsrc;
+ ArrayList data;
+ BinaryWriter reloc = new BinaryWriter(new MemoryStream());
+ uint dateStamp = 0;
+ DateTime origin = new DateTime(1970,1,1);
+ uint numSections = 2; // always have .text and .reloc sections
+ internal SubSystem subSys = SubSystem.Windows_CUI; // default is Windows Console mode
+ internal uint fileAlign = minFileAlign;
+ uint entryPointOffset, entryPointPadding, imageSize, headerSize, headerPadding, entryPointToken = 0;
+ uint relocOffset, relocRVA, relocSize, relocPadding, relocTide, hintNameTableOffset;
+ uint metaDataOffset, runtimeEngineOffset, initDataSize = 0, importTablePadding;
+ uint resourcesSize, resourcesOffset;
+ uint strongNameSigOffset;
+ uint importTableOffset, importLookupTableOffset, totalImportTableSize;
+ MetaData metaData;
+ char[] runtimeEngine = runtimeEngineName.ToCharArray(), hintNameTable;
+ bool doDLL, largeStrings, largeGUID, largeUS, largeBlob;
+ ushort characteristics;
+
+ internal FileImage(bool makeDLL, string fileName) : base(new FileStream(fileName,FileMode.Create)) {
+ InitFileImage(makeDLL);
+ TimeSpan tmp = System.IO.File.GetCreationTime(fileName).Subtract(origin);
+ dateStamp = Convert.ToUInt32(tmp.TotalSeconds);
+ }
+
+ internal FileImage(bool makeDLL, Stream str) : base(str) {
+ InitFileImage(makeDLL);
+ TimeSpan tmp = DateTime.Now.Subtract(origin);
+ dateStamp = Convert.ToUInt32(tmp.TotalSeconds);
+ }
+
+ private void InitFileImage(bool makeDLL) {
+ doDLL = makeDLL;
+ if (doDLL) {
+ hintNameTable = dllHintNameTable.ToCharArray();
+ characteristics = dllCharacteristics;
+ } else {
+ hintNameTable = exeHintNameTable.ToCharArray();
+ characteristics = exeCharacteristics;
+ }
+ text = new Section(textName,0x60000020); // IMAGE_SCN_CNT CODE, EXECUTE, READ
+// rsrc = new Section(rsrcName,0x40000040); // IMAGE_SCN_CNT INITIALIZED_DATA, READ
+ metaData = new MetaData(this);
+ }
+
+ internal MetaData GetMetaData() {
+ return metaData;
+ }
+
+ private uint GetNextSectStart(uint rva, uint tide) {
+ if (tide < SectionAlignment) return rva + SectionAlignment;
+ return rva + ((tide / SectionAlignment) + 1) * SectionAlignment;
+ }
+
+ private void BuildTextSection() {
+ // .text layout
+ // IAT (single entry 8 bytes for pure CIL)
+ // CLIHeader (72 bytes)
+ // CIL instructions for all methods (variable size)
+ // MetaData
+ // ImportTable (40 bytes)
+ // ImportLookupTable(8 bytes) (same as IAT for standard CIL files)
+ // Hint/Name Tables with entry "_CorExeMain" for .exe file and "_CorDllMain" for .dll (14 bytes)
+ // ASCII string "mscoree.dll" referenced in ImportTable (+ padding = 16 bytes)
+ // Entry Point (0xFF25 followed by 4 bytes 0x400000 + RVA of .text)
+ metaData.BuildMetaData(IATSize + CLIHeaderSize);
+ metaDataOffset = IATSize + CLIHeaderSize;
+ // Console.WriteLine("Code starts at " + metaDataOffset);
+ metaDataOffset += metaData.CodeSize();
+ // resourcesStart =
+ resourcesOffset = metaDataOffset + metaData.Size ();
+ resourcesSize = metaData.GetResourcesSize ();
+ if (reserveStrongNameSignatureSpace) {
+ strongNameSigOffset = resourcesOffset + resourcesSize;
+ // fixUps = RVA for vtable
+ importTableOffset = strongNameSigOffset + StrongNameSignatureSize;
+ } else {
+ strongNameSigOffset = 0;
+ // fixUps = RVA for vtable
+ importTableOffset = resourcesOffset + resourcesSize;
+ }
+ importTablePadding = NumToAlign(importTableOffset,16);
+ importTableOffset += importTablePadding;
+ importLookupTableOffset = importTableOffset + ImportTableSize;
+ hintNameTableOffset = importLookupTableOffset + IATSize;
+ runtimeEngineOffset = hintNameTableOffset + (uint)hintNameTable.Length;
+ entryPointOffset = runtimeEngineOffset + (uint)runtimeEngine.Length;
+ totalImportTableSize = entryPointOffset - importTableOffset;
+ // Console.WriteLine("total import table size = " + totalImportTableSize);
+ // Console.WriteLine("entrypoint offset = " + entryPointOffset);
+ entryPointPadding = NumToAlign(entryPointOffset,4) + 2;
+ entryPointOffset += entryPointPadding;
+ text.AddReloc(entryPointOffset+2);
+ text.IncTide(entryPointOffset + 6);
+ //if (text.Tide() < fileAlign) fileAlign = minFileAlign;
+ text.SetSize(NumToAlign(text.Tide(),fileAlign));
+ // Console.WriteLine("text size = " + text.Size() + " text tide = " + text.Tide() + " text padding = " + text.Padding());
+ // Console.WriteLine("metaDataOffset = " + Hex.Int(metaDataOffset));
+ // Console.WriteLine("importTableOffset = " + Hex.Int(importTableOffset));
+ // Console.WriteLine("importLookupTableOffset = " + Hex.Int(importLookupTableOffset));
+ // Console.WriteLine("hintNameTableOffset = " + Hex.Int(hintNameTableOffset));
+ // Console.WriteLine("runtimeEngineOffset = " + Hex.Int(runtimeEngineOffset));
+ // Console.WriteLine("entryPointOffset = " + Hex.Int(entryPointOffset));
+ // Console.WriteLine("entryPointPadding = " + Hex.Int(entryPointPadding));
+
+ }
+
+ internal void BuildRelocSection() {
+ text.DoRelocs(reloc);
+ if (sdata != null) sdata.DoRelocs(reloc);
+ if (rsrc != null) rsrc.DoRelocs(reloc);
+ relocTide = (uint)reloc.Seek(0,SeekOrigin.Current);
+ relocPadding = NumToAlign(relocTide,fileAlign);
+ relocSize = relocTide + relocPadding;
+ imageSize = relocRVA + SectionAlignment;
+ initDataSize += relocSize;
+ }
+
+ private void CalcOffsets() {
+if (sdata != null)
+ numSections++;
+if (rsrc != null)
+ numSections++;
+ headerSize = fileHeaderSize + (numSections * sectionHeaderSize);
+ headerPadding = NumToAlign(headerSize,fileAlign);
+ headerSize += headerPadding;
+ uint offset = headerSize;
+ uint rva = SectionAlignment;
+ text.SetOffset(offset);
+ text.SetRVA(rva);
+ offset += text.Size();
+ rva = GetNextSectStart(rva,text.Tide());
+ // Console.WriteLine("headerSize = " + headerSize);
+ // Console.WriteLine("headerPadding = " + headerPadding);
+ // Console.WriteLine("textOffset = " + Hex.Int(text.Offset()));
+ if (sdata != null) {
+ sdata.SetSize(NumToAlign(sdata.Tide(),fileAlign));
+ sdata.SetOffset(offset);
+ sdata.SetRVA(rva);
+ offset += sdata.Size();
+ rva = GetNextSectStart(rva,sdata.Tide());
+ initDataSize += sdata.Size();
+ }
+ if (rsrc != null) {
+ rsrc.SetSize(NumToAlign(rsrc.Tide(),fileAlign));
+ rsrc.SetOffset(offset);
+ rsrc.SetRVA(rva);
+ offset += rsrc.Size();
+ rva = GetNextSectStart(rva,rsrc.Tide());
+ initDataSize += rsrc.Size();
+ }
+ relocOffset = offset;
+ relocRVA = rva;
+ }
+
+ internal void MakeFile() {
+ if (doDLL) hintNameTable = dllHintNameTable.ToCharArray();
+ else hintNameTable = exeHintNameTable.ToCharArray();
+ BuildTextSection();
+ CalcOffsets();
+ BuildRelocSection();
+ // now write it out
+ WriteHeader();
+ WriteSections();
+ Flush();
+ Close();
+ }
+
+ private void WriteHeader() {
+ Write(DOSHeader);
+ // Console.WriteLine("Writing PEHeader at offset " + Seek(0,SeekOrigin.Current));
+ WritePEHeader();
+ // Console.WriteLine("Writing text section header at offset " + Hex.Long(Seek(0,SeekOrigin.Current)));
+ text.WriteHeader(this,relocRVA);
+ if (sdata != null) sdata.WriteHeader(this,relocRVA);
+ if (rsrc != null) rsrc.WriteHeader(this,relocRVA);
+ // Console.WriteLine("Writing reloc section header at offset " + Seek(0,SeekOrigin.Current));
+ WriteRelocSectionHeader();
+ // Console.WriteLine("Writing padding at offset " + Seek(0,SeekOrigin.Current));
+ WriteZeros(headerPadding);
+ }
+
+ private void WriteSections() {
+ // Console.WriteLine("Writing text section at offset " + Seek(0,SeekOrigin.Current));
+ WriteTextSection();
+ if (sdata != null) WriteSDataSection();
+ if (rsrc != null) WriteRsrcSection();
+ WriteRelocSection();
+ }
+
+ private void WriteIAT() {
+ Write(text.RVA() + hintNameTableOffset);
+ Write(0);
+ }
+
+ private void WriteImportTables() {
+ // Import Table
+ WriteZeros(importTablePadding);
+ // Console.WriteLine("Writing import tables at offset " + Hex.Long(Seek(0,SeekOrigin.Current)));
+ Write(importLookupTableOffset + text.RVA());
+ WriteZeros(8);
+ Write(runtimeEngineOffset + text.RVA());
+ Write(text.RVA()); // IAT is at the beginning of the text section
+ WriteZeros(20);
+ // Import Lookup Table
+ WriteIAT(); // lookup table and IAT are the same
+ // Hint/Name Table
+ // Console.WriteLine("Writing hintname table at " + Hex.Long(Seek(0,SeekOrigin.Current)));
+ Write(hintNameTable);
+ Write(runtimeEngineName.ToCharArray());
+ }
+
+ private void WriteTextSection() {
+ WriteIAT();
+ WriteCLIHeader();
+ // Console.WriteLine("Writing code at " + Hex.Long(Seek(0,SeekOrigin.Current)));
+ metaData.WriteByteCodes(this);
+ // Console.WriteLine("Finished writing code at " + Hex.Long(Seek(0,SeekOrigin.Current)));
+ largeStrings = metaData.LargeStringsIndex();
+ largeGUID = metaData.LargeGUIDIndex();
+ largeUS = metaData.LargeUSIndex();
+ largeBlob = metaData.LargeBlobIndex();
+ metaData.WriteMetaData(this);
+ metaData.WriteResources (this);
+ if (reserveStrongNameSignatureSpace) {
+ WriteZeros(StrongNameSignatureSize);
+ }
+ WriteImportTables();
+ WriteZeros(entryPointPadding);
+ Write((ushort)0x25FF);
+ Write(ImageBase + text.RVA());
+ WriteZeros(text.Padding());
+ }
+
+ private void WriteCLIHeader() {
+ Write(CLIHeaderSize); // Cb
+ Write((short)2); // Major runtime version
+ Write((short)0); // Minor runtime version
+ Write(text.RVA() + metaDataOffset);
+ Write(metaData.Size());
+ Write(runtimeFlags);
+ Write(entryPointToken);
+ if (resourcesSize > 0) {
+ Write (text.RVA () + resourcesOffset);
+ Write (resourcesSize);
+ } else {
+ WriteZeros (8);
+ }
+ // Strong Name Signature (RVA, size)
+ if (reserveStrongNameSignatureSpace) {
+ Write(text.RVA() + strongNameSigOffset);
+ Write(StrongNameSignatureSize);
+ } else {
+ WriteZeros(8);
+ }
+ WriteZeros(8); // CodeManagerTable
+ WriteZeros(8); // VTableFixups NYI
+ WriteZeros(16); // ExportAddressTableJumps, ManagedNativeHeader
+ }
+
+ private void WriteSDataSection() {
+ long size = sdata.Size ();
+ long start = BaseStream.Position;
+ for (int i=0; i < data.Count; i++) {
+ ((DataConstant)data[i]).Write(this);
+ }
+ while (BaseStream.Position < (start + size))
+ Write ((byte) 0);
+ }
+
+ private void WriteRsrcSection() {
+ }
+
+ private void WriteRelocSection() {
+ // Console.WriteLine("Writing reloc section at " + Seek(0,SeekOrigin.Current) + " = " + relocOffset);
+ MemoryStream str = (MemoryStream)reloc.BaseStream;
+ Write(str.ToArray());
+ WriteZeros(NumToAlign((uint)str.Position,fileAlign));
+ }
+
+ internal void SetEntryPoint(uint entryPoint) {
+ entryPointToken = entryPoint;
+ }
+
+ internal void AddInitData(DataConstant cVal) {
+ if (sdata == null) {
+ sdata = new Section(sdataName,0xC0000040); // IMAGE_SCN_CNT INITIALIZED_DATA, READ, WRITE
+ data = new ArrayList();
+ }
+ data.Add(cVal);
+ cVal.DataOffset = sdata.Tide();
+ sdata.IncTide(cVal.GetSize());
+ }
+
+ internal void WriteZeros(uint numZeros) {
+ for (int i=0; i < numZeros; i++) {
+ Write((byte)0);
+ }
+ }
+
+ internal void WritePEHeader() {
+ Write((ushort)0x014C); // Machine - always 0x14C for Managed PE Files (allow others??)
+ Write((ushort)numSections);
+ Write(dateStamp);
+ WriteZeros(8); // Pointer to Symbol Table and Number of Symbols (always zero for ECMA CLI files)
+ Write((ushort)0x00E0); // Size of Optional Header
+ Write(characteristics);
+ // PE Optional Header
+ Write((ushort)0x010B); // Magic
+ Write((byte)0x6); // LMajor pure-IL = 6 C++ = 7
+ Write((byte)0x0); // LMinor
+ Write(text.Size());
+ Write(initDataSize);
+ Write(0); // Check other sections here!!
+ Write(text.RVA() + entryPointOffset);
+ Write(text.RVA());
+ uint dataBase = 0;
+ if (sdata != null) dataBase = sdata.RVA();
+ else if (rsrc != null) dataBase = rsrc.RVA();
+ else dataBase = relocRVA;
+ Write(dataBase);
+ Write(ImageBase);
+ Write(SectionAlignment);
+ Write(fileAlign);
+ Write((ushort)0x04); // OS Major
+ WriteZeros(6); // OS Minor, User Major, User Minor
+ Write((ushort)0x04); // SubSys Major
+ WriteZeros(6); // SybSys Minor, Reserved
+ Write(imageSize);
+ Write(headerSize);
+ Write((int)0); // File Checksum
+ Write((ushort)subSys);
+ Write((short)0); // DLL Flags
+ Write((uint)0x100000); // Stack Reserve Size
+ Write((uint)0x1000); // Stack Commit Size
+ Write((uint)0x100000); // Heap Reserve Size
+ Write((uint)0x1000); // Heap Commit Size
+ Write(0); // Loader Flags
+ Write(0x10); // Number of Data Directories
+ WriteZeros(8); // Export Table
+ Write(importTableOffset + text.RVA());
+ Write(totalImportTableSize);
+ WriteZeros(24); // Resource, Exception and Certificate Tables
+ Write(relocRVA);
+ Write(relocTide);
+ WriteZeros(48); // Debug, Copyright, Global Ptr, TLS, Load Config and Bound Import Tables
+ Write(text.RVA()); // IATRVA - IAT is at start of .text Section
+ Write(IATSize);
+ WriteZeros(8); // Delay Import Descriptor
+ Write(text.RVA()+IATSize); // CLIHeader immediately follows IAT
+ Write(CLIHeaderSize);
+ WriteZeros(8); // Reserved
+ }
+
+ internal void WriteRelocSectionHeader() {
+ Write(relocName.ToCharArray());
+ Write(relocTide);
+ Write(relocRVA);
+ Write(relocSize);
+ Write(relocOffset);
+ WriteZeros(12);
+ Write(relocFlags);
+ }
+
+ private void Align (MemoryStream str, int val) {
+ if ((str.Position % val) != 0) {
+ for (int i=val - (int)(str.Position % val); i > 0; i--) {
+ str.WriteByte(0);
+ }
+ }
+ }
+
+ private uint Align(uint val, uint alignVal) {
+ if ((val % alignVal) != 0) {
+ val += alignVal - (val % alignVal);
+ }
+ return val;
+ }
+
+ private uint NumToAlign(uint val, uint alignVal) {
+ if ((val % alignVal) == 0) return 0;
+ return alignVal - (val % alignVal);
+ }
+
+ internal void StringsIndex(uint ix) {
+ if (largeStrings) Write(ix);
+ else Write((ushort)ix);
+ }
+
+ internal void GUIDIndex(uint ix) {
+ if (largeGUID) Write(ix);
+ else Write((ushort)ix);
+ }
+
+ internal void USIndex(uint ix) {
+ if (largeUS) Write(ix);
+ else Write((ushort)ix);
+ }
+
+ internal void BlobIndex(uint ix) {
+ if (largeBlob) Write(ix);
+ else Write((ushort)ix);
+ }
+
+ internal void WriteIndex(MDTable tabIx,uint ix) {
+ if (metaData.LargeIx(tabIx)) Write(ix);
+ else Write((ushort)ix);
+ }
+
+ internal void WriteCodedIndex(CIx code, MetaDataElement elem) {
+ metaData.WriteCodedIndex(code,elem,this);
+ }
+
+ internal void WriteCodeRVA(uint offs) {
+ Write(text.RVA() + offs);
+ }
+
+ internal void WriteDataRVA(uint offs) {
+ Write(sdata.RVA() + offs);
+ }
+
+ internal void Write3Bytes(uint val) {
+ byte b3 = (byte)((val & FileImage.iByteMask[2]) >> 16);
+ byte b2 = (byte)((val & FileImage.iByteMask[1]) >> 8);;
+ byte b1 = (byte)(val & FileImage.iByteMask[0]);
+ Write(b1);
+ Write(b2);
+ Write(b3);
+ }
+
+ internal bool ReserveStrongNameSignatureSpace {
+ get { return reserveStrongNameSignatureSpace; }
+ set { reserveStrongNameSignatureSpace = value; }
+ }
+
+ }
+ /**************************************************************************/
+ /// <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);
+ }
+
+ }
+
+ /**************************************************************************/
+ /// <summary>
+ /// Descriptor for an IL instruction
+ /// </summary>
+ internal abstract class CILInstruction {
+ protected static readonly sbyte maxByteVal = 127;
+ protected static readonly sbyte minByteVal = -128;
+ protected static readonly byte leadByte = 0xFE;
+ protected static readonly uint USHeapIndex = 0x70000000;
+ protected static readonly int longInstrStart = (int)Op.arglist;
+ public bool twoByteInstr = false;
+ public uint size = 0;
+ public uint offset;
+
+ internal virtual bool Check(MetaData md) {
+ return false;
+ }
+
+ internal virtual void Write(FileImage output) { }
+
+ }
+
+ internal class CILByte : CILInstruction {
+ byte byteVal;
+
+ internal CILByte(byte bVal) {
+ byteVal = bVal;
+ size = 1;
+ }
+
+ internal override void Write(FileImage output) {
+ output.Write(byteVal);
+ }
+
+ }
+
+
+ internal class Instr : CILInstruction {
+ protected int instr;
+
+ internal Instr(int inst) {
+ if (inst >= longInstrStart) {
+ instr = inst - longInstrStart;
+ twoByteInstr = true;
+ size = 2;
+ } else {
+ instr = inst;
+ size = 1;
+ }
+ }
+
+ internal override void Write(FileImage output) {
+ //Console.WriteLine("Writing instruction " + instr + " with size " + size);
+ if (twoByteInstr) output.Write(leadByte);
+ output.Write((byte)instr);
+ }
+
+ }
+
+ internal class IntInstr : Instr {
+ int val;
+ bool byteNum;
+
+ internal IntInstr(int inst, int num, bool byteSize) : base(inst) {
+ val = num;
+ byteNum = byteSize;
+ if (byteNum) size++;
+ else size += 4;
+ }
+
+ internal sealed override void Write(FileImage output) {
+ base.Write(output);
+ if (byteNum)
+ output.Write((sbyte)val);
+ else
+ output.Write(val);
+ }
+
+ }
+
+ internal class UIntInstr : Instr {
+ int val;
+ bool byteNum;
+
+ internal UIntInstr(int inst, int num, bool byteSize) : base(inst) {
+ val = num;
+ byteNum = byteSize;
+ if (byteNum) size++;
+ else size += 2;
+ }
+
+ internal sealed override void Write(FileImage output) {
+ base.Write(output);
+ if (byteNum)
+ output.Write((byte)val);
+ else
+ output.Write((ushort)val);
+ }
+
+ }
+
+ internal class LongInstr : Instr {
+ long val;
+
+ internal LongInstr(int inst, long l) : base(inst) {
+ val = l;
+ size += 8;
+ }
+
+ internal sealed override void Write(FileImage output) {
+ base.Write(output);
+ output.Write(val);
+ }
+
+ }
+
+ internal class FloatInstr : Instr {
+ float fVal;
+
+ internal FloatInstr(int inst, float f) : base(inst) {
+ fVal = f;
+ size += 4;
+ }
+
+ internal sealed override void Write(FileImage output) {
+ base.Write(output);
+ output.Write(fVal);
+ }
+
+ }
+
+ internal class DoubleInstr : Instr {
+ double val;
+
+ internal DoubleInstr(int inst, double d) : base(inst) {
+ val = d;
+ size += 8;
+ }
+
+ internal sealed override void Write(FileImage output) {
+ base.Write(output);
+ output.Write(val);
+ }
+
+ }
+
+ internal class StringInstr : Instr {
+ string val;
+ byte[] bval;
+ uint strIndex;
+
+ internal StringInstr(int inst, string str) : base(inst) {
+ val = str;
+ size += 4;
+ }
+
+ internal StringInstr (int inst, byte[] str) : base (inst) {
+ bval = str;
+ size += 4;
+ }
+
+ internal sealed override bool Check(MetaData md) {
+ if (val != null)
+ strIndex = md.AddToUSHeap(val);
+ else
+ strIndex = md.AddToUSHeap (bval);
+ return false;
+ }
+
+ internal sealed override void Write(FileImage output) {
+ base.Write(output);
+ output.Write(USHeapIndex | strIndex);
+ }
+
+ }
+
+ internal class LabelInstr : CILInstruction {
+ CILLabel label;
+
+ internal LabelInstr(CILLabel lab) {
+ label = lab;
+ label.AddLabelInstr(this);
+ }
+ }
+
+ internal class FieldInstr : Instr {
+ Field field;
+
+ internal FieldInstr(int inst, Field f) : base(inst) {
+ field = f;
+ size += 4;
+ }
+
+ internal sealed override void Write(FileImage output) {
+ base.Write(output);
+ output.Write(field.Token());
+ }
+
+ }
+
+ internal class MethInstr : Instr {
+ Method meth;
+
+ internal MethInstr(int inst, Method m) : base(inst) {
+ meth = m;
+ size += 4;
+ }
+
+ internal sealed override void Write(FileImage output) {
+ base.Write(output);
+ output.Write(meth.Token());
+ }
+
+ }
+
+ internal class SigInstr : Instr {
+ CalliSig signature;
+
+ internal SigInstr(int inst, CalliSig sig) : base(inst) {
+ signature = sig;
+ size += 4;
+ }
+
+ internal sealed override bool Check(MetaData md) {
+ md.AddToTable(MDTable.StandAloneSig,signature);
+ signature.BuildTables(md);
+ return false;
+ }
+
+ internal sealed override void Write(FileImage output) {
+ base.Write(output);
+ output.Write(signature.Token());
+ }
+ }
+
+ internal class TypeInstr : Instr {
+ MetaDataElement theType;
+
+ internal TypeInstr(int inst, Type aType, MetaData md) : base(inst) {
+ theType = aType.GetTypeSpec(md);
+ size += 4;
+ }
+
+ internal sealed override void Write(FileImage output) {
+ base.Write(output);
+ output.Write(theType.Token());
+ }
+
+ }
+
+ internal class BranchInstr : Instr {
+ CILLabel dest;
+ private bool shortVer = true;
+ private static readonly byte longInstrOffset = 13;
+ private int target = 0;
+
+ internal BranchInstr(int inst, CILLabel dst) : base(inst) {
+ dest = dst;
+ dest.AddBranch(this);
+ size++;
+
+ if (inst >= (int) BranchOp.br && inst != (int) BranchOp.leave_s) {
+ shortVer = false;
+ size += 3;
+ }
+ }
+
+ internal sealed override bool Check(MetaData md) {
+ target = (int)dest.GetLabelOffset() - (int)(offset + size);
+ return false;
+ }
+
+ internal sealed override void Write(FileImage output) {
+ base.Write(output);
+ if (shortVer)
+ output.Write((sbyte)target);
+ else
+ output.Write(target);
+ }
+
+ }
+
+ internal class SwitchInstr : Instr {
+ CILLabel[] cases;
+ uint numCases = 0;
+
+ internal SwitchInstr(int inst, CILLabel[] dsts) : base(inst) {
+ cases = dsts;
+ if (cases != null) numCases = (uint)cases.Length;
+ size += 4 + (numCases * 4);
+ for (int i=0; i < numCases; i++) {
+ cases[i].AddBranch(this);
+ }
+ }
+
+ internal sealed override void Write(FileImage output) {
+ base.Write(output);
+ output.Write(numCases);
+ for (int i=0; i < numCases; i++) {
+ int target = (int)cases[i].GetLabelOffset() - (int)(offset + size);
+ output.Write(target);
+ }
+ }
+
+ }
+ /**************************************************************************/
+
+ public class GenericParameter : MetaDataElement
+ {
+ MetaDataElement owner;
+ MetaData metadata;
+ string name;
+ uint nameIx;
+ short index;
+
+ internal GenericParameter (ClassDef owner, MetaData metadata,
+ short index, string name) : this (owner, metadata, index, name, true)
+ {
+ }
+
+ internal GenericParameter (MethodDef owner, MetaData metadata,
+ short index, string name) : this (owner, metadata, index, name, true)
+ {
+ }
+
+ private GenericParameter (MetaDataElement owner, MetaData metadata,
+ short index, string name, bool nadda)
+ {
+ this.owner = owner;
+ this.metadata = metadata;
+ this.index = index;
+ tabIx = MDTable.GenericParam;
+ this.name = name;
+ }
+
+ internal override uint SortKey() {
+ return (owner.Row << MetaData.CIxShiftMap[(uint)CIx.TypeOrMethodDef])
+ | owner.GetCodedIx(CIx.TypeOrMethodDef);
+ }
+
+ 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) +
+ 4 +
+ md.TableIndexSize(MDTable.TypeDef));
+ }
+
+ 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) 0);
+ output.WriteCodedIndex(CIx.TypeOrMethodDef, owner);
+ output.Write ((uint) nameIx);
+ output.WriteIndex(MDTable.TypeDef,owner.Row);
+ }
+
+
+ }
+
+ internal class GenericParamConstraint : MetaDataElement
+ {
+ GenericParameter param;
+ Type type;
+
+ public GenericParamConstraint (GenericParameter param, Type type) {
+ this.param = param;
+ this.type = type;
+ tabIx = MDTable.GenericParamConstraint;
+ }
+
+ 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 : MetaDataElement
+ {
+ Method meth;
+ GenericMethodSig g_sig;
+ uint sidx;
+
+ internal MethodSpec (Method meth, GenericMethodSig g_sig) {
+ this.meth = meth;
+ this.g_sig = g_sig;
+ tabIx = MDTable.MethodSpec;
+ }
+
+ 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);
+ }
+ }
+
+ /**************************************************************************/
+ /// <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 a local of a method
+ /// </summary>
+ public class Local
+ {
+ private static readonly byte Pinned = 0x45;
+ string name;
+ Type type;
+ bool pinned = false, byref = false;
+
+ /// <summary>
+ /// Create a new local variable
+ /// </summary>
+ /// <param name="lName">name of the local variable</param>
+ /// <param name="lType">type of the local variable</param>
+ public Local(string lName, Type lType) {
+ name = lName;
+ type = lType;
+ }
+
+ /// <summary>
+ /// Create a new local variable that is byref and/or pinned
+ /// </summary>
+ /// <param name="lName">local name</param>
+ /// <param name="lType">local type</param>
+ /// <param name="byRef">is byref</param>
+ /// <param name="isPinned">has pinned attribute</param>
+ public Local(string lName, Type lType, bool byRef, bool isPinned)
+ {
+ name = lName;
+ type = lType;
+ byref = byRef;
+ pinned = isPinned;
+ }
+
+ internal void TypeSig(MemoryStream str) {
+ if (pinned) str.WriteByte(Pinned);
+ type.TypeSig(str);
+ }
+
+ }
+ /**************************************************************************/
+ /// <summary>
+ /// Descriptor for the locals for a method
+ /// </summary>
+
+ public class LocalSig : Signature
+ {
+ private static readonly byte LocalSigByte = 0x7;
+ Local[] locals;
+
+ public LocalSig(Local[] locals) {
+ this.locals = locals;
+ tabIx = MDTable.StandAloneSig;
+ }
+
+ internal sealed override void BuildTables(MetaData md) {
+ if (done) return;
+ MemoryStream sig = new MemoryStream();
+ sig.WriteByte(LocalSigByte);
+ MetaData.CompressNum((uint)locals.Length,sig);
+ for (int i=0; i < locals.Length; i++) {
+ ((Local)locals[i]).TypeSig(sig);
+ }
+ sigIx = md.AddToBlobHeap(sig.ToArray());
+ done = true;
+ }
+
+ }
+
+ /**************************************************************************/
+ /// <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;
+ this.rRef = rRef;
+ this.fileOffset = fileOffset;
+ this.resourceBytes = 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 Exception("ERROR: Manifest Resource has byte value and file reference");
+ fileOffset = md.AddResource(resourceBytes);
+ } else {
+ if (rRef == null)
+ throw new Exception("ERROR: 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>
+ /// 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>
+ /// 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
+ private static readonly string version = "v1.0.3705\0\0\0";
+ 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;
+ 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);
+ }