private string GetString(int length)
{
if (length == 0)
{
return string.Empty;
}
EnsureBuffers();
StringBuilder builder = null;
int totalBytesRead = 0;
// used in case of left over multibyte characters in the buffer
int offset = 0;
do
{
int count = ((length - totalBytesRead) > MaxCharBytesSize - offset)
? MaxCharBytesSize - offset
: length - totalBytesRead;
int byteCount = _reader.Read(_byteBuffer, offset, count);
if (byteCount == 0)
{
throw new EndOfStreamException("Unable to read beyond the end of the stream.");
}
totalBytesRead += byteCount;
// Above, byteCount is how many bytes we read this time.
// Below, byteCount is how many bytes are in the _byteBuffer.
byteCount += offset;
if (byteCount == length)
{
// pref optimization to avoid reading into a string builder
// first iteration and all bytes read then return string directly
int charCount = Encoding.UTF8.GetChars(_byteBuffer, 0, byteCount, _charBuffer, 0);
return new string(_charBuffer, 0, charCount);
}
else
{
int lastFullCharStop = GetLastFullCharStop(byteCount - 1);
if (builder == null)
{
builder = new StringBuilder(length);
}
int charCount = Encoding.UTF8.GetChars(_byteBuffer, 0, lastFullCharStop + 1, _charBuffer, 0);
builder.Append(_charBuffer, 0, charCount);
if (lastFullCharStop < byteCount - 1)
{
offset = byteCount - lastFullCharStop - 1;
// copy left over multi byte characters to beginning of buffer for next iteration
Array.Copy(_byteBuffer, lastFullCharStop + 1, _byteBuffer, 0, offset);
}
else
{
offset = 0;
}
}
} while (totalBytesRead < length);
return builder.ToString();
}