[arm] Fix a problem introduced by 3469c138c67e4b7e0afcc6a31046fcca7931d660.
[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                         settings.ConformanceLevel = ConformanceLevel.Fragment;
48                         settings.NewLineChars = "\r\n";
49                         xml_writer_settings = settings;
50
51                         // FIXME: actually it does not likely use ContentType.ToString() but writes those header items by own.
52                         // (so that it could generate "start" header dynamically)
53                         var c = new ContentType ("multipart/related");
54                         c.Parameters ["type"] = "application/xop+xml";
55                         c.Boundary = boundary;
56                         c.Parameters ["start"] = "<" + startUri + ">";
57                         c.Parameters ["start-info"] = startInfo;
58                         content_type = c;
59                 }
60
61                 // constructor arguments
62                 TextWriter writer;
63                 XmlWriterSettings xml_writer_settings;
64                 Encoding encoding;
65                 int max_bytes;
66                 bool write_headers;
67                 bool owns_stream;
68                 ContentType content_type;
69
70                 // state
71                 XmlWriter w;
72                 int depth;
73                 int section_count;
74
75                 XmlWriter CreateWriter ()
76                 {
77                         return XmlWriter.Create (writer, xml_writer_settings);
78                 }
79
80                 public override void Close ()
81                 {
82                         w.Close ();
83                         if (owns_stream)
84                                 writer.Close ();
85                 }
86
87                 public override void Flush ()
88                 {
89                         w.Flush ();
90                 }
91
92                 public override string LookupPrefix (string namespaceUri)
93                 {
94                         return w.LookupPrefix (namespaceUri);
95                 }
96
97                 public override void WriteBase64 (byte [] bytes, int start, int length)
98                 {
99                         CheckState ();
100                         w.WriteBase64 (bytes, start, length);
101                 }
102
103                 public override void WriteCData (string text)
104                 {
105                         CheckState ();
106                         w.WriteCData (text);
107                 }
108
109                 public override void WriteCharEntity (char c)
110                 {
111                         CheckState ();
112                         w.WriteCharEntity (c);
113                 }
114
115                 public override void WriteChars (char [] buffer, int index, int count)
116                 {
117                         CheckState ();
118                         w.WriteChars (buffer, index, count);
119                 }
120
121                 public override void WriteComment (string comment)
122                 {
123                         CheckState ();
124                         w.WriteComment (comment);
125                 }
126
127                 public override void WriteDocType (string name, string pubid, string sysid, string intSubset)
128                 {
129                         throw new NotSupportedException (); // indeed
130                 }
131
132                 public override void WriteEndAttribute ()
133                 {
134                         w.WriteEndAttribute ();
135                 }
136
137                 public override void WriteEndDocument ()
138                 {
139                         // We don't call w.WriteEndElement() because that causes state error
140                         // (which is correct; MTOM writer just does not expect it).
141                 }
142
143                 public override void WriteEndElement ()
144                 {
145                         w.WriteEndElement ();
146                         if (--depth == 0)
147                                 WriteEndOfMimeSection ();
148                 }
149
150                 public override void WriteEntityRef (string name)
151                 {
152                         w.WriteEntityRef (name);
153                 }
154
155                 public override void WriteFullEndElement ()
156                 {
157                         w.WriteFullEndElement ();
158                         if (--depth == 0)
159                                 WriteEndOfMimeSection ();
160                 }
161
162                 public override void WriteProcessingInstruction (string name, string data)
163                 {
164                         throw new NotSupportedException ();
165                 }
166
167                 public override void WriteRaw (string raw)
168                 {
169                         CheckState ();
170                         w.WriteRaw (raw);
171                 }
172
173                 public override void WriteRaw (char [] chars, int index, int count)
174                 {
175                         CheckState ();
176                         w.WriteRaw (chars, index, count);
177                 }
178
179                 public override void WriteStartAttribute (string prefix, string localName, string namespaceURI)
180                 {
181                         CheckState ();
182                         w.WriteStartAttribute (prefix, localName, namespaceURI);
183                 }
184
185                 public override void WriteStartDocument ()
186                 {
187                         CheckState ();
188                         // We don't call w.WriteStartDocument() because that causes state error
189                         // (which is correct; MTOM writer just does not expect it).
190                 }
191
192                 public override void WriteStartDocument (bool standalone)
193                 {
194                         CheckState ();
195                         // We don't call w.WriteStartDocument() because that causes state error
196                         // (which is correct; MTOM writer just does not expect it).
197                 }
198
199                 public override void WriteStartElement (string prefix, string localName, string namespaceURI)
200                 {
201                         CheckState ();
202
203                         if (depth == 0)
204                                 WriteStartOfMimeSection ();
205
206                         w.WriteStartElement (prefix, localName, namespaceURI);
207                         depth++;
208                 }
209
210                 public override WriteState WriteState {
211                         get { return w.WriteState; }
212                 }
213
214                 static readonly char [] eol_chars = "\r\n".ToCharArray ();
215
216                 public override void WriteString (string text)
217                 {
218                         CheckState ();
219
220                         int i1, i2 = 0;
221                         do {
222                                 i1 = text.IndexOfAny (eol_chars, i2);
223                                 if (i1 >= 0) {
224                                         w.WriteString (text.Substring (i2, i1 - i2));
225                                         if (text [i1] == '\r')
226                                                 w.WriteCharEntity ('\r');
227                                         else
228                                                 w.WriteRaw ("\r\n");
229                                         i2 = i1 + 1;
230                                 } else {
231                                         w.WriteString (text.Substring (i2));
232                                         break;
233                                 }
234                         } while (true);
235                 }
236
237                 public override void WriteSurrogateCharEntity (char low, char high)
238                 {
239                         CheckState ();
240                         w.WriteSurrogateCharEntity (low, high);
241                 }
242
243                 public override void WriteWhitespace (string text)
244                 {
245                         CheckState ();
246                         w.WriteWhitespace (text);
247                 }
248
249                 public override string XmlLang {
250                         get { return w.XmlLang; }
251                 }
252
253                 public override XmlSpace XmlSpace {
254                         get { return w.XmlSpace; }
255                 }
256
257                 void CheckState ()
258                 {
259                         if (w == null && write_headers)
260                                 WriteMimeHeaders ();
261                         
262                         if (w == null || w.WriteState == WriteState.Closed || w.WriteState == WriteState.Error)
263                                 w = CreateWriter ();
264                 }
265
266                 void WriteMimeHeaders ()
267                 {
268                         w.Flush ();
269                         writer.Write ("MIME-Version: 1.0\r\n");
270                         writer.Write ("Content-Type: ");
271                         writer.Write (content_type.ToString ());
272                         writer.Write ("\r\n\r\n\r\n");
273                 }
274
275                 void WriteStartOfMimeSection ()
276                 {
277                         section_count++;
278
279                         // I'm not sure what's the expected behavior of this
280                         // strange XmlWriter, but so far - it outputs only one
281                         // section.
282                         if (section_count > 1)
283                                 return;
284
285                         writer.Write ("\r\n");
286                         writer.Write ("--");
287                         writer.Write (content_type.Boundary);
288                         writer.Write ("\r\n");
289                         writer.Write ("Content-ID: ");
290                         writer.Write (content_type.Parameters ["start"]);
291                         writer.Write ("\r\n");
292                         writer.Write ("Content-Transfer-Encoding: 8bit\r\n");
293                         writer.Write ("Content-Type: application/xop+xml;charset=");
294                         writer.Write (xml_writer_settings.Encoding.HeaderName);
295                         writer.Write (";type=\"");
296                         writer.Write (content_type.Parameters ["start-info"].Replace ("\"", "\\\""));
297                         writer.Write ("\"\r\n\r\n");
298                 }
299
300                 void WriteEndOfMimeSection ()
301                 {
302                         // I'm not sure what's the expected behavior of this
303                         // strange XmlWriter, but so far - it outputs only one
304                         // section.
305                         if (section_count > 1)
306                                 return;
307
308                         w.Flush ();
309                         writer.Write ("\r\n");
310                         writer.Write ("--");
311                         writer.Write (content_type.Boundary);
312                         writer.Write ("--\r\n");
313                 }
314         }
315 }
316