123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- 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
- }
|