protected override IntPtr OnRead(IntPtr buffer, IntPtr size) { var start = offset; // 1. read any data that was previously buffered if ((int)size > 0 && offset < bufferedSoFar) { var copied = Math.Min((int)size, bufferedSoFar - offset); if (buffer != IntPtr.Zero) { Marshal.Copy(frontBuffer, offset, buffer, copied); buffer += copied; } offset += copied; size -= copied; } bool isAtEnd = false; // 2. buffer any more data, and then read it if ((int)size > 0 && bufferedSoFar < bufferLength) { var bytesToBuffer = Math.Min((int)size, bufferLength - bufferedSoFar); var tempBuffer = Marshal.AllocCoTaskMem(bytesToBuffer); var bytesRead = stream.Read(tempBuffer, bytesToBuffer); Marshal.Copy(tempBuffer, frontBuffer, offset, bytesRead); Marshal.FreeCoTaskMem(tempBuffer); isAtEnd = bytesRead < bytesToBuffer; bufferedSoFar += bytesRead; if (buffer != IntPtr.Zero) { Marshal.Copy(frontBuffer, offset, buffer, bytesRead); buffer += bytesRead; } offset += bytesRead; size -= bytesRead; } // 3. read the rest directly if ((int)size > 0 && !isAtEnd) { var bytesRead = stream.Read(buffer, (int)size); // past the buffer, so dispose it if (bytesRead > 0) { frontBuffer = null; } offset += bytesRead; size -= bytesRead; } return((IntPtr)(offset - start)); }