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">Microsoft</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. XmlUtf8RawTextWriter( XmlWriterSettings settings )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. XmlUtf8RawTextWriter( Stream stream, XmlWriterSettings settings )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. WriteXmlDeclaration( XmlStandalone standalone )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 WriteXmlDeclaration( string xmldecl )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. WriteDocType( string name, string pubid, string sysid, string subset )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" WriteStartElement( string prefix, string localName, string ns)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: ">" StartElementContent()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: " />". WriteEndElement( string prefix, string localName, string ns )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>" WriteFullEndElement( string prefix, string localName, string ns )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="' WriteStartAttribute( string prefix, string localName, string ns )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: '"' WriteEndAttribute()338 public override void WriteEndAttribute() { 339 340 bufBytes[bufPos++] = (byte) '"'; 341 inAttributeValue = false; 342 attrEndPos = bufPos; 343 344 } 345 WriteNamespaceDeclaration( string prefix, string namespaceName )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 WriteStartNamespaceDeclaration(string prefix)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 WriteEndNamespaceDeclaration()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[>". WriteCData( string text )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. WriteComment( string text )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. WriteProcessingInstruction( string name, string text )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. WriteEntityRef( string name )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. WriteCharEntity( char ch )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 WriteWhitespace( string ws )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 WriteString( string text )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. WriteSurrogateCharEntity( char lowChar, char highChar )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 WriteChars( char[] buffer, int index, int count )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 WriteRaw( char[] buffer, int index, int count )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 WriteRaw( string data )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. Close()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. Flush()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. FlushBuffer()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 FlushEncoder()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 WriteAttributeTextBlock( char *pSrc, char *pSrcEnd )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 WriteElementTextBlock( char *pSrc, char *pSrcEnd )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 RawText( string s )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 RawText( char * pSrcBegin, char * pSrcEnd )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 WriteRawWithCharChecking( char * pSrcBegin, char * pSrcEnd )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 WriteCommentOrPi( string text, int stopChar )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 WriteCDataSection( string text )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. IsSurrogateByte( byte b )1242 private static bool IsSurrogateByte( byte b ) { 1243 return (b & 0xF8) == 0xF0; 1244 } 1245 EncodeSurrogate( char* pSrc, char* pSrcEnd, byte* pDst )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 InvalidXmlChar( int ch, byte* pDst, bool entitize )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 EncodeChar(ref char* pSrc, char*pSrcEnd, ref byte* pDst)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 EncodeMultibyteUTF8( int ch, byte* pDst )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 CharToUTF8( ref char * pSrc, char * pSrcEnd, ref byte * pDst )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 WriteNewLine( byte * pDst )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 "<". Return an updated pointer. 1362 LtEntity( byte * pDst )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 ">". Return an updated pointer. 1372 GtEntity( byte * pDst )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 "&". Return an updated pointer. 1382 AmpEntity( byte * pDst )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 """. Return an updated pointer. 1393 QuoteEntity( byte * pDst )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 "	". Return an updated pointer. 1405 TabEntity( byte * pDst )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 "
". Return an updated pointer. 1416 LineFeedEntity( byte * pDst )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 "
". Return an updated pointer. 1427 CarriageReturnEntity( byte * pDst )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 CharEntity( byte * pDst, char ch )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 RawStartCData( byte * pDst )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 RawEndCData( byte * pDst )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 ValidateContentChars( string chars, string propertyName, bool allowOnlyWhitespace )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 XmlUtf8RawTextWriterIndent( Stream stream, XmlWriterSettings settings )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 WriteDocType( string name, string pubid, string sysid, string subset )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 WriteStartElement( string prefix, string localName, string ns )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 StartElementContent()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 OnRootElement(ConformanceLevel currentConformanceLevel)1601 internal override void OnRootElement(ConformanceLevel currentConformanceLevel) { 1602 // Just remember the current conformance level 1603 conformanceLevel = currentConformanceLevel; 1604 } 1605 WriteEndElement(string prefix, string localName, string ns)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 WriteFullEndElement(string prefix, string localName, string ns)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. WriteStartAttribute( string prefix, string localName, string ns )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 WriteCData( string text )1644 public override void WriteCData( string text ) { 1645 mixedContent = true; 1646 base.WriteCData( text ); 1647 } 1648 WriteComment( string text )1649 public override void WriteComment( string text ) { 1650 if ( !mixedContent && base.textPos != base.bufPos ) { 1651 WriteIndent(); 1652 } 1653 1654 base.WriteComment( text ); 1655 } 1656 WriteProcessingInstruction( string target, string text )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 WriteEntityRef( string name )1665 public override void WriteEntityRef( string name ) { 1666 mixedContent = true; 1667 base.WriteEntityRef( name ); 1668 } 1669 WriteCharEntity( char ch )1670 public override void WriteCharEntity( char ch ) { 1671 mixedContent = true; 1672 base.WriteCharEntity( ch ); 1673 } 1674 WriteSurrogateCharEntity( char lowChar, char highChar )1675 public override void WriteSurrogateCharEntity( char lowChar, char highChar ) { 1676 mixedContent = true; 1677 base.WriteSurrogateCharEntity( lowChar, highChar ); 1678 } 1679 WriteWhitespace( string ws )1680 public override void WriteWhitespace( string ws ) { 1681 mixedContent = true; 1682 base.WriteWhitespace( ws ); 1683 } 1684 WriteString( string text )1685 public override void WriteString( string text ) { 1686 mixedContent = true; 1687 base.WriteString( text ); 1688 } 1689 WriteChars( char[] buffer, int index, int count )1690 public override void WriteChars( char[] buffer, int index, int count ) { 1691 mixedContent = true; 1692 base.WriteChars( buffer, index, count ); 1693 } 1694 WriteRaw( char[] buffer, int index, int count )1695 public override void WriteRaw( char[] buffer, int index, int count ) { 1696 mixedContent = true; 1697 base.WriteRaw( buffer, index, count ); 1698 } 1699 WriteRaw( string data )1700 public override void WriteRaw( string data ) { 1701 mixedContent = true; 1702 base.WriteRaw( data ); 1703 } 1704 WriteBase64( byte[] buffer, int index, int count )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 // Init( XmlWriterSettings settings )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. WriteIndent()1735 private void WriteIndent() { 1736 RawText( base.newLineChars ); 1737 for ( int i = indentLevel; i > 0; i-- ) { 1738 RawText( indentChars ); 1739 } 1740 } 1741 } 1742 } 1743 1744