Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #823 from klimatr26/new-7z-filters
Add support for 7z ARM64 and RISCV filters
- Loading branch information
Showing
7 changed files
with
285 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
using System; | ||
using System.Buffers.Binary; | ||
using System.IO; | ||
|
||
namespace SharpCompress.Compressors.Filters; | ||
|
||
internal class BCJFilterARM64 : Filter | ||
{ | ||
private int _pos; | ||
|
||
public BCJFilterARM64(bool isEncoder, Stream baseStream) | ||
: base(isEncoder, baseStream, 8) => _pos = 0; | ||
|
||
protected override int Transform(byte[] buffer, int offset, int count) | ||
{ | ||
var end = offset + count - 4; | ||
int i; | ||
|
||
for (i = offset; i <= end; i += 4) | ||
{ | ||
uint pc = (uint)(_pos + i - offset); | ||
uint instr = BinaryPrimitives.ReadUInt32LittleEndian( | ||
new ReadOnlySpan<byte>(buffer, i, 4) | ||
); | ||
|
||
if ((instr >> 26) == 0x25) | ||
{ | ||
uint src = instr; | ||
instr = 0x94000000; | ||
|
||
pc >>= 2; | ||
if (!_isEncoder) | ||
pc = 0U - pc; | ||
|
||
instr |= (src + pc) & 0x03FFFFFF; | ||
BinaryPrimitives.WriteUInt32LittleEndian(new Span<byte>(buffer, i, 4), instr); | ||
} | ||
else if ((instr & 0x9F000000) == 0x90000000) | ||
{ | ||
uint src = ((instr >> 29) & 3) | ((instr >> 3) & 0x001FFFFC); | ||
|
||
if (((src + 0x00020000) & 0x001C0000) != 0) | ||
continue; | ||
|
||
instr &= 0x9000001F; | ||
|
||
pc >>= 12; | ||
if (!_isEncoder) | ||
pc = 0U - pc; | ||
|
||
uint dest = src + pc; | ||
instr |= (dest & 3) << 29; | ||
instr |= (dest & 0x0003FFFC) << 3; | ||
instr |= (0U - (dest & 0x00020000)) & 0x00E00000; | ||
BinaryPrimitives.WriteUInt32LittleEndian(new Span<byte>(buffer, i, 4), instr); | ||
} | ||
} | ||
|
||
i -= offset; | ||
_pos += i; | ||
return i; | ||
} | ||
} |
210 changes: 210 additions & 0 deletions
210
src/SharpCompress/Compressors/Filters/BCJFilterRISCV.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
using System; | ||
using System.Buffers.Binary; | ||
using System.IO; | ||
|
||
namespace SharpCompress.Compressors.Filters; | ||
|
||
internal class BCJFilterRISCV : Filter | ||
{ | ||
private int _pos; | ||
|
||
public BCJFilterRISCV(bool isEncoder, Stream baseStream) | ||
: base(isEncoder, baseStream, 8) => _pos = 0; | ||
|
||
private int Decode(byte[] buffer, int offset, int count) | ||
{ | ||
if (count < 8) | ||
{ | ||
return 0; | ||
} | ||
|
||
var end = offset + count - 8; | ||
int i; | ||
for (i = offset; i <= end; i += 2) | ||
{ | ||
uint inst = buffer[i]; | ||
if (inst == 0xEF) | ||
{ | ||
uint b1 = buffer[i + 1]; | ||
if ((b1 & 0x0D) != 0) | ||
continue; | ||
|
||
uint b2 = buffer[i + 2]; | ||
uint b3 = buffer[i + 3]; | ||
uint pc = (uint)(_pos + i); | ||
|
||
uint addr = ((b1 & 0xF0) << 13) | (b2 << 9) | (b3 << 1); | ||
|
||
addr -= pc; | ||
|
||
buffer[i + 1] = (byte)((b1 & 0x0F) | ((addr >> 8) & 0xF0)); | ||
|
||
buffer[i + 2] = (byte)( | ||
((addr >> 16) & 0x0F) | ((addr >> 7) & 0x10) | ((addr << 4) & 0xE0) | ||
); | ||
|
||
buffer[i + 3] = (byte)(((addr >> 4) & 0x7F) | ((addr >> 13) & 0x80)); | ||
|
||
i += 4 - 2; | ||
} | ||
else if ((inst & 0x7F) == 0x17) | ||
{ | ||
uint inst2 = 0; | ||
inst |= (uint)buffer[i + 1] << 8; | ||
inst |= (uint)buffer[i + 2] << 16; | ||
inst |= (uint)buffer[i + 3] << 24; | ||
|
||
if ((inst & 0xE80) != 0) | ||
{ | ||
inst2 = BinaryPrimitives.ReadUInt32LittleEndian( | ||
new ReadOnlySpan<byte>(buffer, i + 4, 4) | ||
); | ||
if (((((inst) << 8) ^ (inst2)) & 0xF8003) != 3) | ||
{ | ||
i += 6 - 2; | ||
continue; | ||
} | ||
uint addr = inst & 0xFFFFF000; | ||
addr += inst2 >> 20; | ||
|
||
inst = 0x17 | (2 << 7) | (inst2 << 12); | ||
inst2 = addr; | ||
} | ||
else | ||
{ | ||
uint inst2_rs1 = inst >> 27; | ||
if ((uint)(((inst) - 0x3117) << 18) >= ((inst2_rs1) & 0x1D)) | ||
{ | ||
i += 4 - 2; | ||
continue; | ||
} | ||
|
||
uint addr = BinaryPrimitives.ReadUInt32BigEndian( | ||
new ReadOnlySpan<byte>(buffer, i + 4, 4) | ||
); | ||
|
||
addr -= (uint)(_pos + i); | ||
|
||
inst2 = (inst >> 12) | (addr << 20); | ||
|
||
inst = 0x17 | (inst2_rs1 << 7) | ((addr + 0x800) & 0xFFFFF000); | ||
} | ||
BinaryPrimitives.WriteUInt32LittleEndian(new Span<byte>(buffer, i, 4), inst); | ||
BinaryPrimitives.WriteUInt32LittleEndian(new Span<byte>(buffer, i + 4, 4), inst2); | ||
|
||
i += 8 - 2; | ||
} | ||
} | ||
i -= offset; | ||
_pos += i; | ||
return i; | ||
} | ||
|
||
private int Encode(byte[] buffer, int offset, int count) | ||
{ | ||
if (count < 8) | ||
{ | ||
return 0; | ||
} | ||
|
||
var end = offset + count - 8; | ||
int i; | ||
for (i = offset; i <= end; i += 2) | ||
{ | ||
uint inst = buffer[i]; | ||
if (inst == 0xEF) | ||
{ | ||
uint b1 = buffer[i + 1]; | ||
if ((b1 & 0x0D) != 0) | ||
continue; | ||
|
||
uint b2 = buffer[i + 2]; | ||
uint b3 = buffer[i + 3]; | ||
uint pc = (uint)(_pos + i); | ||
|
||
uint addr = | ||
((b1 & 0xF0) << 8) | ||
| ((b2 & 0x0F) << 16) | ||
| ((b2 & 0x10) << 7) | ||
| ((b2 & 0xE0) >> 4) | ||
| ((b3 & 0x7F) << 4) | ||
| ((b3 & 0x80) << 13); | ||
|
||
addr += pc; | ||
|
||
buffer[i + 1] = (byte)((b1 & 0x0F) | ((addr >> 13) & 0xF0)); | ||
|
||
buffer[i + 2] = (byte)(addr >> 9); | ||
|
||
buffer[i + 3] = (byte)(addr >> 1); | ||
|
||
i += 4 - 2; | ||
} | ||
else if ((inst & 0x7F) == 0x17) | ||
{ | ||
inst |= (uint)buffer[i + 1] << 8; | ||
inst |= (uint)buffer[i + 2] << 16; | ||
inst |= (uint)buffer[i + 3] << 24; | ||
|
||
if ((inst & 0xE80) != 0) | ||
{ | ||
uint inst2 = BinaryPrimitives.ReadUInt32LittleEndian( | ||
new ReadOnlySpan<byte>(buffer, i + 4, 4) | ||
); | ||
if (((((inst) << 8) ^ (inst2)) & 0xF8003) != 3) | ||
{ | ||
i += 6 - 2; | ||
continue; | ||
} | ||
uint addr = inst & 0xFFFFF000; | ||
addr += (inst2 >> 20) - ((inst2 >> 19) & 0x1000); | ||
|
||
addr += (uint)(_pos + i); | ||
inst = 0x17 | (2 << 7) | (inst2 << 12); | ||
|
||
BinaryPrimitives.WriteUInt32LittleEndian(new Span<byte>(buffer, i, 4), inst); | ||
BinaryPrimitives.WriteUInt32BigEndian(new Span<byte>(buffer, i + 4, 4), addr); | ||
} | ||
else | ||
{ | ||
uint fake_rs1 = inst >> 27; | ||
if ((uint)(((inst) - 0x3117) << 18) >= ((fake_rs1) & 0x1D)) | ||
{ | ||
i += 4 - 2; | ||
continue; | ||
} | ||
|
||
uint fake_addr = BinaryPrimitives.ReadUInt32LittleEndian( | ||
new ReadOnlySpan<byte>(buffer, i + 4, 4) | ||
); | ||
|
||
uint fake_inst2 = (inst >> 12) | (fake_addr << 20); | ||
|
||
inst = 0x17 | (fake_rs1 << 7) | (fake_addr & 0xFFFFF000); | ||
|
||
BinaryPrimitives.WriteUInt32LittleEndian(new Span<byte>(buffer, i, 4), inst); | ||
BinaryPrimitives.WriteUInt32LittleEndian( | ||
new Span<byte>(buffer, i + 4, 4), | ||
fake_inst2 | ||
); | ||
} | ||
i += 8 - 2; | ||
} | ||
} | ||
i -= offset; | ||
_pos += i; | ||
return i; | ||
} | ||
|
||
protected override int Transform(byte[] buffer, int offset, int count) | ||
{ | ||
if (_isEncoder) | ||
{ | ||
return Encode(buffer, offset, count); | ||
} | ||
else | ||
{ | ||
return Decode(buffer, offset, count); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Binary file not shown.
Binary file not shown.