I've found myself needing this for a second time within 6 months, so posting my solution for a partial input stream.
class PartialStream: Stream {
public Stream Source { get; }
public long Offset { get; }
public override long Length { get; }
private long End => Offset + Length;
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override long Position {
get => Source.Position - Offset;
set => throw new NotSupportedException();
}
public PartialStream(Stream source, long length) {
Offset = source.Position;
Length = length;
}
public PartialStream(Stream source, long offset, long length, bool seekToOffset = true) {
if (seekToOffset) source.Seek(offset, SeekOrigin.Begin);
Offset = offset;
Length = length;
}
public override int Read(byte[] array, int offset, int count) {
if (Source.Position >= End) return 0;
if (Source.Position + count > End)
count = (int)(End - Source.Position);
return Source.Read(array, offset, count);
}
public override void Flush() => throw new NotSupportedException();
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
public override void SetLength(long value) => throw new NotSupportedException();
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
}