Fixed AsyncMarkingBinaryReader

This commit is contained in:
Adam Hathcock
2026-01-29 16:23:37 +00:00
parent 659f5d7834
commit c9db03335b
5 changed files with 450 additions and 8 deletions

View File

@@ -47,14 +47,12 @@ internal class AsyncMarkingBinaryReader
public async ValueTask<ushort> ReadUInt16Async(CancellationToken cancellationToken = default)
{
CurrentReadByteCount += 2;
var bytes = await ReadBytesAsync(2, cancellationToken).ConfigureAwait(false);
return BinaryPrimitives.ReadUInt16LittleEndian(bytes);
}
public async ValueTask<uint> ReadUInt32Async(CancellationToken cancellationToken = default)
{
CurrentReadByteCount += 4;
var bytes = await ReadBytesAsync(4, cancellationToken).ConfigureAwait(false);
return BinaryPrimitives.ReadUInt32LittleEndian(bytes);
}
@@ -63,7 +61,6 @@ internal class AsyncMarkingBinaryReader
CancellationToken cancellationToken = default
)
{
CurrentReadByteCount += 8;
var bytes = await ReadBytesAsync(8, cancellationToken).ConfigureAwait(false);
return BinaryPrimitives.ReadUInt64LittleEndian(bytes);
}
@@ -72,7 +69,6 @@ internal class AsyncMarkingBinaryReader
CancellationToken cancellationToken = default
)
{
CurrentReadByteCount += 2;
var bytes = await ReadBytesAsync(2, cancellationToken).ConfigureAwait(false);
return BinaryPrimitives.ReadInt16LittleEndian(bytes);
}
@@ -81,7 +77,6 @@ internal class AsyncMarkingBinaryReader
CancellationToken cancellationToken = default
)
{
CurrentReadByteCount += 4;
var bytes = await ReadBytesAsync(4, cancellationToken).ConfigureAwait(false);
return BinaryPrimitives.ReadInt32LittleEndian(bytes);
}
@@ -90,7 +85,6 @@ internal class AsyncMarkingBinaryReader
CancellationToken cancellationToken = default
)
{
CurrentReadByteCount += 8;
var bytes = await ReadBytesAsync(8, cancellationToken).ConfigureAwait(false);
return BinaryPrimitives.ReadInt64LittleEndian(bytes);
}

View File

@@ -119,7 +119,9 @@ internal partial class FileHeader
{
case FHEXTRA_CRYPT:
{
Rar5CryptoInfo = await Rar5CryptoInfo.CreateAsync(reader, true);
Rar5CryptoInfo = await Rar5CryptoInfo
.CreateAsync(reader, true)
.ConfigureAwait(false);
if (Rar5CryptoInfo.PswCheck.All(singleByte => singleByte == 0))
{
Rar5CryptoInfo = null;

View File

@@ -72,7 +72,7 @@ internal sealed partial class StreamingZipHeaderFactory
)
{
_headerFactory = headerFactory;
_rewindableStream = RewindableStream.EnsureSeekable(stream);
_rewindableStream = new RewindableStream(stream);
_reader = new AsyncBinaryReader(_rewindableStream, leaveOpen: true);
_cancellationToken = cancellationToken;
}

View File

@@ -0,0 +1,188 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpCompress.Common;
using SharpCompress.IO;
using Xunit;
namespace SharpCompress.Test;
public class BinaryReaderParityTests : TestBase
{
private readonly byte[] _testData;
public BinaryReaderParityTests()
{
// Create test data with various patterns
_testData = new byte[256];
for (int i = 0; i < 256; i++)
{
_testData[i] = (byte)i;
}
}
[Fact]
public async Task ReadByte_Parity()
{
using var syncStream = new MemoryStream(_testData);
using var asyncStream = new MemoryStream(_testData);
using var syncReader = new BinaryReader(syncStream);
using var asyncReader = new AsyncBinaryReader(asyncStream);
for (int i = 0; i < 10; i++)
{
byte syncByte = syncReader.ReadByte();
byte asyncByte = await asyncReader.ReadByteAsync();
Assert.Equal(syncByte, asyncByte);
}
}
[Fact]
public async Task ReadBytes_Parity()
{
using var syncStream = new MemoryStream(_testData);
using var asyncStream = new MemoryStream(_testData);
using var syncReader = new BinaryReader(syncStream);
using var asyncReader = new AsyncBinaryReader(asyncStream);
var syncBytes = syncReader.ReadBytes(32);
var asyncBuffer = new byte[32];
await asyncReader.ReadBytesAsync(asyncBuffer, 0, 32);
Assert.Equal(syncBytes, asyncBuffer);
}
[Fact]
public async Task ReadUInt16_Parity()
{
using var syncStream = new MemoryStream(_testData);
using var asyncStream = new MemoryStream(_testData);
using var syncReader = new BinaryReader(syncStream);
using var asyncReader = new AsyncBinaryReader(asyncStream);
ushort syncValue = syncReader.ReadUInt16();
ushort asyncValue = await asyncReader.ReadUInt16Async();
Assert.Equal(syncValue, asyncValue);
}
[Fact]
public async Task ReadUInt32_Parity()
{
using var syncStream = new MemoryStream(_testData);
using var asyncStream = new MemoryStream(_testData);
using var syncReader = new BinaryReader(syncStream);
using var asyncReader = new AsyncBinaryReader(asyncStream);
uint syncValue = syncReader.ReadUInt32();
uint asyncValue = await asyncReader.ReadUInt32Async();
Assert.Equal(syncValue, asyncValue);
}
[Fact]
public async Task ReadUInt64_Parity()
{
using var syncStream = new MemoryStream(_testData);
using var asyncStream = new MemoryStream(_testData);
using var syncReader = new BinaryReader(syncStream);
using var asyncReader = new AsyncBinaryReader(asyncStream);
ulong syncValue = syncReader.ReadUInt64();
ulong asyncValue = await asyncReader.ReadUInt64Async();
Assert.Equal(syncValue, asyncValue);
}
[Fact]
public void Position_Parity()
{
using var syncStream = new MemoryStream(_testData);
using var asyncStream = new MemoryStream(_testData);
using var syncReader = new BinaryReader(syncStream);
using var asyncReader = new AsyncBinaryReader(asyncStream);
// Read some bytes
syncReader.ReadBytes(10);
var asyncBuffer = new byte[10];
asyncReader.ReadBytesAsync(asyncBuffer, 0, 10).AsTask().Wait();
Assert.Equal(syncStream.Position, asyncStream.Position);
Assert.Equal(syncReader.BaseStream.Position, asyncReader.BaseStream.Position);
}
[Fact]
public async Task MultipleReads_Parity()
{
using var syncStream = new MemoryStream(_testData);
using var asyncStream = new MemoryStream(_testData);
using var syncReader = new BinaryReader(syncStream);
using var asyncReader = new AsyncBinaryReader(asyncStream);
// Mix of different read operations
Assert.Equal(syncReader.ReadByte(), await asyncReader.ReadByteAsync());
var syncBytes = new byte[16];
var asyncBytes = new byte[16];
syncStream.Read(syncBytes, 0, 16);
await asyncReader.ReadBytesAsync(asyncBytes, 0, 16);
Assert.Equal(syncBytes, asyncBytes);
Assert.Equal(syncReader.ReadUInt16(), await asyncReader.ReadUInt16Async());
Assert.Equal(syncReader.ReadUInt32(), await asyncReader.ReadUInt32Async());
Assert.Equal(syncReader.ReadUInt64(), await asyncReader.ReadUInt64Async());
}
[Fact]
public async Task ReadByte_Async_Properly_Async()
{
using var stream = new MemoryStream(_testData);
using var reader = new AsyncBinaryReader(stream);
var bytes = new byte[10];
for (int i = 0; i < 10; i++)
{
bytes[i] = await reader.ReadByteAsync();
}
Assert.Equal(_testData.Take(10).ToArray(), bytes);
}
[Fact]
public async Task ReadBytes_Async_Properly_Async()
{
using var stream = new MemoryStream(_testData);
using var reader = new AsyncBinaryReader(stream);
var buffer = new byte[64];
await reader.ReadBytesAsync(buffer, 0, 64);
Assert.Equal(_testData.Take(64).ToArray(), buffer);
}
[Fact]
public async Task SkipAsync_Moves_Position_Correctly()
{
using var stream = new MemoryStream(_testData);
using var reader = new AsyncBinaryReader(stream);
await reader.SkipAsync(10);
Assert.Equal(10, stream.Position);
Assert.Equal(10, reader.BaseStream.Position);
}
[Fact]
public async Task SkipAsync_Then_Read_Works_Correctly()
{
using var stream = new MemoryStream(_testData);
using var reader = new AsyncBinaryReader(stream);
await reader.SkipAsync(10);
byte b = await reader.ReadByteAsync();
Assert.Equal(_testData[10], b);
}
}

View File

@@ -0,0 +1,258 @@
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using SharpCompress.Common.Rar;
using SharpCompress.IO;
using Xunit;
namespace SharpCompress.Test;
public class MarkingBinaryReaderParityTests : TestBase
{
private readonly byte[] _testData;
public MarkingBinaryReaderParityTests()
{
// Create test data with various patterns
_testData = new byte[256];
for (int i = 0; i < 256; i++)
{
_testData[i] = (byte)i;
}
}
[Fact]
public void Mark_Resets_ByteCount()
{
using var stream = new MemoryStream(_testData);
var reader = new MarkingBinaryReader(stream);
reader.ReadBytes(10);
Assert.Equal(10, reader.CurrentReadByteCount);
reader.Mark();
Assert.Equal(0, reader.CurrentReadByteCount);
reader.ReadBytes(5);
Assert.Equal(5, reader.CurrentReadByteCount);
}
[Fact]
public async Task Mark_Resets_ByteCount_Async()
{
using var stream = new MemoryStream(_testData);
var reader = new AsyncMarkingBinaryReader(stream);
await reader.ReadBytesAsync(10);
Assert.Equal(10, reader.CurrentReadByteCount);
reader.Mark();
Assert.Equal(0, reader.CurrentReadByteCount);
await reader.ReadBytesAsync(5);
Assert.Equal(5, reader.CurrentReadByteCount);
}
[Fact]
public void ReadByte_Updates_ByteCount()
{
using var stream = new MemoryStream(_testData);
var reader = new MarkingBinaryReader(stream);
reader.Mark();
reader.ReadByte();
Assert.Equal(1, reader.CurrentReadByteCount);
reader.ReadByte();
Assert.Equal(2, reader.CurrentReadByteCount);
}
[Fact]
public async Task ReadByte_Updates_ByteCount_Async()
{
using var stream = new MemoryStream(_testData);
var reader = new AsyncMarkingBinaryReader(stream);
reader.Mark();
await reader.ReadByteAsync();
Assert.Equal(1, reader.CurrentReadByteCount);
await reader.ReadByteAsync();
Assert.Equal(2, reader.CurrentReadByteCount);
}
[Fact]
public void ReadBytes_Updates_ByteCount()
{
using var stream = new MemoryStream(_testData);
var reader = new MarkingBinaryReader(stream);
reader.Mark();
reader.ReadBytes(16);
Assert.Equal(16, reader.CurrentReadByteCount);
reader.ReadBytes(8);
Assert.Equal(24, reader.CurrentReadByteCount);
}
[Fact]
public async Task ReadBytes_Updates_ByteCount_Async()
{
using var stream = new MemoryStream(_testData);
var reader = new AsyncMarkingBinaryReader(stream);
reader.Mark();
await reader.ReadBytesAsync(16);
Assert.Equal(16, reader.CurrentReadByteCount);
await reader.ReadBytesAsync(8);
Assert.Equal(24, reader.CurrentReadByteCount);
}
[Fact]
public void ReadUInt16_Updates_ByteCount()
{
using var stream = new MemoryStream(_testData);
var reader = new MarkingBinaryReader(stream);
reader.Mark();
reader.ReadUInt16();
Assert.Equal(2, reader.CurrentReadByteCount);
}
[Fact]
public async Task ReadUInt16_Updates_ByteCount_Async()
{
using var stream = new MemoryStream(_testData);
var reader = new AsyncMarkingBinaryReader(stream);
reader.Mark();
await reader.ReadUInt16Async();
Assert.Equal(2, reader.CurrentReadByteCount);
}
[Fact]
public void ReadUInt32_Updates_ByteCount()
{
using var stream = new MemoryStream(_testData);
var reader = new MarkingBinaryReader(stream);
reader.Mark();
reader.ReadUInt32();
Assert.Equal(4, reader.CurrentReadByteCount);
}
[Fact]
public async Task ReadUInt32_Updates_ByteCount_Async()
{
using var stream = new MemoryStream(_testData);
var reader = new AsyncMarkingBinaryReader(stream);
reader.Mark();
await reader.ReadUInt32Async();
Assert.Equal(4, reader.CurrentReadByteCount);
}
[Fact]
public void ReadRarVInt_Updates_ByteCount()
{
// Create valid RAR v-int data: 0x05 (value 5, no continuation bit)
var data = new byte[] { 0x05, 0x85, 0x01, 0x00 }; // 0x05, then 0x85 0x01 (value 5 + 128 = 133)
using var stream = new MemoryStream(data);
var reader = new MarkingBinaryReader(stream);
reader.Mark();
// Read a single-byte v-int (value 5, no continuation bit)
reader.ReadRarVInt();
Assert.Equal(1, reader.CurrentReadByteCount);
reader.Mark();
// Read a two-byte v-int (0x85 means continuation, then 0x01)
reader.ReadRarVInt();
Assert.Equal(2, reader.CurrentReadByteCount);
}
[Fact]
public async Task ReadRarVInt_Updates_ByteCount_Async()
{
// Create valid RAR v-int data: 0x05 (value 5, no continuation bit)
var data = new byte[] { 0x05, 0x85, 0x01, 0x00 };
using var stream = new MemoryStream(data);
var reader = new AsyncMarkingBinaryReader(stream);
reader.Mark();
// Read a single-byte v-int (value 5, no continuation bit)
await reader.ReadRarVIntAsync();
Assert.Equal(1, reader.CurrentReadByteCount);
reader.Mark();
// Read a two-byte v-int (0x85 means continuation, then 0x01)
await reader.ReadRarVIntAsync();
Assert.Equal(2, reader.CurrentReadByteCount);
}
[Fact]
public async Task Sync_Async_ByteCount_Parity()
{
using var syncStream = new MemoryStream(_testData);
using var asyncStream = new MemoryStream(_testData);
var syncReader = new MarkingBinaryReader(syncStream);
var asyncReader = new AsyncMarkingBinaryReader(asyncStream);
syncReader.Mark();
asyncReader.Mark();
// Read bytes with sync
syncReader.ReadByte();
syncReader.ReadByte();
syncReader.ReadUInt16();
syncReader.ReadUInt32();
syncReader.ReadBytes(8);
var syncCount = syncReader.CurrentReadByteCount;
// Read bytes with async
await asyncReader.ReadByteAsync();
await asyncReader.ReadByteAsync();
await asyncReader.ReadUInt16Async();
await asyncReader.ReadUInt32Async();
await asyncReader.ReadBytesAsync(8);
var asyncCount = asyncReader.CurrentReadByteCount;
Assert.Equal(syncCount, asyncCount);
Assert.Equal(16, syncCount);
Assert.Equal(16, asyncCount);
}
[Fact]
public async Task Sync_Async_ByteCount_Parity_Alt()
{
using var syncStream = new MemoryStream(_testData);
using var asyncStream = new MemoryStream(_testData);
var syncReader = new MarkingBinaryReader(syncStream);
var asyncReader = new AsyncMarkingBinaryReader(asyncStream);
syncReader.Mark();
asyncReader.Mark();
// Read bytes with sync
syncReader.ReadByte();
syncReader.ReadByte();
syncReader.ReadUInt16();
syncReader.ReadUInt32();
syncReader.ReadBytes(8);
var syncCount = syncReader.CurrentReadByteCount;
// Read bytes with async
await asyncReader.ReadByteAsync();
await asyncReader.ReadByteAsync();
await asyncReader.ReadUInt16Async();
await asyncReader.ReadUInt32Async();
await asyncReader.ReadBytesAsync(8);
var asyncCount = asyncReader.CurrentReadByteCount;
Assert.Equal(syncCount, asyncCount);
Assert.Equal(16, syncCount);
Assert.Equal(16, asyncCount);
}
}