From 89b19b06f67dde5d427a09a3d066ce97f32b62df Mon Sep 17 00:00:00 2001 From: Caleb Gardner Date: Tue, 10 Nov 2020 22:31:21 -0600 Subject: [PATCH] more work on decompression --- compressionoptions.go | 84 +++++++++++++++++++++++++++++++++++++++---- reader.go | 2 +- squashfs.go | 19 +++++++--- 3 files changed, 93 insertions(+), 12 deletions(-) diff --git a/compressionoptions.go b/compressionoptions.go index ca9d2e5..5f2d881 100644 --- a/compressionoptions.go +++ b/compressionoptions.go @@ -1,6 +1,9 @@ package squashfs -import "io" +import ( + "compress/zlib" + "io" +) const ( zlibCompression = 1 + iota @@ -13,10 +16,10 @@ const ( //TODO: implement decompress for each type of Options type CompressionOptions interface { - Decompress([]byte) []byte - DecompressCopy(*io.Reader, *io.Writer) - Compress([]byte) []byte - CompressCopy(*io.Reader, *io.Writer) + Decompress(*io.SectionReader, int) ([]byte, error) + DecompressCopy(*io.Reader, *io.Writer) (int, error) + Compress(*io.SectionReader, int) ([]byte, error) + CompressCopy(*io.Reader, *io.Writer) (int, error) } //TODO: Allow creation of options for compression. @@ -29,7 +32,7 @@ type gzipOptionsRaw struct { //GzipOptions is the options used for gzip compression. Backed by the raw format, with strategies parsed. type GzipOptions struct { - CompressionOptions + CompressionOptions //TODO: remove raw *gzipOptionsRaw DefaultStrategy bool FilteredStrategy bool @@ -45,11 +48,80 @@ func NewGzipOptions(raw gzipOptionsRaw) GzipOptions { } } +func (gzipOp *GzipOptions) Decompress(rdr *io.SectionReader, blockSize int) ([]byte, error) { + zlibRdr, err := zlib.NewReader(rdr) + defer zlibRdr.Close() + if err != nil { + return nil, err + } + out := make([]byte, 0) + var tmp []byte + read := blockSize + for read == blockSize { + tmp = make([]byte, blockSize) + read, err = zlibRdr.Read(tmp) + if err != io.EOF { + return nil, err + } + if read < blockSize { + tmp = tmp[:read] + } + out = append(out, tmp...) + } + return out, nil +} + +func (gzipOp *GzipOptions) DecompressCopy(rdr *io.Reader, wrt *io.Writer) (int, error) { + zlibRdr, err := zlib.NewReader(*rdr) + defer zlibRdr.Close() + if err != nil { + return 0, err + } + n, err := io.Copy(*wrt, zlibRdr) + return int(n), err +} + +func (gzipOp *GzipOptions) Compress(rdr *io.SectionReader, blockSize int) ([]byte, error) { + +} + +func (gzipOp *GzipOptions) CompressCopy(rdr *io.Reader, wrt *io.Writer) (int, error) { + zlibWrt, err := zlib.NewWriter(*wrt) //TODO: allow setting level + defer zlibWrt.Close() + if err != nil { + return 0, err + } + +} + type xzOptionsRaw struct { dictionarySize int32 executableFilters int32 } +type XzOptions struct { + CompressionOptions //TODO: Remove + raw *xzOptionsRaw + Execx86 bool + ExecPower bool + Execa64 bool + ExecArm bool + ExecArmThumb bool + ExecSparc bool +} + +func NewXzOption(raw xzOptionsRaw) XzOptions { + return XzOptions{ + raw: &raw, + Execx86: raw.executableFilters&0x1 == 0x1, + ExecPower: raw.executableFilters&0x2 == 0x2, + Execa64: raw.executableFilters&0x4 == 0x4, + ExecArm: raw.executableFilters&0x8 == 0x8, + ExecArmThumb: raw.executableFilters&0x10 == 0x10, + ExecSparc: raw.executableFilters&0x20 == 0x20, + } +} + type lz4OptionsRaw struct { version int32 flags int32 diff --git a/reader.go b/reader.go index c5d2161..f688d44 100644 --- a/reader.go +++ b/reader.go @@ -16,7 +16,7 @@ type Reader struct { offset int64 } -//NewReader creates a +//NewReader creates a squashfs.Reader from a io.ReaderAt func NewReader(baseReader io.ReaderAt) Reader { return Reader{ rdr: baseReader, diff --git a/squashfs.go b/squashfs.go index 77a8009..9729626 100644 --- a/squashfs.go +++ b/squashfs.go @@ -13,7 +13,7 @@ var ( //Squashfs is a squashfs backed by a ReadSeeker. type Squashfs struct { - rdr *io.SectionReader //underlying reader + rdr *Reader //underlying reader offset int super Superblock flags SuperblockFlags @@ -21,9 +21,10 @@ type Squashfs struct { } //NewSquashfs creates a new Squashfs backed by the given reader -func NewSquashfs(reader *io.SectionReader) (*Squashfs, error) { +func NewSquashfs(reader io.ReaderAt) (*Squashfs, error) { + rdr := NewReader(reader) var superblock Superblock - err := binary.Read(reader, binary.LittleEndian, &superblock) + err := binary.Read(&rdr, binary.LittleEndian, &superblock) if err != nil { return nil, err } @@ -36,12 +37,20 @@ func NewSquashfs(reader *io.SectionReader) (*Squashfs, error) { switch superblock.Compression { case zlibCompression: var gzipOpRaw gzipOptionsRaw - err = binary.Read(reader, binary.LittleEndian, &gzipOpRaw) + err = binary.Read(&rdr, binary.LittleEndian, &gzipOpRaw) if err != nil { return nil, err } compressionOptions = NewGzipOptions(gzipOpRaw) break + case xzCompression: + var xzOpRaw xzOptionsRaw + err = binary.Read(&rdr, binary.LittleEndian, xzOpRaw) + if err != nil { + return nil, err + } + compressionOptions = NewXzOption(xzOpRaw) + break default: //TODO: all the compression options return nil, errors.New("This type of compression isn't supported yet") @@ -49,7 +58,7 @@ func NewSquashfs(reader *io.SectionReader) (*Squashfs, error) { } //TODO: parse more info return &Squashfs{ - rdr: reader, + rdr: &rdr, super: superblock, flags: flags, compressionOptions: compressionOptions,