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 Bug #479769
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