HtmlEncodedRawTextWriter.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / Xml / System / Xml / Core / HtmlEncodedRawTextWriter.cs / 1 / HtmlEncodedRawTextWriter.cs

                             
//------------------------------------------------------------------------------
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
//  
// [....]
//----------------------------------------------------------------------------- 
 
// WARNING: This file is generated and should not be modified directly.  Instead,
// modify XmlTextWriterGenerator.cxx and run gen.bat in the same directory. 
// This batch file will execute the following commands:
//
//   cl.exe /C /EP /D _XML_UTF8_TEXT_WRITER HtmlTextWriterGenerator.cxx > HtmlUtf8TextWriter.cs
//   cl.exe /C /EP /D _XML_ENCODED_TEXT_WRITER HtmlTextWriterGenerator.cxx > HtmlEncodedTextWriter.cs 
//
// Because these two implementations of XmlTextWriter are so similar, the C++ preprocessor 
// is used to generate each implementation from one template file, using macros and ifdefs. 

 



 

 
 

 



 

 
 

 



 

using System; 
using System.IO; 
using System.Text;
using System.Xml; 
using System.Xml.Schema;
//using System.Xml.Query;
using System.Diagnostics;
using MS.Internal.Xml; 

namespace System.Xml { 
 
    internal class HtmlEncodedRawTextWriter : XmlEncodedRawTextWriter {
// 
// Fields
//
        protected ByteStack         elementScope;
        protected ElementProperties currentElementProperties; 
        private AttributeProperties currentAttributeProperties;
 
        private bool    endsWithAmpersand; 
        private byte [] uriEscapingBuffer;
 
        // settings
        private string  mediaType;

// 
// Static fields
// 
        protected static TernaryTreeReadOnly elementPropertySearch; 
        protected static TernaryTreeReadOnly attributePropertySearch;
 
//
// Constants
//
        private const int StackIncrement = 10; 

// 
// Constructors 
//
 


        public HtmlEncodedRawTextWriter( TextWriter writer, XmlWriterSettings settings ) : base( writer, settings ) {
            Init( settings ); 
        }
 
 
        public HtmlEncodedRawTextWriter( Stream stream, Encoding encoding, XmlWriterSettings settings, bool closeOutput ) : base( stream, encoding, settings, closeOutput ) {
            Init( settings ); 
        }

//
// XmlRawWriter implementation 
//
        internal override void WriteXmlDeclaration( XmlStandalone standalone ) { 
            // Ignore xml declaration 
        }
 
        internal override void WriteXmlDeclaration( string xmldecl ) {
            // Ignore xml declaration
        }
 
        /// Html rules allow public ID without system ID and always output "html"
        public override void WriteDocType( string name, string pubid, string sysid, string subset ) { 
            Debug.Assert( name != null && name.Length > 0 ); 

            if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); } 

            RawText( "'; 
        }
 
        // For the HTML element, it should call this method with ns and prefix as String.Empty
        public override void WriteStartElement( string prefix, string localName, string ns ) {
            Debug.Assert( localName != null && localName.Length != 0 && prefix != null && ns != null );
 
            elementScope.Push( (byte)currentElementProperties );
 
            if ( ns.Length == 0 ) { 
                Debug.Assert( prefix.Length == 0 );
 
                if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); }
                currentElementProperties = (ElementProperties)elementPropertySearch.FindCaseInsensitiveString( localName );
                base.bufChars[bufPos++] = (char) '<';
                base.RawText( localName ); 
                base.attrEndPos = bufPos;
            } 
            else { 
                // Since the HAS_NS has no impact to the ElementTextBlock behavior,
                // we don't need to push it into the stack. 
                currentElementProperties = ElementProperties.HAS_NS;
                base.WriteStartElement( prefix, localName, ns );
            }
        } 

        // Output >. For HTML needs to output META info 
        internal override void StartElementContent() { 
            base.bufChars[base.bufPos++] = (char) '>';
 
            // Detect whether content is output
            this.contentPos = this.bufPos;

            if ( ( currentElementProperties & ElementProperties.HEAD ) != 0 ) { 
                WriteMetaElement();
            } 
        } 

        // end element with /> 
        // for HTML(ns.Length == 0)
        //    not an empty tag 

// empty tag internal override void WriteEndElement( string prefix, string localName, string ns ) { if ( ns.Length == 0 ) { Debug.Assert( prefix.Length == 0 ); if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); } if ( ( currentElementProperties & ElementProperties.EMPTY ) == 0 ) { bufChars[base.bufPos++] = (char) '<'; bufChars[base.bufPos++] = (char) '/'; base.RawText( localName ); bufChars[base.bufPos++] = (char) '>'; } } else { //xml content base.WriteEndElement( prefix, localName, ns ); } currentElementProperties = (ElementProperties)elementScope.Pop(); } internal override void WriteFullEndElement( string prefix, string localName, string ns ) { if ( ns.Length == 0 ) { Debug.Assert( prefix.Length == 0 ); if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); } if ( ( currentElementProperties & ElementProperties.EMPTY ) == 0 ) { bufChars[base.bufPos++] = (char) '<'; bufChars[base.bufPos++] = (char) '/'; base.RawText( localName ); bufChars[base.bufPos++] = (char) '>'; } } else { //xml content base.WriteFullEndElement( prefix, localName, ns ); } currentElementProperties = (ElementProperties)elementScope.Pop(); } // 1. How the outputBooleanAttribute(fBOOL) and outputHtmlUriText(fURI) being set? // When SA is called. // // BOOL_PARENT URI_PARENT Others // fURI // URI att false true false // // fBOOL // BOOL att true false false // // How they change the attribute output behaviors? // // 1) fURI=true fURI=false // SA a=" a=" // AT HtmlURIText HtmlText // EA " " // // 2) fBOOL=true fBOOL=false // SA a a=" // AT HtmlText output nothing // EA output nothing " // // When they get reset? // At the end of attribute. // 2. How the outputXmlTextElementScoped(fENs) and outputXmlTextattributeScoped(fANs) are set? // fANs is in the scope of the fENs. // // SE(localName) SE(ns, pre, localName) SA(localName) SA(ns, pre, localName) // fENs false(default) true(action) // fANs false(default) false(default) false(default) true(action) // how they get reset? // // EE(localName) EE(ns, pre, localName) EENC(ns, pre, localName) EA(localName) EA(ns, pre, localName) // fENs false(action) // fANs false(action) // How they change the TextOutput? // // fENs | fANs Else // AT XmlText HtmlText // // // 3. Flags for processing &{ split situations // // When the flag is set? // // AT src[lastchar]='&' flag&{ = true; // // when it get result? // // AT method. // // How it changes the behaviors? // // flag&{=true // // AT if (src[0] == '{') { // output "&{" // } // else { // output & // } // // EA output amp; // // SA if (flagBOOL == false) { output =";} // // AT if (flagBOOL) { return}; // if (flagNS) {XmlText;} { // } // else if (flagURI) { // HtmlURIText; // } // else { // HtmlText; // } // // AT if (flagNS) {XmlText;} { // } // else if (flagURI) { // HtmlURIText; // } // else if (!flagBOOL) { // HtmlText; //flag&{ handling // } // // // EA if (flagBOOL == false) { output " // } // else if (flag&{) { // output amp; // } // public override void WriteStartAttribute( string prefix, string localName, string ns ) { Debug.Assert( localName != null && localName.Length != 0 && prefix != null && ns != null ); if ( ns.Length == 0 ) { Debug.Assert( prefix.Length == 0 ); if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); } if ( base.attrEndPos == bufPos ) { base.bufChars[bufPos++] = (char) ' '; } base.RawText( localName ); if ( ( currentElementProperties & ( ElementProperties.BOOL_PARENT | ElementProperties.URI_PARENT | ElementProperties.NAME_PARENT ) ) != 0 ) { currentAttributeProperties = (AttributeProperties)attributePropertySearch.FindCaseInsensitiveString( localName ) & (AttributeProperties)currentElementProperties; if ( ( currentAttributeProperties & AttributeProperties.BOOLEAN ) != 0 ) { base.inAttributeValue = true; return; } } else { currentAttributeProperties = AttributeProperties.DEFAULT; } base.bufChars[bufPos++] = (char) '='; base.bufChars[bufPos++] = (char) '"'; } else { base.WriteStartAttribute( prefix, localName, ns ); currentAttributeProperties = AttributeProperties.DEFAULT; } base.inAttributeValue = true; } // Output the amp; at end of EndAttribute public override void WriteEndAttribute() { if ( ( currentAttributeProperties & AttributeProperties.BOOLEAN ) != 0 ) { base.attrEndPos = bufPos; } else { if ( endsWithAmpersand ) { OutputRestAmps(); endsWithAmpersand = false; } if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); } base.bufChars[bufPos++] = (char) '"'; } base.inAttributeValue = false; base.attrEndPos = bufPos; } // HTML PI's use ">" to terminate rather than "?>". public override void WriteProcessingInstruction( string target, string text ) { Debug.Assert( target != null && target.Length != 0 && text != null ); if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); } bufChars[base.bufPos++] = (char) '<'; bufChars[base.bufPos++] = (char) '?'; base.RawText( target ); bufChars[base.bufPos++] = (char) ' '; base.WriteCommentOrPi( text, '?' ); base.bufChars[base.bufPos++] = (char) '>'; if ( base.bufPos > base.bufLen ) { FlushBuffer(); } } // Serialize either attribute or element text using HTML rules. public override unsafe void WriteString( string text ) { Debug.Assert( text != null ); if ( trackTextContent && inTextContent != true ) { ChangeTextContentMark( true ); } fixed ( char * pSrc = text ) { char * pSrcEnd = pSrc + text.Length; if ( base.inAttributeValue) { WriteHtmlAttributeTextBlock( pSrc, pSrcEnd ); } else { WriteHtmlElementTextBlock( pSrc, pSrcEnd ); } } } public override void WriteEntityRef( string name ) { throw new InvalidOperationException( Res.GetString( Res.Xml_InvalidOperation ) ); } public override void WriteCharEntity( char ch ) { throw new InvalidOperationException( Res.GetString( Res.Xml_InvalidOperation ) ); } public override void WriteSurrogateCharEntity( char lowChar, char highChar ) { throw new InvalidOperationException( Res.GetString( Res.Xml_InvalidOperation ) ); } public override unsafe void WriteChars( char[] buffer, int index, int count ) { Debug.Assert( buffer != null ); Debug.Assert( index >= 0 ); Debug.Assert( count >= 0 && index + count <= buffer.Length ); if ( trackTextContent && inTextContent != true ) { ChangeTextContentMark( true ); } fixed ( char * pSrcBegin = &buffer[index] ) { if ( inAttributeValue ) { WriteAttributeTextBlock( pSrcBegin, pSrcBegin + count ); } else { WriteElementTextBlock( pSrcBegin, pSrcBegin + count ); } } } // // Private methods // private void Init( XmlWriterSettings settings ) { Debug.Assert( (int)ElementProperties.URI_PARENT == (int)AttributeProperties.URI ); Debug.Assert( (int)ElementProperties.BOOL_PARENT == (int)AttributeProperties.BOOLEAN ); Debug.Assert( (int)ElementProperties.NAME_PARENT == (int)AttributeProperties.NAME ); if ( elementPropertySearch == null ) { //elementPropertySearch should be init last for the mutli thread safe situation. attributePropertySearch = new TernaryTreeReadOnly(HtmlTernaryTree.htmlAttributes ); elementPropertySearch = new TernaryTreeReadOnly( HtmlTernaryTree.htmlElements ); } elementScope = new ByteStack( StackIncrement ); uriEscapingBuffer = new byte[5]; currentElementProperties = ElementProperties.DEFAULT; mediaType = settings.MediaType; } protected void WriteMetaElement() { base.RawText("" ); } // Justify the stack usage: // // Nested elements has following possible position combinations // 1. Content1Content2 // 2. Content2Content1 // 3. ContentCotent2Content1 // // In the situation 2 and 3, the stored currentElementProrperties will be E2's, // only the top of the stack is the real E1 element properties. protected unsafe void WriteHtmlElementTextBlock( char * pSrc, char * pSrcEnd ) { if ( ( currentElementProperties & ElementProperties.NO_ENTITIES ) != 0 ) { base.RawText( pSrc, pSrcEnd ); } else { base.WriteElementTextBlock( pSrc, pSrcEnd ); } } protected unsafe void WriteHtmlAttributeTextBlock( char * pSrc, char * pSrcEnd ) { if ( ( currentAttributeProperties & ( AttributeProperties.BOOLEAN | AttributeProperties.URI | AttributeProperties.NAME ) ) != 0 ) { if ( ( currentAttributeProperties & AttributeProperties.BOOLEAN ) != 0 ) { //if output boolean attribute, ignore this call. return; } if ( ( currentAttributeProperties & ( AttributeProperties.URI | AttributeProperties.NAME ) ) != 0 ) { WriteUriAttributeText( pSrc, pSrcEnd ); } else { WriteHtmlAttributeText( pSrc, pSrcEnd ); } } else if ( ( currentElementProperties & ElementProperties.HAS_NS ) != 0 ) { base.WriteAttributeTextBlock( pSrc, pSrcEnd ); } else { WriteHtmlAttributeText( pSrc, pSrcEnd ); } } // // &{ split cases // 1). HtmlAttributeText("a&"); // HtmlAttributeText("{b}"); // // 2). HtmlAttributeText("a&"); // EndAttribute(); // 3).split with Flush by the user // HtmlAttributeText("a&"); // FlushBuffer(); // HtmlAttributeText("{b}"); // // Solutions: // case 1)hold the & output as & // if the next income character is {, output { // else output amp; // private unsafe void WriteHtmlAttributeText( char * pSrc, char *pSrcEnd ) { if ( endsWithAmpersand ) { if ( pSrcEnd - pSrc > 0 && pSrc[0] != '{' ) { OutputRestAmps(); } endsWithAmpersand = false; } fixed ( char * pDstBegin = bufChars ) { char * pDst = pDstBegin + this.bufPos; char ch = (char)0; for (;;) { char * pDstEnd = pDst + ( pSrcEnd - pSrc ); if ( pDstEnd > pDstBegin + bufLen ) { pDstEnd = pDstBegin + bufLen; } while ( pDst < pDstEnd && ( ( ( xmlCharType.charProperties[( ch = *pSrc )] & XmlCharType.fAttrValue ) != 0 ) ) ) { *pDst++ = (char)ch; pSrc++; } Debug.Assert( pSrc <= pSrcEnd ); // end of value if ( pSrc >= pSrcEnd ) { break; } // end of buffer if ( pDst >= pDstEnd ) { bufPos = (int)(pDst - pDstBegin); FlushBuffer(); pDst = pDstBegin + 1; continue; } // some character needs to be escaped switch ( ch ) { case '&': if ( pSrc + 1 == pSrcEnd ) { endsWithAmpersand = true; } else if ( pSrc[1] != '{' ) { pDst = XmlEncodedRawTextWriter.AmpEntity(pDst); break; } *pDst++ = (char)ch; break; case '"': pDst = QuoteEntity( pDst ); break; case '<': case '>': case '\'': case (char)0x9: *pDst++ = (char)ch; break; case (char)0xD: // do not normalize new lines in attributes - just escape them pDst = CarriageReturnEntity( pDst ); break; case (char)0xA: // do not normalize new lines in attributes - just escape them pDst = LineFeedEntity( pDst ); break; default: EncodeChar( ref pSrc, pSrcEnd, ref pDst); continue; } pSrc++; } bufPos = (int)(pDst - pDstBegin); } } private unsafe void WriteUriAttributeText( char * pSrc, char * pSrcEnd ) { if ( endsWithAmpersand ) { if ( pSrcEnd - pSrc > 0 && pSrc[0] != '{' ) { OutputRestAmps(); } this.endsWithAmpersand = false; } fixed ( char * pDstBegin = bufChars ) { char * pDst = pDstBegin + this.bufPos; char ch = (char)0; for (;;) { char * pDstEnd = pDst + ( pSrcEnd - pSrc ); if ( pDstEnd > pDstBegin + bufLen ) { pDstEnd = pDstBegin + bufLen; } while ( pDst < pDstEnd && ( ( ( xmlCharType.charProperties[( ch = *pSrc )] & XmlCharType.fAttrValue ) != 0 ) && ch < 0x80 ) ) { *pDst++ = (char)ch; pSrc++; } Debug.Assert( pSrc <= pSrcEnd ); // end of value if ( pSrc >= pSrcEnd ) { break; } // end of buffer if ( pDst >= pDstEnd ) { bufPos = (int)(pDst - pDstBegin); FlushBuffer(); pDst = pDstBegin + 1; continue; } // some character needs to be escaped switch ( ch ) { case '&': if ( pSrc + 1 == pSrcEnd ) { endsWithAmpersand = true; } else if ( pSrc[1] != '{' ) { pDst = XmlEncodedRawTextWriter.AmpEntity(pDst); break; } *pDst++ = (char)ch; break; case '"': pDst = QuoteEntity( pDst ); break; case '<': case '>': case '\'': case (char)0x9: *pDst++ = (char)ch; break; case (char)0xD: // do not normalize new lines in attributes - just escape them pDst = CarriageReturnEntity( pDst ); break; case (char)0xA: // do not normalize new lines in attributes - just escape them pDst = LineFeedEntity( pDst ); break; default: const string hexDigits = "0123456789ABCDEF"; fixed ( byte * pUriEscapingBuffer = uriEscapingBuffer ) { byte * pByte = pUriEscapingBuffer; byte * pEnd = pByte; XmlUtf8RawTextWriter.CharToUTF8( ref pSrc, pSrcEnd, ref pEnd ); while ( pByte < pEnd ) { *pDst++ = (char) '%'; *pDst++ = (char) hexDigits[*pByte >> 4]; *pDst++ = (char) hexDigits[*pByte & 0xF]; pByte++; } } continue; } pSrc++; } bufPos = (int)(pDst - pDstBegin); } } // For handling &{ in Html text field. If & is not followed by {, it still needs to be escaped. private void OutputRestAmps() { base.bufChars[bufPos++] = (char)'a'; base.bufChars[bufPos++] = (char)'m'; base.bufChars[bufPos++] = (char)'p'; base.bufChars[bufPos++] = (char)';'; } } // // Indentation HtmlWriter only indent situations // // Here are all the cases: // ELEMENT1 actions ELEMENT2 actions SC EE // 1). SE SC store SE blockPro SE a). check ELEMENT1 blockPro // EE if SE, EE are blocks b). true: check ELEMENT2 blockPro // c). detect ELEMENT is SE, SC // d). increase the indexlevel // // 2). SE SC, Store EE blockPro EE a). check stored blockPro // EE if SE, EE are blocks b). true: indexLevel same // // // This is an alternative way to make the output looks better // // Indentation HtmlWriter only indent situations // // Here are all the cases: // ELEMENT1 actions ELEMENT2 actions Samples // 1). SE SC store SE blockPro SE a). check ELEMENT1 blockPro (blockPos) // b). true: check ELEMENT2 blockPro // c). detect ELEMENT is SE, SC // d). increase the indentLevel // // 2). EE Store EE blockPro SE a). check stored blockPro // b). true: indentLevel same // c). output block2 // // 3). EE same as above EE a). check stored blockPro // b). true: --indentLevel // c). output block2 // // 4). SE SC same as above EE a). check stored blockPro // b). true: indentLevel no change internal class HtmlEncodedRawTextWriterIndent : HtmlEncodedRawTextWriter { // // Fields // int indentLevel; // for detecting SE SC sitution int endBlockPos; // settings string indentChars; bool newLineOnAttributes; // // Constructors // public HtmlEncodedRawTextWriterIndent( TextWriter writer, XmlWriterSettings settings ) : base( writer, settings ) { Init( settings ); } public HtmlEncodedRawTextWriterIndent( Stream stream, Encoding encoding, XmlWriterSettings settings, bool closeOutput ) : base( stream, encoding, settings, closeOutput ) { Init( settings ); } // // XmlRawWriter overrides // /// /// Serialize the document type declaration. /// public override void WriteDocType( string name, string pubid, string sysid, string subset ) { base.WriteDocType( name, pubid, sysid, subset ); // Allow indentation after DocTypeDecl endBlockPos = base.bufPos; } public override void WriteStartElement(string prefix, string localName, string ns ) { Debug.Assert( localName != null && localName.Length != 0 && prefix != null && ns != null ); if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); } base.elementScope.Push( (byte)base.currentElementProperties ); if ( ns.Length == 0 ) { Debug.Assert( prefix.Length == 0 ); base.currentElementProperties = (ElementProperties)elementPropertySearch.FindCaseInsensitiveString( localName ); if ( endBlockPos == base.bufPos && ( base.currentElementProperties & ElementProperties.BLOCK_WS ) != 0 ) { WriteIndent(); } indentLevel++; base.bufChars[bufPos++] = (char) '<'; } else { base.currentElementProperties = ElementProperties.HAS_NS | ElementProperties.BLOCK_WS; if ( endBlockPos == base.bufPos ) { WriteIndent(); } indentLevel++; base.bufChars[base.bufPos++] = (char) '<'; if ( prefix.Length != 0 ) { base.RawText( prefix ); base.bufChars[base.bufPos++] = (char) ':'; } } base.RawText( localName ); base.attrEndPos = bufPos; } internal override void StartElementContent() { base.bufChars[base.bufPos++] = (char) '>'; // Detect whether content is output base.contentPos = base.bufPos; if ( ( currentElementProperties & ElementProperties.HEAD ) != 0) { WriteIndent(); WriteMetaElement(); endBlockPos = base.bufPos; } else if ( ( base.currentElementProperties & ElementProperties.BLOCK_WS ) != 0 ) { // store the element block position endBlockPos = base.bufPos; } } internal override void WriteEndElement( string prefix, string localName, string ns ) { bool isBlockWs; Debug.Assert( localName != null && localName.Length != 0 && prefix != null && ns != null ); indentLevel--; // If this element has block whitespace properties, isBlockWs = ( base.currentElementProperties & ElementProperties.BLOCK_WS ) != 0; if ( isBlockWs ) { // And if the last node to be output had block whitespace properties, // And if content was output within this element, if ( endBlockPos == base.bufPos && base.contentPos != base.bufPos ) { // Then indent WriteIndent(); } } base.WriteEndElement(prefix, localName, ns); // Reset contentPos in case of empty elements base.contentPos = 0; // Mark end of element in buffer for element's with block whitespace properties if ( isBlockWs ) { endBlockPos = base.bufPos; } } public override void WriteStartAttribute( string prefix, string localName, string ns ) { if ( newLineOnAttributes ) { RawText( base.newLineChars ); indentLevel++; WriteIndent(); indentLevel--; } base.WriteStartAttribute( prefix, localName, ns ); } protected override void FlushBuffer() { // Make sure the buffer will reset the block position endBlockPos = ( endBlockPos == base.bufPos ) ? 1 : 0; base.FlushBuffer(); } // // Private methods // private void Init( XmlWriterSettings settings ) { indentLevel = 0; indentChars = settings.IndentChars; newLineOnAttributes = settings.NewLineOnAttributes; } private void WriteIndent() { // -- suppress ws betw and // -- don't suppress ws betw and // text -- suppress ws betw and text (handled by wcharText method) // -- suppress ws betw and PI // -- suppress ws betw and comment // -- suppress ws betw and // -- suppress ws betw and // text -- suppress ws betw and text (handled by wcharText method) // -- suppress ws betw and PI // -- suppress ws betw and comment RawText( base.newLineChars ); for ( int i = indentLevel; i > 0; i-- ) { RawText( indentChars ); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // // [....] //----------------------------------------------------------------------------- // WARNING: This file is generated and should not be modified directly. Instead, // modify XmlTextWriterGenerator.cxx and run gen.bat in the same directory. // This batch file will execute the following commands: // // cl.exe /C /EP /D _XML_UTF8_TEXT_WRITER HtmlTextWriterGenerator.cxx > HtmlUtf8TextWriter.cs // cl.exe /C /EP /D _XML_ENCODED_TEXT_WRITER HtmlTextWriterGenerator.cxx > HtmlEncodedTextWriter.cs // // Because these two implementations of XmlTextWriter are so similar, the C++ preprocessor // is used to generate each implementation from one template file, using macros and ifdefs. using System; using System.IO; using System.Text; using System.Xml; using System.Xml.Schema; //using System.Xml.Query; using System.Diagnostics; using MS.Internal.Xml; namespace System.Xml { internal class HtmlEncodedRawTextWriter : XmlEncodedRawTextWriter { // // Fields // protected ByteStack elementScope; protected ElementProperties currentElementProperties; private AttributeProperties currentAttributeProperties; private bool endsWithAmpersand; private byte [] uriEscapingBuffer; // settings private string mediaType; // // Static fields // protected static TernaryTreeReadOnly elementPropertySearch; protected static TernaryTreeReadOnly attributePropertySearch; // // Constants // private const int StackIncrement = 10; // // Constructors // public HtmlEncodedRawTextWriter( TextWriter writer, XmlWriterSettings settings ) : base( writer, settings ) { Init( settings ); } public HtmlEncodedRawTextWriter( Stream stream, Encoding encoding, XmlWriterSettings settings, bool closeOutput ) : base( stream, encoding, settings, closeOutput ) { Init( settings ); } // // XmlRawWriter implementation // internal override void WriteXmlDeclaration( XmlStandalone standalone ) { // Ignore xml declaration } internal override void WriteXmlDeclaration( string xmldecl ) { // Ignore xml declaration } /// Html rules allow public ID without system ID and always output "html" public override void WriteDocType( string name, string pubid, string sysid, string subset ) { Debug.Assert( name != null && name.Length > 0 ); if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); } RawText( "'; } // For the HTML element, it should call this method with ns and prefix as String.Empty public override void WriteStartElement( string prefix, string localName, string ns ) { Debug.Assert( localName != null && localName.Length != 0 && prefix != null && ns != null ); elementScope.Push( (byte)currentElementProperties ); if ( ns.Length == 0 ) { Debug.Assert( prefix.Length == 0 ); if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); } currentElementProperties = (ElementProperties)elementPropertySearch.FindCaseInsensitiveString( localName ); base.bufChars[bufPos++] = (char) '<'; base.RawText( localName ); base.attrEndPos = bufPos; } else { // Since the HAS_NS has no impact to the ElementTextBlock behavior, // we don't need to push it into the stack. currentElementProperties = ElementProperties.HAS_NS; base.WriteStartElement( prefix, localName, ns ); } } // Output >. For HTML needs to output META info internal override void StartElementContent() { base.bufChars[base.bufPos++] = (char) '>'; // Detect whether content is output this.contentPos = this.bufPos; if ( ( currentElementProperties & ElementProperties.HEAD ) != 0 ) { WriteMetaElement(); } } // end element with /> // for HTML(ns.Length == 0) // not an empty tag

// empty tag internal override void WriteEndElement( string prefix, string localName, string ns ) { if ( ns.Length == 0 ) { Debug.Assert( prefix.Length == 0 ); if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); } if ( ( currentElementProperties & ElementProperties.EMPTY ) == 0 ) { bufChars[base.bufPos++] = (char) '<'; bufChars[base.bufPos++] = (char) '/'; base.RawText( localName ); bufChars[base.bufPos++] = (char) '>'; } } else { //xml content base.WriteEndElement( prefix, localName, ns ); } currentElementProperties = (ElementProperties)elementScope.Pop(); } internal override void WriteFullEndElement( string prefix, string localName, string ns ) { if ( ns.Length == 0 ) { Debug.Assert( prefix.Length == 0 ); if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); } if ( ( currentElementProperties & ElementProperties.EMPTY ) == 0 ) { bufChars[base.bufPos++] = (char) '<'; bufChars[base.bufPos++] = (char) '/'; base.RawText( localName ); bufChars[base.bufPos++] = (char) '>'; } } else { //xml content base.WriteFullEndElement( prefix, localName, ns ); } currentElementProperties = (ElementProperties)elementScope.Pop(); } // 1. How the outputBooleanAttribute(fBOOL) and outputHtmlUriText(fURI) being set? // When SA is called. // // BOOL_PARENT URI_PARENT Others // fURI // URI att false true false // // fBOOL // BOOL att true false false // // How they change the attribute output behaviors? // // 1) fURI=true fURI=false // SA a=" a=" // AT HtmlURIText HtmlText // EA " " // // 2) fBOOL=true fBOOL=false // SA a a=" // AT HtmlText output nothing // EA output nothing " // // When they get reset? // At the end of attribute. // 2. How the outputXmlTextElementScoped(fENs) and outputXmlTextattributeScoped(fANs) are set? // fANs is in the scope of the fENs. // // SE(localName) SE(ns, pre, localName) SA(localName) SA(ns, pre, localName) // fENs false(default) true(action) // fANs false(default) false(default) false(default) true(action) // how they get reset? // // EE(localName) EE(ns, pre, localName) EENC(ns, pre, localName) EA(localName) EA(ns, pre, localName) // fENs false(action) // fANs false(action) // How they change the TextOutput? // // fENs | fANs Else // AT XmlText HtmlText // // // 3. Flags for processing &{ split situations // // When the flag is set? // // AT src[lastchar]='&' flag&{ = true; // // when it get result? // // AT method. // // How it changes the behaviors? // // flag&{=true // // AT if (src[0] == '{') { // output "&{" // } // else { // output & // } // // EA output amp; // // SA if (flagBOOL == false) { output =";} // // AT if (flagBOOL) { return}; // if (flagNS) {XmlText;} { // } // else if (flagURI) { // HtmlURIText; // } // else { // HtmlText; // } // // AT if (flagNS) {XmlText;} { // } // else if (flagURI) { // HtmlURIText; // } // else if (!flagBOOL) { // HtmlText; //flag&{ handling // } // // // EA if (flagBOOL == false) { output " // } // else if (flag&{) { // output amp; // } // public override void WriteStartAttribute( string prefix, string localName, string ns ) { Debug.Assert( localName != null && localName.Length != 0 && prefix != null && ns != null ); if ( ns.Length == 0 ) { Debug.Assert( prefix.Length == 0 ); if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); } if ( base.attrEndPos == bufPos ) { base.bufChars[bufPos++] = (char) ' '; } base.RawText( localName ); if ( ( currentElementProperties & ( ElementProperties.BOOL_PARENT | ElementProperties.URI_PARENT | ElementProperties.NAME_PARENT ) ) != 0 ) { currentAttributeProperties = (AttributeProperties)attributePropertySearch.FindCaseInsensitiveString( localName ) & (AttributeProperties)currentElementProperties; if ( ( currentAttributeProperties & AttributeProperties.BOOLEAN ) != 0 ) { base.inAttributeValue = true; return; } } else { currentAttributeProperties = AttributeProperties.DEFAULT; } base.bufChars[bufPos++] = (char) '='; base.bufChars[bufPos++] = (char) '"'; } else { base.WriteStartAttribute( prefix, localName, ns ); currentAttributeProperties = AttributeProperties.DEFAULT; } base.inAttributeValue = true; } // Output the amp; at end of EndAttribute public override void WriteEndAttribute() { if ( ( currentAttributeProperties & AttributeProperties.BOOLEAN ) != 0 ) { base.attrEndPos = bufPos; } else { if ( endsWithAmpersand ) { OutputRestAmps(); endsWithAmpersand = false; } if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); } base.bufChars[bufPos++] = (char) '"'; } base.inAttributeValue = false; base.attrEndPos = bufPos; } // HTML PI's use ">" to terminate rather than "?>". public override void WriteProcessingInstruction( string target, string text ) { Debug.Assert( target != null && target.Length != 0 && text != null ); if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); } bufChars[base.bufPos++] = (char) '<'; bufChars[base.bufPos++] = (char) '?'; base.RawText( target ); bufChars[base.bufPos++] = (char) ' '; base.WriteCommentOrPi( text, '?' ); base.bufChars[base.bufPos++] = (char) '>'; if ( base.bufPos > base.bufLen ) { FlushBuffer(); } } // Serialize either attribute or element text using HTML rules. public override unsafe void WriteString( string text ) { Debug.Assert( text != null ); if ( trackTextContent && inTextContent != true ) { ChangeTextContentMark( true ); } fixed ( char * pSrc = text ) { char * pSrcEnd = pSrc + text.Length; if ( base.inAttributeValue) { WriteHtmlAttributeTextBlock( pSrc, pSrcEnd ); } else { WriteHtmlElementTextBlock( pSrc, pSrcEnd ); } } } public override void WriteEntityRef( string name ) { throw new InvalidOperationException( Res.GetString( Res.Xml_InvalidOperation ) ); } public override void WriteCharEntity( char ch ) { throw new InvalidOperationException( Res.GetString( Res.Xml_InvalidOperation ) ); } public override void WriteSurrogateCharEntity( char lowChar, char highChar ) { throw new InvalidOperationException( Res.GetString( Res.Xml_InvalidOperation ) ); } public override unsafe void WriteChars( char[] buffer, int index, int count ) { Debug.Assert( buffer != null ); Debug.Assert( index >= 0 ); Debug.Assert( count >= 0 && index + count <= buffer.Length ); if ( trackTextContent && inTextContent != true ) { ChangeTextContentMark( true ); } fixed ( char * pSrcBegin = &buffer[index] ) { if ( inAttributeValue ) { WriteAttributeTextBlock( pSrcBegin, pSrcBegin + count ); } else { WriteElementTextBlock( pSrcBegin, pSrcBegin + count ); } } } // // Private methods // private void Init( XmlWriterSettings settings ) { Debug.Assert( (int)ElementProperties.URI_PARENT == (int)AttributeProperties.URI ); Debug.Assert( (int)ElementProperties.BOOL_PARENT == (int)AttributeProperties.BOOLEAN ); Debug.Assert( (int)ElementProperties.NAME_PARENT == (int)AttributeProperties.NAME ); if ( elementPropertySearch == null ) { //elementPropertySearch should be init last for the mutli thread safe situation. attributePropertySearch = new TernaryTreeReadOnly(HtmlTernaryTree.htmlAttributes ); elementPropertySearch = new TernaryTreeReadOnly( HtmlTernaryTree.htmlElements ); } elementScope = new ByteStack( StackIncrement ); uriEscapingBuffer = new byte[5]; currentElementProperties = ElementProperties.DEFAULT; mediaType = settings.MediaType; } protected void WriteMetaElement() { base.RawText("" ); } // Justify the stack usage: // // Nested elements has following possible position combinations // 1. Content1Content2 // 2. Content2Content1 // 3. ContentCotent2Content1 // // In the situation 2 and 3, the stored currentElementProrperties will be E2's, // only the top of the stack is the real E1 element properties. protected unsafe void WriteHtmlElementTextBlock( char * pSrc, char * pSrcEnd ) { if ( ( currentElementProperties & ElementProperties.NO_ENTITIES ) != 0 ) { base.RawText( pSrc, pSrcEnd ); } else { base.WriteElementTextBlock( pSrc, pSrcEnd ); } } protected unsafe void WriteHtmlAttributeTextBlock( char * pSrc, char * pSrcEnd ) { if ( ( currentAttributeProperties & ( AttributeProperties.BOOLEAN | AttributeProperties.URI | AttributeProperties.NAME ) ) != 0 ) { if ( ( currentAttributeProperties & AttributeProperties.BOOLEAN ) != 0 ) { //if output boolean attribute, ignore this call. return; } if ( ( currentAttributeProperties & ( AttributeProperties.URI | AttributeProperties.NAME ) ) != 0 ) { WriteUriAttributeText( pSrc, pSrcEnd ); } else { WriteHtmlAttributeText( pSrc, pSrcEnd ); } } else if ( ( currentElementProperties & ElementProperties.HAS_NS ) != 0 ) { base.WriteAttributeTextBlock( pSrc, pSrcEnd ); } else { WriteHtmlAttributeText( pSrc, pSrcEnd ); } } // // &{ split cases // 1). HtmlAttributeText("a&"); // HtmlAttributeText("{b}"); // // 2). HtmlAttributeText("a&"); // EndAttribute(); // 3).split with Flush by the user // HtmlAttributeText("a&"); // FlushBuffer(); // HtmlAttributeText("{b}"); // // Solutions: // case 1)hold the & output as & // if the next income character is {, output { // else output amp; // private unsafe void WriteHtmlAttributeText( char * pSrc, char *pSrcEnd ) { if ( endsWithAmpersand ) { if ( pSrcEnd - pSrc > 0 && pSrc[0] != '{' ) { OutputRestAmps(); } endsWithAmpersand = false; } fixed ( char * pDstBegin = bufChars ) { char * pDst = pDstBegin + this.bufPos; char ch = (char)0; for (;;) { char * pDstEnd = pDst + ( pSrcEnd - pSrc ); if ( pDstEnd > pDstBegin + bufLen ) { pDstEnd = pDstBegin + bufLen; } while ( pDst < pDstEnd && ( ( ( xmlCharType.charProperties[( ch = *pSrc )] & XmlCharType.fAttrValue ) != 0 ) ) ) { *pDst++ = (char)ch; pSrc++; } Debug.Assert( pSrc <= pSrcEnd ); // end of value if ( pSrc >= pSrcEnd ) { break; } // end of buffer if ( pDst >= pDstEnd ) { bufPos = (int)(pDst - pDstBegin); FlushBuffer(); pDst = pDstBegin + 1; continue; } // some character needs to be escaped switch ( ch ) { case '&': if ( pSrc + 1 == pSrcEnd ) { endsWithAmpersand = true; } else if ( pSrc[1] != '{' ) { pDst = XmlEncodedRawTextWriter.AmpEntity(pDst); break; } *pDst++ = (char)ch; break; case '"': pDst = QuoteEntity( pDst ); break; case '<': case '>': case '\'': case (char)0x9: *pDst++ = (char)ch; break; case (char)0xD: // do not normalize new lines in attributes - just escape them pDst = CarriageReturnEntity( pDst ); break; case (char)0xA: // do not normalize new lines in attributes - just escape them pDst = LineFeedEntity( pDst ); break; default: EncodeChar( ref pSrc, pSrcEnd, ref pDst); continue; } pSrc++; } bufPos = (int)(pDst - pDstBegin); } } private unsafe void WriteUriAttributeText( char * pSrc, char * pSrcEnd ) { if ( endsWithAmpersand ) { if ( pSrcEnd - pSrc > 0 && pSrc[0] != '{' ) { OutputRestAmps(); } this.endsWithAmpersand = false; } fixed ( char * pDstBegin = bufChars ) { char * pDst = pDstBegin + this.bufPos; char ch = (char)0; for (;;) { char * pDstEnd = pDst + ( pSrcEnd - pSrc ); if ( pDstEnd > pDstBegin + bufLen ) { pDstEnd = pDstBegin + bufLen; } while ( pDst < pDstEnd && ( ( ( xmlCharType.charProperties[( ch = *pSrc )] & XmlCharType.fAttrValue ) != 0 ) && ch < 0x80 ) ) { *pDst++ = (char)ch; pSrc++; } Debug.Assert( pSrc <= pSrcEnd ); // end of value if ( pSrc >= pSrcEnd ) { break; } // end of buffer if ( pDst >= pDstEnd ) { bufPos = (int)(pDst - pDstBegin); FlushBuffer(); pDst = pDstBegin + 1; continue; } // some character needs to be escaped switch ( ch ) { case '&': if ( pSrc + 1 == pSrcEnd ) { endsWithAmpersand = true; } else if ( pSrc[1] != '{' ) { pDst = XmlEncodedRawTextWriter.AmpEntity(pDst); break; } *pDst++ = (char)ch; break; case '"': pDst = QuoteEntity( pDst ); break; case '<': case '>': case '\'': case (char)0x9: *pDst++ = (char)ch; break; case (char)0xD: // do not normalize new lines in attributes - just escape them pDst = CarriageReturnEntity( pDst ); break; case (char)0xA: // do not normalize new lines in attributes - just escape them pDst = LineFeedEntity( pDst ); break; default: const string hexDigits = "0123456789ABCDEF"; fixed ( byte * pUriEscapingBuffer = uriEscapingBuffer ) { byte * pByte = pUriEscapingBuffer; byte * pEnd = pByte; XmlUtf8RawTextWriter.CharToUTF8( ref pSrc, pSrcEnd, ref pEnd ); while ( pByte < pEnd ) { *pDst++ = (char) '%'; *pDst++ = (char) hexDigits[*pByte >> 4]; *pDst++ = (char) hexDigits[*pByte & 0xF]; pByte++; } } continue; } pSrc++; } bufPos = (int)(pDst - pDstBegin); } } // For handling &{ in Html text field. If & is not followed by {, it still needs to be escaped. private void OutputRestAmps() { base.bufChars[bufPos++] = (char)'a'; base.bufChars[bufPos++] = (char)'m'; base.bufChars[bufPos++] = (char)'p'; base.bufChars[bufPos++] = (char)';'; } } // // Indentation HtmlWriter only indent situations // // Here are all the cases: // ELEMENT1 actions ELEMENT2 actions SC EE // 1). SE SC store SE blockPro SE a). check ELEMENT1 blockPro // EE if SE, EE are blocks b). true: check ELEMENT2 blockPro // c). detect ELEMENT is SE, SC // d). increase the indexlevel // // 2). SE SC, Store EE blockPro EE a). check stored blockPro // EE if SE, EE are blocks b). true: indexLevel same // // // This is an alternative way to make the output looks better // // Indentation HtmlWriter only indent situations // // Here are all the cases: // ELEMENT1 actions ELEMENT2 actions Samples // 1). SE SC store SE blockPro SE a). check ELEMENT1 blockPro (blockPos) // b). true: check ELEMENT2 blockPro // c). detect ELEMENT is SE, SC // d). increase the indentLevel // // 2). EE Store EE blockPro SE a). check stored blockPro // b). true: indentLevel same // c). output block2 // // 3). EE same as above EE a). check stored blockPro // b). true: --indentLevel // c). output block2 // // 4). SE SC same as above EE a). check stored blockPro // b). true: indentLevel no change internal class HtmlEncodedRawTextWriterIndent : HtmlEncodedRawTextWriter { // // Fields // int indentLevel; // for detecting SE SC sitution int endBlockPos; // settings string indentChars; bool newLineOnAttributes; // // Constructors // public HtmlEncodedRawTextWriterIndent( TextWriter writer, XmlWriterSettings settings ) : base( writer, settings ) { Init( settings ); } public HtmlEncodedRawTextWriterIndent( Stream stream, Encoding encoding, XmlWriterSettings settings, bool closeOutput ) : base( stream, encoding, settings, closeOutput ) { Init( settings ); } // // XmlRawWriter overrides // /// /// Serialize the document type declaration. /// public override void WriteDocType( string name, string pubid, string sysid, string subset ) { base.WriteDocType( name, pubid, sysid, subset ); // Allow indentation after DocTypeDecl endBlockPos = base.bufPos; } public override void WriteStartElement(string prefix, string localName, string ns ) { Debug.Assert( localName != null && localName.Length != 0 && prefix != null && ns != null ); if ( trackTextContent && inTextContent != false ) { ChangeTextContentMark( false ); } base.elementScope.Push( (byte)base.currentElementProperties ); if ( ns.Length == 0 ) { Debug.Assert( prefix.Length == 0 ); base.currentElementProperties = (ElementProperties)elementPropertySearch.FindCaseInsensitiveString( localName ); if ( endBlockPos == base.bufPos && ( base.currentElementProperties & ElementProperties.BLOCK_WS ) != 0 ) { WriteIndent(); } indentLevel++; base.bufChars[bufPos++] = (char) '<'; } else { base.currentElementProperties = ElementProperties.HAS_NS | ElementProperties.BLOCK_WS; if ( endBlockPos == base.bufPos ) { WriteIndent(); } indentLevel++; base.bufChars[base.bufPos++] = (char) '<'; if ( prefix.Length != 0 ) { base.RawText( prefix ); base.bufChars[base.bufPos++] = (char) ':'; } } base.RawText( localName ); base.attrEndPos = bufPos; } internal override void StartElementContent() { base.bufChars[base.bufPos++] = (char) '>'; // Detect whether content is output base.contentPos = base.bufPos; if ( ( currentElementProperties & ElementProperties.HEAD ) != 0) { WriteIndent(); WriteMetaElement(); endBlockPos = base.bufPos; } else if ( ( base.currentElementProperties & ElementProperties.BLOCK_WS ) != 0 ) { // store the element block position endBlockPos = base.bufPos; } } internal override void WriteEndElement( string prefix, string localName, string ns ) { bool isBlockWs; Debug.Assert( localName != null && localName.Length != 0 && prefix != null && ns != null ); indentLevel--; // If this element has block whitespace properties, isBlockWs = ( base.currentElementProperties & ElementProperties.BLOCK_WS ) != 0; if ( isBlockWs ) { // And if the last node to be output had block whitespace properties, // And if content was output within this element, if ( endBlockPos == base.bufPos && base.contentPos != base.bufPos ) { // Then indent WriteIndent(); } } base.WriteEndElement(prefix, localName, ns); // Reset contentPos in case of empty elements base.contentPos = 0; // Mark end of element in buffer for element's with block whitespace properties if ( isBlockWs ) { endBlockPos = base.bufPos; } } public override void WriteStartAttribute( string prefix, string localName, string ns ) { if ( newLineOnAttributes ) { RawText( base.newLineChars ); indentLevel++; WriteIndent(); indentLevel--; } base.WriteStartAttribute( prefix, localName, ns ); } protected override void FlushBuffer() { // Make sure the buffer will reset the block position endBlockPos = ( endBlockPos == base.bufPos ) ? 1 : 0; base.FlushBuffer(); } // // Private methods // private void Init( XmlWriterSettings settings ) { indentLevel = 0; indentChars = settings.IndentChars; newLineOnAttributes = settings.NewLineOnAttributes; } private void WriteIndent() { // -- suppress ws betw and // -- don't suppress ws betw and // text -- suppress ws betw and text (handled by wcharText method) // -- suppress ws betw and PI // -- suppress ws betw and comment // -- suppress ws betw and // -- suppress ws betw and // text -- suppress ws betw and text (handled by wcharText method) // -- suppress ws betw and PI // -- suppress ws betw and comment RawText( base.newLineChars ); for ( int i = indentLevel; i > 0; i-- ) { RawText( indentChars ); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK