The Labs \ Source Viewer \ SSCLI \ System.Xml \ XmlUtf8RawTextWriter

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

Developer Fusion