mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-02-12 05:25:03 +00:00
Compare commits
13 Commits
adam/fix-e
...
copilot/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c825ae91a1 | ||
|
|
6478723a8d | ||
|
|
2c7e9b9c21 | ||
|
|
7f3da598d1 | ||
|
|
33e9c78626 | ||
|
|
6f50545c31 | ||
|
|
ab1dd45e9c | ||
|
|
cd5da3da5d | ||
|
|
218af5a8b3 | ||
|
|
e786c00767 | ||
|
|
103ae60631 | ||
|
|
8a54f253d5 | ||
|
|
d0baa16502 |
@@ -5,7 +5,7 @@
|
||||
<PackageVersion Include="AwesomeAssertions" Version="9.3.0" />
|
||||
<PackageVersion Include="Glob" Version="1.1.9" />
|
||||
<PackageVersion Include="JetBrains.Profiler.SelfApi" Version="2.5.16" />
|
||||
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="10.0.0" />
|
||||
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
|
||||
<PackageVersion Include="Mono.Posix.NETStandard" Version="1.0.0" />
|
||||
<PackageVersion Include="SimpleExec" Version="13.0.0" />
|
||||
|
||||
@@ -182,15 +182,15 @@ public partial class SevenZipArchive : AbstractArchive<SevenZipArchiveEntry, Sev
|
||||
);
|
||||
}
|
||||
|
||||
// Wrap with SyncOnlyStream to work around LZMA async bugs
|
||||
// Return a ReadOnlySubStream that reads from the shared folder stream
|
||||
return CreateEntryStream(
|
||||
new SyncOnlyStream(
|
||||
new ReadOnlySubStream(_currentFolderStream, entry.Size, leaveOpen: true)
|
||||
)
|
||||
new ReadOnlySubStream(_currentFolderStream, entry.Size, leaveOpen: true)
|
||||
);
|
||||
}
|
||||
|
||||
protected override ValueTask<EntryStream> GetEntryStreamAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
) => new(GetEntryStream());
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_currentFolderStream?.Dispose();
|
||||
|
||||
603
src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.Async.cs
Normal file
603
src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.Async.cs
Normal file
@@ -0,0 +1,603 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Rar.Headers;
|
||||
using SharpCompress.Compressors.Rar.UnpackV1.Decode;
|
||||
using SharpCompress.Compressors.Rar.UnpackV1.PPM;
|
||||
using SharpCompress.Compressors.Rar.VM;
|
||||
|
||||
namespace SharpCompress.Compressors.Rar.UnpackV1;
|
||||
|
||||
internal sealed partial class Unpack
|
||||
{
|
||||
public async Task DoUnpackAsync(
|
||||
FileHeader fileHeader,
|
||||
Stream readStream,
|
||||
Stream writeStream,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
destUnpSize = fileHeader.UncompressedSize;
|
||||
this.fileHeader = fileHeader;
|
||||
this.readStream = readStream;
|
||||
this.writeStream = writeStream;
|
||||
if (!fileHeader.IsSolid)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
suspended = false;
|
||||
await DoUnpackAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task DoUnpackAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (fileHeader.CompressionMethod == 0)
|
||||
{
|
||||
await UnstoreFileAsync(cancellationToken).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
switch (fileHeader.CompressionAlgorithm)
|
||||
{
|
||||
case 15:
|
||||
await unpack15Async(fileHeader.IsSolid, cancellationToken).ConfigureAwait(false);
|
||||
break;
|
||||
case 20:
|
||||
case 26:
|
||||
await unpack20Async(fileHeader.IsSolid, cancellationToken).ConfigureAwait(false);
|
||||
break;
|
||||
case 29:
|
||||
case 36:
|
||||
await Unpack29Async(fileHeader.IsSolid, cancellationToken).ConfigureAwait(false);
|
||||
break;
|
||||
case 50:
|
||||
await Unpack5Async(fileHeader.IsSolid, cancellationToken).ConfigureAwait(false);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidFormatException(
|
||||
"unknown rar compression version " + fileHeader.CompressionAlgorithm
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UnstoreFileAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var buffer = new byte[(int)Math.Min(0x10000, destUnpSize)];
|
||||
do
|
||||
{
|
||||
var code = await readStream
|
||||
.ReadAsync(buffer, 0, buffer.Length, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (code == 0 || code == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
code = code < destUnpSize ? code : (int)destUnpSize;
|
||||
await writeStream.WriteAsync(buffer, 0, code, cancellationToken).ConfigureAwait(false);
|
||||
destUnpSize -= code;
|
||||
} while (!suspended && destUnpSize > 0);
|
||||
}
|
||||
|
||||
private async Task Unpack29Async(bool solid, CancellationToken cancellationToken = default)
|
||||
{
|
||||
int[] DDecode = new int[PackDef.DC];
|
||||
byte[] DBits = new byte[PackDef.DC];
|
||||
|
||||
int Bits;
|
||||
|
||||
if (DDecode[1] == 0)
|
||||
{
|
||||
int Dist = 0,
|
||||
BitLength = 0,
|
||||
Slot = 0;
|
||||
for (var I = 0; I < DBitLengthCounts.Length; I++, BitLength++)
|
||||
{
|
||||
var count = DBitLengthCounts[I];
|
||||
for (var J = 0; J < count; J++, Slot++, Dist += (1 << BitLength))
|
||||
{
|
||||
DDecode[Slot] = Dist;
|
||||
DBits[Slot] = (byte)BitLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FileExtracted = true;
|
||||
|
||||
if (!suspended)
|
||||
{
|
||||
UnpInitData(solid);
|
||||
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if ((!solid || !tablesRead) && !ReadTables())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ppmError)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
unpPtr &= PackDef.MAXWINMASK;
|
||||
|
||||
if (inAddr > readBorder)
|
||||
{
|
||||
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 260 && wrPtr != unpPtr)
|
||||
{
|
||||
UnpWriteBuf();
|
||||
if (destUnpSize < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (suspended)
|
||||
{
|
||||
FileExtracted = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (unpBlockType == BlockTypes.BLOCK_PPM)
|
||||
{
|
||||
var Ch = ppm.DecodeChar();
|
||||
if (Ch == -1)
|
||||
{
|
||||
ppmError = true;
|
||||
break;
|
||||
}
|
||||
if (Ch == PpmEscChar)
|
||||
{
|
||||
var NextCh = ppm.DecodeChar();
|
||||
if (NextCh == 0)
|
||||
{
|
||||
if (!ReadTables())
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (NextCh == 2 || NextCh == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (NextCh == 3)
|
||||
{
|
||||
if (!ReadVMCodePPM())
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (NextCh == 4)
|
||||
{
|
||||
int Distance = 0,
|
||||
Length = 0;
|
||||
var failed = false;
|
||||
for (var I = 0; I < 4 && !failed; I++)
|
||||
{
|
||||
var ch = ppm.DecodeChar();
|
||||
if (ch == -1)
|
||||
{
|
||||
failed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (I == 3)
|
||||
{
|
||||
Length = ch & 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
Distance = (Distance << 8) + (ch & 0xff);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (failed)
|
||||
{
|
||||
break;
|
||||
}
|
||||
CopyString(Length + 32, Distance + 2);
|
||||
continue;
|
||||
}
|
||||
if (NextCh == 5)
|
||||
{
|
||||
var Length = ppm.DecodeChar();
|
||||
if (Length == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
CopyString(Length + 4, 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
window[unpPtr++] = (byte)Ch;
|
||||
continue;
|
||||
}
|
||||
|
||||
var Number = this.decodeNumber(LD);
|
||||
if (Number < 256)
|
||||
{
|
||||
window[unpPtr++] = (byte)Number;
|
||||
continue;
|
||||
}
|
||||
if (Number >= 271)
|
||||
{
|
||||
var Length = LDecode[Number -= 271] + 3;
|
||||
if ((Bits = LBits[Number]) > 0)
|
||||
{
|
||||
Length += Utility.URShift(GetBits(), (16 - Bits));
|
||||
AddBits(Bits);
|
||||
}
|
||||
|
||||
var DistNumber = this.decodeNumber(DD);
|
||||
var Distance = DDecode[DistNumber] + 1;
|
||||
if ((Bits = DBits[DistNumber]) > 0)
|
||||
{
|
||||
if (DistNumber > 9)
|
||||
{
|
||||
if (Bits > 4)
|
||||
{
|
||||
Distance += ((Utility.URShift(GetBits(), (20 - Bits))) << 4);
|
||||
AddBits(Bits - 4);
|
||||
}
|
||||
if (lowDistRepCount > 0)
|
||||
{
|
||||
lowDistRepCount--;
|
||||
Distance += prevLowDist;
|
||||
}
|
||||
else
|
||||
{
|
||||
var LowDist = this.decodeNumber(LDD);
|
||||
if (LowDist == 16)
|
||||
{
|
||||
lowDistRepCount = PackDef.LOW_DIST_REP_COUNT - 1;
|
||||
Distance += prevLowDist;
|
||||
}
|
||||
else
|
||||
{
|
||||
Distance += LowDist;
|
||||
prevLowDist = LowDist;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Distance += Utility.URShift(GetBits(), (16 - Bits));
|
||||
AddBits(Bits);
|
||||
}
|
||||
}
|
||||
|
||||
if (Distance >= 0x2000)
|
||||
{
|
||||
Length++;
|
||||
if (Distance >= 0x40000L)
|
||||
{
|
||||
Length++;
|
||||
}
|
||||
}
|
||||
|
||||
InsertOldDist(Distance);
|
||||
InsertLastMatch(Length, Distance);
|
||||
CopyString(Length, Distance);
|
||||
continue;
|
||||
}
|
||||
if (Number == 256)
|
||||
{
|
||||
if (!ReadEndOfBlock())
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (Number == 257)
|
||||
{
|
||||
if (!ReadVMCode())
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (Number == 258)
|
||||
{
|
||||
if (lastLength != 0)
|
||||
{
|
||||
CopyString(lastLength, lastDist);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (Number < 263)
|
||||
{
|
||||
var DistNum = Number - 259;
|
||||
var Distance = oldDist[DistNum];
|
||||
for (var I = DistNum; I > 0; I--)
|
||||
{
|
||||
oldDist[I] = oldDist[I - 1];
|
||||
}
|
||||
oldDist[0] = Distance;
|
||||
|
||||
var LengthNumber = this.decodeNumber(RD);
|
||||
var Length = LDecode[LengthNumber] + 2;
|
||||
if ((Bits = LBits[LengthNumber]) > 0)
|
||||
{
|
||||
Length += Utility.URShift(GetBits(), (16 - Bits));
|
||||
AddBits(Bits);
|
||||
}
|
||||
InsertLastMatch(Length, Distance);
|
||||
CopyString(Length, Distance);
|
||||
continue;
|
||||
}
|
||||
if (Number < 272)
|
||||
{
|
||||
var Distance = SDDecode[Number -= 263] + 1;
|
||||
if ((Bits = SDBits[Number]) > 0)
|
||||
{
|
||||
Distance += Utility.URShift(GetBits(), (16 - Bits));
|
||||
AddBits(Bits);
|
||||
}
|
||||
InsertOldDist(Distance);
|
||||
InsertLastMatch(2, Distance);
|
||||
CopyString(2, Distance);
|
||||
}
|
||||
}
|
||||
UnpWriteBuf();
|
||||
}
|
||||
|
||||
private async Task UnpWriteBufAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var WrittenBorder = wrPtr;
|
||||
var WriteSize = (unpPtr - WrittenBorder) & PackDef.MAXWINMASK;
|
||||
for (var I = 0; I < prgStack.Count; I++)
|
||||
{
|
||||
var flt = prgStack[I];
|
||||
if (flt is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (flt.NextWindow)
|
||||
{
|
||||
flt.NextWindow = false;
|
||||
continue;
|
||||
}
|
||||
var BlockStart = flt.BlockStart;
|
||||
var BlockLength = flt.BlockLength;
|
||||
if (((BlockStart - WrittenBorder) & PackDef.MAXWINMASK) < WriteSize)
|
||||
{
|
||||
if (WrittenBorder != BlockStart)
|
||||
{
|
||||
await UnpWriteAreaAsync(WrittenBorder, BlockStart, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
WrittenBorder = BlockStart;
|
||||
WriteSize = (unpPtr - WrittenBorder) & PackDef.MAXWINMASK;
|
||||
}
|
||||
if (BlockLength <= WriteSize)
|
||||
{
|
||||
var BlockEnd = (BlockStart + BlockLength) & PackDef.MAXWINMASK;
|
||||
if (BlockStart < BlockEnd || BlockEnd == 0)
|
||||
{
|
||||
rarVM.setMemory(0, window, BlockStart, BlockLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
var FirstPartLength = PackDef.MAXWINSIZE - BlockStart;
|
||||
rarVM.setMemory(0, window, BlockStart, FirstPartLength);
|
||||
rarVM.setMemory(FirstPartLength, window, 0, BlockEnd);
|
||||
}
|
||||
|
||||
var ParentPrg = filters[flt.ParentFilter].Program;
|
||||
var Prg = flt.Program;
|
||||
|
||||
if (ParentPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE)
|
||||
{
|
||||
Prg.GlobalData.Clear();
|
||||
for (
|
||||
var i = 0;
|
||||
i < ParentPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE;
|
||||
i++
|
||||
)
|
||||
{
|
||||
Prg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = ParentPrg.GlobalData[
|
||||
RarVM.VM_FIXEDGLOBALSIZE + i
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
ExecuteCode(Prg);
|
||||
|
||||
if (Prg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE)
|
||||
{
|
||||
if (ParentPrg.GlobalData.Count < Prg.GlobalData.Count)
|
||||
{
|
||||
ParentPrg.GlobalData.SetSize(Prg.GlobalData.Count);
|
||||
}
|
||||
|
||||
for (var i = 0; i < Prg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; i++)
|
||||
{
|
||||
ParentPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = Prg.GlobalData[
|
||||
RarVM.VM_FIXEDGLOBALSIZE + i
|
||||
];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ParentPrg.GlobalData.Clear();
|
||||
}
|
||||
|
||||
var FilteredDataOffset = Prg.FilteredDataOffset;
|
||||
var FilteredDataSize = Prg.FilteredDataSize;
|
||||
var FilteredData = ArrayPool<byte>.Shared.Rent(FilteredDataSize);
|
||||
try
|
||||
{
|
||||
Array.Copy(
|
||||
rarVM.Mem,
|
||||
FilteredDataOffset,
|
||||
FilteredData,
|
||||
0,
|
||||
FilteredDataSize
|
||||
);
|
||||
|
||||
prgStack[I] = null;
|
||||
while (I + 1 < prgStack.Count)
|
||||
{
|
||||
var NextFilter = prgStack[I + 1];
|
||||
if (
|
||||
NextFilter is null
|
||||
|| NextFilter.BlockStart != BlockStart
|
||||
|| NextFilter.BlockLength != FilteredDataSize
|
||||
|| NextFilter.NextWindow
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
rarVM.setMemory(0, FilteredData, 0, FilteredDataSize);
|
||||
|
||||
var pPrg = filters[NextFilter.ParentFilter].Program;
|
||||
var NextPrg = NextFilter.Program;
|
||||
|
||||
if (pPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE)
|
||||
{
|
||||
NextPrg.GlobalData.SetSize(pPrg.GlobalData.Count);
|
||||
|
||||
for (
|
||||
var i = 0;
|
||||
i < pPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE;
|
||||
i++
|
||||
)
|
||||
{
|
||||
NextPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] =
|
||||
pPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i];
|
||||
}
|
||||
}
|
||||
|
||||
ExecuteCode(NextPrg);
|
||||
|
||||
if (NextPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE)
|
||||
{
|
||||
if (pPrg.GlobalData.Count < NextPrg.GlobalData.Count)
|
||||
{
|
||||
pPrg.GlobalData.SetSize(NextPrg.GlobalData.Count);
|
||||
}
|
||||
|
||||
for (
|
||||
var i = 0;
|
||||
i < NextPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE;
|
||||
i++
|
||||
)
|
||||
{
|
||||
pPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] =
|
||||
NextPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pPrg.GlobalData.Clear();
|
||||
}
|
||||
|
||||
FilteredDataOffset = NextPrg.FilteredDataOffset;
|
||||
FilteredDataSize = NextPrg.FilteredDataSize;
|
||||
if (FilteredData.Length < FilteredDataSize)
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(FilteredData);
|
||||
FilteredData = ArrayPool<byte>.Shared.Rent(FilteredDataSize);
|
||||
}
|
||||
for (var i = 0; i < FilteredDataSize; i++)
|
||||
{
|
||||
FilteredData[i] = NextPrg.GlobalData[FilteredDataOffset + i];
|
||||
}
|
||||
|
||||
I++;
|
||||
prgStack[I] = null;
|
||||
}
|
||||
|
||||
await writeStream
|
||||
.WriteAsync(FilteredData, 0, FilteredDataSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
writtenFileSize += FilteredDataSize;
|
||||
destUnpSize -= FilteredDataSize;
|
||||
WrittenBorder = BlockEnd;
|
||||
WriteSize = (unpPtr - WrittenBorder) & PackDef.MAXWINMASK;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(FilteredData);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var J = I; J < prgStack.Count; J++)
|
||||
{
|
||||
var filt = prgStack[J];
|
||||
if (filt != null && filt.NextWindow)
|
||||
{
|
||||
filt.NextWindow = false;
|
||||
}
|
||||
}
|
||||
wrPtr = WrittenBorder;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await UnpWriteAreaAsync(WrittenBorder, unpPtr, cancellationToken).ConfigureAwait(false);
|
||||
wrPtr = unpPtr;
|
||||
}
|
||||
|
||||
private async Task UnpWriteAreaAsync(
|
||||
int startPtr,
|
||||
int endPtr,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (endPtr < startPtr)
|
||||
{
|
||||
await UnpWriteDataAsync(
|
||||
window,
|
||||
startPtr,
|
||||
-startPtr & PackDef.MAXWINMASK,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
await UnpWriteDataAsync(window, 0, endPtr, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await UnpWriteDataAsync(window, startPtr, endPtr - startPtr, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UnpWriteDataAsync(
|
||||
byte[] data,
|
||||
int offset,
|
||||
int size,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (destUnpSize < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var writeSize = size;
|
||||
if (writeSize > destUnpSize)
|
||||
{
|
||||
writeSize = (int)destUnpSize;
|
||||
}
|
||||
await writeStream
|
||||
.WriteAsync(data, offset, writeSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
writtenFileSize += size;
|
||||
destUnpSize -= size;
|
||||
}
|
||||
}
|
||||
@@ -150,25 +150,6 @@ internal sealed partial class Unpack : BitInput, IRarUnpack
|
||||
DoUnpack();
|
||||
}
|
||||
|
||||
public async System.Threading.Tasks.Task DoUnpackAsync(
|
||||
FileHeader fileHeader,
|
||||
Stream readStream,
|
||||
Stream writeStream,
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
destUnpSize = fileHeader.UncompressedSize;
|
||||
this.fileHeader = fileHeader;
|
||||
this.readStream = readStream;
|
||||
this.writeStream = writeStream;
|
||||
if (!fileHeader.IsSolid)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
suspended = false;
|
||||
await DoUnpackAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public void DoUnpack()
|
||||
{
|
||||
if (fileHeader.CompressionMethod == 0)
|
||||
@@ -203,42 +184,6 @@ internal sealed partial class Unpack : BitInput, IRarUnpack
|
||||
}
|
||||
}
|
||||
|
||||
public async System.Threading.Tasks.Task DoUnpackAsync(
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (fileHeader.CompressionMethod == 0)
|
||||
{
|
||||
await UnstoreFileAsync(cancellationToken).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
switch (fileHeader.CompressionAlgorithm)
|
||||
{
|
||||
case 15: // rar 1.5 compression
|
||||
await unpack15Async(fileHeader.IsSolid, cancellationToken).ConfigureAwait(false);
|
||||
break;
|
||||
|
||||
case 20: // rar 2.x compression
|
||||
case 26: // files larger than 2GB
|
||||
await unpack20Async(fileHeader.IsSolid, cancellationToken).ConfigureAwait(false);
|
||||
break;
|
||||
|
||||
case 29: // rar 3.x compression
|
||||
case 36: // alternative hash
|
||||
await Unpack29Async(fileHeader.IsSolid, cancellationToken).ConfigureAwait(false);
|
||||
break;
|
||||
|
||||
case 50: // rar 5.x compression
|
||||
await Unpack5Async(fileHeader.IsSolid, cancellationToken).ConfigureAwait(false);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidFormatException(
|
||||
"unknown rar compression version " + fileHeader.CompressionAlgorithm
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void UnstoreFile()
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[(int)Math.Min(0x10000, destUnpSize)];
|
||||
@@ -255,26 +200,6 @@ internal sealed partial class Unpack : BitInput, IRarUnpack
|
||||
} while (!suspended && destUnpSize > 0);
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task UnstoreFileAsync(
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var buffer = new byte[(int)Math.Min(0x10000, destUnpSize)];
|
||||
do
|
||||
{
|
||||
var code = await readStream
|
||||
.ReadAsync(buffer, 0, buffer.Length, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (code == 0 || code == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
code = code < destUnpSize ? code : (int)destUnpSize;
|
||||
await writeStream.WriteAsync(buffer, 0, code, cancellationToken).ConfigureAwait(false);
|
||||
destUnpSize -= code;
|
||||
} while (!suspended && destUnpSize > 0);
|
||||
}
|
||||
|
||||
private void Unpack29(bool solid)
|
||||
{
|
||||
Span<int> DDecode = stackalloc int[PackDef.DC];
|
||||
@@ -553,281 +478,6 @@ internal sealed partial class Unpack : BitInput, IRarUnpack
|
||||
UnpWriteBuf();
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task Unpack29Async(
|
||||
bool solid,
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
int[] DDecode = new int[PackDef.DC];
|
||||
byte[] DBits = new byte[PackDef.DC];
|
||||
|
||||
int Bits;
|
||||
|
||||
if (DDecode[1] == 0)
|
||||
{
|
||||
int Dist = 0,
|
||||
BitLength = 0,
|
||||
Slot = 0;
|
||||
for (var I = 0; I < DBitLengthCounts.Length; I++, BitLength++)
|
||||
{
|
||||
var count = DBitLengthCounts[I];
|
||||
for (var J = 0; J < count; J++, Slot++, Dist += (1 << BitLength))
|
||||
{
|
||||
DDecode[Slot] = Dist;
|
||||
DBits[Slot] = (byte)BitLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FileExtracted = true;
|
||||
|
||||
if (!suspended)
|
||||
{
|
||||
UnpInitData(solid);
|
||||
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if ((!solid || !tablesRead) && !ReadTables())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ppmError)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
unpPtr &= PackDef.MAXWINMASK;
|
||||
|
||||
if (inAddr > readBorder)
|
||||
{
|
||||
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 260 && wrPtr != unpPtr)
|
||||
{
|
||||
await UnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (destUnpSize < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (suspended)
|
||||
{
|
||||
FileExtracted = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (unpBlockType == BlockTypes.BLOCK_PPM)
|
||||
{
|
||||
var ch = ppm.DecodeChar();
|
||||
if (ch == -1)
|
||||
{
|
||||
ppmError = true;
|
||||
break;
|
||||
}
|
||||
if (ch == PpmEscChar)
|
||||
{
|
||||
var nextCh = ppm.DecodeChar();
|
||||
if (nextCh == 0)
|
||||
{
|
||||
if (!ReadTables())
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (nextCh == 2 || nextCh == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (nextCh == 3)
|
||||
{
|
||||
if (!ReadVMCode())
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (nextCh == 4)
|
||||
{
|
||||
uint Distance = 0,
|
||||
Length = 0;
|
||||
var failed = false;
|
||||
for (var I = 0; I < 4 && !failed; I++)
|
||||
{
|
||||
var ch2 = ppm.DecodeChar();
|
||||
if (ch2 == -1)
|
||||
{
|
||||
failed = true;
|
||||
}
|
||||
else if (I == 3)
|
||||
{
|
||||
Length = (uint)ch2;
|
||||
}
|
||||
else
|
||||
{
|
||||
Distance = (Distance << 8) + (uint)ch2;
|
||||
}
|
||||
}
|
||||
if (failed)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
CopyString(Length + 32, Distance + 2);
|
||||
continue;
|
||||
}
|
||||
if (nextCh == 5)
|
||||
{
|
||||
var length = ppm.DecodeChar();
|
||||
if (length == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
CopyString((uint)(length + 4), 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
window[unpPtr++] = (byte)ch;
|
||||
continue;
|
||||
}
|
||||
|
||||
var Number = this.decodeNumber(LD);
|
||||
if (Number < 256)
|
||||
{
|
||||
window[unpPtr++] = (byte)Number;
|
||||
continue;
|
||||
}
|
||||
if (Number >= 271)
|
||||
{
|
||||
var Length = LDecode[Number -= 271] + 3;
|
||||
if ((Bits = LBits[Number]) > 0)
|
||||
{
|
||||
Length += GetBits() >> (16 - Bits);
|
||||
AddBits(Bits);
|
||||
}
|
||||
|
||||
var DistNumber = this.decodeNumber(DD);
|
||||
var Distance = DDecode[DistNumber] + 1;
|
||||
if ((Bits = DBits[DistNumber]) > 0)
|
||||
{
|
||||
if (DistNumber > 9)
|
||||
{
|
||||
if (Bits > 4)
|
||||
{
|
||||
Distance += (GetBits() >> (20 - Bits)) << 4;
|
||||
AddBits(Bits - 4);
|
||||
}
|
||||
if (lowDistRepCount > 0)
|
||||
{
|
||||
lowDistRepCount--;
|
||||
Distance += prevLowDist;
|
||||
}
|
||||
else
|
||||
{
|
||||
var LowDist = this.decodeNumber(LDD);
|
||||
if (LowDist == 16)
|
||||
{
|
||||
lowDistRepCount = PackDef.LOW_DIST_REP_COUNT - 1;
|
||||
Distance += prevLowDist;
|
||||
}
|
||||
else
|
||||
{
|
||||
Distance += LowDist;
|
||||
prevLowDist = (int)LowDist;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Distance += GetBits() >> (16 - Bits);
|
||||
AddBits(Bits);
|
||||
}
|
||||
}
|
||||
|
||||
if (Distance >= 0x2000)
|
||||
{
|
||||
Length++;
|
||||
if (Distance >= 0x40000)
|
||||
{
|
||||
Length++;
|
||||
}
|
||||
}
|
||||
|
||||
InsertOldDist(Distance);
|
||||
lastLength = Length;
|
||||
CopyString(Length, Distance);
|
||||
continue;
|
||||
}
|
||||
if (Number == 256)
|
||||
{
|
||||
if (!ReadEndOfBlock())
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (Number == 257)
|
||||
{
|
||||
if (!ReadVMCode())
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (Number == 258)
|
||||
{
|
||||
if (lastLength != 0)
|
||||
{
|
||||
CopyString(lastLength, oldDist[0]);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
if (Number < 263)
|
||||
{
|
||||
var DistNum = Number - 259;
|
||||
var Distance = (uint)oldDist[DistNum];
|
||||
for (var I = DistNum; I > 0; I--)
|
||||
{
|
||||
oldDist[I] = oldDist[I - 1];
|
||||
}
|
||||
oldDist[0] = (int)Distance;
|
||||
|
||||
var LengthNumber = this.decodeNumber(RD);
|
||||
var Length = LDecode[LengthNumber] + 2;
|
||||
if ((Bits = LBits[LengthNumber]) > 0)
|
||||
{
|
||||
Length += GetBits() >> (16 - Bits);
|
||||
AddBits(Bits);
|
||||
}
|
||||
lastLength = Length;
|
||||
CopyString((uint)Length, Distance);
|
||||
continue;
|
||||
}
|
||||
if (Number < 272)
|
||||
{
|
||||
var Distance = SDDecode[Number -= 263] + 1;
|
||||
if ((Bits = SDBits[Number]) > 0)
|
||||
{
|
||||
Distance += GetBits() >> (16 - Bits);
|
||||
AddBits(Bits);
|
||||
}
|
||||
InsertOldDist((uint)Distance);
|
||||
lastLength = 2;
|
||||
CopyString(2, (uint)Distance);
|
||||
}
|
||||
}
|
||||
await UnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private void UnpWriteBuf()
|
||||
{
|
||||
var WrittenBorder = wrPtr;
|
||||
@@ -1684,256 +1334,6 @@ internal sealed partial class Unpack : BitInput, IRarUnpack
|
||||
}
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task UnpWriteBufAsync(
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var WrittenBorder = wrPtr;
|
||||
var WriteSize = (unpPtr - WrittenBorder) & PackDef.MAXWINMASK;
|
||||
for (var I = 0; I < prgStack.Count; I++)
|
||||
{
|
||||
var flt = prgStack[I];
|
||||
if (flt is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (flt.NextWindow)
|
||||
{
|
||||
flt.NextWindow = false;
|
||||
continue;
|
||||
}
|
||||
var BlockStart = flt.BlockStart;
|
||||
var BlockLength = flt.BlockLength;
|
||||
if (((BlockStart - WrittenBorder) & PackDef.MAXWINMASK) < WriteSize)
|
||||
{
|
||||
if (WrittenBorder != BlockStart)
|
||||
{
|
||||
await UnpWriteAreaAsync(WrittenBorder, BlockStart, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
WrittenBorder = BlockStart;
|
||||
WriteSize = (unpPtr - WrittenBorder) & PackDef.MAXWINMASK;
|
||||
}
|
||||
if (BlockLength <= WriteSize)
|
||||
{
|
||||
var BlockEnd = (BlockStart + BlockLength) & PackDef.MAXWINMASK;
|
||||
if (BlockStart < BlockEnd || BlockEnd == 0)
|
||||
{
|
||||
rarVM.setMemory(0, window, BlockStart, BlockLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
var FirstPartLength = PackDef.MAXWINSIZE - BlockStart;
|
||||
rarVM.setMemory(0, window, BlockStart, FirstPartLength);
|
||||
rarVM.setMemory(FirstPartLength, window, 0, BlockEnd);
|
||||
}
|
||||
|
||||
var ParentPrg = filters[flt.ParentFilter].Program;
|
||||
var Prg = flt.Program;
|
||||
|
||||
if (ParentPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE)
|
||||
{
|
||||
Prg.GlobalData.Clear();
|
||||
for (
|
||||
var i = 0;
|
||||
i < ParentPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE;
|
||||
i++
|
||||
)
|
||||
{
|
||||
Prg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = ParentPrg.GlobalData[
|
||||
RarVM.VM_FIXEDGLOBALSIZE + i
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
ExecuteCode(Prg);
|
||||
|
||||
if (Prg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE)
|
||||
{
|
||||
if (ParentPrg.GlobalData.Count < Prg.GlobalData.Count)
|
||||
{
|
||||
ParentPrg.GlobalData.SetSize(Prg.GlobalData.Count);
|
||||
}
|
||||
|
||||
for (var i = 0; i < Prg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; i++)
|
||||
{
|
||||
ParentPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = Prg.GlobalData[
|
||||
RarVM.VM_FIXEDGLOBALSIZE + i
|
||||
];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ParentPrg.GlobalData.Clear();
|
||||
}
|
||||
|
||||
var FilteredDataOffset = Prg.FilteredDataOffset;
|
||||
var FilteredDataSize = Prg.FilteredDataSize;
|
||||
var FilteredData = ArrayPool<byte>.Shared.Rent(FilteredDataSize);
|
||||
try
|
||||
{
|
||||
Array.Copy(
|
||||
rarVM.Mem,
|
||||
FilteredDataOffset,
|
||||
FilteredData,
|
||||
0,
|
||||
FilteredDataSize
|
||||
);
|
||||
|
||||
prgStack[I] = null;
|
||||
while (I + 1 < prgStack.Count)
|
||||
{
|
||||
var NextFilter = prgStack[I + 1];
|
||||
if (
|
||||
NextFilter is null
|
||||
|| NextFilter.BlockStart != BlockStart
|
||||
|| NextFilter.BlockLength != FilteredDataSize
|
||||
|| NextFilter.NextWindow
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
rarVM.setMemory(0, FilteredData, 0, FilteredDataSize);
|
||||
|
||||
var pPrg = filters[NextFilter.ParentFilter].Program;
|
||||
var NextPrg = NextFilter.Program;
|
||||
|
||||
if (pPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE)
|
||||
{
|
||||
NextPrg.GlobalData.SetSize(pPrg.GlobalData.Count);
|
||||
|
||||
for (
|
||||
var i = 0;
|
||||
i < pPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE;
|
||||
i++
|
||||
)
|
||||
{
|
||||
NextPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] =
|
||||
pPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i];
|
||||
}
|
||||
}
|
||||
|
||||
ExecuteCode(NextPrg);
|
||||
|
||||
if (NextPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE)
|
||||
{
|
||||
if (pPrg.GlobalData.Count < NextPrg.GlobalData.Count)
|
||||
{
|
||||
pPrg.GlobalData.SetSize(NextPrg.GlobalData.Count);
|
||||
}
|
||||
|
||||
for (
|
||||
var i = 0;
|
||||
i < NextPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE;
|
||||
i++
|
||||
)
|
||||
{
|
||||
pPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] =
|
||||
NextPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pPrg.GlobalData.Clear();
|
||||
}
|
||||
|
||||
FilteredDataOffset = NextPrg.FilteredDataOffset;
|
||||
FilteredDataSize = NextPrg.FilteredDataSize;
|
||||
if (FilteredData.Length < FilteredDataSize)
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(FilteredData);
|
||||
FilteredData = ArrayPool<byte>.Shared.Rent(FilteredDataSize);
|
||||
}
|
||||
for (var i = 0; i < FilteredDataSize; i++)
|
||||
{
|
||||
FilteredData[i] = NextPrg.GlobalData[FilteredDataOffset + i];
|
||||
}
|
||||
|
||||
I++;
|
||||
prgStack[I] = null;
|
||||
}
|
||||
|
||||
await writeStream
|
||||
.WriteAsync(FilteredData, 0, FilteredDataSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
writtenFileSize += FilteredDataSize;
|
||||
destUnpSize -= FilteredDataSize;
|
||||
WrittenBorder = BlockEnd;
|
||||
WriteSize = (unpPtr - WrittenBorder) & PackDef.MAXWINMASK;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(FilteredData);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var J = I; J < prgStack.Count; J++)
|
||||
{
|
||||
var filt = prgStack[J];
|
||||
if (filt != null && filt.NextWindow)
|
||||
{
|
||||
filt.NextWindow = false;
|
||||
}
|
||||
}
|
||||
wrPtr = WrittenBorder;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await UnpWriteAreaAsync(WrittenBorder, unpPtr, cancellationToken).ConfigureAwait(false);
|
||||
wrPtr = unpPtr;
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task UnpWriteAreaAsync(
|
||||
int startPtr,
|
||||
int endPtr,
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (endPtr < startPtr)
|
||||
{
|
||||
await UnpWriteDataAsync(
|
||||
window,
|
||||
startPtr,
|
||||
-startPtr & PackDef.MAXWINMASK,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
await UnpWriteDataAsync(window, 0, endPtr, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await UnpWriteDataAsync(window, startPtr, endPtr - startPtr, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task UnpWriteDataAsync(
|
||||
byte[] data,
|
||||
int offset,
|
||||
int size,
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (destUnpSize < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var writeSize = size;
|
||||
if (writeSize > destUnpSize)
|
||||
{
|
||||
writeSize = (int)destUnpSize;
|
||||
}
|
||||
await writeStream
|
||||
.WriteAsync(data, offset, writeSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
writtenFileSize += size;
|
||||
destUnpSize -= size;
|
||||
}
|
||||
|
||||
private void CleanUp()
|
||||
{
|
||||
if (ppm != null)
|
||||
|
||||
162
src/SharpCompress/Compressors/Rar/UnpackV1/Unpack15.Async.cs
Normal file
162
src/SharpCompress/Compressors/Rar/UnpackV1/Unpack15.Async.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Compressors.Rar.UnpackV1.Decode;
|
||||
|
||||
namespace SharpCompress.Compressors.Rar.UnpackV1;
|
||||
|
||||
internal partial class Unpack
|
||||
{
|
||||
private async Task unpack15Async(bool solid, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (suspended)
|
||||
{
|
||||
unpPtr = wrPtr;
|
||||
}
|
||||
else
|
||||
{
|
||||
UnpInitData(solid);
|
||||
oldUnpInitData(solid);
|
||||
await unpReadBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (!solid)
|
||||
{
|
||||
initHuff();
|
||||
unpPtr = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
unpPtr = wrPtr;
|
||||
}
|
||||
--destUnpSize;
|
||||
}
|
||||
if (destUnpSize >= 0)
|
||||
{
|
||||
getFlagsBuf();
|
||||
FlagsCnt = 8;
|
||||
}
|
||||
|
||||
while (destUnpSize >= 0)
|
||||
{
|
||||
unpPtr &= PackDef.MAXWINMASK;
|
||||
|
||||
if (
|
||||
inAddr > readTop - 30
|
||||
&& !await unpReadBufAsync(cancellationToken).ConfigureAwait(false)
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 270 && wrPtr != unpPtr)
|
||||
{
|
||||
oldUnpWriteBuf();
|
||||
if (suspended)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (StMode != 0)
|
||||
{
|
||||
huffDecode();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (--FlagsCnt < 0)
|
||||
{
|
||||
getFlagsBuf();
|
||||
FlagsCnt = 7;
|
||||
}
|
||||
|
||||
if ((FlagBuf & 0x80) != 0)
|
||||
{
|
||||
FlagBuf <<= 1;
|
||||
if (Nlzb > Nhfb)
|
||||
{
|
||||
longLZ();
|
||||
}
|
||||
else
|
||||
{
|
||||
huffDecode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FlagBuf <<= 1;
|
||||
if (--FlagsCnt < 0)
|
||||
{
|
||||
getFlagsBuf();
|
||||
FlagsCnt = 7;
|
||||
}
|
||||
if ((FlagBuf & 0x80) != 0)
|
||||
{
|
||||
FlagBuf <<= 1;
|
||||
if (Nlzb > Nhfb)
|
||||
{
|
||||
huffDecode();
|
||||
}
|
||||
else
|
||||
{
|
||||
longLZ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FlagBuf <<= 1;
|
||||
shortLZ();
|
||||
}
|
||||
}
|
||||
}
|
||||
oldUnpWriteBuf();
|
||||
}
|
||||
|
||||
private async Task<bool> unpReadBufAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var dataSize = readTop - inAddr;
|
||||
if (dataSize < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (inAddr > MAX_SIZE / 2)
|
||||
{
|
||||
if (dataSize > 0)
|
||||
{
|
||||
Array.Copy(InBuf, inAddr, InBuf, 0, dataSize);
|
||||
}
|
||||
inAddr = 0;
|
||||
readTop = dataSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
dataSize = readTop;
|
||||
}
|
||||
|
||||
var readCode = await readStream
|
||||
.ReadAsync(InBuf, dataSize, (MAX_SIZE - dataSize) & ~0xf, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (readCode > 0)
|
||||
{
|
||||
readTop += readCode;
|
||||
}
|
||||
readBorder = readTop - 30;
|
||||
return readCode != -1;
|
||||
}
|
||||
|
||||
private async Task oldUnpWriteBufAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (unpPtr < wrPtr)
|
||||
{
|
||||
await writeStream
|
||||
.WriteAsync(window, wrPtr, -wrPtr & PackDef.MAXWINMASK, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
await writeStream
|
||||
.WriteAsync(window, 0, unpPtr, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await writeStream
|
||||
.WriteAsync(window, wrPtr, unpPtr - wrPtr, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
wrPtr = unpPtr;
|
||||
}
|
||||
}
|
||||
@@ -316,110 +316,6 @@ internal partial class Unpack
|
||||
oldUnpWriteBuf();
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task unpack15Async(
|
||||
bool solid,
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (suspended)
|
||||
{
|
||||
unpPtr = wrPtr;
|
||||
}
|
||||
else
|
||||
{
|
||||
UnpInitData(solid);
|
||||
oldUnpInitData(solid);
|
||||
await unpReadBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (!solid)
|
||||
{
|
||||
initHuff();
|
||||
unpPtr = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
unpPtr = wrPtr;
|
||||
}
|
||||
--destUnpSize;
|
||||
}
|
||||
if (destUnpSize >= 0)
|
||||
{
|
||||
getFlagsBuf();
|
||||
FlagsCnt = 8;
|
||||
}
|
||||
|
||||
while (destUnpSize >= 0)
|
||||
{
|
||||
unpPtr &= PackDef.MAXWINMASK;
|
||||
|
||||
if (
|
||||
inAddr > readTop - 30
|
||||
&& !await unpReadBufAsync(cancellationToken).ConfigureAwait(false)
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 270 && wrPtr != unpPtr)
|
||||
{
|
||||
await oldUnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (suspended)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (StMode != 0)
|
||||
{
|
||||
huffDecode();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (--FlagsCnt < 0)
|
||||
{
|
||||
getFlagsBuf();
|
||||
FlagsCnt = 7;
|
||||
}
|
||||
|
||||
if ((FlagBuf & 0x80) != 0)
|
||||
{
|
||||
FlagBuf <<= 1;
|
||||
if (Nlzb > Nhfb)
|
||||
{
|
||||
longLZ();
|
||||
}
|
||||
else
|
||||
{
|
||||
huffDecode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FlagBuf <<= 1;
|
||||
if (--FlagsCnt < 0)
|
||||
{
|
||||
getFlagsBuf();
|
||||
FlagsCnt = 7;
|
||||
}
|
||||
if ((FlagBuf & 0x80) != 0)
|
||||
{
|
||||
FlagBuf <<= 1;
|
||||
if (Nlzb > Nhfb)
|
||||
{
|
||||
huffDecode();
|
||||
}
|
||||
else
|
||||
{
|
||||
longLZ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FlagBuf <<= 1;
|
||||
shortLZ();
|
||||
}
|
||||
}
|
||||
}
|
||||
await oldUnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private bool unpReadBuf()
|
||||
{
|
||||
var dataSize = readTop - inAddr;
|
||||
@@ -455,40 +351,6 @@ internal partial class Unpack
|
||||
return (readCode != -1);
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task<bool> unpReadBufAsync(
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var dataSize = readTop - inAddr;
|
||||
if (dataSize < 0)
|
||||
{
|
||||
return (false);
|
||||
}
|
||||
if (inAddr > MAX_SIZE / 2)
|
||||
{
|
||||
if (dataSize > 0)
|
||||
{
|
||||
Array.Copy(InBuf, inAddr, InBuf, 0, dataSize);
|
||||
}
|
||||
inAddr = 0;
|
||||
readTop = dataSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
dataSize = readTop;
|
||||
}
|
||||
|
||||
var readCode = await readStream
|
||||
.ReadAsync(InBuf, dataSize, (MAX_SIZE - dataSize) & ~0xf, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (readCode > 0)
|
||||
{
|
||||
readTop += readCode;
|
||||
}
|
||||
readBorder = readTop - 30;
|
||||
return (readCode != -1);
|
||||
}
|
||||
|
||||
private int getShortLen1(int pos) => pos == 1 ? Buf60 + 3 : ShortLen1[pos];
|
||||
|
||||
private int getShortLen2(int pos) => pos == 3 ? Buf60 + 3 : ShortLen2[pos];
|
||||
@@ -952,26 +814,4 @@ internal partial class Unpack
|
||||
}
|
||||
wrPtr = unpPtr;
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task oldUnpWriteBufAsync(
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (unpPtr < wrPtr)
|
||||
{
|
||||
await writeStream
|
||||
.WriteAsync(window, wrPtr, -wrPtr & PackDef.MAXWINMASK, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
await writeStream
|
||||
.WriteAsync(window, 0, unpPtr, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await writeStream
|
||||
.WriteAsync(window, wrPtr, unpPtr - wrPtr, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
wrPtr = unpPtr;
|
||||
}
|
||||
}
|
||||
|
||||
275
src/SharpCompress/Compressors/Rar/UnpackV1/Unpack20.Async.cs
Normal file
275
src/SharpCompress/Compressors/Rar/UnpackV1/Unpack20.Async.cs
Normal file
@@ -0,0 +1,275 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Compressors.Rar.UnpackV1.Decode;
|
||||
|
||||
namespace SharpCompress.Compressors.Rar.UnpackV1;
|
||||
|
||||
internal partial class Unpack
|
||||
{
|
||||
private async Task unpack20Async(bool solid, CancellationToken cancellationToken = default)
|
||||
{
|
||||
int Bits;
|
||||
|
||||
if (suspended)
|
||||
{
|
||||
unpPtr = wrPtr;
|
||||
}
|
||||
else
|
||||
{
|
||||
UnpInitData(solid);
|
||||
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!solid)
|
||||
{
|
||||
if (!await ReadTables20Async(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
--destUnpSize;
|
||||
}
|
||||
|
||||
while (destUnpSize >= 0)
|
||||
{
|
||||
unpPtr &= PackDef.MAXWINMASK;
|
||||
|
||||
if (inAddr > readTop - 30)
|
||||
{
|
||||
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 270 && wrPtr != unpPtr)
|
||||
{
|
||||
oldUnpWriteBuf();
|
||||
if (suspended)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (UnpAudioBlock != 0)
|
||||
{
|
||||
var AudioNumber = this.decodeNumber(MD[UnpCurChannel]);
|
||||
|
||||
if (AudioNumber == 256)
|
||||
{
|
||||
if (!await ReadTables20Async(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
window[unpPtr++] = DecodeAudio(AudioNumber);
|
||||
if (++UnpCurChannel == UnpChannels)
|
||||
{
|
||||
UnpCurChannel = 0;
|
||||
}
|
||||
--destUnpSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
var Number = this.decodeNumber(LD);
|
||||
if (Number < 256)
|
||||
{
|
||||
window[unpPtr++] = (byte)Number;
|
||||
--destUnpSize;
|
||||
continue;
|
||||
}
|
||||
if (Number > 269)
|
||||
{
|
||||
var Length = LDecode[Number -= 270] + 3;
|
||||
if ((Bits = LBits[Number]) > 0)
|
||||
{
|
||||
Length += Utility.URShift(GetBits(), (16 - Bits));
|
||||
AddBits(Bits);
|
||||
}
|
||||
|
||||
var DistNumber = this.decodeNumber(DD);
|
||||
var Distance = DDecode[DistNumber] + 1;
|
||||
if ((Bits = DBits[DistNumber]) > 0)
|
||||
{
|
||||
Distance += Utility.URShift(GetBits(), (16 - Bits));
|
||||
AddBits(Bits);
|
||||
}
|
||||
|
||||
if (Distance >= 0x2000)
|
||||
{
|
||||
Length++;
|
||||
if (Distance >= 0x40000L)
|
||||
{
|
||||
Length++;
|
||||
}
|
||||
}
|
||||
|
||||
CopyString20(Length, Distance);
|
||||
continue;
|
||||
}
|
||||
if (Number == 269)
|
||||
{
|
||||
if (!await ReadTables20Async(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (Number == 256)
|
||||
{
|
||||
CopyString20(lastLength, lastDist);
|
||||
continue;
|
||||
}
|
||||
if (Number < 261)
|
||||
{
|
||||
var Distance = oldDist[(oldDistPtr - (Number - 256)) & 3];
|
||||
var LengthNumber = this.decodeNumber(RD);
|
||||
var Length = LDecode[LengthNumber] + 2;
|
||||
if ((Bits = LBits[LengthNumber]) > 0)
|
||||
{
|
||||
Length += Utility.URShift(GetBits(), (16 - Bits));
|
||||
AddBits(Bits);
|
||||
}
|
||||
if (Distance >= 0x101)
|
||||
{
|
||||
Length++;
|
||||
if (Distance >= 0x2000)
|
||||
{
|
||||
Length++;
|
||||
if (Distance >= 0x40000)
|
||||
{
|
||||
Length++;
|
||||
}
|
||||
}
|
||||
}
|
||||
CopyString20(Length, Distance);
|
||||
continue;
|
||||
}
|
||||
if (Number < 270)
|
||||
{
|
||||
var Distance = SDDecode[Number -= 261] + 1;
|
||||
if ((Bits = SDBits[Number]) > 0)
|
||||
{
|
||||
Distance += Utility.URShift(GetBits(), (16 - Bits));
|
||||
AddBits(Bits);
|
||||
}
|
||||
CopyString20(2, Distance);
|
||||
}
|
||||
}
|
||||
ReadLastTables();
|
||||
oldUnpWriteBuf();
|
||||
}
|
||||
|
||||
private async Task<bool> ReadTables20Async(CancellationToken cancellationToken = default)
|
||||
{
|
||||
byte[] BitLength = new byte[PackDef.BC20];
|
||||
byte[] Table = new byte[PackDef.MC20 * 4];
|
||||
int TableSize,
|
||||
N,
|
||||
I;
|
||||
if (inAddr > readTop - 25)
|
||||
{
|
||||
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
var BitField = GetBits();
|
||||
UnpAudioBlock = (BitField & 0x8000);
|
||||
|
||||
if (0 == (BitField & 0x4000))
|
||||
{
|
||||
new Span<byte>(UnpOldTable20).Clear();
|
||||
}
|
||||
AddBits(2);
|
||||
|
||||
if (UnpAudioBlock != 0)
|
||||
{
|
||||
UnpChannels = ((Utility.URShift(BitField, 12)) & 3) + 1;
|
||||
if (UnpCurChannel >= UnpChannels)
|
||||
{
|
||||
UnpCurChannel = 0;
|
||||
}
|
||||
AddBits(2);
|
||||
TableSize = PackDef.MC20 * UnpChannels;
|
||||
}
|
||||
else
|
||||
{
|
||||
TableSize = PackDef.NC20 + PackDef.DC20 + PackDef.RC20;
|
||||
}
|
||||
for (I = 0; I < PackDef.BC20; I++)
|
||||
{
|
||||
BitLength[I] = (byte)(Utility.URShift(GetBits(), 12));
|
||||
AddBits(4);
|
||||
}
|
||||
UnpackUtility.makeDecodeTables(BitLength, 0, BD, PackDef.BC20);
|
||||
I = 0;
|
||||
while (I < TableSize)
|
||||
{
|
||||
if (inAddr > readTop - 5)
|
||||
{
|
||||
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
var Number = this.decodeNumber(BD);
|
||||
if (Number < 16)
|
||||
{
|
||||
Table[I] = (byte)((Number + UnpOldTable20[I]) & 0xf);
|
||||
I++;
|
||||
}
|
||||
else if (Number == 16)
|
||||
{
|
||||
N = (Utility.URShift(GetBits(), 14)) + 3;
|
||||
AddBits(2);
|
||||
while (N-- > 0 && I < TableSize)
|
||||
{
|
||||
Table[I] = Table[I - 1];
|
||||
I++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Number == 17)
|
||||
{
|
||||
N = (Utility.URShift(GetBits(), 13)) + 3;
|
||||
AddBits(3);
|
||||
}
|
||||
else
|
||||
{
|
||||
N = (Utility.URShift(GetBits(), 9)) + 11;
|
||||
AddBits(7);
|
||||
}
|
||||
while (N-- > 0 && I < TableSize)
|
||||
{
|
||||
Table[I++] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (inAddr > readTop)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (UnpAudioBlock != 0)
|
||||
{
|
||||
for (I = 0; I < UnpChannels; I++)
|
||||
{
|
||||
UnpackUtility.makeDecodeTables(Table, I * PackDef.MC20, MD[I], PackDef.MC20);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UnpackUtility.makeDecodeTables(Table, 0, LD, PackDef.NC20);
|
||||
UnpackUtility.makeDecodeTables(Table, PackDef.NC20, DD, PackDef.DC20);
|
||||
UnpackUtility.makeDecodeTables(Table, PackDef.NC20 + PackDef.DC20, RD, PackDef.RC20);
|
||||
}
|
||||
|
||||
for (var i = 0; i < UnpOldTable20.Length; i++)
|
||||
{
|
||||
UnpOldTable20[i] = Table[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -368,163 +368,6 @@ internal partial class Unpack
|
||||
oldUnpWriteBuf();
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task unpack20Async(
|
||||
bool solid,
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
int Bits;
|
||||
|
||||
if (suspended)
|
||||
{
|
||||
unpPtr = wrPtr;
|
||||
}
|
||||
else
|
||||
{
|
||||
UnpInitData(solid);
|
||||
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!solid)
|
||||
{
|
||||
if (!await ReadTables20Async(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
--destUnpSize;
|
||||
}
|
||||
|
||||
while (destUnpSize >= 0)
|
||||
{
|
||||
unpPtr &= PackDef.MAXWINMASK;
|
||||
|
||||
if (inAddr > readTop - 30)
|
||||
{
|
||||
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 270 && wrPtr != unpPtr)
|
||||
{
|
||||
await oldUnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (suspended)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (UnpAudioBlock != 0)
|
||||
{
|
||||
var AudioNumber = this.decodeNumber(MD[UnpCurChannel]);
|
||||
|
||||
if (AudioNumber == 256)
|
||||
{
|
||||
if (!await ReadTables20Async(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
window[unpPtr++] = DecodeAudio(AudioNumber);
|
||||
if (++UnpCurChannel == UnpChannels)
|
||||
{
|
||||
UnpCurChannel = 0;
|
||||
}
|
||||
--destUnpSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
var Number = this.decodeNumber(LD);
|
||||
if (Number < 256)
|
||||
{
|
||||
window[unpPtr++] = (byte)Number;
|
||||
--destUnpSize;
|
||||
continue;
|
||||
}
|
||||
if (Number > 269)
|
||||
{
|
||||
var Length = LDecode[Number -= 270] + 3;
|
||||
if ((Bits = LBits[Number]) > 0)
|
||||
{
|
||||
Length += Utility.URShift(GetBits(), (16 - Bits));
|
||||
AddBits(Bits);
|
||||
}
|
||||
|
||||
var DistNumber = this.decodeNumber(DD);
|
||||
var Distance = DDecode[DistNumber] + 1;
|
||||
if ((Bits = DBits[DistNumber]) > 0)
|
||||
{
|
||||
Distance += Utility.URShift(GetBits(), (16 - Bits));
|
||||
AddBits(Bits);
|
||||
}
|
||||
|
||||
if (Distance >= 0x2000)
|
||||
{
|
||||
Length++;
|
||||
if (Distance >= 0x40000L)
|
||||
{
|
||||
Length++;
|
||||
}
|
||||
}
|
||||
|
||||
CopyString20(Length, Distance);
|
||||
continue;
|
||||
}
|
||||
if (Number == 269)
|
||||
{
|
||||
if (!await ReadTables20Async(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (Number == 256)
|
||||
{
|
||||
CopyString20(lastLength, lastDist);
|
||||
continue;
|
||||
}
|
||||
if (Number < 261)
|
||||
{
|
||||
var Distance = oldDist[(oldDistPtr - (Number - 256)) & 3];
|
||||
var LengthNumber = this.decodeNumber(RD);
|
||||
var Length = LDecode[LengthNumber] + 2;
|
||||
if ((Bits = LBits[LengthNumber]) > 0)
|
||||
{
|
||||
Length += Utility.URShift(GetBits(), (16 - Bits));
|
||||
AddBits(Bits);
|
||||
}
|
||||
if (Distance >= 0x101)
|
||||
{
|
||||
Length++;
|
||||
if (Distance >= 0x2000)
|
||||
{
|
||||
Length++;
|
||||
if (Distance >= 0x40000)
|
||||
{
|
||||
Length++;
|
||||
}
|
||||
}
|
||||
}
|
||||
CopyString20(Length, Distance);
|
||||
continue;
|
||||
}
|
||||
if (Number < 270)
|
||||
{
|
||||
var Distance = SDDecode[Number -= 261] + 1;
|
||||
if ((Bits = SDBits[Number]) > 0)
|
||||
{
|
||||
Distance += Utility.URShift(GetBits(), (16 - Bits));
|
||||
AddBits(Bits);
|
||||
}
|
||||
CopyString20(2, Distance);
|
||||
}
|
||||
}
|
||||
ReadLastTables();
|
||||
await oldUnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private void CopyString20(int Length, int Distance)
|
||||
{
|
||||
lastDist = oldDist[oldDistPtr++ & 3] = Distance;
|
||||
@@ -691,120 +534,6 @@ internal partial class Unpack
|
||||
return (true);
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task<bool> ReadTables20Async(
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
byte[] BitLength = new byte[PackDef.BC20];
|
||||
byte[] Table = new byte[PackDef.MC20 * 4];
|
||||
int TableSize,
|
||||
N,
|
||||
I;
|
||||
if (inAddr > readTop - 25)
|
||||
{
|
||||
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
var BitField = GetBits();
|
||||
UnpAudioBlock = (BitField & 0x8000);
|
||||
|
||||
if (0 == (BitField & 0x4000))
|
||||
{
|
||||
new Span<byte>(UnpOldTable20).Clear();
|
||||
}
|
||||
AddBits(2);
|
||||
|
||||
if (UnpAudioBlock != 0)
|
||||
{
|
||||
UnpChannels = ((Utility.URShift(BitField, 12)) & 3) + 1;
|
||||
if (UnpCurChannel >= UnpChannels)
|
||||
{
|
||||
UnpCurChannel = 0;
|
||||
}
|
||||
AddBits(2);
|
||||
TableSize = PackDef.MC20 * UnpChannels;
|
||||
}
|
||||
else
|
||||
{
|
||||
TableSize = PackDef.NC20 + PackDef.DC20 + PackDef.RC20;
|
||||
}
|
||||
for (I = 0; I < PackDef.BC20; I++)
|
||||
{
|
||||
BitLength[I] = (byte)(Utility.URShift(GetBits(), 12));
|
||||
AddBits(4);
|
||||
}
|
||||
UnpackUtility.makeDecodeTables(BitLength, 0, BD, PackDef.BC20);
|
||||
I = 0;
|
||||
while (I < TableSize)
|
||||
{
|
||||
if (inAddr > readTop - 5)
|
||||
{
|
||||
if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
var Number = this.decodeNumber(BD);
|
||||
if (Number < 16)
|
||||
{
|
||||
Table[I] = (byte)((Number + UnpOldTable20[I]) & 0xf);
|
||||
I++;
|
||||
}
|
||||
else if (Number == 16)
|
||||
{
|
||||
N = (Utility.URShift(GetBits(), 14)) + 3;
|
||||
AddBits(2);
|
||||
while (N-- > 0 && I < TableSize)
|
||||
{
|
||||
Table[I] = Table[I - 1];
|
||||
I++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Number == 17)
|
||||
{
|
||||
N = (Utility.URShift(GetBits(), 13)) + 3;
|
||||
AddBits(3);
|
||||
}
|
||||
else
|
||||
{
|
||||
N = (Utility.URShift(GetBits(), 9)) + 11;
|
||||
AddBits(7);
|
||||
}
|
||||
while (N-- > 0 && I < TableSize)
|
||||
{
|
||||
Table[I++] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (inAddr > readTop)
|
||||
{
|
||||
return (true);
|
||||
}
|
||||
if (UnpAudioBlock != 0)
|
||||
{
|
||||
for (I = 0; I < UnpChannels; I++)
|
||||
{
|
||||
UnpackUtility.makeDecodeTables(Table, I * PackDef.MC20, MD[I], PackDef.MC20);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UnpackUtility.makeDecodeTables(Table, 0, LD, PackDef.NC20);
|
||||
UnpackUtility.makeDecodeTables(Table, PackDef.NC20, DD, PackDef.DC20);
|
||||
UnpackUtility.makeDecodeTables(Table, PackDef.NC20 + PackDef.DC20, RD, PackDef.RC20);
|
||||
}
|
||||
|
||||
for (var i = 0; i < UnpOldTable20.Length; i++)
|
||||
{
|
||||
UnpOldTable20[i] = Table[i];
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
private void unpInitData20(bool Solid)
|
||||
{
|
||||
if (!Solid)
|
||||
|
||||
321
src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.Async.cs
Normal file
321
src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.Async.cs
Normal file
@@ -0,0 +1,321 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Compressors.Rar.UnpackV1.Decode;
|
||||
|
||||
namespace SharpCompress.Compressors.Rar.UnpackV1;
|
||||
|
||||
internal partial class Unpack
|
||||
{
|
||||
private async Task<bool> UnpReadBufAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var DataSize = ReadTop - Inp.InAddr; // Data left to process.
|
||||
if (DataSize < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BlockHeader.BlockSize -= Inp.InAddr - BlockHeader.BlockStart;
|
||||
if (Inp.InAddr > MAX_SIZE / 2)
|
||||
{
|
||||
if (DataSize > 0)
|
||||
{
|
||||
Array.Copy(InBuf, inAddr, InBuf, 0, DataSize);
|
||||
}
|
||||
|
||||
Inp.InAddr = 0;
|
||||
ReadTop = DataSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
DataSize = ReadTop;
|
||||
}
|
||||
|
||||
var ReadCode = 0;
|
||||
if (MAX_SIZE != DataSize)
|
||||
{
|
||||
ReadCode = await readStream
|
||||
.ReadAsync(InBuf, DataSize, MAX_SIZE - DataSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (ReadCode > 0) // Can be also -1.
|
||||
{
|
||||
ReadTop += ReadCode;
|
||||
}
|
||||
|
||||
ReadBorder = ReadTop - 30;
|
||||
BlockHeader.BlockStart = Inp.InAddr;
|
||||
if (BlockHeader.BlockSize != -1) // '-1' means not defined yet.
|
||||
{
|
||||
ReadBorder = Math.Min(ReadBorder, BlockHeader.BlockStart + BlockHeader.BlockSize - 1);
|
||||
}
|
||||
return ReadCode != -1;
|
||||
}
|
||||
|
||||
public async Task Unpack5Async(bool Solid, CancellationToken cancellationToken = default)
|
||||
{
|
||||
FileExtracted = true;
|
||||
|
||||
if (!Suspended)
|
||||
{
|
||||
UnpInitData(Solid);
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check TablesRead5 to be sure that we read tables at least once
|
||||
// regardless of current block header TablePresent flag.
|
||||
// So we can safefly use these tables below.
|
||||
if (
|
||||
!await ReadBlockHeaderAsync(cancellationToken).ConfigureAwait(false)
|
||||
|| !ReadTables()
|
||||
|| !TablesRead5
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
UnpPtr &= MaxWinMask;
|
||||
|
||||
if (Inp.InAddr >= ReadBorder)
|
||||
{
|
||||
var FileDone = false;
|
||||
|
||||
// We use 'while', because for empty block containing only Huffman table,
|
||||
// we'll be on the block border once again just after reading the table.
|
||||
while (
|
||||
Inp.InAddr > BlockHeader.BlockStart + BlockHeader.BlockSize - 1
|
||||
|| Inp.InAddr == BlockHeader.BlockStart + BlockHeader.BlockSize - 1
|
||||
&& Inp.InBit >= BlockHeader.BlockBitSize
|
||||
)
|
||||
{
|
||||
if (BlockHeader.LastBlockInFile)
|
||||
{
|
||||
FileDone = true;
|
||||
break;
|
||||
}
|
||||
if (
|
||||
!await ReadBlockHeaderAsync(cancellationToken).ConfigureAwait(false)
|
||||
|| !ReadTables()
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (FileDone || !await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
((WriteBorder - UnpPtr) & MaxWinMask) < PackDef.MAX_LZ_MATCH + 3
|
||||
&& WriteBorder != UnpPtr
|
||||
)
|
||||
{
|
||||
UnpWriteBuf();
|
||||
if (WrittenFileSize > DestUnpSize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Suspended)
|
||||
{
|
||||
FileExtracted = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var MainSlot = this.DecodeNumber(LD);
|
||||
if (MainSlot < 256)
|
||||
{
|
||||
Window[UnpPtr++] = (byte)MainSlot;
|
||||
continue;
|
||||
}
|
||||
if (MainSlot >= 262)
|
||||
{
|
||||
var Length = SlotToLength(MainSlot - 262);
|
||||
|
||||
int DBits;
|
||||
uint Distance = 1,
|
||||
DistSlot = this.DecodeNumber(DD);
|
||||
if (DistSlot < 4)
|
||||
{
|
||||
DBits = 0;
|
||||
Distance += DistSlot;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBits = (int)((DistSlot / 2) - 1);
|
||||
Distance += (2 | (DistSlot & 1)) << DBits;
|
||||
}
|
||||
|
||||
if (DBits > 0)
|
||||
{
|
||||
if (DBits >= 4)
|
||||
{
|
||||
if (DBits > 4)
|
||||
{
|
||||
Distance += ((Inp.getbits() >> (36 - DBits)) << 4);
|
||||
Inp.AddBits(DBits - 4);
|
||||
}
|
||||
var LowDist = this.DecodeNumber(LDD);
|
||||
Distance += LowDist;
|
||||
}
|
||||
else
|
||||
{
|
||||
Distance += Inp.getbits() >> (32 - DBits);
|
||||
Inp.AddBits(DBits);
|
||||
}
|
||||
}
|
||||
|
||||
if (Distance > 0x100)
|
||||
{
|
||||
Length++;
|
||||
if (Distance > 0x2000)
|
||||
{
|
||||
Length++;
|
||||
if (Distance > 0x40000)
|
||||
{
|
||||
Length++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InsertOldDist(Distance);
|
||||
LastLength = Length;
|
||||
CopyString(Length, Distance);
|
||||
continue;
|
||||
}
|
||||
if (MainSlot == 256)
|
||||
{
|
||||
var Filter = new UnpackFilter();
|
||||
if (
|
||||
!await ReadFilterAsync(Filter, cancellationToken).ConfigureAwait(false)
|
||||
|| !AddFilter(Filter)
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
if (MainSlot == 257)
|
||||
{
|
||||
if (LastLength != 0)
|
||||
{
|
||||
CopyString(LastLength, OldDistN(0));
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
if (MainSlot < 262)
|
||||
{
|
||||
var DistNum = (int)(MainSlot - 258);
|
||||
var Distance = OldDistN(DistNum);
|
||||
for (var I = DistNum; I > 0; I--)
|
||||
{
|
||||
SetOldDistN(I, OldDistN(I - 1));
|
||||
}
|
||||
|
||||
SetOldDistN(0, Distance);
|
||||
|
||||
var LengthSlot = this.DecodeNumber(RD);
|
||||
var Length = SlotToLength(LengthSlot);
|
||||
LastLength = Length;
|
||||
CopyString(Length, Distance);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
UnpWriteBuf();
|
||||
}
|
||||
|
||||
private async Task<bool> ReadBlockHeaderAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
Header.HeaderSize = 0;
|
||||
|
||||
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 7)
|
||||
{
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Inp.faddbits((uint)((8 - Inp.InBit) & 7));
|
||||
|
||||
var BlockFlags = (byte)(Inp.fgetbits() >> 8);
|
||||
Inp.faddbits(8);
|
||||
var ByteCount = (uint)(((BlockFlags >> 3) & 3) + 1);
|
||||
|
||||
if (ByteCount == 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Header.HeaderSize = (int)(2 + ByteCount);
|
||||
|
||||
Header.BlockBitSize = (BlockFlags & 7) + 1;
|
||||
|
||||
var SavedCheckSum = (byte)(Inp.fgetbits() >> 8);
|
||||
Inp.faddbits(8);
|
||||
|
||||
var BlockSize = 0;
|
||||
for (var I = 0; I < ByteCount; I++)
|
||||
{
|
||||
BlockSize += (int)(Inp.fgetbits() >> 8) << (I * 8);
|
||||
Inp.AddBits(8);
|
||||
}
|
||||
|
||||
Header.BlockSize = BlockSize;
|
||||
var CheckSum = (byte)(0x5a ^ BlockFlags ^ BlockSize ^ (BlockSize >> 8) ^ (BlockSize >> 16));
|
||||
if (CheckSum != SavedCheckSum)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Header.BlockStart = Inp.InAddr;
|
||||
ReadBorder = Math.Min(ReadBorder, Header.BlockStart + Header.BlockSize - 1);
|
||||
|
||||
Header.LastBlockInFile = (BlockFlags & 0x40) != 0;
|
||||
Header.TablePresent = (BlockFlags & 0x80) != 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task<bool> ReadFilterAsync(
|
||||
UnpackFilter Filter,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 16)
|
||||
{
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Filter.uBlockStart = ReadFilterData();
|
||||
Filter.uBlockLength = ReadFilterData();
|
||||
if (Filter.BlockLength > MAX_FILTER_BLOCK_SIZE)
|
||||
{
|
||||
Filter.BlockLength = 0;
|
||||
}
|
||||
|
||||
Filter.Type = (byte)(Inp.fgetbits() >> 13);
|
||||
Inp.faddbits(3);
|
||||
|
||||
if (Filter.Type == (byte)FilterType.FILTER_DELTA)
|
||||
{
|
||||
Filter.Channels = (byte)((Inp.fgetbits() >> 11) + 1);
|
||||
Inp.faddbits(5);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -479,354 +479,6 @@ internal partial class Unpack
|
||||
return ReadCode != -1;
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task<bool> UnpReadBufAsync(
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var DataSize = ReadTop - Inp.InAddr; // Data left to process.
|
||||
if (DataSize < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BlockHeader.BlockSize -= Inp.InAddr - BlockHeader.BlockStart;
|
||||
if (Inp.InAddr > MAX_SIZE / 2)
|
||||
{
|
||||
if (DataSize > 0)
|
||||
{
|
||||
Array.Copy(InBuf, inAddr, InBuf, 0, DataSize);
|
||||
}
|
||||
|
||||
Inp.InAddr = 0;
|
||||
ReadTop = DataSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
DataSize = ReadTop;
|
||||
}
|
||||
|
||||
var ReadCode = 0;
|
||||
if (MAX_SIZE != DataSize)
|
||||
{
|
||||
ReadCode = await readStream
|
||||
.ReadAsync(InBuf, DataSize, MAX_SIZE - DataSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (ReadCode > 0) // Can be also -1.
|
||||
{
|
||||
ReadTop += ReadCode;
|
||||
}
|
||||
|
||||
ReadBorder = ReadTop - 30;
|
||||
BlockHeader.BlockStart = Inp.InAddr;
|
||||
if (BlockHeader.BlockSize != -1) // '-1' means not defined yet.
|
||||
{
|
||||
ReadBorder = Math.Min(ReadBorder, BlockHeader.BlockStart + BlockHeader.BlockSize - 1);
|
||||
}
|
||||
return ReadCode != -1;
|
||||
}
|
||||
|
||||
public async System.Threading.Tasks.Task Unpack5Async(
|
||||
bool Solid,
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
FileExtracted = true;
|
||||
|
||||
if (!Suspended)
|
||||
{
|
||||
UnpInitData(Solid);
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check TablesRead5 to be sure that we read tables at least once
|
||||
// regardless of current block header TablePresent flag.
|
||||
// So we can safefly use these tables below.
|
||||
if (
|
||||
!await ReadBlockHeaderAsync(cancellationToken).ConfigureAwait(false)
|
||||
|| !ReadTables()
|
||||
|| !TablesRead5
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
UnpPtr &= MaxWinMask;
|
||||
|
||||
if (Inp.InAddr >= ReadBorder)
|
||||
{
|
||||
var FileDone = false;
|
||||
|
||||
// We use 'while', because for empty block containing only Huffman table,
|
||||
// we'll be on the block border once again just after reading the table.
|
||||
while (
|
||||
Inp.InAddr > BlockHeader.BlockStart + BlockHeader.BlockSize - 1
|
||||
|| Inp.InAddr == BlockHeader.BlockStart + BlockHeader.BlockSize - 1
|
||||
&& Inp.InBit >= BlockHeader.BlockBitSize
|
||||
)
|
||||
{
|
||||
if (BlockHeader.LastBlockInFile)
|
||||
{
|
||||
FileDone = true;
|
||||
break;
|
||||
}
|
||||
if (
|
||||
!await ReadBlockHeaderAsync(cancellationToken).ConfigureAwait(false)
|
||||
|| !ReadTables()
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (FileDone || !await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
((WriteBorder - UnpPtr) & MaxWinMask) < PackDef.MAX_LZ_MATCH + 3
|
||||
&& WriteBorder != UnpPtr
|
||||
)
|
||||
{
|
||||
UnpWriteBuf();
|
||||
if (WrittenFileSize > DestUnpSize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Suspended)
|
||||
{
|
||||
FileExtracted = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//uint MainSlot=DecodeNumber(Inp,LD);
|
||||
var MainSlot = this.DecodeNumber(LD);
|
||||
if (MainSlot < 256)
|
||||
{
|
||||
// if (Fragmented)
|
||||
// FragWindow[UnpPtr++]=(byte)MainSlot;
|
||||
// else
|
||||
Window[UnpPtr++] = (byte)MainSlot;
|
||||
continue;
|
||||
}
|
||||
if (MainSlot >= 262)
|
||||
{
|
||||
var Length = SlotToLength(MainSlot - 262);
|
||||
|
||||
//uint DBits,Distance=1,DistSlot=DecodeNumber(Inp,&BlockTables.DD);
|
||||
int DBits;
|
||||
uint Distance = 1,
|
||||
DistSlot = this.DecodeNumber(DD);
|
||||
if (DistSlot < 4)
|
||||
{
|
||||
DBits = 0;
|
||||
Distance += DistSlot;
|
||||
}
|
||||
else
|
||||
{
|
||||
//DBits=DistSlot/2 - 1;
|
||||
DBits = (int)((DistSlot / 2) - 1);
|
||||
Distance += (2 | (DistSlot & 1)) << DBits;
|
||||
}
|
||||
|
||||
if (DBits > 0)
|
||||
{
|
||||
if (DBits >= 4)
|
||||
{
|
||||
if (DBits > 4)
|
||||
{
|
||||
Distance += ((Inp.getbits() >> (36 - DBits)) << 4);
|
||||
Inp.AddBits(DBits - 4);
|
||||
}
|
||||
//uint LowDist=DecodeNumber(Inp,&BlockTables.LDD);
|
||||
var LowDist = this.DecodeNumber(LDD);
|
||||
Distance += LowDist;
|
||||
}
|
||||
else
|
||||
{
|
||||
Distance += Inp.getbits() >> (32 - DBits);
|
||||
Inp.AddBits(DBits);
|
||||
}
|
||||
}
|
||||
|
||||
if (Distance > 0x100)
|
||||
{
|
||||
Length++;
|
||||
if (Distance > 0x2000)
|
||||
{
|
||||
Length++;
|
||||
if (Distance > 0x40000)
|
||||
{
|
||||
Length++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InsertOldDist(Distance);
|
||||
LastLength = Length;
|
||||
// if (Fragmented)
|
||||
// FragWindow.CopyString(Length,Distance,UnpPtr,MaxWinMask);
|
||||
// else
|
||||
CopyString(Length, Distance);
|
||||
continue;
|
||||
}
|
||||
if (MainSlot == 256)
|
||||
{
|
||||
var Filter = new UnpackFilter();
|
||||
if (
|
||||
!await ReadFilterAsync(Filter, cancellationToken).ConfigureAwait(false)
|
||||
|| !AddFilter(Filter)
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
if (MainSlot == 257)
|
||||
{
|
||||
if (LastLength != 0)
|
||||
// if (Fragmented)
|
||||
// FragWindow.CopyString(LastLength,OldDist[0],UnpPtr,MaxWinMask);
|
||||
// else
|
||||
//CopyString(LastLength,OldDist[0]);
|
||||
{
|
||||
CopyString(LastLength, OldDistN(0));
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
if (MainSlot < 262)
|
||||
{
|
||||
//uint DistNum=MainSlot-258;
|
||||
var DistNum = (int)(MainSlot - 258);
|
||||
//uint Distance=OldDist[DistNum];
|
||||
var Distance = OldDistN(DistNum);
|
||||
//for (uint I=DistNum;I>0;I--)
|
||||
for (var I = DistNum; I > 0; I--)
|
||||
//OldDistN[I]=OldDistN(I-1);
|
||||
{
|
||||
SetOldDistN(I, OldDistN(I - 1));
|
||||
}
|
||||
|
||||
//OldDistN[0]=Distance;
|
||||
SetOldDistN(0, Distance);
|
||||
|
||||
var LengthSlot = this.DecodeNumber(RD);
|
||||
var Length = SlotToLength(LengthSlot);
|
||||
LastLength = Length;
|
||||
// if (Fragmented)
|
||||
// FragWindow.CopyString(Length,Distance,UnpPtr,MaxWinMask);
|
||||
// else
|
||||
CopyString(Length, Distance);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
UnpWriteBuf();
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task<bool> ReadBlockHeaderAsync(
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
Header.HeaderSize = 0;
|
||||
|
||||
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 7)
|
||||
{
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//Inp.faddbits((8-Inp.InBit)&7);
|
||||
Inp.faddbits((uint)((8 - Inp.InBit) & 7));
|
||||
|
||||
var BlockFlags = (byte)(Inp.fgetbits() >> 8);
|
||||
Inp.faddbits(8);
|
||||
//uint ByteCount=((BlockFlags>>3)&3)+1; // Block size byte count.
|
||||
var ByteCount = (uint)(((BlockFlags >> 3) & 3) + 1); // Block size byte count.
|
||||
|
||||
if (ByteCount == 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//Header.HeaderSize=2+ByteCount;
|
||||
Header.HeaderSize = (int)(2 + ByteCount);
|
||||
|
||||
Header.BlockBitSize = (BlockFlags & 7) + 1;
|
||||
|
||||
var SavedCheckSum = (byte)(Inp.fgetbits() >> 8);
|
||||
Inp.faddbits(8);
|
||||
|
||||
var BlockSize = 0;
|
||||
//for (uint I=0;I<ByteCount;I++)
|
||||
for (var I = 0; I < ByteCount; I++)
|
||||
{
|
||||
//BlockSize+=(Inp.fgetbits()>>8)<<(I*8);
|
||||
BlockSize += (int)(Inp.fgetbits() >> 8) << (I * 8);
|
||||
Inp.AddBits(8);
|
||||
}
|
||||
|
||||
Header.BlockSize = BlockSize;
|
||||
var CheckSum = (byte)(0x5a ^ BlockFlags ^ BlockSize ^ (BlockSize >> 8) ^ (BlockSize >> 16));
|
||||
if (CheckSum != SavedCheckSum)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Header.BlockStart = Inp.InAddr;
|
||||
ReadBorder = Math.Min(ReadBorder, Header.BlockStart + Header.BlockSize - 1);
|
||||
|
||||
Header.LastBlockInFile = (BlockFlags & 0x40) != 0;
|
||||
Header.TablePresent = (BlockFlags & 0x80) != 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task<bool> ReadFilterAsync(
|
||||
UnpackFilter Filter,
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 16)
|
||||
{
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Filter.uBlockStart = ReadFilterData();
|
||||
Filter.uBlockLength = ReadFilterData();
|
||||
if (Filter.BlockLength > MAX_FILTER_BLOCK_SIZE)
|
||||
{
|
||||
Filter.BlockLength = 0;
|
||||
}
|
||||
|
||||
//Filter.Type=Inp.fgetbits()>>13;
|
||||
Filter.Type = (byte)(Inp.fgetbits() >> 13);
|
||||
Inp.faddbits(3);
|
||||
|
||||
if (Filter.Type == (byte)FilterType.FILTER_DELTA)
|
||||
{
|
||||
//Filter.Channels=(Inp.fgetbits()>>11)+1;
|
||||
Filter.Channels = (byte)((Inp.fgetbits() >> 11) + 1);
|
||||
Inp.faddbits(5);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//?
|
||||
// void UnpWriteBuf()
|
||||
// {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common.Rar.Headers;
|
||||
using size_t = System.UInt32;
|
||||
|
||||
@@ -23,11 +25,11 @@ internal partial class Unpack : IRarUnpack
|
||||
// NOTE: caller has logic to check for -1 for error we throw instead.
|
||||
readStream.Read(buf, offset, count);
|
||||
|
||||
private async System.Threading.Tasks.Task<int> UnpIO_UnpReadAsync(
|
||||
private async Task<int> UnpIO_UnpReadAsync(
|
||||
byte[] buf,
|
||||
int offset,
|
||||
int count,
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
// NOTE: caller has logic to check for -1 for error we throw instead.
|
||||
await readStream.ReadAsync(buf, offset, count, cancellationToken).ConfigureAwait(false);
|
||||
@@ -35,11 +37,11 @@ internal partial class Unpack : IRarUnpack
|
||||
private void UnpIO_UnpWrite(byte[] buf, size_t offset, uint count) =>
|
||||
writeStream.Write(buf, checked((int)offset), checked((int)count));
|
||||
|
||||
private async System.Threading.Tasks.Task UnpIO_UnpWriteAsync(
|
||||
private async Task UnpIO_UnpWriteAsync(
|
||||
byte[] buf,
|
||||
size_t offset,
|
||||
uint count,
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
await writeStream
|
||||
.WriteAsync(buf, checked((int)offset), checked((int)count), cancellationToken)
|
||||
@@ -66,11 +68,11 @@ internal partial class Unpack : IRarUnpack
|
||||
DoUnpack();
|
||||
}
|
||||
|
||||
public async System.Threading.Tasks.Task DoUnpackAsync(
|
||||
public async Task DoUnpackAsync(
|
||||
FileHeader fileHeader,
|
||||
Stream readStream,
|
||||
Stream writeStream,
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
DestUnpSize = fileHeader.UncompressedSize;
|
||||
@@ -97,9 +99,7 @@ internal partial class Unpack : IRarUnpack
|
||||
}
|
||||
}
|
||||
|
||||
public async System.Threading.Tasks.Task DoUnpackAsync(
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
public async Task DoUnpackAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (fileHeader.IsStored)
|
||||
{
|
||||
@@ -133,9 +133,7 @@ internal partial class Unpack : IRarUnpack
|
||||
} while (!Suspended);
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task UnstoreFileAsync(
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
private async Task UnstoreFileAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var buffer = new byte[(int)Math.Min(0x10000, DestUnpSize)];
|
||||
do
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpCompress.Compressors.Rar.UnpackV2017;
|
||||
|
||||
internal partial class Unpack
|
||||
{
|
||||
private async Task Unpack15Async(bool Solid, CancellationToken cancellationToken = default)
|
||||
{
|
||||
UnpInitData(Solid);
|
||||
UnpInitData15(Solid);
|
||||
await UnpReadBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (!Solid)
|
||||
{
|
||||
InitHuff();
|
||||
UnpPtr = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
UnpPtr = WrPtr;
|
||||
}
|
||||
|
||||
--DestUnpSize;
|
||||
if (DestUnpSize >= 0)
|
||||
{
|
||||
GetFlagsBuf();
|
||||
FlagsCnt = 8;
|
||||
}
|
||||
|
||||
while (DestUnpSize >= 0)
|
||||
{
|
||||
UnpPtr &= MaxWinMask;
|
||||
|
||||
if (
|
||||
Inp.InAddr > ReadTop - 30
|
||||
&& !await UnpReadBufAsync(cancellationToken).ConfigureAwait(false)
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (((WrPtr - UnpPtr) & MaxWinMask) < 270 && WrPtr != UnpPtr)
|
||||
{
|
||||
UnpWriteBuf20();
|
||||
}
|
||||
|
||||
if (StMode != 0)
|
||||
{
|
||||
HuffDecode();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (--FlagsCnt < 0)
|
||||
{
|
||||
GetFlagsBuf();
|
||||
FlagsCnt = 7;
|
||||
}
|
||||
|
||||
if ((FlagBuf & 0x80) != 0)
|
||||
{
|
||||
FlagBuf <<= 1;
|
||||
if (Nlzb > Nhfb)
|
||||
{
|
||||
LongLZ();
|
||||
}
|
||||
else
|
||||
{
|
||||
HuffDecode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FlagBuf <<= 1;
|
||||
if (--FlagsCnt < 0)
|
||||
{
|
||||
GetFlagsBuf();
|
||||
FlagsCnt = 7;
|
||||
}
|
||||
if ((FlagBuf & 0x80) != 0)
|
||||
{
|
||||
FlagBuf <<= 1;
|
||||
if (Nlzb > Nhfb)
|
||||
{
|
||||
HuffDecode();
|
||||
}
|
||||
else
|
||||
{
|
||||
LongLZ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FlagBuf <<= 1;
|
||||
ShortLZ();
|
||||
}
|
||||
}
|
||||
}
|
||||
UnpWriteBuf20();
|
||||
}
|
||||
}
|
||||
@@ -200,102 +200,6 @@ internal partial class Unpack
|
||||
UnpWriteBuf20();
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task Unpack15Async(
|
||||
bool Solid,
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
UnpInitData(Solid);
|
||||
UnpInitData15(Solid);
|
||||
await UnpReadBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (!Solid)
|
||||
{
|
||||
InitHuff();
|
||||
UnpPtr = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
UnpPtr = WrPtr;
|
||||
}
|
||||
|
||||
--DestUnpSize;
|
||||
if (DestUnpSize >= 0)
|
||||
{
|
||||
GetFlagsBuf();
|
||||
FlagsCnt = 8;
|
||||
}
|
||||
|
||||
while (DestUnpSize >= 0)
|
||||
{
|
||||
UnpPtr &= MaxWinMask;
|
||||
|
||||
if (
|
||||
Inp.InAddr > ReadTop - 30
|
||||
&& !await UnpReadBufAsync(cancellationToken).ConfigureAwait(false)
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (((WrPtr - UnpPtr) & MaxWinMask) < 270 && WrPtr != UnpPtr)
|
||||
{
|
||||
await UnpWriteBuf20Async(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (StMode != 0)
|
||||
{
|
||||
HuffDecode();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (--FlagsCnt < 0)
|
||||
{
|
||||
GetFlagsBuf();
|
||||
FlagsCnt = 7;
|
||||
}
|
||||
|
||||
if ((FlagBuf & 0x80) != 0)
|
||||
{
|
||||
FlagBuf <<= 1;
|
||||
if (Nlzb > Nhfb)
|
||||
{
|
||||
LongLZ();
|
||||
}
|
||||
else
|
||||
{
|
||||
HuffDecode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FlagBuf <<= 1;
|
||||
if (--FlagsCnt < 0)
|
||||
{
|
||||
GetFlagsBuf();
|
||||
FlagsCnt = 7;
|
||||
}
|
||||
if ((FlagBuf & 0x80) != 0)
|
||||
{
|
||||
FlagBuf <<= 1;
|
||||
if (Nlzb > Nhfb)
|
||||
{
|
||||
HuffDecode();
|
||||
}
|
||||
else
|
||||
{
|
||||
LongLZ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FlagBuf <<= 1;
|
||||
ShortLZ();
|
||||
}
|
||||
}
|
||||
}
|
||||
await UnpWriteBuf20Async(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
//#define GetShortLen1(pos) ((pos)==1 ? Buf60+3:ShortLen1[pos])
|
||||
private uint GetShortLen1(uint pos) => ((pos) == 1 ? (uint)(Buf60 + 3) : ShortLen1[pos]);
|
||||
|
||||
|
||||
@@ -0,0 +1,319 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using static SharpCompress.Compressors.Rar.UnpackV2017.PackDef;
|
||||
using static SharpCompress.Compressors.Rar.UnpackV2017.Unpack.Unpack20Local;
|
||||
|
||||
namespace SharpCompress.Compressors.Rar.UnpackV2017;
|
||||
|
||||
internal partial class Unpack
|
||||
{
|
||||
private async Task Unpack20Async(bool Solid, CancellationToken cancellationToken = default)
|
||||
{
|
||||
uint Bits;
|
||||
|
||||
if (Suspended)
|
||||
{
|
||||
UnpPtr = WrPtr;
|
||||
}
|
||||
else
|
||||
{
|
||||
UnpInitData(Solid);
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
(!Solid || !TablesRead2)
|
||||
&& !await ReadTables20Async(cancellationToken).ConfigureAwait(false)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
--DestUnpSize;
|
||||
}
|
||||
|
||||
while (DestUnpSize >= 0)
|
||||
{
|
||||
UnpPtr &= MaxWinMask;
|
||||
|
||||
if (Inp.InAddr > ReadTop - 30)
|
||||
{
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (((WrPtr - UnpPtr) & MaxWinMask) < 270 && WrPtr != UnpPtr)
|
||||
{
|
||||
UnpWriteBuf20();
|
||||
if (Suspended)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (UnpAudioBlock)
|
||||
{
|
||||
var AudioNumber = DecodeNumber(Inp, MD[UnpCurChannel]);
|
||||
|
||||
if (AudioNumber == 256)
|
||||
{
|
||||
if (!await ReadTables20Async(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
Window[UnpPtr++] = DecodeAudio((int)AudioNumber);
|
||||
if (++UnpCurChannel == UnpChannels)
|
||||
{
|
||||
UnpCurChannel = 0;
|
||||
}
|
||||
|
||||
--DestUnpSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
var Number = DecodeNumber(Inp, BlockTables.LD);
|
||||
if (Number < 256)
|
||||
{
|
||||
Window[UnpPtr++] = (byte)Number;
|
||||
--DestUnpSize;
|
||||
continue;
|
||||
}
|
||||
if (Number > 269)
|
||||
{
|
||||
var Length = (uint)(LDecode[Number -= 270] + 3);
|
||||
if ((Bits = LBits[Number]) > 0)
|
||||
{
|
||||
Length += Inp.getbits() >> (int)(16 - Bits);
|
||||
Inp.addbits(Bits);
|
||||
}
|
||||
|
||||
var DistNumber = DecodeNumber(Inp, BlockTables.DD);
|
||||
var Distance = DDecode[DistNumber] + 1;
|
||||
if ((Bits = DBits[DistNumber]) > 0)
|
||||
{
|
||||
Distance += Inp.getbits() >> (int)(16 - Bits);
|
||||
Inp.addbits(Bits);
|
||||
}
|
||||
|
||||
if (Distance >= 0x2000)
|
||||
{
|
||||
Length++;
|
||||
if (Distance >= 0x40000L)
|
||||
{
|
||||
Length++;
|
||||
}
|
||||
}
|
||||
|
||||
CopyString20(Length, Distance);
|
||||
continue;
|
||||
}
|
||||
if (Number == 269)
|
||||
{
|
||||
if (!await ReadTables20Async(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
if (Number == 256)
|
||||
{
|
||||
CopyString20(LastLength, LastDist);
|
||||
continue;
|
||||
}
|
||||
if (Number < 261)
|
||||
{
|
||||
var Distance = OldDist[(OldDistPtr - (Number - 256)) & 3];
|
||||
var LengthNumber = DecodeNumber(Inp, BlockTables.RD);
|
||||
var Length = (uint)(LDecode[LengthNumber] + 2);
|
||||
if ((Bits = LBits[LengthNumber]) > 0)
|
||||
{
|
||||
Length += Inp.getbits() >> (int)(16 - Bits);
|
||||
Inp.addbits(Bits);
|
||||
}
|
||||
if (Distance >= 0x101)
|
||||
{
|
||||
Length++;
|
||||
if (Distance >= 0x2000)
|
||||
{
|
||||
Length++;
|
||||
if (Distance >= 0x40000)
|
||||
{
|
||||
Length++;
|
||||
}
|
||||
}
|
||||
}
|
||||
CopyString20(Length, Distance);
|
||||
continue;
|
||||
}
|
||||
if (Number < 270)
|
||||
{
|
||||
var Distance = (uint)(SDDecode[Number -= 261] + 1);
|
||||
if ((Bits = SDBits[Number]) > 0)
|
||||
{
|
||||
Distance += Inp.getbits() >> (int)(16 - Bits);
|
||||
Inp.addbits(Bits);
|
||||
}
|
||||
CopyString20(2, Distance);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
ReadLastTables();
|
||||
UnpWriteBuf20();
|
||||
}
|
||||
|
||||
private async Task UnpWriteBuf20Async(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (UnpPtr != WrPtr)
|
||||
{
|
||||
UnpSomeRead = true;
|
||||
}
|
||||
|
||||
if (UnpPtr < WrPtr)
|
||||
{
|
||||
await UnpIO_UnpWriteAsync(
|
||||
Window,
|
||||
WrPtr,
|
||||
(uint)(-(int)WrPtr & MaxWinMask),
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
await UnpIO_UnpWriteAsync(Window, 0, UnpPtr, cancellationToken).ConfigureAwait(false);
|
||||
UnpAllBuf = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
await UnpIO_UnpWriteAsync(Window, WrPtr, UnpPtr - WrPtr, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
WrPtr = UnpPtr;
|
||||
}
|
||||
|
||||
private async Task<bool> ReadTables20Async(CancellationToken cancellationToken = default)
|
||||
{
|
||||
byte[] BitLength = new byte[checked((int)BC20)];
|
||||
byte[] Table = new byte[checked((int)MC20 * 4)];
|
||||
if (Inp.InAddr > ReadTop - 25)
|
||||
{
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var BitField = Inp.getbits();
|
||||
UnpAudioBlock = (BitField & 0x8000) != 0;
|
||||
|
||||
if ((BitField & 0x4000) != 0)
|
||||
{
|
||||
Array.Clear(UnpOldTable20, 0, UnpOldTable20.Length);
|
||||
}
|
||||
|
||||
Inp.addbits(2);
|
||||
|
||||
uint TableSize;
|
||||
if (UnpAudioBlock)
|
||||
{
|
||||
UnpChannels = ((BitField >> 12) & 3) + 1;
|
||||
if (UnpCurChannel >= UnpChannels)
|
||||
{
|
||||
UnpCurChannel = 0;
|
||||
}
|
||||
|
||||
Inp.addbits(2);
|
||||
TableSize = MC20 * UnpChannels;
|
||||
}
|
||||
else
|
||||
{
|
||||
TableSize = NC20 + DC20 + RC20;
|
||||
}
|
||||
|
||||
for (int I = 0; I < checked((int)BC20); I++)
|
||||
{
|
||||
BitLength[I] = (byte)(Inp.getbits() >> 12);
|
||||
Inp.addbits(4);
|
||||
}
|
||||
MakeDecodeTables(BitLength, 0, BlockTables.BD, BC20);
|
||||
for (int I = 0; I < checked((int)TableSize); )
|
||||
{
|
||||
if (Inp.InAddr > ReadTop - 5)
|
||||
{
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var Number = DecodeNumber(Inp, BlockTables.BD);
|
||||
if (Number < 16)
|
||||
{
|
||||
Table[I] = (byte)((Number + UnpOldTable20[I]) & 0xf);
|
||||
I++;
|
||||
}
|
||||
else if (Number == 16)
|
||||
{
|
||||
var N = (Inp.getbits() >> 14) + 3;
|
||||
Inp.addbits(2);
|
||||
if (I == 0)
|
||||
{
|
||||
return false; // We cannot have "repeat previous" code at the first position.
|
||||
}
|
||||
else
|
||||
{
|
||||
while (N-- > 0 && I < TableSize)
|
||||
{
|
||||
Table[I] = Table[I - 1];
|
||||
I++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint N;
|
||||
if (Number == 17)
|
||||
{
|
||||
N = (Inp.getbits() >> 13) + 3;
|
||||
Inp.addbits(3);
|
||||
}
|
||||
else
|
||||
{
|
||||
N = (Inp.getbits() >> 9) + 11;
|
||||
Inp.addbits(7);
|
||||
}
|
||||
while (N-- > 0 && I < TableSize)
|
||||
{
|
||||
Table[I++] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
TablesRead2 = true;
|
||||
if (Inp.InAddr > ReadTop)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (UnpAudioBlock)
|
||||
{
|
||||
for (int I = 0; I < UnpChannels; I++)
|
||||
{
|
||||
MakeDecodeTables(Table, (int)(I * MC20), MD[I], MC20);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MakeDecodeTables(Table, 0, BlockTables.LD, NC20);
|
||||
MakeDecodeTables(Table, (int)NC20, BlockTables.DD, DC20);
|
||||
MakeDecodeTables(Table, (int)(NC20 + DC20), BlockTables.RD, RC20);
|
||||
}
|
||||
Array.Copy(Table, 0, this.UnpOldTable20, 0, UnpOldTable20.Length);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -342,170 +342,6 @@ internal partial class Unpack
|
||||
UnpWriteBuf20();
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task Unpack20Async(
|
||||
bool Solid,
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
uint Bits;
|
||||
|
||||
if (Suspended)
|
||||
{
|
||||
UnpPtr = WrPtr;
|
||||
}
|
||||
else
|
||||
{
|
||||
UnpInitData(Solid);
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
(!Solid || !TablesRead2)
|
||||
&& !await ReadTables20Async(cancellationToken).ConfigureAwait(false)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
--DestUnpSize;
|
||||
}
|
||||
|
||||
while (DestUnpSize >= 0)
|
||||
{
|
||||
UnpPtr &= MaxWinMask;
|
||||
|
||||
if (Inp.InAddr > ReadTop - 30)
|
||||
{
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (((WrPtr - UnpPtr) & MaxWinMask) < 270 && WrPtr != UnpPtr)
|
||||
{
|
||||
await UnpWriteBuf20Async(cancellationToken).ConfigureAwait(false);
|
||||
if (Suspended)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (UnpAudioBlock)
|
||||
{
|
||||
var AudioNumber = DecodeNumber(Inp, MD[UnpCurChannel]);
|
||||
|
||||
if (AudioNumber == 256)
|
||||
{
|
||||
if (!await ReadTables20Async(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
Window[UnpPtr++] = DecodeAudio((int)AudioNumber);
|
||||
if (++UnpCurChannel == UnpChannels)
|
||||
{
|
||||
UnpCurChannel = 0;
|
||||
}
|
||||
|
||||
--DestUnpSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
var Number = DecodeNumber(Inp, BlockTables.LD);
|
||||
if (Number < 256)
|
||||
{
|
||||
Window[UnpPtr++] = (byte)Number;
|
||||
--DestUnpSize;
|
||||
continue;
|
||||
}
|
||||
if (Number > 269)
|
||||
{
|
||||
var Length = (uint)(LDecode[Number -= 270] + 3);
|
||||
if ((Bits = LBits[Number]) > 0)
|
||||
{
|
||||
Length += Inp.getbits() >> (int)(16 - Bits);
|
||||
Inp.addbits(Bits);
|
||||
}
|
||||
|
||||
var DistNumber = DecodeNumber(Inp, BlockTables.DD);
|
||||
var Distance = DDecode[DistNumber] + 1;
|
||||
if ((Bits = DBits[DistNumber]) > 0)
|
||||
{
|
||||
Distance += Inp.getbits() >> (int)(16 - Bits);
|
||||
Inp.addbits(Bits);
|
||||
}
|
||||
|
||||
if (Distance >= 0x2000)
|
||||
{
|
||||
Length++;
|
||||
if (Distance >= 0x40000L)
|
||||
{
|
||||
Length++;
|
||||
}
|
||||
}
|
||||
|
||||
CopyString20(Length, Distance);
|
||||
continue;
|
||||
}
|
||||
if (Number == 269)
|
||||
{
|
||||
if (!await ReadTables20Async(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
if (Number == 256)
|
||||
{
|
||||
CopyString20(LastLength, LastDist);
|
||||
continue;
|
||||
}
|
||||
if (Number < 261)
|
||||
{
|
||||
var Distance = OldDist[(OldDistPtr - (Number - 256)) & 3];
|
||||
var LengthNumber = DecodeNumber(Inp, BlockTables.RD);
|
||||
var Length = (uint)(LDecode[LengthNumber] + 2);
|
||||
if ((Bits = LBits[LengthNumber]) > 0)
|
||||
{
|
||||
Length += Inp.getbits() >> (int)(16 - Bits);
|
||||
Inp.addbits(Bits);
|
||||
}
|
||||
if (Distance >= 0x101)
|
||||
{
|
||||
Length++;
|
||||
if (Distance >= 0x2000)
|
||||
{
|
||||
Length++;
|
||||
if (Distance >= 0x40000)
|
||||
{
|
||||
Length++;
|
||||
}
|
||||
}
|
||||
}
|
||||
CopyString20(Length, Distance);
|
||||
continue;
|
||||
}
|
||||
if (Number < 270)
|
||||
{
|
||||
var Distance = (uint)(SDDecode[Number -= 261] + 1);
|
||||
if ((Bits = SDBits[Number]) > 0)
|
||||
{
|
||||
Distance += Inp.getbits() >> (int)(16 - Bits);
|
||||
Inp.addbits(Bits);
|
||||
}
|
||||
CopyString20(2, Distance);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
ReadLastTables();
|
||||
await UnpWriteBuf20Async(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private void UnpWriteBuf20()
|
||||
{
|
||||
if (UnpPtr != WrPtr)
|
||||
@@ -527,36 +363,6 @@ internal partial class Unpack
|
||||
WrPtr = UnpPtr;
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task UnpWriteBuf20Async(
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (UnpPtr != WrPtr)
|
||||
{
|
||||
UnpSomeRead = true;
|
||||
}
|
||||
|
||||
if (UnpPtr < WrPtr)
|
||||
{
|
||||
await UnpIO_UnpWriteAsync(
|
||||
Window,
|
||||
WrPtr,
|
||||
(uint)(-(int)WrPtr & MaxWinMask),
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
await UnpIO_UnpWriteAsync(Window, 0, UnpPtr, cancellationToken).ConfigureAwait(false);
|
||||
UnpAllBuf = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
await UnpIO_UnpWriteAsync(Window, WrPtr, UnpPtr - WrPtr, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
WrPtr = UnpPtr;
|
||||
}
|
||||
|
||||
private bool ReadTables20()
|
||||
{
|
||||
Span<byte> BitLength = stackalloc byte[checked((int)BC20)];
|
||||
@@ -677,130 +483,6 @@ internal partial class Unpack
|
||||
return true;
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task<bool> ReadTables20Async(
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
byte[] BitLength = new byte[checked((int)BC20)];
|
||||
byte[] Table = new byte[checked((int)MC20 * 4)];
|
||||
if (Inp.InAddr > ReadTop - 25)
|
||||
{
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var BitField = Inp.getbits();
|
||||
UnpAudioBlock = (BitField & 0x8000) != 0;
|
||||
|
||||
if ((BitField & 0x4000) != 0)
|
||||
{
|
||||
Array.Clear(UnpOldTable20, 0, UnpOldTable20.Length);
|
||||
}
|
||||
|
||||
Inp.addbits(2);
|
||||
|
||||
uint TableSize;
|
||||
if (UnpAudioBlock)
|
||||
{
|
||||
UnpChannels = ((BitField >> 12) & 3) + 1;
|
||||
if (UnpCurChannel >= UnpChannels)
|
||||
{
|
||||
UnpCurChannel = 0;
|
||||
}
|
||||
|
||||
Inp.addbits(2);
|
||||
TableSize = MC20 * UnpChannels;
|
||||
}
|
||||
else
|
||||
{
|
||||
TableSize = NC20 + DC20 + RC20;
|
||||
}
|
||||
|
||||
for (int I = 0; I < checked((int)BC20); I++)
|
||||
{
|
||||
BitLength[I] = (byte)(Inp.getbits() >> 12);
|
||||
Inp.addbits(4);
|
||||
}
|
||||
MakeDecodeTables(BitLength, 0, BlockTables.BD, BC20);
|
||||
for (int I = 0; I < checked((int)TableSize); )
|
||||
{
|
||||
if (Inp.InAddr > ReadTop - 5)
|
||||
{
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var Number = DecodeNumber(Inp, BlockTables.BD);
|
||||
if (Number < 16)
|
||||
{
|
||||
Table[I] = (byte)((Number + UnpOldTable20[I]) & 0xF);
|
||||
I++;
|
||||
}
|
||||
else if (Number < 18)
|
||||
{
|
||||
uint N;
|
||||
if (Number == 16)
|
||||
{
|
||||
N = (Inp.getbits() >> 14) + 3;
|
||||
Inp.addbits(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
N = (Inp.getbits() >> 13) + 11;
|
||||
Inp.addbits(3);
|
||||
}
|
||||
if (I == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while (N-- > 0 && I < checked((int)TableSize))
|
||||
{
|
||||
Table[I] = Table[I - 1];
|
||||
I++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint N;
|
||||
if (Number == 18)
|
||||
{
|
||||
N = (Inp.getbits() >> 13) + 3;
|
||||
Inp.addbits(3);
|
||||
}
|
||||
else
|
||||
{
|
||||
N = (Inp.getbits() >> 9) + 11;
|
||||
Inp.addbits(7);
|
||||
}
|
||||
|
||||
while (N-- > 0 && I < checked((int)TableSize))
|
||||
{
|
||||
Table[I++] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (UnpAudioBlock)
|
||||
{
|
||||
for (int I = 0; I < UnpChannels; I++)
|
||||
{
|
||||
MakeDecodeTables(Table, (int)(I * MC20), MD[I], MC20);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MakeDecodeTables(Table, 0, BlockTables.LD, NC20);
|
||||
MakeDecodeTables(Table, (int)NC20, BlockTables.DD, DC20);
|
||||
MakeDecodeTables(Table, (int)(NC20 + DC20), BlockTables.RD, RC20);
|
||||
}
|
||||
Array.Copy(Table, 0, this.UnpOldTable20, 0, UnpOldTable20.Length);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ReadLastTables()
|
||||
{
|
||||
if (ReadTop >= Inp.InAddr + 5)
|
||||
|
||||
@@ -0,0 +1,709 @@
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using static SharpCompress.Compressors.Rar.UnpackV2017.PackDef;
|
||||
using static SharpCompress.Compressors.Rar.UnpackV2017.UnpackGlobal;
|
||||
using size_t = System.UInt32;
|
||||
|
||||
namespace SharpCompress.Compressors.Rar.UnpackV2017;
|
||||
|
||||
internal partial class Unpack
|
||||
{
|
||||
private async Task Unpack5Async(bool Solid, CancellationToken cancellationToken = default)
|
||||
{
|
||||
FileExtracted = true;
|
||||
|
||||
if (!Suspended)
|
||||
{
|
||||
UnpInitData(Solid);
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check TablesRead5 to be sure that we read tables at least once
|
||||
// regardless of current block header TablePresent flag.
|
||||
// So we can safefly use these tables below.
|
||||
if (
|
||||
!await ReadBlockHeaderAsync(Inp, cancellationToken).ConfigureAwait(false)
|
||||
|| !await ReadTablesAsync(Inp, cancellationToken).ConfigureAwait(false)
|
||||
|| !TablesRead5
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
UnpPtr &= MaxWinMask;
|
||||
|
||||
if (Inp.InAddr >= ReadBorder)
|
||||
{
|
||||
var FileDone = false;
|
||||
|
||||
// We use 'while', because for empty block containing only Huffman table,
|
||||
// we'll be on the block border once again just after reading the table.
|
||||
while (
|
||||
Inp.InAddr > BlockHeader.BlockStart + BlockHeader.BlockSize - 1
|
||||
|| Inp.InAddr == BlockHeader.BlockStart + BlockHeader.BlockSize - 1
|
||||
&& Inp.InBit >= BlockHeader.BlockBitSize
|
||||
)
|
||||
{
|
||||
if (BlockHeader.LastBlockInFile)
|
||||
{
|
||||
FileDone = true;
|
||||
break;
|
||||
}
|
||||
if (
|
||||
!await ReadBlockHeaderAsync(Inp, cancellationToken).ConfigureAwait(false)
|
||||
|| !await ReadTablesAsync(Inp, cancellationToken).ConfigureAwait(false)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (FileDone || !await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (((WriteBorder - UnpPtr) & MaxWinMask) < MAX_LZ_MATCH + 3 && WriteBorder != UnpPtr)
|
||||
{
|
||||
await UnpWriteBufAsync(cancellationToken);
|
||||
if (WrittenFileSize > DestUnpSize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Suspended)
|
||||
{
|
||||
FileExtracted = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var MainSlot = DecodeNumber(Inp, BlockTables.LD);
|
||||
if (MainSlot < 256)
|
||||
{
|
||||
if (Fragmented)
|
||||
{
|
||||
FragWindow[UnpPtr++] = (byte)MainSlot;
|
||||
}
|
||||
else
|
||||
{
|
||||
Window[UnpPtr++] = (byte)MainSlot;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (MainSlot >= 262)
|
||||
{
|
||||
var Length = SlotToLength(Inp, MainSlot - 262);
|
||||
|
||||
uint DBits,
|
||||
Distance = 1,
|
||||
DistSlot = DecodeNumber(Inp, BlockTables.DD);
|
||||
if (DistSlot < 4)
|
||||
{
|
||||
DBits = 0;
|
||||
Distance += DistSlot;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBits = (DistSlot / 2) - 1;
|
||||
Distance += (2 | (DistSlot & 1)) << (int)DBits;
|
||||
}
|
||||
|
||||
if (DBits > 0)
|
||||
{
|
||||
if (DBits >= 4)
|
||||
{
|
||||
if (DBits > 4)
|
||||
{
|
||||
Distance += ((Inp.getbits32() >> (int)(36 - DBits)) << 4);
|
||||
Inp.addbits(DBits - 4);
|
||||
}
|
||||
|
||||
var LowDist = DecodeNumber(Inp, BlockTables.LDD);
|
||||
Distance += LowDist;
|
||||
}
|
||||
else
|
||||
{
|
||||
Distance += Inp.getbits32() >> (int)(32 - DBits);
|
||||
Inp.addbits(DBits);
|
||||
}
|
||||
}
|
||||
|
||||
if (Distance > 0x100)
|
||||
{
|
||||
Length++;
|
||||
if (Distance > 0x2000)
|
||||
{
|
||||
Length++;
|
||||
if (Distance > 0x40000)
|
||||
{
|
||||
Length++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InsertOldDist(Distance);
|
||||
LastLength = Length;
|
||||
if (Fragmented)
|
||||
{
|
||||
FragWindow.CopyString(Length, Distance, ref UnpPtr, MaxWinMask);
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyString(Length, Distance);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (MainSlot == 256)
|
||||
{
|
||||
var Filter = new UnpackFilter();
|
||||
if (
|
||||
!await ReadFilterAsync(Inp, Filter, cancellationToken).ConfigureAwait(false)
|
||||
|| !AddFilter(Filter)
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (MainSlot == 257)
|
||||
{
|
||||
if (LastLength != 0)
|
||||
{
|
||||
if (Fragmented)
|
||||
{
|
||||
FragWindow.CopyString(LastLength, OldDist[0], ref UnpPtr, MaxWinMask);
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyString(LastLength, OldDist[0]);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (MainSlot < 262)
|
||||
{
|
||||
var DistNum = MainSlot - 258;
|
||||
var Distance = OldDist[DistNum];
|
||||
for (var I = DistNum; I > 0; I--)
|
||||
{
|
||||
OldDist[I] = OldDist[I - 1];
|
||||
}
|
||||
|
||||
OldDist[0] = Distance;
|
||||
|
||||
var LengthSlot = DecodeNumber(Inp, BlockTables.RD);
|
||||
var Length = SlotToLength(Inp, LengthSlot);
|
||||
LastLength = Length;
|
||||
if (Fragmented)
|
||||
{
|
||||
FragWindow.CopyString(Length, Distance, ref UnpPtr, MaxWinMask);
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyString(Length, Distance);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
await UnpWriteBufAsync(cancellationToken);
|
||||
}
|
||||
|
||||
private async Task<bool> ReadFilterAsync(
|
||||
BitInput Inp,
|
||||
UnpackFilter Filter,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 16)
|
||||
{
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Filter.BlockStart = ReadFilterData(Inp);
|
||||
Filter.BlockLength = ReadFilterData(Inp);
|
||||
if (Filter.BlockLength > MAX_FILTER_BLOCK_SIZE)
|
||||
{
|
||||
Filter.BlockLength = 0;
|
||||
}
|
||||
|
||||
Filter.Type = (byte)(Inp.fgetbits() >> 13);
|
||||
Inp.faddbits(3);
|
||||
|
||||
if (Filter.Type == FILTER_DELTA)
|
||||
{
|
||||
Filter.Channels = (byte)((Inp.fgetbits() >> 11) + 1);
|
||||
Inp.faddbits(5);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task<bool> UnpReadBufAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var DataSize = ReadTop - Inp.InAddr; // Data left to process.
|
||||
if (DataSize < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BlockHeader.BlockSize -= Inp.InAddr - BlockHeader.BlockStart;
|
||||
if (Inp.InAddr > MAX_SIZE / 2)
|
||||
{
|
||||
if (DataSize > 0)
|
||||
{
|
||||
Buffer.BlockCopy(Inp.InBuf, Inp.InAddr, Inp.InBuf, 0, DataSize);
|
||||
}
|
||||
|
||||
Inp.InAddr = 0;
|
||||
ReadTop = DataSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
DataSize = ReadTop;
|
||||
}
|
||||
|
||||
var ReadCode = 0;
|
||||
if (MAX_SIZE != DataSize)
|
||||
{
|
||||
ReadCode = await UnpIO_UnpReadAsync(
|
||||
Inp.InBuf,
|
||||
DataSize,
|
||||
MAX_SIZE - DataSize,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (ReadCode > 0) // Can be also -1.
|
||||
{
|
||||
ReadTop += ReadCode;
|
||||
}
|
||||
|
||||
ReadBorder = ReadTop - 30;
|
||||
BlockHeader.BlockStart = Inp.InAddr;
|
||||
if (BlockHeader.BlockSize != -1) // '-1' means not defined yet.
|
||||
{
|
||||
ReadBorder = Math.Min(ReadBorder, BlockHeader.BlockStart + BlockHeader.BlockSize - 1);
|
||||
}
|
||||
return ReadCode != -1;
|
||||
}
|
||||
|
||||
private async Task UnpWriteBufAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var WrittenBorder = WrPtr;
|
||||
var FullWriteSize = (UnpPtr - WrittenBorder) & MaxWinMask;
|
||||
var WriteSizeLeft = FullWriteSize;
|
||||
var NotAllFiltersProcessed = false;
|
||||
|
||||
for (var I = 0; I < Filters.Count; I++)
|
||||
{
|
||||
var flt = Filters[I];
|
||||
if (flt.Type == FILTER_NONE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flt.NextWindow)
|
||||
{
|
||||
if (((flt.BlockStart - WrPtr) & MaxWinMask) <= FullWriteSize)
|
||||
{
|
||||
flt.NextWindow = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
var BlockStart = flt.BlockStart;
|
||||
var BlockLength = flt.BlockLength;
|
||||
if (((BlockStart - WrittenBorder) & MaxWinMask) < WriteSizeLeft)
|
||||
{
|
||||
if (WrittenBorder != BlockStart)
|
||||
{
|
||||
await UnpWriteAreaAsync(WrittenBorder, BlockStart, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
WrittenBorder = BlockStart;
|
||||
WriteSizeLeft = (UnpPtr - WrittenBorder) & MaxWinMask;
|
||||
}
|
||||
if (BlockLength <= WriteSizeLeft)
|
||||
{
|
||||
if (BlockLength > 0)
|
||||
{
|
||||
var BlockEnd = (BlockStart + BlockLength) & MaxWinMask;
|
||||
|
||||
FilterSrcMemory = EnsureCapacity(
|
||||
FilterSrcMemory,
|
||||
checked((int)BlockLength)
|
||||
);
|
||||
var Mem = FilterSrcMemory;
|
||||
if (BlockStart < BlockEnd || BlockEnd == 0)
|
||||
{
|
||||
if (Fragmented)
|
||||
{
|
||||
FragWindow.CopyData(Mem, 0, BlockStart, BlockLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy(Window, (int)BlockStart, Mem, 0, (int)BlockLength);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var FirstPartLength = MaxWinSize - BlockStart;
|
||||
if (Fragmented)
|
||||
{
|
||||
FragWindow.CopyData(Mem, 0, BlockStart, FirstPartLength);
|
||||
FragWindow.CopyData(Mem, FirstPartLength, 0, BlockEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy(
|
||||
Window,
|
||||
(int)BlockStart,
|
||||
Mem,
|
||||
0,
|
||||
(int)FirstPartLength
|
||||
);
|
||||
Buffer.BlockCopy(
|
||||
Window,
|
||||
0,
|
||||
Mem,
|
||||
(int)FirstPartLength,
|
||||
(int)BlockEnd
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var OutMem = ApplyFilter(Mem, BlockLength, flt);
|
||||
|
||||
Filters[I].Type = FILTER_NONE;
|
||||
|
||||
if (OutMem != null)
|
||||
{
|
||||
await UnpIO_UnpWriteAsync(OutMem, 0, BlockLength, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
WrittenFileSize += BlockLength;
|
||||
}
|
||||
|
||||
WrittenBorder = BlockEnd;
|
||||
WriteSizeLeft = (UnpPtr - WrittenBorder) & MaxWinMask;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NotAllFiltersProcessed = true;
|
||||
for (var J = I; J < Filters.Count; J++)
|
||||
{
|
||||
var fltj = Filters[J];
|
||||
if (
|
||||
fltj.Type != FILTER_NONE
|
||||
&& fltj.NextWindow == false
|
||||
&& ((fltj.BlockStart - WrPtr) & MaxWinMask) < FullWriteSize
|
||||
)
|
||||
{
|
||||
fltj.NextWindow = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var EmptyCount = 0;
|
||||
for (var I = 0; I < Filters.Count; I++)
|
||||
{
|
||||
if (EmptyCount > 0)
|
||||
{
|
||||
Filters[I - EmptyCount] = Filters[I];
|
||||
}
|
||||
|
||||
if (Filters[I].Type == FILTER_NONE)
|
||||
{
|
||||
EmptyCount++;
|
||||
}
|
||||
}
|
||||
if (EmptyCount > 0)
|
||||
{
|
||||
Filters.RemoveRange(Filters.Count - EmptyCount, EmptyCount);
|
||||
}
|
||||
|
||||
if (!NotAllFiltersProcessed)
|
||||
{
|
||||
await UnpWriteAreaAsync(WrittenBorder, UnpPtr, cancellationToken).ConfigureAwait(false);
|
||||
WrPtr = UnpPtr;
|
||||
}
|
||||
|
||||
WriteBorder = (UnpPtr + Math.Min(MaxWinSize, UNPACK_MAX_WRITE)) & MaxWinMask;
|
||||
|
||||
if (
|
||||
WriteBorder == UnpPtr
|
||||
|| WrPtr != UnpPtr
|
||||
&& ((WrPtr - UnpPtr) & MaxWinMask) < ((WriteBorder - UnpPtr) & MaxWinMask)
|
||||
)
|
||||
{
|
||||
WriteBorder = WrPtr;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UnpWriteAreaAsync(
|
||||
size_t StartPtr,
|
||||
size_t EndPtr,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (EndPtr != StartPtr)
|
||||
{
|
||||
UnpSomeRead = true;
|
||||
}
|
||||
|
||||
if (EndPtr < StartPtr)
|
||||
{
|
||||
UnpAllBuf = true;
|
||||
}
|
||||
|
||||
if (Fragmented)
|
||||
{
|
||||
var SizeToWrite = (EndPtr - StartPtr) & MaxWinMask;
|
||||
while (SizeToWrite > 0)
|
||||
{
|
||||
var BlockSize = FragWindow.GetBlockSize(StartPtr, SizeToWrite);
|
||||
FragWindow.GetBuffer(StartPtr, out var __buffer, out var __offset);
|
||||
await UnpWriteDataAsync(__buffer, __offset, BlockSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
SizeToWrite -= BlockSize;
|
||||
StartPtr = (StartPtr + BlockSize) & MaxWinMask;
|
||||
}
|
||||
}
|
||||
else if (EndPtr < StartPtr)
|
||||
{
|
||||
await UnpWriteDataAsync(Window, StartPtr, MaxWinSize - StartPtr, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
await UnpWriteDataAsync(Window, 0, EndPtr, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await UnpWriteDataAsync(Window, StartPtr, EndPtr - StartPtr, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UnpWriteDataAsync(
|
||||
byte[] Data,
|
||||
size_t offset,
|
||||
size_t Size,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (WrittenFileSize >= DestUnpSize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var WriteSize = Size;
|
||||
var LeftToWrite = DestUnpSize - WrittenFileSize;
|
||||
if (WriteSize > LeftToWrite)
|
||||
{
|
||||
WriteSize = (size_t)LeftToWrite;
|
||||
}
|
||||
|
||||
await UnpIO_UnpWriteAsync(Data, offset, WriteSize, cancellationToken).ConfigureAwait(false);
|
||||
WrittenFileSize += Size;
|
||||
}
|
||||
|
||||
private async Task<bool> ReadBlockHeaderAsync(
|
||||
BitInput Inp,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
BlockHeader.HeaderSize = 0;
|
||||
|
||||
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 7)
|
||||
{
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Inp.faddbits((uint)((8 - Inp.InBit) & 7));
|
||||
|
||||
var BlockFlags = (byte)(Inp.fgetbits() >> 8);
|
||||
Inp.faddbits(8);
|
||||
var ByteCount = (uint)(((BlockFlags >> 3) & 3) + 1); // Block size byte count.
|
||||
|
||||
if (ByteCount == 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BlockHeader.HeaderSize = (int)(2 + ByteCount);
|
||||
|
||||
BlockHeader.BlockBitSize = (BlockFlags & 7) + 1;
|
||||
|
||||
var SavedCheckSum = (byte)(Inp.fgetbits() >> 8);
|
||||
Inp.faddbits(8);
|
||||
|
||||
var BlockSize = 0;
|
||||
for (uint I = 0; I < ByteCount; I++)
|
||||
{
|
||||
BlockSize += (int)((Inp.fgetbits() >> 8) << (int)(I * 8));
|
||||
Inp.addbits(8);
|
||||
}
|
||||
|
||||
BlockHeader.BlockSize = BlockSize;
|
||||
var CheckSum = (byte)(0x5a ^ BlockFlags ^ BlockSize ^ (BlockSize >> 8) ^ (BlockSize >> 16));
|
||||
if (CheckSum != SavedCheckSum)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BlockHeader.BlockStart = Inp.InAddr;
|
||||
ReadBorder = Math.Min(ReadBorder, BlockHeader.BlockStart + BlockHeader.BlockSize - 1);
|
||||
|
||||
BlockHeader.LastBlockInFile = (BlockFlags & 0x40) != 0;
|
||||
BlockHeader.TablePresent = (BlockFlags & 0x80) != 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task<bool> ReadTablesAsync(
|
||||
BitInput Inp,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (!BlockHeader.TablePresent)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 25)
|
||||
{
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var BitLength = new byte[checked((int)BC)];
|
||||
for (int I = 0; I < BC; I++)
|
||||
{
|
||||
uint Length = (byte)(Inp.fgetbits() >> 12);
|
||||
Inp.faddbits(4);
|
||||
if (Length == 15)
|
||||
{
|
||||
uint ZeroCount = (byte)(Inp.fgetbits() >> 12);
|
||||
Inp.faddbits(4);
|
||||
if (ZeroCount == 0)
|
||||
{
|
||||
BitLength[I] = 15;
|
||||
}
|
||||
else
|
||||
{
|
||||
ZeroCount += 2;
|
||||
while (ZeroCount-- > 0 && I < BitLength.Length)
|
||||
{
|
||||
BitLength[I++] = 0;
|
||||
}
|
||||
|
||||
I--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BitLength[I] = (byte)Length;
|
||||
}
|
||||
}
|
||||
|
||||
MakeDecodeTables(BitLength, 0, BlockTables.BD, BC);
|
||||
|
||||
var Table = new byte[checked((int)HUFF_TABLE_SIZE)];
|
||||
const int TableSize = checked((int)HUFF_TABLE_SIZE);
|
||||
for (int I = 0; I < TableSize; )
|
||||
{
|
||||
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 5)
|
||||
{
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var Number = DecodeNumber(Inp, BlockTables.BD);
|
||||
if (Number < 16)
|
||||
{
|
||||
Table[I] = (byte)Number;
|
||||
I++;
|
||||
}
|
||||
else if (Number < 18)
|
||||
{
|
||||
uint N;
|
||||
if (Number == 16)
|
||||
{
|
||||
N = (Inp.fgetbits() >> 13) + 3;
|
||||
Inp.faddbits(3);
|
||||
}
|
||||
else
|
||||
{
|
||||
N = (Inp.fgetbits() >> 9) + 11;
|
||||
Inp.faddbits(7);
|
||||
}
|
||||
if (I == 0)
|
||||
{
|
||||
// We cannot have "repeat previous" code at the first position.
|
||||
// Multiple such codes would shift Inp position without changing I,
|
||||
// which can lead to reading beyond of Inp boundary in mutithreading
|
||||
// mode, where Inp.ExternalBuffer disables bounds check and we just
|
||||
// reserve a lot of buffer space to not need such check normally.
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (N-- > 0 && I < TableSize)
|
||||
{
|
||||
Table[I] = Table[I - 1];
|
||||
I++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint N;
|
||||
if (Number == 18)
|
||||
{
|
||||
N = (Inp.fgetbits() >> 13) + 3;
|
||||
Inp.faddbits(3);
|
||||
}
|
||||
else
|
||||
{
|
||||
N = (Inp.fgetbits() >> 9) + 11;
|
||||
Inp.faddbits(7);
|
||||
}
|
||||
while (N-- > 0 && I < TableSize)
|
||||
{
|
||||
Table[I++] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
TablesRead5 = true;
|
||||
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
MakeDecodeTables(Table, 0, BlockTables.LD, NC);
|
||||
MakeDecodeTables(Table, (int)NC, BlockTables.DD, DC);
|
||||
MakeDecodeTables(Table, (int)(NC + DC), BlockTables.LDD, LDC);
|
||||
MakeDecodeTables(Table, (int)(NC + DC + LDC), BlockTables.RD, RC);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -24,11 +24,7 @@ internal partial class Unpack
|
||||
// Check TablesRead5 to be sure that we read tables at least once
|
||||
// regardless of current block header TablePresent flag.
|
||||
// So we can safefly use these tables below.
|
||||
if (
|
||||
!ReadBlockHeader(Inp, ref BlockHeader)
|
||||
|| !ReadTables(Inp, ref BlockHeader, ref BlockTables)
|
||||
|| !TablesRead5
|
||||
)
|
||||
if (!ReadBlockHeader(Inp) || !ReadTables(Inp) || !TablesRead5)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -55,10 +51,7 @@ internal partial class Unpack
|
||||
FileDone = true;
|
||||
break;
|
||||
}
|
||||
if (
|
||||
!ReadBlockHeader(Inp, ref BlockHeader)
|
||||
|| !ReadTables(Inp, ref BlockHeader, ref BlockTables)
|
||||
)
|
||||
if (!ReadBlockHeader(Inp) || !ReadTables(Inp))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -216,180 +209,6 @@ internal partial class Unpack
|
||||
UnpWriteBuf();
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task Unpack5Async(
|
||||
bool Solid,
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
FileExtracted = true;
|
||||
|
||||
if (!Suspended)
|
||||
{
|
||||
UnpInitData(Solid);
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!ReadBlockHeader(Inp, ref BlockHeader)
|
||||
|| !ReadTables(Inp, ref BlockHeader, ref BlockTables)
|
||||
|| !TablesRead5
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
UnpPtr &= MaxWinMask;
|
||||
|
||||
if (Inp.InAddr >= ReadBorder)
|
||||
{
|
||||
var FileDone = false;
|
||||
|
||||
while (
|
||||
Inp.InAddr > BlockHeader.BlockStart + BlockHeader.BlockSize - 1
|
||||
|| Inp.InAddr == BlockHeader.BlockStart + BlockHeader.BlockSize - 1
|
||||
&& Inp.InBit >= BlockHeader.BlockBitSize
|
||||
)
|
||||
{
|
||||
if (BlockHeader.LastBlockInFile)
|
||||
{
|
||||
FileDone = true;
|
||||
break;
|
||||
}
|
||||
if (
|
||||
!ReadBlockHeader(Inp, ref BlockHeader)
|
||||
|| !ReadTables(Inp, ref BlockHeader, ref BlockTables)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (FileDone || !await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (((WriteBorder - UnpPtr) & MaxWinMask) < MAX_LZ_MATCH + 3 && WriteBorder != UnpPtr)
|
||||
{
|
||||
await UnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (WrittenFileSize > DestUnpSize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint MainSlot = DecodeNumber(Inp, BlockTables.LD);
|
||||
if (MainSlot < 256)
|
||||
{
|
||||
if (Fragmented)
|
||||
{
|
||||
FragWindow[UnpPtr++] = (byte)MainSlot;
|
||||
}
|
||||
else
|
||||
{
|
||||
Window[UnpPtr++] = (byte)MainSlot;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (MainSlot >= 262)
|
||||
{
|
||||
uint Length = SlotToLength(Inp, MainSlot - 262);
|
||||
|
||||
uint DBits,
|
||||
Distance = 1,
|
||||
DistSlot = DecodeNumber(Inp, BlockTables.DD);
|
||||
if (DistSlot < 4)
|
||||
{
|
||||
DBits = 0;
|
||||
Distance += DistSlot;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBits = (DistSlot / 2) - 1;
|
||||
Distance += (2 | (DistSlot & 1)) << (int)DBits;
|
||||
}
|
||||
|
||||
if (DBits > 0)
|
||||
{
|
||||
if (DBits >= 4)
|
||||
{
|
||||
if (DBits > 4)
|
||||
{
|
||||
Distance += ((Inp.getbits() >> (int)(20 - DBits)) << 4);
|
||||
Inp.addbits(DBits - 4);
|
||||
}
|
||||
|
||||
uint LowDist = DecodeNumber(Inp, BlockTables.LDD);
|
||||
Distance += LowDist;
|
||||
}
|
||||
else
|
||||
{
|
||||
Distance += Inp.getbits() >> (int)(16 - DBits);
|
||||
Inp.addbits(DBits);
|
||||
}
|
||||
}
|
||||
|
||||
if (Distance > 0x100)
|
||||
{
|
||||
Length++;
|
||||
if (Distance > 0x2000)
|
||||
{
|
||||
Length++;
|
||||
if (Distance > 0x40000)
|
||||
{
|
||||
Length++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InsertOldDist(Distance);
|
||||
LastLength = Length;
|
||||
CopyString(Length, Distance);
|
||||
continue;
|
||||
}
|
||||
if (MainSlot == 256)
|
||||
{
|
||||
var Filter = new UnpackFilter();
|
||||
if (!ReadFilter(Inp, Filter) || !AddFilter(Filter))
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (MainSlot == 257)
|
||||
{
|
||||
if (LastLength != 0)
|
||||
{
|
||||
CopyString((uint)LastLength, (uint)OldDist[0]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (MainSlot < 262)
|
||||
{
|
||||
uint DistNum = MainSlot - 258;
|
||||
uint Distance = (uint)OldDist[(int)DistNum];
|
||||
for (var I = (int)DistNum; I > 0; I--)
|
||||
{
|
||||
OldDist[I] = OldDist[I - 1];
|
||||
}
|
||||
OldDist[0] = Distance;
|
||||
|
||||
uint LengthSlot = DecodeNumber(Inp, BlockTables.RD);
|
||||
uint Length = SlotToLength(Inp, LengthSlot);
|
||||
LastLength = Length;
|
||||
CopyString(Length, Distance);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
await UnpWriteBufAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private uint ReadFilterData(BitInput Inp)
|
||||
{
|
||||
var ByteCount = (Inp.fgetbits() >> 14) + 1;
|
||||
@@ -507,58 +326,6 @@ internal partial class Unpack
|
||||
return ReadCode != -1;
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task<bool> UnpReadBufAsync(
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var DataSize = ReadTop - Inp.InAddr; // Data left to process.
|
||||
if (DataSize < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BlockHeader.BlockSize -= Inp.InAddr - BlockHeader.BlockStart;
|
||||
if (Inp.InAddr > MAX_SIZE / 2)
|
||||
{
|
||||
if (DataSize > 0)
|
||||
{
|
||||
Buffer.BlockCopy(Inp.InBuf, Inp.InAddr, Inp.InBuf, 0, DataSize);
|
||||
}
|
||||
|
||||
Inp.InAddr = 0;
|
||||
ReadTop = DataSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
DataSize = ReadTop;
|
||||
}
|
||||
|
||||
var ReadCode = 0;
|
||||
if (MAX_SIZE != DataSize)
|
||||
{
|
||||
ReadCode = await UnpIO_UnpReadAsync(
|
||||
Inp.InBuf,
|
||||
DataSize,
|
||||
MAX_SIZE - DataSize,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (ReadCode > 0) // Can be also -1.
|
||||
{
|
||||
ReadTop += ReadCode;
|
||||
}
|
||||
|
||||
ReadBorder = ReadTop - 30;
|
||||
BlockHeader.BlockStart = Inp.InAddr;
|
||||
if (BlockHeader.BlockSize != -1) // '-1' means not defined yet.
|
||||
{
|
||||
ReadBorder = Math.Min(ReadBorder, BlockHeader.BlockStart + BlockHeader.BlockSize - 1);
|
||||
}
|
||||
return ReadCode != -1;
|
||||
}
|
||||
|
||||
private void UnpWriteBuf()
|
||||
{
|
||||
var WrittenBorder = WrPtr;
|
||||
@@ -753,163 +520,6 @@ internal partial class Unpack
|
||||
}
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task UnpWriteBufAsync(
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var WrittenBorder = WrPtr;
|
||||
var FullWriteSize = (UnpPtr - WrittenBorder) & MaxWinMask;
|
||||
var WriteSizeLeft = FullWriteSize;
|
||||
var NotAllFiltersProcessed = false;
|
||||
|
||||
for (var I = 0; I < Filters.Count; I++)
|
||||
{
|
||||
var flt = Filters[I];
|
||||
if (flt.Type == FILTER_NONE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flt.NextWindow)
|
||||
{
|
||||
if (((flt.BlockStart - WrPtr) & MaxWinMask) <= FullWriteSize)
|
||||
{
|
||||
flt.NextWindow = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
var BlockStart = flt.BlockStart;
|
||||
var BlockLength = flt.BlockLength;
|
||||
if (((BlockStart - WrittenBorder) & MaxWinMask) < WriteSizeLeft)
|
||||
{
|
||||
if (WrittenBorder != BlockStart)
|
||||
{
|
||||
await UnpWriteAreaAsync(WrittenBorder, BlockStart, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
WrittenBorder = BlockStart;
|
||||
WriteSizeLeft = (UnpPtr - WrittenBorder) & MaxWinMask;
|
||||
}
|
||||
if (BlockLength <= WriteSizeLeft)
|
||||
{
|
||||
if (BlockLength > 0)
|
||||
{
|
||||
var BlockEnd = (BlockStart + BlockLength) & MaxWinMask;
|
||||
|
||||
FilterSrcMemory = EnsureCapacity(
|
||||
FilterSrcMemory,
|
||||
checked((int)BlockLength)
|
||||
);
|
||||
var Mem = FilterSrcMemory;
|
||||
if (BlockStart < BlockEnd || BlockEnd == 0)
|
||||
{
|
||||
if (Fragmented)
|
||||
{
|
||||
FragWindow.CopyData(Mem, 0, BlockStart, BlockLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy(Window, (int)BlockStart, Mem, 0, (int)BlockLength);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var FirstPartLength = MaxWinSize - BlockStart;
|
||||
if (Fragmented)
|
||||
{
|
||||
FragWindow.CopyData(Mem, 0, BlockStart, FirstPartLength);
|
||||
FragWindow.CopyData(Mem, FirstPartLength, 0, BlockEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy(
|
||||
Window,
|
||||
(int)BlockStart,
|
||||
Mem,
|
||||
0,
|
||||
(int)FirstPartLength
|
||||
);
|
||||
Buffer.BlockCopy(
|
||||
Window,
|
||||
0,
|
||||
Mem,
|
||||
(int)FirstPartLength,
|
||||
(int)BlockEnd
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var OutMem = ApplyFilter(Mem, BlockLength, flt);
|
||||
|
||||
Filters[I].Type = FILTER_NONE;
|
||||
|
||||
if (OutMem != null)
|
||||
{
|
||||
await UnpIO_UnpWriteAsync(OutMem, 0, BlockLength, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
WrittenFileSize += BlockLength;
|
||||
}
|
||||
|
||||
WrittenBorder = BlockEnd;
|
||||
WriteSizeLeft = (UnpPtr - WrittenBorder) & MaxWinMask;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NotAllFiltersProcessed = true;
|
||||
for (var J = I; J < Filters.Count; J++)
|
||||
{
|
||||
var fltj = Filters[J];
|
||||
if (
|
||||
fltj.Type != FILTER_NONE
|
||||
&& fltj.NextWindow == false
|
||||
&& ((fltj.BlockStart - WrPtr) & MaxWinMask) < FullWriteSize
|
||||
)
|
||||
{
|
||||
fltj.NextWindow = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var EmptyCount = 0;
|
||||
for (var I = 0; I < Filters.Count; I++)
|
||||
{
|
||||
if (EmptyCount > 0)
|
||||
{
|
||||
Filters[I - EmptyCount] = Filters[I];
|
||||
}
|
||||
|
||||
if (Filters[I].Type == FILTER_NONE)
|
||||
{
|
||||
EmptyCount++;
|
||||
}
|
||||
}
|
||||
if (EmptyCount > 0)
|
||||
{
|
||||
Filters.RemoveRange(Filters.Count - EmptyCount, EmptyCount);
|
||||
}
|
||||
|
||||
if (!NotAllFiltersProcessed)
|
||||
{
|
||||
await UnpWriteAreaAsync(WrittenBorder, UnpPtr, cancellationToken).ConfigureAwait(false);
|
||||
WrPtr = UnpPtr;
|
||||
}
|
||||
|
||||
WriteBorder = (UnpPtr + Math.Min(MaxWinSize, UNPACK_MAX_WRITE)) & MaxWinMask;
|
||||
|
||||
if (
|
||||
WriteBorder == UnpPtr
|
||||
|| WrPtr != UnpPtr
|
||||
&& ((WrPtr - UnpPtr) & MaxWinMask) < ((WriteBorder - UnpPtr) & MaxWinMask)
|
||||
)
|
||||
{
|
||||
WriteBorder = WrPtr;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] ApplyFilter(byte[] __d, uint DataSize, UnpackFilter Flt)
|
||||
{
|
||||
var Data = 0;
|
||||
@@ -1041,48 +651,6 @@ internal partial class Unpack
|
||||
}
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task UnpWriteAreaAsync(
|
||||
size_t StartPtr,
|
||||
size_t EndPtr,
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (EndPtr != StartPtr)
|
||||
{
|
||||
UnpSomeRead = true;
|
||||
}
|
||||
|
||||
if (EndPtr < StartPtr)
|
||||
{
|
||||
UnpAllBuf = true;
|
||||
}
|
||||
|
||||
if (Fragmented)
|
||||
{
|
||||
var SizeToWrite = (EndPtr - StartPtr) & MaxWinMask;
|
||||
while (SizeToWrite > 0)
|
||||
{
|
||||
var BlockSize = FragWindow.GetBlockSize(StartPtr, SizeToWrite);
|
||||
FragWindow.GetBuffer(StartPtr, out var __buffer, out var __offset);
|
||||
await UnpWriteDataAsync(__buffer, __offset, BlockSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
SizeToWrite -= BlockSize;
|
||||
StartPtr = (StartPtr + BlockSize) & MaxWinMask;
|
||||
}
|
||||
}
|
||||
else if (EndPtr < StartPtr)
|
||||
{
|
||||
await UnpWriteDataAsync(Window, StartPtr, MaxWinSize - StartPtr, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
await UnpWriteDataAsync(Window, 0, EndPtr, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await UnpWriteDataAsync(Window, StartPtr, EndPtr - StartPtr, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void UnpWriteData(byte[] Data, size_t offset, size_t Size)
|
||||
{
|
||||
if (WrittenFileSize >= DestUnpSize)
|
||||
@@ -1101,29 +669,6 @@ internal partial class Unpack
|
||||
WrittenFileSize += Size;
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task UnpWriteDataAsync(
|
||||
byte[] Data,
|
||||
size_t offset,
|
||||
size_t Size,
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (WrittenFileSize >= DestUnpSize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var WriteSize = Size;
|
||||
var LeftToWrite = DestUnpSize - WrittenFileSize;
|
||||
if (WriteSize > LeftToWrite)
|
||||
{
|
||||
WriteSize = (size_t)LeftToWrite;
|
||||
}
|
||||
|
||||
await UnpIO_UnpWriteAsync(Data, offset, WriteSize, cancellationToken).ConfigureAwait(false);
|
||||
WrittenFileSize += Size;
|
||||
}
|
||||
|
||||
private void UnpInitData50(bool Solid)
|
||||
{
|
||||
if (!Solid)
|
||||
@@ -1132,9 +677,9 @@ internal partial class Unpack
|
||||
}
|
||||
}
|
||||
|
||||
private bool ReadBlockHeader(BitInput Inp, ref UnpackBlockHeader Header)
|
||||
private bool ReadBlockHeader(BitInput Inp)
|
||||
{
|
||||
Header.HeaderSize = 0;
|
||||
BlockHeader.HeaderSize = 0;
|
||||
|
||||
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 7)
|
||||
{
|
||||
@@ -1155,9 +700,9 @@ internal partial class Unpack
|
||||
return false;
|
||||
}
|
||||
|
||||
Header.HeaderSize = (int)(2 + ByteCount);
|
||||
BlockHeader.HeaderSize = (int)(2 + ByteCount);
|
||||
|
||||
Header.BlockBitSize = (BlockFlags & 7) + 1;
|
||||
BlockHeader.BlockBitSize = (BlockFlags & 7) + 1;
|
||||
|
||||
var SavedCheckSum = (byte)(Inp.fgetbits() >> 8);
|
||||
Inp.faddbits(8);
|
||||
@@ -1169,28 +714,24 @@ internal partial class Unpack
|
||||
Inp.addbits(8);
|
||||
}
|
||||
|
||||
Header.BlockSize = BlockSize;
|
||||
BlockHeader.BlockSize = BlockSize;
|
||||
var CheckSum = (byte)(0x5a ^ BlockFlags ^ BlockSize ^ (BlockSize >> 8) ^ (BlockSize >> 16));
|
||||
if (CheckSum != SavedCheckSum)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Header.BlockStart = Inp.InAddr;
|
||||
ReadBorder = Math.Min(ReadBorder, Header.BlockStart + Header.BlockSize - 1);
|
||||
BlockHeader.BlockStart = Inp.InAddr;
|
||||
ReadBorder = Math.Min(ReadBorder, BlockHeader.BlockStart + BlockHeader.BlockSize - 1);
|
||||
|
||||
Header.LastBlockInFile = (BlockFlags & 0x40) != 0;
|
||||
Header.TablePresent = (BlockFlags & 0x80) != 0;
|
||||
BlockHeader.LastBlockInFile = (BlockFlags & 0x40) != 0;
|
||||
BlockHeader.TablePresent = (BlockFlags & 0x80) != 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ReadTables(
|
||||
BitInput Inp,
|
||||
ref UnpackBlockHeader Header,
|
||||
ref UnpackBlockTables Tables
|
||||
)
|
||||
private bool ReadTables(BitInput Inp)
|
||||
{
|
||||
if (!Header.TablePresent)
|
||||
if (!BlockHeader.TablePresent)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -1233,7 +774,7 @@ internal partial class Unpack
|
||||
}
|
||||
}
|
||||
|
||||
MakeDecodeTables(BitLength, 0, Tables.BD, BC);
|
||||
MakeDecodeTables(BitLength, 0, BlockTables.BD, BC);
|
||||
|
||||
Span<byte> Table = stackalloc byte[checked((int)HUFF_TABLE_SIZE)];
|
||||
const int TableSize = checked((int)HUFF_TABLE_SIZE);
|
||||
@@ -1247,7 +788,7 @@ internal partial class Unpack
|
||||
}
|
||||
}
|
||||
|
||||
var Number = DecodeNumber(Inp, Tables.BD);
|
||||
var Number = DecodeNumber(Inp, BlockTables.BD);
|
||||
if (Number < 16)
|
||||
{
|
||||
Table[I] = (byte)Number;
|
||||
@@ -1309,10 +850,10 @@ internal partial class Unpack
|
||||
return false;
|
||||
}
|
||||
|
||||
MakeDecodeTables(Table, 0, Tables.LD, NC);
|
||||
MakeDecodeTables(Table, (int)NC, Tables.DD, DC);
|
||||
MakeDecodeTables(Table, (int)(NC + DC), Tables.LDD, LDC);
|
||||
MakeDecodeTables(Table, (int)(NC + DC + LDC), Tables.RD, RC);
|
||||
MakeDecodeTables(Table, 0, BlockTables.LD, NC);
|
||||
MakeDecodeTables(Table, (int)NC, BlockTables.DD, DC);
|
||||
MakeDecodeTables(Table, (int)(NC + DC), BlockTables.LDD, LDC);
|
||||
MakeDecodeTables(Table, (int)(NC + DC + LDC), BlockTables.RD, RC);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using static SharpCompress.Compressors.Rar.UnpackV2017.PackDef;
|
||||
using static SharpCompress.Compressors.Rar.UnpackV2017.UnpackGlobal;
|
||||
@@ -196,10 +198,10 @@ internal sealed partial class Unpack : BitInput
|
||||
}
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task DoUnpackAsync(
|
||||
private async Task DoUnpackAsync(
|
||||
uint Method,
|
||||
bool Solid,
|
||||
System.Threading.CancellationToken cancellationToken = default
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
// Methods <50 will crash in Fragmented mode when accessing NULL Window.
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
".NETFramework,Version=v4.8": {
|
||||
"Microsoft.Bcl.AsyncInterfaces": {
|
||||
"type": "Direct",
|
||||
"requested": "[10.0.0, )",
|
||||
"resolved": "10.0.0",
|
||||
"contentHash": "vFuwSLj9QJBbNR0NeNO4YVASUbokxs+i/xbuu8B+Fs4FAZg5QaFa6eGrMaRqTzzNI5tAb97T7BhSxtLckFyiRA==",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw==",
|
||||
"dependencies": {
|
||||
"System.Threading.Tasks.Extensions": "4.6.3"
|
||||
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.NETFramework.ReferenceAssemblies": {
|
||||
@@ -91,10 +91,10 @@
|
||||
},
|
||||
"System.Threading.Tasks.Extensions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.6.3",
|
||||
"contentHash": "7sCiwilJLYbTZELaKnc7RecBBXWXA+xMLQWZKWawBxYjp6DBlSE3v9/UcvKBvr1vv2tTOhipiogM8rRmxlhrVA==",
|
||||
"resolved": "4.5.4",
|
||||
"contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==",
|
||||
"dependencies": {
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.1.2"
|
||||
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
|
||||
}
|
||||
},
|
||||
"System.ValueTuple": {
|
||||
@@ -106,11 +106,11 @@
|
||||
".NETStandard,Version=v2.0": {
|
||||
"Microsoft.Bcl.AsyncInterfaces": {
|
||||
"type": "Direct",
|
||||
"requested": "[10.0.0, )",
|
||||
"resolved": "10.0.0",
|
||||
"contentHash": "vFuwSLj9QJBbNR0NeNO4YVASUbokxs+i/xbuu8B+Fs4FAZg5QaFa6eGrMaRqTzzNI5tAb97T7BhSxtLckFyiRA==",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw==",
|
||||
"dependencies": {
|
||||
"System.Threading.Tasks.Extensions": "4.6.3"
|
||||
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.NETFramework.ReferenceAssemblies": {
|
||||
@@ -206,10 +206,10 @@
|
||||
},
|
||||
"System.Threading.Tasks.Extensions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.6.3",
|
||||
"contentHash": "7sCiwilJLYbTZELaKnc7RecBBXWXA+xMLQWZKWawBxYjp6DBlSE3v9/UcvKBvr1vv2tTOhipiogM8rRmxlhrVA==",
|
||||
"resolved": "4.5.4",
|
||||
"contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==",
|
||||
"dependencies": {
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.1.2"
|
||||
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -3,6 +3,8 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Archives.SevenZip;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Test.Mocks;
|
||||
using Xunit;
|
||||
|
||||
@@ -224,4 +226,95 @@ public class SevenZipArchiveAsyncTests : ArchiveTests
|
||||
|
||||
VerifyFiles();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SevenZipArchive_Solid_ExtractAllEntries_Contiguous_Async()
|
||||
{
|
||||
// This test verifies that solid archives iterate entries as contiguous streams
|
||||
// rather than recreating the decompression stream for each entry
|
||||
var testArchive = Path.Combine(TEST_ARCHIVES_PATH, "7Zip.solid.7z");
|
||||
await using var archive = SevenZipArchive.OpenAsyncArchive(testArchive);
|
||||
Assert.True(((SevenZipArchive)archive).IsSolid);
|
||||
|
||||
await using var reader = await archive.ExtractAllEntriesAsync();
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
await reader.WriteEntryToDirectoryAsync(SCRATCH_FILES_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
VerifyFiles();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SevenZipArchive_Solid_VerifyStreamReuse()
|
||||
{
|
||||
// This test verifies that the folder stream is reused within each folder
|
||||
// and not recreated for each entry in solid archives
|
||||
var testArchive = Path.Combine(TEST_ARCHIVES_PATH, "7Zip.solid.7z");
|
||||
await using var archive = SevenZipArchive.OpenAsyncArchive(testArchive);
|
||||
Assert.True(((SevenZipArchive)archive).IsSolid);
|
||||
|
||||
await using var reader = await archive.ExtractAllEntriesAsync();
|
||||
|
||||
var sevenZipReader = Assert.IsType<SevenZipArchive.SevenZipReader>(reader);
|
||||
sevenZipReader.DiagnosticsEnabled = true;
|
||||
|
||||
Stream? currentFolderStreamInstance = null;
|
||||
object? currentFolder = null;
|
||||
var entryCount = 0;
|
||||
var entriesInCurrentFolder = 0;
|
||||
var streamRecreationsWithinFolder = 0;
|
||||
|
||||
while (await reader.MoveToNextEntryAsync())
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
// Extract the entry to trigger GetEntryStream
|
||||
using var entryStream = await reader.OpenEntryStreamAsync();
|
||||
var buffer = new byte[4096];
|
||||
while (entryStream.Read(buffer, 0, buffer.Length) > 0)
|
||||
{
|
||||
// Read the stream to completion
|
||||
}
|
||||
|
||||
entryCount++;
|
||||
|
||||
var folderStream = sevenZipReader.DiagnosticsCurrentFolderStream;
|
||||
var folder = sevenZipReader.DiagnosticsCurrentFolder;
|
||||
|
||||
Assert.NotNull(folderStream); // Folder stream should exist
|
||||
|
||||
// Check if we're in a new folder
|
||||
if (currentFolder == null || !ReferenceEquals(currentFolder, folder))
|
||||
{
|
||||
// Starting a new folder
|
||||
currentFolder = folder;
|
||||
currentFolderStreamInstance = folderStream;
|
||||
entriesInCurrentFolder = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Same folder - verify stream wasn't recreated
|
||||
entriesInCurrentFolder++;
|
||||
|
||||
if (!ReferenceEquals(currentFolderStreamInstance, folderStream))
|
||||
{
|
||||
// Stream was recreated within the same folder - this is the bug we're testing for!
|
||||
streamRecreationsWithinFolder++;
|
||||
}
|
||||
|
||||
currentFolderStreamInstance = folderStream;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verify we actually tested multiple entries
|
||||
Assert.True(entryCount > 1, "Test should have multiple entries to verify stream reuse");
|
||||
|
||||
// The critical check: within a single folder, the stream should NEVER be recreated
|
||||
Assert.Equal(0, streamRecreationsWithinFolder); // Folder stream should remain the same for all entries in the same folder
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,4 +344,21 @@ public class SevenZipArchiveTests : ArchiveTests
|
||||
// The critical check: within a single folder, the stream should NEVER be recreated
|
||||
Assert.Equal(0, streamRecreationsWithinFolder); // Folder stream should remain the same for all entries in the same folder
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SevenZipArchive_Cheat_CanBeOpenedWithArchiveFactory()
|
||||
{
|
||||
// Regression test for issue #1204: 7zip file couldn't be opened with ArchiveFactory.OpenArchive()
|
||||
// due to Microsoft.Bcl.AsyncInterfaces version conflict (version 10.0.0 was too new)
|
||||
var testArchive = Path.Combine(TEST_ARCHIVES_PATH, "cheat.7z");
|
||||
|
||||
// Test that ArchiveFactory can open the file
|
||||
using var archive = ArchiveFactory.OpenArchive(testArchive);
|
||||
Assert.NotNull(archive);
|
||||
Assert.True(archive.Entries.Any());
|
||||
|
||||
// Verify we can read entries
|
||||
var entry = archive.Entries.First();
|
||||
Assert.NotNull(entry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,10 +190,10 @@
|
||||
},
|
||||
"System.Threading.Tasks.Extensions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.6.3",
|
||||
"contentHash": "7sCiwilJLYbTZELaKnc7RecBBXWXA+xMLQWZKWawBxYjp6DBlSE3v9/UcvKBvr1vv2tTOhipiogM8rRmxlhrVA==",
|
||||
"resolved": "4.5.4",
|
||||
"contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==",
|
||||
"dependencies": {
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.1.2"
|
||||
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
|
||||
}
|
||||
},
|
||||
"System.ValueTuple": {
|
||||
@@ -275,7 +275,7 @@
|
||||
"sharpcompress": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Microsoft.Bcl.AsyncInterfaces": "[10.0.0, )",
|
||||
"Microsoft.Bcl.AsyncInterfaces": "[8.0.0, )",
|
||||
"System.Buffers": "[4.6.1, )",
|
||||
"System.Memory": "[4.6.3, )",
|
||||
"System.Text.Encoding.CodePages": "[10.0.0, )"
|
||||
@@ -283,11 +283,11 @@
|
||||
},
|
||||
"Microsoft.Bcl.AsyncInterfaces": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[10.0.0, )",
|
||||
"resolved": "10.0.0",
|
||||
"contentHash": "vFuwSLj9QJBbNR0NeNO4YVASUbokxs+i/xbuu8B+Fs4FAZg5QaFa6eGrMaRqTzzNI5tAb97T7BhSxtLckFyiRA==",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw==",
|
||||
"dependencies": {
|
||||
"System.Threading.Tasks.Extensions": "4.6.3"
|
||||
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||
}
|
||||
},
|
||||
"System.Buffers": {
|
||||
@@ -527,9 +527,9 @@
|
||||
},
|
||||
"Microsoft.Bcl.AsyncInterfaces": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[10.0.0, )",
|
||||
"resolved": "10.0.0",
|
||||
"contentHash": "vFuwSLj9QJBbNR0NeNO4YVASUbokxs+i/xbuu8B+Fs4FAZg5QaFa6eGrMaRqTzzNI5tAb97T7BhSxtLckFyiRA=="
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BIN
tests/TestArchives/Archives/cheat.7z
Normal file
BIN
tests/TestArchives/Archives/cheat.7z
Normal file
Binary file not shown.
Reference in New Issue
Block a user