721 lines
29 KiB
C#
721 lines
29 KiB
C#
|
//
|
||
|
// 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;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|