2798082ba2fd45596b857773c1919e68e4928ead
[mono.git] / mcs / class / Mono.Cecil / Mono.Cecil / AssemblyNameReference.cs
1 //
2 // AssemblyNameReference.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@gmail.com)
6 //
7 // Copyright (c) 2008 - 2010 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 using System.Globalization;
31 using System.Security.Cryptography;
32 using System.Text;
33
34 namespace Mono.Cecil {
35
36         public class AssemblyNameReference : IMetadataScope {
37
38                 string name;
39                 string culture;
40                 Version version;
41                 uint attributes;
42                 byte [] public_key;
43                 byte [] public_key_token;
44                 AssemblyHashAlgorithm hash_algorithm;
45                 byte [] hash;
46
47                 internal MetadataToken token;
48
49                 string full_name;
50
51                 public string Name {
52                         get { return name; }
53                         set {
54                                 name = value;
55                                 full_name = null;
56                         }
57                 }
58
59                 public string Culture {
60                         get { return culture; }
61                         set {
62                                 culture = value;
63                                 full_name = null;
64                         }
65                 }
66
67                 public Version Version {
68                         get { return version; }
69                         set {
70                                  version = value;
71                                  full_name = null;
72                         }
73                 }
74
75                 public AssemblyAttributes Attributes {
76                         get { return (AssemblyAttributes) attributes; }
77                         set { attributes = (uint) value; }
78                 }
79
80                 public bool HasPublicKey {
81                         get { return attributes.GetAttributes ((uint) AssemblyAttributes.PublicKey); }
82                         set { attributes = attributes.SetAttributes ((uint) AssemblyAttributes.PublicKey, value); }
83                 }
84
85                 public bool IsSideBySideCompatible {
86                         get { return attributes.GetAttributes ((uint) AssemblyAttributes.SideBySideCompatible); }
87                         set { attributes = attributes.SetAttributes ((uint) AssemblyAttributes.SideBySideCompatible, value); }
88                 }
89
90                 public bool IsRetargetable {
91                         get { return attributes.GetAttributes ((uint) AssemblyAttributes.Retargetable); }
92                         set { attributes = attributes.SetAttributes ((uint) AssemblyAttributes.Retargetable, value); }
93                 }
94
95                 public byte [] PublicKey {
96                         get { return public_key; }
97                         set {
98                                 public_key = value;
99                                 HasPublicKey = !public_key.IsNullOrEmpty ();
100                                 public_key_token = Empty<byte>.Array;
101                                 full_name = null;
102                         }
103                 }
104
105                 public byte [] PublicKeyToken {
106                         get {
107                                 if (public_key_token.IsNullOrEmpty () && !public_key.IsNullOrEmpty ()) {
108                                         var hash = HashPublicKey ();
109                                         // we need the last 8 bytes in reverse order
110                                         public_key_token = new byte [8];
111                                         Array.Copy (hash, (hash.Length - 8), public_key_token, 0, 8);
112                                         Array.Reverse (public_key_token, 0, 8);
113                                 }
114                                 return public_key_token;
115                         }
116                         set {
117                                 public_key_token = value;
118                                 full_name = null;
119                         }
120                 }
121
122                 byte [] HashPublicKey ()
123                 {
124                         HashAlgorithm algorithm;
125
126                         switch (hash_algorithm) {
127                         case AssemblyHashAlgorithm.Reserved:
128 #if SILVERLIGHT
129                                 throw new NotSupportedException ();
130 #else
131                                 algorithm = MD5.Create ();
132                                 break;
133 #endif
134                         default:
135                                 // None default to SHA1
136 #if SILVERLIGHT
137                                 algorithm = new SHA1Managed ();
138                                 break;
139 #else
140                                 algorithm = SHA1.Create ();
141                                 break;
142 #endif
143                         }
144
145                         using (algorithm)
146                                 return algorithm.ComputeHash (public_key);
147                 }
148
149                 public virtual MetadataScopeType MetadataScopeType {
150                         get { return MetadataScopeType.AssemblyNameReference; }
151                 }
152
153                 public string FullName {
154                         get {
155                                 if (full_name != null)
156                                         return full_name;
157
158                                 const string sep = ", ";
159
160                                 var builder = new StringBuilder ();
161                                 builder.Append (name);
162                                 if (version != null) {
163                                         builder.Append (sep);
164                                         builder.Append ("Version=");
165                                         builder.Append (version.ToString ());
166                                 }
167                                 builder.Append (sep);
168                                 builder.Append ("Culture=");
169                                 builder.Append (string.IsNullOrEmpty (culture) ? "neutral" : culture);
170                                 builder.Append (sep);
171                                 builder.Append ("PublicKeyToken=");
172
173                                 if (this.PublicKeyToken != null && public_key_token.Length > 0) {
174                                         for (int i = 0 ; i < public_key_token.Length ; i++) {
175                                                 builder.Append (public_key_token [i].ToString ("x2"));
176                                         }
177                                 } else
178                                         builder.Append ("null");
179
180                                 return full_name = builder.ToString ();
181                         }
182                 }
183
184                 public static AssemblyNameReference Parse (string fullName)
185                 {
186                         if (fullName == null)
187                                 throw new ArgumentNullException ("fullName");
188                         if (fullName.Length == 0)
189                                 throw new ArgumentException ("Name can not be empty");
190
191                         var name = new AssemblyNameReference ();
192                         var tokens = fullName.Split (',');
193                         for (int i = 0; i < tokens.Length; i++) {
194                                 var token = tokens [i].Trim ();
195
196                                 if (i == 0) {
197                                         name.Name = token;
198                                         continue;
199                                 }
200
201                                 var parts = token.Split ('=');
202                                 if (parts.Length != 2)
203                                         throw new ArgumentException ("Malformed name");
204
205                                 switch (parts [0]) {
206                                 case "Version":
207                                         name.Version = new Version (parts [1]);
208                                         break;
209                                 case "Culture":
210                                         name.Culture = parts [1];
211                                         break;
212                                 case "PublicKeyToken":
213                                         string pk_token = parts [1];
214                                         if (pk_token == "null")
215                                                 break;
216
217                                         name.PublicKeyToken = new byte [pk_token.Length / 2];
218                                         for (int j = 0; j < name.PublicKeyToken.Length; j++) {
219                                                 name.PublicKeyToken [j] = Byte.Parse (pk_token.Substring (j * 2, 2), NumberStyles.HexNumber);
220                                         }
221                                         break;
222                                 }
223                         }
224
225                         return name;
226                 }
227
228                 public AssemblyHashAlgorithm HashAlgorithm {
229                         get { return hash_algorithm; }
230                         set { hash_algorithm = value; }
231                 }
232
233                 public virtual byte [] Hash {
234                         get { return hash; }
235                         set { hash = value; }
236                 }
237
238                 public MetadataToken MetadataToken {
239                         get { return token; }
240                         set { token = value; }
241                 }
242
243                 internal AssemblyNameReference ()
244                 {
245                 }
246
247                 public AssemblyNameReference (string name, Version version)
248                 {
249                         if (name == null)
250                                 throw new ArgumentNullException ("name");
251
252                         this.name = name;
253                         this.version = version;
254                         this.hash_algorithm = AssemblyHashAlgorithm.None;
255                         this.token = new MetadataToken (TokenType.AssemblyRef);
256                 }
257
258                 public override string ToString ()
259                 {
260                         return this.FullName;
261                 }
262         }
263 }