mirror of
https://github.com/AssetRipper/AssetRipper.git
synced 2025-12-11 20:15:29 +01:00
130 lines
2.9 KiB
C#
130 lines
2.9 KiB
C#
namespace AssetRipper.IO.Files.Streams;
|
|
|
|
/// <summary>
|
|
/// A stream implementation for accessing a subset of another stream
|
|
/// </summary>
|
|
public sealed class PartialStream : Stream
|
|
{
|
|
public PartialStream(Stream baseStream, long offset, long length) : this(baseStream, offset, length, true) { }
|
|
|
|
public PartialStream(Stream baseStream, long offset, long length, bool leaveOpen)
|
|
{
|
|
if (offset + length > baseStream.Length)
|
|
{
|
|
throw new ArgumentException("The base stream is not long enough for the given offset and length.");
|
|
}
|
|
m_stream = baseStream ?? throw new ArgumentNullException(nameof(baseStream));
|
|
m_baseOffset = offset;
|
|
Length = length;
|
|
m_leaveOpen = leaveOpen;
|
|
}
|
|
|
|
~PartialStream()
|
|
{
|
|
Dispose(false);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override void Flush()
|
|
{
|
|
m_stream.Flush();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int Read(byte[] buffer, int offset, int count)
|
|
{
|
|
count = (int)Math.Max(Math.Min(count, Length - Position), 0);
|
|
int read = m_stream.Read(buffer, offset, count);
|
|
return read;
|
|
}
|
|
|
|
public override int Read(Span<byte> buffer)
|
|
{
|
|
int count = buffer.Length;
|
|
count = (int)Math.Max(Math.Min(count, Length - Position), 0);
|
|
return m_stream.Read(buffer[..count]);
|
|
}
|
|
|
|
public override int ReadByte()
|
|
=> m_stream.ReadByte();
|
|
|
|
/// <inheritdoc/>
|
|
public override long Seek(long offset, SeekOrigin origin)
|
|
{
|
|
if (origin == SeekOrigin.Begin)
|
|
{
|
|
return m_stream.Seek(m_baseOffset + offset, SeekOrigin.Begin) - m_baseOffset;
|
|
}
|
|
else if (origin == SeekOrigin.End)
|
|
{
|
|
return m_stream.Seek(m_baseOffset + Length + offset, SeekOrigin.Begin) - m_baseOffset;
|
|
}
|
|
else
|
|
{
|
|
return m_stream.Seek(offset, origin) - m_baseOffset;
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override void SetLength(long value)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override void Write(byte[] buffer, int offset, int count)
|
|
{
|
|
if (Position + count > Length)
|
|
{
|
|
throw new Exception("Partial stream's position is out of range");
|
|
}
|
|
m_stream.Write(buffer, offset, count);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
if (m_leaveOpen)
|
|
{
|
|
if (!m_isDisposed)
|
|
{
|
|
m_isDisposed = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_stream?.Dispose();
|
|
}
|
|
base.Dispose(disposing);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override bool CanRead => m_stream.CanRead;
|
|
/// <inheritdoc/>
|
|
public override bool CanSeek => m_stream.CanSeek;
|
|
/// <inheritdoc/>
|
|
public override bool CanWrite => m_stream.CanWrite;
|
|
/// <inheritdoc/>
|
|
public override long Length { get; }
|
|
|
|
/// <inheritdoc/>
|
|
public override long Position
|
|
{
|
|
get => m_stream.Position - m_baseOffset;
|
|
set
|
|
{
|
|
if (value < 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(value), "Non-negative number required");
|
|
}
|
|
m_stream.Position = m_baseOffset + value;
|
|
}
|
|
}
|
|
|
|
private readonly Stream m_stream;
|
|
private readonly long m_baseOffset;
|
|
private readonly bool m_leaveOpen;
|
|
|
|
private bool m_isDisposed;
|
|
}
|