| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667 |
- // 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
- }
- }
|