MegaBites-AI/Windows-powershell
0308
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections.Generic;5using System.Reflection;6using System.Resources;7 8namespace System.Management.Automation9{10 /// <summary>11 /// </summary>12 internal static class ResourceManagerCache13 {14 /// <summary>15 /// Maintains a cache of ResourceManager objects. This is a dictionary that is keyed based on the path16 /// to the default resource assembly. The value is another dictionary that is keyed based on the base17 /// name for the resource that is being retrieved. The value for this dictionary is the ResourceManager.18 /// </summary>19 private static readonly Dictionary<string, Dictionary<string, ResourceManager>> s_resourceManagerCache =20 new Dictionary<string, Dictionary<string, ResourceManager>>(StringComparer.OrdinalIgnoreCase);21 22 /// <summary>23 /// Used to synchronize access to the ResourceManagerCache.24 /// </summary>25 private static readonly object s_syncRoot = new object();26 27 /// <summary>28 /// Gets the ResourceManager from the cache or gets an instance of the ResourceManager29 /// and returns it if it isn't already present in the cache.30 /// </summary>31 /// <param name="assembly">32 /// The assembly to be used as the base for resource lookup.33 /// </param>34 /// <param name="baseName">35 /// The base name of the resources to get the ResourceManager for.36 /// </param>37 /// <returns>38 /// A ResourceManager instance for the assembly and base name that were specified.39 /// </returns>40 internal static ResourceManager GetResourceManager(41 Assembly assembly,42 string baseName)43 {44 if (assembly == null)45 {46 throw PSTraceSource.NewArgumentNullException(nameof(assembly));47 }48 49 if (string.IsNullOrEmpty(baseName))50 {51 throw PSTraceSource.NewArgumentException(nameof(baseName));52 }53 54 // Check to see if the manager is already in the cache55 56 ResourceManager manager = null;57 Dictionary<string, ResourceManager> baseNameCache;58 59 string assemblyManifestFileLocation = assembly.Location;60 lock (s_syncRoot)61 {62 // First do the lookup based on the assembly location63 64 if (s_resourceManagerCache.TryGetValue(assemblyManifestFileLocation, out baseNameCache) && baseNameCache != null)65 {66 // Now do the lookup based on the resource base name67 baseNameCache.TryGetValue(baseName, out manager);68 }69 }70 71 // If it's not in the cache, create it an add it.72 if (manager == null)73 {74 manager = InitRMWithAssembly(baseName, assembly);75 76 // Add the new resource manager to the hash77 78 if (baseNameCache != null)79 {80 lock (s_syncRoot)81 {82 // Since the assembly is already cached, we just have83 // to cache the base name entry84 85 baseNameCache[baseName] = manager;86 }87 }88 else89 {90 // Since the assembly wasn't cached, we have to create base name91 // cache entry and then add it into the cache keyed by the assembly92 // location93 94 var baseNameCacheEntry = new Dictionary<string, ResourceManager>();95 96 baseNameCacheEntry[baseName] = manager;97 98 lock (s_syncRoot)99 {100 s_resourceManagerCache[assemblyManifestFileLocation] = baseNameCacheEntry;101 }102 }103 }104 105 Diagnostics.Assert(106 manager != null,107 "If the manager was not already created, it should have been dynamically created or an exception should have been thrown");108 109 return manager;110 }111 112 /// <summary>113 /// Design For Testability -- assert on failed resource lookup.114 /// </summary>115 private static bool s_DFT_monitorFailingResourceLookup = true;116 117 internal static bool DFT_DoMonitorFailingResourceLookup118 {119 get { return ResourceManagerCache.s_DFT_monitorFailingResourceLookup; }120 121 set { ResourceManagerCache.s_DFT_monitorFailingResourceLookup = value; }122 }123 124 /// <summary>125 /// Gets the string from the resource manager based on the assembly,126 /// base name, resource ID, and culture specified.127 /// </summary>128 /// <param name="assembly">129 /// The base assembly from which to get the resources from.130 /// </param>131 /// <param name="baseName">132 /// The base name of the resource to retrieve the string from.133 /// </param>134 /// <param name="resourceId">135 /// Resource ID for which the localized string needs to be retrieved136 /// </param>137 /// <returns>138 /// Localized String, or null if the string does not exist139 /// </returns>140 /// <remarks>141 /// The current thread's UI culture is used.142 /// </remarks>143 /// <throws>144 /// ArgumentException if <paramref name="baseName"/> or <paramref name="resourceId"/>145 /// are null or empty..146 /// InvalidOperationException if the value of the specified resource is not a string147 /// MissingManifestResourceException if no usable set of resources have been found, and148 /// there are no neutral culture resources.149 /// </throws>150 internal static string GetResourceString(151 Assembly assembly,152 string baseName,153 string resourceId)154 {155 if (assembly == null)156 {157 throw PSTraceSource.NewArgumentNullException(nameof(assembly));158 }159 160 if (string.IsNullOrEmpty(baseName))161 {162 throw PSTraceSource.NewArgumentException(nameof(baseName));163 }164 165 if (string.IsNullOrEmpty(resourceId))166 {167 throw PSTraceSource.NewArgumentException(nameof(resourceId));168 }169 170 ResourceManager resourceManager = null;171 string text = string.Empty;172 173 // For a non-existing resource defined by {assembly,baseName,resourceId}174 // MissingManifestResourceException is thrown only at the time when resource retrieval method175 // such as ResourceManager.GetString or ResourceManager.GetObject is called,176 // not when you instantiate a ResourceManager object.177 try178 {179 // try with original baseName first180 // if it fails then try with alternative resource path format181 resourceManager = GetResourceManager(assembly, baseName);182 text = resourceManager.GetString(resourceId);183 }184 catch (MissingManifestResourceException)185 {186 const string resourcesSubstring = ".resources.";187 int resourcesSubstringIndex = baseName.IndexOf(resourcesSubstring);188 string newBaseName = string.Empty;189 if (resourcesSubstringIndex != -1)190 {191 newBaseName = baseName.Substring(resourcesSubstringIndex + resourcesSubstring.Length); // e.g. "FileSystemProviderStrings"192 }193 else194 {195 newBaseName = string.Concat(assembly.GetName().Name, resourcesSubstring, baseName); // e.g. "System.Management.Automation.resources.FileSystemProviderStrings"196 }197 198 resourceManager = GetResourceManager(assembly, newBaseName);199 text = resourceManager.GetString(resourceId);200 }201 202 if (string.IsNullOrEmpty(text) && s_DFT_monitorFailingResourceLookup)203 {204 Diagnostics.Assert(false,205 "Lookup failure: baseName " + baseName + " resourceId " + resourceId);206 }207 208 return text;209 }210 211 /// <summary>212 /// Creates a Resource manager instance based on the assembly specified.213 /// </summary>214 /// <param name="baseName">215 /// The root name of the resources.216 /// For example, the root name for the resource file217 /// named "MyResource.en-US.resources" is "MyResource".218 /// </param>219 /// <param name="assemblyToUse">220 /// The main Assembly for the resources221 /// </param>222 /// <returns>Resource Manager instance.</returns>223 /// <exception cref="ArgumentException">224 /// Thrown if the resource manager instance could not be created225 /// </exception>226 private static ResourceManager InitRMWithAssembly(string baseName, Assembly assemblyToUse)227 {228 ResourceManager rm = null;229 230 if (baseName != null && assemblyToUse != null)231 {232 rm = new ResourceManager(baseName, assemblyToUse);233 }234 else235 {236 // 2004/10/11-JonN Do we need a better error message? I don't think so,237 // since this is private.238 throw PSTraceSource.NewArgumentException(nameof(assemblyToUse));239 }240 241 return rm;242 }243 }244}245 