// // XmlMtomDictionaryWriter.cs // // Author: // Atsushi Enomoto // // Copyright (C) 2009 Novell, Inc. http://www.novell.com // // 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. // using System; using System.IO; using System.Net.Mime; using System.Text; namespace System.Xml { internal class XmlMtomDictionaryWriter : XmlDictionaryWriter { public XmlMtomDictionaryWriter (Stream stream, Encoding encoding, int maxSizeInBytes, string startInfo, string boundary, string startUri, bool writeMessageHeaders, bool ownsStream) { writer = new StreamWriter (stream, encoding); max_bytes = maxSizeInBytes; write_headers = writeMessageHeaders; owns_stream = ownsStream; var settings = new XmlWriterSettings (); settings.Encoding = encoding; settings.OmitXmlDeclaration = true; xml_writer_settings = settings; // FIXME: actually it does not likely use ContentType.ToString() but writes those header items by own. // (so that it could generate "start" header dynamically) var c = new ContentType ("multipart/related"); c.Parameters ["type"] = "application/xop+xml"; c.Boundary = boundary; c.Parameters ["start"] = "<" + startUri + ">"; c.Parameters ["start-info"] = startInfo; content_type = c; } // constructor arguments TextWriter writer; XmlWriterSettings xml_writer_settings; Encoding encoding; int max_bytes; bool write_headers; bool owns_stream; ContentType content_type; // state XmlWriter w; int depth; int section_count; XmlWriter CreateWriter () { return XmlWriter.Create (writer, xml_writer_settings); } public override void Close () { w.Close (); if (owns_stream) writer.Close (); } public override void Flush () { w.Flush (); } public override string LookupPrefix (string namespaceUri) { return w.LookupPrefix (namespaceUri); } public override void WriteBase64 (byte [] bytes, int start, int length) { CheckState (); w.WriteBase64 (bytes, start, length); } public override void WriteCData (string text) { CheckState (); w.WriteCData (text); } public override void WriteCharEntity (char c) { CheckState (); w.WriteCharEntity (c); } public override void WriteChars (char [] buffer, int index, int count) { CheckState (); w.WriteChars (buffer, index, count); } public override void WriteComment (string comment) { CheckState (); w.WriteComment (comment); } public override void WriteDocType (string name, string pubid, string sysid, string intSubset) { throw new NotSupportedException (); // indeed } public override void WriteEndAttribute () { w.WriteEndAttribute (); } public override void WriteEndDocument () { w.WriteEndDocument (); } public override void WriteEndElement () { w.WriteEndElement (); if (--depth == 0) WriteEndOfMimeSection (); } public override void WriteEntityRef (string name) { w.WriteEntityRef (name); } public override void WriteFullEndElement () { w.WriteFullEndElement (); if (--depth == 0) WriteEndOfMimeSection (); } public override void WriteProcessingInstruction (string name, string data) { throw new NotSupportedException (); } public override void WriteRaw (string raw) { CheckState (); w.WriteRaw (raw); } public override void WriteRaw (char [] chars, int index, int count) { CheckState (); w.WriteRaw (chars, index, count); } public override void WriteStartAttribute (string prefix, string localName, string namespaceURI) { CheckState (); w.WriteStartAttribute (prefix, localName, namespaceURI); } public override void WriteStartDocument () { CheckState (); w.WriteStartDocument (); } public override void WriteStartDocument (bool standalone) { CheckState (); w.WriteStartDocument (standalone); } public override void WriteStartElement (string prefix, string localName, string namespaceURI) { CheckState (); if (depth == 0) WriteStartOfMimeSection (); w.WriteStartElement (prefix, localName, namespaceURI); depth++; } public override WriteState WriteState { get { return w.WriteState; } } public override void WriteString (string text) { CheckState (); int i1, i2 = 0; do { i1 = text.IndexOf ('\r', i2); if (i1 >= 0) { w.WriteString (text.Substring (i2, i1 - i2)); WriteCharEntity ('\r'); i2 = i1 + 1; } else { w.WriteString (text.Substring (i2)); break; } } while (true); } public override void WriteSurrogateCharEntity (char low, char high) { CheckState (); w.WriteSurrogateCharEntity (low, high); } public override void WriteWhitespace (string text) { CheckState (); w.WriteWhitespace (text); } public override string XmlLang { get { return w.XmlLang; } } public override XmlSpace XmlSpace { get { return w.XmlSpace; } } void CheckState () { if (w == null && write_headers) WriteMimeHeaders (); if (w == null || w.WriteState == WriteState.Closed || w.WriteState == WriteState.Error) w = CreateWriter (); } void WriteMimeHeaders () { writer.Write ("MIME-Version: 1.0\r\n"); writer.Write ("Content-Type: "); writer.Write (content_type.ToString ()); writer.Write ("\r\n\r\n\r\n"); } void WriteStartOfMimeSection () { section_count++; // I'm not sure what's the expected behavior of this // strange XmlWriter, but so far - it outputs only one // section. if (section_count > 1) return; writer.Write ("\r\n"); writer.Write ("--"); writer.Write (content_type.Boundary); writer.Write ("\r\n"); writer.Write ("Content-ID: "); writer.Write (content_type.Parameters ["start"]); writer.Write ("\r\n"); writer.Write ("Content-Transfer-Encoding: 8bit\r\n"); writer.Write ("Content-Type: application/xop+xml;charset="); writer.Write (xml_writer_settings.Encoding.HeaderName); writer.Write (";type=\""); writer.Write (content_type.Parameters ["start-info"].Replace ("\"", "\\\"")); writer.Write ("\"\r\n\r\n"); } void WriteEndOfMimeSection () { // I'm not sure what's the expected behavior of this // strange XmlWriter, but so far - it outputs only one // section. if (section_count > 1) return; writer.Write ("\r\n"); writer.Write ("--"); writer.Write (content_type.Boundary); writer.Write ("--\r\n"); } } }