ResourceManager.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. //
  2. // System.Resources.ResourceManager.cs
  3. //
  4. // Authors:
  5. // Duncan Mak ([email protected])
  6. // Dick Porter ([email protected])
  7. //
  8. // (C) 2001, 2002 Ximian, Inc. http://www.ximian.com
  9. //
  10. //
  11. // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
  12. //
  13. // Permission is hereby granted, free of charge, to any person obtaining
  14. // a copy of this software and associated documentation files (the
  15. // "Software"), to deal in the Software without restriction, including
  16. // without limitation the rights to use, copy, modify, merge, publish,
  17. // distribute, sublicense, and/or sell copies of the Software, and to
  18. // permit persons to whom the Software is furnished to do so, subject to
  19. // the following conditions:
  20. //
  21. // The above copyright notice and this permission notice shall be
  22. // included in all copies or substantial portions of the Software.
  23. //
  24. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  26. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  27. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  28. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  29. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  30. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  31. //
  32. using System.Collections;
  33. using System.Reflection;
  34. using System.Globalization;
  35. using System.IO;
  36. namespace System.Resources
  37. {
  38. [Serializable]
  39. public class ResourceManager
  40. {
  41. public static readonly int HeaderVersionNumber = 1;
  42. public static readonly int MagicNumber = unchecked((int)0xBEEFCACE);
  43. protected string BaseNameField;
  44. protected Assembly MainAssembly;
  45. // Maps cultures to ResourceSet objects
  46. protected Hashtable ResourceSets;
  47. private bool ignoreCase;
  48. private Type resourceSetType;
  49. private String resourceDir;
  50. /* Recursing through culture parents stops here */
  51. private CultureInfo neutral_culture;
  52. // constructors
  53. protected ResourceManager () {
  54. ResourceSets=new Hashtable();
  55. ignoreCase=false;
  56. resourceSetType=typeof(ResourceSet);
  57. resourceDir=null;
  58. neutral_culture=null;
  59. }
  60. public ResourceManager (Type resourceSource) : this()
  61. {
  62. if (resourceSource == null)
  63. throw new ArgumentNullException ("resourceSource is null.");
  64. BaseNameField = resourceSource.FullName;
  65. MainAssembly = resourceSource.Assembly;
  66. /* Temporary workaround for bug 43567 */
  67. resourceSetType = typeof(ResourceSet);
  68. neutral_culture = GetNeutralResourcesLanguage(MainAssembly);
  69. }
  70. public ResourceManager (string baseName, Assembly assembly) : this()
  71. {
  72. if (baseName == null)
  73. throw new ArgumentNullException ("baseName is null.");
  74. if(assembly == null)
  75. throw new ArgumentNullException ("assembly is null.");
  76. BaseNameField = baseName;
  77. MainAssembly = assembly;
  78. neutral_culture = GetNeutralResourcesLanguage(MainAssembly);
  79. }
  80. private Type CheckResourceSetType(Type usingResourceSet)
  81. {
  82. if(usingResourceSet==null) {
  83. return(typeof(ResourceSet));
  84. } else {
  85. if (!usingResourceSet.IsSubclassOf (typeof (ResourceSet)))
  86. throw new ArgumentException ("Type must be from ResourceSet.");
  87. return(usingResourceSet);
  88. }
  89. }
  90. public ResourceManager (string baseName, Assembly assembly, Type usingResourceSet) : this()
  91. {
  92. if (baseName == null)
  93. throw new ArgumentNullException ("baseName is null.");
  94. if(assembly == null)
  95. throw new ArgumentNullException ("assembly is null.");
  96. BaseNameField = baseName;
  97. MainAssembly = assembly;
  98. resourceSetType = CheckResourceSetType(usingResourceSet);
  99. neutral_culture = GetNeutralResourcesLanguage(MainAssembly);
  100. }
  101. /* Private constructor for CreateFileBasedResourceManager */
  102. private ResourceManager(String baseName, String resourceDir, Type usingResourceSet) : this()
  103. {
  104. if(baseName==null) {
  105. throw new ArgumentNullException("The base name is null");
  106. }
  107. if(baseName.EndsWith(".resources")) {
  108. throw new ArgumentException("The base name ends in '.resources'");
  109. }
  110. if(resourceDir==null) {
  111. throw new ArgumentNullException("The resourceDir is null");
  112. }
  113. BaseNameField = baseName;
  114. MainAssembly = null;
  115. resourceSetType = CheckResourceSetType(usingResourceSet);
  116. this.resourceDir = resourceDir;
  117. }
  118. public static ResourceManager CreateFileBasedResourceManager (string baseName,
  119. string resourceDir, Type usingResourceSet)
  120. {
  121. return new ResourceManager(baseName, resourceDir, usingResourceSet);
  122. }
  123. public virtual string BaseName
  124. {
  125. get { return BaseNameField; }
  126. }
  127. public virtual bool IgnoreCase
  128. {
  129. get { return ignoreCase; }
  130. set { ignoreCase = value; }
  131. }
  132. public virtual Type ResourceSetType
  133. {
  134. get { return resourceSetType; }
  135. }
  136. public virtual object GetObject(string name)
  137. {
  138. return(GetObject(name, null));
  139. }
  140. public virtual object GetObject(string name, CultureInfo culture)
  141. {
  142. if(name==null) {
  143. throw new ArgumentNullException("name is null");
  144. }
  145. if(culture==null) {
  146. culture=CultureInfo.CurrentUICulture;
  147. }
  148. lock(this) {
  149. ResourceSet set=InternalGetResourceSet(culture, true, true);
  150. object obj=null;
  151. if(set != null) {
  152. obj=set.GetObject(name, ignoreCase);
  153. if(obj != null) {
  154. return(obj);
  155. }
  156. }
  157. /* Try parent cultures */
  158. do {
  159. culture=culture.Parent;
  160. set=InternalGetResourceSet(culture, true, true);
  161. if(set!=null) {
  162. obj=set.GetObject(name, ignoreCase);
  163. if(obj != null) {
  164. return(obj);
  165. }
  166. }
  167. } while(!culture.Equals(neutral_culture) &&
  168. !culture.Equals(CultureInfo.InvariantCulture));
  169. }
  170. return(null);
  171. }
  172. public virtual ResourceSet GetResourceSet (CultureInfo culture,
  173. bool createIfNotExists, bool tryParents)
  174. {
  175. if (culture == null) {
  176. throw new ArgumentNullException ("CultureInfo is a null reference.");
  177. }
  178. lock(this) {
  179. return(InternalGetResourceSet(culture, createIfNotExists, tryParents));
  180. }
  181. }
  182. public virtual string GetString (string name)
  183. {
  184. return(GetString(name, null));
  185. }
  186. public virtual string GetString (string name, CultureInfo culture)
  187. {
  188. if (name == null) {
  189. throw new ArgumentNullException ("Name is null.");
  190. }
  191. if(culture==null) {
  192. culture=CultureInfo.CurrentUICulture;
  193. }
  194. lock(this) {
  195. ResourceSet set=InternalGetResourceSet(culture, true, true);
  196. string str=null;
  197. if(set!=null) {
  198. str=set.GetString(name, ignoreCase);
  199. if(str!=null) {
  200. return(str);
  201. }
  202. }
  203. /* Try parent cultures */
  204. do {
  205. culture=culture.Parent;
  206. set=InternalGetResourceSet(culture, true, true);
  207. if(set!=null) {
  208. str=set.GetString(name, ignoreCase);
  209. if(str!=null) {
  210. return(str);
  211. }
  212. }
  213. } while(!culture.Equals(neutral_culture) &&
  214. !culture.Equals(CultureInfo.InvariantCulture));
  215. }
  216. return(null);
  217. }
  218. protected virtual string GetResourceFileName (CultureInfo culture)
  219. {
  220. if(culture.Equals(CultureInfo.InvariantCulture)) {
  221. return(BaseNameField + ".resources");
  222. } else {
  223. return(BaseNameField + "." + culture.Name + ".resources");
  224. }
  225. }
  226. static Stream GetManifestResourceStreamNoCase (Assembly ass, string fn)
  227. {
  228. foreach (string s in ass.GetManifestResourceNames ())
  229. if (String.Compare (fn, s, true, CultureInfo.InvariantCulture) == 0)
  230. return ass.GetManifestResourceStream (s);
  231. return null;
  232. }
  233. protected virtual ResourceSet InternalGetResourceSet (CultureInfo culture, bool Createifnotexists, bool tryParents)
  234. {
  235. ResourceSet set;
  236. if (culture == null) {
  237. string msg = String.Format ("Could not find any resource appropiate for the " +
  238. "specified culture or its parents (assembly:{0})",
  239. MainAssembly != null ? MainAssembly.GetName ().Name : "");
  240. throw new MissingManifestResourceException (msg);
  241. }
  242. /* if we already have this resource set, return it */
  243. set=(ResourceSet)ResourceSets[culture];
  244. if(set!=null) {
  245. return(set);
  246. }
  247. if(MainAssembly != null) {
  248. /* Assembly resources */
  249. Stream stream;
  250. string filename=GetResourceFileName(culture);
  251. stream=MainAssembly.GetManifestResourceStream(filename);
  252. if (stream == null)
  253. stream = GetManifestResourceStreamNoCase (MainAssembly, filename);
  254. if(stream==null) {
  255. /* Try a satellite assembly */
  256. Version sat_version=GetSatelliteContractVersion(MainAssembly);
  257. Assembly a = null;
  258. try {
  259. a = MainAssembly.GetSatelliteAssembly (culture, sat_version);
  260. stream=a.GetManifestResourceStream(filename);
  261. if (stream == null)
  262. stream = GetManifestResourceStreamNoCase (a, filename);
  263. } catch (Exception) {} // Ignored
  264. }
  265. if(stream!=null && Createifnotexists==true) {
  266. object[] args=new Object[1];
  267. args[0]=stream;
  268. /* should we catch
  269. * MissingMethodException, or
  270. * just let someone else deal
  271. * with it?
  272. */
  273. set=(ResourceSet)Activator.CreateInstance(resourceSetType, args);
  274. } else if (culture.Equals (CultureInfo.InvariantCulture)) {
  275. string msg = "Could not find any resource appropiate for the " +
  276. "specified culture or its parents. " +
  277. "Make sure \"{1}\" was correctly embedded or " +
  278. "linked into assembly \"{0}\".";
  279. msg = String.Format (msg, MainAssembly != null ? MainAssembly.GetName ().Name : "", filename);
  280. throw new MissingManifestResourceException (msg);
  281. }
  282. } else if(resourceDir != null) {
  283. /* File resources */
  284. string filename=Path.Combine(resourceDir, this.GetResourceFileName(culture));
  285. if(File.Exists(filename) &&
  286. Createifnotexists==true) {
  287. object[] args=new Object[1];
  288. args[0]=filename;
  289. /* should we catch
  290. * MissingMethodException, or
  291. * just let someone else deal
  292. * with it?
  293. */
  294. set=(ResourceSet)Activator.CreateInstance(resourceSetType, args);
  295. }
  296. }
  297. if(set==null && tryParents==true) {
  298. // avoid endless recursion
  299. if (!culture.Equals (neutral_culture) && !culture.Equals(CultureInfo.InvariantCulture))
  300. set = InternalGetResourceSet (culture.Parent, Createifnotexists, tryParents);
  301. }
  302. if(set!=null) {
  303. ResourceSets.Add(culture, set);
  304. }
  305. return(set);
  306. }
  307. public virtual void ReleaseAllResources ()
  308. {
  309. lock(this)
  310. {
  311. foreach (ResourceSet r in ResourceSets)
  312. r.Close();
  313. ResourceSets.Clear();
  314. }
  315. }
  316. protected static CultureInfo GetNeutralResourcesLanguage (Assembly a)
  317. {
  318. object[] attrs;
  319. attrs=a.GetCustomAttributes(typeof(NeutralResourcesLanguageAttribute), false);
  320. if(attrs.Length==0) {
  321. return(CultureInfo.InvariantCulture);
  322. } else {
  323. NeutralResourcesLanguageAttribute res_attr=(NeutralResourcesLanguageAttribute)attrs[0];
  324. return(new CultureInfo(res_attr.CultureName));
  325. }
  326. }
  327. protected static Version GetSatelliteContractVersion (Assembly a)
  328. {
  329. object[] attrs;
  330. attrs=a.GetCustomAttributes(typeof(SatelliteContractVersionAttribute), false);
  331. if(attrs.Length==0) {
  332. return(null);
  333. } else {
  334. SatelliteContractVersionAttribute sat_attr=(SatelliteContractVersionAttribute)attrs[0];
  335. /* Version(string) can throw
  336. * ArgumentException if the version is
  337. * invalid, but the spec for
  338. * GetSatelliteContractVersion says we
  339. * can throw the same exception for
  340. * the same reason, so dont bother to
  341. * catch it.
  342. */
  343. return(new Version(sat_attr.Version));
  344. }
  345. }
  346. }
  347. }