3 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
5 // Permission is hereby granted, free of charge, to any person obtaining
6 // a copy of this software and associated documentation files (the
7 // "Software"), to deal in the Software without restriction, including
8 // without limitation the rights to use, copy, modify, merge, publish,
9 // distribute, sublicense, and/or sell copies of the Software, and to
10 // permit persons to whom the Software is furnished to do so, subject to
11 // the following conditions:
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 // System.Reflection.Emit/CustomAttributeBuilder.cs
29 // Paolo Molaro (lupus@ximian.com)
31 // (C) 2001 Ximian, Inc. http://www.ximian.com
35 using System.Reflection;
36 using System.Reflection.Emit;
37 using System.Runtime.CompilerServices;
38 using System.Runtime.InteropServices;
40 namespace System.Reflection.Emit {
41 public class CustomAttributeBuilder {
45 internal ConstructorInfo Ctor {
49 internal byte[] Data {
53 [MethodImplAttribute(MethodImplOptions.InternalCall)]
54 static extern byte[] GetBlob(Assembly asmb, ConstructorInfo con, object[] constructorArgs, PropertyInfo[] namedProperties, object[] propertyValues, FieldInfo[] namedFields, object[] fieldValues);
56 internal CustomAttributeBuilder( ConstructorInfo con, byte[] cdata) {
58 data = (byte[])cdata.Clone ();
59 /* should we check that the user supplied data is correct? */
62 public CustomAttributeBuilder( ConstructorInfo con, object[] constructorArgs)
64 Initialize (con, constructorArgs, new PropertyInfo [0], new object [0],
65 new FieldInfo [0], new object [0]);
67 public CustomAttributeBuilder( ConstructorInfo con, object[] constructorArgs,
68 FieldInfo[] namedFields, object[] fieldValues)
70 Initialize (con, constructorArgs, new PropertyInfo [0], new object [0],
71 namedFields, fieldValues);
73 public CustomAttributeBuilder( ConstructorInfo con, object[] constructorArgs,
74 PropertyInfo[] namedProperties, object[] propertyValues)
76 Initialize (con, constructorArgs, namedProperties, propertyValues, new FieldInfo [0],
79 public CustomAttributeBuilder( ConstructorInfo con, object[] constructorArgs,
80 PropertyInfo[] namedProperties, object[] propertyValues,
81 FieldInfo[] namedFields, object[] fieldValues)
83 Initialize (con, constructorArgs, namedProperties, propertyValues, namedFields, fieldValues);
86 private void Initialize (ConstructorInfo con, object [] constructorArgs,
87 PropertyInfo [] namedProperties, object [] propertyValues,
88 FieldInfo [] namedFields, object [] fieldValues)
92 throw new ArgumentNullException ("con");
93 if (constructorArgs == null)
94 throw new ArgumentNullException ("constructorArgs");
95 if (namedProperties == null)
96 throw new ArgumentNullException ("namedProperties");
97 if (propertyValues == null)
98 throw new ArgumentNullException ("propertyValues");
99 if (namedFields == null)
100 throw new ArgumentNullException ("namedFields");
101 if (fieldValues == null)
102 throw new ArgumentNullException ("fieldValues");
103 if (con.GetParameterCount () != constructorArgs.Length)
104 throw new ArgumentException ("Parameter count does not match " +
105 "passed in argument value count.");
106 if (namedProperties.Length != propertyValues.Length)
107 throw new ArgumentException ("Array lengths must be the same.",
108 "namedProperties, propertyValues");
109 if (namedFields.Length != fieldValues.Length)
110 throw new ArgumentException ("Array lengths must be the same.",
111 "namedFields, fieldValues");
112 if ((con.Attributes & MethodAttributes.Static) == MethodAttributes.Static ||
113 (con.Attributes & MethodAttributes.Private) == MethodAttributes.Private)
114 throw new ArgumentException ("Cannot have private or static constructor.");
116 Type atype = ctor.DeclaringType;
119 foreach (FieldInfo fi in namedFields) {
120 Type t = fi.DeclaringType;
121 if ((atype != t) && (!t.IsSubclassOf (atype)) && (!atype.IsSubclassOf (t)))
122 throw new ArgumentException ("Field '" + fi.Name + "' does not belong to the same class as the constructor");
123 // FIXME: Check enums and TypeBuilders as well
124 if (fieldValues [i] != null)
125 // IsEnum does not seem to work on TypeBuilders
126 if (!(fi.FieldType is TypeBuilder) && !fi.FieldType.IsEnum && !fi.FieldType.IsAssignableFrom (fieldValues [i].GetType ())) {
128 // mcs allways uses object[] for array types and
129 // MS.NET allows this
131 if (!fi.FieldType.IsArray)
132 throw new ArgumentException ("Value of field '" + fi.Name + "' does not match field type: " + fi.FieldType);
138 foreach (PropertyInfo pi in namedProperties) {
140 throw new ArgumentException ("Property '" + pi.Name + "' does not have a setter.");
141 Type t = pi.DeclaringType;
142 if ((atype != t) && (!t.IsSubclassOf (atype)) && (!atype.IsSubclassOf (t)))
143 throw new ArgumentException ("Property '" + pi.Name + "' does not belong to the same class as the constructor");
144 if (propertyValues [i] != null) {
145 if (!(pi.PropertyType is TypeBuilder) && !pi.PropertyType.IsEnum && !pi.PropertyType.IsAssignableFrom (propertyValues [i].GetType ()))
146 if (!pi.PropertyType.IsArray)
147 throw new ArgumentException ("Value of property '" + pi.Name + "' does not match property type: " + pi.PropertyType + " -> " + propertyValues [i]);
153 foreach (ParameterInfo pi in con.GetParameters ()) {
155 Type paramType = pi.ParameterType;
156 if (constructorArgs [i] != null)
157 if (!(paramType is TypeBuilder) && !paramType.IsEnum && !paramType.IsAssignableFrom (constructorArgs [i].GetType ()))
158 if (!paramType.IsArray)
159 throw new ArgumentException ("Value of argument " + i + " does not match parameter type: " + paramType + " -> " + constructorArgs [i]);
164 data = GetBlob (atype.Assembly, con, constructorArgs, namedProperties, propertyValues, namedFields, fieldValues);
168 internal static int decode_len (byte[] data, int pos, out int rpos) {
170 if ((data [pos] & 0x80) == 0) {
171 len = (int)(data [pos++] & 0x7f);
172 } else if ((data [pos] & 0x40) == 0) {
173 len = ((data [pos] & 0x3f) << 8) + data [pos + 1];
176 len = ((data [pos] & 0x1f) << 24) + (data [pos + 1] << 16) + (data [pos + 2] << 8) + data [pos + 3];
183 internal static string string_from_bytes (byte[] data, int pos, int len)
185 return System.Text.Encoding.UTF8.GetString(data, pos, len);
188 internal string string_arg ()
191 int len = decode_len (data, pos, out pos);
192 return string_from_bytes (data, pos, len);
195 internal static UnmanagedMarshal get_umarshal (CustomAttributeBuilder customBuilder, bool is_field) {
196 byte[] data = customBuilder.Data;
197 UnmanagedType subtype = UnmanagedType.I4;
200 int utype; /* the (stupid) ctor takes a short or an enum ... */
201 Type marshalTypeRef = null;
202 string marshalCookie = String.Empty;
203 utype = (int)data [2];
204 utype |= ((int)data [3]) << 8;
206 string first_type_name = customBuilder.Ctor.GetParameters()[0].ParameterType.FullName;
208 if (first_type_name == "System.Int16")
210 int nnamed = (int)data [pos++];
211 nnamed |= ((int)data [pos++]) << 8;
213 for (int i = 0; i < nnamed; ++i) {
214 int paramType; // What is this ?
215 paramType = (int)data [pos++];
216 paramType |= ((int)data [pos++]) << 8;
217 int len = decode_len (data, pos, out pos);
218 string named_name = string_from_bytes (data, pos, len);
221 switch (named_name) {
223 value = (int)data [pos++];
224 value |= ((int)data [pos++]) << 8;
225 value |= ((int)data [pos++]) << 16;
226 value |= ((int)data [pos++]) << 24;
227 subtype = (UnmanagedType)value;
230 value = (int)data [pos++];
231 value |= ((int)data [pos++]) << 8;
232 value |= ((int)data [pos++]) << 16;
233 value |= ((int)data [pos++]) << 24;
236 case "MarshalTypeRef":
238 len = decode_len (data, pos, out pos);
239 marshalTypeRef = Type.GetType (string_from_bytes (data, pos, len));
242 case "MarshalCookie":
243 len = decode_len (data, pos, out pos);
244 marshalCookie = string_from_bytes (data, pos, len);
248 len = decode_len(data, pos, out pos);
249 string v = string_from_bytes (data, pos, len);
255 switch ((UnmanagedType)utype) {
256 case UnmanagedType.LPArray:
257 return UnmanagedMarshal.DefineLPArray (subtype);
258 case UnmanagedType.SafeArray:
259 return UnmanagedMarshal.DefineSafeArray (subtype);
260 case UnmanagedType.ByValArray:
261 return UnmanagedMarshal.DefineByValArray (sizeConst);
262 case UnmanagedType.ByValTStr:
263 return UnmanagedMarshal.DefineByValTStr (sizeConst);
264 case UnmanagedType.CustomMarshaler:
265 return UnmanagedMarshal.DefineCustom ( marshalTypeRef, marshalCookie, marshalTypeRef.ToString (), Guid.Empty);
267 return UnmanagedMarshal.DefineUnmanagedMarshal ((UnmanagedType)utype);