/* * PERWAPI - An API for Reading and Writing PE Files * * Copyright (c) Diane Corney, Queensland University of Technology, 2004. * * This program is free software; you can redistribute it and/or modify * it under the terms of the PERWAPI Copyright as included with this * distribution in the file PERWAPIcopyright.rtf. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY as is explained in the copyright notice. * * The author may be contacted at d.corney@qut.edu.au * * Version Date: 26/01/07 */ using System; using System.IO; using System.Collections; using System.Security.Cryptography; namespace QUT.PERWAPI { /**************************************************************************/ /// /// Descriptor for a class/interface declared in another module of THIS /// assembly, or in another assembly. /// public class ClassRef : ClassDesc { protected ReferenceScope scope; protected uint resScopeIx = 0; internal ExternClass externClass; internal ClassDef defOf; internal bool readAsDef = false; /*-------------------- Constructors ---------------------------------*/ internal ClassRef(ReferenceScope scope, string nsName, string name) : base(nsName, name) { this.scope = scope; tabIx = MDTable.TypeRef; } internal ClassRef(uint scopeIx, string nsName, string name) : base(nsName, name) { resScopeIx = scopeIx; tabIx = MDTable.TypeRef; } internal static ClassRef ReadDef(PEReader buff, ReferenceScope resScope, uint index) { uint junk = buff.ReadUInt32(); string cName = buff.GetString(); string nsName = buff.GetString(); ClassRef newClass = (ClassRef)resScope.GetExistingClass(nsName, cName); if (newClass == null) { newClass = new ClassRef(resScope, nsName, cName); resScope.AddToClassList(newClass); } newClass.readAsDef = true; newClass.Row = index; junk = buff.GetCodedIndex(CIx.TypeDefOrRef); newClass.fieldIx = buff.GetIndex(MDTable.Field); newClass.methodIx = buff.GetIndex(MDTable.Method); return newClass; } internal static void Read(PEReader buff, TableRow[] typeRefs, bool resolve) { for (uint i = 0; i < typeRefs.Length; i++) { uint resScopeIx = buff.GetCodedIndex(CIx.ResolutionScope); string name = buff.GetString(); string nameSpace = buff.GetString(); if (buff.CodedTable(CIx.ResolutionScope, resScopeIx) == MDTable.TypeRef) typeRefs[i] = new NestedClassRef(resScopeIx, nameSpace, name); else typeRefs[i] = new ClassRef(resScopeIx, nameSpace, name); typeRefs[i].Row = i + 1; } if (resolve) { for (int i = 0; i < typeRefs.Length; i++) { ((ClassRef)typeRefs[i]).ResolveParent(buff, false); } } } internal static ClassRef ReadClass(PEReader buff, ReferenceScope resScope) { uint resScopeIx = buff.GetCodedIndex(CIx.ResolutionScope); string name = buff.GetString(); string nameSpace = buff.GetString(); ClassRef newClass = (ClassRef)resScope.GetExistingClass(nameSpace, name); if (newClass == null) newClass = new ClassRef(resScope, nameSpace, name); return newClass; } internal virtual void ResolveParent(PEReader buff, bool isExtern) { CIx cIx = CIx.ResolutionScope; if (isExtern) cIx = CIx.Implementation; if (scope != null) return; MetaDataElement parentScope = buff.GetCodedElement(cIx, resScopeIx); if (parentScope is Module) { // special code for glitch in Everett ilasm ClassDef newDef = new ClassDef((PEFile)parentScope, 0, nameSpace, name); ((Module)parentScope).AddToClassList(newDef); buff.InsertInTable(MDTable.TypeRef, Row, newDef); } else { scope = (ReferenceScope)buff.GetCodedElement(cIx, resScopeIx); ClassRef existing = (ClassRef)scope.GetExistingClass(nameSpace, name); if (existing == null) { scope.AddToClassList(this); } else { if (isExtern) buff.InsertInTable(MDTable.ExportedType, Row, existing); else buff.InsertInTable(MDTable.TypeRef, Row, existing); } } } /*------------------------- public set and get methods --------------------------*/ /// /// Add a method to this class /// /// method name /// return type /// parameter types /// a descriptor for this method public MethodRef AddMethod(string name, Type retType, Type[] pars) { System.Diagnostics.Debug.Assert(retType != null); MethodRef meth = (MethodRef)GetMethodDesc(name, pars); if (meth != null) DescriptorError(meth); meth = new MethodRef(this, name, retType, pars); methods.Add(meth); return meth; } /// /// Add a method to this class /// /// method name /// generic parameters /// return type /// parameter types /// a descriptor for this method public MethodRef AddMethod(string name, GenericParam[] genPars, Type retType, Type[] pars) { MethodRef meth = AddMethod(name, retType, pars); if ((genPars != null) && (genPars.Length > 0)) { for (int i = 0; i < genPars.Length; i++) { genPars[i].SetMethParam(meth, i); } meth.SetGenericParams(genPars); } return meth; } /// /// Add a method to this class /// /// method name /// return type /// parameter types /// optional parameter types /// a descriptor for this method public MethodRef AddVarArgMethod(string name, Type retType, Type[] pars, Type[] optPars) { MethodRef meth = AddMethod(name, retType, pars); meth.MakeVarArgMethod(null, optPars); return meth; } /// /// Add a method to this class /// /// method name /// generic parameters /// return type /// parameter types /// optional parameter types /// a descriptor for this method public MethodRef AddVarArgMethod(string name, GenericParam[] genPars, Type retType, Type[] pars, Type[] optPars) { MethodRef meth = AddMethod(name, genPars, retType, pars); meth.MakeVarArgMethod(null, optPars); return meth; } /// /// Get the method "name" for this class /// /// The method name /// Descriptor for the method "name" for this class public MethodRef GetMethod(string name) { return (MethodRef)GetMethodDesc(name); } /// /// Get the method "name(parTypes)" for this class /// /// Method name /// Method signature /// Descriptor for "name(parTypes)" public MethodRef GetMethod(string name, Type[] parTypes) { return (MethodRef)GetMethodDesc(name, parTypes); } /// /// Get the vararg method "name(parTypes,optTypes)" for this class /// /// Method name /// Method parameter types /// Optional parameter types /// Descriptor for "name(parTypes,optTypes)" public MethodRef GetMethod(string name, Type[] parTypes, Type[] optTypes) { return (MethodRef)GetMethodDesc(name, parTypes, optTypes); } /// /// Get the descriptors for the all methods name "name" for this class /// /// Method name /// List of methods called "name" public MethodRef[] GetMethods(string name) { ArrayList meths = GetMeths(name); return (MethodRef[])meths.ToArray(typeof(MethodRef)); } /// /// Get all the methods for this class /// /// List of methods for this class public MethodRef[] GetMethods() { return (MethodRef[])methods.ToArray(typeof(MethodRef)); } /// /// Add a field to this class /// /// field name /// field type /// a descriptor for this field public FieldRef AddField(string name, Type fType) { FieldRef fld = (FieldRef)FindField(name); if (fld != null) DescriptorError(fld); fld = new FieldRef(this, name, fType); fields.Add(fld); return fld; } /// /// Get the descriptor for the field "name" for this class /// /// Field name /// Descriptor for field "name" public FieldRef GetField(string name) { return (FieldRef)FindField(name); } /// /// Get all the fields for this class /// /// List of fields for this class public FieldRef[] GetFields() { return (FieldRef[])fields.ToArray(typeof(FieldRef)); } /// /// Add a nested class to this class /// /// Nested class name /// Descriptor for the nested class "name" public NestedClassRef AddNestedClass(string name) { NestedClassRef nestedClass = (NestedClassRef)GetNested(name); if (nestedClass != null) DescriptorError(nestedClass); nestedClass = new NestedClassRef(this, name); AddToClassList(nestedClass); return nestedClass; } /// /// Get the nested class "name" /// /// Nestec class name /// Descriptor for the nested class "name" public NestedClassRef GetNestedClass(string name) { // check nested names return (NestedClassRef)GetNested(name); } /// /// Make this Class exported from an Assembly (ie. add to ExportedType table) /// public void MakeExported() { if ((scope == null) || (!(scope is ModuleRef))) throw new Exception("Module not set for class to be exported"); ((ModuleRef)scope).AddToExportedClassList(this); } /// /// Get the scope or "parent" of this ClassRef (either ModuleRef or AssemblyRef) /// /// Descriptor for the scope containing this class public virtual ReferenceScope GetScope() { return scope; } public override MetaDataElement GetParent() { return scope; } /*----------------------------- internal functions ------------------------------*/ internal void SetExternClass(ExternClass eClass) { externClass = eClass; } internal void SetScope(ReferenceScope scope) { this.scope = scope; } internal void AddField(FieldRef fld) { fields.Add(fld); fld.SetParent(this); } internal void AddMethod(MethodRef meth) { MethodRef m = (MethodRef)GetMethodDesc(meth.Name(), meth.GetParTypes()); if (m == null) { methods.Add(meth); meth.SetParent(this); } } /* internal FieldRef GetExistingField(string fName, uint tyIx, PEReader buff) { FieldRef existing = (FieldRef)FindField(fName); if (existing != null) { Type fType = buff.GetBlobType(tyIx); if (!fType.SameType(existing.GetFieldType())) throw new DescriptorException("Cannot have two fields (" + fName + ") for class " + name); } return existing; } */ /* internal MethodRef CheckForMethod(string mName, uint sigIx, PEReader buff) { int exIx = FindMeth(mName,0); if (exIx > -1) { MethSig mType = buff.ReadMethSig(sigIx); mType.name = mName; exIx = FindMeth(mType,0); if (exIx > -1) return (MethodRef)methods[exIx]; } return null; } */ internal override string ClassName() { string nameString = nameSpace + "." + name; if ((scope != null) && (scope is AssemblyRef)) nameString += (", " + ((AssemblyRef)scope).AssemblyString()); return nameString; } internal bool HasParent(uint tok) { return resScopeIx == tok; } internal override void BuildTables(MetaDataOut md) { if (!special) { md.AddToTable(MDTable.TypeRef, this); nameIx = md.AddToStringsHeap(name); nameSpaceIx = md.AddToStringsHeap(nameSpace); } scope.BuildMDTables(md); } internal override void BuildCILInfo(CILWriter output) { if (!special && scope != null) { output.AddRef(scope); } } internal static uint Size(MetaData md) { return md.CodedIndexSize(CIx.ResolutionScope) + 2 * md.StringsIndexSize(); } internal override void Write(PEWriter output) { output.WriteCodedIndex(CIx.ResolutionScope, scope); output.StringsIndex(nameIx); output.StringsIndex(nameSpaceIx); } internal override void WriteType(CILWriter output) { if ((nameSpace == null) || (nameSpace == "")) { output.Write("[" + scope.Name() + "]" + name); } else { output.Write("[" + scope.Name() + "]" + nameSpace + "." + name); } } internal override sealed uint TypeDefOrRefToken() { uint cIx = Row; cIx = (cIx << 2) | 0x1; return cIx; } 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; } internal override string NameString() { string nameString = ""; if (scope != null) nameString = "[" + scope.NameString() + "]"; if ((nameSpace != null) && (nameSpace.Length > 0)) nameString += nameSpace + "."; nameString += name; return nameString; } } /**************************************************************************/ /// /// Descriptor for a reference to a Nested Class /// public class NestedClassRef : ClassRef { ClassRef parent; internal uint parentIx = 0; /*-------------------- Constructors ---------------------------------*/ internal NestedClassRef(ClassRef parent, string name) : base(parent.GetScope(), "", name) { this.parent = parent; } internal NestedClassRef(uint scopeIx, string nsName, string name) : base(scopeIx, nsName, name) { } internal NestedClassRef(ReferenceScope scope, string nsName, string name) : base(scope, nsName, name) { } internal override void ResolveParent(PEReader buff, bool isExtern) { if (parent != null) return; CIx cIx = CIx.ResolutionScope; if (isExtern) cIx = CIx.Implementation; parent = (ClassRef)buff.GetCodedElement(cIx, resScopeIx); parent.ResolveParent(buff, isExtern); parent = (ClassRef)buff.GetCodedElement(cIx, resScopeIx); if (parent == null) return; NestedClassRef existing = parent.GetNestedClass(name); if (existing == null) { scope = parent.GetScope(); parent.AddToClassList(this); } else if (isExtern) buff.InsertInTable(MDTable.ExportedType, Row, existing); else buff.InsertInTable(MDTable.TypeRef, Row, existing); } /// /// Get the scope of this ClassRef (either ModuleRef or AssemblyRef) /// /// Descriptor for the scope containing this class public override ReferenceScope GetScope() { if (scope == null) scope = parent.GetScope(); return scope; } /// /// Get the parent (enclosing ClassRef) for this nested class /// /// Enclosing class descriptor public ClassRef GetParentClass() { return parent; } internal void SetParent(ClassRef paren) { parent = paren; } internal override string ClassName() { string nameString = name; if (parent != null) nameString = parent.TypeName() + "+" + name; if ((scope != null) && (scope is AssemblyRef)) nameString += (", " + ((AssemblyRef)scope).AssemblyString()); return nameString; } internal override string NameString() { if (parent == null) return name; return parent.NameString() + "+" + name; } internal sealed override void BuildTables(MetaDataOut md) { if (!special) { md.AddToTable(MDTable.TypeRef, this); nameIx = md.AddToStringsHeap(name); nameSpaceIx = md.AddToStringsHeap(nameSpace); } parent.BuildMDTables(md); } internal sealed override void Write(PEWriter output) { output.WriteCodedIndex(CIx.ResolutionScope, parent); output.StringsIndex(nameIx); output.StringsIndex(nameSpaceIx); } } /**************************************************************************/ /// /// Descriptor for a class defined in System (mscorlib) /// internal class SystemClass : ClassRef { PrimitiveType elemType; internal bool added = false; internal SystemClass(AssemblyRef paren, PrimitiveType eType) : base(paren, "System", eType.GetName()) { elemType = eType; } // internal override sealed void AddTypeSpec(MetaDataOut md) { // elemType.AddTypeSpec(md); // if (typeSpec == null) typeSpec = (TypeSpec)elemType.GetTypeSpec(md); // return typeSpec; // } internal sealed override void TypeSig(MemoryStream str) { str.WriteByte(elemType.GetTypeIndex()); } internal override bool SameType(Type tstType) { if (tstType is SystemClass) return elemType == ((SystemClass)tstType).elemType; return elemType == tstType; } } }