2009-04-14 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / System.Runtime.Serialization / System.Xml / XmlMtomDictionaryWriter.cs
1 //
2 // XmlMtomDictionaryWriter.cs
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2009 Novell, Inc.  http://www.novell.com
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 using System;
29 using System.IO;
30 using System.Net.Mime;
31 using System.Text;
32
33 namespace System.Xml
34 {
35         internal class XmlMtomDictionaryWriter : XmlDictionaryWriter
36         {
37                 public XmlMtomDictionaryWriter (Stream stream, Encoding encoding, int maxSizeInBytes, string startInfo, string boundary, string startUri, bool writeMessageHeaders, bool ownsStream)
38                 {
39                         writer = new StreamWriter (stream, encoding);
40                         max_bytes = maxSizeInBytes;
41                         write_headers = writeMessageHeaders;
42                         owns_stream = ownsStream;
43
44                         var settings = new XmlWriterSettings ();
45                         settings.Encoding = encoding;
46                         settings.OmitXmlDeclaration = true;
47                         xml_writer_settings = settings;
48
49                         // FIXME: actually it does not likely use ContentType.ToString() but writes those header items by own.
50                         // (so that it could generate "start" header dynamically)
51                         var c = new ContentType ("multipart/related");
52                         c.Parameters ["type"] = "application/xop+xml";
53                         c.Boundary = boundary;
54                         c.Parameters ["start"] = "<" + startUri + ">";
55                         c.Parameters ["start-info"] = startInfo;
56                         content_type = c;
57                 }
58
59                 // constructor arguments
60                 TextWriter writer;
61                 XmlWriterSettings xml_writer_settings;
62                 Encoding encoding;
63                 int max_bytes;
64                 bool write_headers;
65                 bool owns_stream;
66                 ContentType content_type;
67
68                 // state
69                 XmlWriter w;
70                 int depth;
71                 int section_count;
72
73                 XmlWriter CreateWriter ()
74                 {
75                         return XmlWriter.Create (writer, xml_writer_settings);
76                 }
77
78                 public override void Close ()
79                 {
80                         w.Close ();
81                         if (owns_stream)
82                                 writer.Close ();
83                 }
84
85                 public override void Flush ()
86                 {
87                         w.Flush ();
88                 }
89
90                 public override string LookupPrefix (string namespaceUri)
91                 {
92                         return w.LookupPrefix (namespaceUri);
93                 }
94
95                 public override void WriteBase64 (byte [] bytes, int start, int length)
96                 {
97                         CheckState ();
98                         w.WriteBase64 (bytes, start, length);
99                 }
100
101                 public override void WriteCData (string text)
102                 {
103                         CheckState ();
104                         w.WriteCData (text);
105                 }
106
107                 public override void WriteCharEntity (char c)
108                 {
109                         CheckState ();
110                         w.WriteCharEntity (c);
111                 }
112
113                 public override void WriteChars (char [] buffer, int index, int count)
114                 {
115                         CheckState ();
116                         w.WriteChars (buffer, index, count);
117                 }
118
119                 public override void WriteComment (string comment)
120                 {
121                         CheckState ();
122                         w.WriteComment (comment);
123                 }
124
125                 public override void WriteDocType (string name, string pubid, string sysid, string intSubset)
126                 {
127                         throw new NotSupportedException (); // indeed
128                 }
129
130                 public override void WriteEndAttribute ()
131                 {
132                         w.WriteEndAttribute ();
133                 }
134
135                 public override void WriteEndDocument ()
136                 {
137                         w.WriteEndDocument ();
138                 }
139
140                 public override void WriteEndElement ()
141                 {
142                         w.WriteEndElement ();
143                         if (--depth == 0)
144                                 WriteEndOfMimeSection ();
145                 }
146
147                 public override void WriteEntityRef (string name)
148                 {
149                         w.WriteEntityRef (name);
150                 }
151
152                 public override void WriteFullEndElement ()
153                 {
154                         w.WriteFullEndElement ();
155                         if (--depth == 0)
156                                 WriteEndOfMimeSection ();
157                 }
158
159                 public override void WriteProcessingInstruction (string name, string data)
160                 {
161                         throw new NotSupportedException ();
162                 }
163
164                 public override void WriteRaw (string raw)
165                 {
166                         CheckState ();
167                         w.WriteRaw (raw);
168                 }
169
170                 public override void WriteRaw (char [] chars, int index, int count)
171                 {
172                         CheckState ();
173                         w.WriteRaw (chars, index, count);
174                 }
175
176                 public override void WriteStartAttribute (string prefix, string localName, string namespaceURI)
177                 {
178                         CheckState ();
179                         w.WriteStartAttribute (prefix, localName, namespaceURI);
180                 }
181
182                 public override void WriteStartDocument ()
183                 {
184                         CheckState ();
185                         w.WriteStartDocument ();
186                 }
187
188                 public override void WriteStartDocument (bool standalone)
189                 {
190                         CheckState ();
191                         w.WriteStartDocument (standalone);
192                 }
193
194                 public override void WriteStartElement (string prefix, string localName, string namespaceURI)
195                 {
196                         CheckState ();
197
198                         if (depth == 0)
199                                 WriteStartOfMimeSection ();
200
201                         w.WriteStartElement (prefix, localName, namespaceURI);
202                         depth++;
203                 }
204
205                 public override WriteState WriteState {
206                         get { return w.WriteState; }
207                 }
208
209                 public override void WriteString (string text)
210                 {
211                         CheckState ();
212
213                         int i1, i2 = 0;
214                         do {
215                                 i1 = text.IndexOf ('\r', i2);
216                                 if (i1 >= 0) {
217                                         w.WriteString (text.Substring (i2, i1 - i2));
218                                         WriteCharEntity ('\r');
219                                         i2 = i1 + 1;
220                                 } else {
221                                         w.WriteString (text.Substring (i2));
222                                         break;
223                                 }
224                         } while (true);
225                 }
226
227                 public override void WriteSurrogateCharEntity (char low, char high)
228                 {
229                         CheckState ();
230                         w.WriteSurrogateCharEntity (low, high);
231                 }
232
233                 public override void WriteWhitespace (string text)
234                 {
235                         CheckState ();
236                         w.WriteWhitespace (text);
237                 }
238
239                 public override string XmlLang {
240                         get { return w.XmlLang; }
241                 }
242
243                 public override XmlSpace XmlSpace {
244                         get { return w.XmlSpace; }
245                 }
246
247                 void CheckState ()
248                 {
249                         if (w == null && write_headers)
250                                 WriteMimeHeaders ();
251                         if (w == null || w.WriteState == WriteState.Closed || w.WriteState == WriteState.Error)
252                                 w = CreateWriter ();
253                 }
254
255                 void WriteMimeHeaders ()
256                 {
257                         writer.Write ("MIME-Version: 1.0\r\n");
258                         writer.Write ("Content-Type: ");
259                         writer.Write (content_type.ToString ());
260                         writer.Write ("\r\n\r\n\r\n");
261                 }
262
263                 void WriteStartOfMimeSection ()
264                 {
265                         section_count++;
266
267                         // I'm not sure what's the expected behavior of this
268                         // strange XmlWriter, but so far - it outputs only one
269                         // section.
270                         if (section_count > 1)
271                                 return;
272
273                         writer.Write ("\r\n");
274                         writer.Write ("--");
275                         writer.Write (content_type.Boundary);
276                         writer.Write ("\r\n");
277                         writer.Write ("Content-ID: ");
278                         writer.Write (content_type.Parameters ["start"]);
279                         writer.Write ("\r\n");
280                         writer.Write ("Content-Transfer-Encoding: 8bit\r\n");
281                         writer.Write ("Content-Type: application/xop+xml;charset=");
282                         writer.Write (xml_writer_settings.Encoding.HeaderName);
283                         writer.Write (";type=\"");
284                         writer.Write (content_type.Parameters ["start-info"].Replace ("\"", "\\\""));
285                         writer.Write ("\"\r\n\r\n");
286                 }
287
288                 void WriteEndOfMimeSection ()
289                 {
290                         // I'm not sure what's the expected behavior of this
291                         // strange XmlWriter, but so far - it outputs only one
292                         // section.
293                         if (section_count > 1)
294                                 return;
295
296                         writer.Write ("\r\n");
297                         writer.Write ("--");
298                         writer.Write (content_type.Boundary);
299                         writer.Write ("--\r\n");
300                 }
301         }
302 }
303