/* * 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 { /**************************************************************************/ /// /// The base descriptor for a class /// public abstract class Class : Type { //protected int row = 0; protected string name, nameSpace; protected uint nameIx, nameSpaceIx; protected ArrayList nestedClasses = new ArrayList(); protected bool special = false; protected ArrayList fields = new ArrayList(); protected ArrayList methods = new ArrayList(); internal uint fieldIx = 0, methodIx = 0, fieldEndIx = 0, methodEndIx = 0; protected string[] fieldNames, methodNames; protected ArrayList genericParams = new ArrayList(); /*-------------------- Constructors ---------------------------------*/ internal Class() : base((byte)ElementType.Class) { } /*------------------------- public set and get methods --------------------------*/ public virtual void MakeValueClass() { typeIndex = (byte)ElementType.ValueType; } /// /// Get the name of this class /// /// class name public string Name() { return name; } /// /// Get the namespace that includes this class /// /// namespace name public string NameSpace() { return nameSpace; } /// /// Get the string representation of the qualified name /// of this class /// /// class qualified name public override string TypeName() { if ((nameSpace == null) || (nameSpace == "")) return name; return nameSpace + "." + name; } /// /// Get the descriptor for the method "name" of this class /// /// The name of the method to be retrieved /// The method descriptor for "name" public Method GetMethodDesc(string name) { for (int i = 0; i < methods.Count; i++) { if (((Method)methods[i]).HasName(name)) return (Method)methods[i]; } return null; } /// /// Get the descriptor for the method called "name" with the signature "parTypes" /// /// The name of the method /// The signature of the method /// The method descriptor for name(parTypes) public Method GetMethodDesc(string name, Type[] parTypes) { for (int i = 0; i < methods.Count; i++) { if (((Method)methods[i]).HasNameAndSig(name, parTypes)) return (Method)methods[i]; } return null; } /// /// Get the vararg method "name(parTypes,optTypes)" for this class /// /// Method name /// Method parameter types /// Optional parameter types /// Descriptor for "name(parTypes,optTypes)" public Method GetMethodDesc(string name, Type[] parTypes, Type[] optParTypes) { for (int i = 0; i < methods.Count; i++) { if (((Method)methods[i]).HasNameAndSig(name, parTypes, optParTypes)) return (Method)methods[i]; } return null; } /// /// Get all the methods of this class called "name" /// /// The method name /// List of methods called "name" public Method[] GetMethodDescs(string name) { ArrayList meths = GetMeths(name); return (Method[])meths.ToArray(typeof(Method)); } /// /// Get all the methods for this class /// /// List of methods for this class public Method[] GetMethodDescs() { return (Method[])methods.ToArray(typeof(Method)); } /// /// Remove the specified method from this class /// /// method name public void RemoveMethod(string name) { Method meth = GetMethodDesc(name); if (meth != null) methods.Remove(meth); } /// /// Remove the specified method from this class /// /// method name /// method parameter types public void RemoveMethod(string name, Type[] parTypes) { Method meth = GetMethodDesc(name, parTypes); if (meth != null) methods.Remove(meth); } /// /// Remove the specified method from this class /// /// method name /// method parameter types /// optional method parameter types public void RemoveMethod(string name, Type[] parTypes, Type[] optTypes) { Method meth = GetMethodDesc(name, parTypes, optTypes); if (meth != null) methods.Remove(meth); } /// /// Remove the specified method from this class /// /// method descriptor public void RemoveMethod(Method meth) { methods.Remove(meth); } /// /// Remove the specified method from this class /// /// index into list of methods for specified method public void RemoveMethod(int ix) { methods.RemoveAt(ix); } /// /// Get the descriptor for the field "name" for this class /// /// Field name /// Descriptor for field "name" public Field GetFieldDesc(string name) { return FindField(name); } /// /// Get all the fields for this class /// /// List of fields for this class public Field[] GetFieldDescs() { return (Field[])fields.ToArray(typeof(Field)); } /// /// Remove the specified field from this class /// /// field name public void RemoveField(string name) { Field f = FindField(name); if (f != null) fields.Remove(f); } /// /// Instantiate this generic type with the supplied types /// /// types to instantiate with /// descriptor for instantiated generic type public virtual ClassSpec Instantiate(Type[] genTypes) { return new ClassSpec(this, genTypes); } /// /// Denote this class as "special" such as a default module class /// public virtual void MakeSpecial() { special = true; } /// /// Get the owing scope of this class /// /// owner of this class public abstract MetaDataElement GetParent(); /// /// Get any nested classes of this class /// /// list of nested classes public Class[] GetNestedClasses() { return (Class[])nestedClasses.ToArray(typeof(Class)); } /// /// How many nested classes does this class have? /// /// number of nested classes public int GetNestedClassCount() { return nestedClasses.Count; } /*------------------------- internal functions --------------------------*/ internal virtual Type GetGenPar(uint ix) { return null; } protected ArrayList GetMeths(string name) { ArrayList meths = new ArrayList(); for (int i = 0; i < methods.Count; i++) { if (((Method)methods[i]).HasName(name)) meths.Add(methods[i]); } return meths; } internal ArrayList GetFieldList() { return fields; } internal ArrayList GetMethodList() { return methods; } internal bool isValueType() { return typeIndex == (byte)ElementType.ValueType; } internal bool isSpecial() { return special; } internal void AddToFieldList(Field f) { f.SetParent(this); fields.Add(f); } internal void AddToList(ArrayList list, MDTable tabIx) { switch (tabIx) { case (MDTable.Field): fields.AddRange(list); break; case (MDTable.Method): methods.AddRange(list); break; case (MDTable.TypeDef): nestedClasses.AddRange(list); break; default: throw new Exception("Unknown list type"); } } internal void AddToMethodList(Method m) { m.SetParent(this); methods.Add(m); } internal void AddToClassList(Class nClass) { nestedClasses.Add(nClass); } internal Class GetNested(string name) { for (int i = 0; i < nestedClasses.Count; i++) { if (((Class)nestedClasses[i]).Name() == name) return (Class)nestedClasses[i]; } return null; } internal Method GetMethod(MethSig mSig) { return GetMethodDesc(mSig.name, mSig.parTypes, mSig.optParTypes); } protected Field FindField(string name) { for (int i = 0; i < fields.Count; i++) { if (((Field)fields[i]).Name() == name) return (Field)fields[i]; } return null; } internal void SetBuffer(PEReader buff) { buffer = buff; } internal override void TypeSig(MemoryStream sig) { sig.WriteByte(typeIndex); MetaDataOut.CompressNum(BlobUtil.CompressUInt(TypeDefOrRefToken()), sig); } internal abstract string ClassName(); internal virtual uint TypeDefOrRefToken() { return 0; } } /**************************************************************************/ /// /// /// public class ClassSpec : Class { Class genClass; uint sigIx; private static byte GENERICINST = 0x15; /*-------------------- Constructors ---------------------------------*/ internal ClassSpec(Class clType, Type[] gPars) { this.typeIndex = GENERICINST; genClass = clType; genericParams = new ArrayList(gPars); tabIx = MDTable.TypeSpec; typeIndex = GENERICINST; ArrayList classMethods = clType.GetMethodList(); ArrayList classFields = clType.GetFieldList(); for (int i = 0; i < classMethods.Count; i++) { MethSig mSig = ((Method)classMethods[i]).GetSig(); //.InstantiateGenTypes(this,gPars); if (mSig != null) { MethodRef newMeth = new MethodRef(mSig); newMeth.SetParent(this); newMeth.GenericParams = ((Method)classMethods[i]).GenericParams; methods.Add(newMeth); } } for (int i = 0; i < classFields.Count; i++) { Type fType = ((Field)classFields[i]).GetFieldType(); //if ((fType is GenericParam) && (((GenericParam)fType).GetParent() == genClass)) { // fType = gPars[((GenericParam)fType).Index]; //} fields.Add(new FieldRef(this, ((Field)classFields[i]).Name(), fType)); } } /*------------------------- public set and get methods --------------------------*/ /// /// Get the generic class that this is an instantiation of /// /// generic class public override MetaDataElement GetParent() { return null; } /// /// Get the specified generic parameter number /// /// generic parameter number /// generic parameter number ix public Type GetGenericParamType(int ix) { if (ix >= genericParams.Count) return null; return (Type)genericParams[ix]; } /// /// Get the generic parameters of this class /// /// list of generic parameters public Type[] GetGenericParamTypes() { return (Type[])genericParams.ToArray(typeof(Type)); } /// /// Get the generic class that this class instantiates /// /// generic class public Class GetGenericClass() { return genClass; } /// /// Count how many generic parameters this class has /// /// number of generic parameters public int GetGenericParCount() { return genericParams.Count; } /*----------------------------- internal functions ------------------------------*/ internal void AddMethod(Method meth) { methods.Add(meth); meth.SetParent(this); } internal override string ClassName() { // need to return something here?? return null; } internal override sealed uint TypeDefOrRefToken() { uint cIx = Row; cIx = (cIx << 2) | 0x2; return cIx; } internal override Type GetGenPar(uint ix) { if (genClass == null) return new GenericParam(null, this, (int)ix); return genClass.GetGenPar(ix); //if (ix >= genericParams.Count) return null; //return (Type)genericParams[(int)ix]; } internal override sealed Type AddTypeSpec(MetaDataOut md) { md.AddToTable(MDTable.TypeSpec, this); BuildMDTables(md); return this; } internal override void BuildTables(MetaDataOut md) { //md.AddToTable(MDTable.TypeSpec,this); if (!genClass.isDef()) genClass.BuildMDTables(md); for (int i = 0; i < genericParams.Count; i++) { if (!((Type)genericParams[i]).isDef() && (!(genericParams[i] is GenericParam))) ((Type)genericParams[i]).BuildMDTables(md); } } internal override void BuildSignatures(MetaDataOut md) { MemoryStream outSig = new MemoryStream(); TypeSig(outSig); sigIx = md.AddToBlobHeap(outSig.ToArray()); } internal sealed override void TypeSig(MemoryStream sig) { sig.WriteByte(typeIndex); genClass.TypeSig(sig); //MetaDataOut.CompressNum((uint)genericParams.Count, sig); MetaDataOut.CompressNum(BlobUtil.CompressUInt((uint)genericParams.Count), sig); for (int i = 0; i < genericParams.Count; i++) { ((Type)genericParams[i]).TypeSig(sig); } } internal sealed override void Write(PEWriter output) { //Console.WriteLine("Writing the blob index for a TypeSpec"); output.BlobIndex(sigIx); } internal sealed override uint GetCodedIx(CIx code) { switch (code) { case (CIx.TypeDefOrRef): return 2; case (CIx.HasCustomAttr): return 13; case (CIx.MemberRefParent): return 4; } return 0; } } /**************************************************************************/ /// /// wrapper for TypeSpec parent of MethodRef or FieldRef /// public class ConstructedTypeSpec : Class { TypeSpec constrType; public ConstructedTypeSpec(TypeSpec tySpec) : base() { constrType = tySpec; this.typeIndex = constrType.GetTypeIndex(); } public TypeSpec Spec { get { return constrType; } } public override MetaDataElement GetParent() { return null; } internal override string ClassName() { return constrType.NameString(); } } /**************************************************************************/ public abstract class ClassDesc : Class { /*-------------------- Constructors ---------------------------------*/ internal ClassDesc(string nameSpaceName, string className) { nameSpace = nameSpaceName; name = className; } internal ClassDesc() { } /*------------------------- public set and get methods --------------------------*/ public GenericParam GetGenericParam(int ix) { if (ix >= genericParams.Count) return null; return (GenericParam)genericParams[ix]; } public GenericParam[] GetGenericParams() { return (GenericParam[])genericParams.ToArray(typeof(GenericParam)); } public virtual void SetGenericParams(GenericParam[] genPars) { for (int i = 0; i < genPars.Length; i++) { genPars[i].SetClassParam(this, i); } genericParams = new ArrayList(genPars); } /*----------------------------- internal functions ------------------------------*/ protected void DeleteGenericParam(int pos) { genericParams.RemoveAt(pos); for (int i = pos; i < genericParams.Count; i++) { GenericParam gp = (GenericParam)genericParams[i]; gp.Index = (uint)i; } } internal void AddGenericParam(GenericParam par) { genericParams.Add(par); //par.SetClassParam(this,genericParams.Count-1); } internal override Type GetGenPar(uint ix) { // create generic param descriptor if one does not exist // - used when reading exported interface // The next two lines are *required* for v2.0 beta release! (kjg) for (int i = genericParams.Count; i <= ix; i++) genericParams.Add(new GenericParam("gp" + i, this, i)); return (GenericParam)genericParams[(int)ix]; } } }