in cs/src/io/unsafe/InputStream.cs [97:204]
internal override void EndOfStream(int count)
{
// The unread bytes left in the buffer. May be negative, which
// indicates that this stream has been advanced beyond where we
// are in the underlying stream and some bytes will need to be
// skipped.
var remaining = end - position;
bool failed = false;
byte[][] tempBuffers = EmptyTempBuffers;
// Check whether we need to read in chunks to avoid allocating a
// ton of memory ahead of time.
if ((count > buffer.Length && (count - buffer.Length > ActiveAllocationChunk)))
{
// Calculate number of temp buffers; we round down since the
// last chunk is read directly into final buffer. Note:
// Difference is adjusted by -1 to round down correctly in
// cases where the difference is exactly a multiple of the
// allocation chunk size.
int numTempBuffers = (count - buffer.Length - 1) / ActiveAllocationChunk;
tempBuffers = new byte[numTempBuffers][];
for (int i = 0; i < tempBuffers.Length; i++)
{
tempBuffers[i] = new byte[ActiveAllocationChunk];
if (remaining < 0)
{
// We need to skip ahead in the underlying stream.
// Borrow the buffer to do the skipping before we do
// the real read.
// Only should happen for the first iteration, as we
// reset remaining.
Debug.Assert(i == 0);
AdvanceUnderlyingStream(-remaining, tempBuffers[i]);
remaining = 0;
}
var bytesRead = stream.Read(tempBuffers[i], 0, ActiveAllocationChunk);
if (bytesRead != ActiveAllocationChunk)
{
failed = true;
break;
}
}
}
if (!failed)
{
var oldBuffer = buffer;
if (!canReuseBuffer || count > buffer.Length)
{
buffer = new byte[Math.Max(bufferLength, count)];
canReuseBuffer = true;
}
int offset;
if (remaining > 0)
{
// Copy any remaining bytes from the old buffer into the
// final buffer. This may just move the bytes to the
// beginning of the buffer.
Buffer.BlockCopy(oldBuffer, position, buffer, 0, remaining);
offset = remaining;
}
else if (remaining < 0)
{
// Nothing in the old buffer, but we need to skip ahead
// in the underlying stream.
AdvanceUnderlyingStream(-remaining, buffer);
offset = 0;
}
else
{
// The stars are aligned, so just start at the beginning
// of the final buffer.
offset = 0;
}
// Copy from any temp buffers into the final buffer. In the
// common case, there are no temp buffers.
foreach (byte[] tempBuffer in tempBuffers)
{
Buffer.BlockCopy(
tempBuffer,
0,
buffer,
offset,
tempBuffer.Length);
offset += tempBuffer.Length;
}
// Read the final block; update valid length and position.
end = offset + stream.Read(buffer, offset, buffer.Length - offset);
position = 0;
}
if (count > end)
{
base.EndOfStream(count - end);
}
}