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



Yahoo! PhotosNEW, 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

Attachment: 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

Reply via email to