1 //------------------------------------------------------------------------------
2 // <copyright file="XmlWellFormedWriter.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
12 using System.Diagnostics;
13 using System.Collections;
14 using System.Globalization;
15 using System.Collections.Generic;
17 // OpenIssue : is it better to cache the current namespace decls for each elem
18 // as the current code does, or should it just always walk the namespace stack?
20 namespace System.Xml {
22 internal partial class XmlWellFormedWriter : XmlWriter {
24 // Private types used by the XmlWellFormedWriter are defined in XmlWellFormedWriterHelpers.cs
32 XmlRawWriter rawWriter; // writer as XmlRawWriter
33 IXmlNamespaceResolver predefinedNamespaces; // writer as IXmlNamespaceResolver
35 // namespace management
38 Dictionary<string, int> nsHashtable;
42 ElementScope[] elemScopeStack;
48 Dictionary<string, int> attrHashTable;
50 // special attribute caching (xmlns, xml:space, xml:lang)
51 SpecialAttribute specAttr = SpecialAttribute.No;
52 AttributeValueCache attrValueCache;
61 bool omitDuplNamespaces;
62 bool writeEndDocumentOnClose;
64 // actual conformance level
65 ConformanceLevel conformanceLevel;
72 XmlCharType xmlCharType = XmlCharType.Instance;
75 SecureStringHasher hasher;
81 const int ElementStackInitialSize = 8;
82 const int NamespaceStackInitialSize = 8;
83 const int AttributeArrayInitialSize = 8;
85 const int MaxAttrDuplWalkCount = 2;
86 const int MaxNamespacesWalkCount = 3;
88 const int MaxAttrDuplWalkCount = 14;
89 const int MaxNamespacesWalkCount = 16;
108 RootLevelSpecAttr = 12,
109 RootLevelB64Attr = 13,
110 AfterRootLevelAttr = 14,
115 StartContentEle = 102,
116 StartContentB64 = 103,
125 PostB64RootAttr = 114,
129 StartRootLevelAttr = 118,
150 internal static readonly string[] stateName = {
151 "Start", // State.Start
152 "TopLevel", // State.TopLevel
153 "Document", // State.Document
154 "Element Start Tag", // State.Element
155 "Element Content", // State.Content
156 "Element Content", // State.B64Content
157 "Attribute", // State.B64Attribute
158 "EndRootElement", // State.AfterRootEle
159 "Attribute", // State.Attribute
160 "Special Attribute", // State.SpecialAttr
161 "End Document", // State.EndDocument
162 "Root Level Attribute Value", // State.RootLevelAttr
163 "Root Level Special Attribute Value", // State.RootLevelSpecAttr
164 "Root Level Base64 Attribute Value", // State.RootLevelB64Attr
165 "After Root Level Attribute", // State.AfterRootLevelAttr
166 "Closed", // State.Closed
167 "Error", // State.Error
170 internal static readonly string[] tokenName = {
171 "StartDocument", // Token.StartDocument
172 "EndDocument", // Token.EndDocument
174 "Comment", // Token.Comment
176 "StartElement", // Token.StartElement
177 "EndElement", // Token.EndElement
178 "StartAttribute", // Token.StartAttribut
179 "EndAttribute", // Token.EndAttribute
180 "Text", // Token.Text
181 "CDATA", // Token.CData
182 "Atomic value", // Token.AtomicValue
183 "Base64", // Token.Base64
184 "RawData", // Token.RawData
185 "Whitespace", // Token.Whitespace
188 private static WriteState[] state2WriteState = {
189 WriteState.Start, // State.Start
190 WriteState.Prolog, // State.TopLevel
191 WriteState.Prolog, // State.Document
192 WriteState.Element, // State.Element
193 WriteState.Content, // State.Content
194 WriteState.Content, // State.B64Content
195 WriteState.Attribute, // State.B64Attribute
196 WriteState.Content, // State.AfterRootEle
197 WriteState.Attribute, // State.Attribute
198 WriteState.Attribute, // State.SpecialAttr
199 WriteState.Content, // State.EndDocument
200 WriteState.Attribute, // State.RootLevelAttr
201 WriteState.Attribute, // State.RootLevelSpecAttr
202 WriteState.Attribute, // State.RootLevelB64Attr
203 WriteState.Attribute, // State.AfterRootLevelAttr
204 WriteState.Closed, // State.Closed
205 WriteState.Error, // State.Error
208 private static readonly State[] StateTableDocument = {
209 // 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
210 /* 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,
211 /* 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,
212 /* 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,
213 /* 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,
214 /* 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,
215 /* 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,
216 /* 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,
217 /* 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,
218 /* 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,
219 /* 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,
220 /* 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,
221 /* 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,
222 /* 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,
223 /* 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,
224 /* 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
227 private static readonly State[] StateTableAuto = {
228 // 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
229 /* 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 */
230 /* 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 */
231 /* 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 */
232 /* 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 */
233 /* 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 */
234 /* 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 */
235 /* 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 */
236 /* 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 */
237 /* 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 */
238 /* 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 */
239 /* 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 */
240 /* 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 */
241 /* 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 */
242 /* 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 */
243 /* 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 */
247 // Constructor & finalizer
249 internal XmlWellFormedWriter(XmlWriter writer, XmlWriterSettings settings) {
250 Debug.Assert(writer != null);
251 Debug.Assert(settings != null);
252 Debug.Assert(MaxNamespacesWalkCount <= 3);
254 this.writer = writer;
256 rawWriter = writer as XmlRawWriter;
257 predefinedNamespaces = writer as IXmlNamespaceResolver;
258 if (rawWriter != null) {
259 rawWriter.NamespaceResolver = new NamespaceResolverProxy(this);
262 checkCharacters = settings.CheckCharacters;
263 omitDuplNamespaces = (settings.NamespaceHandling & NamespaceHandling.OmitDuplicates) != 0;
264 writeEndDocumentOnClose = settings.WriteEndDocumentOnClose;
266 conformanceLevel = settings.ConformanceLevel;
267 stateTable = (conformanceLevel == ConformanceLevel.Document) ? StateTableDocument : StateTableAuto;
269 currentState = State.Start;
271 nsStack = new Namespace[NamespaceStackInitialSize];
272 nsStack[0].Set("xmlns", XmlReservedNs.NsXmlNs, NamespaceKind.Special);
273 nsStack[1].Set("xml", XmlReservedNs.NsXml, NamespaceKind.Special);
274 if (predefinedNamespaces == null) {
275 nsStack[2].Set(string.Empty, string.Empty, NamespaceKind.Implied);
278 string defaultNs = predefinedNamespaces.LookupNamespace(string.Empty);
279 nsStack[2].Set(string.Empty, (defaultNs == null ? string.Empty : defaultNs), NamespaceKind.Implied);
283 elemScopeStack = new ElementScope[ElementStackInitialSize];
284 elemScopeStack[0].Set(string.Empty, string.Empty, string.Empty, nsTop);
285 elemScopeStack[0].xmlSpace = XmlSpace.None;
286 elemScopeStack[0].xmlLang = null;
289 attrStack = new AttrName[AttributeArrayInitialSize];
291 hasher = new SecureStringHasher();
295 // XmlWriter implementation
297 public override WriteState WriteState {
299 if ((int)currentState <= (int)State.Error) {
300 return state2WriteState[(int)currentState];
303 Debug.Assert(false, "Expected currentState <= State.Error ");
304 return WriteState.Error;
309 public override XmlWriterSettings Settings {
311 XmlWriterSettings settings = writer.Settings;
312 settings.ReadOnly = false;
313 settings.ConformanceLevel = conformanceLevel;
314 if (omitDuplNamespaces) {
315 settings.NamespaceHandling |= NamespaceHandling.OmitDuplicates;
317 settings.WriteEndDocumentOnClose = writeEndDocumentOnClose;
318 settings.ReadOnly = true;
323 public override void WriteStartDocument() {
324 WriteStartDocumentImpl(XmlStandalone.Omit);
327 public override void WriteStartDocument(bool standalone) {
328 WriteStartDocumentImpl(standalone ? XmlStandalone.Yes : XmlStandalone.No);
331 public override void WriteEndDocument() {
333 // auto-close all elements
334 while (elemTop > 0) {
337 State prevState = currentState;
338 AdvanceState(Token.EndDocument);
340 if (prevState != State.AfterRootEle) {
341 throw new ArgumentException(Res.GetString(Res.Xml_NoRoot));
343 if (rawWriter == null) {
344 writer.WriteEndDocument();
348 currentState = State.Error;
353 public override void WriteDocType(string name, string pubid, string sysid, string subset) {
355 if (name == null || name.Length == 0) {
356 throw new ArgumentException(Res.GetString(Res.Xml_EmptyName));
358 XmlConvert.VerifyQName(name, ExceptionType.XmlException);
360 if (conformanceLevel == ConformanceLevel.Fragment) {
361 throw new InvalidOperationException(Res.GetString(Res.Xml_DtdNotAllowedInFragment));
364 AdvanceState(Token.Dtd);
366 currentState = State.Error;
367 throw new InvalidOperationException(Res.GetString(Res.Xml_DtdAlreadyWritten));
370 if (conformanceLevel == ConformanceLevel.Auto) {
371 conformanceLevel = ConformanceLevel.Document;
372 stateTable = StateTableDocument;
378 if (checkCharacters) {
380 if ((i = xmlCharType.IsPublicId(pubid)) >= 0) {
381 throw new ArgumentException(Res.GetString(Res.Xml_InvalidCharacter, XmlException.BuildCharExceptionArgs(pubid, i)), "pubid");
385 if ((i = xmlCharType.IsOnlyCharData(sysid)) >= 0) {
386 throw new ArgumentException(Res.GetString(Res.Xml_InvalidCharacter, XmlException.BuildCharExceptionArgs(sysid, i)), "sysid");
389 if (subset != null) {
390 if ((i = xmlCharType.IsOnlyCharData(subset)) >= 0) {
391 throw new ArgumentException(Res.GetString(Res.Xml_InvalidCharacter, XmlException.BuildCharExceptionArgs(subset, i)), "subset");
397 writer.WriteDocType(name, pubid, sysid, subset);
401 currentState = State.Error;
406 public override void WriteStartElement(string prefix, string localName, string ns) {
409 if (localName == null || localName.Length == 0) {
410 throw new ArgumentException(Res.GetString(Res.Xml_EmptyLocalName));
412 CheckNCName(localName);
414 AdvanceState(Token.StartElement);
416 // lookup prefix / namespace
417 if (prefix == null) {
419 prefix = LookupPrefix(ns);
421 if (prefix == null) {
422 prefix = string.Empty;
425 else if (prefix.Length > 0) {
428 ns = LookupNamespace(prefix);
430 if (ns == null || (ns != null && ns.Length == 0)) {
431 throw new ArgumentException(Res.GetString(Res.Xml_PrefixForEmptyNs));
435 ns = LookupNamespace(prefix);
437 Debug.Assert(prefix.Length == 0);
442 if (elemTop == 0 && rawWriter != null) {
443 // notify the underlying raw writer about the root level element
444 rawWriter.OnRootElement(conformanceLevel);
448 writer.WriteStartElement(prefix, localName, ns);
450 // push element on stack and add/check namespace
452 if (top == elemScopeStack.Length) {
453 ElementScope[] newStack = new ElementScope[top * 2];
454 Array.Copy(elemScopeStack, newStack, top);
455 elemScopeStack = newStack;
457 elemScopeStack[top].Set(prefix, localName, ns, nsTop);
459 PushNamespaceImplicit(prefix, ns);
461 if (attrCount >= MaxAttrDuplWalkCount) {
462 attrHashTable.Clear();
468 currentState = State.Error;
474 public override void WriteEndElement() {
476 AdvanceState(Token.EndElement);
480 throw new XmlException(Res.Xml_NoStartTag, string.Empty);
484 if (rawWriter != null) {
485 elemScopeStack[top].WriteEndElement(rawWriter);
488 writer.WriteEndElement();
492 int prevNsTop = elemScopeStack[top].prevNSTop;
493 if (useNsHashtable && prevNsTop < nsTop) {
494 PopNamespaces(prevNsTop + 1, nsTop);
499 // check "one root element" condition for ConformanceLevel.Document
501 if (conformanceLevel == ConformanceLevel.Document) {
502 currentState = State.AfterRootEle;
505 currentState = State.TopLevel;
510 currentState = State.Error;
515 public override void WriteFullEndElement() {
517 AdvanceState(Token.EndElement);
521 throw new XmlException(Res.Xml_NoStartTag, string.Empty);
525 if (rawWriter != null) {
526 elemScopeStack[top].WriteFullEndElement(rawWriter);
529 writer.WriteFullEndElement();
533 int prevNsTop = elemScopeStack[top].prevNSTop;
534 if (useNsHashtable && prevNsTop < nsTop) {
535 PopNamespaces(prevNsTop + 1, nsTop);
540 // check "one root element" condition for ConformanceLevel.Document
542 if (conformanceLevel == ConformanceLevel.Document) {
543 currentState = State.AfterRootEle;
546 currentState = State.TopLevel;
551 currentState = State.Error;
556 public override void WriteStartAttribute(string prefix, string localName, string namespaceName) {
559 if (localName == null || localName.Length == 0) {
560 if (prefix == "xmlns") {
562 prefix = string.Empty;
565 throw new ArgumentException(Res.GetString(Res.Xml_EmptyLocalName));
568 CheckNCName(localName);
570 AdvanceState(Token.StartAttribute);
572 // lookup prefix / namespace
573 if (prefix == null) {
574 if (namespaceName != null) {
575 // special case prefix=null/localname=xmlns
576 if (!(localName == "xmlns" && namespaceName == XmlReservedNs.NsXmlNs))
577 prefix = LookupPrefix(namespaceName);
579 if (prefix == null) {
580 prefix = string.Empty;
583 if (namespaceName == null) {
584 if (prefix != null && prefix.Length > 0) {
585 namespaceName = LookupNamespace(prefix);
587 if (namespaceName == null) {
588 namespaceName = string.Empty;
592 if (prefix.Length == 0) {
593 if (localName[0] == 'x' && localName == "xmlns") {
594 if (namespaceName.Length > 0 && namespaceName != XmlReservedNs.NsXmlNs) {
595 throw new ArgumentException(Res.GetString(Res.Xml_XmlnsPrefix));
597 curDeclPrefix = String.Empty;
598 SetSpecialAttribute(SpecialAttribute.DefaultXmlns);
599 goto SkipPushAndWrite;
601 else if (namespaceName.Length > 0) {
602 prefix = LookupPrefix(namespaceName);
603 if (prefix == null || prefix.Length == 0) {
604 prefix = GeneratePrefix();
609 if (prefix[0] == 'x') {
610 if (prefix == "xmlns") {
611 if (namespaceName.Length > 0 && namespaceName != XmlReservedNs.NsXmlNs) {
612 throw new ArgumentException(Res.GetString(Res.Xml_XmlnsPrefix));
614 curDeclPrefix = localName;
615 SetSpecialAttribute(SpecialAttribute.PrefixedXmlns);
616 goto SkipPushAndWrite;
618 else if (prefix == "xml") {
619 if (namespaceName.Length > 0 && namespaceName != XmlReservedNs.NsXml) {
620 throw new ArgumentException(Res.GetString(Res.Xml_XmlPrefix));
624 SetSpecialAttribute(SpecialAttribute.XmlSpace);
625 goto SkipPushAndWrite;
627 SetSpecialAttribute(SpecialAttribute.XmlLang);
628 goto SkipPushAndWrite;
635 if (namespaceName.Length == 0) {
636 // attributes cannot have default namespace
637 prefix = string.Empty;
640 string definedNs = LookupLocalNamespace(prefix);
641 if (definedNs != null && definedNs != namespaceName) {
642 prefix = GeneratePrefix();
647 if (prefix.Length != 0) {
648 PushNamespaceImplicit(prefix, namespaceName);
653 // add attribute to the list and check for duplicates
654 AddAttribute( prefix, localName, namespaceName );
656 if (specAttr == SpecialAttribute.No) {
657 // write attribute name
658 writer.WriteStartAttribute( prefix, localName, namespaceName );
662 currentState = State.Error;
667 public override void WriteEndAttribute() {
669 AdvanceState(Token.EndAttribute);
671 if (specAttr != SpecialAttribute.No) {
675 case SpecialAttribute.DefaultXmlns:
676 value = attrValueCache.StringValue;
677 if (PushNamespaceExplicit(string.Empty, value)) { // returns true if the namespace declaration should be written out
678 if (rawWriter != null) {
679 if (rawWriter.SupportsNamespaceDeclarationInChunks) {
680 rawWriter.WriteStartNamespaceDeclaration(string.Empty);
681 attrValueCache.Replay(rawWriter);
682 rawWriter.WriteEndNamespaceDeclaration();
685 rawWriter.WriteNamespaceDeclaration(string.Empty, value);
689 writer.WriteStartAttribute(string.Empty, "xmlns", XmlReservedNs.NsXmlNs);
690 attrValueCache.Replay(writer);
691 writer.WriteEndAttribute();
694 curDeclPrefix = null;
696 case SpecialAttribute.PrefixedXmlns:
697 value = attrValueCache.StringValue;
698 if (value.Length == 0) {
699 throw new ArgumentException(Res.GetString(Res.Xml_PrefixForEmptyNs));
701 if (value == XmlReservedNs.NsXmlNs || (value == XmlReservedNs.NsXml && curDeclPrefix != "xml")) {
702 throw new ArgumentException(Res.GetString(Res.Xml_CanNotBindToReservedNamespace));
704 if (PushNamespaceExplicit(curDeclPrefix, value)) { // returns true if the namespace declaration should be written out
705 if (rawWriter != null) {
706 if (rawWriter.SupportsNamespaceDeclarationInChunks) {
707 rawWriter.WriteStartNamespaceDeclaration(curDeclPrefix);
708 attrValueCache.Replay(rawWriter);
709 rawWriter.WriteEndNamespaceDeclaration();
712 rawWriter.WriteNamespaceDeclaration(curDeclPrefix, value);
716 writer.WriteStartAttribute("xmlns", curDeclPrefix, XmlReservedNs.NsXmlNs);
717 attrValueCache.Replay(writer);
718 writer.WriteEndAttribute();
721 curDeclPrefix = null;
723 case SpecialAttribute.XmlSpace:
724 attrValueCache.Trim();
725 value = attrValueCache.StringValue;
727 if (value == "default") {
728 elemScopeStack[elemTop].xmlSpace = XmlSpace.Default;
730 else if (value == "preserve") {
731 elemScopeStack[elemTop].xmlSpace = XmlSpace.Preserve;
734 throw new ArgumentException(Res.GetString(Res.Xml_InvalidXmlSpace, value));
736 writer.WriteStartAttribute("xml", "space", XmlReservedNs.NsXml);
737 attrValueCache.Replay(writer);
738 writer.WriteEndAttribute();
740 case SpecialAttribute.XmlLang:
741 value = attrValueCache.StringValue;
742 elemScopeStack[elemTop].xmlLang = value;
743 writer.WriteStartAttribute("xml", "lang", XmlReservedNs.NsXml);
744 attrValueCache.Replay(writer);
745 writer.WriteEndAttribute();
748 specAttr = SpecialAttribute.No;
749 attrValueCache.Clear();
752 writer.WriteEndAttribute();
756 currentState = State.Error;
761 public override void WriteCData(string text) {
766 AdvanceState(Token.CData);
767 writer.WriteCData(text);
770 currentState = State.Error;
775 public override void WriteComment(string text) {
780 AdvanceState(Token.Comment);
781 writer.WriteComment(text);
784 currentState = State.Error;
789 public override void WriteProcessingInstruction(string name, string text) {
792 if (name == null || name.Length == 0) {
793 throw new ArgumentException(Res.GetString(Res.Xml_EmptyName));
802 // xml declaration is a special case (not a processing instruction, but we allow WriteProcessingInstruction as a convenience)
803 if (name.Length == 3 && string.Compare(name, "xml", StringComparison.OrdinalIgnoreCase) == 0) {
804 if (currentState != State.Start) {
805 throw new ArgumentException(Res.GetString(conformanceLevel == ConformanceLevel.Document ? Res.Xml_DupXmlDecl : Res.Xml_CannotWriteXmlDecl));
808 xmlDeclFollows = true;
809 AdvanceState(Token.PI);
811 if (rawWriter != null) {
812 // Translate PI into an xml declaration
813 rawWriter.WriteXmlDeclaration(text);
816 writer.WriteProcessingInstruction(name, text);
820 AdvanceState(Token.PI);
821 writer.WriteProcessingInstruction(name, text);
825 currentState = State.Error;
830 public override void WriteEntityRef(string name) {
833 if (name == null || name.Length == 0) {
834 throw new ArgumentException(Res.GetString(Res.Xml_EmptyName));
838 AdvanceState(Token.Text);
840 attrValueCache.WriteEntityRef(name);
843 writer.WriteEntityRef(name);
847 currentState = State.Error;
852 public override void WriteCharEntity(char ch) {
854 if (Char.IsSurrogate(ch)) {
855 throw new ArgumentException(Res.GetString(Res.Xml_InvalidSurrogateMissingLowChar));
858 AdvanceState(Token.Text);
860 attrValueCache.WriteCharEntity(ch);
863 writer.WriteCharEntity(ch);
867 currentState = State.Error;
872 public override void WriteSurrogateCharEntity(char lowChar, char highChar) {
874 if (!Char.IsSurrogatePair(highChar, lowChar)) {
875 throw XmlConvert.CreateInvalidSurrogatePairException(lowChar, highChar);
878 AdvanceState(Token.Text);
880 attrValueCache.WriteSurrogateCharEntity(lowChar, highChar);
883 writer.WriteSurrogateCharEntity(lowChar, highChar);
887 currentState = State.Error;
892 public override void WriteWhitespace(string ws) {
897 if (!XmlCharType.Instance.IsOnlyWhitespace(ws)) {
898 throw new ArgumentException(Res.GetString(Res.Xml_NonWhitespace));
901 AdvanceState(Token.Whitespace);
903 attrValueCache.WriteWhitespace(ws);
906 writer.WriteWhitespace(ws);
910 currentState = State.Error;
915 public override void WriteString(string text) {
921 AdvanceState(Token.Text);
923 attrValueCache.WriteString(text);
926 writer.WriteString(text);
930 currentState = State.Error;
935 public override void WriteChars(char[] buffer, int index, int count) {
937 if (buffer == null) {
938 throw new ArgumentNullException("buffer");
941 throw new ArgumentOutOfRangeException("index");
944 throw new ArgumentOutOfRangeException("count");
946 if (count > buffer.Length - index) {
947 throw new ArgumentOutOfRangeException("count");
950 AdvanceState(Token.Text);
952 attrValueCache.WriteChars(buffer, index, count);
955 writer.WriteChars(buffer, index, count);
959 currentState = State.Error;
964 public override void WriteRaw(char[] buffer, int index, int count) {
966 if (buffer == null) {
967 throw new ArgumentNullException("buffer");
970 throw new ArgumentOutOfRangeException("index");
973 throw new ArgumentOutOfRangeException("count");
975 if (count > buffer.Length - index) {
976 throw new ArgumentOutOfRangeException("count");
979 AdvanceState(Token.RawData);
981 attrValueCache.WriteRaw(buffer, index, count);
984 writer.WriteRaw(buffer, index, count);
988 currentState = State.Error;
993 public override void WriteRaw(string data) {
999 AdvanceState(Token.RawData);
1000 if (SaveAttrValue) {
1001 attrValueCache.WriteRaw(data);
1004 writer.WriteRaw(data);
1008 currentState = State.Error;
1013 public override void WriteBase64(byte[] buffer, int index, int count) {
1015 if (buffer == null) {
1016 throw new ArgumentNullException("buffer");
1019 throw new ArgumentOutOfRangeException("index");
1022 throw new ArgumentOutOfRangeException("count");
1024 if (count > buffer.Length - index) {
1025 throw new ArgumentOutOfRangeException("count");
1028 AdvanceState(Token.Base64);
1029 writer.WriteBase64(buffer, index, count);
1032 currentState = State.Error;
1037 public override void Close() {
1038 if (currentState != State.Closed) {
1040 if (writeEndDocumentOnClose) {
1041 while (currentState != State.Error && elemTop > 0) {
1046 if (currentState != State.Error && elemTop > 0) {
1047 //finish the start element tag '>'
1049 AdvanceState(Token.EndElement);
1052 currentState = State.Error;
1058 if (InBase64 && rawWriter != null) {
1059 rawWriter.WriteEndBase64();
1066 if (rawWriter != null) {
1067 rawWriter.Close(WriteState);
1074 currentState = State.Closed;
1080 public override void Flush() {
1085 currentState = State.Error;
1090 public override string LookupPrefix(string ns) {
1093 throw new ArgumentNullException("ns");
1095 for (int i = nsTop; i >= 0; i--) {
1096 if (nsStack[i].namespaceUri == ns) {
1097 string prefix = nsStack[i].prefix;
1098 for (i++; i <= nsTop; i++) {
1099 if (nsStack[i].prefix == prefix) {
1106 return (predefinedNamespaces != null) ? predefinedNamespaces.LookupPrefix(ns) : null;
1109 currentState = State.Error;
1114 public override XmlSpace XmlSpace {
1117 for (i = elemTop; i >= 0 && elemScopeStack[i].xmlSpace == (System.Xml.XmlSpace)(int)-1; i--) ;
1118 Debug.Assert(i >= 0);
1119 return elemScopeStack[i].xmlSpace;
1123 public override string XmlLang {
1126 for (i = elemTop; i > 0 && elemScopeStack[i].xmlLang == null; i--) ;
1127 Debug.Assert(i >= 0);
1128 return elemScopeStack[i].xmlLang;
1132 public override void WriteQualifiedName(string localName, string ns) {
1134 if (localName == null || localName.Length == 0) {
1135 throw new ArgumentException(Res.GetString(Res.Xml_EmptyLocalName));
1137 CheckNCName(localName);
1139 AdvanceState(Token.Text);
1140 string prefix = String.Empty;
1141 if (ns != null && ns.Length != 0) {
1142 prefix = LookupPrefix(ns);
1143 if (prefix == null) {
1144 if (currentState != State.Attribute) {
1145 throw new ArgumentException(Res.GetString(Res.Xml_UndefNamespace, ns));
1147 prefix = GeneratePrefix();
1148 PushNamespaceImplicit(prefix, ns);
1151 // if this is a special attribute, then just convert this to text
1152 // otherwise delegate to raw-writer
1153 if (SaveAttrValue || rawWriter == null) {
1154 if (prefix.Length != 0) {
1155 WriteString(prefix);
1158 WriteString(localName);
1161 rawWriter.WriteQualifiedName(prefix, localName, ns);
1165 currentState = State.Error;
1170 public override void WriteValue(bool value) {
1172 AdvanceState(Token.AtomicValue);
1173 writer.WriteValue(value);
1176 currentState = State.Error;
1181 public override void WriteValue(DateTime value) {
1183 AdvanceState(Token.AtomicValue);
1184 writer.WriteValue(value);
1187 currentState = State.Error;
1192 public override void WriteValue(DateTimeOffset value) {
1194 AdvanceState(Token.AtomicValue);
1195 writer.WriteValue(value);
1198 currentState = State.Error;
1203 public override void WriteValue(double value) {
1205 AdvanceState(Token.AtomicValue);
1206 writer.WriteValue(value);
1209 currentState = State.Error;
1214 public override void WriteValue(float value) {
1216 AdvanceState(Token.AtomicValue);
1217 writer.WriteValue(value);
1220 currentState = State.Error;
1225 public override void WriteValue(decimal value) {
1227 AdvanceState(Token.AtomicValue);
1228 writer.WriteValue(value);
1231 currentState = State.Error;
1236 public override void WriteValue(int value) {
1238 AdvanceState(Token.AtomicValue);
1239 writer.WriteValue(value);
1242 currentState = State.Error;
1247 public override void WriteValue(long value) {
1249 AdvanceState(Token.AtomicValue);
1250 writer.WriteValue(value);
1253 currentState = State.Error;
1258 public override void WriteValue(string value) {
1260 if (value == null) {
1263 if (SaveAttrValue) {
1264 AdvanceState(Token.Text);
1265 attrValueCache.WriteValue(value);
1268 AdvanceState(Token.AtomicValue);
1269 writer.WriteValue(value);
1273 currentState = State.Error;
1278 public override void WriteValue(object value) {
1280 if (SaveAttrValue && value is string) {
1281 AdvanceState(Token.Text);
1282 attrValueCache.WriteValue((string)value);
1285 AdvanceState(Token.AtomicValue);
1286 writer.WriteValue(value);
1290 currentState = State.Error;
1295 public override void WriteBinHex(byte[] buffer, int index, int count) {
1296 if (IsClosedOrErrorState) {
1297 throw new InvalidOperationException(Res.GetString(Res.Xml_ClosedOrError));
1300 AdvanceState(Token.Text);
1301 base.WriteBinHex(buffer, index, count);
1304 currentState = State.Error;
1313 internal XmlWriter InnerWriter {
1319 internal XmlRawWriter RawWriter {
1329 private bool SaveAttrValue {
1331 return specAttr != SpecialAttribute.No;
1335 private bool InBase64 {
1337 return (currentState == State.B64Content || currentState == State.B64Attribute || currentState == State.RootLevelB64Attr);
1341 private void SetSpecialAttribute(SpecialAttribute special) {
1343 if (State.Attribute == currentState)
1344 currentState = State.SpecialAttr;
1345 else if (State.RootLevelAttr == currentState)
1346 currentState = State.RootLevelSpecAttr;
1348 Debug.Assert(false, "State.Attribute == currentState || State.RootLevelAttr == currentState");
1350 if (attrValueCache == null) {
1351 attrValueCache = new AttributeValueCache();
1355 private void WriteStartDocumentImpl(XmlStandalone standalone) {
1357 AdvanceState(Token.StartDocument);
1359 if (conformanceLevel == ConformanceLevel.Auto) {
1360 conformanceLevel = ConformanceLevel.Document;
1361 stateTable = StateTableDocument;
1363 else if (conformanceLevel == ConformanceLevel.Fragment) {
1364 throw new InvalidOperationException(Res.GetString(Res.Xml_CannotStartDocumentOnFragment));
1367 if (rawWriter != null) {
1368 if (!xmlDeclFollows) {
1369 rawWriter.WriteXmlDeclaration(standalone);
1373 // We do not pass the standalone value here - Dev10
1374 writer.WriteStartDocument();
1378 currentState = State.Error;
1383 private void StartFragment() {
1384 conformanceLevel = ConformanceLevel.Fragment;
1385 Debug.Assert(stateTable == StateTableAuto);
1388 // PushNamespaceImplicit is called when a prefix/namespace pair is used in an element name, attribute name or some other qualified name.
1389 private void PushNamespaceImplicit(string prefix, string ns) {
1392 // See if the prefix is already defined
1393 int existingNsIndex = LookupNamespaceIndex(prefix);
1395 // Prefix is already defined
1396 if (existingNsIndex != -1) {
1397 // It is defined in the current scope
1398 if (existingNsIndex > elemScopeStack[elemTop].prevNSTop) {
1399 // The new namespace Uri needs to be the same as the one that is already declared
1400 if (nsStack[existingNsIndex].namespaceUri != ns) {
1401 throw new XmlException(Res.Xml_RedefinePrefix, new string[] { prefix, nsStack[existingNsIndex].namespaceUri, ns });
1403 // No additional work needed
1406 // The prefix is defined but in a different scope
1408 // existing declaration is special one (xml, xmlns) -> validate that the new one is the same and can be declared
1409 if (nsStack[existingNsIndex].kind == NamespaceKind.Special) {
1410 if (prefix == "xml") {
1411 if (ns != nsStack[existingNsIndex].namespaceUri) {
1412 throw new ArgumentException(Res.GetString(Res.Xml_XmlPrefix));
1415 kind = NamespaceKind.Implied;
1419 Debug.Assert(prefix == "xmlns");
1420 throw new ArgumentException(Res.GetString(Res.Xml_XmlnsPrefix));
1423 // regular namespace declaration -> compare the namespace Uris to decide if the prefix is redefined
1425 kind = (nsStack[existingNsIndex].namespaceUri == ns) ? NamespaceKind.Implied : NamespaceKind.NeedToWrite;
1429 // No existing declaration found in the namespace stack
1431 // validate special declaration (xml, xmlns)
1432 if ((ns == XmlReservedNs.NsXml && prefix != "xml") ||
1433 (ns == XmlReservedNs.NsXmlNs && prefix != "xmlns")) {
1434 throw new ArgumentException(Res.GetString(Res.Xml_NamespaceDeclXmlXmlns, prefix));
1437 // check if it can be found in the predefinedNamespaces (which are provided by the user)
1438 if (predefinedNamespaces != null) {
1439 string definedNs = predefinedNamespaces.LookupNamespace(prefix);
1440 // compare the namespace Uri to decide if the prefix is redefined
1441 kind = (definedNs == ns) ? NamespaceKind.Implied : NamespaceKind.NeedToWrite;
1444 // Namespace not declared anywhere yet, we need to write it out
1445 kind = NamespaceKind.NeedToWrite;
1449 AddNamespace(prefix, ns, kind);
1452 // PushNamespaceExplicit is called when a namespace declaration is written out;
1453 // It returs true if the namespace declaration should we written out, false if it should be omited (if OmitDuplicateNamespaceDeclarations is true)
1454 private bool PushNamespaceExplicit(string prefix, string ns) {
1455 bool writeItOut = true;
1457 // See if the prefix is already defined
1458 int existingNsIndex = LookupNamespaceIndex(prefix);
1460 // Existing declaration in the current scope
1461 if (existingNsIndex != -1) {
1462 // It is defined in the current scope
1463 if (existingNsIndex > elemScopeStack[elemTop].prevNSTop) {
1464 // The new namespace Uri needs to be the same as the one that is already declared
1465 if (nsStack[existingNsIndex].namespaceUri != ns) {
1466 throw new XmlException(Res.Xml_RedefinePrefix, new string[] { prefix, nsStack[existingNsIndex].namespaceUri, ns });
1468 // Check for duplicate declarations
1469 NamespaceKind existingNsKind = nsStack[existingNsIndex].kind;
1470 if (existingNsKind == NamespaceKind.Written) {
1471 throw DupAttrException((prefix.Length == 0) ? string.Empty : "xmlns", (prefix.Length == 0) ? "xmlns" : prefix);
1473 // Check if it can be omitted
1474 if (omitDuplNamespaces && existingNsKind != NamespaceKind.NeedToWrite) {
1477 nsStack[existingNsIndex].kind = NamespaceKind.Written;
1478 // No additional work needed
1481 // The prefix is defined but in a different scope
1483 // check if is the same and can be omitted
1484 if (nsStack[existingNsIndex].namespaceUri == ns && omitDuplNamespaces) {
1489 // No existing declaration found in the namespace stack
1491 // check if it can be found in the predefinedNamespaces (which are provided by the user)
1492 if (predefinedNamespaces != null) {
1493 string definedNs = predefinedNamespaces.LookupNamespace(prefix);
1494 // compare the namespace Uri to decide if the prefix is redefined
1495 if (definedNs == ns && omitDuplNamespaces) {
1501 // validate special declaration (xml, xmlns)
1502 if ((ns == XmlReservedNs.NsXml && prefix != "xml") ||
1503 (ns == XmlReservedNs.NsXmlNs && prefix != "xmlns")) {
1504 throw new ArgumentException(Res.GetString(Res.Xml_NamespaceDeclXmlXmlns, prefix));
1506 if (prefix.Length > 0 && prefix[0] == 'x') {
1507 if (prefix == "xml") {
1508 if (ns != XmlReservedNs.NsXml) {
1509 throw new ArgumentException(Res.GetString(Res.Xml_XmlPrefix));
1512 else if (prefix == "xmlns") {
1513 throw new ArgumentException(Res.GetString(Res.Xml_XmlnsPrefix));
1517 AddNamespace(prefix, ns, NamespaceKind.Written);
1522 private void AddNamespace(string prefix, string ns, NamespaceKind kind) {
1524 if (top == nsStack.Length) {
1525 Namespace[] newStack = new Namespace[top * 2];
1526 Array.Copy(nsStack, newStack, top);
1529 nsStack[top].Set(prefix, ns, kind);
1531 if (useNsHashtable) {
1533 AddToNamespaceHashtable(nsTop);
1535 else if (nsTop == MaxNamespacesWalkCount) {
1537 nsHashtable = new Dictionary<string, int>(hasher);
1538 for (int i = 0; i <= nsTop; i++) {
1539 AddToNamespaceHashtable(i);
1541 useNsHashtable = true;
1545 private void AddToNamespaceHashtable(int namespaceIndex) {
1546 string prefix = nsStack[namespaceIndex].prefix;
1547 int existingNsIndex;
1548 if (nsHashtable.TryGetValue(prefix, out existingNsIndex)) {
1549 nsStack[namespaceIndex].prevNsIndex = existingNsIndex;
1551 nsHashtable[prefix] = namespaceIndex;
1554 private int LookupNamespaceIndex(string prefix) {
1556 if (useNsHashtable) {
1557 if (nsHashtable.TryGetValue(prefix, out index)) {
1562 for (int i = nsTop; i >= 0; i--) {
1563 if (nsStack[i].prefix == prefix) {
1571 private void PopNamespaces(int indexFrom, int indexTo) {
1572 Debug.Assert(useNsHashtable);
1573 Debug.Assert(indexFrom <= indexTo);
1574 for (int i = indexTo; i >= indexFrom; i--) {
1575 Debug.Assert(nsHashtable.ContainsKey(nsStack[i].prefix));
1576 if (nsStack[i].prevNsIndex == -1) {
1577 nsHashtable.Remove(nsStack[i].prefix);
1580 nsHashtable[nsStack[i].prefix] = nsStack[i].prevNsIndex;
1585 static private XmlException DupAttrException(string prefix, string localName) {
1586 StringBuilder sb = new StringBuilder();
1587 if (prefix.Length > 0) {
1591 sb.Append(localName);
1592 return new XmlException(Res.Xml_DupAttributeName, sb.ToString());
1595 // Advance the state machine
1596 private void AdvanceState(Token token) {
1597 if ((int)currentState >= (int)State.Closed) {
1598 if (currentState == State.Closed || currentState == State.Error) {
1599 throw new InvalidOperationException(Res.GetString(Res.Xml_ClosedOrError));
1602 throw new InvalidOperationException(Res.GetString(Res.Xml_WrongToken, tokenName[(int)token], GetStateName(currentState)));
1607 State newState = stateTable[((int)token << 4) + (int)currentState];
1608 // [ (int)token * 16 + (int)currentState ];
1610 if ((int)newState >= (int)State.Error) {
1613 ThrowInvalidStateTransition(token, currentState);
1616 case State.StartContent:
1617 StartElementContent();
1618 newState = State.Content;
1621 case State.StartContentEle:
1622 StartElementContent();
1623 newState = State.Element;
1626 case State.StartContentB64:
1627 StartElementContent();
1628 newState = State.B64Content;
1631 case State.StartDoc:
1632 WriteStartDocument();
1633 newState = State.Document;
1636 case State.StartDocEle:
1637 WriteStartDocument();
1638 newState = State.Element;
1641 case State.EndAttrSEle:
1642 WriteEndAttribute();
1643 StartElementContent();
1644 newState = State.Element;
1647 case State.EndAttrEEle:
1648 WriteEndAttribute();
1649 StartElementContent();
1650 newState = State.Content;
1653 case State.EndAttrSCont:
1654 WriteEndAttribute();
1655 StartElementContent();
1656 newState = State.Content;
1659 case State.EndAttrSAttr:
1660 WriteEndAttribute();
1661 newState = State.Attribute;
1664 case State.PostB64Cont:
1665 if (rawWriter != null) {
1666 rawWriter.WriteEndBase64();
1668 currentState = State.Content;
1671 case State.PostB64Attr:
1672 if (rawWriter != null) {
1673 rawWriter.WriteEndBase64();
1675 currentState = State.Attribute;
1678 case State.PostB64RootAttr:
1679 if (rawWriter != null) {
1680 rawWriter.WriteEndBase64();
1682 currentState = State.RootLevelAttr;
1685 case State.StartFragEle:
1687 newState = State.Element;
1690 case State.StartFragCont:
1692 newState = State.Content;
1695 case State.StartFragB64:
1697 newState = State.B64Content;
1700 case State.StartRootLevelAttr:
1701 WriteEndAttribute();
1702 newState = State.RootLevelAttr;
1706 Debug.Assert(false, "We should not get to this point.");
1711 currentState = newState;
1714 private void StartElementContent() {
1715 // write namespace declarations
1716 int start = elemScopeStack[elemTop].prevNSTop;
1717 for (int i = nsTop; i > start; i--) {
1718 if (nsStack[i].kind == NamespaceKind.NeedToWrite) {
1719 nsStack[i].WriteDecl(writer, rawWriter);
1723 if (rawWriter != null) {
1724 rawWriter.StartElementContent();
1728 private static string GetStateName(State state) {
1729 if (state >= State.Error) {
1730 Debug.Assert(false, "We should never get to this point. State = " + state);
1734 return stateName[(int)state];
1738 internal string LookupNamespace(string prefix) {
1739 for (int i = nsTop; i >= 0; i--) {
1740 if (nsStack[i].prefix == prefix) {
1741 return nsStack[i].namespaceUri;
1744 return (predefinedNamespaces != null) ? predefinedNamespaces.LookupNamespace(prefix) : null;
1747 private string LookupLocalNamespace(string prefix) {
1748 for (int i = nsTop; i > elemScopeStack[elemTop].prevNSTop; i--) {
1749 if (nsStack[i].prefix == prefix) {
1750 return nsStack[i].namespaceUri;
1756 private string GeneratePrefix() {
1757 string genPrefix = "p" + (nsTop - 2).ToString("d", CultureInfo.InvariantCulture);
1758 if (LookupNamespace(genPrefix) == null) {
1765 s = string.Concat(genPrefix, i.ToString(CultureInfo.InvariantCulture));
1767 } while (LookupNamespace(s) != null);
1771 #if SILVERLIGHT && !SILVERLIGHT_DISABLE_SECURITY && XMLCHARTYPE_USE_RESOURCE
1772 [System.Security.SecuritySafeCritical]
1774 private unsafe void CheckNCName(string ncname) {
1775 Debug.Assert(ncname != null && ncname.Length > 0);
1778 int endPos = ncname.Length;
1780 // Check if first character is StartNCName (inc. surrogates)
1781 if ((xmlCharType.charProperties[ncname[0]] & XmlCharType.fNCStartNameSC) != 0) { // if ( xmlCharType.IsStartNCNameChar( ncname[0] ) ) {
1784 #if XML10_FIFTH_EDITION
1785 else if (xmlCharType.IsNCNameSurrogateChar(ncname, 0)) { // surrogate ranges are same for NCName and StartNCName
1790 throw InvalidCharsException(ncname, 0);
1793 // Check if following characters are NCName (inc. surrogates)
1794 while (i < endPos) {
1795 if ((xmlCharType.charProperties[ncname[i]] & XmlCharType.fNCNameSC) != 0) { // if ( xmlCharType.IsNCNameChar( ncname[i] ) ) {
1798 #if XML10_FIFTH_EDITION
1799 else if (xmlCharType.IsNCNameSurrogateChar(ncname, i)) {
1804 throw InvalidCharsException(ncname, i);
1809 private static Exception InvalidCharsException(string name, int badCharIndex) {
1810 string[] badCharArgs = XmlException.BuildCharExceptionArgs(name, badCharIndex);
1811 string[] args = new string[3];
1813 args[1] = badCharArgs[0];
1814 args[2] = badCharArgs[1];
1815 return new ArgumentException(Res.GetString(Res.Xml_InvalidNameCharsDetail, args));
1818 // This method translates speficic state transition errors in more friendly error messages
1819 private void ThrowInvalidStateTransition(Token token, State currentState) {
1820 string wrongTokenMessage = Res.GetString(Res.Xml_WrongToken, tokenName[(int)token], GetStateName(currentState));
1821 switch (currentState) {
1822 case State.AfterRootEle:
1824 if (conformanceLevel == ConformanceLevel.Document) {
1825 throw new InvalidOperationException(wrongTokenMessage + ' ' + Res.GetString(Res.Xml_ConformanceLevelFragment));
1829 throw new InvalidOperationException(wrongTokenMessage);
1832 private bool IsClosedOrErrorState {
1834 return (int)currentState >= (int)State.Closed;
1838 private void AddAttribute(string prefix, string localName, string namespaceName) {
1839 int top = attrCount++;
1840 if (top == attrStack.Length) {
1841 AttrName[] newStack = new AttrName[top * 2];
1842 Array.Copy(attrStack, newStack, top);
1843 attrStack = newStack;
1845 attrStack[top].Set(prefix, localName, namespaceName);
1847 if (attrCount < MaxAttrDuplWalkCount) {
1848 // check for duplicates
1849 for (int i = 0; i < top; i++) {
1850 if (attrStack[i].IsDuplicate(prefix, localName, namespaceName)) {
1851 throw DupAttrException(prefix, localName);
1856 // reached the threshold -> add all attributes to hash table
1857 if (attrCount == MaxAttrDuplWalkCount) {
1858 if (attrHashTable == null) {
1859 attrHashTable = new Dictionary<string, int>(hasher);
1861 Debug.Assert(attrHashTable.Count == 0);
1862 for (int i = 0; i < top; i++) {
1863 AddToAttrHashTable(i);
1867 // add last attribute to hash table and check for duplicates
1868 AddToAttrHashTable(top);
1869 int prev = attrStack[top].prev;
1871 // indexes are stored incremented by 1, 0 means no entry
1873 if (attrStack[prev].IsDuplicate(prefix, localName, namespaceName)) {
1874 throw DupAttrException(prefix, localName);
1876 prev = attrStack[prev].prev;
1881 private void AddToAttrHashTable(int attributeIndex) {
1882 string localName = attrStack[attributeIndex].localName;
1883 int count = attrHashTable.Count;
1884 attrHashTable[localName] = 0; // overwrite on collision
1885 if (count != attrHashTable.Count) {
1888 // chain to previous attribute in stack with the same localName
1889 int prev = attributeIndex - 1;
1891 if (attrStack[prev].localName == localName) {
1896 Debug.Assert(prev >= 0 && attrStack[prev].localName == localName);
1897 attrStack[attributeIndex].prev = prev + 1; // indexes are stored incremented by 1