Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / Xml / System / Xml / Core / XmlWellformedWriter.cs / 1 / 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; } IDictionaryIXmlNamespaceResolver.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; // check characters 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 { // check local name 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/check namespace 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; // check "one root element" condition for ConformanceLevel.Document 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; // check "one root element" condition for ConformanceLevel.Document 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 { // check local name 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 check for duplicates 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 { // check name if (name == null || name.Length == 0) { throw new ArgumentException(Res.GetString(Res.Xml_EmptyName)); } CheckNCName(name); // check text 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 { // check name 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) { // check for duplicates 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 check for duplicates 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. // //[....] //----------------------------------------------------------------------------- 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; } IDictionaryIXmlNamespaceResolver.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; // check characters 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 { // check local name 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/check namespace 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; // check "one root element" condition for ConformanceLevel.Document 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; // check "one root element" condition for ConformanceLevel.Document 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 { // check local name 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 check for duplicates 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 { // check name if (name == null || name.Length == 0) { throw new ArgumentException(Res.GetString(Res.Xml_EmptyName)); } CheckNCName(name); // check text 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 { // check name 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) { // check for duplicates 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 check for duplicates 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.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- UIHelper.cs
- DebugInfoExpression.cs
- UnsafeNativeMethodsPenimc.cs
- SynthesizerStateChangedEventArgs.cs
- PointAnimation.cs
- ConfigXmlSignificantWhitespace.cs
- DesignSurfaceManager.cs
- OdbcReferenceCollection.cs
- TdsParserSessionPool.cs
- XmlChildNodes.cs
- EventProxy.cs
- DeviceContext2.cs
- HtmlButton.cs
- CompilerScopeManager.cs
- OleStrCAMarshaler.cs
- XmlSchemaGroupRef.cs
- FreezableCollection.cs
- ToolTipService.cs
- GeometryValueSerializer.cs
- NullExtension.cs
- MailMessage.cs
- TextServicesPropertyRanges.cs
- ProviderSettings.cs
- XmlSchemaDocumentation.cs
- ServiceEndpointElement.cs
- NullRuntimeConfig.cs
- DeploymentExceptionMapper.cs
- HtmlTernaryTree.cs
- UserInitiatedRoutedEventPermission.cs
- SmtpClient.cs
- KnownBoxes.cs
- FindCriteriaElement.cs
- ErrorTableItemStyle.cs
- AdornerLayer.cs
- RequestTimeoutManager.cs
- SqlCacheDependencyDatabaseCollection.cs
- SharedStatics.cs
- NotSupportedException.cs
- TargetException.cs
- WebPartAuthorizationEventArgs.cs
- DataGridViewCellLinkedList.cs
- listitem.cs
- HttpRuntimeSection.cs
- PolyLineSegment.cs
- Bind.cs
- TableRow.cs
- CommandID.cs
- SourceLineInfo.cs
- HelpInfo.cs
- _UriTypeConverter.cs
- OleDbStruct.cs
- UInt16.cs
- TextModifier.cs
- RegexGroup.cs
- RSACryptoServiceProvider.cs
- FixUpCollection.cs
- ValidationRuleCollection.cs
- Image.cs
- DataBindEngine.cs
- UIElementParagraph.cs
- CallbackValidatorAttribute.cs
- StreamGeometry.cs
- ClientUtils.cs
- SiteMapDataSourceView.cs
- PtsContext.cs
- HttpCacheParams.cs
- OdbcConnectionOpen.cs
- Stroke2.cs
- SqlParameterCollection.cs
- QilInvokeLateBound.cs
- PersistChildrenAttribute.cs
- CodePageEncoding.cs
- CacheDependency.cs
- SQLInt16Storage.cs
- MergeFailedEvent.cs
- DataGridViewRowDividerDoubleClickEventArgs.cs
- PinnedBufferMemoryStream.cs
- RawUIStateInputReport.cs
- BoundingRectTracker.cs
- DispatchOperationRuntime.cs
- XamlStackWriter.cs
- LicenseContext.cs
- ReturnType.cs
- EventMappingSettings.cs
- OperatorExpressions.cs
- ArrowControl.xaml.cs
- FixedSOMTableRow.cs
- SamlAssertion.cs
- XmlSchemaCollection.cs
- UriWriter.cs
- XPathDocumentBuilder.cs
- SecurityCriticalDataForSet.cs
- ObjectDataSourceMethodEventArgs.cs
- ObjectSet.cs
- SBCSCodePageEncoding.cs
- Logging.cs
- Bidi.cs
- SessionState.cs
- DriveNotFoundException.cs
- ReadOnlyTernaryTree.cs