]>
Commit | Line | Data |
---|---|---|
15c0b25d AP |
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 | ||
5 | package xz | |
6 | ||
7 | import ( | |
8 | "errors" | |
9 | "fmt" | |
10 | "io" | |
11 | ||
12 | "github.com/ulikunitz/xz/lzma" | |
13 | ) | |
14 | ||
15 | // LZMA filter constants. | |
16 | const ( | |
17 | lzmaFilterID = 0x21 | |
18 | lzmaFilterLen = 3 | |
19 | ) | |
20 | ||
21 | // lzmaFilter declares the LZMA2 filter information stored in an xz | |
22 | // block header. | |
23 | type lzmaFilter struct { | |
24 | dictCap int64 | |
25 | } | |
26 | ||
27 | // String returns a representation of the LZMA filter. | |
28 | func (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. | |
33 | func (f lzmaFilter) id() uint64 { return lzmaFilterID } | |
34 | ||
35 | // MarshalBinary converts the lzmaFilter in its encoded representation. | |
36 | func (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. | |
43 | func (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. | |
63 | func (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. | |
87 | func (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. | |
117 | func (f lzmaFilter) last() bool { return true } |