Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Current status:
* Handles archives split into multiple volumes, (`7za a -v100m test.7z ...`).
* Handles self-extracting archives, (`7za a -sfx archive.exe ...`).
* Validates CRC values as it parses the file.
* Supports ARM, BCJ, BCJ2, Brotli, Bzip2, Copy, Deflate, Delta, LZ4, LZMA, LZMA2, PPC, SPARC and Zstandard methods.
* Supports ARM, ARM64, BCJ, BCJ2, Brotli, Bzip2, Copy, Deflate, Delta, LZ4, LZMA, LZMA2, PPC, SPARC and Zstandard methods.
* Implements the `fs.FS` interface so you can treat an opened 7-zip archive like a filesystem.

More examples of 7-zip archives are needed to test all of the different combinations/algorithms possible.
Expand Down
11 changes: 4 additions & 7 deletions internal/bra/arm.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,23 @@ func (c *arm) Convert(b []byte, encoding bool) int {
}

if c.ip == 0 {
c.ip += armAlignment
c.ip = armAlignment
}

var i int

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

c.ip += uint32(armAlignment)
c.ip += armAlignment

if b[i+3] == 0xeb {
v <<= 2

if encoding {
v += c.ip
v += c.ip >> 2
} else {
v -= c.ip
v -= c.ip >> 2
}

v >>= 2
v &= 0x00ffffff
v |= 0xeb000000
}
Expand Down
78 changes: 78 additions & 0 deletions internal/bra/arm64.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package bra

import (
"encoding/binary"
"io"
)

const arm64Alignment = 4

type arm64 struct {
ip uint32
}

func (c *arm64) Size() int { return arm64Alignment }

func (c *arm64) Convert(b []byte, encoding bool) int {
if len(b) < c.Size() {
return 0
}

var i int

for i = 0; i < len(b) & ^(arm64Alignment-1); i, c.ip = i+arm64Alignment, c.ip+arm64Alignment {
v := binary.LittleEndian.Uint32(b[i:])

if (v-0x94000000)&0xfc000000 == 0 {
if encoding {
v += c.ip >> 2
} else {
v -= c.ip >> 2
}

v &= 0x03ffffff
v |= 0x94000000

binary.LittleEndian.PutUint32(b[i:], v)

continue
}

v -= 0x90000000

if v&0x9f000000 == 0 {
const (
flag = uint32(1) << (24 - 4)
mask = uint32(1)<<24 - flag<<1
)

v += flag

if v&mask > 0 {
continue
}

z, ip := v&0xffffffe0|v>>26, (c.ip>>(12-3)) & ^uint32(7)

if encoding {
z += ip
} else {
z -= ip
}

v &= 0x1f
v |= 0x90000000
v |= z << 26
v |= 0x00ffffe0 & ((z & (flag<<1 - 1)) - flag)

binary.LittleEndian.PutUint32(b[i:], v)
}
}

return i
}

// NewARM64Reader returns a new ARM64 io.ReadCloser.
func NewARM64Reader(_ []byte, _ uint64, readers []io.ReadCloser) (io.ReadCloser, error) {
return newReader(readers, new(arm64))
}
4 changes: 1 addition & 3 deletions internal/bra/ppc.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func (c *ppc) Convert(b []byte, encoding bool) int {

var i int

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

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

c.ip += uint32(ppcAlignment)

binary.BigEndian.PutUint32(b[i:], v)
}

Expand Down
8 changes: 4 additions & 4 deletions internal/bra/sparc.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ func (c *sparc) Convert(b []byte, encoding bool) int {

var i int

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

if (b[i+0] == 0x40 && b[i+1]&0xc0 == 0) || (b[i+0] == 0x7f && b[i+1] >= 0xc0) {
const flag = uint32(1) << 24

v <<= 2

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

v &= 0x01ffffff
v -= uint32(1) << 24
v -= flag
v ^= 0xff000000
v >>= 2
v |= 0x40000000
}

c.ip += uint32(sparcAlignment)

binary.BigEndian.PutUint32(b[i:], v)
}

Expand Down
8 changes: 8 additions & 0 deletions reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ func TestOpenReader(t *testing.T) {
file: "COMPRESS-492.7z",
err: sevenzip.ErrMissingUnpackInfo,
},
{
name: "arm64",
file: "arm64.7z",
},
}

for _, table := range tables {
Expand Down Expand Up @@ -657,3 +661,7 @@ func BenchmarkARM(b *testing.B) {
func BenchmarkSPARC(b *testing.B) {
benchmarkArchive(b, "sparc.7z", "", true)
}

func BenchmarkARM64(b *testing.B) {
benchmarkArchive(b, "arm64.7z", "", true)
}
2 changes: 2 additions & 0 deletions register.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ func init() {
RegisterDecompressor([]byte{0x04, 0xf7, 0x11, 0x04}, Decompressor(lz4.NewReader))
// AES-CBC-256 & SHA-256
RegisterDecompressor([]byte{0x06, 0xf1, 0x07, 0x01}, Decompressor(aes7z.NewReader))
// ARM64
RegisterDecompressor([]byte{0x0a}, Decompressor(bra.NewARM64Reader))
// LZMA2
RegisterDecompressor([]byte{0x21}, Decompressor(lzma2.NewReader))
}
Expand Down
Binary file added testdata/arm64.7z
Binary file not shown.
Loading