/*
* 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
{
/**************************************************************************/
///
/// Base class for Event and Property descriptors
///
public abstract class Feature : MetaDataElement
{
private static readonly int INITSIZE = 5;
private static readonly ushort specialName = 0x200;
private static readonly ushort rtsSpecialName = 0x400;
private static readonly ushort noSpecialName = 0xFDFF;
private static readonly ushort noRTSSpecialName = 0xFBFF;
protected ClassDef parent;
protected ushort flags = 0;
protected string name;
protected int tide = 0;
protected uint nameIx;
protected MethodSemantics[] methods = new MethodSemantics[INITSIZE];
/*-------------------- Constructors ---------------------------------*/
internal Feature(string name, ClassDef par)
{
parent = par;
this.name = name;
}
internal Feature() { }
internal static string[] GetFeatureNames(PEReader buff, MDTable tabIx, MDTable mapTabIx,
ClassDef theClass, uint classIx)
{
buff.SetElementPosition(mapTabIx, 0);
uint start = 0, end = 0, i = 0;
for (; (i < buff.GetTableSize(tabIx)) && (start == 0); i++)
{
if (buff.GetIndex(MDTable.TypeDef) == classIx)
{
start = buff.GetIndex(tabIx);
}
}
if (start == 0) return null;
if (i < buff.GetTableSize(mapTabIx))
{
uint junk = buff.GetIndex(MDTable.TypeDef);
end = buff.GetIndex(tabIx);
}
else
end = buff.GetTableSize(tabIx);
if (tabIx == MDTable.Event)
theClass.eventIx = start;
else
theClass.propIx = start;
string[] names = new string[end - start];
buff.SetElementPosition(tabIx, start);
for (i = start; i < end; i++)
{
uint junk = buff.ReadUInt16();
names[i] = buff.GetString();
if (tabIx == MDTable.Event)
junk = buff.GetCodedIndex(CIx.TypeDefOrRef);
else
junk = buff.GetBlobIx();
}
return names;
}
/*------------------------- public set and get methods --------------------------*/
///
/// Set the specialName attribute for this Event or Property
///
public void SetSpecialName() { flags |= specialName; }
public bool HasSpecialName() { return (flags & specialName) != 0; }
public void ClearSpecialName() { flags &= noSpecialName; }
///
/// Set the RTSpecialName attribute for this Event or Property
///
public void SetRTSpecialName() { flags |= rtsSpecialName; }
public bool HasRTSSpecialName() { return (flags & rtsSpecialName) != 0; }
public void ClearRTSSpecialName() { flags &= noRTSSpecialName; }
public string Name() { return name; }
public void SetName(string nam) { name = nam; }
internal void AddMethod(MethodSemantics meth)
{
if (tide == methods.Length)
{
MethodSemantics[] mTmp = methods;
methods = new MethodSemantics[tide * 2];
for (int i = 0; i < tide; i++)
{
methods[i] = mTmp[i];
}
}
methods[tide++] = meth;
}
public void AddMethod(MethodDef meth, MethodType mType)
{
AddMethod(new MethodSemantics(mType, meth, this));
}
public MethodDef GetMethod(MethodType mType)
{
for (int i = 0; i < tide; i++)
{
if (methods[i].GetMethodType() == mType)
return methods[i].GetMethod();
}
return null;
}
public void RemoveMethod(MethodDef meth)
{
bool found = false;
for (int i = 0; i < tide; i++)
{
if (found)
methods[i - 1] = methods[i];
else if (methods[i].GetMethod() == meth)
found = true;
}
}
public void RemoveMethod(MethodType mType)
{
bool found = false;
for (int i = 0; i < tide; i++)
{
if (found)
methods[i - 1] = methods[i];
else if (methods[i].GetMethodType() == mType)
found = true;
}
}
internal void SetParent(ClassDef paren)
{
parent = paren;
}
internal ClassDef GetParent()
{
return parent;
}
}
/*****************************************************************************/
///
/// Descriptor for an event
///
public class Event : Feature
{
Type eventType;
uint typeIx = 0;
/*-------------------- Constructors ---------------------------------*/
internal Event(string name, Type eType, ClassDef parent)
: base(name, parent)
{
eventType = eType;
tabIx = MDTable.Event;
}
internal Event(PEReader buff)
{
flags = buff.ReadUInt16();
name = buff.GetString();
typeIx = buff.GetCodedIndex(CIx.TypeDefOrRef);
tabIx = MDTable.Event;
}
internal static void Read(PEReader buff, TableRow[] events)
{
for (int i = 0; i < events.Length; i++)
events[i] = new Event(buff);
}
internal static string[] ReadNames(PEReader buff, ClassDef theClass, uint classIx)
{
return Feature.GetFeatureNames(buff, MDTable.Event, MDTable.EventMap, theClass, classIx);
}
internal override void Resolve(PEReader buff)
{
eventType = (Type)buff.GetCodedElement(CIx.TypeDefOrRef, typeIx);
}
/*------------------------- public set and get methods --------------------------*/
public Type GetEventType() { return eventType; }
/*----------------------------- internal functions ------------------------------*/
internal void ChangeRefsToDefs(ClassDef newType, ClassDef[] oldTypes)
{
throw new NotYetImplementedException("Merge for Events");
}
internal sealed override void BuildTables(MetaDataOut md)
{
md.AddToTable(MDTable.Event, this);
nameIx = md.AddToStringsHeap(name);
eventType.BuildMDTables(md);
for (int i = 0; i < tide; i++)
{
methods[i].BuildMDTables(md);
}
}
internal override void BuildCILInfo(CILWriter output)
{
eventType.BuildCILInfo(output);
}
internal static uint Size(MetaData md)
{
return 2 + md.StringsIndexSize() + md.CodedIndexSize(CIx.TypeDefOrRef);
}
internal sealed override void Write(PEWriter output)
{
output.Write(flags);
output.StringsIndex(nameIx);
output.WriteCodedIndex(CIx.TypeDefOrRef, eventType);
}
internal override void Write(CILWriter output)
{
throw new NotYetImplementedException("Write CIL for event");
}
internal sealed override uint GetCodedIx(CIx code)
{
switch (code)
{
case (CIx.HasCustomAttr): return 10;
case (CIx.HasSemantics): return 0;
}
return 0;
}
}
/**************************************************************************/
///
/// Descriptor for the Property of a class
///
public class Property : Feature
{
internal static readonly byte PropertyTag = 0x8;
Constant constVal;
uint typeBlobIx = 0;
Type[] parList;
Type returnType;
uint numPars = 0;
/*-------------------- Constructors ---------------------------------*/
internal Property(string name, Type retType, Type[] pars, ClassDef parent)
: base(name, parent)
{
returnType = retType;
parList = pars;
if (pars != null) numPars = (uint)pars.Length;
tabIx = MDTable.Property;
}
internal Property(PEReader buff)
{
flags = buff.ReadUInt16();
name = buff.GetString();
typeBlobIx = buff.GetBlobIx();
tabIx = MDTable.Property;
}
internal static void Read(PEReader buff, TableRow[] props)
{
for (int i = 0; i < props.Length; i++)
props[i] = new Property(buff);
}
internal static string[] ReadNames(PEReader buff, ClassDef theClass, uint classIx)
{
return Feature.GetFeatureNames(buff, MDTable.Property, MDTable.PropertyMap, theClass, classIx);
}
internal sealed override void Resolve(PEReader buff)
{
buff.ReadPropertySig(typeBlobIx, this);
}
///
/// Add an initial value for this property
///
/// the initial value for this property
public void AddInitValue(Constant constVal)
{
this.constVal = constVal;
}
public Constant GetInitValue() { return constVal; }
public void RemoveInitValue() { constVal = null; }
public Type GetPropertyType() { return returnType; }
public void SetPropertyType(Type pType) { returnType = pType; }
public Type[] GetPropertyParams() { return parList; }
public void SetPropertyParams(Type[] parTypes)
{
parList = parTypes;
if (parList != null) numPars = (uint)parList.Length;
}
internal void ChangeRefsToDefs(ClassDef newType, ClassDef[] oldTypes)
{
throw new NotYetImplementedException("Merge for Properties");
}
internal sealed override void BuildTables(MetaDataOut md)
{
md.AddToTable(MDTable.Property, this);
nameIx = md.AddToStringsHeap(name);
for (int i = 0; i < numPars; i++)
parList[i].BuildMDTables(md);
for (int i = 0; i < tide; i++)
methods[i].BuildMDTables(md);
if (constVal != null)
{
ConstantElem constElem = new ConstantElem(this, constVal);
constElem.BuildMDTables(md);
}
}
internal sealed override void BuildSignatures(MetaDataOut md)
{
MemoryStream sig = new MemoryStream();
sig.WriteByte(PropertyTag);
MetaDataOut.CompressNum(BlobUtil.CompressUInt(numPars), sig);
returnType.TypeSig(sig);
for (int i = 0; i < numPars; i++)
{
parList[i].BuildSignatures(md);
parList[i].TypeSig(sig);
}
typeBlobIx = md.AddToBlobHeap(sig.ToArray());
done = false;
}
internal override void BuildCILInfo(CILWriter output)
{
returnType.BuildCILInfo(output);
for (int i = 0; i < numPars; i++)
{
parList[i].BuildCILInfo(output);
}
}
internal static uint Size(MetaData md)
{
return 2 + md.StringsIndexSize() + md.BlobIndexSize();
}
internal sealed override void Write(PEWriter output)
{
output.Write(flags);
output.StringsIndex(nameIx);
output.BlobIndex(typeBlobIx);
}
internal override void Write(CILWriter output)
{
throw new NotYetImplementedException("Write CIL for property");
}
internal sealed override uint GetCodedIx(CIx code)
{
switch (code)
{
case (CIx.HasCustomAttr): return 9;
case (CIx.HasConstant): return 2;
case (CIx.HasSemantics): return 1;
}
return 0;
}
}
}