2
Copyright (C) 2009-2012 Jeroen Frijters
4
This software is provided 'as-is', without any express or implied
5
warranty. In no event will the authors be held liable for any damages
6
arising from the use of this software.
8
Permission is granted to anyone to use this software for any purpose,
9
including commercial applications, and to alter it and redistribute it
10
freely, subject to the following restrictions:
12
1. The origin of this software must not be misrepresented; you must not
13
claim that you wrote the original software. If you use this software
14
in a product, an acknowledgment in the product documentation would be
15
appreciated but is not required.
16
2. Altered source versions must be plainly marked as such, and must not be
17
misrepresented as being the original software.
18
3. This notice may not be removed or altered from any source distribution.
25
using System.Globalization;
26
using System.Configuration.Assemblies;
28
using System.Security.Cryptography;
30
using IKVM.Reflection.Reader;
32
namespace IKVM.Reflection
34
public sealed class AssemblyName : ICloneable
37
private string culture;
38
private Version version;
39
private byte[] publicKeyToken;
40
private byte[] publicKey;
41
private StrongNameKeyPair keyPair;
42
private AssemblyNameFlags flags;
43
private AssemblyHashAlgorithm hashAlgorithm;
44
private AssemblyVersionCompatibility versionCompatibility = AssemblyVersionCompatibility.SameMachine;
45
private ProcessorArchitecture processorArchitecture;
46
private string codeBase;
53
public AssemblyName(string assemblyName)
55
if (assemblyName == null)
57
throw new ArgumentNullException("assemblyName");
59
if (assemblyName == "")
61
throw new ArgumentException();
63
ParsedAssemblyName parsed;
64
switch (Fusion.ParseAssemblyName(assemblyName, out parsed))
66
case ParseAssemblyResult.GenericError:
67
case ParseAssemblyResult.DuplicateKey:
68
throw new FileLoadException();
71
if (parsed.Culture != null)
73
if (parsed.Culture.Equals("neutral", StringComparison.InvariantCultureIgnoreCase))
77
else if (parsed.Culture == "")
79
throw new FileLoadException();
83
culture = new CultureInfo(parsed.Culture).Name;
86
if (parsed.Version != null && parsed.Version.Major != 65535 && parsed.Version.Minor != 65535)
88
// our Fusion parser returns -1 for build and revision for incomplete version numbers (and we want 65535)
89
version = new Version(parsed.Version.Major, parsed.Version.Minor, parsed.Version.Build & 0xFFFF, parsed.Version.Revision & 0xFFFF);
91
if (parsed.PublicKeyToken != null)
93
if (parsed.PublicKeyToken.Equals("null", StringComparison.InvariantCultureIgnoreCase))
95
publicKeyToken = Empty<byte>.Array;
97
else if (parsed.PublicKeyToken.Length != 16)
99
throw new FileLoadException();
103
publicKeyToken = ParseKey(parsed.PublicKeyToken);
106
if (parsed.Retargetable.HasValue)
108
if (parsed.Culture == null || parsed.PublicKeyToken == null || parsed.Version == null || parsed.Version.Build == -1 || parsed.Version.Revision == -1)
110
throw new FileLoadException();
112
if (parsed.Retargetable.Value)
114
flags |= AssemblyNameFlags.Retargetable;
117
ProcessorArchitecture = parsed.ProcessorArchitecture;
118
if (parsed.WindowsRuntime)
120
ContentType = AssemblyContentType.WindowsRuntime;
124
private static byte[] ParseKey(string key)
126
if ((key.Length & 1) != 0)
128
throw new FileLoadException();
130
byte[] buf = new byte[key.Length / 2];
131
for (int i = 0; i < buf.Length; i++)
133
buf[i] = (byte)(ParseHexDigit(key[i * 2]) * 16 + ParseHexDigit(key[i * 2 + 1]));
138
private static int ParseHexDigit(char digit)
140
if (digit >= '0' && digit <= '9')
147
if (digit >= 'a' && digit <= 'f')
149
return 10 + digit - 'a';
153
throw new FileLoadException();
158
public override string ToString()
166
set { name = value; }
169
public CultureInfo CultureInfo
171
get { return culture == null ? null : new CultureInfo(culture); }
172
set { culture = value == null ? null : value.Name; }
175
public string CultureName
177
get { return culture; }
180
internal string Culture
182
get { return culture; }
183
set { culture = value; }
186
public Version Version
188
get { return version; }
189
set { version = value; }
192
public StrongNameKeyPair KeyPair
194
get { return keyPair; }
195
set { keyPair = value; }
198
public string CodeBase
200
get { return codeBase; }
201
set { codeBase = value; }
204
public string EscapedCodeBase
208
// HACK use the real AssemblyName to escape the codebase
209
System.Reflection.AssemblyName tmp = new System.Reflection.AssemblyName();
210
tmp.CodeBase = codeBase;
211
return tmp.EscapedCodeBase;
215
public ProcessorArchitecture ProcessorArchitecture
217
get { return processorArchitecture; }
220
if (value >= ProcessorArchitecture.None && value <= ProcessorArchitecture.Arm)
222
processorArchitecture = value;
223
flags = (flags & ~(AssemblyNameFlags)0x70) | (AssemblyNameFlags)((int)value << 4);
228
public AssemblyNameFlags Flags
230
get { return flags & (AssemblyNameFlags)~0xEF0; }
231
set { flags = (flags & (AssemblyNameFlags)0xEF0) | (value & (AssemblyNameFlags)~0xEF0); }
234
public AssemblyVersionCompatibility VersionCompatibility
236
get { return versionCompatibility; }
237
set { versionCompatibility = value; }
240
public AssemblyContentType ContentType
242
get { return (AssemblyContentType)(((int)flags & 0xE00) >> 9); }
245
if (value >= AssemblyContentType.Default && value <= AssemblyContentType.WindowsRuntime)
247
flags = (flags & ~(AssemblyNameFlags)0xE00) | (AssemblyNameFlags)((int)value << 9);
252
public byte[] GetPublicKey()
257
public void SetPublicKey(byte[] publicKey)
259
this.publicKey = publicKey;
260
flags = (flags & ~AssemblyNameFlags.PublicKey) | (publicKey == null ? 0 : AssemblyNameFlags.PublicKey);
263
public byte[] GetPublicKeyToken()
265
if (publicKeyToken == null && publicKey != null)
267
// note that GetPublicKeyToken() has a side effect in this case, because we retain this token even after the public key subsequently gets changed
268
publicKeyToken = ComputePublicKeyToken(publicKey);
270
return publicKeyToken;
273
public void SetPublicKeyToken(byte[] publicKeyToken)
275
this.publicKeyToken = publicKeyToken;
278
public AssemblyHashAlgorithm HashAlgorithm
280
get { return hashAlgorithm; }
281
set { hashAlgorithm = value; }
289
public string FullName
297
StringBuilder sb = new StringBuilder();
298
bool doubleQuotes = name.StartsWith(" ") || name.EndsWith(" ") || name.IndexOf('\'') != -1;
299
bool singleQuotes = name.IndexOf('"') != -1;
304
else if (doubleQuotes)
308
if (name.IndexOf(',') != -1 || name.IndexOf('\\') != -1 || name.IndexOf('=') != -1 || (singleQuotes && name.IndexOf('\'') != -1))
310
for (int i = 0; i < name.Length; i++)
313
if (c == ',' || c == '\\' || c == '=' || (singleQuotes && c == '\''))
328
else if (doubleQuotes)
334
if ((version.Major & 0xFFFF) != 0xFFFF)
336
sb.Append(", Version=").Append(version.Major & 0xFFFF);
337
if ((version.Minor & 0xFFFF) != 0xFFFF)
339
sb.Append('.').Append(version.Minor & 0xFFFF);
340
if ((version.Build & 0xFFFF) != 0xFFFF)
342
sb.Append('.').Append(version.Build & 0xFFFF);
343
if ((version.Revision & 0xFFFF) != 0xFFFF)
345
sb.Append('.').Append(version.Revision & 0xFFFF);
353
sb.Append(", Culture=").Append(culture == "" ? "neutral" : culture);
355
byte[] publicKeyToken = this.publicKeyToken;
356
if ((publicKeyToken == null || publicKeyToken.Length == 0) && publicKey != null)
358
publicKeyToken = ComputePublicKeyToken(publicKey);
360
if (publicKeyToken != null)
362
sb.Append(", PublicKeyToken=");
363
if (publicKeyToken.Length == 0)
369
AppendPublicKey(sb, publicKeyToken);
372
if ((Flags & AssemblyNameFlags.Retargetable) != 0)
374
sb.Append(", Retargetable=Yes");
376
if (ContentType == AssemblyContentType.WindowsRuntime)
378
sb.Append(", ContentType=WindowsRuntime");
380
return sb.ToString();
384
private static byte[] ComputePublicKeyToken(byte[] publicKey)
386
if (publicKey.Length == 0)
390
byte[] hash = new SHA1Managed().ComputeHash(publicKey);
391
byte[] token = new byte[8];
392
for (int i = 0; i < token.Length; i++)
394
token[i] = hash[hash.Length - 1 - i];
399
internal static string ComputePublicKeyToken(string publicKey)
401
StringBuilder sb = new StringBuilder(16);
402
AppendPublicKey(sb, ComputePublicKeyToken(ParseKey(publicKey)));
403
return sb.ToString();
406
private static void AppendPublicKey(StringBuilder sb, byte[] publicKey)
408
for (int i = 0; i < publicKey.Length; i++)
410
sb.Append("0123456789abcdef"[publicKey[i] >> 4]);
411
sb.Append("0123456789abcdef"[publicKey[i] & 0x0F]);
415
public override bool Equals(object obj)
417
AssemblyName other = obj as AssemblyName;
418
return other != null && other.FullName == this.FullName;
421
public override int GetHashCode()
423
return FullName.GetHashCode();
426
public object Clone()
428
AssemblyName copy = (AssemblyName)MemberwiseClone();
429
copy.publicKey = Copy(publicKey);
430
copy.publicKeyToken = Copy(publicKeyToken);
434
private static byte[] Copy(byte[] b)
436
return b == null || b.Length == 0 ? b : (byte[])b.Clone();
439
public static bool ReferenceMatchesDefinition(AssemblyName reference, AssemblyName definition)
441
// HACK use the real AssemblyName to implement the (broken) ReferenceMatchesDefinition method
442
return System.Reflection.AssemblyName.ReferenceMatchesDefinition(new System.Reflection.AssemblyName(reference.FullName), new System.Reflection.AssemblyName(definition.FullName));
445
public static AssemblyName GetAssemblyName(string path)
449
path = Path.GetFullPath(path);
450
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
452
ModuleReader module = new ModuleReader(null, null, fs, path);
453
if (module.Assembly == null)
455
throw new BadImageFormatException("Module does not contain a manifest");
457
return module.Assembly.GetName();
460
catch (IOException x)
462
throw new FileNotFoundException(x.Message, x);
464
catch (UnauthorizedAccessException x)
466
throw new FileNotFoundException(x.Message, x);
470
internal AssemblyNameFlags RawFlags
472
get { return flags; }
473
set { flags = value; }