private void ReadPartialUTF8Text(bool withEndElement, int length)
{
// The maxBytesPerRead includes the quota for the XmlBinaryNodeType.TextNode, so we need
// to account for that.
const int maxTextNodeLength = 5;
int maxLength = Math.Max(_maxBytesPerRead - maxTextNodeLength, 0);
if (length <= maxLength)
{
if (withEndElement)
ReadText(MoveToAtomicTextWithEndElement(), ValueHandleType.UTF8, length);
else
ReadText(MoveToComplexText(), ValueHandleType.UTF8, length);
}
else
{
// We also need to make sure we have enough room to insert a new XmlBinaryNodeType.TextNode
// for the split data.
int actual = Math.Max(maxLength - maxTextNodeLength, 0);
int offset = BufferReader.ReadBytes(actual);
// We need to make sure we don't split a utf8 character, so scan backwards for a
// character boundary. We'll actually always push off at least one character since
// although we find the character boundary, we don't bother to figure out if we have
// all the bytes that comprise the character.
int i;
for (i = offset + actual - 1; i >= offset; i--)
{
byte b = BufferReader.GetByte(i);
// The first byte of UTF8 character sequence has either the high bit off, or the
// two high bits set.
if ((b & 0x80) == 0 || (b & 0xC0) == 0xC0)
break;
}
// Move any split characters so we can insert the node
int byteCount = (offset + actual - i);
// Include the split characters in the count
BufferReader.Offset = BufferReader.Offset - byteCount;
actual -= byteCount;
MoveToComplexText().Value.SetValue(ValueHandleType.UTF8, offset, actual);
if (this.OutsideRootElement)
VerifyWhitespace();
XmlBinaryNodeType nodeType = (withEndElement ? XmlBinaryNodeType.Chars32TextWithEndElement : XmlBinaryNodeType.Chars32Text);
InsertNode(nodeType, length - actual);
}
}