Split archive handling fix. XZ stream decoding bug fix (in X64Convert filter). XZ stream support added to zip/zipx.

This commit is contained in:
Nanook
2023-02-02 00:18:37 +00:00
parent d1ea8517d2
commit 48a341b79c
5 changed files with 91 additions and 66 deletions

View File

@@ -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
}

View File

@@ -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;
@@ -97,6 +98,10 @@ internal abstract class ZipFilePart : FilePart
: Header.UncompressedSize
);
}
case ZipCompressionMethod.Xz:
{
return new XZStream(stream);
}
case ZipCompressionMethod.PPMd:
{
Span<byte> props = stackalloc byte[2];

View File

@@ -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)

View File

@@ -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 => throw new NotSupportedException();
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;
}

View File

@@ -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)
}
}