private Token ScanLiteral(LiteralType literalType)
{
Debug.Assert(_chars[_curPos] == '"' || _chars[_curPos] == '\'');
char quoteChar = _chars[_curPos];
char replaceChar = (literalType == LiteralType.AttributeValue) ? (char)0x20 : (char)0xA;
int startQuoteEntityId = _currentEntityId;
_literalLineInfo.Set(LineNo, LinePos);
_curPos++;
_tokenStartPos = _curPos;
#if SILVERLIGHT
stringBuilder.Clear();
#else
_stringBuilder.Length = 0;
#endif
for (;;)
{
while (_xmlCharType.IsAttributeValueChar(_chars[_curPos]) && _chars[_curPos] != '%')
{
_curPos++;
}
if (_chars[_curPos] == quoteChar && _currentEntityId == startQuoteEntityId)
{
if (_stringBuilder.Length > 0)
{
_stringBuilder.Append(_chars, _tokenStartPos, _curPos - _tokenStartPos);
}
_curPos++;
_literalQuoteChar = quoteChar;
return Token.Literal;
}
int tmp1 = _curPos - _tokenStartPos;
if (tmp1 > 0)
{
_stringBuilder.Append(_chars, _tokenStartPos, tmp1);
_tokenStartPos = _curPos;
}
switch (_chars[_curPos])
{
case '"':
case '\'':
case '>':
_curPos++;
continue;
// eol
case (char)0xA:
_curPos++;
if (Normalize)
{
_stringBuilder.Append(replaceChar); // For attributes: CDATA normalization of 0xA
_tokenStartPos = _curPos;
}
_readerAdapter.OnNewLine(_curPos);
continue;
case (char)0xD:
if (_chars[_curPos + 1] == (char)0xA)
{
if (Normalize)
{
if (literalType == LiteralType.AttributeValue)
{
_stringBuilder.Append(_readerAdapter.IsEntityEolNormalized ? "\u0020\u0020" : "\u0020"); // CDATA normalization of 0xD 0xA
}
else
{
_stringBuilder.Append(_readerAdapter.IsEntityEolNormalized ? "\u000D\u000A" : "\u000A"); // EOL normalization of 0xD 0xA
}
_tokenStartPos = _curPos + 2;
SaveParsingBuffer(); // EOL normalization of 0xD 0xA in internal subset value
_readerAdapter.CurrentPosition++;
}
_curPos += 2;
}
else if (_curPos + 1 == _charsUsed)
{
goto ReadData;
}
else
{
_curPos++;
if (Normalize)
{
_stringBuilder.Append(replaceChar); // For attributes: CDATA normalization of 0xD and 0xD 0xA
_tokenStartPos = _curPos; // For entities: EOL normalization of 0xD and 0xD 0xA
}
}
_readerAdapter.OnNewLine(_curPos);
continue;
// tab
case (char)0x9:
if (literalType == LiteralType.AttributeValue && Normalize)
{
_stringBuilder.Append((char)0x20); // For attributes: CDATA normalization of 0x9
_tokenStartPos++;
}
_curPos++;
continue;
// attribute values cannot contain '<'
case '<':
if (literalType == LiteralType.AttributeValue)
{
Throw(_curPos, SR.Xml_BadAttributeChar, XmlException.BuildCharExceptionArgs('<', '\0'));
}
_curPos++;
continue;
// parameter entity reference
case '%':
if (literalType != LiteralType.EntityReplText)
{
_curPos++;
continue;
}
HandleEntityReference(true, true, literalType == LiteralType.AttributeValue);
_tokenStartPos = _curPos;
continue;
// general entity reference
case '&':
if (literalType == LiteralType.SystemOrPublicID)
{
_curPos++;
continue;
}
if (_curPos + 1 == _charsUsed)
{
goto ReadData;
}
// numeric characters reference
if (_chars[_curPos + 1] == '#')
{
SaveParsingBuffer();
int endPos = _readerAdapter.ParseNumericCharRef(SaveInternalSubsetValue ? _internalSubsetValueSb : null);
LoadParsingBuffer();
_stringBuilder.Append(_chars, _curPos, endPos - _curPos);
_readerAdapter.CurrentPosition = endPos;
_tokenStartPos = endPos;
_curPos = endPos;
continue;
}
else
{
// general entity reference
SaveParsingBuffer();
if (literalType == LiteralType.AttributeValue)
{
int endPos = _readerAdapter.ParseNamedCharRef(true, SaveInternalSubsetValue ? _internalSubsetValueSb : null);
LoadParsingBuffer();
if (endPos >= 0)
{
_stringBuilder.Append(_chars, _curPos, endPos - _curPos);
_readerAdapter.CurrentPosition = endPos;
_tokenStartPos = endPos;
_curPos = endPos;
continue;
}
else
{
HandleEntityReference(false, true, true);
_tokenStartPos = _curPos;
}
continue;
}
else
{
int endPos = _readerAdapter.ParseNamedCharRef(false, null);
LoadParsingBuffer();
if (endPos >= 0)
{
_tokenStartPos = _curPos;
_curPos = endPos;
continue;
}
else
{
_stringBuilder.Append('&');
_curPos++;
_tokenStartPos = _curPos;
// Bypass general entities in entity values
XmlQualifiedName entityName = ScanEntityName();
VerifyEntityReference(entityName, false, false, false);
}
continue;
}
}
default:
// end of buffer
if (_curPos == _charsUsed)
{
goto ReadData;
}
// surrogate chars
else
{
char ch = _chars[_curPos];
if (XmlCharType.IsHighSurrogate(ch))
{
if (_curPos + 1 == _charsUsed)
{
goto ReadData;
}
_curPos++;
if (XmlCharType.IsLowSurrogate(_chars[_curPos]))
{
_curPos++;
continue;
}
}
ThrowInvalidChar(_chars, _charsUsed, _curPos);
return Token.None;
}
}
ReadData:
Debug.Assert(_curPos - _tokenStartPos == 0);
// read new characters into the buffer
if (_readerAdapter.IsEof || ReadData() == 0)
{
if (literalType == LiteralType.SystemOrPublicID || !HandleEntityEnd(true))
{
Throw(_curPos, SR.Xml_UnclosedQuote);
}
}
_tokenStartPos = _curPos;
}
}