///
/// Implementation from: https://social.msdn.microsoft.com/Forums/vstudio/en-US/c409b63b-37df-40ca-9322-458ffe06ea48/how-to-access-part-of-a-filestream-or-memorystream?forum=netfxbcl
///
using System;
using System.IO;
namespace GLTF.Utilities
{
///
/// Allows only part of a stream to be accessed
/// Prevents reading of the stream past the desired length
/// SubStream start is based on input position
///
public class SubStream : Stream
{
private Stream _baseStream;
private readonly long _length;
private long _position;
public override bool CanRead
{
get
{
CheckDisposed();
return _baseStream.CanRead;
}
}
public override bool CanSeek
{
get
{
CheckDisposed();
return false;
}
}
public override bool CanWrite
{
get
{
CheckDisposed();
return false;
}
}
public override long Length
{
get
{
CheckDisposed();
return _length;
}
}
public override long Position
{
get
{
CheckDisposed();
return _position;
}
set
{
throw new NotImplementedException();
}
}
public SubStream(Stream baseStream, long offset, long length)
{
if (baseStream == null) throw new ArgumentNullException(nameof(baseStream));
if (!baseStream.CanRead) throw new ArgumentException("cannot read base stream");
if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset));
if (!baseStream.CanSeek) throw new ArgumentException("cannot seek on base stream");
_length = length;
_baseStream = baseStream;
_baseStream.Seek(offset, SeekOrigin.Current);
}
public override void Flush()
{
CheckDisposed();
_baseStream.Flush();
}
public override long Seek(long offset, SeekOrigin origin)
{
CheckDisposed();
return _baseStream.Seek(offset, origin);
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
public override int Read(byte[] buffer, int offset, int count)
{
CheckDisposed();
long remaining = _length - _position;
if (remaining <= 0)
{
return 0;
}
if (remaining < count)
{
count = (int)remaining;
}
int read = _baseStream.Read(buffer, offset, count);
_position += read;
return read;
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
private void CheckDisposed()
{
if (_baseStream == null)
{
throw new ObjectDisposedException(GetType().Name);
}
}
}
}