2 Copyright (C) 2008 Jeroen Frijters
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
26 using System.Collections.Generic;
27 using System.Diagnostics;
28 using IKVM.Reflection.Writer;
30 namespace IKVM.Reflection.Emit
32 public sealed class CustomAttributeBuilder
34 private readonly ConstructorInfo con;
35 private readonly byte[] blob;
36 private readonly object[] constructorArgs;
37 private readonly PropertyInfo[] namedProperties;
38 private readonly object[] propertyValues;
39 private readonly FieldInfo[] namedFields;
40 private readonly object[] fieldValues;
42 internal CustomAttributeBuilder(ConstructorInfo con, byte[] blob)
48 public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs)
49 : this(con, constructorArgs, null, null, null,null)
53 public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, FieldInfo[] namedFields, object[] fieldValues)
54 : this(con, constructorArgs, null, null, namedFields, fieldValues)
58 public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, PropertyInfo[] namedProperties, object[] propertyValues)
59 : this(con, constructorArgs, namedProperties, propertyValues, null, null)
63 public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, PropertyInfo[] namedProperties, object[] propertyValues, FieldInfo[] namedFields, object[] fieldValues)
66 this.constructorArgs = constructorArgs;
67 this.namedProperties = namedProperties;
68 this.propertyValues = propertyValues;
69 this.namedFields = namedFields;
70 this.fieldValues = fieldValues;
73 private sealed class BlobWriter
75 private readonly ModuleBuilder moduleBuilder;
76 private readonly CustomAttributeBuilder cab;
77 private readonly ByteBuffer bb;
79 internal BlobWriter(ModuleBuilder moduleBuilder, CustomAttributeBuilder cab, ByteBuffer bb)
81 this.moduleBuilder = moduleBuilder;
86 internal void WriteCustomAttributeBlob()
90 ParameterInfo[] pi = cab.con.GetParameters();
91 for (int i = 0; i < pi.Length; i++)
93 WriteFixedArg(pi[i].ParameterType, cab.constructorArgs[i]);
95 WriteNamedArguments(false);
98 internal void WriteNamedArguments(bool forDeclSecurity)
102 if (cab.namedFields != null)
104 named += cab.namedFields.Length;
106 if (cab.namedProperties != null)
108 named += cab.namedProperties.Length;
112 WritePackedLen(named);
116 WriteUInt16((ushort)named);
118 if (cab.namedFields != null)
120 for (int i = 0; i < cab.namedFields.Length; i++)
122 WriteNamedArg(0x53, cab.namedFields[i].FieldType, cab.namedFields[i].Name, cab.fieldValues[i]);
125 if (cab.namedProperties != null)
127 for (int i = 0; i < cab.namedProperties.Length; i++)
129 WriteNamedArg(0x54, cab.namedProperties[i].PropertyType, cab.namedProperties[i].Name, cab.propertyValues[i]);
134 private void WriteNamedArg(byte fieldOrProperty, Type type, string name, object value)
136 WriteByte(fieldOrProperty);
137 WriteFieldOrPropType(type);
139 WriteFixedArg(type, value);
142 private void WriteByte(byte value)
147 private void WriteUInt16(ushort value)
152 private void WriteInt32(int value)
157 private void WriteFixedArg(Type type, object value)
159 Universe u = moduleBuilder.universe;
160 if (type == u.System_String)
162 WriteString((string)value);
164 else if (type == u.System_Type)
166 WriteTypeName((Type)value);
168 else if (type == u.System_Object)
172 type = u.System_String;
174 else if (value is Type)
176 // value.GetType() would return a subclass of Type, but we don't want to deal with that
177 type = u.System_Type;
181 type = u.Import(value.GetType());
183 WriteFieldOrPropType(type);
184 WriteFixedArg(type, value);
186 else if (type.IsArray)
194 Array array = (Array)value;
195 Type elemType = type.GetElementType();
196 WriteInt32(array.Length);
197 foreach (object val in array)
199 WriteFixedArg(elemType, val);
203 else if (type.IsEnum)
205 WriteFixedArg(type.GetEnumUnderlyingTypeImpl(), value);
209 switch (Type.GetTypeCode(type))
211 case TypeCode.Boolean:
212 WriteByte((bool)value ? (byte)1 : (byte)0);
215 WriteUInt16((char)value);
218 WriteByte((byte)(sbyte)value);
221 WriteByte((byte)value);
224 WriteUInt16((ushort)(short)value);
226 case TypeCode.UInt16:
227 WriteUInt16((ushort)value);
230 WriteInt32((int)value);
232 case TypeCode.UInt32:
233 WriteInt32((int)(uint)value);
236 WriteInt64((long)value);
238 case TypeCode.UInt64:
239 WriteInt64((long)(ulong)value);
241 case TypeCode.Single:
242 WriteSingle((float)value);
244 case TypeCode.Double:
245 WriteDouble((double)value);
248 throw new ArgumentException();
253 private void WriteInt64(long value)
258 private void WriteSingle(float value)
263 private void WriteDouble(double value)
268 private void WriteTypeName(Type type)
273 if (type.Assembly == moduleBuilder.Assembly)
275 name = type.FullName;
279 name = type.AssemblyQualifiedName;
285 private void WriteString(string val)
290 private void WritePackedLen(int len)
292 bb.WriteCompressedInt(len);
295 private void WriteFieldOrPropType(Type type)
297 Universe u = type.Module.universe;
298 if (type == u.System_Type)
302 else if (type == u.System_Object)
306 else if (type.IsArray)
309 WriteFieldOrPropType(type.GetElementType());
311 else if (type.IsEnum)
318 switch (Type.GetTypeCode(type))
320 case TypeCode.Boolean:
335 case TypeCode.UInt16:
341 case TypeCode.UInt32:
347 case TypeCode.UInt64:
350 case TypeCode.Single:
353 case TypeCode.Double:
356 case TypeCode.String:
360 throw new ArgumentException();
366 internal bool IsPseudoCustomAttribute
368 get { return con.DeclaringType.IsPseudoCustomAttribute; }
371 internal ConstructorInfo Constructor
376 internal int WriteBlob(ModuleBuilder moduleBuilder)
381 bb = ByteBuffer.Wrap(blob);
385 bb = new ByteBuffer(100);
386 BlobWriter bw = new BlobWriter(moduleBuilder, this, bb);
387 bw.WriteCustomAttributeBlob();
389 return moduleBuilder.Blobs.Add(bb);
392 internal object GetConstructorArgument(int pos)
394 return constructorArgs[pos];
397 internal int ConstructorArgumentCount
399 get { return constructorArgs == null ? 0 : constructorArgs.Length; }
402 internal T? GetFieldValue<T>(string name) where T : struct
404 object val = GetFieldValue(name);
409 else if (val != null)
411 if (typeof(T).IsEnum)
413 Debug.Assert(Enum.GetUnderlyingType(typeof(T)) == val.GetType());
414 return (T)Enum.ToObject(typeof(T), val);
418 Debug.Assert(Enum.GetUnderlyingType(val.GetType()) == typeof(T));
419 return (T)Convert.ChangeType(val, typeof(T));
428 internal object GetFieldValue(string name)
430 if (namedFields != null)
432 for (int i = 0; i < namedFields.Length; i++)
434 if (namedFields[i].Name == name)
436 return fieldValues[i];
443 internal void WriteNamedArgumentsForDeclSecurity(ModuleBuilder moduleBuilder, ByteBuffer bb)
445 BlobWriter bw = new BlobWriter(moduleBuilder, this, bb);
446 bw.WriteNamedArguments(true);
449 internal CustomAttributeData ToData(Assembly asm)
453 return new CustomAttributeData(asm, con, new IKVM.Reflection.Reader.ByteReader(blob, 0, blob.Length));
457 List<CustomAttributeNamedArgument> namedArgs = new List<CustomAttributeNamedArgument>();
458 if (namedProperties != null)
460 for (int i = 0; i < namedProperties.Length; i++)
462 namedArgs.Add(new CustomAttributeNamedArgument(namedProperties[i], new CustomAttributeTypedArgument(namedProperties[i].PropertyType, propertyValues[i])));
465 if (namedFields != null)
467 for (int i = 0; i < namedFields.Length; i++)
469 namedArgs.Add(new CustomAttributeNamedArgument(namedFields[i], new CustomAttributeTypedArgument(namedFields[i].FieldType, fieldValues[i])));
472 return new CustomAttributeData(con, constructorArgs, namedArgs);
476 internal bool HasBlob
478 get { return blob != null; }
481 internal CustomAttributeBuilder DecodeBlob(Assembly asm)
489 return ToData(asm).__ToBuilder();