1// Copyright 2014-2017 Ulrich Kunitz. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package xz 6 7import ( 8 "errors" 9 "fmt" 10 "io" 11 12 "github.com/ulikunitz/xz/lzma" 13) 14 15// LZMA filter constants. 16const ( 17 lzmaFilterID = 0x21 18 lzmaFilterLen = 3 19) 20 21// lzmaFilter declares the LZMA2 filter information stored in an xz 22// block header. 23type lzmaFilter struct { 24 dictCap int64 25} 26 27// String returns a representation of the LZMA filter. 28func (f lzmaFilter) String() string { 29 return fmt.Sprintf("LZMA dict cap %#x", f.dictCap) 30} 31 32// id returns the ID for the LZMA2 filter. 33func (f lzmaFilter) id() uint64 { return lzmaFilterID } 34 35// MarshalBinary converts the lzmaFilter in its encoded representation. 36func (f lzmaFilter) MarshalBinary() (data []byte, err error) { 37 c := lzma.EncodeDictCap(f.dictCap) 38 return []byte{lzmaFilterID, 1, c}, nil 39} 40 41// UnmarshalBinary unmarshals the given data representation of the LZMA2 42// filter. 43func (f *lzmaFilter) UnmarshalBinary(data []byte) error { 44 if len(data) != lzmaFilterLen { 45 return errors.New("xz: data for LZMA2 filter has wrong length") 46 } 47 if data[0] != lzmaFilterID { 48 return errors.New("xz: wrong LZMA2 filter id") 49 } 50 if data[1] != 1 { 51 return errors.New("xz: wrong LZMA2 filter size") 52 } 53 dc, err := lzma.DecodeDictCap(data[2]) 54 if err != nil { 55 return errors.New("xz: wrong LZMA2 dictionary size property") 56 } 57 58 f.dictCap = dc 59 return nil 60} 61 62// reader creates a new reader for the LZMA2 filter. 63func (f lzmaFilter) reader(r io.Reader, c *ReaderConfig) (fr io.Reader, 64 err error) { 65 66 config := new(lzma.Reader2Config) 67 if c != nil { 68 config.DictCap = c.DictCap 69 } 70 dc := int(f.dictCap) 71 if dc < 1 { 72 return nil, errors.New("xz: LZMA2 filter parameter " + 73 "dictionary capacity overflow") 74 } 75 if dc > config.DictCap { 76 config.DictCap = dc 77 } 78 79 fr, err = config.NewReader2(r) 80 if err != nil { 81 return nil, err 82 } 83 return fr, nil 84} 85 86// writeCloser creates a io.WriteCloser for the LZMA2 filter. 87func (f lzmaFilter) writeCloser(w io.WriteCloser, c *WriterConfig, 88) (fw io.WriteCloser, err error) { 89 config := new(lzma.Writer2Config) 90 if c != nil { 91 *config = lzma.Writer2Config{ 92 Properties: c.Properties, 93 DictCap: c.DictCap, 94 BufSize: c.BufSize, 95 Matcher: c.Matcher, 96 } 97 } 98 99 dc := int(f.dictCap) 100 if dc < 1 { 101 return nil, errors.New("xz: LZMA2 filter parameter " + 102 "dictionary capacity overflow") 103 } 104 if dc > config.DictCap { 105 config.DictCap = dc 106 } 107 108 fw, err = config.NewWriter2(w) 109 if err != nil { 110 return nil, err 111 } 112 return fw, nil 113} 114 115// last returns true, because an LZMA2 filter must be the last filter in 116// the filter list. 117func (f lzmaFilter) last() bool { return true } 118