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 bool IsValidType (Type t)
88 /* FIXME: Add more checks */
89 if (t.IsArray && t.GetArrayRank () > 1)
94 private void Initialize (ConstructorInfo con, object [] constructorArgs,
95 PropertyInfo [] namedProperties, object [] propertyValues,
96 FieldInfo [] namedFields, object [] fieldValues)
100 throw new ArgumentNullException ("con");
101 if (constructorArgs == null)
102 throw new ArgumentNullException ("constructorArgs");
103 if (namedProperties == null)
104 throw new ArgumentNullException ("namedProperties");
105 if (propertyValues == null)
106 throw new ArgumentNullException ("propertyValues");
107 if (namedFields == null)
108 throw new ArgumentNullException ("namedFields");
109 if (fieldValues == null)
110 throw new ArgumentNullException ("fieldValues");
111 if (con.GetParameterCount () != constructorArgs.Length)
112 throw new ArgumentException ("Parameter count does not match " +
113 "passed in argument value count.");
114 if (namedProperties.Length != propertyValues.Length)
115 throw new ArgumentException ("Array lengths must be the same.",
116 "namedProperties, propertyValues");
117 if (namedFields.Length != fieldValues.Length)
118 throw new ArgumentException ("Array lengths must be the same.",
119 "namedFields, fieldValues");
120 if ((con.Attributes & MethodAttributes.Static) == MethodAttributes.Static ||
121 (con.Attributes & MethodAttributes.Private) == MethodAttributes.Private)
122 throw new ArgumentException ("Cannot have private or static constructor.");
124 Type atype = ctor.DeclaringType;
127 foreach (FieldInfo fi in namedFields) {
128 Type t = fi.DeclaringType;
129 if (!IsValidType (t))
130 throw new ArgumentException ("Field '" + fi.Name + "' does not have a valid type.");
131 if ((atype != t) && (!t.IsSubclassOf (atype)) && (!atype.IsSubclassOf (t)))
132 throw new ArgumentException ("Field '" + fi.Name + "' does not belong to the same class as the constructor");
133 // FIXME: Check enums and TypeBuilders as well
134 if (fieldValues [i] != null)
135 // IsEnum does not seem to work on TypeBuilders
136 if (!(fi.FieldType is TypeBuilder) && !fi.FieldType.IsEnum && !fi.FieldType.IsAssignableFrom (fieldValues [i].GetType ())) {
138 // mcs allways uses object[] for array types and
139 // MS.NET allows this
141 if (!fi.FieldType.IsArray)
142 throw new ArgumentException ("Value of field '" + fi.Name + "' does not match field type: " + fi.FieldType);
148 foreach (PropertyInfo pi in namedProperties) {
150 throw new ArgumentException ("Property '" + pi.Name + "' does not have a setter.");
151 Type t = pi.DeclaringType;
152 if (!IsValidType (t))
153 throw new ArgumentException ("Property '" + pi.Name + "' does not have a valid type.");
154 if ((atype != t) && (!t.IsSubclassOf (atype)) && (!atype.IsSubclassOf (t)))
155 throw new ArgumentException ("Property '" + pi.Name + "' does not belong to the same class as the constructor");
156 if (propertyValues [i] != null) {
157 if (!(pi.PropertyType is TypeBuilder) && !pi.PropertyType.IsEnum && !pi.PropertyType.IsAssignableFrom (propertyValues [i].GetType ()))
158 if (!pi.PropertyType.IsArray)
159 throw new ArgumentException ("Value of property '" + pi.Name + "' does not match property type: " + pi.PropertyType + " -> " + propertyValues [i]);
165 foreach (ParameterInfo pi in con.GetParameters ()) {
167 Type paramType = pi.ParameterType;
168 if (!IsValidType (paramType))
169 throw new ArgumentException ("Argument " + i + " does not have a valid type.");
170 if (constructorArgs [i] != null)
171 if (!(paramType is TypeBuilder) && !paramType.IsEnum && !paramType.IsAssignableFrom (constructorArgs [i].GetType ()))
172 if (!paramType.IsArray)
173 throw new ArgumentException ("Value of argument " + i + " does not match parameter type: " + paramType + " -> " + constructorArgs [i]);
178 data = GetBlob (atype.Assembly, con, constructorArgs, namedProperties, propertyValues, namedFields, fieldValues);
182 internal static int decode_len (byte[] data, int pos, out int rpos) {
184 if ((data [pos] & 0x80) == 0) {
185 len = (int)(data [pos++] & 0x7f);
186 } else if ((data [pos] & 0x40) == 0) {
187 len = ((data [pos] & 0x3f) << 8) + data [pos + 1];
190 len = ((data [pos] & 0x1f) << 24) + (data [pos + 1] << 16) + (data [pos + 2] << 8) + data [pos + 3];
197 internal static string string_from_bytes (byte[] data, int pos, int len)
199 return System.Text.Encoding.UTF8.GetString(data, pos, len);
202 internal string string_arg ()
205 int len = decode_len (data, pos, out pos);
206 return string_from_bytes (data, pos, len);
209 internal static UnmanagedMarshal get_umarshal (CustomAttributeBuilder customBuilder, bool is_field) {
210 byte[] data = customBuilder.Data;
211 UnmanagedType subtype = (UnmanagedType)0x50; /* NATIVE_MAX */
213 int sizeParamIndex = -1;
214 bool hasSize = false;
216 int utype; /* the (stupid) ctor takes a short or an enum ... */
217 Type marshalTypeRef = null;
218 string marshalCookie = String.Empty;
219 utype = (int)data [2];
220 utype |= ((int)data [3]) << 8;
222 string first_type_name = customBuilder.Ctor.GetParameters()[0].ParameterType.FullName;
224 if (first_type_name == "System.Int16")
226 int nnamed = (int)data [pos++];
227 nnamed |= ((int)data [pos++]) << 8;
229 for (int i = 0; i < nnamed; ++i) {
230 int paramType; // What is this ?
231 paramType = (int)data [pos++];
232 paramType |= ((int)data [pos++]) << 8;
233 int len = decode_len (data, pos, out pos);
234 string named_name = string_from_bytes (data, pos, len);
237 switch (named_name) {
239 value = (int)data [pos++];
240 value |= ((int)data [pos++]) << 8;
241 value |= ((int)data [pos++]) << 16;
242 value |= ((int)data [pos++]) << 24;
243 subtype = (UnmanagedType)value;
246 value = (int)data [pos++];
247 value |= ((int)data [pos++]) << 8;
248 value |= ((int)data [pos++]) << 16;
249 value |= ((int)data [pos++]) << 24;
253 case "SizeSizeParamIndex":
254 value = (int)data [pos++];
255 value |= ((int)data [pos++]) << 8;
256 sizeParamIndex = value;
259 case "MarshalTypeRef":
261 len = decode_len (data, pos, out pos);
262 marshalTypeRef = Type.GetType (string_from_bytes (data, pos, len));
265 case "MarshalCookie":
266 len = decode_len (data, pos, out pos);
267 marshalCookie = string_from_bytes (data, pos, len);
271 len = decode_len(data, pos, out pos);
272 string_from_bytes (data, pos, len);
278 switch ((UnmanagedType)utype) {
279 case UnmanagedType.LPArray:
281 return UnmanagedMarshal.DefineLPArrayInternal (subtype, sizeConst, sizeParamIndex);
283 return UnmanagedMarshal.DefineLPArray (subtype);
284 case UnmanagedType.SafeArray:
285 return UnmanagedMarshal.DefineSafeArray (subtype);
286 case UnmanagedType.ByValArray:
287 return UnmanagedMarshal.DefineByValArray (sizeConst);
288 case UnmanagedType.ByValTStr:
289 return UnmanagedMarshal.DefineByValTStr (sizeConst);
290 case UnmanagedType.CustomMarshaler:
291 return UnmanagedMarshal.DefineCustom ( marshalTypeRef, marshalCookie, marshalTypeRef.ToString (), Guid.Empty);
293 return UnmanagedMarshal.DefineUnmanagedMarshal ((UnmanagedType)utype);