PageRenderTime 32ms CodeModel.GetById 8ms app.highlight 18ms RepoModel.GetById 2ms app.codeStats 0ms

/Mono.Cecil/AssemblyNameReference.cs

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