Skip to content

Commit

Permalink
Merge pull request #722 from Nanook/fixes-XZ-zip
Browse files Browse the repository at this point in the history
Zip Multipart fix, XZ stream fix, XZ stream support added to zip/zipx
  • Loading branch information
adamhathcock committed Mar 1, 2023
2 parents d1ea851 + b9d0195 commit 9ecf652
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 64 deletions.
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.

0 comments on commit 9ecf652

Please sign in to comment.