2 Copyright (C) 2008-2011 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;
29 using IKVM.Reflection.Writer;
31 namespace IKVM.Reflection.Emit
33 public sealed class CustomAttributeBuilder
35 private readonly ConstructorInfo con;
36 private readonly byte[] blob;
37 private readonly object[] constructorArgs;
38 private readonly PropertyInfo[] namedProperties;
39 private readonly object[] propertyValues;
40 private readonly FieldInfo[] namedFields;
41 private readonly object[] fieldValues;
43 internal CustomAttributeBuilder(ConstructorInfo con, byte[] blob)
49 private CustomAttributeBuilder(ConstructorInfo con, int securityAction, byte[] blob)
53 this.constructorArgs = new object[] { securityAction };
56 public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs)
57 : this(con, constructorArgs, null, null, null,null)
61 public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, FieldInfo[] namedFields, object[] fieldValues)
62 : this(con, constructorArgs, null, null, namedFields, fieldValues)
66 public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, PropertyInfo[] namedProperties, object[] propertyValues)
67 : this(con, constructorArgs, namedProperties, propertyValues, null, null)
71 public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, PropertyInfo[] namedProperties, object[] propertyValues, FieldInfo[] namedFields, object[] fieldValues)
74 this.constructorArgs = constructorArgs;
75 this.namedProperties = namedProperties;
76 this.propertyValues = propertyValues;
77 this.namedFields = namedFields;
78 this.fieldValues = fieldValues;
81 public static CustomAttributeBuilder __FromBlob(ConstructorInfo con, byte[] blob)
83 return new CustomAttributeBuilder(con, blob);
86 public static CustomAttributeBuilder __FromBlob(ConstructorInfo con, int securityAction, byte[] blob)
88 return new CustomAttributeBuilder(con, securityAction, blob);
91 public static CustomAttributeTypedArgument __MakeTypedArgument(Type type, object value)
93 return new CustomAttributeTypedArgument(type, value);
96 private sealed class BlobWriter
98 private readonly Assembly assembly;
99 private readonly CustomAttributeBuilder cab;
100 private readonly ByteBuffer bb;
102 internal BlobWriter(Assembly assembly, CustomAttributeBuilder cab, ByteBuffer bb)
104 this.assembly = assembly;
109 internal void WriteCustomAttributeBlob()
113 ParameterInfo[] pi = cab.con.GetParameters();
114 for (int i = 0; i < pi.Length; i++)
116 WriteFixedArg(pi[i].ParameterType, cab.constructorArgs[i]);
118 WriteNamedArguments(false);
121 internal void WriteNamedArguments(bool forDeclSecurity)
125 if (cab.namedFields != null)
127 named += cab.namedFields.Length;
129 if (cab.namedProperties != null)
131 named += cab.namedProperties.Length;
135 WritePackedLen(named);
139 WriteUInt16((ushort)named);
141 if (cab.namedFields != null)
143 for (int i = 0; i < cab.namedFields.Length; i++)
145 WriteNamedArg(0x53, cab.namedFields[i].FieldType, cab.namedFields[i].Name, cab.fieldValues[i]);
148 if (cab.namedProperties != null)
150 for (int i = 0; i < cab.namedProperties.Length; i++)
152 WriteNamedArg(0x54, cab.namedProperties[i].PropertyType, cab.namedProperties[i].Name, cab.propertyValues[i]);
157 private void WriteNamedArg(byte fieldOrProperty, Type type, string name, object value)
159 WriteByte(fieldOrProperty);
160 WriteFieldOrPropType(type);
162 WriteFixedArg(type, value);
165 private void WriteByte(byte value)
170 private void WriteUInt16(ushort value)
175 private void WriteInt32(int value)
180 private void WriteFixedArg(Type type, object value)
182 Universe u = assembly.universe;
183 if (type == u.System_String)
185 WriteString((string)value);
187 else if (type == u.System_Boolean)
189 WriteByte((bool)value ? (byte)1 : (byte)0);
191 else if (type == u.System_Char)
193 WriteUInt16((char)value);
195 else if (type == u.System_SByte)
197 WriteByte((byte)(sbyte)value);
199 else if (type == u.System_Byte)
201 WriteByte((byte)value);
203 else if (type == u.System_Int16)
205 WriteUInt16((ushort)(short)value);
207 else if (type == u.System_UInt16)
209 WriteUInt16((ushort)value);
211 else if (type == u.System_Int32)
213 WriteInt32((int)value);
215 else if (type == u.System_UInt32)
217 WriteInt32((int)(uint)value);
219 else if (type == u.System_Int64)
221 WriteInt64((long)value);
223 else if (type == u.System_UInt64)
225 WriteInt64((long)(ulong)value);
227 else if (type == u.System_Single)
229 WriteSingle((float)value);
231 else if (type == u.System_Double)
233 WriteDouble((double)value);
235 else if (type == u.System_Type)
237 WriteTypeName((Type)value);
239 else if (type == u.System_Object)
243 type = u.System_String;
245 else if (value is Type)
247 // value.GetType() would return a subclass of Type, but we don't want to deal with that
248 type = u.System_Type;
250 else if (value is CustomAttributeTypedArgument)
252 CustomAttributeTypedArgument cta = (CustomAttributeTypedArgument)value;
254 type = cta.ArgumentType;
258 type = u.Import(value.GetType());
260 WriteFieldOrPropType(type);
261 WriteFixedArg(type, value);
263 else if (type.IsArray)
271 Array array = (Array)value;
272 Type elemType = type.GetElementType();
273 WriteInt32(array.Length);
274 foreach (object val in array)
276 WriteFixedArg(elemType, val);
280 else if (type.IsEnum)
282 WriteFixedArg(type.GetEnumUnderlyingTypeImpl(), value);
286 throw new ArgumentException();
290 private void WriteInt64(long value)
295 private void WriteSingle(float value)
300 private void WriteDouble(double value)
305 private void WriteTypeName(Type type)
310 StringBuilder sb = new StringBuilder();
311 GetTypeName(sb, type, false);
312 name = sb.ToString();
317 private void GetTypeName(StringBuilder sb, Type type, bool isTypeParam)
319 bool v1 = !assembly.ManifestModule.__IsMissing && assembly.ManifestModule.MDStreamVersion < 0x20000;
320 bool includeAssemblyName = type.Assembly != assembly && (!v1 || type.Assembly != type.Module.universe.Mscorlib);
321 if (isTypeParam && includeAssemblyName)
325 GetTypeNameImpl(sb, type);
326 if (includeAssemblyName)
338 sb.Append(type.Assembly.FullName.Replace("]", "\\]")).Append(']');
342 sb.Append(type.Assembly.FullName);
347 private void GetTypeNameImpl(StringBuilder sb, Type type)
349 if (type.HasElementType)
351 GetTypeNameImpl(sb, type.GetElementType());
352 sb.Append(((ElementHolderType)type).GetSuffix());
354 else if (type.IsConstructedGenericType)
356 sb.Append(type.GetGenericTypeDefinition().FullName);
359 foreach (Type typeParam in type.GetGenericArguments())
362 GetTypeName(sb, typeParam, true);
369 sb.Append(type.FullName);
373 private void WriteString(string val)
378 private void WritePackedLen(int len)
380 bb.WriteCompressedInt(len);
383 private void WriteFieldOrPropType(Type type)
385 Universe u = type.Module.universe;
386 if (type == u.System_Type)
390 else if (type == u.System_Object)
394 else if (type == u.System_Boolean)
398 else if (type == u.System_Char)
402 else if (type == u.System_SByte)
406 else if (type == u.System_Byte)
410 else if (type == u.System_Int16)
414 else if (type == u.System_UInt16)
418 else if (type == u.System_Int32)
422 else if (type == u.System_UInt32)
426 else if (type == u.System_Int64)
430 else if (type == u.System_UInt64)
434 else if (type == u.System_Single)
438 else if (type == u.System_Double)
442 else if (type == u.System_String)
446 else if (type.IsArray)
449 WriteFieldOrPropType(type.GetElementType());
451 else if (type.IsEnum)
458 throw new ArgumentException();
463 internal bool IsPseudoCustomAttribute
465 get { return con.DeclaringType.IsPseudoCustomAttribute; }
468 internal ConstructorInfo Constructor
473 internal int WriteBlob(ModuleBuilder moduleBuilder)
478 bb = ByteBuffer.Wrap(blob);
482 bb = new ByteBuffer(100);
483 BlobWriter bw = new BlobWriter(moduleBuilder.Assembly, this, bb);
484 bw.WriteCustomAttributeBlob();
486 return moduleBuilder.Blobs.Add(bb);
489 internal object GetConstructorArgument(int pos)
491 return constructorArgs[pos];
494 internal int ConstructorArgumentCount
496 get { return constructorArgs == null ? 0 : constructorArgs.Length; }
499 internal T? GetFieldValue<T>(string name) where T : struct
501 object val = GetFieldValue(name);
506 else if (val != null)
508 if (typeof(T).IsEnum)
510 Debug.Assert(Enum.GetUnderlyingType(typeof(T)) == val.GetType());
511 return (T)Enum.ToObject(typeof(T), val);
515 Debug.Assert(Enum.GetUnderlyingType(val.GetType()) == typeof(T));
516 return (T)Convert.ChangeType(val, typeof(T));
525 internal object GetFieldValue(string name)
527 if (namedFields != null)
529 for (int i = 0; i < namedFields.Length; i++)
531 if (namedFields[i].Name == name)
533 return fieldValues[i];
540 internal string GetLegacyDeclSecurity()
542 if (con.DeclaringType == con.Module.universe.System_Security_Permissions_PermissionSetAttribute
544 && (namedFields == null || namedFields.Length == 0)
545 && namedProperties != null
546 && namedProperties.Length == 1
547 && namedProperties[0].Name == "XML")
549 return propertyValues[0] as string;
554 internal void WriteNamedArgumentsForDeclSecurity(ModuleBuilder moduleBuilder, ByteBuffer bb)
562 BlobWriter bw = new BlobWriter(moduleBuilder.Assembly, this, bb);
563 bw.WriteNamedArguments(true);
567 internal CustomAttributeData ToData(Assembly asm)
571 if (constructorArgs != null)
573 return new CustomAttributeData(asm, con, (int)constructorArgs[0], blob, -1);
575 return new CustomAttributeData(asm, con, new IKVM.Reflection.Reader.ByteReader(blob, 0, blob.Length));
579 List<CustomAttributeNamedArgument> namedArgs = new List<CustomAttributeNamedArgument>();
580 if (namedProperties != null)
582 for (int i = 0; i < namedProperties.Length; i++)
584 namedArgs.Add(new CustomAttributeNamedArgument(namedProperties[i], RewrapValue(namedProperties[i].PropertyType, propertyValues[i])));
587 if (namedFields != null)
589 for (int i = 0; i < namedFields.Length; i++)
591 namedArgs.Add(new CustomAttributeNamedArgument(namedFields[i], RewrapValue(namedFields[i].FieldType, fieldValues[i])));
594 List<CustomAttributeTypedArgument> args = new List<CustomAttributeTypedArgument>(constructorArgs.Length);
595 ParameterInfo[] parameters = this.Constructor.GetParameters();
596 for (int i = 0; i < constructorArgs.Length; i++)
598 args.Add(RewrapValue(parameters[i].ParameterType, constructorArgs[i]));
600 return new CustomAttributeData(asm.ManifestModule, con, args, namedArgs);
604 private static CustomAttributeTypedArgument RewrapValue(Type type, object value)
608 Array array = (Array)value;
609 Type arrayType = type.Module.universe.Import(array.GetType());
610 return RewrapArray(arrayType, array);
612 else if (value is CustomAttributeTypedArgument)
614 CustomAttributeTypedArgument arg = (CustomAttributeTypedArgument)value;
615 if (arg.Value is Array)
617 return RewrapArray(arg.ArgumentType, (Array)arg.Value);
623 return new CustomAttributeTypedArgument(type, value);
627 private static CustomAttributeTypedArgument RewrapArray(Type arrayType, Array array)
629 Type elementType = arrayType.GetElementType();
630 CustomAttributeTypedArgument[] newArray = new CustomAttributeTypedArgument[array.Length];
631 for (int i = 0; i < newArray.Length; i++)
633 newArray[i] = RewrapValue(elementType, array.GetValue(i));
635 return new CustomAttributeTypedArgument(arrayType, newArray);
638 internal bool HasBlob
640 get { return blob != null; }
643 internal CustomAttributeBuilder DecodeBlob(Assembly asm)
651 return ToData(asm).__ToBuilder();
655 internal byte[] GetBlob(Assembly asm)
657 ByteBuffer bb = new ByteBuffer(100);
658 BlobWriter bw = new BlobWriter(asm, this, bb);
659 bw.WriteCustomAttributeBlob();