forked from ycl2045/rardecode
-
Notifications
You must be signed in to change notification settings - Fork 0
/
decode_reader.go
297 lines (272 loc) · 7.07 KB
/
decode_reader.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
package rardecode
import (
"bufio"
"errors"
"io"
)
const (
minWindowSize = 0x40000
maxQueuedFilters = 8192
)
var (
errTooManyFilters = errors.New("rardecode: too many filters")
errInvalidFilter = errors.New("rardecode: invalid filter")
)
// filter functions take a byte slice, the current output offset and
// returns transformed data.
type filter func(b []byte, offset int64) ([]byte, error)
// filterBlock is a block of data to be processed by a filter.
type filterBlock struct {
length int // length of block
offset int // bytes to be read before start of block
reset bool // drop all existing queued filters
filter filter // filter function
}
// decoder is the interface for decoding compressed data
type decoder interface {
init(r io.ByteReader, reset bool) error // initialize decoder for current file
fill(w *window) ([]*filterBlock, error) // fill window with decoded data, returning any filters
}
// window is a sliding window buffer.
type window struct {
buf []byte
mask int // buf length mask
r int // index in buf for reads (beginning)
w int // index in buf for writes (end)
l int // length of bytes to be processed by copyBytes
o int // offset of bytes to be processed by copyBytes
}
// buffered returns the number of bytes yet to be read from window
func (w *window) buffered() int { return (w.w - w.r) & w.mask }
// available returns the number of bytes that can be written before the window is full
func (w *window) available() int { return (w.r - w.w - 1) & w.mask }
func (w *window) reset(log2size uint, clear bool) {
size := 1 << log2size
if size < minWindowSize {
size = minWindowSize
}
if size > len(w.buf) {
b := make([]byte, size)
if clear {
w.w = 0
} else if len(w.buf) > 0 {
n := copy(b, w.buf[w.w:])
n += copy(b[n:], w.buf[:w.w])
w.w = n
}
w.buf = b
w.mask = size - 1
} else if clear {
for i := range w.buf {
w.buf[i] = 0
}
w.w = 0
}
w.r = w.w
}
// writeByte writes c to the end of the window
func (w *window) writeByte(c byte) {
w.buf[w.w] = c
w.w = (w.w + 1) & w.mask
}
// copyBytes copies len bytes at off distance from the end
// to the end of the window.
func (w *window) copyBytes(len, off int) {
len &= w.mask
n := w.available()
if len > n {
// if there is not enough space availaible we copy
// as much as we can and save the offset and length
// of the remaining data to be copied later.
w.l = len - n
w.o = off
len = n
}
i := (w.w - off) & w.mask
for ; len > 0; len-- {
w.buf[w.w] = w.buf[i]
w.w = (w.w + 1) & w.mask
i = (i + 1) & w.mask
}
}
// read reads bytes from the beginning of the window into p
func (w *window) read(p []byte) (n int) {
if w.r > w.w {
n = copy(p, w.buf[w.r:])
w.r = (w.r + n) & w.mask
p = p[n:]
}
if w.r < w.w {
l := copy(p, w.buf[w.r:w.w])
w.r += l
n += l
}
if w.l > 0 && n > 0 {
// if we have successfully read data, copy any
// leftover data from a previous copyBytes.
l := w.l
w.l = 0
w.copyBytes(l, w.o)
}
return n
}
// decodeReader implements io.Reader for decoding compressed data in RAR archives.
type decodeReader struct {
win window // sliding window buffer used as decode dictionary
dec decoder // decoder being used to unpack file
r *bufio.Reader // reader for unprocessed file contents
tot int64 // total bytes read
buf []byte // filter input/output buffer
outbuf []byte // filter output not yet read
err error
filters []*filterBlock // list of filterBlock's, each with offset relative to previous in list
}
func (d *decodeReader) init(r io.Reader, dec decoder, winsize uint, reset bool) error {
if reset {
d.filters = nil
}
d.err = nil
d.outbuf = nil
d.tot = 0
d.win.reset(winsize, reset)
if d.r == nil {
d.r = bufio.NewReader(r)
} else {
d.r.Reset(r)
}
d.dec = dec
return d.dec.init(d.r, reset)
}
func (d *decodeReader) readErr() error {
err := d.err
d.err = nil
return err
}
// queueFilter adds a filterBlock to the end decodeReader's filters.
func (d *decodeReader) queueFilter(f *filterBlock) error {
if f.reset {
d.filters = nil
}
if len(d.filters) >= maxQueuedFilters {
return errTooManyFilters
}
// offset & length must be < window size
f.offset &= d.win.mask
f.length &= d.win.mask
// make offset relative to previous filter in list
for _, fb := range d.filters {
if f.offset < fb.offset {
// filter block must not start before previous filter
return errInvalidFilter
}
f.offset -= fb.offset
}
d.filters = append(d.filters, f)
return nil
}
// processFilters processes any filters valid at the current read index
// and stores the output in outbuf.
func (d *decodeReader) processFilters() (err error) {
f := d.filters[0]
if f.offset > 0 {
return nil
}
d.filters = d.filters[1:]
if d.win.buffered() < f.length {
// fill() didn't return enough bytes
err = d.readErr()
if err == nil || err == io.EOF {
return errInvalidFilter
}
return err
}
if cap(d.buf) < f.length {
d.buf = make([]byte, f.length)
}
d.outbuf = d.buf[:f.length]
n := d.win.read(d.outbuf)
for {
// run filter passing buffer and total bytes read so far
d.outbuf, err = f.filter(d.outbuf, d.tot)
if err != nil {
return err
}
if cap(d.outbuf) > cap(d.buf) {
// Filter returned a bigger buffer, save it for future filters.
d.buf = d.outbuf
}
if len(d.filters) == 0 {
return nil
}
f = d.filters[0]
if f.offset != 0 {
// next filter not at current offset
f.offset -= n
return nil
}
if f.length != len(d.outbuf) {
return errInvalidFilter
}
d.filters = d.filters[1:]
if cap(d.outbuf) < cap(d.buf) {
// Filter returned a smaller buffer. Copy it back to the saved buffer
// so the next filter can make use of the larger buffer if needed.
d.outbuf = append(d.buf[:0], d.outbuf...)
}
}
}
// fill fills the decodeReader's window
func (d *decodeReader) fill() {
if d.err != nil {
return
}
var fl []*filterBlock
fl, d.err = d.dec.fill(&d.win) // fill window using decoder
for _, f := range fl {
err := d.queueFilter(f)
if err != nil {
d.err = err
return
}
}
}
// Read decodes data and stores it in p.
func (d *decodeReader) Read(p []byte) (n int, err error) {
if len(d.outbuf) == 0 {
// no filter output, see if we need to create more
if d.win.buffered() == 0 {
// fill empty window
d.fill()
if d.win.buffered() == 0 {
return 0, d.readErr()
}
} else if len(d.filters) > 0 {
f := d.filters[0]
if f.offset == 0 && f.length > d.win.buffered() {
d.fill() // filter at current offset needs more data
}
}
if len(d.filters) > 0 {
if err := d.processFilters(); err != nil {
return 0, err
}
}
}
if len(d.outbuf) > 0 {
// copy filter output into p
n = copy(p, d.outbuf)
d.outbuf = d.outbuf[n:]
} else if len(d.filters) > 0 {
f := d.filters[0]
if f.offset < len(p) {
// only read data up to beginning of next filter
p = p[:f.offset]
}
n = d.win.read(p) // read directly from window
f.offset -= n // adjust first filter offset by bytes just read
} else {
n = d.win.read(p) // read directly from window
}
d.tot += int64(n)
return n, nil
}