1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4 namespace System.Xml
5 {
6     using System.Globalization;
7     using System.IO;
8     using System.Runtime;
9     using System.Runtime.Serialization;
10     using System.Text;
11     using System.Threading.Tasks;
12 
13     abstract class XmlBaseWriter : XmlDictionaryWriter, IFragmentCapableXmlDictionaryWriter
14     {
15         XmlNodeWriter writer;
16         NamespaceManager nsMgr;
17         Element[] elements;
18         int depth;
19         string attributeLocalName;
20         string attributeValue;
21         bool isXmlAttribute;
22         bool isXmlnsAttribute;
23         WriteState writeState;
24         DocumentState documentState;
25         byte[] trailBytes;
26         int trailByteCount;
27         XmlStreamNodeWriter nodeWriter;
28         XmlSigningNodeWriter signingWriter;
29         XmlUTF8NodeWriter textFragmentWriter;
30         XmlNodeWriter oldWriter;
31         Stream oldStream;
32         int oldNamespaceBoundary;
33         bool inList;
34         const string xmlnsNamespace = "http://www.w3.org/2000/xmlns/";
35         const string xmlNamespace = "http://www.w3.org/XML/1998/namespace";
36         static BinHexEncoding binhexEncoding;
37         static string[] prefixes = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" };
38         XmlBaseWriterNodeWriterAsyncHelper nodeWriterAsyncHelper;
39 
XmlBaseWriter()40         protected XmlBaseWriter()
41         {
42             this.nsMgr = new NamespaceManager();
43             this.writeState = WriteState.Start;
44             this.documentState = DocumentState.None;
45         }
46 
SetOutput(XmlStreamNodeWriter writer)47         protected void SetOutput(XmlStreamNodeWriter writer)
48         {
49             this.inList = false;
50             this.writer = writer;
51             this.nodeWriter = writer;
52             this.writeState = WriteState.Start;
53             this.documentState = DocumentState.None;
54             this.nsMgr.Clear();
55             if (this.depth != 0)
56             {
57                 this.elements = null;
58                 this.depth = 0;
59             }
60             this.attributeLocalName = null;
61             this.attributeValue = null;
62             this.oldWriter = null;
63             this.oldStream = null;
64         }
65 
Flush()66         public override void Flush()
67         {
68             if (IsClosed)
69                 ThrowClosed();
70 
71             writer.Flush();
72         }
73 
Close()74         public override void Close()
75         {
76             if (IsClosed)
77                 return;
78 
79             try
80             {
81                 FinishDocument();
82                 AutoComplete(WriteState.Closed);
83                 writer.Flush();
84             }
85             finally
86             {
87                 nsMgr.Close();
88                 if (depth != 0)
89                 {
90                     elements = null;
91                     depth = 0;
92                 }
93                 attributeValue = null;
94                 attributeLocalName = null;
95                 nodeWriter.Close();
96                 if (signingWriter != null)
97                 {
98                     signingWriter.Close();
99                 }
100                 if (textFragmentWriter != null)
101                 {
102                     textFragmentWriter.Close();
103                 }
104                 oldWriter = null;
105                 oldStream = null;
106             }
107         }
108 
109         protected bool IsClosed
110         {
111             get { return writeState == WriteState.Closed; }
112         }
113 
ThrowClosed()114         protected void ThrowClosed()
115         {
116             throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlWriterClosed)));
117         }
118 
119         static BinHexEncoding BinHexEncoding
120         {
121             get
122             {
123                 if (binhexEncoding == null)
124                     binhexEncoding = new BinHexEncoding();
125                 return binhexEncoding;
126             }
127         }
128 
129         public override string XmlLang
130         {
131             get
132             {
133                 return nsMgr.XmlLang;
134             }
135         }
136 
137         public override XmlSpace XmlSpace
138         {
139             get
140             {
141                 return nsMgr.XmlSpace;
142             }
143         }
144 
145         public override WriteState WriteState
146         {
147             get
148             {
149                 return writeState;
150             }
151         }
152 
WriteXmlnsAttribute(string prefix, string ns)153         public override void WriteXmlnsAttribute(string prefix, string ns)
154         {
155             if (IsClosed)
156                 ThrowClosed();
157 
158             if (ns == null)
159                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("ns");
160 
161             if (writeState != WriteState.Element)
162                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteXmlnsAttribute", WriteState.ToString())));
163 
164             if (prefix == null)
165             {
166                 prefix = nsMgr.LookupPrefix(ns);
167                 if (prefix == null)
168                 {
169                     GeneratePrefix(ns, null);
170                 }
171             }
172             else
173             {
174                 nsMgr.AddNamespaceIfNotDeclared(prefix, ns, null);
175             }
176         }
177 
WriteXmlnsAttribute(string prefix, XmlDictionaryString ns)178         public override void WriteXmlnsAttribute(string prefix, XmlDictionaryString ns)
179         {
180             if (IsClosed)
181                 ThrowClosed();
182 
183             if (ns == null)
184                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("ns");
185 
186             if (writeState != WriteState.Element)
187                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteXmlnsAttribute", WriteState.ToString())));
188 
189             if (prefix == null)
190             {
191                 prefix = nsMgr.LookupPrefix(ns.Value);
192                 if (prefix == null)
193                 {
194                     GeneratePrefix(ns.Value, ns);
195                 }
196             }
197             else
198             {
199                 nsMgr.AddNamespaceIfNotDeclared(prefix, ns.Value, ns);
200             }
201         }
202 
StartAttribute(ref string prefix, string localName, string ns, XmlDictionaryString xNs)203         void StartAttribute(ref string prefix, string localName, string ns, XmlDictionaryString xNs)
204         {
205             if (IsClosed)
206                 ThrowClosed();
207 
208             if (writeState == WriteState.Attribute)
209                 WriteEndAttribute();
210 
211             if (localName == null || (localName.Length == 0 && prefix != "xmlns"))
212                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("localName"));
213 
214             if (writeState != WriteState.Element)
215                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteStartAttribute", WriteState.ToString())));
216 
217             if (prefix == null)
218             {
219                 if (ns == xmlnsNamespace && localName != "xmlns")
220                     prefix = "xmlns";
221                 else if (ns == xmlNamespace)
222                     prefix = "xml";
223                 else
224                     prefix = string.Empty;
225             }
226 
227             // Normalize a (prefix,localName) of (null, "xmlns") to ("xmlns", string.Empty).
228             if (prefix.Length == 0 && localName == "xmlns")
229             {
230                 prefix = "xmlns";
231                 localName = string.Empty;
232             }
233 
234             isXmlnsAttribute = false;
235             isXmlAttribute = false;
236             if (prefix == "xml")
237             {
238                 if (ns != null && ns != xmlNamespace)
239                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlPrefixBoundToNamespace, "xml", xmlNamespace, ns), "ns"));
240                 isXmlAttribute = true;
241                 attributeValue = string.Empty;
242                 attributeLocalName = localName;
243             }
244             else if (prefix == "xmlns")
245             {
246                 if (ns != null && ns != xmlnsNamespace)
247                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlPrefixBoundToNamespace, "xmlns", xmlnsNamespace, ns), "ns"));
248                 isXmlnsAttribute = true;
249                 attributeValue = string.Empty;
250                 attributeLocalName = localName;
251             }
252             else if (ns == null)
253             {
254                 // A null namespace means the namespace of the given prefix.
255                 if (prefix.Length == 0)
256                 {
257                     // An empty prefix on an attribute means no namespace (not the default namespace)
258                     ns = string.Empty;
259                 }
260                 else
261                 {
262                     ns = nsMgr.LookupNamespace(prefix);
263 
264                     if (ns == null)
265                         throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlUndefinedPrefix, prefix), "prefix"));
266                 }
267             }
268             else if (ns.Length == 0)
269             {
270                 // An empty namespace means no namespace; prefix must be empty
271                 if (prefix.Length != 0)
272                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlEmptyNamespaceRequiresNullPrefix), "prefix"));
273             }
274             else if (prefix.Length == 0)
275             {
276                 // No prefix specified - try to find a prefix corresponding to the given namespace
277                 prefix = nsMgr.LookupAttributePrefix(ns);
278 
279                 // If we didn't find anything with the right namespace, generate one.
280                 if (prefix == null)
281                 {
282                     // Watch for special values
283                     if (ns.Length == xmlnsNamespace.Length && ns == xmlnsNamespace)
284                         throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlSpecificBindingNamespace, "xmlns", ns)));
285                     if (ns.Length == xmlNamespace.Length && ns == xmlNamespace)
286                         throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlSpecificBindingNamespace, "xml", ns)));
287 
288                     prefix = GeneratePrefix(ns, xNs);
289                 }
290             }
291             else
292             {
293                 nsMgr.AddNamespaceIfNotDeclared(prefix, ns, xNs);
294             }
295             writeState = WriteState.Attribute;
296         }
297 
WriteStartAttribute(string prefix, string localName, string namespaceUri)298         public override void WriteStartAttribute(string prefix, string localName, string namespaceUri)
299         {
300             StartAttribute(ref prefix, localName, namespaceUri, null);
301             if (!isXmlnsAttribute)
302             {
303                 writer.WriteStartAttribute(prefix, localName);
304             }
305         }
306 
WriteStartAttribute(string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri)307         public override void WriteStartAttribute(string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri)
308         {
309             StartAttribute(ref prefix, (localName != null ? localName.Value : null), (namespaceUri != null ? namespaceUri.Value : null), namespaceUri);
310             if (!isXmlnsAttribute)
311             {
312                 writer.WriteStartAttribute(prefix, localName);
313             }
314         }
315 
WriteEndAttribute()316         public override void WriteEndAttribute()
317         {
318             if (IsClosed)
319                 ThrowClosed();
320 
321             if (writeState != WriteState.Attribute)
322                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteEndAttribute", WriteState.ToString())));
323 
324             FlushBase64();
325             try
326             {
327                 if (isXmlAttribute)
328                 {
329                     if (attributeLocalName == "lang")
330                     {
331                         nsMgr.AddLangAttribute(attributeValue);
332                     }
333                     else if (attributeLocalName == "space")
334                     {
335                         if (attributeValue == "preserve")
336                         {
337                             nsMgr.AddSpaceAttribute(XmlSpace.Preserve);
338                         }
339                         else if (attributeValue == "default")
340                         {
341                             nsMgr.AddSpaceAttribute(XmlSpace.Default);
342                         }
343                         else
344                         {
345                             throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlInvalidXmlSpace, attributeValue)));
346                         }
347                     }
348                     else
349                     {
350                         // XmlTextWriter specifically allows for other localNames
351                     }
352                     isXmlAttribute = false;
353                     attributeLocalName = null;
354                     attributeValue = null;
355                 }
356 
357                 if (isXmlnsAttribute)
358                 {
359                     nsMgr.AddNamespaceIfNotDeclared(attributeLocalName, attributeValue, null);
360                     isXmlnsAttribute = false;
361                     attributeLocalName = null;
362                     attributeValue = null;
363                 }
364                 else
365                 {
366                     writer.WriteEndAttribute();
367                 }
368             }
369             finally
370             {
371                 writeState = WriteState.Element;
372             }
373         }
374 
WriteComment(string text)375         public override void WriteComment(string text)
376         {
377             if (IsClosed)
378                 ThrowClosed();
379 
380             if (writeState == WriteState.Attribute)
381                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteComment", WriteState.ToString())));
382 
383             if (text == null)
384             {
385                 text = string.Empty;
386             }
387             else if (text.IndexOf("--", StringComparison.Ordinal) != -1 || (text.Length > 0 && text[text.Length - 1] == '-'))
388             {
389                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlInvalidCommentChars), "text"));
390             }
391 
392             StartComment();
393             FlushBase64();
394             writer.WriteComment(text);
395             EndComment();
396         }
397 
WriteFullEndElement()398         public override void WriteFullEndElement()
399         {
400             if (IsClosed)
401                 ThrowClosed();
402 
403             if (writeState == WriteState.Attribute)
404                 WriteEndAttribute();
405 
406             if (writeState != WriteState.Element && writeState != WriteState.Content)
407                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteFullEndElement", WriteState.ToString())));
408 
409             AutoComplete(WriteState.Content);
410             WriteEndElement();
411         }
412 
WriteCData(string text)413         public override void WriteCData(string text)
414         {
415             if (IsClosed)
416                 ThrowClosed();
417 
418             if (writeState == WriteState.Attribute)
419                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteCData", WriteState.ToString())));
420 
421             if (text == null)
422                 text = string.Empty;
423 
424             if (text.Length > 0)
425             {
426                 StartContent();
427                 FlushBase64();
428                 writer.WriteCData(text);
429                 EndContent();
430             }
431         }
432 
WriteDocType(string name, string pubid, string sysid, string subset)433         public override void WriteDocType(string name, string pubid, string sysid, string subset)
434         {
435             throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.XmlMethodNotSupported, "WriteDocType")));
436         }
437 
StartElement(ref string prefix, string localName, string ns, XmlDictionaryString xNs)438         void StartElement(ref string prefix, string localName, string ns, XmlDictionaryString xNs)
439         {
440             if (IsClosed)
441                 ThrowClosed();
442 
443             if (this.documentState == DocumentState.Epilog)
444                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlOnlyOneRoot)));
445             if (localName == null)
446                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("localName"));
447             if (localName.Length == 0)
448                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.InvalidLocalNameEmpty), "localName"));
449             if (writeState == WriteState.Attribute)
450                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteStartElement", WriteState.ToString())));
451 
452             FlushBase64();
453             AutoComplete(WriteState.Element);
454             Element element = EnterScope();
455             if (ns == null)
456             {
457                 if (prefix == null)
458                     prefix = string.Empty;
459 
460                 ns = nsMgr.LookupNamespace(prefix);
461 
462                 if (ns == null)
463                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlUndefinedPrefix, prefix), "prefix"));
464             }
465             else if (prefix == null)
466             {
467                 prefix = nsMgr.LookupPrefix(ns);
468 
469                 if (prefix == null)
470                 {
471                     prefix = string.Empty;
472                     nsMgr.AddNamespace(string.Empty, ns, xNs);
473                 }
474             }
475             else
476             {
477                 nsMgr.AddNamespaceIfNotDeclared(prefix, ns, xNs);
478             }
479             element.Prefix = prefix;
480             element.LocalName = localName;
481         }
482 
WriteStartElement(string prefix, string localName, string namespaceUri)483         public override void WriteStartElement(string prefix, string localName, string namespaceUri)
484         {
485             StartElement(ref prefix, localName, namespaceUri, null);
486             writer.WriteStartElement(prefix, localName);
487         }
488 
WriteStartElement(string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri)489         public override void WriteStartElement(string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri)
490         {
491             StartElement(ref prefix, (localName != null ? localName.Value : null), (namespaceUri != null ? namespaceUri.Value : null), namespaceUri);
492             writer.WriteStartElement(prefix, localName);
493         }
494 
WriteEndElement()495         public override void WriteEndElement()
496         {
497             if (IsClosed)
498                 ThrowClosed();
499 
500             if (depth == 0)
501                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidDepth, "WriteEndElement", depth.ToString(CultureInfo.InvariantCulture))));
502 
503             if (writeState == WriteState.Attribute)
504                 WriteEndAttribute();
505 
506             FlushBase64();
507             if (writeState == WriteState.Element)
508             {
509                 nsMgr.DeclareNamespaces(writer);
510                 writer.WriteEndStartElement(true);
511             }
512             else
513             {
514                 Element element = elements[depth];
515                 writer.WriteEndElement(element.Prefix, element.LocalName);
516             }
517 
518             ExitScope();
519             writeState = WriteState.Content;
520         }
521 
EnterScope()522         Element EnterScope()
523         {
524             nsMgr.EnterScope();
525             depth++;
526             if (elements == null)
527             {
528                 elements = new Element[4];
529             }
530             else if (elements.Length == depth)
531             {
532                 Element[] newElementNodes = new Element[depth * 2];
533                 Array.Copy(elements, newElementNodes, depth);
534                 elements = newElementNodes;
535             }
536             Element element = elements[depth];
537             if (element == null)
538             {
539                 element = new Element();
540                 elements[depth] = element;
541             }
542             return element;
543         }
544 
ExitScope()545         void ExitScope()
546         {
547             elements[depth].Clear();
548             depth--;
549             if (depth == 0 && documentState == DocumentState.Document)
550                 this.documentState = DocumentState.Epilog;
551             nsMgr.ExitScope();
552         }
553 
FlushElement()554         protected void FlushElement()
555         {
556             if (this.writeState == WriteState.Element)
557             {
558                 AutoComplete(WriteState.Content);
559             }
560         }
561 
StartComment()562         protected void StartComment()
563         {
564             FlushElement();
565         }
566 
EndComment()567         protected void EndComment()
568         {
569         }
570 
StartContent()571         protected void StartContent()
572         {
573             FlushElement();
574             if (depth == 0)
575                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlIllegalOutsideRoot)));
576         }
577 
StartContent(char ch)578         protected void StartContent(char ch)
579         {
580             FlushElement();
581             if (depth == 0)
582                 VerifyWhitespace(ch);
583         }
584 
StartContent(string s)585         protected void StartContent(string s)
586         {
587             FlushElement();
588             if (depth == 0)
589                 VerifyWhitespace(s);
590         }
591 
StartContent(char[] chars, int offset, int count)592         protected void StartContent(char[] chars, int offset, int count)
593         {
594             FlushElement();
595             if (depth == 0)
596                 VerifyWhitespace(chars, offset, count);
597         }
598 
VerifyWhitespace(char ch)599         void VerifyWhitespace(char ch)
600         {
601             if (!IsWhitespace(ch))
602                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlIllegalOutsideRoot)));
603         }
604 
VerifyWhitespace(string s)605         void VerifyWhitespace(string s)
606         {
607             for (int i = 0; i < s.Length; i++)
608                 if (!IsWhitespace(s[i]))
609                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlIllegalOutsideRoot)));
610         }
611 
VerifyWhitespace(char[] chars, int offset, int count)612         void VerifyWhitespace(char[] chars, int offset, int count)
613         {
614             for (int i = 0; i < count; i++)
615                 if (!IsWhitespace(chars[offset + i]))
616                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlIllegalOutsideRoot)));
617         }
618 
IsWhitespace(char ch)619         bool IsWhitespace(char ch)
620         {
621             return (ch == ' ' || ch == '\n' || ch == '\r' || ch == 't');
622         }
623 
EndContent()624         protected void EndContent()
625         {
626         }
627 
AutoComplete(WriteState writeState)628         void AutoComplete(WriteState writeState)
629         {
630             if (this.writeState == WriteState.Element)
631             {
632                 EndStartElement();
633             }
634             this.writeState = writeState;
635         }
636 
EndStartElement()637         void EndStartElement()
638         {
639             nsMgr.DeclareNamespaces(writer);
640             writer.WriteEndStartElement(false);
641         }
642 
LookupPrefix(string ns)643         public override string LookupPrefix(string ns)
644         {
645             if (ns == null)
646                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("ns"));
647 
648             if (IsClosed)
649                 ThrowClosed();
650 
651             return nsMgr.LookupPrefix(ns);
652         }
653 
LookupNamespace(string prefix)654         internal string LookupNamespace(string prefix)
655         {
656             if (prefix == null)
657                 return null;
658             return nsMgr.LookupNamespace(prefix);
659         }
660 
GetQualifiedNamePrefix(string namespaceUri, XmlDictionaryString xNs)661         string GetQualifiedNamePrefix(string namespaceUri, XmlDictionaryString xNs)
662         {
663             string prefix = nsMgr.LookupPrefix(namespaceUri);
664             if (prefix == null)
665             {
666                 if (writeState != WriteState.Attribute)
667                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlNamespaceNotFound, namespaceUri), "namespaceUri"));
668 
669                 prefix = GeneratePrefix(namespaceUri, xNs);
670             }
671             return prefix;
672         }
673 
WriteQualifiedName(string localName, string namespaceUri)674         public override void WriteQualifiedName(string localName, string namespaceUri)
675         {
676             if (IsClosed)
677                 ThrowClosed();
678             if (localName == null)
679                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("localName"));
680             if (localName.Length == 0)
681                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.InvalidLocalNameEmpty), "localName"));
682             if (namespaceUri == null)
683                 namespaceUri = string.Empty;
684             string prefix = GetQualifiedNamePrefix(namespaceUri, null);
685             if (prefix.Length != 0)
686             {
687                 WriteString(prefix);
688                 WriteString(":");
689             }
690             WriteString(localName);
691         }
692 
WriteQualifiedName(XmlDictionaryString localName, XmlDictionaryString namespaceUri)693         public override void WriteQualifiedName(XmlDictionaryString localName, XmlDictionaryString namespaceUri)
694         {
695             if (IsClosed)
696                 ThrowClosed();
697             if (localName == null)
698                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("localName"));
699             if (localName.Value.Length == 0)
700                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.InvalidLocalNameEmpty), "localName"));
701             if (namespaceUri == null)
702                 namespaceUri = XmlDictionaryString.Empty;
703             string prefix = GetQualifiedNamePrefix(namespaceUri.Value, namespaceUri);
704 
705             FlushBase64();
706             if (attributeValue != null)
707                 WriteAttributeText(string.Concat(prefix, ":", namespaceUri.Value));
708 
709             if (!isXmlnsAttribute)
710             {
711                 StartContent();
712                 writer.WriteQualifiedName(prefix, localName);
713                 EndContent();
714             }
715         }
716 
WriteStartDocument()717         public override void WriteStartDocument()
718         {
719             if (IsClosed)
720                 ThrowClosed();
721 
722             if (writeState != WriteState.Start)
723                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteStartDocument", WriteState.ToString())));
724 
725             writeState = WriteState.Prolog;
726             documentState = DocumentState.Document;
727             writer.WriteDeclaration();
728         }
729 
WriteStartDocument(bool standalone)730         public override void WriteStartDocument(bool standalone)
731         {
732             if (IsClosed)
733                 ThrowClosed();
734 
735             WriteStartDocument();
736         }
737 
738 
WriteProcessingInstruction(string name, string text)739         public override void WriteProcessingInstruction(string name, string text)
740         {
741             if (IsClosed)
742                 ThrowClosed();
743 
744             if (name != "xml")
745                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlProcessingInstructionNotSupported), "name"));
746 
747             if (writeState != WriteState.Start)
748                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidDeclaration)));
749 
750             // The only thing the text can legitimately contain is version, encoding, and standalone.
751             // We only support version 1.0, we can only write whatever encoding we were supplied,
752             // and we don't support DTDs, so whatever values are supplied in the text argument are irrelevant.
753             writer.WriteDeclaration();
754         }
755 
FinishDocument()756         void FinishDocument()
757         {
758             if (this.writeState == WriteState.Attribute)
759             {
760                 WriteEndAttribute();
761             }
762 
763             while (this.depth > 0)
764             {
765                 WriteEndElement();
766             }
767         }
768 
WriteEndDocument()769         public override void WriteEndDocument()
770         {
771             if (IsClosed)
772                 ThrowClosed();
773 
774             if (writeState == WriteState.Start || writeState == WriteState.Prolog)
775                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlNoRootElement)));
776 
777             FinishDocument();
778             writeState = WriteState.Start;
779             documentState = DocumentState.End;
780         }
781 
782         protected int NamespaceBoundary
783         {
784             get
785             {
786                 return nsMgr.NamespaceBoundary;
787             }
788             set
789             {
790                 nsMgr.NamespaceBoundary = value;
791             }
792         }
793 
WriteEntityRef(string name)794         public override void WriteEntityRef(string name)
795         {
796             throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.XmlMethodNotSupported, "WriteEntityRef")));
797         }
798 
WriteName(string name)799         public override void WriteName(string name)
800         {
801             if (IsClosed)
802                 ThrowClosed();
803 
804             WriteString(name);
805         }
806 
WriteNmToken(string name)807         public override void WriteNmToken(string name)
808         {
809             throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.XmlMethodNotSupported, "WriteNmToken")));
810         }
811 
WriteWhitespace(string whitespace)812         public override void WriteWhitespace(string whitespace)
813         {
814             if (IsClosed)
815                 ThrowClosed();
816 
817             if (whitespace == null)
818                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("whitespace");
819 
820             for (int i = 0; i < whitespace.Length; ++i)
821             {
822                 char c = whitespace[i];
823                 if (c != ' ' &&
824                     c != '\t' &&
825                     c != '\n' &&
826                     c != '\r')
827                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlOnlyWhitespace), "whitespace"));
828             }
829 
830             WriteString(whitespace);
831         }
832 
WriteString(string value)833         public override void WriteString(string value)
834         {
835             if (IsClosed)
836                 ThrowClosed();
837 
838             if (value == null)
839                 value = string.Empty;
840 
841             if (value.Length > 0 || this.inList)
842             {
843                 FlushBase64();
844 
845                 if (attributeValue != null)
846                     WriteAttributeText(value);
847 
848                 if (!isXmlnsAttribute)
849                 {
850                     StartContent(value);
851                     writer.WriteEscapedText(value);
852                     EndContent();
853                 }
854             }
855         }
856 
WriteString(XmlDictionaryString value)857         public override void WriteString(XmlDictionaryString value)
858         {
859             if (IsClosed)
860                 ThrowClosed();
861 
862             if (value == null)
863                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
864 
865             if (value.Value.Length > 0)
866             {
867                 FlushBase64();
868 
869                 if (attributeValue != null)
870                     WriteAttributeText(value.Value);
871 
872                 if (!isXmlnsAttribute)
873                 {
874                     StartContent(value.Value);
875                     writer.WriteEscapedText(value);
876                     EndContent();
877                 }
878             }
879         }
880 
WriteChars(char[] chars, int offset, int count)881         public override void WriteChars(char[] chars, int offset, int count)
882         {
883             if (IsClosed)
884                 ThrowClosed();
885 
886             if (chars == null)
887                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("chars"));
888 
889             // Not checking upper bound because it will be caught by "count".  This is what XmlTextWriter does.
890             if (offset < 0)
891                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeNonNegative)));
892 
893             if (count < 0)
894                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeNonNegative)));
895             if (count > chars.Length - offset)
896                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.SizeExceedsRemainingBufferSpace, chars.Length - offset)));
897 
898             if (count > 0)
899             {
900                 FlushBase64();
901 
902                 if (attributeValue != null)
903                     WriteAttributeText(new string(chars, offset, count));
904 
905                 if (!isXmlnsAttribute)
906                 {
907                     StartContent(chars, offset, count);
908                     writer.WriteEscapedText(chars, offset, count);
909                     EndContent();
910                 }
911             }
912         }
913 
WriteRaw(string value)914         public override void WriteRaw(string value)
915         {
916             if (IsClosed)
917                 ThrowClosed();
918 
919             if (value == null)
920                 value = string.Empty;
921 
922             if (value.Length > 0)
923             {
924                 FlushBase64();
925 
926                 if (attributeValue != null)
927                     WriteAttributeText(value);
928 
929                 if (!isXmlnsAttribute)
930                 {
931                     StartContent(value);
932                     writer.WriteText(value);
933                     EndContent();
934                 }
935             }
936         }
937 
WriteRaw(char[] chars, int offset, int count)938         public override void WriteRaw(char[] chars, int offset, int count)
939         {
940             if (IsClosed)
941                 ThrowClosed();
942 
943             if (chars == null)
944                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("chars"));
945 
946             // Not checking upper bound because it will be caught by "count".  This is what XmlTextWriter does.
947             if (offset < 0)
948                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeNonNegative)));
949 
950             if (count < 0)
951                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeNonNegative)));
952             if (count > chars.Length - offset)
953                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.SizeExceedsRemainingBufferSpace, chars.Length - offset)));
954 
955             if (count > 0)
956             {
957                 FlushBase64();
958 
959                 if (attributeValue != null)
960                     WriteAttributeText(new string(chars, offset, count));
961 
962                 if (!isXmlnsAttribute)
963                 {
964                     StartContent(chars, offset, count);
965                     writer.WriteText(chars, offset, count);
966                     EndContent();
967                 }
968             }
969         }
970 
WriteCharEntity(char ch)971         public override void WriteCharEntity(char ch)
972         {
973             if (IsClosed)
974                 ThrowClosed();
975 
976             if (ch >= 0xd800 && ch <= 0xdfff)
977                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlMissingLowSurrogate), "ch"));
978 
979             if (attributeValue != null)
980                 WriteAttributeText(ch.ToString());
981 
982             if (!isXmlnsAttribute)
983             {
984                 StartContent(ch);
985                 FlushBase64();
986                 writer.WriteCharEntity(ch);
987                 EndContent();
988             }
989         }
990 
WriteSurrogateCharEntity(char lowChar, char highChar)991         public override void WriteSurrogateCharEntity(char lowChar, char highChar)
992         {
993             if (IsClosed)
994                 ThrowClosed();
995 
996             SurrogateChar ch = new SurrogateChar(lowChar, highChar);
997 
998             if (attributeValue != null)
999             {
1000                 char[] chars = new char[2] { highChar, lowChar };
1001                 WriteAttributeText(new string(chars));
1002             }
1003 
1004             if (!isXmlnsAttribute)
1005             {
1006                 StartContent();
1007                 FlushBase64();
1008                 writer.WriteCharEntity(ch.Char);
1009                 EndContent();
1010             }
1011         }
1012 
WriteValue(object value)1013         public override void WriteValue(object value)
1014         {
1015             if (IsClosed)
1016                 ThrowClosed();
1017 
1018             if (value == null)
1019                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("value"));
1020 
1021             else if (value is object[])
1022             {
1023                 WriteValue((object[])value);
1024             }
1025             else if (value is Array)
1026             {
1027                 WriteValue((Array)value);
1028             }
1029             else if (value is IStreamProvider)
1030             {
1031                 WriteValue((IStreamProvider)value);
1032             }
1033             else
1034             {
1035                 WritePrimitiveValue(value);
1036             }
1037         }
1038 
WritePrimitiveValue(object value)1039         protected void WritePrimitiveValue(object value)
1040         {
1041             if (IsClosed)
1042                 ThrowClosed();
1043 
1044             if (value == null)
1045                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("value"));
1046 
1047             if (value is ulong)
1048             {
1049                 WriteValue((ulong)value);
1050             }
1051             else if (value is string)
1052             {
1053                 WriteValue((string)value);
1054             }
1055             else if (value is int)
1056             {
1057                 WriteValue((int)value);
1058             }
1059             else if (value is long)
1060             {
1061                 WriteValue((long)value);
1062             }
1063             else if (value is bool)
1064             {
1065                 WriteValue((bool)value);
1066             }
1067             else if (value is double)
1068             {
1069                 WriteValue((double)value);
1070             }
1071             else if (value is DateTime)
1072             {
1073                 WriteValue((DateTime)value);
1074             }
1075             else if (value is float)
1076             {
1077                 WriteValue((float)value);
1078             }
1079             else if (value is decimal)
1080             {
1081                 WriteValue((decimal)value);
1082             }
1083             else if (value is XmlDictionaryString)
1084             {
1085                 WriteValue((XmlDictionaryString)value);
1086             }
1087             else if (value is UniqueId)
1088             {
1089                 WriteValue((UniqueId)value);
1090             }
1091             else if (value is Guid)
1092             {
1093                 WriteValue((Guid)value);
1094             }
1095             else if (value is TimeSpan)
1096             {
1097                 WriteValue((TimeSpan)value);
1098             }
1099             else if (value.GetType().IsArray)
1100             {
1101                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlNestedArraysNotSupported), "value"));
1102             }
1103             else
1104             {
1105                 base.WriteValue(value);
1106             }
1107         }
1108 
WriteValue(string value)1109         public override void WriteValue(string value)
1110         {
1111             if (IsClosed)
1112                 ThrowClosed();
1113 
1114             WriteString(value);
1115         }
1116 
WriteValue(int value)1117         public override void WriteValue(int value)
1118         {
1119             if (IsClosed)
1120                 ThrowClosed();
1121 
1122             FlushBase64();
1123             if (attributeValue != null)
1124                 WriteAttributeText(XmlConverter.ToString(value));
1125 
1126             if (!isXmlnsAttribute)
1127             {
1128                 StartContent();
1129                 writer.WriteInt32Text(value);
1130                 EndContent();
1131             }
1132         }
1133 
WriteValue(long value)1134         public override void WriteValue(long value)
1135         {
1136             if (IsClosed)
1137                 ThrowClosed();
1138 
1139             FlushBase64();
1140             if (attributeValue != null)
1141                 WriteAttributeText(XmlConverter.ToString(value));
1142 
1143             if (!isXmlnsAttribute)
1144             {
1145                 StartContent();
1146                 writer.WriteInt64Text(value);
1147                 EndContent();
1148             }
1149         }
1150 
WriteValue(ulong value)1151         void WriteValue(ulong value)
1152         {
1153             if (IsClosed)
1154                 ThrowClosed();
1155 
1156             FlushBase64();
1157             if (attributeValue != null)
1158                 WriteAttributeText(XmlConverter.ToString(value));
1159 
1160             if (!isXmlnsAttribute)
1161             {
1162                 StartContent();
1163                 writer.WriteUInt64Text(value);
1164                 EndContent();
1165             }
1166         }
1167 
WriteValue(bool value)1168         public override void WriteValue(bool value)
1169         {
1170             if (IsClosed)
1171                 ThrowClosed();
1172 
1173             FlushBase64();
1174             if (attributeValue != null)
1175                 WriteAttributeText(XmlConverter.ToString(value));
1176 
1177             if (!isXmlnsAttribute)
1178             {
1179                 StartContent();
1180                 writer.WriteBoolText(value);
1181                 EndContent();
1182             }
1183         }
1184 
WriteValue(decimal value)1185         public override void WriteValue(decimal value)
1186         {
1187             if (IsClosed)
1188                 ThrowClosed();
1189 
1190             FlushBase64();
1191             if (attributeValue != null)
1192                 WriteAttributeText(XmlConverter.ToString(value));
1193 
1194             if (!isXmlnsAttribute)
1195             {
1196                 StartContent();
1197                 writer.WriteDecimalText(value);
1198                 EndContent();
1199             }
1200         }
1201 
WriteValue(float value)1202         public override void WriteValue(float value)
1203         {
1204             if (IsClosed)
1205                 ThrowClosed();
1206 
1207             FlushBase64();
1208             if (attributeValue != null)
1209                 WriteAttributeText(XmlConverter.ToString(value));
1210 
1211             if (!isXmlnsAttribute)
1212             {
1213                 StartContent();
1214                 writer.WriteFloatText(value);
1215                 EndContent();
1216             }
1217         }
1218 
WriteValue(double value)1219         public override void WriteValue(double value)
1220         {
1221             if (IsClosed)
1222                 ThrowClosed();
1223 
1224             FlushBase64();
1225             if (attributeValue != null)
1226                 WriteAttributeText(XmlConverter.ToString(value));
1227 
1228             if (!isXmlnsAttribute)
1229             {
1230                 StartContent();
1231                 writer.WriteDoubleText(value);
1232                 EndContent();
1233             }
1234         }
1235 
WriteValue(XmlDictionaryString value)1236         public override void WriteValue(XmlDictionaryString value)
1237         {
1238             WriteString(value);
1239         }
1240 
WriteValue(DateTime value)1241         public override void WriteValue(DateTime value)
1242         {
1243             if (IsClosed)
1244                 ThrowClosed();
1245 
1246             FlushBase64();
1247             if (attributeValue != null)
1248                 WriteAttributeText(XmlConverter.ToString(value));
1249 
1250             if (!isXmlnsAttribute)
1251             {
1252                 StartContent();
1253                 writer.WriteDateTimeText(value);
1254                 EndContent();
1255             }
1256         }
1257 
WriteValue(UniqueId value)1258         public override void WriteValue(UniqueId value)
1259         {
1260             if (IsClosed)
1261                 ThrowClosed();
1262 
1263             if (value == null)
1264                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
1265 
1266             FlushBase64();
1267             if (attributeValue != null)
1268                 WriteAttributeText(XmlConverter.ToString(value));
1269 
1270             if (!isXmlnsAttribute)
1271             {
1272                 StartContent();
1273                 writer.WriteUniqueIdText(value);
1274                 EndContent();
1275             }
1276         }
1277 
WriteValue(Guid value)1278         public override void WriteValue(Guid value)
1279         {
1280             if (IsClosed)
1281                 ThrowClosed();
1282 
1283             FlushBase64();
1284             if (attributeValue != null)
1285                 WriteAttributeText(XmlConverter.ToString(value));
1286 
1287             if (!isXmlnsAttribute)
1288             {
1289                 StartContent();
1290                 writer.WriteGuidText(value);
1291                 EndContent();
1292             }
1293         }
1294 
WriteValue(TimeSpan value)1295         public override void WriteValue(TimeSpan value)
1296         {
1297             if (IsClosed)
1298                 ThrowClosed();
1299 
1300             FlushBase64();
1301             if (attributeValue != null)
1302                 WriteAttributeText(XmlConverter.ToString(value));
1303 
1304             if (!isXmlnsAttribute)
1305             {
1306                 StartContent();
1307                 writer.WriteTimeSpanText(value);
1308                 EndContent();
1309             }
1310         }
1311 
WriteBase64(byte[] buffer, int offset, int count)1312         public override void WriteBase64(byte[] buffer, int offset, int count)
1313         {
1314             if (IsClosed)
1315                 ThrowClosed();
1316 
1317             EnsureBufferBounds(buffer, offset, count);
1318             if (count > 0)
1319             {
1320                 if (trailByteCount > 0)
1321                 {
1322                     while (trailByteCount < 3 && count > 0)
1323                     {
1324                         trailBytes[trailByteCount++] = buffer[offset++];
1325                         count--;
1326                     }
1327                 }
1328 
1329                 int totalByteCount = trailByteCount + count;
1330                 int actualByteCount = totalByteCount - (totalByteCount % 3);
1331 
1332                 if (trailBytes == null)
1333                 {
1334                     trailBytes = new byte[3];
1335                 }
1336 
1337                 if (actualByteCount >= 3)
1338                 {
1339                     if (attributeValue != null)
1340                     {
1341                         WriteAttributeText(XmlConverter.Base64Encoding.GetString(trailBytes, 0, trailByteCount));
1342                         WriteAttributeText(XmlConverter.Base64Encoding.GetString(buffer, offset, actualByteCount - trailByteCount));
1343                     }
1344 
1345                     if (!isXmlnsAttribute)
1346                     {
1347                         StartContent();
1348                         writer.WriteBase64Text(trailBytes, trailByteCount, buffer, offset, actualByteCount - trailByteCount);
1349                         EndContent();
1350                     }
1351                     trailByteCount = (totalByteCount - actualByteCount);
1352 
1353                     if (trailByteCount > 0)
1354                     {
1355                         int trailOffset = offset + count - trailByteCount;
1356                         for (int i = 0; i < trailByteCount; i++)
1357                             trailBytes[i] = buffer[trailOffset++];
1358                     }
1359                 }
1360                 else
1361                 {
1362                     Buffer.BlockCopy(buffer, offset, trailBytes, trailByteCount, count);
1363                     trailByteCount += count;
1364                 }
1365             }
1366         }
1367 
BeginWriteBase64(byte[] buffer, int offset, int count, AsyncCallback callback, object state)1368         internal override IAsyncResult BeginWriteBase64(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
1369         {
1370             if (IsClosed)
1371                 ThrowClosed();
1372 
1373             EnsureBufferBounds(buffer, offset, count);
1374 
1375             return new WriteBase64AsyncResult(buffer, offset, count, this, callback, state);
1376         }
1377 
EndWriteBase64(IAsyncResult result)1378         internal override void EndWriteBase64(IAsyncResult result)
1379         {
1380             WriteBase64AsyncResult.End(result);
1381         }
1382 
WriteBase64Async(AsyncEventArgs<XmlWriteBase64AsyncArguments> state)1383         internal override AsyncCompletionResult WriteBase64Async(AsyncEventArgs<XmlWriteBase64AsyncArguments> state)
1384         {
1385             if (this.nodeWriterAsyncHelper == null)
1386             {
1387                 this.nodeWriterAsyncHelper = new XmlBaseWriterNodeWriterAsyncHelper(this);
1388             }
1389 
1390             this.nodeWriterAsyncHelper.SetArguments(state);
1391 
1392             if (this.nodeWriterAsyncHelper.StartAsync() == AsyncCompletionResult.Completed)
1393             {
1394                 return AsyncCompletionResult.Completed;
1395             }
1396 
1397             return AsyncCompletionResult.Queued;
1398         }
1399 
1400         class WriteBase64AsyncResult : AsyncResult
1401         {
1402             static AsyncCompletion onComplete = new AsyncCompletion(OnComplete);
1403             XmlBaseWriter writer;
1404             byte[] buffer;
1405             int offset;
1406             int count;
1407             int actualByteCount;
1408             int totalByteCount;
1409 
WriteBase64AsyncResult(byte[] buffer, int offset, int count, XmlBaseWriter writer, AsyncCallback callback, object state)1410             public WriteBase64AsyncResult(byte[] buffer, int offset, int count, XmlBaseWriter writer, AsyncCallback callback, object state)
1411                 : base(callback, state)
1412             {
1413                 this.writer = writer;
1414                 this.buffer = buffer;
1415                 this.offset = offset;
1416                 this.count = count;
1417 
1418                 bool completeSelf = true;
1419 
1420                 if (this.count > 0)
1421                 {
1422                     if (writer.trailByteCount > 0)
1423                     {
1424                         while (writer.trailByteCount < 3 && this.count > 0)
1425                         {
1426                             writer.trailBytes[writer.trailByteCount++] = buffer[this.offset++];
1427                             this.count--;
1428                         }
1429                     }
1430 
1431                     this.totalByteCount = writer.trailByteCount + this.count;
1432                     this.actualByteCount = totalByteCount - (totalByteCount % 3);
1433 
1434                     if (writer.trailBytes == null)
1435                     {
1436                         writer.trailBytes = new byte[3];
1437                     }
1438 
1439                     if (actualByteCount >= 3)
1440                     {
1441                         if (writer.attributeValue != null)
1442                         {
1443                             writer.WriteAttributeText(XmlConverter.Base64Encoding.GetString(writer.trailBytes, 0, writer.trailByteCount));
1444                             writer.WriteAttributeText(XmlConverter.Base64Encoding.GetString(buffer, this.offset, actualByteCount - writer.trailByteCount));
1445                         }
1446 
1447                         // StartContent/WriteBase64Text/EndContent will be called from HandleWriteBase64 as appropriate
1448                         completeSelf = HandleWriteBase64Text(null);
1449                     }
1450                     else
1451                     {
1452                         Buffer.BlockCopy(buffer, this.offset, writer.trailBytes, writer.trailByteCount, this.count);
1453                         writer.trailByteCount += this.count;
1454                     }
1455                 }
1456 
1457                 if (completeSelf)
1458                 {
1459                     this.Complete(true);
1460                 }
1461             }
1462 
OnComplete(IAsyncResult result)1463             static bool OnComplete(IAsyncResult result)
1464             {
1465                 WriteBase64AsyncResult thisPtr = (WriteBase64AsyncResult)result.AsyncState;
1466                 return thisPtr.HandleWriteBase64Text(result);
1467             }
1468 
HandleWriteBase64Text(IAsyncResult result)1469             bool HandleWriteBase64Text(IAsyncResult result)
1470             {
1471                 // in this code block if count > 0 && actualByteCount >= 3
1472                 if (!writer.isXmlnsAttribute)
1473                 {
1474                     if (result == null)
1475                     {
1476                         this.writer.StartContent();
1477                         result = this.writer.writer.BeginWriteBase64Text(this.writer.trailBytes,
1478                             this.writer.trailByteCount,
1479                             this.buffer,
1480                             this.offset,
1481                             this.actualByteCount - this.writer.trailByteCount,
1482                             PrepareAsyncCompletion(onComplete),
1483                             this);
1484 
1485                         if (!result.CompletedSynchronously)
1486                         {
1487                             return false;
1488                         }
1489                     }
1490                     this.writer.writer.EndWriteBase64Text(result);
1491                     this.writer.EndContent();
1492                 }
1493 
1494                 this.writer.trailByteCount = (totalByteCount - actualByteCount);
1495                 if (this.writer.trailByteCount > 0)
1496                 {
1497                     int trailOffset = offset + count - this.writer.trailByteCount;
1498                     for (int i = 0; i < this.writer.trailByteCount; i++)
1499                         this.writer.trailBytes[i] = this.buffer[trailOffset++];
1500                 }
1501 
1502                 return true;
1503             }
1504 
End(IAsyncResult result)1505             public static void End(IAsyncResult result)
1506             {
1507                 AsyncResult.End<WriteBase64AsyncResult>(result);
1508             }
1509         }
1510 
WriteBinHex(byte[] buffer, int offset, int count)1511         public override void WriteBinHex(byte[] buffer, int offset, int count)
1512         {
1513             if (IsClosed)
1514                 ThrowClosed();
1515 
1516             EnsureBufferBounds(buffer, offset, count);
1517 
1518             WriteRaw(BinHexEncoding.GetString(buffer, offset, count));
1519         }
1520 
1521         public override bool CanCanonicalize
1522         {
1523             get
1524             {
1525                 return true;
1526             }
1527         }
1528 
1529         protected bool Signing
1530         {
1531             get
1532             {
1533                 return writer == signingWriter;
1534             }
1535         }
1536 
StartCanonicalization(Stream stream, bool includeComments, string[] inclusivePrefixes)1537         public override void StartCanonicalization(Stream stream, bool includeComments, string[] inclusivePrefixes)
1538         {
1539             if (IsClosed)
1540                 ThrowClosed();
1541             if (Signing)
1542                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlCanonicalizationStarted)));
1543             FlushElement();
1544             if (signingWriter == null)
1545                 signingWriter = CreateSigningNodeWriter();
1546             signingWriter.SetOutput(writer, stream, includeComments, inclusivePrefixes);
1547             writer = signingWriter;
1548             SignScope(signingWriter.CanonicalWriter);
1549         }
1550 
EndCanonicalization()1551         public override void EndCanonicalization()
1552         {
1553             if (IsClosed)
1554                 ThrowClosed();
1555             if (!Signing)
1556                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlCanonicalizationNotStarted)));
1557             signingWriter.Flush();
1558             writer = signingWriter.NodeWriter;
1559         }
1560 
CreateSigningNodeWriter()1561         protected abstract XmlSigningNodeWriter CreateSigningNodeWriter();
1562 
1563         public virtual bool CanFragment
1564         {
1565             get
1566             {
1567                 return true;
1568             }
1569         }
1570 
StartFragment(Stream stream, bool generateSelfContainedTextFragment)1571         public void StartFragment(Stream stream, bool generateSelfContainedTextFragment)
1572         {
1573             if (!CanFragment)
1574                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
1575             if (IsClosed)
1576                 ThrowClosed();
1577             if (stream == null)
1578                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("stream"));
1579             if (oldStream != null || oldWriter != null)
1580                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException());
1581             if (WriteState == WriteState.Attribute)
1582                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "StartFragment", WriteState.ToString())));
1583             FlushElement();
1584             writer.Flush();
1585 
1586             oldNamespaceBoundary = NamespaceBoundary;
1587 
1588             XmlStreamNodeWriter fragmentWriter = null;
1589             if (generateSelfContainedTextFragment)
1590             {
1591                 this.NamespaceBoundary = depth + 1;
1592                 if (textFragmentWriter == null)
1593                     textFragmentWriter = new XmlUTF8NodeWriter();
1594                 textFragmentWriter.SetOutput(stream, false, Encoding.UTF8);
1595                 fragmentWriter = textFragmentWriter;
1596             }
1597 
1598             if (Signing)
1599             {
1600                 if (fragmentWriter != null)
1601                 {
1602                     oldWriter = signingWriter.NodeWriter;
1603                     signingWriter.NodeWriter = fragmentWriter;
1604                 }
1605                 else
1606                 {
1607                     oldStream = ((XmlStreamNodeWriter)signingWriter.NodeWriter).Stream;
1608                     ((XmlStreamNodeWriter)signingWriter.NodeWriter).Stream = stream;
1609                 }
1610             }
1611             else
1612             {
1613                 if (fragmentWriter != null)
1614                 {
1615                     oldWriter = writer;
1616                     writer = fragmentWriter;
1617                 }
1618                 else
1619                 {
1620                     oldStream = nodeWriter.Stream;
1621                     nodeWriter.Stream = stream;
1622                 }
1623             }
1624         }
1625 
EndFragment()1626         public void EndFragment()
1627         {
1628             if (IsClosed)
1629                 ThrowClosed();
1630             if (oldStream == null && oldWriter == null)
1631                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException());
1632             if (WriteState == WriteState.Attribute)
1633                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "EndFragment", WriteState.ToString())));
1634 
1635             FlushElement();
1636             writer.Flush();
1637 
1638             if (Signing)
1639             {
1640                 if (oldWriter != null)
1641                     signingWriter.NodeWriter = oldWriter;
1642                 else
1643                     ((XmlStreamNodeWriter)signingWriter.NodeWriter).Stream = oldStream;
1644             }
1645             else
1646             {
1647                 if (oldWriter != null)
1648                     writer = oldWriter;
1649                 else
1650                     nodeWriter.Stream = oldStream;
1651             }
1652             NamespaceBoundary = oldNamespaceBoundary;
1653             oldWriter = null;
1654             oldStream = null;
1655         }
1656 
WriteFragment(byte[] buffer, int offset, int count)1657         public void WriteFragment(byte[] buffer, int offset, int count)
1658         {
1659             if (!CanFragment)
1660                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
1661             if (IsClosed)
1662                 ThrowClosed();
1663             if (buffer == null)
1664                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("buffer"));
1665             if (offset < 0)
1666                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeNonNegative)));
1667             if (count < 0)
1668                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeNonNegative)));
1669             if (count > buffer.Length - offset)
1670                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.SizeExceedsRemainingBufferSpace, buffer.Length - offset)));
1671             if (WriteState == WriteState.Attribute)
1672                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteFragment", WriteState.ToString())));
1673             if (writer != nodeWriter)
1674                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException());
1675             FlushElement();
1676             FlushBase64();
1677             nodeWriter.Flush();
1678             nodeWriter.Stream.Write(buffer, offset, count);
1679         }
1680 
FlushBase64()1681         void FlushBase64()
1682         {
1683             if (trailByteCount > 0)
1684             {
1685                 FlushTrailBytes();
1686             }
1687         }
1688 
FlushTrailBytes()1689         void FlushTrailBytes()
1690         {
1691             if (attributeValue != null)
1692                 WriteAttributeText(XmlConverter.Base64Encoding.GetString(trailBytes, 0, trailByteCount));
1693 
1694             if (!isXmlnsAttribute)
1695             {
1696                 StartContent();
1697                 writer.WriteBase64Text(trailBytes, trailByteCount, trailBytes, 0, 0);
1698                 EndContent();
1699             }
1700             trailByteCount = 0;
1701         }
1702 
WriteValue(object[] array)1703         void WriteValue(object[] array)
1704         {
1705             FlushBase64();
1706             StartContent();
1707             writer.WriteStartListText();
1708             this.inList = true;
1709             for (int i = 0; i < array.Length; i++)
1710             {
1711                 if (i != 0)
1712                 {
1713                     writer.WriteListSeparator();
1714                 }
1715                 WritePrimitiveValue(array[i]);
1716             }
1717             this.inList = false;
1718             writer.WriteEndListText();
1719             EndContent();
1720         }
1721 
WriteValue(Array array)1722         void WriteValue(Array array)
1723         {
1724             FlushBase64();
1725             StartContent();
1726             writer.WriteStartListText();
1727             this.inList = true;
1728             for (int i = 0; i < array.Length; i++)
1729             {
1730                 if (i != 0)
1731                 {
1732                     writer.WriteListSeparator();
1733                 }
1734                 WritePrimitiveValue(array.GetValue(i));
1735             }
1736             this.inList = false;
1737             writer.WriteEndListText();
1738             EndContent();
1739         }
1740 
StartArray(int count)1741         protected void StartArray(int count)
1742         {
1743             FlushBase64();
1744             if (this.documentState == DocumentState.Epilog)
1745                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlOnlyOneRoot)));
1746             if (this.documentState == DocumentState.Document && count > 1 && depth == 0)
1747                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlOnlyOneRoot)));
1748             if (writeState == WriteState.Attribute)
1749                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidWriteState, "WriteStartElement", WriteState.ToString())));
1750             AutoComplete(WriteState.Content);
1751         }
1752 
EndArray()1753         protected void EndArray()
1754         {
1755         }
1756 
EnsureBufferBounds(byte[] buffer, int offset, int count)1757         void EnsureBufferBounds(byte[] buffer, int offset, int count)
1758         {
1759             if (buffer == null)
1760                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("buffer");
1761 
1762             // Not checking upper bound because it will be caught by "count".  This is what XmlTextWriter does.
1763             if (offset < 0)
1764                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeNonNegative)));
1765 
1766             if (count < 0)
1767                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeNonNegative)));
1768             if (count > buffer.Length - offset)
1769                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.SizeExceedsRemainingBufferSpace, buffer.Length - offset)));
1770         }
1771 
GeneratePrefix(string ns, XmlDictionaryString xNs)1772         string GeneratePrefix(string ns, XmlDictionaryString xNs)
1773         {
1774             if (writeState != WriteState.Element && writeState != WriteState.Attribute)
1775                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.XmlInvalidPrefixState, WriteState.ToString())));
1776 
1777             string prefix = nsMgr.AddNamespace(ns, xNs);
1778 
1779             if (prefix != null)
1780                 return prefix;
1781 
1782             while (true)
1783             {
1784                 int prefixId = elements[depth].PrefixId++;
1785                 prefix = string.Concat("d", depth.ToString(CultureInfo.InvariantCulture), "p", prefixId.ToString(CultureInfo.InvariantCulture));
1786 
1787                 if (nsMgr.LookupNamespace(prefix) == null)
1788                 {
1789                     nsMgr.AddNamespace(prefix, ns, xNs);
1790                     return prefix;
1791                 }
1792             }
1793         }
1794 
SignScope(XmlCanonicalWriter signingWriter)1795         protected void SignScope(XmlCanonicalWriter signingWriter)
1796         {
1797             nsMgr.Sign(signingWriter);
1798         }
1799 
WriteAttributeText(string value)1800         void WriteAttributeText(string value)
1801         {
1802             if (attributeValue.Length == 0)
1803                 attributeValue = value;
1804             else
1805                 attributeValue += value;
1806         }
1807 
1808         class Element
1809         {
1810             string prefix;
1811             string localName;
1812             int prefixId;
1813 
1814             public string Prefix
1815             {
1816                 get
1817                 {
1818                     return prefix;
1819                 }
1820                 set
1821                 {
1822                     prefix = value;
1823                 }
1824             }
1825 
1826             public string LocalName
1827             {
1828                 get
1829                 {
1830                     return localName;
1831                 }
1832                 set
1833                 {
1834                     localName = value;
1835                 }
1836             }
1837 
1838             public int PrefixId
1839             {
1840                 get
1841                 {
1842                     return prefixId;
1843                 }
1844                 set
1845                 {
1846                     prefixId = value;
1847                 }
1848             }
1849 
Clear()1850             public void Clear()
1851             {
1852                 this.prefix = null;
1853                 this.localName = null;
1854                 this.prefixId = 0;
1855             }
1856         }
1857 
1858         enum DocumentState : byte
1859         {
1860             None,       // Not inside StartDocument/EndDocument - Allows multiple root elemnts
1861             Document,   // Inside StartDocument/EndDocument
1862             Epilog,     // EndDocument must be called
1863             End         // Nothing further to write
1864         }
1865 
1866         class NamespaceManager
1867         {
1868             Namespace[] namespaces;
1869             Namespace lastNameSpace;
1870             int nsCount;
1871             int depth;
1872             XmlAttribute[] attributes;
1873             int attributeCount;
1874             XmlSpace space;
1875             string lang;
1876             int namespaceBoundary;
1877             int nsTop;
1878             Namespace defaultNamespace;
1879 
NamespaceManager()1880             public NamespaceManager()
1881             {
1882                 defaultNamespace = new Namespace();
1883                 defaultNamespace.Depth = 0;
1884                 defaultNamespace.Prefix = string.Empty;
1885                 defaultNamespace.Uri = string.Empty;
1886                 defaultNamespace.UriDictionaryString = null;
1887             }
1888 
1889             public string XmlLang
1890             {
1891                 get
1892                 {
1893                     return lang;
1894                 }
1895             }
1896 
1897             public XmlSpace XmlSpace
1898             {
1899                 get
1900                 {
1901                     return space;
1902                 }
1903             }
1904 
Clear()1905             public void Clear()
1906             {
1907                 if (this.namespaces == null)
1908                 {
1909                     this.namespaces = new Namespace[4];
1910                     this.namespaces[0] = defaultNamespace;
1911                 }
1912                 this.nsCount = 1;
1913                 this.nsTop = 0;
1914                 this.depth = 0;
1915                 this.attributeCount = 0;
1916                 this.space = XmlSpace.None;
1917                 this.lang = null;
1918                 this.lastNameSpace = null;
1919                 this.namespaceBoundary = 0;
1920             }
1921 
1922             public int NamespaceBoundary
1923             {
1924                 get
1925                 {
1926                     return namespaceBoundary;
1927                 }
1928                 set
1929                 {
1930                     int i;
1931                     for (i = 0; i < nsCount; i++)
1932                         if (namespaces[i].Depth >= value)
1933                             break;
1934 
1935                     nsTop = i;
1936                     namespaceBoundary = value;
1937                     lastNameSpace = null;
1938                 }
1939             }
1940 
Close()1941             public void Close()
1942             {
1943                 if (depth == 0)
1944                 {
1945                     if (namespaces != null && namespaces.Length > 32)
1946                         namespaces = null;
1947                     if (attributes != null && attributes.Length > 4)
1948                         attributes = null;
1949                 }
1950                 else
1951                 {
1952                     namespaces = null;
1953                     attributes = null;
1954                 }
1955                 lang = null;
1956             }
1957 
DeclareNamespaces(XmlNodeWriter writer)1958             public void DeclareNamespaces(XmlNodeWriter writer)
1959             {
1960                 int i = this.nsCount;
1961                 while (i > 0)
1962                 {
1963                     Namespace nameSpace = namespaces[i - 1];
1964                     if (nameSpace.Depth != depth)
1965                         break;
1966                     i--;
1967                 }
1968                 while (i < this.nsCount)
1969                 {
1970                     Namespace nameSpace = namespaces[i];
1971                     if (nameSpace.UriDictionaryString != null)
1972                         writer.WriteXmlnsAttribute(nameSpace.Prefix, nameSpace.UriDictionaryString);
1973                     else
1974                         writer.WriteXmlnsAttribute(nameSpace.Prefix, nameSpace.Uri);
1975                     i++;
1976                 }
1977             }
1978 
EnterScope()1979             public void EnterScope()
1980             {
1981                 depth++;
1982             }
1983 
ExitScope()1984             public void ExitScope()
1985             {
1986                 while (nsCount > 0)
1987                 {
1988                     Namespace nameSpace = namespaces[nsCount - 1];
1989                     if (nameSpace.Depth != depth)
1990                         break;
1991                     if (lastNameSpace == nameSpace)
1992                         lastNameSpace = null;
1993                     nameSpace.Clear();
1994                     nsCount--;
1995                 }
1996                 while (attributeCount > 0)
1997                 {
1998                     XmlAttribute attribute = attributes[attributeCount - 1];
1999                     if (attribute.Depth != depth)
2000                         break;
2001                     space = attribute.XmlSpace;
2002                     lang = attribute.XmlLang;
2003                     attribute.Clear();
2004                     attributeCount--;
2005                 }
2006                 depth--;
2007             }
2008 
AddLangAttribute(string lang)2009             public void AddLangAttribute(string lang)
2010             {
2011                 AddAttribute();
2012                 this.lang = lang;
2013             }
2014 
AddSpaceAttribute(XmlSpace space)2015             public void AddSpaceAttribute(XmlSpace space)
2016             {
2017                 AddAttribute();
2018                 this.space = space;
2019             }
2020 
AddAttribute()2021             void AddAttribute()
2022             {
2023                 if (attributes == null)
2024                 {
2025                     attributes = new XmlAttribute[1];
2026                 }
2027                 else if (attributes.Length == attributeCount)
2028                 {
2029                     XmlAttribute[] newAttributes = new XmlAttribute[attributeCount * 2];
2030                     Array.Copy(attributes, newAttributes, attributeCount);
2031                     attributes = newAttributes;
2032                 }
2033                 XmlAttribute attribute = attributes[attributeCount];
2034                 if (attribute == null)
2035                 {
2036                     attribute = new XmlAttribute();
2037                     attributes[attributeCount] = attribute;
2038                 }
2039                 attribute.XmlLang = this.lang;
2040                 attribute.XmlSpace = this.space;
2041                 attribute.Depth = depth;
2042                 attributeCount++;
2043             }
2044 
AddNamespace(string uri, XmlDictionaryString uriDictionaryString)2045             public string AddNamespace(string uri, XmlDictionaryString uriDictionaryString)
2046             {
2047                 if (uri.Length == 0)
2048                 {
2049                     // Empty namespace can only be bound to the empty prefix
2050                     AddNamespaceIfNotDeclared(string.Empty, uri, uriDictionaryString);
2051                     return string.Empty;
2052                 }
2053                 else
2054                 {
2055                     for (int i = 0; i < prefixes.Length; i++)
2056                     {
2057                         string prefix = prefixes[i];
2058                         bool declared = false;
2059                         for (int j = nsCount - 1; j >= nsTop; j--)
2060                         {
2061                             Namespace nameSpace = namespaces[j];
2062                             if (nameSpace.Prefix == prefix)
2063                             {
2064                                 declared = true;
2065                                 break;
2066                             }
2067                         }
2068                         if (!declared)
2069                         {
2070                             AddNamespace(prefix, uri, uriDictionaryString);
2071                             return prefix;
2072                         }
2073                     }
2074                 }
2075                 return null;
2076             }
2077 
AddNamespaceIfNotDeclared(string prefix, string uri, XmlDictionaryString uriDictionaryString)2078             public void AddNamespaceIfNotDeclared(string prefix, string uri, XmlDictionaryString uriDictionaryString)
2079             {
2080                 if (LookupNamespace(prefix) != uri)
2081                 {
2082                     AddNamespace(prefix, uri, uriDictionaryString);
2083                 }
2084             }
2085 
AddNamespace(string prefix, string uri, XmlDictionaryString uriDictionaryString)2086             public void AddNamespace(string prefix, string uri, XmlDictionaryString uriDictionaryString)
2087             {
2088                 if (prefix.Length >= 3)
2089                 {
2090                     // Upper and lower case letter differ by a bit.
2091                     if ((prefix[0] & ~32) == 'X' && (prefix[1] & ~32) == 'M' && (prefix[2] & ~32) == 'L')
2092                     {
2093                         if (prefix == "xml" && uri == xmlNamespace)
2094                             return;
2095                         if (prefix == "xmlns" && uri == xmlnsNamespace)
2096                             return;
2097                         throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlReservedPrefix), "prefix"));
2098                     }
2099                 }
2100                 Namespace nameSpace;
2101                 for (int i = nsCount - 1; i >= 0; i--)
2102                 {
2103                     nameSpace = namespaces[i];
2104                     if (nameSpace.Depth != depth)
2105                         break;
2106                     if (nameSpace.Prefix == prefix)
2107                     {
2108                         if (nameSpace.Uri == uri)
2109                             return;
2110                         throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlPrefixBoundToNamespace, prefix, nameSpace.Uri, uri), "prefix"));
2111                     }
2112                 }
2113                 if (prefix.Length != 0 && uri.Length == 0)
2114                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlEmptyNamespaceRequiresNullPrefix), "prefix"));
2115                 if (uri.Length == xmlnsNamespace.Length && uri == xmlnsNamespace)
2116                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlSpecificBindingNamespace, "xmlns", uri)));
2117                 // The addressing namespace and the xmlNamespace are the same length, so add a quick check to try to disambiguate
2118                 if (uri.Length == xmlNamespace.Length && uri[18] == 'X' && uri == xmlNamespace)
2119                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlSpecificBindingNamespace, "xml", uri)));
2120 
2121                 if (namespaces.Length == nsCount)
2122                 {
2123                     Namespace[] newNamespaces = new Namespace[nsCount * 2];
2124                     Array.Copy(namespaces, newNamespaces, nsCount);
2125                     namespaces = newNamespaces;
2126                 }
2127                 nameSpace = namespaces[nsCount];
2128                 if (nameSpace == null)
2129                 {
2130                     nameSpace = new Namespace();
2131                     namespaces[nsCount] = nameSpace;
2132                 }
2133                 nameSpace.Depth = depth;
2134                 nameSpace.Prefix = prefix;
2135                 nameSpace.Uri = uri;
2136                 nameSpace.UriDictionaryString = uriDictionaryString;
2137                 nsCount++;
2138                 lastNameSpace = null;
2139             }
2140 
LookupPrefix(string ns)2141             public string LookupPrefix(string ns)
2142             {
2143                 if (lastNameSpace != null && lastNameSpace.Uri == ns)
2144                     return lastNameSpace.Prefix;
2145                 int nsCount = this.nsCount;
2146                 for (int i = nsCount - 1; i >= nsTop; i--)
2147                 {
2148                     Namespace nameSpace = namespaces[i];
2149                     if (object.ReferenceEquals(nameSpace.Uri, ns))
2150                     {
2151                         string prefix = nameSpace.Prefix;
2152                         // Make sure that the prefix refers to the namespace in scope
2153                         bool declared = false;
2154                         for (int j = i + 1; j < nsCount; j++)
2155                         {
2156                             if (namespaces[j].Prefix == prefix)
2157                             {
2158                                 declared = true;
2159                                 break;
2160                             }
2161                         }
2162                         if (!declared)
2163                         {
2164                             lastNameSpace = nameSpace;
2165                             return prefix;
2166                         }
2167                     }
2168                 }
2169                 for (int i = nsCount - 1; i >= nsTop; i--)
2170                 {
2171                     Namespace nameSpace = namespaces[i];
2172                     if (nameSpace.Uri == ns)
2173                     {
2174                         string prefix = nameSpace.Prefix;
2175                         // Make sure that the prefix refers to the namespace in scope
2176                         bool declared = false;
2177                         for (int j = i + 1; j < nsCount; j++)
2178                         {
2179                             if (namespaces[j].Prefix == prefix)
2180                             {
2181                                 declared = true;
2182                                 break;
2183                             }
2184                         }
2185                         if (!declared)
2186                         {
2187                             lastNameSpace = nameSpace;
2188                             return prefix;
2189                         }
2190                     }
2191                 }
2192 
2193                 if (ns.Length == 0)
2194                 {
2195                     // Make sure the default binding is still valid
2196                     bool emptyPrefixUnassigned = true;
2197                     for (int i = nsCount - 1; i >= nsTop; i--)
2198                     {
2199                         if (namespaces[i].Prefix.Length == 0)
2200                         {
2201                             emptyPrefixUnassigned = false;
2202                             break;
2203                         }
2204                     }
2205                     if (emptyPrefixUnassigned)
2206                         return string.Empty;
2207                 }
2208 
2209                 if (ns == xmlnsNamespace)
2210                     return "xmlns";
2211                 if (ns == xmlNamespace)
2212                     return "xml";
2213                 return null;
2214             }
2215 
LookupAttributePrefix(string ns)2216             public string LookupAttributePrefix(string ns)
2217             {
2218                 if (lastNameSpace != null && lastNameSpace.Uri == ns && lastNameSpace.Prefix.Length != 0)
2219                     return lastNameSpace.Prefix;
2220 
2221                 int nsCount = this.nsCount;
2222                 for (int i = nsCount - 1; i >= nsTop; i--)
2223                 {
2224                     Namespace nameSpace = namespaces[i];
2225 
2226                     if (object.ReferenceEquals(nameSpace.Uri, ns))
2227                     {
2228                         string prefix = nameSpace.Prefix;
2229                         if (prefix.Length != 0)
2230                         {
2231                             // Make sure that the prefix refers to the namespace in scope
2232                             bool declared = false;
2233                             for (int j = i + 1; j < nsCount; j++)
2234                             {
2235                                 if (namespaces[j].Prefix == prefix)
2236                                 {
2237                                     declared = true;
2238                                     break;
2239                                 }
2240                             }
2241                             if (!declared)
2242                             {
2243                                 lastNameSpace = nameSpace;
2244                                 return prefix;
2245                             }
2246                         }
2247                     }
2248                 }
2249                 for (int i = nsCount - 1; i >= nsTop; i--)
2250                 {
2251                     Namespace nameSpace = namespaces[i];
2252                     if (nameSpace.Uri == ns)
2253                     {
2254                         string prefix = nameSpace.Prefix;
2255                         if (prefix.Length != 0)
2256                         {
2257                             // Make sure that the prefix refers to the namespace in scope
2258                             bool declared = false;
2259                             for (int j = i + 1; j < nsCount; j++)
2260                             {
2261                                 if (namespaces[j].Prefix == prefix)
2262                                 {
2263                                     declared = true;
2264                                     break;
2265                                 }
2266                             }
2267                             if (!declared)
2268                             {
2269                                 lastNameSpace = nameSpace;
2270                                 return prefix;
2271                             }
2272                         }
2273                     }
2274                 }
2275                 if (ns.Length == 0)
2276                     return string.Empty;
2277                 return null;
2278             }
2279 
LookupNamespace(string prefix)2280             public string LookupNamespace(string prefix)
2281             {
2282                 int nsCount = this.nsCount;
2283                 if (prefix.Length == 0)
2284                 {
2285                     for (int i = nsCount - 1; i >= nsTop; i--)
2286                     {
2287                         Namespace nameSpace = namespaces[i];
2288                         if (nameSpace.Prefix.Length == 0)
2289                             return nameSpace.Uri;
2290                     }
2291                     return string.Empty;
2292                 }
2293                 if (prefix.Length == 1)
2294                 {
2295                     char prefixChar = prefix[0];
2296                     for (int i = nsCount - 1; i >= nsTop; i--)
2297                     {
2298                         Namespace nameSpace = namespaces[i];
2299                         if (nameSpace.PrefixChar == prefixChar)
2300                             return nameSpace.Uri;
2301                     }
2302                     return null;
2303                 }
2304                 for (int i = nsCount - 1; i >= nsTop; i--)
2305                 {
2306                     Namespace nameSpace = namespaces[i];
2307                     if (nameSpace.Prefix == prefix)
2308                         return nameSpace.Uri;
2309                 }
2310                 if (prefix == "xmlns")
2311                     return xmlnsNamespace;
2312                 if (prefix == "xml")
2313                     return xmlNamespace;
2314                 return null;
2315             }
2316 
Sign(XmlCanonicalWriter signingWriter)2317             public void Sign(XmlCanonicalWriter signingWriter)
2318             {
2319                 int nsCount = this.nsCount;
2320                 Fx.Assert(nsCount >= 1 && namespaces[0].Prefix.Length == 0 && namespaces[0].Uri.Length == 0, "");
2321                 for (int i = 1; i < nsCount; i++)
2322                 {
2323                     Namespace nameSpace = namespaces[i];
2324 
2325                     bool found = false;
2326                     for (int j = i + 1; j < nsCount && !found; j++)
2327                     {
2328                         found = (nameSpace.Prefix == namespaces[j].Prefix);
2329                     }
2330 
2331                     if (!found)
2332                     {
2333                         signingWriter.WriteXmlnsAttribute(nameSpace.Prefix, nameSpace.Uri);
2334                     }
2335                 }
2336             }
2337 
2338             class XmlAttribute
2339             {
2340                 XmlSpace space;
2341                 string lang;
2342                 int depth;
2343 
XmlAttribute()2344                 public XmlAttribute()
2345                 {
2346                 }
2347 
2348                 public int Depth
2349                 {
2350                     get
2351                     {
2352                         return depth;
2353                     }
2354                     set
2355                     {
2356                         depth = value;
2357                     }
2358                 }
2359 
2360                 public string XmlLang
2361                 {
2362                     get
2363                     {
2364                         return lang;
2365                     }
2366                     set
2367                     {
2368                         lang = value;
2369                     }
2370                 }
2371 
2372                 public XmlSpace XmlSpace
2373                 {
2374                     get
2375                     {
2376                         return space;
2377                     }
2378                     set
2379                     {
2380                         space = value;
2381                     }
2382                 }
2383 
Clear()2384                 public void Clear()
2385                 {
2386                     this.lang = null;
2387                 }
2388             }
2389 
2390             class Namespace
2391             {
2392                 string prefix;
2393                 string ns;
2394                 XmlDictionaryString xNs;
2395                 int depth;
2396                 char prefixChar;
2397 
Namespace()2398                 public Namespace()
2399                 {
2400                 }
2401 
Clear()2402                 public void Clear()
2403                 {
2404                     this.prefix = null;
2405                     this.prefixChar = (char)0;
2406                     this.ns = null;
2407                     this.xNs = null;
2408                     this.depth = 0;
2409                 }
2410 
2411                 public int Depth
2412                 {
2413                     get
2414                     {
2415                         return depth;
2416                     }
2417                     set
2418                     {
2419                         depth = value;
2420                     }
2421                 }
2422 
2423                 public char PrefixChar
2424                 {
2425                     get
2426                     {
2427                         return prefixChar;
2428                     }
2429                 }
2430 
2431                 public string Prefix
2432                 {
2433                     get
2434                     {
2435                         return prefix;
2436                     }
2437                     set
2438                     {
2439                         if (value.Length == 1)
2440                             prefixChar = value[0];
2441                         else
2442                             prefixChar = (char)0;
2443                         prefix = value;
2444                     }
2445                 }
2446 
2447                 public string Uri
2448                 {
2449                     get
2450                     {
2451                         return ns;
2452                     }
2453                     set
2454                     {
2455                         ns = value;
2456                     }
2457                 }
2458 
2459                 public XmlDictionaryString UriDictionaryString
2460                 {
2461                     get
2462                     {
2463                         return xNs;
2464                     }
2465                     set
2466                     {
2467                         xNs = value;
2468                     }
2469                 }
2470             }
2471         }
2472 
2473         class XmlBaseWriterNodeWriterAsyncHelper
2474         {
2475             static AsyncEventArgsCallback onWriteComplete;
2476 
2477             XmlBaseWriter writer;
2478             byte[] buffer;
2479             int offset;
2480             int count;
2481             int actualByteCount;
2482             int totalByteCount;
2483             AsyncEventArgs<XmlNodeWriterWriteBase64TextArgs> nodeWriterAsyncState;
2484             XmlNodeWriterWriteBase64TextArgs nodeWriterArgs;
2485             AsyncEventArgs<XmlWriteBase64AsyncArguments> inputState;
2486 
XmlBaseWriterNodeWriterAsyncHelper(XmlBaseWriter writer)2487             public XmlBaseWriterNodeWriterAsyncHelper(XmlBaseWriter writer)
2488             {
2489                 this.writer = writer;
2490             }
2491 
SetArguments(AsyncEventArgs<XmlWriteBase64AsyncArguments> inputState)2492             public void SetArguments(AsyncEventArgs<XmlWriteBase64AsyncArguments> inputState)
2493             {
2494                 Fx.Assert(inputState != null, "InputState cannot be null.");
2495                 this.inputState = inputState;
2496                 this.buffer = inputState.Arguments.Buffer;
2497                 this.offset = inputState.Arguments.Offset;
2498                 this.count = inputState.Arguments.Count;
2499             }
2500 
StartAsync()2501             public AsyncCompletionResult StartAsync()
2502             {
2503                 bool completeSelf = true;
2504 
2505                 if (this.count > 0)
2506                 {
2507                     // Bytes that have been already been read.
2508                     if (this.writer.trailByteCount > 0)
2509                     {
2510                         // Copy over up to 3 trailing bytes into the trailBytes buffer.
2511                         while (this.writer.trailByteCount < 3 && this.count > 0)
2512                         {
2513                             this.writer.trailBytes[this.writer.trailByteCount++] = this.buffer[this.offset++];
2514                             this.count--;
2515                         }
2516                     }
2517 
2518                     this.totalByteCount = this.writer.trailByteCount + this.count;
2519                     this.actualByteCount = this.totalByteCount - (this.totalByteCount % 3);
2520 
2521                     if (this.writer.trailBytes == null)
2522                     {
2523                         this.writer.trailBytes = new byte[3];
2524                     }
2525 
2526                     if (actualByteCount >= 3)
2527                     {
2528                         if (this.writer.attributeValue != null)
2529                         {
2530                             this.writer.WriteAttributeText(XmlConverter.Base64Encoding.GetString(this.writer.trailBytes, 0, this.writer.trailByteCount));
2531                             this.writer.WriteAttributeText(XmlConverter.Base64Encoding.GetString(this.buffer, this.offset, actualByteCount - this.writer.trailByteCount));
2532                         }
2533 
2534                         // StartContent/WriteBase64Text/EndContent will be called from HandleWriteBase64 as appropriate
2535                         completeSelf = HandleWriteBase64Text(false);
2536                     }
2537                     else
2538                     {
2539                         Buffer.BlockCopy(this.buffer, this.offset, this.writer.trailBytes, this.writer.trailByteCount, this.count);
2540                         this.writer.trailByteCount += this.count;
2541                     }
2542                 }
2543 
2544                 if (completeSelf)
2545                 {
2546                     this.Clear();
2547                     return AsyncCompletionResult.Completed;
2548                 }
2549 
2550                 return AsyncCompletionResult.Queued;
2551             }
2552 
OnWriteComplete(IAsyncEventArgs asyncEventArgs)2553             static void OnWriteComplete(IAsyncEventArgs asyncEventArgs)
2554             {
2555                 bool completeSelf = false;
2556                 Exception completionException = null;
2557                 XmlBaseWriterNodeWriterAsyncHelper thisPtr = (XmlBaseWriterNodeWriterAsyncHelper)asyncEventArgs.AsyncState;
2558                 AsyncEventArgs<XmlWriteBase64AsyncArguments> inputState = thisPtr.inputState;
2559 
2560                 try
2561                 {
2562                     if (asyncEventArgs.Exception != null)
2563                     {
2564                         completionException = asyncEventArgs.Exception;
2565                         completeSelf = true;
2566                     }
2567                     else
2568                     {
2569                         completeSelf = thisPtr.HandleWriteBase64Text(true);
2570                     }
2571                 }
2572                 catch (Exception exception)
2573                 {
2574                     if (Fx.IsFatal(exception))
2575                     {
2576                         throw;
2577                     }
2578 
2579                     completionException = exception;
2580                     completeSelf = true;
2581                 }
2582 
2583                 if (completeSelf)
2584                 {
2585                     thisPtr.Clear();
2586                     inputState.Complete(false, completionException);
2587                 }
2588             }
2589 
HandleWriteBase64Text(bool isAsyncCallback)2590             bool HandleWriteBase64Text(bool isAsyncCallback)
2591             {
2592                 Fx.Assert(this.count > 0 && this.actualByteCount >= 3, "HandleWriteBase64Text cannot be invoked with less than 3 bytes.");
2593                 if (!writer.isXmlnsAttribute)
2594                 {
2595                     if (!isAsyncCallback)
2596                     {
2597                         if (this.nodeWriterAsyncState == null)
2598                         {
2599                             this.nodeWriterAsyncState = new AsyncEventArgs<XmlNodeWriterWriteBase64TextArgs>();
2600                             this.nodeWriterArgs = new XmlNodeWriterWriteBase64TextArgs();
2601                         }
2602                         if (onWriteComplete == null)
2603                         {
2604                             onWriteComplete = new AsyncEventArgsCallback(OnWriteComplete);
2605                         }
2606 
2607                         this.writer.StartContent();
2608                         this.nodeWriterArgs.TrailBuffer = this.writer.trailBytes;
2609                         this.nodeWriterArgs.TrailCount = this.writer.trailByteCount;
2610                         this.nodeWriterArgs.Buffer = this.buffer;
2611                         this.nodeWriterArgs.Offset = this.offset;
2612                         this.nodeWriterArgs.Count = this.actualByteCount - this.writer.trailByteCount;
2613 
2614                         this.nodeWriterAsyncState.Set(onWriteComplete, this.nodeWriterArgs, this);
2615                         if (this.writer.writer.WriteBase64TextAsync(this.nodeWriterAsyncState) != AsyncCompletionResult.Completed)
2616                         {
2617                             return false;
2618                         }
2619 
2620                         this.nodeWriterAsyncState.Complete(true);
2621                     }
2622 
2623                     this.writer.EndContent();
2624                 }
2625 
2626                 this.writer.trailByteCount = (this.totalByteCount - this.actualByteCount);
2627                 if (this.writer.trailByteCount > 0)
2628                 {
2629                     int trailOffset = offset + count - this.writer.trailByteCount;
2630                     for (int i = 0; i < this.writer.trailByteCount; i++)
2631                         this.writer.trailBytes[i] = this.buffer[trailOffset++];
2632                 }
2633 
2634                 return true;
2635             }
2636 
Clear()2637             void Clear()
2638             {
2639                 this.inputState = null;
2640                 this.buffer = null;
2641                 this.offset = 0;
2642                 this.count = 0;
2643                 this.actualByteCount = 0;
2644                 this.totalByteCount = 0;
2645             }
2646         }
2647     }
2648 }
2649