You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
wikeyun/vendor/github.com/saracen/go7z/register.go

130 lines
3.5 KiB

package go7z
import (
"bytes"
"compress/bzip2"
"compress/flate"
"encoding/binary"
"io"
"sync"
"github.com/saracen/go7z/filters"
"github.com/ulikunitz/xz/lzma"
)
// Decompressor is a handler function called when a registered decompressor is
// initialized.
type Decompressor func(r []io.Reader, options []byte, unpackSize uint64, ro *ReaderOptions) (io.Reader, error)
var (
decompressors sync.Map // map[uint32]Decompressor
)
func init() {
// copy
RegisterDecompressor(0x00, Decompressor(func(r []io.Reader, options []byte, unpackSize uint64, ro *ReaderOptions) (io.Reader, error) {
if len(r) != 1 {
return nil, ErrNotSupported
}
return r[0], nil
}))
// delta
RegisterDecompressor(0x03, Decompressor(func(r []io.Reader, options []byte, unpackSize uint64, ro *ReaderOptions) (io.Reader, error) {
if len(r) != 1 || len(options) == 0 || len(options) > 1 {
return nil, ErrNotSupported
}
return filters.NewDeltaDecoder(r[0], uint(options[0])+1, int64(unpackSize))
}))
// lzma
RegisterDecompressor(0x030101, Decompressor(func(r []io.Reader, options []byte, unpackSize uint64, ro *ReaderOptions) (io.Reader, error) {
if len(r) != 1 {
return nil, ErrNotSupported
}
// We can't set options in the lzma decoder library, so instead we add
// a fake header
header := bytes.NewBuffer(options)
binary.Write(header, binary.LittleEndian, unpackSize)
return lzma.NewReader(io.MultiReader(header, r[0]))
}))
// lzma2
RegisterDecompressor(0x21, Decompressor(func(r []io.Reader, options []byte, unpackSize uint64, ro *ReaderOptions) (io.Reader, error) {
if len(r) != 1 {
return nil, ErrNotSupported
}
config := lzma.Reader2Config{}
if len(options) > 0 {
config.DictCap = int(2 | (options[0] & 1))
config.DictCap <<= (options[0] >> 1) + 11
}
return config.NewReader2(r[0])
}))
// bcj2
RegisterDecompressor(0x303011b, Decompressor(func(r []io.Reader, options []byte, unpackSize uint64, ro *ReaderOptions) (io.Reader, error) {
if len(r) != 4 {
return nil, ErrNotSupported
}
return filters.NewBCJ2Decoder(r[0], r[1], r[2], r[3], int64(unpackSize))
}))
// deflate
RegisterDecompressor(0x40108, Decompressor(func(r []io.Reader, options []byte, unpackSize uint64, ro *ReaderOptions) (io.Reader, error) {
if len(r) != 1 {
return nil, ErrNotSupported
}
return flate.NewReader(r[0]), nil
}))
// bzip2
RegisterDecompressor(0x40202, Decompressor(func(r []io.Reader, options []byte, unpackSize uint64, ro *ReaderOptions) (io.Reader, error) {
if len(r) != 1 {
return nil, ErrNotSupported
}
return bzip2.NewReader(r[0]), nil
}))
// AES
RegisterDecompressor(0x6f10701, Decompressor(func(r []io.Reader, options []byte, unpackSize uint64, ro *ReaderOptions) (io.Reader, error) {
if len(r) != 1 {
return nil, ErrNotSupported
}
if len(options) < 2 {
return nil, ErrNotSupported
}
saltSize := ((options[0] >> 7) & 1) + (options[1] >> 4)
ivSize := ((options[0] >> 6) & 1) + (options[1] & 0x0F)
power := int(options[0]) & 0x3f
options = options[2:]
salt := options[:saltSize]
iv := options[saltSize : saltSize+ivSize]
return filters.NewAESDecrypter(r[0], power, salt, iv, ro.Password())
}))
}
// RegisterDecompressor registers a decompressor.
func RegisterDecompressor(method uint32, dcomp Decompressor) {
if _, dup := decompressors.LoadOrStore(method, dcomp); dup {
panic("decompressor already registered")
}
}
func decompressor(method uint32) Decompressor {
di, ok := decompressors.Load(method)
if !ok {
return nil
}
return di.(Decompressor)
}