internal override async Task<int> ReadAsyncInternal(char[] buffer, int index, int count)
{
if (CharPos_Prop == CharLen_Prop && (await ReadBufferAsync().ConfigureAwait(false)) == 0)
{
return 0;
}
int charsRead = 0;
// As a perf optimization, if we had exactly one buffer's worth of
// data read in, let's try writing directly to the user's buffer.
bool readToUserBuffer = false;
Byte[] tmpByteBuffer = ByteBuffer_Prop;
Stream tmpStream = Stream_Prop;
while (count > 0)
{
// n is the characters available in _charBuffer
int n = CharLen_Prop - CharPos_Prop;
// charBuffer is empty, let's read from the stream
if (n == 0)
{
CharLen_Prop = 0;
CharPos_Prop = 0;
if (!CheckPreamble_Prop)
{
ByteLen_Prop = 0;
}
readToUserBuffer = count >= MaxCharsPerBuffer_Prop;
// We loop here so that we read in enough bytes to yield at least 1 char.
// We break out of the loop if the stream is blocked (EOF is reached).
do
{
Debug.Assert(n == 0);
if (CheckPreamble_Prop)
{
Debug.Assert(BytePos_Prop <= Preamble_Prop.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?");
int tmpBytePos = BytePos_Prop;
int len = await tmpStream.ReadAsync(tmpByteBuffer, tmpBytePos, tmpByteBuffer.Length - tmpBytePos).ConfigureAwait(false);
Debug.Assert(len >= 0, "Stream.Read returned a negative number! This is a bug in your stream class.");
if (len == 0)
{
// EOF but we might have buffered bytes from previous
// attempts to detect preamble that needs to be decoded now
if (ByteLen_Prop > 0)
{
if (readToUserBuffer)
{
n = Decoder_Prop.GetChars(tmpByteBuffer, 0, ByteLen_Prop, buffer, index + charsRead);
CharLen_Prop = 0; // StreamReader's buffer is empty.
}
else
{
n = Decoder_Prop.GetChars(tmpByteBuffer, 0, ByteLen_Prop, CharBuffer_Prop, 0);
CharLen_Prop += n; // Number of chars in StreamReader's buffer.
}
}
// How can part of the preamble yield any chars?
Debug.Assert(n == 0);
IsBlocked_Prop = true;
break;
}
else
{
ByteLen_Prop += len;
}
}
else
{
Debug.Assert(BytePos_Prop == 0, "_bytePos can be non zero only when we are trying to _checkPreamble. Are two threads using this StreamReader at the same time?");
ByteLen_Prop = await tmpStream.ReadAsync(tmpByteBuffer, 0, tmpByteBuffer.Length).ConfigureAwait(false);
Debug.Assert(ByteLen_Prop >= 0, "Stream.Read returned a negative number! This is a bug in your stream class.");
if (ByteLen_Prop == 0) // EOF
{
IsBlocked_Prop = true;
break;
}
}
// _isBlocked == whether we read fewer bytes than we asked for.
// Note we must check it here because CompressBuffer or
// DetectEncoding will change _byteLen.
IsBlocked_Prop = (ByteLen_Prop < tmpByteBuffer.Length);
// Check for preamble before detect encoding. This is not to override the
// user supplied Encoding for the one we implicitly detect. The user could
// customize the encoding which we will loose, such as ThrowOnError on UTF8
// Note: we don't need to recompute readToUserBuffer optimization as IsPreamble
// doesn't change the encoding or affect _maxCharsPerBuffer
if (IsPreamble())
{
continue;
}
// On the first call to ReadBuffer, if we're supposed to detect the encoding, do it.
if (DetectEncoding_Prop && ByteLen_Prop >= 2)
{
DetectEncoding();
// DetectEncoding changes some buffer state. Recompute this.
readToUserBuffer = count >= MaxCharsPerBuffer_Prop;
}
Debug.Assert(n == 0);
CharPos_Prop = 0;
if (readToUserBuffer)
{
n += Decoder_Prop.GetChars(tmpByteBuffer, 0, ByteLen_Prop, buffer, index + charsRead);
// Why did the bytes yield no chars?
Debug.Assert(n > 0);
CharLen_Prop = 0; // StreamReader's buffer is empty.
}
else
{
n = Decoder_Prop.GetChars(tmpByteBuffer, 0, ByteLen_Prop, CharBuffer_Prop, 0);
// Why did the bytes yield no chars?
Debug.Assert(n > 0);
CharLen_Prop += n; // Number of chars in StreamReader's buffer.
}
} while (n == 0);
if (n == 0)
{
break; // We're at EOF
}
} // if (n == 0)
// Got more chars in charBuffer than the user requested
if (n > count)
{
n = count;
}
if (!readToUserBuffer)
{
Buffer.BlockCopy(CharBuffer_Prop, CharPos_Prop * 2, buffer, (index + charsRead) * 2, n * 2);
CharPos_Prop += n;
}
charsRead += n;
count -= n;
// This function shouldn't block for an indefinite amount of time,
// or reading from a network stream won't work right. If we got
// fewer bytes than we requested, then we want to break right here.
if (IsBlocked_Prop)
{
break;
}
} // while (count > 0)
return charsRead;
}