XmlWellformedWriter.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FXUpdate3074 / FXUpdate3074 / 1.1 / untmp / whidbey / QFE / ndp / fx / src / Xml / System / Xml / Core / XmlWellformedWriter.cs / 5 / XmlWellformedWriter.cs

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

// OpenIssue : is it better to cache the current namespace decls for each elem 
//  as the current code does, or should it just always walk the namespace stack?

namespace System.Xml {
 
    internal class XmlWellFormedWriter : XmlWriter {
        // 
        // Private types 
        //
        class NamespaceResolverProxy : IXmlNamespaceResolver { 
            XmlWellFormedWriter wfWriter;

            internal NamespaceResolverProxy(XmlWellFormedWriter wfWriter) {
                this.wfWriter = wfWriter; 
            }
 
            IDictionary IXmlNamespaceResolver.GetNamespacesInScope(XmlNamespaceScope scope) { 
                throw new NotImplementedException();
            } 
            string IXmlNamespaceResolver.LookupNamespace(string prefix) {
                return wfWriter.LookupNamespace(prefix);
            }
 
            string IXmlNamespaceResolver.LookupPrefix(string namespaceName) {
                return wfWriter.LookupPrefix(namespaceName); 
            } 
        }
 
        struct ElementScope {
            internal int prevNSTop;
            internal string prefix;
            internal string localName; 
            internal string namespaceUri;
            internal XmlSpace xmlSpace; 
            internal string xmlLang; 

            internal void Set(string prefix, string localName, string namespaceUri, int prevNSTop) { 
                this.prevNSTop = prevNSTop;
                this.prefix = prefix;
                this.namespaceUri = namespaceUri;
                this.localName = localName; 
                this.xmlSpace = (System.Xml.XmlSpace)(int)-1;
                this.xmlLang = null; 
            } 

            internal void WriteEndElement(XmlRawWriter rawWriter) { 
                rawWriter.WriteEndElement(prefix, localName, namespaceUri);
            }

            internal void WriteFullEndElement(XmlRawWriter rawWriter) { 
                rawWriter.WriteFullEndElement(prefix, localName, namespaceUri);
            } 
        } 

        enum NamespaceKind { 
            Written,
            NeedToWrite,
            Implied,
            Special, 
        }
 
        struct Namespace { 
            internal string prefix;
            internal string namespaceUri; 
            internal NamespaceKind kind;
            internal int prevNsIndex;

            internal void Set(string prefix, string namespaceUri, NamespaceKind kind) { 
                this.prefix = prefix;
                this.namespaceUri = namespaceUri; 
                this.kind = kind; 
                this.prevNsIndex = -1;
            } 

            internal void WriteDecl(XmlWriter writer, XmlRawWriter rawWriter) {
                Debug.Assert(kind == NamespaceKind.NeedToWrite);
                if (null != rawWriter) { 
                    rawWriter.WriteNamespaceDeclaration(prefix, namespaceUri);
                } 
                else { 
                    if (prefix.Length == 0) {
                        writer.WriteStartAttribute(string.Empty, "xmlns", XmlReservedNs.NsXmlNs); 
                    }
                    else {
                        writer.WriteStartAttribute("xmlns", prefix, XmlReservedNs.NsXmlNs);
                    } 
                    writer.WriteString(namespaceUri);
                    writer.WriteEndAttribute(); 
                } 
            }
        } 

        struct AttrName {
            internal string prefix;
            internal string namespaceUri; 
            internal string localName;
            internal int prev; 
 
            internal void Set(string prefix, string localName, string namespaceUri) {
                this.prefix = prefix; 
                this.namespaceUri = namespaceUri;
                this.localName = localName;
                this.prev = 0;
            } 

            internal bool IsDuplicate(string prefix, string localName, string namespaceUri) { 
                return ((this.localName == localName) 
                    && ((this.prefix == prefix) || (this.namespaceUri == namespaceUri)));
            } 
        }

        enum State {
            Start = 0, 
            TopLevel = 1,
            Document = 2, 
            Element = 3, 
            Content = 4,
            B64Content = 5, 
            B64Attribute = 6,
            AfterRootEle = 7,
            Attribute = 8,
            SpecialAttr = 9, 
            EndDocument = 10,
            RootLevelAttr = 11, 
            RootLevelSpecAttr = 12, 
            RootLevelB64Attr = 13,
            AfterRootLevelAttr = 14, 
            Closed = 15,
            Error = 16,

            StartContent = 101, 
            StartContentEle = 102,
            StartContentB64 = 103, 
            StartDoc = 104, 
            StartDocEle = 106,
            EndAttrSEle = 107, 
            EndAttrEEle = 108,
            EndAttrSCont = 109,
            EndAttrSAttr = 111,
            PostB64Cont = 112, 
            PostB64Attr = 113,
            PostB64RootAttr = 114, 
            StartFragEle = 115, 
            StartFragCont = 116,
            StartFragB64 = 117, 
            StartRootLevelAttr = 118,
        }

 
        enum Token {
            StartDocument, 
            EndDocument, 
            PI,
            Comment, 
            Dtd,
            StartElement,
            EndElement,
            StartAttribute, 
            EndAttribute,
            Text, 
            CData, 
            AtomicValue,
            Base64, 
            RawData,
            Whitespace,
        }
 
        enum SpecialAttribute {
            No = 0, 
            DefaultXmlns, 
            PrefixedXmlns,
            XmlSpace, 
            XmlLang
        }

        // 
        // Fields
        // 
        // underlying writer 
        XmlWriter writer;
        XmlRawWriter rawWriter;  // writer as XmlRawWriter 
        IXmlNamespaceResolver predefinedNamespaces; // writer as IXmlNamespaceResolver

        // namespace management
        Namespace[] nsStack; 
        int nsTop;
        Dictionary nsHashtable; 
        bool useNsHashtable; 

        // element scoping 
        ElementScope[] elemScopeStack;
        int elemTop;

        // attribute tracking 
        AttrName[] attrStack;
        int attrCount; 
        Dictionary attrHashTable; 

        // special attribute caching (xmlns, xml:space, xml:lang) 
        SpecialAttribute specAttr = SpecialAttribute.No;
        StringBuilder attrValue;
        string curDeclPrefix;
 
        // state machine
        State[] stateTable; 
        State currentState; 

        // settings 
        bool checkCharacters;

        // actual conformance level
        ConformanceLevel conformanceLevel; 

        // flags 
        bool dtdWritten; 
        bool xmlDeclFollows;
 
        // char type tables
        XmlCharType xmlCharType = XmlCharType.Instance;

        // hash randomizer 
        SecureStringHasher hasher;
 
 
        //
        // Constants 
        //
        const int ElementStackInitialSize = 8;
        const int NamespaceStackInitialSize = 8;
        const int AttributeArrayInitialSize = 8; 
#if DEBUG
        const int MaxAttrDuplWalkCount = 2; 
        const int MaxNamespacesWalkCount = 3; 
#else
        const int MaxAttrDuplWalkCount = 14; 
        const int MaxNamespacesWalkCount = 16;
#endif

        internal static readonly string[] stateName = { 
            "Start",                     // State.Start
            "TopLevel",                  // State.TopLevel 
            "Document",                  // State.Document 
            "Element Start Tag",         // State.Element
            "Element Content",           // State.Content 
            "Element Content",           // State.B64Content
            "Attribute",                 // State.B64Attribute
            "EndRootElement",            // State.AfterRootEle
            "Attribute",                 // State.Attribute 
            "Special Attribute",         // State.SpecialAttr
            "End Document",              // State.EndDocument 
            "Root Level Attribute Value",           // State.RootLevelAttr 
            "Root Level Special Attribute Value",   // State.RootLevelSpecAttr
            "Root Level Base64 Attribute Value",    // State.RootLevelB64Attr 
            "After Root Level Attribute",           // State.AfterRootLevelAttr
            "Closed",                    // State.Closed
            "Error",                     // State.Error
        }; 

        internal static readonly string[] tokenName = { 
            "StartDocument",            // Token.StartDocument 
            "EndDocument",              // Token.EndDocument
            "PI",                       // Token.PI 
            "Comment",                  // Token.Comment
            "DTD",                      // Token.Dtd
            "StartElement",             // Token.StartElement
            "EndElement",               // Token.EndElement 
            "StartAttribute",           // Token.StartAttribut
            "EndAttribute",             // Token.EndAttribute 
            "Text",                     // Token.Text 
            "CDATA",                    // Token.CData
            "Atomic value",             // Token.AtomicValue 
            "Base64",                   // Token.Base64
            "RawData",                  // Token.RawData
            "Whitespace",               // Token.Whitespace
        }; 

        private static WriteState[] state2WriteState = { 
            WriteState.Start,       // State.Start 
            WriteState.Prolog,      // State.TopLevel
            WriteState.Prolog,      // State.Document 
            WriteState.Element,     // State.Element
            WriteState.Content,     // State.Content
            WriteState.Content,     // State.B64Content
            WriteState.Attribute,   // State.B64Attribute 
            WriteState.Content,     // State.AfterRootEle
            WriteState.Attribute,   // State.Attribute 
            WriteState.Attribute,   // State.SpecialAttr 
            WriteState.Content,     // State.EndDocument
            WriteState.Attribute,   // State.RootLevelAttr 
            WriteState.Attribute,   // State.RootLevelSpecAttr
            WriteState.Attribute,   // State.RootLevelB64Attr
            WriteState.Attribute,   // State.AfterRootLevelAttr
            WriteState.Closed,      // State.Closed 
            WriteState.Error,       // State.Error
        }; 
 
        private static readonly State[] StateTableDocument = {
    //                         State.Start           State.TopLevel   State.Document     State.Element          State.Content     State.B64Content      State.B64Attribute   State.AfterRootEle    State.Attribute,      State.SpecialAttr,   State.EndDocument,  State.RootLevelAttr,      State.RootLevelSpecAttr,  State.RootLevelB64Attr   State.AfterRootLevelAttr, // 16 
    /* Token.StartDocument  */ State.Document,       State.Error,     State.Error,       State.Error,           State.Error,      State.PostB64Cont,    State.Error,         State.Error,          State.Error,          State.Error,         State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error,
    /* Token.EndDocument    */ State.Error,          State.Error,     State.Error,       State.Error,           State.Error,      State.PostB64Cont,    State.Error,         State.EndDocument,    State.Error,          State.Error,         State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error,
    /* Token.PI             */ State.StartDoc,       State.TopLevel,  State.Document,    State.StartContent,    State.Content,    State.PostB64Cont,    State.PostB64Attr,   State.AfterRootEle,   State.EndAttrSCont,   State.EndAttrSCont,  State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error,
    /* Token.Comment        */ State.StartDoc,       State.TopLevel,  State.Document,    State.StartContent,    State.Content,    State.PostB64Cont,    State.PostB64Attr,   State.AfterRootEle,   State.EndAttrSCont,   State.EndAttrSCont,  State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error, 
    /* Token.Dtd            */ State.StartDoc,       State.TopLevel,  State.Document,    State.Error,           State.Error,      State.PostB64Cont,    State.PostB64Attr,   State.Error,          State.Error,          State.Error,         State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error,
    /* Token.StartElement   */ State.StartDocEle,    State.Element,   State.Element,     State.StartContentEle, State.Element,    State.PostB64Cont,    State.PostB64Attr,   State.Error,          State.EndAttrSEle,    State.EndAttrSEle,   State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error, 
    /* Token.EndElement     */ State.Error,          State.Error,     State.Error,       State.StartContent,    State.Content,    State.PostB64Cont,    State.PostB64Attr,   State.Error,          State.EndAttrEEle,    State.EndAttrEEle,   State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error, 
    /* Token.StartAttribute */ State.Error,          State.Error,     State.Error,       State.Attribute,       State.Error,      State.PostB64Cont,    State.PostB64Attr,   State.Error,          State.EndAttrSAttr,   State.EndAttrSAttr,  State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error,
    /* Token.EndAttribute   */ State.Error,          State.Error,     State.Error,       State.Error,           State.Error,      State.PostB64Cont,    State.PostB64Attr,   State.Error,          State.Element,        State.Element,       State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error, 
    /* Token.Text           */ State.Error,          State.Error,     State.Error,       State.StartContent,    State.Content,    State.PostB64Cont,    State.PostB64Attr,   State.Error,          State.Attribute,      State.SpecialAttr,   State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error,
    /* Token.CData          */ State.Error,          State.Error,     State.Error,       State.StartContent,    State.Content,    State.PostB64Cont,    State.PostB64Attr,   State.Error,          State.EndAttrSCont,   State.EndAttrSCont,  State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error,
    /* Token.AtomicValue    */ State.Error,          State.Error,     State.Error,       State.StartContent,    State.Content,    State.PostB64Cont,    State.PostB64Attr,   State.Error,          State.Attribute,      State.Error,         State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error,
    /* Token.Base64         */ State.Error,          State.Error,     State.Error,       State.StartContentB64, State.B64Content, State.B64Content,     State.B64Attribute,  State.Error,          State.B64Attribute,   State.Error,         State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error, 
    /* Token.RawData        */ State.StartDoc,       State.Error,     State.Document,    State.StartContent,    State.Content,    State.PostB64Cont,    State.PostB64Attr,   State.AfterRootEle,   State.Attribute,      State.SpecialAttr,   State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error,
    /* Token.Whitespace     */ State.StartDoc,       State.TopLevel,  State.Document,    State.StartContent,    State.Content,    State.PostB64Cont,    State.PostB64Attr,   State.AfterRootEle,   State.Attribute,      State.SpecialAttr,   State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error 
        }; 

        private static readonly State[] StateTableAuto = { 
    //                         State.Start           State.TopLevel       State.Document     State.Element          State.Content     State.B64Content      State.B64Attribute   State.AfterRootEle    State.Attribute,      State.SpecialAttr,   State.EndDocument,  State.RootLevelAttr,      State.RootLevelSpecAttr,  State.RootLevelB64Attr,  State.AfterRootLevelAttr  // 16
    /* Token.StartDocument  */ State.Document,       State.Error,         State.Error,       State.Error,           State.Error,      State.PostB64Cont,    State.Error,         State.Error,          State.Error,          State.Error,         State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error, /* Token.StartDocument  */
    /* Token.EndDocument    */ State.Error,          State.Error,         State.Error,       State.Error,           State.Error,      State.PostB64Cont,    State.Error,         State.EndDocument,    State.Error,          State.Error,         State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error, /* Token.EndDocument    */
    /* Token.PI             */ State.TopLevel,       State.TopLevel,      State.Error,       State.StartContent,    State.Content,    State.PostB64Cont,    State.PostB64Attr,   State.AfterRootEle,   State.EndAttrSCont,   State.EndAttrSCont,  State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error, /* Token.PI             */ 
    /* Token.Comment        */ State.TopLevel,       State.TopLevel,      State.Error,       State.StartContent,    State.Content,    State.PostB64Cont,    State.PostB64Attr,   State.AfterRootEle,   State.EndAttrSCont,   State.EndAttrSCont,  State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error, /* Token.Comment        */
    /* Token.Dtd            */ State.StartDoc,       State.TopLevel,      State.Error,       State.Error,           State.Error,      State.PostB64Cont,    State.PostB64Attr,   State.Error,          State.Error,          State.Error,         State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error, /* Token.Dtd            */ 
    /* Token.StartElement   */ State.StartFragEle,   State.Element,       State.Error,       State.StartContentEle, State.Element,    State.PostB64Cont,    State.PostB64Attr,   State.Element,        State.EndAttrSEle,    State.EndAttrSEle,   State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error, /* Token.StartElement   */ 
    /* Token.EndElement     */ State.Error,          State.Error,         State.Error,       State.StartContent,    State.Content,    State.PostB64Cont,    State.PostB64Attr,   State.Error,          State.EndAttrEEle,    State.EndAttrEEle,   State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error, /* Token.EndElement     */
    /* Token.StartAttribute */ State.RootLevelAttr,  State.Error,         State.Error,       State.Attribute,       State.Error,      State.PostB64Cont,    State.PostB64Attr,   State.Error,          State.EndAttrSAttr,   State.EndAttrSAttr,  State.Error,        State.StartRootLevelAttr, State.StartRootLevelAttr, State.PostB64RootAttr,   State.RootLevelAttr,      State.Error, /* Token.StartAttribute */ 
    /* Token.EndAttribute   */ State.Error,          State.Error,         State.Error,       State.Error,           State.Error,      State.PostB64Cont,    State.PostB64Attr,   State.Error,          State.Element,        State.Element,       State.Error,        State.AfterRootLevelAttr, State.AfterRootLevelAttr, State.PostB64RootAttr,   State.Error,              State.Error, /* Token.EndAttribute   */
    /* Token.Text           */ State.StartFragCont,  State.StartFragCont, State.Error,       State.StartContent,    State.Content,    State.PostB64Cont,    State.PostB64Attr,   State.Content,        State.Attribute,      State.SpecialAttr,   State.Error,        State.RootLevelAttr,      State.RootLevelSpecAttr,  State.PostB64RootAttr,   State.Error,              State.Error, /* Token.Text           */
    /* Token.CData          */ State.StartFragCont,  State.StartFragCont, State.Error,       State.StartContent,    State.Content,    State.PostB64Cont,    State.PostB64Attr,   State.Content,        State.EndAttrSCont,   State.EndAttrSCont,  State.Error,        State.Error,              State.Error,              State.Error,             State.Error,              State.Error, /* Token.CData          */
    /* Token.AtomicValue    */ State.StartFragCont,  State.StartFragCont, State.Error,       State.StartContent,    State.Content,    State.PostB64Cont,    State.PostB64Attr,   State.Content,        State.Attribute,      State.Error,         State.Error,        State.RootLevelAttr,      State.Error,              State.PostB64RootAttr,   State.Error,              State.Error, /* Token.AtomicValue    */ 
    /* Token.Base64         */ State.StartFragB64,   State.StartFragB64,  State.Error,       State.StartContentB64, State.B64Content, State.B64Content,     State.B64Attribute,  State.B64Content,     State.B64Attribute,   State.Error,         State.Error,        State.RootLevelB64Attr,   State.Error,              State.RootLevelB64Attr,  State.Error,              State.Error, /* Token.Base64         */
    /* Token.RawData        */ State.StartFragCont,  State.TopLevel,      State.Error,       State.StartContent,    State.Content,    State.PostB64Cont,    State.PostB64Attr,   State.Content,        State.Attribute,      State.SpecialAttr,   State.Error,        State.RootLevelAttr,      State.RootLevelSpecAttr,  State.PostB64RootAttr,   State.AfterRootLevelAttr, State.Error, /* Token.RawData        */ 
    /* Token.Whitespace     */ State.TopLevel,       State.TopLevel,      State.Error,       State.StartContent,    State.Content,    State.PostB64Cont,    State.PostB64Attr,   State.AfterRootEle,   State.Attribute,      State.SpecialAttr,   State.Error,        State.RootLevelAttr,      State.RootLevelSpecAttr,  State.PostB64RootAttr,   State.AfterRootLevelAttr, State.Error, /* Token.Whitespace     */ 
        };
 
        //
        // Constructor & finalizer
        //
        internal XmlWellFormedWriter(XmlWriter writer, XmlWriterSettings settings) { 
            Debug.Assert(writer != null);
            Debug.Assert(settings != null); 
            Debug.Assert(MaxNamespacesWalkCount <= 3); 

            this.writer = writer; 

            rawWriter = writer as XmlRawWriter;
            predefinedNamespaces = writer as IXmlNamespaceResolver;
            if (rawWriter != null) { 
                rawWriter.NamespaceResolver = new NamespaceResolverProxy(this);
            } 
 
            checkCharacters = settings.CheckCharacters;
 
            conformanceLevel = settings.ConformanceLevel;
            stateTable = (conformanceLevel == ConformanceLevel.Document) ? StateTableDocument : StateTableAuto;

            currentState = State.Start; 

            nsStack = new Namespace[NamespaceStackInitialSize]; 
            nsStack[0].Set("xmlns", XmlReservedNs.NsXmlNs, NamespaceKind.Special); 
            nsStack[1].Set("xml", XmlReservedNs.NsXml, NamespaceKind.Special);
            if (predefinedNamespaces == null) { 
                nsStack[2].Set(string.Empty, string.Empty, NamespaceKind.Implied);
            }
            else {
                string defaultNs = predefinedNamespaces.LookupNamespace(string.Empty); 
                nsStack[2].Set(string.Empty, (defaultNs == null ? string.Empty : defaultNs), NamespaceKind.Implied);
            } 
            nsTop = 2; 

            elemScopeStack = new ElementScope[ElementStackInitialSize]; 
            elemScopeStack[0].Set(string.Empty, string.Empty, string.Empty, nsTop);
            elemScopeStack[0].xmlSpace = XmlSpace.None;
            elemScopeStack[0].xmlLang = null;
            elemTop = 0; 

            attrStack = new AttrName[AttributeArrayInitialSize]; 
 
            attrValue = new StringBuilder();
 
            hasher = new SecureStringHasher();
        }

        // 
        // XmlWriter implementation
        // 
        public override WriteState WriteState { 
            get {
                if ((int)currentState <= (int)State.Error) { 
                    return state2WriteState[(int)currentState];
                }
                else {
                    Debug.Assert(false, "Expected currentState <= State.Error "); 
                    return WriteState.Error;
                } 
            } 
        }
 
        public override XmlWriterSettings Settings {
            get {
                XmlWriterSettings settings = writer.Settings;
                settings.ReadOnly = false; 
                settings.ConformanceLevel = conformanceLevel;
                settings.ReadOnly = true; 
                return settings; 
            }
        } 

        public override void WriteStartDocument() {
            WriteStartDocumentImpl(XmlStandalone.Omit);
        } 

        public override void WriteStartDocument(bool standalone) { 
            WriteStartDocumentImpl(standalone ? XmlStandalone.Yes : XmlStandalone.No); 
        }
 
        public override void WriteEndDocument() {
            try {
                // auto-close all elements
                while (elemTop > 0) { 
                    WriteEndElement();
                } 
                State prevState = currentState; 
                AdvanceState(Token.EndDocument);
 
                if (prevState != State.AfterRootEle) {
                    throw new ArgumentException(Res.GetString(Res.Xml_NoRoot));
                }
                if (rawWriter == null) { 
                    writer.WriteEndDocument();
                } 
            } 
            catch {
                currentState = State.Error; 
                throw;
            }
        }
 
        public override void WriteDocType(string name, string pubid, string sysid, string subset) {
            try { 
                if (name == null || name.Length == 0) { 
                    throw new ArgumentException(Res.GetString(Res.Xml_EmptyName));
                } 
                XmlConvert.VerifyQName(name);

                if (conformanceLevel == ConformanceLevel.Fragment) {
                    throw new InvalidOperationException(Res.GetString(Res.Xml_DtdNotAllowedInFragment)); 
                }
 
                AdvanceState(Token.Dtd); 
                if (dtdWritten) {
                    currentState = State.Error; 
                    throw new InvalidOperationException(Res.GetString(Res.Xml_DtdAlreadyWritten));
                }

                if (conformanceLevel == ConformanceLevel.Auto) { 
                    conformanceLevel = ConformanceLevel.Document;
                    stateTable = StateTableDocument; 
                } 

                int i; 

                //
                if (checkCharacters) {
                    if (pubid != null) { 
                        if ((i = xmlCharType.IsPublicId(pubid)) >= 0) {
                            throw new ArgumentException(Res.GetString(Res.Xml_InvalidCharacter, XmlException.BuildCharExceptionStr(pubid[i])), "pubid"); 
                        } 
                    }
                    if (sysid != null) { 
                        if ((i = xmlCharType.IsOnlyCharData(sysid)) >= 0) {
                            throw new ArgumentException(Res.GetString(Res.Xml_InvalidCharacter, XmlException.BuildCharExceptionStr(sysid[i])), "sysid");
                        }
                    } 
                    if (subset != null) {
                        if ((i = xmlCharType.IsOnlyCharData(subset)) >= 0) { 
                            throw new ArgumentException(Res.GetString(Res.Xml_InvalidCharacter, XmlException.BuildCharExceptionStr(subset[i])), "subset"); 
                        }
                    } 
                }

                // write doctype
                writer.WriteDocType(name, pubid, sysid, subset); 
                dtdWritten = true;
            } 
            catch { 
                currentState = State.Error;
                throw; 
            }
        }

        public override void WriteStartElement(string prefix, string localName, string ns) { 
            try {
                // 
                if (localName == null || localName.Length == 0) { 
                    throw new ArgumentException(Res.GetString(Res.Xml_EmptyLocalName));
                } 
                CheckNCName(localName);

                AdvanceState(Token.StartElement);
 
                // lookup prefix / namespace
                if (prefix == null) { 
                    if (ns != null) { 
                        prefix = LookupPrefix(ns);
                    } 
                    if (prefix == null) {
                        prefix = string.Empty;
                    }
                } 
                else if (prefix.Length > 0) {
                    CheckNCName(prefix); 
                    if (ns == null) { 
                        ns = LookupNamespace(prefix);
                    } 
                    if (ns == null || (ns != null && ns.Length == 0)) {
                        throw new ArgumentException(Res.GetString(Res.Xml_PrefixForEmptyNs));
                    }
                } 
                if (ns == null) {
                    ns = LookupNamespace(prefix); 
                    if (ns == null) { 
                        Debug.Assert(prefix.Length == 0);
                        ns = string.Empty; 
                    }
                }

                if (elemTop == 0 && rawWriter != null) 
                {
                    // notify the underlying raw writer about the root level element 
                    rawWriter.OnRootElement(conformanceLevel); 
                }
 
                // write start tag
                writer.WriteStartElement(prefix, localName, ns);

                // push element on stack and add/ 
                int top = ++elemTop;
                if (top == elemScopeStack.Length) { 
                    ElementScope[] newStack = new ElementScope[top * 2]; 
                    Array.Copy(elemScopeStack, newStack, top);
                    elemScopeStack = newStack; 
                }
                elemScopeStack[top].Set(prefix, localName, ns, nsTop);

                PushNamespace(prefix, ns, false); 

                if (attrCount >= MaxAttrDuplWalkCount) { 
                    attrHashTable.Clear(); 
                }
                attrCount = 0; 

            }
            catch {
                currentState = State.Error; 
                throw;
            } 
        } 

 
        public override void WriteEndElement() {
            try {
                AdvanceState(Token.EndElement);
 
                int top = elemTop;
                if (top == 0) { 
                    throw new XmlException(Res.Xml_NoStartTag, string.Empty); 
                }
 
                // write end tag
                if (rawWriter != null) {
                    elemScopeStack[top].WriteEndElement(rawWriter);
                } 
                else {
                    writer.WriteEndElement(); 
                } 

                // pop namespaces 
                int prevNsTop = elemScopeStack[top].prevNSTop;
                if (useNsHashtable && prevNsTop < nsTop) {
                    PopNamespaces(prevNsTop + 1, nsTop);
                } 
                nsTop = prevNsTop;
                elemTop = --top; 
 
                //
                if (top == 0) { 
                    if (conformanceLevel == ConformanceLevel.Document) {
                        currentState = State.AfterRootEle;
                    }
                    else { 
                        currentState = State.TopLevel;
                    } 
                } 
            }
            catch { 
                currentState = State.Error;
                throw;
            }
        } 

        public override void WriteFullEndElement() { 
            try { 
                AdvanceState(Token.EndElement);
 
                int top = elemTop;
                if (top == 0) {
                    throw new XmlException(Res.Xml_NoStartTag, string.Empty);
                } 

                // write end tag 
                if (rawWriter != null) { 
                    elemScopeStack[top].WriteFullEndElement(rawWriter);
                } 
                else {
                    writer.WriteFullEndElement();
                }
 
                // pop namespaces
                int prevNsTop = elemScopeStack[top].prevNSTop; 
                if (useNsHashtable && prevNsTop < nsTop) { 
                    PopNamespaces(prevNsTop + 1, nsTop);
                } 
                nsTop = prevNsTop;
                elemTop = --top;

                // 
                if (top == 0) {
                    if (conformanceLevel == ConformanceLevel.Document) { 
                        currentState = State.AfterRootEle; 
                    }
                    else { 
                        currentState = State.TopLevel;
                    }
                }
            } 
            catch {
                currentState = State.Error; 
                throw; 
            }
        } 

        public override void WriteStartAttribute(string prefix, string localName, string namespaceName) {
            try {
                // 
                if (localName == null || localName.Length == 0) {
                    if (prefix == "xmlns") { 
                        localName = "xmlns"; 
                        prefix = string.Empty;
                    } 
                    else {
                        throw new ArgumentException(Res.GetString(Res.Xml_EmptyLocalName));
                    }
                } 
                CheckNCName(localName);
 
                AdvanceState(Token.StartAttribute); 

                // lookup prefix / namespace 
                if (prefix == null) {
                    if (namespaceName != null) {
                        // special case prefix=null/localname=xmlns
                        if (!(localName == "xmlns" && namespaceName == XmlReservedNs.NsXmlNs)) 
                            prefix = LookupPrefix(namespaceName);
                    } 
                    if (prefix == null) { 
                        prefix = string.Empty;
                    } 
                }
                if (namespaceName == null) {
                    if (prefix != null && prefix.Length > 0) {
                        namespaceName = LookupNamespace(prefix); 
                    }
                    if (namespaceName == null) { 
                        namespaceName = string.Empty; 
                    }
                } 

                if (prefix.Length == 0) {
                    if (localName[0] == 'x' && localName == "xmlns") {
                        if (namespaceName.Length > 0 && namespaceName != XmlReservedNs.NsXmlNs) { 
                            throw new ArgumentException(Res.GetString(Res.Xml_XmlnsPrefix));
                        } 
                        curDeclPrefix = String.Empty; 
                        SetSpecialAttribute(SpecialAttribute.DefaultXmlns);
                        goto SkipPushAndWrite; 
                    }
                    else if (namespaceName.Length > 0) {
                        prefix = LookupPrefix(namespaceName);
                        if (prefix == null || prefix.Length == 0) { 
                            prefix = GeneratePrefix();
                        } 
                    } 
                }
                else { 
                    if (prefix[0] == 'x') {
                        if (prefix == "xmlns") {
                            if (namespaceName.Length > 0 && namespaceName != XmlReservedNs.NsXmlNs) {
                                throw new ArgumentException(Res.GetString(Res.Xml_XmlnsPrefix)); 
                            }
                            curDeclPrefix = localName; 
                            SetSpecialAttribute(SpecialAttribute.PrefixedXmlns); 
                            goto SkipPushAndWrite;
                        } 
                        else if (prefix == "xml") {
                            if (namespaceName.Length > 0 && namespaceName != XmlReservedNs.NsXml) {
                                throw new ArgumentException(Res.GetString(Res.Xml_XmlPrefix));
                            } 
                            switch (localName) {
                                case "space": 
                                    SetSpecialAttribute(SpecialAttribute.XmlSpace); 
                                    goto SkipPushAndWrite;
                                case "lang": 
                                    SetSpecialAttribute(SpecialAttribute.XmlLang);
                                    goto SkipPushAndWrite;
                            }
                        } 
                    }
 
                    CheckNCName(prefix); 

                    if (namespaceName.Length == 0) { 
                        // attributes cannot have default namespace
                        prefix = string.Empty;
                    }
                    else { 
                        string definedNs = LookupLocalNamespace(prefix);
                        if (definedNs != null && definedNs != namespaceName) { 
                            prefix = GeneratePrefix(); 
                        }
                    } 
                }

                if (prefix.Length != 0) {
                    PushNamespace(prefix, namespaceName, false); 
                }
 
                // write attribute name 
                writer.WriteStartAttribute(prefix, localName, namespaceName);
 
            SkipPushAndWrite:
                // add attribute to the list and
                AddAttribute(prefix, localName, namespaceName);
            } 
            catch {
                currentState = State.Error; 
                throw; 
            }
        } 

        public override void WriteEndAttribute() {
            try {
                AdvanceState(Token.EndAttribute); 

                if (specAttr != SpecialAttribute.No) { 
                    string value; 
                    if (attrValue != null) {
                        value = attrValue.ToString(); 
                        attrValue.Length = 0;
                    }
                    else {
                        value = string.Empty; 
                    }
 
                    switch (specAttr) { 
                        case SpecialAttribute.DefaultXmlns:
                            PushNamespace(string.Empty, value, true); 
                            if (rawWriter != null) {
                                rawWriter.WriteNamespaceDeclaration(string.Empty, value);
                            }
                            else { 
                                writer.WriteAttributeString(string.Empty, "xmlns", XmlReservedNs.NsXmlNs, value);
                            } 
                            curDeclPrefix = null; 
                            break;
                        case SpecialAttribute.PrefixedXmlns: 
                            if (value.Length == 0) {
                                throw new ArgumentException(Res.GetString(Res.Xml_PrefixForEmptyNs));
                            }
                            if (value == XmlReservedNs.NsXmlNs || (value == XmlReservedNs.NsXml && curDeclPrefix != "xml")) { 
                                throw new ArgumentException(Res.GetString(Res.Xml_CanNotBindToReservedNamespace));
                            } 
                            PushNamespace(curDeclPrefix, value, true); 
                            if (rawWriter != null) {
                                rawWriter.WriteNamespaceDeclaration(curDeclPrefix, value); 
                            }
                            else {
                                writer.WriteAttributeString("xmlns", curDeclPrefix, XmlReservedNs.NsXmlNs, value);
                            } 
                            curDeclPrefix = null;
                            break; 
                        case SpecialAttribute.XmlSpace: 
                            value = XmlConvert.TrimString(value);
                            if (value == "default") { 
                                elemScopeStack[elemTop].xmlSpace = XmlSpace.Default;
                            }
                            else if (value == "preserve") {
                                elemScopeStack[elemTop].xmlSpace = XmlSpace.Preserve; 
                            }
                            else { 
                                throw new ArgumentException(Res.GetString(Res.Xml_InvalidXmlSpace, value)); 
                            }
                            writer.WriteAttributeString("xml", "space", XmlReservedNs.NsXml, value); 
                            break;
                        case SpecialAttribute.XmlLang:
                            elemScopeStack[elemTop].xmlLang = value;
                            writer.WriteAttributeString("xml", "lang", XmlReservedNs.NsXml, value); 
                            break;
                    } 
                    specAttr = SpecialAttribute.No; 
                }
                else { 
                    writer.WriteEndAttribute();
                }
            }
            catch { 
                currentState = State.Error;
                throw; 
            } 
        }
 
        public override void WriteCData(string text) {
            try {
                if (text == null) {
                    text = string.Empty; 
                }
                AdvanceState(Token.CData); 
                writer.WriteCData(text); 
            }
            catch { 
                currentState = State.Error;
                throw;
            }
        } 

        public override void WriteComment(string text) { 
            try { 
                if (text == null) {
                    text = string.Empty; 
                }
                AdvanceState(Token.Comment);
                writer.WriteComment(text);
            } 
            catch {
                currentState = State.Error; 
                throw; 
            }
        } 

        public override void WriteProcessingInstruction(string name, string text) {
            try {
                // 
                if (name == null || name.Length == 0) {
                    throw new ArgumentException(Res.GetString(Res.Xml_EmptyName)); 
                } 
                CheckNCName(name);
 
                //
                if (text == null) {
                    text = string.Empty;
                } 

                // xml declaration is a special case (not a processing instruction, but we allow WriteProcessingInstruction as a convenience) 
                if (name.Length == 3 && string.Compare(name, "xml", StringComparison.OrdinalIgnoreCase) == 0) { 
                    if (currentState != State.Start) {
                        throw new ArgumentException(Res.GetString(conformanceLevel == ConformanceLevel.Document ? Res.Xml_DupXmlDecl : Res.Xml_CannotWriteXmlDecl)); 
                    }

                    xmlDeclFollows = true;
                    AdvanceState(Token.PI); 

                    if (rawWriter != null) { 
                        // Translate PI into an xml declaration 
                        rawWriter.WriteXmlDeclaration(text);
                    } 
                    else {
                        writer.WriteProcessingInstruction(name, text);
                    }
                } 
                else {
                    AdvanceState(Token.PI); 
                    writer.WriteProcessingInstruction(name, text); 
                }
            } 
            catch {
                currentState = State.Error;
                throw;
            } 
        }
 
        public override void WriteEntityRef(string name) { 
            try {
                // 
                if (name == null || name.Length == 0) {
                    throw new ArgumentException(Res.GetString(Res.Xml_EmptyName));
                }
                CheckNCName(name); 

                AdvanceState(Token.Text); 
                if (SaveAttrValue) { 
                    attrValue.Append('&');
                    attrValue.Append(name); 
                    attrValue.Append(';');
                }
                else {
                    writer.WriteEntityRef(name); 
                }
            } 
            catch { 
                currentState = State.Error;
                throw; 
            }
        }

        public override void WriteCharEntity(char ch) { 
            try {
                if (Char.IsSurrogate(ch)) { 
                    throw new ArgumentException(Res.GetString(Res.Xml_InvalidSurrogateMissingLowChar)); 
                }
 
                AdvanceState(Token.Text);
                if (SaveAttrValue) {
                    attrValue.Append(ch);
                } 
                else {
                    writer.WriteCharEntity(ch); 
                } 
            }
            catch { 
                currentState = State.Error;
                throw;
            }
        } 

        public override void WriteSurrogateCharEntity(char lowChar, char highChar) { 
            try { 
                if (!Char.IsSurrogatePair(highChar, lowChar)) {
                    throw XmlConvert.CreateInvalidSurrogatePairException(lowChar, highChar); 
                }

                AdvanceState(Token.Text);
                if (SaveAttrValue) { 
                    attrValue.Append(highChar);
                    attrValue.Append(lowChar); 
                } 
                else {
                    writer.WriteSurrogateCharEntity(lowChar, highChar); 
                }
            }
            catch {
                currentState = State.Error; 
                throw;
            } 
        } 

        public override void WriteWhitespace(string ws) { 
            try {
                if (ws == null) {
                    ws = string.Empty;
                } 
                if (!XmlCharType.Instance.IsOnlyWhitespace(ws)) {
                    throw new ArgumentException(Res.GetString(Res.Xml_NonWhitespace)); 
                } 

                AdvanceState(Token.Whitespace); 
                if (SaveAttrValue) {
                    attrValue.Append(ws);
                }
                else { 
                    writer.WriteWhitespace(ws);
                } 
            } 
            catch {
                currentState = State.Error; 
                throw;
            }
        }
 
        public override void WriteString(string text) {
            try { 
                if (text == null) { 
                    return;
                } 

                AdvanceState(Token.Text);
                if (SaveAttrValue) {
                    attrValue.Append(text); 
                }
                else { 
                    writer.WriteString(text); 
                }
            } 
            catch {
                currentState = State.Error;
                throw;
            } 
        }
 
        public override void WriteChars(char[] buffer, int index, int count) { 
            try {
                if (buffer == null) { 
                    throw new ArgumentNullException("buffer");
                }
                if (index < 0) {
                    throw new ArgumentOutOfRangeException("index"); 
                }
                if (count < 0) { 
                    throw new ArgumentOutOfRangeException("count"); 
                }
                if (count > buffer.Length - index) { 
                    throw new ArgumentOutOfRangeException("count");
                }

                AdvanceState(Token.Text); 
                if (SaveAttrValue) {
                    attrValue.Append(buffer, index, count); 
                } 
                else {
                    writer.WriteChars(buffer, index, count); 
                }
            }
            catch {
                currentState = State.Error; 
                throw;
            } 
        } 

        public override void WriteRaw(char[] buffer, int index, int count) { 
            try {
                if (buffer == null) {
                    throw new ArgumentNullException("buffer");
                } 
                if (index < 0) {
                    throw new ArgumentOutOfRangeException("index"); 
                } 
                if (count < 0) {
                    throw new ArgumentOutOfRangeException("count"); 
                }
                if (count > buffer.Length - index) {
                    throw new ArgumentOutOfRangeException("count");
                } 

                AdvanceState(Token.RawData); 
                if (SaveAttrValue) { 
                    attrValue.Append(buffer, index, count);
                } 
                else {
                    writer.WriteRaw(buffer, index, count);
                }
            } 
            catch {
                currentState = State.Error; 
                throw; 
            }
        } 

        public override void WriteRaw(string data) {
            try {
                if (data == null) { 
                    return;
                } 
 
                AdvanceState(Token.RawData);
                if (SaveAttrValue) { 
                    attrValue.Append(data);
                }
                else {
                    writer.WriteRaw(data); 
                }
            } 
            catch { 
                currentState = State.Error;
                throw; 
            }
        }

        public override void WriteBase64(byte[] buffer, int index, int count) { 
            try {
                if (buffer == null) { 
                    throw new ArgumentNullException("buffer"); 
                }
                if (index < 0) { 
                    throw new ArgumentOutOfRangeException("index");
                }
                if (count < 0) {
                    throw new ArgumentOutOfRangeException("count"); 
                }
                if (count > buffer.Length - index) { 
                    throw new ArgumentOutOfRangeException("count"); 
                }
 
                AdvanceState(Token.Base64);
                writer.WriteBase64(buffer, index, count);
            }
            catch { 
                currentState = State.Error;
                throw; 
            } 
        }
 
        public override void Close() {
            if (currentState != State.Closed) {
                while (currentState != State.Error && elemTop > 0) {
                    WriteEndElement(); 
                }
                writer.Flush(); 
 
                if (rawWriter != null) {
                    rawWriter.Close(WriteState); 
                }
                else {
                    writer.Close();
                } 
                currentState = State.Closed;
            } 
        } 

        public override void Flush() { 
            try {
                writer.Flush();
            }
            catch { 
                currentState = State.Error;
                throw; 
            } 
        }
 
        public override string LookupPrefix(string ns) {
            try {
                if (ns == null) {
                    throw new ArgumentNullException("ns"); 
                }
                for (int i = nsTop; i >= 0; i--) { 
                    if (nsStack[i].namespaceUri == ns) { 
                        string prefix = nsStack[i].prefix;
                        for (i++; i <= nsTop; i++) { 
                            if (nsStack[i].prefix == prefix) {
                                return null;
                            }
                        } 
                        return prefix;
                    } 
                } 
                return (predefinedNamespaces != null) ? predefinedNamespaces.LookupPrefix(ns) : null;
            } 
            catch {
                currentState = State.Error;
                throw;
            } 
        }
 
        public override XmlSpace XmlSpace { 
            get {
                int i; 
                for (i = elemTop; i >= 0 && elemScopeStack[i].xmlSpace == (System.Xml.XmlSpace)(int)-1; i--) ;
                Debug.Assert(i >= 0);
                return elemScopeStack[i].xmlSpace;
            } 
        }
 
        public override string XmlLang { 
            get {
                int i; 
                for (i = elemTop; i > 0 && elemScopeStack[i].xmlLang == null; i--) ;
                Debug.Assert(i >= 0);
                return elemScopeStack[i].xmlLang;
            } 
        }
 
        public override void WriteQualifiedName(string localName, string ns) { 
            try {
                if (localName == null || localName.Length == 0) { 
                    throw new ArgumentException(Res.GetString(Res.Xml_EmptyLocalName));
                }
                CheckNCName(localName);
 
                AdvanceState(Token.Text);
                string prefix = String.Empty; 
                if (ns != null && ns.Length != 0) { 
                    prefix = LookupPrefix(ns);
                    if (prefix == null) { 
                        if (currentState != State.Attribute) {
                            throw new ArgumentException(Res.GetString(Res.Xml_UndefNamespace, ns));
                        }
                        prefix = GeneratePrefix(); 
                        PushNamespace(prefix, ns, false);
                    } 
                } 
                // if this is a special attribute, then just convert this to text
                // otherwise delegate to raw-writer 
                if (SaveAttrValue || rawWriter == null) {
                    if (prefix.Length != 0) {
                        WriteString(prefix);
                        WriteString(":"); 
                    }
                    WriteString(localName); 
                } 
                else {
                    rawWriter.WriteQualifiedName(prefix, localName, ns); 
                }
            }
            catch {
                currentState = State.Error; 
                throw;
            } 
        } 

        public override void WriteValue(bool value) { 
            try {
                AdvanceState(Token.AtomicValue);
                writer.WriteValue(value);
            } 
            catch {
                currentState = State.Error; 
                throw; 
            }
        } 

        public override void WriteValue(DateTime value) {
            try {
                AdvanceState(Token.AtomicValue); 
                writer.WriteValue(value);
            } 
            catch { 
                currentState = State.Error;
                throw; 
            }
        }

        public override void WriteValue(double value) { 
            try {
                AdvanceState(Token.AtomicValue); 
                writer.WriteValue(value); 
            }
            catch { 
                currentState = State.Error;
                throw;
            }
        } 

        public override void WriteValue(float value) { 
            try { 
                AdvanceState(Token.AtomicValue);
                writer.WriteValue(value); 
            }
            catch {
                currentState = State.Error;
                throw; 
            }
        } 
 
        public override void WriteValue(decimal value) {
            try { 
                AdvanceState(Token.AtomicValue);
                writer.WriteValue(value);
            }
            catch { 
                currentState = State.Error;
                throw; 
            } 
        }
 
        public override void WriteValue(int value) {
            try {
                AdvanceState(Token.AtomicValue);
                writer.WriteValue(value); 
            }
            catch { 
                currentState = State.Error; 
                throw;
            } 
        }

        public override void WriteValue(long value) {
            try { 
                AdvanceState(Token.AtomicValue);
                writer.WriteValue(value); 
            } 
            catch {
                currentState = State.Error; 
                throw;
            }
        }
 
        public override void WriteValue(string value) {
            try { 
                if (SaveAttrValue) { 
                    AdvanceState(Token.Text);
                    attrValue.Append(value); 
                }
                else {
                    AdvanceState(Token.AtomicValue);
                    writer.WriteValue(value); 
                }
            } 
            catch { 
                currentState = State.Error;
                throw; 
            }
        }

        public override void WriteValue(object value) { 
            try {
                if (SaveAttrValue && value is string) { 
                    AdvanceState(Token.Text); 
                    attrValue.Append(value);
                } 
                else {
                    AdvanceState(Token.AtomicValue);
                    writer.WriteValue(value);
                } 
            }
            catch { 
                currentState = State.Error; 
                throw;
            } 
        }

        public override void WriteBinHex(byte[] buffer, int index, int count) {
            if (IsClosedOrErrorState) { 
                throw new InvalidOperationException(Res.GetString(Res.Xml_ClosedOrError));
            } 
            try { 
                AdvanceState(Token.Text);
                base.WriteBinHex(buffer, index, count); 
            }
            catch {
                currentState = State.Error;
                throw; 
            }
        } 
 
        //
        // Internal methods 
        //
        internal XmlWriter InnerWriter {
            get {
                return this.writer; 
            }
        } 
 
        //
        // Private methods 
        //
        private bool SaveAttrValue {
            get {
                return specAttr != SpecialAttribute.No; 
            }
        } 
 
        private void SetSpecialAttribute(SpecialAttribute special) {
            specAttr = special; 
            if (State.Attribute == currentState)
                currentState = State.SpecialAttr;
            else if (State.RootLevelAttr == currentState)
                currentState = State.RootLevelSpecAttr; 
            else
                Debug.Assert(false, "State.Attribute == currentState || State.RootLevelAttr == currentState"); 
        } 

        private void WriteStartDocumentImpl(XmlStandalone standalone) { 
            try {
                AdvanceState(Token.StartDocument);

                if (conformanceLevel == ConformanceLevel.Auto) { 
                    conformanceLevel = ConformanceLevel.Document;
                    stateTable = StateTableDocument; 
                } 
                else if (conformanceLevel == ConformanceLevel.Fragment) {
                    throw new InvalidOperationException(Res.GetString(Res.Xml_CannotStartDocumentOnFragment)); 
                }

                if (rawWriter != null) {
                    if (!xmlDeclFollows) { 
                        rawWriter.WriteXmlDeclaration(standalone);
                    } 
                } 
                else {
                    writer.WriteStartDocument(); 
                }
            }
            catch {
                currentState = State.Error; 
                throw;
            } 
        } 

        private void StartFragment() { 
            conformanceLevel = ConformanceLevel.Fragment;
            Debug.Assert(stateTable == StateTableAuto);
        }
 
        private void PushNamespace(string prefix, string ns, bool explicitlyDefined) {
            NamespaceKind kind; 
            int existingNsIndex = LookupNamespaceIndex(prefix); 

            if (existingNsIndex != -1) { 
                if (existingNsIndex > elemScopeStack[elemTop].prevNSTop) { // in current scope
                    if (nsStack[existingNsIndex].namespaceUri != ns) {
                        throw new XmlException(Res.Xml_RedefinePrefix, new string[] { prefix, nsStack[existingNsIndex].namespaceUri, ns });
                    } 
                    if (explicitlyDefined) {
                        if (nsStack[existingNsIndex].kind == NamespaceKind.Written) { 
                            throw DupAttrException((prefix.Length == 0) ? string.Empty : "xmlns", (prefix.Length == 0) ? "xmlns" : prefix); 
                        }
                        nsStack[existingNsIndex].kind = NamespaceKind.Written; 
                    }
                    return;
                }
                else { 
                    if (!explicitlyDefined) {
                        if (nsStack[existingNsIndex].kind == NamespaceKind.Special) { 
                            if (prefix == "xml") { 
                                if (ns != nsStack[existingNsIndex].namespaceUri) {
                                    throw new ArgumentException(Res.GetString(Res.Xml_XmlPrefix)); 
                                }
                                else {
                                    kind = NamespaceKind.Implied;
                                } 
                            }
                            else { 
                                Debug.Assert(prefix == "xmlns"); 
                                throw new ArgumentException(Res.GetString(Res.Xml_XmlnsPrefix));
                            } 
                        }
                        else {
                            kind = (nsStack[existingNsIndex].namespaceUri == ns) ? NamespaceKind.Implied : NamespaceKind.NeedToWrite;
                        } 
                        goto AddNamespace;
                    } 
                } 
            }
 
            if ((ns == XmlReservedNs.NsXml && prefix != "xml") ||
                 (ns == XmlReservedNs.NsXmlNs && prefix != "xmlns")) {
                throw new ArgumentException(Res.GetString(Res.Xml_NamespaceDeclXmlXmlns, prefix));
            } 

            if (!explicitlyDefined) { 
                // not explicitly defined, not found before 
                // not found - we need to search the underlying writer context and declare it if not found
                if (predefinedNamespaces == null) { 
                    kind = NamespaceKind.NeedToWrite; // should write out
                }
                else {
                    string definedNs = predefinedNamespaces.LookupNamespace(prefix); 
                    kind = (definedNs == ns) ? NamespaceKind.Implied : NamespaceKind.NeedToWrite;
                } 
            } 
            else {
                // explicitly defined 
                if (prefix.Length > 0 && prefix[0] == 'x') {
                    if (prefix == "xml") {
                        if (ns != XmlReservedNs.NsXml) {
                            throw new ArgumentException(Res.GetString(Res.Xml_XmlPrefix)); 
                        }
                    } 
                    else if (prefix == "xmlns") { 
                        throw new ArgumentException(Res.GetString(Res.Xml_XmlnsPrefix));
                    } 
                }
                kind = NamespaceKind.Written;
            }
 
        AddNamespace:
            int top = ++nsTop; 
            if (top == nsStack.Length) { 
                Namespace[] newStack = new Namespace[top * 2];
                Array.Copy(nsStack, newStack, top); 
                nsStack = newStack;
            }
            nsStack[top].Set(prefix, ns, kind);
 
            if (useNsHashtable) {
                // add last 
                AddToNamespaceHashtable(nsTop); 
            }
            else if (nsTop == MaxNamespacesWalkCount) { 
                // add all
                nsHashtable = new Dictionary(hasher);
                for (int i = 0; i <= nsTop; i++) {
                    AddToNamespaceHashtable(i); 
                }
                useNsHashtable = true; 
            } 
        }
 
        private 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 int LookupNamespaceIndex(string prefix) {
            int index;
            if (useNsHashtable) {
                if (nsHashtable.TryGetValue(prefix, out index)) { 
                    return index;
                } 
            } 
            else {
                for (int i = nsTop; i >= 0; i--) { 
                    if (nsStack[i].prefix == prefix) {
                        return i;
                    }
                } 
            }
            return -1; 
        } 

        private void PopNamespaces(int indexFrom, int indexTo) { 
            Debug.Assert(useNsHashtable);
            Debug.Assert(indexFrom <= indexTo);
            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; 
                }
            }
        }
 
        static private XmlException DupAttrException(string prefix, string localName) {
            StringBuilder sb = new StringBuilder(); 
            if (prefix.Length > 0) { 
                sb.Append(prefix);
                sb.Append(':'); 
            }
            sb.Append(localName);
            return new XmlException(Res.Xml_DupAttributeName, sb.ToString());
        } 

        // Advance the state machine 
        private void AdvanceState(Token token) { 
            if ((int)currentState >= (int)State.Closed) {
                if (currentState == State.Closed || currentState == State.Error) { 
                    throw new InvalidOperationException(Res.GetString(Res.Xml_ClosedOrError));
                }
                else {
                    throw new InvalidOperationException(Res.GetString(Res.Xml_WrongToken, tokenName[(int)token], GetStateName(currentState))); 
                }
            } 
 
        Advance:
            State newState = stateTable[((int)token << 4) + (int)currentState]; 
            //                         [ (int)token * 16 + (int)currentState ];

            if ((int)newState >= (int)State.Error) {
                switch (newState) { 
                    case State.Error:
                        ThrowInvalidStateTransition(token, currentState); 
                        break; 

                    case State.StartContent: 
                        StartElementContent();
                        newState = State.Content;
                        break;
 
                    case State.StartContentEle:
                        StartElementContent(); 
                        newState = State.Element; 
                        break;
 
                    case State.StartContentB64:
                        StartElementContent();
                        newState = State.B64Content;
                        break; 

                    case State.StartDoc: 
                        WriteStartDocument(); 
                        newState = State.Document;
                        break; 

                    case State.StartDocEle:
                        WriteStartDocument();
                        newState = State.Element; 
                        break;
 
                    case State.EndAttrSEle: 
                        WriteEndAttribute();
                        StartElementContent(); 
                        newState = State.Element;
                        break;

                    case State.EndAttrEEle: 
                        WriteEndAttribute();
                        StartElementContent(); 
                        newState = State.Content; 
                        break;
 
                    case State.EndAttrSCont:
                        WriteEndAttribute();
                        StartElementContent();
                        newState = State.Content; 
                        break;
 
                    case State.EndAttrSAttr: 
                        WriteEndAttribute();
                        newState = State.Attribute; 
                        break;

                    case State.PostB64Cont:
                        if (rawWriter != null) { 
                            rawWriter.WriteEndBase64();
                        } 
                        currentState = State.Content; 
                        goto Advance;
 
                    case State.PostB64Attr:
                        if (rawWriter != null) {
                            rawWriter.WriteEndBase64();
                        } 
                        currentState = State.Attribute;
                        goto Advance; 
 
                    case State.PostB64RootAttr:
                        if (rawWriter != null) { 
                            rawWriter.WriteEndBase64();
                        }
                        currentState = State.RootLevelAttr;
                        goto Advance; 

                    case State.StartFragEle: 
                        StartFragment(); 
                        newState = State.Element;
                        break; 

                    case State.StartFragCont:
                        StartFragment();
                        newState = State.Content; 
                        break;
 
                    case State.StartFragB64: 
                        StartFragment();
                        newState = State.B64Content; 
                        break;

                    case State.StartRootLevelAttr:
                        WriteEndAttribute(); 
                        newState = State.RootLevelAttr;
                        break; 
 
                    default:
                        Debug.Assert(false, "We should not get to this point."); 
                        break;
                }
            }
 
            currentState = newState;
        } 
 
        private void StartElementContent() {
            // write namespace declarations 
            int start = elemScopeStack[elemTop].prevNSTop;
            for (int i = nsTop; i > start; i--) {
                if (nsStack[i].kind == NamespaceKind.NeedToWrite) {
                    nsStack[i].WriteDecl(writer, rawWriter); 
                }
            } 
 
            if (rawWriter != null) {
                rawWriter.StartElementContent(); 
            }
        }

        private static string GetStateName(State state) { 
            if (state >= State.Error) {
                Debug.Assert(false, "We should never get to this point. State = " + state); 
                return "Error"; 
            }
            else { 
                return stateName[(int)state];
            }
        }
 
        internal string LookupNamespace(string prefix) {
            for (int i = nsTop; i >= 0; i--) { 
                if (nsStack[i].prefix == prefix) { 
                    return nsStack[i].namespaceUri;
                } 
            }
            return (predefinedNamespaces != null) ? predefinedNamespaces.LookupNamespace(prefix) : null;
        }
 
        private string LookupLocalNamespace(string prefix) {
            for (int i = nsTop; i > elemScopeStack[elemTop].prevNSTop; i--) { 
                if (nsStack[i].prefix == prefix) { 
                    return nsStack[i].namespaceUri;
                } 
            }
            return null;
        }
 
        private string GeneratePrefix() {
            string genPrefix = "p" + (nsTop - 2).ToString("d", CultureInfo.InvariantCulture); 
            if (LookupNamespace(genPrefix) == null) { 
                return genPrefix;
            } 
            int i = 0;

            string s;
            do { 
                s = string.Concat(genPrefix, i.ToString(CultureInfo.InvariantCulture));
                i++; 
            } while (LookupNamespace(s) != null); 
            return s;
        } 

        private unsafe void CheckNCName(string ncname) {
            Debug.Assert(ncname != null && ncname.Length > 0);
            if ((xmlCharType.charProperties[ncname[0]] & XmlCharType.fNCStartName) != 0) { // if ( xmlCharType.IsStartNCNameChar( ncname[0] ) ) { 
                int i = 1;
                int endPos = ncname.Length; 
                while (i < endPos) { 
                    if ((xmlCharType.charProperties[ncname[i]] & XmlCharType.fNCName) == 0) { // if ( !xmlCharType.IsNCNameChar( ncname[i] ) ) {
                        throw InvalidCharsException(ncname, ncname[i]); 
                    }
                    i++;
                }
            } 
            else {
                throw InvalidCharsException(ncname, ncname[0]); 
            } 
        }
 
        private static Exception InvalidCharsException(string name, char badChar) {
            string[] args = new string[3];
            args[0] = name;
            args[1] = badChar.ToString(CultureInfo.InvariantCulture); 
            args[2] = ((int)badChar).ToString("X2", CultureInfo.InvariantCulture);
            return new ArgumentException(Res.GetString(Res.Xml_InvalidNameCharsDetail, args)); 
        } 

        // This method translates speficic state transition errors in more friendly error messages 
        private void ThrowInvalidStateTransition(Token token, State currentState) {
            string wrongTokenMessage = Res.GetString(Res.Xml_WrongToken, tokenName[(int)token], GetStateName(currentState));
            switch (currentState) {
                case State.AfterRootEle: 
                case State.Start:
                    if (conformanceLevel == ConformanceLevel.Document) { 
                        throw new InvalidOperationException(wrongTokenMessage + ' ' + Res.GetString(Res.Xml_ConformanceLevelFragment)); 
                    }
                    break; 
            }
            throw new InvalidOperationException(wrongTokenMessage);
        }
 
        private bool IsClosedOrErrorState {
            get { 
                return (int)currentState >= (int)State.Closed; 
            }
        } 

        private void AddAttribute(string prefix, string localName, string namespaceName) {
            int top = attrCount++;
            if (top == attrStack.Length) { 
                AttrName[] newStack = new AttrName[top * 2];
                Array.Copy(attrStack, newStack, top); 
                attrStack = newStack; 
            }
            attrStack[top].Set(prefix, localName, namespaceName); 

            if (attrCount < MaxAttrDuplWalkCount) {
                //
                for (int i = 0; i < top; i++) { 
                    if (attrStack[i].IsDuplicate(prefix, localName, namespaceName)) {
                        throw DupAttrException(prefix, localName); 
                    } 
                }
            } 
            else {
                // reached the threshold -> add all attributes to hash table
                if (attrCount == MaxAttrDuplWalkCount) {
                    if (attrHashTable == null) { 
                        attrHashTable = new Dictionary(hasher);
                    } 
                    Debug.Assert(attrHashTable.Count == 0); 
                    for (int i = 0; i < top; i++) {
                        AddToAttrHashTable(i); 
                    }
                }

                // add last attribute to hash table and 
                AddToAttrHashTable(top);
                int prev = attrStack[top].prev; 
                while (prev > 0) { 
                    // indexes are stored incremented by 1, 0 means no entry
                    prev--; 
                    if (attrStack[prev].IsDuplicate(prefix, localName, namespaceName)) {
                        throw DupAttrException(prefix, localName);
                    }
                    prev = attrStack[prev].prev; 
                }
            } 
        } 

        private void AddToAttrHashTable(int attributeIndex) { 
            string localName = attrStack[attributeIndex].localName;
            int count = attrHashTable.Count;
            attrHashTable[localName] = 0; // overwrite on collision
            if (count != attrHashTable.Count) { 
                return;
            } 
            // chain to previous attribute in stack with the same localName 
            int prev = attributeIndex - 1;
            while (prev >= 0) { 
                if (attrStack[prev].localName == localName) {
                    break;
                }
                prev--; 
            }
            Debug.Assert(prev >= 0 && attrStack[prev].localName == localName); 
            attrStack[attributeIndex].prev = prev + 1; // indexes are stored incremented by 1 
        }
 
        //
        // Internal methods
        //
        internal XmlRawWriter RawWriter { 
            get {
                return rawWriter; 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

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