/*
* 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
{
/**************************************************************************/
///
/// Abstract class to represent a row of the Meta Data Tables
///
public abstract class TableRow
{
internal PEReader buffer;
private uint row = 0;
///
/// The index of the Meta Data Table containing this element
///
protected MDTable tabIx;
/*-------------------- Constructors ---------------------------------*/
internal TableRow() { }
internal TableRow(PEReader buff, uint ix, MDTable tableIx)
{
buffer = buff;
row = ix;
tabIx = tableIx;
}
///
/// The row number of this element in the Meta Data Table
///
public uint Row
{
get { return row; }
set { row = value; }
}
}
/****************************************************/
///
/// Base class for all Meta Data table elements
///
public abstract class MetaDataElement : TableRow, IComparable
{
///
/// The list of custom attributes associated with this meta data element
///
protected ArrayList customAttributes;
protected bool done = false;
protected bool sortTable = false;
internal bool unresolved = false;
/*-------------------- Constructors ---------------------------------*/
internal MetaDataElement() { }
///
/// Get any custom attributes associated with this meta data element
///
/// Array of custom attribute descriptors
public CustomAttribute[] GetCustomAttributes()
{
if (customAttributes == null) return new CustomAttribute[0];
return (CustomAttribute[])customAttributes.ToArray(typeof(CustomAttribute));
}
///
/// Associate some custom attribute(s) with this meta data element
///
/// list of custom attributes
public void SetCustomAttributes(CustomAttribute[] cas)
{
if (cas == null)
customAttributes = null;
else
customAttributes = new ArrayList(cas);
}
// FIXME: this is temporary
public string GetNameString()
{
return this.NameString();
}
internal virtual bool isDef() { return false; }
internal virtual void Resolve(PEReader buff) { }
internal virtual void ResolveDetails(PEReader buff) { }
internal virtual uint GetCodedIx(CIx code) { return 0; }
internal bool NeedToSort() { return sortTable; }
internal virtual uint SortKey()
{
throw new PEFileException("Trying to sort table of " + this);
//return 0;
}
///
/// Add a custom attribute to this item
///
/// the constructor method for this attribute
/// the byte value of the parameters
public void AddCustomAttribute(Method ctorMeth, byte[] val)
{
if (customAttributes == null)
{
customAttributes = new ArrayList();
}
customAttributes.Add(new CustomAttribute(this, ctorMeth, val));
}
///
/// Add a custom attribute to this item
///
/// the constructor method for this attribute
/// the constant values of the parameters
public void AddCustomAttribute(Method ctorMeth, Constant[] cVals)
{
if (customAttributes == null)
{
customAttributes = new ArrayList();
}
customAttributes.Add(new CustomAttribute(this, ctorMeth, cVals));
}
///
/// Associate a custom attribute with this meta data element
///
public void AddCustomAttribute(CustomAttribute ca)
{
if (customAttributes == null)
{
customAttributes = new ArrayList();
}
customAttributes.Add(ca);
}
internal uint Token()
{
if (Row == 0) throw new Exception("Meta data token is zero!!");
return (((uint)tabIx << 24) | Row);
}
internal void BuildMDTables(MetaDataOut md)
{
if (done) return;
done = true;
if (Diag.DiagOn) Console.WriteLine("In BuildMDTables");
BuildTables(md);
if (customAttributes != null)
{
for (int i = 0; i < customAttributes.Count; i++)
{
CustomAttribute ca = (CustomAttribute)customAttributes[i];
ca.BuildTables(md);
}
}
}
internal virtual void BuildTables(MetaDataOut md) { }
internal virtual void BuildSignatures(MetaDataOut md)
{
done = false;
}
internal virtual void BuildCILInfo(CILWriter output) { }
internal virtual void AddToTable(MetaDataOut md)
{
md.AddToTable(tabIx, this);
}
internal virtual void Write(PEWriter output) { }
internal virtual void Write(CILWriter output)
{
throw new Exception("CIL backend not yet fully implemented - " + GetType().ToString());
}
internal virtual string NameString() { return "NoName"; }
internal void DescriptorError(MetaDataElement elem)
{
throw new DescriptorException(elem.NameString());
}
#region IComparable Members
public int CompareTo(object obj)
{
uint otherKey = ((MetaDataElement)obj).SortKey();
uint thisKey = SortKey();
if (thisKey == otherKey)
{
if (this is GenericParam)
{
if (((GenericParam)this).Index < ((GenericParam)obj).Index)
return -1;
else
return 1;
}
return 0;
}
if (thisKey < otherKey) return -1;
return 1;
}
#endregion
}
/**************************************************************************/
///
/// Descriptor for GenericParamConstraint
///
public class GenericParamConstraint : MetaDataElement
{
uint parentIx, constraintIx;
GenericParam parent;
Class constraint;
/*-------------------- Constructors ---------------------------------*/
public GenericParamConstraint(GenericParam parent, Class constraint)
{
this.parent = parent;
this.constraint = constraint;
tabIx = MDTable.GenericParamConstraint;
}
internal GenericParamConstraint(PEReader buff)
{
parentIx = buff.GetIndex(MDTable.GenericParam);
constraintIx = buff.GetCodedIndex(CIx.TypeDefOrRef);
tabIx = MDTable.GenericParamConstraint;
}
internal static void Read(PEReader buff, TableRow[] gpars)
{
for (int i = 0; i < gpars.Length; i++)
gpars[i] = new GenericParamConstraint(buff);
}
internal override void Resolve(PEReader buff)
{
parent = (GenericParam)buff.GetElement(MDTable.GenericParam, parentIx);
parent.AddConstraint((Class)buff.GetCodedElement(CIx.TypeDefOrRef, constraintIx));
}
internal static uint Size(MetaData md)
{
return md.TableIndexSize(MDTable.GenericParam) + md.CodedIndexSize(CIx.TypeDefOrRef);
}
internal override void Write(PEWriter output)
{
output.WriteIndex(MDTable.GenericParam, parent.Row);
output.WriteCodedIndex(CIx.TypeDefOrRef, constraint);
}
}
/**************************************************************************/
///
/// Descriptor for pinvoke information for a method
///
public class ImplMap : MetaDataElement
{
private static readonly ushort NoMangle = 0x01;
ushort flags;
MethodDef meth;
string importName;
uint iNameIx, scopeIx = 0, memForIndex = 0;
ModuleRef importScope;
/*-------------------- Constructors ---------------------------------*/
internal ImplMap(ushort flag, MethodDef implMeth, string iName, ModuleRef mScope)
{
flags = flag;
meth = implMeth;
importName = iName;
importScope = mScope;
tabIx = MDTable.ImplMap;
if (iName == null) flags |= NoMangle;
sortTable = true;
//throw(new NotYetImplementedException("PInvoke "));
}
internal ImplMap(PEReader buff)
{
flags = buff.ReadUInt16();
memForIndex = buff.GetCodedIndex(CIx.MemberForwarded);
importName = buff.GetString();
scopeIx = buff.GetIndex(MDTable.ModuleRef);
sortTable = true;
tabIx = MDTable.ImplMap;
}
internal static void Read(PEReader buff, TableRow[] impls)
{
for (int i = 0; i < impls.Length; i++)
impls[i] = new ImplMap(buff);
}
internal override void Resolve(PEReader buff)
{
meth = (MethodDef)buff.GetCodedElement(CIx.MemberForwarded, memForIndex);
importScope = (ModuleRef)buff.GetElement(MDTable.ModuleRef, scopeIx);
if (meth != null) meth.AddPInvokeInfo(this);
}
internal override uint SortKey()
{
return (meth.Row << MetaData.CIxShiftMap[(uint)CIx.MemberForwarded])
| meth.GetCodedIx(CIx.MemberForwarded);
}
internal sealed override void BuildTables(MetaDataOut md)
{
md.AddToTable(MDTable.ImplMap, this);
iNameIx = md.AddToStringsHeap(importName);
importScope.BuildMDTables(md);
}
internal static uint Size(MetaData md)
{
return 2 + md.CodedIndexSize(CIx.MemberForwarded) +
md.StringsIndexSize() + md.TableIndexSize(MDTable.ModuleRef);
}
internal sealed override void Write(PEWriter output)
{
output.Write(flags);
output.WriteCodedIndex(CIx.MemberForwarded, meth);
output.StringsIndex(iNameIx);
output.WriteIndex(MDTable.ModuleRef, importScope.Row);
}
}
/**************************************************************************/
///
/// Base class for field/methods (member of a class)
///
public abstract class Member : MetaDataElement
{
protected string name;
protected uint nameIx = 0, sigIx = 0;
protected byte[] signature;
protected uint parentIx = 0;
protected Class parent;
/*-------------------- Constructors ---------------------------------*/
internal Member(string memName, Class paren)
{
name = memName;
parent = paren;
tabIx = MDTable.MemberRef;
}
internal Member(uint parenIx, string name, uint sIx)
{
parentIx = parenIx;
this.name = name;
sigIx = sIx;
tabIx = MDTable.MemberRef;
}
internal Member(string name)
{
this.name = name;
tabIx = MDTable.MemberRef;
}
internal static void ReadMember(PEReader buff, TableRow[] members)
{
for (int i = 0; i < members.Length; i++)
{
uint parenIx = buff.GetCodedIndex(CIx.MemberRefParent);
string memName = buff.GetString();
uint sigIx = buff.GetBlobIx();
if (buff.FirstBlobByte(sigIx) == Field.FieldTag) // got a field
members[i] = new FieldRef(parenIx, memName, sigIx);
else
members[i] = new MethodRef(parenIx, memName, sigIx);
}
}
internal virtual Member ResolveParent(PEReader buff) { return null; }
public MetaDataElement GetParent()
{
if (parent == null) return null;
if (parent.isSpecial())
return parent.GetParent();
return parent;
}
internal void SetParent(Class paren)
{
parent = paren;
}
public string Name() { return name; }
public string QualifiedName() { return parent.TypeName() + "." + name; }
internal bool HasName(string name)
{
return (this.name == name);
}
protected void WriteFlags(CILWriter output, uint flags)
{
uint vis = (flags & 0x07); // visibility mask
switch (vis)
{
case 0: output.Write("compilercontrolled "); break;
case 1: output.Write("private "); break;
case 2: output.Write("famandassem "); break;
case 3: output.Write("assembly "); break;
case 4: output.Write("family "); break;
case 5: output.Write("famorassem "); break;
case 6: output.Write("public "); break;
}
if ((flags & (ushort)FieldAttr.Static) != 0)
{
output.Write("static ");
}
if ((flags & (ushort)FieldAttr.Initonly) != 0)
{
if (this is MethodDef)
{
output.Write("final ");
}
else
{
output.Write("initonly ");
}
}
if ((flags & (ushort)FieldAttr.Literal) != 0)
{
if (this is MethodDef)
{
output.Write("virtual ");
}
else
{
output.Write("literal ");
}
}
if ((flags & (ushort)FieldAttr.Notserialized) != 0)
{
if (this is MethodDef)
{
output.Write("hidebysig ");
}
else
{
output.Write("notserialized ");
}
}
if (this is MethodDef)
{
// more flags required here
if ((flags & (ushort)MethAttr.Abstract) != 0)
{
output.Write("abstract ");
}
if ((flags & (ushort)MethAttr.SpecialName) != 0)
{
output.Write("specialname ");
}
if ((flags & (ushort)MethAttr.RTSpecialName) != 0)
{
output.Write("rtspecialname ");
}
}
else
{
// more flags required here
if ((flags & (ushort)FieldAttr.SpecialName) != 0)
{
output.Write("specialname ");
}
if ((flags & (ushort)FieldAttr.RTSpecialName) != 0)
{
output.Write("rtsspecialname ");
}
}
}
internal abstract void WriteType(CILWriter output);
}
/**************************************************************************/
///
/// Descriptor for interface implemented by a class
///
public class InterfaceImpl : MetaDataElement
{
ClassDef theClass;
Class theInterface;
uint classIx = 0, interfacesIndex = 0;
/*-------------------- Constructors ---------------------------------*/
internal InterfaceImpl(ClassDef theClass, Class theInterface)
{
this.theClass = theClass;
this.theInterface = theInterface;
tabIx = MDTable.InterfaceImpl;
}
internal InterfaceImpl(ClassDef theClass, TableRow theInterface)
{
this.theClass = theClass;
this.theInterface = (Class)theInterface;
tabIx = MDTable.InterfaceImpl;
}
internal InterfaceImpl(PEReader buff)
{
classIx = buff.GetIndex(MDTable.TypeDef);
interfacesIndex = buff.GetCodedIndex(CIx.TypeDefOrRef);
tabIx = MDTable.InterfaceImpl;
}
internal override void Resolve(PEReader buff)
{
theClass = (ClassDef)buff.GetElement(MDTable.TypeDef, classIx);
theInterface = (Class)buff.GetCodedElement(CIx.TypeDefOrRef, interfacesIndex);
theClass.AddImplementedInterface(this);
}
internal static void Read(PEReader buff, TableRow[] impls)
{
for (int i = 0; i < impls.Length; i++)
impls[i] = new InterfaceImpl(buff);
}
internal ClassDef TheClass() { return theClass; }
internal Class TheInterface() { return theInterface; }
internal sealed override void BuildTables(MetaDataOut md)
{
md.AddToTable(MDTable.InterfaceImpl, this);
if (!theInterface.isDef()) theInterface.BuildMDTables(md);
if (theInterface is ClassSpec) md.AddToTable(MDTable.TypeSpec, theInterface);
}
internal static uint Size(MetaData md)
{
return md.TableIndexSize(MDTable.TypeDef) +
md.CodedIndexSize(CIx.TypeDefOrRef);
}
internal sealed override void Write(PEWriter output)
{
output.WriteIndex(MDTable.TypeDef, theClass.Row);
output.WriteCodedIndex(CIx.TypeDefOrRef, theInterface);
}
internal sealed override uint GetCodedIx(CIx code) { return 5; }
}
/**************************************************************************/
///
/// Descriptor for resources used in this PE file NOT YET IMPLEMENTED
///
public class ManifestResource : MetaDataElement
{
private static readonly uint PublicResource = 0x1;
private static readonly uint PrivateResource = 0x2;
string mrName;
MetaDataElement impl; // can be AssemblyRef, ResourceFile or ModuleFile
uint fileOffset = 0;
uint nameIx = 0, implIx = 0;
uint flags = 0;
PEFile pefile;
byte[] resourceBytes;
/*-------------------- Constructors ---------------------------------*/
internal ManifestResource(PEFile pefile, string name, byte[] resBytes, bool isPub)
{
InitResource(pefile, name, isPub);
this.resourceBytes = resBytes;
}
internal ManifestResource(PEFile pefile, string name, MetaDataElement fileRef, uint offset, bool isPub)
{
InitResource(pefile, name, isPub);
impl = fileRef;
fileOffset = offset;
}
internal ManifestResource(PEFile pefile, ManifestResource mres, bool isPub)
{
this.pefile = pefile;
mrName = mres.mrName;
flags = mres.flags;
this.impl = mres.impl;
this.fileOffset = mres.fileOffset;
this.resourceBytes = mres.resourceBytes;
}
internal ManifestResource(PEReader buff)
{
fileOffset = buff.ReadUInt32();
flags = buff.ReadUInt32();
mrName = buff.GetString();
implIx = buff.GetCodedIndex(CIx.Implementation);
tabIx = MDTable.ManifestResource;
}
private void InitResource(PEFile pefile, string name, bool isPub)
{
this.pefile = pefile;
mrName = name;
if (isPub) flags = PublicResource;
else flags = PrivateResource;
tabIx = MDTable.ManifestResource;
}
internal static void Read(PEReader buff, TableRow[] mrs)
{
for (int i = 0; i < mrs.Length; i++)
mrs[i] = new ManifestResource(buff);
}
internal override void Resolve(PEReader buff)
{
impl = buff.GetCodedElement(CIx.Implementation, implIx);
if (impl == null)
{
if (!buff.skipBody)
resourceBytes = buff.GetResource(fileOffset);
}
}
/*------------------------- public set and get methods --------------------------*/
public string Name
{
get { return mrName; }
set { mrName = value; }
}
public byte[] ResourceBytes
{
get { return resourceBytes; }
set { resourceBytes = value; }
}
public AssemblyRef ResourceAssembly
{
get { if (impl is AssemblyRef) return (AssemblyRef)impl; return null; }
set { impl = value; }
}
public ResourceFile ResFile
{
get { if (impl is ResourceFile) return (ResourceFile)impl; return null; }
set { impl = value; }
}
public ModuleRef ResourceModule
{
get { if (impl is ModuleFile) return ((ModuleFile)impl).fileModule; return null; }
set { impl = value.modFile; }
}
public uint FileOffset
{
get { return fileOffset; }
set { fileOffset = value; }
}
public bool IsPublic
{
get
{
return flags == PublicResource;
}
set
{
if (value)
flags = PublicResource;
else
flags = PrivateResource;
}
}
/*----------------------------- internal functions ------------------------------*/
internal sealed override void BuildTables(MetaDataOut md)
{
md.AddToTable(MDTable.ManifestResource, this);
nameIx = md.AddToStringsHeap(mrName);
if (resourceBytes != null)
{
if (impl != null)
throw new Exception("ERROR: Manifest Resource has byte value and file reference");
fileOffset = md.AddResource(resourceBytes);
}
else
{
if (impl == null)
throw new Exception("ERROR: Manifest Resource has no implementation or value");
impl.BuildMDTables(md);
}
}
internal static uint Size(MetaData md)
{
return 8 + md.StringsIndexSize() +
md.CodedIndexSize(CIx.Implementation);
}
internal sealed override void Write(PEWriter output)
{
output.Write(fileOffset);
output.Write(flags);
output.StringsIndex(nameIx);
output.WriteCodedIndex(CIx.Implementation, impl);
}
internal sealed override uint GetCodedIx(CIx code) { return 18; }
}
/**************************************************************************/
///
/// Base class for elements in the PropertyMap, EventMap and
/// NestedClass MetaData tables
///
public class MapElem : MetaDataElement
{
ClassDef theClass, parent;
uint elemIx, classIx, endIx = 0;
/*-------------------- Constructors ---------------------------------*/
internal MapElem(ClassDef classDef, uint elIx, MDTable tableIx)
{
theClass = classDef;
elemIx = elIx;
tabIx = tableIx;
sortTable = tabIx == MDTable.NestedClass;
}
internal MapElem(ClassDef classDef, ClassDef paren, MDTable tableIx)
{
theClass = classDef;
parent = paren;
tabIx = tableIx;
sortTable = tabIx == MDTable.NestedClass;
}
internal MapElem(PEReader buff, MDTable tab)
{
tabIx = tab;
classIx = buff.GetIndex(MDTable.TypeDef);
elemIx = buff.GetIndex(tab);
sortTable = tabIx == MDTable.NestedClass;
}
internal static void Read(PEReader buff, TableRow[] maps, MDTable tab)
{
if (tab == MDTable.NestedClass)
{
for (int i = 0; i < maps.Length; i++)
{
//maps[i] = new MapElem(buff,tab);
uint nestClassIx = buff.GetIndex(MDTable.TypeDef);
uint enclClassIx = buff.GetIndex(MDTable.TypeDef);
ClassDef parent = (ClassDef)buff.GetElement(MDTable.TypeDef, enclClassIx);
ClassDef nestClass = ((ClassDef)buff.GetElement(MDTable.TypeDef, nestClassIx)).MakeNestedClass(parent);
buff.InsertInTable(MDTable.TypeDef, nestClass.Row, nestClass);
}
}
else
{ // event or property map
MapElem prev = new MapElem(buff, tab);
maps[0] = prev;
for (int i = 1; i < maps.Length; i++)
{
maps[i] = new MapElem(buff, tab);
prev.endIx = ((MapElem)maps[i]).elemIx;
prev = (MapElem)maps[i];
}
switch (tab)
{
case MDTable.PropertyMap:
prev.endIx = buff.GetTableSize(MDTable.Property) + 1;
break;
case MDTable.EventMap:
prev.endIx = buff.GetTableSize(MDTable.Event) + 1;
break;
default:
prev.endIx = buff.GetTableSize(tab) + 1;
break;
}
}
}
internal static void ReadNestedClassInfo(PEReader buff, uint num, uint[] parIxs)
{
for (int i = 0; i < parIxs.Length; i++) parIxs[i] = 0;
for (int i = 0; i < num; i++)
{
int ix = (int)buff.GetIndex(MDTable.TypeDef);
parIxs[ix - 1] = buff.GetIndex(MDTable.TypeDef);
}
}
internal override void Resolve(PEReader buff)
{
theClass = (ClassDef)buff.GetElement(MDTable.TypeDef, classIx);
if (tabIx == MDTable.EventMap)
{
for (uint i = elemIx; i < endIx; i++)
theClass.AddEvent((Event)buff.GetElement(MDTable.Event, i));
}
else if (tabIx == MDTable.PropertyMap)
{
for (uint i = elemIx; i < endIx; i++)
theClass.AddProperty((Property)buff.GetElement(MDTable.Property, i));
}
else
{ // must be nested class -- already done
//ClassDef parent = (ClassDef)buff.GetElement(MDTable.TypeDef,elemIx);
//parent.MakeNested(theClass);
}
}
internal static uint Size(MetaData md, MDTable tabIx)
{
return md.TableIndexSize(MDTable.TypeDef) + md.TableIndexSize(tabIx);
}
internal override uint SortKey()
{
return theClass.Row;
}
internal sealed override void BuildTables(MetaDataOut md)
{
md.AddToTable(tabIx, this);
}
internal sealed override void Write(PEWriter output)
{
output.WriteIndex(MDTable.TypeDef, theClass.Row);
if (parent != null)
output.WriteIndex(MDTable.TypeDef, parent.Row);
else
output.WriteIndex(tabIx, elemIx);
}
}
/**************************************************************************/
///
/// Descriptor for an overriding method (.override)
///
public class MethodImpl : MetaDataElement
{
ClassDef parent;
Method header, body;
uint classIx = 0, methBodyIx = 0, methDeclIx = 0;
bool resolved = true;
/*-------------------- Constructors ---------------------------------*/
internal MethodImpl(ClassDef par, Method decl, Method bod)
{
parent = par;
header = decl;
body = bod;
tabIx = MDTable.MethodImpl;
}
internal MethodImpl(PEReader buff, ClassDef par, uint bIx, uint dIx)
{
buffer = buff;
parent = par;
methBodyIx = bIx;
methDeclIx = dIx;
tabIx = MDTable.MethodImpl;
resolved = false;
}
internal MethodImpl(PEReader buff)
{
classIx = buff.GetIndex(MDTable.TypeDef);
methBodyIx = buff.GetCodedIndex(CIx.MethodDefOrRef);
methDeclIx = buff.GetCodedIndex(CIx.MethodDefOrRef);
tabIx = MDTable.MethodImpl;
}
/*internal static MethodImpl[] GetMethodImpls(PEReader buff, ClassDef paren, uint classIx) {
buff.SetElementPosition(MDTable.MethodImpl,0);
ArrayList impls = new ArrayList();
for (int i=0; i < buff.GetTableSize(MDTable.MethodImpl); i++) {
uint cIx = buff.GetIndex(MDTable.TypeDef);
uint bIx = buff.GetCodedIndex(CIx.MethodDefOrRef);
uint dIx = buff.GetCodedIndex(CIx.MethodDefOrRef);
if (cIx == classIx)
paren.AddMethodOverride(new MethodImpl(buff,paren,bIx,dIx));
}
return (MethodImpl[])impls.ToArray(typeof(MethodImpl));
}
*/
public Method Body
{
get
{
if ((body == null) && (methBodyIx != 0))
body = (Method)buffer.GetCodedElement(CIx.MethodDefOrRef, methBodyIx);
return body;
}
set
{
body = value;
if ((!resolved) && (header != null)) resolved = true;
}
}
public Method Header
{
get
{
if ((header == null) && (methDeclIx != 0))
header = (Method)buffer.GetCodedElement(CIx.MethodDefOrRef, methDeclIx);
return header;
}
set
{
header = value;
if ((!resolved) && (body != null)) resolved = true;
}
}
internal void SetOwner(ClassDef cl)
{
parent = cl;
}
internal static void Read(PEReader buff, TableRow[] impls)
{
for (int i = 0; i < impls.Length; i++)
impls[i] = new MethodImpl(buff);
}
internal override void Resolve(PEReader buff)
{
body = (Method)buff.GetCodedElement(CIx.MethodDefOrRef, methBodyIx);
header = (Method)buff.GetCodedElement(CIx.MethodDefOrRef, methDeclIx);
parent = (ClassDef)buff.GetElement(MDTable.TypeDef, classIx);
parent.AddMethodImpl(this);
resolved = true;
}
internal void ResolveMethDetails()
{
body = (Method)buffer.GetCodedElement(CIx.MethodDefOrRef, methBodyIx);
header = (Method)buffer.GetCodedElement(CIx.MethodDefOrRef, methDeclIx);
resolved = true;
}
internal void ChangeRefsToDefs(ClassDef newType, ClassDef[] oldTypes)
{
throw new NotYetImplementedException("Merge for MethodImpls");
}
internal sealed override void BuildTables(MetaDataOut md)
{
md.AddToTable(MDTable.MethodImpl, this);
if (!resolved) ResolveMethDetails();
if (body is MethodRef) body.BuildMDTables(md);
if (header is MethodRef) header.BuildMDTables(md);
}
internal static uint Size(MetaData md)
{
return md.TableIndexSize(MDTable.TypeDef) + 2 * md.CodedIndexSize(CIx.MethodDefOrRef);
}
internal sealed override void Write(PEWriter output)
{
output.WriteIndex(MDTable.TypeDef, parent.Row);
output.WriteCodedIndex(CIx.MethodDefOrRef, body);
output.WriteCodedIndex(CIx.MethodDefOrRef, header);
}
}
/**************************************************************************/
///
/// Descriptor for Property and Event methods
///
public class MethodSemantics : MetaDataElement
{
MethodType type;
MethodDef meth;
Feature eventOrProp;
uint methIx = 0, assocIx = 0;
/*-------------------- Constructors ---------------------------------*/
internal MethodSemantics(MethodType mType, MethodDef method, Feature feature)
{
type = mType;
meth = method;
eventOrProp = feature;
sortTable = true;
tabIx = MDTable.MethodSemantics;
}
internal MethodSemantics(PEReader buff)
{
type = (MethodType)buff.ReadUInt16();
methIx = buff.GetIndex(MDTable.Method);
assocIx = buff.GetCodedIndex(CIx.HasSemantics);
sortTable = true;
tabIx = MDTable.MethodSemantics;
}
internal static void Read(PEReader buff, TableRow[] methSems)
{
for (int i = 0; i < methSems.Length; i++)
methSems[i] = new MethodSemantics(buff);
}
internal override void Resolve(PEReader buff)
{
meth = (MethodDef)buff.GetElement(MDTable.Method, methIx);
eventOrProp = (Feature)buff.GetCodedElement(CIx.HasSemantics, assocIx);
eventOrProp.AddMethod(this);
}
internal MethodType GetMethodType() { return type; }
internal MethodDef GetMethod() { return meth; }
internal override uint SortKey()
{
return meth.Row;
}
internal sealed override void BuildTables(MetaDataOut md)
{
md.AddToTable(MDTable.MethodSemantics, this);
}
internal static uint Size(MetaData md)
{
return 2 + md.TableIndexSize(MDTable.Method) + md.CodedIndexSize(CIx.HasSemantics);
}
internal sealed override void Write(PEWriter output)
{
output.Write((ushort)type);
output.WriteIndex(MDTable.Method, meth.Row);
output.WriteCodedIndex(CIx.HasSemantics, eventOrProp);
}
}
/**************************************************************************/
///
/// Descriptor for a parameter of a method defined in this assembly/module
///
public class Param : MetaDataElement
{
private static readonly ushort hasDefault = 0x1000;
private static readonly ushort noDefault = 0xEFFF;
private static readonly ushort hasFieldMarshal = 0x2000;
private static readonly ushort noFieldMarshal = 0xDFFF;
protected string pName;
protected uint nameIx = 0;
Type pType;
internal ushort seqNo = 0;
ushort parMode;
Constant defaultVal;
NativeType marshalType;
/*-------------------- Constructors ---------------------------------*/
///
/// Create a new parameter for a method
///
/// param mode (in, out, opt)
/// parameter name
/// parameter type
public Param(ParamAttr mode, string parName, Type parType)
{
pName = parName;
pType = parType;
parMode = (ushort)mode;
tabIx = MDTable.Param;
}
// EXPERIMENTAL kjg Nov 19 2007
public static Param DefaultParam()
{
return new Param(ParamAttr.Default, "", null);
}
internal Param(PEReader buff)
{
parMode = buff.ReadUInt16();
seqNo = buff.ReadUInt16();
pName = buff.GetString();
tabIx = MDTable.Param;
}
internal static void Read(PEReader buff, TableRow[] pars)
{
for (int i = 0; i < pars.Length; i++)
pars[i] = new Param(buff);
}
internal void Resolve(PEReader buff, uint fIx, Type type)
{
this.pType = type;
}
///
/// Add a default value to this parameter
///
/// the default value for the parameter
public void AddDefaultValue(Constant cVal)
{
defaultVal = cVal;
parMode |= hasDefault;
}
///
/// Get the default constant value for this parameter
///
///
public Constant GetDefaultValue() { return defaultVal; }
///
/// Remove the default constant value for this parameter
///
public void RemoveDefaultValue() { defaultVal = null; parMode &= noDefault; }
///
/// Add marshalling information about this parameter
///
public void SetMarshalType(NativeType mType)
{
marshalType = mType;
parMode |= hasFieldMarshal;
}
///
/// Get the parameter marshalling information
///
/// The native type to marshall to
public NativeType GetMarshalType() { return marshalType; }
///
/// Remove any marshalling information for this parameter
///
public void RemoveMashalType() { marshalType = null; parMode &= noFieldMarshal; }
///
/// Get the type of this parameter
///
public Type GetParType() { return pType; }
///
/// Set the type of this parameter
///
public void SetParType(Type parType) { pType = parType; }
public void AddAttribute(ParamAttr att)
{
this.parMode |= (ushort)att;
}
public ParamAttr GetAttributes() { return (ParamAttr)parMode; }
public void SetAttributes(ParamAttr att)
{
this.parMode = (ushort)att;
}
///
/// Retrieve the name of this parameter
///
/// parameter name
public string GetName() { return pName; }
///
/// Set the name of this parameter
///
/// parameter name
public void SetName(string nam) { pName = nam; }
/*------------------------ internal functions ----------------------------*/
internal Param Copy(Type paramType)
{
return new Param((ParamAttr)parMode, pName, paramType);
}
internal sealed override void BuildTables(MetaDataOut md)
{
md.AddToTable(MDTable.Param, this);
nameIx = md.AddToStringsHeap(pName);
if (defaultVal != null)
{
ConstantElem constElem = new ConstantElem(this, defaultVal);
constElem.BuildMDTables(md);
}
if (marshalType != null)
{
FieldMarshal marshalInfo = new FieldMarshal(this, marshalType);
marshalInfo.BuildMDTables(md);
}
}
internal override void BuildCILInfo(CILWriter output)
{
pType.BuildCILInfo(output);
}
internal void TypeSig(MemoryStream str)
{
pType.TypeSig(str);
}
internal static uint Size(MetaData md)
{
return 4 + md.StringsIndexSize();
}
internal sealed override void Write(PEWriter output)
{
output.Write(parMode);
output.Write(seqNo);
output.StringsIndex(nameIx);
}
internal override void Write(CILWriter output)
{
pType.WriteType(output);
output.Write(" " + pName);
}
internal sealed override uint GetCodedIx(CIx code)
{
switch (code)
{
case (CIx.HasCustomAttr): return 4;
case (CIx.HasConstant): return 1;
case (CIx.HasFieldMarshal): return 1;
}
return 0;
}
}
/**************************************************************************/
///
/// Summary description for ConstantElem.
///
internal class ConstantElem : MetaDataElement
{
MetaDataElement parent;
Constant cValue;
uint valIx = 0, parentIx = 0;
/*-------------------- Constructors ---------------------------------*/
internal ConstantElem(MetaDataElement parent, Constant val)
{
this.parent = parent;
cValue = val;
sortTable = true;
tabIx = MDTable.Constant;
}
internal ConstantElem(PEReader buff)
{
byte constType = buff.ReadByte();
byte pad = buff.ReadByte();
parentIx = buff.GetCodedIndex(CIx.HasConstant);
//valIx = buff.GetBlobIx();
cValue = buff.GetBlobConst(constType);
sortTable = true;
tabIx = MDTable.Constant;
}
internal override void Resolve(PEReader buff)
{
parent = buff.GetCodedElement(CIx.HasConstant, parentIx);
if (parent != null)
{
if (parent is Param) ((Param)parent).AddDefaultValue(cValue);
else if (parent is FieldDef) ((FieldDef)parent).AddValue(cValue);
else ((Property)parent).AddInitValue(cValue);
}
}
internal static void Read(PEReader buff, TableRow[] consts)
{
for (int i = 0; i < consts.Length; i++)
consts[i] = new ConstantElem(buff);
}
/*----------------------------- internal functions ------------------------------*/
internal override uint SortKey()
{
return (parent.Row << MetaData.CIxShiftMap[(uint)CIx.HasConstant])
| parent.GetCodedIx(CIx.HasConstant);
}
internal sealed override void BuildTables(MetaDataOut md)
{
md.AddToTable(MDTable.Constant, this);
valIx = cValue.GetBlobIndex(md);
}
internal static uint Size(MetaData md)
{
return 2 + md.CodedIndexSize(CIx.HasConstant) + md.BlobIndexSize();
}
internal sealed override void Write(PEWriter output)
{
output.Write(cValue.GetTypeIndex());
output.Write((byte)0);
output.WriteCodedIndex(CIx.HasConstant, parent);
output.BlobIndex(valIx);
}
}
/**************************************************************************/
///
/// Descriptor for security permissions for a class or a method NOT YET IMPLEMENTED
///
public class DeclSecurity : MetaDataElement
{
SecurityAction action;
MetaDataElement parent;
uint parentIx = 0, permissionIx;
byte[] permissionSet;
/*-------------------- Constructors ---------------------------------*/
internal DeclSecurity(MetaDataElement paren, SecurityAction act, byte[] perSet)
{
parent = paren;
action = act;
permissionSet = perSet;
sortTable = true;
tabIx = MDTable.DeclSecurity;
}
internal DeclSecurity(PEReader buff)
{
action = (SecurityAction)buff.ReadUInt16();
parentIx = buff.GetCodedIndex(CIx.HasDeclSecurity);
permissionSet = buff.GetBlob();
sortTable = true;
tabIx = MDTable.DeclSecurity;
}
internal static void Read(PEReader buff, TableRow[] secs)
{
for (int i = 0; i < secs.Length; i++)
secs[i] = new DeclSecurity(buff);
}
internal static DeclSecurity FindSecurity(PEReader buff, MetaDataElement paren, uint codedParIx)
{
buff.SetElementPosition(MDTable.DeclSecurity, 0);
for (int i = 0; i < buff.GetTableSize(MDTable.DeclSecurity); i++)
{
uint act = buff.ReadUInt16();
if (buff.GetCodedIndex(CIx.HasDeclSecurity) == codedParIx)
return new DeclSecurity(paren, (SecurityAction)act, buff.GetBlob());
uint junk = buff.GetBlobIx();
}
return null;
}
internal override void Resolve(PEReader buff)
{
parent = buff.GetCodedElement(CIx.HasDeclSecurity, parentIx);
if (parent != null)
{
if (parent is ClassDef) ((ClassDef)parent).AddSecurity(this);
if (parent is Assembly) ((Assembly)parent).AddSecurity(this);
if (parent is MethodDef) ((MethodDef)parent).AddSecurity(this);
}
}
internal override uint SortKey()
{
return (parent.Row << MetaData.CIxShiftMap[(uint)CIx.HasDeclSecurity])
| parent.GetCodedIx(CIx.HasDeclSecurity);
}
internal sealed override void BuildTables(MetaDataOut md)
{
md.AddToTable(MDTable.DeclSecurity, this);
permissionIx = md.AddToBlobHeap(permissionSet);
}
internal static uint Size(MetaData md)
{
return 2 + md.CodedIndexSize(CIx.HasDeclSecurity) + md.BlobIndexSize();
}
internal sealed override void Write(PEWriter output)
{
output.Write((UInt16)action); // or should this be 2 bytes??
output.WriteCodedIndex(CIx.HasDeclSecurity, parent);
output.BlobIndex(permissionIx);
}
}
}