diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.Async.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.Async.cs index 37655cf14..0581ba26f 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.Async.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.Async.cs @@ -1,5 +1,6 @@ using System; using System.Buffers; +using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -112,7 +113,10 @@ private async Task Unpack29Async(bool solid, CancellationToken cancellationToken { return; } - if ((!solid || !tablesRead) && !ReadTables()) + if ( + (!solid || !tablesRead) + && !await ReadTablesAsync(cancellationToken).ConfigureAwait(false) + ) { return; } @@ -161,7 +165,7 @@ private async Task Unpack29Async(bool solid, CancellationToken cancellationToken var NextCh = ppm.DecodeChar(); if (NextCh == 0) { - if (!ReadTables()) + if (!await ReadTablesAsync(cancellationToken).ConfigureAwait(false)) { break; } @@ -294,7 +298,7 @@ private async Task Unpack29Async(bool solid, CancellationToken cancellationToken } if (Number == 256) { - if (!ReadEndOfBlock()) + if (!await ReadEndOfBlockAsync(cancellationToken).ConfigureAwait(false)) { break; } @@ -302,7 +306,7 @@ private async Task Unpack29Async(bool solid, CancellationToken cancellationToken } if (Number == 257) { - if (!ReadVMCode()) + if (!await ReadVMCodeAsync(cancellationToken).ConfigureAwait(false)) { break; } @@ -600,4 +604,193 @@ await writeStream writtenFileSize += size; destUnpSize -= size; } + + private async Task ReadTablesAsync(CancellationToken cancellationToken = default) + { + var bitLength = new byte[PackDef.BC]; + var table = new byte[PackDef.HUFF_TABLE_SIZE]; + + if (inAddr > readTop - 25) + { + if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false)) + { + return false; + } + } + AddBits((8 - inBit) & 7); + long bitField = GetBits() & unchecked((int)0xffFFffFF); + if ((bitField & 0x8000) != 0) + { + unpBlockType = BlockTypes.BLOCK_PPM; + return ppm.DecodeInit(this, PpmEscChar); + } + unpBlockType = BlockTypes.BLOCK_LZ; + + prevLowDist = 0; + lowDistRepCount = 0; + + if ((bitField & 0x4000) == 0) + { + new Span(unpOldTable).Clear(); + } + AddBits(2); + + for (var i = 0; i < PackDef.BC; i++) + { + var length = (Utility.URShift(GetBits(), 12)) & 0xFF; + AddBits(4); + if (length == 15) + { + var zeroCount = (Utility.URShift(GetBits(), 12)) & 0xFF; + AddBits(4); + if (zeroCount == 0) + { + bitLength[i] = 15; + } + else + { + zeroCount += 2; + while (zeroCount-- > 0 && i < bitLength.Length) + { + bitLength[i++] = 0; + } + i--; + } + } + else + { + bitLength[i] = (byte)length; + } + } + + UnpackUtility.makeDecodeTables(bitLength, 0, BD, PackDef.BC); + + var TableSize = PackDef.HUFF_TABLE_SIZE; + + for (var i = 0; i < TableSize; ) + { + if (inAddr > readTop - 5) + { + if (!await unpReadBufAsync(cancellationToken).ConfigureAwait(false)) + { + return false; + } + } + var Number = this.decodeNumber(BD); + if (Number < 16) + { + table[i] = (byte)((Number + unpOldTable[i]) & 0xf); + i++; + } + else if (Number < 18) + { + int N; + if (Number == 16) + { + N = (Utility.URShift(GetBits(), 13)) + 3; + AddBits(3); + } + else + { + N = (Utility.URShift(GetBits(), 9)) + 11; + AddBits(7); + } + while (N-- > 0 && i < TableSize) + { + table[i] = table[i - 1]; + i++; + } + } + else + { + int N; + if (Number == 18) + { + N = (Utility.URShift(GetBits(), 13)) + 3; + AddBits(3); + } + else + { + N = (Utility.URShift(GetBits(), 9)) + 11; + AddBits(7); + } + while (N-- > 0 && i < TableSize) + { + table[i++] = 0; + } + } + } + tablesRead = true; + if (inAddr > readTop) + { + return false; + } + UnpackUtility.makeDecodeTables(table, 0, LD, PackDef.NC); + UnpackUtility.makeDecodeTables(table, PackDef.NC, DD, PackDef.DC); + UnpackUtility.makeDecodeTables(table, PackDef.NC + PackDef.DC, LDD, PackDef.LDC); + UnpackUtility.makeDecodeTables( + table, + PackDef.NC + PackDef.DC + PackDef.LDC, + RD, + PackDef.RC + ); + + new Span(table).CopyTo(unpOldTable); + return true; + } + + private async Task ReadEndOfBlockAsync(CancellationToken cancellationToken = default) + { + var BitField = GetBits(); + bool NewTable, + NewFile = false; + if ((BitField & 0x8000) != 0) + { + NewTable = true; + AddBits(1); + } + else + { + NewFile = true; + NewTable = (BitField & 0x4000) != 0; + AddBits(2); + } + tablesRead = !NewTable; + return !( + NewFile || NewTable && !await ReadTablesAsync(cancellationToken).ConfigureAwait(false) + ); + } + + private async Task ReadVMCodeAsync(CancellationToken cancellationToken = default) + { + var FirstByte = GetBits() >> 8; + AddBits(8); + var Length = (FirstByte & 7) + 1; + if (Length == 7) + { + Length = (GetBits() >> 8) + 7; + AddBits(8); + } + else if (Length == 8) + { + Length = GetBits(); + AddBits(16); + } + + var vmCode = new List(); + for (var I = 0; I < Length; I++) + { + if ( + inAddr >= readTop - 1 + && !await unpReadBufAsync(cancellationToken).ConfigureAwait(false) + && I < Length - 1 + ) + { + return false; + } + vmCode.Add((byte)(GetBits() >> 8)); + AddBits(8); + } + return AddVMCode(FirstByte, vmCode); + } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.Async.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.Async.cs index 48df787ec..432922c46 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.Async.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.Async.cs @@ -70,7 +70,7 @@ public async Task Unpack5Async(bool Solid, CancellationToken cancellationToken = // So we can safefly use these tables below. if ( !await ReadBlockHeaderAsync(cancellationToken).ConfigureAwait(false) - || !ReadTables() + || !await ReadTablesAsync(cancellationToken).ConfigureAwait(false) || !TablesRead5 ) { @@ -101,7 +101,7 @@ public async Task Unpack5Async(bool Solid, CancellationToken cancellationToken = } if ( !await ReadBlockHeaderAsync(cancellationToken).ConfigureAwait(false) - || !ReadTables() + || !await ReadTablesAsync(cancellationToken).ConfigureAwait(false) ) { return; diff --git a/src/SharpCompress/packages.lock.json b/src/SharpCompress/packages.lock.json index 03c03a9a4..a401c7021 100644 --- a/src/SharpCompress/packages.lock.json +++ b/src/SharpCompress/packages.lock.json @@ -268,9 +268,9 @@ "net10.0": { "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[10.0.5, )", - "resolved": "10.0.5", - "contentHash": "A+5ZuQ0f449tM+MQrhf6R9ZX7lYpjk/ODEwLYKrnF6111rtARx8fVsm4YznUnQiKnnXfaXNBqgxmil6RW3L3SA==" + "requested": "[10.0.0, )", + "resolved": "10.0.0", + "contentHash": "kICGrGYEzCNI3wPzfEXcwNHgTvlvVn9yJDhSdRK+oZQy4jvYH529u7O0xf5ocQKzOMjfS07+3z9PKRIjrFMJDA==" }, "Microsoft.NETFramework.ReferenceAssemblies": { "type": "Direct", @@ -400,9 +400,9 @@ "net8.0": { "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[8.0.25, )", - "resolved": "8.0.25", - "contentHash": "sqX4nmBft05ivqKvUT4nxaN8rT3apCLt9SWFkfRrQPwra1zPwFknQAw1lleuMCKOCLvVmOWwrC2iPSm9RiXZUg==" + "requested": "[8.0.22, )", + "resolved": "8.0.22", + "contentHash": "MhcMithKEiyyNkD2ZfbDZPmcOdi0GheGfg8saEIIEfD/fol3iHmcV8TsZkD4ZYz5gdUuoX4YtlVySUU7Sxl9SQ==" }, "Microsoft.NETFramework.ReferenceAssemblies": { "type": "Direct",