//
// XmlDictionaryWriter.cs
//
// Author:
// Atsushi Enomoto <atsushi@ximian.com>
//
// Copyright (C) 2005 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.
//
#if NET_2_0
using System;
using System.IO;
using System.Text;
namespace System.Xml{
public abstract partial class XmlDictionaryWriter : XmlWriter
{
static readonly Encoding utf8_unmarked = new UTF8Encoding (false);
int depth;
protected XmlDictionaryWriter ()
{
}
internal int Depth {
get { return depth; }
set { depth = value; }
}
public virtual bool CanCanonicalize {
get { return false; }
}
public static XmlDictionaryWriter CreateBinaryWriter (
Stream stream)
{
return CreateBinaryWriter (stream, null, null, false);
}
public static XmlDictionaryWriter CreateBinaryWriter (
Stream stream, IXmlDictionary dictionary)
{
return CreateBinaryWriter (stream, dictionary, null, false);
}
public static XmlDictionaryWriter CreateBinaryWriter (
Stream stream, IXmlDictionary dictionary,
XmlBinaryWriterSession session)
{
return CreateBinaryWriter (stream, dictionary, session, false);
}
public static XmlDictionaryWriter CreateBinaryWriter (
Stream stream, IXmlDictionary dictionary,
XmlBinaryWriterSession session, bool ownsStream)
{
return new XmlBinaryDictionaryWriter (stream,
dictionary, session, ownsStream);
}
public static XmlDictionaryWriter CreateDictionaryWriter (XmlWriter writer)
{
return new XmlSimpleDictionaryWriter (writer);
}
#if !NET_2_1
public static XmlDictionaryWriter CreateMtomWriter (
Stream stream, Encoding encoding, int maxSizeInBytes,
string startInfo)
{
return CreateMtomWriter (stream, encoding,
maxSizeInBytes, startInfo, Guid.NewGuid () + "id=1", "http://tempuri.org/0/" + DateTime.Now.Ticks, true, false);
}
public static XmlDictionaryWriter CreateMtomWriter (
Stream stream, Encoding encoding, int maxSizeInBytes,
string startInfo, string boundary, string startUri,
bool writeMessageHeaders, bool ownsStream)
{
return new XmlMtomDictionaryWriter (stream, encoding, maxSizeInBytes, startInfo, boundary, startUri, writeMessageHeaders, ownsStream);
}
#endif
public static XmlDictionaryWriter CreateTextWriter (
Stream stream)
{
return CreateTextWriter (stream, Encoding.UTF8);
}
public static XmlDictionaryWriter CreateTextWriter (
Stream stream, Encoding encoding)
{
return CreateTextWriter (stream, encoding, false);
}
// BTW looks like it creates an instance of different
// implementation than those from XmlWriter.Create().
public static XmlDictionaryWriter CreateTextWriter (
Stream stream, Encoding encoding, bool ownsStream)
{
if (stream == null)
throw new ArgumentNullException ("stream");
if (encoding == null)
throw new ArgumentNullException ("encoding");
switch (encoding.CodePage) {
case 1200:
case 1201: // utf-16
case 65001: // utf-8
encoding = utf8_unmarked;
break;
default:
throw new XmlException (String.Format ("XML declaration is required for encoding code page {0} but this XmlWriter does not support XML declaration.", encoding.CodePage));
}
XmlWriterSettings s = new XmlWriterSettings ();
s.Encoding = encoding;
s.CloseOutput = ownsStream;
s.OmitXmlDeclaration = true;
return CreateDictionaryWriter (XmlWriter.Create (stream, s));
}
public virtual void EndCanonicalization ()
{
throw new NotSupportedException ();
}
public virtual void StartCanonicalization (
Stream stream, bool includeComments,
string [] inclusivePrefixes)
{
throw new NotSupportedException ();
}
public void WriteAttributeString (
XmlDictionaryString localName,
XmlDictionaryString namespaceUri,
string value)
{
WriteAttributeString (null, localName, namespaceUri, value);
}
public void WriteAttributeString (string prefix,
XmlDictionaryString localName,
XmlDictionaryString namespaceUri,
string value)
{
WriteStartAttribute (prefix, localName, namespaceUri);
WriteString (value);
WriteEndAttribute ();
}
public void WriteElementString (
XmlDictionaryString localName,
XmlDictionaryString namespaceUri,
string value)
{
WriteElementString (null, localName, namespaceUri, value);
}
public void WriteElementString (string prefix,
XmlDictionaryString localName,
XmlDictionaryString namespaceUri,
string value)
{
WriteStartElement (prefix, localName, namespaceUri);
WriteString (value);
WriteEndElement ();
}
public virtual void WriteNode (XmlDictionaryReader reader,
bool defattr)
{
if (reader == null)
throw new ArgumentNullException ("reader");
switch (reader.NodeType) {
case XmlNodeType.Element:
// gratuitously copied from System.XML/System.Xml/XmlWriter.cs:WriteNode(XmlReader,bool)
// as there doesn't seem to be a way to hook into attribute writing w/o handling Element.
XmlDictionaryString ename, ens;
if (reader.TryGetLocalNameAsDictionaryString (out ename) && reader.TryGetLocalNameAsDictionaryString (out ens))
WriteStartElement (reader.Prefix, ename, ens);
else
WriteStartElement (reader.Prefix, reader.LocalName, reader.NamespaceURI);
// Well, I found that MS.NET took this way, since
// there was a error-prone SgmlReader that fails
// MoveToNextAttribute().
if (reader.HasAttributes) {
for (int i = 0; i < reader.AttributeCount; i++) {
reader.MoveToAttribute (i);
WriteAttribute (reader, defattr);
}
reader.MoveToElement ();
}
if (reader.IsEmptyElement)
WriteEndElement ();
else {
int depth = reader.Depth;
reader.Read ();
if (reader.NodeType != XmlNodeType.EndElement) {
do {
WriteNode (reader, defattr);
} while (depth < reader.Depth);
}
WriteFullEndElement ();
}
reader.Read ();
break;
case XmlNodeType.Attribute:
case XmlNodeType.Text:
WriteTextNode (reader, defattr);
break;
default:
base.WriteNode (reader, defattr);
break;
}
}
private void WriteAttribute (XmlDictionaryReader reader, bool defattr)
{
if (!defattr && reader.IsDefault)
return;
XmlDictionaryString name, ns;
if (reader.TryGetLocalNameAsDictionaryString (out name) && reader.TryGetLocalNameAsDictionaryString (out ns))
WriteStartAttribute (reader.Prefix, name, ns);
else
WriteStartAttribute (reader.Prefix, reader.LocalName, reader.NamespaceURI);
#if NET_2_1
// no ReadAttributeValue() in 2.1 profile.
WriteTextNode (reader, true);
#else
while (reader.ReadAttributeValue ()) {
switch (reader.NodeType) {
case XmlNodeType.Text:
WriteTextNode (reader, true);
break;
case XmlNodeType.EntityReference:
WriteEntityRef (reader.Name);
break;
}
}
#endif
WriteEndAttribute ();
}
public override void WriteNode (XmlReader reader, bool defattr)
{
if (reader == null)
throw new ArgumentNullException ("reader");
XmlDictionaryReader dr = reader as XmlDictionaryReader;
if (dr != null)
WriteNode (dr, defattr);
else
base.WriteNode (reader, defattr);
}
public virtual void WriteQualifiedName (
XmlDictionaryString localName,
XmlDictionaryString namespaceUri)
{
WriteQualifiedName (localName.Value, namespaceUri.Value);
}
public void WriteStartAttribute (
XmlDictionaryString localName,
XmlDictionaryString namespaceUri)
{
WriteStartAttribute (localName.Value, namespaceUri.Value);
}
public virtual void WriteStartAttribute (string prefix,
XmlDictionaryString localName,
XmlDictionaryString namespaceUri)
{
WriteStartAttribute (prefix, localName.Value, namespaceUri.Value);
}
public void WriteStartElement (
XmlDictionaryString localName,
XmlDictionaryString namespaceUri)
{
WriteStartElement (null, localName, namespaceUri);
}
public virtual void WriteStartElement (string prefix,
XmlDictionaryString localName,
XmlDictionaryString namespaceUri)
{
if (localName == null)
throw new ArgumentException ("localName must not be null.", "localName");
WriteStartElement (prefix, localName.Value,
namespaceUri != null ? namespaceUri.Value : null);
}
public virtual void WriteString (XmlDictionaryString value)
{
WriteString (value.Value);
}
protected virtual void WriteTextNode (XmlDictionaryReader reader, bool isAttribute)
{
WriteString (reader.Value);
if (!isAttribute)
reader.Read ();
}
public virtual void WriteValue (Guid guid)
{
WriteString (guid.ToString ());
}
public virtual void WriteValue (IStreamProvider value)
{
if (value == null)
throw new ArgumentNullException ("value");
Stream stream = value.GetStream ();
byte[] buf = new byte [Math.Min (2048, stream.CanSeek ? stream.Length : 2048)];
int read;
while ((read = stream.Read (buf, 0, buf.Length)) > 0) {
WriteBase64 (buf, 0, read);
}
value.ReleaseStream (stream);
}
public virtual void WriteValue (TimeSpan duration)
{
WriteString (XmlConvert.ToString (duration));
}
public virtual void WriteValue (UniqueId id)
{
if (id == null)
throw new ArgumentNullException ("id");
WriteString (id.ToString ());
}
public virtual void WriteValue (XmlDictionaryString value)
{
WriteValue (value.Value);
}
public virtual void WriteXmlAttribute (string localName, string value)
{
WriteAttributeString ("xml", localName, "http://www.w3.org/XML/1998/namespace", value);
}
public virtual void WriteXmlAttribute (XmlDictionaryString localName,
XmlDictionaryString value)
{
WriteXmlAttribute (localName.Value, value.Value);
}
public virtual void WriteXmlnsAttribute (
string prefix, string namespaceUri)
{
// BTW .NET 2.0 those XmlWriters from XmlWrite.Create()
// rejects namespace overriding i.e.
//
// xw.WriteStartElement ("foo", "urn:foo");
// xw.WriteXmlnsAttribute ("foo", "urn:bar");
//
// causes an XmlException. We need fix in sys.xml.dll
// When the prefix is null, this writer must mock
// a dummy namespace up. It is then up to the actual
// writer how it is determined in the output. (When
// there is a duplicate, then it will be further
// modified.)
if (prefix == null)
prefix = "d" + Depth + "p1";
if (prefix == String.Empty)
WriteAttributeString ("xmlns", namespaceUri);
else
WriteAttributeString ("xmlns", prefix, "http://www.w3.org/2000/xmlns/", namespaceUri);
}
public virtual void WriteXmlnsAttribute (string prefix,
XmlDictionaryString namespaceUri)
{
WriteXmlnsAttribute (prefix, namespaceUri.Value);
}
}
}
#endif
|