merge -r 53370:58178
[mono.git] / mcs / class / PEAPI / PEAPI.cs
1 using System;
2 using System.IO;
3 using System.Collections;
4 using System.Text;
5
6 namespace PEAPI {
7
8         /**************************************************************************/  
9         /// <summary>
10         /// Image for a PEFile
11         /// File Structure
12         ///     DOS Header (128 bytes) 
13         ///     PE Signature ("PE\0\0") 
14         ///     PEFileHeader (20 bytes)
15         ///     PEOptionalHeader (224 bytes) 
16         ///     SectionHeaders (40 bytes * NumSections)
17         ///
18         ///     Sections .text (always present - contains metadata)
19         ///              .sdata (contains any initialised data in the file - may not be present)
20         ///                     (for ilams /debug this contains the Debug table)
21         ///              .reloc (always present - in pure CIL only has one fixup)
22         ///               others???  c# produces .rsrc section containing a Resource Table
23         ///
24         /// .text layout
25         ///     IAT (single entry 8 bytes for pure CIL)
26         ///     CLIHeader (72 bytes)
27         ///     CIL instructions for all methods (variable size)
28         ///     MetaData 
29         ///       Root (20 bytes + UTF-8 Version String + quad align padding)
30         ///       StreamHeaders (8 bytes + null terminated name string + quad align padding)
31         ///       Streams 
32         ///         #~        (always present - holds metadata tables)
33         ///         #Strings  (always present - holds identifier strings)
34         ///         #US       (Userstring heap)
35         ///         #Blob     (signature blobs)
36         ///         #GUID     (guids for assemblies or Modules)
37         ///    ImportTable (40 bytes)
38         ///    ImportLookupTable(8 bytes) (same as IAT for standard CIL files)
39         ///    Hint/Name Tables with entry "_CorExeMain" for .exe file and "_CorDllMain" for .dll (14 bytes)
40         ///    ASCII string "mscoree.dll" referenced in ImportTable (+ padding = 16 bytes)
41         ///    Entry Point  (0xFF25 followed by 4 bytes 0x400000 + RVA of .text)
42         ///
43         ///  #~ stream structure
44         ///    Header (24 bytes)
45         ///    Rows   (4 bytes * numTables)
46         ///    Tables
47         /// </summary>
48         internal class FileImage : BinaryWriter {
49
50                 internal readonly static uint[] iByteMask = {0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000};
51                 internal readonly static ulong[] lByteMask = {0x00000000000000FF, 0x000000000000FF00,
52                         0x0000000000FF0000, 0x00000000FF000000,
53                         0x000000FF00000000, 0x0000FF0000000000,
54                         0x00FF000000000000, 0xFF00000000000000 };
55                 internal readonly static uint nibble0Mask = 0x0000000F;
56                 internal readonly static uint nibble1Mask = 0x000000F0;
57
58                 private static readonly byte[] DOSHeader = { 0x4d,0x5a,0x90,0x00,0x03,0x00,0x00,0x00,
59                         0x04,0x00,0x00,0x00,0xff,0xff,0x00,0x00,
60                         0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
61                         0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
62                         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
63                         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
64                         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
65                         0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,
66                         0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd,
67                         0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68,
68                         0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,
69                         0x61,0x6d,0x20,0x63,0x61,0x6e,0x6e,0x6f,
70                         0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,
71                         0x20,0x69,0x6e,0x20,0x44,0x4f,0x53,0x20,
72                         0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0d,0x0a,
73                         0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
74                         0x50,0x45,0x00,0x00};
75                 private static byte[] PEHeader = { 0x4c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
76                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77                         0xE0, 0x00, 0x0E, 0x01, // PE Header Standard Fields
78                         0x0B, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 
79                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
80                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
81                 };
82
83                 private static readonly uint minFileAlign = 0x200;
84                 private static readonly uint maxFileAlign = 0x1000;
85                 private static readonly uint fileHeaderSize = 0x178;
86                 private static readonly uint sectionHeaderSize = 40;
87                 private static readonly uint SectionAlignment = 0x2000;
88                 private static readonly uint ImageBase = 0x400000;
89                 private static readonly uint ImportTableSize = 40;
90                 private static readonly uint IATSize = 8;
91                 private static readonly uint CLIHeaderSize = 72;
92                 private uint runtimeFlags = 0x01;  // COMIMAGE_FLAGS_ILONLY
93                 // 32BITREQUIRED 0x02, STRONGNAMESIGNED 0x08, TRACKDEBUGDATA 0x10000
94                 private static readonly uint StrongNameSignatureSize = 128;
95                 private bool reserveStrongNameSignatureSpace = false;
96
97                 private static readonly uint relocFlags = 0x42000040;
98                 private static readonly ushort exeCharacteristics = 0x010E;
99                 private static readonly ushort dllCharacteristics = 0x210E;
100                 // section names are all 8 bytes
101                 private static readonly string textName = ".text\0\0\0";
102                 private static readonly string sdataName = ".sdata\0\0";
103                 private static readonly string relocName = ".reloc\0\0";
104                 private static readonly string rsrcName = ".rsrc\0\0\0";
105                 private static readonly string exeHintNameTable = "\0\0_CorExeMain\0";
106                 private static readonly string dllHintNameTable = "\0\0_CorDllMain\0";
107                 private static readonly string runtimeEngineName = "mscoree.dll\0\0";
108
109                 private Section text, sdata, rsrc;
110                 ArrayList data;
111                 BinaryWriter reloc = new BinaryWriter(new MemoryStream());
112                 uint dateStamp = 0;
113                 DateTime origin = new DateTime(1970,1,1);
114                 uint numSections = 2; // always have .text  and .reloc sections
115                 internal SubSystem subSys = SubSystem.Windows_CUI;  // default is Windows Console mode
116                 internal long stackReserve = 0x100000; // default is 1Mb 
117                 internal uint fileAlign = minFileAlign;
118                 uint entryPointOffset, entryPointPadding, imageSize, headerSize, headerPadding, entryPointToken = 0;
119                 uint relocOffset, relocRVA, relocSize, relocPadding, relocTide, hintNameTableOffset;
120                 uint metaDataOffset, runtimeEngineOffset, initDataSize = 0, importTablePadding;
121                 uint resourcesSize, resourcesOffset;
122                 uint strongNameSigOffset;
123                 uint importTableOffset, importLookupTableOffset, totalImportTableSize;
124                 MetaData metaData;
125                 char[] runtimeEngine = runtimeEngineName.ToCharArray(), hintNameTable;
126                 bool doDLL, largeStrings, largeGUID, largeUS, largeBlob;
127                 ushort characteristics;
128
129                 internal FileImage(bool makeDLL, string fileName) : base(new FileStream(fileName,FileMode.Create)) 
130                 {
131                         InitFileImage(makeDLL);
132                         TimeSpan tmp = System.IO.File.GetCreationTime(fileName).Subtract(origin);
133                         dateStamp = Convert.ToUInt32(tmp.TotalSeconds);
134                 }
135
136                 internal FileImage(bool makeDLL, Stream str) : base(str) 
137                 {
138                         InitFileImage(makeDLL);
139                         TimeSpan tmp = DateTime.Now.Subtract(origin);
140                         dateStamp = Convert.ToUInt32(tmp.TotalSeconds);
141                 }
142
143                 private void InitFileImage(bool makeDLL) 
144                 {
145                         doDLL = makeDLL;
146                         if (doDLL) {
147                                 hintNameTable = dllHintNameTable.ToCharArray();
148                                 characteristics = dllCharacteristics;
149                         } else {
150                                 hintNameTable = exeHintNameTable.ToCharArray();
151                                 characteristics = exeCharacteristics;
152                         }
153                         text = new Section(textName,0x60000020);     // IMAGE_SCN_CNT  CODE, EXECUTE, READ
154                         //                      rsrc = new Section(rsrcName,0x40000040);     // IMAGE_SCN_CNT  INITIALIZED_DATA, READ
155                         metaData = new MetaData(this);
156                 }
157
158                 internal MetaData GetMetaData() 
159                 {
160                         return metaData;
161                 }
162
163                 private uint GetNextSectStart(uint rva, uint tide) 
164                 {
165                         if (tide < SectionAlignment) return rva + SectionAlignment;
166                         return rva + ((tide / SectionAlignment) + 1) * SectionAlignment;
167                 }
168
169                 private void BuildTextSection() 
170                 {
171                         // .text layout
172                         //    IAT (single entry 8 bytes for pure CIL)
173                         //    CLIHeader (72 bytes)
174                         //    CIL instructions for all methods (variable size)
175                         //    MetaData 
176                         //    ImportTable (40 bytes)
177                         //    ImportLookupTable(8 bytes) (same as IAT for standard CIL files)
178                         //    Hint/Name Tables with entry "_CorExeMain" for .exe file and "_CorDllMain" for .dll (14 bytes)
179                         //    ASCII string "mscoree.dll" referenced in ImportTable (+ padding = 16 bytes)
180                         //    Entry Point  (0xFF25 followed by 4 bytes 0x400000 + RVA of .text)
181                         metaData.BuildMetaData(IATSize + CLIHeaderSize);
182                         metaDataOffset = IATSize + CLIHeaderSize;
183                         // Console.WriteLine("Code starts at " + metaDataOffset);
184                         metaDataOffset += metaData.CodeSize();
185                         // resourcesStart =
186                         resourcesOffset = metaDataOffset + metaData.Size ();
187                         resourcesSize = metaData.GetResourcesSize ();
188                         if (reserveStrongNameSignatureSpace) {
189                                 strongNameSigOffset = resourcesOffset + resourcesSize;
190                                 // fixUps = RVA for vtable
191                                 importTableOffset = strongNameSigOffset + StrongNameSignatureSize;
192                         } else {
193                                 strongNameSigOffset = 0;
194                                 // fixUps = RVA for vtable
195                                 importTableOffset = resourcesOffset + resourcesSize;
196                         }
197                         importTablePadding = NumToAlign(importTableOffset,16);
198                         importTableOffset += importTablePadding;
199                         importLookupTableOffset = importTableOffset + ImportTableSize;
200                         hintNameTableOffset = importLookupTableOffset + IATSize;
201                         runtimeEngineOffset = hintNameTableOffset + (uint)hintNameTable.Length;
202                         entryPointOffset = runtimeEngineOffset + (uint)runtimeEngine.Length;
203                         totalImportTableSize = entryPointOffset - importTableOffset;
204                         // Console.WriteLine("total import table size = " + totalImportTableSize);
205                         // Console.WriteLine("entrypoint offset = " + entryPointOffset);
206                         entryPointPadding = NumToAlign(entryPointOffset,4) + 2;
207                         entryPointOffset += entryPointPadding;
208                         text.AddReloc(entryPointOffset+2);
209                         text.IncTide(entryPointOffset + 6);
210                         //if (text.Tide() < fileAlign) fileAlign = minFileAlign;
211                         text.SetSize(NumToAlign(text.Tide(),fileAlign));
212                         // Console.WriteLine("text size = " + text.Size() + " text tide = " + text.Tide() + " text padding = " + text.Padding());
213                         // Console.WriteLine("metaDataOffset = " + Hex.Int(metaDataOffset));
214                         // Console.WriteLine("importTableOffset = " + Hex.Int(importTableOffset));
215                         // Console.WriteLine("importLookupTableOffset = " + Hex.Int(importLookupTableOffset));
216                         // Console.WriteLine("hintNameTableOffset = " + Hex.Int(hintNameTableOffset));
217                         // Console.WriteLine("runtimeEngineOffset = " + Hex.Int(runtimeEngineOffset));
218                         // Console.WriteLine("entryPointOffset = " + Hex.Int(entryPointOffset));
219                         // Console.WriteLine("entryPointPadding = " + Hex.Int(entryPointPadding));
220
221                 }
222
223                 internal void BuildRelocSection() 
224                 {
225                         text.DoRelocs(reloc);
226                         if (sdata != null) sdata.DoRelocs(reloc);
227                         if (rsrc != null) rsrc.DoRelocs(reloc);
228                         relocTide = (uint)reloc.Seek(0,SeekOrigin.Current);
229                         relocPadding = NumToAlign(relocTide,fileAlign);
230                         relocSize = relocTide + relocPadding;
231                         imageSize = relocRVA + SectionAlignment;
232                         initDataSize += relocSize;
233                 }
234
235                 private void CalcOffsets() 
236                 {
237                         if (sdata != null)
238                                 numSections++;
239                         if (rsrc != null)
240                                 numSections++;
241                         headerSize = fileHeaderSize + (numSections * sectionHeaderSize);
242                         headerPadding = NumToAlign(headerSize,fileAlign);
243                         headerSize += headerPadding;
244                         uint offset = headerSize;
245                         uint rva = SectionAlignment;
246                         text.SetOffset(offset);
247                         text.SetRVA(rva);
248                         offset += text.Size();
249                         rva  = GetNextSectStart(rva,text.Tide());
250                         // Console.WriteLine("headerSize = " + headerSize);
251                         // Console.WriteLine("headerPadding = " + headerPadding);
252                         // Console.WriteLine("textOffset = " + Hex.Int(text.Offset()));
253                         if (sdata != null) { 
254                                 sdata.SetSize(NumToAlign(sdata.Tide(),fileAlign));
255                                 sdata.SetOffset(offset);
256                                 sdata.SetRVA(rva);
257                                 offset += sdata.Size();
258                                 rva = GetNextSectStart(rva,sdata.Tide());
259                                 initDataSize += sdata.Size();
260                         }
261                         if (rsrc != null) { 
262                                 rsrc.SetSize(NumToAlign(rsrc.Tide(),fileAlign));
263                                 rsrc.SetOffset(offset);
264                                 rsrc.SetRVA(rva);
265                                 offset += rsrc.Size();
266                                 rva = GetNextSectStart(rva,rsrc.Tide());
267                                 initDataSize += rsrc.Size();
268                         }
269                         relocOffset = offset;
270                         relocRVA = rva;
271                 }
272
273                 internal void MakeFile() 
274                 {
275                         if (doDLL) hintNameTable = dllHintNameTable.ToCharArray();
276                         else hintNameTable = exeHintNameTable.ToCharArray();
277                         BuildTextSection();
278                         CalcOffsets();
279                         BuildRelocSection();
280                         // now write it out
281                         WriteHeader();
282                         WriteSections();
283                         Flush();
284                         Close();
285                 }
286
287                 private void WriteHeader() 
288                 {
289                         Write(DOSHeader);
290                         // Console.WriteLine("Writing PEHeader at offset " + Seek(0,SeekOrigin.Current));
291                         WritePEHeader();
292                         // Console.WriteLine("Writing text section header at offset " + Hex.Long(Seek(0,SeekOrigin.Current)));
293                         text.WriteHeader(this,relocRVA);
294                         if (sdata != null) sdata.WriteHeader(this,relocRVA);
295                         if (rsrc != null) rsrc.WriteHeader(this,relocRVA);
296                         // Console.WriteLine("Writing reloc section header at offset " + Seek(0,SeekOrigin.Current));
297                         WriteRelocSectionHeader();
298                         // Console.WriteLine("Writing padding at offset " + Seek(0,SeekOrigin.Current));
299                         WriteZeros(headerPadding);
300                 }
301
302                 private void WriteSections() 
303                 {
304                         // Console.WriteLine("Writing text section at offset " + Seek(0,SeekOrigin.Current));
305                         WriteTextSection();
306                         if (sdata != null) WriteSDataSection();
307                         if (rsrc != null) WriteRsrcSection();
308                         WriteRelocSection();
309                 }
310
311                 private void WriteIAT() 
312                 {
313                         Write(text.RVA() + hintNameTableOffset);
314                         Write(0);
315                 }
316
317                 private void WriteImportTables() 
318                 {
319                         // Import Table
320                         WriteZeros(importTablePadding);
321                         // Console.WriteLine("Writing import tables at offset " + Hex.Long(Seek(0,SeekOrigin.Current)));
322                         Write(importLookupTableOffset + text.RVA());
323                         WriteZeros(8); 
324                         Write(runtimeEngineOffset + text.RVA());
325                         Write(text.RVA());    // IAT is at the beginning of the text section
326                         WriteZeros(20);
327                         // Import Lookup Table
328                         WriteIAT();                // lookup table and IAT are the same
329                         // Hint/Name Table
330                         // Console.WriteLine("Writing hintname table at " + Hex.Long(Seek(0,SeekOrigin.Current)));
331                         Write(hintNameTable);
332                         Write(runtimeEngineName.ToCharArray());
333                 }
334
335                 private void WriteTextSection() 
336                 {
337                         WriteIAT();
338                         WriteCLIHeader();
339                         // Console.WriteLine("Writing code at " + Hex.Long(Seek(0,SeekOrigin.Current)));
340                         metaData.WriteByteCodes(this);
341                         // Console.WriteLine("Finished writing code at " + Hex.Long(Seek(0,SeekOrigin.Current)));
342                         largeStrings = metaData.LargeStringsIndex();
343                         largeGUID = metaData.LargeGUIDIndex();
344                         largeUS = metaData.LargeUSIndex();
345                         largeBlob = metaData.LargeBlobIndex();
346                         metaData.WriteMetaData(this);
347                         metaData.WriteResources (this);
348                         if (reserveStrongNameSignatureSpace) {
349                                 WriteZeros(StrongNameSignatureSize);
350                         }
351                         WriteImportTables();
352                         WriteZeros(entryPointPadding);
353                         Write((ushort)0x25FF);
354                         Write(ImageBase + text.RVA());
355                         WriteZeros(text.Padding());
356                 }
357
358                 private void WriteCLIHeader() 
359                 {
360                         Write(CLIHeaderSize);       // Cb
361                         Write((short)2);            // Major runtime version
362                         Write((short)0);            // Minor runtime version
363                         Write(text.RVA() + metaDataOffset);
364                         Write(metaData.Size());
365                         Write(runtimeFlags);
366                         Write(entryPointToken);
367                         if (resourcesSize > 0) {
368                                 Write (text.RVA () + resourcesOffset);
369                                 Write (resourcesSize);
370                         } else {
371                                 WriteZeros (8);
372                         }
373                         // Strong Name Signature (RVA, size)
374                         if (reserveStrongNameSignatureSpace) {
375                                 Write(text.RVA() + strongNameSigOffset); 
376                                 Write(StrongNameSignatureSize);
377                         } else {
378                                 WriteZeros(8);
379                         }
380                         WriteZeros(8);                     // CodeManagerTable
381                         WriteZeros(8);                     // VTableFixups NYI
382                         WriteZeros(16);                    // ExportAddressTableJumps, ManagedNativeHeader
383                 }
384
385                 private void WriteSDataSection() 
386                 {
387                         long size = sdata.Size ();
388                         long start = BaseStream.Position;
389                         for (int i=0; i < data.Count; i++) {
390                                 ((DataConstant)data[i]).Write(this);
391                         }
392                         while (BaseStream.Position < (start + size))
393                                 Write ((byte) 0);
394                 }
395
396                 private void WriteRsrcSection() 
397                 {
398                 }
399
400                 private void WriteRelocSection() 
401                 {
402                         // Console.WriteLine("Writing reloc section at " + Seek(0,SeekOrigin.Current) + " = " + relocOffset);
403                         MemoryStream str = (MemoryStream)reloc.BaseStream;
404                         Write(str.ToArray());
405                         WriteZeros(NumToAlign((uint)str.Position,fileAlign));
406                 }
407
408                 internal void SetEntryPoint(uint entryPoint) 
409                 {
410                         entryPointToken = entryPoint;
411                 }
412
413                 internal void AddInitData(DataConstant cVal) 
414                 {
415                         if (sdata == null) {                    
416                                 sdata = new Section(sdataName,0xC0000040);   // IMAGE_SCN_CNT  INITIALIZED_DATA, READ, WRITE
417                                 data = new ArrayList(); 
418                         }
419                         data.Add(cVal);
420                         cVal.DataOffset = sdata.Tide();
421                         sdata.IncTide(cVal.GetSize());
422                 }
423
424                 internal void WriteZeros(uint numZeros) 
425                 {
426                         for (int i=0; i < numZeros; i++) {
427                                 Write((byte)0);
428                         }
429                 }
430
431                 internal void WritePEHeader() 
432                 {
433                         Write((ushort)0x014C);  // Machine - always 0x14C for Managed PE Files (allow others??)
434                         Write((ushort)numSections);
435                         Write(dateStamp);
436                         WriteZeros(8); // Pointer to Symbol Table and Number of Symbols (always zero for ECMA CLI files)
437                         Write((ushort)0x00E0);  // Size of Optional Header
438                         Write(characteristics);
439                         // PE Optional Header
440                         Write((ushort)0x010B);   // Magic
441                         Write((byte)0x6);        // LMajor pure-IL = 6   C++ = 7
442                         Write((byte)0x0);        // LMinor
443                         Write(text.Size());
444                         Write(initDataSize);
445                         Write(0);                // Check other sections here!!
446                         Write(text.RVA() + entryPointOffset);
447                         Write(text.RVA());
448                         uint dataBase = 0;
449                         if (sdata != null) dataBase = sdata.RVA();
450                         else if (rsrc != null) dataBase = rsrc.RVA();
451                         else dataBase = relocRVA;
452                         Write(dataBase);
453                         Write(ImageBase);
454                         Write(SectionAlignment);
455                         Write(fileAlign);
456                         Write((ushort)0x04);     // OS Major
457                         WriteZeros(6);                  // OS Minor, User Major, User Minor
458                         Write((ushort)0x04);     // SubSys Major
459                         WriteZeros(6);           // SybSys Minor, Reserved
460                         Write(imageSize);
461                         Write(headerSize);
462                         Write((int)0);           // File Checksum
463                         Write((ushort)subSys);
464                         Write((short)0);         // DLL Flags
465                         Write((uint)stackReserve);   // Stack Reserve Size
466                         Write((uint)0x1000);     // Stack Commit Size
467                         Write((uint)0x100000);   // Heap Reserve Size
468                         Write((uint)0x1000);     // Heap Commit Size
469                         Write(0);                // Loader Flags
470                         Write(0x10);             // Number of Data Directories
471                         WriteZeros(8);                  // Export Table
472                         Write(importTableOffset + text.RVA());
473                         Write(totalImportTableSize);
474                         WriteZeros(24);            // Resource, Exception and Certificate Tables
475                         Write(relocRVA);
476                         Write(relocTide);
477                         WriteZeros(48);            // Debug, Copyright, Global Ptr, TLS, Load Config and Bound Import Tables
478                         Write(text.RVA());         // IATRVA - IAT is at start of .text Section
479                         Write(IATSize);
480                         WriteZeros(8);             // Delay Import Descriptor
481                         Write(text.RVA()+IATSize); // CLIHeader immediately follows IAT
482                         Write(CLIHeaderSize);    
483                         WriteZeros(8);             // Reserved
484                 }
485
486                 internal void WriteRelocSectionHeader() 
487                 {
488                         Write(relocName.ToCharArray());
489                         Write(relocTide);
490                         Write(relocRVA);
491                         Write(relocSize);
492                         Write(relocOffset);
493                         WriteZeros(12);
494                         Write(relocFlags);
495                 }
496
497                 private void Align (MemoryStream str, int val) 
498                 {
499                         if ((str.Position % val) != 0) {
500                                 for (int i=val - (int)(str.Position % val); i > 0; i--) {
501                                         str.WriteByte(0);
502                                 }
503                         }
504                 }
505
506                 private uint Align(uint val, uint alignVal) 
507                 {
508                         if ((val % alignVal) != 0) {
509                                 val += alignVal - (val % alignVal);
510                         }
511                         return val;
512                 }
513
514                 private uint NumToAlign(uint val, uint alignVal) 
515                 {
516                         if ((val % alignVal) == 0) return 0;
517                         return alignVal - (val % alignVal);
518                 }
519
520                 internal void StringsIndex(uint ix) 
521                 {
522                         if (largeStrings) Write(ix);
523                         else Write((ushort)ix);
524                 }
525
526                 internal void GUIDIndex(uint ix) 
527                 {
528                         if (largeGUID) Write(ix);
529                         else Write((ushort)ix);
530                 }
531
532                 internal void USIndex(uint ix) 
533                 {
534                         if (largeUS) Write(ix);
535                         else Write((ushort)ix);
536                 }
537
538                 internal void BlobIndex(uint ix) 
539                 {
540                         if (largeBlob) Write(ix);
541                         else Write((ushort)ix);
542                 }
543
544                 internal void WriteIndex(MDTable tabIx,uint ix) 
545                 {
546                         if (metaData.LargeIx(tabIx)) Write(ix);
547                         else Write((ushort)ix);
548                 }
549
550                 internal void WriteCodedIndex(CIx code, MetaDataElement elem) 
551                 {
552                         metaData.WriteCodedIndex(code,elem,this);
553                 }
554
555                 internal void WriteCodeRVA(uint offs) 
556                 {
557                         Write(text.RVA() + offs);
558                 }
559
560                 internal void WriteDataRVA(uint offs) 
561                 {
562                         Write(sdata.RVA() + offs);
563                 }
564
565                 internal void Write3Bytes(uint val) 
566                 {
567                         byte b3 = (byte)((val & FileImage.iByteMask[2]) >> 16);
568                         byte b2 = (byte)((val & FileImage.iByteMask[1]) >> 8);;
569                         byte b1 = (byte)(val & FileImage.iByteMask[0]);
570                         Write(b1);
571                         Write(b2);
572                         Write(b3);
573                 }
574
575                 internal bool ReserveStrongNameSignatureSpace {
576                         get { return reserveStrongNameSignatureSpace; }
577                         set { reserveStrongNameSignatureSpace = value; }
578                 }
579
580         }
581
582         /**************************************************************************/  
583         /// <summary>
584         /// Base class for the PEFile (starting point)
585         /// </summary>
586         public class PEFile {
587
588                 private static readonly string mscorlibName = "mscorlib";
589                 private Module thisMod;
590                 private ClassDef moduleClass;
591                 private ArrayList classRefList = new ArrayList();
592                 private ArrayList classDefList = new ArrayList();
593                 private ArrayList resources = new ArrayList ();
594                 private Assembly thisAssembly;
595                 private static bool isMSCorlib;
596                 private int corFlags = 1;
597                 FileImage fileImage;
598                 MetaData metaData;
599
600                 /// <summary>
601                 /// Create a new PEFile.  Each PEFile is a module.
602                 /// </summary>
603                 /// <param name="name">module name, also used for the file name</param>
604                 /// <param name="isDLL">create a .dll or .exe file</param>
605                 /// <param name="hasAssembly">this file is an assembly and 
606                 /// will contain the assembly manifest.  The assembly name is the 
607                 /// same as the module name</param>
608                 public PEFile(string name, bool isDLL, bool hasAssembly)
609                         : this (name, null, isDLL, hasAssembly, null, null) 
610                 {
611                         // Console.WriteLine(Hex.Byte(0x12));
612                         // Console.WriteLine(Hex.Short(0x1234));
613                         // Console.WriteLine(Hex.Int(0x12345678));
614                 }
615
616                 /// <summary>
617                 /// Create a new PEFile.  Each PEFile is a module.
618                 /// </summary>
619                 /// <param name="name">module name, also used for the file name</param>
620                 /// <param name="isDLL">create a .dll or .exe file</param>
621                 /// <param name="hasAssembly">this file is an assembly and 
622                 /// will contain the assembly manifest.  The assembly name is the 
623                 /// same as the module name</param>
624                 /// <param name="outputDir">write the PEFile to this directory.  If this
625                 /// string is null then the output will be to the current directory</param>
626                 public PEFile(string name, bool isDLL, bool hasAssembly, string outputDir)
627                         : this (name, null, isDLL, hasAssembly, outputDir, null) 
628                 {
629                         // Console.WriteLine(Hex.Byte(0x12));
630                         // Console.WriteLine(Hex.Short(0x1234));
631                         // Console.WriteLine(Hex.Int(0x12345678));
632                 }
633
634                 /// <summary>
635                 /// Create a new PEFile
636                 /// </summary>
637                 /// <param name="name">module name</param>
638                 /// <param name="isDLL">create a .dll or .exe</param>
639                 /// <param name="hasAssembly">this PEfile is an assembly and
640                 /// will contain the assemly manifest.  The assembly name is the
641                 /// same as the module name</param>
642                 /// <param name="outStream">write the PEFile to this stream instead
643                 /// of to a new file</param>
644                 public PEFile(string name, bool isDLL, bool hasAssembly, Stream outStream)
645                         : this (name, null, isDLL, hasAssembly, null, outStream) 
646                 {
647                 }
648
649                 public PEFile(string name, string module_name, bool isDLL, bool hasAssembly, Stream outStream)
650                         : this (name, module_name, isDLL, hasAssembly, null, outStream) 
651                 {
652                 }  
653
654                 public PEFile(string name, string module_name, bool isDLL, bool hasAssembly, string outputDir, Stream outStream) 
655                 {
656                         SetName (name);
657                         string fname = module_name == null ? MakeFileName (outputDir, name, isDLL) : module_name;
658                         if (outStream == null)
659                                 fileImage = new FileImage (isDLL, fname);
660                         else  
661                                 fileImage = new FileImage (isDLL, outStream);
662
663                         InitPEFile (name, fname, hasAssembly);
664                 }
665
666                 private void SetName (string name)
667                 {
668                         if (name == "mscorlib")
669                                 isMSCorlib = true;
670                 }
671
672                 private void InitPEFile(string name, string fName, bool hasAssembly) 
673                 {
674                         metaData = fileImage.GetMetaData();
675                         thisMod = new Module(fName,metaData);
676                         if (hasAssembly) {
677                                 thisAssembly = new Assembly(name,metaData);
678                                 metaData.AddToTable(MDTable.Assembly,thisAssembly);      
679                         }
680                         moduleClass = AddClass(TypeAttr.Private,"","<Module>");
681                         moduleClass.SpecialNoSuper();
682                         metaData.AddToTable(MDTable.Module,thisMod);
683                 }
684
685                 internal static bool IsMSCorlib {
686                         get { return isMSCorlib; }
687                 }
688
689                 public ClassDef ModuleClass {
690                         get { return moduleClass; }
691                 }
692
693                 /// <summary>
694                 /// Set the subsystem (.subsystem) (Default is Windows Console mode)
695                 /// </summary>
696                 /// <param name="subS">subsystem value</param>
697                 public void SetSubSystem(SubSystem subS) 
698                 {
699                         fileImage.subSys = subS;
700                 }
701
702                 /// <summary>
703                 /// Set the flags (.corflags)
704                 /// </summary>
705                 /// <param name="flags">the flags value</param>
706                 public void SetCorFlags(int flags) 
707                 {
708                         corFlags = flags;
709                 }
710
711                 public void SetStackReserve (long stackReserve)
712                 {
713                         fileImage.stackReserve = stackReserve;
714                 }
715
716                 private string MakeFileName(string dirName, string name, bool isDLL) 
717                 {
718                         string result = "";
719                         if ((dirName != null) && (dirName.CompareTo("") != 0)) {
720                                 result = dirName;
721                                 if (!dirName.EndsWith("\\")) result += "\\";
722                         }
723                         result += name;
724
725                         // if (isDLL) result += ".dll";  else result += ".exe";
726
727                         return result;
728                 }
729
730                 /// <summary>
731                 /// Add an external assembly to this PEFile (.assembly extern)
732                 /// </summary>
733                 /// <param name="assemName">the external assembly name</param>
734                 /// <returns>a descriptor for this external assembly</returns>
735                 public AssemblyRef AddExternAssembly(string assemName) 
736                 {
737                         if (assemName.CompareTo(mscorlibName) == 0) return metaData.mscorlib;
738                         AssemblyRef anAssem = new AssemblyRef(metaData,assemName);
739                         metaData.AddToTable(MDTable.AssemblyRef,anAssem);
740                         // Console.WriteLine("Adding assembly " + assemName);
741                         return anAssem;
742                 }
743
744                 /// <summary>
745                 /// Add an external module to this PEFile (.module extern)
746                 /// </summary>
747                 /// <param name="name">the external module name</param>
748                 /// <returns>a descriptor for this external module</returns>
749                 public ModuleRef AddExternModule(string name) 
750                 {
751                         ModuleRef modRef = new ModuleRef(metaData,name);
752                         metaData.AddToTable(MDTable.ModuleRef,modRef);
753                         return modRef;
754                 }
755
756                 /// <summary>
757                 /// Add a "global" method to this module
758                 /// </summary>
759                 /// <param name="name">method name</param>
760                 /// <param name="retType">return type</param>
761                 /// <param name="pars">method parameters</param>
762                 /// <returns>a descriptor for this new "global" method</returns>
763                 public MethodDef AddMethod(string name, Type retType, Param[] pars) 
764                 {
765                         return moduleClass.AddMethod(name,retType,pars);
766                 }
767
768                 /// <summary>
769                 /// Add a "global" method to this module
770                 /// </summary>
771                 /// <param name="mAtts">method attributes</param>
772                 /// <param name="iAtts">method implementation attributes</param>
773                 /// <param name="name">method name</param>
774                 /// <param name="retType">return type</param>
775                 /// <param name="pars">method parameters</param>
776                 /// <returns>a descriptor for this new "global" method</returns>
777                 public MethodDef AddMethod(MethAttr mAtts, ImplAttr iAtts, string name, Type retType, Param[] pars) 
778                 {
779                         return moduleClass.AddMethod(mAtts,iAtts,name,retType,pars);
780                 }
781
782                 public MethodRef AddMethodToTypeSpec (Type item, string name, Type retType, Type[] pars) 
783                 {
784                         MethodRef meth = new MethodRef (item.GetTypeSpec (metaData), name, retType, pars, false, null);
785                         metaData.AddToTable (MDTable.MemberRef,meth);
786                         return meth;
787                 }
788
789                 public MethodRef AddVarArgMethodToTypeSpec (Type item, string name, Type retType,
790                                 Type[] pars, Type[] optPars) {
791                         MethodRef meth = new MethodRef(item.GetTypeSpec (metaData), name,retType,pars,true,optPars);
792                         metaData.AddToTable(MDTable.MemberRef,meth);
793                         return meth;
794                 }
795
796                 public FieldRef AddFieldToTypeSpec (Type item, string name, Type fType) 
797                 {
798                         FieldRef field = new FieldRef (item.GetTypeSpec (metaData), name,fType);
799                         metaData.AddToTable (MDTable.MemberRef,field);
800                         return field;
801                 }
802
803                 public void AddMethodSpec (Method m, GenericMethodSig g_sig)
804                 {
805                         MethodSpec ms = new MethodSpec (m, g_sig);
806                         metaData.AddToTable (MDTable.MethodSpec, ms);
807                 }
808
809                 /// <summary>
810                 /// Add a "global" field to this module
811                 /// </summary>
812                 /// <param name="name">field name</param>
813                 /// <param name="fType">field type</param>
814                 /// <returns>a descriptor for this new "global" field</returns>
815                 public FieldDef AddField(string name, Type fType) 
816                 {
817                         return moduleClass.AddField(name,fType);
818                 }
819
820                 /// <summary>
821                 /// Add a "global" field to this module
822                 /// </summary>
823                 /// <param name="attrSet">attributes of this field</param>
824                 /// <param name="name">field name</param>
825                 /// <param name="fType">field type</param>
826                 /// <returns>a descriptor for this new "global" field</returns>
827                 public FieldDef AddField(FieldAttr attrSet, string name, Type fType) 
828                 {
829                         return moduleClass.AddField(attrSet,name,fType);
830                 }
831
832                 /// <summary>
833                 /// Add a class to this module
834                 /// </summary>
835                 /// <param name="attrSet">attributes of this class</param>
836                 /// <param name="nsName">name space name</param>
837                 /// <param name="name">class name</param>
838                 /// <returns>a descriptor for this new class</returns>
839                 public ClassDef AddClass(TypeAttr attrSet, string nsName, string name) 
840                 {
841                         return AddClass (attrSet, nsName, name, null);
842                 }
843
844                 /// <summary>
845                 /// Add a class which extends System.ValueType to this module
846                 /// </summary>
847                 /// <param name="attrSet">attributes of this class</param>
848                 /// <param name="nsName">name space name</param>
849                 /// <param name="name">class name</param>
850                 /// <returns>a descriptor for this new class</returns>
851                 public ClassDef AddValueClass(TypeAttr attrSet, string nsName, string name, ValueClass vClass) 
852                 {
853                         ClassDef aClass = new ClassDef(attrSet,nsName,name,metaData);
854                         if (!ClassDef.IsValueType (nsName, name) && !ClassDef.IsEnum (nsName, name)) {
855                                 aClass.MakeValueClass(vClass);
856                         } else {
857                                 if (ClassDef.IsEnum (nsName, name))
858                                         aClass.SetSuper (metaData.mscorlib.ValueType ());
859                                 else
860                                         aClass.SetSuper (metaData.mscorlib.GetSpecialSystemClass (PrimitiveType.Object));
861
862                                 metaData.mscorlib.SetSpecialSystemClass (nsName, name, aClass);
863                         }
864                         aClass.SetTypeIndex (PrimitiveType.ValueType.GetTypeIndex ());
865                         metaData.AddToTable(MDTable.TypeDef,aClass);
866                         return aClass;
867                 }
868
869                 /// <summary>
870                 /// Add a class to this module
871                 /// </summary>
872                 /// <param name="attrSet">attributes of this class</param>
873                 /// <param name="nsName">name space name</param>
874                 /// <param name="name">class name</param>
875                 /// <param name="superType">super type of this class (extends)</param>
876                 /// <returns>a descriptor for this new class</returns>
877                 public ClassDef AddClass(TypeAttr attrSet, string nsName, string name, Class superType) 
878                 {
879                         ClassDef aClass = new ClassDef(attrSet,nsName,name,metaData);
880                         if (superType != null)
881                                 aClass.SetSuper(superType);
882                         if (PEFile.IsMSCorlib)
883                                 metaData.mscorlib.SetSpecialSystemClass (nsName, name, aClass);
884                         metaData.AddToTable(MDTable.TypeDef,aClass);
885                         return aClass;
886                 }
887
888                 public FileRef AddFile(string fName, byte[] hashBytes, bool hasMetaData, bool entryPoint) 
889                 {
890                         FileRef file = new FileRef(fName,hashBytes,hasMetaData,entryPoint,metaData);
891                         metaData.AddToTable(MDTable.File,file);
892                         return file;
893                 }
894
895                 /// <summary>
896                 /// Add a manifest resource to this PEFile NOT YET IMPLEMENTED
897                 /// </summary>
898                 /// <param name="mr"></param>
899                 public void AddManifestResource(ManifestResource mr) 
900                 {
901                         metaData.AddToTable(MDTable.ManifestResource,mr);
902                         resources.Add (mr);
903                         //mr.FixName(metaData);
904                 }
905
906                 public void AddCustomAttribute (Method meth, byte [] data, MetaDataElement element)
907                 {
908                         metaData.AddCustomAttribute (new CustomAttribute (element, meth, data));
909                 }
910
911                 public void AddDeclSecurity (SecurityAction sec_action, byte [] data, MetaDataElement element)
912                 {
913                         metaData.AddDeclSecurity (new DeclSecurity (element, (ushort) sec_action, data));
914                 }
915
916                 /// <summary>
917                 /// Add a managed resource from another assembly.
918                 /// </summary>
919                 /// <param name="resName">The name of the resource</param>
920                 /// <param name="assem">The assembly where the resource is</param>
921                 /// <param name="isPublic">Access for the resource</param>
922                 public void AddExternalManagedResource (string resName, AssemblyRef assem, uint flags) 
923                 {
924                         resources.Add (new ManifestResource (resName, flags, assem));
925                 }
926
927                 /// <summary>
928                 /// Add a managed resource from another assembly.
929                 /// </summary>
930                 /// <param name="mr"></param>
931                 /// <param name="isPublic"></param>
932                 public void AddExternalManagedResource (ManifestResource mr) 
933                 {
934                         resources.Add (new ManifestResource (mr));
935                 }
936                 /// <summary>
937                 /// Find a resource
938                 /// </summary>
939                 /// <param name="name">The name of the resource</param>
940                 /// <returns>The resource with the name "name" or null </returns>
941                 public ManifestResource GetResource (string name) 
942                 {
943                         for (int i = 0; i < resources.Count; i ++) {
944                                 if (((ManifestResource) resources [i]).Name == name)
945                                         return (ManifestResource) resources [i];
946                         }
947                         return null;
948                 }
949
950                 public ManifestResource [] GetResources() 
951                 {
952                         return (ManifestResource []) resources.ToArray (typeof (ManifestResource));
953                 }
954
955                 /// <summary>
956                 /// Write out the PEFile (the "bake" function)
957                 /// </summary>
958                 public void WritePEFile() { /* the "bake" function */
959                         fileImage.ReserveStrongNameSignatureSpace = thisAssembly.HasPublicKey;
960                         fileImage.MakeFile();
961                 }
962
963                 /// <summary>
964                 /// Get the descriptor of this module
965                 /// </summary>
966                 /// <returns>the descriptor for this module</returns>
967                 public Module GetThisModule() 
968                 {
969                         return thisMod;
970                 }
971
972                 /// <summary>
973                 /// Get the descriptor for this assembly.  The PEFile must have been
974                 /// created with hasAssembly = true
975                 /// </summary>
976                 /// <returns>the descriptor for this assembly</returns>
977                 public Assembly GetThisAssembly() 
978                 {
979                         return thisAssembly;
980                 }
981
982         }
983
984         /**************************************************************************/  
985         /// <summary>
986         /// Descriptor for a Section in a PEFile  eg .text, .sdata
987         /// </summary>
988         internal class Section {
989                 private static readonly uint relocPageSize = 4096;  // 4K pages for fixups
990
991                 char[] name; 
992                 uint offset = 0, tide = 0, size = 0, rva = 0, relocTide = 0;
993                 //uint relocOff = 0;
994                 uint flags = 0, padding = 0;
995                 uint[] relocs; 
996
997                 internal Section(string sName, uint sFlags) 
998                 {
999                         name = sName.ToCharArray();
1000                         flags = sFlags;
1001                 }
1002
1003                 internal uint Tide() { return tide; }
1004
1005                 internal void IncTide(uint incVal) { tide += incVal; }
1006
1007                 internal uint Padding() { return padding; }
1008
1009                 internal uint Size() { return size; }
1010
1011                 internal void SetSize(uint pad) 
1012                 {
1013                         padding = pad;
1014                         size = tide + padding;
1015                 }
1016
1017                 internal uint RVA() { return rva; }
1018
1019                 internal void SetRVA(uint rva) { this.rva = rva; }
1020
1021                 internal uint Offset() { return offset; }
1022
1023                 internal void SetOffset(uint offs) { offset = offs; }
1024
1025                 internal void DoBlock(BinaryWriter reloc, uint page, int start, int end) 
1026                 {
1027                         //Console.WriteLine("rva = " + rva + "  page = " + page);
1028                         reloc.Write(rva + page);
1029                         reloc.Write((uint)(((end-start+1)*2) + 8));
1030                         for (int j=start; j < end; j++) {
1031                                 //Console.WriteLine("reloc offset = " + relocs[j]);
1032                                 reloc.Write((ushort)((0x3 << 12) | (relocs[j] - page)));
1033                         }
1034                         reloc.Write((ushort)0);
1035                 }
1036
1037                 internal void DoRelocs(BinaryWriter reloc) 
1038                 {
1039                         if (relocTide > 0) {
1040                                 //relocOff = (uint)reloc.Seek(0,SeekOrigin.Current);
1041                                 uint block = (relocs[0]/relocPageSize + 1) * relocPageSize;
1042                                 int start = 0;
1043                                 for (int i=1; i < relocTide; i++) {
1044                                         if (relocs[i] >= block) {
1045                                                 DoBlock(reloc,block-relocPageSize,start,i);
1046                                                 start = i;
1047                                                 block = (relocs[i]/relocPageSize + 1) * relocPageSize;
1048                                         }
1049                                 }
1050                                 DoBlock(reloc,block-relocPageSize,start,(int)relocTide);
1051                         }
1052                 }
1053
1054                 internal void AddReloc(uint offs) 
1055                 {
1056                         int pos = 0;
1057                         if (relocs == null) {
1058                                 relocs = new uint[5];
1059                         } else {
1060                                 if (relocTide >= relocs.Length) {
1061                                         uint[] tmp = relocs;
1062                                         relocs = new uint[tmp.Length + 5];
1063                                         for (int i=0; i < relocTide; i++) {
1064                                                 relocs[i] = tmp[i];
1065                                         }
1066                                 }
1067                                 while ((pos < relocTide) && (relocs[pos] < offs)) pos++;
1068                                 for (int i=pos; i < relocTide; i++) {
1069                                         relocs[i+1] = relocs[i];
1070                                 }
1071                         }
1072                         relocs[pos] = offs;
1073                         relocTide++;    
1074                 }
1075
1076                 internal void WriteHeader(BinaryWriter output, uint relocRVA) 
1077                 {
1078                         output.Write(name);
1079                         output.Write(tide);
1080                         output.Write(rva);
1081                         output.Write(size);
1082                         output.Write(offset);
1083                         output.Write(0);
1084                         //output.Write(relocRVA + relocOff);
1085                         output.Write(0);
1086                         output.Write(0);
1087                         //output.Write((ushort)relocTide);
1088                         //output.Write((ushort)0);
1089                         output.Write(flags);
1090                 }
1091
1092         }
1093
1094         public class Hex {
1095                 readonly static char[] hexDigit = {'0','1','2','3','4','5','6','7',
1096                         '8','9','A','B','C','D','E','F'};
1097                 readonly static uint[] iByteMask = {0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000};
1098                 readonly static ulong[] lByteMask = {0x00000000000000FF, 0x000000000000FF00, 
1099                         0x0000000000FF0000, 0x00000000FF000000,
1100                         0x000000FF00000000, 0x0000FF0000000000,
1101                         0x00FF000000000000, 0xFF00000000000000 };
1102                 readonly static uint nibble0Mask = 0x0000000F;
1103                 readonly static uint nibble1Mask = 0x000000F0;
1104
1105                 public static String Byte(int b) 
1106                 {
1107                         char[] str = new char[2];
1108                         uint num = (uint)b;
1109                         uint b1 = num & nibble0Mask;
1110                         uint b2 = (num & nibble1Mask) >> 4;
1111                         str[0] = hexDigit[b2];
1112                         str[1] = hexDigit[b1];
1113                         return new String(str);
1114                 }
1115
1116                 public static String Short(int b) 
1117                 {
1118                         char[] str = new char[4];
1119                         uint num1 = (uint)b & iByteMask[0];
1120                         uint num2 = ((uint)b & iByteMask[1]) >> 8;
1121                         uint b1 = num1 & nibble0Mask;
1122                         uint b2 = (num1 & nibble1Mask) >> 4;
1123                         uint b3 = num2 & nibble0Mask;
1124                         uint b4 = (num2 & nibble1Mask) >> 4;
1125                         str[0] = hexDigit[b4];
1126                         str[1] = hexDigit[b3];
1127                         str[2] = hexDigit[b2];
1128                         str[3] = hexDigit[b1];
1129                         return new String(str);
1130                 }
1131
1132                 public static String Int(int val) 
1133                 {
1134                         char[] str = new char[8];
1135                         uint num = (uint)val;
1136                         int strIx = 7;
1137                         for (int i=0; i < iByteMask.Length; i++) {
1138                                 uint b = num & iByteMask[i];
1139                                 b >>= (i*8);
1140                                 uint b1 = b & nibble0Mask;
1141                                 uint b2 = (b & nibble1Mask) >> 4;
1142                                 str[strIx--] = hexDigit[b1];
1143                                 str[strIx--] = hexDigit[b2];
1144                         }
1145                         return new String(str);
1146                 }
1147
1148                 public static String Int(uint num) 
1149                 {
1150                         char[] str = new char[8];
1151                         int strIx = 7;
1152                         for (int i=0; i < iByteMask.Length; i++) {
1153                                 uint b = num & iByteMask[i];
1154                                 b >>= (i*8);
1155                                 uint b1 = b & nibble0Mask;
1156                                 uint b2 = (b & nibble1Mask) >> 4;
1157                                 str[strIx--] = hexDigit[b1];
1158                                 str[strIx--] = hexDigit[b2];
1159                         }
1160                         return new String(str);
1161                 }
1162
1163                 public static String Long(long lnum) 
1164                 {
1165                         ulong num = (ulong)lnum;
1166                         char[] str = new char[16];
1167                         int strIx = 15;
1168                         for (int i=0; i < lByteMask.Length; i++) {
1169                                 ulong b = num & lByteMask[i];
1170                                 b >>= (i*8);
1171                                 ulong b1 = b & nibble0Mask;
1172                                 ulong b2 = (b & nibble1Mask) >> 4;
1173                                 str[strIx--] = hexDigit[b1];
1174                                 str[strIx--] = hexDigit[b2];
1175                         }
1176                         return new String(str);
1177                 }
1178         }
1179
1180         /// <summary>
1181         /// Error for invalid PE file
1182         /// </summary>
1183         public class PEFileException : System.Exception {
1184                 public PEFileException(string msg) : base("Error in PE File:  " + msg) { }
1185         }
1186
1187         public class NotYetImplementedException : System.Exception  {
1188                 public NotYetImplementedException(string msg) : base(msg + " Not Yet Implemented") { }
1189         }
1190
1191         public class TypeSignatureException : System.Exception {
1192                 public TypeSignatureException(string msg) : base(msg) { }
1193         }
1194
1195 }