BCJ executable filter (only for decoding), used by XZ.

This commit is contained in:
louis-michel
2022-06-10 13:29:42 -04:00
parent fa5c91ecf6
commit 0f112d0685
11 changed files with 995 additions and 1 deletions

View File

@@ -0,0 +1,297 @@
/*
* BranchExecFilter.cs -- Converters for executable
* <Contribution by Louis-Michel Bergeron, on behalf of aDolus Technolog Inc., 2022>
* @TODO Encoding
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SharpCompress.Compressors.Filters
{
[CLSCompliant(false)]
public sealed class BranchExecFilter
{
public enum Alignment : int
{
ARCH_x86_ALIGNMENT = 1,
ARCH_PowerPC_ALIGNMENT = 4,
ARCH_IA64_ALIGNMENT = 16,
ARCH_ARM_ALIGNMENT = 4,
ARCH_ARMTHUMB_ALIGNMENT = 2,
ARCH_SPARC_ALIGNMENT = 4,
}
public static void X86Converter(byte[] data, UInt32 ip, ref UInt32 state) {
long i = 0;
long size = data.Length;
UInt32 pos = 0;
UInt32 mask = state & 7;
if (size < 5)
return;
size -= 4;
ip += 5;
for (;;)
{
i = pos;
for (; i < size; i++)
{
if ((data[i] & 0xFE) == 0xE8)
{
break;
}
}
UInt32 d = (UInt32)(i) - pos;
pos = (UInt32)i;
if (i >= size)
{
state = (d > 2 ? 0 : mask >> (int)d);
return;
}
if (d > 2)
{
mask = 0;
}
else
{
mask >>= (int)d;
if (mask != 0 && (mask > 4 || mask == 3 || (((((data[(UInt32)(mask >> 1) + 1])) + 1) & 0xFE) == 0) ))
{
mask = (mask >> 1) | 4;
pos++;
continue;
}
}
if ((((data[i + 4]) + 1) & 0xFE) == 0)
{
UInt32 inst = ((UInt32)data[i + 4] << 24) | ((UInt32)data[i + 3] << 16) | ((UInt32)data[i + 2] << 8) | ((UInt32)data[i + 1]);
UInt32 cur = ip + (UInt32)pos;
pos += 5;
inst -= cur;
if (mask != 0)
{
UInt32 sh = (mask & 6) << 2;
if (((((((Byte)(inst >> (int)sh))) + 1) & 0xFE) == 0))
{
inst ^= (((UInt32)0x100 << (int)sh) - 1);
inst -= cur;
}
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));
}
else
{
mask = (mask >> 1) | 4;
pos++;
}
}
}
public static void PowerPCConverter(byte[] data, UInt32 ip)
{
long i = 0;
long size = data.Length;
size &= ~(UInt32)3;
ip -= 4;
for (;; ) // infinite loop
{
for (;; ) // infinite loop
{
if (i >= size)
return;
i += 4;
if ((data[i - 4] & 0xFC) == 0x48 && (data[i - 1] & 3) == 1)
break;
}
{
UInt32 inst = BitConverter.ToUInt32(data, (int)i - 4);
if (BitConverter.IsLittleEndian)
{
inst = Utility.SwapUINT32(inst);
}
inst -= (UInt32)(ip + i);
inst &= 0x03FFFFFF;
inst |= 0x48000000;
Utility.SetBigUInt32(ref data, inst, (i - 4));
}
}
}
public static void ARMConverter(byte[] data, UInt32 ip)
{
long i = 0;
long size = data.Length;
size &= ~(UInt32)3;
ip += 4;
for (;;) // infinite loop
{
for (;;) // infinite loop
{
if (i >= size)
{
return;
}
i += 4;
if (data[i - 1] == 0xEB)
break;
}
UInt32 inst = BitConverter.ToUInt32(data, (int)i - 4);
inst <<= 2;
inst -= (UInt32)(ip + i);
inst >>= 2;
inst &= 0x00FFFFFF;
inst |= 0xEB000000;
Utility.SetLittleUInt32(ref data, inst, i - 4);
}
}
public static void ARMTConverter(byte[] data, UInt32 ip)
{
long i = 0;
long size = data.Length;
size &= ~(UInt32)1;
long lim = size - 4;
for (;;)
{
UInt32 b1;
for (;;)
{
UInt32 b3;
if (i > lim)
return;
b1 = data[i + 1];
b3 = data[i + 3];
i += 2;
b1 ^= 8;
if ((b3 & b1) >= 0xF8)
break;
}
UInt32 inst = ((UInt32)b1 << 19)
+ (((UInt32)data[i + 1] & 0x7) << 8)
+ (((UInt32)data[i - 2] << 11))
+ (data[i]);
i += 2;
UInt32 cur = ((UInt32)(ip + i)) >> 1;
inst -= cur;
data[i - 4] = (Byte)(inst >> 11);
data[i - 3] = (Byte)(0xF0 | ((inst >> 19) & 0x7));
data[i - 2] = (Byte)inst;
data[i - 1] = (Byte)(0xF8 | (inst >> 8));
}
}
public static void IA64Converter(byte[] data, UInt32 ip)
{
UInt32 i = 0;
long size = data.Length;
if (size < 16)
throw new InvalidDataException("Unexpected data size");
size -= 16;
do
{
UInt32 m = ((UInt32)0x334B0000 >> (data[i] & 0x1E)) & 3;
if (m != 0)
{
m++;
do
{
UInt32 iterator = (UInt32)( (i + (m * 5) - 8));
if (((data[iterator + 3] >> (int)m) & 15) == 5
&& (((data[iterator - 1] | ((UInt32)data[iterator] << 8)) >> (int)m) & 0x70) == 0)
{
UInt32 raw = BitConverter.ToUInt32(data, (int)iterator);
UInt32 inst = raw >> (int)m;
inst = (inst & 0xFFFFF) | ((inst & (1 << 23)) >> 3);
inst <<= 4;
inst -= (ip + (UInt32)i);
inst >>= 4;
inst &= 0x1FFFFF;
inst += 0x700000;
inst &= 0x8FFFFF;
raw &= ~((UInt32)0x8FFFFF << (int)m);
raw |= (inst << (int)m);
Utility.SetLittleUInt32(ref data, raw, iterator);
}
}
while (++m <= 4);
}
i += 16;
}
while (i <= size);
return;
}
public static void SPARCConverter(byte[] data, UInt32 ip)
{
long i = 0;
long size = data.Length;
size &= ~(UInt32)3;
ip -= 4;
for (;;) // infinite loop
{
for (;;) // infinite loop
{
if (i >= size)
return;
i += 4;
if ((data[i - 4] == 0x40 && (data[i - 3] & 0xC0) == 0) ||
(data[i - 4] == 0x7F && (data[i - 3] >= 0xC0)))
break;
}
UInt32 inst = BitConverter.ToUInt32(data, (int)i - 4);
if (BitConverter.IsLittleEndian)
{
inst = Utility.SwapUINT32(inst);
}
inst <<= 2;
inst -= (UInt32)(ip + i);
inst &= 0x01FFFFFF;
inst -= (UInt32)1 << 24;
inst ^= 0xFF000000;
inst >>= 2;
inst |= 0x40000000;
Utility.SetBigUInt32(ref data, inst, (i - 4));
}
}
}
}

View File

@@ -0,0 +1,68 @@
/*
* ArmFilter.cs -- XZ converter ARM executable
* <Contribution by Louis-Michel Bergeron, on behalf of aDolus Technolog Inc., 2022>
* @TODO Properties offset
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpCompress.Compressors.Filters;
namespace SharpCompress.Compressors.Xz.Filters
{
internal class ArmFilter : BlockFilter
{
public override bool AllowAsLast => false;
public override bool AllowAsNonLast => true;
public override bool ChangesDataSize => false;
private UInt32 _ip = 0;
//private UInt32 _offset = 0;
public override void Init(byte[] properties)
{
if (properties.Length != 0 && properties.Length != 4)
{
throw new InvalidDataException("ARM properties unexpected length");
}
if (properties.Length == 4)
{
// Even XZ doesn't support it.
throw new InvalidDataException("ARM properties offset is not supported");
//_offset = BitConverter.ToUInt32(properties, 0);
//
//if (_offset % (UInt32)BranchExec.Alignment.ARCH_ARM_ALIGNMENT != 0)
//{
// throw new InvalidDataException("Filter offset does not match alignment");
//}
}
}
public override void ValidateFilter()
{
}
public override int Read(byte[] buffer, int offset, int count)
{
int bytesRead = BaseStream.Read(buffer, offset, count);
BranchExecFilter.ARMConverter(buffer, _ip);
_ip += (UInt32)bytesRead;
return bytesRead;
}
public override void SetBaseStream(Stream stream)
{
BaseStream = stream;
}
}
}

View File

@@ -0,0 +1,69 @@
/*
* ArmFThumbFilter.cs -- XZ converter ARMThumb executable
* <Contribution by Louis-Michel Bergeron, on behalf of aDolus Technolog Inc., 2022>
* @TODO Properties offset
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpCompress.Compressors.Filters;
namespace SharpCompress.Compressors.Xz.Filters
{
internal class ArmThumbFilter : BlockFilter
{
public override bool AllowAsLast => false;
public override bool AllowAsNonLast => true;
public override bool ChangesDataSize => false;
private UInt32 _ip = 0;
//private UInt32 _offset = 0;
public override void Init(byte[] properties)
{
if (properties.Length != 0 && properties.Length != 4)
{
throw new InvalidDataException("ARM Thumb properties unexpected length");
}
if (properties.Length == 4)
{
// Even XZ doesn't support it.
throw new InvalidDataException("ARM Thumb properties offset is not supported");
//_offset = BitConverter.ToUInt32(properties, 0);
//
//if (_offset % (UInt32)BranchExec.Alignment.ARCH_ARMTHUMB_ALIGNMENT != 0)
//{
// throw new InvalidDataException("Filter offset does not match alignment");
//}
}
}
public override void ValidateFilter()
{
}
public override int Read(byte[] buffer, int offset, int count)
{
int bytesRead = BaseStream.Read(buffer, offset, count);
BranchExecFilter.ARMTConverter(buffer, _ip);
_ip += (UInt32)bytesRead;
return bytesRead;
}
public override void SetBaseStream(Stream stream)
{
BaseStream = stream;
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
@@ -20,6 +20,12 @@ namespace SharpCompress.Compressors.Xz.Filters
private static readonly Dictionary<FilterTypes, Type> FilterMap = new Dictionary<FilterTypes, Type>
{
{FilterTypes.ARCH_x86_FILTER, typeof(X86Filter) },
{FilterTypes.ARCH_PowerPC_FILTER, typeof(PowerPCFilter) },
{FilterTypes.ARCH_IA64_FILTER, typeof(IA64Filter) },
{FilterTypes.ARCH_ARM_FILTER, typeof(ArmFilter) },
{FilterTypes.ARCH_ARMTHUMB_FILTER, typeof(ArmThumbFilter) },
{FilterTypes.ARCH_SPARC_FILTER, typeof(SparcFilter) },
{FilterTypes.LZMA2, typeof(Lzma2Filter) }
};

View File

@@ -0,0 +1,67 @@
/*
* IA64Filter.cs -- XZ converter IA64 executable
* <Contribution by Louis-Michel Bergeron, on behalf of aDolus Technolog Inc., 2022>
* @TODO Properties offset
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpCompress.Compressors.Filters;
namespace SharpCompress.Compressors.Xz.Filters
{
internal class IA64Filter : BlockFilter
{
public override bool AllowAsLast => false;
public override bool AllowAsNonLast => true;
public override bool ChangesDataSize => false;
private UInt32 _ip = 0;
//private UInt32 _offset = 0;
public override void Init(byte[] properties)
{
if (properties.Length != 0 && properties.Length != 4)
{
throw new InvalidDataException("IA64 properties unexpected length");
}
if (properties.Length == 4)
{
// Even XZ doesn't support it.
throw new InvalidDataException("IA64 properties offset is not supported");
//_offset = BitConverter.ToUInt32(properties, 0);
//
//if (_offset % (UInt32)BranchExec.Alignment.ARCH_IA64_ALIGNMENT != 0)
//{
// throw new InvalidDataException("Filter offset does not match alignment");
//}
}
}
public override void ValidateFilter()
{
}
public override int Read(byte[] buffer, int offset, int count)
{
int bytesRead = BaseStream.Read(buffer, offset, count);
BranchExecFilter.IA64Converter(buffer, _ip);
_ip += (UInt32)bytesRead;
return bytesRead;
}
public override void SetBaseStream(Stream stream)
{
BaseStream = stream;
}
}
}

View File

@@ -0,0 +1,66 @@
/*
* PowerPCFilter.cs -- XZ converter PowerPC executable
* <Contribution by Louis-Michel Bergeron, on behalf of aDolus Technolog Inc., 2022>
* @TODO Properties offset
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpCompress.Compressors.Filters;
namespace SharpCompress.Compressors.Xz.Filters
{
internal class PowerPCFilter : BlockFilter
{
public override bool AllowAsLast => false;
public override bool AllowAsNonLast => true;
public override bool ChangesDataSize => false;
private UInt32 _ip = 0;
//private UInt32 _offset = 0;
public override void Init(byte[] properties)
{
if (properties.Length != 0 && properties.Length != 4)
{
throw new InvalidDataException("PPC properties unexpected length");
}
if (properties.Length == 4)
{
// Even XZ doesn't support it.
throw new InvalidDataException("PPC properties offset is not supported");
//_offset = BitConverter.ToUInt32(properties, 0);
//
//if (_offset % (UInt32)BranchExec.Alignment.ARCH_PowerPC_ALIGNMENT != 0)
//{
// throw new InvalidDataException("Filter offset does not match alignment");
//}
}
}
public override void ValidateFilter() { }
public override int Read(byte[] buffer, int offset, int count)
{
int bytesRead = BaseStream.Read(buffer, offset, count);
BranchExecFilter.PowerPCConverter(buffer, _ip);
_ip += (UInt32)bytesRead;
return bytesRead;
}
public override void SetBaseStream(Stream stream)
{
BaseStream = stream;
}
}
}

View File

@@ -0,0 +1,65 @@
/*
* SparcFilter.cs -- XZ converter SPARC executable
* <Contribution by Louis-Michel Bergeron, on behalf of aDolus Technolog Inc., 2022>
* @TODO Properties offset
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpCompress.Compressors.Filters;
namespace SharpCompress.Compressors.Xz.Filters
{
internal class SparcFilter : BlockFilter
{
public override bool AllowAsLast => false;
public override bool AllowAsNonLast => true;
public override bool ChangesDataSize => false;
private UInt32 _ip = 0;
//private UInt32 _offset = 0;
public override void Init(byte[] properties) {
if (properties.Length != 0 && properties.Length != 4)
{
throw new InvalidDataException("SPARC properties unexpected length");
}
if (properties.Length == 4)
{
// Even XZ doesn't support it.
throw new InvalidDataException("SPARC properties offset is not supported");
//_offset = BitConverter.ToUInt32(properties, 0);
//
//if (_offset % (UInt32)BranchExec.Alignment.ARCH_SPARC_ALIGNMENT != 0)
//{
// throw new InvalidDataException("Filter offset does not match alignment");
//}
}
}
public override void ValidateFilter() {
}
public override int Read(byte[] buffer, int offset, int count){
int bytesRead = BaseStream.Read(buffer, offset, count);
BranchExecFilter.SPARCConverter(buffer, _ip);
_ip += (UInt32)bytesRead;
return bytesRead;
}
public override void SetBaseStream(Stream stream) {
BaseStream = stream;
}
}
}

View File

@@ -0,0 +1,70 @@
/*
* X86Filter.cs -- XZ converter x86 executable
* <Contribution by Louis-Michel Bergeron, on behalf of aDolus Technolog Inc., 2022>
* @TODO Properties offset
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpCompress.Compressors.Filters;
namespace SharpCompress.Compressors.Xz.Filters
{
internal class X86Filter : BlockFilter
{
public override bool AllowAsLast => false;
public override bool AllowAsNonLast => true;
public override bool ChangesDataSize => false;
private UInt32 _ip = 0;
private UInt32 _state = 0;
//private UInt32 _offset = 0;
public override void Init(byte[] properties)
{
if (properties.Length != 0 && properties.Length != 4)
{
throw new InvalidDataException("X86 properties unexpected length");
}
if (properties.Length == 4)
{
// Even XZ doesn't support it.
throw new InvalidDataException("X86 properties offset is not supported");
//_offset = BitConverter.ToUInt32(properties, 0);
//
//if (_offset % (UInt32)BranchExec.Alignment.ARCH_x86_ALIGNMENT != 0)
//{
// throw new InvalidDataException("Filter offset does not match alignment");
//}
}
}
public override void ValidateFilter()
{
}
public override int Read(byte[] buffer, int offset, int count)
{
int bytesRead = BaseStream.Read(buffer, offset, count);
BranchExecFilter.X86Converter(buffer, _ip, ref _state);
_ip += (UInt32)bytesRead;
return bytesRead;
}
public override void SetBaseStream(Stream stream)
{
BaseStream = stream;
}
}
}

View File

@@ -315,5 +315,46 @@ namespace SharpCompress
{
return source.Replace('\0', ' ').Trim();
}
/// <summary>
/// Swap the endianness of a UINT32
/// </summary>
/// <param name="number">The UINT32 you want to swap his endianness</param>
/// <returns>Return the new UINT32 in the other endianness format</returns>
public static UInt32 SwapUINT32(UInt32 number)
{
return (number >> 24) |
((number << 8) & 0x00FF0000) |
((number >> 8) & 0x0000FF00) |
(number << 24);
}
/// <summary>
/// Insert a little endian UINT32 into a byte array
/// </summary>
/// <param name="buffer">The buffer to insert into</param>
/// <param name="number">The UINT32 to insert</param>
/// <param name="offset">Offset of the buffer to insert into</param>
public static void SetLittleUInt32(ref byte[] buffer, UInt32 number, long offset)
{
buffer[offset] = (byte)(number);
buffer[offset + 1] = (byte)(number >> 8);
buffer[offset + 2] = (byte)(number >> 16);
buffer[offset + 3] = (byte)(number >> 24);
}
/// <summary>
/// Insert a big endian UINT32 into a byte array
/// </summary>
/// <param name="buffer">The buffer to insert into</param>
/// <param name="number">The UINT32 to insert</param>
/// <param name="offset">Offset of the buffer to insert into</param>
public static void SetBigUInt32(ref byte[] buffer, UInt32 number, long offset)
{
buffer[offset] = (byte)(number >> 24);
buffer[offset + 1] = (byte)(number >> 16);
buffer[offset + 2] = (byte)(number >> 8);
buffer[offset + 3] = (byte)number;
}
}
}

View File

@@ -0,0 +1,157 @@
/*
* BranchExecTests.cs -- Test for converters
* <Contribution by Louis-Michel Bergeron, on behalf of aDolus Technolog Inc., 2022>
*
* All data is extracted from busybox, where "ip" is the offset within the busybox file.
*/
using SharpCompress.Compressors.Filters;
using Xunit;
namespace SharpCompress.Test.Filters
{
public class BranchExecTests
{
private static byte[] x86resultData { get; } = new byte[] {
0x12, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x00, 0x00, 0xE8, 0xBD, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x6D, 0x01, 0x00, 0x00, 0xF0, 0xCA,
0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xBC, 0x09, 0x00, 0x00, 0x14, 0xC2, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x98, 0x0B, 0x00, 0x00, 0x60, 0x75, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xF1, 0xFF, 0x42, 0x01, 0x00, 0x00, 0x08, 0xC8, 0x00, 0x00, 0x1C, 0x00,
};
private static byte[] x86Data { get; } = new byte[] {
0x12, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x00, 0x00, 0xE8, 0xCA, 0x20, 0x00, 0x00, 0x07, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x6D, 0x01, 0x00, 0x00, 0xF0, 0xCA,
0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xBC, 0x09, 0x00, 0x00, 0x14, 0xC2, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x98, 0x0B, 0x00, 0x00, 0x60, 0x75, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xF1, 0xFF, 0x42, 0x01, 0x00, 0x00, 0x08, 0xC8, 0x00, 0x00, 0x1C, 0x00,
};
private static byte[] ppcResultData { get; } = new byte[] {
0xF8, 0x6B, 0x2E, 0x8C, 0x95, 0xC5, 0x4B, 0x1B, 0x94, 0x78, 0x9E, 0x7C, 0xBD, 0x8B, 0xA8, 0xAF, 0x31, 0x20, 0xFE, 0x0F, 0xB3, 0x15, 0x9A, 0x7C, 0xD5, 0x5C,
0xC2, 0xC0, 0xEC, 0xE9, 0x43, 0x2B, 0xD0, 0x9F, 0x2C, 0xFC, 0xB8, 0x2B, 0x6B, 0x15, 0xCD, 0x3F, 0x0C, 0xAF, 0x8F, 0x68, 0xB0, 0x6E, 0x6B, 0x30, 0x2E, 0x8C,
0x3F, 0x7E, 0x96, 0x7C, 0x93, 0xB2, 0xA4, 0x0E, 0x43, 0xEA, 0x20, 0x10, 0x38, 0x6D, 0x37, 0xF8, 0x87, 0xFE, 0xA9, 0x63, 0x75, 0xF5, 0x56, 0x34, 0x4A, 0xE3,
0xCF, 0x89, 0x18, 0x08, 0xC2, 0x76, 0x74, 0x12, 0xEC, 0xA7, 0x6D, 0xC2, 0xB7, 0x1B, 0x7A, 0xB2, 0xD4, 0xED
};
private static byte[] ppcData { get; } = new byte[] {
0xF8, 0x6B, 0x2E, 0x8C, 0x95, 0xC5, 0x4B, 0x1B, 0x94, 0x78, 0x9E, 0x7C, 0xBD, 0x8B, 0xA8, 0xAF, 0x31, 0x20, 0xFE, 0x0F, 0xB3, 0x15, 0x9A, 0x7C, 0xD5, 0x5C,
0xC2, 0xC0, 0xEC, 0xE9, 0x43, 0x2B, 0xD0, 0x9F, 0x2C, 0xFC, 0xB8, 0x2B, 0x6B, 0x15, 0xCD, 0x3F, 0x0C, 0xAF, 0x8F, 0x68, 0xB0, 0x6E, 0x6B, 0x30, 0x2E, 0x8C,
0x3F, 0x7E, 0x96, 0x7C, 0x93, 0xB2, 0xA4, 0x0E, 0x43, 0xEA, 0x20, 0x10, 0x38, 0x6D, 0x37, 0xF8, 0x87, 0xFE, 0xA9, 0x63, 0x75, 0xF5, 0x56, 0x34, 0x4A, 0xE3,
0xD6, 0x75, 0x18, 0x08, 0xC2, 0x76, 0x74, 0x12, 0xEC, 0xA7, 0x6D, 0xC2, 0xB7, 0x1B, 0x7A, 0xB2, 0xD4, 0xED
};
private static byte[] armResultData { get; } = new byte[] {
0x7C, 0xFC, 0x0A, 0x00, 0x16, 0x42, 0x01, 0x00, 0x80, 0xFC, 0x0A, 0x00, 0x16, 0xB8, 0x00, 0x00, 0x84, 0xFC, 0x0A, 0x00, 0x16, 0x3A, 0x00, 0x00, 0x04, 0xE0,
0x2D, 0xE5, 0x04, 0xD0, 0x4D, 0xE2, 0x0E, 0x04, 0x00, 0xEB, 0x04, 0xD0, 0x8D, 0xE2, 0x04, 0xE0, 0x9D, 0xE4, 0x1E, 0xFF, 0x2F, 0xE1, 0x04, 0xE0, 0x2D, 0xE5,
0x04, 0xE0, 0x9F, 0xE5, 0x0E, 0xE0, 0x8F, 0xE0, 0x08, 0xF0, 0xBE, 0xE5, 0xF0, 0x3A, 0x0A, 0x00, 0x00, 0xC6, 0x8F, 0xE2, 0xA3, 0xCA, 0x8C, 0xE2, 0xF0, 0xFA,
0xBC, 0xE5, 0x00, 0xC6, 0x8F, 0xE2, 0xA3, 0xCA, 0x8C, 0xE2, 0xE8, 0xFA, 0xBC, 0xE5, 0x00, 0xC6, 0x8F, 0xE2
};
private static byte[] armData { get; } = new byte[] {
0x7C, 0xFC, 0x0A, 0x00, 0x16, 0x42, 0x01, 0x00, 0x80, 0xFC, 0x0A, 0x00, 0x16, 0xB8, 0x00, 0x00, 0x84, 0xFC, 0x0A, 0x00, 0x16, 0x3A, 0x00, 0x00, 0x04, 0xE0,
0x2D, 0xE5, 0x04, 0xD0, 0x4D, 0xE2, 0x18, 0x13, 0x00, 0xEB, 0x04, 0xD0, 0x8D, 0xE2, 0x04, 0xE0, 0x9D, 0xE4, 0x1E, 0xFF, 0x2F, 0xE1, 0x04, 0xE0, 0x2D, 0xE5,
0x04, 0xE0, 0x9F, 0xE5, 0x0E, 0xE0, 0x8F, 0xE0, 0x08, 0xF0, 0xBE, 0xE5, 0xF0, 0x3A, 0x0A, 0x00, 0x00, 0xC6, 0x8F, 0xE2, 0xA3, 0xCA, 0x8C, 0xE2, 0xF0, 0xFA,
0xBC, 0xE5, 0x00, 0xC6, 0x8F, 0xE2, 0xA3, 0xCA, 0x8C, 0xE2, 0xE8, 0xFA, 0xBC, 0xE5, 0x00, 0xC6, 0x8F, 0xE2
};
private static byte[] armtResultData { get; } = new byte[] {
0x95, 0x23, 0xB6, 0xB1, 0xBE, 0x60, 0x79, 0xF0, 0xF6, 0x01, 0xD9, 0x7F, 0x2E, 0x03, 0x31, 0x1C, 0xFD, 0xD3, 0x40, 0x0F, 0x21, 0x3C, 0x06, 0x97, 0xE5, 0xC3,
0x57, 0x11, 0x76, 0x6F, 0xE3, 0x70, 0xED, 0x49, 0xCB, 0xB5, 0xC9, 0x42, 0x59, 0x10, 0x2F, 0xBD, 0xAE, 0xB1, 0x40, 0x4D, 0x9D, 0x7C, 0xE9, 0xFC, 0x48, 0x3E,
0xBC, 0x7F, 0x0B, 0x23, 0xB0, 0x8A, 0x4D, 0x02, 0x39, 0xC4, 0xFB, 0x66, 0x83, 0x7F, 0xA7, 0xBD, 0x12, 0xAC, 0xED, 0x31, 0x34, 0x93, 0x4D, 0x8D, 0xD7, 0x94,
0x93, 0x1C, 0x0A, 0x50, 0x54, 0x4B, 0x03, 0x55, 0x27, 0xFE, 0xCE, 0x29, 0x66, 0x52, 0x81, 0xAE, 0x69, 0xA0, 0x69, 0xF2, 0x3D, 0xFF, 0xA1, 0x8A, 0x5D, 0x61,
0x7D, 0xC5, 0x94, 0x0A, 0x7D, 0xED, 0x11, 0x0F
};
private static byte[] armtData { get; } = new byte[] {
0x95, 0x23, 0xB6, 0xB1, 0xBE, 0x60, 0x79, 0xF0, 0xF6, 0x01, 0xD9, 0x7F, 0x2E, 0x03, 0x31, 0x1C, 0xFD, 0xD3, 0x40, 0x0F, 0x21, 0x3C, 0x06, 0x97, 0xE5, 0xC3,
0x57, 0x11, 0x76, 0x6F, 0xE3, 0x70, 0xED, 0x49, 0xCB, 0xB5, 0xC9, 0x42, 0x59, 0x10, 0x2F, 0xBD, 0xAE, 0xB1, 0x40, 0x4D, 0x9D, 0x7C, 0xE9, 0xFC, 0x48, 0x3E,
0xBC, 0x7F, 0x0B, 0x23, 0xB0, 0x8A, 0x4D, 0x02, 0x39, 0xC4, 0xFB, 0x66, 0x83, 0x7F, 0xA7, 0xBD, 0x12, 0xAC, 0xED, 0x31, 0x34, 0x93, 0x4D, 0x8D, 0xD7, 0x94,
0x93, 0x1C, 0x0A, 0x50, 0x54, 0x4B, 0x03, 0x55, 0x27, 0xFE, 0xCE, 0x29, 0x66, 0x52, 0x81, 0xAE, 0x69, 0xA0, 0x6A, 0xF2, 0x6F, 0xFC, 0xA1, 0x8A, 0x5D, 0x61,
0x7D, 0xC5, 0x94, 0x0A, 0x7D, 0xED, 0x11, 0x0F
};
private static byte[] ia64ResultData { get; } = new byte[] {
0x4D, 0xF8, 0xF2, 0x0D, 0x06, 0x2F, 0x74, 0x0F, 0xF0, 0x91, 0x06, 0x0B, 0x19, 0x22, 0x91, 0x5A, 0x66, 0x56, 0xA7, 0x15, 0x77, 0x1E, 0x2F, 0xA3, 0xE4, 0xDE,
0x93, 0x1C, 0xD5, 0xCE, 0x6E, 0x45, 0x36, 0x15, 0x15, 0x65, 0x4E, 0xC5, 0xA3, 0x8C, 0x5A, 0x8B, 0x8A, 0x1C, 0x12, 0x5B, 0x39, 0x1F, 0xA0, 0xF2, 0x93, 0x7C,
0x7F, 0x5D, 0xD9, 0x30, 0x1F, 0xF6, 0x5C, 0x10, 0x62, 0x3E, 0xB4, 0x64, 0x56, 0x48, 0xB2, 0x20, 0x39, 0xE8, 0x44, 0x10, 0x87, 0x9E, 0x2C, 0xFC, 0x29, 0x0E,
0x20, 0x76, 0xCE, 0xDA, 0x93, 0x1C, 0xED, 0x54, 0x0D, 0xAF, 0xEC, 0xDE, 0x93, 0x1C, 0x2B, 0x72, 0xD5, 0x0D
};
private static byte[] ia64Data { get; } = new byte[] {
0x4D, 0xF8, 0xF2, 0x0D, 0x06, 0x2F, 0x74, 0x0F, 0xF0, 0x91, 0x06, 0x0B, 0x19, 0x22, 0x91, 0x5A, 0x66, 0x56, 0xA7, 0x15, 0x77, 0x1E, 0x2F, 0xA3, 0xE4, 0xDE,
0x93, 0x1C, 0xD5, 0xCE, 0x6E, 0x45, 0x36, 0x15, 0x15, 0x65, 0x4E, 0xC5, 0xA3, 0x8C, 0x5A, 0x8B, 0x8A, 0x1C, 0x12, 0x5B, 0x39, 0x1F, 0xA0, 0xF2, 0x93, 0x7C,
0x7F, 0x5D, 0xD9, 0x30, 0x1F, 0xF6, 0x5C, 0x10, 0x62, 0x3E, 0xB4, 0x64, 0x56, 0x48, 0xB2, 0x20, 0x39, 0xE8, 0x44, 0x80, 0x8C, 0x9E, 0x2C, 0xFC, 0x29, 0x0E,
0x20, 0x76, 0xCE, 0xDA, 0x93, 0x1C, 0xED, 0x54, 0x0D, 0xAF, 0xEC, 0xDE, 0x93, 0x1C, 0x2B, 0x72, 0xD5, 0x0D
};
private static byte[] sparcResultData { get; } = new byte[] {
0x78, 0x2E, 0x73, 0x6F, 0x2E, 0x33, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xA2, 0x0D,
0x10, 0x12, 0x30, 0x03, 0xC9, 0x37, 0x40, 0x1A, 0x85, 0xD9, 0x44, 0x34, 0x40, 0x32, 0x85, 0xA0, 0x30, 0x40, 0x00, 0x70, 0x00, 0x40, 0x84, 0x80, 0x04, 0x00,
0xE4, 0xAC, 0x07, 0x04, 0x21, 0x44, 0x02, 0x20, 0x10, 0x00, 0x40, 0xC2, 0x89, 0x98, 0x85, 0x00, 0x58, 0x6A, 0x41, 0x8E, 0x18, 0xA1, 0x91, 0x00, 0x10, 0x00,
};
private static byte[] sparcData { get; } = new byte[] {
0x78, 0x2E, 0x73, 0x6F, 0x2E, 0x33, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x44, 0x0B, 0x00, 0x00, 0x00, 0xA2, 0x0D,
0x10, 0x12, 0x30, 0x03, 0xC9, 0x37, 0x40, 0x1A, 0x86, 0x21, 0x44, 0x34, 0x40, 0x32, 0x85, 0xA0, 0x30, 0x40, 0x00, 0x70, 0x00, 0x40, 0x84, 0x80, 0x04, 0x00,
0xE4, 0xAC, 0x07, 0x04, 0x21, 0x44, 0x02, 0x20, 0x10, 0x00, 0x40, 0xC2, 0x89, 0x98, 0x85, 0x00, 0x58, 0x6A, 0x41, 0x8E, 0x18, 0xA1, 0x91, 0x00, 0x10, 0x00,
};
private void CompareBuffer(byte[] testBuffer, byte[] targetBuffer)
{
Assert.Equal(testBuffer, targetBuffer);
}
[Fact]
public void X86ConverterDecodeTest()
{
uint state = 0;
uint ip = 0x2000;
var testData = x86Data;
BranchExecFilter.X86Converter(testData, ip, ref state);
CompareBuffer(testData, x86resultData);
}
[Fact]
public void PowerPCConverterDecodeTest()
{
uint ip = 0x6A0;
var testData = ppcData;
BranchExecFilter.PowerPCConverter(testData, ip);
CompareBuffer(testData, ppcResultData);
}
[Fact]
public void ARMConverteDecoderTest()
{
uint ip = 0x3C00;
var testData = armData;
BranchExecFilter.ARMConverter(testData, ip);
CompareBuffer(testData, armResultData);
}
[Fact]
public void ARMTConverterDecodeTest()
{
uint ip = 0xA00;
var testData = armtData;
BranchExecFilter.ARMTConverter(testData, ip);
CompareBuffer(testData, armtResultData);
}
[Fact]
public void IA64ConverterDecodeTest()
{
uint ip = 0xAA0;
var testData = ia64Data;
BranchExecFilter.IA64Converter(testData, ip);
CompareBuffer(testData, ia64ResultData);
}
[Fact]
public void SPARCConverterDecodeTest()
{
uint ip = 0x100;
var testData = sparcData;
BranchExecFilter.SPARCConverter(testData, ip);
CompareBuffer(testData, sparcResultData);
}
}
}

View File

@@ -0,0 +1,88 @@
/*
* BCJTests.cs -- XZ converter test class
* <Contribution by Louis-Michel Bergeron, on behalf of aDolus Technolog Inc., 2022>
*/
using System.IO;
using SharpCompress.Compressors.Xz.Filters;
using Xunit;
namespace SharpCompress.Test.Xz.Filters
{
public class BCJTests : XZTestsBase
{
private readonly ArmFilter armFilter;
private readonly ArmThumbFilter armtFilter;
private readonly IA64Filter ia64Filter;
private readonly PowerPCFilter ppcFilter;
private readonly SparcFilter sparcFilter;
private readonly X86Filter x86Filter;
public BCJTests()
{
armFilter = new ArmFilter();
armtFilter = new ArmThumbFilter();
ia64Filter = new IA64Filter();
ppcFilter = new PowerPCFilter();
sparcFilter = new SparcFilter();
x86Filter = new X86Filter();
}
[Fact]
public void IsOnlyAllowedLast()
{
Assert.False(armFilter.AllowAsLast);
Assert.True(armFilter.AllowAsNonLast);
Assert.False(armtFilter.AllowAsLast);
Assert.True(armtFilter.AllowAsNonLast);
Assert.False(ia64Filter.AllowAsLast);
Assert.True(ia64Filter.AllowAsNonLast);
Assert.False(ppcFilter.AllowAsLast);
Assert.True(ppcFilter.AllowAsNonLast);
Assert.False(sparcFilter.AllowAsLast);
Assert.True(sparcFilter.AllowAsNonLast);
Assert.False(x86Filter.AllowAsLast);
Assert.True(x86Filter.AllowAsNonLast);
}
[Fact]
public void ChangesStreamSize()
{
Assert.False(armFilter.ChangesDataSize);
Assert.False(armtFilter.ChangesDataSize);
Assert.False(ia64Filter.ChangesDataSize);
Assert.False(ppcFilter.ChangesDataSize);
Assert.False(sparcFilter.ChangesDataSize);
Assert.False(x86Filter.ChangesDataSize);
}
[Theory]
[InlineData(new byte[] { 0 })]
[InlineData(new byte[] { 0, 0, 0, 0, 0 })]
public void OnlyAcceptsOneByte(byte[] bytes)
{
InvalidDataException ex;
ex = Assert.Throws<InvalidDataException>(() => armFilter.Init(bytes));
Assert.Equal("ARM properties unexpected length", ex.Message);
ex = Assert.Throws<InvalidDataException>(() => armtFilter.Init(bytes));
Assert.Equal("ARM Thumb properties unexpected length", ex.Message);
ex = Assert.Throws<InvalidDataException>(() => ia64Filter.Init(bytes));
Assert.Equal("IA64 properties unexpected length", ex.Message);
ex = Assert.Throws<InvalidDataException>(() => ppcFilter.Init(bytes));
Assert.Equal("PPC properties unexpected length", ex.Message);
ex = Assert.Throws<InvalidDataException>(() => sparcFilter.Init(bytes));
Assert.Equal("SPARC properties unexpected length", ex.Message);
ex = Assert.Throws<InvalidDataException>(() => x86Filter.Init(bytes));
Assert.Equal("X86 properties unexpected length", ex.Message);
}
}
}