2 // System.Resources.ResourceManager.cs
5 // Duncan Mak (duncan@ximian.com)
6 // Dick Porter (dick@ximian.com)
8 // (C) 2001, 2002 Ximian, Inc. http://www.ximian.com
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System
.Collections
;
35 using System
.Reflection
;
36 using System
.Globalization
;
39 namespace System
.Resources
42 public class ResourceManager
44 public static readonly int HeaderVersionNumber
= 1;
45 public static readonly int MagicNumber
= unchecked((int)0xBEEFCACE);
47 protected string BaseNameField
;
48 protected Assembly MainAssembly
;
49 // Maps cultures to ResourceSet objects
50 protected Hashtable ResourceSets
;
52 private bool ignoreCase
;
53 private Type resourceSetType
;
54 private String resourceDir
;
56 /* Recursing through culture parents stops here */
57 private CultureInfo neutral_culture
;
60 protected ResourceManager () {
61 ResourceSets
=new Hashtable();
63 resourceSetType
=typeof(ResourceSet
);
68 public ResourceManager (Type resourceSource
) : this()
70 if (resourceSource
== null)
71 throw new ArgumentNullException ("resourceSource is null.");
73 BaseNameField
= resourceSource
.FullName
;
74 MainAssembly
= resourceSource
.Assembly
;
76 /* Temporary workaround for bug 43567 */
77 resourceSetType
= typeof(ResourceSet
);
78 neutral_culture
= GetNeutralResourcesLanguage(MainAssembly
);
81 public ResourceManager (string baseName
, Assembly assembly
) : this()
84 throw new ArgumentNullException ("baseName is null.");
86 throw new ArgumentNullException ("assembly is null.");
88 BaseNameField
= baseName
;
89 MainAssembly
= assembly
;
90 neutral_culture
= GetNeutralResourcesLanguage(MainAssembly
);
93 private Type
CheckResourceSetType(Type usingResourceSet
)
95 if(usingResourceSet
==null) {
96 return(typeof(ResourceSet
));
98 if (!usingResourceSet
.IsSubclassOf (typeof (ResourceSet
)))
99 throw new ArgumentException ("Type must be from ResourceSet.");
101 return(usingResourceSet
);
105 public ResourceManager (string baseName
, Assembly assembly
, Type usingResourceSet
) : this()
107 if (baseName
== null)
108 throw new ArgumentNullException ("baseName is null.");
110 throw new ArgumentNullException ("assembly is null.");
112 BaseNameField
= baseName
;
113 MainAssembly
= assembly
;
114 resourceSetType
= CheckResourceSetType(usingResourceSet
);
115 neutral_culture
= GetNeutralResourcesLanguage(MainAssembly
);
118 /* Private constructor for CreateFileBasedResourceManager */
119 private ResourceManager(String baseName
, String resourceDir
, Type usingResourceSet
) : this()
122 throw new ArgumentNullException("The base name is null");
124 if(baseName
.EndsWith(".resources")) {
125 throw new ArgumentException("The base name ends in '.resources'");
127 if(resourceDir
==null) {
128 throw new ArgumentNullException("The resourceDir is null");
131 BaseNameField
= baseName
;
133 resourceSetType
= CheckResourceSetType(usingResourceSet
);
134 this.resourceDir
= resourceDir
;
137 public static ResourceManager
CreateFileBasedResourceManager (string baseName
,
138 string resourceDir
, Type usingResourceSet
)
140 return new ResourceManager(baseName
, resourceDir
, usingResourceSet
);
143 public virtual string BaseName
145 get { return BaseNameField; }
148 public virtual bool IgnoreCase
150 get { return ignoreCase; }
151 set { ignoreCase = value; }
154 public virtual Type ResourceSetType
156 get { return resourceSetType; }
159 public virtual object GetObject(string name
)
161 return(GetObject(name
, null));
164 public virtual object GetObject(string name
, CultureInfo culture
)
167 throw new ArgumentNullException("name is null");
171 culture
=CultureInfo
.CurrentUICulture
;
175 ResourceSet
set=InternalGetResourceSet(culture
, true, true);
179 obj
=set.GetObject(name
, ignoreCase
);
185 /* Try parent cultures */
188 culture
=culture
.Parent
;
190 set=InternalGetResourceSet(culture
, true, true);
192 obj
=set.GetObject(name
, ignoreCase
);
197 } while(!culture
.Equals(neutral_culture
) &&
198 !culture
.Equals(CultureInfo
.InvariantCulture
));
205 public virtual ResourceSet
GetResourceSet (CultureInfo culture
,
206 bool createIfNotExists
, bool tryParents
)
209 if (culture
== null) {
210 throw new ArgumentNullException ("CultureInfo is a null reference.");
214 return(InternalGetResourceSet(culture
, createIfNotExists
, tryParents
));
218 public virtual string GetString (string name
)
220 return(GetString(name
, null));
223 public virtual string GetString (string name
, CultureInfo culture
)
226 throw new ArgumentNullException ("Name is null.");
230 culture
=CultureInfo
.CurrentUICulture
;
234 ResourceSet
set=InternalGetResourceSet(culture
, true, true);
238 str
=set.GetString(name
, ignoreCase
);
244 /* Try parent cultures */
247 culture
=culture
.Parent
;
249 set=InternalGetResourceSet(culture
, true, true);
251 str
=set.GetString(name
, ignoreCase
);
256 } while(!culture
.Equals(neutral_culture
) &&
257 !culture
.Equals(CultureInfo
.InvariantCulture
));
263 protected virtual string GetResourceFileName (CultureInfo culture
)
265 if(culture
.Equals(CultureInfo
.InvariantCulture
)) {
266 return(BaseNameField
+ ".resources");
268 return(BaseNameField
+ "." + culture
.Name
+ ".resources");
272 protected virtual ResourceSet
InternalGetResourceSet (CultureInfo culture
, bool Createifnotexists
, bool tryParents
)
276 if (culture
== null) {
277 string msg
= String
.Format ("Could not find any resource appropiate for the " +
278 "specified culture or its parents (assembly:{0})",
279 MainAssembly
!= null ? MainAssembly
.GetName ().Name
: "");
281 throw new MissingManifestResourceException (msg
);
283 /* if we already have this resource set, return it */
284 set=(ResourceSet
)ResourceSets
[culture
];
289 if(MainAssembly
!= null) {
290 /* Assembly resources */
292 string filename
=GetResourceFileName(culture
);
294 stream
=MainAssembly
.GetManifestResourceStream(filename
);
296 /* Try a satellite assembly */
297 Version sat_version
=GetSatelliteContractVersion(MainAssembly
);
300 a
= MainAssembly
.GetSatelliteAssembly (culture
, sat_version
);
301 stream
=a
.GetManifestResourceStream(filename
);
302 } catch (Exception
) {} // Ignored
305 if(stream
!=null && Createifnotexists
==true) {
306 object[] args
=new Object
[1];
311 * MissingMethodException, or
312 * just let someone else deal
315 set=(ResourceSet
)Activator
.CreateInstance(resourceSetType
, args
);
316 } else if (culture
== CultureInfo
.InvariantCulture
) {
317 string msg
= "Could not find any resource appropiate for the " +
318 "specified culture or its parents (assembly:{0})";
320 msg
= String
.Format (msg
, MainAssembly
!= null ? MainAssembly
.GetName ().Name
: "");
322 throw new MissingManifestResourceException (msg
);
324 } else if(resourceDir
!= null) {
326 string filename
=Path
.Combine(resourceDir
, this.GetResourceFileName(culture
));
327 if(File
.Exists(filename
) &&
328 Createifnotexists
==true) {
329 object[] args
=new Object
[1];
334 * MissingMethodException, or
335 * just let someone else deal
338 set=(ResourceSet
)Activator
.CreateInstance(resourceSetType
, args
);
342 if(set==null && tryParents
==true) {
343 // avoid endless recursion
344 if (!culture
.Equals (neutral_culture
) && !culture
.Equals(CultureInfo
.InvariantCulture
))
345 set = InternalGetResourceSet (culture
.Parent
, Createifnotexists
, tryParents
);
349 ResourceSets
.Add(culture
, set);
355 public virtual void ReleaseAllResources ()
359 foreach (ResourceSet r
in ResourceSets
)
361 ResourceSets
.Clear();
365 protected static CultureInfo
GetNeutralResourcesLanguage (Assembly a
)
369 attrs
=a
.GetCustomAttributes(typeof(NeutralResourcesLanguageAttribute
), false);
371 if(attrs
.Length
==0) {
372 return(CultureInfo
.InvariantCulture
);
374 NeutralResourcesLanguageAttribute res_attr
=(NeutralResourcesLanguageAttribute
)attrs
[0];
376 return(new CultureInfo(res_attr
.CultureName
));
380 protected static Version
GetSatelliteContractVersion (Assembly a
)
384 attrs
=a
.GetCustomAttributes(typeof(SatelliteContractVersionAttribute
), false);
386 if(attrs
.Length
==0) {
389 SatelliteContractVersionAttribute sat_attr
=(SatelliteContractVersionAttribute
)attrs
[0];
391 /* Version(string) can throw
392 * ArgumentException if the version is
393 * invalid, but the spec for
394 * GetSatelliteContractVersion says we
395 * can throw the same exception for
396 * the same reason, so dont bother to
399 return(new Version(sat_attr
.Version
));