Hi All
I think I found a bug in the ResxResourceReader. If a resx file contains a resource of the type System.Drawing.Bitmap, the reader fails to to read the specific item. I have attached a test file as well as test program that first use a patched version of the ResxResourceReader to successfully load the resx file and then secondly tries to load it with the current ResxResourceReader in the Mono runtime.
I have also included a patch file for fixing this bug. Please review
Here is the command line for compiling the test program
$ gmcs -r:System.Windows.Forms -r:System.Drawing -out:Test.exe -target:exe Main.cs ResxReader.cs
Regards
Gideon de Swardt
http://sonskyn-techno.blogspot.com
I think I found a bug in the ResxResourceReader. If a resx file contains a resource of the type System.Drawing.Bitmap, the reader fails to to read the specific item. I have attached a test file as well as test program that first use a patched version of the ResxResourceReader to successfully load the resx file and then secondly tries to load it with the current ResxResourceReader in the Mono runtime.
I have also included a patch file for fixing this bug. Please review
Here is the command line for compiling the test program
$ gmcs -r:System.Windows.Forms -r:System.Drawing -out:Test.exe -target:exe Main.cs ResxReader.cs
Regards
Gideon de Swardt
http://sonskyn-techno.blogspot.com
Yahoo! Photos – NEW, now offering a quality print service from just 8p a photo.
// project created on 9/1/2006 at 1:58 AM
using System;
namespace ResxTest
{
class MainClass
{
public static void Main(string[] args)
{
try
{
// Read the created file
Console.WriteLine("Read the resx files using the patch");
ResXResourceReader reader = new ResXResourceReader("test.resx");
reader.Close();
Console.WriteLine("Read the resx files current ResxResourceReader");
System.Resources.ResXResourceReader org_reader = new System.Resources.ResXResourceReader("test.resx");
org_reader.Close();
}
catch (Exception exception)
{
Console.WriteLine("\r\nEXCEPTION!!!!!\r\n");
Console.WriteLine(exception.Message);
}
}
}
}// Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // Copyright (c) 2004-2005 Novell, Inc. // // Authors: // Duncan Mak [EMAIL PROTECTED] // Nick Drochak [EMAIL PROTECTED] // Paolo Molaro [EMAIL PROTECTED] // Peter Bartok [EMAIL PROTECTED] //
// COMPLETE
using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml;
namespace ResxTest
{
public class ResXResourceReader : IResourceReader, IDisposable
{
#region Local Variables
private Stream stream;
private XmlTextReader reader;
private Hashtable hasht;
private ITypeResolutionService typeresolver;
#endregion // Local Variables
#region Constructors & Destructor
public ResXResourceReader (Stream stream)
{
if (stream == null)
throw new ArgumentNullException ("Value cannot be null.");
if (!stream.CanRead)
throw new ArgumentException ("Stream was not readable.");
this.stream = stream;
basic_setup ();
}
public ResXResourceReader (Stream stream, ITypeResolutionService typeresolver) : this(stream) {
this.typeresolver = typeresolver;
}
public ResXResourceReader (string fileName)
{
stream = File.OpenRead (fileName);
basic_setup ();
}
public ResXResourceReader (string fileName, ITypeResolutionService typeresolver) : this(fileName) {
this.typeresolver = typeresolver;
}
public ResXResourceReader(TextReader reader) {
this.reader = new XmlTextReader(reader);
this.hasht = new Hashtable();
load_data();
}
public ResXResourceReader (TextReader reader, ITypeResolutionService typeresolver) : this(reader) {
this.typeresolver = typeresolver;
}
~ResXResourceReader() {
Dispose(false);
}
#endregion // Constructors & Destructor
#region Private Methods
void basic_setup () {
reader = new XmlTextReader (stream);
hasht = new Hashtable ();
if (!IsStreamValid()){
throw new ArgumentException("Stream is not a valid .resx file! It was possibly truncated.");
}
load_data ();
}
static string get_attr (XmlTextReader reader, string name) {
if (!reader.HasAttributes)
return null;
for (int i = 0; i < reader.AttributeCount; i++) {
reader.MoveToAttribute (i);
if (String.Compare (reader.Name, name, true) == 0) {
string v = reader.Value;
reader.MoveToElement ();
return v;
}
}
reader.MoveToElement ();
return null;
}
static string get_value (XmlTextReader reader, string name)
{
return get_value (reader, name, true);
}
// Returns the value of the next XML element with the specified
// name from the reader. canBeCdata == true specifies that
// the element may be a CDATA node as well.
static string get_value (XmlTextReader reader, string name, bool canBeCdata) {
bool gotelement = false;
while (reader.Read ()) {
if (reader.NodeType == XmlNodeType.Element && String.Compare (reader.Name, name, true) == 0) {
gotelement = true;
break;
}
if (canBeCdata && reader.NodeType == XmlNodeType.CDATA)
return reader.Value;
}
if (!gotelement)
return null;
while (reader.Read ()) {
if (reader.NodeType == XmlNodeType.Text || reader.NodeType == XmlNodeType.CDATA) {
string v = reader.Value;
return v;
}
else if (reader.NodeType == XmlNodeType.EndElement && reader.Value == string.Empty)
{
string v = reader.Value;
return v;
}
}
return null;
}
private bool IsStreamValid() {
bool gotroot = false;
bool gotmime = false;
while (reader.Read ()) {
if (reader.NodeType == XmlNodeType.Element && String.Compare (reader.Name, "root", true) == 0) {
gotroot = true;
break;
}
}
if (!gotroot)
return false;
while (reader.Read ()) {
if (reader.NodeType == XmlNodeType.Element && String.Compare (reader.Name, "resheader", true) == 0) {
string v = get_attr (reader, "name");
if (v != null && String.Compare (v, "resmimetype", true) == 0) {
v = get_value (reader, "value");
if (String.Compare (v, "text/microsoft-resx", true) == 0) {
gotmime = true;
break;
}
}
} else if (reader.NodeType == XmlNodeType.Element && String.Compare (reader.Name, "data", true) == 0) {
/* 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;
}
}
}
return gotmime;
}
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");
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");
if (mt != null && 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);
if (c is System.Drawing.ImageConverter)
v = c.ConvertFrom(Convert.FromBase64String(val));
else
v = c.ConvertFromInvariantString (val);
}
} else if (mt != null) {
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;
}
}
}
}
private Type GetType(string type) {
if (typeresolver == null) {
return Type.GetType(type);
} else {
return typeresolver.GetType(type);
}
}
#endregion // Private Methods
#region Public Methods
public void Close ()
{
if (stream != null) {
stream.Close ();
stream = null;
}
if (reader != null) {
reader.Close();
reader = null;
}
}
public IDictionaryEnumerator GetEnumerator () {
if (null == stream){
throw new InvalidOperationException("ResourceReader is closed.");
}
else {
return hasht.GetEnumerator ();
}
}
IEnumerator IEnumerable.GetEnumerator ()
{
return ((IResourceReader) this).GetEnumerator();
}
void IDisposable.Dispose ()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing) {
if (disposing) {
Close();
}
}
public static ResXResourceReader FromFileContents(string fileContents) {
return new ResXResourceReader(new StringReader(fileContents));
}
public static ResXResourceReader FromFileContents(string fileContents, ITypeResolutionService typeResolver) {
return new ResXResourceReader(new StringReader(fileContents), typeResolver);
}
#endregion // Public Methods
} // public sealed class ResXResourceReader
[Serializable]
internal class ResXNullRef
{
}
[Serializable]
[TypeConverter(typeof(ResXFileRef.Converter))]
public class ResXFileRef {
#region Converter Class
public class Converter : TypeConverter {
#region Constructors
public Converter() {
}
#endregion // Constructors
#region Methods
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
return sourceType == typeof(string);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
return destinationType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) {
string[] parts;
byte[] buffer;
if ( !(value is String)) {
return base.ConvertFrom(context, culture, value);
}
parts = ((string)value).Split(';');
using (FileStream file = new FileStream(parts[0], FileMode.Open, FileAccess.Read, FileShare.Read)) {
buffer = new byte[file.Length];
file.Read(buffer, 0, (int)file.Length);
}
return Activator.CreateInstance(Type.GetType(parts[1]), BindingFlags.CreateInstance | BindingFlags.Public | BindingFlags.Instance, null, new object[] { new MemoryStream(buffer) }, culture);
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) {
if (destinationType != typeof(String)) {
return base.ConvertTo (context, culture, value, destinationType);
}
return ((ResXFileRef)value).ToString();
}
#endregion // Methods
}
#endregion // Converter Class
#region Local Variables
private string filename;
private string typename;
#endregion // Local Variables
#region Public Constructors
public ResXFileRef(string fileName, string typeName) {
this.filename = fileName;
this.typename = typeName;
}
#endregion // Public Constructors
#region Public Instance Properties
#endregion // Public Instance Properties
#region Public Instance Methods
public override string ToString() {
return filename + ";" + typename;
}
#endregion // Public Instance Methods
}
} // namespace System.Resources
test.resx
Description: Binary data
Index: ResXResourceReader.cs
===================================================================
--- ResXResourceReader.cs (revision 66180)
+++ ResXResourceReader.cs (working copy)
@@ -220,7 +220,10 @@
v = Convert.FromBase64String(val);
} else {
TypeConverter c = TypeDescriptor.GetConverter (tt);
- v = c.ConvertFromInvariantString (val);
+ if (c is System.Drawing.ImageConverter)
+ v = c.ConvertFrom(Convert.FromBase64String(val));
+ else
+ v = c.ConvertFromInvariantString (val);
}
} else if ((mt != null) && (mt.Length > 0)) {
byte [] data = Convert.FromBase64String (val);
_______________________________________________ Mono-winforms-list maillist - [email protected] http://lists.ximian.com/mailman/listinfo/mono-winforms-list
