a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
278 lines
8.5 KiB
C#
278 lines
8.5 KiB
C#
//
|
|
// StructureReader.cs
|
|
//
|
|
// Author:
|
|
// Jb Evain (jbevain@gmail.com)
|
|
//
|
|
// (C) 2005 Jb Evain
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
namespace Mono.Cecil {
|
|
|
|
using System;
|
|
using System.IO;
|
|
|
|
using Mono.Cecil.Binary;
|
|
using Mono.Cecil.Metadata;
|
|
|
|
internal sealed class StructureReader : BaseStructureVisitor {
|
|
|
|
ImageReader m_ir;
|
|
Image m_img;
|
|
bool m_manifestOnly;
|
|
AssemblyDefinition m_asmDef;
|
|
ModuleDefinition m_module;
|
|
MetadataStreamCollection m_streams;
|
|
TablesHeap m_tHeap;
|
|
MetadataTableReader m_tableReader;
|
|
|
|
public bool ManifestOnly {
|
|
get { return m_manifestOnly; }
|
|
}
|
|
|
|
public ImageReader ImageReader {
|
|
get { return m_ir; }
|
|
}
|
|
|
|
public Image Image {
|
|
get { return m_img; }
|
|
}
|
|
|
|
public StructureReader (ImageReader ir)
|
|
{
|
|
if (ir.Image.CLIHeader == null)
|
|
throw new ImageFormatException ("The image is not a managed assembly");
|
|
|
|
m_ir = ir;
|
|
m_img = ir.Image;
|
|
m_streams = m_img.MetadataRoot.Streams;
|
|
m_tHeap = m_streams.TablesHeap;
|
|
m_tableReader = ir.MetadataReader.TableReader;
|
|
}
|
|
|
|
public StructureReader (ImageReader ir, bool manifestOnly) : this (ir)
|
|
{
|
|
m_manifestOnly = manifestOnly;
|
|
}
|
|
|
|
byte [] ReadBlob (uint pointer)
|
|
{
|
|
if (pointer == 0)
|
|
return new byte [0];
|
|
|
|
return m_streams.BlobHeap.Read (pointer);
|
|
}
|
|
|
|
string ReadString (uint pointer)
|
|
{
|
|
return m_streams.StringsHeap [pointer];
|
|
}
|
|
|
|
public override void VisitAssemblyDefinition (AssemblyDefinition asm)
|
|
{
|
|
if (!m_tHeap.HasTable (AssemblyTable.RId))
|
|
throw new ReflectionException ("No assembly manifest");
|
|
|
|
asm.MetadataToken = new MetadataToken (TokenType.Assembly, 1);
|
|
m_asmDef = asm;
|
|
|
|
switch (m_img.MetadataRoot.Header.Version) {
|
|
case "v1.0.3705" :
|
|
asm.Runtime = TargetRuntime.NET_1_0;
|
|
break;
|
|
case "v1.1.4322" :
|
|
asm.Runtime = TargetRuntime.NET_1_1;
|
|
break;
|
|
case "v2.0.50727":
|
|
asm.Runtime = TargetRuntime.NET_2_0;
|
|
break;
|
|
case "v4.0.30319" :
|
|
asm.Runtime = TargetRuntime.NET_4_0;
|
|
break;
|
|
}
|
|
|
|
if ((m_img.PEFileHeader.Characteristics & ImageCharacteristics.Dll) != 0)
|
|
asm.Kind = AssemblyKind.Dll;
|
|
else if (m_img.PEOptionalHeader.NTSpecificFields.SubSystem == SubSystem.WindowsGui ||
|
|
m_img.PEOptionalHeader.NTSpecificFields.SubSystem == SubSystem.WindowsCeGui)
|
|
asm.Kind = AssemblyKind.Windows;
|
|
else
|
|
asm.Kind = AssemblyKind.Console;
|
|
}
|
|
|
|
public override void VisitAssemblyNameDefinition (AssemblyNameDefinition name)
|
|
{
|
|
AssemblyTable atable = m_tableReader.GetAssemblyTable ();
|
|
AssemblyRow arow = atable [0];
|
|
name.Name = ReadString (arow.Name);
|
|
name.Flags = arow.Flags;
|
|
name.PublicKey = ReadBlob (arow.PublicKey);
|
|
|
|
name.Culture = ReadString (arow.Culture);
|
|
name.Version = new Version (
|
|
arow.MajorVersion, arow.MinorVersion,
|
|
arow.BuildNumber, arow.RevisionNumber);
|
|
name.HashAlgorithm = arow.HashAlgId;
|
|
name.MetadataToken = new MetadataToken (TokenType.Assembly, 1);
|
|
}
|
|
|
|
public override void VisitAssemblyNameReferenceCollection (AssemblyNameReferenceCollection names)
|
|
{
|
|
if (!m_tHeap.HasTable (AssemblyRefTable.RId))
|
|
return;
|
|
|
|
AssemblyRefTable arTable = m_tableReader.GetAssemblyRefTable ();
|
|
for (int i = 0; i < arTable.Rows.Count; i++) {
|
|
AssemblyRefRow arRow = arTable [i];
|
|
AssemblyNameReference aname = new AssemblyNameReference (
|
|
ReadString (arRow.Name),
|
|
ReadString (arRow.Culture),
|
|
new Version (arRow.MajorVersion, arRow.MinorVersion,
|
|
arRow.BuildNumber, arRow.RevisionNumber));
|
|
aname.PublicKeyToken = ReadBlob (arRow.PublicKeyOrToken);
|
|
aname.Hash = ReadBlob (arRow.HashValue);
|
|
aname.Flags = arRow.Flags;
|
|
aname.MetadataToken = new MetadataToken (TokenType.AssemblyRef, (uint) i + 1);
|
|
names.Add (aname);
|
|
}
|
|
}
|
|
|
|
public override void VisitResourceCollection (ResourceCollection resources)
|
|
{
|
|
if (!m_tHeap.HasTable (ManifestResourceTable.RId))
|
|
return;
|
|
|
|
ManifestResourceTable mrTable = m_tableReader.GetManifestResourceTable ();
|
|
FileTable fTable = m_tableReader.GetFileTable ();
|
|
|
|
for (int i = 0; i < mrTable.Rows.Count; i++) {
|
|
ManifestResourceRow mrRow = mrTable [i];
|
|
if (mrRow.Implementation.RID == 0) {
|
|
EmbeddedResource eres = new EmbeddedResource (
|
|
ReadString (mrRow.Name), mrRow.Flags);
|
|
|
|
BinaryReader br = m_ir.MetadataReader.GetDataReader (
|
|
m_img.CLIHeader.Resources.VirtualAddress);
|
|
br.BaseStream.Position += mrRow.Offset;
|
|
|
|
eres.Data = br.ReadBytes (br.ReadInt32 ());
|
|
|
|
resources.Add (eres);
|
|
continue;
|
|
}
|
|
|
|
switch (mrRow.Implementation.TokenType) {
|
|
case TokenType.File :
|
|
FileRow fRow = fTable [(int) mrRow.Implementation.RID - 1];
|
|
LinkedResource lres = new LinkedResource (
|
|
ReadString (mrRow.Name), mrRow.Flags,
|
|
ReadString (fRow.Name));
|
|
lres.Hash = ReadBlob (fRow.HashValue);
|
|
resources.Add (lres);
|
|
break;
|
|
case TokenType.AssemblyRef :
|
|
AssemblyNameReference asm =
|
|
m_module.AssemblyReferences [(int) mrRow.Implementation.RID - 1];
|
|
AssemblyLinkedResource alr = new AssemblyLinkedResource (
|
|
ReadString (mrRow.Name),
|
|
mrRow.Flags, asm);
|
|
resources.Add (alr);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void VisitModuleDefinitionCollection (ModuleDefinitionCollection modules)
|
|
{
|
|
ModuleTable mt = m_tableReader.GetModuleTable ();
|
|
if (mt == null || mt.Rows.Count != 1)
|
|
throw new ReflectionException ("Can not read main module");
|
|
|
|
ModuleRow mr = mt [0];
|
|
string name = ReadString (mr.Name);
|
|
ModuleDefinition main = new ModuleDefinition (name, m_asmDef, this, true);
|
|
main.Mvid = m_streams.GuidHeap [mr.Mvid];
|
|
main.MetadataToken = new MetadataToken (TokenType.Module, 1);
|
|
modules.Add (main);
|
|
m_module = main;
|
|
m_module.Accept (this);
|
|
|
|
FileTable ftable = m_tableReader.GetFileTable ();
|
|
if (ftable == null || ftable.Rows.Count == 0)
|
|
return;
|
|
|
|
foreach (FileRow frow in ftable.Rows) {
|
|
if (frow.Flags != FileAttributes.ContainsMetaData)
|
|
continue;
|
|
|
|
name = ReadString (frow.Name);
|
|
FileInfo location = new FileInfo (
|
|
m_img.FileInformation != null ? Path.Combine (m_img.FileInformation.DirectoryName, name) : name);
|
|
if (!File.Exists (location.FullName))
|
|
throw new FileNotFoundException ("Module not found : " + name);
|
|
|
|
try {
|
|
ImageReader module = ImageReader.Read (location.FullName);
|
|
mt = module.Image.MetadataRoot.Streams.TablesHeap [ModuleTable.RId] as ModuleTable;
|
|
if (mt == null || mt.Rows.Count != 1)
|
|
throw new ReflectionException ("Can not read module : " + name);
|
|
|
|
mr = mt [0];
|
|
ModuleDefinition modext = new ModuleDefinition (name, m_asmDef,
|
|
new StructureReader (module, m_manifestOnly), false);
|
|
modext.Mvid = module.Image.MetadataRoot.Streams.GuidHeap [mr.Mvid];
|
|
|
|
modules.Add (modext);
|
|
modext.Accept (this);
|
|
} catch (ReflectionException) {
|
|
throw;
|
|
} catch (Exception e) {
|
|
throw new ReflectionException ("Can not read module : " + name, e);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void VisitModuleReferenceCollection (ModuleReferenceCollection modules)
|
|
{
|
|
if (!m_tHeap.HasTable (ModuleRefTable.RId))
|
|
return;
|
|
|
|
ModuleRefTable mrTable = m_tableReader.GetModuleRefTable ();
|
|
for (int i = 0; i < mrTable.Rows.Count; i++) {
|
|
ModuleRefRow mrRow = mrTable [i];
|
|
ModuleReference mod = new ModuleReference (ReadString (mrRow.Name));
|
|
mod.MetadataToken = MetadataToken.FromMetadataRow (TokenType.ModuleRef, i);
|
|
modules.Add (mod);
|
|
}
|
|
}
|
|
|
|
public override void TerminateAssemblyDefinition (AssemblyDefinition asm)
|
|
{
|
|
if (m_manifestOnly)
|
|
return;
|
|
|
|
foreach (ModuleDefinition mod in asm.Modules)
|
|
mod.Controller.Reader.VisitModuleDefinition (mod);
|
|
}
|
|
}
|
|
}
|