mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-09-22 23:15:20 +00:00
Sync with master
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using SharpCompress.Common.Rar.Headers;
|
||||
|
||||
namespace SharpCompress.Common.Rar;
|
||||
@@ -11,7 +11,8 @@ public abstract class RarEntry : Entry
|
||||
/// As the V2017 port isn't complete, add this check to use the legacy Rar code.
|
||||
/// </summary>
|
||||
internal bool IsRarV3 =>
|
||||
FileHeader.CompressionAlgorithm == 20
|
||||
FileHeader.CompressionAlgorithm == 15
|
||||
|| FileHeader.CompressionAlgorithm == 20
|
||||
|| FileHeader.CompressionAlgorithm == 26
|
||||
|| FileHeader.CompressionAlgorithm == 29
|
||||
|| FileHeader.CompressionAlgorithm == 36; //Nanook - Added 20+26 as Test arc from WinRar2.8 (algo 20) was failing with 2017 code
|
||||
|
||||
@@ -7,6 +7,7 @@ internal enum ZipCompressionMethod
|
||||
Deflate64 = 9,
|
||||
BZip2 = 12,
|
||||
LZMA = 14,
|
||||
Xz = 95,
|
||||
PPMd = 98,
|
||||
WinzipAes = 0x63 //http://www.winzip.com/aes_info.htm
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using SharpCompress.Compressors.Deflate;
|
||||
using SharpCompress.Compressors.Deflate64;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
using SharpCompress.Compressors.PPMd;
|
||||
using SharpCompress.Compressors.Xz;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Common.Zip;
|
||||
@@ -107,6 +108,10 @@ internal abstract class ZipFilePart : FilePart
|
||||
: Header.UncompressedSize
|
||||
);
|
||||
}
|
||||
case ZipCompressionMethod.Xz:
|
||||
{
|
||||
return new XZStream(stream);
|
||||
}
|
||||
case ZipCompressionMethod.PPMd:
|
||||
{
|
||||
Span<byte> props = stackalloc byte[2];
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace SharpCompress.Compressors.Filters;
|
||||
|
||||
@@ -22,89 +23,102 @@ public sealed class BranchExecFilter
|
||||
ARCH_SPARC_ALIGNMENT = 4,
|
||||
}
|
||||
|
||||
public static void X86Converter(byte[] data, uint ip, ref uint state)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool X86TestByte(byte b)
|
||||
{
|
||||
long i = 0;
|
||||
long size = data.Length;
|
||||
uint pos = 0;
|
||||
var mask = state & 7;
|
||||
if (size < 5)
|
||||
{
|
||||
return b == 0x00 || b == 0xFF;
|
||||
}
|
||||
|
||||
//Replaced X86Converter with bcj_x86() - https://github.com/torvalds/linux/blob/master/lib/xz/xz_dec_bcj.c
|
||||
//This was to fix an issue decoding a Test zip made with WinZip (that 7zip was also able to read).
|
||||
//The previous version of the code would corrupt 2 bytes in the Test.exe at 0x6CF9 (3D6D - should be 4000) - Test zip: WinZip27.Xz.zipx
|
||||
public static void X86Converter(byte[] buf, uint ip, ref uint state)
|
||||
{
|
||||
bool[] mask_to_allowed_status = new[] { true, true, true, false, true, false, false, false };
|
||||
|
||||
byte[] mask_to_bit_num = new byte[] { 0, 1, 2, 2, 3, 3, 3, 3 };
|
||||
|
||||
int i;
|
||||
int prev_pos = -1;
|
||||
uint prev_mask = state & 7;
|
||||
uint src;
|
||||
uint dest;
|
||||
uint j;
|
||||
byte b;
|
||||
uint pos = ip;
|
||||
|
||||
uint size = (uint)buf.Length;
|
||||
|
||||
if (size <= 4)
|
||||
return;
|
||||
}
|
||||
|
||||
size -= 4;
|
||||
ip += 5;
|
||||
|
||||
for (; ; )
|
||||
for (i = 0; i < size; ++i)
|
||||
{
|
||||
i = pos;
|
||||
if ((buf[i] & 0xFE) != 0xE8)
|
||||
continue;
|
||||
|
||||
for (; i < size; i++)
|
||||
prev_pos = i - prev_pos;
|
||||
if (prev_pos > 3)
|
||||
{
|
||||
if ((data[i] & 0xFE) == 0xE8)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var d = (uint)(i) - pos;
|
||||
pos = (uint)i;
|
||||
if (i >= size)
|
||||
{
|
||||
state = (d > 2 ? 0 : mask >> (int)d);
|
||||
return;
|
||||
}
|
||||
if (d > 2)
|
||||
{
|
||||
mask = 0;
|
||||
prev_mask = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask >>= (int)d;
|
||||
if (
|
||||
mask != 0
|
||||
&& (mask > 4 || mask == 3 || (((((data[(mask >> 1) + 1])) + 1) & 0xFE) == 0))
|
||||
)
|
||||
prev_mask = (prev_mask << (prev_pos - 1)) & 7;
|
||||
if (prev_mask != 0)
|
||||
{
|
||||
mask = (mask >> 1) | 4;
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ((((data[i + 4]) + 1) & 0xFE) == 0)
|
||||
{
|
||||
var inst =
|
||||
((uint)data[i + 4] << 24)
|
||||
| ((uint)data[i + 3] << 16)
|
||||
| ((uint)data[i + 2] << 8)
|
||||
| data[i + 1];
|
||||
var cur = ip + pos;
|
||||
pos += 5;
|
||||
|
||||
inst -= cur;
|
||||
if (mask != 0)
|
||||
{
|
||||
var sh = (mask & 6) << 2;
|
||||
if (((((((byte)(inst >> (int)sh))) + 1) & 0xFE) == 0))
|
||||
b = buf[i + 4 - mask_to_bit_num[prev_mask]];
|
||||
if (!mask_to_allowed_status[prev_mask]
|
||||
|| X86TestByte(b))
|
||||
{
|
||||
inst ^= (((uint)0x100 << (int)sh) - 1);
|
||||
inst -= cur;
|
||||
prev_pos = i;
|
||||
prev_mask = (prev_mask << 1) | 1;
|
||||
continue;
|
||||
}
|
||||
mask = 0;
|
||||
}
|
||||
data[i + 1] = (byte)inst;
|
||||
data[i + 2] = (byte)(inst >> 8);
|
||||
data[i + 3] = (byte)(inst >> 16);
|
||||
data[i + 4] = (byte)(0 - ((inst >> 24) & 1));
|
||||
}
|
||||
|
||||
prev_pos = i;
|
||||
|
||||
if (X86TestByte(buf[i + 4]))
|
||||
{
|
||||
src = ((uint)buf[i + 4] << 24)
|
||||
| ((uint)buf[i + 3] << 16)
|
||||
| ((uint)buf[i + 2] << 8)
|
||||
| buf[i + 1];
|
||||
|
||||
while (true)
|
||||
{
|
||||
dest = src - (pos + (uint)i + 5);
|
||||
if (prev_mask == 0)
|
||||
break;
|
||||
|
||||
j = mask_to_bit_num[prev_mask] * 8u;
|
||||
b = (byte)(dest >> (24 - (int)j));
|
||||
if (!X86TestByte(b))
|
||||
break;
|
||||
|
||||
src = dest ^ ((1u << (32 - (int)j)) - 1u);
|
||||
}
|
||||
|
||||
dest &= 0x01FFFFFF;
|
||||
dest |= 0 - (dest & 0x01000000);
|
||||
buf[i + 1] = (byte)dest;
|
||||
buf[i + 2] = (byte)(dest >> 8);
|
||||
buf[i + 3] = (byte)(dest >> 16);
|
||||
buf[i + 4] = (byte)(dest >> 24);
|
||||
i += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask = (mask >> 1) | 4;
|
||||
pos++;
|
||||
prev_mask = (prev_mask << 1) | 1;
|
||||
}
|
||||
}
|
||||
prev_pos = i - prev_pos;
|
||||
prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1);
|
||||
state = prev_mask;
|
||||
return;
|
||||
}
|
||||
|
||||
public static void PowerPCConverter(byte[] data, uint ip)
|
||||
|
||||
42
src/SharpCompress/Compressors/Filters/DeltaFilter.cs
Normal file
42
src/SharpCompress/Compressors/Filters/DeltaFilter.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.Compressors.Filters
|
||||
{
|
||||
internal class DeltaFilter : Filter
|
||||
{
|
||||
private const int DISTANCE_MIN = 1;
|
||||
private const int DISTANCE_MAX = 256;
|
||||
private const int DISTANCE_MASK = DISTANCE_MAX - 1;
|
||||
|
||||
private int _distance;
|
||||
private byte[] _history;
|
||||
private int _position;
|
||||
|
||||
public DeltaFilter(bool isEncoder, Stream baseStream, byte[] info)
|
||||
: base(isEncoder, baseStream, 1)
|
||||
{
|
||||
_distance = info[0];
|
||||
_history = new byte[DISTANCE_MAX];
|
||||
_position = 0;
|
||||
|
||||
if (_distance < DISTANCE_MIN)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
protected override int Transform(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int end = offset + count;
|
||||
|
||||
for( int i = offset; i < end; i++ )
|
||||
{
|
||||
buffer[i] += _history[(_distance + _position--) & DISTANCE_MASK];
|
||||
_history[_position & DISTANCE_MASK] = buffer[i];
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ namespace SharpCompress.Compressors.LZMA;
|
||||
internal static class DecoderRegistry
|
||||
{
|
||||
private const uint K_COPY = 0x0;
|
||||
private const uint K_DELTA = 0x3;
|
||||
private const uint K_LZMA2 = 0x21;
|
||||
private const uint K_LZMA = 0x030101;
|
||||
private const uint K_PPMD = 0x030401;
|
||||
@@ -37,6 +38,8 @@ internal static class DecoderRegistry
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
return inStreams.Single();
|
||||
case K_DELTA:
|
||||
return new DeltaFilter(false, inStreams.Single(), info);
|
||||
case K_LZMA:
|
||||
case K_LZMA2:
|
||||
return new LzmaStream(info, inStreams.Single(), -1, limit);
|
||||
|
||||
@@ -2,9 +2,10 @@ using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.IO;
|
||||
|
||||
internal class ReadOnlySubStream : NonDisposingStream
|
||||
{
|
||||
private long _position;
|
||||
|
||||
public ReadOnlySubStream(Stream stream, long bytesToRead) : this(stream, null, bytesToRead) { }
|
||||
|
||||
public ReadOnlySubStream(Stream stream, long? origin, long bytesToRead)
|
||||
@@ -15,6 +16,7 @@ internal class ReadOnlySubStream : NonDisposingStream
|
||||
stream.Position = origin.Value;
|
||||
}
|
||||
BytesLeftToRead = bytesToRead;
|
||||
_position = 0;
|
||||
}
|
||||
|
||||
private long BytesLeftToRead { get; set; }
|
||||
@@ -31,7 +33,7 @@ internal class ReadOnlySubStream : NonDisposingStream
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get => Stream.Position;
|
||||
get => _position; //allow position to be read (XZ uses this to calculate alignment)
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
@@ -45,6 +47,7 @@ internal class ReadOnlySubStream : NonDisposingStream
|
||||
if (read > 0)
|
||||
{
|
||||
BytesLeftToRead -= read;
|
||||
_position += read;
|
||||
}
|
||||
return read;
|
||||
}
|
||||
@@ -59,6 +62,7 @@ internal class ReadOnlySubStream : NonDisposingStream
|
||||
if (value != -1)
|
||||
{
|
||||
--BytesLeftToRead;
|
||||
_position++;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@ public class SourceStream : Stream
|
||||
// Add length of previous stream
|
||||
_prevSize += length;
|
||||
Current.Seek(0, SeekOrigin.Begin);
|
||||
r = -1; //BugFix: reset to allow loop if count is still not 0 - was breaking split zipx (lzma xz etc)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -355,6 +355,22 @@ public class RarArchiveTests : ArchiveTests
|
||||
[Fact]
|
||||
public void Rar2_ArchiveFileRead() => ArchiveFileRead("Rar2.rar");
|
||||
|
||||
[Fact]
|
||||
public void Rar15_ArchiveFileRead()
|
||||
{
|
||||
UseExtensionInsteadOfNameToVerify = true;
|
||||
UseCaseInsensitiveToVerify= true;
|
||||
ArchiveFileRead("Rar15.rar");
|
||||
}
|
||||
[Fact]
|
||||
public void Rar15_ArchiveVersionTest()
|
||||
{
|
||||
var testArchive = Path.Combine(TEST_ARCHIVES_PATH, "Rar15.rar");
|
||||
|
||||
using var archive = RarArchive.Open(testArchive);
|
||||
Assert.Equal(1, archive.MinVersion);
|
||||
Assert.Equal(1, archive.MaxVersion);
|
||||
}
|
||||
[Fact]
|
||||
public void Rar2_ArchiveVersionTest()
|
||||
{
|
||||
|
||||
@@ -109,4 +109,8 @@ public class SevenZipArchiveTests : ArchiveTests
|
||||
//"7Zip.BZip2.split.005",
|
||||
//"7Zip.BZip2.split.006",
|
||||
//"7Zip.BZip2.split.007"
|
||||
|
||||
[Fact]
|
||||
public void SevenZipArchive_delta_FileRead() =>
|
||||
ArchiveFileRead("7Zip.delta.7z");
|
||||
}
|
||||
|
||||
@@ -138,12 +138,23 @@ public class TestBase : IDisposable
|
||||
}
|
||||
|
||||
protected bool UseExtensionInsteadOfNameToVerify { get; set; }
|
||||
protected bool UseCaseInsensitiveToVerify { get; set; }
|
||||
|
||||
protected void VerifyFilesByExtension()
|
||||
{
|
||||
var extracted = Directory
|
||||
.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories)
|
||||
.ToLookup(path => Path.GetExtension(path));
|
||||
ILookup<string, string> extracted;
|
||||
if (UseCaseInsensitiveToVerify)
|
||||
{
|
||||
extracted = Directory
|
||||
.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories)
|
||||
.ToLookup(path => Path.GetExtension(path).ToLowerInvariant());
|
||||
}
|
||||
else
|
||||
{
|
||||
extracted = Directory
|
||||
.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories)
|
||||
.ToLookup(path => Path.GetExtension(path));
|
||||
}
|
||||
var original = Directory
|
||||
.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories)
|
||||
.ToLookup(path => Path.GetExtension(path));
|
||||
|
||||
@@ -76,6 +76,9 @@ public class ZipArchiveTests : ArchiveTests
|
||||
public void WinZip26_X_Multi_ArchiveFileRead() =>
|
||||
ArchiveStreamMultiRead(null, "WinZip26.nocomp.multi.zipx", "WinZip26.nocomp.multi.zx01"); //min split size is 64k so no compression used
|
||||
|
||||
[Fact]
|
||||
public void WinZip27_X_XZ_ArchiveFileRead() => ArchiveFileRead("WinZip27_XZ.zipx");
|
||||
|
||||
[Fact]
|
||||
public void Zip_Deflate_Streamed2_ArchiveFileRead() => ArchiveFileRead("Zip.deflate.dd-.zip");
|
||||
|
||||
|
||||
BIN
tests/TestArchives/Archives/7Zip.delta.7z
Normal file
BIN
tests/TestArchives/Archives/7Zip.delta.7z
Normal file
Binary file not shown.
BIN
tests/TestArchives/Archives/Rar15.rar
Normal file
BIN
tests/TestArchives/Archives/Rar15.rar
Normal file
Binary file not shown.
BIN
tests/TestArchives/Archives/WinZip27_XZ.zipx
Normal file
BIN
tests/TestArchives/Archives/WinZip27_XZ.zipx
Normal file
Binary file not shown.
Reference in New Issue
Block a user