mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
158 lines
5.3 KiB
C#
158 lines
5.3 KiB
C#
using System;
|
|
using System.IO;
|
|
|
|
namespace libhac.Streams
|
|
{
|
|
public class SectorStream : Stream
|
|
{
|
|
private readonly Stream _baseStream;
|
|
private readonly long _offset;
|
|
private readonly int _maxBufferSize;
|
|
private readonly bool _keepOpen;
|
|
|
|
/// <summary>
|
|
/// The size of the sectors.
|
|
/// </summary>
|
|
public int SectorSize { get; }
|
|
|
|
/// <summary>
|
|
/// The maximum number of sectors that can be read or written in a single operation.
|
|
/// </summary>
|
|
public int MaxSectors { get; }
|
|
|
|
/// <summary>
|
|
/// The current sector this stream is at
|
|
/// </summary>
|
|
protected long CurrentSector { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Creates a new stream
|
|
/// </summary>
|
|
/// <param name="baseStream">The base stream to read/write from</param>
|
|
/// <param name="sectorSize">The size of the sectors to read/write</param>
|
|
public SectorStream(Stream baseStream, int sectorSize)
|
|
: this(baseStream, sectorSize, 1, 0)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new stream
|
|
/// </summary>
|
|
/// <param name="baseStream">The base stream to read/write from</param>
|
|
/// <param name="sectorSize">The size of the sectors to read/write</param>
|
|
/// <param name="maxSectors">The maximum number of sectors to read/write at once</param>
|
|
/// <param name="offset">Offset to start counting sectors</param>
|
|
public SectorStream(Stream baseStream, int sectorSize, int maxSectors, long offset)
|
|
: this(baseStream, sectorSize, maxSectors, offset, false)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new stream
|
|
/// </summary>
|
|
/// <param name="baseStream">The base stream to read/write from</param>
|
|
/// <param name="sectorSize">The size of the sectors to read/write</param>
|
|
/// <param name="maxSectors">The maximum number of sectors to read/write at once</param>
|
|
/// <param name="offset">Offset to start counting sectors</param>
|
|
/// <param name="keepOpen">Should this stream leave the base stream open when disposed?</param>
|
|
public SectorStream(Stream baseStream, int sectorSize, int maxSectors, long offset, bool keepOpen)
|
|
{
|
|
SectorSize = sectorSize;
|
|
_baseStream = baseStream;
|
|
MaxSectors = maxSectors;
|
|
_offset = offset;
|
|
_keepOpen = keepOpen;
|
|
_maxBufferSize = MaxSectors * SectorSize;
|
|
}
|
|
|
|
public override void Flush()
|
|
{
|
|
_baseStream.Flush();
|
|
}
|
|
|
|
public override int Read(byte[] buffer, int offset, int count)
|
|
{
|
|
ValidateSize(count);
|
|
int bytesRead = _baseStream.Read(buffer, offset, count);
|
|
CurrentSector += bytesRead / SectorSize;
|
|
return bytesRead;
|
|
}
|
|
|
|
public override long Seek(long offset, SeekOrigin origin)
|
|
{
|
|
switch (origin)
|
|
{
|
|
case SeekOrigin.Begin:
|
|
Position = offset;
|
|
break;
|
|
case SeekOrigin.Current:
|
|
Position += offset;
|
|
break;
|
|
case SeekOrigin.End:
|
|
Position = Length - offset;
|
|
break;
|
|
}
|
|
|
|
return Position;
|
|
}
|
|
|
|
public override void SetLength(long value)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override void Write(byte[] buffer, int offset, int count)
|
|
{
|
|
ValidateSize(count);
|
|
_baseStream.Write(buffer, offset, count);
|
|
CurrentSector += count / SectorSize;
|
|
}
|
|
|
|
public override bool CanRead => _baseStream.CanRead;
|
|
public override bool CanSeek => _baseStream.CanSeek;
|
|
public override bool CanWrite => _baseStream.CanWrite;
|
|
public override long Length => _baseStream.Length - _offset;
|
|
public override long Position
|
|
{
|
|
get => _baseStream.Position - _offset;
|
|
set
|
|
{
|
|
ValidateSizeMultiple(value);
|
|
_baseStream.Position = value + _offset;
|
|
CurrentSector = value / SectorSize;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validates that the size is a multiple of the sector size and smaller than the max buffer size
|
|
/// </summary>
|
|
protected void ValidateSize(long value)
|
|
{
|
|
ValidateSizeMultiple(value);
|
|
|
|
if (value > _maxBufferSize)
|
|
throw new ArgumentException($"Value cannot be greater than {_maxBufferSize}");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validates that the size is a multiple of the sector size
|
|
/// </summary>
|
|
protected void ValidateSizeMultiple(long value)
|
|
{
|
|
if (value < 0)
|
|
throw new ArgumentException("Value must be non-negative");
|
|
if (value % SectorSize != 0)
|
|
throw new ArgumentException($"Value must be a multiple of {SectorSize}");
|
|
}
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
if (!_keepOpen)
|
|
{
|
|
_baseStream.Dispose();
|
|
}
|
|
|
|
base.Dispose(disposing);
|
|
}
|
|
}
|
|
}
|