2014-08-13 10:39:27 +01:00
//
// 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.
//
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 ) ;
protected XmlDictionaryWriter ( )
{
}
internal int Depth { get ; set ; }
internal int NSIndex { get ; set ; }
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" ) ;
2015-04-07 09:35:12 +01:00
if ( reader . ReadState = = ReadState . Initial )
reader . Read ( ) ;
2014-08-13 10:39:27 +01:00
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 & & String . IsNullOrEmpty ( namespaceUri ) )
prefix = String . Empty ;
else if ( prefix = = null )
prefix = "d" + Depth + "p" + ( + + NSIndex ) ;
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 ) ;
}
}
}