From b30a88075fcf124ccd863b9c521ede593179a6e6 Mon Sep 17 00:00:00 2001 From: Matt Dainty Date: Fri, 29 Apr 2022 18:17:41 +0100 Subject: [PATCH] Add Delta decompressor --- README.md | 2 +- internal/delta/reader.go | 72 +++++++++++++++++++++++++++++++++++++++ reader_test.go | 4 +++ register.go | 3 ++ testdata/delta.7z | Bin 0 -> 36322 bytes 5 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 internal/delta/reader.go create mode 100644 testdata/delta.7z diff --git a/README.md b/README.md index 5c01cd4..19aebf8 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,6 @@ Current status: * Handles password-protected versions of both of the above (`7za a -mhc=on|off -mhe=on -ppassword test.7z ...`). * Handles archives split into multiple volumes, (`7za a -v100m test.7z ...`). * Validates CRC values as it parses the file. -* Supports BCJ2, Bzip2, Deflate, Copy, LZMA and LZMA2 methods. +* Supports BCJ2, Bzip2, Copy, Deflate, Delta, LZMA and LZMA2 methods. More examples of 7-zip archives are needed to test all of the different combinations/algorithms possible. diff --git a/internal/delta/reader.go b/internal/delta/reader.go new file mode 100644 index 0000000..7c332a5 --- /dev/null +++ b/internal/delta/reader.go @@ -0,0 +1,72 @@ +package delta + +import ( + "errors" + "io" +) + +const ( + stateSize = 256 +) + +type readCloser struct { + rc io.ReadCloser + state [stateSize]byte + delta int +} + +func (rc *readCloser) Close() (err error) { + if rc.rc != nil { + err = rc.rc.Close() + rc.rc = nil + } + return +} + +func (rc *readCloser) Read(p []byte) (int, error) { + if rc.rc == nil { + return 0, errors.New("delta: Read after Close") + } + + n, err := rc.rc.Read(p) + if err != nil { + return n, err + } + + var buffer [stateSize]byte + copy(buffer[:], rc.state[:rc.delta]) + + var j int + for i := 0; i < n; { + for j = 0; j < rc.delta && i < n; i++ { + p[i] = buffer[j] + p[i] + buffer[j] = p[i] + j++ + } + } + + if j == rc.delta { + j = 0 + } + + copy(rc.state[:], buffer[j:rc.delta]) + copy(rc.state[rc.delta-j:], buffer[:j]) + + return n, nil +} + +// NewReader returns a new Delta io.ReadCloser. +func NewReader(p []byte, _ uint64, readers []io.ReadCloser) (io.ReadCloser, error) { + if len(readers) != 1 { + return nil, errors.New("delta: need exactly one reader") + } + + if len(p) != 1 { + return nil, errors.New("delta: not enough properties") + } + + return &readCloser{ + rc: readers[0], + delta: int(p[0] + 1), + }, nil +} diff --git a/reader_test.go b/reader_test.go index 288ceac..d99c830 100644 --- a/reader_test.go +++ b/reader_test.go @@ -125,6 +125,10 @@ func BenchmarkDeflate(b *testing.B) { benchmarkArchive("deflate.7z", b) } +func BenchmarkDelta(b *testing.B) { + benchmarkArchive("delta.7z", b) +} + func BenchmarkLZMA(b *testing.B) { benchmarkArchive("lzma.7z", b) } diff --git a/register.go b/register.go index b940464..f82a3c0 100644 --- a/register.go +++ b/register.go @@ -9,6 +9,7 @@ import ( "github.com/bodgit/sevenzip/internal/bcj2" "github.com/bodgit/sevenzip/internal/bzip2" "github.com/bodgit/sevenzip/internal/deflate" + "github.com/bodgit/sevenzip/internal/delta" "github.com/bodgit/sevenzip/internal/lzma" "github.com/bodgit/sevenzip/internal/lzma2" ) @@ -30,6 +31,8 @@ func init() { } return readers[0], nil })) + // Delta + RegisterDecompressor([]byte{0x03}, Decompressor(delta.NewReader)) // LZMA RegisterDecompressor([]byte{0x03, 0x01, 0x01}, Decompressor(lzma.NewReader)) // BCJ2 diff --git a/testdata/delta.7z b/testdata/delta.7z new file mode 100644 index 0000000000000000000000000000000000000000..d5152b2088b61070f49a4c0a9a29befbf1b370f0 GIT binary patch literal 36322 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

HP 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 emA*s$eSNiWRUWBS#=duar0>Mfzw?7i