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