| File: System\ComponentModel\Design\DesigntimeLicenseContext.cs | Web Access |
| Project: src\runtime\src\libraries\System.ComponentModel.TypeConverter\src\System.ComponentModel.TypeConverter.csproj (System.ComponentModel.TypeConverter) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Reflection; namespace System.ComponentModel.Design { /// <summary> /// Provides design-time support for licensing. /// </summary> public class DesigntimeLicenseContext : LicenseContext { internal Hashtable _savedLicenseKeys = new Hashtable(); /// <summary> /// Gets or sets the license usage mode. /// </summary> public override LicenseUsageMode UsageMode => LicenseUsageMode.Designtime; /// <summary> /// Gets a saved license key. /// </summary> public override string? GetSavedLicenseKey(Type type, Assembly? resourceAssembly) => null; /// <summary> /// Sets a saved license key. /// </summary> public override void SetSavedLicenseKey(Type type, string key) { ArgumentNullException.ThrowIfNull(type); _savedLicenseKeys[type.AssemblyQualifiedName!] = key; } } internal sealed class RuntimeLicenseContext : LicenseContext { internal Hashtable? _savedLicenseKeys; /// <summary> /// This method takes a file URL and converts it to a local path. The trick here is that /// if there is a '#' in the path, everything after this is treated as a fragment. So /// we need to append the fragment to the end of the path. /// </summary> private static string GetLocalPath(string fileName) { Debug.Assert(fileName != null && fileName.Length > 0, "Cannot get local path, fileName is not valid"); Uri uri = new Uri(fileName); return uri.LocalPath + uri.Fragment; } [UnconditionalSuppressMessage("SingleFile", "IL3000: Avoid accessing Assembly file path when publishing as a single file", Justification = "Suppressing the warning until gets fixed, see https://github.com/dotnet/runtime/issues/50821")] public override string? GetSavedLicenseKey(Type type, Assembly? resourceAssembly) { if (_savedLicenseKeys == null || _savedLicenseKeys[type.AssemblyQualifiedName!] == null) { _savedLicenseKeys ??= new Hashtable(); resourceAssembly ??= Assembly.GetEntryAssembly(); if (resourceAssembly == null) { // If Assembly.EntryAssembly returns null, then we will // try everything. foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) { // Assemblies loaded in memory return empty string from Location. string location = asm.Location; if (location == string.Empty) continue; string fileName = new FileInfo(location).Name; Stream? s = asm.GetManifestResourceStream(fileName + ".licenses"); // Since the casing may be different depending on how the assembly was loaded, // we'll do a case insensitive lookup for this manifest resource stream... s ??= CaseInsensitiveManifestResourceStreamLookup(asm, fileName + ".licenses"); if (s != null) { DesigntimeLicenseContextSerializer.Deserialize(s, fileName.ToUpperInvariant(), this); break; } } } else { string location = resourceAssembly.Location; if (location != string.Empty) { string fileName = Path.GetFileName(location); string licResourceName = fileName + ".licenses"; // First try the filename Stream? s = resourceAssembly.GetManifestResourceStream(licResourceName); if (s == null) { string? resolvedName = null; CompareInfo comparer = CultureInfo.InvariantCulture.CompareInfo; string shortAssemblyName = resourceAssembly.GetName().Name!; // If the assembly has been renamed, we try our best to find a good match in the available resources // by looking at the assembly name (which doesn't change even after a file rename) + ".exe.licenses" or + ".dll.licenses" foreach (string existingName in resourceAssembly.GetManifestResourceNames()) { if (comparer.Compare(existingName, licResourceName, CompareOptions.IgnoreCase) == 0 || comparer.Compare(existingName, shortAssemblyName + ".exe.licenses", CompareOptions.IgnoreCase) == 0 || comparer.Compare(existingName, shortAssemblyName + ".dll.licenses", CompareOptions.IgnoreCase) == 0) { resolvedName = existingName; break; } } if (resolvedName != null) { s = resourceAssembly.GetManifestResourceStream(resolvedName); } } if (s != null) { DesigntimeLicenseContextSerializer.Deserialize(s, fileName.ToUpperInvariant(), this); } } } } return (string?)_savedLicenseKeys[type.AssemblyQualifiedName!]; } /** * Looks up a .licenses file in the assembly manifest using * case-insensitive lookup rules. We do this because the name * we are attempting to locate could have different casing * depending on how the assembly was loaded. **/ private static Stream? CaseInsensitiveManifestResourceStreamLookup(Assembly satellite, string name) { CompareInfo comparer = CultureInfo.InvariantCulture.CompareInfo; // Loop through the resource names in the assembly. // We try to handle the case where the assembly file name has been renamed // by trying to guess the original file name based on the assembly name. string assemblyShortName = satellite.GetName().Name!; foreach (string existingName in satellite.GetManifestResourceNames()) { if (comparer.Compare(existingName, name, CompareOptions.IgnoreCase) == 0 || comparer.Compare(existingName, assemblyShortName + ".exe.licenses") == 0 || comparer.Compare(existingName, assemblyShortName + ".dll.licenses") == 0) { name = existingName; break; } } // Finally, attempt to return our stream based on the // case insensitive match we found. return satellite.GetManifestResourceStream(name); } } }