X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FManaged.Windows.Forms%2FSystem.Resources%2FResXResourceReader.cs;h=084f5bd5eabf606595905e775ee7da52d3702d9f;hb=e2b2d181084848f3c5dde2788370db1b79893c69;hp=3e093fcd53fbd7552c2f1f20228ddefd7ce472f5;hpb=b585d00928892398dfbfc315ed78b8032fa14708;p=mono.git diff --git a/mcs/class/Managed.Windows.Forms/System.Resources/ResXResourceReader.cs b/mcs/class/Managed.Windows.Forms/System.Resources/ResXResourceReader.cs index 3e093fcd53f..084f5bd5eab 100644 --- a/mcs/class/Managed.Windows.Forms/System.Resources/ResXResourceReader.cs +++ b/mcs/class/Managed.Windows.Forms/System.Resources/ResXResourceReader.cs @@ -24,12 +24,13 @@ // Nick Drochak ndrochak@gol.com // Paolo Molaro lupus@ximian.com // Peter Bartok pbartok@novell.com -// - -// COMPLETE +// Gert Driesen drieseng@users.sourceforge.net +// Olivier Dufour olivier.duff@gmail.com +// Gary Barnett gary.barnett.mono@gmail.com using System; using System.Collections; +using System.Collections.Specialized; using System.ComponentModel; using System.ComponentModel.Design; using System.Globalization; @@ -37,247 +38,406 @@ using System.IO; 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 Stream stream; - private XmlTextReader reader; - private Hashtable hasht; - private ITypeResolutionService typeresolver; + private string fileName; + private Stream stream; + private TextReader reader; + private Hashtable hasht; + private ITypeResolutionService typeresolver; + private XmlTextReader xmlReader; + private string basepath; + private bool useResXDataNodes; + private AssemblyName [] assemblyNames; + private Hashtable hashtm; #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; - basic_setup (); } - public ResXResourceReader (Stream stream, ITypeResolutionService typeresolver) : this(stream) { - this.typeresolver = typeresolver; + public ResXResourceReader (Stream stream, ITypeResolutionService typeResolver) + : this (stream) + { + this.typeresolver = typeResolver; } - + public ResXResourceReader (string fileName) { - stream = File.OpenRead (fileName); - basic_setup (); + this.fileName = fileName; } - public ResXResourceReader (string fileName, ITypeResolutionService typeresolver) : this(fileName) { - this.typeresolver = typeresolver; + public ResXResourceReader (string fileName, ITypeResolutionService typeResolver) + : this (fileName) + { + this.typeresolver = typeResolver; } - public ResXResourceReader(TextReader reader) { - this.reader = new XmlTextReader(reader); - this.hasht = new Hashtable(); + public ResXResourceReader (TextReader reader) + { + this.reader = reader; + } + + public ResXResourceReader (TextReader reader, ITypeResolutionService typeResolver) + : this (reader) + { + this.typeresolver = typeResolver; + } + + public ResXResourceReader (Stream stream, AssemblyName [] assemblyNames) + : this (stream) + { + this.assemblyNames = assemblyNames; + } - load_data(); + public ResXResourceReader (string fileName, AssemblyName [] assemblyNames) + : this (fileName) + { + this.assemblyNames = assemblyNames; } - public ResXResourceReader (TextReader reader, ITypeResolutionService typeresolver) : this(reader) { - this.typeresolver = typeresolver; + public ResXResourceReader (TextReader reader, AssemblyName [] assemblyNames) + : this (reader) + { + this.assemblyNames = assemblyNames; } - ~ResXResourceReader() { - Dispose(false); + ~ResXResourceReader () + { + Dispose (false); } #endregion // Constructors & Destructor + public string BasePath { + get { return basepath; } + set { basepath = value; } + } + + public bool UseResXDataNodes { + get { return useResXDataNodes; } + set { + if (xmlReader != null) + throw new InvalidOperationException (); + useResXDataNodes = value; + } + } #region Private Methods - void basic_setup () { - reader = new XmlTextReader (stream); + private void LoadData () + { hasht = new Hashtable (); + hashtm = new Hashtable (); + if (fileName != null) { + stream = File.OpenRead (fileName); + } + + try { + xmlReader = null; + if (stream != null) { + xmlReader = new XmlTextReader (stream); + } else if (reader != null) { + xmlReader = new XmlTextReader (reader); + } + + if (xmlReader == null) { + throw new InvalidOperationException ("ResourceReader is closed."); + } + + xmlReader.WhitespaceHandling = WhitespaceHandling.None; - if (!IsStreamValid()){ - throw new ArgumentException("Stream is not a valid .resx file! It was possibly truncated."); + ResXHeader header = new ResXHeader (); + try { + while (xmlReader.Read ()) { + if (xmlReader.NodeType != XmlNodeType.Element) + continue; + + switch (xmlReader.LocalName) { + case "resheader": + ParseHeaderNode (header); + break; + case "data": + ParseDataNode (false); + break; + case "metadata": + ParseDataNode (true); + break; + } + } + } 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); + } + header.Verify (); + } finally { + if (fileName != null) { + stream.Close (); + stream = null; + } + xmlReader = null; } - 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; - } + + private void ParseHeaderNode (ResXHeader header) + { + string v = GetAttribute ("name"); + if (v == null) + return; + + if (String.Compare (v, "resmimetype", true) == 0) { + header.ResMimeType = GetHeaderValue (); + } else if (String.Compare (v, "reader", true) == 0) { + header.Reader = GetHeaderValue (); + } else if (String.Compare (v, "version", true) == 0) { + header.Version = GetHeaderValue (); + } else if (String.Compare (v, "writer", true) == 0) { + header.Writer = GetHeaderValue (); } - reader.MoveToElement (); - return null; } - static string get_value (XmlTextReader reader, string name) { - bool gotelement = false; - while (reader.Read ()) { - if (reader.NodeType == XmlNodeType.Element && String.Compare (reader.Name, name, true) == 0) { - gotelement = true; - break; - } + private string GetHeaderValue () + { + string value = null; + xmlReader.ReadStartElement (); + if (xmlReader.NodeType == XmlNodeType.Element) { + value = xmlReader.ReadElementString (); + } else { + value = xmlReader.Value.Trim (); } - if (!gotelement) + return value; + } + + private string GetAttribute (string name) + { + if (!xmlReader.HasAttributes) 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; + for (int i = 0; i < xmlReader.AttributeCount; i++) { + xmlReader.MoveToAttribute (i); + if (String.Compare (xmlReader.Name, name, true) == 0) { + string v = xmlReader.Value; + xmlReader.MoveToElement (); return v; } } + xmlReader.MoveToElement (); 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; + private string GetDataValue (bool meta, out string comment) + { + string value = null; + comment = null; + while (xmlReader.Read ()) { + if (xmlReader.NodeType == XmlNodeType.EndElement && xmlReader.LocalName == (meta ? "metadata" : "data")) 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; + + if (xmlReader.NodeType == XmlNodeType.Element) { + if (xmlReader.Name.Equals ("value")) { + xmlReader.WhitespaceHandling = WhitespaceHandling.Significant; + value = xmlReader.ReadString (); + xmlReader.WhitespaceHandling = WhitespaceHandling.None; + } else if (xmlReader.Name.Equals ("comment")) { + xmlReader.WhitespaceHandling = WhitespaceHandling.Significant; + comment = xmlReader.ReadString (); + xmlReader.WhitespaceHandling = WhitespaceHandling.None; + if (xmlReader.NodeType == XmlNodeType.EndElement && xmlReader.LocalName == (meta ? "metadata" : "data")) 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; } } + else + value = xmlReader.Value.Trim (); } - return gotmime; + return value; } - private void load_data () + private void ParseDataNode (bool meta) { - 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"); + 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"); - 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) { - TypeConverter c = TypeDescriptor.GetConverter (tt); - v = c.ConvertFromString (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; - } - } + string comment = null; + string value = GetDataValue (meta, out comment); + + ResXDataNode node = new ResXDataNode (name, mime_type, type_name, value, comment, pos, BasePath); + + if (useResXDataNodes) { + hashtable [name] = node; + return; } - } - private Type GetType(string type) { - if (typeresolver == null) { - return Type.GetType(type); - } else { - return typeresolver.GetType(type); + if (name == null) + throw new ArgumentException (string.Format (CultureInfo.CurrentCulture, + "Could not find a name for a resource. The resource value was '{0}'.", + node.GetValue ((AssemblyName []) null).ToString())); + + // 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; + } } + } + #endregion // Private Methods #region Public Methods public void Close () { - if (stream != null) { - stream.Close (); - stream = null; - } - if (reader != null) { - reader.Close(); + reader.Close (); reader = null; } } - - public IDictionaryEnumerator GetEnumerator () { - if (null == stream){ - throw new InvalidOperationException("ResourceReader is closed."); - } - else { - return hasht.GetEnumerator (); + + public IDictionaryEnumerator GetEnumerator () + { + if (hasht == null) { + LoadData (); } + return hasht.GetEnumerator (); } - + IEnumerator IEnumerable.GetEnumerator () { - return ((IResourceReader) this).GetEnumerator(); + return ((IResourceReader) this).GetEnumerator (); } - + void IDisposable.Dispose () { - Dispose(true); - GC.SuppressFinalize(this); + Dispose (true); + GC.SuppressFinalize (this); } - protected virtual void Dispose(bool disposing) { + protected virtual void Dispose (bool disposing) + { if (disposing) { - Close(); + Close (); } } - public static ResXResourceReader FromFileContents(string fileContents) { - return new ResXResourceReader(new StringReader(fileContents)); + 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); + public static ResXResourceReader FromFileContents (string fileContents, ITypeResolutionService typeResolver) + { + return new ResXResourceReader (new StringReader (fileContents), typeResolver); + } + + public static ResXResourceReader FromFileContents (string fileContents, AssemblyName [] assemblyNames) + { + return new ResXResourceReader (new StringReader (fileContents), assemblyNames); + } + + public IDictionaryEnumerator GetMetadataEnumerator () + { + if (hashtm == null) + LoadData (); + return hashtm.GetEnumerator (); } #endregion // Public Methods - - } // public sealed class ResXResourceReader -} // namespace System.Resources + + #region Internal Classes + private class ResXHeader + { + private string resMimeType; + private string reader; + private string version; + private string writer; + + public string ResMimeType + { + get { return resMimeType; } + set { resMimeType = value; } + } + + public string Reader { + get { return reader; } + set { reader = value; } + } + + public string Version { + get { return version; } + set { version = value; } + } + + public string Writer { + get { return writer; } + set { writer = value; } + } + + public void Verify () + { + if (!IsValid) + throw new ArgumentException ("Invalid ResX input. Could " + + "not find valid \"resheader\" tags for the ResX " + + "reader & writer type names."); + } + + public bool IsValid { + get { + if (string.Compare (ResMimeType, ResXResourceWriter.ResMimeType) != 0) + return false; + if (Reader == null || Writer == null) + return false; + string readerType = Reader.Split (',') [0].Trim (); + if (readerType != typeof (ResXResourceReader).FullName) + return false; + string writerType = Writer.Split (',') [0].Trim (); + if (writerType != typeof (ResXResourceWriter).FullName) + return false; + return true; + } + } + } + #endregion + } +}