private int ReadData()
{
// Append Mode: Append new bytes and characters to the buffers, do not rewrite them. Allocate new buffers
// if the current ones are full
// Rewrite Mode: Reuse the buffers. If there is less than half of the char buffer left for new data, move
// the characters that has not been parsed yet to the front of the buffer. Same for bytes.
if (_ps.isEof)
{
return 0;
}
int charsRead;
if (_ps.appendMode)
{
// the character buffer is full -> allocate a new one
if (_ps.charsUsed == _ps.chars.Length - 1)
{
// invalidate node values kept in buffer - applies to attribute values only
for (int i = 0; i < _attrCount; i++)
{
_nodes[_index + i + 1].OnBufferInvalidated();
}
char[] newChars = new char[_ps.chars.Length * 2];
BlockCopyChars(_ps.chars, 0, newChars, 0, _ps.chars.Length);
_ps.chars = newChars;
}
if (_ps.stream != null)
{
// the byte buffer is full -> allocate a new one
if (_ps.bytesUsed - _ps.bytePos < MaxByteSequenceLen)
{
if (_ps.bytes.Length - _ps.bytesUsed < MaxByteSequenceLen)
{
byte[] newBytes = new byte[_ps.bytes.Length * 2];
BlockCopy(_ps.bytes, 0, newBytes, 0, _ps.bytesUsed);
_ps.bytes = newBytes;
}
}
}
charsRead = _ps.chars.Length - _ps.charsUsed - 1;
if (charsRead > ApproxXmlDeclLength)
{
charsRead = ApproxXmlDeclLength;
}
}
else
{
int charsLen = _ps.chars.Length;
if (charsLen - _ps.charsUsed <= charsLen / 2)
{
// invalidate node values kept in buffer - applies to attribute values only
for (int i = 0; i < _attrCount; i++)
{
_nodes[_index + i + 1].OnBufferInvalidated();
}
// move unparsed characters to front, unless the whole buffer contains unparsed characters
int copyCharsCount = _ps.charsUsed - _ps.charPos;
if (copyCharsCount < charsLen - 1)
{
_ps.lineStartPos = _ps.lineStartPos - _ps.charPos;
if (copyCharsCount > 0)
{
BlockCopyChars(_ps.chars, _ps.charPos, _ps.chars, 0, copyCharsCount);
}
_ps.charPos = 0;
_ps.charsUsed = copyCharsCount;
}
else
{
char[] newChars = new char[_ps.chars.Length * 2];
BlockCopyChars(_ps.chars, 0, newChars, 0, _ps.chars.Length);
_ps.chars = newChars;
}
}
if (_ps.stream != null)
{
// move undecoded bytes to the front to make some space in the byte buffer
int bytesLeft = _ps.bytesUsed - _ps.bytePos;
if (bytesLeft <= MaxBytesToMove)
{
if (bytesLeft == 0)
{
_ps.bytesUsed = 0;
}
else
{
BlockCopy(_ps.bytes, _ps.bytePos, _ps.bytes, 0, bytesLeft);
_ps.bytesUsed = bytesLeft;
}
_ps.bytePos = 0;
}
}
charsRead = _ps.chars.Length - _ps.charsUsed - 1;
}
if (_ps.stream != null)
{
if (!_ps.isStreamEof)
{
// read new bytes
if (_ps.bytePos == _ps.bytesUsed && _ps.bytes.Length - _ps.bytesUsed > 0)
{
int read = _ps.stream.Read(_ps.bytes, _ps.bytesUsed, _ps.bytes.Length - _ps.bytesUsed);
if (read == 0)
{
_ps.isStreamEof = true;
}
_ps.bytesUsed += read;
}
}
int originalBytePos = _ps.bytePos;
// decode chars
charsRead = GetChars(charsRead);
if (charsRead == 0 && _ps.bytePos != originalBytePos)
{
// GetChars consumed some bytes but it was not enough bytes to form a character -> try again
return ReadData();
}
}
else if (_ps.textReader != null)
{
// read chars
charsRead = _ps.textReader.Read(_ps.chars, _ps.charsUsed, _ps.chars.Length - _ps.charsUsed - 1);
_ps.charsUsed += charsRead;
}
else
{
charsRead = 0;
}
RegisterConsumedCharacters(charsRead, InEntity);
if (charsRead == 0)
{
Debug.Assert(_ps.charsUsed < _ps.chars.Length);
_ps.isEof = true;
}
_ps.chars[_ps.charsUsed] = (char)0;
return charsRead;
}