in src/dotnet-svcutil/lib/src/FrameworkFork/Microsoft.Xml/Xml/Core/XmlRawTextWriterGenerator.cxx [1184:1927]
protected unsafe void WriteCommentOrPi( string text, int stopChar ) {
if ( text.Length == 0 ) {
if ( bufPos >= bufLen ) {
FlushBuffer();
}
return;
}
// write text
fixed ( char * pSrcBegin = text )
fixed ( _BUFFER_TYPE * pDstBegin = _BUFFER ) {
char * pSrc = pSrcBegin;
char * pSrcEnd = pSrcBegin + text.Length;
_BUFFER_TYPE * pDst = pDstBegin + bufPos;
int ch = 0;
for (;;) {
_BUFFER_TYPE * pDstEnd = pDst + ( pSrcEnd - pSrc );
if ( pDstEnd > pDstBegin + bufLen ) {
pDstEnd = pDstBegin + bufLen;
}
#ifdef _XML_UTF8_TEXT_WRITER
while ( pDst < pDstEnd && ( XMLCHARTYPE_ISTEXT( ( ch = *pSrc ) ) && ch != stopChar && ch <= 0x7F ) ) {
#else
while ( pDst < pDstEnd && ( XMLCHARTYPE_ISTEXT( ( ch = *pSrc ) ) && ch != stopChar ) ) {
#endif
*pDst = (_BUFFER_TYPE)ch;
pDst++;
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;
}
// handle special characters
switch ( ch ) {
case '-':
*pDst = (_BUFFER_TYPE) '-';
pDst++;
if ( ch == stopChar ) {
// Insert space between adjacent dashes or before comment's end dashes
if ( pSrc + 1 == pSrcEnd || *(pSrc + 1)== '-' ) {
*pDst = (_BUFFER_TYPE) ' ';
pDst++;
}
}
break;
case '?':
*pDst = (_BUFFER_TYPE) '?';
pDst++;
if ( ch == stopChar ) {
// Processing instruction: insert space between adjacent '?' and '>'
if ( pSrc + 1 < pSrcEnd && *(pSrc + 1)== '>' ) {
*pDst = (_BUFFER_TYPE) ' ';
pDst++;
}
}
break;
case ']':
*pDst = (_BUFFER_TYPE) ']';
pDst++;
break;
case (char)0xD:
if ( newLineHandling == NewLineHandling.Replace ) {
// Normalize "\r\n", or "\r" to NewLineChars
if ( pSrc[1] == '\n' ) {
pSrc++;
}
pDst = WriteNewLine( pDst );
}
else {
*pDst = (_BUFFER_TYPE)ch;
pDst++;
}
break;
case (char)0xA:
if ( newLineHandling == NewLineHandling.Replace ) {
pDst = WriteNewLine( pDst );
}
else {
*pDst = (_BUFFER_TYPE)ch;
pDst++;
}
break;
case '<':
case '&':
case (char)0x9:
*pDst = (_BUFFER_TYPE)ch;
pDst++;
break;
default:
_ENCODE_CHAR(false);
continue;
}
pSrc++;
}
bufPos = (int)(pDst - pDstBegin);
}
}
protected unsafe void WriteCDataSection( string text ) {
if ( text.Length == 0 ) {
if ( bufPos >= bufLen ) {
FlushBuffer();
}
return;
}
// write text
fixed ( char * pSrcBegin = text )
fixed ( _BUFFER_TYPE * pDstBegin = _BUFFER ) {
char * pSrc = pSrcBegin;
char * pSrcEnd = pSrcBegin + text.Length;
_BUFFER_TYPE * pDst = pDstBegin + bufPos;
int ch = 0;
for (;;) {
_BUFFER_TYPE * pDstEnd = pDst + ( pSrcEnd - pSrc );
if ( pDstEnd > pDstBegin + bufLen ) {
pDstEnd = pDstBegin + bufLen;
}
#ifdef _XML_UTF8_TEXT_WRITER
while ( pDst < pDstEnd && ( XMLCHARTYPE_ISATTRIBUTEVALUECHAR( ( ch = *pSrc ) ) && ch != ']' && ch <= 0x7F ) ) {
#else
while ( pDst < pDstEnd && ( XMLCHARTYPE_ISATTRIBUTEVALUECHAR( ( ch = *pSrc ) ) && ch != ']' ) ) {
#endif
*pDst = (_BUFFER_TYPE)ch;
pDst++;
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;
}
// handle special characters
switch ( ch ) {
case '>':
if ( hadDoubleBracket && pDst[-1] == (_BUFFER_TYPE) ']') { // pDst[-1] will always correct - there is a padding character at _BUFFER[0]
// The characters "]]>" were found within the CData text
pDst = RawEndCData( pDst );
pDst = RawStartCData( pDst );
}
*pDst = (_BUFFER_TYPE) '>';
pDst++;
break;
case ']':
if ( pDst[-1] == (_BUFFER_TYPE)']' ) { // pDst[-1] will always correct - there is a padding character at _BUFFER[0]
hadDoubleBracket = true;
}
else {
hadDoubleBracket = false;
}
*pDst = (_BUFFER_TYPE)']';
pDst++;
break;
case (char)0xD:
if ( newLineHandling == NewLineHandling.Replace ) {
// Normalize "\r\n", or "\r" to NewLineChars
if ( pSrc[1] == '\n' ) {
pSrc++;
}
pDst = WriteNewLine( pDst );
}
else {
*pDst = (_BUFFER_TYPE)ch;
pDst++;
}
break;
case (char)0xA:
if ( newLineHandling == NewLineHandling.Replace ) {
pDst = WriteNewLine( pDst );
}
else {
*pDst = (_BUFFER_TYPE)ch;
pDst++;
}
break;
case '&':
case '<':
case '"':
case '\'':
case (char)0x9:
*pDst = (_BUFFER_TYPE)ch;
pDst++;
break;
default:
_ENCODE_CHAR(false);
continue;
}
pSrc++;
}
bufPos = (int)(pDst - pDstBegin);
}
}
#ifdef _XML_UTF8_TEXT_WRITER
// Returns true if UTF8 encoded byte is first of four bytes that encode a surrogate pair.
// To do this, detect the bit pattern 11110xxx.
private static bool IsSurrogateByte( byte b ) {
return (b & 0xF8) == 0xF0;
}
#endif
private static unsafe _BUFFER_TYPE* EncodeSurrogate( char* pSrc, char* pSrcEnd, _BUFFER_TYPE* pDst ) {
Debug.Assert( XmlCharType.IsSurrogate( *pSrc ) );
int ch = *pSrc;
if ( ch <= XmlCharType.SurHighEnd ) {
if ( pSrc + 1 < pSrcEnd ) {
int lowChar = pSrc[1];
if ( lowChar >= XmlCharType.SurLowStart ) {
#ifdef _XML_UTF8_TEXT_WRITER
// Calculate Unicode scalar value for easier manipulations (see section 3.7 in Unicode spec)
// The scalar value repositions surrogate values to start at 0x10000.
ch = XmlCharType.CombineSurrogateChar( lowChar, ch );
pDst[0] = (byte)( 0xF0 | ( ch >> 18 ) );
pDst[1] = (byte)( 0x80 | ( ch >> 12 ) & 0x3F );
pDst[2] = (byte)( 0x80 | ( ch >> 6 ) & 0x3F );
pDst[3] = (byte)( 0x80 | ch & 0x3F);
pDst += 4;
#else
pDst[0] = (char)ch;
pDst[1] = (char)lowChar;
pDst += 2;
#endif
return pDst;
}
throw XmlConvert.CreateInvalidSurrogatePairException( (char)lowChar, (char)ch );
}
throw new ArgumentException( Res.GetString( Res.Xml_InvalidSurrogateMissingLowChar ) );
}
throw XmlConvert.CreateInvalidHighSurrogateCharException( (char)ch );
}
private unsafe _BUFFER_TYPE* InvalidXmlChar( int ch, _BUFFER_TYPE* pDst, bool entitize ) {
Debug.Assert( !xmlCharType.IsWhiteSpace( (char)ch ) );
Debug.Assert( !xmlCharType.IsAttributeValueChar( (char)ch ) );
if ( checkCharacters ) {
// This method will never be called on surrogates, so it is ok to pass in '\0' to the CreateInvalidCharException
throw XmlConvert.CreateInvalidCharException( (char)ch, '\0' );
}
else {
if ( entitize ) {
return CharEntity( pDst, (char)ch );
}
else {
#ifdef _XML_UTF8_TEXT_WRITER
if ( ch < 0x80 ) {
#endif
*pDst = (_BUFFER_TYPE)ch;
pDst++;
#ifdef _XML_UTF8_TEXT_WRITER
}
else {
pDst = EncodeMultibyteUTF8( ch, pDst );
}
#endif
return pDst;
}
}
}
internal unsafe void EncodeChar(ref char* pSrc, char*pSrcEnd, ref _BUFFER_TYPE* pDst) {
int ch = *pSrc;
_ENCODE_CHAR(false);
}
#ifdef _XML_UTF8_TEXT_WRITER
internal static unsafe byte* EncodeMultibyteUTF8( int ch, byte* pDst ) {
Debug.Assert( ch >= 0x80 && !XmlCharType.IsSurrogate( ch ) );
/* UTF8-2: If ch is in 0x80-0x7ff range, then use 2 bytes to encode it */ \
if ( ch < 0x800 ) {
*pDst = (byte)( unchecked((sbyte)0xC0) | (ch >> 6) );
}
/* UTF8-3: If ch is anything else, then default to using 3 bytes to encode it. */
else {
*pDst = (byte)( unchecked((sbyte)0xE0) | ( ch >> 12 ) );
pDst++;
*pDst = (byte)( unchecked((sbyte)0x80) | ( ch >> 6 ) & 0x3F);
}
pDst++;
*pDst = (byte)( 0x80 | ch & 0x3F );
return pDst + 1;
}
// Encode *pSrc as a sequence of UTF8 bytes. Write the bytes to pDst and return an updated pointer.
internal static unsafe void CharToUTF8( ref char * pSrc, char * pSrcEnd, ref byte * pDst ) {
int ch = *pSrc;
if ( ch <= 0x7F ) {
*pDst = (byte)ch;
pDst++;
pSrc++;
}
else if ( XmlCharType.IsSurrogate( ch ) ) {
pDst = EncodeSurrogate( pSrc, pSrcEnd, pDst );
pSrc += 2;
}
else {
pDst = EncodeMultibyteUTF8( ch, pDst );
pSrc++;
}
}
#endif
#ifdef _XML_ENCODED_TEXT_WRITER
protected void ChangeTextContentMark( bool value ) {
Debug.Assert( inTextContent != value );
Debug.Assert( inTextContent || ((lastMarkPos & 1) == 0) );
inTextContent = value;
if ( lastMarkPos + 1 == textContentMarks.Length ) {
GrowTextContentMarks();
}
textContentMarks[++lastMarkPos] = this.bufPos;
}
private void GrowTextContentMarks() {
Debug.Assert( lastMarkPos + 1 == textContentMarks.Length );
int[] newTextContentMarks = new int[ textContentMarks.Length * 2 ];
Array.Copy( textContentMarks, newTextContentMarks, textContentMarks.Length );
textContentMarks = newTextContentMarks;
}
#endif
// Write NewLineChars to the specified buffer position and return an updated position.
protected unsafe _BUFFER_TYPE * WriteNewLine( _BUFFER_TYPE * pDst ) {
fixed ( _BUFFER_TYPE * pDstBegin = _BUFFER ) {
bufPos = (int) (pDst - pDstBegin);
// Let RawText do the real work
RawText( newLineChars );
return pDstBegin + bufPos;
}
}
// Following methods do not check whether pDst is beyond the bufSize because the buffer was allocated with a OVERFLOW to accomodate
// for the writes of small constant-length string as below.
// Entitize '<' as "<". Return an updated pointer.
protected static unsafe _BUFFER_TYPE * LtEntity( _BUFFER_TYPE * pDst ) {
pDst[0] = (_BUFFER_TYPE)'&';
pDst[1] = (_BUFFER_TYPE)'l';
pDst[2] = (_BUFFER_TYPE)'t';
pDst[3] = (_BUFFER_TYPE)';';
return pDst + 4;
}
// Entitize '>' as ">". Return an updated pointer.
protected static unsafe _BUFFER_TYPE * GtEntity( _BUFFER_TYPE * pDst ) {
pDst[0] = (_BUFFER_TYPE)'&';
pDst[1] = (_BUFFER_TYPE)'g';
pDst[2] = (_BUFFER_TYPE)'t';
pDst[3] = (_BUFFER_TYPE)';';
return pDst + 4;
}
// Entitize '&' as "&". Return an updated pointer.
protected static unsafe _BUFFER_TYPE * AmpEntity( _BUFFER_TYPE * pDst ) {
pDst[0] = (_BUFFER_TYPE)'&';
pDst[1] = (_BUFFER_TYPE)'a';
pDst[2] = (_BUFFER_TYPE)'m';
pDst[3] = (_BUFFER_TYPE)'p';
pDst[4] = (_BUFFER_TYPE)';';
return pDst + 5;
}
// Entitize '"' as """. Return an updated pointer.
protected static unsafe _BUFFER_TYPE * QuoteEntity( _BUFFER_TYPE * pDst ) {
pDst[0] = (_BUFFER_TYPE)'&';
pDst[1] = (_BUFFER_TYPE)'q';
pDst[2] = (_BUFFER_TYPE)'u';
pDst[3] = (_BUFFER_TYPE)'o';
pDst[4] = (_BUFFER_TYPE)'t';
pDst[5] = (_BUFFER_TYPE)';';
return pDst + 6;
}
// Entitize '\t' as "	". Return an updated pointer.
protected static unsafe _BUFFER_TYPE * TabEntity( _BUFFER_TYPE * pDst ) {
pDst[0] = (_BUFFER_TYPE)'&';
pDst[1] = (_BUFFER_TYPE)'#';
pDst[2] = (_BUFFER_TYPE)'x';
pDst[3] = (_BUFFER_TYPE)'9';
pDst[4] = (_BUFFER_TYPE)';';
return pDst + 5;
}
// Entitize 0xa as "
". Return an updated pointer.
protected static unsafe _BUFFER_TYPE * LineFeedEntity( _BUFFER_TYPE * pDst ) {
pDst[0] = (_BUFFER_TYPE)'&';
pDst[1] = (_BUFFER_TYPE)'#';
pDst[2] = (_BUFFER_TYPE)'x';
pDst[3] = (_BUFFER_TYPE)'A';
pDst[4] = (_BUFFER_TYPE)';';
return pDst + 5;
}
// Entitize 0xd as "
". Return an updated pointer.
protected static unsafe _BUFFER_TYPE * CarriageReturnEntity( _BUFFER_TYPE * pDst ) {
pDst[0] = (_BUFFER_TYPE)'&';
pDst[1] = (_BUFFER_TYPE)'#';
pDst[2] = (_BUFFER_TYPE)'x';
pDst[3] = (_BUFFER_TYPE)'D';
pDst[4] = (_BUFFER_TYPE)';';
return pDst + 5;
}
private static unsafe _BUFFER_TYPE * CharEntity( _BUFFER_TYPE * pDst, char ch ) {
string s = ((int)ch).ToString( "X",NumberFormatInfo.InvariantInfo );
pDst[0] = (_BUFFER_TYPE)'&';
pDst[1] = (_BUFFER_TYPE)'#';
pDst[2] = (_BUFFER_TYPE)'x';
pDst += 3;
fixed ( char *pSrc = s ) {
char *pS = pSrc;
while ( ( *pDst++ = (_BUFFER_TYPE)*pS++ ) != 0 );
}
pDst[-1] = (_BUFFER_TYPE)';';
return pDst;
}
// Write "<![CDATA[" to the specified buffer. Return an updated pointer.
protected static unsafe _BUFFER_TYPE * RawStartCData( _BUFFER_TYPE * pDst ) {
pDst[0] = (_BUFFER_TYPE)'<';
pDst[1] = (_BUFFER_TYPE)'!';
pDst[2] = (_BUFFER_TYPE)'[';
pDst[3] = (_BUFFER_TYPE)'C';
pDst[4] = (_BUFFER_TYPE)'D';
pDst[5] = (_BUFFER_TYPE)'A';
pDst[6] = (_BUFFER_TYPE)'T';
pDst[7] = (_BUFFER_TYPE)'A';
pDst[8] = (_BUFFER_TYPE)'[';
return pDst + 9;
}
// Write "]]>" to the specified buffer. Return an updated pointer.
protected static unsafe _BUFFER_TYPE * RawEndCData( _BUFFER_TYPE * pDst ) {
pDst[0] = (_BUFFER_TYPE)']';
pDst[1] = (_BUFFER_TYPE)']';
pDst[2] = (_BUFFER_TYPE)'>';
return pDst + 3;
}
protected unsafe void ValidateContentChars( string chars, string propertyName, bool allowOnlyWhitespace ) {
if ( allowOnlyWhitespace ) {
if ( !xmlCharType.IsOnlyWhitespace( chars ) ) {
throw new ArgumentException( Res.GetString( Res.Xml_IndentCharsNotWhitespace, propertyName ) );
}
}
else {
string error = null;
for ( int i = 0; i < chars.Length; i++ ) {
if ( !xmlCharType.IsTextChar( chars[i] ) ) {
switch ( chars[i] ) {
case '\n':
case '\r':
case '\t':
continue;
case '<':
case '&':
case ']':
error = Res.GetString( Res.Xml_InvalidCharacter, XmlException.BuildCharExceptionArgs( chars, i ) );
goto Error;
default:
if ( XmlCharType.IsHighSurrogate(chars[i]) ) {
if ( i + 1 < chars.Length ) {
if ( XmlCharType.IsLowSurrogate(chars[i + 1]) ) {
i++;
continue;
}
}
error = Res.GetString( Res.Xml_InvalidSurrogateMissingLowChar );
goto Error;
}
else if ( XmlCharType.IsLowSurrogate(chars[i]) ) {
error = Res.GetString( Res.Xml_InvalidSurrogateHighChar, ((uint)chars[i]).ToString( "X", CultureInfo.InvariantCulture ) );
goto Error;
}
continue;
}
}
}
return;
Error:
throw new ArgumentException( Res.GetString( Res.Xml_InvalidCharsInIndent, new string[] { propertyName, error } ) );
}
}
}
// Same as base text writer class except that elements, attributes, comments, and pi's are indented.
internal class _CLASS_NAME_INDENT : _CLASS_NAME {
//
// Fields
//
protected int indentLevel;
protected bool newLineOnAttributes;
protected string indentChars;
protected bool mixedContent;
private BitStack mixedContentStack;
protected ConformanceLevel conformanceLevel = ConformanceLevel.Auto;
//
// Constructors
//
#ifdef _XML_ENCODED_TEXT_WRITER
public _CLASS_NAME_INDENT( TextWriter writer, XmlWriterSettings settings ) : base( writer, settings ) {
Init( settings );
}
#endif
public _CLASS_NAME_INDENT( Stream stream, XmlWriterSettings settings ) : base( stream, settings ) {
Init( settings );
}
//
// XmlWriter methods
//
public override XmlWriterSettings Settings {
get {
XmlWriterSettings settings = base.Settings;
settings.ReadOnly = false;
settings.Indent = true;
settings.IndentChars = indentChars;
settings.NewLineOnAttributes = newLineOnAttributes;
settings.ReadOnly = true;
return settings;
}
}
public override void WriteDocType( string name, string pubid, string sysid, string subset ) {
// Add indentation
if ( !mixedContent && base.textPos != base.bufPos) {
WriteIndent();
}
base.WriteDocType( name, pubid, sysid, subset );
}
public override void WriteStartElement( string prefix, string localName, string ns ) {
Debug.Assert( localName != null && localName.Length != 0 && prefix != null && ns != null );
// Add indentation
if ( !mixedContent && base.textPos != base.bufPos) {
WriteIndent();
}
indentLevel++;
mixedContentStack.PushBit( mixedContent );
base.WriteStartElement( prefix, localName, ns );
}
internal override void StartElementContent() {
// If this is the root element and we're writing a document
// do not inherit the mixedContent flag into the root element.
// This is to allow for whitespace nodes on root level
// without disabling indentation for the whole document.
if (indentLevel == 1 && conformanceLevel == ConformanceLevel.Document) {
mixedContent = false;
}
else {
mixedContent = mixedContentStack.PeekBit();
}
base.StartElementContent();
}
internal override void OnRootElement(ConformanceLevel currentConformanceLevel) {
// Just remember the current conformance level
conformanceLevel = currentConformanceLevel;
}
internal override void WriteEndElement(string prefix, string localName, string ns) {
// Add indentation
indentLevel--;
if ( !mixedContent && base.contentPos != base.bufPos ) {
// There was content, so try to indent
if ( base.textPos != base.bufPos ) {
WriteIndent();
}
}
mixedContent = mixedContentStack.PopBit();
base.WriteEndElement( prefix, localName, ns );
}
internal override void WriteFullEndElement(string prefix, string localName, string ns) {
// Add indentation
indentLevel--;
if ( !mixedContent && base.contentPos != base.bufPos ) {
// There was content, so try to indent
if ( base.textPos != base.bufPos ) {
WriteIndent();
}
}
mixedContent = mixedContentStack.PopBit();
base.WriteFullEndElement( prefix, localName, ns );
}
// Same as base class, plus possible indentation.
public override void WriteStartAttribute( string prefix, string localName, string ns ) {
// Add indentation
if ( newLineOnAttributes ) {
WriteIndent();
}
base.WriteStartAttribute( prefix, localName, ns );
}
public override void WriteCData( string text ) {
mixedContent = true;
base.WriteCData( text );
}
public override void WriteComment( string text ) {
if ( !mixedContent && base.textPos != base.bufPos ) {
WriteIndent();
}
base.WriteComment( text );
}
public override void WriteProcessingInstruction( string target, string text ) {
if ( !mixedContent && base.textPos != base.bufPos ) {
WriteIndent();
}
base.WriteProcessingInstruction( target, text );
}
public override void WriteEntityRef( string name ) {
mixedContent = true;
base.WriteEntityRef( name );
}
public override void WriteCharEntity( char ch ) {
mixedContent = true;
base.WriteCharEntity( ch );
}
public override void WriteSurrogateCharEntity( char lowChar, char highChar ) {
mixedContent = true;
base.WriteSurrogateCharEntity( lowChar, highChar );
}
public override void WriteWhitespace( string ws ) {
mixedContent = true;
base.WriteWhitespace( ws );
}
public override void WriteString( string text ) {
mixedContent = true;
base.WriteString( text );
}
public override void WriteChars( char[] buffer, int index, int count ) {
mixedContent = true;
base.WriteChars( buffer, index, count );
}
public override void WriteRaw( char[] buffer, int index, int count ) {
mixedContent = true;
base.WriteRaw( buffer, index, count );
}
public override void WriteRaw( string data ) {
mixedContent = true;
base.WriteRaw( data );
}
public override void WriteBase64( byte[] buffer, int index, int count ) {
mixedContent = true;
base.WriteBase64( buffer, index, count );
}
//
// Private methods
//
private void Init( XmlWriterSettings settings ) {
indentLevel = 0;
indentChars = settings.IndentChars;
newLineOnAttributes = settings.NewLineOnAttributes;
mixedContentStack = new BitStack();
// check indent characters that they are valid XML characters
if ( base.checkCharacters ) {
if ( newLineOnAttributes ) {
base.ValidateContentChars( indentChars, "IndentChars", true );
base.ValidateContentChars( newLineChars, "NewLineChars", true );
}
else {
base.ValidateContentChars( indentChars, "IndentChars", false );
if ( base.newLineHandling != NewLineHandling.Replace ) {
base.ValidateContentChars( newLineChars, "NewLineChars", false );
}
}
}
}
// Add indentation to output. Write newline and then repeat IndentChars for each indent level.
private void WriteIndent() {
RawText( base.newLineChars );
for ( int i = indentLevel; i > 0; i-- ) {
RawText( indentChars );
}
}
}
}