Robert Jordan wrote:
Indeed, Mono's ResXResourceWriter uses ConvertTo (typeof (byte[]))
when a certain TypeConverter supports it, but fails to convert
it back, unless the patch I attached is applied.

But the real issue still remains: why does MS.NET not use ConvertTo
(typeof (byte[]))? Because the type is serializable? I'll run some
tests...

The attached patches fix this problem together with some other
issues I found while testing (see changelogs).

The test cases pass on MS.NET as well.

Robert

Index: System.Resources/ChangeLog
===================================================================
--- System.Resources/ChangeLog  (revision 66181)
+++ System.Resources/ChangeLog  (working copy)
@@ -1,3 +1,14 @@
+2006-10-03  Robert Jordan  <[EMAIL PROTECTED]>
+
+       * ResXResourceReader.cs: Factored out parse_data_node () from load_data 
()
+       to be able to correctly handle data nodes that occur before resheader.
+       Fixed handling of objects that have a byte[] converter.
+
+       * ResXResourceWriter.cs: Fixed AddResource (string, object) to support
+       only serializable type, matching MS.
+       Fixed WriteBytes to not emit the mimetype attribute when the
+       type is byte[], otherwise MS.NET won't parse correctly.
+
 2006-10-02  Sebastien Pouliot  <[EMAIL PROTECTED]>
 
        * ResXResourceReader.cs: Handle empty mimetype just like a null 
Index: System.Resources/ResXResourceReader.cs
===================================================================
--- System.Resources/ResXResourceReader.cs      (revision 66181)
+++ System.Resources/ResXResourceReader.cs      (working copy)
@@ -180,11 +180,7 @@
                                        /* resheader apparently can appear 
anywhere, so we collect
                                         * the data even if we haven't 
validated yet.
                                         */
-                                       string n = get_attr (reader, "name");
-                                       if (n != null) {
-                                               string v = get_value (reader, 
"value");
-                                               hasht [n] = v;
-                                       }
+                                       parse_data_node ();
                                }
                        }
                        return gotmime;
@@ -193,51 +189,66 @@
                private void load_data ()
                {
                        while (reader.Read ()) {
-                               if (reader.NodeType == XmlNodeType.Element && 
String.Compare (reader.Name, "data", true) == 0) {
-                                       string n = get_attr (reader, "name");
-                                       string t = get_attr (reader, "type");
-                                       string mt = get_attr (reader, 
"mimetype");
+                               if (reader.NodeType == XmlNodeType.Element && 
String.Compare (reader.Name, "data", true) == 0)
+                                       parse_data_node ();
 
-                                       Type tt = t == null ? null : 
Type.GetType (t);
+                       }
+               }
 
-                                       if (t != null && tt == null) {
-                                               throw new SystemException ("The 
type `" + t +"' could not be resolved");
-                                       }
-                                       if (tt == typeof (ResXNullRef)) {
-                                               hasht [n] = null;
-                                               continue;
-                                       }
-                                       if (n != null) {
-                                               object v = null;
-                                               string val = get_value (reader, 
"value");
+               void parse_data_node ()
+               {
+                       string name = get_attr (reader, "name");
+                       string type_name = get_attr (reader, "type");
+                       string mime_type = get_attr (reader, "mimetype");
 
-                                               if ((mt != null) && (mt.Length 
> 0) && (tt != null)) {
-                                                       TypeConverter c = 
TypeDescriptor.GetConverter (tt);
-                                                       v = c.ConvertFrom 
(Convert.FromBase64String (val));
-                                               } else if (tt != null) {
-                                                       // MS seems to handle 
Byte[] without any mimetype :-(
-                                                       if 
(t.StartsWith("System.Byte[], mscorlib")) {
-                                                               v = 
Convert.FromBase64String(val);
-                                                       } else {
-                                                               TypeConverter c 
= TypeDescriptor.GetConverter (tt);
-                                                               v = 
c.ConvertFromInvariantString (val);
-                                                       }
-                                               } else if ((mt != null) && 
(mt.Length > 0)) {
-                                                       byte [] data = 
Convert.FromBase64String (val);
-                                                       BinaryFormatter f = new 
BinaryFormatter ();
-                                                       using (MemoryStream s = 
new MemoryStream (data)) {
-                                                               v = 
f.Deserialize (s);
-                                                       }
-                                               } else {
-                                                       v = val;
-                                               }
-                                               hasht [n] = v;
+                       if (name == null)
+                               return;
+
+                       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)) {
+                               hasht [name] = null;
+                               return;
+                       }
+
+                       string value = get_value (reader, "value");
+                       object obj = null;
+
+                       if (type != null) {
+                               TypeConverter c = TypeDescriptor.GetConverter 
(type);
+
+                               if (c == null) {
+                                       obj = null;
+                               } else if (c.CanConvertFrom (typeof (string))) {
+                                       obj = c.ConvertFromInvariantString 
(value);
+                               } else if (c.CanConvertFrom (typeof (byte[]))) {
+                                       obj = c.ConvertFrom 
(Convert.FromBase64String (value));
+                               } else {
+                                       // the type must be a byte[]
+                                       obj  = Convert.FromBase64String(value);
+                               }
+                       } else if (mime_type != null && mime_type != 
String.Empty) {
+                               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 {
+                                       // invalid mime type
+                                       obj = null;
                                }
+                       } else {
+                               obj = value;
                        }
+                       hasht [name] = obj;
                }
 
-               private Type GetType(string type) {
+               private Type ResolveType (string type) {
                        if (typeresolver == null) {
                                return Type.GetType(type);
                        } else {
Index: System.Resources/ResXResourceWriter.cs
===================================================================
--- System.Resources/ResXResourceWriter.cs      (revision 66181)
+++ System.Resources/ResXResourceWriter.cs      (working copy)
@@ -138,18 +138,21 @@
                        writer.WriteString(sb.ToString());
                }
 
-               void WriteBytes (string name, string typename, byte [] value, 
int offset, int length)
+               void WriteBytes (string name, Type type, byte [] value, int 
offset, int length)
                {
                        writer.WriteStartElement ("data");
                        writer.WriteAttributeString ("name", name);
 
-                       if (typename != null) {
-                               writer.WriteAttributeString ("type", typename);
+                       if (type != null) {
+                               writer.WriteAttributeString ("type", 
type.AssemblyQualifiedName);
+                                // byte[] should never get a mimetype, 
otherwise MS.NET won't be able
+                                // to parse the data.
+                                if (type != typeof (byte[]))
+                                    writer.WriteAttributeString ("mimetype", 
ByteArraySerializedObjectMimeType);
                                writer.WriteStartElement ("value");
                                WriteNiceBase64(value, offset, length);
                        } else {
-                               writer.WriteAttributeString ("mimetype",
-                                               
"application/x-microsoft.net.object.binary.base64");
+                               writer.WriteAttributeString ("mimetype", 
BinSerializedObjectMimeType);
                                writer.WriteStartElement ("value");
                                writer.WriteBase64 (value, offset, length);
                        }
@@ -158,9 +161,9 @@
                        writer.WriteEndElement ();
                }
 
-               void WriteBytes (string name, string typename, byte [] value)
+               void WriteBytes (string name, Type type, byte [] value)
                {
-                       WriteBytes (name, typename, value, 0, value.Length);
+                       WriteBytes (name, type, value, 0, value.Length);
                }
 
                void WriteString (string name, string value)
@@ -168,12 +171,12 @@
                         WriteString (name, value, null);
                }
 
-               void WriteString (string name, string value, string typename)
+               void WriteString (string name, string value, Type type)
                {
                        writer.WriteStartElement ("data");
                        writer.WriteAttributeString ("name", name);
-                        if (typename != null)
-                                writer.WriteAttributeString ("type", typename);
+                        if (type != null)
+                                writer.WriteAttributeString ("type", 
type.AssemblyQualifiedName);
                        writer.WriteStartElement ("value");
                        writer.WriteString (value);
                        writer.WriteEndElement ();
@@ -195,7 +198,7 @@
                        if (writer == null)
                                InitWriter ();
 
-                       WriteBytes (name, value.GetType 
().AssemblyQualifiedName, value);
+                       WriteBytes (name, value.GetType (), value);
                }
 
                public void AddResource (string name, object value)
@@ -216,6 +219,9 @@
                        if (value == null)
                                throw new ArgumentNullException ("value");
 
+                        if (!value.GetType ().IsSerializable)
+                                throw new InvalidOperationException 
(String.Format ("The element '{0}' of type '{1}' is not serializable.", name, 
value.GetType ().Name));
+
                        if (written)
                                throw new InvalidOperationException ("The 
resource is already generated.");
 
@@ -225,13 +231,13 @@
                        TypeConverter converter = TypeDescriptor.GetConverter 
(value);
                        if (converter != null && converter.CanConvertTo (typeof 
(string)) && converter.CanConvertFrom (typeof (string))) {
                                string str = (string) 
converter.ConvertToInvariantString (value);
-                               WriteString (name, str, value.GetType 
().AssemblyQualifiedName);
+                               WriteString (name, str, value.GetType ());
                                return;
                        }
                        
                        if (converter != null && converter.CanConvertTo (typeof 
(byte[])) && converter.CanConvertFrom (typeof (byte[]))) {
                                byte[] b = (byte[]) converter.ConvertTo (value, 
typeof (byte[]));
-                               WriteBytes (name, 
value.GetType().AssemblyQualifiedName, b);
+                               WriteBytes (name, value.GetType (), b);
                                return;
                        }
                        
Index: Test/System.Resources/WriterTest.cs
===================================================================
--- Test/System.Resources/WriterTest.cs (revision 66185)
+++ Test/System.Resources/WriterTest.cs (working copy)
@@ -7,9 +7,12 @@
 
 using System;
 using System.Collections;
+using System.ComponentModel;
 using System.Drawing;
+using System.Globalization;
 using System.IO;
 using System.Resources;
+using System.Text;
 using NUnit.Framework;
 
 namespace MonoTests.System.Resources
@@ -33,6 +36,16 @@
                         w.AddResource ("ByteArray2", (object) new byte[] {15, 
16, 17});
                         w.AddResource ("IntArray", new int[] {1012, 1013, 
1014});
                         w.AddResource ("StringArray", new string[] {"hello", 
"world"});
+                        w.AddResource ("Image", new Bitmap (1, 1));
+                        w.AddResource ("StrType", new MyStrType ("hello"));
+                        w.AddResource ("BinType", new MyBinType ("world"));
+
+                        try {
+                                w.AddResource ("NonSerType", new 
MyNonSerializableType ());
+                                Assert.Fail ("#0");
+                        } catch (InvalidOperationException) {
+                        }
+
                         w.Generate ();
                         w.Close ();
 
@@ -53,8 +66,141 @@
                         Assert.AreEqual (16, ((byte[]) h["ByteArray2"])[1], 
"#8");
                         Assert.AreEqual (1013, ((int[]) h["IntArray"])[1], 
"#9");
                         Assert.AreEqual ("world", ((string[]) 
h["StringArray"])[1], "#10");
+                        Assert.AreEqual (typeof (Bitmap), h["Image"].GetType 
(), "#11");
+                        Assert.AreEqual ("hello", ((MyStrType) 
h["StrType"]).Value, "#12");
+                        Assert.AreEqual ("world", ((MyBinType) 
h["BinType"]).Value, "#13");
 
                         File.Delete (fileName);
                 }
         }
+
+        [Serializable]
+        [TypeConverter(typeof(MyStrTypeConverter))]
+       public class MyStrType
+       {
+                public string Value;
+
+               public MyStrType (string s)
+               {
+                        Value = s;
+               }
+       }
+
+        public class MyStrTypeConverter : TypeConverter
+        {
+                public override bool CanConvertTo(ITypeDescriptorContext 
context, Type destinationType)
+                {
+                        if (destinationType == typeof(string)) 
+                                return true;
+                        return base.CanConvertTo (context, destinationType);
+                }
+
+                public override bool CanConvertFrom(ITypeDescriptorContext 
context, Type sourceType)
+                {
+                        if (sourceType == typeof(string)) 
+                                return true;
+                        return base.CanConvertFrom (context, sourceType);
+                }
+
+                public override object ConvertTo(ITypeDescriptorContext 
context, CultureInfo culture, object value, Type destinationType)
+                {
+                        if (destinationType == typeof(string)) 
+                                return ((MyStrType) value).Value;
+                        return base.ConvertTo (context, culture, value, 
destinationType);
+                }
+
+                public override object ConvertFrom(ITypeDescriptorContext 
context, CultureInfo culture, object value)
+                {
+                        if (value.GetType() == typeof(string))
+                                return new MyStrType((string) value);
+                        return base.ConvertFrom (context, culture, value);
+                }
+
+        }
+
+
+        [Serializable]
+        [TypeConverter(typeof(MyBinTypeConverter))]
+       public class MyBinType
+       {
+                public string Value;
+
+               public MyBinType (string s)
+               {
+                        Value = s;
+               }
+       }
+
+        public class MyBinTypeConverter : TypeConverter
+        {
+                public override bool CanConvertTo(ITypeDescriptorContext 
context, Type destinationType)
+                {
+                        if (destinationType == typeof(byte[])) 
+                                return true;
+                        return base.CanConvertTo (context, destinationType);
+                }
+
+                public override bool CanConvertFrom(ITypeDescriptorContext 
context, Type sourceType)
+                {
+                        if (sourceType == typeof(byte[])) 
+                                return true;
+                        return base.CanConvertFrom (context, sourceType);
+                }
+
+                public override object ConvertTo(ITypeDescriptorContext 
context, CultureInfo culture, object value, Type destinationType)
+                {
+                        if (destinationType == typeof(byte[])) 
+                                return Encoding.Default.GetBytes (((MyBinType) 
value).Value);
+                        return base.ConvertTo (context, culture, value, 
destinationType);
+                }
+
+                public override object ConvertFrom(ITypeDescriptorContext 
context, CultureInfo culture, object value)
+                {
+                        if (value.GetType() == typeof(byte[]))
+                                return new MyBinType 
(Encoding.Default.GetString ((byte[]) value));
+                        return base.ConvertFrom (context, culture, value);
+                }
+
+        }
+
+
+        [TypeConverter(typeof(MyNonSerializableTypeConverter))]
+       public class MyNonSerializableType
+       {
+               public MyNonSerializableType ()
+               {
+               }
+       }
+
+        public class MyNonSerializableTypeConverter : TypeConverter
+        {
+                public override bool CanConvertTo(ITypeDescriptorContext 
context, Type destinationType)
+                {
+                        if (destinationType == typeof(byte[])) 
+                                return true;
+                        return base.CanConvertTo (context, destinationType);
+                }
+
+                public override bool CanConvertFrom(ITypeDescriptorContext 
context, Type sourceType)
+                {
+                        if (sourceType == typeof(byte[])) 
+                                return true;
+                        return base.CanConvertFrom (context, sourceType);
+                }
+
+                public override object ConvertTo(ITypeDescriptorContext 
context, CultureInfo culture, object value, Type destinationType)
+                {
+                        if (destinationType == typeof(byte[])) 
+                                return new byte[] {0, 1, 2, 3};
+                        return base.ConvertTo (context, culture, value, 
destinationType);
+                }
+
+                public override object ConvertFrom(ITypeDescriptorContext 
context, CultureInfo culture, object value)
+                {
+                        if (value.GetType() == typeof(byte[]))
+                                return new MyNonSerializableType();
+                        return base.ConvertFrom (context, culture, value);
+                }
+
+        }
 }
Index: Test/System.Resources/compat_1_1.resx
===================================================================
--- Test/System.Resources/compat_1_1.resx       (revision 66185)
+++ Test/System.Resources/compat_1_1.resx       (working copy)
@@ -78,4 +78,16 @@
   <data name="StringArray" 
mimetype="application/x-microsoft.net.object.binary.base64">
     
<value>AAEAAAD/////AQAAAAAAAAARAQAAAAIAAAAGAgAAAAVoZWxsbwYDAAAABXdvcmxkCw==</value>
   </data>
+  <data name="InvalidMimeType" mimetype="foo">
+    
<value>AAEAAAD/////AQAAAAAAAAARAQAAAAIAAAAGAgAAAAVoZWxsbwYDAAAABXdvcmxkCw==</value>
+  </data>
+  <data name="Image" type="System.Drawing.Bitmap, System.Drawing, 
Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" 
mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+       
iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+       
YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAtJREFUGFdjYAAC
+       
AAAFAAGq1chRAAAAAElFTkSuQmCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+       
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+       AAAAAAAAAAAAAAAAAAAAAA==
+    </value>
+  </data>
 </root>
Index: Test/System.Resources/compat_2_0.resx
===================================================================
--- Test/System.Resources/compat_2_0.resx       (revision 66185)
+++ Test/System.Resources/compat_2_0.resx       (working copy)
@@ -97,4 +97,16 @@
   <data name="StringArray" 
mimetype="application/x-microsoft.net.object.binary.base64">
     
<value>AAEAAAD/////AQAAAAAAAAARAQAAAAIAAAAGAgAAAAVoZWxsbwYDAAAABXdvcmxkCw==</value>
   </data>
+  <data name="InvalidMimeType" mimetype="foo">
+    
<value>AAEAAAD/////AQAAAAAAAAARAQAAAAIAAAAGAgAAAAVoZWxsbwYDAAAABXdvcmxkCw==</value>
+  </data>
+  <data name="Image" type="System.Drawing.Bitmap, System.Drawing, 
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" 
mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+       
iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+       
YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAtJREFUGFdjYAAC
+       
AAAFAAGq1chRAAAAAElFTkSuQmCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+       
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+       AAAAAAAAAAAAAAAAAAAAAA==
+    </value>
+  </data>
 </root>
Index: Test/System.Resources/ChangeLog
===================================================================
--- Test/System.Resources/ChangeLog     (revision 66185)
+++ Test/System.Resources/ChangeLog     (working copy)
@@ -1,3 +1,12 @@
+2006-10-03  Robert Jordan  <[EMAIL PROTECTED]>
+
+       * compat_2_0.resx, compat_1_1.resx: Added an Image element to test the
+       type converter. Added InvalidMimeType, an element with an invalid 
mimetype
+       attribute.
+       * CompatTest.cs: Added assert for InvalidMimeType and Image element.
+       Fixed test for the 2.0 profile.
+       * WriterTest.cs: Added type converter tests.
+       
 2006-01-14  Robert Jordan  <[EMAIL PROTECTED]>
 
        * compat_2_0.resx: Added a CDATA element as a test for bug #77253.
Index: Test/System.Resources/CompatTest.cs
===================================================================
--- Test/System.Resources/CompatTest.cs (revision 66185)
+++ Test/System.Resources/CompatTest.cs (working copy)
@@ -38,6 +38,9 @@
                                 Assert.AreEqual (16, ((byte[]) 
h["ByteArray2"])[1], fileName + "#8");
                                 Assert.AreEqual (1013, ((int[]) 
h["IntArray"])[1], fileName + "#9");
                                 Assert.AreEqual ("world", ((string[]) 
h["StringArray"])[1], fileName + "#10");
+                                Assert.IsNull (h["InvalidMimeType"]);
+                                Assert.IsNotNull (h["Image"], fileName + 
"#11");
+                                Assert.AreEqual (typeof (Bitmap), 
h["Image"].GetType (), fileName + "#12");
                         }
                 }
 
@@ -45,7 +48,14 @@
                 public void TestReader ()
                 {
                         Helper.TestReader 
("Test/System.Resources/compat_1_1.resx");
+                }
+
+#if NET_2_0
+                [Test]
+                public void TestReader_2_0 ()
+                {
                         Helper.TestReader 
("Test/System.Resources/compat_2_0.resx");
                 }
+#endif
         }
 }
_______________________________________________
Mono-winforms-list maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-winforms-list

Reply via email to