2010-06-03 Jb Evain <jbevain@novell.com>
[mcs.git] / nunit24 / NUnitCore / core / AssemblyReader.cs
blobef854991022176a9ef5f7cb73f6b2919e22a996b
1 // ****************************************************************
2 // Copyright 2007, Charlie Poole
3 // This is free software licensed under the NUnit license. You may
4 // obtain a copy of the license at http://nunit.org/?p=license&r=2.4
5 // ****************************************************************
6 using System;
7 using System.Reflection;
8 using System.Text;
9 using System.IO;
11 namespace NUnit.Core
13 /// <summary>
14 /// AssemblyReader knows how to find various things in an assembly header
15 /// </summary>
16 public class AssemblyReader : IDisposable
18 private string assemblyPath;
19 private BinaryReader rdr;
20 private FileStream fs;
22 UInt16 dos_magic = 0xffff;
23 uint pe_signature = 0xffffffff;
24 UInt16 numDataSections;
25 UInt16 optionalHeaderSize;
27 private uint peHeader = 0;
28 private uint fileHeader = 0;
29 private uint optionalHeader = 0;
30 private uint dataDirectory = 0;
31 private uint dataSections = 0;
33 private struct Section
35 public uint virtualAddress;
36 public uint virtualSize;
37 public uint fileOffset;
40 private Section[] sections;
42 public AssemblyReader( string assemblyPath )
44 this.assemblyPath = assemblyPath;
45 CalcHeaderOffsets();
48 public AssemblyReader( Assembly assembly )
50 this.assemblyPath = TestFixtureBuilder.GetAssemblyPath( assembly );
51 CalcHeaderOffsets();
54 private void CalcHeaderOffsets()
56 this.fs = new FileStream( assemblyPath, FileMode.Open, FileAccess.Read );
57 this.rdr = new BinaryReader( fs );
58 dos_magic = rdr.ReadUInt16();
59 if ( dos_magic == 0x5a4d )
61 fs.Position = 0x3c;
62 peHeader = rdr.ReadUInt32();
63 fileHeader = peHeader + 4;
64 optionalHeader = fileHeader + 20;
65 dataDirectory = optionalHeader + 96;
66 // dotNetDirectoryEntry = dataDirectory + 14 * 8;
68 fs.Position = peHeader;
69 pe_signature = rdr.ReadUInt32();
70 rdr.ReadUInt16(); // machine
71 numDataSections = rdr.ReadUInt16();
72 fs.Position += 12;
73 optionalHeaderSize = rdr.ReadUInt16();
74 dataSections = optionalHeader + optionalHeaderSize;
76 sections = new Section[numDataSections];
77 fs.Position = dataSections;
78 for( int i = 0; i < numDataSections; i++ )
80 fs.Position += 8;
81 sections[i].virtualSize = rdr.ReadUInt32();
82 sections[i].virtualAddress = rdr.ReadUInt32();
83 uint rawDataSize = rdr.ReadUInt32();
84 sections[i].fileOffset = rdr.ReadUInt32();
85 if ( sections[i].virtualSize == 0 )
86 sections[i].virtualSize = rawDataSize;
88 fs.Position += 16;
93 private uint DataDirectoryRva( int n )
95 fs.Position = dataDirectory + n * 8;
96 return rdr.ReadUInt32();
99 private uint RvaToLfa( uint rva )
101 for( int i = 0; i < numDataSections; i++ )
102 if ( rva >= sections[i].virtualAddress && rva < sections[i].virtualAddress + sections[i].virtualSize )
103 return rva - sections[i].virtualAddress + sections[i].fileOffset;
105 return 0;
108 public string AssemblyPath
110 get { return assemblyPath; }
113 public bool IsValidPeFile
115 get { return dos_magic == 0x5a4d && pe_signature == 0x00004550; }
118 public bool IsDotNetFile
120 get { return IsValidPeFile && DataDirectoryRva(14) != 0; }
123 public string ImageRuntimeVersion
125 get
127 string runtimeVersion = string.Empty;
129 uint rva = DataDirectoryRva(14);
130 if ( rva != 0 )
132 fs.Position = RvaToLfa( rva ) + 8;
133 uint metadata = rdr.ReadUInt32();
134 fs.Position = RvaToLfa( metadata );
135 if ( rdr.ReadUInt32() == 0x424a5342 )
137 // Copy string representing runtime version
138 fs.Position += 12;
139 StringBuilder sb = new StringBuilder();
140 char c;
141 while ((c = rdr.ReadChar())!= '\0')
142 sb.Append(c);
144 if (sb[0] == 'v') // Last sanity check
145 runtimeVersion = sb.ToString();
147 // Could do fixups here for bad values in older files
148 // like 1.x86, 1.build, etc. But we are only using
149 // the major version anyway
153 return runtimeVersion;
157 public void Dispose()
159 if ( fs != null )
160 fs.Close();
161 if ( rdr != null )
162 rdr.Close();
164 fs = null;
165 rdr = null;