diff options
Diffstat (limited to 'vendor/github.com/ulikunitz/xz/lzma/reader2.go')
-rw-r--r-- | vendor/github.com/ulikunitz/xz/lzma/reader2.go | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/vendor/github.com/ulikunitz/xz/lzma/reader2.go b/vendor/github.com/ulikunitz/xz/lzma/reader2.go new file mode 100644 index 0000000..a55cfaa --- /dev/null +++ b/vendor/github.com/ulikunitz/xz/lzma/reader2.go | |||
@@ -0,0 +1,232 @@ | |||
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 lzma | ||
6 | |||
7 | import ( | ||
8 | "errors" | ||
9 | "io" | ||
10 | |||
11 | "github.com/ulikunitz/xz/internal/xlog" | ||
12 | ) | ||
13 | |||
14 | // Reader2Config stores the parameters for the LZMA2 reader. | ||
15 | // format. | ||
16 | type Reader2Config struct { | ||
17 | DictCap int | ||
18 | } | ||
19 | |||
20 | // fill converts the zero values of the configuration to the default values. | ||
21 | func (c *Reader2Config) fill() { | ||
22 | if c.DictCap == 0 { | ||
23 | c.DictCap = 8 * 1024 * 1024 | ||
24 | } | ||
25 | } | ||
26 | |||
27 | // Verify checks the reader configuration for errors. Zero configuration values | ||
28 | // will be replaced by default values. | ||
29 | func (c *Reader2Config) Verify() error { | ||
30 | c.fill() | ||
31 | if !(MinDictCap <= c.DictCap && int64(c.DictCap) <= MaxDictCap) { | ||
32 | return errors.New("lzma: dictionary capacity is out of range") | ||
33 | } | ||
34 | return nil | ||
35 | } | ||
36 | |||
37 | // Reader2 supports the reading of LZMA2 chunk sequences. Note that the | ||
38 | // first chunk should have a dictionary reset and the first compressed | ||
39 | // chunk a properties reset. The chunk sequence may not be terminated by | ||
40 | // an end-of-stream chunk. | ||
41 | type Reader2 struct { | ||
42 | r io.Reader | ||
43 | err error | ||
44 | |||
45 | dict *decoderDict | ||
46 | ur *uncompressedReader | ||
47 | decoder *decoder | ||
48 | chunkReader io.Reader | ||
49 | |||
50 | cstate chunkState | ||
51 | ctype chunkType | ||
52 | } | ||
53 | |||
54 | // NewReader2 creates a reader for an LZMA2 chunk sequence. | ||
55 | func NewReader2(lzma2 io.Reader) (r *Reader2, err error) { | ||
56 | return Reader2Config{}.NewReader2(lzma2) | ||
57 | } | ||
58 | |||
59 | // NewReader2 creates an LZMA2 reader using the given configuration. | ||
60 | func (c Reader2Config) NewReader2(lzma2 io.Reader) (r *Reader2, err error) { | ||
61 | if err = c.Verify(); err != nil { | ||
62 | return nil, err | ||
63 | } | ||
64 | r = &Reader2{r: lzma2, cstate: start} | ||
65 | r.dict, err = newDecoderDict(c.DictCap) | ||
66 | if err != nil { | ||
67 | return nil, err | ||
68 | } | ||
69 | if err = r.startChunk(); err != nil { | ||
70 | r.err = err | ||
71 | } | ||
72 | return r, nil | ||
73 | } | ||
74 | |||
75 | // uncompressed tests whether the chunk type specifies an uncompressed | ||
76 | // chunk. | ||
77 | func uncompressed(ctype chunkType) bool { | ||
78 | return ctype == cU || ctype == cUD | ||
79 | } | ||
80 | |||
81 | // startChunk parses a new chunk. | ||
82 | func (r *Reader2) startChunk() error { | ||
83 | r.chunkReader = nil | ||
84 | header, err := readChunkHeader(r.r) | ||
85 | if err != nil { | ||
86 | if err == io.EOF { | ||
87 | err = io.ErrUnexpectedEOF | ||
88 | } | ||
89 | return err | ||
90 | } | ||
91 | xlog.Debugf("chunk header %v", header) | ||
92 | if err = r.cstate.next(header.ctype); err != nil { | ||
93 | return err | ||
94 | } | ||
95 | if r.cstate == stop { | ||
96 | return io.EOF | ||
97 | } | ||
98 | if header.ctype == cUD || header.ctype == cLRND { | ||
99 | r.dict.Reset() | ||
100 | } | ||
101 | size := int64(header.uncompressed) + 1 | ||
102 | if uncompressed(header.ctype) { | ||
103 | if r.ur != nil { | ||
104 | r.ur.Reopen(r.r, size) | ||
105 | } else { | ||
106 | r.ur = newUncompressedReader(r.r, r.dict, size) | ||
107 | } | ||
108 | r.chunkReader = r.ur | ||
109 | return nil | ||
110 | } | ||
111 | br := ByteReader(io.LimitReader(r.r, int64(header.compressed)+1)) | ||
112 | if r.decoder == nil { | ||
113 | state := newState(header.props) | ||
114 | r.decoder, err = newDecoder(br, state, r.dict, size) | ||
115 | if err != nil { | ||
116 | return err | ||
117 | } | ||
118 | r.chunkReader = r.decoder | ||
119 | return nil | ||
120 | } | ||
121 | switch header.ctype { | ||
122 | case cLR: | ||
123 | r.decoder.State.Reset() | ||
124 | case cLRN, cLRND: | ||
125 | r.decoder.State = newState(header.props) | ||
126 | } | ||
127 | err = r.decoder.Reopen(br, size) | ||
128 | if err != nil { | ||
129 | return err | ||
130 | } | ||
131 | r.chunkReader = r.decoder | ||
132 | return nil | ||
133 | } | ||
134 | |||
135 | // Read reads data from the LZMA2 chunk sequence. | ||
136 | func (r *Reader2) Read(p []byte) (n int, err error) { | ||
137 | if r.err != nil { | ||
138 | return 0, r.err | ||
139 | } | ||
140 | for n < len(p) { | ||
141 | var k int | ||
142 | k, err = r.chunkReader.Read(p[n:]) | ||
143 | n += k | ||
144 | if err != nil { | ||
145 | if err == io.EOF { | ||
146 | err = r.startChunk() | ||
147 | if err == nil { | ||
148 | continue | ||
149 | } | ||
150 | } | ||
151 | r.err = err | ||
152 | return n, err | ||
153 | } | ||
154 | if k == 0 { | ||
155 | r.err = errors.New("lzma: Reader2 doesn't get data") | ||
156 | return n, r.err | ||
157 | } | ||
158 | } | ||
159 | return n, nil | ||
160 | } | ||
161 | |||
162 | // EOS returns whether the LZMA2 stream has been terminated by an | ||
163 | // end-of-stream chunk. | ||
164 | func (r *Reader2) EOS() bool { | ||
165 | return r.cstate == stop | ||
166 | } | ||
167 | |||
168 | // uncompressedReader is used to read uncompressed chunks. | ||
169 | type uncompressedReader struct { | ||
170 | lr io.LimitedReader | ||
171 | Dict *decoderDict | ||
172 | eof bool | ||
173 | err error | ||
174 | } | ||
175 | |||
176 | // newUncompressedReader initializes a new uncompressedReader. | ||
177 | func newUncompressedReader(r io.Reader, dict *decoderDict, size int64) *uncompressedReader { | ||
178 | ur := &uncompressedReader{ | ||
179 | lr: io.LimitedReader{R: r, N: size}, | ||
180 | Dict: dict, | ||
181 | } | ||
182 | return ur | ||
183 | } | ||
184 | |||
185 | // Reopen reinitializes an uncompressed reader. | ||
186 | func (ur *uncompressedReader) Reopen(r io.Reader, size int64) { | ||
187 | ur.err = nil | ||
188 | ur.eof = false | ||
189 | ur.lr = io.LimitedReader{R: r, N: size} | ||
190 | } | ||
191 | |||
192 | // fill reads uncompressed data into the dictionary. | ||
193 | func (ur *uncompressedReader) fill() error { | ||
194 | if !ur.eof { | ||
195 | n, err := io.CopyN(ur.Dict, &ur.lr, int64(ur.Dict.Available())) | ||
196 | if err != io.EOF { | ||
197 | return err | ||
198 | } | ||
199 | ur.eof = true | ||
200 | if n > 0 { | ||
201 | return nil | ||
202 | } | ||
203 | } | ||
204 | if ur.lr.N != 0 { | ||
205 | return io.ErrUnexpectedEOF | ||
206 | } | ||
207 | return io.EOF | ||
208 | } | ||
209 | |||
210 | // Read reads uncompressed data from the limited reader. | ||
211 | func (ur *uncompressedReader) Read(p []byte) (n int, err error) { | ||
212 | if ur.err != nil { | ||
213 | return 0, ur.err | ||
214 | } | ||
215 | for { | ||
216 | var k int | ||
217 | k, err = ur.Dict.Read(p[n:]) | ||
218 | n += k | ||
219 | if n >= len(p) { | ||
220 | return n, nil | ||
221 | } | ||
222 | if err != nil { | ||
223 | break | ||
224 | } | ||
225 | err = ur.fill() | ||
226 | if err != nil { | ||
227 | break | ||
228 | } | ||
229 | } | ||
230 | ur.err = err | ||
231 | return n, err | ||
232 | } | ||