2004-01-09 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / corlib / System.Resources / ResourceManager.cs
index cd420d2cf367e4bee7efaed73f6bf4ccfbca9854..1f7182547fed8d3065e566bd9c97b72ed1c99316 100644 (file)
 //     
 // System.Resources.ResourceManager.cs
 //
-// Author:
+// Authors:
 //     Duncan Mak (duncan@ximian.com)
+//     Dick Porter (dick@ximian.com)
 //
-// 2001 (C) Ximian, Inc. http://www.ximian.com
+// (C) 2001, 2002 Ximian, Inc. http://www.ximian.com
 //
 
 using System.Collections;
 using System.Reflection;
 using System.Globalization;
+using System.IO;
 
 namespace System.Resources
 {
        [Serializable]
        public class ResourceManager
        {
-               public static readonly int HeaderVersionNumber;
-               // public static readonly int MagicNumber = 0xBEEFCACE;
+               public static readonly int HeaderVersionNumber = 1;
+               public static readonly int MagicNumber = unchecked((int)0xBEEFCACE);
 
                protected string BaseNameField;
                protected Assembly MainAssembly;
+               // Maps cultures to ResourceSet objects
                protected Hashtable ResourceSets;
                
                private bool ignoreCase;
                private Type resourceSetType;
+               private String resourceDir;
+               
+               /* Recursing through culture parents stops here */
+               private CultureInfo neutral_culture;
                
                // constructors
-               public ResourceManager () {}
+               protected ResourceManager () {
+                       ResourceSets=new Hashtable();
+                       ignoreCase=false;
+                       resourceSetType=typeof(ResourceSet);
+                       resourceDir=null;
+                       neutral_culture=null;
+               }
                
-               public ResourceManager (Type resourceSource)
+               public ResourceManager (Type resourceSource) : this()
                {
                        if (resourceSource == null)
                                throw new ArgumentNullException ("resourceSource is null.");
                        
                        BaseNameField = resourceSource.FullName;
                        MainAssembly = resourceSource.Assembly;
-                       
-                       ignoreCase = false;
-                       resourceSetType = resourceSource;
+
+                       /* Temporary workaround for bug 43567 */
+                       resourceSetType = typeof(ResourceSet);
+                       neutral_culture = GetNeutralResourcesLanguage(MainAssembly);
                }
                
-               public ResourceManager (string baseName, Assembly assembly)
+               public ResourceManager (string baseName, Assembly assembly) : this()
                {
-                       if (baseName == null || assembly == null)
-                               throw new ArgumentNullException ("The arguments are null.");
+                       if (baseName == null)
+                               throw new ArgumentNullException ("baseName is null.");
+                       if(assembly == null)
+                               throw new ArgumentNullException ("assembly is null.");
                        
                        BaseNameField = baseName;
                        MainAssembly = assembly;
-                       ignoreCase = false;
-                       resourceSetType = typeof (ResourceSet);
+                       neutral_culture = GetNeutralResourcesLanguage(MainAssembly);
                }
                         
-               public ResourceManager (string baseName, Assembly assembly, Type usingResourceSet)
+               private Type CheckResourceSetType(Type usingResourceSet)
                {
-                       if (baseName == null || assembly == null)
-                               throw new ArgumentNullException ("The arguments are null.");
-                       
-                       BaseNameField = baseName;
-                       MainAssembly = assembly;
-                       
-                       if (usingResourceSet == null) // defaults resourceSet type.
-                               resourceSetType = typeof (ResourceSet);
-                       else {
+                       if(usingResourceSet==null) {
+                               return(typeof(ResourceSet));
+                       } else {
                                if (!usingResourceSet.IsSubclassOf (typeof (ResourceSet)))
                                        throw new ArgumentException ("Type must be from ResourceSet.");
                                
+                               return(usingResourceSet);
                        }
                }
                
-               [MonoTODO]
+               public ResourceManager (string baseName, Assembly assembly, Type usingResourceSet) : this()
+               {
+                       if (baseName == null)
+                               throw new ArgumentNullException ("baseName is null.");
+                       if(assembly == null)
+                               throw new ArgumentNullException ("assembly is null.");
+                       
+                       BaseNameField = baseName;
+                       MainAssembly = assembly;
+                       resourceSetType = CheckResourceSetType(usingResourceSet);
+                       neutral_culture = GetNeutralResourcesLanguage(MainAssembly);
+               }
+               
+               /* Private constructor for CreateFileBasedResourceManager */
+               private ResourceManager(String baseName, String resourceDir, Type usingResourceSet) : this()
+               {
+                       if(baseName==null) {
+                               throw new ArgumentNullException("The base name is null");
+                       }
+                       if(baseName.EndsWith(".resources")) {
+                               throw new ArgumentException("The base name ends in '.resources'");
+                       }
+                       if(resourceDir==null) {
+                               throw new ArgumentNullException("The resourceDir is null");
+                       }
+
+                       BaseNameField = baseName;
+                       MainAssembly = null;
+                       resourceSetType = CheckResourceSetType(usingResourceSet);
+                       this.resourceDir = resourceDir;
+               }
+               
                public static ResourceManager CreateFileBasedResourceManager (string baseName,
                                                      string resourceDir, Type usingResourceSet)
                {
-                       return null;
+                       return new ResourceManager(baseName, resourceDir, usingResourceSet);
                }
 
                public virtual string BaseName
@@ -91,73 +132,247 @@ namespace System.Resources
                {
                        get { return resourceSetType; }
                }
-                        
-               [MonoTODO]
+
+               public virtual object GetObject(string name)
+               {
+                       return(GetObject(name, null));
+               }
+
+               public virtual object GetObject(string name, CultureInfo culture)
+               {
+                       if(name==null) {
+                               throw new ArgumentNullException("name is null");
+                       }
+
+                       if(culture==null) {
+                               culture=CultureInfo.CurrentUICulture;
+                       }
+
+                       lock(this) {
+                               ResourceSet set=InternalGetResourceSet(culture, true, true);
+                               object obj=null;
+                               
+                               if(set != null) {
+                                       obj=set.GetObject(name, ignoreCase);
+                                       if(obj != null) {
+                                               return(obj);
+                                       }
+                               }
+                               
+                               /* Try parent cultures */
+
+                               do {
+                                       culture=culture.Parent;
+
+                                       set=InternalGetResourceSet(culture, true, true);
+                                       if(set!=null) {
+                                               obj=set.GetObject(name, ignoreCase);
+                                               if(obj != null) {
+                                                       return(obj);
+                                               }
+                                       }
+                               } while(!culture.Equals(neutral_culture) &&
+                                       !culture.Equals(CultureInfo.InvariantCulture));
+                       }
+                       
+                       return(null);
+               }
+               
+               
                public virtual ResourceSet GetResourceSet (CultureInfo culture,
                                           bool createIfNotExists, bool tryParents)
                        
                {
-                       if (culture == null)
+                       if (culture == null) {
                                throw new ArgumentNullException ("CultureInfo is a null reference.");
-                       return null;
+                       }
+
+                       lock(this) {
+                               return(InternalGetResourceSet(culture, createIfNotExists, tryParents));
+                       }
                }
                
-               [MonoTODO]
                public virtual string GetString (string name)
                {
-                       if (name == null)
-                               throw new ArgumentNullException ("Name is null.");
-                       if (ResourceSets.Contains (name)) {
-                               if (!(ResourceSets[name] is string))
-                                       throw new InvalidOperationException ("The resource is " +
-                                                                            "not a string.");
-                               return ResourceSets[name].ToString();
-                       }
-                       return null;    
+                       return(GetString(name, null));
                }
 
-               [MonoTODO]
                public virtual string GetString (string name, CultureInfo culture)
                {
-                                if (name == null)
-                                        throw new ArgumentNullException ("Name is null.");
-                                return null;
+                       if (name == null) {
+                               throw new ArgumentNullException ("Name is null.");
+                       }
+
+                       if(culture==null) {
+                               culture=CultureInfo.CurrentUICulture;
+                       }
+
+                       lock(this) {
+                               ResourceSet set=InternalGetResourceSet(culture, true, true);
+                               string str=null;
+
+                               if(set!=null) {
+                                       str=set.GetString(name, ignoreCase);
+                                       if(str!=null) {
+                                               return(str);
+                                       }
+                               }
+
+                               /* Try parent cultures */
+
+                               do {
+                                       culture=culture.Parent;
+
+                                       set=InternalGetResourceSet(culture, true, true);
+                                       if(set!=null) {
+                                               str=set.GetString(name, ignoreCase);
+                                               if(str!=null) {
+                                                       return(str);
+                                               }
+                                       }
+                               } while(!culture.Equals(neutral_culture) &&
+                                       !culture.Equals(CultureInfo.InvariantCulture));
+                       }
+                       
+                       return(null);
                }
 
                protected virtual string GetResourceFileName (CultureInfo culture)
                {
-                       return culture.Name + ".resources";
+                       if(culture.Equals(CultureInfo.InvariantCulture)) {
+                               return(BaseNameField + ".resources");
+                       } else {
+                               return(BaseNameField + "." +  culture.Name + ".resources");
+                       }
                }
+               
+               protected virtual ResourceSet InternalGetResourceSet (CultureInfo culture, bool Createifnotexists, bool tryParents)
+               {
+                       ResourceSet set;
+                       
+                       if (culture == null) {
+                               string msg = String.Format ("Could not find any resource appropiate for the " +
+                                                           "specified culture or its parents (assembly:{0})",
+                                                           MainAssembly != null ? MainAssembly.GetName ().Name : "");
+                                                           
+                               throw new MissingManifestResourceException (msg);
+                       }
+                       /* if we already have this resource set, return it */
+                       set=(ResourceSet)ResourceSets[culture];
+                       if(set!=null) {
+                               return(set);
+                       }
+
+                       if(MainAssembly != null) {
+                               /* Assembly resources */
+                               Stream stream;
+                               string filename=GetResourceFileName(culture);
+                               
+                               stream=MainAssembly.GetManifestResourceStream(filename);
+                               if(stream==null) {
+                                       /* Try a satellite assembly */
+                                       Version sat_version=GetSatelliteContractVersion(MainAssembly);
+                                       Assembly a = null;
+                                       try {
+                                               a = MainAssembly.GetSatelliteAssembly (culture, sat_version);
+                                               stream=a.GetManifestResourceStream(filename);
+                                       } catch (Exception) {} // Ignored
+                               }
+
+                               if(stream!=null && Createifnotexists==true) {
+                                       object[] args=new Object[1];
+
+                                       args[0]=stream;
+                                       
+                                       /* should we catch
+                                        * MissingMethodException, or
+                                        * just let someone else deal
+                                        * with it?
+                                        */
+                                       set=(ResourceSet)Activator.CreateInstance(resourceSetType, args);
+                               } else if (culture == CultureInfo.InvariantCulture) {
+                                       string msg = "Could not find any resource appropiate for the " +
+                                                    "specified culture or its parents (assembly:{0})";
+                                                    
+                                       msg = String.Format (msg, MainAssembly != null ? MainAssembly.GetName ().Name : "");
+                                                           
+                                       throw new MissingManifestResourceException (msg);
+                               }
+                       } else if(resourceDir != null) {
+                               /* File resources */
+                               string filename=Path.Combine(resourceDir, this.GetResourceFileName(culture));
+                               if(File.Exists(filename) &&
+                                  Createifnotexists==true) {
+                                       object[] args=new Object[1];
+
+                                       args[0]=filename;
+                                       
+                                       /* should we catch
+                                        * MissingMethodException, or
+                                        * just let someone else deal
+                                        * with it?
+                                        */
+                                       set=(ResourceSet)Activator.CreateInstance(resourceSetType, args);
+                               }
+                       }
+
+                       if(set==null && tryParents==true) {
+                               set=this.InternalGetResourceSet(culture.Parent, Createifnotexists, tryParents);
+                       }
 
-               [MonoTODO]
-               protected virtual ResourceSet InternalGetResourceSet (CultureInfo culture,
-                                                  bool Createifnotexists, bool tryParents)
-                        {
-                                return null;
-                        }
+                       if(set!=null) {
+                               ResourceSets.Add(culture, set);
+                       }
+                       
+                       return(set);
+               }
                   
                public virtual void ReleaseAllResources ()
                {
-                       foreach (ResourceSet r in ResourceSets)
-                               r.Close();
+                       lock(this) 
+                       {
+                               foreach (ResourceSet r in ResourceSets)
+                                       r.Close();
+                               ResourceSets.Clear();
+                       }
                }
 
                protected static CultureInfo GetNeutralResourcesLanguage (Assembly a)
                {
-                       foreach (Attribute attribute in a.GetCustomAttributes (false)) {
-                               if (attribute is NeutralResourcesLanguageAttribute)
-                                       return new CultureInfo ((attribute as NeutralResourcesLanguageAttribute).CultureName);
+                       object[] attrs;
+
+                       attrs=a.GetCustomAttributes(typeof(NeutralResourcesLanguageAttribute), false);
+
+                       if(attrs.Length==0) {
+                               return(CultureInfo.InvariantCulture);
+                       } else {
+                               NeutralResourcesLanguageAttribute res_attr=(NeutralResourcesLanguageAttribute)attrs[0];
+                               
+                               return(new CultureInfo(res_attr.CultureName));
                        }
-                       return null;
                }
 
                protected static Version GetSatelliteContractVersion (Assembly a)
                {
-                       foreach (Attribute attribute in a.GetCustomAttributes (false)) {
-                               if (attribute is SatelliteContractVersionAttribute)
-                                       return new Version ((attribute as SatelliteContractVersionAttribute).Version);
+                       object[] attrs;
+                       
+                       attrs=a.GetCustomAttributes(typeof(SatelliteContractVersionAttribute), false);
+
+                       if(attrs.Length==0) {
+                               return(null);
+                       } else {
+                               SatelliteContractVersionAttribute sat_attr=(SatelliteContractVersionAttribute)attrs[0];
+
+                               /* Version(string) can throw
+                                * ArgumentException if the version is
+                                * invalid, but the spec for
+                                * GetSatelliteContractVersion says we
+                                * can throw the same exception for
+                                * the same reason, so dont bother to
+                                * catch it.
+                                */
+                               return(new Version(sat_attr.Version));
                        }
-                       return null; // return null if no version was found.
                }
        }
 }