99 lines
3.3 KiB
C#
99 lines
3.3 KiB
C#
namespace ReFuel.Gltf.IO
|
|
{
|
|
public class StreamWrapper : Stream
|
|
{
|
|
private readonly Stream _proxy;
|
|
|
|
public Stream BaseStream { get; }
|
|
public bool KeepOpen { get; }
|
|
public long Offset { get; private init; } = 0;
|
|
public long Limit { get; private init; } = -1;
|
|
|
|
public override bool CanRead => _proxy.CanRead;
|
|
public override bool CanSeek => _proxy.CanSeek;
|
|
public override bool CanWrite => _proxy.CanWrite;
|
|
public override long Length => Limit < 0 ? _proxy.Length : Math.Min(Limit, Length - Offset);
|
|
|
|
public override long Position
|
|
{
|
|
get => ToRelOffset(_proxy.Position);
|
|
set => _proxy.Position = ToAbsOffset(value);
|
|
}
|
|
|
|
public StreamWrapper(Stream baseStream, bool keepOpen = false)
|
|
{
|
|
BaseStream = baseStream;
|
|
KeepOpen = keepOpen;
|
|
|
|
_proxy = Synchronized(baseStream);
|
|
}
|
|
|
|
public override void Flush() => _proxy.Flush();
|
|
|
|
public override int Read(byte[] buffer, int offset, int count) => _proxy.Read(buffer, offset, count);
|
|
|
|
public override long Seek(long offset, SeekOrigin origin) => _proxy.Seek(offset, origin);
|
|
|
|
public override void SetLength(long value) => _proxy.SetLength(value);
|
|
|
|
public override void Write(byte[] buffer, int offset, int count) => _proxy.Write(buffer, offset, count);
|
|
|
|
public StreamWrapper Fork(long offset = 0, long limit = -1, bool keepOpen = false)
|
|
{
|
|
if (limit < 0)
|
|
limit = Limit;
|
|
|
|
if (offset < 0 || offset > Length)
|
|
throw new ArgumentOutOfRangeException(nameof(offset), "Offset out of range.");
|
|
|
|
if (limit >= 0 && offset + limit > Length)
|
|
throw new ArgumentOutOfRangeException(nameof(limit), "Limit too large for the given offset.");
|
|
|
|
return ForkAbs(ToAbsOffset(offset), limit, keepOpen);
|
|
}
|
|
|
|
public StreamWrapper ForkAbs(long offset = 0, long limit = -1, bool keepOpen = false)
|
|
{
|
|
if (offset < 0 || offset > BaseStream.Length)
|
|
throw new ArgumentOutOfRangeException(nameof(offset), "Offset out of range.");
|
|
|
|
if (limit >= 0 && offset + limit > BaseStream.Length)
|
|
throw new ArgumentOutOfRangeException(nameof(limit), "Limit too large for the given offset.");
|
|
|
|
return new StreamWrapper(BaseStream, keepOpen)
|
|
{
|
|
Offset = offset,
|
|
Limit = limit,
|
|
};
|
|
}
|
|
|
|
private long ToAbsOffset(long offset)
|
|
{
|
|
if (offset < 0)
|
|
throw new ArgumentOutOfRangeException(nameof(offset), offset, "The relative offset cannot be less than zero.");
|
|
|
|
if (Limit >= 0 && offset > Limit)
|
|
throw new ArgumentOutOfRangeException(nameof(offset), offset, "The relative offset cannot be greater than the limit.");
|
|
|
|
return offset + Offset;
|
|
}
|
|
|
|
private long ToRelOffset(long offset)
|
|
{
|
|
return offset - Offset;
|
|
}
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
base.Dispose(disposing);
|
|
|
|
if (!disposing)
|
|
return;
|
|
|
|
_proxy.Dispose();
|
|
if (!KeepOpen)
|
|
BaseStream.Dispose();
|
|
}
|
|
}
|
|
}
|