25using System.Globalization;
27using System.Reflection.Metadata;
28using System.Security.Cryptography;
43 byte[] publicKeyToken;
45 StrongNameKeyPair keyPair;
46 AssemblyNameFlags flags;
47 AssemblyHashAlgorithm hashAlgorithm;
48 AssemblyVersionCompatibility versionCompatibility = AssemblyVersionCompatibility.SameMachine;
69 if (assemblyName ==
null)
70 throw new ArgumentNullException(
"assemblyName");
71 if (assemblyName ==
"")
72 throw new ArgumentException();
74 switch (
Fusion.ParseAssemblyName(assemblyName, out var parsed))
78 throw new FileLoadException();
81 if (!ParseVersion(parsed.Version, parsed.Retargetable.HasValue, out version))
82 throw new FileLoadException();
85 if (parsed.Culture !=
null)
87 if (parsed.Culture.Equals(
"neutral", StringComparison.OrdinalIgnoreCase))
89 else if (parsed.Culture ==
"")
90 throw new FileLoadException();
92 culture =
new CultureInfo(parsed.Culture).Name;
95 if (parsed.PublicKeyToken !=
null)
97 if (parsed.PublicKeyToken.Equals(
"null", StringComparison.OrdinalIgnoreCase))
98 publicKeyToken = Array.Empty<
byte>();
99 else if (parsed.PublicKeyToken.Length != 16)
100 throw new FileLoadException();
102 publicKeyToken = ParseKey(parsed.PublicKeyToken);
105 if (parsed.Retargetable.HasValue)
107 if (parsed.Culture ==
null || parsed.PublicKeyToken ==
null || version ==
null)
108 throw new FileLoadException();
109 if (parsed.Retargetable.Value)
110 flags |= AssemblyNameFlags.Retargetable;
113 ProcessorArchitecture = parsed.ProcessorArchitecture;
114 if (parsed.WindowsRuntime)
115 ContentType = AssemblyContentType.WindowsRuntime;
118 static byte[] ParseKey(
string key)
120 if ((key.Length & 1) != 0)
121 throw new FileLoadException();
123 var buf =
new byte[key.Length / 2];
124 for (
int i = 0; i < buf.Length; i++)
125 buf[i] = (
byte)(ParseHexDigit(key[i * 2]) * 16 + ParseHexDigit(key[i * 2 + 1]));
130 static int ParseHexDigit(
char digit)
132 if (digit >=
'0' && digit <=
'9')
139 if (digit >=
'a' && digit <=
'f')
140 return 10 + digit -
'a';
142 throw new FileLoadException();
146 public override string ToString()
157 public CultureInfo CultureInfo
159 get => culture ==
null ? null :
new CultureInfo(culture);
160 set => culture = value?.Name;
163 public string CultureName
166 set => culture = value;
169 public Version Version
172 set => version = value;
175 public StrongNameKeyPair KeyPair
178 set => keyPair = value;
181 public string CodeBase
184 set => codeBase = value;
187 public string EscapedCodeBase
192 var tmp =
new System.Reflection.AssemblyName();
193 tmp.CodeBase = codeBase;
194 return tmp.EscapedCodeBase;
198 public ProcessorArchitecture ProcessorArchitecture
200 get => (ProcessorArchitecture)(((
int)flags & 0x70) >> 4);
203 if (value >= ProcessorArchitecture.None && value <= ProcessorArchitecture.Arm64)
204 flags = (flags & ~(AssemblyNameFlags)0x70) | (AssemblyNameFlags)((int)value << 4);
208 public AssemblyNameFlags Flags
210 get => flags & (AssemblyNameFlags)~0xEF0;
211 set => flags = (flags & (AssemblyNameFlags)0xEF0) | (value & (AssemblyNameFlags)~0xEF0);
214 public AssemblyVersionCompatibility VersionCompatibility
216 get => versionCompatibility;
217 set => versionCompatibility = value;
220 public AssemblyContentType ContentType
222 get => (AssemblyContentType)(((
int)flags & 0xE00) >> 9);
225 if (value >= AssemblyContentType.Default && value <= AssemblyContentType.WindowsRuntime)
226 flags = (flags & ~(AssemblyNameFlags)0xE00) | (AssemblyNameFlags)((int)value << 9);
230 public byte[] GetPublicKey()
235 public void SetPublicKey(
byte[] publicKey)
237 this.publicKey = publicKey;
238 flags = (flags & ~AssemblyNameFlags.PublicKey) | (publicKey ==
null ? 0 : AssemblyNameFlags.PublicKey);
241 public byte[] GetPublicKeyToken()
243 if (publicKeyToken ==
null && publicKey !=
null)
246 publicKeyToken = ComputePublicKeyToken(publicKey);
249 return publicKeyToken;
252 public void SetPublicKeyToken(
byte[] publicKeyToken)
254 this.publicKeyToken = publicKeyToken;
257 public AssemblyHashAlgorithm HashAlgorithm
259 get => hashAlgorithm;
260 set => hashAlgorithm = value;
263 public byte[] __Hash => hash;
265 public string FullName
272 ushort versionMajor = 0xFFFF;
273 ushort versionMinor = 0xFFFF;
274 ushort versionBuild = 0xFFFF;
275 ushort versionRevision = 0xFFFF;
279 versionMajor = (ushort)version.Major;
280 versionMinor = (ushort)version.Minor;
281 versionBuild = (ushort)version.Build;
282 versionRevision = (ushort)version.Revision;
285 var publicKeyToken = this.publicKeyToken;
286 if ((publicKeyToken ==
null || publicKeyToken.Length == 0) && publicKey !=
null)
287 publicKeyToken = ComputePublicKeyToken(publicKey);
289 return GetFullName(name, versionMajor, versionMinor, versionBuild, versionRevision, culture, publicKeyToken, (
int)flags);
293 internal static string GetFullName(
string name, ushort versionMajor, ushort versionMinor, ushort versionBuild, ushort versionRevision,
string culture,
byte[] publicKeyToken,
int flags)
295 var sb =
new StringBuilder();
296 bool doubleQuotes = name.StartsWith(
" ") || name.EndsWith(
" ") || name.IndexOf(
'\'') != -1;
297 bool singleQuotes = name.IndexOf(
'"') != -1;
300 else if (doubleQuotes)
303 if (name.IndexOf(
',') != -1 || name.IndexOf(
'\\') != -1 || name.IndexOf(
'=') != -1 || (singleQuotes && name.IndexOf(
'\'') != -1))
305 for (
int i = 0; i < name.Length; i++)
308 if (c ==
',' || c ==
'\\' || c ==
'=' || (singleQuotes && c ==
'\''))
323 else if (doubleQuotes)
327 if (versionMajor != 0xFFFF)
329 sb.Append(
", Version=").Append(versionMajor);
330 if (versionMinor != 0xFFFF)
332 sb.Append(
'.').Append(versionMinor);
333 if (versionBuild != 0xFFFF)
335 sb.Append(
'.').Append(versionBuild);
336 if (versionRevision != 0xFFFF)
338 sb.Append(
'.').Append(versionRevision);
345 sb.Append(
", Culture=").Append(culture ==
"" ?
"neutral" : culture);
347 if (publicKeyToken !=
null)
349 sb.Append(
", PublicKeyToken=");
350 if (publicKeyToken.Length == 0)
356 AppendPublicKey(sb, publicKeyToken);
359 if ((flags & (
int)AssemblyNameFlags.Retargetable) != 0)
361 sb.Append(
", Retargetable=Yes");
363 if ((AssemblyContentType)((flags & 0xE00) >> 9) == AssemblyContentType.WindowsRuntime)
365 sb.Append(
", ContentType=WindowsRuntime");
368 return sb.ToString();
371 internal static byte[] ComputePublicKeyToken(
byte[] publicKey)
373 if (publicKey.Length == 0)
377 using (SHA1 sha1 = SHA1.Create())
378 hash = sha1.ComputeHash(publicKey);
380 var token =
new byte[8];
381 for (
int i = 0; i < token.Length; i++)
382 token[i] = hash[hash.Length - 1 - i];
387 internal static string ComputePublicKeyToken(
string publicKey)
389 var sb =
new StringBuilder(16);
390 AppendPublicKey(sb, ComputePublicKeyToken(ParseKey(publicKey)));
391 return sb.ToString();
394 static void AppendPublicKey(StringBuilder sb,
byte[] publicKey)
396 for (
int i = 0; i < publicKey.Length; i++)
398 sb.Append(
"0123456789abcdef"[publicKey[i] >> 4]);
399 sb.Append(
"0123456789abcdef"[publicKey[i] & 0x0F]);
403 public override bool Equals(
object obj)
405 return obj is
AssemblyName other && other.FullName == FullName;
408 public override int GetHashCode()
410 return FullName.GetHashCode();
413 public object Clone()
416 copy.publicKey = Copy(publicKey);
417 copy.publicKeyToken = Copy(publicKeyToken);
421 static byte[] Copy(
byte[] b)
423 return b ==
null || b.Length == 0 ? b : (
byte[])b.Clone();
429 return System.Reflection.AssemblyName.ReferenceMatchesDefinition(
new System.Reflection.AssemblyName(reference.FullName),
new System.Reflection.AssemblyName(definition.FullName));
439 public static AssemblyName GetAssemblyName(
string assemblyFile)
443 using var st =
new FileStream(Path.GetFullPath(assemblyFile), FileMode.Open, FileAccess.Read, FileShare.Read);
444 using var pe =
new System.Reflection.PortableExecutable.PEReader(st);
445 var mr = pe.GetMetadataReader();
447 if (mr.IsAssembly ==
false)
448 throw new BadImageFormatException(
"Module does not contain a manifest");
450 var nm = mr.GetAssemblyDefinition().Name;
452 throw new BadImageFormatException(
"Module does not contain a manifest");
456 catch (IOException e)
458 throw new FileNotFoundException(e.Message, e);
460 catch (UnauthorizedAccessException e)
462 throw new FileNotFoundException(e.Message, e);
466 internal AssemblyNameFlags RawFlags
469 set => flags = value;
472 static bool ParseVersion(
string str,
bool mustBeComplete, out Version version)
479 var parts = str.Split(
'.');
480 if (parts.Length < 2 || parts.Length > 4)
483 return parts.Length == 1 && ushort.TryParse(parts[0], NumberStyles.Integer,
null, out _);
485 if (parts[0] ==
"" || parts[1] ==
"")
491 ushort build = 65535, revision = 65535;
492 if (ushort.TryParse(parts[0], NumberStyles.Integer,
null, out ushort major) &&
493 ushort.TryParse(parts[1], NumberStyles.Integer,
null, out ushort minor) &&
494 (parts.Length <= 2 || parts[2] ==
"" || ushort.TryParse(parts[2], NumberStyles.Integer,
null, out build)) &&
495 (parts.Length <= 3 || parts[3] ==
"" || (parts[2] !=
"" && ushort.TryParse(parts[3], NumberStyles.Integer,
null, out revision))))
497 if (mustBeComplete && (parts.Length < 4 || parts[2] ==
"" || parts[3] ==
""))
499 else if (major == 65535 || minor == 65535)
502 version =
new Version(major, minor, build, revision);
IKVM.Reflection.AssemblyName AssemblyName
global::java.lang.invoke.LambdaForm.Name Name