XmlTextWriter.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / Xml / System / Xml / Core / XmlTextWriter.cs / 1 / XmlTextWriter.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
using System; 
using System.Collections;
using System.Collections.Generic; 
using System.IO;
using System.Text;
using System.Diagnostics;
using System.Globalization; 

namespace System.Xml { 
 
    // Specifies formatting options for XmlTextWriter.
    public enum Formatting { 
        // No special formatting is done (this is the default).
        None,

        //This option causes child elements to be indented using the Indentation and IndentChar properties. 
        // It only indents Element Content (http://www.w3.org/TR/1998/REC-xml-19980210#sec-element-content)
        // and not Mixed Content (http://www.w3.org/TR/1998/REC-xml-19980210#sec-mixed-content) 
        // according to the XML 1.0 definitions of these terms. 
        Indented,
    }; 

    // Represents a writer that provides fast non-cached forward-only way of generating XML streams
    // containing XML documents that conform to the W3CExtensible Markup Language (XML) 1.0 specification
    // and the Namespaces in XML specification. 
    public class XmlTextWriter : XmlWriter {
// 
// Private types 
//
        enum NamespaceState { 
            Uninitialized,
            NotDeclaredButInScope,
            DeclaredButNotWrittenOut,
            DeclaredAndWrittenOut 
        }
 
        struct TagInfo { 
            internal string name;
            internal string prefix; 
            internal string defaultNs;
            internal NamespaceState defaultNsState;
            internal XmlSpace xmlSpace;
            internal string xmlLang; 
            internal int prevNsTop;
            internal int prefixCount; 
            internal bool mixed; // whether to pretty print the contents of this element. 

            internal void Init( int nsTop ) { 
                name = null;
                defaultNs = String.Empty;
                defaultNsState = NamespaceState.Uninitialized;
                xmlSpace = XmlSpace.None; 
                xmlLang = null;
                prevNsTop = nsTop; 
                prefixCount = 0; 
                mixed = false;
            } 
        }

        struct Namespace {
            internal string prefix; 
            internal string ns;
            internal bool   declared; 
            internal int prevNsIndex; 

            internal void Set( string prefix, string ns, bool declared ) { 
                this.prefix = prefix;
                this.ns = ns;
                this.declared = declared;
                this.prevNsIndex = -1; 
            }
        } 
 
        enum SpecialAttr {
            None, 
            XmlSpace,
            XmlLang,
            XmlNs
        }; 

        // State machine is working through autocomplete 
        private enum State { 
            Start,
            Prolog, 
            PostDTD,
            Element,
            Attribute,
            Content, 
            AttrOnly,
            Epilog, 
            Error, 
            Closed,
        } 

        private enum Token {
            PI,
            Doctype, 
            Comment,
            CData, 
            StartElement, 
            EndElement,
            LongEndElement, 
            StartAttribute,
            EndAttribute,
            Content,
            Base64, 
            RawData,
            Whitespace, 
            Empty 
        }
 
//
// Fields
//
        // output 
        TextWriter textWriter;
        XmlTextEncoder xmlEncoder; 
        Encoding encoding; 

        // formatting 
        Formatting formatting;
        bool indented; // perf - faster to check a boolean.
        int  indentation;
        char indentChar; 

        // element stack 
        TagInfo[] stack; 
        int top;
 
        // state machine for AutoComplete
        State[] stateTable;
        State currentState;
        Token lastToken; 

        // Base64 content 
        XmlTextWriterBase64Encoder base64Encoder; 

        // misc 
        char quoteChar;
        char curQuoteChar;
        bool namespaces;
        SpecialAttr specialAttr; 
        string prefixForXmlNs;
        bool flush; 
 
        // namespaces
        Namespace[] nsStack; 
        int nsTop;
        Dictionary nsHashtable;
        bool useNsHashtable;
 
        // char types
        XmlCharType xmlCharType = XmlCharType.Instance; 
 
//
// Constants and constant tables 
//
        const int NamespaceStackInitialSize = 8;
#if DEBUG
        const int MaxNamespacesWalkCount = 3; 
#else
        const int MaxNamespacesWalkCount = 16; 
#endif 

        static string[] stateName = { 
            "Start",
            "Prolog",
            "PostDTD",
            "Element", 
            "Attribute",
            "Content", 
            "AttrOnly", 
            "Epilog",
            "Error", 
            "Closed",
        };

        static string[] tokenName = { 
            "PI",
            "Doctype", 
            "Comment", 
            "CData",
            "StartElement", 
            "EndElement",
            "LongEndElement",
            "StartAttribute",
            "EndAttribute", 
            "Content",
            "Base64", 
            "RawData", 
            "Whitespace",
            "Empty" 
        };

        static readonly State[] stateTableDefault = {
            //                          State.Start      State.Prolog     State.PostDTD    State.Element    State.Attribute  State.Content   State.AttrOnly   State.Epilog 
            //
            /* Token.PI             */ State.Prolog,    State.Prolog,    State.PostDTD,   State.Content,   State.Content,   State.Content,  State.Error,     State.Epilog, 
            /* Token.Doctype        */ State.PostDTD,   State.PostDTD,   State.Error,     State.Error,     State.Error,     State.Error,    State.Error,     State.Error, 
            /* Token.Comment        */ State.Prolog,    State.Prolog,    State.PostDTD,   State.Content,   State.Content,   State.Content,  State.Error,     State.Epilog,
            /* Token.CData          */ State.Content,   State.Content,   State.Error,     State.Content,   State.Content,   State.Content,  State.Error,     State.Epilog, 
            /* Token.StartElement   */ State.Element,   State.Element,   State.Element,   State.Element,   State.Element,   State.Element,  State.Error,     State.Element,
            /* Token.EndElement     */ State.Error,     State.Error,     State.Error,     State.Content,   State.Content,   State.Content,  State.Error,     State.Error,
            /* Token.LongEndElement */ State.Error,     State.Error,     State.Error,     State.Content,   State.Content,   State.Content,  State.Error,     State.Error,
            /* Token.StartAttribute */ State.AttrOnly,  State.Error,     State.Error,     State.Attribute, State.Attribute, State.Error,    State.Error,     State.Error, 
            /* Token.EndAttribute   */ State.Error,     State.Error,     State.Error,     State.Error,     State.Element,   State.Error,    State.Epilog,     State.Error,
            /* Token.Content        */ State.Content,   State.Content,   State.Error,     State.Content,   State.Attribute, State.Content,  State.Attribute, State.Epilog, 
            /* Token.Base64         */ State.Content,   State.Content,   State.Error,     State.Content,   State.Attribute, State.Content,  State.Attribute, State.Epilog, 
            /* Token.RawData        */ State.Prolog,    State.Prolog,    State.PostDTD,   State.Content,   State.Attribute, State.Content,  State.Attribute, State.Epilog,
            /* Token.Whitespace     */ State.Prolog,    State.Prolog,    State.PostDTD,   State.Content,   State.Attribute, State.Content,  State.Attribute, State.Epilog, 
        };

        static readonly State[] stateTableDocument = {
            //                          State.Start      State.Prolog     State.PostDTD    State.Element    State.Attribute  State.Content   State.AttrOnly   State.Epilog 
            //
            /* Token.PI             */ State.Error,     State.Prolog,    State.PostDTD,   State.Content,   State.Content,   State.Content,  State.Error,     State.Epilog, 
            /* Token.Doctype        */ State.Error,     State.PostDTD,   State.Error,     State.Error,     State.Error,     State.Error,    State.Error,     State.Error, 
            /* Token.Comment        */ State.Error,     State.Prolog,    State.PostDTD,   State.Content,   State.Content,   State.Content,  State.Error,     State.Epilog,
            /* Token.CData          */ State.Error,     State.Error,     State.Error,     State.Content,   State.Content,   State.Content,  State.Error,     State.Error, 
            /* Token.StartElement   */ State.Error,     State.Element,   State.Element,   State.Element,   State.Element,   State.Element,  State.Error,     State.Error,
            /* Token.EndElement     */ State.Error,     State.Error,     State.Error,     State.Content,   State.Content,   State.Content,  State.Error,     State.Error,
            /* Token.LongEndElement */ State.Error,     State.Error,     State.Error,     State.Content,   State.Content,   State.Content,  State.Error,     State.Error,
            /* Token.StartAttribute */ State.Error,     State.Error,     State.Error,     State.Attribute, State.Attribute, State.Error,    State.Error,     State.Error, 
            /* Token.EndAttribute   */ State.Error,     State.Error,     State.Error,     State.Error,     State.Element,   State.Error,    State.Error,     State.Error,
            /* Token.Content        */ State.Error,     State.Error,     State.Error,     State.Content,   State.Attribute, State.Content,  State.Error,     State.Error, 
            /* Token.Base64         */ State.Error,     State.Error,     State.Error,     State.Content,   State.Attribute, State.Content,  State.Error,     State.Error, 
            /* Token.RawData        */ State.Error,     State.Prolog,    State.PostDTD,   State.Content,   State.Attribute, State.Content,  State.Error,     State.Epilog,
            /* Token.Whitespace     */ State.Error,     State.Prolog,    State.PostDTD,   State.Content,   State.Attribute, State.Content,  State.Error,     State.Epilog, 
        };

//
// Constructors 
//
        internal XmlTextWriter() { 
            namespaces = true; 
            formatting = Formatting.None;
            indentation = 2; 
            indentChar = ' ';
            // namespaces
            nsStack = new Namespace[NamespaceStackInitialSize];
            nsTop = -1; 
            // element stack
            stack = new TagInfo[10]; 
            top = 0;// 0 is an empty sentanial element 
            stack[top].Init( -1 );
            quoteChar = '"'; 

            stateTable = stateTableDefault;
            currentState = State.Start;
            lastToken = Token.Empty; 
        }
 
        // Creates an instance of the XmlTextWriter class using the specified stream. 
        public XmlTextWriter(Stream w, Encoding encoding) : this() {
            this.encoding = encoding; 
            if (encoding != null)
                textWriter = new StreamWriter(w, encoding);
            else
                textWriter = new StreamWriter(w); 
            xmlEncoder = new XmlTextEncoder(textWriter);
            xmlEncoder.QuoteChar = this.quoteChar; 
        } 

        // Creates an instance of the XmlTextWriter class using the specified file. 
        public XmlTextWriter(String filename, Encoding encoding)
        : this(new FileStream(filename, FileMode.Create,
                              FileAccess.Write, FileShare.Read), encoding) {
        } 

        // Creates an instance of the XmlTextWriter class using the specified TextWriter. 
        public XmlTextWriter(TextWriter w) : this() { 
            textWriter = w;
 
            encoding = w.Encoding;
            xmlEncoder = new XmlTextEncoder(w);
            xmlEncoder.QuoteChar = this.quoteChar;
        } 

// 
// XmlTextWriter properties 
//
        // Gets the XmlTextWriter base stream. 
        public Stream BaseStream  {
            get {
                StreamWriter streamWriter = textWriter as StreamWriter;
                return (streamWriter == null ? null : streamWriter.BaseStream); 
            }
        } 
 
        // Gets or sets a value indicating whether to do namespace support.
        public bool Namespaces { 
            get { return this.namespaces;}
            set {
                if (this.currentState != State.Start)
                    throw new InvalidOperationException(Res.GetString(Res.Xml_NotInWriteState)); 

                this.namespaces = value; 
            } 
        }
 
        // Indicates how the output is formatted.
        public Formatting Formatting {
            get { return this.formatting;}
            set { this.formatting = value; this.indented = value == Formatting.Indented;} 
        }
 
        // Gets or sets how many IndentChars to write for each level in the hierarchy when Formatting is set to "Indented". 
        public int Indentation {
            get { return this.indentation;} 
            set {
                if (value < 0)
                    throw new ArgumentException(Res.GetString(Res.Xml_InvalidIndentation));
                this.indentation = value; 
            }
        } 
 
        // Gets or sets which character to use for indenting when Formatting is set to "Indented".
        public char IndentChar { 
            get { return this.indentChar;}
            set { this.indentChar = value;}
        }
 
        // Gets or sets which character to use to quote attribute values.
        public char QuoteChar { 
            get { return this.quoteChar;} 
            set {
                if (value != '"' && value != '\'') { 
                    throw new ArgumentException(Res.GetString(Res.Xml_InvalidQuote));
                }
                this.quoteChar = value;
                this.xmlEncoder.QuoteChar = value; 
            }
        } 
 
//
// XmlWriter implementation 
//
        // Writes out the XML declaration with the version "1.0".
        public override void WriteStartDocument() {
            StartDocument(-1); 
        }
 
        // Writes out the XML declaration with the version "1.0" and the standalone attribute. 
        public override void WriteStartDocument(bool standalone) {
            StartDocument(standalone ? 1 : 0); 
        }

        // Closes any open elements or attributes and puts the writer back in the Start state.
        public override void WriteEndDocument() { 
            try {
                AutoCompleteAll(); 
                if (this.currentState != State.Epilog) { 
                    throw new ArgumentException(Res.GetString(Res.Xml_NoRoot));
                } 
                this.stateTable = stateTableDefault;
                this.currentState = State.Start;
                this.lastToken = Token.Empty;
            } 
            catch {
                currentState = State.Error; 
                throw; 
            }
        } 

        // Writes out the DOCTYPE declaration with the specified name and optional attributes.
        public override void WriteDocType(string name, string pubid, string sysid, string subset) {
            try { 
                ValidateName(name, false);
 
                AutoComplete(Token.Doctype); 
                textWriter.Write("'); 
            }
            catch {
                currentState = State.Error;
                throw; 
            }
        } 
 
        // Writes out the specified start tag and associates it with the given namespace and prefix.
        public override void WriteStartElement(string prefix, string localName, string ns) { 
            try {
                AutoComplete(Token.StartElement);
                PushStack();
                textWriter.Write('<'); 

                if (this.namespaces) { 
                    // Propagate default namespace and mix model down the stack. 
                    stack[top].defaultNs = stack[top-1].defaultNs;
                    if (stack[top-1].defaultNsState != NamespaceState.Uninitialized) 
                        stack[top].defaultNsState = NamespaceState.NotDeclaredButInScope;
                    stack[top].mixed = stack[top-1].mixed;
                    if (ns == null) {
                        // use defined prefix 
                        if (prefix != null && prefix.Length != 0 && (LookupNamespace(prefix) == -1)) {
                            throw new ArgumentException(Res.GetString(Res.Xml_UndefPrefix)); 
                        } 
                    }
                    else { 
                        if (prefix == null) {
                            string definedPrefix = FindPrefix(ns);
                            if (definedPrefix != null) {
                                prefix = definedPrefix; 
                            }
                            else { 
                                PushNamespace(null, ns, false); // new default 
                            }
                        } 
                        else if (prefix.Length == 0) {
                            PushNamespace(null, ns, false); // new default
                        }
                        else { 
                            if (ns.Length == 0) {
                                prefix = null; 
                            } 
                            VerifyPrefixXml(prefix, ns);
                            PushNamespace(prefix, ns, false); // define 
                        }
                    }
                    stack[top].prefix = null;
                    if (prefix != null && prefix.Length != 0) { 
                        stack[top].prefix = prefix;
                        textWriter.Write(prefix); 
                        textWriter.Write(':'); 
                    }
                } 
                else {
                    if ((ns != null && ns.Length != 0) || (prefix != null && prefix.Length != 0)) {
                        throw new ArgumentException(Res.GetString(Res.Xml_NoNamespaces));
                    } 
                }
                stack[top].name = localName; 
                textWriter.Write(localName); 
            }
            catch { 
                currentState = State.Error;
                throw;
            }
        } 

        // Closes one element and pops the corresponding namespace scope. 
        public override  void WriteEndElement() { 
            InternalWriteEndElement(false);
        } 

        // Closes one element and pops the corresponding namespace scope.
        public override  void WriteFullEndElement() {
            InternalWriteEndElement(true); 
        }
 
        // Writes the start of an attribute. 
        public override  void WriteStartAttribute(string prefix, string localName, string ns) {
            try { 
                AutoComplete(Token.StartAttribute);

                this.specialAttr = SpecialAttr.None;
                if (this.namespaces) { 

                    if (prefix != null && prefix.Length == 0) { 
                        prefix = null; 
                    }
 
                    if (ns == XmlReservedNs.NsXmlNs && prefix == null && localName != "xmlns") {
                        prefix = "xmlns";
                    }
 
                    if (prefix == "xml") {
                        if (localName == "lang") { 
                            this.specialAttr = SpecialAttr.XmlLang; 
                        }
                        else if (localName == "space") { 
                            this.specialAttr = SpecialAttr.XmlSpace;
                        }
                        /* bug54408. to be fwd compatible we need to treat xml prefix as reserved
                        and not really insist on a specific value. Who knows in the future it 
                        might be OK to say xml:blabla
                        else { 
                            throw new ArgumentException(Res.GetString(Res.Xml_InvalidPrefix)); 
                        }*/
                    } 
                    else if (prefix == "xmlns") {

                        if (XmlReservedNs.NsXmlNs != ns && ns != null) {
                            throw new ArgumentException(Res.GetString(Res.Xml_XmlnsBelongsToReservedNs)); 
                        }
                        if (localName == null || localName.Length == 0) { 
                            localName = prefix; 
                            prefix = null;
                            this.prefixForXmlNs = null; 
                        }
                        else {
                            this.prefixForXmlNs = localName;
                        } 
                        this.specialAttr = SpecialAttr.XmlNs;
                    } 
                    else if (prefix == null && localName == "xmlns") { 
                        if (XmlReservedNs.NsXmlNs != ns && ns != null) {
                            // add the below line back in when DOM is fixed 
                            throw new ArgumentException(Res.GetString(Res.Xml_XmlnsBelongsToReservedNs));
                        }
                        this.specialAttr = SpecialAttr.XmlNs;
                        this.prefixForXmlNs = null; 
                    }
                    else { 
                        if (ns == null) { 
                            // use defined prefix
                            if (prefix != null && (LookupNamespace(prefix) == -1)) { 
                                throw new ArgumentException(Res.GetString(Res.Xml_UndefPrefix));
                            }
                        }
                        else if (ns.Length == 0) { 
                            // empty namespace require null prefix
                            prefix = string.Empty; 
                        } 
                        else { // ns.Length != 0
                            VerifyPrefixXml(prefix, ns); 
                            if (prefix != null && LookupNamespaceInCurrentScope(prefix) != -1) {
                                prefix = null;
                            }
                            // Now verify prefix validity 
                            string definedPrefix = FindPrefix(ns);
                            if (definedPrefix != null && (prefix == null || prefix == definedPrefix)) { 
                                prefix = definedPrefix; 
                            }
                            else { 
                                if (prefix == null) {
                                    prefix = GeneratePrefix(); // need a prefix if
                                }
                                PushNamespace(prefix, ns, false); 
                            }
                        } 
                    } 
                    if (prefix != null && prefix.Length != 0) {
                        textWriter.Write(prefix); 
                        textWriter.Write(':');
                    }
                }
                else { 
                    if ((ns != null && ns.Length != 0) || (prefix != null && prefix.Length != 0)) {
                        throw new ArgumentException(Res.GetString(Res.Xml_NoNamespaces)); 
                    } 
                    if (localName == "xml:lang") {
                        this.specialAttr = SpecialAttr.XmlLang; 
                    }
                    else if (localName == "xml:space") {
                        this.specialAttr = SpecialAttr.XmlSpace;
                    } 
                }
                xmlEncoder.StartAttribute(this.specialAttr != SpecialAttr.None); 
 
                textWriter.Write(localName);
                textWriter.Write('='); 
                if (this.curQuoteChar != this.quoteChar) {
                    this.curQuoteChar = this.quoteChar;
                    xmlEncoder.QuoteChar = this.quoteChar;
                } 
                textWriter.Write(this.curQuoteChar);
            } 
            catch { 
                currentState = State.Error;
                throw; 
            }
        }

        // Closes the attribute opened by WriteStartAttribute. 
        public override void WriteEndAttribute() {
            try { 
                AutoComplete(Token.EndAttribute); 
            }
            catch { 
                currentState = State.Error;
                throw;
            }
        } 

        // Writes out a <![CDATA[...]]> block containing the specified text. 
        public override void WriteCData(string text) { 
            try {
                AutoComplete(Token.CData); 
                if (null != text && text.IndexOf("]]>", StringComparison.Ordinal) >= 0) {
                    throw new ArgumentException(Res.GetString(Res.Xml_InvalidCDataChars));
                }
                textWriter.Write(""); 
            }
            catch {
                currentState = State.Error;
                throw; 
            }
        } 
 
        // Writes out a comment  containing the specified text.
        public override void WriteComment(string text) { 
            try {
                if (null != text && (text.IndexOf("--", StringComparison.Ordinal)>=0 || (text.Length != 0 && text[text.Length-1] == '-'))) {
                    throw new ArgumentException(Res.GetString(Res.Xml_InvalidCommentChars));
                } 
                AutoComplete(Token.Comment);
                textWriter.Write("");
            }
            catch {
                currentState = State.Error; 
                throw;
            } 
        } 

        // Writes out a processing instruction with a space between the name and text as follows:  
        public override void WriteProcessingInstruction(string name, string text) {
            try {
                if (null != text && text.IndexOf("?>", StringComparison.Ordinal)>=0) {
                    throw new ArgumentException(Res.GetString(Res.Xml_InvalidPiChars)); 
                }
                if (0 == String.Compare(name, "xml", StringComparison.OrdinalIgnoreCase) && this.stateTable == stateTableDocument) { 
                    throw new ArgumentException(Res.GetString(Res.Xml_DupXmlDecl)); 
                }
                AutoComplete(Token.PI); 
                InternalWriteProcessingInstruction(name, text);
            }
            catch {
                currentState = State.Error; 
                throw;
            } 
        } 

        // Writes out an entity reference as follows: "&"+name+";". 
        public override void WriteEntityRef(string name) {
            try {
                ValidateName(name, false);
                AutoComplete(Token.Content); 
                xmlEncoder.WriteEntityRef(name);
            } 
            catch { 
                currentState = State.Error;
                throw; 
            }
        }

        // Forces the generation of a character entity for the specified Unicode character value. 
        public override void WriteCharEntity(char ch) {
            try { 
                AutoComplete(Token.Content); 
                xmlEncoder.WriteCharEntity(ch);
            } 
            catch {
                currentState = State.Error;
                throw;
            } 
        }
 
        // Writes out the given whitespace. 
        public override void WriteWhitespace(string ws) {
            try { 
                if (null == ws || ws.Length == 0) {
                    throw new ArgumentException(Res.GetString(Res.Xml_NonWhitespace));
                }
 
                if (!xmlCharType.IsOnlyWhitespace(ws)) {
                    throw new ArgumentException(Res.GetString(Res.Xml_NonWhitespace)); 
                } 
                AutoComplete(Token.Whitespace);
                xmlEncoder.Write(ws); 
            }
            catch {
                currentState = State.Error;
                throw; 
            }
        } 
 
        // Writes out the specified text content.
        public override void WriteString(string text) { 
            try {
                if (null != text && text.Length != 0 ) {
                    AutoComplete(Token.Content);
                    xmlEncoder.Write(text); 
                }
            } 
            catch { 
                currentState = State.Error;
                throw; 
            }
        }

        // Writes out the specified surrogate pair as a character entity. 
        public override void WriteSurrogateCharEntity(char lowChar, char highChar){
            try { 
                AutoComplete(Token.Content); 
                xmlEncoder.WriteSurrogateCharEntity(lowChar, highChar);
            } 
            catch {
                currentState = State.Error;
                throw;
            } 
        }
 
 
        // Writes out the specified text content.
        public override void WriteChars(Char[] buffer, int index, int count) { 
            try {
                AutoComplete(Token.Content);
                xmlEncoder.Write(buffer, index, count);
            } 
            catch {
                currentState = State.Error; 
                throw; 
            }
        } 

        // Writes raw markup from the specified character buffer.
        public override void WriteRaw(Char[] buffer, int index, int count) {
            try { 
                AutoComplete(Token.RawData);
                xmlEncoder.WriteRaw(buffer, index, count); 
            } 
            catch {
                currentState = State.Error; 
                throw;
            }
        }
 
        // Writes raw markup from the specified character string.
        public override void WriteRaw(String data) { 
            try { 
                AutoComplete(Token.RawData);
                xmlEncoder.WriteRawWithSurrogateChecking(data); 
            }
            catch {
                currentState = State.Error;
                throw; 
            }
        } 
 
        // Encodes the specified binary bytes as base64 and writes out the resulting text.
        public override void WriteBase64(byte[] buffer, int index, int count) { 
            try {
                if (!this.flush) {
                    AutoComplete(Token.Base64);
                } 

                this.flush = true; 
                // No need for us to explicitly validate the args. The StreamWriter will do 
                // it for us.
                if (null == this.base64Encoder) { 
                    this.base64Encoder = new XmlTextWriterBase64Encoder( xmlEncoder );
                }
                // Encode will call WriteRaw to write out the encoded characters
                this.base64Encoder.Encode( buffer, index, count ); 
            }
            catch { 
                currentState = State.Error; 
                throw;
            } 
        }


        // Encodes the specified binary bytes as binhex and writes out the resulting text. 
        public override void WriteBinHex( byte[] buffer, int index, int count ) {
            try { 
                AutoComplete( Token.Content ); 
                BinHexEncoder.Encode( buffer, index, count, this );
            } 
            catch {
                currentState = State.Error;
                throw;
            } 
        }
 
        // Returns the state of the XmlWriter. 
        public override WriteState WriteState {
            get { 
                switch (this.currentState) {
                    case State.Start :
                        return WriteState.Start;
                    case State.Prolog : 
                    case State.PostDTD :
                        return WriteState.Prolog; 
                    case State.Element : 
                        return WriteState.Element;
                    case State.Attribute : 
                    case State.AttrOnly:
                        return WriteState.Attribute;
                    case State.Content :
                    case State.Epilog : 
                        return WriteState.Content;
                    case State.Error: 
                        return WriteState.Error; 
                    case State.Closed:
                        return WriteState.Closed; 
                    default:
                        Debug.Assert( false );
                        return WriteState.Error;
                } 
            }
        } 
 
        // Closes the XmlWriter and the underlying stream/TextWriter.
        public override void Close() { 
            try {
                AutoCompleteAll();
            }
            catch { // never fail 
            }
            finally { 
                this.currentState = State.Closed; 
                textWriter.Close();
            } 
        }

        // Flushes whatever is in the buffer to the underlying stream/TextWriter and flushes the underlying stream/TextWriter.
        public override void Flush() { 
            textWriter.Flush();
        } 
 
        // Writes out the specified name, ensuring it is a valid Name according to the XML specification
        // (http://www.w3.org/TR/1998/REC-xml-19980210#NT-Name 
        public override void WriteName(string name) {
            try {
                AutoComplete(Token.Content);
                InternalWriteName(name, false); 
            }
            catch { 
                currentState = State.Error; 
                throw;
            } 
        }

        // Writes out the specified namespace-qualified name by looking up the prefix that is in scope for the given namespace.
        public override void WriteQualifiedName(string localName, string ns) { 
            try {
                AutoComplete(Token.Content); 
                if (this.namespaces) { 
                    if (ns != null && ns.Length != 0 && ns != stack[top].defaultNs) {
                        string prefix = FindPrefix(ns); 
                        if (prefix == null) {
                            if (this.currentState != State.Attribute) {
                                throw new ArgumentException(Res.GetString(Res.Xml_UndefNamespace, ns));
                            } 
                            prefix = GeneratePrefix(); // need a prefix if
                            PushNamespace(prefix, ns, false); 
                        } 
                        if (prefix.Length != 0) {
                            InternalWriteName(prefix, true); 
                            textWriter.Write(':');
                        }
                    }
                } 
                else if (ns != null && ns.Length != 0) {
                    throw new ArgumentException(Res.GetString(Res.Xml_NoNamespaces)); 
                } 
                InternalWriteName(localName, true);
            } 
            catch {
                currentState = State.Error;
                throw;
            } 
        }
 
        // Returns the closest prefix defined in the current namespace scope for the specified namespace URI. 
        public override string LookupPrefix(string ns) {
            if (ns == null || ns.Length == 0) { 
                throw new ArgumentException(Res.GetString(Res.Xml_EmptyName));
            }
            string s =  FindPrefix(ns);
            if (s == null && ns == stack[top].defaultNs) { 
                s = string.Empty;
            } 
            return s; 
        }
 
        // Gets an XmlSpace representing the current xml:space scope.
        public override XmlSpace XmlSpace {
            get {
                for (int i = top; i > 0; i--) { 
                    XmlSpace xs = stack[i].xmlSpace;
                    if (xs != XmlSpace.None) 
                        return xs; 
                }
                return XmlSpace.None; 
            }
        }

        // Gets the current xml:lang scope. 
        public override string XmlLang {
            get { 
                for (int i = top; i > 0; i--) { 
                    String xlang = stack[i].xmlLang;
                    if (xlang != null) 
                        return xlang;
                }
                return null;
            } 
        }
 
        // Writes out the specified name, ensuring it is a valid NmToken 
        // according to the XML specification (http://www.w3.org/TR/1998/REC-xml-19980210#NT-Name).
        public override void WriteNmToken(string name) { 
            try {
                AutoComplete(Token.Content);

                if (name == null || name.Length == 0) { 
                    throw new ArgumentException(Res.GetString(Res.Xml_EmptyName));
                } 
                if (!xmlCharType.IsNmToken(name)) { 
                    throw new ArgumentException(Res.GetString(Res.Xml_InvalidNameChars, name));
                } 
                textWriter.Write(name);
            }
            catch {
                currentState = State.Error; 
                throw;
            } 
        } 

// 
// Private implementation methods
//
        void StartDocument(int standalone) {
            try { 
                if (this.currentState != State.Start) {
                    throw new InvalidOperationException(Res.GetString(Res.Xml_NotTheFirst)); 
                } 
                this.stateTable = stateTableDocument;
                this.currentState = State.Prolog; 

                StringBuilder bufBld = new StringBuilder(128);
                bufBld.Append("version=" + quoteChar + "1.0" + quoteChar);
                if (this.encoding != null) { 
                    bufBld.Append(" encoding=");
                    bufBld.Append(quoteChar); 
                    bufBld.Append(this.encoding.WebName); 
                    bufBld.Append(quoteChar);
                } 
                if (standalone >= 0) {
                    bufBld.Append(" standalone=");
                    bufBld.Append(quoteChar);
                    bufBld.Append(standalone == 0 ? "no" : "yes"); 
                    bufBld.Append(quoteChar);
                } 
                InternalWriteProcessingInstruction("xml", bufBld.ToString()); 
            }
            catch { 
                currentState = State.Error;
                throw;
            }
        } 

        void AutoComplete(Token token) { 
            if (this.currentState == State.Closed) { 
                throw new InvalidOperationException(Res.GetString(Res.Xml_Closed));
            } 
            else if (this.currentState == State.Error) {
                throw new InvalidOperationException(Res.GetString(Res.Xml_WrongToken, tokenName[(int)token], stateName[(int)State.Error]));
            }
 
            State newState = this.stateTable[(int)token * 8 + (int)this.currentState];
            if (newState == State.Error) { 
                throw new InvalidOperationException(Res.GetString(Res.Xml_WrongToken, tokenName[(int)token], stateName[(int)this.currentState])); 
            }
 
            switch (token) {
                case Token.Doctype:
                    if (this.indented && this.currentState != State.Start) {
                        Indent(false); 
                    }
                    break; 
 
                case Token.StartElement:
                case Token.Comment: 
                case Token.PI:
                case Token.CData:
                    if (this.currentState == State.Attribute) {
                        WriteEndAttributeQuote(); 
                        WriteEndStartTag(false);
                    } 
                    else if (this.currentState == State.Element) { 
                        WriteEndStartTag(false);
                    } 
                    if (token == Token.CData) {
                        stack[top].mixed = true;
                    }
                    else if (this.indented && this.currentState != State.Start) { 
                        Indent(false);
                    } 
                    break; 

                case Token.EndElement: 
                case Token.LongEndElement:
                    if (this.flush) {
                        FlushEncoders();
                    } 
                    if (this.currentState == State.Attribute) {
                        WriteEndAttributeQuote(); 
                    } 
                    if (this.currentState == State.Content) {
                        token = Token.LongEndElement; 
                    }
                    else {
                        WriteEndStartTag(token == Token.EndElement);
                    } 
                    if (stateTableDocument == this.stateTable && top == 1) {
                        newState = State.Epilog; 
                    } 
                    break;
 
                case Token.StartAttribute:
                    if (this.flush) {
                        FlushEncoders();
                    } 
                    if (this.currentState == State.Attribute) {
                        WriteEndAttributeQuote(); 
                        textWriter.Write(' '); 
                    }
                    else if (this.currentState == State.Element) { 
                        textWriter.Write(' ');
                    }
                    break;
 
                case Token.EndAttribute:
                    if (this.flush) { 
                        FlushEncoders(); 
                    }
                    WriteEndAttributeQuote(); 
                    break;

                case Token.Whitespace:
                case Token.Content: 
                case Token.RawData:
                case Token.Base64: 
 
                    if (token != Token.Base64 && this.flush) {
                        FlushEncoders(); 
                    }
                    if (this.currentState == State.Element && this.lastToken != Token.Content) {
                        WriteEndStartTag(false);
                    } 
                    if (newState == State.Content) {
                        stack[top].mixed = true; 
                    } 
                    break;
 
                default:
                    throw new InvalidOperationException(Res.GetString(Res.Xml_InvalidOperation));
            }
            this.currentState = newState; 
            this.lastToken = token;
        } 
 
        void AutoCompleteAll() {
            if (this.flush) { 
                FlushEncoders();
            }
            while (top > 0) {
                WriteEndElement(); 
            }
        } 
 
        void InternalWriteEndElement(bool longFormat) {
            try { 
                if (top <= 0) {
                    throw new InvalidOperationException(Res.GetString(Res.Xml_NoStartTag));
                }
                // if we are in the element, we need to close it. 
                AutoComplete(longFormat ?  Token.LongEndElement : Token.EndElement);
                if (this.lastToken == Token.LongEndElement) { 
                    if (this.indented) { 
                        Indent(true);
                    } 
                    textWriter.Write('<');
                    textWriter.Write('/');
                    if (this.namespaces && stack[top].prefix != null) {
                        textWriter.Write(stack[top].prefix); 
                        textWriter.Write(':');
                    } 
                    textWriter.Write(stack[top].name); 
                    textWriter.Write('>');
                } 

                // pop namespaces
                int prevNsTop = stack[top].prevNsTop;
                if (useNsHashtable && prevNsTop < nsTop) { 
                    PopNamespaces(prevNsTop + 1, nsTop);
                } 
                nsTop = prevNsTop; 
                top--;
            } 
            catch {
                currentState = State.Error;
                throw;
            } 
        }
 
        void WriteEndStartTag(bool empty) { 
            xmlEncoder.StartAttribute(false);
            for (int i = nsTop; i > stack[top].prevNsTop; i--) { 
                if (!nsStack[i].declared) {
                    textWriter.Write(" xmlns");
                    textWriter.Write(':');
                    textWriter.Write(nsStack[i].prefix); 
                    textWriter.Write('=');
                    textWriter.Write(this.quoteChar); 
                    xmlEncoder.Write(nsStack[i].ns); 
                    textWriter.Write(this.quoteChar);
                } 
            }
            // Default
            if ((stack[top].defaultNs != stack[top - 1].defaultNs) &&
                (stack[top].defaultNsState == NamespaceState.DeclaredButNotWrittenOut)) { 
                textWriter.Write(" xmlns");
                textWriter.Write('='); 
                textWriter.Write(this.quoteChar); 
                xmlEncoder.Write(stack[top].defaultNs);
                textWriter.Write(this.quoteChar); 
                stack[top].defaultNsState = NamespaceState.DeclaredAndWrittenOut;
            }
            xmlEncoder.EndAttribute();
            if (empty) { 
                textWriter.Write(" /");
            } 
            textWriter.Write('>'); 
        }
 
        void WriteEndAttributeQuote() {
            if (this.specialAttr != SpecialAttr.None) {
                // Ok, now to handle xmlspace, etc.
                HandleSpecialAttribute(); 
            }
            xmlEncoder.EndAttribute(); 
            textWriter.Write(this.curQuoteChar); 
        }
 
        void Indent(bool beforeEndElement) {
            // pretty printing.
            if (top == 0) {
                textWriter.WriteLine(); 
            }
            else if (!stack[top].mixed) { 
                textWriter.WriteLine(); 
                int i = beforeEndElement ? top - 1 : top;
                for (i *= this.indentation; i > 0; i--) { 
                    textWriter.Write(this.indentChar);
                }
            }
        } 

        // pushes new namespace scope, and returns generated prefix, if one 
        // was needed to resolve conflicts. 
        void PushNamespace(string prefix, string ns, bool declared) {
            if (XmlReservedNs.NsXmlNs == ns) { 
                throw new ArgumentException(Res.GetString(Res.Xml_CanNotBindToReservedNamespace));
            }

            if (prefix == null) { 
                switch (stack[top].defaultNsState) {
                    case NamespaceState.DeclaredButNotWrittenOut: 
                        Debug.Assert (declared == true, "Unexpected situation!!"); 
                        // the first namespace that the user gave us is what we
                        // like to keep. 
                        break;
                    case NamespaceState.Uninitialized:
                    case NamespaceState.NotDeclaredButInScope:
                        // we now got a brand new namespace that we need to remember 
                        stack[top].defaultNs = ns;
                        break; 
                    default: 
                        Debug.Assert(false, "Should have never come here");
                        return; 
                }
                stack[top].defaultNsState = (declared ? NamespaceState.DeclaredAndWrittenOut : NamespaceState.DeclaredButNotWrittenOut);
            }
            else { 
                if (prefix.Length != 0 && ns.Length == 0) {
                    throw new ArgumentException(Res.GetString(Res.Xml_PrefixForEmptyNs)); 
                } 

                int existingNsIndex = LookupNamespace(prefix); 
                if (existingNsIndex != -1 && nsStack[existingNsIndex].ns == ns) {
                    // it is already in scope.
                    if (declared) {
                        nsStack[existingNsIndex].declared = true; 
                    }
                } 
                else { 
                    // see if prefix conflicts for the current element
                    if (declared) { 
                        if (existingNsIndex != -1 && existingNsIndex > stack[top].prevNsTop) {
                            nsStack[existingNsIndex].declared = true; // old one is silenced now
                        }
                    } 
                    AddNamespace(prefix, ns, declared);
                } 
            } 
        }
 
        void AddNamespace(string prefix, string ns, bool declared) {
            int nsIndex = ++nsTop;
            if ( nsIndex == nsStack.Length ) {
                Namespace[] newStack = new Namespace[nsIndex * 2]; 
                Array.Copy(nsStack, newStack, nsIndex);
                nsStack = newStack; 
            } 
            nsStack[nsIndex].Set(prefix, ns, declared);
 
            if (useNsHashtable) {
                AddToNamespaceHashtable(nsIndex);
            }
            else if (nsIndex == MaxNamespacesWalkCount) { 
                // add all
                nsHashtable = new Dictionary(new SecureStringHasher()); 
                for (int i = 0; i <= nsIndex; i++) { 
                    AddToNamespaceHashtable(i);
                } 
                useNsHashtable = true;
            }
        }
 
        void AddToNamespaceHashtable(int namespaceIndex) {
            string prefix = nsStack[namespaceIndex].prefix; 
            int existingNsIndex; 
            if ( nsHashtable.TryGetValue(prefix, out existingNsIndex)) {
                nsStack[namespaceIndex].prevNsIndex = existingNsIndex; 
            }
            nsHashtable[prefix] = namespaceIndex;
        }
 
        private void PopNamespaces(int indexFrom, int indexTo) {
            Debug.Assert(useNsHashtable); 
            for (int i = indexTo; i >= indexFrom; i--) { 
                Debug.Assert(nsHashtable.ContainsKey(nsStack[i].prefix));
                if (nsStack[i].prevNsIndex == -1) { 
                    nsHashtable.Remove(nsStack[i].prefix);
                }
                else {
                    nsHashtable[nsStack[i].prefix] = nsStack[i].prevNsIndex; 
                }
            } 
        } 

        string GeneratePrefix() { 
            int temp = stack[top].prefixCount++ + 1;
            return "d" + top.ToString("d", CultureInfo.InvariantCulture)
                + "p" + temp.ToString("d", CultureInfo.InvariantCulture);
        } 

        void InternalWriteProcessingInstruction(string name, string text) { 
            textWriter.Write("");
        } 
 
        int LookupNamespace( string prefix ) {
            if ( useNsHashtable ) { 
                int nsIndex;
                if ( nsHashtable.TryGetValue( prefix, out nsIndex ) ) {
                    return nsIndex;
                } 
            }
            else { 
                for ( int i = nsTop; i >= 0; i-- ) { 
                    if ( nsStack[i].prefix == prefix ) {
                        return i; 
                    }
                }
            }
            return -1; 
        }
 
        int LookupNamespaceInCurrentScope( string prefix ) { 
            if ( useNsHashtable ) {
                int nsIndex; 
                if ( nsHashtable.TryGetValue( prefix, out nsIndex ) ) {
                    if ( nsIndex > stack[top].prevNsTop ) {
                        return nsIndex;
                    } 
                }
            } 
            else { 
                for ( int i = nsTop; i > stack[top].prevNsTop; i-- ) {
                    if ( nsStack[i].prefix == prefix ) { 
                        return i;
                    }
                }
            } 
            return -1;
        } 
 
        string FindPrefix(string ns) {
            for (int i = nsTop; i >= 0; i--) { 
                if (nsStack[i].ns == ns) {
                    if (LookupNamespace(nsStack[i].prefix) == i) {
                        return nsStack[i].prefix;
                    } 
                }
            } 
            return null; 
        }
 
        // There are three kind of strings we write out - Name, LocalName and Prefix.
        // Both LocalName and Prefix can be represented with NCName == false and Name
        // can be represented as NCName == true
 
        void InternalWriteName(string name, bool NCName) {
            ValidateName(name, NCName); 
            textWriter.Write(name); 
        }
 
        private unsafe void ValidateName(string name, bool NCName) {
            if (name == null || name.Length == 0) {
                throw new ArgumentException(Res.GetString(Res.Xml_EmptyName));
            } 
            int nameLength = name.Length;
            int position   = 0; 
            int colonPosition = -1; 

            if (namespaces) { 
                if ((xmlCharType.charProperties[name[position]] & XmlCharType.fNCStartName) != 0) { // if (xmlCharType.IsStartNCNameChar(name[position])) {
            Continue:
                    position ++;
                    while (position < nameLength && 
                        (xmlCharType.charProperties[name[position]] & XmlCharType.fNCName) != 0) { // xmlCharType.IsNCNameChar(name[position])) {
                        position ++; 
                    } 
                    if (position == nameLength) {
                        return; 
                    }
                    if (name[position] == ':') {
                        if (!NCName) {
                            if (colonPosition == -1) { 
                                if (position + 1 < nameLength) {
                                    colonPosition = position; 
                                    // We should check if the character after ':' is a valid start name 
                                    // character but we can't do that because of backward compatilibity
                                    goto Continue; 
                                }
                            }
                        }
                    } 
                }
            } 
            else { 
                if ((xmlCharType.charProperties[name[0]] & XmlCharType.fNCStartName) != 0 || name[0] == ':') { // if (xmlCharType.IsStartNameChar(name[0])) {
                    position ++; 
                    while (position < nameLength &&
                        ((xmlCharType.charProperties[name[position]] & XmlCharType.fNCName) != 0 || name[position] == ':')) { // xmlCharType.IsNameChar(name[position])) {
                        position ++;
                    } 
                    if (position == nameLength) {
                        return; 
                    } 
                }
            } 
            throw new ArgumentException(Res.GetString(Res.Xml_InvalidNameChars, name));
        }

        void HandleSpecialAttribute() { 
            string value = xmlEncoder.AttributeValue;
            switch (this.specialAttr) { 
                case SpecialAttr.XmlLang: 
                    stack[top].xmlLang = value;
                    break; 
                case SpecialAttr.XmlSpace:
                    // validate XmlSpace attribute
                    value = XmlConvert.TrimString(value);
                    if (value == "default") { 
                        stack[top].xmlSpace = XmlSpace.Default;
                    } 
                    else if (value == "preserve") { 
                        stack[top].xmlSpace = XmlSpace.Preserve;
                    } 
                    else {
                        throw new ArgumentException(Res.GetString(Res.Xml_InvalidXmlSpace, value));
                    }
                    break; 
                case SpecialAttr.XmlNs:
                    VerifyPrefixXml(this.prefixForXmlNs, value); 
                    PushNamespace(this.prefixForXmlNs, value, true); 
                    break;
            } 
        }


        void VerifyPrefixXml(string prefix, string ns) { 

            if (prefix != null && prefix.Length == 3) { 
                if ( 
                   (prefix[0] == 'x' || prefix[0] == 'X') &&
                   (prefix[1] == 'm' || prefix[1] == 'M') && 
                   (prefix[2] == 'l' || prefix[2] == 'L')
                   ) {
                    if (XmlReservedNs.NsXml != ns) {
                        throw new ArgumentException(Res.GetString(Res.Xml_InvalidPrefix)); 
                    }
                } 
            } 
        }
 
        void PushStack() {
            if (top == stack.Length - 1) {
                TagInfo[] na = new TagInfo[stack.Length + 10];
                if (top > 0) Array.Copy(stack,na,top + 1); 
                stack = na;
            } 
 
            top++; // Move up stack
            stack[top].Init(nsTop); 
        }

        void FlushEncoders()
        { 
            if (null != this.base64Encoder) {
                // The Flush will call WriteRaw to write out the rest of the encoded characters 
                this.base64Encoder.Flush(); 
            }
            this.flush = false; 
        }
   }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
using System; 
using System.Collections;
using System.Collections.Generic; 
using System.IO;
using System.Text;
using System.Diagnostics;
using System.Globalization; 

namespace System.Xml { 
 
    // Specifies formatting options for XmlTextWriter.
    public enum Formatting { 
        // No special formatting is done (this is the default).
        None,

        //This option causes child elements to be indented using the Indentation and IndentChar properties. 
        // It only indents Element Content (http://www.w3.org/TR/1998/REC-xml-19980210#sec-element-content)
        // and not Mixed Content (http://www.w3.org/TR/1998/REC-xml-19980210#sec-mixed-content) 
        // according to the XML 1.0 definitions of these terms. 
        Indented,
    }; 

    // Represents a writer that provides fast non-cached forward-only way of generating XML streams
    // containing XML documents that conform to the W3CExtensible Markup Language (XML) 1.0 specification
    // and the Namespaces in XML specification. 
    public class XmlTextWriter : XmlWriter {
// 
// Private types 
//
        enum NamespaceState { 
            Uninitialized,
            NotDeclaredButInScope,
            DeclaredButNotWrittenOut,
            DeclaredAndWrittenOut 
        }
 
        struct TagInfo { 
            internal string name;
            internal string prefix; 
            internal string defaultNs;
            internal NamespaceState defaultNsState;
            internal XmlSpace xmlSpace;
            internal string xmlLang; 
            internal int prevNsTop;
            internal int prefixCount; 
            internal bool mixed; // whether to pretty print the contents of this element. 

            internal void Init( int nsTop ) { 
                name = null;
                defaultNs = String.Empty;
                defaultNsState = NamespaceState.Uninitialized;
                xmlSpace = XmlSpace.None; 
                xmlLang = null;
                prevNsTop = nsTop; 
                prefixCount = 0; 
                mixed = false;
            } 
        }

        struct Namespace {
            internal string prefix; 
            internal string ns;
            internal bool   declared; 
            internal int prevNsIndex; 

            internal void Set( string prefix, string ns, bool declared ) { 
                this.prefix = prefix;
                this.ns = ns;
                this.declared = declared;
                this.prevNsIndex = -1; 
            }
        } 
 
        enum SpecialAttr {
            None, 
            XmlSpace,
            XmlLang,
            XmlNs
        }; 

        // State machine is working through autocomplete 
        private enum State { 
            Start,
            Prolog, 
            PostDTD,
            Element,
            Attribute,
            Content, 
            AttrOnly,
            Epilog, 
            Error, 
            Closed,
        } 

        private enum Token {
            PI,
            Doctype, 
            Comment,
            CData, 
            StartElement, 
            EndElement,
            LongEndElement, 
            StartAttribute,
            EndAttribute,
            Content,
            Base64, 
            RawData,
            Whitespace, 
            Empty 
        }
 
//
// Fields
//
        // output 
        TextWriter textWriter;
        XmlTextEncoder xmlEncoder; 
        Encoding encoding; 

        // formatting 
        Formatting formatting;
        bool indented; // perf - faster to check a boolean.
        int  indentation;
        char indentChar; 

        // element stack 
        TagInfo[] stack; 
        int top;
 
        // state machine for AutoComplete
        State[] stateTable;
        State currentState;
        Token lastToken; 

        // Base64 content 
        XmlTextWriterBase64Encoder base64Encoder; 

        // misc 
        char quoteChar;
        char curQuoteChar;
        bool namespaces;
        SpecialAttr specialAttr; 
        string prefixForXmlNs;
        bool flush; 
 
        // namespaces
        Namespace[] nsStack; 
        int nsTop;
        Dictionary nsHashtable;
        bool useNsHashtable;
 
        // char types
        XmlCharType xmlCharType = XmlCharType.Instance; 
 
//
// Constants and constant tables 
//
        const int NamespaceStackInitialSize = 8;
#if DEBUG
        const int MaxNamespacesWalkCount = 3; 
#else
        const int MaxNamespacesWalkCount = 16; 
#endif 

        static string[] stateName = { 
            "Start",
            "Prolog",
            "PostDTD",
            "Element", 
            "Attribute",
            "Content", 
            "AttrOnly", 
            "Epilog",
            "Error", 
            "Closed",
        };

        static string[] tokenName = { 
            "PI",
            "Doctype", 
            "Comment", 
            "CData",
            "StartElement", 
            "EndElement",
            "LongEndElement",
            "StartAttribute",
            "EndAttribute", 
            "Content",
            "Base64", 
            "RawData", 
            "Whitespace",
            "Empty" 
        };

        static readonly State[] stateTableDefault = {
            //                          State.Start      State.Prolog     State.PostDTD    State.Element    State.Attribute  State.Content   State.AttrOnly   State.Epilog 
            //
            /* Token.PI             */ State.Prolog,    State.Prolog,    State.PostDTD,   State.Content,   State.Content,   State.Content,  State.Error,     State.Epilog, 
            /* Token.Doctype        */ State.PostDTD,   State.PostDTD,   State.Error,     State.Error,     State.Error,     State.Error,    State.Error,     State.Error, 
            /* Token.Comment        */ State.Prolog,    State.Prolog,    State.PostDTD,   State.Content,   State.Content,   State.Content,  State.Error,     State.Epilog,
            /* Token.CData          */ State.Content,   State.Content,   State.Error,     State.Content,   State.Content,   State.Content,  State.Error,     State.Epilog, 
            /* Token.StartElement   */ State.Element,   State.Element,   State.Element,   State.Element,   State.Element,   State.Element,  State.Error,     State.Element,
            /* Token.EndElement     */ State.Error,     State.Error,     State.Error,     State.Content,   State.Content,   State.Content,  State.Error,     State.Error,
            /* Token.LongEndElement */ State.Error,     State.Error,     State.Error,     State.Content,   State.Content,   State.Content,  State.Error,     State.Error,
            /* Token.StartAttribute */ State.AttrOnly,  State.Error,     State.Error,     State.Attribute, State.Attribute, State.Error,    State.Error,     State.Error, 
            /* Token.EndAttribute   */ State.Error,     State.Error,     State.Error,     State.Error,     State.Element,   State.Error,    State.Epilog,     State.Error,
            /* Token.Content        */ State.Content,   State.Content,   State.Error,     State.Content,   State.Attribute, State.Content,  State.Attribute, State.Epilog, 
            /* Token.Base64         */ State.Content,   State.Content,   State.Error,     State.Content,   State.Attribute, State.Content,  State.Attribute, State.Epilog, 
            /* Token.RawData        */ State.Prolog,    State.Prolog,    State.PostDTD,   State.Content,   State.Attribute, State.Content,  State.Attribute, State.Epilog,
            /* Token.Whitespace     */ State.Prolog,    State.Prolog,    State.PostDTD,   State.Content,   State.Attribute, State.Content,  State.Attribute, State.Epilog, 
        };

        static readonly State[] stateTableDocument = {
            //                          State.Start      State.Prolog     State.PostDTD    State.Element    State.Attribute  State.Content   State.AttrOnly   State.Epilog 
            //
            /* Token.PI             */ State.Error,     State.Prolog,    State.PostDTD,   State.Content,   State.Content,   State.Content,  State.Error,     State.Epilog, 
            /* Token.Doctype        */ State.Error,     State.PostDTD,   State.Error,     State.Error,     State.Error,     State.Error,    State.Error,     State.Error, 
            /* Token.Comment        */ State.Error,     State.Prolog,    State.PostDTD,   State.Content,   State.Content,   State.Content,  State.Error,     State.Epilog,
            /* Token.CData          */ State.Error,     State.Error,     State.Error,     State.Content,   State.Content,   State.Content,  State.Error,     State.Error, 
            /* Token.StartElement   */ State.Error,     State.Element,   State.Element,   State.Element,   State.Element,   State.Element,  State.Error,     State.Error,
            /* Token.EndElement     */ State.Error,     State.Error,     State.Error,     State.Content,   State.Content,   State.Content,  State.Error,     State.Error,
            /* Token.LongEndElement */ State.Error,     State.Error,     State.Error,     State.Content,   State.Content,   State.Content,  State.Error,     State.Error,
            /* Token.StartAttribute */ State.Error,     State.Error,     State.Error,     State.Attribute, State.Attribute, State.Error,    State.Error,     State.Error, 
            /* Token.EndAttribute   */ State.Error,     State.Error,     State.Error,     State.Error,     State.Element,   State.Error,    State.Error,     State.Error,
            /* Token.Content        */ State.Error,     State.Error,     State.Error,     State.Content,   State.Attribute, State.Content,  State.Error,     State.Error, 
            /* Token.Base64         */ State.Error,     State.Error,     State.Error,     State.Content,   State.Attribute, State.Content,  State.Error,     State.Error, 
            /* Token.RawData        */ State.Error,     State.Prolog,    State.PostDTD,   State.Content,   State.Attribute, State.Content,  State.Error,     State.Epilog,
            /* Token.Whitespace     */ State.Error,     State.Prolog,    State.PostDTD,   State.Content,   State.Attribute, State.Content,  State.Error,     State.Epilog, 
        };

//
// Constructors 
//
        internal XmlTextWriter() { 
            namespaces = true; 
            formatting = Formatting.None;
            indentation = 2; 
            indentChar = ' ';
            // namespaces
            nsStack = new Namespace[NamespaceStackInitialSize];
            nsTop = -1; 
            // element stack
            stack = new TagInfo[10]; 
            top = 0;// 0 is an empty sentanial element 
            stack[top].Init( -1 );
            quoteChar = '"'; 

            stateTable = stateTableDefault;
            currentState = State.Start;
            lastToken = Token.Empty; 
        }
 
        // Creates an instance of the XmlTextWriter class using the specified stream. 
        public XmlTextWriter(Stream w, Encoding encoding) : this() {
            this.encoding = encoding; 
            if (encoding != null)
                textWriter = new StreamWriter(w, encoding);
            else
                textWriter = new StreamWriter(w); 
            xmlEncoder = new XmlTextEncoder(textWriter);
            xmlEncoder.QuoteChar = this.quoteChar; 
        } 

        // Creates an instance of the XmlTextWriter class using the specified file. 
        public XmlTextWriter(String filename, Encoding encoding)
        : this(new FileStream(filename, FileMode.Create,
                              FileAccess.Write, FileShare.Read), encoding) {
        } 

        // Creates an instance of the XmlTextWriter class using the specified TextWriter. 
        public XmlTextWriter(TextWriter w) : this() { 
            textWriter = w;
 
            encoding = w.Encoding;
            xmlEncoder = new XmlTextEncoder(w);
            xmlEncoder.QuoteChar = this.quoteChar;
        } 

// 
// XmlTextWriter properties 
//
        // Gets the XmlTextWriter base stream. 
        public Stream BaseStream  {
            get {
                StreamWriter streamWriter = textWriter as StreamWriter;
                return (streamWriter == null ? null : streamWriter.BaseStream); 
            }
        } 
 
        // Gets or sets a value indicating whether to do namespace support.
        public bool Namespaces { 
            get { return this.namespaces;}
            set {
                if (this.currentState != State.Start)
                    throw new InvalidOperationException(Res.GetString(Res.Xml_NotInWriteState)); 

                this.namespaces = value; 
            } 
        }
 
        // Indicates how the output is formatted.
        public Formatting Formatting {
            get { return this.formatting;}
            set { this.formatting = value; this.indented = value == Formatting.Indented;} 
        }
 
        // Gets or sets how many IndentChars to write for each level in the hierarchy when Formatting is set to "Indented". 
        public int Indentation {
            get { return this.indentation;} 
            set {
                if (value < 0)
                    throw new ArgumentException(Res.GetString(Res.Xml_InvalidIndentation));
                this.indentation = value; 
            }
        } 
 
        // Gets or sets which character to use for indenting when Formatting is set to "Indented".
        public char IndentChar { 
            get { return this.indentChar;}
            set { this.indentChar = value;}
        }
 
        // Gets or sets which character to use to quote attribute values.
        public char QuoteChar { 
            get { return this.quoteChar;} 
            set {
                if (value != '"' && value != '\'') { 
                    throw new ArgumentException(Res.GetString(Res.Xml_InvalidQuote));
                }
                this.quoteChar = value;
                this.xmlEncoder.QuoteChar = value; 
            }
        } 
 
//
// XmlWriter implementation 
//
        // Writes out the XML declaration with the version "1.0".
        public override void WriteStartDocument() {
            StartDocument(-1); 
        }
 
        // Writes out the XML declaration with the version "1.0" and the standalone attribute. 
        public override void WriteStartDocument(bool standalone) {
            StartDocument(standalone ? 1 : 0); 
        }

        // Closes any open elements or attributes and puts the writer back in the Start state.
        public override void WriteEndDocument() { 
            try {
                AutoCompleteAll(); 
                if (this.currentState != State.Epilog) { 
                    throw new ArgumentException(Res.GetString(Res.Xml_NoRoot));
                } 
                this.stateTable = stateTableDefault;
                this.currentState = State.Start;
                this.lastToken = Token.Empty;
            } 
            catch {
                currentState = State.Error; 
                throw; 
            }
        } 

        // Writes out the DOCTYPE declaration with the specified name and optional attributes.
        public override void WriteDocType(string name, string pubid, string sysid, string subset) {
            try { 
                ValidateName(name, false);
 
                AutoComplete(Token.Doctype); 
                textWriter.Write("'); 
            }
            catch {
                currentState = State.Error;
                throw; 
            }
        } 
 
        // Writes out the specified start tag and associates it with the given namespace and prefix.
        public override void WriteStartElement(string prefix, string localName, string ns) { 
            try {
                AutoComplete(Token.StartElement);
                PushStack();
                textWriter.Write('<'); 

                if (this.namespaces) { 
                    // Propagate default namespace and mix model down the stack. 
                    stack[top].defaultNs = stack[top-1].defaultNs;
                    if (stack[top-1].defaultNsState != NamespaceState.Uninitialized) 
                        stack[top].defaultNsState = NamespaceState.NotDeclaredButInScope;
                    stack[top].mixed = stack[top-1].mixed;
                    if (ns == null) {
                        // use defined prefix 
                        if (prefix != null && prefix.Length != 0 && (LookupNamespace(prefix) == -1)) {
                            throw new ArgumentException(Res.GetString(Res.Xml_UndefPrefix)); 
                        } 
                    }
                    else { 
                        if (prefix == null) {
                            string definedPrefix = FindPrefix(ns);
                            if (definedPrefix != null) {
                                prefix = definedPrefix; 
                            }
                            else { 
                                PushNamespace(null, ns, false); // new default 
                            }
                        } 
                        else if (prefix.Length == 0) {
                            PushNamespace(null, ns, false); // new default
                        }
                        else { 
                            if (ns.Length == 0) {
                                prefix = null; 
                            } 
                            VerifyPrefixXml(prefix, ns);
                            PushNamespace(prefix, ns, false); // define 
                        }
                    }
                    stack[top].prefix = null;
                    if (prefix != null && prefix.Length != 0) { 
                        stack[top].prefix = prefix;
                        textWriter.Write(prefix); 
                        textWriter.Write(':'); 
                    }
                } 
                else {
                    if ((ns != null && ns.Length != 0) || (prefix != null && prefix.Length != 0)) {
                        throw new ArgumentException(Res.GetString(Res.Xml_NoNamespaces));
                    } 
                }
                stack[top].name = localName; 
                textWriter.Write(localName); 
            }
            catch { 
                currentState = State.Error;
                throw;
            }
        } 

        // Closes one element and pops the corresponding namespace scope. 
        public override  void WriteEndElement() { 
            InternalWriteEndElement(false);
        } 

        // Closes one element and pops the corresponding namespace scope.
        public override  void WriteFullEndElement() {
            InternalWriteEndElement(true); 
        }
 
        // Writes the start of an attribute. 
        public override  void WriteStartAttribute(string prefix, string localName, string ns) {
            try { 
                AutoComplete(Token.StartAttribute);

                this.specialAttr = SpecialAttr.None;
                if (this.namespaces) { 

                    if (prefix != null && prefix.Length == 0) { 
                        prefix = null; 
                    }
 
                    if (ns == XmlReservedNs.NsXmlNs && prefix == null && localName != "xmlns") {
                        prefix = "xmlns";
                    }
 
                    if (prefix == "xml") {
                        if (localName == "lang") { 
                            this.specialAttr = SpecialAttr.XmlLang; 
                        }
                        else if (localName == "space") { 
                            this.specialAttr = SpecialAttr.XmlSpace;
                        }
                        /* bug54408. to be fwd compatible we need to treat xml prefix as reserved
                        and not really insist on a specific value. Who knows in the future it 
                        might be OK to say xml:blabla
                        else { 
                            throw new ArgumentException(Res.GetString(Res.Xml_InvalidPrefix)); 
                        }*/
                    } 
                    else if (prefix == "xmlns") {

                        if (XmlReservedNs.NsXmlNs != ns && ns != null) {
                            throw new ArgumentException(Res.GetString(Res.Xml_XmlnsBelongsToReservedNs)); 
                        }
                        if (localName == null || localName.Length == 0) { 
                            localName = prefix; 
                            prefix = null;
                            this.prefixForXmlNs = null; 
                        }
                        else {
                            this.prefixForXmlNs = localName;
                        } 
                        this.specialAttr = SpecialAttr.XmlNs;
                    } 
                    else if (prefix == null && localName == "xmlns") { 
                        if (XmlReservedNs.NsXmlNs != ns && ns != null) {
                            // add the below line back in when DOM is fixed 
                            throw new ArgumentException(Res.GetString(Res.Xml_XmlnsBelongsToReservedNs));
                        }
                        this.specialAttr = SpecialAttr.XmlNs;
                        this.prefixForXmlNs = null; 
                    }
                    else { 
                        if (ns == null) { 
                            // use defined prefix
                            if (prefix != null && (LookupNamespace(prefix) == -1)) { 
                                throw new ArgumentException(Res.GetString(Res.Xml_UndefPrefix));
                            }
                        }
                        else if (ns.Length == 0) { 
                            // empty namespace require null prefix
                            prefix = string.Empty; 
                        } 
                        else { // ns.Length != 0
                            VerifyPrefixXml(prefix, ns); 
                            if (prefix != null && LookupNamespaceInCurrentScope(prefix) != -1) {
                                prefix = null;
                            }
                            // Now verify prefix validity 
                            string definedPrefix = FindPrefix(ns);
                            if (definedPrefix != null && (prefix == null || prefix == definedPrefix)) { 
                                prefix = definedPrefix; 
                            }
                            else { 
                                if (prefix == null) {
                                    prefix = GeneratePrefix(); // need a prefix if
                                }
                                PushNamespace(prefix, ns, false); 
                            }
                        } 
                    } 
                    if (prefix != null && prefix.Length != 0) {
                        textWriter.Write(prefix); 
                        textWriter.Write(':');
                    }
                }
                else { 
                    if ((ns != null && ns.Length != 0) || (prefix != null && prefix.Length != 0)) {
                        throw new ArgumentException(Res.GetString(Res.Xml_NoNamespaces)); 
                    } 
                    if (localName == "xml:lang") {
                        this.specialAttr = SpecialAttr.XmlLang; 
                    }
                    else if (localName == "xml:space") {
                        this.specialAttr = SpecialAttr.XmlSpace;
                    } 
                }
                xmlEncoder.StartAttribute(this.specialAttr != SpecialAttr.None); 
 
                textWriter.Write(localName);
                textWriter.Write('='); 
                if (this.curQuoteChar != this.quoteChar) {
                    this.curQuoteChar = this.quoteChar;
                    xmlEncoder.QuoteChar = this.quoteChar;
                } 
                textWriter.Write(this.curQuoteChar);
            } 
            catch { 
                currentState = State.Error;
                throw; 
            }
        }

        // Closes the attribute opened by WriteStartAttribute. 
        public override void WriteEndAttribute() {
            try { 
                AutoComplete(Token.EndAttribute); 
            }
            catch { 
                currentState = State.Error;
                throw;
            }
        } 

        // Writes out a <![CDATA[...]]> block containing the specified text. 
        public override void WriteCData(string text) { 
            try {
                AutoComplete(Token.CData); 
                if (null != text && text.IndexOf("]]>", StringComparison.Ordinal) >= 0) {
                    throw new ArgumentException(Res.GetString(Res.Xml_InvalidCDataChars));
                }
                textWriter.Write(""); 
            }
            catch {
                currentState = State.Error;
                throw; 
            }
        } 
 
        // Writes out a comment  containing the specified text.
        public override void WriteComment(string text) { 
            try {
                if (null != text && (text.IndexOf("--", StringComparison.Ordinal)>=0 || (text.Length != 0 && text[text.Length-1] == '-'))) {
                    throw new ArgumentException(Res.GetString(Res.Xml_InvalidCommentChars));
                } 
                AutoComplete(Token.Comment);
                textWriter.Write("");
            }
            catch {
                currentState = State.Error; 
                throw;
            } 
        } 

        // Writes out a processing instruction with a space between the name and text as follows:  
        public override void WriteProcessingInstruction(string name, string text) {
            try {
                if (null != text && text.IndexOf("?>", StringComparison.Ordinal)>=0) {
                    throw new ArgumentException(Res.GetString(Res.Xml_InvalidPiChars)); 
                }
                if (0 == String.Compare(name, "xml", StringComparison.OrdinalIgnoreCase) && this.stateTable == stateTableDocument) { 
                    throw new ArgumentException(Res.GetString(Res.Xml_DupXmlDecl)); 
                }
                AutoComplete(Token.PI); 
                InternalWriteProcessingInstruction(name, text);
            }
            catch {
                currentState = State.Error; 
                throw;
            } 
        } 

        // Writes out an entity reference as follows: "&"+name+";". 
        public override void WriteEntityRef(string name) {
            try {
                ValidateName(name, false);
                AutoComplete(Token.Content); 
                xmlEncoder.WriteEntityRef(name);
            } 
            catch { 
                currentState = State.Error;
                throw; 
            }
        }

        // Forces the generation of a character entity for the specified Unicode character value. 
        public override void WriteCharEntity(char ch) {
            try { 
                AutoComplete(Token.Content); 
                xmlEncoder.WriteCharEntity(ch);
            } 
            catch {
                currentState = State.Error;
                throw;
            } 
        }
 
        // Writes out the given whitespace. 
        public override void WriteWhitespace(string ws) {
            try { 
                if (null == ws || ws.Length == 0) {
                    throw new ArgumentException(Res.GetString(Res.Xml_NonWhitespace));
                }
 
                if (!xmlCharType.IsOnlyWhitespace(ws)) {
                    throw new ArgumentException(Res.GetString(Res.Xml_NonWhitespace)); 
                } 
                AutoComplete(Token.Whitespace);
                xmlEncoder.Write(ws); 
            }
            catch {
                currentState = State.Error;
                throw; 
            }
        } 
 
        // Writes out the specified text content.
        public override void WriteString(string text) { 
            try {
                if (null != text && text.Length != 0 ) {
                    AutoComplete(Token.Content);
                    xmlEncoder.Write(text); 
                }
            } 
            catch { 
                currentState = State.Error;
                throw; 
            }
        }

        // Writes out the specified surrogate pair as a character entity. 
        public override void WriteSurrogateCharEntity(char lowChar, char highChar){
            try { 
                AutoComplete(Token.Content); 
                xmlEncoder.WriteSurrogateCharEntity(lowChar, highChar);
            } 
            catch {
                currentState = State.Error;
                throw;
            } 
        }
 
 
        // Writes out the specified text content.
        public override void WriteChars(Char[] buffer, int index, int count) { 
            try {
                AutoComplete(Token.Content);
                xmlEncoder.Write(buffer, index, count);
            } 
            catch {
                currentState = State.Error; 
                throw; 
            }
        } 

        // Writes raw markup from the specified character buffer.
        public override void WriteRaw(Char[] buffer, int index, int count) {
            try { 
                AutoComplete(Token.RawData);
                xmlEncoder.WriteRaw(buffer, index, count); 
            } 
            catch {
                currentState = State.Error; 
                throw;
            }
        }
 
        // Writes raw markup from the specified character string.
        public override void WriteRaw(String data) { 
            try { 
                AutoComplete(Token.RawData);
                xmlEncoder.WriteRawWithSurrogateChecking(data); 
            }
            catch {
                currentState = State.Error;
                throw; 
            }
        } 
 
        // Encodes the specified binary bytes as base64 and writes out the resulting text.
        public override void WriteBase64(byte[] buffer, int index, int count) { 
            try {
                if (!this.flush) {
                    AutoComplete(Token.Base64);
                } 

                this.flush = true; 
                // No need for us to explicitly validate the args. The StreamWriter will do 
                // it for us.
                if (null == this.base64Encoder) { 
                    this.base64Encoder = new XmlTextWriterBase64Encoder( xmlEncoder );
                }
                // Encode will call WriteRaw to write out the encoded characters
                this.base64Encoder.Encode( buffer, index, count ); 
            }
            catch { 
                currentState = State.Error; 
                throw;
            } 
        }


        // Encodes the specified binary bytes as binhex and writes out the resulting text. 
        public override void WriteBinHex( byte[] buffer, int index, int count ) {
            try { 
                AutoComplete( Token.Content ); 
                BinHexEncoder.Encode( buffer, index, count, this );
            } 
            catch {
                currentState = State.Error;
                throw;
            } 
        }
 
        // Returns the state of the XmlWriter. 
        public override WriteState WriteState {
            get { 
                switch (this.currentState) {
                    case State.Start :
                        return WriteState.Start;
                    case State.Prolog : 
                    case State.PostDTD :
                        return WriteState.Prolog; 
                    case State.Element : 
                        return WriteState.Element;
                    case State.Attribute : 
                    case State.AttrOnly:
                        return WriteState.Attribute;
                    case State.Content :
                    case State.Epilog : 
                        return WriteState.Content;
                    case State.Error: 
                        return WriteState.Error; 
                    case State.Closed:
                        return WriteState.Closed; 
                    default:
                        Debug.Assert( false );
                        return WriteState.Error;
                } 
            }
        } 
 
        // Closes the XmlWriter and the underlying stream/TextWriter.
        public override void Close() { 
            try {
                AutoCompleteAll();
            }
            catch { // never fail 
            }
            finally { 
                this.currentState = State.Closed; 
                textWriter.Close();
            } 
        }

        // Flushes whatever is in the buffer to the underlying stream/TextWriter and flushes the underlying stream/TextWriter.
        public override void Flush() { 
            textWriter.Flush();
        } 
 
        // Writes out the specified name, ensuring it is a valid Name according to the XML specification
        // (http://www.w3.org/TR/1998/REC-xml-19980210#NT-Name 
        public override void WriteName(string name) {
            try {
                AutoComplete(Token.Content);
                InternalWriteName(name, false); 
            }
            catch { 
                currentState = State.Error; 
                throw;
            } 
        }

        // Writes out the specified namespace-qualified name by looking up the prefix that is in scope for the given namespace.
        public override void WriteQualifiedName(string localName, string ns) { 
            try {
                AutoComplete(Token.Content); 
                if (this.namespaces) { 
                    if (ns != null && ns.Length != 0 && ns != stack[top].defaultNs) {
                        string prefix = FindPrefix(ns); 
                        if (prefix == null) {
                            if (this.currentState != State.Attribute) {
                                throw new ArgumentException(Res.GetString(Res.Xml_UndefNamespace, ns));
                            } 
                            prefix = GeneratePrefix(); // need a prefix if
                            PushNamespace(prefix, ns, false); 
                        } 
                        if (prefix.Length != 0) {
                            InternalWriteName(prefix, true); 
                            textWriter.Write(':');
                        }
                    }
                } 
                else if (ns != null && ns.Length != 0) {
                    throw new ArgumentException(Res.GetString(Res.Xml_NoNamespaces)); 
                } 
                InternalWriteName(localName, true);
            } 
            catch {
                currentState = State.Error;
                throw;
            } 
        }
 
        // Returns the closest prefix defined in the current namespace scope for the specified namespace URI. 
        public override string LookupPrefix(string ns) {
            if (ns == null || ns.Length == 0) { 
                throw new ArgumentException(Res.GetString(Res.Xml_EmptyName));
            }
            string s =  FindPrefix(ns);
            if (s == null && ns == stack[top].defaultNs) { 
                s = string.Empty;
            } 
            return s; 
        }
 
        // Gets an XmlSpace representing the current xml:space scope.
        public override XmlSpace XmlSpace {
            get {
                for (int i = top; i > 0; i--) { 
                    XmlSpace xs = stack[i].xmlSpace;
                    if (xs != XmlSpace.None) 
                        return xs; 
                }
                return XmlSpace.None; 
            }
        }

        // Gets the current xml:lang scope. 
        public override string XmlLang {
            get { 
                for (int i = top; i > 0; i--) { 
                    String xlang = stack[i].xmlLang;
                    if (xlang != null) 
                        return xlang;
                }
                return null;
            } 
        }
 
        // Writes out the specified name, ensuring it is a valid NmToken 
        // according to the XML specification (http://www.w3.org/TR/1998/REC-xml-19980210#NT-Name).
        public override void WriteNmToken(string name) { 
            try {
                AutoComplete(Token.Content);

                if (name == null || name.Length == 0) { 
                    throw new ArgumentException(Res.GetString(Res.Xml_EmptyName));
                } 
                if (!xmlCharType.IsNmToken(name)) { 
                    throw new ArgumentException(Res.GetString(Res.Xml_InvalidNameChars, name));
                } 
                textWriter.Write(name);
            }
            catch {
                currentState = State.Error; 
                throw;
            } 
        } 

// 
// Private implementation methods
//
        void StartDocument(int standalone) {
            try { 
                if (this.currentState != State.Start) {
                    throw new InvalidOperationException(Res.GetString(Res.Xml_NotTheFirst)); 
                } 
                this.stateTable = stateTableDocument;
                this.currentState = State.Prolog; 

                StringBuilder bufBld = new StringBuilder(128);
                bufBld.Append("version=" + quoteChar + "1.0" + quoteChar);
                if (this.encoding != null) { 
                    bufBld.Append(" encoding=");
                    bufBld.Append(quoteChar); 
                    bufBld.Append(this.encoding.WebName); 
                    bufBld.Append(quoteChar);
                } 
                if (standalone >= 0) {
                    bufBld.Append(" standalone=");
                    bufBld.Append(quoteChar);
                    bufBld.Append(standalone == 0 ? "no" : "yes"); 
                    bufBld.Append(quoteChar);
                } 
                InternalWriteProcessingInstruction("xml", bufBld.ToString()); 
            }
            catch { 
                currentState = State.Error;
                throw;
            }
        } 

        void AutoComplete(Token token) { 
            if (this.currentState == State.Closed) { 
                throw new InvalidOperationException(Res.GetString(Res.Xml_Closed));
            } 
            else if (this.currentState == State.Error) {
                throw new InvalidOperationException(Res.GetString(Res.Xml_WrongToken, tokenName[(int)token], stateName[(int)State.Error]));
            }
 
            State newState = this.stateTable[(int)token * 8 + (int)this.currentState];
            if (newState == State.Error) { 
                throw new InvalidOperationException(Res.GetString(Res.Xml_WrongToken, tokenName[(int)token], stateName[(int)this.currentState])); 
            }
 
            switch (token) {
                case Token.Doctype:
                    if (this.indented && this.currentState != State.Start) {
                        Indent(false); 
                    }
                    break; 
 
                case Token.StartElement:
                case Token.Comment: 
                case Token.PI:
                case Token.CData:
                    if (this.currentState == State.Attribute) {
                        WriteEndAttributeQuote(); 
                        WriteEndStartTag(false);
                    } 
                    else if (this.currentState == State.Element) { 
                        WriteEndStartTag(false);
                    } 
                    if (token == Token.CData) {
                        stack[top].mixed = true;
                    }
                    else if (this.indented && this.currentState != State.Start) { 
                        Indent(false);
                    } 
                    break; 

                case Token.EndElement: 
                case Token.LongEndElement:
                    if (this.flush) {
                        FlushEncoders();
                    } 
                    if (this.currentState == State.Attribute) {
                        WriteEndAttributeQuote(); 
                    } 
                    if (this.currentState == State.Content) {
                        token = Token.LongEndElement; 
                    }
                    else {
                        WriteEndStartTag(token == Token.EndElement);
                    } 
                    if (stateTableDocument == this.stateTable && top == 1) {
                        newState = State.Epilog; 
                    } 
                    break;
 
                case Token.StartAttribute:
                    if (this.flush) {
                        FlushEncoders();
                    } 
                    if (this.currentState == State.Attribute) {
                        WriteEndAttributeQuote(); 
                        textWriter.Write(' '); 
                    }
                    else if (this.currentState == State.Element) { 
                        textWriter.Write(' ');
                    }
                    break;
 
                case Token.EndAttribute:
                    if (this.flush) { 
                        FlushEncoders(); 
                    }
                    WriteEndAttributeQuote(); 
                    break;

                case Token.Whitespace:
                case Token.Content: 
                case Token.RawData:
                case Token.Base64: 
 
                    if (token != Token.Base64 && this.flush) {
                        FlushEncoders(); 
                    }
                    if (this.currentState == State.Element && this.lastToken != Token.Content) {
                        WriteEndStartTag(false);
                    } 
                    if (newState == State.Content) {
                        stack[top].mixed = true; 
                    } 
                    break;
 
                default:
                    throw new InvalidOperationException(Res.GetString(Res.Xml_InvalidOperation));
            }
            this.currentState = newState; 
            this.lastToken = token;
        } 
 
        void AutoCompleteAll() {
            if (this.flush) { 
                FlushEncoders();
            }
            while (top > 0) {
                WriteEndElement(); 
            }
        } 
 
        void InternalWriteEndElement(bool longFormat) {
            try { 
                if (top <= 0) {
                    throw new InvalidOperationException(Res.GetString(Res.Xml_NoStartTag));
                }
                // if we are in the element, we need to close it. 
                AutoComplete(longFormat ?  Token.LongEndElement : Token.EndElement);
                if (this.lastToken == Token.LongEndElement) { 
                    if (this.indented) { 
                        Indent(true);
                    } 
                    textWriter.Write('<');
                    textWriter.Write('/');
                    if (this.namespaces && stack[top].prefix != null) {
                        textWriter.Write(stack[top].prefix); 
                        textWriter.Write(':');
                    } 
                    textWriter.Write(stack[top].name); 
                    textWriter.Write('>');
                } 

                // pop namespaces
                int prevNsTop = stack[top].prevNsTop;
                if (useNsHashtable && prevNsTop < nsTop) { 
                    PopNamespaces(prevNsTop + 1, nsTop);
                } 
                nsTop = prevNsTop; 
                top--;
            } 
            catch {
                currentState = State.Error;
                throw;
            } 
        }
 
        void WriteEndStartTag(bool empty) { 
            xmlEncoder.StartAttribute(false);
            for (int i = nsTop; i > stack[top].prevNsTop; i--) { 
                if (!nsStack[i].declared) {
                    textWriter.Write(" xmlns");
                    textWriter.Write(':');
                    textWriter.Write(nsStack[i].prefix); 
                    textWriter.Write('=');
                    textWriter.Write(this.quoteChar); 
                    xmlEncoder.Write(nsStack[i].ns); 
                    textWriter.Write(this.quoteChar);
                } 
            }
            // Default
            if ((stack[top].defaultNs != stack[top - 1].defaultNs) &&
                (stack[top].defaultNsState == NamespaceState.DeclaredButNotWrittenOut)) { 
                textWriter.Write(" xmlns");
                textWriter.Write('='); 
                textWriter.Write(this.quoteChar); 
                xmlEncoder.Write(stack[top].defaultNs);
                textWriter.Write(this.quoteChar); 
                stack[top].defaultNsState = NamespaceState.DeclaredAndWrittenOut;
            }
            xmlEncoder.EndAttribute();
            if (empty) { 
                textWriter.Write(" /");
            } 
            textWriter.Write('>'); 
        }
 
        void WriteEndAttributeQuote() {
            if (this.specialAttr != SpecialAttr.None) {
                // Ok, now to handle xmlspace, etc.
                HandleSpecialAttribute(); 
            }
            xmlEncoder.EndAttribute(); 
            textWriter.Write(this.curQuoteChar); 
        }
 
        void Indent(bool beforeEndElement) {
            // pretty printing.
            if (top == 0) {
                textWriter.WriteLine(); 
            }
            else if (!stack[top].mixed) { 
                textWriter.WriteLine(); 
                int i = beforeEndElement ? top - 1 : top;
                for (i *= this.indentation; i > 0; i--) { 
                    textWriter.Write(this.indentChar);
                }
            }
        } 

        // pushes new namespace scope, and returns generated prefix, if one 
        // was needed to resolve conflicts. 
        void PushNamespace(string prefix, string ns, bool declared) {
            if (XmlReservedNs.NsXmlNs == ns) { 
                throw new ArgumentException(Res.GetString(Res.Xml_CanNotBindToReservedNamespace));
            }

            if (prefix == null) { 
                switch (stack[top].defaultNsState) {
                    case NamespaceState.DeclaredButNotWrittenOut: 
                        Debug.Assert (declared == true, "Unexpected situation!!"); 
                        // the first namespace that the user gave us is what we
                        // like to keep. 
                        break;
                    case NamespaceState.Uninitialized:
                    case NamespaceState.NotDeclaredButInScope:
                        // we now got a brand new namespace that we need to remember 
                        stack[top].defaultNs = ns;
                        break; 
                    default: 
                        Debug.Assert(false, "Should have never come here");
                        return; 
                }
                stack[top].defaultNsState = (declared ? NamespaceState.DeclaredAndWrittenOut : NamespaceState.DeclaredButNotWrittenOut);
            }
            else { 
                if (prefix.Length != 0 && ns.Length == 0) {
                    throw new ArgumentException(Res.GetString(Res.Xml_PrefixForEmptyNs)); 
                } 

                int existingNsIndex = LookupNamespace(prefix); 
                if (existingNsIndex != -1 && nsStack[existingNsIndex].ns == ns) {
                    // it is already in scope.
                    if (declared) {
                        nsStack[existingNsIndex].declared = true; 
                    }
                } 
                else { 
                    // see if prefix conflicts for the current element
                    if (declared) { 
                        if (existingNsIndex != -1 && existingNsIndex > stack[top].prevNsTop) {
                            nsStack[existingNsIndex].declared = true; // old one is silenced now
                        }
                    } 
                    AddNamespace(prefix, ns, declared);
                } 
            } 
        }
 
        void AddNamespace(string prefix, string ns, bool declared) {
            int nsIndex = ++nsTop;
            if ( nsIndex == nsStack.Length ) {
                Namespace[] newStack = new Namespace[nsIndex * 2]; 
                Array.Copy(nsStack, newStack, nsIndex);
                nsStack = newStack; 
            } 
            nsStack[nsIndex].Set(prefix, ns, declared);
 
            if (useNsHashtable) {
                AddToNamespaceHashtable(nsIndex);
            }
            else if (nsIndex == MaxNamespacesWalkCount) { 
                // add all
                nsHashtable = new Dictionary(new SecureStringHasher()); 
                for (int i = 0; i <= nsIndex; i++) { 
                    AddToNamespaceHashtable(i);
                } 
                useNsHashtable = true;
            }
        }
 
        void AddToNamespaceHashtable(int namespaceIndex) {
            string prefix = nsStack[namespaceIndex].prefix; 
            int existingNsIndex; 
            if ( nsHashtable.TryGetValue(prefix, out existingNsIndex)) {
                nsStack[namespaceIndex].prevNsIndex = existingNsIndex; 
            }
            nsHashtable[prefix] = namespaceIndex;
        }
 
        private void PopNamespaces(int indexFrom, int indexTo) {
            Debug.Assert(useNsHashtable); 
            for (int i = indexTo; i >= indexFrom; i--) { 
                Debug.Assert(nsHashtable.ContainsKey(nsStack[i].prefix));
                if (nsStack[i].prevNsIndex == -1) { 
                    nsHashtable.Remove(nsStack[i].prefix);
                }
                else {
                    nsHashtable[nsStack[i].prefix] = nsStack[i].prevNsIndex; 
                }
            } 
        } 

        string GeneratePrefix() { 
            int temp = stack[top].prefixCount++ + 1;
            return "d" + top.ToString("d", CultureInfo.InvariantCulture)
                + "p" + temp.ToString("d", CultureInfo.InvariantCulture);
        } 

        void InternalWriteProcessingInstruction(string name, string text) { 
            textWriter.Write("");
        } 
 
        int LookupNamespace( string prefix ) {
            if ( useNsHashtable ) { 
                int nsIndex;
                if ( nsHashtable.TryGetValue( prefix, out nsIndex ) ) {
                    return nsIndex;
                } 
            }
            else { 
                for ( int i = nsTop; i >= 0; i-- ) { 
                    if ( nsStack[i].prefix == prefix ) {
                        return i; 
                    }
                }
            }
            return -1; 
        }
 
        int LookupNamespaceInCurrentScope( string prefix ) { 
            if ( useNsHashtable ) {
                int nsIndex; 
                if ( nsHashtable.TryGetValue( prefix, out nsIndex ) ) {
                    if ( nsIndex > stack[top].prevNsTop ) {
                        return nsIndex;
                    } 
                }
            } 
            else { 
                for ( int i = nsTop; i > stack[top].prevNsTop; i-- ) {
                    if ( nsStack[i].prefix == prefix ) { 
                        return i;
                    }
                }
            } 
            return -1;
        } 
 
        string FindPrefix(string ns) {
            for (int i = nsTop; i >= 0; i--) { 
                if (nsStack[i].ns == ns) {
                    if (LookupNamespace(nsStack[i].prefix) == i) {
                        return nsStack[i].prefix;
                    } 
                }
            } 
            return null; 
        }
 
        // There are three kind of strings we write out - Name, LocalName and Prefix.
        // Both LocalName and Prefix can be represented with NCName == false and Name
        // can be represented as NCName == true
 
        void InternalWriteName(string name, bool NCName) {
            ValidateName(name, NCName); 
            textWriter.Write(name); 
        }
 
        private unsafe void ValidateName(string name, bool NCName) {
            if (name == null || name.Length == 0) {
                throw new ArgumentException(Res.GetString(Res.Xml_EmptyName));
            } 
            int nameLength = name.Length;
            int position   = 0; 
            int colonPosition = -1; 

            if (namespaces) { 
                if ((xmlCharType.charProperties[name[position]] & XmlCharType.fNCStartName) != 0) { // if (xmlCharType.IsStartNCNameChar(name[position])) {
            Continue:
                    position ++;
                    while (position < nameLength && 
                        (xmlCharType.charProperties[name[position]] & XmlCharType.fNCName) != 0) { // xmlCharType.IsNCNameChar(name[position])) {
                        position ++; 
                    } 
                    if (position == nameLength) {
                        return; 
                    }
                    if (name[position] == ':') {
                        if (!NCName) {
                            if (colonPosition == -1) { 
                                if (position + 1 < nameLength) {
                                    colonPosition = position; 
                                    // We should check if the character after ':' is a valid start name 
                                    // character but we can't do that because of backward compatilibity
                                    goto Continue; 
                                }
                            }
                        }
                    } 
                }
            } 
            else { 
                if ((xmlCharType.charProperties[name[0]] & XmlCharType.fNCStartName) != 0 || name[0] == ':') { // if (xmlCharType.IsStartNameChar(name[0])) {
                    position ++; 
                    while (position < nameLength &&
                        ((xmlCharType.charProperties[name[position]] & XmlCharType.fNCName) != 0 || name[position] == ':')) { // xmlCharType.IsNameChar(name[position])) {
                        position ++;
                    } 
                    if (position == nameLength) {
                        return; 
                    } 
                }
            } 
            throw new ArgumentException(Res.GetString(Res.Xml_InvalidNameChars, name));
        }

        void HandleSpecialAttribute() { 
            string value = xmlEncoder.AttributeValue;
            switch (this.specialAttr) { 
                case SpecialAttr.XmlLang: 
                    stack[top].xmlLang = value;
                    break; 
                case SpecialAttr.XmlSpace:
                    // validate XmlSpace attribute
                    value = XmlConvert.TrimString(value);
                    if (value == "default") { 
                        stack[top].xmlSpace = XmlSpace.Default;
                    } 
                    else if (value == "preserve") { 
                        stack[top].xmlSpace = XmlSpace.Preserve;
                    } 
                    else {
                        throw new ArgumentException(Res.GetString(Res.Xml_InvalidXmlSpace, value));
                    }
                    break; 
                case SpecialAttr.XmlNs:
                    VerifyPrefixXml(this.prefixForXmlNs, value); 
                    PushNamespace(this.prefixForXmlNs, value, true); 
                    break;
            } 
        }


        void VerifyPrefixXml(string prefix, string ns) { 

            if (prefix != null && prefix.Length == 3) { 
                if ( 
                   (prefix[0] == 'x' || prefix[0] == 'X') &&
                   (prefix[1] == 'm' || prefix[1] == 'M') && 
                   (prefix[2] == 'l' || prefix[2] == 'L')
                   ) {
                    if (XmlReservedNs.NsXml != ns) {
                        throw new ArgumentException(Res.GetString(Res.Xml_InvalidPrefix)); 
                    }
                } 
            } 
        }
 
        void PushStack() {
            if (top == stack.Length - 1) {
                TagInfo[] na = new TagInfo[stack.Length + 10];
                if (top > 0) Array.Copy(stack,na,top + 1); 
                stack = na;
            } 
 
            top++; // Move up stack
            stack[top].Init(nsTop); 
        }

        void FlushEncoders()
        { 
            if (null != this.base64Encoder) {
                // The Flush will call WriteRaw to write out the rest of the encoded characters 
                this.base64Encoder.Flush(); 
            }
            this.flush = false; 
        }
   }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK