1 /*
2   Copyright (C) 2009-2012 Jeroen Frijters
3 
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.
7 
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:
11 
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.
19 
20   Jeroen Frijters
21   jeroen@frijters.net
22 
23 */
24 using System;
25 using System.Collections.Generic;
26 using System.Text;
27 using System.IO;
28 using IKVM.Reflection.Reader;
29 using IKVM.Reflection.Emit;
30 using IKVM.Reflection.Metadata;
31 
32 namespace IKVM.Reflection
33 {
34 	public sealed class CustomAttributeData
35 	{
36 		internal static readonly IList<CustomAttributeData> EmptyList = new List<CustomAttributeData>(0).AsReadOnly();
37 
38 		/*
39 		 * There are several states a CustomAttributeData object can be in:
40 		 *
41 		 * 1) Unresolved Custom Attribute
42 		 *    - customAttributeIndex >= 0
43 		 *    - declSecurityIndex == -1
44 		 *    - declSecurityBlob == null
45 		 *    - lazyConstructor = null
46 		 *    - lazyConstructorArguments = null
47 		 *    - lazyNamedArguments = null
48 		 *
49 		 * 2) Resolved Custom Attribute
50 		 *    - customAttributeIndex >= 0
51 		 *    - declSecurityIndex == -1
52 		 *    - declSecurityBlob == null
53 		 *    - lazyConstructor != null
54 		 *    - lazyConstructorArguments != null
55 		 *    - lazyNamedArguments != null
56 		 *
57 		 * 3) Pre-resolved Custom Attribute
58 		 *    - customAttributeIndex = -1
59 		 *    - declSecurityIndex == -1
60 		 *    - declSecurityBlob == null
61 		 *    - lazyConstructor != null
62 		 *    - lazyConstructorArguments != null
63 		 *    - lazyNamedArguments != null
64 		 *
65 		 * 4) Pseudo Custom Attribute, .NET 1.x declarative security or result of CustomAttributeBuilder.ToData()
66 		 *    - customAttributeIndex = -1
67 		 *    - declSecurityIndex == -1
68 		 *    - declSecurityBlob == null
69 		 *    - lazyConstructor != null
70 		 *    - lazyConstructorArguments != null
71 		 *    - lazyNamedArguments != null
72 		 *
73 		 * 5) Unresolved declarative security
74 		 *    - customAttributeIndex = -1
75 		 *    - declSecurityIndex >= 0
76 		 *    - declSecurityBlob != null
77 		 *    - lazyConstructor != null
78 		 *    - lazyConstructorArguments != null
79 		 *    - lazyNamedArguments == null
80 		 *
81 		 * 6) Resolved declarative security
82 		 *    - customAttributeIndex = -1
83 		 *    - declSecurityIndex >= 0
84 		 *    - declSecurityBlob == null
85 		 *    - lazyConstructor != null
86 		 *    - lazyConstructorArguments != null
87 		 *    - lazyNamedArguments != null
88 		 *
89 		 */
90 		private readonly Module module;
91 		private readonly int customAttributeIndex;
92 		private readonly int declSecurityIndex;
93 		private readonly byte[] declSecurityBlob;
94 		private ConstructorInfo lazyConstructor;
95 		private IList<CustomAttributeTypedArgument> lazyConstructorArguments;
96 		private IList<CustomAttributeNamedArgument> lazyNamedArguments;
97 
98 		// 1) Unresolved Custom Attribute
CustomAttributeData(Module module, int index)99 		internal CustomAttributeData(Module module, int index)
100 		{
101 			this.module = module;
102 			this.customAttributeIndex = index;
103 			this.declSecurityIndex = -1;
104 		}
105 
106 		// 4) Pseudo Custom Attribute, .NET 1.x declarative security
CustomAttributeData(Module module, ConstructorInfo constructor, object[] args, List<CustomAttributeNamedArgument> namedArguments)107 		internal CustomAttributeData(Module module, ConstructorInfo constructor, object[] args, List<CustomAttributeNamedArgument> namedArguments)
108 			: this(module, constructor, WrapConstructorArgs(args, constructor.MethodSignature), namedArguments)
109 		{
110 		}
111 
WrapConstructorArgs(object[] args, MethodSignature sig)112 		private static List<CustomAttributeTypedArgument> WrapConstructorArgs(object[] args, MethodSignature sig)
113 		{
114 			List<CustomAttributeTypedArgument> list = new List<CustomAttributeTypedArgument>();
115 			for (int i = 0; i < args.Length; i++)
116 			{
117 				list.Add(new CustomAttributeTypedArgument(sig.GetParameterType(i), args[i]));
118 			}
119 			return list;
120 		}
121 
122 		// 4) Pseudo Custom Attribute, .NET 1.x declarative security or result of CustomAttributeBuilder.ToData()
CustomAttributeData(Module module, ConstructorInfo constructor, List<CustomAttributeTypedArgument> constructorArgs, List<CustomAttributeNamedArgument> namedArguments)123 		internal CustomAttributeData(Module module, ConstructorInfo constructor, List<CustomAttributeTypedArgument> constructorArgs, List<CustomAttributeNamedArgument> namedArguments)
124 		{
125 			this.module = module;
126 			this.customAttributeIndex = -1;
127 			this.declSecurityIndex = -1;
128 			this.lazyConstructor = constructor;
129 			lazyConstructorArguments = constructorArgs.AsReadOnly();
130 			if (namedArguments == null)
131 			{
132 				this.lazyNamedArguments = Empty<CustomAttributeNamedArgument>.Array;
133 			}
134 			else
135 			{
136 				this.lazyNamedArguments = namedArguments.AsReadOnly();
137 			}
138 		}
139 
140 		// 3) Pre-resolved Custom Attribute
CustomAttributeData(Assembly asm, ConstructorInfo constructor, ByteReader br)141 		internal CustomAttributeData(Assembly asm, ConstructorInfo constructor, ByteReader br)
142 		{
143 			this.module = asm.ManifestModule;
144 			this.customAttributeIndex = -1;
145 			this.declSecurityIndex = -1;
146 			this.lazyConstructor = constructor;
147 			if (br.Length == 0)
148 			{
149 				// it's legal to have an empty blob
150 				lazyConstructorArguments = Empty<CustomAttributeTypedArgument>.Array;
151 				lazyNamedArguments = Empty<CustomAttributeNamedArgument>.Array;
152 			}
153 			else
154 			{
155 				if (br.ReadUInt16() != 1)
156 				{
157 					throw new BadImageFormatException();
158 				}
159 				lazyConstructorArguments = ReadConstructorArguments(module, br, constructor);
160 				lazyNamedArguments = ReadNamedArguments(module, br, br.ReadUInt16(), constructor.DeclaringType, true);
161 			}
162 		}
163 
ToString()164 		public override string ToString()
165 		{
166 			StringBuilder sb = new StringBuilder();
167 			sb.Append('[');
168 			sb.Append(Constructor.DeclaringType.FullName);
169 			sb.Append('(');
170 			string sep = "";
171 			ParameterInfo[] parameters = Constructor.GetParameters();
172 			IList<CustomAttributeTypedArgument> args = ConstructorArguments;
173 			for (int i = 0; i < parameters.Length; i++)
174 			{
175 				sb.Append(sep);
176 				sep = ", ";
177 				AppendValue(sb, parameters[i].ParameterType, args[i]);
178 			}
179 			foreach (CustomAttributeNamedArgument named in NamedArguments)
180 			{
181 				sb.Append(sep);
182 				sep = ", ";
183 				sb.Append(named.MemberInfo.Name);
184 				sb.Append(" = ");
185 				FieldInfo fi = named.MemberInfo as FieldInfo;
186 				Type type = fi != null ? fi.FieldType : ((PropertyInfo)named.MemberInfo).PropertyType;
187 				AppendValue(sb, type, named.TypedValue);
188 			}
189 			sb.Append(')');
190 			sb.Append(']');
191 			return sb.ToString();
192 		}
193 
AppendValue(StringBuilder sb, Type type, CustomAttributeTypedArgument arg)194 		private static void AppendValue(StringBuilder sb, Type type, CustomAttributeTypedArgument arg)
195 		{
196 			if (arg.ArgumentType == arg.ArgumentType.Module.universe.System_String)
197 			{
198 				sb.Append('"').Append(arg.Value).Append('"');
199 			}
200 			else if (arg.ArgumentType.IsArray)
201 			{
202 				Type elementType = arg.ArgumentType.GetElementType();
203 				string elementTypeName;
204 				if (elementType.IsPrimitive
205 					|| elementType == type.Module.universe.System_Object
206 					|| elementType == type.Module.universe.System_String
207 					|| elementType == type.Module.universe.System_Type)
208 				{
209 					elementTypeName = elementType.Name;
210 				}
211 				else
212 				{
213 					elementTypeName = elementType.FullName;
214 				}
215 				sb.Append("new ").Append(elementTypeName).Append("[").Append(((Array)arg.Value).Length).Append("] { ");
216 				string sep = "";
217 				foreach (CustomAttributeTypedArgument elem in (CustomAttributeTypedArgument[])arg.Value)
218 				{
219 					sb.Append(sep);
220 					sep = ", ";
221 					AppendValue(sb, elementType, elem);
222 				}
223 				sb.Append(" }");
224 			}
225 			else
226 			{
227 				if (arg.ArgumentType != type || (type.IsEnum && !arg.Value.Equals(0)))
228 				{
229 					sb.Append('(');
230 					sb.Append(arg.ArgumentType.FullName);
231 					sb.Append(')');
232 				}
233 				sb.Append(arg.Value);
234 			}
235 		}
236 
ReadDeclarativeSecurity(Module module, int index, List<CustomAttributeData> list)237 		internal static void ReadDeclarativeSecurity(Module module, int index, List<CustomAttributeData> list)
238 		{
239 			Universe u = module.universe;
240 			Assembly asm = module.Assembly;
241 			int action = module.DeclSecurity.records[index].Action;
242 			ByteReader br = module.GetBlob(module.DeclSecurity.records[index].PermissionSet);
243 			if (br.PeekByte() == '.')
244 			{
245 				br.ReadByte();
246 				int count = br.ReadCompressedUInt();
247 				for (int j = 0; j < count; j++)
248 				{
249 					Type type = ReadType(module, br);
250 					ConstructorInfo constructor = type.GetPseudoCustomAttributeConstructor(u.System_Security_Permissions_SecurityAction);
251 					// LAMESPEC there is an additional length here (probably of the named argument list)
252 					byte[] blob = br.ReadBytes(br.ReadCompressedUInt());
253 					list.Add(new CustomAttributeData(asm, constructor, action, blob, index));
254 				}
255 			}
256 			else
257 			{
258 				// .NET 1.x format (xml)
259 				char[] buf = new char[br.Length / 2];
260 				for (int i = 0; i < buf.Length; i++)
261 				{
262 					buf[i] = br.ReadChar();
263 				}
264 				string xml = new String(buf);
265 				ConstructorInfo constructor = u.System_Security_Permissions_PermissionSetAttribute.GetPseudoCustomAttributeConstructor(u.System_Security_Permissions_SecurityAction);
266 				List<CustomAttributeNamedArgument> args = new List<CustomAttributeNamedArgument>();
267 				args.Add(new CustomAttributeNamedArgument(GetProperty(null, u.System_Security_Permissions_PermissionSetAttribute, "XML", u.System_String),
268 					new CustomAttributeTypedArgument(u.System_String, xml)));
269 				list.Add(new CustomAttributeData(asm.ManifestModule, constructor, new object[] { action }, args));
270 			}
271 		}
272 
273 		// 5) Unresolved declarative security
CustomAttributeData(Assembly asm, ConstructorInfo constructor, int securityAction, byte[] blob, int index)274 		internal CustomAttributeData(Assembly asm, ConstructorInfo constructor, int securityAction, byte[] blob, int index)
275 		{
276 			this.module = asm.ManifestModule;
277 			this.customAttributeIndex = -1;
278 			this.declSecurityIndex = index;
279 			Universe u = constructor.Module.universe;
280 			this.lazyConstructor = constructor;
281 			List<CustomAttributeTypedArgument> list = new List<CustomAttributeTypedArgument>();
282 			list.Add(new CustomAttributeTypedArgument(u.System_Security_Permissions_SecurityAction, securityAction));
283 			this.lazyConstructorArguments =  list.AsReadOnly();
284 			this.declSecurityBlob = blob;
285 		}
286 
ReadFieldOrPropType(Module context, ByteReader br)287 		private static Type ReadFieldOrPropType(Module context, ByteReader br)
288 		{
289 			Universe u = context.universe;
290 			switch (br.ReadByte())
291 			{
292 				case Signature.ELEMENT_TYPE_BOOLEAN:
293 					return u.System_Boolean;
294 				case Signature.ELEMENT_TYPE_CHAR:
295 					return u.System_Char;
296 				case Signature.ELEMENT_TYPE_I1:
297 					return u.System_SByte;
298 				case Signature.ELEMENT_TYPE_U1:
299 					return u.System_Byte;
300 				case Signature.ELEMENT_TYPE_I2:
301 					return u.System_Int16;
302 				case Signature.ELEMENT_TYPE_U2:
303 					return u.System_UInt16;
304 				case Signature.ELEMENT_TYPE_I4:
305 					return u.System_Int32;
306 				case Signature.ELEMENT_TYPE_U4:
307 					return u.System_UInt32;
308 				case Signature.ELEMENT_TYPE_I8:
309 					return u.System_Int64;
310 				case Signature.ELEMENT_TYPE_U8:
311 					return u.System_UInt64;
312 				case Signature.ELEMENT_TYPE_R4:
313 					return u.System_Single;
314 				case Signature.ELEMENT_TYPE_R8:
315 					return u.System_Double;
316 				case Signature.ELEMENT_TYPE_STRING:
317 					return u.System_String;
318 				case Signature.ELEMENT_TYPE_SZARRAY:
319 					return ReadFieldOrPropType(context, br).MakeArrayType();
320 				case 0x55:
321 					return ReadType(context, br);
322 				case 0x50:
323 					return u.System_Type;
324 				case 0x51:
325 					return u.System_Object;
326 				default:
327 					throw new BadImageFormatException();
328 			}
329 		}
330 
ReadFixedArg(Module context, ByteReader br, Type type)331 		private static CustomAttributeTypedArgument ReadFixedArg(Module context, ByteReader br, Type type)
332 		{
333 			Universe u = context.universe;
334 			if (type == u.System_String)
335 			{
336 				return new CustomAttributeTypedArgument(type, br.ReadString());
337 			}
338 			else if (type == u.System_Boolean)
339 			{
340 				return new CustomAttributeTypedArgument(type, br.ReadByte() != 0);
341 			}
342 			else if (type == u.System_Char)
343 			{
344 				return new CustomAttributeTypedArgument(type, br.ReadChar());
345 			}
346 			else if (type == u.System_Single)
347 			{
348 				return new CustomAttributeTypedArgument(type, br.ReadSingle());
349 			}
350 			else if (type == u.System_Double)
351 			{
352 				return new CustomAttributeTypedArgument(type, br.ReadDouble());
353 			}
354 			else if (type == u.System_SByte)
355 			{
356 				return new CustomAttributeTypedArgument(type, br.ReadSByte());
357 			}
358 			else if (type == u.System_Int16)
359 			{
360 				return new CustomAttributeTypedArgument(type, br.ReadInt16());
361 			}
362 			else if (type == u.System_Int32)
363 			{
364 				return new CustomAttributeTypedArgument(type, br.ReadInt32());
365 			}
366 			else if (type == u.System_Int64)
367 			{
368 				return new CustomAttributeTypedArgument(type, br.ReadInt64());
369 			}
370 			else if (type == u.System_Byte)
371 			{
372 				return new CustomAttributeTypedArgument(type, br.ReadByte());
373 			}
374 			else if (type == u.System_UInt16)
375 			{
376 				return new CustomAttributeTypedArgument(type, br.ReadUInt16());
377 			}
378 			else if (type == u.System_UInt32)
379 			{
380 				return new CustomAttributeTypedArgument(type, br.ReadUInt32());
381 			}
382 			else if (type == u.System_UInt64)
383 			{
384 				return new CustomAttributeTypedArgument(type, br.ReadUInt64());
385 			}
386 			else if (type == u.System_Type)
387 			{
388 				return new CustomAttributeTypedArgument(type, ReadType(context, br));
389 			}
390 			else if (type == u.System_Object)
391 			{
392 				return ReadFixedArg(context, br, ReadFieldOrPropType(context, br));
393 			}
394 			else if (type.IsArray)
395 			{
396 				int length = br.ReadInt32();
397 				if (length == -1)
398 				{
399 					return new CustomAttributeTypedArgument(type, null);
400 				}
401 				Type elementType = type.GetElementType();
402 				CustomAttributeTypedArgument[] array = new CustomAttributeTypedArgument[length];
403 				for (int i = 0; i < length; i++)
404 				{
405 					array[i] = ReadFixedArg(context, br, elementType);
406 				}
407 				return new CustomAttributeTypedArgument(type, array);
408 			}
409 			else if (type.IsEnum)
410 			{
411 				return new CustomAttributeTypedArgument(type, ReadFixedArg(context, br, type.GetEnumUnderlyingTypeImpl()).Value);
412 			}
413 			else
414 			{
415 				throw new InvalidOperationException();
416 			}
417 		}
418 
ReadType(Module context, ByteReader br)419 		private static Type ReadType(Module context, ByteReader br)
420 		{
421 			string typeName = br.ReadString();
422 			if (typeName == null)
423 			{
424 				return null;
425 			}
426 			if (typeName.Length > 0 && typeName[typeName.Length - 1] == 0)
427 			{
428 				// there are broken compilers that emit an extra NUL character after the type name
429 				typeName = typeName.Substring(0, typeName.Length - 1);
430 			}
431 			return TypeNameParser.Parse(typeName, true).GetType(context.universe, context, true, typeName, true, false);
432 		}
433 
ReadConstructorArguments(Module context, ByteReader br, ConstructorInfo constructor)434 		private static IList<CustomAttributeTypedArgument> ReadConstructorArguments(Module context, ByteReader br, ConstructorInfo constructor)
435 		{
436 			MethodSignature sig = constructor.MethodSignature;
437 			int count = sig.GetParameterCount();
438 			List<CustomAttributeTypedArgument> list = new List<CustomAttributeTypedArgument>(count);
439 			for (int i = 0; i < count; i++)
440 			{
441 				list.Add(ReadFixedArg(context, br, sig.GetParameterType(i)));
442 			}
443 			return list.AsReadOnly();
444 		}
445 
ReadNamedArguments(Module context, ByteReader br, int named, Type type, bool required)446 		private static IList<CustomAttributeNamedArgument> ReadNamedArguments(Module context, ByteReader br, int named, Type type, bool required)
447 		{
448 			List<CustomAttributeNamedArgument> list = new List<CustomAttributeNamedArgument>(named);
449 			for (int i = 0; i < named; i++)
450 			{
451 				byte fieldOrProperty = br.ReadByte();
452 				Type fieldOrPropertyType = ReadFieldOrPropType(context, br);
453 				if (fieldOrPropertyType.__IsMissing && !required)
454 				{
455 					return null;
456 				}
457 				string name = br.ReadString();
458 				CustomAttributeTypedArgument value = ReadFixedArg(context, br, fieldOrPropertyType);
459 				MemberInfo member;
460 				switch (fieldOrProperty)
461 				{
462 					case 0x53:
463 						member = GetField(context, type, name, fieldOrPropertyType);
464 						break;
465 					case 0x54:
466 						member = GetProperty(context, type, name, fieldOrPropertyType);
467 						break;
468 					default:
469 						throw new BadImageFormatException();
470 				}
471 				list.Add(new CustomAttributeNamedArgument(member, value));
472 			}
473 			return list.AsReadOnly();
474 		}
475 
GetField(Module context, Type type, string name, Type fieldType)476 		private static FieldInfo GetField(Module context, Type type, string name, Type fieldType)
477 		{
478 			Type org = type;
479 			for (; type != null && !type.__IsMissing; type = type.BaseType)
480 			{
481 				foreach (FieldInfo field in type.__GetDeclaredFields())
482 				{
483 					if (field.IsPublic && !field.IsStatic && field.Name == name)
484 					{
485 						return field;
486 					}
487 				}
488 			}
489 			// if the field is missing, we stick the missing field on the first missing base type
490 			if (type == null)
491 			{
492 				type = org;
493 			}
494 			FieldSignature sig = FieldSignature.Create(fieldType, new CustomModifiers());
495 			return type.FindField(name, sig)
496 				?? type.Module.universe.GetMissingFieldOrThrow(context, type, name, sig);
497 		}
498 
GetProperty(Module context, Type type, string name, Type propertyType)499 		private static PropertyInfo GetProperty(Module context, Type type, string name, Type propertyType)
500 		{
501 			Type org = type;
502 			for (; type != null && !type.__IsMissing; type = type.BaseType)
503 			{
504 				foreach (PropertyInfo property in type.__GetDeclaredProperties())
505 				{
506 					if (property.IsPublic && !property.IsStatic && property.Name == name)
507 					{
508 						return property;
509 					}
510 				}
511 			}
512 			// if the property is missing, we stick the missing property on the first missing base type
513 			if (type == null)
514 			{
515 				type = org;
516 			}
517 			return type.Module.universe.GetMissingPropertyOrThrow(context, type, name,
518 				PropertySignature.Create(CallingConventions.Standard | CallingConventions.HasThis, propertyType, null, new PackedCustomModifiers()));
519 		}
520 
521 		[Obsolete("Use AttributeType property instead.")]
__TryReadTypeName(out string ns, out string name)522 		internal bool __TryReadTypeName(out string ns, out string name)
523 		{
524 			if (Constructor.DeclaringType.IsNested)
525 			{
526 				ns = null;
527 				name = null;
528 				return false;
529 			}
530 			TypeName typeName = AttributeType.TypeName;
531 			ns = typeName.Namespace;
532 			name = typeName.Name;
533 			return true;
534 		}
535 
__GetBlob()536 		public byte[] __GetBlob()
537 		{
538 			if (declSecurityBlob != null)
539 			{
540 				return (byte[])declSecurityBlob.Clone();
541 			}
542 			else if (customAttributeIndex == -1)
543 			{
544 				return __ToBuilder().GetBlob(module.Assembly);
545 			}
546 			else
547 			{
548 				return ((ModuleReader)module).GetBlobCopy(module.CustomAttribute.records[customAttributeIndex].Value);
549 			}
550 		}
551 
552 		public int __Parent
553 		{
554 			get
555 			{
556 				return customAttributeIndex >= 0
557 					? module.CustomAttribute.records[customAttributeIndex].Parent
558 					: declSecurityIndex >= 0
559 						? module.DeclSecurity.records[declSecurityIndex].Parent
560 						: 0;
561 			}
562 		}
563 
564 		// .NET 4.5 API
565 		public Type AttributeType
566 		{
567 			get { return Constructor.DeclaringType; }
568 		}
569 
570 		public ConstructorInfo Constructor
571 		{
572 			get
573 			{
574 				if (lazyConstructor == null)
575 				{
576 					lazyConstructor = (ConstructorInfo)module.ResolveMethod(module.CustomAttribute.records[customAttributeIndex].Type);
577 				}
578 				return lazyConstructor;
579 			}
580 		}
581 
582 		public IList<CustomAttributeTypedArgument> ConstructorArguments
583 		{
584 			get
585 			{
586 				if (lazyConstructorArguments == null)
587 				{
588 					LazyParseArguments(false);
589 				}
590 				return lazyConstructorArguments;
591 			}
592 		}
593 
594 		public IList<CustomAttributeNamedArgument> NamedArguments
595 		{
596 			get
597 			{
598 				if (lazyNamedArguments == null)
599 				{
600 					if (customAttributeIndex >= 0)
601 					{
602 						// 1) Unresolved Custom Attribute
603 						LazyParseArguments(true);
604 					}
605 					else
606 					{
607 						// 5) Unresolved declarative security
608 						ByteReader br = new ByteReader(declSecurityBlob, 0, declSecurityBlob.Length);
609 						// LAMESPEC the count of named arguments is a compressed integer (instead of UInt16 as NumNamed in custom attributes)
610 						lazyNamedArguments = ReadNamedArguments(module, br, br.ReadCompressedUInt(), Constructor.DeclaringType, true);
611 					}
612 				}
613 				return lazyNamedArguments;
614 			}
615 		}
616 
LazyParseArguments(bool requireNameArguments)617 		private void LazyParseArguments(bool requireNameArguments)
618 		{
619 			ByteReader br = module.GetBlob(module.CustomAttribute.records[customAttributeIndex].Value);
620 			if (br.Length == 0)
621 			{
622 				// it's legal to have an empty blob
623 				lazyConstructorArguments = Empty<CustomAttributeTypedArgument>.Array;
624 				lazyNamedArguments = Empty<CustomAttributeNamedArgument>.Array;
625 			}
626 			else
627 			{
628 				if (br.ReadUInt16() != 1)
629 				{
630 					throw new BadImageFormatException();
631 				}
632 				lazyConstructorArguments = ReadConstructorArguments(module, br, Constructor);
633 				lazyNamedArguments = ReadNamedArguments(module, br, br.ReadUInt16(), Constructor.DeclaringType, requireNameArguments);
634 			}
635 		}
636 
__ToBuilder()637 		public CustomAttributeBuilder __ToBuilder()
638 		{
639 			ParameterInfo[] parameters = Constructor.GetParameters();
640 			object[] args = new object[ConstructorArguments.Count];
641 			for (int i = 0; i < args.Length; i++)
642 			{
643 				args[i] = RewrapArray(parameters[i].ParameterType, ConstructorArguments[i]);
644 			}
645 			List<PropertyInfo> namedProperties = new List<PropertyInfo>();
646 			List<object> propertyValues = new List<object>();
647 			List<FieldInfo> namedFields = new List<FieldInfo>();
648 			List<object> fieldValues = new List<object>();
649 			foreach (CustomAttributeNamedArgument named in NamedArguments)
650 			{
651 				PropertyInfo pi = named.MemberInfo as PropertyInfo;
652 				if (pi != null)
653 				{
654 					namedProperties.Add(pi);
655 					propertyValues.Add(RewrapArray(pi.PropertyType, named.TypedValue));
656 				}
657 				else
658 				{
659 					FieldInfo fi = (FieldInfo)named.MemberInfo;
660 					namedFields.Add(fi);
661 					fieldValues.Add(RewrapArray(fi.FieldType, named.TypedValue));
662 				}
663 			}
664 			return new CustomAttributeBuilder(Constructor, args, namedProperties.ToArray(), propertyValues.ToArray(), namedFields.ToArray(), fieldValues.ToArray());
665 		}
666 
RewrapArray(Type type, CustomAttributeTypedArgument arg)667 		private static object RewrapArray(Type type, CustomAttributeTypedArgument arg)
668 		{
669 			IList<CustomAttributeTypedArgument> list = arg.Value as IList<CustomAttributeTypedArgument>;
670 			if (list != null)
671 			{
672 				Type elementType = arg.ArgumentType.GetElementType();
673 				object[] arr = new object[list.Count];
674 				for (int i = 0; i < arr.Length; i++)
675 				{
676 					arr[i] = RewrapArray(elementType, list[i]);
677 				}
678 				if (type == type.Module.universe.System_Object)
679 				{
680 					return CustomAttributeBuilder.__MakeTypedArgument(arg.ArgumentType, arr);
681 				}
682 				return arr;
683 			}
684 			else
685 			{
686 				return arg.Value;
687 			}
688 		}
689 
GetCustomAttributes(MemberInfo member)690 		public static IList<CustomAttributeData> GetCustomAttributes(MemberInfo member)
691 		{
692 			return __GetCustomAttributes(member, null, false);
693 		}
694 
GetCustomAttributes(Assembly assembly)695 		public static IList<CustomAttributeData> GetCustomAttributes(Assembly assembly)
696 		{
697 			return assembly.GetCustomAttributesData(null);
698 		}
699 
GetCustomAttributes(Module module)700 		public static IList<CustomAttributeData> GetCustomAttributes(Module module)
701 		{
702 			return __GetCustomAttributes(module, null, false);
703 		}
704 
GetCustomAttributes(ParameterInfo parameter)705 		public static IList<CustomAttributeData> GetCustomAttributes(ParameterInfo parameter)
706 		{
707 			return __GetCustomAttributes(parameter, null, false);
708 		}
709 
__GetCustomAttributes(Assembly assembly, Type attributeType, bool inherit)710 		public static IList<CustomAttributeData> __GetCustomAttributes(Assembly assembly, Type attributeType, bool inherit)
711 		{
712 			return assembly.GetCustomAttributesData(attributeType);
713 		}
714 
__GetCustomAttributes(Module module, Type attributeType, bool inherit)715 		public static IList<CustomAttributeData> __GetCustomAttributes(Module module, Type attributeType, bool inherit)
716 		{
717 			if (module.__IsMissing)
718 			{
719 				throw new MissingModuleException((MissingModule)module);
720 			}
721 			return GetCustomAttributesImpl(null, module, 0x00000001, attributeType) ?? EmptyList;
722 		}
723 
__GetCustomAttributes(ParameterInfo parameter, Type attributeType, bool inherit)724 		public static IList<CustomAttributeData> __GetCustomAttributes(ParameterInfo parameter, Type attributeType, bool inherit)
725 		{
726 			Module module = parameter.Module;
727 			List<CustomAttributeData> list = null;
728 			if (module.universe.ReturnPseudoCustomAttributes)
729 			{
730 				if (attributeType == null || attributeType.IsAssignableFrom(parameter.Module.universe.System_Runtime_InteropServices_MarshalAsAttribute))
731 				{
732 					FieldMarshal spec;
733 					if (parameter.__TryGetFieldMarshal(out spec))
734 					{
735 						if (list == null)
736 						{
737 							list = new List<CustomAttributeData>();
738 						}
739 						list.Add(CustomAttributeData.CreateMarshalAsPseudoCustomAttribute(parameter.Module, spec));
740 					}
741 				}
742 			}
743 			ModuleBuilder mb = module as ModuleBuilder;
744 			int token = parameter.MetadataToken;
745 			if (mb != null && mb.IsSaved && ModuleBuilder.IsPseudoToken(token))
746 			{
747 				token = mb.ResolvePseudoToken(token);
748 			}
749 			return GetCustomAttributesImpl(list, module, token, attributeType) ?? EmptyList;
750 		}
751 
__GetCustomAttributes(MemberInfo member, Type attributeType, bool inherit)752 		public static IList<CustomAttributeData> __GetCustomAttributes(MemberInfo member, Type attributeType, bool inherit)
753 		{
754 			if (!member.IsBaked)
755 			{
756 				// like .NET we we don't return custom attributes for unbaked members
757 				throw new NotImplementedException();
758 			}
759 			if (!inherit || !IsInheritableAttribute(attributeType))
760 			{
761 				return GetCustomAttributesImpl(null, member, attributeType) ?? EmptyList;
762 			}
763 			List<CustomAttributeData> list = new List<CustomAttributeData>();
764 			for (; ; )
765 			{
766 				GetCustomAttributesImpl(list, member, attributeType);
767 				Type type = member as Type;
768 				if (type != null)
769 				{
770 					type = type.BaseType;
771 					if (type == null)
772 					{
773 						return list;
774 					}
775 					member = type;
776 					continue;
777 				}
778 				MethodInfo method = member as MethodInfo;
779 				if (method != null)
780 				{
781 					MemberInfo prev = member;
782 					method = method.GetBaseDefinition();
783 					if (method == null || method == prev)
784 					{
785 						return list;
786 					}
787 					member = method;
788 					continue;
789 				}
790 				return list;
791 			}
792 		}
793 
GetCustomAttributesImpl(List<CustomAttributeData> list, MemberInfo member, Type attributeType)794 		private static List<CustomAttributeData> GetCustomAttributesImpl(List<CustomAttributeData> list, MemberInfo member, Type attributeType)
795 		{
796 			if (member.Module.universe.ReturnPseudoCustomAttributes)
797 			{
798 				List<CustomAttributeData> pseudo = member.GetPseudoCustomAttributes(attributeType);
799 				if (list == null)
800 				{
801 					list = pseudo;
802 				}
803 				else if (pseudo != null)
804 				{
805 					list.AddRange(pseudo);
806 				}
807 			}
808 			return GetCustomAttributesImpl(list, member.Module, member.GetCurrentToken(), attributeType);
809 		}
810 
GetCustomAttributesImpl(List<CustomAttributeData> list, Module module, int token, Type attributeType)811 		internal static List<CustomAttributeData> GetCustomAttributesImpl(List<CustomAttributeData> list, Module module, int token, Type attributeType)
812 		{
813 			foreach (int i in module.CustomAttribute.Filter(token))
814 			{
815 				if (attributeType == null)
816 				{
817 					if (list == null)
818 					{
819 						list = new List<CustomAttributeData>();
820 					}
821 					list.Add(new CustomAttributeData(module, i));
822 				}
823 				else
824 				{
825 					if (attributeType.IsAssignableFrom(module.ResolveMethod(module.CustomAttribute.records[i].Type).DeclaringType))
826 					{
827 						if (list == null)
828 						{
829 							list = new List<CustomAttributeData>();
830 						}
831 						list.Add(new CustomAttributeData(module, i));
832 					}
833 				}
834 			}
835 			return list;
836 		}
837 
__GetCustomAttributes(Type type, Type interfaceType, Type attributeType, bool inherit)838 		public static IList<CustomAttributeData> __GetCustomAttributes(Type type, Type interfaceType, Type attributeType, bool inherit)
839 		{
840 			Module module = type.Module;
841 			foreach (int i in module.InterfaceImpl.Filter(type.MetadataToken))
842 			{
843 				if (module.ResolveType(module.InterfaceImpl.records[i].Interface, type) == interfaceType)
844 				{
845 					return GetCustomAttributesImpl(null, module, (InterfaceImplTable.Index << 24) | (i + 1), attributeType) ?? EmptyList;
846 				}
847 			}
848 			return EmptyList;
849 		}
850 
__GetDeclarativeSecurity(Assembly assembly)851 		public static IList<CustomAttributeData> __GetDeclarativeSecurity(Assembly assembly)
852 		{
853 			if (assembly.__IsMissing)
854 			{
855 				throw new MissingAssemblyException((MissingAssembly)assembly);
856 			}
857 			return assembly.ManifestModule.GetDeclarativeSecurity(0x20000001);
858 		}
859 
__GetDeclarativeSecurity(Type type)860 		public static IList<CustomAttributeData> __GetDeclarativeSecurity(Type type)
861 		{
862 			if ((type.Attributes & TypeAttributes.HasSecurity) != 0)
863 			{
864 				return type.Module.GetDeclarativeSecurity(type.MetadataToken);
865 			}
866 			else
867 			{
868 				return EmptyList;
869 			}
870 		}
871 
__GetDeclarativeSecurity(MethodBase method)872 		public static IList<CustomAttributeData> __GetDeclarativeSecurity(MethodBase method)
873 		{
874 			if ((method.Attributes & MethodAttributes.HasSecurity) != 0)
875 			{
876 				return method.Module.GetDeclarativeSecurity(method.MetadataToken);
877 			}
878 			else
879 			{
880 				return EmptyList;
881 			}
882 		}
883 
IsInheritableAttribute(Type attribute)884 		private static bool IsInheritableAttribute(Type attribute)
885 		{
886 			Type attributeUsageAttribute = attribute.Module.universe.System_AttributeUsageAttribute;
887 			IList<CustomAttributeData> attr = __GetCustomAttributes(attribute, attributeUsageAttribute, false);
888 			if (attr.Count != 0)
889 			{
890 				foreach (CustomAttributeNamedArgument named in attr[0].NamedArguments)
891 				{
892 					if (named.MemberInfo.Name == "Inherited")
893 					{
894 						return (bool)named.TypedValue.Value;
895 					}
896 				}
897 			}
898 			return true;
899 		}
900 
CreateDllImportPseudoCustomAttribute(Module module, ImplMapFlags flags, string entryPoint, string dllName, MethodImplAttributes attr)901 		internal static CustomAttributeData CreateDllImportPseudoCustomAttribute(Module module, ImplMapFlags flags, string entryPoint, string dllName, MethodImplAttributes attr)
902 		{
903 			Type type = module.universe.System_Runtime_InteropServices_DllImportAttribute;
904 			ConstructorInfo constructor = type.GetPseudoCustomAttributeConstructor(module.universe.System_String);
905 			List<CustomAttributeNamedArgument> list = new List<CustomAttributeNamedArgument>();
906 			System.Runtime.InteropServices.CharSet charSet;
907 			switch (flags & ImplMapFlags.CharSetMask)
908 			{
909 				case ImplMapFlags.CharSetAnsi:
910 					charSet = System.Runtime.InteropServices.CharSet.Ansi;
911 					break;
912 				case ImplMapFlags.CharSetUnicode:
913 					charSet = System.Runtime.InteropServices.CharSet.Unicode;
914 					break;
915 				case ImplMapFlags.CharSetAuto:
916 					charSet = System.Runtime.InteropServices.CharSet.Auto;
917 					break;
918 				case ImplMapFlags.CharSetNotSpec:
919 				default:
920 					charSet = System.Runtime.InteropServices.CharSet.None;
921 					break;
922 			}
923 			System.Runtime.InteropServices.CallingConvention callingConvention;
924 			switch (flags & ImplMapFlags.CallConvMask)
925 			{
926 				case ImplMapFlags.CallConvCdecl:
927 					callingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl;
928 					break;
929 				case ImplMapFlags.CallConvFastcall:
930 					callingConvention = System.Runtime.InteropServices.CallingConvention.FastCall;
931 					break;
932 				case ImplMapFlags.CallConvStdcall:
933 					callingConvention = System.Runtime.InteropServices.CallingConvention.StdCall;
934 					break;
935 				case ImplMapFlags.CallConvThiscall:
936 					callingConvention = System.Runtime.InteropServices.CallingConvention.ThisCall;
937 					break;
938 				case ImplMapFlags.CallConvWinapi:
939 					callingConvention = System.Runtime.InteropServices.CallingConvention.Winapi;
940 					break;
941 				default:
942 					callingConvention = 0;
943 					break;
944 			}
945 			AddNamedArgument(list, type, "EntryPoint", entryPoint);
946 			AddNamedArgument(list, type, "CharSet", module.universe.System_Runtime_InteropServices_CharSet, (int)charSet);
947 			AddNamedArgument(list, type, "ExactSpelling", (int)flags, (int)ImplMapFlags.NoMangle);
948 			AddNamedArgument(list, type, "SetLastError", (int)flags, (int)ImplMapFlags.SupportsLastError);
949 			AddNamedArgument(list, type, "PreserveSig", (int)attr, (int)MethodImplAttributes.PreserveSig);
950 			AddNamedArgument(list, type, "CallingConvention", module.universe.System_Runtime_InteropServices_CallingConvention, (int)callingConvention);
951 			AddNamedArgument(list, type, "BestFitMapping", (int)flags, (int)ImplMapFlags.BestFitOn);
952 			AddNamedArgument(list, type, "ThrowOnUnmappableChar", (int)flags, (int)ImplMapFlags.CharMapErrorOn);
953 			return new CustomAttributeData(module, constructor, new object[] { dllName }, list);
954 		}
955 
CreateMarshalAsPseudoCustomAttribute(Module module, FieldMarshal fm)956 		internal static CustomAttributeData CreateMarshalAsPseudoCustomAttribute(Module module, FieldMarshal fm)
957 		{
958 			Type typeofMarshalAs = module.universe.System_Runtime_InteropServices_MarshalAsAttribute;
959 			Type typeofUnmanagedType = module.universe.System_Runtime_InteropServices_UnmanagedType;
960 			Type typeofVarEnum = module.universe.System_Runtime_InteropServices_VarEnum;
961 			Type typeofType = module.universe.System_Type;
962 			List<CustomAttributeNamedArgument> named = new List<CustomAttributeNamedArgument>();
963 			AddNamedArgument(named, typeofMarshalAs, "ArraySubType", typeofUnmanagedType, (int)(fm.ArraySubType ?? 0));
964 			AddNamedArgument(named, typeofMarshalAs, "SizeParamIndex", module.universe.System_Int16, fm.SizeParamIndex ?? 0);
965 			AddNamedArgument(named, typeofMarshalAs, "SizeConst", module.universe.System_Int32, fm.SizeConst ?? 0);
966 			AddNamedArgument(named, typeofMarshalAs, "IidParameterIndex", module.universe.System_Int32, fm.IidParameterIndex ?? 0);
967 			AddNamedArgument(named, typeofMarshalAs, "SafeArraySubType", typeofVarEnum, (int)(fm.SafeArraySubType ?? 0));
968 			if (fm.SafeArrayUserDefinedSubType != null)
969 			{
970 				AddNamedArgument(named, typeofMarshalAs, "SafeArrayUserDefinedSubType", typeofType, fm.SafeArrayUserDefinedSubType);
971 			}
972 			if (fm.MarshalType != null)
973 			{
974 				AddNamedArgument(named, typeofMarshalAs, "MarshalType", module.universe.System_String, fm.MarshalType);
975 			}
976 			if (fm.MarshalTypeRef != null)
977 			{
978 				AddNamedArgument(named, typeofMarshalAs, "MarshalTypeRef", module.universe.System_Type, fm.MarshalTypeRef);
979 			}
980 			if (fm.MarshalCookie != null)
981 			{
982 				AddNamedArgument(named, typeofMarshalAs, "MarshalCookie", module.universe.System_String, fm.MarshalCookie);
983 			}
984 			ConstructorInfo constructor = typeofMarshalAs.GetPseudoCustomAttributeConstructor(typeofUnmanagedType);
985 			return new CustomAttributeData(module, constructor, new object[] { (int)fm.UnmanagedType }, named);
986 		}
987 
AddNamedArgument(List<CustomAttributeNamedArgument> list, Type type, string fieldName, string value)988 		private static void AddNamedArgument(List<CustomAttributeNamedArgument> list, Type type, string fieldName, string value)
989 		{
990 			AddNamedArgument(list, type, fieldName, type.Module.universe.System_String, value);
991 		}
992 
AddNamedArgument(List<CustomAttributeNamedArgument> list, Type type, string fieldName, int flags, int flagMask)993 		private static void AddNamedArgument(List<CustomAttributeNamedArgument> list, Type type, string fieldName, int flags, int flagMask)
994 		{
995 			AddNamedArgument(list, type, fieldName, type.Module.universe.System_Boolean, (flags & flagMask) != 0);
996 		}
997 
AddNamedArgument(List<CustomAttributeNamedArgument> list, Type attributeType, string fieldName, Type valueType, object value)998 		private static void AddNamedArgument(List<CustomAttributeNamedArgument> list, Type attributeType, string fieldName, Type valueType, object value)
999 		{
1000 			// some fields are not available on the .NET Compact Framework version of DllImportAttribute/MarshalAsAttribute
1001 			FieldInfo field = attributeType.FindField(fieldName, FieldSignature.Create(valueType, new CustomModifiers()));
1002 			if (field != null)
1003 			{
1004 				list.Add(new CustomAttributeNamedArgument(field, new CustomAttributeTypedArgument(valueType, value)));
1005 			}
1006 		}
1007 
CreateFieldOffsetPseudoCustomAttribute(Module module, int offset)1008 		internal static CustomAttributeData CreateFieldOffsetPseudoCustomAttribute(Module module, int offset)
1009 		{
1010 			Type type = module.universe.System_Runtime_InteropServices_FieldOffsetAttribute;
1011 			ConstructorInfo constructor = type.GetPseudoCustomAttributeConstructor(module.universe.System_Int32);
1012 			return new CustomAttributeData(module, constructor, new object[] { offset }, null);
1013 		}
1014 
CreatePreserveSigPseudoCustomAttribute(Module module)1015 		internal static CustomAttributeData CreatePreserveSigPseudoCustomAttribute(Module module)
1016 		{
1017 			Type type = module.universe.System_Runtime_InteropServices_PreserveSigAttribute;
1018 			ConstructorInfo constructor = type.GetPseudoCustomAttributeConstructor();
1019 			return new CustomAttributeData(module, constructor, Empty<object>.Array, null);
1020 		}
1021 	}
1022 }
1023