Skip to content

Commit

Permalink
Sync with master
Browse files Browse the repository at this point in the history
  • Loading branch information
Erior committed Mar 1, 2023
2 parents 606923b + d76a473 commit 9e6f9d5
Show file tree
Hide file tree
Showing 15 changed files with 173 additions and 68 deletions.
5 changes: 3 additions & 2 deletions src/SharpCompress/Common/Rar/RarEntry.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using SharpCompress.Common.Rar.Headers;

namespace SharpCompress.Common.Rar;
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/SharpCompress/Common/Zip/ZipCompressionMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
5 changes: 5 additions & 0 deletions src/SharpCompress/Common/Zip/ZipFilePart.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using SharpCompress.Compressors.Deflate64;
using SharpCompress.Compressors.LZMA;
using SharpCompress.Compressors.PPMd;
using SharpCompress.Compressors.Xz;
using SharpCompress.IO;

namespace SharpCompress.Common.Zip;
Expand Down Expand Up @@ -107,6 +108,10 @@ protected Stream CreateDecompressionStream(Stream stream, ZipCompressionMethod m
: Header.UncompressedSize
);
}
case ZipCompressionMethod.Xz:
{
return new XZStream(stream);
}
case ZipCompressionMethod.PPMd:
{
Span<byte> props = stackalloc byte[2];
Expand Down
136 changes: 75 additions & 61 deletions src/SharpCompress/Compressors/Filters/BranchExecFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

using System;
using System.IO;
using System.Runtime.CompilerServices;

namespace SharpCompress.Compressors.Filters;

Expand All @@ -22,89 +23,102 @@ public enum Alignment : int
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;

for (; i < size; i++)
{
if ((data[i] & 0xFE) == 0xE8)
{
break;
}
}
if ((buf[i] & 0xFE) != 0xE8)
continue;

var d = (uint)(i) - pos;
pos = (uint)i;
if (i >= size)
prev_pos = i - prev_pos;
if (prev_pos > 3)
{
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;
b = buf[i + 4 - mask_to_bit_num[prev_mask]];
if (!mask_to_allowed_status[prev_mask]
|| X86TestByte(b))
{
prev_pos = i;
prev_mask = (prev_mask << 1) | 1;
continue;
}
}
}

if ((((data[i + 4]) + 1) & 0xFE) == 0)
prev_pos = i;

if (X86TestByte(buf[i + 4]))
{
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)
src = ((uint)buf[i + 4] << 24)
| ((uint)buf[i + 3] << 16)
| ((uint)buf[i + 2] << 8)
| buf[i + 1];

while (true)
{
var sh = (mask & 6) << 2;
if (((((((byte)(inst >> (int)sh))) + 1) & 0xFE) == 0))
{
inst ^= (((uint)0x100 << (int)sh) - 1);
inst -= cur;
}
mask = 0;
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);
}
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));

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)
Expand Down
42 changes: 42 additions & 0 deletions src/SharpCompress/Compressors/Filters/DeltaFilter.cs
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
3 changes: 3 additions & 0 deletions src/SharpCompress/Compressors/LZMA/Registry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -37,6 +38,8 @@ long limit
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);
Expand Down
8 changes: 6 additions & 2 deletions src/SharpCompress/IO/ReadOnlySubStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
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)
Expand All @@ -15,6 +16,7 @@ public ReadOnlySubStream(Stream stream, long? origin, long bytesToRead)
stream.Position = origin.Value;
}
BytesLeftToRead = bytesToRead;
_position = 0;
}

private long BytesLeftToRead { get; set; }
Expand All @@ -31,7 +33,7 @@ public ReadOnlySubStream(Stream stream, long? origin, long bytesToRead)

public override long Position
{
get => Stream.Position;
get => _position; //allow position to be read (XZ uses this to calculate alignment)
set => throw new NotSupportedException();
}

Expand All @@ -45,6 +47,7 @@ public override int Read(byte[] buffer, int offset, int count)
if (read > 0)
{
BytesLeftToRead -= read;
_position += read;
}
return read;
}
Expand All @@ -59,6 +62,7 @@ public override int ReadByte()
if (value != -1)
{
--BytesLeftToRead;
_position++;
}
return value;
}
Expand Down
1 change: 1 addition & 0 deletions src/SharpCompress/IO/SourceStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ public override int Read(byte[] buffer, int offset, int count)
// 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)
}
}

Expand Down
16 changes: 16 additions & 0 deletions tests/SharpCompress.Test/Rar/RarArchiveTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,22 @@ public void Rar_Jpg_ArchiveFileRead()
[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()
{
Expand Down
4 changes: 4 additions & 0 deletions tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
17 changes: 14 additions & 3 deletions tests/SharpCompress.Test/TestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,23 @@ protected void VerifyFilesByExtensionEx()
}

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));
Expand Down
3 changes: 3 additions & 0 deletions tests/SharpCompress.Test/Zip/ZipArchiveTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down
Binary file added tests/TestArchives/Archives/7Zip.delta.7z
Binary file not shown.
Binary file added tests/TestArchives/Archives/Rar15.rar
Binary file not shown.
Binary file added tests/TestArchives/Archives/WinZip27_XZ.zipx
Binary file not shown.

0 comments on commit 9e6f9d5

Please sign in to comment.