aboutsummaryrefslogtreecommitdiff
path: root/source/ShiftUI/Keyboard/ResXResourceWriter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'source/ShiftUI/Keyboard/ResXResourceWriter.cs')
-rw-r--r--source/ShiftUI/Keyboard/ResXResourceWriter.cs667
1 files changed, 667 insertions, 0 deletions
diff --git a/source/ShiftUI/Keyboard/ResXResourceWriter.cs b/source/ShiftUI/Keyboard/ResXResourceWriter.cs
new file mode 100644
index 0000000..42b3961
--- /dev/null
+++ b/source/ShiftUI/Keyboard/ResXResourceWriter.cs
@@ -0,0 +1,667 @@
+// 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]
+// Gonzalo Paniagua Javier [email protected]
+// Peter Bartok [email protected]
+// Gary Barnett [email protected]
+// includes code by Mike Krüger and Lluis Sanchez
+
+using System.ComponentModel;
+using System.IO;
+using System.Runtime.Serialization.Formatters.Binary;
+using System.Text;
+using System.Xml;
+using System.Reflection;
+
+namespace System.Resources
+{
+#if INSIDE_SYSTEM_WEB
+ internal
+#else
+ public
+#endif
+ class ResXResourceWriter : IResourceWriter, IDisposable
+ {
+ #region Local Variables
+ private string filename;
+ private Stream stream;
+ private TextWriter textwriter;
+ private XmlTextWriter writer;
+ private bool written;
+ private string base_path;
+ #endregion // Local Variables
+
+ #region Static Fields
+ public static readonly string BinSerializedObjectMimeType = "application/x-microsoft.net.object.binary.base64";
+ public static readonly string ByteArraySerializedObjectMimeType = "application/x-microsoft.net.object.bytearray.base64";
+ public static readonly string DefaultSerializedObjectMimeType = BinSerializedObjectMimeType;
+ public static readonly string ResMimeType = "text/microsoft-resx";
+ public static readonly string ResourceSchema = schema;
+ public static readonly string SoapSerializedObjectMimeType = "application/x-microsoft.net.object.soap.base64";
+ public static readonly string Version = "2.0";
+ #endregion // Static Fields
+
+ #region Constructors & Destructor
+ public ResXResourceWriter (Stream stream)
+ {
+ if (stream == null)
+ throw new ArgumentNullException ("stream");
+
+ if (!stream.CanWrite)
+ throw new ArgumentException ("stream is not writable.", "stream");
+
+ this.stream = stream;
+ }
+
+ public ResXResourceWriter (TextWriter textWriter)
+ {
+ if (textWriter == null)
+ throw new ArgumentNullException ("textWriter");
+
+ this.textwriter = textWriter;
+ }
+
+ public ResXResourceWriter (string fileName)
+ {
+ if (fileName == null)
+ throw new ArgumentNullException ("fileName");
+
+ this.filename = fileName;
+ }
+
+ ~ResXResourceWriter() {
+ Dispose(false);
+ }
+ #endregion // Constructors & Destructor
+
+ void InitWriter ()
+ {
+ if (filename != null)
+ stream = File.Open (filename, FileMode.Create);
+ if (textwriter == null)
+ textwriter = new StreamWriter (stream, Encoding.UTF8);
+
+ writer = new XmlTextWriter (textwriter);
+ writer.Formatting = Formatting.Indented;
+ writer.WriteStartDocument ();
+ writer.WriteStartElement ("root");
+ writer.WriteRaw (schema);
+ WriteHeader ("resmimetype", "text/microsoft-resx");
+ WriteHeader ("version", "1.3");
+ WriteHeader ("reader", typeof (ResXResourceReader).AssemblyQualifiedName);
+ WriteHeader ("writer", typeof (ResXResourceWriter).AssemblyQualifiedName);
+ }
+
+ void WriteHeader (string name, string value)
+ {
+ writer.WriteStartElement ("resheader");
+ writer.WriteAttributeString ("name", name);
+ writer.WriteStartElement ("value");
+ writer.WriteString (value);
+ writer.WriteEndElement ();
+ writer.WriteEndElement ();
+ }
+
+ void WriteNiceBase64(byte[] value, int offset, int length) {
+ string b64;
+ StringBuilder sb;
+ int pos;
+ int inc;
+ string ins;
+
+ b64 = Convert.ToBase64String(value, offset, length);
+
+ // Wild guess; two extra newlines, and one newline/tab pair for every 80 chars
+ sb = new StringBuilder(b64, b64.Length + ((b64.Length + 160) / 80) * 3);
+ pos = 0;
+ inc = 80 + Environment.NewLine.Length + 1;
+ ins = Environment.NewLine + "\t";
+ while (pos < sb.Length) {
+ sb.Insert(pos, ins);
+ pos += inc;
+ }
+ sb.Insert(sb.Length, Environment.NewLine);
+ writer.WriteString(sb.ToString());
+ }
+ void WriteBytes (string name, Type type, byte[] value, int offset, int length)
+ {
+ WriteBytes (name, type, value, offset, length, String.Empty);
+ }
+
+ void WriteBytes (string name, Type type, byte[] value, int offset, int length, string comment)
+ {
+ writer.WriteStartElement ("data");
+ writer.WriteAttributeString ("name", name);
+
+ 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", BinSerializedObjectMimeType);
+ writer.WriteStartElement ("value");
+ writer.WriteBase64 (value, offset, length);
+ }
+
+ writer.WriteEndElement ();
+
+ if (!(comment == null || comment.Equals (String.Empty))) {
+ writer.WriteStartElement ("comment");
+ writer.WriteString (comment);
+ writer.WriteEndElement ();
+ }
+
+ writer.WriteEndElement ();
+ }
+
+ void WriteBytes (string name, Type type, byte [] value, string comment)
+ {
+ WriteBytes (name, type, value, 0, value.Length, comment);
+ }
+
+ void WriteString (string name, string value)
+ {
+ WriteString (name, value, null);
+ }
+ void WriteString (string name, string value, Type type)
+ {
+ WriteString (name, value, type, String.Empty);
+ }
+ void WriteString (string name, string value, Type type, string comment)
+ {
+ writer.WriteStartElement ("data");
+ writer.WriteAttributeString ("name", name);
+ if (type != null)
+ writer.WriteAttributeString ("type", type.AssemblyQualifiedName);
+ writer.WriteStartElement ("value");
+ writer.WriteString (value);
+ writer.WriteEndElement ();
+ if (!(comment == null || comment.Equals (String.Empty))) {
+ writer.WriteStartElement ("comment");
+ writer.WriteString (comment);
+ writer.WriteEndElement ();
+ }
+ writer.WriteEndElement ();
+ writer.WriteWhitespace ("\n ");
+ }
+
+ public void AddResource (string name, byte [] value)
+ {
+ if (name == null)
+ throw new ArgumentNullException ("name");
+
+ if (value == null)
+ throw new ArgumentNullException ("value");
+
+ if (written)
+ throw new InvalidOperationException ("The resource is already generated.");
+
+ if (writer == null)
+ InitWriter ();
+
+ WriteBytes (name, value.GetType (), value, null);
+ }
+
+ public void AddResource (string name, object value)
+ {
+ AddResource (name, value, String.Empty);
+ }
+
+ private void AddResource (string name, object value, string comment)
+ {
+ if (value is string) {
+ AddResource (name, (string) value, comment);
+ return;
+ }
+
+ if (name == null)
+ throw new ArgumentNullException ("name");
+
+ if (value != null && !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.");
+
+ if (writer == null)
+ InitWriter ();
+
+ if (value is byte[]) {
+ WriteBytes (name, value.GetType (), (byte []) value, comment);
+ return;
+ }
+
+ if (value == null) {
+ // nulls written as ResXNullRef
+ WriteString (name, "", typeof (ResXNullRef), comment);
+ return;
+ }
+
+ TypeConverter converter = TypeDescriptor.GetConverter (value);
+ if (value is ResXFileRef) {
+ ResXFileRef fileRef = ProcessFileRefBasePath ((ResXFileRef) value);
+ string str = (string) converter.ConvertToInvariantString (fileRef);
+ WriteString (name, str, value.GetType (), comment);
+ return;
+ }
+
+ if (converter != null && converter.CanConvertTo (typeof (string)) && converter.CanConvertFrom (typeof (string))) {
+ string str = (string) converter.ConvertToInvariantString (value);
+ WriteString (name, str, value.GetType (), comment);
+ return;
+ }
+
+ if (converter != null && converter.CanConvertTo (typeof (byte[])) && converter.CanConvertFrom (typeof (byte[]))) {
+ byte[] b = (byte[]) converter.ConvertTo (value, typeof (byte[]));
+ WriteBytes (name, value.GetType (), b, comment);
+ return;
+ }
+
+ MemoryStream ms = new MemoryStream ();
+ BinaryFormatter fmt = new BinaryFormatter ();
+ try {
+ fmt.Serialize (ms, value);
+ } catch (Exception e) {
+ throw new InvalidOperationException ("Cannot add a " + value.GetType () +
+ "because it cannot be serialized: " +
+ e.Message);
+ }
+
+ WriteBytes (name, null, ms.GetBuffer (), 0, (int) ms.Length, comment);
+ ms.Close ();
+ }
+
+ public void AddResource (string name, string value)
+ {
+ AddResource (name, value, string.Empty);
+ }
+
+ private void AddResource (string name, string value, string comment)
+ {
+ if (name == null)
+ throw new ArgumentNullException ("name");
+
+ if (value == null)
+ throw new ArgumentNullException ("value");
+
+ if (written)
+ throw new InvalidOperationException ("The resource is already generated.");
+
+ if (writer == null)
+ InitWriter ();
+
+ WriteString (name, value, null, comment);
+ }
+
+ [MonoTODO ("Stub, not implemented")]
+ public virtual void AddAlias (string aliasName, AssemblyName assemblyName)
+ {
+ }
+
+ public void AddResource (ResXDataNode node)
+ {
+ if (node == null)
+ throw new ArgumentNullException ("node");
+
+ if (writer == null)
+ InitWriter ();
+
+ if (node.IsWritable)
+ WriteWritableNode (node);
+ else if (node.FileRef != null)
+ AddResource (node.Name, node.FileRef, node.Comment);
+ else
+ AddResource (node.Name, node.GetValue ((AssemblyName []) null), node.Comment);
+ }
+
+ ResXFileRef ProcessFileRefBasePath (ResXFileRef fileRef)
+ {
+ if (String.IsNullOrEmpty (BasePath))
+ return fileRef;
+
+ string newPath = AbsoluteToRelativePath (BasePath, fileRef.FileName);
+ return new ResXFileRef (newPath, fileRef.TypeName, fileRef.TextFileEncoding);
+ }
+
+ static bool IsSeparator (char ch)
+ {
+ return ch == Path.DirectorySeparatorChar || ch == Path.AltDirectorySeparatorChar || ch == Path.VolumeSeparatorChar;
+ }
+ //adapted from MonoDevelop.Core
+ unsafe static string AbsoluteToRelativePath (string baseDirectoryPath, string absPath)
+ {
+ if (string.IsNullOrEmpty (baseDirectoryPath))
+ return absPath;
+
+ baseDirectoryPath = baseDirectoryPath.TrimEnd (Path.DirectorySeparatorChar);
+
+ fixed (char* bPtr = baseDirectoryPath, aPtr = absPath) {
+ var bEnd = bPtr + baseDirectoryPath.Length;
+ var aEnd = aPtr + absPath.Length;
+ char* lastStartA = aEnd;
+ char* lastStartB = bEnd;
+
+ int indx = 0;
+ // search common base path
+ var a = aPtr;
+ var b = bPtr;
+ while (a < aEnd) {
+ if (*a != *b)
+ break;
+ if (IsSeparator (*a)) {
+ indx++;
+ lastStartA = a + 1;
+ lastStartB = b;
+ }
+ a++;
+ b++;
+ if (b >= bEnd) {
+ if (a >= aEnd || IsSeparator (*a)) {
+ indx++;
+ lastStartA = a + 1;
+ lastStartB = b;
+ }
+ break;
+ }
+ }
+ if (indx == 0)
+ return absPath;
+
+ if (lastStartA >= aEnd)
+ return ".";
+
+ // handle case a: some/path b: some/path/deeper...
+ if (a >= aEnd) {
+ if (IsSeparator (*b)) {
+ lastStartA = a + 1;
+ lastStartB = b;
+ }
+ }
+
+ // look how many levels to go up into the base path
+ int goUpCount = 0;
+ while (lastStartB < bEnd) {
+ if (IsSeparator (*lastStartB))
+ goUpCount++;
+ lastStartB++;
+ }
+ var size = goUpCount * 2 + goUpCount + aEnd - lastStartA;
+ var result = new char [size];
+ fixed (char* rPtr = result) {
+ // go paths up
+ var r = rPtr;
+ for (int i = 0; i < goUpCount; i++) {
+ *(r++) = '.';
+ *(r++) = '.';
+ *(r++) = Path.DirectorySeparatorChar;
+ }
+ // copy the remaining absulute path
+ while (lastStartA < aEnd)
+ *(r++) = *(lastStartA++);
+ }
+ return new string (result);
+ }
+ }
+
+ // avoids instantiating objects
+ void WriteWritableNode (ResXDataNode node)
+ {
+ writer.WriteStartElement ("data");
+ writer.WriteAttributeString ("name", node.Name);
+ if (!(node.Type == null || node.Type.Equals (String.Empty)))
+ writer.WriteAttributeString ("type", node.Type);
+ if (!(node.MimeType == null || node.MimeType.Equals (String.Empty)))
+ writer.WriteAttributeString ("mimetype", node.MimeType);
+ writer.WriteStartElement ("value");
+ writer.WriteString (node.DataString);
+ writer.WriteEndElement ();
+ if (!(node.Comment == null || node.Comment.Equals (String.Empty))) {
+ writer.WriteStartElement ("comment");
+ writer.WriteString (node.Comment);
+ writer.WriteEndElement ();
+ }
+ writer.WriteEndElement ();
+ writer.WriteWhitespace ("\n ");
+ }
+
+ public void AddMetadata (string name, string value)
+ {
+ if (name == null)
+ throw new ArgumentNullException ("name");
+
+ if (value == null)
+ throw new ArgumentNullException ("value");
+
+ if (written)
+ throw new InvalidOperationException ("The resource is already generated.");
+
+ if (writer == null)
+ InitWriter ();
+
+ writer.WriteStartElement ("metadata");
+ writer.WriteAttributeString ("name", name);
+ writer.WriteAttributeString ("xml:space", "preserve");
+
+ writer.WriteElementString ("value", value);
+
+ writer.WriteEndElement ();
+ }
+
+ public void AddMetadata (string name, byte[] value)
+ {
+ if (name == null)
+ throw new ArgumentNullException ("name");
+
+ if (value == null)
+ throw new ArgumentNullException ("value");
+
+ if (written)
+ throw new InvalidOperationException ("The resource is already generated.");
+
+ if (writer == null)
+ InitWriter ();
+
+ writer.WriteStartElement ("metadata");
+ writer.WriteAttributeString ("name", name);
+
+ writer.WriteAttributeString ("type", value.GetType ().AssemblyQualifiedName);
+
+ writer.WriteStartElement ("value");
+ WriteNiceBase64 (value, 0, value.Length);
+ writer.WriteEndElement ();
+
+ writer.WriteEndElement ();
+ }
+
+ public void AddMetadata (string name, object value)
+ {
+ if (value is string) {
+ AddMetadata (name, (string)value);
+ return;
+ }
+
+ if (value is byte[]) {
+ AddMetadata (name, (byte[])value);
+ return;
+ }
+
+ if (name == null)
+ throw new ArgumentNullException ("name");
+
+ 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.");
+
+ if (writer == null)
+ InitWriter ();
+
+ Type type = value.GetType ();
+
+ TypeConverter converter = TypeDescriptor.GetConverter (value);
+ if (converter != null && converter.CanConvertTo (typeof (string)) && converter.CanConvertFrom (typeof (string))) {
+ string str = (string)converter.ConvertToInvariantString (value);
+ writer.WriteStartElement ("metadata");
+ writer.WriteAttributeString ("name", name);
+ if (type != null)
+ writer.WriteAttributeString ("type", type.AssemblyQualifiedName);
+ writer.WriteStartElement ("value");
+ writer.WriteString (str);
+ writer.WriteEndElement ();
+ writer.WriteEndElement ();
+ writer.WriteWhitespace ("\n ");
+ return;
+ }
+
+ if (converter != null && converter.CanConvertTo (typeof (byte[])) && converter.CanConvertFrom (typeof (byte[]))) {
+ byte[] b = (byte[])converter.ConvertTo (value, typeof (byte[]));
+ writer.WriteStartElement ("metadata");
+ writer.WriteAttributeString ("name", name);
+
+ if (type != null) {
+ writer.WriteAttributeString ("type", type.AssemblyQualifiedName);
+ writer.WriteAttributeString ("mimetype", ByteArraySerializedObjectMimeType);
+ writer.WriteStartElement ("value");
+ WriteNiceBase64 (b, 0, b.Length);
+ } else {
+ writer.WriteAttributeString ("mimetype", BinSerializedObjectMimeType);
+ writer.WriteStartElement ("value");
+ writer.WriteBase64 (b, 0, b.Length);
+ }
+
+ writer.WriteEndElement ();
+ writer.WriteEndElement ();
+ return;
+ }
+
+ MemoryStream ms = new MemoryStream ();
+ BinaryFormatter fmt = new BinaryFormatter ();
+ try {
+ fmt.Serialize (ms, value);
+ } catch (Exception e) {
+ throw new InvalidOperationException ("Cannot add a " + value.GetType () +
+ "because it cannot be serialized: " +
+ e.Message);
+ }
+
+ writer.WriteStartElement ("metadata");
+ writer.WriteAttributeString ("name", name);
+
+ if (type != null) {
+ writer.WriteAttributeString ("type", type.AssemblyQualifiedName);
+ writer.WriteAttributeString ("mimetype", ByteArraySerializedObjectMimeType);
+ writer.WriteStartElement ("value");
+ WriteNiceBase64 (ms.GetBuffer (), 0, ms.GetBuffer ().Length);
+ } else {
+ writer.WriteAttributeString ("mimetype", BinSerializedObjectMimeType);
+ writer.WriteStartElement ("value");
+ writer.WriteBase64 (ms.GetBuffer (), 0, ms.GetBuffer ().Length);
+ }
+
+ writer.WriteEndElement ();
+ writer.WriteEndElement ();
+ ms.Close ();
+ }
+
+ public void Close ()
+ {
+ if (!written) {
+ Generate ();
+ }
+
+ if (writer != null) {
+ writer.Close ();
+ stream = null;
+ filename = null;
+ textwriter = null;
+ }
+ }
+
+ public virtual void Dispose ()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ public void Generate ()
+ {
+ if (written)
+ throw new InvalidOperationException ("The resource is already generated.");
+
+ written = true;
+ writer.WriteEndElement ();
+ writer.Flush ();
+ }
+
+ protected virtual void Dispose (bool disposing)
+ {
+ if (disposing)
+ Close();
+ }
+
+ static string schema = @"
+ <xsd:schema id='root' xmlns='' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:msdata='urn:schemas-microsoft-com:xml-msdata'>
+ <xsd:element name='root' msdata:IsDataSet='true'>
+ <xsd:complexType>
+ <xsd:choice maxOccurs='unbounded'>
+ <xsd:element name='data'>
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name='value' type='xsd:string' minOccurs='0' msdata:Ordinal='1' />
+ <xsd:element name='comment' type='xsd:string' minOccurs='0' msdata:Ordinal='2' />
+ </xsd:sequence>
+ <xsd:attribute name='name' type='xsd:string' msdata:Ordinal='1' />
+ <xsd:attribute name='type' type='xsd:string' msdata:Ordinal='3' />
+ <xsd:attribute name='mimetype' type='xsd:string' msdata:Ordinal='4' />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name='resheader'>
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name='value' type='xsd:string' minOccurs='0' msdata:Ordinal='1' />
+ </xsd:sequence>
+ <xsd:attribute name='name' type='xsd:string' use='required' />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+".Replace ("'", "\"");
+
+ #region Public Properties
+ public string BasePath {
+ get { return base_path; }
+ set { base_path = value; }
+ }
+ #endregion
+ }
+}