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