-
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
package rardecode
import (
"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
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.ByteReader, 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)
d.dec = dec
return d.dec.init(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
}