private void TestParseVersion(string value, int major, int minor, int build, int revision, AssemblyIdentityParts expectedParts) { AssemblyIdentityParts actualParts; ulong actual; Assert.True(AssemblyIdentity.TryParseVersion(value, out actual, out actualParts)); Assert.Equal(expectedParts, actualParts); Version actualVersion = AssemblyIdentity.ToVersion(actual); Assert.Equal(new Version(major, minor, build, revision), actualVersion); // compare with fusion var fusionName = FusionAssemblyIdentity.ToAssemblyNameObject("Name, Version=" + value); Assert.NotNull(fusionName); AssemblyIdentityParts fusionParts = 0; var fusionVersion = FusionAssemblyIdentity.GetVersion(fusionName, out fusionParts); Assert.Equal(fusionVersion, actualVersion); // Test limitation: // When constructing INameObject with CANOF.PARSE_DISPLAY_NAME option, // the Version=* is treated as unspecified version. That's also done by TryParseDisplayName, // but outside of TryParseVersion, which we are testing here. if (value == "*") { Assert.Equal((AssemblyIdentityParts)0, fusionParts); } else { Assert.Equal(expectedParts, fusionParts); } }
private void TestParseVersionInvalid(string value) { AssemblyIdentityParts actualParts; ulong actual; Assert.False(AssemblyIdentity.TryParseVersion(value, out actual, out actualParts)); // compare with fusion var fusionName = FusionAssemblyIdentity.ToAssemblyNameObject("Name, Version=" + value); if (fusionName != null) { AssemblyIdentityParts fusionParts = 0; var fusionVersion = FusionAssemblyIdentity.GetVersion(fusionName, out fusionParts); // name parsing succeeds but there is no version: Assert.Equal((AssemblyIdentityParts)0, fusionParts); } }
private void TestParseVersion( string value, int major, int minor, int build, int revision, AssemblyIdentityParts expectedParts ) { AssemblyIdentityParts actualParts; ulong actual; Assert.True(AssemblyIdentity.TryParseVersion(value, out actual, out actualParts)); Assert.Equal(expectedParts, actualParts); Version actualVersion = AssemblyIdentity.ToVersion(actual); Assert.Equal(new Version(major, minor, build, revision), actualVersion); // compare with fusion var fusionName = FusionAssemblyIdentity.ToAssemblyNameObject("Name, Version=" + value); Assert.NotNull(fusionName); AssemblyIdentityParts fusionParts = 0; var fusionVersion = FusionAssemblyIdentity.GetVersion(fusionName, out fusionParts); Assert.Equal(fusionVersion, actualVersion); // Test limitation: // When constructing INameObject with CANOF.PARSE_DISPLAY_NAME option, // the Version=* is treated as unspecified version. That's also done by TryParseDisplayName, // but outside of TryParseVersion, which we are testing here. if (value == "*") { Assert.Equal((AssemblyIdentityParts)0, fusionParts); } else { Assert.Equal(expectedParts, fusionParts); } }
internal static Version GetVersion(IAssemblyName name, out AssemblyIdentityParts parts) { uint?major = GetPropertyWord(name, PropertyId.MAJOR_VERSION); uint?minor = GetPropertyWord(name, PropertyId.MINOR_VERSION); uint?build = GetPropertyWord(name, PropertyId.BUILD_NUMBER); uint?revision = GetPropertyWord(name, PropertyId.REVISION_NUMBER); parts = 0; if (major != null) { parts |= AssemblyIdentityParts.VersionMajor; } if (minor != null) { parts |= AssemblyIdentityParts.VersionMinor; } if (build != null) { parts |= AssemblyIdentityParts.VersionBuild; } if (revision != null) { parts |= AssemblyIdentityParts.VersionRevision; } return(new Version( (int)(major ?? 0), (int)(minor ?? 0), (int)(build ?? 0), (int)(revision ?? 0) )); }
private void TestParseDisplayName(string displayName, AssemblyIdentity expected, AssemblyIdentityParts expectedParts, AssemblyIdentity expectedFusion) { var fusion = FusionAssemblyIdentity.ToAssemblyIdentity(FusionAssemblyIdentity.ToAssemblyNameObject(displayName)); Assert.Equal(expectedFusion, fusion); AssemblyIdentity id = null; AssemblyIdentityParts actualParts; bool success = AssemblyIdentity.TryParseDisplayName(displayName, out id, out actualParts); Assert.Equal(expected, id); Assert.Equal(success, id != null); Assert.Equal(expectedParts, actualParts); }
private void TestParseDisplayName(string displayName, AssemblyIdentity expected, AssemblyIdentityParts expectedParts = 0) { TestParseDisplayName(displayName, expected, expectedParts, expected); }
internal virtual bool ApplyUnificationPolicies(ref AssemblyIdentity reference, ref AssemblyIdentity definition, AssemblyIdentityParts referenceParts, out bool isFxAssembly) { isFxAssembly = false; return true; }
internal override bool ApplyUnificationPolicies( ref AssemblyIdentity reference, ref AssemblyIdentity definition, AssemblyIdentityParts referenceParts, out bool isFxAssembly) { if (reference.ContentType == AssemblyContentType.Default && SimpleNameComparer.Equals(reference.Name, definition.Name) && SimpleNameComparer.Equals(reference.Name, "mscorlib")) { isFxAssembly = true; reference = definition; return(true); } if (!reference.IsRetargetable && definition.IsRetargetable) { // Reference is not retargetable, but definition is retargetable. // Non-equivalent. isFxAssembly = false; return(false); } // Notes: // an assembly might be both retargetable and portable // in that case retargeatable table acts as an override. // Apply portability policy transforms first (e.g. rewrites references to SL assemblies to their desktop equivalents) // If the reference is partial and is missing version or PKT it is not ported. reference = Port(reference); definition = Port(definition); if (reference.IsRetargetable && !definition.IsRetargetable) { if (!AssemblyIdentity.IsFullName(referenceParts)) { isFxAssembly = false; return(false); } // Reference needs to be retargeted before comparison, // unless it's optionally retargetable and we already match the PK bool skipRetargeting = IsOptionallyRetargetableAssembly(reference) && AssemblyIdentity.KeysEqual(reference, definition); if (!skipRetargeting) { reference = Retarget(reference); } } // At this point we are in one of the following states: // // 1) Both ref/def are not retargetable // 2) Both ref/def are retargetable // 3) Ref is retargetable (and has been retargeted) // // We can do a straight compare of ref/def at this point using the // regular rules if (reference.IsRetargetable && definition.IsRetargetable) { isFxAssembly = IsRetargetableAssembly(definition); } else { isFxAssembly = IsFrameworkAssembly(definition); } return(true); }
/// <summary> /// Parses display name filling defaults for any basic properties that are missing. /// </summary> /// <param name="displayName">Display name.</param> /// <param name="identity">A full assembly identity.</param> /// <param name="parts"> /// Parts of the assembly identity that were specified in the display name, /// or 0 if the parsing failed. /// </param> /// <returns>True if display name parsed correctly.</returns> /// <remarks> /// The simple name has to be non-empty. /// A partially specified version might be missing build and/or revision number. The default value for these is 65535. /// The default culture is neutral (<see cref="CultureName"/> is <see cref="String.Empty"/>. /// If neither public key nor token is specified the identity is considered weak. /// </remarks> /// <exception cref="ArgumentNullException"><paramref name="displayName"/> is null.</exception> public static bool TryParseDisplayName(string displayName, out AssemblyIdentity identity, out AssemblyIdentityParts parts) { // see ndp\clr\src\Binder\TextualIdentityParser.cpp, ndp\clr\src\Binder\StringLexer.cpp identity = null; parts = 0; if (displayName == null) { throw new ArgumentNullException(nameof(displayName)); } if (displayName.IndexOf('\0') >= 0) { return(false); } int position = 0; string simpleName; if (!TryParseNameToken(displayName, ref position, out simpleName)) { return(false); } var parsedParts = AssemblyIdentityParts.Name; var seen = AssemblyIdentityParts.Name; Version version = null; string culture = null; bool isRetargetable = false; var contentType = AssemblyContentType.Default; var publicKey = default(ImmutableArray <byte>); var publicKeyToken = default(ImmutableArray <byte>); while (position < displayName.Length) { // Parse ',' name '=' value if (displayName[position] != ',') { return(false); } position++; string propertyName; if (!TryParseNameToken(displayName, ref position, out propertyName)) { return(false); } if (position >= displayName.Length || displayName[position] != '=') { return(false); } position++; string propertyValue; if (!TryParseNameToken(displayName, ref position, out propertyValue)) { return(false); } // Process property if (string.Equals(propertyName, "Version", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.Version) != 0) { return(false); } seen |= AssemblyIdentityParts.Version; if (propertyValue == "*") { continue; } ulong versionLong; AssemblyIdentityParts versionParts; if (!TryParseVersion(propertyValue, out versionLong, out versionParts)) { return(false); } version = ToVersion(versionLong); parsedParts |= versionParts; } else if (string.Equals(propertyName, "Culture", StringComparison.OrdinalIgnoreCase) || string.Equals(propertyName, "Language", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.Culture) != 0) { return(false); } seen |= AssemblyIdentityParts.Culture; if (propertyValue == "*") { continue; } culture = string.Equals(propertyValue, InvariantCultureDisplay, StringComparison.OrdinalIgnoreCase) ? null : propertyValue; parsedParts |= AssemblyIdentityParts.Culture; } else if (string.Equals(propertyName, "PublicKey", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.PublicKey) != 0) { return(false); } seen |= AssemblyIdentityParts.PublicKey; if (propertyValue == "*") { continue; } ImmutableArray <byte> value; if (!TryParsePublicKey(propertyValue, out value)) { return(false); } // NOTE: Fusion would also set the public key token (as derived from the public key) here. // We may need to do this as well for error cases, as Fusion would fail to parse the // assembly name if public key token calculation failed. publicKey = value; parsedParts |= AssemblyIdentityParts.PublicKey; } else if (string.Equals(propertyName, "PublicKeyToken", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.PublicKeyToken) != 0) { return(false); } seen |= AssemblyIdentityParts.PublicKeyToken; if (propertyValue == "*") { continue; } ImmutableArray <byte> value; if (!TryParsePublicKeyToken(propertyValue, out value)) { return(false); } publicKeyToken = value; parsedParts |= AssemblyIdentityParts.PublicKeyToken; } else if (string.Equals(propertyName, "Retargetable", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.Retargetability) != 0) { return(false); } seen |= AssemblyIdentityParts.Retargetability; if (propertyValue == "*") { continue; } if (string.Equals(propertyValue, "Yes", StringComparison.OrdinalIgnoreCase)) { isRetargetable = true; } else if (string.Equals(propertyValue, "No", StringComparison.OrdinalIgnoreCase)) { isRetargetable = false; } else { return(false); } parsedParts |= AssemblyIdentityParts.Retargetability; } else if (string.Equals(propertyName, "ContentType", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.ContentType) != 0) { return(false); } seen |= AssemblyIdentityParts.ContentType; if (propertyValue == "*") { continue; } if (string.Equals(propertyValue, "WindowsRuntime", StringComparison.OrdinalIgnoreCase)) { contentType = AssemblyContentType.WindowsRuntime; } else { return(false); } parsedParts |= AssemblyIdentityParts.ContentType; } else { parsedParts |= AssemblyIdentityParts.Unknown; } } // incompatible values: if (isRetargetable && contentType == AssemblyContentType.WindowsRuntime) { return(false); } bool hasPublicKey = !publicKey.IsDefault; bool hasPublicKeyToken = !publicKeyToken.IsDefault; identity = new AssemblyIdentity(simpleName, version, culture, hasPublicKey ? publicKey : publicKeyToken, hasPublicKey, isRetargetable, contentType); if (hasPublicKey && hasPublicKeyToken && !identity.PublicKeyToken.SequenceEqual(publicKeyToken)) { identity = null; return(false); } parts = parsedParts; return(true); }
/// <summary> /// Parses display name filling defaults for any basic properties that are missing. /// </summary> /// <param name="displayName">Display name.</param> /// <param name="identity">A full assembly identity.</param> /// <param name="parts"> /// Parts of the assembly identity that were specified in the display name, /// or 0 if the parsing failed. /// </param> /// <returns>True if display name parsed correctly.</returns> /// <remarks> /// The simple name has to be non-empty. /// A partially specified version might be missing build and/or revision number. The default value for these is 65535. /// The default culture is neutral (<see cref="CultureName"/> is <see cref="String.Empty"/>. /// If neither public key nor token is specified the identity is considered weak. /// </remarks> /// <exception cref="ArgumentNullException"><paramref name="displayName"/> is null.</exception> public static bool TryParseDisplayName(string displayName, out AssemblyIdentity identity, out AssemblyIdentityParts parts) { // see ndp\clr\src\Binder\TextualIdentityParser.cpp, ndp\clr\src\Binder\StringLexer.cpp identity = null; parts = 0; if (displayName == null) { throw new ArgumentNullException(nameof(displayName)); } if (displayName.IndexOf('\0') >= 0) { return false; } int position = 0; string simpleName; if (!TryParseNameToken(displayName, ref position, out simpleName)) { return false; } var parsedParts = AssemblyIdentityParts.Name; var seen = AssemblyIdentityParts.Name; Version version = null; string culture = null; bool isRetargetable = false; var contentType = AssemblyContentType.Default; var publicKey = default(ImmutableArray<byte>); var publicKeyToken = default(ImmutableArray<byte>); while (position < displayName.Length) { // Parse ',' name '=' value if (displayName[position] != ',') { return false; } position++; string propertyName; if (!TryParseNameToken(displayName, ref position, out propertyName)) { return false; } if (position >= displayName.Length || displayName[position] != '=') { return false; } position++; string propertyValue; if (!TryParseNameToken(displayName, ref position, out propertyValue)) { return false; } // Process property if (string.Equals(propertyName, "Version", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.Version) != 0) { return false; } seen |= AssemblyIdentityParts.Version; if (propertyValue == "*") { continue; } ulong versionLong; AssemblyIdentityParts versionParts; if (!TryParseVersion(propertyValue, out versionLong, out versionParts)) { return false; } version = ToVersion(versionLong); parsedParts |= versionParts; } else if (string.Equals(propertyName, "Culture", StringComparison.OrdinalIgnoreCase) || string.Equals(propertyName, "Language", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.Culture) != 0) { return false; } seen |= AssemblyIdentityParts.Culture; if (propertyValue == "*") { continue; } culture = string.Equals(propertyValue, "neutral", StringComparison.OrdinalIgnoreCase) ? null : propertyValue; parsedParts |= AssemblyIdentityParts.Culture; } else if (string.Equals(propertyName, "PublicKey", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.PublicKey) != 0) { return false; } seen |= AssemblyIdentityParts.PublicKey; if (propertyValue == "*") { continue; } ImmutableArray<byte> value; if (!TryParsePublicKey(propertyValue, out value)) { return false; } // NOTE: Fusion would also set the public key token (as derived from the public key) here. // We may need to do this as well for error cases, as Fusion would fail to parse the // assembly name if public key token calculation failed. publicKey = value; parsedParts |= AssemblyIdentityParts.PublicKey; } else if (string.Equals(propertyName, "PublicKeyToken", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.PublicKeyToken) != 0) { return false; } seen |= AssemblyIdentityParts.PublicKeyToken; if (propertyValue == "*") { continue; } ImmutableArray<byte> value; if (!TryParsePublicKeyToken(propertyValue, out value)) { return false; } publicKeyToken = value; parsedParts |= AssemblyIdentityParts.PublicKeyToken; } else if (string.Equals(propertyName, "Retargetable", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.Retargetability) != 0) { return false; } seen |= AssemblyIdentityParts.Retargetability; if (propertyValue == "*") { continue; } if (string.Equals(propertyValue, "Yes", StringComparison.OrdinalIgnoreCase)) { isRetargetable = true; } else if (string.Equals(propertyValue, "No", StringComparison.OrdinalIgnoreCase)) { isRetargetable = false; } else { return false; } parsedParts |= AssemblyIdentityParts.Retargetability; } else if (string.Equals(propertyName, "ContentType", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.ContentType) != 0) { return false; } seen |= AssemblyIdentityParts.ContentType; if (propertyValue == "*") { continue; } if (string.Equals(propertyValue, "WindowsRuntime", StringComparison.OrdinalIgnoreCase)) { contentType = AssemblyContentType.WindowsRuntime; } else { return false; } parsedParts |= AssemblyIdentityParts.ContentType; } else { parsedParts |= AssemblyIdentityParts.Unknown; } } // incompatible values: if (isRetargetable && contentType == AssemblyContentType.WindowsRuntime) { return false; } bool hasPublicKey = !publicKey.IsDefault; bool hasPublicKeyToken = !publicKeyToken.IsDefault; identity = new AssemblyIdentity(simpleName, version, culture, hasPublicKey ? publicKey : publicKeyToken, hasPublicKey, isRetargetable, contentType); if (hasPublicKey && hasPublicKeyToken && !identity.PublicKeyToken.SequenceEqual(publicKeyToken)) { identity = null; return false; } parts = parsedParts; return true; }
private void TestParseDisplayName(string displayName, AssemblyIdentity expected, AssemblyIdentityParts expectedParts, AssemblyIdentity expectedFusion) { var fusion = FusionAssemblyIdentity.ToAssemblyIdentity(FusionAssemblyIdentity.ToAssemblyNameObject(displayName)); Assert.Equal(expectedFusion, fusion); AssemblyIdentity id = null; AssemblyIdentityParts actualParts; bool success = AssemblyIdentity.TryParseDisplayName(displayName, out id, out actualParts); Assert.Equal(expected, id); Assert.Equal(success, id != null); Assert.Equal(expectedParts, actualParts); }
private void TestParseDisplayName(string displayName, AssemblyIdentity expected, AssemblyIdentityParts expectedParts = 0) { TestParseDisplayName(displayName, expected, expectedParts, expected); }
internal virtual bool ApplyUnificationPolicies(ref AssemblyIdentity reference, ref AssemblyIdentity definition, AssemblyIdentityParts referenceParts, out bool isFxAssembly) { isFxAssembly = false; return(true); }
/// <summary> /// Parses display name filling defaults for any basic properties that are missing. /// </summary> /// <param name="displayName">Display name.</param> /// <param name="identity">A full assembly identity.</param> /// <param name="parts"> /// Parts of the assembly identity that were specified in the display name, /// or 0 if the parsing failed. /// </param> /// <returns>True if display name parsed correctly.</returns> /// <remarks> /// The simple name has to be non-empty. /// A partially specified version might be missing build and/or revision number. The default value for these is 65535. /// The default culture is neutral (<see cref="CultureName"/> is <see cref="String.Empty"/>. /// If neither public key nor token is specified the identity is considered weak. /// </remarks> /// <exception cref="ArgumentNullException"><paramref name="displayName"/> is null.</exception> public static bool TryParseDisplayName(string displayName, out AssemblyIdentity identity, out AssemblyIdentityParts parts) { // see ndp\clr\src\Binder\TextualIdentityParser.cpp, ndp\clr\src\Binder\StringLexer.cpp identity = null; parts = 0; if (displayName == null) { throw new ArgumentNullException("displayName"); } if (displayName.IndexOf('\0') >= 0) { return false; } int position = 0; string simpleName = TryParseNameToken(displayName, ',', ref position); if (simpleName == null) { return false; } var parsedParts = AssemblyIdentityParts.Name; var seen = AssemblyIdentityParts.Name; Version version = null; string culture = null; bool isRetargetable = false; var contentType = AssemblyContentType.Default; var publicKey = default(ImmutableArray<byte>); var publicKeyToken = default(ImmutableArray<byte>); while (position < displayName.Length) { string propertyName = TryParseNameToken(displayName, '=', ref position); if (propertyName == null) { return false; } string propertyValue = TryParseNameToken(displayName, ',', ref position); if (propertyValue == null) { return false; } if (string.Equals(propertyName, "Version", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.Version) != 0) { return false; } seen |= AssemblyIdentityParts.Version; if (propertyValue == "*") { continue; } ulong versionLong; AssemblyIdentityParts versionParts; if (!TryParseVersion(propertyValue, out versionLong, out versionParts)) { return false; } version = ToVersion(versionLong); parsedParts |= versionParts; } else if (string.Equals(propertyName, "Culture", StringComparison.OrdinalIgnoreCase) || string.Equals(propertyName, "Language", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.Culture) != 0) { return false; } seen |= AssemblyIdentityParts.Culture; if (propertyValue == "*") { continue; } culture = string.Equals(propertyValue, "neutral", StringComparison.OrdinalIgnoreCase) ? null : propertyValue; parsedParts |= AssemblyIdentityParts.Culture; } else if (string.Equals(propertyName, "PublicKey", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.PublicKey) != 0) { return false; } seen |= AssemblyIdentityParts.PublicKey; if (propertyValue == "*") { continue; } ImmutableArray<byte> value = ParseKey(propertyValue); if (value.Length == 0) { return false; } publicKey = value; parsedParts |= AssemblyIdentityParts.PublicKey; } else if (string.Equals(propertyName, "PublicKeyToken", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.PublicKeyToken) != 0) { return false; } seen |= AssemblyIdentityParts.PublicKeyToken; if (propertyValue == "*") { continue; } ImmutableArray<byte> value; if (string.Equals(propertyValue, "null", StringComparison.OrdinalIgnoreCase) || string.Equals(propertyValue, "neutral", StringComparison.OrdinalIgnoreCase)) { value = ImmutableArray.Create<byte>(); } else { value = ParseKey(propertyValue); if (value.Length != PublicKeyTokenSize) { return false; } } publicKeyToken = value; parsedParts |= AssemblyIdentityParts.PublicKeyToken; } else if (string.Equals(propertyName, "Retargetable", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.Retargetability) != 0) { return false; } seen |= AssemblyIdentityParts.Retargetability; if (propertyValue == "*") { continue; } if (string.Equals(propertyValue, "Yes", StringComparison.OrdinalIgnoreCase)) { isRetargetable = true; } else if (string.Equals(propertyValue, "No", StringComparison.OrdinalIgnoreCase)) { isRetargetable = false; } else { return false; } parsedParts |= AssemblyIdentityParts.Retargetability; } else if (string.Equals(propertyName, "ContentType", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.ContentType) != 0) { return false; } seen |= AssemblyIdentityParts.ContentType; if (propertyValue == "*") { continue; } if (string.Equals(propertyValue, "WindowsRuntime", StringComparison.OrdinalIgnoreCase)) { contentType = AssemblyContentType.WindowsRuntime; } else { return false; } parsedParts |= AssemblyIdentityParts.ContentType; } else { parsedParts |= AssemblyIdentityParts.Unknown; } } // incompatible values: if (isRetargetable && contentType == AssemblyContentType.WindowsRuntime) { return false; } bool hasPublicKey = !publicKey.IsDefault; bool hasPublicKeyToken = !publicKeyToken.IsDefault; identity = new AssemblyIdentity(simpleName, version, culture, hasPublicKey ? publicKey : publicKeyToken, hasPublicKey, isRetargetable, contentType); if (hasPublicKey && hasPublicKeyToken && !identity.PublicKeyToken.SequenceEqual(publicKeyToken)) { identity = null; return false; } parts = parsedParts; return true; }
/// <summary> /// Parses display name filling defaults for any basic properties that are missing. /// </summary> /// <param name="displayName">Display name.</param> /// <param name="identity">A full assembly identity.</param> /// <param name="parts"> /// Parts of the assembly identity that were specified in the display name, /// or 0 if the parsing failed. /// </param> /// <returns>True if display name parsed correctly.</returns> /// <remarks> /// The simple name has to be non-empty. /// A partially specified version might be missing build and/or revision number. The default value for these is 65535. /// The default culture is neutral (<see cref="CultureName"/> is <see cref="String.Empty"/>. /// If neither public key nor token is specified the identity is considered weak. /// </remarks> /// <exception cref="ArgumentNullException"><paramref name="displayName"/> is null.</exception> public static bool TryParseDisplayName(string displayName, out AssemblyIdentity identity, out AssemblyIdentityParts parts) { // see ndp\clr\src\Binder\TextualIdentityParser.cpp, ndp\clr\src\Binder\StringLexer.cpp identity = null; parts = 0; if (displayName == null) { throw new ArgumentNullException("displayName"); } if (displayName.IndexOf('\0') >= 0) { return(false); } int position = 0; string simpleName = TryParseNameToken(displayName, ',', ref position); if (simpleName == null) { return(false); } var parsedParts = AssemblyIdentityParts.Name; var seen = AssemblyIdentityParts.Name; Version version = null; string culture = null; bool isRetargetable = false; var contentType = AssemblyContentType.Default; var publicKey = default(ImmutableArray <byte>); var publicKeyToken = default(ImmutableArray <byte>); while (position < displayName.Length) { string propertyName = TryParseNameToken(displayName, '=', ref position); if (propertyName == null) { return(false); } string propertyValue = TryParseNameToken(displayName, ',', ref position); if (propertyValue == null) { return(false); } if (string.Equals(propertyName, "Version", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.Version) != 0) { return(false); } seen |= AssemblyIdentityParts.Version; if (propertyValue == "*") { continue; } ulong versionLong; AssemblyIdentityParts versionParts; if (!TryParseVersion(propertyValue, out versionLong, out versionParts)) { return(false); } version = ToVersion(versionLong); parsedParts |= versionParts; } else if (string.Equals(propertyName, "Culture", StringComparison.OrdinalIgnoreCase) || string.Equals(propertyName, "Language", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.Culture) != 0) { return(false); } seen |= AssemblyIdentityParts.Culture; if (propertyValue == "*") { continue; } culture = string.Equals(propertyValue, "neutral", StringComparison.OrdinalIgnoreCase) ? null : propertyValue; parsedParts |= AssemblyIdentityParts.Culture; } else if (string.Equals(propertyName, "PublicKey", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.PublicKey) != 0) { return(false); } seen |= AssemblyIdentityParts.PublicKey; if (propertyValue == "*") { continue; } ImmutableArray <byte> value = ParseKey(propertyValue); if (value.Length == 0) { return(false); } publicKey = value; parsedParts |= AssemblyIdentityParts.PublicKey; } else if (string.Equals(propertyName, "PublicKeyToken", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.PublicKeyToken) != 0) { return(false); } seen |= AssemblyIdentityParts.PublicKeyToken; if (propertyValue == "*") { continue; } ImmutableArray <byte> value; if (string.Equals(propertyValue, "null", StringComparison.OrdinalIgnoreCase) || string.Equals(propertyValue, "neutral", StringComparison.OrdinalIgnoreCase)) { value = ImmutableArray.Create <byte>(); } else { value = ParseKey(propertyValue); if (value.Length != PublicKeyTokenSize) { return(false); } } publicKeyToken = value; parsedParts |= AssemblyIdentityParts.PublicKeyToken; } else if (string.Equals(propertyName, "Retargetable", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.Retargetability) != 0) { return(false); } seen |= AssemblyIdentityParts.Retargetability; if (propertyValue == "*") { continue; } if (string.Equals(propertyValue, "Yes", StringComparison.OrdinalIgnoreCase)) { isRetargetable = true; } else if (string.Equals(propertyValue, "No", StringComparison.OrdinalIgnoreCase)) { isRetargetable = false; } else { return(false); } parsedParts |= AssemblyIdentityParts.Retargetability; } else if (string.Equals(propertyName, "ContentType", StringComparison.OrdinalIgnoreCase)) { if ((seen & AssemblyIdentityParts.ContentType) != 0) { return(false); } seen |= AssemblyIdentityParts.ContentType; if (propertyValue == "*") { continue; } if (string.Equals(propertyValue, "WindowsRuntime", StringComparison.OrdinalIgnoreCase)) { contentType = AssemblyContentType.WindowsRuntime; } else { return(false); } parsedParts |= AssemblyIdentityParts.ContentType; } else { parsedParts |= AssemblyIdentityParts.Unknown; } } // incompatible values: if (isRetargetable && contentType == AssemblyContentType.WindowsRuntime) { return(false); } bool hasPublicKey = !publicKey.IsDefault; bool hasPublicKeyToken = !publicKeyToken.IsDefault; identity = new AssemblyIdentity(simpleName, version, culture, hasPublicKey ? publicKey : publicKeyToken, hasPublicKey, isRetargetable, contentType); if (hasPublicKey && hasPublicKeyToken && !identity.PublicKeyToken.SequenceEqual(publicKeyToken)) { identity = null; return(false); } parts = parsedParts; return(true); }
internal override bool ApplyUnificationPolicies( ref AssemblyIdentity reference, ref AssemblyIdentity definition, AssemblyIdentityParts referenceParts, out bool isFxAssembly) { if (reference.ContentType == AssemblyContentType.Default && SimpleNameComparer.Equals(reference.Name, definition.Name) && SimpleNameComparer.Equals(reference.Name, "mscorlib")) { isFxAssembly = true; reference = definition; return true; } if (!reference.IsRetargetable && definition.IsRetargetable) { // Reference is not retargetable, but definition is retargetable. // Non-equivalent. isFxAssembly = false; return false; } // Notes: // an assembly might be both retargetable and portable // in that case retargeatable table acts as an override. // Apply portability policy transforms first (e.g. rewrites references to SL assemblies to their desktop equivalents) // If the reference is partial and is missing version or PKT it is not ported. reference = Port(reference); definition = Port(definition); if (reference.IsRetargetable && !definition.IsRetargetable) { if (!AssemblyIdentity.IsFullName(referenceParts)) { isFxAssembly = false; return false; } // Reference needs to be retargeted before comparison, // unless it's optionally retargetable and we already match the PK bool skipRetargeting = IsOptionallyRetargetableAssembly(reference) && AssemblyIdentity.KeysEqual(reference, definition); if (!skipRetargeting) { reference = Retarget(reference); } } // At this point we are in one of the following states: // // 1) Both ref/def are not retargetable // 2) Both ref/def are retargetable // 3) Ref is retargetable (and has been retargeted) // // We can do a straight compare of ref/def at this point using the // regular rules if (reference.IsRetargetable && definition.IsRetargetable) { isFxAssembly = IsRetargetableAssembly(definition); } else { isFxAssembly = IsFrameworkAssembly(definition); } return true; }
internal static bool IsFullName(AssemblyIdentityParts parts) { const AssemblyIdentityParts nvc = AssemblyIdentityParts.Name | AssemblyIdentityParts.Version | AssemblyIdentityParts.Culture; return((parts & nvc) == nvc && (parts & AssemblyIdentityParts.PublicKeyOrToken) != 0); }
// internal for testing // Parses version format: // [version-part]{[.][version-part], 3} // Where version part is // [*]|[0-9]* // The number of dots in the version determines the present parts, i.e. // "1..2" parses as "1.0.2.0" with Major, Minor and Build parts. // "1.*" parses as "1.0.0.0" with Major and Minor parts. internal static bool TryParseVersion(string str, out ulong result, out AssemblyIdentityParts parts) { Debug.Assert(str.Length > 0); Debug.Assert(str.IndexOf('\0') < 0); const int MaxVersionParts = 4; const int BitsPerVersionPart = 16; parts = 0; result = 0; int partOffset = BitsPerVersionPart * (MaxVersionParts - 1); int partIndex = 0; int partValue = 0; bool partHasValue = false; bool partHasWildcard = false; int i = 0; while (true) { char c = (i < str.Length) ? str[i++] : '\0'; if (c == '.' || c == 0) { if (partIndex == MaxVersionParts || partHasValue && partHasWildcard) { return false; } result |= ((ulong)partValue) << partOffset; if (partHasValue || partHasWildcard) { parts |= (AssemblyIdentityParts)((int)AssemblyIdentityParts.VersionMajor << partIndex); } if (c == 0) { return true; } // next part: partValue = 0; partOffset -= BitsPerVersionPart; partIndex++; partHasWildcard = partHasValue = false; } else if (c >= '0' && c <= '9') { partHasValue = true; partValue = partValue * 10 + c - '0'; if (partValue > ushort.MaxValue) { return false; } } else if (c == '*') { partHasWildcard = true; } else { return false; } } }
// internal for testing // Parses version format: // [version-part]{[.][version-part], 3} // Where version part is // [*]|[0-9]* // The number of dots in the version determines the present parts, i.e. // "1..2" parses as "1.0.2.0" with Major, Minor and Build parts. // "1.*" parses as "1.0.0.0" with Major and Minor parts. internal static bool TryParseVersion(string str, out ulong result, out AssemblyIdentityParts parts) { Debug.Assert(str.Length > 0); Debug.Assert(str.IndexOf('\0') < 0); const int MaxVersionParts = 4; const int BitsPerVersionPart = 16; parts = 0; result = 0; int partOffset = BitsPerVersionPart * (MaxVersionParts - 1); int partIndex = 0; int partValue = 0; bool partHasValue = false; bool partHasWildcard = false; int i = 0; while (true) { char c = (i < str.Length) ? str[i++] : '\0'; if (c == '.' || c == 0) { if (partIndex == MaxVersionParts || partHasValue && partHasWildcard) { return(false); } result |= ((ulong)partValue) << partOffset; if (partHasValue || partHasWildcard) { parts |= (AssemblyIdentityParts)((int)AssemblyIdentityParts.VersionMajor << partIndex); } if (c == 0) { return(true); } // next part: partValue = 0; partOffset -= BitsPerVersionPart; partIndex++; partHasWildcard = partHasValue = false; } else if (c >= '0' && c <= '9') { partHasValue = true; partValue = partValue * 10 + c - '0'; if (partValue > ushort.MaxValue) { return(false); } } else if (c == '*') { partHasWildcard = true; } else { return(false); } } }
internal static Version GetVersion(IAssemblyName name, out AssemblyIdentityParts parts) { uint? major = GetPropertyWord(name, PropertyId.MAJOR_VERSION); uint? minor = GetPropertyWord(name, PropertyId.MINOR_VERSION); uint? build = GetPropertyWord(name, PropertyId.BUILD_NUMBER); uint? revision = GetPropertyWord(name, PropertyId.REVISION_NUMBER); parts = 0; if (major != null) { parts |= AssemblyIdentityParts.VersionMajor; } if (minor != null) { parts |= AssemblyIdentityParts.VersionMinor; } if (build != null) { parts |= AssemblyIdentityParts.VersionBuild; } if (revision != null) { parts |= AssemblyIdentityParts.VersionRevision; } return new Version((int)(major ?? 0), (int)(minor ?? 0), (int)(build ?? 0), (int)(revision ?? 0)); }