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