singrdk/base/Windows/mkmsil/msil/MetaDataCustomAttribute.cs

721 lines
29 KiB
C#
Raw Normal View History

2008-11-17 18:29:00 -05:00
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
using System;
namespace Bartok.MSIL
{
using System.IO;
public class MetaDataCustomAttribute: MetaDataObject {
// Constructor Methods
internal MetaDataCustomAttribute(int parentIndex,
MetaDataObject type,
byte[] buffer) {
this.parentIndex = parentIndex;
this.type = type;
this.buffer = buffer;
}
// This is technically not a constructor method, but it is meant to
// be used to set up the object
internal void resolveReferences(MetaDataLoader loader) {
this.parent = loader.getHasCustomAttribute(this.parentIndex);
this.parent.AddCustomAttribute(this);
}
// Resolve all the custom attributes found in the assemblies registered
// in 'resolver', using all the type information found in 'resolver' and
// 'resolvers'.
internal void resolveReferences(MetaDataResolver resolver,
MetaDataResolver[] resolvers)
{
if (this.buffer[0] != 0x01 || this.buffer[1] != 0x00) {
throw new MetaDataLoader.IllegalMetaDataFormatException("Custom Attribute doesn't start with 0x0001!");
}
SignatureMethod signature;
if (this.type is MetaDataMethod) {
MetaDataMethod method = (MetaDataMethod) this.type;
signature = (SignatureMethod) method.Signature;
if (!method.Name.Equals(".ctor")) {
throw new MetaDataLoader.IllegalMetaDataFormatException("Custom attribute with unexpected method name: "+method.Name);
}
this.typeDefOrRef = method.Parent;
this.name = method.Parent.FullName;
}
else if (this.type is MetaDataMemberRef) {
MetaDataMemberRef memberRef = (MetaDataMemberRef) this.type;
signature = (SignatureMethod) memberRef.Signature;
if (!memberRef.Name.Equals(".ctor")) {
throw new MetaDataLoader.IllegalMetaDataFormatException("Custom attribute with unexpected memberRef name: "+memberRef.Name);
}
MetaDataObject methodParent = memberRef.Class;
this.typeDefOrRef = methodParent;
if (methodParent is MetaDataTypeDefinition) {
this.name = ((MetaDataTypeDefinition) methodParent).FullName;
}
else if (methodParent is MetaDataTypeReference) {
this.name = ((MetaDataTypeReference) methodParent).FullName;
}
else {
throw new MetaDataLoader.IllegalMetaDataFormatException("Custom attribute with unexpected class type: "+methodParent);
}
}
else {
throw new MetaDataLoader.IllegalMetaDataFormatException("Custom attribute with unexpected type: "+this.type);
}
Signature.Param[] parameters = signature.Parameters;
int fixedCount = parameters.Length;
this.fixedArgs = new Object[fixedCount];
MemoryStream stream =
new MemoryStream(this.buffer, 2, this.buffer.Length - 2, false);
BinaryReader reader = new BinaryReader(stream);
for (int i = 0; i < fixedCount; i++) {
Signature.Param parameter = parameters[i];
Signature.Type paramType = parameter.Type;
Object value =
ExtractParameter(paramType, reader, resolver, resolvers);
fixedArgs[i] = value;
}
short namedCount = ((reader.PeekChar() == -1) ?
(short) 0 :
reader.ReadInt16());
if (namedCount > this.buffer.Length &&
this.Name.Equals("System.Runtime.CompilerServices.RequiredAttributeAttribute")) {
// Some CLR libraries have been compiled against a version of
// mscorlib that had a fixed parameter to RequiredAttribute.
// Simply ignore whatever the parameter was!
namedCount = 0;
}
this.namedArgs = new NamedArg[namedCount];
for (int i = 0; i < namedCount; i++) {
SerializationTypes propOrField = (SerializationTypes)
reader.ReadByte();
ElementTypes fieldType = (ElementTypes) reader.ReadByte();
ElementTypes arrayType = ElementTypes.END;
switch (fieldType) {
case ElementTypes.SZARRAY: {
arrayType = (ElementTypes) reader.ReadByte();
if (arrayType == (ElementTypes) SerializationTypes.ENUM) {
throw new Exception("Not implemented: Array of ENUM "+
"for named field/property");
}
break;
}
case (ElementTypes) SerializationTypes.ENUM: {
String enumName = ExtractString(reader);
if (enumName.Length == 0) {
throw new Exception("Empty enum name");
}
// Hope it is a 4-byte enum
fieldType = (ElementTypes) SerializationTypes.U4;
break;
}
case (ElementTypes) SerializationTypes.TAGGED_OBJECT: {
throw new Exception("Not implemented: "+fieldType+
" for named field/property");
}
default: {
break;
}
}
String name = ExtractString(reader);
Object value;
if (fieldType == ElementTypes.SZARRAY) {
value = ExtractArrayValue(arrayType, reader);
}
else {
value = ExtractValue(fieldType, reader);
}
if (propOrField == SerializationTypes.FIELD ||
propOrField == SerializationTypes.PROPERTY) {
this.namedArgs[i] =
new NamedArg(propOrField == SerializationTypes.FIELD,
-1, name, value);
}
else {
throw new MetaDataLoader.IllegalMetaDataFormatException("Unknown prop-or-field type: "+propOrField);
}
}
}
private static MetaDataObject ResolveTypeRef(MetaDataResolver resolver,
MetaDataResolver[] resolvers,
MetaDataTypeReference typeRef) {
MetaDataObject result = resolver.ResolveTypeRef(typeRef);
int i = 0;
while (result == null && i < resolvers.Length) {
MetaDataResolver testResolver = resolvers[i];
i++;
if (testResolver != resolver) {
result = testResolver.ResolveTypeRef(typeRef);
}
}
return result;
}
private static MetaDataTypeDefinition ResolveName(MetaDataResolver resolver,
MetaDataResolver[] resolvers,
String typeName) {
MetaDataTypeDefinition typeDef = resolver.ResolveName(typeName);
int i = 0;
while (typeDef == null && i < resolvers.Length) {
MetaDataResolver testResolver = resolvers[i];
i++;
if (testResolver != resolver) {
typeDef = testResolver.ResolveName(typeName);
}
}
return typeDef;
}
private static Object ExtractParameter(Signature.Type type,
BinaryReader reader,
MetaDataResolver resolver,
MetaDataResolver[] resolvers)
{
switch (type.ElementType) {
case ElementTypes.VALUETYPE: {
MetaDataObject classObject = type.ClassObject;
if (classObject is MetaDataTypeReference) {
MetaDataTypeReference classReference =
(MetaDataTypeReference) classObject;
MetaDataObject resolvedObject =
ResolveTypeRef(resolver, resolvers, classReference);
if (resolvedObject is MetaDataTypeDefinition) {
classObject = resolvedObject;
}
}
if (classObject is MetaDataTypeReference) {
// We will simply assume it is an I4 enum
Console.Out.WriteLine("====>>> WARNING: Making I4 enum assumption for "+classObject);
return reader.ReadInt32();
}
else if (classObject is MetaDataTypeDefinition) {
MetaDataTypeDefinition classDef =
(MetaDataTypeDefinition) classObject;
MetaDataObject superClass = classDef.Extends;
String superName;
if (superClass is MetaDataTypeDefinition) {
superName =
((MetaDataTypeDefinition) superClass).FullName;
}
else if (superClass is MetaDataTypeReference) {
superName =
((MetaDataTypeReference) superClass).FullName;
}
else {
throw new MetaDataLoader.IllegalMetaDataFormatException("Unexpected superclass of valuetype: "+superClass);
}
if (!superName.Equals("System.Enum")) {
throw new MetaDataLoader.IllegalMetaDataFormatException("Found valuetype that wasn't an Enum");
}
return ExtractEnumValue(classDef, reader,
resolver, resolvers);
}
else {
throw new MetaDataLoader.IllegalMetaDataFormatException("Unexpected valuetype class: "+classObject);
}
}
case ElementTypes.CLASS: {
MetaDataObject classObject = type.ClassObject;
if (classObject is MetaDataTypeReference) {
MetaDataTypeReference classReference =
(MetaDataTypeReference) classObject;
MetaDataObject resolvedObject =
ResolveTypeRef(resolver, resolvers, classReference);
if (resolvedObject is MetaDataTypeDefinition) {
classObject = resolvedObject;
}
}
String className;
if (classObject is MetaDataTypeReference) {
className =
((MetaDataTypeReference) classObject).FullName;
}
else if (classObject is MetaDataTypeDefinition) {
className =
((MetaDataTypeDefinition) classObject).FullName;
}
else {
throw new MetaDataLoader.IllegalMetaDataFormatException("Unexpected class: "+classObject);
}
if (className.Equals("System.String")) {
return ExtractString(reader);
}
else if (className.Equals("System.Object")) {
goto case ElementTypes.OBJECT;
}
else if (className.Equals("System.Type")) {
return ExtractString(reader);
}
if (!(classObject is MetaDataTypeDefinition)) {
throw new MetaDataLoader.IllegalMetaDataFormatException("Cannot determine whether the following is an array: "+classObject);
}
MetaDataObject superClass =
((MetaDataTypeDefinition) classObject).Extends;
Console.WriteLine("class is "+classObject);
throw new Exception("Not implemented: object encoding an array");
}
case ElementTypes.OBJECT:
case (ElementTypes) SerializationTypes.TAGGED_OBJECT: {
SerializationTypes objectType = (SerializationTypes)
reader.ReadByte();
switch (objectType) {
case SerializationTypes.ENUM: {
String typeName = ExtractString(reader);
// Some Stringified type names include a bunch of
// information past the type, none of which we
// are concerned about for the moment.
int nameEnd = typeName.IndexOf(',');
if (nameEnd >= 0) {
typeName = typeName.Substring(0, nameEnd);
}
// A type defined within another type has a "+"
// as the separator. Convert it to ".", which is
// the convention the rest of the reader uses.
typeName = typeName.Replace('+','.');
MetaDataTypeDefinition typeDef =
ResolveName(resolver, resolvers, typeName);
if (typeDef == null) {
throw new Exception("No typedef for "+typeName);
}
return ExtractEnumValue(typeDef, reader,
resolver, resolvers);
}
case SerializationTypes.TYPE: {
return ExtractValue((ElementTypes) objectType,
reader);
}
default: {
throw new Exception("Found OBJECT type with type "+objectType);
}
}
}
case ElementTypes.SZARRAY: {
return ExtractArrayValue(type.TypeObject, reader,
resolver, resolvers);
}
default: {
return ExtractValue(type.ElementType, reader);
}
}
}
private static Object ExtractValue(ElementTypes type,
BinaryReader reader)
{
switch (type) {
case ElementTypes.BOOLEAN:
return reader.ReadBoolean();
case ElementTypes.CHAR:
return (char) reader.ReadUInt16();
case ElementTypes.I1:
return reader.ReadSByte();
case ElementTypes.U1:
return reader.ReadByte();
case ElementTypes.I2:
return reader.ReadInt16();
case ElementTypes.U2:
return reader.ReadUInt16();
case ElementTypes.I4:
return reader.ReadInt32();
case ElementTypes.U4:
return reader.ReadUInt32();
case ElementTypes.I8:
return reader.ReadInt64();
case ElementTypes.U8:
return reader.ReadUInt64();
case ElementTypes.R4:
return reader.ReadSingle();
case ElementTypes.R8:
return reader.ReadDouble();
case ElementTypes.STRING:
case (ElementTypes) SerializationTypes.TYPE:
return ExtractString(reader);
default:
throw new MetaDataLoader.IllegalMetaDataFormatException("Found unexpected type "+type+" in custom attribute parameter");
}
}
private static String ExtractString(BinaryReader reader) {
byte firstByte = reader.ReadByte();
if (firstByte == 0xFF) {
return null;
}
int size;
if ((firstByte & 0x80) == 0) {
// encoded in a single byte
size = firstByte;
}
else if ((firstByte & 0x40) == 0) {
// encoded in two bytes
size = unchecked(((firstByte & 0x3F) << 8) |
reader.ReadByte());
}
else {
// encoded in four bytes
size = unchecked((int) (((firstByte & 0x3F) << 24) |
(reader.ReadByte() << 16) |
(reader.ReadByte() << 8) |
(reader.ReadByte())));
}
byte[] bytes = reader.ReadBytes(size);
if (bytes.Length != size) {
throw new Exception("Didn't get the bytes requested");
}
return (new System.Text.UTF8Encoding()).GetString(bytes);
}
private static Object ExtractEnumValue(MetaDataTypeDefinition typeDef,
BinaryReader reader,
MetaDataResolver resolver,
MetaDataResolver[] resolvers)
{
MetaDataField[] classFields = typeDef.Fields;
for (int i = 0; i < classFields.Length; i++) {
if ((classFields[i].Flags & (int) MetaDataField.FieldAttributes.Static) == 0) {
if (!classFields[i].Name.Equals("value__")) {
throw new MetaDataLoader.IllegalMetaDataFormatException("Found enum with non-static field "+classFields[i].Name);
}
return ExtractParameter(classFields[i].Signature.FieldType,
reader, resolver, resolvers);
}
}
throw new MetaDataLoader.IllegalMetaDataFormatException("Found enum without non-static field");
}
private static Object ExtractArrayValue(Signature.Type type,
BinaryReader reader,
MetaDataResolver resolver,
MetaDataResolver[] resolvers)
{
int arraySize = reader.ReadInt32();
if (arraySize >= 0) {
ElementTypes elementType = type.ElementType;
if (elementType == ElementTypes.CLASS) {
Object[] array = new Object[arraySize];
for (int i = 0; i < arraySize; i++) {
array[i] = ExtractParameter(type, reader,
resolver, resolvers);
}
return array;
}
else {
return ExtractArrayValue(elementType, arraySize, reader);
}
}
else {
throw new Exception("Not implemented: custom attribute class "+
"array with negative length");
}
}
private static Object ExtractArrayValue(ElementTypes elementType,
BinaryReader reader)
{
int arraySize = reader.ReadInt32();
if (arraySize >= 0) {
return ExtractArrayValue(elementType, arraySize, reader);
}
else {
throw new Exception("Not implemented: custom atribute array "+
"with negative length");
}
}
private static Object ExtractArrayValue(ElementTypes elementType,
int arraySize,
BinaryReader reader)
{
switch (elementType) {
case ElementTypes.BOOLEAN: {
bool[] array = new bool[arraySize];
for (int i = 0; i < arraySize; i++) {
array[i] = reader.ReadBoolean();
}
return array;
}
case ElementTypes.CHAR: {
char[] array = new char[arraySize];
for (int i = 0; i < arraySize; i++) {
array[i] = (char) reader.ReadUInt16();
}
return array;
}
case ElementTypes.I1: {
sbyte[] array = new sbyte[arraySize];
for (int i = 0; i < arraySize; i++) {
array[i] = reader.ReadSByte();
}
return array;
}
case ElementTypes.U1: {
byte[] array = new byte[arraySize];
for (int i = 0; i < arraySize; i++) {
array[i] = reader.ReadByte();
}
return array;
}
case ElementTypes.I2: {
short[] array = new short[arraySize];
for (int i = 0; i < arraySize; i++) {
array[i] = reader.ReadInt16();
}
return array;
}
case ElementTypes.U2: {
ushort[] array = new ushort[arraySize];
for (int i = 0; i < arraySize; i++) {
array[i] = reader.ReadUInt16();
}
return array;
}
case ElementTypes.I4: {
int[] array = new int[arraySize];
for (int i = 0; i < arraySize; i++) {
array[i] = reader.ReadInt32();
}
return array;
}
case ElementTypes.U4: {
uint[] array = new uint[arraySize];
for (int i = 0; i < arraySize; i++) {
array[i] = reader.ReadUInt32();
}
return array;
}
case ElementTypes.I8: {
long[] array = new long[arraySize];
for (int i = 0; i < arraySize; i++) {
array[i] = reader.ReadInt64();
}
return array;
}
case ElementTypes.U8: {
ulong[] array = new ulong[arraySize];
for (int i = 0; i < arraySize; i++) {
array[i] = reader.ReadUInt64();
}
return array;
}
case ElementTypes.R4: {
float[] array = new float[arraySize];
for (int i = 0; i < arraySize; i++) {
array[i] = reader.ReadSingle();
}
return array;
}
case ElementTypes.R8: {
double[] array = new double[arraySize];
for (int i = 0; i < arraySize; i++) {
array[i] = reader.ReadDouble();
}
return array;
}
case ElementTypes.STRING: {
String[] array = new String[arraySize];
for (int i = 0; i < arraySize; i++) {
array[i] = ExtractString(reader);
}
return array;
}
default:
throw new Exception("Not implemented: custom attribute "+
"array of type "+elementType);
}
}
// Access Methods
// Who owns this custom attribute
public MetaDataObject Parent {
get { return this.parent; }
}
// The fully qualified name of the custom attribute
public String Name {
get { return this.name; }
}
// The type definition or reference of the custom attribute
public MetaDataObject TypeDefOrRef {
get { return this.typeDefOrRef; }
}
// The constructor method or memberref of the custom attribute
public MetaDataObject Type {
get { return this.type; }
}
// The array of arguments to the custom attribute constructor
public Object[] FixedArgs {
get { return this.fixedArgs; }
}
// The array of custom attribute fields and properties explicitly set
public NamedArg[] NamedArgs {
get { return this.namedArgs; }
}
// Debug Methods
public override String ToString() {
return ("MetaDataCustomAttribute("+
this.type+","+this.fixedArgs+","+this.namedArgs+","+
this.parentIndex+
(this.parent==null?"":("<"+this.parent.ToString()+">"))+
")["+new MetaDataBlob(this.buffer)+"]");
}
public override String ToStringLong() {
System.Text.StringBuilder sb =
new System.Text.StringBuilder("MetaDataCustomAttribute(");
sb.Append(this.type);
sb.Append(",");
if (this.fixedArgs != null) {
sb.Append("FixedArgs(");
for (int i = 0; i < this.fixedArgs.Length; i++) {
sb.Append(this.fixedArgs[i]);
sb.Append(",");
}
sb.Append("),");
}
else {
sb.Append("FixedArgs(),");
}
if (this.namedArgs != null) {
sb.Append("NamedArgs(");
for (int i = 0; i < this.namedArgs.Length; i++) {
sb.Append(this.namedArgs[i]);
sb.Append(",");
}
sb.Append("),");
}
else {
sb.Append("NamedArgs(),");
}
sb.Append(this.parent);
sb.Append("(");
sb.Append(this.parentIndex);
sb.Append("))[");
sb.Append(new MetaDataBlob(this.buffer));
sb.Append("]");
return sb.ToString();
}
// State
private readonly byte[] buffer;
private readonly int parentIndex;
private String name;
private MetaDataObject parent;
private MetaDataObject type;
private MetaDataObject typeDefOrRef;
private Object[] fixedArgs;
private NamedArg[] namedArgs;
public class FixedArg {
// A negative value for arrayDim signifies a nonArray
internal FixedArg(SerializationTypes type, int arrayDim,
Object value) {
this.arrayDim = arrayDim;
this.type = type;
this.value = value;
}
public bool IsArray {
get { return this.arrayDim >= 0; }
}
public int ArrayDim {
get {
if (this.arrayDim < 0) {
throw new Exception("FixedArg is not an array");
}
return this.arrayDim;
}
}
public SerializationTypes Type {
get { return this.type; }
}
public Object Value {
get { return this.value; }
}
public override String ToString() {
return ("FixedArg("+this.type+((arrayDim<0)?"":("["+arrayDim+"]"))+"->"+this.value+")");
}
private int arrayDim;
private SerializationTypes type;
private Object value;
}
public class NamedArg {
internal NamedArg(bool isFieldArg, int arrayDim,
String name, Object value)
{
this.isFieldArg = isFieldArg;
this.arrayDim = arrayDim;
this.type = type;
this.name = name;
this.value = value;
}
public bool IsFieldArg {
get { return this.isFieldArg; }
}
public bool IsArray {
get { return this.arrayDim >= 0; }
}
public int ArrayDim {
get {
if (this.arrayDim < 0) {
throw new Exception("NamedArg is not an array");
}
return this.arrayDim;
}
}
public SerializationTypes Type {
get { return this.type; }
}
public String Name {
get { return this.name; }
}
public Object Value {
get { return this.value; }
}
public override String ToString() {
return ("NamedArg("+this.name+":"+this.type+((arrayDim<0)?"":("["+arrayDim+"]"))+"->"+this.value+")");
}
private bool isFieldArg;
private int arrayDim;
private String name;
private SerializationTypes type;
private Object value;
}
}
}