private int ReadCore(byte[] array, int offset, int count)
{
Debug.Assert((_readPos == 0 && _readLength == 0 && _writePos >= 0) || (_writePos == 0 && _readPos <= _readLength),
"We're either reading or writing, but not both.");
bool isBlocked = false;
int n = _readLength - _readPos;
// if the read buffer is empty, read into either user's array or our
// buffer, depending on number of bytes user asked for and buffer size.
if (n == 0)
{
if (!CanRead) throw Error.GetReadNotSupported();
if (_writePos > 0) FlushWriteBuffer();
if (!CanSeek || (count >= _bufferLength))
{
n = ReadNative(array, offset, count);
// Throw away read buffer.
_readPos = 0;
_readLength = 0;
return n;
}
n = ReadNative(GetBuffer(), 0, _bufferLength);
if (n == 0) return 0;
isBlocked = n < _bufferLength;
_readPos = 0;
_readLength = n;
}
// Now copy min of count or numBytesAvailable (i.e. near EOF) to array.
if (n > count) n = count;
Buffer.BlockCopy(GetBuffer(), _readPos, array, offset, n);
_readPos += n;
// We may have read less than the number of bytes the user asked
// for, but that is part of the Stream contract. Reading again for
// more data may cause us to block if we're using a device with
// no clear end of file, such as a serial port or pipe. If we
// blocked here & this code was used with redirected pipes for a
// process's standard output, this can lead to deadlocks involving
// two processes. But leave this here for files to avoid what would
// probably be a breaking change. --
// If we are reading from a device with no clear EOF like a
// serial port or a pipe, this will cause us to block incorrectly.
if (!_isPipe)
{
// If we hit the end of the buffer and didn't have enough bytes, we must
// read some more from the underlying stream. However, if we got
// fewer bytes from the underlying stream than we asked for (i.e. we're
// probably blocked), don't ask for more bytes.
if (n < count && !isBlocked)
{
Debug.Assert(_readPos == _readLength, "Read buffer should be empty!");
int moreBytesRead = ReadNative(array, offset + n, count - n);
n += moreBytesRead;
// We've just made our buffer inconsistent with our position
// pointer. We must throw away the read buffer.
_readPos = 0;
_readLength = 0;
}
}
return n;
}