2010-01-20 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mcs / class / System.Runtime.Serialization / System.Xml / XmlDictionaryWriter.cs
1 //
2 // XmlDictionaryWriter.cs
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2005 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 #if NET_2_0
29 using System;
30 using System.IO;
31 using System.Text;
32
33 namespace System.Xml
34 {
35         public abstract partial class XmlDictionaryWriter : XmlWriter
36         {
37                 static readonly Encoding utf8_unmarked = new UTF8Encoding (false);
38
39                 int depth;
40
41                 protected XmlDictionaryWriter ()
42                 {
43                 }
44
45                 internal int Depth {
46                         get { return depth; }
47                         set { depth = value; }
48                 }
49
50                 public virtual bool CanCanonicalize {
51                         get { return false; }
52                 }
53
54                 public static XmlDictionaryWriter CreateBinaryWriter (
55                         Stream stream)
56                 {
57                         return CreateBinaryWriter (stream, null, null, false);
58                 }
59
60                 public static XmlDictionaryWriter CreateBinaryWriter (
61                         Stream stream, IXmlDictionary dictionary)
62                 {
63                         return CreateBinaryWriter (stream, dictionary, null, false);
64                 }
65
66                 public static XmlDictionaryWriter CreateBinaryWriter (
67                         Stream stream, IXmlDictionary dictionary,
68                         XmlBinaryWriterSession session)
69                 {
70                         return CreateBinaryWriter (stream, dictionary, session, false);
71                 }
72
73                 public static XmlDictionaryWriter CreateBinaryWriter (
74                         Stream stream, IXmlDictionary dictionary,
75                         XmlBinaryWriterSession session, bool ownsStream)
76                 {
77                         return new XmlBinaryDictionaryWriter (stream,
78                                 dictionary, session, ownsStream);
79                 }
80
81                 public static XmlDictionaryWriter CreateDictionaryWriter (XmlWriter writer)
82                 {
83                         return new XmlSimpleDictionaryWriter (writer);
84                 }
85 #if !NET_2_1
86                 public static XmlDictionaryWriter CreateMtomWriter (
87                         Stream stream, Encoding encoding, int maxSizeInBytes,
88                         string startInfo)
89                 {
90                         return CreateMtomWriter (stream, encoding,
91                                 maxSizeInBytes, startInfo, Guid.NewGuid () + "id=1", "http://tempuri.org/0/" + DateTime.Now.Ticks, true, false);
92                 }
93
94                 public static XmlDictionaryWriter CreateMtomWriter (
95                         Stream stream, Encoding encoding, int maxSizeInBytes,
96                         string startInfo, string boundary, string startUri,
97                         bool writeMessageHeaders, bool ownsStream)
98                 {
99                         return new XmlMtomDictionaryWriter (stream, encoding, maxSizeInBytes, startInfo, boundary, startUri, writeMessageHeaders, ownsStream);
100                 }
101 #endif
102                 public static XmlDictionaryWriter CreateTextWriter (
103                         Stream stream)
104                 {
105                         return CreateTextWriter (stream, Encoding.UTF8);
106                 }
107
108                 public static XmlDictionaryWriter CreateTextWriter (
109                         Stream stream, Encoding encoding)
110                 {
111                         return CreateTextWriter (stream, encoding, false);
112                 }
113
114                 // BTW looks like it creates an instance of different
115                 // implementation than those from XmlWriter.Create().
116                 public static XmlDictionaryWriter CreateTextWriter (
117                         Stream stream, Encoding encoding, bool ownsStream)
118                 {
119                         if (stream == null)
120                                 throw new ArgumentNullException ("stream");
121                         if (encoding == null)
122                                 throw new ArgumentNullException ("encoding");
123
124                         switch (encoding.CodePage) {
125                         case 1200:
126                         case 1201: // utf-16
127                         case 65001: // utf-8
128                                 encoding = utf8_unmarked;
129                                 break;
130                         default:
131                                 throw new XmlException (String.Format ("XML declaration is required for encoding code page {0} but this XmlWriter does not support XML declaration.", encoding.CodePage));
132                         }
133
134                         XmlWriterSettings s = new XmlWriterSettings ();
135                         s.Encoding = encoding;
136                         s.CloseOutput = ownsStream;
137                         s.OmitXmlDeclaration = true;
138                         return CreateDictionaryWriter (XmlWriter.Create (stream, s));
139                 }
140
141                 public virtual void EndCanonicalization ()
142                 {
143                         throw new NotSupportedException ();
144                 }
145
146                 public virtual void StartCanonicalization (
147                         Stream stream, bool includeComments,
148                         string [] inclusivePrefixes)
149                 {
150                         throw new NotSupportedException ();
151                 }
152
153                 public void WriteAttributeString (
154                         XmlDictionaryString localName,
155                         XmlDictionaryString namespaceUri,
156                         string value)
157                 {
158                         WriteAttributeString (null, localName, namespaceUri, value);
159                 }
160
161                 public void WriteAttributeString (string prefix,
162                         XmlDictionaryString localName,
163                         XmlDictionaryString namespaceUri,
164                         string value)
165                 {
166                         WriteStartAttribute (prefix, localName, namespaceUri);
167                         WriteString (value);
168                         WriteEndAttribute ();
169                 }
170
171                 public void WriteElementString (
172                         XmlDictionaryString localName,
173                         XmlDictionaryString namespaceUri,
174                         string value)
175                 {
176                         WriteElementString (null, localName, namespaceUri, value);
177                 }
178
179                 public void WriteElementString (string prefix,
180                         XmlDictionaryString localName,
181                         XmlDictionaryString namespaceUri,
182                         string value)
183                 {
184                         WriteStartElement (prefix, localName, namespaceUri);
185                         WriteString (value);
186                         WriteEndElement ();
187                 }
188
189                 [MonoTODO ("make use of dictionary reader optimization")]
190                 public virtual void WriteNode (XmlDictionaryReader reader,
191                         bool defattr)
192                 {
193                         if (reader == null)
194                                 throw new ArgumentNullException ("reader");
195
196                         switch (reader.NodeType) {
197                         case XmlNodeType.Element:
198                                 // gratuitously copied from System.XML/System.Xml/XmlWriter.cs:WriteNode(XmlReader,bool)
199                                 // as there doesn't seem to be a way to hook into attribute writing w/o handling Element.
200                                 WriteStartElement (reader.Prefix, reader.LocalName, reader.NamespaceURI);
201                                 // Well, I found that MS.NET took this way, since
202                                 // there was a error-prone SgmlReader that fails
203                                 // MoveToNextAttribute().
204                                 if (reader.HasAttributes) {
205                                         for (int i = 0; i < reader.AttributeCount; i++) {
206                                                 reader.MoveToAttribute (i);
207                                                 WriteAttribute (reader, defattr);
208                                         }
209                                         reader.MoveToElement ();
210                                 }
211                                 if (reader.IsEmptyElement)
212                                         WriteEndElement ();
213                                 else {
214                                         int depth = reader.Depth;
215                                         reader.Read ();
216                                         if (reader.NodeType != XmlNodeType.EndElement) {
217                                                 do {
218                                                         WriteNode (reader, defattr);
219                                                 } while (depth < reader.Depth);
220                                         }
221                                         WriteFullEndElement ();
222                                 }
223                                 reader.Read ();
224                                 break;
225                         case XmlNodeType.Attribute:
226                         case XmlNodeType.Text:
227                                 WriteTextNode (reader, defattr);
228                                 break;
229                         default:
230                                 base.WriteNode (reader, defattr);
231                                 break;
232                         }
233                 }
234
235                 private void WriteAttribute (XmlDictionaryReader reader, bool defattr)
236                 {
237                         if (!defattr && reader.IsDefault)
238                                 return;
239
240                         WriteStartAttribute (reader.Prefix, reader.LocalName, reader.NamespaceURI);
241 #if NET_2_1
242                         // no ReadAttributeValue() in 2.1 profile.
243                         WriteTextNode (reader, true);
244 #else
245                         while (reader.ReadAttributeValue ()) {
246                                 switch (reader.NodeType) {
247                                 case XmlNodeType.Text:
248                                         WriteTextNode (reader, true);
249                                         break;
250                                 case XmlNodeType.EntityReference:
251                                         WriteEntityRef (reader.Name);
252                                         break;
253                                 }
254                         }
255 #endif
256                         WriteEndAttribute ();
257                 }
258
259                 public override void WriteNode (XmlReader reader, bool defattr)
260                 {
261                         if (reader == null)
262                                 throw new ArgumentNullException ("reader");
263
264                         XmlDictionaryReader dr = reader as XmlDictionaryReader;
265                         if (dr != null)
266                                 WriteNode (dr, defattr);
267                         else
268                                 base.WriteNode (reader, defattr);
269                 }
270
271                 public virtual void WriteQualifiedName (
272                         XmlDictionaryString localName,
273                         XmlDictionaryString namespaceUri)
274                 {
275                         WriteQualifiedName (localName.Value, namespaceUri.Value);
276                 }
277
278                 public void WriteStartAttribute (
279                         XmlDictionaryString localName,
280                         XmlDictionaryString namespaceUri)
281                 {
282                         WriteStartAttribute (localName.Value, namespaceUri.Value);
283                 }
284
285                 public virtual void WriteStartAttribute (string prefix,
286                         XmlDictionaryString localName,
287                         XmlDictionaryString namespaceUri)
288                 {
289                         WriteStartAttribute (prefix, localName.Value, namespaceUri.Value);
290                 }
291
292                 public void WriteStartElement (
293                         XmlDictionaryString localName,
294                         XmlDictionaryString namespaceUri)
295                 {
296                         WriteStartElement (null, localName, namespaceUri);
297                 }
298
299                 public virtual void WriteStartElement (string prefix,
300                         XmlDictionaryString localName,
301                         XmlDictionaryString namespaceUri)
302                 {
303                         if (localName == null)
304                                 throw new ArgumentException ("localName must not be null.", "localName");
305                         WriteStartElement (prefix, localName.Value,
306                                         namespaceUri != null ? namespaceUri.Value : null);
307                 }
308
309                 public virtual void WriteString (XmlDictionaryString value)
310                 {
311                         WriteString (value.Value);
312                 }
313
314                 protected virtual void WriteTextNode (XmlDictionaryReader reader, bool isAttribute)
315                 {
316                         WriteString (reader.Value);
317                         if (!isAttribute)
318                                 reader.Read ();
319                 }
320
321                 public virtual void WriteValue (Guid guid)
322                 {
323                         WriteString (guid.ToString ());
324                 }
325
326                 public virtual void WriteValue (IStreamProvider value)
327                 {
328                         if (value == null)
329                                 throw new ArgumentNullException ("value");
330
331                         Stream stream = value.GetStream ();
332                         byte[] buf = new byte [Math.Min (2048, stream.CanSeek ? stream.Length : 2048)];
333                         int read;
334                         while ((read = stream.Read (buf, 0, buf.Length)) > 0) {
335                                 WriteBase64 (buf, 0, read);
336                         }
337                         value.ReleaseStream (stream);
338                 }
339
340                 public virtual void WriteValue (TimeSpan duration)
341                 {
342                         WriteString (XmlConvert.ToString (duration));
343                 }
344
345                 public virtual void WriteValue (UniqueId id)
346                 {
347                         if (id == null)
348                                 throw new ArgumentNullException ("id");
349                         WriteString (id.ToString ());
350                 }
351
352                 public virtual void WriteValue (XmlDictionaryString value)
353                 {
354                         WriteValue (value.Value);
355                 }
356
357                 public virtual void WriteXmlAttribute (string localName, string value)
358                 {
359                         WriteAttributeString ("xml", localName, "http://www.w3.org/XML/1998/namespace", value);
360                 }
361
362                 public virtual void WriteXmlAttribute (XmlDictionaryString localName,
363                         XmlDictionaryString value)
364                 {
365                         WriteXmlAttribute (localName.Value, value.Value);
366                 }
367
368                 public virtual void WriteXmlnsAttribute (
369                         string prefix, string namespaceUri)
370                 {
371                         // BTW .NET 2.0 those XmlWriters from XmlWrite.Create()
372                         // rejects namespace overriding i.e.
373                         //
374                         //      xw.WriteStartElement ("foo", "urn:foo");
375                         //      xw.WriteXmlnsAttribute ("foo", "urn:bar");
376                         //
377                         // causes an XmlException. We need fix in sys.xml.dll
378
379                         // When the prefix is null, this writer must mock
380                         // a dummy namespace up. It is then up to the actual
381                         // writer how it is determined in the output. (When
382                         // there is a duplicate, then it will be further 
383                         // modified.)
384                         if (prefix == null)
385                                 prefix = "d" + Depth + "p1";
386
387                         if (prefix == String.Empty)
388                                 WriteAttributeString ("xmlns", namespaceUri);
389                         else
390                                 WriteAttributeString ("xmlns", prefix, "http://www.w3.org/2000/xmlns/", namespaceUri);
391                 }
392
393                 public virtual void WriteXmlnsAttribute (string prefix,
394                         XmlDictionaryString namespaceUri)
395                 {
396                         WriteXmlnsAttribute (prefix, namespaceUri.Value);
397                 }
398         }
399 }
400 #endif