Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Xml / System / Xml / Core / XmlEncodedRawTextWriterAsync.cs
1
2 using System;
3 using System.IO;
4 using System.Xml;
5 using System.Text;
6 using System.Diagnostics;
7 using System.Globalization;
8 using System.Security;
9 using System.Threading.Tasks;
10
11 namespace System.Xml {
12
13     // Concrete implementation of XmlWriter abstract class that serializes events as encoded XML
14     // text.  The general-purpose XmlEncodedTextWriter uses the Encoder class to output to any
15     // encoding.  The XmlUtf8TextWriter class combined the encoding operation with serialization
16     // in order to achieve better performance.
17     internal partial class XmlEncodedRawTextWriter : XmlRawWriter {
18
19         protected void CheckAsyncCall() {
20             if (!useAsync) {
21                 throw new InvalidOperationException(Res.GetString(Res.Xml_WriterAsyncNotSetException));
22             }
23         }
24
25         // Write the xml declaration.  This must be the first call.  
26         internal override async Task WriteXmlDeclarationAsync( XmlStandalone standalone ) {
27             CheckAsyncCall();
28             // Output xml declaration only if user allows it and it was not already output
29             if ( !omitXmlDeclaration && !autoXmlDeclaration ) {
30
31                 if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); }
32
33                 await RawTextAsync( "<?xml version=\"" ).ConfigureAwait(false);
34
35                 // Version
36                 await RawTextAsync( "1.0" ).ConfigureAwait(false);
37
38                 // Encoding
39                 if ( encoding != null ) {
40                     await RawTextAsync( "\" encoding=\"" ).ConfigureAwait(false);
41                     await RawTextAsync( encoding.WebName ).ConfigureAwait(false);
42                 }
43
44                 // Standalone
45                 if ( standalone != XmlStandalone.Omit ) {
46                     await RawTextAsync( "\" standalone=\"" ).ConfigureAwait(false);
47                     await RawTextAsync( standalone == XmlStandalone.Yes ? "yes" : "no" ).ConfigureAwait(false);
48                 }
49
50                 await RawTextAsync( "\"?>" ).ConfigureAwait(false);
51             }
52         }
53
54         internal override Task WriteXmlDeclarationAsync( string xmldecl ) {
55             CheckAsyncCall();
56             // Output xml declaration only if user allows it and it was not already output
57             if ( !omitXmlDeclaration && !autoXmlDeclaration ) {
58                 return WriteProcessingInstructionAsync( "xml", xmldecl );
59             }
60
61             return AsyncHelper.DoneTask;
62
63         }
64
65         // Serialize the document type declaration.
66         public override async Task WriteDocTypeAsync( string name, string pubid, string sysid, string subset ) {
67             CheckAsyncCall();
68             Debug.Assert( name != null && name.Length > 0 );
69
70             if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); }
71
72             await RawTextAsync( "<!DOCTYPE ").ConfigureAwait(false);
73             await RawTextAsync(name).ConfigureAwait(false);
74             if ( pubid != null ) {
75                 await RawTextAsync( " PUBLIC \"" ).ConfigureAwait(false);
76                 await RawTextAsync( pubid ).ConfigureAwait(false);
77                 await RawTextAsync( "\" \"").ConfigureAwait(false);
78                 if ( sysid != null ) {
79                     await RawTextAsync( sysid ).ConfigureAwait(false);
80                 }
81                 bufChars[bufPos++] = (char) '"';
82             }
83             else if ( sysid != null ) {
84                 await RawTextAsync( " SYSTEM \"" ).ConfigureAwait(false);
85                 await RawTextAsync( sysid ).ConfigureAwait(false);
86                 bufChars[bufPos++] = (char) '"';
87             }
88             else {
89                 bufChars[bufPos++] = (char) ' ';
90             }
91
92             if ( subset != null ) {
93                 bufChars[bufPos++] = (char) '[';
94                 await RawTextAsync( subset ).ConfigureAwait(false);
95                 bufChars[bufPos++] = (char) ']';
96             }
97
98             bufChars[this.bufPos++] = (char) '>';
99         }
100
101         // Serialize the beginning of an element start tag: "<prefix:localName"
102         public override Task WriteStartElementAsync( string prefix, string localName, string ns) {
103             CheckAsyncCall();
104             Debug.Assert( localName != null && localName.Length > 0 );
105             Debug.Assert( prefix != null );
106
107             if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); }
108             Task task;
109             bufChars[bufPos++] = (char) '<';
110             if (prefix != null && prefix.Length != 0) {
111                 task = RawTextAsync(string.Concat(prefix, ":", localName));
112             }
113             else {
114                 task = RawTextAsync(localName);
115             }
116             return task.CallVoidFuncWhenFinish(WriteStartElementAsync_SetAttEndPos);
117         }
118
119         private void WriteStartElementAsync_SetAttEndPos() {
120             attrEndPos = bufPos;
121         }
122
123         // Serialize an element end tag: "</prefix:localName>", if content was output.  Otherwise, serialize
124         // the shortcut syntax: " />".
125         internal override Task WriteEndElementAsync(string prefix, string localName, string ns) {
126             CheckAsyncCall();
127             Debug.Assert(localName != null && localName.Length > 0);
128             Debug.Assert(prefix != null);
129
130             if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); }
131
132             if (contentPos != bufPos) {
133                 // Content has been output, so can't use shortcut syntax
134                 bufChars[bufPos++] = (char)'<';
135                 bufChars[bufPos++] = (char)'/';
136
137                 if (prefix != null && prefix.Length != 0) {
138                     return RawTextAsync(string.Concat(prefix, ":", localName, ">"));
139
140                 }
141                 else {
142                     return RawTextAsync(string.Concat(localName, ">"));
143                 }
144             }
145             else {
146                 // Use shortcut syntax; overwrite the already output '>' character
147                 bufPos--;
148                 bufChars[bufPos++] = (char)' ';
149                 bufChars[bufPos++] = (char)'/';
150                 bufChars[bufPos++] = (char)'>';
151             }
152             return AsyncHelper.DoneTask;
153         }
154
155         // Serialize a full element end tag: "</prefix:localName>"
156         internal override Task WriteFullEndElementAsync(string prefix, string localName, string ns) {
157             CheckAsyncCall();
158             Debug.Assert( localName != null && localName.Length > 0 );
159             Debug.Assert( prefix != null );
160
161             if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); }
162
163             bufChars[bufPos++] = (char) '<';
164             bufChars[bufPos++] = (char) '/';
165
166             if (prefix != null && prefix.Length != 0) {
167                 return RawTextAsync(string.Concat(prefix, ":", localName, ">"));
168             }
169             else {
170                 return RawTextAsync(string.Concat(localName, ">"));
171             }
172         }
173
174         // Serialize an attribute tag using double quotes around the attribute value: 'prefix:localName="'
175         protected internal override Task WriteStartAttributeAsync( string prefix, string localName, string ns ) {
176             CheckAsyncCall();
177             Debug.Assert( localName != null && localName.Length  > 0 );
178             Debug.Assert( prefix != null );
179
180             if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); }
181
182             if ( attrEndPos == bufPos ) {
183                 bufChars[bufPos++] = (char) ' ';
184             }
185             Task task;
186             if (prefix != null && prefix.Length > 0) {
187                 task = RawTextAsync(string.Concat(prefix, ":", localName));
188             }
189             else {
190                 task = RawTextAsync(localName);
191             }
192             return task.CallVoidFuncWhenFinish(WriteStartAttribute_SetInAttribute);
193         }
194
195         private void WriteStartAttribute_SetInAttribute() {
196             bufChars[bufPos++] = (char)'=';
197             bufChars[bufPos++] = (char)'"';
198             inAttributeValue = true;
199         }
200
201         // Serialize the end of an attribute value using double quotes: '"'
202         protected internal override Task WriteEndAttributeAsync() {
203             CheckAsyncCall();
204             if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); }
205             bufChars[bufPos++] = (char) '"';
206             inAttributeValue = false;
207             attrEndPos = bufPos;
208
209             return AsyncHelper.DoneTask;
210         }
211
212         internal override async Task WriteNamespaceDeclarationAsync( string prefix, string namespaceName ) {
213             CheckAsyncCall();
214             Debug.Assert( prefix != null && namespaceName != null );
215
216             await this.WriteStartNamespaceDeclarationAsync( prefix ).ConfigureAwait(false);
217             await this.WriteStringAsync( namespaceName ).ConfigureAwait(false);
218             await this.WriteEndNamespaceDeclarationAsync().ConfigureAwait(false);
219         }
220
221         internal override async Task WriteStartNamespaceDeclarationAsync(string prefix) {
222             CheckAsyncCall();
223             Debug.Assert( prefix != null );
224
225             if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); }
226
227             // VSTFDEVDIV bug #583965: Inconsistency between Silverlight 2 and Dev10 in the way a single xmlns attribute is serialized    
228             // Resolved as: Won't fix (breaking change)
229
230 #if SILVERLIGHT
231             if ( attrEndPos == bufPos ) {
232                 bufChars[bufPos++] = (char)' ';
233             }
234 #endif
235
236             if ( prefix.Length == 0 ) {
237                 await RawTextAsync( " xmlns=\"" ).ConfigureAwait(false);
238             }
239             else {
240                 await RawTextAsync( " xmlns:" ).ConfigureAwait(false);
241                 await RawTextAsync( prefix ).ConfigureAwait(false);
242                 bufChars[bufPos++] = (char)'=';
243                 bufChars[bufPos++] = (char)'"';
244             }
245
246             inAttributeValue = true;
247             if ( trackTextContent && inTextContent != true ) { ChangeTextContentMark( true ); }
248         }
249
250         internal override Task WriteEndNamespaceDeclarationAsync() {
251             CheckAsyncCall();
252             if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); }
253             inAttributeValue = false;
254
255             bufChars[bufPos++] = (char)'"';
256             attrEndPos = bufPos;
257
258             return AsyncHelper.DoneTask;
259
260         }
261
262         // Serialize a CData section.  If the "]]>" pattern is found within
263         // the text, replace it with "]]><![CDATA[>".
264         public override async Task WriteCDataAsync( string text ) {
265             CheckAsyncCall();
266             Debug.Assert( text != null );
267
268             if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); }
269
270             if ( mergeCDataSections && bufPos == cdataPos ) {
271                 // Merge adjacent cdata sections - overwrite the "]]>" characters
272                 Debug.Assert( bufPos >= 4 );
273                 bufPos -= 3;
274             }
275             else {
276                 // Start a new cdata section
277                 bufChars[bufPos++] = (char) '<';
278                 bufChars[bufPos++] = (char) '!';
279                 bufChars[bufPos++] = (char) '[';
280                 bufChars[bufPos++] = (char) 'C';
281                 bufChars[bufPos++] = (char) 'D';
282                 bufChars[bufPos++] = (char) 'A';
283                 bufChars[bufPos++] = (char) 'T';
284                 bufChars[bufPos++] = (char) 'A';
285                 bufChars[bufPos++] = (char) '[';
286             }
287
288             await WriteCDataSectionAsync( text ).ConfigureAwait(false);
289
290             bufChars[bufPos++] = (char) ']';
291             bufChars[bufPos++] = (char) ']';
292             bufChars[bufPos++] = (char) '>';
293
294             textPos = bufPos;
295             cdataPos = bufPos;
296         }
297
298         // Serialize a comment.
299         public override async Task WriteCommentAsync( string text ) {
300             CheckAsyncCall();
301             Debug.Assert( text != null );
302
303             if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); }
304
305             bufChars[bufPos++] = (char) '<';
306             bufChars[bufPos++] = (char) '!';
307             bufChars[bufPos++] = (char) '-';
308             bufChars[bufPos++] = (char) '-';
309
310             await WriteCommentOrPiAsync( text, '-' ).ConfigureAwait(false);
311
312             bufChars[bufPos++] = (char) '-';
313             bufChars[bufPos++] = (char) '-';
314             bufChars[bufPos++] = (char) '>';
315         }
316
317         // Serialize a processing instruction.
318         public override async Task WriteProcessingInstructionAsync( string name, string text ) {
319             CheckAsyncCall();
320             Debug.Assert( name != null && name.Length > 0 );
321             Debug.Assert( text != null );
322
323             if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); }
324
325             bufChars[bufPos++] = (char) '<';
326             bufChars[bufPos++] = (char) '?';
327             await RawTextAsync( name ).ConfigureAwait(false);
328
329             if ( text.Length > 0 ) {
330                 bufChars[bufPos++] = (char) ' ';
331                 await WriteCommentOrPiAsync( text, '?' ).ConfigureAwait(false);
332             }
333
334             bufChars[bufPos++] = (char) '?';
335             bufChars[bufPos++] = (char) '>';
336         }
337
338         // Serialize an entity reference.
339         public override async Task WriteEntityRefAsync( string name ) {
340             CheckAsyncCall();
341             Debug.Assert( name != null && name.Length > 0 );
342
343             if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); }
344
345             bufChars[bufPos++] = (char) '&';
346             await RawTextAsync( name ).ConfigureAwait(false);
347             bufChars[bufPos++] = (char) ';';
348
349             if ( bufPos > bufLen ) {
350                 await FlushBufferAsync().ConfigureAwait(false);
351             }
352
353             textPos = bufPos;
354         }
355
356         // Serialize a character entity reference.
357         public override async Task WriteCharEntityAsync( char ch ) {
358             CheckAsyncCall();
359             string strVal = ((int)ch).ToString( "X", NumberFormatInfo.InvariantInfo );
360
361             if ( checkCharacters && !xmlCharType.IsCharData( ch ) ) {
362                 // we just have a single char, not a surrogate, therefore we have to pass in '\0' for the second char
363                 throw XmlConvert.CreateInvalidCharException( ch, '\0' );
364             }
365
366             if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); }
367
368             bufChars[bufPos++] = (char)'&';
369             bufChars[bufPos++] = (char)'#';
370             bufChars[bufPos++] = (char)'x';
371             await RawTextAsync( strVal ).ConfigureAwait(false);
372             bufChars[bufPos++] = (char)';';
373
374             if ( bufPos > bufLen ) {
375                 await FlushBufferAsync().ConfigureAwait(false);
376             }
377
378             textPos = bufPos;
379         }
380
381         // Serialize a whitespace node.
382
383         public override  Task WriteWhitespaceAsync( string ws ) {
384             CheckAsyncCall();
385             Debug.Assert( ws != null );
386             if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); }
387
388             if ( inAttributeValue) {
389                 return WriteAttributeTextBlockAsync(ws);
390             }
391             else {
392                 return WriteElementTextBlockAsync(ws);
393             }
394
395         }
396
397         // Serialize either attribute or element text using XML rules.
398
399         public override  Task WriteStringAsync( string text ) {
400             CheckAsyncCall();
401             Debug.Assert( text != null );
402             if ( trackTextContent && inTextContent != true ) { ChangeTextContentMark( true ); }
403
404             if ( inAttributeValue) {
405                 return WriteAttributeTextBlockAsync( text );
406             }
407             else {
408                 return WriteElementTextBlockAsync( text );
409             }
410
411         }
412
413         // Serialize surrogate character entity.
414         public override async Task WriteSurrogateCharEntityAsync( char lowChar, char highChar ) {
415             CheckAsyncCall();
416             if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); }
417             int surrogateChar = XmlCharType.CombineSurrogateChar( lowChar, highChar );
418
419             bufChars[bufPos++] = (char)'&';
420             bufChars[bufPos++] = (char)'#';
421             bufChars[bufPos++] = (char)'x';
422             await RawTextAsync( surrogateChar.ToString( "X", NumberFormatInfo.InvariantInfo ) ).ConfigureAwait(false);
423             bufChars[bufPos++] = (char)';';
424             textPos = bufPos;
425         }
426
427         // Serialize either attribute or element text using XML rules.
428         // Arguments are validated in the XmlWellformedWriter layer.
429
430         public override  Task WriteCharsAsync( char[] buffer, int index, int count ) {
431             CheckAsyncCall();
432             Debug.Assert( buffer != null );
433             Debug.Assert( index >= 0 );
434             Debug.Assert( count >= 0 && index + count <= buffer.Length );
435
436             if ( trackTextContent && inTextContent != true ) { ChangeTextContentMark( true ); }
437
438             if ( inAttributeValue) {
439                 return WriteAttributeTextBlockAsync( buffer, index, count );
440             }
441             else {
442                 return WriteElementTextBlockAsync( buffer, index, count );
443             }
444
445         }
446
447         // Serialize raw data.
448         // Arguments are validated in the XmlWellformedWriter layer
449
450         public override  async Task WriteRawAsync( char[] buffer, int index, int count ) {
451             CheckAsyncCall();
452             Debug.Assert( buffer != null );
453             Debug.Assert( index >= 0 );
454             Debug.Assert( count >= 0 && index + count <= buffer.Length );
455
456             if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); }
457
458             await WriteRawWithCharCheckingAsync( buffer, index, count).ConfigureAwait(false);
459
460             textPos = bufPos;
461         }
462
463         // Serialize raw data.
464
465         public override  async Task WriteRawAsync( string data ) {
466             CheckAsyncCall();
467             Debug.Assert( data != null );
468
469             if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); }
470
471             await WriteRawWithCharCheckingAsync(data).ConfigureAwait(false);
472
473             textPos = bufPos;
474         }
475
476         // Flush all characters in the buffer to output and call Flush() on the output object.
477         public override async Task FlushAsync() {
478             CheckAsyncCall();
479             await FlushBufferAsync().ConfigureAwait(false);
480             await FlushEncoderAsync().ConfigureAwait(false);
481
482             if ( stream != null ) {
483                 await stream.FlushAsync().ConfigureAwait(false); 
484             }
485             else if ( writer != null ) {
486                 await writer.FlushAsync().ConfigureAwait(false);
487             }
488
489         }
490
491 //
492 // Implementation methods
493 //
494         // Flush all characters in the buffer to output.  Do not flush the output object.
495         protected virtual async Task FlushBufferAsync() {
496             try {
497                 // Output all characters (except for previous characters stored at beginning of buffer)
498                 if ( !writeToNull ) {
499
500                     Debug.Assert( stream != null || writer != null );
501
502                     if ( stream != null ) {
503                         if ( trackTextContent ) {
504                             charEntityFallback.Reset( textContentMarks, lastMarkPos );
505                             // reset text content tracking
506
507                             if ((lastMarkPos & 1) != 0) {
508                                 // If the previous buffer ended inside a text content we need to preserve that info
509                                 //   which means the next index to which we write has to be even
510                                 textContentMarks[1] = 1;
511                                 lastMarkPos = 1;
512                             }
513                             else {
514                                 lastMarkPos = 0;
515                             }
516                             Debug.Assert( textContentMarks[0] == 1 );
517                         }
518                         await EncodeCharsAsync( 1, bufPos, true ).ConfigureAwait(false);
519                     }
520                     else {
521                         // Write text to TextWriter
522                         await writer.WriteAsync( bufChars, 1, bufPos - 1 ).ConfigureAwait(false);
523                     }
524
525                 }
526             }
527             catch {
528                 // Future calls to flush (i.e. when Close() is called) don't attempt to write to stream
529                 writeToNull = true;
530                 throw;
531             }
532             finally {
533                 // Move last buffer character to the beginning of the buffer (so that previous character can always be determined)
534                 bufChars[0] = bufChars[bufPos - 1];
535
536                 // Reset buffer position
537                 textPos = (textPos == bufPos) ? 1 : 0;
538                 attrEndPos = (attrEndPos == bufPos) ? 1 : 0;
539                 contentPos = 0;    // Needs to be zero, since overwriting '>' character is no longer possible
540                 cdataPos = 0;      // Needs to be zero, since overwriting ']]>' characters is no longer possible
541                 bufPos = 1;        // Buffer position starts at 1, because we need to be able to safely step back -1 in case we need to
542                                    // close an empty element or in CDATA section detection of double ]; _BUFFER[0] will always be 0
543             }
544         }
545
546         private async Task EncodeCharsAsync( int startOffset, int endOffset, bool writeAllToStream ) {
547             // Write encoded text to stream
548             int chEnc;
549             int bEnc;
550             bool completed;
551             while ( startOffset < endOffset ) {
552                 if ( charEntityFallback != null ) {
553                     charEntityFallback.StartOffset = startOffset;
554                 }
555                 encoder.Convert( bufChars, startOffset, endOffset - startOffset, bufBytes, bufBytesUsed, bufBytes.Length - bufBytesUsed, false, out chEnc, out bEnc, out completed );
556                 startOffset += chEnc;
557                 bufBytesUsed += bEnc;
558                 if ( bufBytesUsed >= ( bufBytes.Length - 16 ) ) {
559                     await stream.WriteAsync( bufBytes, 0, bufBytesUsed ).ConfigureAwait(false);
560                     bufBytesUsed = 0;
561                 }
562             }
563             if ( writeAllToStream && bufBytesUsed > 0 ) {
564                 await stream.WriteAsync( bufBytes, 0, bufBytesUsed ).ConfigureAwait(false);
565                 bufBytesUsed = 0;
566             }
567         }
568
569         private Task FlushEncoderAsync() {
570             Debug.Assert( bufPos == 1 );
571             if ( stream != null ) {
572                 int chEnc;
573                 int bEnc;
574                 bool completed;
575                 // decode no chars, just flush
576                 encoder.Convert( bufChars, 1, 0, bufBytes, 0, bufBytes.Length, true, out chEnc, out bEnc, out completed );
577                 if ( bEnc != 0 ) {
578                     return stream.WriteAsync( bufBytes, 0, bEnc );
579                 }
580             }
581
582             return AsyncHelper.DoneTask;
583
584         }
585
586         // Serialize text that is part of an attribute value.  The '&', '<', '>', and '"' characters
587         // are entitized.
588         [SecuritySafeCritical]
589         protected unsafe int WriteAttributeTextBlockNoFlush( char *pSrc, char *pSrcEnd) { 
590             char* pRaw = pSrc;
591
592             fixed ( char * pDstBegin = bufChars ) {
593                 char * pDst = pDstBegin + this.bufPos;
594
595                 int ch = 0;
596                 for (;;) {
597                     char * pDstEnd = pDst + ( pSrcEnd - pSrc );
598                     if ( pDstEnd > pDstBegin + bufLen ) {
599                         pDstEnd = pDstBegin + bufLen;
600                     }
601
602                     while ( pDst < pDstEnd && ( ( ( xmlCharType.charProperties[( ch = *pSrc )] & XmlCharType.fAttrValue ) != 0 ) ) ) {
603
604                         *pDst = (char)ch;
605                         pDst++;
606                         pSrc++;
607                     }
608                     Debug.Assert( pSrc <= pSrcEnd );
609
610                     // end of value
611                     if ( pSrc >= pSrcEnd ) {
612                         break;
613                     }
614
615                     // end of buffer
616                     if ( pDst >= pDstEnd ) {
617
618                         bufPos = (int)(pDst - pDstBegin);
619                         return (int)(pSrc - pRaw); 
620
621                     }
622
623                     // some character needs to be escaped
624                     switch ( ch ) {
625                         case '&':
626                             pDst = AmpEntity( pDst );
627                             break;
628                         case '<':
629                             pDst = LtEntity( pDst );
630                             break;
631                         case '>':
632                             pDst = GtEntity( pDst );
633                             break;
634                         case '"':
635                             pDst = QuoteEntity( pDst );
636                             break;
637                         case '\'':
638                             *pDst = (char)ch;
639                             pDst++;
640                             break;
641                         case (char)0x9:
642                             if ( newLineHandling == NewLineHandling.None ) {
643                                 *pDst = (char)ch;
644                                 pDst++;
645                             }
646                             else {
647                                 // escape tab in attributes
648                                 pDst = TabEntity( pDst );
649                             }
650                             break;
651                         case (char)0xD:
652                             if ( newLineHandling == NewLineHandling.None ) {
653                                 *pDst = (char)ch;
654                                 pDst++;
655                             }
656                             else {
657                                 // escape new lines in attributes
658                                 pDst = CarriageReturnEntity( pDst );
659                             }
660                             break;
661                         case (char)0xA:
662                             if ( newLineHandling == NewLineHandling.None ) {
663                                 *pDst = (char)ch;
664                                 pDst++;
665                             }
666                             else {
667                                 // escape new lines in attributes
668                                 pDst = LineFeedEntity( pDst );
669                             }
670                             break;
671                         default:
672                            if ( XmlCharType.IsSurrogate( ch ) ) { pDst = EncodeSurrogate( pSrc, pSrcEnd, pDst ); pSrc += 2; } else if ( ch <= 0x7F || ch >= 0xFFFE ) { pDst = InvalidXmlChar( ch, pDst, true ); pSrc++; } else { *pDst = (char)ch; pDst++; pSrc++; };
673                             continue;
674                     }
675                     pSrc++;
676                 }
677                 bufPos = (int)(pDst - pDstBegin);
678             }
679
680             return -1;
681
682         }
683
684         [SecuritySafeCritical]
685         protected unsafe int WriteAttributeTextBlockNoFlush( char[] chars, int index, int count ) {
686
687             if (count == 0)
688             {
689                 return -1;
690             }
691             fixed(char* pSrc = &chars[index]) {
692                 char* pSrcBeg = pSrc;
693                 char* pSrcEnd = pSrcBeg + count;
694                 return WriteAttributeTextBlockNoFlush(pSrcBeg, pSrcEnd);
695             }
696         }
697
698         [SecuritySafeCritical]
699         protected unsafe int WriteAttributeTextBlockNoFlush( string text, int index, int count ) {
700
701             if (count == 0)
702             {
703                 return -1;
704             }
705             fixed(char* pSrc = text) {
706                 char* pSrcBeg = pSrc + index;
707                 char* pSrcEnd = pSrcBeg + count;
708                 return WriteAttributeTextBlockNoFlush(pSrcBeg, pSrcEnd);
709             }
710         }
711
712         protected async Task WriteAttributeTextBlockAsync(char[] chars, int index, int count ) {
713             int writeLen = 0;
714             int curIndex = index;
715             int leftCount = count;
716             do {
717                 writeLen = WriteAttributeTextBlockNoFlush(chars, curIndex, leftCount);
718                 curIndex += writeLen;
719                 leftCount -= writeLen;
720                 if (writeLen >= 0) {
721                     await FlushBufferAsync().ConfigureAwait(false);
722                 }
723             } while(writeLen >= 0);
724         }
725
726         protected Task WriteAttributeTextBlockAsync(string text) {
727             int writeLen = 0;
728             int curIndex = 0;
729             int leftCount = text.Length;
730
731             writeLen = WriteAttributeTextBlockNoFlush(text, curIndex, leftCount);
732             curIndex += writeLen;
733             leftCount -= writeLen;
734             if (writeLen >= 0) {
735                 return _WriteAttributeTextBlockAsync(text, curIndex, leftCount);
736             }
737
738             return AsyncHelper.DoneTask;
739         }
740
741
742         private async Task _WriteAttributeTextBlockAsync(string text, int curIndex, int leftCount) {
743             int writeLen;
744             await FlushBufferAsync().ConfigureAwait(false); 
745             do {
746                 writeLen = WriteAttributeTextBlockNoFlush(text, curIndex, leftCount);
747                 curIndex += writeLen;
748                 leftCount -= writeLen;
749                 if (writeLen >= 0) {
750                     await FlushBufferAsync().ConfigureAwait(false);
751                 }
752             } while(writeLen >= 0);
753         }
754
755         // Serialize text that is part of element content.  The '&', '<', and '>' characters
756         // are entitized.
757         [SecuritySafeCritical]
758         protected unsafe int WriteElementTextBlockNoFlush(char *pSrc, char *pSrcEnd, out bool needWriteNewLine) { 
759             needWriteNewLine = false;
760             char* pRaw = pSrc;
761
762             fixed ( char * pDstBegin = bufChars ) {
763                 char * pDst = pDstBegin + this.bufPos;
764
765                 int ch = 0;
766                 for (;;) {
767                     char * pDstEnd = pDst + ( pSrcEnd - pSrc );
768                     if ( pDstEnd > pDstBegin + bufLen ) {
769                         pDstEnd = pDstBegin + bufLen;
770                     }
771
772                     while ( pDst < pDstEnd && ( ( ( xmlCharType.charProperties[( ch = *pSrc )] & XmlCharType.fAttrValue ) != 0 ) ) ) {
773
774                         *pDst = (char)ch;
775                         pDst++;
776                         pSrc++;
777                     }
778                     Debug.Assert( pSrc <= pSrcEnd );
779
780                     // end of value
781                     if ( pSrc >= pSrcEnd ) {
782                         break;
783                     }
784
785                     // end of buffer
786                     if ( pDst >= pDstEnd ) {
787
788                         bufPos = (int)(pDst - pDstBegin);
789                         return (int)(pSrc - pRaw); 
790
791                     }
792
793                     // some character needs to be escaped
794                     switch ( ch ) {
795                         case '&':
796                             pDst = AmpEntity( pDst );
797                             break;
798                         case '<':
799                             pDst = LtEntity( pDst );
800                             break;
801                         case '>':
802                             pDst = GtEntity( pDst );
803                             break;
804                         case '"':
805                         case '\'':
806                         case (char)0x9:
807                             *pDst = (char)ch;
808                             pDst++;
809                             break;
810                         case (char)0xA:
811                             if ( newLineHandling == NewLineHandling.Replace ) {
812
813                                 bufPos = (int)(pDst - pDstBegin);
814                                 needWriteNewLine = true;
815                                 return (int)(pSrc - pRaw); 
816
817                             }
818                             else {
819                                 *pDst = (char)ch;
820                                 pDst++;
821                             }
822                             break;
823                         case (char)0xD:
824                             switch ( newLineHandling ) {
825                                 case NewLineHandling.Replace:
826                                     // Replace "\r\n", or "\r" with NewLineChars
827                                     if ( pSrc[1] == '\n' ) {
828                                         pSrc++;
829                                     }
830
831                                     bufPos = (int)(pDst - pDstBegin);
832                                     needWriteNewLine = true;
833                                     return (int)(pSrc - pRaw); 
834
835                                 case NewLineHandling.Entitize:
836                                     // Entitize 0xD
837                                     pDst = CarriageReturnEntity( pDst );
838                                     break;
839                                 case NewLineHandling.None:
840                                     *pDst = (char)ch;
841                                     pDst++;
842                                     break;
843                             }
844                             break;
845                         default:
846                             if ( XmlCharType.IsSurrogate( ch ) ) { pDst = EncodeSurrogate( pSrc, pSrcEnd, pDst ); pSrc += 2; } else if ( ch <= 0x7F || ch >= 0xFFFE ) { pDst = InvalidXmlChar( ch, pDst, true ); pSrc++; } else { *pDst = (char)ch; pDst++; pSrc++; };
847                             continue;
848                     }
849                     pSrc++;
850                 }
851                 bufPos = (int)(pDst - pDstBegin);
852                 textPos = bufPos;
853                 contentPos = 0;
854             }
855
856             return -1;
857
858         }
859
860         [SecuritySafeCritical]
861         protected unsafe int WriteElementTextBlockNoFlush( char[] chars, int index, int count, out bool needWriteNewLine ) { 
862             needWriteNewLine = false;
863             if (count == 0)
864             {
865                 contentPos = 0;
866                 return -1;
867             }
868             fixed (char* pSrc = &chars[index]) {
869                 char* pSrcBeg = pSrc;
870                 char* pSrcEnd = pSrcBeg + count;
871                 return WriteElementTextBlockNoFlush(pSrcBeg, pSrcEnd, out needWriteNewLine);
872             }
873         }
874
875         [SecuritySafeCritical]
876         protected unsafe int WriteElementTextBlockNoFlush( string text, int index, int count, out bool needWriteNewLine ) { 
877             needWriteNewLine = false;
878             if (count == 0)
879             {
880                 contentPos = 0;
881                 return -1;
882             }
883             fixed (char* pSrc = text) {
884                 char* pSrcBeg = pSrc + index;
885                 char* pSrcEnd = pSrcBeg + count;
886                 return WriteElementTextBlockNoFlush(pSrcBeg, pSrcEnd, out needWriteNewLine);
887             }
888         }
889
890         protected async Task WriteElementTextBlockAsync(char[] chars, int index, int count ) {
891             int writeLen = 0;
892             int curIndex = index;
893             int leftCount = count;
894             bool needWriteNewLine = false;
895             do {
896                 writeLen = WriteElementTextBlockNoFlush(chars, curIndex, leftCount, out needWriteNewLine);
897                 curIndex += writeLen;
898                 leftCount -= writeLen;
899                 if (needWriteNewLine)
900                 {
901                     //hit WriteNewLine
902                     await RawTextAsync(newLineChars).ConfigureAwait(false);
903                     curIndex++;
904                     leftCount--;
905                 }
906                 else if (writeLen >= 0)
907                 {
908                     await FlushBufferAsync().ConfigureAwait(false);
909                 }
910             } while(writeLen >= 0 || needWriteNewLine);
911         }
912
913         protected Task WriteElementTextBlockAsync(string text) {
914             int writeLen = 0;
915             int curIndex = 0;
916             int leftCount = text.Length;
917             bool needWriteNewLine = false;
918
919             writeLen = WriteElementTextBlockNoFlush(text, curIndex, leftCount, out needWriteNewLine);
920             curIndex += writeLen;
921             leftCount -= writeLen;
922             if (needWriteNewLine) {
923                 return _WriteElementTextBlockAsync(true, text, curIndex, leftCount);
924             }
925             else if (writeLen >= 0) {
926                 return _WriteElementTextBlockAsync(false, text, curIndex, leftCount);
927             }
928
929             return AsyncHelper.DoneTask;
930         }
931
932         private async Task _WriteElementTextBlockAsync(bool newLine, string text, int curIndex, int leftCount) {
933             int writeLen = 0;
934             bool needWriteNewLine = false;
935
936             if (newLine) {
937                 await RawTextAsync(newLineChars).ConfigureAwait(false);
938                 curIndex++;
939                 leftCount--;
940             }
941             else {
942                 await FlushBufferAsync().ConfigureAwait(false);
943             }
944
945             do {
946                 writeLen = WriteElementTextBlockNoFlush(text, curIndex, leftCount, out needWriteNewLine);
947                 curIndex += writeLen;
948                 leftCount -= writeLen;
949                 if (needWriteNewLine) {
950                     //hit WriteNewLine
951                     await RawTextAsync(newLineChars).ConfigureAwait(false);
952                     curIndex++;
953                     leftCount--;
954                 }
955                 else if (writeLen >= 0) {
956                     await FlushBufferAsync().ConfigureAwait(false);
957                 }
958             } while (writeLen >= 0 || needWriteNewLine);
959         }
960
961         [SecuritySafeCritical]
962         protected unsafe int RawTextNoFlush( char * pSrcBegin, char * pSrcEnd ) {
963             char* pRaw = pSrcBegin;
964
965             fixed ( char * pDstBegin = bufChars ) {
966                 char * pDst = pDstBegin + this.bufPos;
967                 char * pSrc = pSrcBegin;
968
969                 int ch = 0;
970                 for (;;) {
971                     char * pDstEnd = pDst + ( pSrcEnd - pSrc );
972                     if ( pDstEnd > pDstBegin + this.bufLen ) {
973                         pDstEnd = pDstBegin + this.bufLen;
974                     }
975
976                     while ( pDst < pDstEnd && ( ( ch = *pSrc ) < XmlCharType.SurHighStart ) ) {
977
978                         pSrc++;
979                         *pDst = (char)ch;
980                         pDst++;
981                     }
982                     Debug.Assert( pSrc <= pSrcEnd );
983
984                     // end of value
985                     if ( pSrc >= pSrcEnd ) {
986                         break;
987                     }
988
989                     // end of buffer
990                     if ( pDst >= pDstEnd ) {
991
992                         bufPos = (int)(pDst - pDstBegin);
993                         return (int)(pSrc - pRaw);
994
995                     }
996
997                     if ( XmlCharType.IsSurrogate( ch ) ) { pDst = EncodeSurrogate( pSrc, pSrcEnd, pDst ); pSrc += 2; } else if ( ch <= 0x7F || ch >= 0xFFFE ) { pDst = InvalidXmlChar( ch, pDst, false ); pSrc++; } else { *pDst = (char)ch; pDst++; pSrc++; };
998                 }
999
1000                 bufPos = (int)(pDst - pDstBegin);
1001             }
1002
1003             return -1;
1004             
1005         }
1006
1007         [SecuritySafeCritical]
1008         protected unsafe int RawTextNoFlush( string text, int index, int count ) {
1009             if (count == 0)
1010             {
1011                 return -1;
1012             }
1013             fixed(char* pSrc = text) {
1014                 char* pSrcBegin = pSrc + index;
1015                 char* pSrcEnd = pSrcBegin + count;
1016                 return RawTextNoFlush(pSrcBegin, pSrcEnd );
1017             }
1018         }
1019
1020         protected Task RawTextAsync(string text) {
1021             int writeLen = 0;
1022             int curIndex = 0;
1023             int leftCount = text.Length;
1024
1025             writeLen = RawTextNoFlush(text, curIndex, leftCount);
1026             curIndex += writeLen;
1027             leftCount -= writeLen;
1028             if (writeLen >= 0) {
1029                 return _RawTextAsync(text, curIndex, leftCount);
1030             }
1031             
1032             return AsyncHelper.DoneTask;
1033         }
1034
1035         private async Task _RawTextAsync(string text, int curIndex, int leftCount) {
1036             await FlushBufferAsync().ConfigureAwait(false);
1037             int writeLen = 0;
1038             do {
1039                 writeLen = RawTextNoFlush(text, curIndex, leftCount);
1040                 curIndex += writeLen;
1041                 leftCount -= writeLen;
1042                 if (writeLen >= 0) {
1043                     await FlushBufferAsync().ConfigureAwait(false);
1044                 }
1045             } while (writeLen >= 0);
1046         }
1047
1048         [SecuritySafeCritical]
1049         protected unsafe int WriteRawWithCharCheckingNoFlush( char * pSrcBegin, char * pSrcEnd, out bool needWriteNewLine) {
1050             needWriteNewLine = false;
1051             char* pRaw = pSrcBegin;
1052
1053             fixed ( char * pDstBegin = bufChars ) {
1054                 char * pSrc = pSrcBegin;
1055                 char * pDst = pDstBegin + bufPos;
1056
1057                 int ch = 0;
1058                 for (;;) {
1059                     char * pDstEnd = pDst + ( pSrcEnd - pSrc );
1060                     if ( pDstEnd > pDstBegin + bufLen ) {
1061                         pDstEnd = pDstBegin + bufLen;
1062                     }
1063
1064                     while ( pDst < pDstEnd && ( ( ( xmlCharType.charProperties[( ch = *pSrc )] & XmlCharType.fText ) != 0 ) ) ) {
1065
1066                         *pDst = (char)ch;
1067                         pDst++;
1068                         pSrc++;
1069                     }
1070
1071                     Debug.Assert( pSrc <= pSrcEnd );
1072
1073                     // end of value
1074                     if ( pSrc >= pSrcEnd ) {
1075                         break;
1076                     }
1077
1078                     // end of buffer
1079                     if ( pDst >= pDstEnd ) {
1080
1081                         bufPos = (int)(pDst - pDstBegin);
1082                         return (int)(pSrc - pRaw); 
1083
1084                     }
1085
1086                     // handle special characters
1087                     switch ( ch ) {
1088                         case ']':
1089                         case '<':
1090                         case '&':
1091                         case (char)0x9:
1092                             *pDst = (char)ch;
1093                             pDst++;
1094                             break;
1095                         case (char)0xD:
1096                             if ( newLineHandling == NewLineHandling.Replace ) {
1097                                 // Normalize "\r\n", or "\r" to NewLineChars
1098                                 if ( pSrc[1] == '\n' ) {
1099                                     pSrc++;
1100                                 }
1101
1102                                 bufPos = (int)(pDst - pDstBegin);
1103                                 needWriteNewLine = true;
1104                                 return (int)(pSrc - pRaw); 
1105
1106                             }
1107                             else {
1108                                 *pDst = (char)ch;
1109                                 pDst++;
1110                             }
1111                             break;
1112                         case (char)0xA:
1113                             if ( newLineHandling == NewLineHandling.Replace ) {
1114
1115                                 bufPos = (int)(pDst - pDstBegin);
1116                                 needWriteNewLine = true;
1117                                 return (int)(pSrc - pRaw); 
1118
1119                             }
1120                             else {
1121                                 *pDst = (char)ch;
1122                                 pDst++;
1123                             }
1124                             break;
1125                         default:
1126                             if ( XmlCharType.IsSurrogate( ch ) ) { pDst = EncodeSurrogate( pSrc, pSrcEnd, pDst ); pSrc += 2; } else if ( ch <= 0x7F || ch >= 0xFFFE ) { pDst = InvalidXmlChar( ch, pDst, false ); pSrc++; } else { *pDst = (char)ch; pDst++; pSrc++; };
1127                             continue;
1128                     }
1129                     pSrc++;
1130                 }
1131                 bufPos = (int)(pDst - pDstBegin);
1132             }
1133
1134             return -1;
1135
1136         }
1137
1138         [SecuritySafeCritical]
1139         protected unsafe int WriteRawWithCharCheckingNoFlush( char[] chars, int index, int count, out bool needWriteNewLine ) {
1140             needWriteNewLine = false;
1141             if (count == 0)
1142             {
1143                 return -1;
1144             }
1145             fixed(char* pSrc = &chars[index]) {
1146                 char* pSrcBeg = pSrc;
1147                 char* pSrcEnd = pSrcBeg + count;
1148                 return WriteRawWithCharCheckingNoFlush(pSrcBeg, pSrcEnd, out needWriteNewLine);
1149             }
1150         }
1151
1152         [SecuritySafeCritical]
1153         protected unsafe int WriteRawWithCharCheckingNoFlush(string text, int index, int count , out bool needWriteNewLine) {
1154             needWriteNewLine = false;
1155             if (count == 0)
1156             {
1157                 return -1;
1158             }
1159             fixed(char* pSrc = text) {
1160                 char* pSrcBeg = pSrc + index;
1161                 char* pSrcEnd = pSrcBeg + count;
1162                 return WriteRawWithCharCheckingNoFlush(pSrcBeg, pSrcEnd, out needWriteNewLine);
1163             }
1164         }
1165
1166         protected async Task WriteRawWithCharCheckingAsync(char[] chars, int index, int count ) {
1167             int writeLen = 0;
1168             int curIndex = index;
1169             int leftCount = count;
1170             bool needWriteNewLine = false;
1171             do {
1172                 writeLen = WriteRawWithCharCheckingNoFlush(chars, curIndex, leftCount, out needWriteNewLine);
1173                 curIndex += writeLen;
1174                 leftCount -= writeLen;
1175                 if (needWriteNewLine)
1176                 {
1177                     await RawTextAsync(newLineChars).ConfigureAwait(false);
1178                     curIndex++;
1179                     leftCount--;
1180                 }
1181                 else if (writeLen >= 0)
1182                 {
1183                     await FlushBufferAsync().ConfigureAwait(false);
1184                 }
1185             } while(writeLen >= 0 || needWriteNewLine);
1186         }
1187
1188          protected async Task WriteRawWithCharCheckingAsync(string text ) {
1189             int writeLen = 0;
1190             int curIndex = 0;
1191             int leftCount = text.Length;
1192             bool needWriteNewLine = false;
1193             do {
1194                 writeLen = WriteRawWithCharCheckingNoFlush(text, curIndex, leftCount, out needWriteNewLine);
1195                 curIndex += writeLen;
1196                 leftCount -= writeLen;
1197                 if (needWriteNewLine)
1198                 {
1199                     await RawTextAsync(newLineChars).ConfigureAwait(false);
1200                     curIndex++;
1201                     leftCount--;
1202                 }
1203                 else if (writeLen >= 0)
1204                 {
1205                     await FlushBufferAsync().ConfigureAwait(false);
1206                 }
1207             } while(writeLen >= 0 || needWriteNewLine);
1208         }
1209
1210         [SecuritySafeCritical]
1211         protected unsafe int WriteCommentOrPiNoFlush( string text, int index, int count, int stopChar, out bool needWriteNewLine  ) {
1212
1213             needWriteNewLine = false;
1214             if (count == 0)
1215             {
1216                 return -1;
1217             }
1218             fixed ( char * pSrcText = text ) {
1219             char * pSrcBegin = pSrcText + index;
1220
1221             fixed ( char * pDstBegin = bufChars ) {
1222                 char * pSrc = pSrcBegin;
1223
1224                 char* pRaw = pSrc;
1225
1226                 char * pSrcEnd = pSrcBegin + count;
1227
1228                 char * pDst = pDstBegin + bufPos;
1229
1230                 int ch = 0;
1231                 for (;;) {
1232                     char * pDstEnd = pDst + ( pSrcEnd - pSrc );
1233                     if ( pDstEnd > pDstBegin + bufLen ) {
1234                         pDstEnd = pDstBegin + bufLen;
1235                     }
1236
1237                     while ( pDst < pDstEnd && ( ( ( xmlCharType.charProperties[( ch = *pSrc )] & XmlCharType.fText ) != 0 ) && ch != stopChar ) ) {
1238
1239                         *pDst = (char)ch;
1240                         pDst++;
1241                         pSrc++;
1242                     }
1243
1244                     Debug.Assert( pSrc <= pSrcEnd );
1245
1246                     // end of value
1247                     if ( pSrc >= pSrcEnd ) {
1248                         break;
1249                     }
1250
1251                     // end of buffer
1252                     if ( pDst >= pDstEnd ) {
1253
1254                         bufPos = (int)(pDst - pDstBegin);
1255                         return (int)(pSrc - pRaw); 
1256
1257                     }
1258
1259                     // handle special characters
1260                     switch ( ch ) {
1261                         case '-':
1262                             *pDst = (char) '-';
1263                             pDst++;
1264                             if ( ch == stopChar ) {
1265                                 // Insert space between adjacent dashes or before comment's end dashes
1266                                 if ( pSrc + 1 == pSrcEnd || *(pSrc + 1)== '-' ) {
1267                                     *pDst = (char) ' ';
1268                                     pDst++;
1269                                 }
1270                             }
1271                             break;
1272                         case '?':
1273                             *pDst = (char) '?';
1274                             pDst++;
1275                             if ( ch == stopChar ) {
1276                                 // Processing instruction: insert space between adjacent '?' and '>' 
1277                                 if ( pSrc + 1 < pSrcEnd && *(pSrc + 1)== '>' ) {
1278                                     *pDst = (char) ' ';
1279                                     pDst++;
1280                                 }
1281                             }
1282                             break;
1283                         case ']':
1284                             *pDst = (char) ']';
1285                             pDst++;
1286                             break;
1287                         case (char)0xD:
1288                             if ( newLineHandling == NewLineHandling.Replace ) {
1289                                 // Normalize "\r\n", or "\r" to NewLineChars
1290                                 if ( pSrc[1] == '\n' ) {
1291                                     pSrc++;
1292                                 }
1293
1294                                 bufPos = (int)(pDst - pDstBegin);
1295                                 needWriteNewLine = true;
1296                                 return (int)(pSrc - pRaw); 
1297
1298                             }
1299                             else {
1300                                 *pDst = (char)ch;
1301                                 pDst++;
1302                             }
1303                             break;
1304                         case (char)0xA:
1305                             if ( newLineHandling == NewLineHandling.Replace ) {
1306
1307                                 bufPos = (int)(pDst - pDstBegin);
1308                                 needWriteNewLine = true;
1309                                 return (int)(pSrc - pRaw); 
1310
1311                             }
1312                             else {
1313                                 *pDst = (char)ch;
1314                                 pDst++;
1315                             }
1316                             break;
1317                         case '<':
1318                         case '&':
1319                         case (char)0x9:
1320                             *pDst = (char)ch;
1321                             pDst++;
1322                             break;
1323                         default:
1324                             if ( XmlCharType.IsSurrogate( ch ) ) { pDst = EncodeSurrogate( pSrc, pSrcEnd, pDst ); pSrc += 2; } else if ( ch <= 0x7F || ch >= 0xFFFE ) { pDst = InvalidXmlChar( ch, pDst, false ); pSrc++; } else { *pDst = (char)ch; pDst++; pSrc++; };
1325                             continue;
1326                     }
1327                     pSrc++;
1328                 }
1329                 bufPos = (int)(pDst - pDstBegin);
1330             }
1331
1332             return -1;
1333             }
1334
1335         }
1336
1337         protected async Task WriteCommentOrPiAsync(string text, int stopChar) {
1338
1339             if ( text.Length == 0 ) {
1340                 if ( bufPos >= bufLen ) {
1341                     await FlushBufferAsync().ConfigureAwait(false);
1342                 }
1343                 return;
1344             }
1345
1346             int writeLen = 0;
1347             int curIndex = 0;
1348             int leftCount = text.Length;
1349             bool needWriteNewLine = false;
1350             do {
1351                 writeLen = WriteCommentOrPiNoFlush(text, curIndex, leftCount, stopChar, out needWriteNewLine);
1352                 curIndex += writeLen;
1353                 leftCount -= writeLen;
1354                 if (needWriteNewLine)
1355                 {
1356                     await RawTextAsync(newLineChars).ConfigureAwait(false);
1357                     curIndex++;
1358                     leftCount--;
1359                 }
1360                 else if (writeLen >= 0)
1361                 {
1362                     await FlushBufferAsync().ConfigureAwait(false);
1363                 }
1364             } while(writeLen >= 0 || needWriteNewLine);
1365         }
1366
1367         [SecuritySafeCritical]
1368         protected unsafe int WriteCDataSectionNoFlush(  string text, int index, int count , out bool needWriteNewLine) {
1369             needWriteNewLine = false;
1370             if (count == 0)
1371             {
1372                 return -1;
1373             }
1374
1375                       // write text
1376
1377             fixed ( char * pSrcText = text ) {
1378             
1379             char* pSrcBegin = pSrcText + index;
1380
1381             fixed ( char * pDstBegin = bufChars ) {
1382                 char * pSrc = pSrcBegin;
1383
1384                 char * pSrcEnd = pSrcBegin + count;
1385
1386                 char * pRaw = pSrc;
1387
1388                 char * pDst = pDstBegin + bufPos;
1389
1390                 int ch = 0;
1391                 for (;;) {
1392                     char * pDstEnd = pDst + ( pSrcEnd - pSrc );
1393                     if ( pDstEnd > pDstBegin + bufLen ) {
1394                         pDstEnd = pDstBegin + bufLen;
1395                     }
1396
1397                     while ( pDst < pDstEnd && ( ( ( xmlCharType.charProperties[( ch = *pSrc )] & XmlCharType.fAttrValue ) != 0 ) && ch != ']' ) ) {
1398
1399                         *pDst = (char)ch;
1400                         pDst++;
1401                         pSrc++;
1402                     }
1403
1404                     Debug.Assert( pSrc <= pSrcEnd );
1405
1406                     // end of value
1407                     if ( pSrc >= pSrcEnd ) {
1408                         break;
1409                     }
1410
1411                     // end of buffer
1412                     if ( pDst >= pDstEnd ) {
1413
1414                         bufPos = (int)(pDst - pDstBegin);
1415                         return (int)(pSrc - pRaw); 
1416
1417                     }
1418
1419                     // handle special characters
1420                     switch ( ch ) {
1421                         case '>':
1422                             if ( hadDoubleBracket && pDst[-1] == (char) ']') {   // pDst[-1] will always correct - there is a padding character at _BUFFER[0]
1423                                 // The characters "]]>" were found within the CData text
1424                                 pDst = RawEndCData( pDst );
1425                                 pDst = RawStartCData( pDst );
1426                             }
1427                             *pDst = (char) '>';
1428                             pDst++;
1429                             break;
1430                         case ']':
1431                             if ( pDst[-1] == (char)']' ) {   // pDst[-1] will always correct - there is a padding character at _BUFFER[0]
1432                                 hadDoubleBracket = true;
1433                             }
1434                             else {
1435                                 hadDoubleBracket = false;
1436                             }
1437                             *pDst = (char)']';
1438                             pDst++;
1439                             break;
1440                         case (char)0xD:
1441                             if ( newLineHandling == NewLineHandling.Replace ) {
1442                                 // Normalize "\r\n", or "\r" to NewLineChars
1443                                 if ( pSrc[1] == '\n' ) {
1444                                     pSrc++;
1445                                 }
1446
1447                                 bufPos = (int)(pDst - pDstBegin);
1448                                 needWriteNewLine = true;
1449                                 return (int)(pSrc - pRaw); 
1450
1451                             }
1452                             else {
1453                                 *pDst = (char)ch;
1454                                 pDst++;
1455                             }
1456                             break;
1457                         case (char)0xA:
1458                             if ( newLineHandling == NewLineHandling.Replace ) {
1459
1460                                 bufPos = (int)(pDst - pDstBegin);
1461                                 needWriteNewLine = true;
1462                                 return (int)(pSrc - pRaw); 
1463
1464                             }
1465                             else {
1466                                 *pDst = (char)ch;
1467                                 pDst++;
1468                             }
1469                             break;
1470                         case '&':
1471                         case '<':
1472                         case '"':
1473                         case '\'':
1474                         case (char)0x9:
1475                             *pDst = (char)ch;
1476                             pDst++;
1477                             break;
1478                         default:
1479                             if ( XmlCharType.IsSurrogate( ch ) ) { pDst = EncodeSurrogate( pSrc, pSrcEnd, pDst ); pSrc += 2; } else if ( ch <= 0x7F || ch >= 0xFFFE ) { pDst = InvalidXmlChar( ch, pDst, false ); pSrc++; } else { *pDst = (char)ch; pDst++; pSrc++; };
1480                             continue;
1481                     }
1482                     pSrc++;
1483                 }
1484                 bufPos = (int)(pDst - pDstBegin);
1485             }
1486
1487             return -1;
1488             }
1489
1490         }
1491
1492         protected async Task WriteCDataSectionAsync(string text) {
1493
1494             if ( text.Length == 0 ) {
1495                 if ( bufPos >= bufLen ) {
1496                     await FlushBufferAsync().ConfigureAwait(false);
1497                 }
1498                 return;
1499             }
1500
1501             int writeLen = 0;
1502             int curIndex = 0;
1503             int leftCount = text.Length;
1504             bool needWriteNewLine = false;
1505             do {
1506                 writeLen = WriteCDataSectionNoFlush(text, curIndex, leftCount, out needWriteNewLine);
1507                 curIndex += writeLen;
1508                 leftCount -= writeLen;
1509                 if (needWriteNewLine)
1510                 {
1511                     await RawTextAsync(newLineChars).ConfigureAwait(false);
1512                     curIndex++;
1513                     leftCount--;
1514                 }
1515                 else if (writeLen >= 0)
1516                 {
1517                     await FlushBufferAsync().ConfigureAwait(false);
1518                 }
1519             } while(writeLen >= 0 || needWriteNewLine);
1520         }
1521
1522     }
1523
1524     // Same as base text writer class except that elements, attributes, comments, and pi's are indented.
1525     internal partial class XmlEncodedRawTextWriterIndent : XmlEncodedRawTextWriter {
1526
1527         public override async Task WriteDocTypeAsync( string name, string pubid, string sysid, string subset ) {
1528             CheckAsyncCall();
1529             // Add indentation
1530             if ( !mixedContent && base.textPos != base.bufPos) {
1531                 await WriteIndentAsync().ConfigureAwait(false);
1532             }
1533             await base.WriteDocTypeAsync( name, pubid, sysid, subset ).ConfigureAwait(false);
1534         }
1535
1536         public override async Task WriteStartElementAsync( string prefix, string localName, string ns ) {
1537             CheckAsyncCall();
1538             Debug.Assert( localName != null && localName.Length != 0 && prefix != null && ns != null );
1539
1540             // Add indentation
1541             if ( !mixedContent && base.textPos != base.bufPos) {
1542                 await WriteIndentAsync().ConfigureAwait(false);
1543             }
1544             indentLevel++;
1545             mixedContentStack.PushBit( mixedContent );
1546
1547             await base.WriteStartElementAsync( prefix, localName, ns ).ConfigureAwait(false);
1548         }
1549
1550         internal override async Task WriteEndElementAsync(string prefix, string localName, string ns) {
1551             CheckAsyncCall();
1552             // Add indentation
1553             indentLevel--;
1554             if ( !mixedContent && base.contentPos != base.bufPos ) {
1555                 // There was content, so try to indent
1556                 if ( base.textPos != base.bufPos ) {
1557                     await WriteIndentAsync().ConfigureAwait(false);
1558                 }
1559             }
1560             mixedContent = mixedContentStack.PopBit();
1561
1562             await base.WriteEndElementAsync( prefix, localName, ns ).ConfigureAwait(false);
1563         }
1564
1565         internal override async Task WriteFullEndElementAsync(string prefix, string localName, string ns) {
1566             CheckAsyncCall();
1567             // Add indentation
1568             indentLevel--;
1569             if ( !mixedContent && base.contentPos != base.bufPos ) {
1570                 // There was content, so try to indent
1571                 if ( base.textPos != base.bufPos ) {
1572                     await WriteIndentAsync().ConfigureAwait(false);
1573                 }
1574             }
1575             mixedContent = mixedContentStack.PopBit();
1576
1577             await base.WriteFullEndElementAsync( prefix, localName, ns ).ConfigureAwait(false);
1578         }
1579
1580         // Same as base class, plus possible indentation.
1581         protected internal override async Task WriteStartAttributeAsync( string prefix, string localName, string ns ) {
1582             CheckAsyncCall();
1583             // Add indentation
1584             if ( newLineOnAttributes ) {
1585                 await WriteIndentAsync().ConfigureAwait(false);
1586             }
1587
1588             await base.WriteStartAttributeAsync( prefix, localName, ns ).ConfigureAwait(false);
1589         }
1590
1591         public override Task WriteCDataAsync( string text ) {
1592             CheckAsyncCall();
1593             mixedContent = true;
1594             return base.WriteCDataAsync( text );
1595         }
1596     
1597         public override async Task WriteCommentAsync( string text ) {
1598             CheckAsyncCall();
1599             if ( !mixedContent && base.textPos != base.bufPos ) {
1600                 await WriteIndentAsync().ConfigureAwait(false);
1601             }
1602
1603             await base.WriteCommentAsync( text ).ConfigureAwait(false);
1604         }
1605
1606         public override async Task WriteProcessingInstructionAsync( string target, string text ) {
1607             CheckAsyncCall();
1608             if ( !mixedContent && base.textPos != base.bufPos ) {
1609                 await WriteIndentAsync().ConfigureAwait(false);
1610             }
1611
1612             await base.WriteProcessingInstructionAsync( target, text ).ConfigureAwait(false);
1613         }
1614
1615         public override Task WriteEntityRefAsync( string name ) {
1616             CheckAsyncCall();
1617             mixedContent = true;
1618             return base.WriteEntityRefAsync( name );
1619         }
1620
1621         public override Task WriteCharEntityAsync( char ch ) {
1622             CheckAsyncCall();
1623             mixedContent = true;
1624             return base.WriteCharEntityAsync( ch );
1625         }
1626
1627         public override Task WriteSurrogateCharEntityAsync( char lowChar, char highChar ) {
1628             CheckAsyncCall();
1629             mixedContent = true;
1630             return base.WriteSurrogateCharEntityAsync( lowChar, highChar );
1631         }
1632
1633         public override Task WriteWhitespaceAsync( string ws ) {
1634             CheckAsyncCall();
1635             mixedContent = true;
1636             return base.WriteWhitespaceAsync( ws );
1637         }
1638
1639         public override Task WriteStringAsync( string text ) {
1640             CheckAsyncCall();
1641             mixedContent = true;
1642             return base.WriteStringAsync( text );
1643         }
1644
1645         public override Task WriteCharsAsync( char[] buffer, int index, int count ) {
1646             CheckAsyncCall();
1647             mixedContent = true;
1648             return base.WriteCharsAsync( buffer, index, count );
1649         }
1650
1651         public override Task WriteRawAsync( char[] buffer, int index, int count ) {
1652             CheckAsyncCall();
1653             mixedContent = true;
1654             return base.WriteRawAsync( buffer, index, count );
1655         }
1656
1657         public override Task WriteRawAsync( string data ) {
1658             CheckAsyncCall();
1659             mixedContent = true;
1660             return base.WriteRawAsync( data );
1661         }
1662
1663         public override Task WriteBase64Async( byte[] buffer, int index, int count ) {
1664             CheckAsyncCall();
1665             mixedContent = true;
1666             return base.WriteBase64Async( buffer, index, count );
1667         }
1668
1669         // Add indentation to output.  Write newline and then repeat IndentChars for each indent level.
1670         private async Task WriteIndentAsync() {
1671             CheckAsyncCall();
1672             await RawTextAsync( base.newLineChars ).ConfigureAwait(false);
1673             for ( int i = indentLevel; i > 0; i-- ) {
1674                 await RawTextAsync( indentChars ).ConfigureAwait(false);
1675             }
1676         }
1677     }
1678 }
1679