Merge pull request #409 from Alkarex/patch-1
[mono.git] / mcs / class / Managed.Windows.Forms / System.Resources / ResXResourceReader.cs
index 54f7227b4832838bcc6d8174323b41bd6fc11fb1..084f5bd5eabf606595905e775ee7da52d3702d9f 100644 (file)
@@ -25,7 +25,8 @@
 //     Paolo Molaro    lupus@ximian.com
 //     Peter Bartok    pbartok@novell.com
 //     Gert Driesen    drieseng@users.sourceforge.net
-//
+//     Olivier Dufour  olivier.duff@gmail.com
+//     Gary Barnett    gary.barnett.mono@gmail.com
 
 using System;
 using System.Collections;
@@ -38,10 +39,17 @@ using System.Resources;
 using System.Runtime.Serialization.Formatters.Binary;
 using System.Xml;
 using System.Reflection;
+using System.Drawing;
+using System.Runtime.Serialization;
 
 namespace System.Resources
 {
-       public class ResXResourceReader : IResourceReader, IDisposable
+#if INSIDE_SYSTEM_WEB
+       internal
+#else
+       public
+#endif
+       class ResXResourceReader : IResourceReader, IDisposable
        {
                #region Local Variables
                private string fileName;
@@ -50,67 +58,52 @@ namespace System.Resources
                private Hashtable hasht;
                private ITypeResolutionService typeresolver;
                private XmlTextReader xmlReader;
-
-
-#if NET_2_0
                private string basepath;
                private bool useResXDataNodes;
                private AssemblyName [] assemblyNames;
                private Hashtable hashtm;
-#endif
                #endregion      // Local Variables
 
                #region Constructors & Destructor
                public ResXResourceReader (Stream stream)
                {
                        if (stream == null)
-                               throw new ArgumentNullException ("Value cannot be null.");
+                               throw new ArgumentNullException ("stream");
 
                        if (!stream.CanRead)
                                throw new ArgumentException ("Stream was not readable.");
 
                        this.stream = stream;
-#if NET_2_0
-                       this.useResXDataNodes = false;
-#endif
-        }
+               }
 
-               public ResXResourceReader (Stream stream, ITypeResolutionService typeresolver)
+               public ResXResourceReader (Stream stream, ITypeResolutionService typeResolver)
                        : this (stream)
                {
-                       this.typeresolver = typeresolver;
+                       this.typeresolver = typeResolver;
                }
 
                public ResXResourceReader (string fileName)
                {
                        this.fileName = fileName;
-#if NET_2_0
-                       this.useResXDataNodes = false;
-#endif
-        }
+               }
 
-               public ResXResourceReader (string fileName, ITypeResolutionService typeresolver)
+               public ResXResourceReader (string fileName, ITypeResolutionService typeResolver)
                        : this (fileName)
                {
-                       this.typeresolver = typeresolver;
+                       this.typeresolver = typeResolver;
                }
 
                public ResXResourceReader (TextReader reader)
                {
                        this.reader = reader;
-#if NET_2_0
-                       this.useResXDataNodes = false;
-#endif
                }
 
-               public ResXResourceReader (TextReader reader, ITypeResolutionService typeresolver)
+               public ResXResourceReader (TextReader reader, ITypeResolutionService typeResolver)
                        : this (reader)
                {
-                       this.typeresolver = typeresolver;
+                       this.typeresolver = typeResolver;
                }
 
-#if NET_2_0
-
                public ResXResourceReader (Stream stream, AssemblyName [] assemblyNames)
                        : this (stream)
                {
@@ -129,19 +122,17 @@ namespace System.Resources
                        this.assemblyNames = assemblyNames;
                }
 
-
-#endif
                ~ResXResourceReader ()
                {
                        Dispose (false);
                }
                #endregion      // Constructors & Destructor
 
-#if NET_2_0
                public string BasePath {
                        get { return basepath; }
                        set { basepath = value; }
                }
+
                public bool UseResXDataNodes {
                        get { return useResXDataNodes; }
                        set {
@@ -150,15 +141,12 @@ namespace System.Resources
                                useResXDataNodes = value; 
                        }
                }
-#endif
 
                #region Private Methods
                private void LoadData ()
                {
                        hasht = new Hashtable ();
-#if NET_2_0
                        hashtm = new Hashtable ();
-#endif
                        if (fileName != null) {
                                stream = File.OpenRead (fileName);
                        }
@@ -190,27 +178,22 @@ namespace System.Resources
                                                case "data":
                                                        ParseDataNode (false);
                                                        break;
-#if NET_2_0
                                                case "metadata":
                                                        ParseDataNode (true);
                                                        break;
-#endif
                                                }
                                        }
-#if NET_2_0
                                } catch (XmlException ex) {
                                        throw new ArgumentException ("Invalid ResX input.", ex);
+                               } catch (SerializationException ex) {
+                                       throw ex;
+                               } catch (TargetInvocationException ex) {
+                                       throw ex;
                                } catch (Exception ex) {
                                        XmlException xex = new XmlException (ex.Message, ex, 
                                                xmlReader.LineNumber, xmlReader.LinePosition);
                                        throw new ArgumentException ("Invalid ResX input.", xex);
                                }
-#else
-                               } catch (Exception ex) {
-                                       throw new ArgumentException ("Invalid ResX input.", ex);
-                               }
-#endif
-
                                header.Verify ();
                        } finally {
                                if (fileName != null) {
@@ -266,10 +249,10 @@ namespace System.Resources
                        return null;
                }
 
-               private string GetDataValue (bool meta)
+               private string GetDataValue (bool meta, out string comment)
                {
                        string value = null;
-#if NET_2_0
+                       comment = null;
                        while (xmlReader.Read ()) {
                                if (xmlReader.NodeType == XmlNodeType.EndElement && xmlReader.LocalName == (meta ? "metadata" : "data"))
                                        break;
@@ -280,7 +263,9 @@ namespace System.Resources
                                                value = xmlReader.ReadString ();
                                                xmlReader.WhitespaceHandling = WhitespaceHandling.None;
                                        } else if (xmlReader.Name.Equals ("comment")) {
-                                               xmlReader.Skip ();
+                                               xmlReader.WhitespaceHandling = WhitespaceHandling.Significant;
+                                               comment = xmlReader.ReadString ();
+                                               xmlReader.WhitespaceHandling = WhitespaceHandling.None;
                                                if (xmlReader.NodeType == XmlNodeType.EndElement && xmlReader.LocalName == (meta ? "metadata" : "data"))
                                                        break;
                                        }
@@ -288,127 +273,57 @@ namespace System.Resources
                                else
                                        value = xmlReader.Value.Trim ();
                        }
-#else
-                       xmlReader.Read ();
-                       if (xmlReader.NodeType == XmlNodeType.Element) {
-                               value = xmlReader.ReadElementString ();
-                       } else {
-                               value = xmlReader.Value.Trim ();
-                       }
-
-                       if (value == null)
-                               value = string.Empty;
-#endif
                        return value;
                }
 
                private void ParseDataNode (bool meta)
                {
+                       Hashtable hashtable = ((meta && ! useResXDataNodes) ? hashtm : hasht);
+                       Point pos = new Point (xmlReader.LineNumber, xmlReader.LinePosition);
                        string name = GetAttribute ("name");
                        string type_name = GetAttribute ("type");
                        string mime_type = GetAttribute ("mimetype");
-#if NET_2_0
-                       Hashtable hashtable = (meta ? hashtm : hasht);
-#else
-                       Hashtable hashtable = hasht;
-#endif
 
-                       Type type = type_name == null ? null : ResolveType (type_name);
 
-                       if (type_name != null && type == null)
-                               throw new ArgumentException (String.Format (
-                                       "The type '{0}' of the element '{1}' could not be resolved.", type_name, name));
-
-                       if (type == typeof (ResXNullRef)) {
-                               
-#if NET_2_0
-                               if (useResXDataNodes)
-                                       hashtable [name] = new ResXDataNode(name, null);
-                               else
-#endif
-                                       hashtable [name] = null;
-                               return;
-                       }
+                       string comment = null;
+                       string value = GetDataValue (meta, out comment);
 
-                       string value = GetDataValue (meta);
-                       object obj = null;
+                       ResXDataNode node = new ResXDataNode (name, mime_type, type_name, value, comment, pos, BasePath);
 
-                       if (mime_type != null && mime_type.Length > 0) {
-                               if (mime_type == ResXResourceWriter.BinSerializedObjectMimeType) {
-                                       byte [] data = Convert.FromBase64String (value);
-                                       BinaryFormatter f = new BinaryFormatter ();
-                                       using (MemoryStream s = new MemoryStream (data)) {
-                                               obj = f.Deserialize (s);
-                                       }
-                               } else if (mime_type == ResXResourceWriter.ByteArraySerializedObjectMimeType) {
-                                       if (type != null) {
-                                               TypeConverter c = TypeDescriptor.GetConverter (type);
-                                               if (c.CanConvertFrom (typeof (byte [])))
-                                                       obj = c.ConvertFrom (Convert.FromBase64String (value));
-                                       }
-                               }
-                       } else if (type != null) {
-                               if (type == typeof (byte [])) {
-                                       obj = Convert.FromBase64String (value);
-                               } else {
-                                       TypeConverter c = TypeDescriptor.GetConverter (type);
-                                       if (c.CanConvertFrom (typeof (string))) {
-#if NET_2_0
-                                               if (BasePath != null && type == typeof (ResXFileRef)) {
-                                                       string [] parts = ResXFileRef.Parse (value);
-                                                       parts [0] = Path.Combine (BasePath, parts [0]);
-                                                       obj = c.ConvertFromInvariantString (string.Join (";", parts));
-                                               } else {
-                                                       obj = c.ConvertFromInvariantString (value);
-                                               }
-#else
-                                               obj = c.ConvertFromInvariantString (value);
-#endif
-                                       }
-                               }
-                       } else {
-                               obj = value;
+                       if (useResXDataNodes) {
+                               hashtable [name] = node;
+                               return;
                        }
 
-#if ONLY_1_1
-                       if (obj == null)
-                               obj = value;
-#endif
-
                        if (name == null)
                                throw new ArgumentException (string.Format (CultureInfo.CurrentCulture,
-                                       "Could not find a name for a resource. The resource value "
-                                       + "was '{0}'.", obj));
-#if NET_2_0
-                       if (useResXDataNodes)
-                               hashtable [name] = new ResXDataNode(name, obj);
-                       else
-#endif
-                       hashtable [name] = obj;
-               }
+                                                       "Could not find a name for a resource. The resource value was '{0}'.",
+                                                       node.GetValue ((AssemblyName []) null).ToString()));
 
-               private Type ResolveType (string type)
-               {
-                       if (typeresolver != null) {
-                               return typeresolver.GetType (type);
-                       } 
-#if NET_2_0
-                       if (assemblyNames != null) {
-                               Type result;
-                               foreach (AssemblyName assem in assemblyNames) {
-                                       Assembly myAssembly = Assembly.Load (assem);
-                                       result = myAssembly.GetType (type, false);
-                                       if (result != null)
-                                               return result;
-                                       //else loop
+                       // useResXDataNodes is false, add to dictionary of values
+                       if (assemblyNames != null) { 
+                               try {
+                                       hashtable [name] = node.GetValue (assemblyNames);
+                               } catch (TypeLoadException ex) {
+                                       // different error messages depending on type of resource, hacky solution
+                                       if (node.handler is TypeConverterFromResXHandler)
+                                               hashtable [name] = null;
+                                       else 
+                                               throw ex;
+                               }
+                       } else { // there is a typeresolver or its null
+                               try {
+                                       hashtable [name] = node.GetValue (typeresolver); 
+                               } catch (TypeLoadException ex) {
+                                       if (node.handler is TypeConverterFromResXHandler)
+                                               hashtable [name] = null;
+                                       else 
+                                               throw ex;
                                }
-                               //if type not found on assembly list we return null or we get from current assembly?
-                               //=> unit test needed
                        }
-#endif
-                       return Type.GetType (type);
 
                }
+
                #endregion      // Private Methods
 
                #region Public Methods
@@ -455,7 +370,7 @@ namespace System.Resources
                {
                        return new ResXResourceReader (new StringReader (fileContents), typeResolver);
                }
-#if NET_2_0
+
                public static ResXResourceReader FromFileContents (string fileContents, AssemblyName [] assemblyNames)
                {
                        return new ResXResourceReader (new StringReader (fileContents), assemblyNames);
@@ -467,7 +382,7 @@ namespace System.Resources
                                LoadData ();
                        return hashtm.GetEnumerator ();
                }
-#endif
+
                #endregion      // Public Methods
 
                #region Internal Classes