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