Skip to content

Commit bc4353e

Browse files
committed
fix: Add ARM64 filter support
1 parent 0af225b commit bc4353e

File tree

8 files changed

+98
-15
lines changed

8 files changed

+98
-15
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Current status:
2121
* Handles archives split into multiple volumes, (`7za a -v100m test.7z ...`).
2222
* Handles self-extracting archives, (`7za a -sfx archive.exe ...`).
2323
* Validates CRC values as it parses the file.
24-
* Supports ARM, BCJ, BCJ2, Brotli, Bzip2, Copy, Deflate, Delta, LZ4, LZMA, LZMA2, PPC, SPARC and Zstandard methods.
24+
* Supports ARM, ARM64, BCJ, BCJ2, Brotli, Bzip2, Copy, Deflate, Delta, LZ4, LZMA, LZMA2, PPC, SPARC and Zstandard methods.
2525
* Implements the `fs.FS` interface so you can treat an opened 7-zip archive like a filesystem.
2626

2727
More examples of 7-zip archives are needed to test all of the different combinations/algorithms possible.

internal/bra/arm.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,23 @@ func (c *arm) Convert(b []byte, encoding bool) int {
1919
}
2020

2121
if c.ip == 0 {
22-
c.ip += armAlignment
22+
c.ip = armAlignment
2323
}
2424

2525
var i int
2626

2727
for i = 0; i < len(b) & ^(armAlignment-1); i += armAlignment {
2828
v := binary.LittleEndian.Uint32(b[i:])
2929

30-
c.ip += uint32(armAlignment)
30+
c.ip += armAlignment
3131

3232
if b[i+3] == 0xeb {
33-
v <<= 2
34-
3533
if encoding {
36-
v += c.ip
34+
v += c.ip >> 2
3735
} else {
38-
v -= c.ip
36+
v -= c.ip >> 2
3937
}
4038

41-
v >>= 2
4239
v &= 0x00ffffff
4340
v |= 0xeb000000
4441
}

internal/bra/arm64.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package bra
2+
3+
import (
4+
"encoding/binary"
5+
"io"
6+
)
7+
8+
const arm64Alignment = 4
9+
10+
type arm64 struct {
11+
ip uint32
12+
}
13+
14+
func (c *arm64) Size() int { return arm64Alignment }
15+
16+
func (c *arm64) Convert(b []byte, encoding bool) int {
17+
if len(b) < c.Size() {
18+
return 0
19+
}
20+
21+
var i int
22+
23+
for i = 0; i < len(b) & ^(arm64Alignment-1); i, c.ip = i+arm64Alignment, c.ip+arm64Alignment {
24+
v := binary.LittleEndian.Uint32(b[i:])
25+
26+
if (v-0x94000000)&0xfc000000 == 0 {
27+
if encoding {
28+
v += c.ip >> 2
29+
} else {
30+
v -= c.ip >> 2
31+
}
32+
33+
v &= 0x03ffffff
34+
v |= 0x94000000
35+
36+
binary.LittleEndian.PutUint32(b[i:], v)
37+
38+
continue
39+
}
40+
41+
v -= 0x90000000
42+
43+
if v&0x9f000000 == 0 {
44+
const (
45+
flag = uint32(1) << (24 - 4)
46+
mask = uint32(1)<<24 - flag<<1
47+
)
48+
49+
v += flag
50+
51+
if v&mask > 0 {
52+
continue
53+
}
54+
55+
z, ip := v&0xffffffe0|v>>26, (c.ip>>(12-3)) & ^uint32(7)
56+
57+
if encoding {
58+
z += ip
59+
} else {
60+
z -= ip
61+
}
62+
63+
v &= 0x1f
64+
v |= 0x90000000
65+
v |= z << 26
66+
v |= 0x00ffffe0 & ((z & (flag<<1 - 1)) - flag)
67+
68+
binary.LittleEndian.PutUint32(b[i:], v)
69+
}
70+
}
71+
72+
return i
73+
}
74+
75+
// NewARM64Reader returns a new ARM64 io.ReadCloser.
76+
func NewARM64Reader(_ []byte, _ uint64, readers []io.ReadCloser) (io.ReadCloser, error) {
77+
return newReader(readers, new(arm64))
78+
}

internal/bra/ppc.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ func (c *ppc) Convert(b []byte, encoding bool) int {
2020

2121
var i int
2222

23-
for i = 0; i < len(b) & ^(ppcAlignment-1); i += ppcAlignment {
23+
for i = 0; i < len(b) & ^(ppcAlignment-1); i, c.ip = i+ppcAlignment, c.ip+ppcAlignment {
2424
v := binary.BigEndian.Uint32(b[i:])
2525

2626
if b[i+0]&0xfc == 0x48 && b[i+3]&3 == 1 {
@@ -34,8 +34,6 @@ func (c *ppc) Convert(b []byte, encoding bool) int {
3434
v |= 0x48000000
3535
}
3636

37-
c.ip += uint32(ppcAlignment)
38-
3937
binary.BigEndian.PutUint32(b[i:], v)
4038
}
4139

internal/bra/sparc.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ func (c *sparc) Convert(b []byte, encoding bool) int {
2020

2121
var i int
2222

23-
for i = 0; i < len(b) & ^(sparcAlignment-1); i += sparcAlignment {
23+
for i = 0; i < len(b) & ^(sparcAlignment-1); i, c.ip = i+sparcAlignment, c.ip+sparcAlignment {
2424
v := binary.BigEndian.Uint32(b[i:])
2525

2626
if (b[i+0] == 0x40 && b[i+1]&0xc0 == 0) || (b[i+0] == 0x7f && b[i+1] >= 0xc0) {
27+
const flag = uint32(1) << 24
28+
2729
v <<= 2
2830

2931
if encoding {
@@ -33,14 +35,12 @@ func (c *sparc) Convert(b []byte, encoding bool) int {
3335
}
3436

3537
v &= 0x01ffffff
36-
v -= uint32(1) << 24
38+
v -= flag
3739
v ^= 0xff000000
3840
v >>= 2
3941
v |= 0x40000000
4042
}
4143

42-
c.ip += uint32(sparcAlignment)
43-
4444
binary.BigEndian.PutUint32(b[i:], v)
4545
}
4646

reader_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,10 @@ func TestOpenReader(t *testing.T) {
197197
file: "COMPRESS-492.7z",
198198
err: sevenzip.ErrMissingUnpackInfo,
199199
},
200+
{
201+
name: "arm64",
202+
file: "arm64.7z",
203+
},
200204
}
201205

202206
for _, table := range tables {
@@ -657,3 +661,7 @@ func BenchmarkARM(b *testing.B) {
657661
func BenchmarkSPARC(b *testing.B) {
658662
benchmarkArchive(b, "sparc.7z", "", true)
659663
}
664+
665+
func BenchmarkARM64(b *testing.B) {
666+
benchmarkArchive(b, "arm64.7z", "", true)
667+
}

register.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ func init() {
6969
RegisterDecompressor([]byte{0x04, 0xf7, 0x11, 0x04}, Decompressor(lz4.NewReader))
7070
// AES-CBC-256 & SHA-256
7171
RegisterDecompressor([]byte{0x06, 0xf1, 0x07, 0x01}, Decompressor(aes7z.NewReader))
72+
// ARM64
73+
RegisterDecompressor([]byte{0x0a}, Decompressor(bra.NewARM64Reader))
7274
// LZMA2
7375
RegisterDecompressor([]byte{0x21}, Decompressor(lzma2.NewReader))
7476
}

testdata/arm64.7z

48.7 KB
Binary file not shown.

0 commit comments

Comments
 (0)