2026-01-22 13:38:20 +00:00
|
|
|
using System;
|
|
|
|
|
using System.Buffers;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace SharpCompress.IO;
|
|
|
|
|
|
|
|
|
|
internal partial class BufferedSubStream
|
|
|
|
|
{
|
|
|
|
|
private async ValueTask RefillCacheAsync(CancellationToken cancellationToken)
|
|
|
|
|
{
|
2026-01-26 14:20:42 +00:00
|
|
|
if (_isDisposed)
|
|
|
|
|
{
|
|
|
|
|
throw new ObjectDisposedException(nameof(BufferedSubStream));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var count = (int)Math.Min(BytesLeftToRead, _cache!.Length);
|
2026-01-22 13:38:20 +00:00
|
|
|
_cacheOffset = 0;
|
|
|
|
|
if (count == 0)
|
|
|
|
|
{
|
|
|
|
|
_cacheLength = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-01-26 14:20:42 +00:00
|
|
|
// Only seek if we're not already at the correct position
|
|
|
|
|
// This avoids expensive seek operations when reading sequentially
|
2026-01-31 15:29:34 +00:00
|
|
|
if (_stream.CanSeek && _stream.Position != origin)
|
2026-01-26 14:20:42 +00:00
|
|
|
{
|
2026-01-31 15:29:34 +00:00
|
|
|
_stream.Position = origin;
|
2026-01-26 14:20:42 +00:00
|
|
|
}
|
2026-01-31 15:29:34 +00:00
|
|
|
_cacheLength = await _stream
|
2026-01-22 13:38:20 +00:00
|
|
|
.ReadAsync(_cache, 0, count, cancellationToken)
|
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
|
origin += _cacheLength;
|
|
|
|
|
BytesLeftToRead -= _cacheLength;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override async Task<int> ReadAsync(
|
|
|
|
|
byte[] buffer,
|
|
|
|
|
int offset,
|
|
|
|
|
int count,
|
|
|
|
|
CancellationToken cancellationToken
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
if (count > Length)
|
|
|
|
|
{
|
|
|
|
|
count = (int)Length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (count > 0)
|
|
|
|
|
{
|
|
|
|
|
if (_cacheOffset == _cacheLength)
|
|
|
|
|
{
|
|
|
|
|
await RefillCacheAsync(cancellationToken).ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
count = Math.Min(count, _cacheLength - _cacheOffset);
|
2026-01-26 14:20:42 +00:00
|
|
|
Buffer.BlockCopy(_cache!, _cacheOffset, buffer, offset, count);
|
2026-01-22 13:38:20 +00:00
|
|
|
_cacheOffset += count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if !LEGACY_DOTNET
|
|
|
|
|
public override async ValueTask<int> ReadAsync(
|
|
|
|
|
Memory<byte> buffer,
|
|
|
|
|
CancellationToken cancellationToken = default
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
var count = buffer.Length;
|
|
|
|
|
if (count > Length)
|
|
|
|
|
{
|
|
|
|
|
count = (int)Length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (count > 0)
|
|
|
|
|
{
|
|
|
|
|
if (_cacheOffset == _cacheLength)
|
|
|
|
|
{
|
|
|
|
|
await RefillCacheAsync(cancellationToken).ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
count = Math.Min(count, _cacheLength - _cacheOffset);
|
2026-01-26 14:20:42 +00:00
|
|
|
_cache!.AsSpan(_cacheOffset, count).CopyTo(buffer.Span);
|
2026-01-22 13:38:20 +00:00
|
|
|
_cacheOffset += count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|