2009-06-12 Bill Holmes <billholmes54@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
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
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                                 reader.Read ();
212                                 WriteNode (reader, defattr);
213                                 break;
214                         case XmlNodeType.Attribute:
215                         case XmlNodeType.Text:
216                                 WriteTextNode (reader, defattr);
217                                 break;
218                         default:
219                                 base.WriteNode (reader, defattr);
220                                 break;
221                         }
222                 }
223
224                 private void WriteAttribute (XmlDictionaryReader reader, bool defattr)
225                 {
226                         if (!defattr && reader.IsDefault)
227                                 return;
228
229                         WriteStartAttribute (reader.Prefix, reader.LocalName, reader.NamespaceURI);
230 #if NET_2_1
231                         // no ReadAttributeValue() in 2.1 profile.
232                         WriteTextNode (reader, true);
233 #else
234                         while (reader.ReadAttributeValue ()) {
235                                 switch (reader.NodeType) {
236                                 case XmlNodeType.Text:
237                                         WriteTextNode (reader, true);
238                                         break;
239                                 case XmlNodeType.EntityReference:
240                                         WriteEntityRef (reader.Name);
241                                         break;
242                                 }
243                         }
244 #endif
245                         WriteEndAttribute ();
246                 }
247
248                 public override void WriteNode (XmlReader reader, bool defattr)
249                 {
250                         if (reader == null)
251                                 throw new ArgumentNullException ("reader");
252
253                         XmlDictionaryReader dr = reader as XmlDictionaryReader;
254                         if (dr != null)
255                                 WriteNode (dr, defattr);
256                         else
257                                 base.WriteNode (reader, defattr);
258                 }
259
260                 public virtual void WriteQualifiedName (
261                         XmlDictionaryString localName,
262                         XmlDictionaryString namespaceUri)
263                 {
264                         WriteQualifiedName (localName.Value, namespaceUri.Value);
265                 }
266
267                 public void WriteStartAttribute (
268                         XmlDictionaryString localName,
269                         XmlDictionaryString namespaceUri)
270                 {
271                         WriteStartAttribute (localName.Value, namespaceUri.Value);
272                 }
273
274                 public virtual void WriteStartAttribute (string prefix,
275                         XmlDictionaryString localName,
276                         XmlDictionaryString namespaceUri)
277                 {
278                         WriteStartAttribute (prefix, localName.Value, namespaceUri.Value);
279                 }
280
281                 public void WriteStartElement (
282                         XmlDictionaryString localName,
283                         XmlDictionaryString namespaceUri)
284                 {
285                         WriteStartElement (null, localName, namespaceUri);
286                 }
287
288                 public virtual void WriteStartElement (string prefix,
289                         XmlDictionaryString localName,
290                         XmlDictionaryString namespaceUri)
291                 {
292                         if (localName == null)
293                                 throw new ArgumentException ("localName must not be null.", "localName");
294                         WriteStartElement (prefix, localName.Value,
295                                         namespaceUri != null ? namespaceUri.Value : null);
296                 }
297
298                 public virtual void WriteString (XmlDictionaryString value)
299                 {
300                         WriteString (value.Value);
301                 }
302
303                 protected virtual void WriteTextNode (XmlDictionaryReader reader, bool isAttribute)
304                 {
305                         WriteString (reader.Value);
306                         if (!isAttribute)
307                                 reader.Read ();
308                 }
309
310                 public virtual void WriteValue (Guid guid)
311                 {
312                         WriteString (guid.ToString ());
313                 }
314
315                 public virtual void WriteValue (IStreamProvider value)
316                 {
317                         if (value == null)
318                                 throw new ArgumentNullException ("value");
319
320                         Stream stream = value.GetStream ();
321                         byte[] buf = new byte [Math.Min (2048, stream.CanSeek ? stream.Length : 2048)];
322                         int read;
323                         while ((read = stream.Read (buf, 0, buf.Length)) > 0) {
324                                 WriteBase64 (buf, 0, read);
325                         }
326                         value.ReleaseStream (stream);
327                 }
328
329                 public virtual void WriteValue (TimeSpan duration)
330                 {
331                         WriteString (XmlConvert.ToString (duration));
332                 }
333
334                 public virtual void WriteValue (UniqueId id)
335                 {
336                         if (id == null)
337                                 throw new ArgumentNullException ("id");
338                         WriteString (id.ToString ());
339                 }
340
341                 public virtual void WriteValue (XmlDictionaryString value)
342                 {
343                         WriteValue (value.Value);
344                 }
345
346                 public virtual void WriteXmlAttribute (string localName, string value)
347                 {
348                         WriteAttributeString ("xml", localName, "http://www.w3.org/XML/1998/namespace", value);
349                 }
350
351                 public virtual void WriteXmlAttribute (XmlDictionaryString localName,
352                         XmlDictionaryString value)
353                 {
354                         WriteXmlAttribute (localName.Value, value.Value);
355                 }
356
357                 public virtual void WriteXmlnsAttribute (
358                         string prefix, string namespaceUri)
359                 {
360                         // BTW .NET 2.0 those XmlWriters from XmlWrite.Create()
361                         // rejects namespace overriding i.e.
362                         //
363                         //      xw.WriteStartElement ("foo", "urn:foo");
364                         //      xw.WriteXmlnsAttribute ("foo", "urn:bar");
365                         //
366                         // causes an XmlException. We need fix in sys.xml.dll
367
368                         // When the prefix is null, this writer must mock
369                         // a dummy namespace up. It is then up to the actual
370                         // writer how it is determined in the output. (When
371                         // there is a duplicate, then it will be further 
372                         // modified.)
373                         if (prefix == null)
374                                 prefix = "d" + Depth + "p1";
375
376                         if (prefix == String.Empty)
377                                 WriteAttributeString ("xmlns", namespaceUri);
378                         else
379                                 WriteAttributeString ("xmlns", prefix, "http://www.w3.org/2000/xmlns/", namespaceUri);
380                 }
381
382                 public virtual void WriteXmlnsAttribute (string prefix,
383                         XmlDictionaryString namespaceUri)
384                 {
385                         WriteXmlnsAttribute (prefix, namespaceUri.Value);
386                 }
387         }
388 }
389 #endif