CustomAttributeBuilder.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. //
  2. // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining
  5. // a copy of this software and associated documentation files (the
  6. // "Software"), to deal in the Software without restriction, including
  7. // without limitation the rights to use, copy, modify, merge, publish,
  8. // distribute, sublicense, and/or sell copies of the Software, and to
  9. // permit persons to whom the Software is furnished to do so, subject to
  10. // the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be
  13. // included in all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  19. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  20. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  21. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. //
  23. //
  24. // System.Reflection.Emit/CustomAttributeBuilder.cs
  25. //
  26. // Author:
  27. // Paolo Molaro ([email protected])
  28. //
  29. // (C) 2001 Ximian, Inc. http://www.ximian.com
  30. //
  31. using System;
  32. using System.Reflection;
  33. using System.Reflection.Emit;
  34. using System.Runtime.CompilerServices;
  35. using System.Runtime.InteropServices;
  36. namespace System.Reflection.Emit {
  37. #if NET_2_0
  38. [ComVisible (true)]
  39. [ComDefaultInterface (typeof (_CustomAttributeBuilder))]
  40. #endif
  41. [ClassInterface (ClassInterfaceType.None)]
  42. public class CustomAttributeBuilder : _CustomAttributeBuilder {
  43. ConstructorInfo ctor;
  44. byte[] data;
  45. internal ConstructorInfo Ctor {
  46. get {return ctor;}
  47. }
  48. internal byte[] Data {
  49. get {return data;}
  50. }
  51. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  52. static extern byte[] GetBlob(Assembly asmb, ConstructorInfo con, object[] constructorArgs, PropertyInfo[] namedProperties, object[] propertyValues, FieldInfo[] namedFields, object[] fieldValues);
  53. internal CustomAttributeBuilder( ConstructorInfo con, byte[] cdata) {
  54. ctor = con;
  55. data = (byte[])cdata.Clone ();
  56. /* should we check that the user supplied data is correct? */
  57. }
  58. public CustomAttributeBuilder( ConstructorInfo con, object[] constructorArgs)
  59. {
  60. Initialize (con, constructorArgs, new PropertyInfo [0], new object [0],
  61. new FieldInfo [0], new object [0]);
  62. }
  63. public CustomAttributeBuilder( ConstructorInfo con, object[] constructorArgs,
  64. FieldInfo[] namedFields, object[] fieldValues)
  65. {
  66. Initialize (con, constructorArgs, new PropertyInfo [0], new object [0],
  67. namedFields, fieldValues);
  68. }
  69. public CustomAttributeBuilder( ConstructorInfo con, object[] constructorArgs,
  70. PropertyInfo[] namedProperties, object[] propertyValues)
  71. {
  72. Initialize (con, constructorArgs, namedProperties, propertyValues, new FieldInfo [0],
  73. new object [0]);
  74. }
  75. public CustomAttributeBuilder( ConstructorInfo con, object[] constructorArgs,
  76. PropertyInfo[] namedProperties, object[] propertyValues,
  77. FieldInfo[] namedFields, object[] fieldValues)
  78. {
  79. Initialize (con, constructorArgs, namedProperties, propertyValues, namedFields, fieldValues);
  80. }
  81. private bool IsValidType (Type t)
  82. {
  83. /* FIXME: Add more checks */
  84. if (t.IsArray && t.GetArrayRank () > 1)
  85. return false;
  86. return true;
  87. }
  88. private void Initialize (ConstructorInfo con, object [] constructorArgs,
  89. PropertyInfo [] namedProperties, object [] propertyValues,
  90. FieldInfo [] namedFields, object [] fieldValues)
  91. {
  92. ctor = con;
  93. if (con == null)
  94. throw new ArgumentNullException ("con");
  95. if (constructorArgs == null)
  96. throw new ArgumentNullException ("constructorArgs");
  97. if (namedProperties == null)
  98. throw new ArgumentNullException ("namedProperties");
  99. if (propertyValues == null)
  100. throw new ArgumentNullException ("propertyValues");
  101. if (namedFields == null)
  102. throw new ArgumentNullException ("namedFields");
  103. if (fieldValues == null)
  104. throw new ArgumentNullException ("fieldValues");
  105. if (con.GetParameterCount () != constructorArgs.Length)
  106. throw new ArgumentException ("Parameter count does not match " +
  107. "passed in argument value count.");
  108. if (namedProperties.Length != propertyValues.Length)
  109. throw new ArgumentException ("Array lengths must be the same.",
  110. "namedProperties, propertyValues");
  111. if (namedFields.Length != fieldValues.Length)
  112. throw new ArgumentException ("Array lengths must be the same.",
  113. "namedFields, fieldValues");
  114. if ((con.Attributes & MethodAttributes.Static) == MethodAttributes.Static ||
  115. (con.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private)
  116. throw new ArgumentException ("Cannot have private or static constructor.");
  117. Type atype = ctor.DeclaringType;
  118. int i;
  119. i = 0;
  120. foreach (FieldInfo fi in namedFields) {
  121. Type t = fi.DeclaringType;
  122. if (!IsValidType (t))
  123. throw new ArgumentException ("Field '" + fi.Name + "' does not have a valid type.");
  124. if ((atype != t) && (!t.IsSubclassOf (atype)) && (!atype.IsSubclassOf (t)))
  125. throw new ArgumentException ("Field '" + fi.Name + "' does not belong to the same class as the constructor");
  126. // FIXME: Check enums and TypeBuilders as well
  127. if (fieldValues [i] != null)
  128. // IsEnum does not seem to work on TypeBuilders
  129. if (!(fi.FieldType is TypeBuilder) && !fi.FieldType.IsEnum && !fi.FieldType.IsInstanceOfType (fieldValues [i])) {
  130. //
  131. // mcs allways uses object[] for array types and
  132. // MS.NET allows this
  133. //
  134. if (!fi.FieldType.IsArray)
  135. throw new ArgumentException ("Value of field '" + fi.Name + "' does not match field type: " + fi.FieldType);
  136. }
  137. i ++;
  138. }
  139. i = 0;
  140. foreach (PropertyInfo pi in namedProperties) {
  141. if (!pi.CanWrite)
  142. throw new ArgumentException ("Property '" + pi.Name + "' does not have a setter.");
  143. Type t = pi.DeclaringType;
  144. if (!IsValidType (t))
  145. throw new ArgumentException ("Property '" + pi.Name + "' does not have a valid type.");
  146. if ((atype != t) && (!t.IsSubclassOf (atype)) && (!atype.IsSubclassOf (t)))
  147. throw new ArgumentException ("Property '" + pi.Name + "' does not belong to the same class as the constructor");
  148. if (propertyValues [i] != null) {
  149. if (!(pi.PropertyType is TypeBuilder) && !pi.PropertyType.IsEnum && !pi.PropertyType.IsInstanceOfType (propertyValues [i]))
  150. if (!pi.PropertyType.IsArray)
  151. throw new ArgumentException ("Value of property '" + pi.Name + "' does not match property type: " + pi.PropertyType + " -> " + propertyValues [i]);
  152. }
  153. i ++;
  154. }
  155. i = 0;
  156. foreach (ParameterInfo pi in con.GetParameters ()) {
  157. if (pi != null) {
  158. Type paramType = pi.ParameterType;
  159. if (!IsValidType (paramType))
  160. throw new ArgumentException ("Argument " + i + " does not have a valid type.");
  161. if (constructorArgs [i] != null)
  162. if (!(paramType is TypeBuilder) && !paramType.IsEnum && !paramType.IsInstanceOfType (constructorArgs [i]))
  163. if (!paramType.IsArray)
  164. throw new ArgumentException ("Value of argument " + i + " does not match parameter type: " + paramType + " -> " + constructorArgs [i]);
  165. }
  166. i ++;
  167. }
  168. data = GetBlob (atype.Assembly, con, constructorArgs, namedProperties, propertyValues, namedFields, fieldValues);
  169. }
  170. /* helper methods */
  171. internal static int decode_len (byte[] data, int pos, out int rpos) {
  172. int len = 0;
  173. if ((data [pos] & 0x80) == 0) {
  174. len = (int)(data [pos++] & 0x7f);
  175. } else if ((data [pos] & 0x40) == 0) {
  176. len = ((data [pos] & 0x3f) << 8) + data [pos + 1];
  177. pos += 2;
  178. } else {
  179. len = ((data [pos] & 0x1f) << 24) + (data [pos + 1] << 16) + (data [pos + 2] << 8) + data [pos + 3];
  180. pos += 4;
  181. }
  182. rpos = pos;
  183. return len;
  184. }
  185. internal static string string_from_bytes (byte[] data, int pos, int len)
  186. {
  187. return System.Text.Encoding.UTF8.GetString(data, pos, len);
  188. }
  189. internal string string_arg ()
  190. {
  191. int pos = 2;
  192. int len = decode_len (data, pos, out pos);
  193. return string_from_bytes (data, pos, len);
  194. }
  195. internal static UnmanagedMarshal get_umarshal (CustomAttributeBuilder customBuilder, bool is_field) {
  196. byte[] data = customBuilder.Data;
  197. UnmanagedType subtype = (UnmanagedType)0x50; /* NATIVE_MAX */
  198. int sizeConst = -1;
  199. int sizeParamIndex = -1;
  200. bool hasSize = false;
  201. int value;
  202. int utype; /* the (stupid) ctor takes a short or an enum ... */
  203. string marshalTypeName = null;
  204. Type marshalTypeRef = null;
  205. string marshalCookie = String.Empty;
  206. utype = (int)data [2];
  207. utype |= ((int)data [3]) << 8;
  208. string first_type_name = customBuilder.Ctor.GetParameters()[0].ParameterType.FullName;
  209. int pos = 6;
  210. if (first_type_name == "System.Int16")
  211. pos = 4;
  212. int nnamed = (int)data [pos++];
  213. nnamed |= ((int)data [pos++]) << 8;
  214. for (int i = 0; i < nnamed; ++i) {
  215. int paramType; // What is this ?
  216. paramType = (int)data [pos++];
  217. paramType |= ((int)data [pos++]) << 8;
  218. int len = decode_len (data, pos, out pos);
  219. string named_name = string_from_bytes (data, pos, len);
  220. pos += len;
  221. switch (named_name) {
  222. case "ArraySubType":
  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;
  228. break;
  229. case "SizeConst":
  230. value = (int)data [pos++];
  231. value |= ((int)data [pos++]) << 8;
  232. value |= ((int)data [pos++]) << 16;
  233. value |= ((int)data [pos++]) << 24;
  234. sizeConst = value;
  235. hasSize = true;
  236. break;
  237. case "SizeParamIndex":
  238. value = (int)data [pos++];
  239. value |= ((int)data [pos++]) << 8;
  240. sizeParamIndex = value;
  241. hasSize = true;
  242. break;
  243. case "MarshalType":
  244. len = decode_len (data, pos, out pos);
  245. marshalTypeName = string_from_bytes (data, pos, len);
  246. pos += len;
  247. break;
  248. case "MarshalTypeRef":
  249. len = decode_len (data, pos, out pos);
  250. marshalTypeName = string_from_bytes (data, pos, len);
  251. marshalTypeRef = Type.GetType (marshalTypeName);
  252. pos += len;
  253. break;
  254. case "MarshalCookie":
  255. len = decode_len (data, pos, out pos);
  256. marshalCookie = string_from_bytes (data, pos, len);
  257. pos += len;
  258. break;
  259. default:
  260. len = decode_len(data, pos, out pos);
  261. string_from_bytes (data, pos, len);
  262. pos += len;
  263. break;
  264. }
  265. }
  266. switch ((UnmanagedType)utype) {
  267. case UnmanagedType.LPArray:
  268. if (hasSize)
  269. return UnmanagedMarshal.DefineLPArrayInternal (subtype, sizeConst, sizeParamIndex);
  270. else
  271. return UnmanagedMarshal.DefineLPArray (subtype);
  272. case UnmanagedType.SafeArray:
  273. return UnmanagedMarshal.DefineSafeArray (subtype);
  274. case UnmanagedType.ByValArray:
  275. return UnmanagedMarshal.DefineByValArray (sizeConst);
  276. case UnmanagedType.ByValTStr:
  277. return UnmanagedMarshal.DefineByValTStr (sizeConst);
  278. case UnmanagedType.CustomMarshaler:
  279. return UnmanagedMarshal.DefineCustom (marshalTypeRef, marshalCookie, marshalTypeName, Guid.Empty);
  280. default:
  281. return UnmanagedMarshal.DefineUnmanagedMarshal ((UnmanagedType)utype);
  282. }
  283. }
  284. static Type elementTypeToType (int elementType) {
  285. /* Partition II, section 23.1.16 */
  286. switch (elementType) {
  287. case 0x02:
  288. return typeof (bool);
  289. case 0x03:
  290. return typeof (char);
  291. case 0x04:
  292. return typeof (sbyte);
  293. case 0x05:
  294. return typeof (byte);
  295. case 0x06:
  296. return typeof (short);
  297. case 0x07:
  298. return typeof (ushort);
  299. case 0x08:
  300. return typeof (int);
  301. case 0x09:
  302. return typeof (uint);
  303. case 0x0a:
  304. return typeof (long);
  305. case 0x0b:
  306. return typeof (ulong);
  307. case 0x0c:
  308. return typeof (float);
  309. case 0x0d:
  310. return typeof (double);
  311. case 0x0e:
  312. return typeof (string);
  313. default:
  314. throw new Exception ("Unknown element type '" + elementType + "'");
  315. }
  316. }
  317. static object decode_cattr_value (Type t, byte[] data, int pos, out int rpos) {
  318. switch (Type.GetTypeCode (t)) {
  319. case TypeCode.String:
  320. if (data [pos] == 0xff) {
  321. rpos = pos + 1;
  322. return null;
  323. }
  324. int len = decode_len (data, pos, out pos);
  325. rpos = pos + len;
  326. return string_from_bytes (data, pos, len);
  327. case TypeCode.Int32:
  328. rpos = pos + 4;
  329. return data [pos] + (data [pos + 1] << 8) + (data [pos + 2] << 16) + (data [pos + 3] << 24);
  330. case TypeCode.Boolean:
  331. rpos = pos + 1;
  332. return (data [pos] == 0) ? false : true;
  333. case TypeCode.Object:
  334. int subtype = data [pos];
  335. pos += 1;
  336. if (subtype >= 0x02 && subtype <= 0x0e)
  337. return decode_cattr_value (elementTypeToType (subtype), data, pos, out rpos);
  338. else
  339. throw new Exception ("Subtype '" + subtype + "' of type object not yet handled in decode_cattr_value");
  340. default:
  341. throw new Exception ("FIXME: Type " + t + " not yet handled in decode_cattr_value.");
  342. }
  343. }
  344. internal struct CustomAttributeInfo {
  345. public ConstructorInfo ctor;
  346. public object[] ctorArgs;
  347. public string[] namedParamNames;
  348. public object[] namedParamValues;
  349. }
  350. internal static CustomAttributeInfo decode_cattr (CustomAttributeBuilder customBuilder) {
  351. byte[] data = customBuilder.Data;
  352. ConstructorInfo ctor = customBuilder.Ctor;
  353. int pos = 0;
  354. CustomAttributeInfo info = new CustomAttributeInfo ();
  355. // Prolog
  356. if (data.Length < 2)
  357. throw new Exception ("Custom attr length is only '" + data.Length + "'");
  358. if ((data [0] != 0x1) || (data [1] != 0x00))
  359. throw new Exception ("Prolog invalid");
  360. pos = 2;
  361. ParameterInfo [] pi = ctor.GetParameters ();
  362. info.ctor = ctor;
  363. info.ctorArgs = new object [pi.Length];
  364. for (int i = 0; i < pi.Length; ++i)
  365. info.ctorArgs [i] = decode_cattr_value (pi [i].ParameterType, data, pos, out pos);
  366. int num_named = data [pos] + (data [pos + 1] * 256);
  367. pos += 2;
  368. info.namedParamNames = new string [num_named];
  369. info.namedParamValues = new object [num_named];
  370. for (int i = 0; i < num_named; ++i) {
  371. int named_type = data [pos++];
  372. int data_type = data [pos++];
  373. string enum_type_name = null;
  374. if (data_type == 0x55) {
  375. int len2 = decode_len (data, pos, out pos);
  376. enum_type_name = string_from_bytes (data, pos, len2);
  377. pos += len2;
  378. }
  379. int len = decode_len (data, pos, out pos);
  380. string name = string_from_bytes (data, pos, len);
  381. info.namedParamNames [i] = name;
  382. pos += len;
  383. if (named_type == 0x53) {
  384. /* Field */
  385. FieldInfo fi = ctor.DeclaringType.GetField (name, BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance);
  386. if (fi == null)
  387. throw new Exception ("Custom attribute type '" + ctor.DeclaringType + "' doesn't contain a field named '" + name + "'");
  388. object val = decode_cattr_value (fi.FieldType, data, pos, out pos);
  389. if (enum_type_name != null) {
  390. Type enumType = Type.GetType (enum_type_name);
  391. val = Enum.ToObject (enumType, val);
  392. }
  393. info.namedParamValues [i] = val;
  394. }
  395. else
  396. // FIXME:
  397. throw new Exception ("Unknown named type: " + named_type);
  398. }
  399. return info;
  400. }
  401. void _CustomAttributeBuilder.GetIDsOfNames ([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
  402. {
  403. throw new NotImplementedException ();
  404. }
  405. void _CustomAttributeBuilder.GetTypeInfo (uint iTInfo, uint lcid, IntPtr ppTInfo)
  406. {
  407. throw new NotImplementedException ();
  408. }
  409. void _CustomAttributeBuilder.GetTypeInfoCount (out uint pcTInfo)
  410. {
  411. throw new NotImplementedException ();
  412. }
  413. void _CustomAttributeBuilder.Invoke (uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
  414. {
  415. throw new NotImplementedException ();
  416. }
  417. }
  418. }