/*
* 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;
namespace QUT.PERWAPI
{
/**************************************************************************/
// Classes used to describe constant values
/**************************************************************************/
///
/// Descriptor for a constant value, to be written in the blob heap
///
public abstract class Constant
{
protected uint size = 0;
internal ElementType type;
protected uint blobIndex;
internal MetaDataOut addedToBlobHeap;
/*-------------------- Constructors ---------------------------------*/
internal Constant() { }
internal virtual uint GetBlobIndex(MetaDataOut md) { return 0; }
internal uint GetSize() { return size; }
internal byte GetTypeIndex() { return (byte)type; }
internal virtual void Write(BinaryWriter bw) { }
internal virtual void Write(CILWriter output)
{
throw new NotYetImplementedException("Constant values for CIL");
}
}
/**************************************************************************/
public abstract class BlobConstant : Constant { }
/**************************************************************************/
///
/// Boolean constant
///
public class BoolConst : BlobConstant
{
bool val;
/*-------------------- Constructors ---------------------------------*/
///
/// Create a new boolean constant with the value "val"
///
/// value of this boolean constant
public BoolConst(bool val)
{
this.val = val;
size = 1;
type = ElementType.Boolean;
}
public bool GetBool()
{
return val;
}
internal sealed override uint GetBlobIndex(MetaDataOut md)
{
if (addedToBlobHeap != md)
{
if (val) blobIndex = md.AddToBlobHeap(1, 1);
else blobIndex = md.AddToBlobHeap(0, 1);
addedToBlobHeap = md;
}
return blobIndex;
}
internal sealed override void Write(BinaryWriter bw)
{
if (val) bw.Write((sbyte)1);
else bw.Write((sbyte)0);
}
}
/**************************************************************************/
public class CharConst : BlobConstant
{
char val;
/*-------------------- Constructors ---------------------------------*/
public CharConst(char val)
{
this.val = val;
size = 2;
type = ElementType.Char;
}
internal CharConst(PEReader buff)
{
val = buff.ReadChar();
size = 2;
type = ElementType.Char;
}
public char GetChar()
{ // KJG addition 2005-Mar-01
return val;
}
internal sealed override uint GetBlobIndex(MetaDataOut md)
{
if (addedToBlobHeap != md)
{
blobIndex = md.AddToBlobHeap(val);
addedToBlobHeap = md;
}
return blobIndex;
}
internal sealed override void Write(BinaryWriter bw)
{
bw.Write(val);
}
}
/**************************************************************************/
public class NullRefConst : BlobConstant
{
/*-------------------- Constructors ---------------------------------*/
public NullRefConst()
{
size = 4;
type = ElementType.Class;
}
internal NullRefConst(PEReader buff)
{
uint junk = buff.ReadUInt32();
size = 4;
type = ElementType.Class;
}
internal sealed override uint GetBlobIndex(MetaDataOut md)
{
if (addedToBlobHeap != md)
{
blobIndex = md.AddToBlobHeap(0, 4);
addedToBlobHeap = md;
}
return blobIndex;
}
internal sealed override void Write(BinaryWriter bw)
{
bw.Write((int)0);
}
}
/**************************************************************************/
///
/// Constant array
///
public class ArrayConst : BlobConstant
{
Constant[] elements;
/*-------------------- Constructors ---------------------------------*/
public ArrayConst(Constant[] elems)
{
type = ElementType.SZArray;
size = 5; // one byte for SZARRAY, 4 bytes for length
elements = elems;
for (int i = 0; i < elements.Length; i++)
{
size += elements[i].GetSize();
}
}
public Constant[] GetArray()
{
return elements;
}
internal sealed override uint GetBlobIndex(MetaDataOut md)
{
if (addedToBlobHeap != md)
{
MemoryStream str = new MemoryStream();
BinaryWriter bw = new BinaryWriter(str);
Write(bw);
blobIndex = md.AddToBlobHeap(str.ToArray());
addedToBlobHeap = md;
}
return blobIndex;
}
internal sealed override void Write(BinaryWriter bw)
{
bw.Write((byte)type);
bw.Write(elements.Length);
for (int i = 0; i < elements.Length; i++)
{
elements[i].Write(bw);
}
}
}
/**************************************************************************/
public class ClassTypeConst : BlobConstant
{
string name;
Class desc;
/*-------------------- Constructors ---------------------------------*/
public ClassTypeConst(string className)
{
name = className;
type = ElementType.ClassType;
}
public ClassTypeConst(Class classDesc)
{
desc = classDesc;
type = ElementType.ClassType;
}
public Class GetClass()
{
return desc;
}
public String GetClassName()
{
if (name == null) name = desc.TypeName();
// CHECK - ClassName or TypeName
// if (name == null) return desc.ClassName();
return name;
}
internal override void Write(BinaryWriter bw)
{
if (name == null) name = desc.TypeName();
// CHECK - ClassName or TypeName
// if (name == null) name = desc.ClassName();
bw.Write(name);
}
}
/**************************************************************************/
public class BoxedSimpleConst : BlobConstant
{
SimpleConstant sConst;
/*-------------------- Constructors ---------------------------------*/
public BoxedSimpleConst(SimpleConstant con)
{
sConst = con;
type = (ElementType)sConst.GetTypeIndex();
}
public SimpleConstant GetConst()
{
return sConst;
}
internal override void Write(BinaryWriter bw)
{
bw.Write((byte)type);
sConst.Write(bw);
}
}
/**************************************************************************/
///
/// Descriptor for a constant value
///
public abstract class DataConstant : Constant
{
private uint dataOffset = 0;
/*-------------------- Constructors ---------------------------------*/
internal DataConstant() { }
public uint DataOffset
{
get { return dataOffset; }
set { dataOffset = value; }
}
}
/**************************************************************************/
///
/// Constant for a memory address
///
public class AddressConstant : DataConstant
{
DataConstant data;
/*-------------------- Constructors ---------------------------------*/
public AddressConstant(DataConstant dConst)
{
data = dConst;
size = 4;
type = ElementType.TypedByRef;
}
internal AddressConstant(PEReader buff)
{
}
public DataConstant GetConst()
{
return data;
}
internal sealed override void Write(BinaryWriter bw)
{
((PEWriter)bw).WriteDataRVA(data.DataOffset);
}
}
/**************************************************************************/
public class ByteArrConst : DataConstant
{
byte[] val;
/*-------------------- Constructors ---------------------------------*/
public ByteArrConst(byte[] val)
{
this.val = val;
size = (uint)val.Length;
}
public byte[] GetArray()
{
return val;
}
internal sealed override uint GetBlobIndex(MetaDataOut md)
{
if (addedToBlobHeap != md)
{
blobIndex = md.AddToBlobHeap(val);
addedToBlobHeap = md;
}
return blobIndex;
}
internal sealed override void Write(BinaryWriter bw)
{
bw.Write(val);
}
}
/**************************************************************************/
public class RepeatedConstant : DataConstant
{
DataConstant data;
uint repCount;
/*-------------------- Constructors ---------------------------------*/
public RepeatedConstant(DataConstant dConst, int repeatCount)
{
data = dConst;
repCount = (uint)repeatCount;
type = ElementType.SZArray;
size = data.GetSize() * repCount;
}
public DataConstant GetConst()
{
return data;
}
public uint GetCount()
{
return repCount;
}
internal sealed override void Write(BinaryWriter bw)
{
for (int i = 0; i < repCount; i++)
{
data.Write(bw);
}
}
}
/**************************************************************************/
public class StringConst : DataConstant
{
string val;
byte[] strBytes;
/*-------------------- Constructors ---------------------------------*/
public StringConst(string val)
{
this.val = val;
size = (uint)val.Length; // need to add null ??
type = ElementType.String;
}
internal StringConst(byte[] sBytes)
{
strBytes = sBytes;
size = (uint)strBytes.Length;
type = ElementType.String;
}
public string GetString()
{
return val;
}
public byte[] GetStringBytes()
{
return strBytes;
}
internal sealed override uint GetBlobIndex(MetaDataOut md)
{
if (addedToBlobHeap != md)
{
if (val == null)
blobIndex = md.AddToBlobHeap(strBytes);
else
blobIndex = md.AddToBlobHeap(val);
addedToBlobHeap = md;
}
return blobIndex;
}
internal sealed override void Write(BinaryWriter bw)
{
if ((val == null) && (strBytes != null))
{
bw.Write(strBytes);
}
else
bw.Write(val);
}
}
/**************************************************************************/
public abstract class SimpleConstant : DataConstant { }
/**************************************************************************/
public class IntConst : SimpleConstant
{
long val;
/*-------------------- Constructors ---------------------------------*/
public IntConst(sbyte val)
{
this.val = val;
size = 1; //8;
type = ElementType.I8;
}
public IntConst(short val)
{
this.val = val;
size = 2; //16;
type = ElementType.I2;
}
public IntConst(int val)
{
this.val = val;
size = 4; //32;
type = ElementType.I4;
}
public IntConst(long val)
{
this.val = val;
size = 8; //64;
type = ElementType.I8;
}
internal IntConst(PEReader buff, int numBytes)
{
switch (numBytes)
{
case (1): val = buff.ReadSByte();
type = ElementType.I8;
break;
case (2): val = buff.ReadInt16();
type = ElementType.I2;
break;
case (4): val = buff.ReadInt32();
type = ElementType.I4;
break;
case (8): val = buff.ReadInt64();
type = ElementType.I8;
break;
default: val = 0;
break;
}
size = (uint)numBytes; // * 4;
}
public int GetIntSize()
{
return (int)size;
}
public ElementType GetIntType()
{
return type;
}
public int GetInt()
{
if (size < 8)
return (int)val;
else
throw new Exception("Constant is long");
}
public long GetLong()
{
return val;
}
internal sealed override uint GetBlobIndex(MetaDataOut md)
{
if (addedToBlobHeap != md)
{
blobIndex = md.AddToBlobHeap(val, size);
//switch (size) {
// case (1) : md.AddToBlobHeap((sbyte)val); break;
// case (2) : md.AddToBlobHeap((short)val); break;
// case (4) : md.AddToBlobHeap((int)val); break;
// default : md.AddToBlobHeap(val); break;
//}
addedToBlobHeap = md;
}
return blobIndex;
}
internal sealed override void Write(BinaryWriter bw)
{
switch (size)
{
case (1): bw.Write((sbyte)val); break;
case (2): bw.Write((short)val); break;
case (4): bw.Write((int)val); break;
default: bw.Write(val); break;
}
}
}
/**************************************************************************/
public class UIntConst : SimpleConstant
{
ulong val;
/*-------------------- Constructors ---------------------------------*/
public UIntConst(byte val)
{
this.val = val;
size = 1;
type = ElementType.U8;
}
public UIntConst(ushort val)
{
this.val = val;
size = 2;
type = ElementType.U2;
}
public UIntConst(uint val)
{
this.val = val;
size = 4;
type = ElementType.U4;
}
public UIntConst(ulong val)
{
this.val = val;
size = 8;
type = ElementType.U8;
}
public int GetIntSize()
{
return (int)size;
}
public ElementType GetUIntType()
{
return type;
}
public uint GetUInt()
{
return (uint)val;
}
public ulong GetULong()
{
return val;
}
public long GetLong()
{ // KJG addition
if (val <= (ulong)(System.Int64.MaxValue))
return (long)val;
else
throw new Exception("UInt Constant too large");
}
public long GetULongAsLong()
{ // KJG addition
return (long)val;
}
internal sealed override uint GetBlobIndex(MetaDataOut md)
{
if (addedToBlobHeap != md)
{
blobIndex = md.AddToBlobHeap(val, size);
//switch (size) {
// case (1) : blobIndex = md.AddToBlobHeap((byte)val); break;
// case (2) : blobIndex = md.AddToBlobHeap((ushort)val); break;
// case (4) : blobIndex = md.AddToBlobHeap((uint)val); break;
// default : blobIndex = md.AddToBlobHeap(val); break;
//}
addedToBlobHeap = md;
}
return blobIndex;
}
internal sealed override void Write(BinaryWriter bw)
{
switch (size)
{
case (1): bw.Write((byte)val); break;
case (2): bw.Write((ushort)val); break;
case (4): bw.Write((uint)val); break;
default: bw.Write(val); break;
}
}
}
/**************************************************************************/
public class FloatConst : SimpleConstant
{
float val;
/*-------------------- Constructors ---------------------------------*/
public FloatConst(float val)
{
this.val = val;
size = 4;
type = ElementType.R4;
}
internal FloatConst(PEReader buff)
{
val = buff.ReadSingle();
size = 4;
type = ElementType.R4;
}
public float GetFloat()
{
return val;
}
public double GetDouble()
{ // KJG addition 2005-Mar-01
return (double)val;
}
internal sealed override uint GetBlobIndex(MetaDataOut md)
{
if (addedToBlobHeap != md)
{
blobIndex = md.AddToBlobHeap(val);
addedToBlobHeap = md;
}
return blobIndex;
}
internal sealed override void Write(BinaryWriter bw)
{
bw.Write(val);
}
}
/**************************************************************************/
public class DoubleConst : SimpleConstant
{
double val;
/*-------------------- Constructors ---------------------------------*/
public DoubleConst(double val)
{
this.val = val;
size = 8;
type = ElementType.R8;
}
internal DoubleConst(PEReader buff)
{
val = buff.ReadDouble();
size = 8;
type = ElementType.R8;
}
public double GetDouble()
{ // KJG addition 2005-Mar-01
return val;
}
internal sealed override uint GetBlobIndex(MetaDataOut md)
{
if (addedToBlobHeap != md)
{
blobIndex = md.AddToBlobHeap(val);
addedToBlobHeap = md;
}
return blobIndex;
}
internal sealed override void Write(BinaryWriter bw)
{
bw.Write(val);
}
}
}