mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-07-09 02:26:47 +00:00
Merge remote-tracking branch 'origin/release' into copilot/fix-async-only-stream-writes
This commit is contained in:
@@ -45,7 +45,21 @@ internal class AsyncMarkingBinaryReader : IDisposable
|
||||
{
|
||||
CurrentReadByteCount += count;
|
||||
var bytes = new byte[count];
|
||||
await _reader.ReadBytesAsync(bytes, 0, count, cancellationToken).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
await _reader.ReadBytesAsync(bytes, 0, count, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (IncompleteArchiveException ex)
|
||||
{
|
||||
throw new InvalidFormatException(
|
||||
string.Format(
|
||||
Constants.DefaultCultureInfo,
|
||||
"Could not read the requested amount of bytes. End of stream reached. Requested: {0}",
|
||||
count
|
||||
),
|
||||
ex
|
||||
);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
@@ -281,13 +281,13 @@ internal class ModelPpm
|
||||
|
||||
internal bool DecodeInit(IRarUnpack unpackRead, int escChar)
|
||||
{
|
||||
var maxOrder = unpackRead.Char & 0xff;
|
||||
var maxOrder = unpackRead.ReadChar() & 0xff;
|
||||
var reset = ((maxOrder & 0x20) != 0);
|
||||
|
||||
var maxMb = 0;
|
||||
if (reset)
|
||||
{
|
||||
maxMb = unpackRead.Char;
|
||||
maxMb = unpackRead.ReadChar();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -298,7 +298,7 @@ internal class ModelPpm
|
||||
}
|
||||
if ((maxOrder & 0x40) != 0)
|
||||
{
|
||||
escChar = unpackRead.Char;
|
||||
escChar = unpackRead.ReadChar();
|
||||
unpackRead.PpmEscChar = escChar;
|
||||
}
|
||||
Coder = new RangeCoder(unpackRead);
|
||||
@@ -333,6 +333,65 @@ internal class ModelPpm
|
||||
return (_minContext.Address != 0);
|
||||
}
|
||||
|
||||
internal async ValueTask<bool> DecodeInitAsync(
|
||||
IRarUnpack unpackRead,
|
||||
int escChar,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var maxOrder =
|
||||
await unpackRead.ReadCharAsync(cancellationToken).ConfigureAwait(false) & 0xff;
|
||||
var reset = ((maxOrder & 0x20) != 0);
|
||||
|
||||
var maxMb = 0;
|
||||
if (reset)
|
||||
{
|
||||
maxMb = await unpackRead.ReadCharAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SubAlloc.GetAllocatedMemory() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ((maxOrder & 0x40) != 0)
|
||||
{
|
||||
escChar = await unpackRead.ReadCharAsync(cancellationToken).ConfigureAwait(false);
|
||||
unpackRead.PpmEscChar = escChar;
|
||||
}
|
||||
Coder = new RangeCoder();
|
||||
await Coder.InitAsync(unpackRead, cancellationToken).ConfigureAwait(false);
|
||||
if (reset)
|
||||
{
|
||||
maxOrder = (maxOrder & 0x1f) + 1;
|
||||
if (maxOrder > 16)
|
||||
{
|
||||
maxOrder = 16 + ((maxOrder - 16) * 3);
|
||||
}
|
||||
if (maxOrder == 1)
|
||||
{
|
||||
SubAlloc.StopSubAllocator();
|
||||
return false;
|
||||
}
|
||||
SubAlloc.StartSubAllocator((maxMb + 1) << 20);
|
||||
_minContext = new PpmContext(Heap);
|
||||
|
||||
_maxContext = new PpmContext(Heap);
|
||||
FoundState = new State(Heap);
|
||||
_dummySee2Cont = new See2Context();
|
||||
for (var i = 0; i < 25; i++)
|
||||
{
|
||||
for (var j = 0; j < 16; j++)
|
||||
{
|
||||
_see2Cont[i][j] = new See2Context();
|
||||
}
|
||||
}
|
||||
StartModelRare(maxOrder);
|
||||
}
|
||||
return _minContext.Address != 0;
|
||||
}
|
||||
|
||||
public virtual int DecodeChar()
|
||||
{
|
||||
// Debug
|
||||
|
||||
@@ -19,7 +19,7 @@ internal class RangeCoder
|
||||
private long _low,
|
||||
_code,
|
||||
_range;
|
||||
private readonly IRarUnpack _unpackRead;
|
||||
private IRarUnpack _unpackRead;
|
||||
private readonly Stream _stream;
|
||||
|
||||
internal RangeCoder(IRarUnpack unpackRead)
|
||||
@@ -36,6 +36,24 @@ internal class RangeCoder
|
||||
|
||||
internal RangeCoder() { }
|
||||
|
||||
internal async ValueTask InitAsync(
|
||||
IRarUnpack unpackRead,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
_unpackRead = unpackRead;
|
||||
SubRange = new SubRange();
|
||||
|
||||
_low = _code = 0L;
|
||||
_range = 0xFFFFffffL;
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
_code =
|
||||
((_code << 8) | await ReadCharAsync(cancellationToken).ConfigureAwait(false))
|
||||
& UINT_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
private void Init()
|
||||
{
|
||||
SubRange = new SubRange();
|
||||
@@ -44,7 +62,7 @@ internal class RangeCoder
|
||||
_range = 0xFFFFffffL;
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
_code = ((_code << 8) | Char) & UINT_MASK;
|
||||
_code = ((_code << 8) | ReadChar()) & UINT_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,20 +91,17 @@ internal class RangeCoder
|
||||
}
|
||||
}
|
||||
|
||||
private long Char
|
||||
private long ReadChar()
|
||||
{
|
||||
get
|
||||
if (_unpackRead != null)
|
||||
{
|
||||
if (_unpackRead != null)
|
||||
{
|
||||
return (_unpackRead.Char);
|
||||
}
|
||||
if (_stream != null)
|
||||
{
|
||||
return _stream.ReadByte();
|
||||
}
|
||||
return -1;
|
||||
return (_unpackRead.ReadChar());
|
||||
}
|
||||
if (_stream != null)
|
||||
{
|
||||
return _stream.ReadByte();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
internal SubRange SubRange { get; private set; }
|
||||
@@ -121,7 +136,7 @@ internal class RangeCoder
|
||||
_range = (-_low & (BOT - 1)) & UINT_MASK;
|
||||
c2 = false;
|
||||
}
|
||||
_code = ((_code << 8) | Char) & UINT_MASK;
|
||||
_code = ((_code << 8) | ReadChar()) & UINT_MASK;
|
||||
_range = (_range << 8) & UINT_MASK;
|
||||
_low = (_low << 8) & UINT_MASK;
|
||||
}
|
||||
@@ -131,7 +146,7 @@ internal class RangeCoder
|
||||
{
|
||||
if (_unpackRead != null)
|
||||
{
|
||||
return _unpackRead.Char;
|
||||
return await _unpackRead.ReadCharAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
if (_stream != null)
|
||||
{
|
||||
|
||||
@@ -22,6 +22,7 @@ internal interface IRarUnpack
|
||||
bool Suspended { get; set; }
|
||||
|
||||
long DestSize { get; }
|
||||
int Char { get; }
|
||||
int ReadChar();
|
||||
ValueTask<int> ReadCharAsync(CancellationToken cancellationToken);
|
||||
int PpmEscChar { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -112,7 +113,10 @@ internal sealed partial class Unpack
|
||||
{
|
||||
return;
|
||||
}
|
||||
if ((!solid || !tablesRead) && !ReadTables())
|
||||
if (
|
||||
(!solid || !tablesRead)
|
||||
&& !await ReadTablesAsync(cancellationToken).ConfigureAwait(false)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -137,7 +141,7 @@ internal sealed partial class Unpack
|
||||
|
||||
if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 260 && wrPtr != unpPtr)
|
||||
{
|
||||
UnpWriteBuf();
|
||||
await UnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (destUnpSize < 0)
|
||||
{
|
||||
return;
|
||||
@@ -150,7 +154,7 @@ internal sealed partial class Unpack
|
||||
}
|
||||
if (unpBlockType == BlockTypes.BLOCK_PPM)
|
||||
{
|
||||
var Ch = ppm.DecodeChar();
|
||||
var Ch = await ppm.DecodeCharAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (Ch == -1)
|
||||
{
|
||||
ppmError = true;
|
||||
@@ -158,10 +162,10 @@ internal sealed partial class Unpack
|
||||
}
|
||||
if (Ch == PpmEscChar)
|
||||
{
|
||||
var NextCh = ppm.DecodeChar();
|
||||
var NextCh = await ppm.DecodeCharAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (NextCh == 0)
|
||||
{
|
||||
if (!ReadTables())
|
||||
if (!await ReadTablesAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -173,7 +177,7 @@ internal sealed partial class Unpack
|
||||
}
|
||||
if (NextCh == 3)
|
||||
{
|
||||
if (!ReadVMCodePPM())
|
||||
if (!await ReadVMCodePPMAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -186,7 +190,8 @@ internal sealed partial class Unpack
|
||||
var failed = false;
|
||||
for (var I = 0; I < 4 && !failed; I++)
|
||||
{
|
||||
var ch = ppm.DecodeChar();
|
||||
var ch = await ppm.DecodeCharAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (ch == -1)
|
||||
{
|
||||
failed = true;
|
||||
@@ -212,7 +217,8 @@ internal sealed partial class Unpack
|
||||
}
|
||||
if (NextCh == 5)
|
||||
{
|
||||
var Length = ppm.DecodeChar();
|
||||
var Length = await ppm.DecodeCharAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (Length == -1)
|
||||
{
|
||||
break;
|
||||
@@ -294,7 +300,7 @@ internal sealed partial class Unpack
|
||||
}
|
||||
if (Number == 256)
|
||||
{
|
||||
if (!ReadEndOfBlock())
|
||||
if (!await ReadEndOfBlockAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -302,7 +308,7 @@ internal sealed partial class Unpack
|
||||
}
|
||||
if (Number == 257)
|
||||
{
|
||||
if (!ReadVMCode())
|
||||
if (!await ReadVMCodeAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -350,7 +356,7 @@ internal sealed partial class Unpack
|
||||
CopyString(2, Distance);
|
||||
}
|
||||
}
|
||||
UnpWriteBuf();
|
||||
await UnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task UnpWriteBufAsync(CancellationToken cancellationToken = default)
|
||||
@@ -600,4 +606,267 @@ internal sealed partial class Unpack
|
||||
writtenFileSize += size;
|
||||
destUnpSize -= size;
|
||||
}
|
||||
|
||||
private async Task<bool> ReadTablesAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var bitLengthArray = ArrayPool<byte>.Shared.Rent(PackDef.BC);
|
||||
var bitLength = new Memory<byte>(bitLengthArray, 0, PackDef.BC);
|
||||
var tableArray = ArrayPool<byte>.Shared.Rent(PackDef.HUFF_TABLE_SIZE);
|
||||
var table = new Memory<byte>(tableArray, 0, PackDef.HUFF_TABLE_SIZE);
|
||||
|
||||
try
|
||||
{
|
||||
if (inAddr > readTop - 25)
|
||||
{
|
||||
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
AddBits((8 - inBit) & 7);
|
||||
long bitField = GetBits() & unchecked((int)0xffFFffFF);
|
||||
if ((bitField & 0x8000) != 0)
|
||||
{
|
||||
unpBlockType = BlockTypes.BLOCK_PPM;
|
||||
return await ppm.DecodeInitAsync(this, PpmEscChar, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
unpBlockType = BlockTypes.BLOCK_LZ;
|
||||
|
||||
prevLowDist = 0;
|
||||
lowDistRepCount = 0;
|
||||
|
||||
if ((bitField & 0x4000) == 0)
|
||||
{
|
||||
new Span<byte>(unpOldTable).Clear();
|
||||
}
|
||||
|
||||
AddBits(2);
|
||||
|
||||
for (var i = 0; i < PackDef.BC; i++)
|
||||
{
|
||||
var length = (Utility.URShift(GetBits(), 12)) & 0xFF;
|
||||
AddBits(4);
|
||||
if (length == 15)
|
||||
{
|
||||
var zeroCount = (Utility.URShift(GetBits(), 12)) & 0xFF;
|
||||
AddBits(4);
|
||||
if (zeroCount == 0)
|
||||
{
|
||||
bitLength.Span[i] = 15;
|
||||
}
|
||||
else
|
||||
{
|
||||
zeroCount += 2;
|
||||
while (zeroCount-- > 0 && i < bitLength.Length)
|
||||
{
|
||||
bitLength.Span[i++] = 0;
|
||||
}
|
||||
|
||||
i--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bitLength.Span[i] = (byte)length;
|
||||
}
|
||||
}
|
||||
|
||||
UnpackUtility.makeDecodeTables(bitLength.Span, 0, BD, PackDef.BC);
|
||||
|
||||
var TableSize = PackDef.HUFF_TABLE_SIZE;
|
||||
|
||||
for (var i = 0; i < TableSize; )
|
||||
{
|
||||
if (inAddr > readTop - 5)
|
||||
{
|
||||
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var Number = this.decodeNumber(BD);
|
||||
if (Number < 16)
|
||||
{
|
||||
table.Span[i] = (byte)((Number + unpOldTable[i]) & 0xf);
|
||||
i++;
|
||||
}
|
||||
else if (Number < 18)
|
||||
{
|
||||
int N;
|
||||
if (Number == 16)
|
||||
{
|
||||
N = (Utility.URShift(GetBits(), 13)) + 3;
|
||||
AddBits(3);
|
||||
}
|
||||
else
|
||||
{
|
||||
N = (Utility.URShift(GetBits(), 9)) + 11;
|
||||
AddBits(7);
|
||||
}
|
||||
|
||||
while (N-- > 0 && i < TableSize)
|
||||
{
|
||||
table.Span[i] = table.Span[i - 1];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int N;
|
||||
if (Number == 18)
|
||||
{
|
||||
N = (Utility.URShift(GetBits(), 13)) + 3;
|
||||
AddBits(3);
|
||||
}
|
||||
else
|
||||
{
|
||||
N = (Utility.URShift(GetBits(), 9)) + 11;
|
||||
AddBits(7);
|
||||
}
|
||||
|
||||
while (N-- > 0 && i < TableSize)
|
||||
{
|
||||
table.Span[i++] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tablesRead = true;
|
||||
if (inAddr > readTop)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
UnpackUtility.makeDecodeTables(table.Span, 0, LD, PackDef.NC);
|
||||
UnpackUtility.makeDecodeTables(table.Span, PackDef.NC, DD, PackDef.DC);
|
||||
UnpackUtility.makeDecodeTables(table.Span, PackDef.NC + PackDef.DC, LDD, PackDef.LDC);
|
||||
UnpackUtility.makeDecodeTables(
|
||||
table.Span,
|
||||
PackDef.NC + PackDef.DC + PackDef.LDC,
|
||||
RD,
|
||||
PackDef.RC
|
||||
);
|
||||
|
||||
table.Span.CopyTo(unpOldTable);
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(bitLengthArray);
|
||||
ArrayPool<byte>.Shared.Return(tableArray);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> ReadEndOfBlockAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var BitField = GetBits();
|
||||
bool NewTable,
|
||||
NewFile = false;
|
||||
if ((BitField & 0x8000) != 0)
|
||||
{
|
||||
NewTable = true;
|
||||
AddBits(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
NewFile = true;
|
||||
NewTable = (BitField & 0x4000) != 0;
|
||||
AddBits(2);
|
||||
}
|
||||
tablesRead = !NewTable;
|
||||
return !(
|
||||
NewFile || NewTable && !await ReadTablesAsync(cancellationToken).ConfigureAwait(false)
|
||||
);
|
||||
}
|
||||
|
||||
private async Task<bool> ReadVMCodeAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var FirstByte = GetBits() >> 8;
|
||||
AddBits(8);
|
||||
var Length = (FirstByte & 7) + 1;
|
||||
if (Length == 7)
|
||||
{
|
||||
Length = (GetBits() >> 8) + 7;
|
||||
AddBits(8);
|
||||
}
|
||||
else if (Length == 8)
|
||||
{
|
||||
Length = GetBits();
|
||||
AddBits(16);
|
||||
}
|
||||
|
||||
var vmCode = new List<byte>();
|
||||
for (var I = 0; I < Length; I++)
|
||||
{
|
||||
if (
|
||||
inAddr >= readTop - 1
|
||||
&& !await unpReadBufAsync(cancellationToken).ConfigureAwait(false)
|
||||
&& I < Length - 1
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
vmCode.Add((byte)(GetBits() >> 8));
|
||||
AddBits(8);
|
||||
}
|
||||
return AddVMCode(FirstByte, vmCode);
|
||||
}
|
||||
|
||||
public async ValueTask<int> ReadCharAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (inAddr > MAX_SIZE - 30)
|
||||
{
|
||||
await unpReadBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
return InBuf[inAddr++] & 0xff;
|
||||
}
|
||||
|
||||
private async Task<bool> ReadVMCodePPMAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var FirstByte = await ppm.DecodeCharAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (FirstByte == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var Length = (FirstByte & 7) + 1;
|
||||
if (Length == 7)
|
||||
{
|
||||
var B1 = await ppm.DecodeCharAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (B1 == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Length = B1 + 7;
|
||||
}
|
||||
else if (Length == 8)
|
||||
{
|
||||
var B1 = await ppm.DecodeCharAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (B1 == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var B2 = await ppm.DecodeCharAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (B2 == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Length = (B1 * 256) + B2;
|
||||
}
|
||||
|
||||
var vmCode = new List<byte>();
|
||||
for (var I = 0; I < Length; I++)
|
||||
{
|
||||
var Ch = await ppm.DecodeCharAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (Ch == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
vmCode.Add((byte)Ch);
|
||||
}
|
||||
return AddVMCode(FirstByte, vmCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,16 +55,13 @@ internal sealed partial class Unpack : BitInput, IRarUnpack
|
||||
set => suspended = value;
|
||||
}
|
||||
|
||||
public int Char
|
||||
public int ReadChar()
|
||||
{
|
||||
get
|
||||
if (inAddr > MAX_SIZE - 30)
|
||||
{
|
||||
if (inAddr > MAX_SIZE - 30)
|
||||
{
|
||||
unpReadBuf();
|
||||
}
|
||||
return (InBuf[inAddr++] & 0xff);
|
||||
unpReadBuf();
|
||||
}
|
||||
return (InBuf[inAddr++] & 0xff);
|
||||
}
|
||||
|
||||
public int PpmEscChar { get; set; }
|
||||
|
||||
@@ -48,7 +48,7 @@ internal partial class Unpack
|
||||
}
|
||||
if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 270 && wrPtr != unpPtr)
|
||||
{
|
||||
oldUnpWriteBuf();
|
||||
await oldUnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (suspended)
|
||||
{
|
||||
return;
|
||||
@@ -105,7 +105,7 @@ internal partial class Unpack
|
||||
}
|
||||
}
|
||||
}
|
||||
oldUnpWriteBuf();
|
||||
await oldUnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task<bool> unpReadBufAsync(CancellationToken cancellationToken = default)
|
||||
|
||||
@@ -45,7 +45,7 @@ internal partial class Unpack
|
||||
}
|
||||
if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 270 && wrPtr != unpPtr)
|
||||
{
|
||||
oldUnpWriteBuf();
|
||||
await oldUnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (suspended)
|
||||
{
|
||||
return;
|
||||
@@ -157,8 +157,8 @@ internal partial class Unpack
|
||||
CopyString20(2, Distance);
|
||||
}
|
||||
}
|
||||
ReadLastTables();
|
||||
oldUnpWriteBuf();
|
||||
await ReadLastTablesAsync(cancellationToken).ConfigureAwait(false);
|
||||
await oldUnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task<bool> ReadTables20Async(CancellationToken cancellationToken = default)
|
||||
@@ -272,4 +272,25 @@ internal partial class Unpack
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task ReadLastTablesAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (readTop >= inAddr + 5)
|
||||
{
|
||||
if (UnpAudioBlock != 0)
|
||||
{
|
||||
if (this.decodeNumber(MD[UnpCurChannel]) == 256)
|
||||
{
|
||||
await ReadTables20Async(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.decodeNumber(LD) == 269)
|
||||
{
|
||||
await ReadTables20Async(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ internal partial class Unpack
|
||||
// So we can safefly use these tables below.
|
||||
if (
|
||||
!await ReadBlockHeaderAsync(cancellationToken).ConfigureAwait(false)
|
||||
|| !ReadTables()
|
||||
|| !await ReadTablesAsync(cancellationToken).ConfigureAwait(false)
|
||||
|| !TablesRead5
|
||||
)
|
||||
{
|
||||
@@ -101,7 +101,7 @@ internal partial class Unpack
|
||||
}
|
||||
if (
|
||||
!await ReadBlockHeaderAsync(cancellationToken).ConfigureAwait(false)
|
||||
|| !ReadTables()
|
||||
|| !await ReadTablesAsync(cancellationToken).ConfigureAwait(false)
|
||||
)
|
||||
{
|
||||
return;
|
||||
@@ -118,7 +118,7 @@ internal partial class Unpack
|
||||
&& WriteBorder != UnpPtr
|
||||
)
|
||||
{
|
||||
UnpWriteBuf();
|
||||
await UnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (WrittenFileSize > DestUnpSize)
|
||||
{
|
||||
return;
|
||||
@@ -197,7 +197,7 @@ internal partial class Unpack
|
||||
var Filter = new UnpackFilter();
|
||||
if (
|
||||
!await ReadFilterAsync(Filter, cancellationToken).ConfigureAwait(false)
|
||||
|| !AddFilter(Filter)
|
||||
|| !await AddFilterAsync(Filter, cancellationToken).ConfigureAwait(false)
|
||||
)
|
||||
{
|
||||
break;
|
||||
@@ -232,7 +232,7 @@ internal partial class Unpack
|
||||
continue;
|
||||
}
|
||||
}
|
||||
UnpWriteBuf();
|
||||
await UnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task<bool> ReadBlockHeaderAsync(CancellationToken cancellationToken = default)
|
||||
@@ -318,4 +318,24 @@ internal partial class Unpack
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task<bool> AddFilterAsync(
|
||||
UnpackFilter Filter,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (Filters.Count >= MAX_UNPACK_FILTERS)
|
||||
{
|
||||
await UnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (Filters.Count >= MAX_UNPACK_FILTERS)
|
||||
{
|
||||
InitFilters();
|
||||
}
|
||||
}
|
||||
|
||||
Filter.NextWindow = WrPtr != UnpPtr && ((WrPtr - UnpPtr) & MaxWinMask) <= Filter.BlockStart;
|
||||
Filter.uBlockStart = (uint)((Filter.BlockStart + UnpPtr) & MaxWinMask);
|
||||
Filters.Add(Filter);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,17 +154,25 @@ internal partial class Unpack : IRarUnpack
|
||||
|
||||
public long DestSize => DestUnpSize;
|
||||
|
||||
public int Char
|
||||
public int ReadChar()
|
||||
{
|
||||
get
|
||||
// TODO: coderb: not sure where the "MAXSIZE-30" comes from, ported from V1 code
|
||||
if (InAddr > MAX_SIZE - 30)
|
||||
{
|
||||
// TODO: coderb: not sure where the "MAXSIZE-30" comes from, ported from V1 code
|
||||
if (InAddr > MAX_SIZE - 30)
|
||||
{
|
||||
UnpReadBuf();
|
||||
}
|
||||
return InBuf[InAddr++];
|
||||
UnpReadBuf();
|
||||
}
|
||||
return InBuf[InAddr++];
|
||||
}
|
||||
|
||||
public async ValueTask<int> ReadCharAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
// TODO: coderb: not sure where the "MAXSIZE-30" comes from, ported from V1 code
|
||||
if (InAddr > MAX_SIZE - 30)
|
||||
{
|
||||
await UnpReadBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
return InBuf[InAddr++];
|
||||
}
|
||||
|
||||
public int PpmEscChar
|
||||
|
||||
@@ -41,7 +41,7 @@ internal partial class Unpack
|
||||
|
||||
if (((WrPtr - UnpPtr) & MaxWinMask) < 270 && WrPtr != UnpPtr)
|
||||
{
|
||||
UnpWriteBuf20();
|
||||
await UnpWriteBuf20Async(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (StMode != 0)
|
||||
@@ -95,6 +95,6 @@ internal partial class Unpack
|
||||
}
|
||||
}
|
||||
}
|
||||
UnpWriteBuf20();
|
||||
await UnpWriteBuf20Async(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ internal partial class Unpack
|
||||
|
||||
if (((WrPtr - UnpPtr) & MaxWinMask) < 270 && WrPtr != UnpPtr)
|
||||
{
|
||||
UnpWriteBuf20();
|
||||
await UnpWriteBuf20Async(cancellationToken).ConfigureAwait(false);
|
||||
if (Suspended)
|
||||
{
|
||||
return;
|
||||
@@ -165,8 +165,8 @@ internal partial class Unpack
|
||||
continue;
|
||||
}
|
||||
}
|
||||
ReadLastTables();
|
||||
UnpWriteBuf20();
|
||||
await ReadLastTables20Async(cancellationToken).ConfigureAwait(false);
|
||||
await UnpWriteBuf20Async(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task UnpWriteBuf20Async(CancellationToken cancellationToken = default)
|
||||
@@ -316,4 +316,22 @@ internal partial class Unpack
|
||||
Array.Copy(Table, 0, this.UnpOldTable20, 0, UnpOldTable20.Length);
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task ReadLastTables20Async(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (ReadTop >= Inp.InAddr + 5)
|
||||
{
|
||||
if (UnpAudioBlock)
|
||||
{
|
||||
if (DecodeNumber(Inp, MD[UnpCurChannel]) == 256)
|
||||
{
|
||||
await ReadTables20Async(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
else if (DecodeNumber(Inp, BlockTables.LD) == 269)
|
||||
{
|
||||
await ReadTables20Async(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,15 +60,10 @@ public sealed class AsyncBinaryReader : IDisposable
|
||||
int offset,
|
||||
int count,
|
||||
CancellationToken ct = default
|
||||
)
|
||||
{
|
||||
await _stream.ReadExactAsync(bytes, offset, count, ct).ConfigureAwait(false);
|
||||
}
|
||||
) => await _stream.ReadExactAsync(bytes, offset, count, ct).ConfigureAwait(false);
|
||||
|
||||
public async ValueTask SkipAsync(int count, CancellationToken ct = default)
|
||||
{
|
||||
public async ValueTask SkipAsync(int count, CancellationToken ct = default) =>
|
||||
await _stream.SkipAsync(count, ct).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
@@ -5,14 +5,9 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace SharpCompress.Test.Mocks;
|
||||
|
||||
public class AsyncOnlyStream : Stream
|
||||
public class AsyncOnlyStream(Stream stream) : Stream
|
||||
{
|
||||
private readonly Stream _stream;
|
||||
|
||||
public AsyncOnlyStream(Stream stream)
|
||||
{
|
||||
_stream = stream ?? throw new ArgumentNullException(nameof(stream));
|
||||
}
|
||||
private readonly Stream _stream = stream ?? throw new ArgumentNullException(nameof(stream));
|
||||
|
||||
public override bool CanRead => _stream.CanRead;
|
||||
public override bool CanSeek => _stream.CanSeek;
|
||||
|
||||
@@ -13,6 +13,31 @@ namespace SharpCompress.Test.Rar;
|
||||
|
||||
public class RarArchiveAsyncTests : ArchiveTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("Rar15.rar")]
|
||||
[InlineData("Rar2.rar")]
|
||||
[InlineData("Rar.rar")]
|
||||
[InlineData("Rar.Audio_program.rar")]
|
||||
[InlineData("Rar5.rar")]
|
||||
[InlineData("Rar5.solid.rar")]
|
||||
public async ValueTask Rar_Archive_Recently_Changed_Unpackers_Async(string filename)
|
||||
{
|
||||
var extractedEntries = 0;
|
||||
await using var archive = await RarArchive.OpenAsyncArchive(
|
||||
Path.Combine(TEST_ARCHIVES_PATH, filename),
|
||||
new ReaderOptions { LookForHeader = true }
|
||||
);
|
||||
|
||||
await foreach (var entry in archive.EntriesAsync.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
using var output = new AsyncOnlyStream(new MemoryStream());
|
||||
await entry.WriteToAsync(output);
|
||||
extractedEntries++;
|
||||
}
|
||||
|
||||
Assert.True(extractedEntries > 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async ValueTask Rar_EncryptedFileAndHeader_Archive_Async() =>
|
||||
await ReadRarPasswordAsync("Rar.encrypted_filesAndHeader.rar", "test");
|
||||
|
||||
@@ -13,6 +13,32 @@ namespace SharpCompress.Test.Rar;
|
||||
|
||||
public class RarArchiveTests : ArchiveTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("Rar15.rar")]
|
||||
[InlineData("Rar2.rar")]
|
||||
[InlineData("Rar.rar")]
|
||||
[InlineData("Rar.Audio_program.rar")]
|
||||
[InlineData("Rar5.rar")]
|
||||
[InlineData("Rar5.solid.rar")]
|
||||
public void Rar_Archive_Recently_Changed_Unpackers_Sync(string filename)
|
||||
{
|
||||
var extractedEntries = 0;
|
||||
using var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename));
|
||||
using var archive = RarArchive.OpenArchive(
|
||||
stream,
|
||||
new ReaderOptions { LookForHeader = true }
|
||||
);
|
||||
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
using var output = new MemoryStream();
|
||||
entry.WriteTo(output);
|
||||
extractedEntries++;
|
||||
}
|
||||
|
||||
Assert.True(extractedEntries > 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Rar_EncryptedFileAndHeader_Archive() =>
|
||||
ReadRarPassword("Rar.encrypted_filesAndHeader.rar", "test");
|
||||
|
||||
@@ -14,6 +14,30 @@ namespace SharpCompress.Test.Rar;
|
||||
|
||||
public class RarReaderAsyncTests : ReaderTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("Rar15.rar")]
|
||||
[InlineData("Rar.rar")]
|
||||
[InlineData("Rar.Audio_program.rar")]
|
||||
[InlineData("Rar5.rar")]
|
||||
[InlineData("Rar5.solid.rar")]
|
||||
public async ValueTask Rar_Reader_Async_Uses_Only_Async_Stream_Operations(string filename)
|
||||
{
|
||||
using var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename));
|
||||
await using var reader = await ReaderFactory.OpenAsyncReader(
|
||||
new AsyncOnlyStream(stream),
|
||||
new ReaderOptions { LookForHeader = true }
|
||||
);
|
||||
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
using var output = new AsyncOnlyStream(new MemoryStream());
|
||||
await reader.WriteEntryToAsync(output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async ValueTask Rar_Multi_Reader_Async() =>
|
||||
await DoRar_Multi_Reader_Async([
|
||||
|
||||
Reference in New Issue
Block a user