private bool ParseText(out int startPos, out int endPos, ref int outOrChars)
{
char[] chars = _ps.chars;
int pos = _ps.charPos;
int rcount = 0;
int rpos = -1;
int orChars = outOrChars;
char c;
for (;;)
{
// parse text content
unsafe
{
while (_xmlCharType.IsTextChar(c = chars[pos]))
{
orChars |= (int)c;
pos++;
}
}
switch (c)
{
case (char)0x9:
pos++;
continue;
// eol
case (char)0xA:
pos++;
OnNewLine(pos);
continue;
case (char)0xD:
if (chars[pos + 1] == (char)0xA)
{
if (!_ps.eolNormalized && _parsingMode == ParsingMode.Full)
{
if (pos - _ps.charPos > 0)
{
if (rcount == 0)
{
rcount = 1;
rpos = pos;
}
else
{
ShiftBuffer(rpos + rcount, rpos, pos - rpos - rcount);
rpos = pos - rcount;
rcount++;
}
}
else
{
_ps.charPos++;
}
}
pos += 2;
}
else if (pos + 1 < _ps.charsUsed || _ps.isEof)
{
if (!_ps.eolNormalized)
{
chars[pos] = (char)0xA; // EOL normalization of 0xD
}
pos++;
}
else
{
goto ReadData;
}
OnNewLine(pos);
continue;
// some tag
case '<':
goto ReturnPartialValue;
// entity reference
case '&':
// try to parse char entity inline
int charRefEndPos, charCount;
EntityType entityType;
if ((charRefEndPos = ParseCharRefInline(pos, out charCount, out entityType)) > 0)
{
if (rcount > 0)
{
ShiftBuffer(rpos + rcount, rpos, pos - rpos - rcount);
}
rpos = pos - rcount;
rcount += (charRefEndPos - pos - charCount);
pos = charRefEndPos;
if (!_xmlCharType.IsWhiteSpace(chars[charRefEndPos - charCount]) ||
(_v1Compat && entityType == EntityType.CharacterDec))
{
orChars |= 0xFF;
}
}
else
{
if (pos > _ps.charPos)
{
goto ReturnPartialValue;
}
switch (HandleEntityReference(false, EntityExpandType.All, out pos))
{
case EntityType.Unexpanded:
// make sure we will report EntityReference after the text node
_nextParsingFunction = _parsingFunction;
_parsingFunction = ParsingFunction.EntityReference;
// end the value (returns nothing)
goto NoValue;
case EntityType.CharacterDec:
if (!_v1Compat)
{
goto case EntityType.CharacterHex;
}
orChars |= 0xFF;
break;
case EntityType.CharacterHex:
case EntityType.CharacterNamed:
if (!_xmlCharType.IsWhiteSpace(_ps.chars[pos - 1]))
{
orChars |= 0xFF;
}
break;
default:
pos = _ps.charPos;
break;
}
chars = _ps.chars;
}
continue;
case ']':
if (_ps.charsUsed - pos < 3 && !_ps.isEof)
{
goto ReadData;
}
if (chars[pos + 1] == ']' && chars[pos + 2] == '>')
{
Throw(pos, SR.Xml_CDATAEndInText);
}
orChars |= ']';
pos++;
continue;
default:
// end of buffer
if (pos == _ps.charsUsed)
{
goto ReadData;
}
// surrogate chars
else
{
char ch = chars[pos];
if (XmlCharType.IsHighSurrogate(ch))
{
if (pos + 1 == _ps.charsUsed)
{
goto ReadData;
}
pos++;
if (XmlCharType.IsLowSurrogate(chars[pos]))
{
pos++;
orChars |= ch;
continue;
}
}
int offset = pos - _ps.charPos;
if (ZeroEndingStream(pos))
{
chars = _ps.chars;
pos = _ps.charPos + offset;
goto ReturnPartialValue;
}
else
{
ThrowInvalidChar(_ps.chars, _ps.charsUsed, _ps.charPos + offset);
}
break;
}
}
ReadData:
if (pos > _ps.charPos)
{
goto ReturnPartialValue;
}
// read new characters into the buffer
if (ReadData() == 0)
{
if (_ps.charsUsed - _ps.charPos > 0)
{
if (_ps.chars[_ps.charPos] != (char)0xD && _ps.chars[_ps.charPos] != ']')
{
Throw(SR.Xml_UnexpectedEOF1);
}
Debug.Assert(_ps.isEof);
}
else
{
if (!InEntity)
{
// end the value (returns nothing)
goto NoValue;
}
if (HandleEntityEnd(true))
{
// report EndEntity after the text node
_nextParsingFunction = _parsingFunction;
_parsingFunction = ParsingFunction.ReportEndEntity;
// end the value (returns nothing)
goto NoValue;
}
}
}
pos = _ps.charPos;
chars = _ps.chars;
continue;
}
NoValue:
startPos = endPos = pos;
return true;
ReturnPartialValue:
if (_parsingMode == ParsingMode.Full && rcount > 0)
{
ShiftBuffer(rpos + rcount, rpos, pos - rpos - rcount);
}
startPos = _ps.charPos;
endPos = pos - rcount;
_ps.charPos = pos;
outOrChars = orChars;
return c == '<';
}