Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zip Multipart fix, XZ stream fix, XZ stream support added to zip/zipx #722

Merged
merged 2 commits into from
Mar 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -97,6 +98,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
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 => throw new NotSupportedException();
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
5 changes: 4 additions & 1 deletion tests/SharpCompress.Test/Zip/ZipArchiveTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using System.Linq;
using System.Text;
Expand Down 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/WinZip27_XZ.zipx
Binary file not shown.