1 // 2 // CustomAttribute.cs 3 // 4 // Author: 5 // Jb Evain (jbevain@gmail.com) 6 // 7 // Copyright (c) 2008 - 2011 Jb Evain 8 // 9 // Permission is hereby granted, free of charge, to any person obtaining 10 // a copy of this software and associated documentation files (the 11 // "Software"), to deal in the Software without restriction, including 12 // without limitation the rights to use, copy, modify, merge, publish, 13 // distribute, sublicense, and/or sell copies of the Software, and to 14 // permit persons to whom the Software is furnished to do so, subject to 15 // the following conditions: 16 // 17 // The above copyright notice and this permission notice shall be 18 // included in all copies or substantial portions of the Software. 19 // 20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 // 28 29 using System; 30 31 using Mono.Collections.Generic; 32 33 namespace Mono.Cecil { 34 35 public struct CustomAttributeArgument { 36 37 readonly TypeReference type; 38 readonly object value; 39 40 public TypeReference Type { 41 get { return type; } 42 } 43 44 public object Value { 45 get { return value; } 46 } 47 CustomAttributeArgumentMono.Cecil.CustomAttributeArgument48 public CustomAttributeArgument (TypeReference type, object value) 49 { 50 Mixin.CheckType (type); 51 this.type = type; 52 this.value = value; 53 } 54 } 55 56 public struct CustomAttributeNamedArgument { 57 58 readonly string name; 59 readonly CustomAttributeArgument argument; 60 61 public string Name { 62 get { return name; } 63 } 64 65 public CustomAttributeArgument Argument { 66 get { return argument; } 67 } 68 CustomAttributeNamedArgumentMono.Cecil.CustomAttributeNamedArgument69 public CustomAttributeNamedArgument (string name, CustomAttributeArgument argument) 70 { 71 Mixin.CheckName (name); 72 this.name = name; 73 this.argument = argument; 74 } 75 } 76 77 public interface ICustomAttribute { 78 79 TypeReference AttributeType { get; } 80 81 bool HasFields { get; } 82 bool HasProperties { get; } 83 Collection<CustomAttributeNamedArgument> Fields { get; } 84 Collection<CustomAttributeNamedArgument> Properties { get; } 85 } 86 87 public sealed class CustomAttribute : ICustomAttribute { 88 89 readonly internal uint signature; 90 internal bool resolved; 91 MethodReference constructor; 92 byte [] blob; 93 internal Collection<CustomAttributeArgument> arguments; 94 internal Collection<CustomAttributeNamedArgument> fields; 95 internal Collection<CustomAttributeNamedArgument> properties; 96 97 public MethodReference Constructor { 98 get { return constructor; } 99 set { constructor = value; } 100 } 101 102 public TypeReference AttributeType { 103 get { return constructor.DeclaringType; } 104 } 105 106 public bool IsResolved { 107 get { return resolved; } 108 } 109 110 public bool HasConstructorArguments { 111 get { 112 Resolve (); 113 114 return !arguments.IsNullOrEmpty (); 115 } 116 } 117 118 public Collection<CustomAttributeArgument> ConstructorArguments { 119 get { 120 Resolve (); 121 122 return arguments ?? (arguments = new Collection<CustomAttributeArgument> ()); 123 } 124 } 125 126 public bool HasFields { 127 get { 128 Resolve (); 129 130 return !fields.IsNullOrEmpty (); 131 } 132 } 133 134 public Collection<CustomAttributeNamedArgument> Fields { 135 get { 136 Resolve (); 137 138 return fields ?? (fields = new Collection<CustomAttributeNamedArgument> ()); 139 } 140 } 141 142 public bool HasProperties { 143 get { 144 Resolve (); 145 146 return !properties.IsNullOrEmpty (); 147 } 148 } 149 150 public Collection<CustomAttributeNamedArgument> Properties { 151 get { 152 Resolve (); 153 154 return properties ?? (properties = new Collection<CustomAttributeNamedArgument> ()); 155 } 156 } 157 158 internal bool HasImage { 159 get { return constructor != null && constructor.HasImage; } 160 } 161 162 internal ModuleDefinition Module { 163 get { return constructor.Module; } 164 } 165 CustomAttribute(uint signature, MethodReference constructor)166 internal CustomAttribute (uint signature, MethodReference constructor) 167 { 168 this.signature = signature; 169 this.constructor = constructor; 170 this.resolved = false; 171 } 172 CustomAttribute(MethodReference constructor)173 public CustomAttribute (MethodReference constructor) 174 { 175 this.constructor = constructor; 176 this.resolved = true; 177 } 178 CustomAttribute(MethodReference constructor, byte [] blob)179 public CustomAttribute (MethodReference constructor, byte [] blob) 180 { 181 this.constructor = constructor; 182 this.resolved = false; 183 this.blob = blob; 184 } 185 GetBlob()186 public byte [] GetBlob () 187 { 188 if (blob != null) 189 return blob; 190 191 if (!HasImage) 192 throw new NotSupportedException (); 193 194 return blob = Module.Read (this, (attribute, reader) => reader.ReadCustomAttributeBlob (attribute.signature)); 195 } 196 Resolve()197 void Resolve () 198 { 199 if (resolved || !HasImage) 200 return; 201 202 try { 203 Module.Read (this, (attribute, reader) => { 204 reader.ReadCustomAttributeSignature (attribute); 205 return this; 206 }); 207 208 resolved = true; 209 } catch (ResolutionException) { 210 if (arguments != null) 211 arguments.Clear (); 212 if (fields != null) 213 fields.Clear (); 214 if (properties != null) 215 properties.Clear (); 216 217 resolved = false; 218 } 219 } 220 } 221 222 static partial class Mixin { 223 CheckName(string name)224 public static void CheckName (string name) 225 { 226 if (name == null) 227 throw new ArgumentNullException ("name"); 228 if (name.Length == 0) 229 throw new ArgumentException ("Empty name"); 230 } 231 } 232 } 233