package rardecode import ( "bytes" "errors" "io" ) const ( maxCodeSize = 0x10000 maxUniqueFilters = 1024 ) var ( // Errors marking the end of the decoding block and/or file errEndOfFile = errors.New("rardecode: end of file") errEndOfBlock = errors.New("rardecode: end of block") errEndOfBlockAndFile = errors.New("rardecode: end of block and file") ) // decoder29 implements the decoder interface for RAR 3.0 compression (unpack version 29) // Decode input is broken up into 1 or more blocks. The start of each block specifies // the decoding algorithm (ppm or lz) and optional data to initialize with. // Block length is not stored, it is determined only after decoding an end of file and/or // block marker in the data. type decoder29 struct { br *rarBitReader hdrRead bool // block header has been read isPPM bool // current block is PPM eof bool // at file eof fnum int // current filter number (index into filters) flen []int // filter block length history filters []v3Filter // list of current filters used by archive encoding lz *lz29Decoder // lz decoder ppm *ppm29Decoder // ppm decoder } func (d *decoder29) version() int { return decode29Ver } // init intializes the decoder for decoding a new file. func (d *decoder29) init(r byteReader, reset bool, size int64, ver int) { if d.br == nil { d.br = newRarBitReader(r) } else { d.br.reset(r) } d.eof = false if reset { d.initFilters() if d.lz != nil { d.lz.reset() } if d.ppm != nil { d.ppm.reset() } d.hdrRead = false } } func (d *decoder29) initFilters() { d.fnum = 0 d.flen = nil d.filters = nil } // readVMCode reads the raw bytes for the code/commands used in a vm filter func readVMCode(br *rarBitReader) ([]byte, error) { n, err := br.readUint32() if err != nil { return nil, err } if n > maxCodeSize || n == 0 { return nil, ErrInvalidFilter } buf := make([]byte, n) _, err = io.ReadFull(br, buf) if err != nil { return nil, err } var x byte for _, c := range buf[1:] { x ^= c } // simple xor checksum on data if x != buf[0] { return nil, ErrInvalidFilter } return buf, nil } func (d *decoder29) parseVMFilter(buf []byte) (*filterBlock, error) { flags := buf[0] br := newRarBitReader(bytes.NewReader(buf[1:])) fb := new(filterBlock) // Find the filter number which is an index into d.filters. // If filter number == len(d.filters) it is a new filter to be added. if flags&0x80 > 0 { n, err := br.readUint32() if err != nil { return nil, err } if n == 0 { d.initFilters() } else { n-- if n > maxUniqueFilters { return nil, ErrInvalidFilter } if int(n) > len(d.filters) { return nil, ErrInvalidFilter } } d.fnum = int(n) } // filter offset n, err := br.readUint32() if err != nil { return nil, err } if flags&0x40 > 0 { n += 258 } fb.offset = int(n) // filter length if d.fnum == len(d.flen) { d.flen = append(d.flen, 0) } if flags&0x20 > 0 { n, err = br.readUint32() if err != nil { return nil, err } //fb.length = int(n) d.flen[d.fnum] = int(n) } fb.length = d.flen[d.fnum] // initial register values r := make(map[int]uint32) if flags&0x10 > 0 { bits, err := br.readBits(vmRegs - 1) if err != nil { return nil, err } for i := 0; i < vmRegs-1; i++ { if bits&1 > 0 { r[i], err = br.readUint32() if err != nil { return nil, err } } bits >>= 1 } } // filter is new so read the code for it if d.fnum == len(d.filters) { code, err := readVMCode(br) if err != nil { return nil, err } f, err := getV3Filter(code) if err != nil { return nil, err } d.filters = append(d.filters, f) d.flen = append(d.flen, fb.length) } // read global data var g []byte if flags&0x08 > 0 { n, err := br.readUint32() if err != nil { return nil, err } if n > vmGlobalSize-vmFixedGlobalSize { return nil, ErrInvalidFilter } g = make([]byte, n) _, err = io.ReadFull(br, g) if err != nil { return nil, err } } // create filter function f := d.filters[d.fnum] fb.filter = func(buf []byte, offset int64) ([]byte, error) { return f(r, g, buf, offset) } return fb, nil } // readBlockHeader determines and initializes the current decoder for a new decode block. func (d *decoder29) readBlockHeader() error { d.br.alignByte() n, err := d.br.readBits(1) if err == nil { if n > 0 { d.isPPM = true if d.ppm == nil { d.ppm = newPPM29Decoder() } err = d.ppm.init(d.br) } else { d.isPPM = false if d.lz == nil { d.lz = new(lz29Decoder) } err = d.lz.init(d.br) } } if err == io.EOF { err = ErrDecoderOutOfData } d.hdrRead = true return err } func (d *decoder29) fill(dr *decodeReader) error { if d.eof { return io.EOF } for dr.notFull() { var err error if !d.hdrRead { if err = d.readBlockHeader(); err != nil { return err } } var b []byte if d.isPPM { b, err = d.ppm.fill(dr) } else { b, err = d.lz.fill(dr) } if len(b) > 0 && err == nil { // parse raw data for filter and add to list of filters var f *filterBlock f, err = d.parseVMFilter(b) if f != nil { err = dr.queueFilter(f) } } switch err { case nil: continue case errEndOfBlock: d.hdrRead = false continue case errEndOfFile: d.eof = true err = io.EOF case errEndOfBlockAndFile: d.eof = true d.hdrRead = false err = io.EOF case io.EOF: err = ErrDecoderOutOfData } return err } return nil }