summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/nwaples
diff options
context:
space:
mode:
authorPhilippHomann <homann.philipp@googlemail.com>2020-06-05 22:47:39 +0200
committerGitHub <noreply@github.com>2020-06-05 16:47:39 -0400
commit684b7a999f6e3b928ad4ae993f92a6b83e0c4486 (patch)
tree64cfa190c811053f0d111ef73ac8e31858db0624 /vendor/github.com/nwaples
parent209b17c4e25fe72d2fdf46f412fc388bc274a516 (diff)
downloadgitea-684b7a999f6e3b928ad4ae993f92a6b83e0c4486.tar.gz
gitea-684b7a999f6e3b928ad4ae993f92a6b83e0c4486.zip
Dump: add output format tar and output to stdout (#10376)
* Dump: Use mholt/archive/v3 to support tar including many compressions Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Dump: Allow dump output to stdout Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Dump: Fixed bug present since #6677 where SessionConfig.Provider is never "file" Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Dump: never pack RepoRootPath, LFS.ContentPath and LogRootPath when they are below AppDataPath Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Dump: also dump LFS (fixes #10058) Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Dump: never dump CustomPath if CustomPath is a subdir of or equal to AppDataPath (fixes #10365) Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Use log.Info instead of fmt.Fprintf Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * import ordering * make fmt Co-authored-by: zeripath <art27@cantab.net> Co-authored-by: techknowlogick <techknowlogick@gitea.io> Co-authored-by: Matti R <matti@mdranta.net>
Diffstat (limited to 'vendor/github.com/nwaples')
-rw-r--r--vendor/github.com/nwaples/rardecode/LICENSE23
-rw-r--r--vendor/github.com/nwaples/rardecode/README.md4
-rw-r--r--vendor/github.com/nwaples/rardecode/archive.go306
-rw-r--r--vendor/github.com/nwaples/rardecode/archive15.go468
-rw-r--r--vendor/github.com/nwaples/rardecode/archive50.go475
-rw-r--r--vendor/github.com/nwaples/rardecode/bit_reader.go119
-rw-r--r--vendor/github.com/nwaples/rardecode/decode29.go264
-rw-r--r--vendor/github.com/nwaples/rardecode/decode29_lz.go247
-rw-r--r--vendor/github.com/nwaples/rardecode/decode29_ppm.go132
-rw-r--r--vendor/github.com/nwaples/rardecode/decode50.go294
-rw-r--r--vendor/github.com/nwaples/rardecode/decode_reader.go290
-rw-r--r--vendor/github.com/nwaples/rardecode/decrypt_reader.go126
-rw-r--r--vendor/github.com/nwaples/rardecode/filters.go416
-rw-r--r--vendor/github.com/nwaples/rardecode/go.mod1
-rw-r--r--vendor/github.com/nwaples/rardecode/huffman.go208
-rw-r--r--vendor/github.com/nwaples/rardecode/ppm_model.go1096
-rw-r--r--vendor/github.com/nwaples/rardecode/reader.go369
-rw-r--r--vendor/github.com/nwaples/rardecode/vm.go687
18 files changed, 5525 insertions, 0 deletions
diff --git a/vendor/github.com/nwaples/rardecode/LICENSE b/vendor/github.com/nwaples/rardecode/LICENSE
new file mode 100644
index 0000000000..0050f92dfc
--- /dev/null
+++ b/vendor/github.com/nwaples/rardecode/LICENSE
@@ -0,0 +1,23 @@
+Copyright (c) 2015, Nicholas Waples
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/nwaples/rardecode/README.md b/vendor/github.com/nwaples/rardecode/README.md
new file mode 100644
index 0000000000..513464c251
--- /dev/null
+++ b/vendor/github.com/nwaples/rardecode/README.md
@@ -0,0 +1,4 @@
+# rardecode
+[![GoDoc](https://godoc.org/github.com/nwaples/rardecode?status.svg)](https://godoc.org/github.com/nwaples/rardecode)
+
+A go package for reading RAR archives.
diff --git a/vendor/github.com/nwaples/rardecode/archive.go b/vendor/github.com/nwaples/rardecode/archive.go
new file mode 100644
index 0000000000..8929f12649
--- /dev/null
+++ b/vendor/github.com/nwaples/rardecode/archive.go
@@ -0,0 +1,306 @@
+package rardecode
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+const (
+ maxSfxSize = 0x100000 // maximum number of bytes to read when searching for RAR signature
+ sigPrefix = "Rar!\x1A\x07"
+
+ fileFmt15 = iota + 1 // Version 1.5 archive file format
+ fileFmt50 // Version 5.0 archive file format
+)
+
+var (
+ errNoSig = errors.New("rardecode: RAR signature not found")
+ errVerMismatch = errors.New("rardecode: volume version mistmatch")
+ errCorruptHeader = errors.New("rardecode: corrupt block header")
+ errCorruptFileHeader = errors.New("rardecode: corrupt file header")
+ errBadHeaderCrc = errors.New("rardecode: bad header crc")
+ errUnknownArc = errors.New("rardecode: unknown archive version")
+ errUnknownDecoder = errors.New("rardecode: unknown decoder version")
+ errUnsupportedDecoder = errors.New("rardecode: unsupported decoder version")
+ errArchiveContinues = errors.New("rardecode: archive continues in next volume")
+ errArchiveEnd = errors.New("rardecode: archive end reached")
+ errDecoderOutOfData = errors.New("rardecode: decoder expected more data than is in packed file")
+
+ reDigits = regexp.MustCompile(`\d+`)
+)
+
+type readBuf []byte
+
+func (b *readBuf) byte() byte {
+ v := (*b)[0]
+ *b = (*b)[1:]
+ return v
+}
+
+func (b *readBuf) uint16() uint16 {
+ v := uint16((*b)[0]) | uint16((*b)[1])<<8
+ *b = (*b)[2:]
+ return v
+}
+
+func (b *readBuf) uint32() uint32 {
+ v := uint32((*b)[0]) | uint32((*b)[1])<<8 | uint32((*b)[2])<<16 | uint32((*b)[3])<<24
+ *b = (*b)[4:]
+ return v
+}
+
+func (b *readBuf) bytes(n int) []byte {
+ v := (*b)[:n]
+ *b = (*b)[n:]
+ return v
+}
+
+func (b *readBuf) uvarint() uint64 {
+ var x uint64
+ var s uint
+ for i, n := range *b {
+ if n < 0x80 {
+ *b = (*b)[i+1:]
+ return x | uint64(n)<<s
+ }
+ x |= uint64(n&0x7f) << s
+ s += 7
+
+ }
+ // if we run out of bytes, just return 0
+ *b = (*b)[len(*b):]
+ return 0
+}
+
+// readFull wraps io.ReadFull to return io.ErrUnexpectedEOF instead
+// of io.EOF when 0 bytes are read.
+func readFull(r io.Reader, buf []byte) error {
+ _, err := io.ReadFull(r, buf)
+ if err == io.EOF {
+ return io.ErrUnexpectedEOF
+ }
+ return err
+}
+
+// findSig searches for the RAR signature and version at the beginning of a file.
+// It searches no more than maxSfxSize bytes.
+func findSig(br *bufio.Reader) (int, error) {
+ for n := 0; n <= maxSfxSize; {
+ b, err := br.ReadSlice(sigPrefix[0])
+ n += len(b)
+ if err == bufio.ErrBufferFull {
+ continue
+ } else if err != nil {
+ if err == io.EOF {
+ err = errNoSig
+ }
+ return 0, err
+ }
+
+ b, err = br.Peek(len(sigPrefix[1:]) + 2)
+ if err != nil {
+ if err == io.EOF {
+ err = errNoSig
+ }
+ return 0, err
+ }
+ if !bytes.HasPrefix(b, []byte(sigPrefix[1:])) {
+ continue
+ }
+ b = b[len(sigPrefix)-1:]
+
+ var ver int
+ switch {
+ case b[0] == 0:
+ ver = fileFmt15
+ case b[0] == 1 && b[1] == 0:
+ ver = fileFmt50
+ default:
+ continue
+ }
+ _, _ = br.ReadSlice('\x00')
+
+ return ver, nil
+ }
+ return 0, errNoSig
+}
+
+// volume extends a fileBlockReader to be used across multiple
+// files in a multi-volume archive
+type volume struct {
+ fileBlockReader
+ f *os.File // current file handle
+ br *bufio.Reader // buffered reader for current volume file
+ dir string // volume directory
+ file string // current volume file
+ num int // volume number
+ old bool // uses old naming scheme
+}
+
+// nextVolName updates name to the next filename in the archive.
+func (v *volume) nextVolName() {
+ if v.num == 0 {
+ // check file extensions
+ i := strings.LastIndex(v.file, ".")
+ if i < 0 {
+ // no file extension, add one
+ i = len(v.file)
+ v.file += ".rar"
+ } else {
+ ext := strings.ToLower(v.file[i+1:])
+ // replace with .rar for empty extensions & self extracting archives
+ if ext == "" || ext == "exe" || ext == "sfx" {
+ v.file = v.file[:i+1] + "rar"
+ }
+ }
+ if a, ok := v.fileBlockReader.(*archive15); ok {
+ v.old = a.old
+ }
+ // new naming scheme must have volume number in filename
+ if !v.old && reDigits.FindStringIndex(v.file) == nil {
+ v.old = true
+ }
+ // For old style naming if 2nd and 3rd character of file extension is not a digit replace
+ // with "00" and ignore any trailing characters.
+ if v.old && (len(v.file) < i+4 || v.file[i+2] < '0' || v.file[i+2] > '9' || v.file[i+3] < '0' || v.file[i+3] > '9') {
+ v.file = v.file[:i+2] + "00"
+ return
+ }
+ }
+ // new style volume naming
+ if !v.old {
+ // find all numbers in volume name
+ m := reDigits.FindAllStringIndex(v.file, -1)
+ if l := len(m); l > 1 {
+ // More than 1 match so assume name.part###of###.rar style.
+ // Take the last 2 matches where the first is the volume number.
+ m = m[l-2 : l]
+ if strings.Contains(v.file[m[0][1]:m[1][0]], ".") || !strings.Contains(v.file[:m[0][0]], ".") {
+ // Didn't match above style as volume had '.' between the two numbers or didnt have a '.'
+ // before the first match. Use the second number as volume number.
+ m = m[1:]
+ }
+ }
+ // extract and increment volume number
+ lo, hi := m[0][0], m[0][1]
+ n, err := strconv.Atoi(v.file[lo:hi])
+ if err != nil {
+ n = 0
+ } else {
+ n++
+ }
+ // volume number must use at least the same number of characters as previous volume
+ vol := fmt.Sprintf("%0"+fmt.Sprint(hi-lo)+"d", n)
+ v.file = v.file[:lo] + vol + v.file[hi:]
+ return
+ }
+ // old style volume naming
+ i := strings.LastIndex(v.file, ".")
+ // get file extension
+ b := []byte(v.file[i+1:])
+ // start incrementing volume number digits from rightmost
+ for j := 2; j >= 0; j-- {
+ if b[j] != '9' {
+ b[j]++
+ break
+ }
+ // digit overflow
+ if j == 0 {
+ // last character before '.'
+ b[j] = 'A'
+ } else {
+ // set to '0' and loop to next character
+ b[j] = '0'
+ }
+ }
+ v.file = v.file[:i+1] + string(b)
+}
+
+func (v *volume) next() (*fileBlockHeader, error) {
+ for {
+ var atEOF bool
+
+ h, err := v.fileBlockReader.next()
+ switch err {
+ case errArchiveContinues:
+ case io.EOF:
+ // Read all of volume without finding an end block. The only way
+ // to tell if the archive continues is to try to open the next volume.
+ atEOF = true
+ default:
+ return h, err
+ }
+
+ v.f.Close()
+ v.nextVolName()
+ v.f, err = os.Open(v.dir + v.file) // Open next volume file
+ if err != nil {
+ if atEOF && os.IsNotExist(err) {
+ // volume not found so assume that the archive has ended
+ return nil, io.EOF
+ }
+ return nil, err
+ }
+ v.num++
+ v.br.Reset(v.f)
+ ver, err := findSig(v.br)
+ if err != nil {
+ return nil, err
+ }
+ if v.version() != ver {
+ return nil, errVerMismatch
+ }
+ v.reset() // reset encryption
+ }
+}
+
+func (v *volume) Close() error {
+ // may be nil if os.Open fails in next()
+ if v.f == nil {
+ return nil
+ }
+ return v.f.Close()
+}
+
+func openVolume(name, password string) (*volume, error) {
+ var err error
+ v := new(volume)
+ v.dir, v.file = filepath.Split(name)
+ v.f, err = os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ v.br = bufio.NewReader(v.f)
+ v.fileBlockReader, err = newFileBlockReader(v.br, password)
+ if err != nil {
+ v.f.Close()
+ return nil, err
+ }
+ return v, nil
+}
+
+func newFileBlockReader(br *bufio.Reader, pass string) (fileBlockReader, error) {
+ runes := []rune(pass)
+ if len(runes) > maxPassword {
+ pass = string(runes[:maxPassword])
+ }
+ ver, err := findSig(br)
+ if err != nil {
+ return nil, err
+ }
+ switch ver {
+ case fileFmt15:
+ return newArchive15(br, pass), nil
+ case fileFmt50:
+ return newArchive50(br, pass), nil
+ }
+ return nil, errUnknownArc
+}
diff --git a/vendor/github.com/nwaples/rardecode/archive15.go b/vendor/github.com/nwaples/rardecode/archive15.go
new file mode 100644
index 0000000000..260176c06b
--- /dev/null
+++ b/vendor/github.com/nwaples/rardecode/archive15.go
@@ -0,0 +1,468 @@
+package rardecode
+
+import (
+ "bufio"
+ "bytes"
+ "crypto/sha1"
+ "errors"
+ "hash"
+ "hash/crc32"
+ "io"
+ "io/ioutil"
+ "strconv"
+ "strings"
+ "time"
+ "unicode/utf16"
+)
+
+const (
+ // block types
+ blockArc = 0x73
+ blockFile = 0x74
+ blockService = 0x7a
+ blockEnd = 0x7b
+
+ // block flags
+ blockHasData = 0x8000
+
+ // archive block flags
+ arcVolume = 0x0001
+ arcSolid = 0x0008
+ arcNewNaming = 0x0010
+ arcEncrypted = 0x0080
+
+ // file block flags
+ fileSplitBefore = 0x0001
+ fileSplitAfter = 0x0002
+ fileEncrypted = 0x0004
+ fileSolid = 0x0010
+ fileWindowMask = 0x00e0
+ fileLargeData = 0x0100
+ fileUnicode = 0x0200
+ fileSalt = 0x0400
+ fileVersion = 0x0800
+ fileExtTime = 0x1000
+
+ // end block flags
+ endArcNotLast = 0x0001
+
+ saltSize = 8 // size of salt for calculating AES keys
+ cacheSize30 = 4 // number of AES keys to cache
+ hashRounds = 0x40000
+)
+
+var (
+ errMultipleDecoders = errors.New("rardecode: multiple decoders in a single archive not supported")
+)
+
+type blockHeader15 struct {
+ htype byte // block header type
+ flags uint16
+ data readBuf // header data
+ dataSize int64 // size of extra block data
+}
+
+// fileHash32 implements fileChecksum for 32-bit hashes
+type fileHash32 struct {
+ hash.Hash32 // hash to write file contents to
+ sum uint32 // 32bit checksum for file
+}
+
+func (h *fileHash32) valid() bool {
+ return h.sum == h.Sum32()
+}
+
+// archive15 implements fileBlockReader for RAR 1.5 file format archives
+type archive15 struct {
+ byteReader // reader for current block data
+ v *bufio.Reader // reader for current archive volume
+ dec decoder // current decoder
+ decVer byte // current decoder version
+ multi bool // archive is multi-volume
+ old bool // archive uses old naming scheme
+ solid bool // archive is a solid archive
+ encrypted bool
+ pass []uint16 // password in UTF-16
+ checksum fileHash32 // file checksum
+ buf readBuf // temporary buffer
+ keyCache [cacheSize30]struct { // cache of previously calculated decryption keys
+ salt []byte
+ key []byte
+ iv []byte
+ }
+}
+
+// Calculates the key and iv for AES decryption given a password and salt.
+func calcAes30Params(pass []uint16, salt []byte) (key, iv []byte) {
+ p := make([]byte, 0, len(pass)*2+len(salt))
+ for _, v := range pass {
+ p = append(p, byte(v), byte(v>>8))
+ }
+ p = append(p, salt...)
+
+ hash := sha1.New()
+ iv = make([]byte, 16)
+ s := make([]byte, 0, hash.Size())
+ for i := 0; i < hashRounds; i++ {
+ hash.Write(p)
+ hash.Write([]byte{byte(i), byte(i >> 8), byte(i >> 16)})
+ if i%(hashRounds/16) == 0 {
+ s = hash.Sum(s[:0])
+ iv[i/(hashRounds/16)] = s[4*4+3]
+ }
+ }
+ key = hash.Sum(s[:0])
+ key = key[:16]
+
+ for k := key; len(k) >= 4; k = k[4:] {
+ k[0], k[1], k[2], k[3] = k[3], k[2], k[1], k[0]
+ }
+ return key, iv
+}
+
+// parseDosTime converts a 32bit DOS time value to time.Time
+func parseDosTime(t uint32) time.Time {
+ n := int(t)
+ sec := n & 0x1f << 1
+ min := n >> 5 & 0x3f
+ hr := n >> 11 & 0x1f
+ day := n >> 16 & 0x1f
+ mon := time.Month(n >> 21 & 0x0f)
+ yr := n>>25&0x7f + 1980
+ return time.Date(yr, mon, day, hr, min, sec, 0, time.Local)
+}
+
+// decodeName decodes a non-unicode filename from a file header.
+func decodeName(buf []byte) string {
+ i := bytes.IndexByte(buf, 0)
+ if i < 0 {
+ return string(buf) // filename is UTF-8
+ }
+
+ name := buf[:i]
+ encName := readBuf(buf[i+1:])
+ if len(encName) < 2 {
+ return "" // invalid encoding
+ }
+ highByte := uint16(encName.byte()) << 8
+ flags := encName.byte()
+ flagBits := 8
+ var wchars []uint16 // decoded characters are UTF-16
+ for len(wchars) < len(name) && len(encName) > 0 {
+ if flagBits == 0 {
+ flags = encName.byte()
+ flagBits = 8
+ if len(encName) == 0 {
+ break
+ }
+ }
+ switch flags >> 6 {
+ case 0:
+ wchars = append(wchars, uint16(encName.byte()))
+ case 1:
+ wchars = append(wchars, uint16(encName.byte())|highByte)
+ case 2:
+ if len(encName) < 2 {
+ break
+ }
+ wchars = append(wchars, encName.uint16())
+ case 3:
+ n := encName.byte()
+ b := name[len(wchars):]
+ if l := int(n&0x7f) + 2; l < len(b) {
+ b = b[:l]
+ }
+ if n&0x80 > 0 {
+ if len(encName) < 1 {
+ break
+ }
+ ec := encName.byte()
+ for _, c := range b {
+ wchars = append(wchars, uint16(c+ec)|highByte)
+ }
+ } else {
+ for _, c := range b {
+ wchars = append(wchars, uint16(c))
+ }
+ }
+ }
+ flags <<= 2
+ flagBits -= 2
+ }
+ return string(utf16.Decode(wchars))
+}
+
+// readExtTimes reads and parses the optional extra time field from the file header.
+func readExtTimes(f *fileBlockHeader, b *readBuf) {
+ if len(*b) < 2 {
+ return // invalid, not enough data
+ }
+ flags := b.uint16()
+
+ ts := []*time.Time{&f.ModificationTime, &f.CreationTime, &f.AccessTime}
+
+ for i, t := range ts {
+ n := flags >> uint((3-i)*4)
+ if n&0x8 == 0 {
+ continue
+ }
+ if i != 0 { // ModificationTime already read so skip
+ if len(*b) < 4 {
+ return // invalid, not enough data
+ }
+ *t = parseDosTime(b.uint32())
+ }
+ if n&0x4 > 0 {
+ *t = t.Add(time.Second)
+ }
+ n &= 0x3
+ if n == 0 {
+ continue
+ }
+ if len(*b) < int(n) {
+ return // invalid, not enough data
+ }
+ // add extra time data in 100's of nanoseconds
+ d := time.Duration(0)
+ for j := 3 - n; j < n; j++ {
+ d |= time.Duration(b.byte()) << (j * 8)
+ }
+ d *= 100
+ *t = t.Add(d)
+ }
+}
+
+func (a *archive15) getKeys(salt []byte) (key, iv []byte) {
+ // check cache of keys
+ for _, v := range a.keyCache {
+ if bytes.Equal(v.salt[:], salt) {
+ return v.key, v.iv
+ }
+ }
+ key, iv = calcAes30Params(a.pass, salt)
+
+ // save a copy in the cache
+ copy(a.keyCache[1:], a.keyCache[:])
+ a.keyCache[0].salt = append([]byte(nil), salt...) // copy so byte slice can be reused
+ a.keyCache[0].key = key
+ a.keyCache[0].iv = iv
+
+ return key, iv
+}
+
+func (a *archive15) parseFileHeader(h *blockHeader15) (*fileBlockHeader, error) {
+ f := new(fileBlockHeader)
+
+ f.first = h.flags&fileSplitBefore == 0
+ f.last = h.flags&fileSplitAfter == 0
+
+ f.solid = h.flags&fileSolid > 0
+ f.IsDir = h.flags&fileWindowMask == fileWindowMask
+ if !f.IsDir {
+ f.winSize = uint(h.flags&fileWindowMask)>>5 + 16
+ }
+
+ b := h.data
+ if len(b) < 21 {
+ return nil, errCorruptFileHeader
+ }
+
+ f.PackedSize = h.dataSize
+ f.UnPackedSize = int64(b.uint32())
+ f.HostOS = b.byte() + 1
+ if f.HostOS > HostOSBeOS {
+ f.HostOS = HostOSUnknown
+ }
+ a.checksum.sum = b.uint32()
+
+ f.ModificationTime = parseDosTime(b.uint32())
+ unpackver := b.byte() // decoder version
+ method := b.byte() - 0x30 // decryption method
+ namesize := int(b.uint16())
+ f.Attributes = int64(b.uint32())
+ if h.flags&fileLargeData > 0 {
+ if len(b) < 8 {
+ return nil, errCorruptFileHeader
+ }
+ _ = b.uint32() // already read large PackedSize in readBlockHeader
+ f.UnPackedSize |= int64(b.uint32()) << 32
+ f.UnKnownSize = f.UnPackedSize == -1
+ } else if int32(f.UnPackedSize) == -1 {
+ f.UnKnownSize = true
+ f.UnPackedSize = -1
+ }
+ if len(b) < namesize {
+ return nil, errCorruptFileHeader
+ }
+ name := b.bytes(namesize)
+ if h.flags&fileUnicode == 0 {
+ f.Name = string(name)
+ } else {
+ f.Name = decodeName(name)
+ }
+ // Rar 4.x uses '\' as file separator
+ f.Name = strings.Replace(f.Name, "\\", "/", -1)
+
+ if h.flags&fileVersion > 0 {
+ // file version is stored as ';n' appended to file name
+ i := strings.LastIndex(f.Name, ";")
+ if i > 0 {
+ j, err := strconv.Atoi(f.Name[i+1:])
+ if err == nil && j >= 0 {
+ f.Version = j
+ f.Name = f.Name[:i]
+ }
+ }
+ }
+
+ var salt []byte
+ if h.flags&fileSalt > 0 {
+ if len(b) < saltSize {
+ return nil, errCorruptFileHeader
+ }
+ salt = b.bytes(saltSize)
+ }
+ if h.flags&fileExtTime > 0 {
+ readExtTimes(f, &b)
+ }
+
+ if !f.first {
+ return f, nil
+ }
+ // fields only needed for first block in a file
+ if h.flags&fileEncrypted > 0 && len(salt) == saltSize {
+ f.key, f.iv = a.getKeys(salt)
+ }
+ a.checksum.Reset()
+ f.cksum = &a.checksum
+ if method == 0 {
+ return f, nil
+ }
+ if a.dec == nil {
+ switch unpackver {
+ case 15, 20, 26:
+ return nil, errUnsupportedDecoder
+ case 29:
+ a.dec = new(decoder29)
+ default:
+ return nil, errUnknownDecoder
+ }
+ a.decVer = unpackver
+ } else if a.decVer != unpackver {
+ return nil, errMultipleDecoders
+ }
+ f.decoder = a.dec
+ return f, nil
+}
+
+// readBlockHeader returns the next block header in the archive.
+// It will return io.EOF if there were no bytes read.
+func (a *archive15) readBlockHeader() (*blockHeader15, error) {
+ var err error
+ b := a.buf[:7]
+ r := io.Reader(a.v)
+ if a.encrypted {
+ salt := a.buf[:saltSize]
+ _, err = io.ReadFull(r, salt)
+ if err != nil {
+ return nil, err
+ }
+ key, iv := a.getKeys(salt)
+ r = newAesDecryptReader(r, key, iv)
+ err = readFull(r, b)
+ } else {
+ _, err = io.ReadFull(r, b)
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ crc := b.uint16()
+ hash := crc32.NewIEEE()
+ hash.Write(b)
+ h := new(blockHeader15)
+ h.htype = b.byte()
+ h.flags = b.uint16()
+ size := b.uint16()
+ if size < 7 {
+ return nil, errCorruptHeader
+ }
+ size -= 7
+ if int(size) > cap(a.buf) {
+ a.buf = readBuf(make([]byte, size))
+ }
+ h.data = a.buf[:size]
+ if err := readFull(r, h.data); err != nil {
+ return nil, err
+ }
+ hash.Write(h.data)
+ if crc != uint16(hash.Sum32()) {
+ return nil, errBadHeaderCrc
+ }
+ if h.flags&blockHasData > 0 {
+ if len(h.data) < 4 {
+ return nil, errCorruptHeader
+ }
+ h.dataSize = int64(h.data.uint32())
+ }
+ if (h.htype == blockService || h.htype == blockFile) && h.flags&fileLargeData > 0 {
+ if len(h.data) < 25 {
+ return nil, errCorruptHeader
+ }
+ b := h.data[21:25]
+ h.dataSize |= int64(b.uint32()) << 32
+ }
+ return h, nil
+}
+
+// next advances to the next file block in the archive
+func (a *archive15) next() (*fileBlockHeader, error) {
+ for {
+ // could return an io.EOF here as 1.5 archives may not have an end block.
+ h, err := a.readBlockHeader()
+ if err != nil {
+ return nil, err
+ }
+ a.byteReader = limitByteReader(a.v, h.dataSize) // reader for block data
+
+ switch h.htype {
+ case blockFile:
+ return a.parseFileHeader(h)
+ case blockArc:
+ a.encrypted = h.flags&arcEncrypted > 0
+ a.multi = h.flags&arcVolume > 0
+ a.old = h.flags&arcNewNaming == 0
+ a.solid = h.flags&arcSolid > 0
+ case blockEnd:
+ if h.flags&endArcNotLast == 0 || !a.multi {
+ return nil, errArchiveEnd
+ }
+ return nil, errArchiveContinues
+ default:
+ _, err = io.Copy(ioutil.Discard, a.byteReader)
+ }
+ if err != nil {
+ return nil, err
+ }
+ }
+}
+
+func (a *archive15) version() int { return fileFmt15 }
+
+func (a *archive15) reset() {
+ a.encrypted = false // reset encryption when opening new volume file
+}
+
+func (a *archive15) isSolid() bool {
+ return a.solid
+}
+
+// newArchive15 creates a new fileBlockReader for a Version 1.5 archive
+func newArchive15(r *bufio.Reader, password string) fileBlockReader {
+ a := new(archive15)
+ a.v = r
+ a.pass = utf16.Encode([]rune(password)) // convert to UTF-16
+ a.checksum.Hash32 = crc32.NewIEEE()
+ a.buf = readBuf(make([]byte, 100))
+ return a
+}
diff --git a/vendor/github.com/nwaples/rardecode/archive50.go b/vendor/github.com/nwaples/rardecode/archive50.go
new file mode 100644
index 0000000000..1d8f850dcd
--- /dev/null
+++ b/vendor/github.com/nwaples/rardecode/archive50.go
@@ -0,0 +1,475 @@
+package rardecode
+
+import (
+ "bufio"
+ "bytes"
+ "crypto/hmac"
+ "crypto/sha256"
+ "errors"
+ "hash"
+ "hash/crc32"
+ "io"
+ "io/ioutil"
+ "time"
+)
+
+const (
+ // block types
+ block5Arc = 1
+ block5File = 2
+ block5Service = 3
+ block5Encrypt = 4
+ block5End = 5
+
+ // block flags
+ block5HasExtra = 0x0001
+ block5HasData = 0x0002
+ block5DataNotFirst = 0x0008
+ block5DataNotLast = 0x0010
+
+ // end block flags
+ endArc5NotLast = 0x0001
+
+ // archive encryption block flags
+ enc5CheckPresent = 0x0001 // password check data is present
+
+ // main archive block flags
+ arc5MultiVol = 0x0001
+ arc5Solid = 0x0004
+
+ // file block flags
+ file5IsDir = 0x0001
+ file5HasUnixMtime = 0x0002
+ file5HasCRC32 = 0x0004
+ file5UnpSizeUnknown = 0x0008
+
+ // file encryption record flags
+ file5EncCheckPresent = 0x0001 // password check data is present
+ file5EncUseMac = 0x0002 // use MAC instead of plain checksum
+
+ cacheSize50 = 4
+ maxPbkdf2Salt = 64
+ pwCheckSize = 8
+ maxKdfCount = 24
+
+ minHeaderSize = 7
+)
+
+var (
+ errBadPassword = errors.New("rardecode: incorrect password")
+ errCorruptEncrypt = errors.New("rardecode: corrupt encryption data")
+ errUnknownEncMethod = errors.New("rardecode: unknown encryption method")
+)
+
+type extra struct {
+ ftype uint64 // field type
+ data readBuf // field data
+}
+
+type blockHeader50 struct {
+ htype uint64 // block type
+ flags uint64
+ data readBuf // block header data
+ extra []extra // extra fields
+ dataSize int64 // size of block data
+}
+
+// leHash32 wraps a hash.Hash32 to return the result of Sum in little
+// endian format.
+type leHash32 struct {
+ hash.Hash32
+}
+
+func (h leHash32) Sum(b []byte) []byte {
+ s := h.Sum32()
+ return append(b, byte(s), byte(s>>8), byte(s>>16), byte(s>>24))
+}
+
+func newLittleEndianCRC32() hash.Hash32 {
+ return leHash32{crc32.NewIEEE()}
+}
+
+// hash50 implements fileChecksum for RAR 5 archives
+type hash50 struct {
+ hash.Hash // hash file data is written to
+ sum []byte // file checksum
+ key []byte // if present used with hmac in calculating checksum from hash
+}
+
+func (h *hash50) valid() bool {
+ sum := h.Sum(nil)
+ if len(h.key) > 0 {
+ mac := hmac.New(sha256.New, h.key)
+ mac.Write(sum)
+ sum = mac.Sum(sum[:0])
+ if len(h.sum) == 4 {
+ // CRC32
+ for i, v := range sum[4:] {
+ sum[i&3] ^= v
+ }
+ sum = sum[:4]
+ }
+ }
+ return bytes.Equal(sum, h.sum)
+}
+
+// archive50 implements fileBlockReader for RAR 5 file format archives
+type archive50 struct {
+ byteReader // reader for current block data
+ v *bufio.Reader // reader for current archive volume
+ pass []byte
+ blockKey []byte // key used to encrypt blocks
+ multi bool // archive is multi-volume
+ solid bool // is a solid archive
+ checksum hash50 // file checksum
+ dec decoder // optional decoder used to unpack file
+ buf readBuf // temporary buffer
+ keyCache [cacheSize50]struct { // encryption key cache
+ kdfCount int
+ salt []byte
+ keys [][]byte
+ }
+}
+
+// calcKeys50 calculates the keys used in RAR 5 archive processing.
+// The returned slice of byte slices contains 3 keys.
+// Key 0 is used for block or file decryption.
+// Key 1 is optionally used for file checksum calculation.
+// Key 2 is optionally used for password checking.
+func calcKeys50(pass, salt []byte, kdfCount int) [][]byte {
+ if len(salt) > maxPbkdf2Salt {
+ salt = salt[:maxPbkdf2Salt]
+ }
+ keys := make([][]byte, 3)
+ if len(keys) == 0 {
+ return keys
+ }
+
+ prf := hmac.New(sha256.New, pass)
+ prf.Write(salt)
+ prf.Write([]byte{0, 0, 0, 1})
+
+ t := prf.Sum(nil)
+ u := append([]byte(nil), t...)
+
+ kdfCount--
+
+ for i, iter := range []int{kdfCount, 16, 16} {
+ for iter > 0 {
+ prf.Reset()
+ prf.Write(u)
+ u = prf.Sum(u[:0])
+ for j := range u {
+ t[j] ^= u[j]
+ }
+ iter--
+ }
+ keys[i] = append([]byte(nil), t...)
+ }
+
+ pwcheck := keys[2]
+ for i, v := range pwcheck[pwCheckSize:] {
+ pwcheck[i&(pwCheckSize-1)] ^= v
+ }
+ keys[2] = pwcheck[:pwCheckSize]
+
+ return keys
+}
+
+// getKeys reads kdfcount and salt from b and returns the corresponding encryption keys.
+func (a *archive50) getKeys(b *readBuf) (keys [][]byte, err error) {
+ if len(*b) < 17 {
+ return nil, errCorruptEncrypt
+ }
+ // read kdf count and salt
+ kdfCount := int(b.byte())
+ if kdfCount > maxKdfCount {
+ return nil, errCorruptEncrypt
+ }
+ kdfCount = 1 << uint(kdfCount)
+ salt := b.bytes(16)
+
+ // check cache of keys for match
+ for _, v := range a.keyCache {
+ if kdfCount == v.kdfCount && bytes.Equal(salt, v.salt) {
+ return v.keys, nil
+ }
+ }
+ // not found, calculate keys
+ keys = calcKeys50(a.pass, salt, kdfCount)
+
+ // store in cache
+ copy(a.keyCache[1:], a.keyCache[:])
+ a.keyCache[0].kdfCount = kdfCount
+ a.keyCache[0].salt = append([]byte(nil), salt...)
+ a.keyCache[0].keys = keys
+
+ return keys, nil
+}
+
+// checkPassword calculates if a password is correct given password check data and keys.
+func checkPassword(b *readBuf, keys [][]byte) error {
+ if len(*b) < 12 {
+ return nil // not enough bytes, ignore for the moment
+ }
+ pwcheck := b.bytes(8)
+ sum := b.bytes(4)
+ csum := sha256.Sum256(pwcheck)
+ if bytes.Equal(sum, csum[:len(sum)]) && !bytes.Equal(pwcheck, keys[2]) {
+ return errBadPassword
+ }
+ return nil
+}
+
+// parseFileEncryptionRecord processes the optional file encryption record from a file header.
+func (a *archive50) parseFileEncryptionRecord(b readBuf, f *fileBlockHeader) error {
+ if ver := b.uvarint(); ver != 0 {
+ return errUnknownEncMethod
+ }
+ flags := b.uvarint()
+
+ keys, err := a.getKeys(&b)
+ if err != nil {
+ return err
+ }
+
+ f.key = keys[0]
+ if len(b) < 16 {
+ return errCorruptEncrypt
+ }
+ f.iv = b.bytes(16)
+
+ if flags&file5EncCheckPresent > 0 {
+ if err := checkPassword(&b, keys); err != nil {
+ return err
+ }
+ }
+ if flags&file5EncUseMac > 0 {
+ a.checksum.key = keys[1]
+ }
+ return nil
+}
+
+func (a *archive50) parseFileHeader(h *blockHeader50) (*fileBlockHeader, error) {
+ a.checksum.sum = nil
+ a.checksum.key = nil
+
+ f := new(fileBlockHeader)
+
+ f.first = h.flags&block5DataNotFirst == 0
+ f.last = h.flags&block5DataNotLast == 0
+
+ flags := h.data.uvarint() // file flags
+ f.IsDir = flags&file5IsDir > 0
+ f.UnKnownSize = flags&file5UnpSizeUnknown > 0
+ f.UnPackedSize = int64(h.data.uvarint())
+ f.PackedSize = h.dataSize
+ f.Attributes = int64(h.data.uvarint())
+ if flags&file5HasUnixMtime > 0 {
+ if len(h.data) < 4 {
+ return nil, errCorruptFileHeader
+ }
+ f.ModificationTime = time.Unix(int64(h.data.uint32()), 0)
+ }
+ if flags&file5HasCRC32 > 0 {
+ if len(h.data) < 4 {
+ return nil, errCorruptFileHeader
+ }
+ a.checksum.sum = append([]byte(nil), h.data.bytes(4)...)
+ if f.first {
+ a.checksum.Hash = newLittleEndianCRC32()
+ f.cksum = &a.checksum
+ }
+ }
+
+ flags = h.data.uvarint() // compression flags
+ f.solid = flags&0x0040 > 0
+ f.winSize = uint(flags&0x3C00)>>10 + 17
+ method := (flags >> 7) & 7 // compression method (0 == none)
+ if f.first && method != 0 {
+ unpackver := flags & 0x003f
+ if unpackver != 0 {
+ return nil, errUnknownDecoder
+ }
+ if a.dec == nil {
+ a.dec = new(decoder50)
+ }
+ f.decoder = a.dec
+ }
+ switch h.data.uvarint() {
+ case 0:
+ f.HostOS = HostOSWindows
+ case 1:
+ f.HostOS = HostOSUnix
+ default:
+ f.HostOS = HostOSUnknown
+ }
+ nlen := int(h.data.uvarint())
+ if len(h.data) < nlen {
+ return nil, errCorruptFileHeader
+ }
+ f.Name = string(h.data.bytes(nlen))
+
+ // parse optional extra records
+ for _, e := range h.extra {
+ var err error
+ switch e.ftype {
+ case 1: // encryption
+ err = a.parseFileEncryptionRecord(e.data, f)
+ case 2:
+ // TODO: hash
+ case 3:
+ // TODO: time
+ case 4: // version
+ _ = e.data.uvarint() // ignore flags field
+ f.Version = int(e.data.uvarint())
+ case 5:
+ // TODO: redirection
+ case 6:
+ // TODO: owner
+ }
+ if err != nil {
+ return nil, err
+ }
+ }
+ return f, nil
+}
+
+// parseEncryptionBlock calculates the key for block encryption.
+func (a *archive50) parseEncryptionBlock(b readBuf) error {
+ if ver := b.uvarint(); ver != 0 {
+ return errUnknownEncMethod
+ }
+ flags := b.uvarint()
+ keys, err := a.getKeys(&b)
+ if err != nil {
+ return err
+ }
+ if flags&enc5CheckPresent > 0 {
+ if err := checkPassword(&b, keys); err != nil {
+ return err
+ }
+ }
+ a.blockKey = keys[0]
+ return nil
+}
+
+func (a *archive50) readBlockHeader() (*blockHeader50, error) {
+ r := io.Reader(a.v)
+ if a.blockKey != nil {
+ // block is encrypted
+ iv := a.buf[:16]
+ if err := readFull(r, iv); err != nil {
+ return nil, err
+ }
+ r = newAesDecryptReader(r, a.blockKey, iv)
+ }
+
+ b := a.buf[:minHeaderSize]
+ if err := readFull(r, b); err != nil {
+ return nil, err
+ }
+ crc := b.uint32()
+
+ hash := crc32.NewIEEE()
+ hash.Write(b)
+
+ size := int(b.uvarint()) // header size
+ if size > cap(a.buf) {
+ a.buf = readBuf(make([]byte, size))
+ } else {
+ a.buf = a.buf[:size]
+ }
+ n := copy(a.buf, b) // copy left over bytes
+ if err := readFull(r, a.buf[n:]); err != nil { // read rest of header
+ return nil, err
+ }
+
+ // check header crc
+ hash.Write(a.buf[n:])
+ if crc != hash.Sum32() {
+ return nil, errBadHeaderCrc
+ }
+
+ b = a.buf
+ h := new(blockHeader50)
+ h.htype = b.uvarint()
+ h.flags = b.uvarint()
+
+ var extraSize int
+ if h.flags&block5HasExtra > 0 {
+ extraSize = int(b.uvarint())
+ }
+ if h.flags&block5HasData > 0 {
+ h.dataSize = int64(b.uvarint())
+ }
+ if len(b) < extraSize {
+ return nil, errCorruptHeader
+ }
+ h.data = b.bytes(len(b) - extraSize)
+
+ // read header extra records
+ for len(b) > 0 {
+ size = int(b.uvarint())
+ if len(b) < size {
+ return nil, errCorruptHeader
+ }
+ data := readBuf(b.bytes(size))
+ ftype := data.uvarint()
+ h.extra = append(h.extra, extra{ftype, data})
+ }
+
+ return h, nil
+}
+
+// next advances to the next file block in the archive
+func (a *archive50) next() (*fileBlockHeader, error) {
+ for {
+ h, err := a.readBlockHeader()
+ if err != nil {
+ return nil, err
+ }
+ a.byteReader = limitByteReader(a.v, h.dataSize)
+ switch h.htype {
+ case block5File:
+ return a.parseFileHeader(h)
+ case block5Arc:
+ flags := h.data.uvarint()
+ a.multi = flags&arc5MultiVol > 0
+ a.solid = flags&arc5Solid > 0
+ case block5Encrypt:
+ err = a.parseEncryptionBlock(h.data)
+ case block5End:
+ flags := h.data.uvarint()
+ if flags&endArc5NotLast == 0 || !a.multi {
+ return nil, errArchiveEnd
+ }
+ return nil, errArchiveContinues
+ default:
+ // discard block data
+ _, err = io.Copy(ioutil.Discard, a.byteReader)
+ }
+ if err != nil {
+ return nil, err
+ }
+ }
+}
+
+func (a *archive50) version() int { return fileFmt50 }
+
+func (a *archive50) reset() {
+ a.blockKey = nil // reset encryption when opening new volume file
+}
+
+func (a *archive50) isSolid() bool {
+ return a.solid
+}
+
+// newArchive50 creates a new fileBlockReader for a Version 5 archive.
+func newArchive50(r *bufio.Reader, password string) fileBlockReader {
+ a := new(archive50)
+ a.v = r
+ a.pass = []byte(password)
+ a.buf = make([]byte, 100)
+ return a
+}
diff --git a/vendor/github.com/nwaples/rardecode/bit_reader.go b/vendor/github.com/nwaples/rardecode/bit_reader.go
new file mode 100644
index 0000000000..9b284efa31
--- /dev/null
+++ b/vendor/github.com/nwaples/rardecode/bit_reader.go
@@ -0,0 +1,119 @@
+package rardecode
+
+import "io"
+
+type bitReader interface {
+ readBits(n uint) (int, error) // read n bits of data
+ unreadBits(n uint) // revert the reading of the last n bits read
+}
+
+type limitedBitReader struct {
+ br bitReader
+ n int
+ err error // error to return if br returns EOF before all n bits have been read
+}
+
+// limitBitReader returns a bitReader that reads from br and stops with io.EOF after n bits.
+// If br returns an io.EOF before reading n bits, err is returned.
+func limitBitReader(br bitReader, n int, err error) bitReader {
+ return &limitedBitReader{br, n, err}
+}
+
+func (l *limitedBitReader) readBits(n uint) (int, error) {
+ if int(n) > l.n {
+ return 0, io.EOF
+ }
+ v, err := l.br.readBits(n)
+ if err == nil {
+ l.n -= int(n)
+ } else if err == io.EOF {
+ err = l.err
+ }
+ return v, err
+}
+
+func (l *limitedBitReader) unreadBits(n uint) {
+ l.n += int(n)
+ l.br.unreadBits(n)
+}
+
+// rarBitReader wraps an io.ByteReader to perform various bit and byte
+// reading utility functions used in RAR file processing.
+type rarBitReader struct {
+ r io.ByteReader
+ v int
+ n uint
+}
+
+func (r *rarBitReader) reset(br io.ByteReader) {
+ r.r = br
+ r.n = 0
+ r.v = 0
+}
+
+func (r *rarBitReader) readBits(n uint) (int, error) {
+ for n > r.n {
+ c, err := r.r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ r.v = r.v<<8 | int(c)
+ r.n += 8
+ }
+ r.n -= n
+ return (r.v >> r.n) & ((1 << n) - 1), nil
+}
+
+func (r *rarBitReader) unreadBits(n uint) {
+ r.n += n
+}
+
+// alignByte aligns the current bit reading input to the next byte boundary.
+func (r *rarBitReader) alignByte() {
+ r.n -= r.n % 8
+}
+
+// readUint32 reads a RAR V3 encoded uint32
+func (r *rarBitReader) readUint32() (uint32, error) {
+ n, err := r.readBits(2)
+ if err != nil {
+ return 0, err
+ }
+ if n != 1 {
+ n, err = r.readBits(4 << uint(n))
+ return uint32(n), err
+ }
+ n, err = r.readBits(4)
+ if err != nil {
+ return 0, err
+ }
+ if n == 0 {
+ n, err = r.readBits(8)
+ n |= -1 << 8
+ return uint32(n), err
+ }
+ nlow, err := r.readBits(4)
+ n = n<<4 | nlow
+ return uint32(n), err
+}
+
+func (r *rarBitReader) ReadByte() (byte, error) {
+ n, err := r.readBits(8)
+ return byte(n), err
+}
+
+// readFull reads len(p) bytes into p. If fewer bytes are read an error is returned.
+func (r *rarBitReader) readFull(p []byte) error {
+ for i := range p {
+ c, err := r.ReadByte()
+ if err != nil {
+ return err
+ }
+ p[i] = c
+ }
+ return nil
+}
+
+func newRarBitReader(r io.ByteReader) *rarBitReader {
+ return &rarBitReader{r: r}
+}
diff --git a/vendor/github.com/nwaples/rardecode/decode29.go b/vendor/github.com/nwaples/rardecode/decode29.go
new file mode 100644
index 0000000000..638645e79b
--- /dev/null
+++ b/vendor/github.com/nwaples/rardecode/decode29.go
@@ -0,0 +1,264 @@
+package rardecode
+
+import (
+ "bytes"
+ "errors"
+ "io"
+)
+
+const (
+ maxCodeSize = 0x10000
+ maxUniqueFilters = 1024
+)
+
+var (
+ // Errors marking the end of the decoding block and/or file
+ endOfFile = errors.New("rardecode: end of file")
+ endOfBlock = errors.New("rardecode: end of block")
+ endOfBlockAndFile = 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
+ 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
+
+ // current decode function (lz or ppm).
+ // When called it should perform a single decode operation, and either apply the
+ // data to the window or return they raw bytes for a filter.
+ decode func(w *window) ([]byte, error)
+
+ lz lz29Decoder // lz decoder
+ ppm ppm29Decoder // ppm decoder
+}
+
+// init intializes the decoder for decoding a new file.
+func (d *decoder29) init(r io.ByteReader, reset bool) error {
+ if d.br == nil {
+ d.br = newRarBitReader(r)
+ } else {
+ d.br.reset(r)
+ }
+ d.eof = false
+ if reset {
+ d.initFilters()
+ d.lz.reset()
+ d.ppm.reset()
+ d.decode = nil
+ }
+ if d.decode == nil {
+ return d.readBlockHeader()
+ }
+ return nil
+}
+
+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 = br.readFull(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()
+ fb.reset = true
+ } 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 = br.readFull(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.decode = d.ppm.decode
+ err = d.ppm.init(d.br)
+ } else {
+ d.decode = d.lz.decode
+ err = d.lz.init(d.br)
+ }
+ }
+ if err == io.EOF {
+ err = errDecoderOutOfData
+ }
+ return err
+
+}
+
+func (d *decoder29) fill(w *window) ([]*filterBlock, error) {
+ if d.eof {
+ return nil, io.EOF
+ }
+
+ var fl []*filterBlock
+
+ for w.available() > 0 {
+ b, err := d.decode(w) // perform a single decode operation
+ 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 {
+ // make offset relative to read index (from write index)
+ f.offset += w.buffered()
+ fl = append(fl, f)
+ }
+ }
+
+ switch err {
+ case nil:
+ continue
+ case endOfBlock:
+ err = d.readBlockHeader()
+ if err == nil {
+ continue
+ }
+ case endOfFile:
+ d.eof = true
+ err = io.EOF
+ case endOfBlockAndFile:
+ d.eof = true
+ d.decode = nil // clear decoder, it will be setup by next init()
+ err = io.EOF
+ case io.EOF:
+ err = errDecoderOutOfData
+ }
+ return fl, err
+ }
+ // return filters
+ return fl, nil
+}
diff --git a/vendor/github.com/nwaples/rardecode/decode29_lz.go b/vendor/github.com/nwaples/rardecode/decode29_lz.go
new file mode 100644
index 0000000000..94470853dc
--- /dev/null
+++ b/vendor/github.com/nwaples/rardecode/decode29_lz.go
@@ -0,0 +1,247 @@
+package rardecode
+
+const (
+ mainSize = 299
+ offsetSize = 60
+ lowOffsetSize = 17
+ lengthSize = 28
+ tableSize = mainSize + offsetSize + lowOffsetSize + lengthSize
+)
+
+var (
+ lengthBase = [28]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20,
+ 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224}
+ lengthExtraBits = [28]uint{0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2,
+ 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5}
+
+ offsetBase = [60]int{0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96,
+ 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096,
+ 6144, 8192, 12288, 16384, 24576, 32768, 49152, 65536, 98304,
+ 131072, 196608, 262144, 327680, 393216, 458752, 524288,
+ 589824, 655360, 720896, 786432, 851968, 917504, 983040,
+ 1048576, 1310720, 1572864, 1835008, 2097152, 2359296, 2621440,
+ 2883584, 3145728, 3407872, 3670016, 3932160}
+ offsetExtraBits = [60]uint{0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6,
+ 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14,
+ 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18}
+
+ shortOffsetBase = [8]int{0, 4, 8, 16, 32, 64, 128, 192}
+ shortOffsetExtraBits = [8]uint{2, 2, 3, 4, 5, 6, 6, 6}
+)
+
+type lz29Decoder struct {
+ codeLength [tableSize]byte
+
+ mainDecoder huffmanDecoder
+ offsetDecoder huffmanDecoder
+ lowOffsetDecoder huffmanDecoder
+ lengthDecoder huffmanDecoder
+
+ offset [4]int // history of previous offsets
+ length int // previous length
+ lowOffset int
+ lowOffsetRepeats int
+
+ br *rarBitReader
+}
+
+func (d *lz29Decoder) reset() {
+ for i := range d.offset {
+ d.offset[i] = 0
+ }
+ d.length = 0
+ for i := range d.codeLength {
+ d.codeLength[i] = 0
+ }
+}
+
+func (d *lz29Decoder) init(br *rarBitReader) error {
+ d.br = br
+ d.lowOffset = 0
+ d.lowOffsetRepeats = 0
+
+ n, err := d.br.readBits(1)
+ if err != nil {
+ return err
+ }
+ addOld := n > 0
+
+ cl := d.codeLength[:]
+ if err = readCodeLengthTable(d.br, cl, addOld); err != nil {
+ return err
+ }
+
+ d.mainDecoder.init(cl[:mainSize])
+ cl = cl[mainSize:]
+ d.offsetDecoder.init(cl[:offsetSize])
+ cl = cl[offsetSize:]
+ d.lowOffsetDecoder.init(cl[:lowOffsetSize])
+ cl = cl[lowOffsetSize:]
+ d.lengthDecoder.init(cl)
+
+ return nil
+}
+
+func (d *lz29Decoder) readFilterData() (b []byte, err error) {
+ flags, err := d.br.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+
+ n := (int(flags) & 7) + 1
+ switch n {
+ case 7:
+ n, err = d.br.readBits(8)
+ n += 7
+ if err != nil {
+ return nil, err
+ }
+ case 8:
+ n, err = d.br.readBits(16)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ buf := make([]byte, n+1)
+ buf[0] = flags
+ err = d.br.readFull(buf[1:])
+
+ return buf, err
+}
+
+func (d *lz29Decoder) readEndOfBlock() error {
+ n, err := d.br.readBits(1)
+ if err != nil {
+ return err
+ }
+ if n > 0 {
+ return endOfBlock
+ }
+ n, err = d.br.readBits(1)
+ if err != nil {
+ return err
+ }
+ if n > 0 {
+ return endOfBlockAndFile
+ }
+ return endOfFile
+}
+
+func (d *lz29Decoder) decode(win *window) ([]byte, error) {
+ sym, err := d.mainDecoder.readSym(d.br)
+ if err != nil {
+ return nil, err
+ }
+
+ switch {
+ case sym < 256:
+ // literal
+ win.writeByte(byte(sym))
+ return nil, nil
+ case sym == 256:
+ return nil, d.readEndOfBlock()
+ case sym == 257:
+ return d.readFilterData()
+ case sym == 258:
+ // use previous offset and length
+ case sym < 263:
+ i := sym - 259
+ offset := d.offset[i]
+ copy(d.offset[1:i+1], d.offset[:i])
+ d.offset[0] = offset
+
+ i, err := d.lengthDecoder.readSym(d.br)
+ if err != nil {
+ return nil, err
+ }
+ d.length = lengthBase[i] + 2
+ bits := lengthExtraBits[i]
+ if bits > 0 {
+ n, err := d.br.readBits(bits)
+ if err != nil {
+ return nil, err
+ }
+ d.length += n
+ }
+ case sym < 271:
+ i := sym - 263
+ copy(d.offset[1:], d.offset[:])
+ offset := shortOffsetBase[i] + 1
+ bits := shortOffsetExtraBits[i]
+ if bits > 0 {
+ n, err := d.br.readBits(bits)
+ if err != nil {
+ return nil, err
+ }
+ offset += n
+ }
+ d.offset[0] = offset
+
+ d.length = 2
+ default:
+ i := sym - 271
+ d.length = lengthBase[i] + 3
+ bits := lengthExtraBits[i]
+ if bits > 0 {
+ n, err := d.br.readBits(bits)
+ if err != nil {
+ return nil, err
+ }
+ d.length += n
+ }
+
+ i, err = d.offsetDecoder.readSym(d.br)
+ if err != nil {
+ return nil, err
+ }
+ offset := offsetBase[i] + 1
+ bits = offsetExtraBits[i]
+
+ switch {
+ case bits >= 4:
+ if bits > 4 {
+ n, err := d.br.readBits(bits - 4)
+ if err != nil {
+ return nil, err
+ }
+ offset += n << 4
+ }
+
+ if d.lowOffsetRepeats > 0 {
+ d.lowOffsetRepeats--
+ offset += d.lowOffset
+ } else {
+ n, err := d.lowOffsetDecoder.readSym(d.br)
+ if err != nil {
+ return nil, err
+ }
+ if n == 16 {
+ d.lowOffsetRepeats = 15
+ offset += d.lowOffset
+ } else {
+ offset += n
+ d.lowOffset = n
+ }
+ }
+ case bits > 0:
+ n, err := d.br.readBits(bits)
+ if err != nil {
+ return nil, err
+ }
+ offset += n
+ }
+
+ if offset >= 0x2000 {
+ d.length++
+ if offset >= 0x40000 {
+ d.length++
+ }
+ }
+ copy(d.offset[1:], d.offset[:])
+ d.offset[0] = offset
+ }
+ win.copyBytes(d.length, d.offset[0])
+ return nil, nil
+}
diff --git a/vendor/github.com/nwaples/rardecode/decode29_ppm.go b/vendor/github.com/nwaples/rardecode/decode29_ppm.go
new file mode 100644
index 0000000000..39c3199584
--- /dev/null
+++ b/vendor/github.com/nwaples/rardecode/decode29_ppm.go
@@ -0,0 +1,132 @@
+package rardecode
+
+import "io"
+
+type ppm29Decoder struct {
+ m model // ppm model
+ esc byte // escape character
+ br io.ByteReader
+}
+
+func (d *ppm29Decoder) init(br *rarBitReader) error {
+ maxOrder, err := br.readBits(7)
+ if err != nil {
+ return err
+ }
+ reset := maxOrder&0x20 > 0
+
+ // Should have flushed all unread bits from bitReader by now,
+ // use underlying ByteReader
+ d.br = br.r
+
+ var maxMB int
+ if reset {
+ c, err := d.br.ReadByte()
+ if err != nil {
+ return err
+ }
+ maxMB = int(c) + 1
+ }
+
+ if maxOrder&0x40 > 0 {
+ d.esc, err = d.br.ReadByte()
+ if err != nil {
+ return err
+ }
+ }
+
+ maxOrder = (maxOrder & 0x1f) + 1
+ if maxOrder > 16 {
+ maxOrder = 16 + (maxOrder-16)*3
+ }
+
+ return d.m.init(d.br, reset, maxOrder, maxMB)
+}
+
+func (d *ppm29Decoder) reset() {
+ d.esc = 2
+}
+
+func (d *ppm29Decoder) readFilterData() ([]byte, error) {
+ c, err := d.m.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+ n := int(c&7) + 1
+ if n == 7 {
+ b, err := d.m.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+ n += int(b)
+ } else if n == 8 {
+ b, err := d.m.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+ n = int(b) << 8
+ b, err = d.m.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+ n |= int(b)
+ }
+
+ n++
+ buf := make([]byte, n)
+ buf[0] = byte(c)
+ for i := 1; i < n; i++ {
+ buf[i], err = d.m.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+ }
+ return buf, nil
+}
+
+func (d *ppm29Decoder) decode(w *window) ([]byte, error) {
+ c, err := d.m.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+ if c != d.esc {
+ w.writeByte(c)
+ return nil, nil
+ }
+ c, err = d.m.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+
+ switch c {
+ case 0:
+ return nil, endOfBlock
+ case 2:
+ return nil, endOfBlockAndFile
+ case 3:
+ return d.readFilterData()
+ case 4:
+ offset := 0
+ for i := 0; i < 3; i++ {
+ c, err = d.m.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+ offset = offset<<8 | int(c)
+ }
+ len, err := d.m.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+ w.copyBytes(int(len)+32, offset+2)
+ case 5:
+ len, err := d.m.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+ w.copyBytes(int(len)+4, 1)
+ default:
+ w.writeByte(d.esc)
+ }
+ return nil, nil
+}
diff --git a/vendor/github.com/nwaples/rardecode/decode50.go b/vendor/github.com/nwaples/rardecode/decode50.go
new file mode 100644
index 0000000000..1939a444ab
--- /dev/null
+++ b/vendor/github.com/nwaples/rardecode/decode50.go
@@ -0,0 +1,294 @@
+package rardecode
+
+import (
+ "errors"
+ "io"
+)
+
+const (
+ mainSize5 = 306
+ offsetSize5 = 64
+ lowoffsetSize5 = 16
+ lengthSize5 = 44
+ tableSize5 = mainSize5 + offsetSize5 + lowoffsetSize5 + lengthSize5
+)
+
+var (
+ errUnknownFilter = errors.New("rardecode: unknown V5 filter")
+ errCorruptDecodeHeader = errors.New("rardecode: corrupt decode header")
+)
+
+// decoder50 implements the decoder interface for RAR 5 compression.
+// Decode input it broken up into 1 or more blocks. Each block starts with
+// a header containing block length and optional code length tables to initialize
+// the huffman decoders with.
+type decoder50 struct {
+ r io.ByteReader
+ br bitReader // bit reader for current data block
+ codeLength [tableSize5]byte
+
+ lastBlock bool // current block is last block in compressed file
+
+ mainDecoder huffmanDecoder
+ offsetDecoder huffmanDecoder
+ lowoffsetDecoder huffmanDecoder
+ lengthDecoder huffmanDecoder
+
+ offset [4]int
+ length int
+}
+
+func (d *decoder50) init(r io.ByteReader, reset bool) error {
+ d.r = r
+ d.lastBlock = false
+
+ if reset {
+ for i := range d.offset {
+ d.offset[i] = 0
+ }
+ d.length = 0
+ for i := range d.codeLength {
+ d.codeLength[i] = 0
+ }
+ }
+ err := d.readBlockHeader()
+ if err == io.EOF {
+ return errDecoderOutOfData
+ }
+ return err
+}
+
+func (d *decoder50) readBlockHeader() error {
+ flags, err := d.r.ReadByte()
+ if err != nil {
+ return err
+ }
+
+ bytecount := (flags>>3)&3 + 1
+ if bytecount == 4 {
+ return errCorruptDecodeHeader
+ }
+
+ hsum, err := d.r.ReadByte()
+ if err != nil {
+ return err
+ }
+
+ blockBits := int(flags)&0x07 + 1
+ blockBytes := 0
+ sum := 0x5a ^ flags
+ for i := byte(0); i < bytecount; i++ {
+ n, err := d.r.ReadByte()
+ if err != nil {
+ return err
+ }
+ sum ^= n
+ blockBytes |= int(n) << (i * 8)
+ }
+ if sum != hsum { // bad header checksum
+ return errCorruptDecodeHeader
+ }
+ blockBits += (blockBytes - 1) * 8
+
+ // create bit reader for block
+ d.br = limitBitReader(newRarBitReader(d.r), blockBits, errDecoderOutOfData)
+ d.lastBlock = flags&0x40 > 0
+
+ if flags&0x80 > 0 {
+ // read new code length tables and reinitialize huffman decoders
+ cl := d.codeLength[:]
+ err = readCodeLengthTable(d.br, cl, false)
+ if err != nil {
+ return err
+ }
+ d.mainDecoder.init(cl[:mainSize5])
+ cl = cl[mainSize5:]
+ d.offsetDecoder.init(cl[:offsetSize5])
+ cl = cl[offsetSize5:]
+ d.lowoffsetDecoder.init(cl[:lowoffsetSize5])
+ cl = cl[lowoffsetSize5:]
+ d.lengthDecoder.init(cl)
+ }
+ return nil
+}
+
+func slotToLength(br bitReader, n int) (int, error) {
+ if n >= 8 {
+ bits := uint(n/4 - 1)
+ n = (4 | (n & 3)) << bits
+ if bits > 0 {
+ b, err := br.readBits(bits)
+ if err != nil {
+ return 0, err
+ }
+ n |= b
+ }
+ }
+ n += 2
+ return n, nil
+}
+
+// readFilter5Data reads an encoded integer used in V5 filters.
+func readFilter5Data(br bitReader) (int, error) {
+ // TODO: should data really be uint? (for 32bit ints).
+ // It will be masked later anyway by decode window mask.
+ bytes, err := br.readBits(2)
+ if err != nil {
+ return 0, err
+ }
+ bytes++
+
+ var data int
+ for i := 0; i < bytes; i++ {
+ n, err := br.readBits(8)
+ if err != nil {
+ return 0, err
+ }
+ data |= n << (uint(i) * 8)
+ }
+ return data, nil
+}
+
+func readFilter(br bitReader) (*filterBlock, error) {
+ fb := new(filterBlock)
+ var err error
+
+ fb.offset, err = readFilter5Data(br)
+ if err != nil {
+ return nil, err
+ }
+ fb.length, err = readFilter5Data(br)
+ if err != nil {
+ return nil, err
+ }
+ ftype, err := br.readBits(3)
+ if err != nil {
+ return nil, err
+ }
+ switch ftype {
+ case 0:
+ n, err := br.readBits(5)
+ if err != nil {
+ return nil, err
+ }
+ fb.filter = func(buf []byte, offset int64) ([]byte, error) { return filterDelta(n+1, buf) }
+ case 1:
+ fb.filter = func(buf []byte, offset int64) ([]byte, error) { return filterE8(0xe8, true, buf, offset) }
+ case 2:
+ fb.filter = func(buf []byte, offset int64) ([]byte, error) { return filterE8(0xe9, true, buf, offset) }
+ case 3:
+ fb.filter = filterArm
+ default:
+ return nil, errUnknownFilter
+ }
+ return fb, nil
+}
+
+func (d *decoder50) decodeSym(win *window, sym int) (*filterBlock, error) {
+ switch {
+ case sym < 256:
+ // literal
+ win.writeByte(byte(sym))
+ return nil, nil
+ case sym == 256:
+ f, err := readFilter(d.br)
+ f.offset += win.buffered()
+ return f, err
+ case sym == 257:
+ // use previous offset and length
+ case sym < 262:
+ i := sym - 258
+ offset := d.offset[i]
+ copy(d.offset[1:i+1], d.offset[:i])
+ d.offset[0] = offset
+
+ sl, err := d.lengthDecoder.readSym(d.br)
+ if err != nil {
+ return nil, err
+ }
+ d.length, err = slotToLength(d.br, sl)
+ if err != nil {
+ return nil, err
+ }
+ default:
+ length, err := slotToLength(d.br, sym-262)
+ if err != nil {
+ return nil, err
+ }
+
+ offset := 1
+ slot, err := d.offsetDecoder.readSym(d.br)
+ if err != nil {
+ return nil, err
+ }
+ if slot < 4 {
+ offset += slot
+ } else {
+ bits := uint(slot/2 - 1)
+ offset += (2 | (slot & 1)) << bits
+
+ if bits >= 4 {
+ if bits > 4 {
+ n, err := d.br.readBits(bits - 4)
+ if err != nil {
+ return nil, err
+ }
+ offset += n << 4
+ }
+ n, err := d.lowoffsetDecoder.readSym(d.br)
+ if err != nil {
+ return nil, err
+ }
+ offset += n
+ } else {
+ n, err := d.br.readBits(bits)
+ if err != nil {
+ return nil, err
+ }
+ offset += n
+ }
+ }
+ if offset > 0x100 {
+ length++
+ if offset > 0x2000 {
+ length++
+ if offset > 0x40000 {
+ length++
+ }
+ }
+ }
+ copy(d.offset[1:], d.offset[:])
+ d.offset[0] = offset
+ d.length = length
+ }
+ win.copyBytes(d.length, d.offset[0])
+ return nil, nil
+}
+
+func (d *decoder50) fill(w *window) ([]*filterBlock, error) {
+ var fl []*filterBlock
+
+ for w.available() > 0 {
+ sym, err := d.mainDecoder.readSym(d.br)
+ if err == nil {
+ var f *filterBlock
+ f, err = d.decodeSym(w, sym)
+ if f != nil {
+ fl = append(fl, f)
+ }
+ } else if err == io.EOF {
+ // reached end of the block
+ if d.lastBlock {
+ return fl, io.EOF
+ }
+ err = d.readBlockHeader()
+ }
+ if err != nil {
+ if err == io.EOF {
+ return fl, errDecoderOutOfData
+ }
+ return fl, err
+ }
+ }
+ return fl, nil
+}
diff --git a/vendor/github.com/nwaples/rardecode/decode_reader.go b/vendor/github.com/nwaples/rardecode/decode_reader.go
new file mode 100644
index 0000000000..b346936ce3
--- /dev/null
+++ b/vendor/github.com/nwaples/rardecode/decode_reader.go
@@ -0,0 +1,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
+}
diff --git a/vendor/github.com/nwaples/rardecode/decrypt_reader.go b/vendor/github.com/nwaples/rardecode/decrypt_reader.go
new file mode 100644
index 0000000000..bb9f279c43
--- /dev/null
+++ b/vendor/github.com/nwaples/rardecode/decrypt_reader.go
@@ -0,0 +1,126 @@
+package rardecode
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "io"
+)
+
+// cipherBlockReader implements Block Mode decryption of an io.Reader object.
+type cipherBlockReader struct {
+ r io.Reader
+ mode cipher.BlockMode
+ inbuf []byte // input buffer for partial data block
+ outbuf []byte // output buffer used when output slice < block size
+ n int // bytes read from outbuf
+ err error
+}
+
+// read reads and decrypts one or more input blocks into p.
+// len(p) must be >= cipher block size.
+func (cr *cipherBlockReader) read(p []byte) (n int, err error) {
+ bs := cr.mode.BlockSize()
+ // round p down to a multiple of the block size
+ l := len(p) - len(p)%bs
+ p = p[:l]
+
+ l = len(cr.inbuf)
+ if l > 0 {
+ // copy any buffered input into p
+ copy(p, cr.inbuf)
+ cr.inbuf = cr.inbuf[:0]
+ }
+ // read data for at least one block
+ n, err = io.ReadAtLeast(cr.r, p[l:], bs-l)
+ n += l
+ p = p[:n]
+
+ l = n % bs
+ // check if p is a multiple of the cipher block size
+ if l > 0 {
+ n -= l
+ // save trailing partial block to process later
+ cr.inbuf = append(cr.inbuf, p[n:]...)
+ p = p[:n]
+ }
+
+ if err != nil {
+ if err == io.ErrUnexpectedEOF || err == io.ErrShortBuffer {
+ // ignore trailing bytes < block size length
+ err = io.EOF
+ }
+ return 0, err
+ }
+ cr.mode.CryptBlocks(p, p) // decrypt block(s)
+ return n, nil
+}
+
+// Read reads and decrypts data into p.
+// If the input is not a multiple of the cipher block size,
+// the trailing bytes will be ignored.
+func (cr *cipherBlockReader) Read(p []byte) (n int, err error) {
+ for {
+ if cr.n < len(cr.outbuf) {
+ // return buffered output
+ n = copy(p, cr.outbuf[cr.n:])
+ cr.n += n
+ return n, nil
+ }
+ if cr.err != nil {
+ err = cr.err
+ cr.err = nil
+ return 0, err
+ }
+ if len(p) >= cap(cr.outbuf) {
+ break
+ }
+ // p is not large enough to process a block, use outbuf instead
+ n, cr.err = cr.read(cr.outbuf[:cap(cr.outbuf)])
+ cr.outbuf = cr.outbuf[:n]
+ cr.n = 0
+ }
+ // read blocks into p
+ return cr.read(p)
+}
+
+// ReadByte returns the next decrypted byte.
+func (cr *cipherBlockReader) ReadByte() (byte, error) {
+ for {
+ if cr.n < len(cr.outbuf) {
+ c := cr.outbuf[cr.n]
+ cr.n++
+ return c, nil
+ }
+ if cr.err != nil {
+ err := cr.err
+ cr.err = nil
+ return 0, err
+ }
+ // refill outbuf
+ var n int
+ n, cr.err = cr.read(cr.outbuf[:cap(cr.outbuf)])
+ cr.outbuf = cr.outbuf[:n]
+ cr.n = 0
+ }
+}
+
+// newCipherBlockReader returns a cipherBlockReader that decrypts the given io.Reader using
+// the provided block mode cipher.
+func newCipherBlockReader(r io.Reader, mode cipher.BlockMode) *cipherBlockReader {
+ cr := &cipherBlockReader{r: r, mode: mode}
+ cr.outbuf = make([]byte, 0, mode.BlockSize())
+ cr.inbuf = make([]byte, 0, mode.BlockSize())
+ return cr
+}
+
+// newAesDecryptReader returns a cipherBlockReader that decrypts input from a given io.Reader using AES.
+// It will panic if the provided key is invalid.
+func newAesDecryptReader(r io.Reader, key, iv []byte) *cipherBlockReader {
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ panic(err)
+ }
+ mode := cipher.NewCBCDecrypter(block, iv)
+
+ return newCipherBlockReader(r, mode)
+}
diff --git a/vendor/github.com/nwaples/rardecode/filters.go b/vendor/github.com/nwaples/rardecode/filters.go
new file mode 100644
index 0000000000..a9eb0407d9
--- /dev/null
+++ b/vendor/github.com/nwaples/rardecode/filters.go
@@ -0,0 +1,416 @@
+package rardecode
+
+import (
+ "bytes"
+ "encoding/binary"
+ "hash/crc32"
+ "io"
+)
+
+const (
+ fileSize = 0x1000000
+
+ vmGlobalAddr = 0x3C000
+ vmGlobalSize = 0x02000
+ vmFixedGlobalSize = 0x40
+
+ maxUint32 = 1<<32 - 1
+)
+
+// v3Filter is the interface type for RAR V3 filters.
+// v3Filter performs the same function as the filter type, except that it also takes
+// the initial register values r, and global data as input for the RAR V3 VM.
+type v3Filter func(r map[int]uint32, global, buf []byte, offset int64) ([]byte, error)
+
+var (
+ // standardV3Filters is a list of known filters. We can replace the use of a vm
+ // filter with a custom filter function.
+ standardV3Filters = []struct {
+ crc uint32 // crc of code byte slice for filter
+ len int // length of code byte slice for filter
+ f v3Filter // replacement filter function
+ }{
+ {0xad576887, 53, e8FilterV3},
+ {0x3cd7e57e, 57, e8e9FilterV3},
+ {0x3769893f, 120, itaniumFilterV3},
+ {0x0e06077d, 29, deltaFilterV3},
+ {0x1c2c5dc8, 149, filterRGBV3},
+ {0xbc85e701, 216, filterAudioV3},
+ }
+
+ // itanium filter byte masks
+ byteMask = []int{4, 4, 6, 6, 0, 0, 7, 7, 4, 4, 0, 0, 4, 4, 0, 0}
+)
+
+func filterE8(c byte, v5 bool, buf []byte, offset int64) ([]byte, error) {
+ off := int32(offset)
+ for b := buf; len(b) >= 5; {
+ ch := b[0]
+ b = b[1:]
+ off++
+ if ch != 0xe8 && ch != c {
+ continue
+ }
+ if v5 {
+ off %= fileSize
+ }
+ addr := int32(binary.LittleEndian.Uint32(b))
+ if addr < 0 {
+ if addr+off >= 0 {
+ binary.LittleEndian.PutUint32(b, uint32(addr+fileSize))
+ }
+ } else if addr < fileSize {
+ binary.LittleEndian.PutUint32(b, uint32(addr-off))
+ }
+ off += 4
+ b = b[4:]
+ }
+ return buf, nil
+}
+
+func e8FilterV3(r map[int]uint32, global, buf []byte, offset int64) ([]byte, error) {
+ return filterE8(0xe8, false, buf, offset)
+}
+
+func e8e9FilterV3(r map[int]uint32, global, buf []byte, offset int64) ([]byte, error) {
+ return filterE8(0xe9, false, buf, offset)
+}
+
+func getBits(buf []byte, pos, count uint) uint32 {
+ n := binary.LittleEndian.Uint32(buf[pos/8:])
+ n >>= pos & 7
+ mask := uint32(maxUint32) >> (32 - count)
+ return n & mask
+}
+
+func setBits(buf []byte, pos, count uint, bits uint32) {
+ mask := uint32(maxUint32) >> (32 - count)
+ mask <<= pos & 7
+ bits <<= pos & 7
+ n := binary.LittleEndian.Uint32(buf[pos/8:])
+ n = (n & ^mask) | (bits & mask)
+ binary.LittleEndian.PutUint32(buf[pos/8:], n)
+}
+
+func itaniumFilterV3(r map[int]uint32, global, buf []byte, offset int64) ([]byte, error) {
+ fileOffset := uint32(offset) >> 4
+
+ for b := buf; len(b) > 21; b = b[16:] {
+ c := int(b[0]&0x1f) - 0x10
+ if c >= 0 {
+ mask := byteMask[c]
+ if mask != 0 {
+ for i := uint(0); i <= 2; i++ {
+ if mask&(1<<i) == 0 {
+ continue
+ }
+ pos := i*41 + 18
+ if getBits(b, pos+24, 4) == 5 {
+ n := getBits(b, pos, 20)
+ n -= fileOffset
+ setBits(b, pos, 20, n)
+ }
+ }
+ }
+ }
+ fileOffset++
+ }
+ return buf, nil
+}
+
+func filterDelta(n int, buf []byte) ([]byte, error) {
+ var res []byte
+ l := len(buf)
+ if cap(buf) >= 2*l {
+ res = buf[l : 2*l] // use unused capacity
+ } else {
+ res = make([]byte, l, 2*l)
+ }
+
+ i := 0
+ for j := 0; j < n; j++ {
+ var c byte
+ for k := j; k < len(res); k += n {
+ c -= buf[i]
+ i++
+ res[k] = c
+ }
+ }
+ return res, nil
+}
+
+func deltaFilterV3(r map[int]uint32, global, buf []byte, offset int64) ([]byte, error) {
+ return filterDelta(int(r[0]), buf)
+}
+
+func abs(n int) int {
+ if n < 0 {
+ n = -n
+ }
+ return n
+}
+
+func filterRGBV3(r map[int]uint32, global, buf []byte, offset int64) ([]byte, error) {
+ width := int(r[0] - 3)
+ posR := int(r[1])
+ if posR < 0 || width < 0 {
+ return buf, nil
+ }
+
+ var res []byte
+ l := len(buf)
+ if cap(buf) >= 2*l {
+ res = buf[l : 2*l] // use unused capacity
+ } else {
+ res = make([]byte, l, 2*l)
+ }
+
+ for c := 0; c < 3; c++ {
+ var prevByte int
+ for i := c; i < len(res); i += 3 {
+ var predicted int
+ upperPos := i - width
+ if upperPos >= 3 {
+ upperByte := int(res[upperPos])
+ upperLeftByte := int(res[upperPos-3])
+ predicted = prevByte + upperByte - upperLeftByte
+ pa := abs(predicted - prevByte)
+ pb := abs(predicted - upperByte)
+ pc := abs(predicted - upperLeftByte)
+ if pa <= pb && pa <= pc {
+ predicted = prevByte
+ } else if pb <= pc {
+ predicted = upperByte
+ } else {
+ predicted = upperLeftByte
+ }
+ } else {
+ predicted = prevByte
+ }
+ prevByte = (predicted - int(buf[0])) & 0xFF
+ res[i] = uint8(prevByte)
+ buf = buf[1:]
+ }
+
+ }
+ for i := posR; i < len(res)-2; i += 3 {
+ c := res[i+1]
+ res[i] += c
+ res[i+2] += c
+ }
+ return res, nil
+}
+
+func filterAudioV3(r map[int]uint32, global, buf []byte, offset int64) ([]byte, error) {
+ var res []byte
+ l := len(buf)
+ if cap(buf) >= 2*l {
+ res = buf[l : 2*l] // use unused capacity
+ } else {
+ res = make([]byte, l, 2*l)
+ }
+
+ chans := int(r[0])
+ for c := 0; c < chans; c++ {
+ var prevByte, byteCount int
+ var diff [7]int
+ var d, k [3]int
+
+ for i := c; i < len(res); i += chans {
+ predicted := prevByte<<3 + k[0]*d[0] + k[1]*d[1] + k[2]*d[2]
+ predicted = int(int8(predicted >> 3))
+
+ curByte := int(int8(buf[0]))
+ buf = buf[1:]
+ predicted -= curByte
+ res[i] = uint8(predicted)
+
+ dd := curByte << 3
+ diff[0] += abs(dd)
+ diff[1] += abs(dd - d[0])
+ diff[2] += abs(dd + d[0])
+ diff[3] += abs(dd - d[1])
+ diff[4] += abs(dd + d[1])
+ diff[5] += abs(dd - d[2])
+ diff[6] += abs(dd + d[2])
+
+ prevDelta := int(int8(predicted - prevByte))
+ prevByte = predicted
+ d[2] = d[1]
+ d[1] = prevDelta - d[0]
+ d[0] = prevDelta
+
+ if byteCount&0x1f == 0 {
+ min := diff[0]
+ diff[0] = 0
+ n := 0
+ for j := 1; j < len(diff); j++ {
+ if diff[j] < min {
+ min = diff[j]
+ n = j
+ }
+ diff[j] = 0
+ }
+ n--
+ if n >= 0 {
+ m := n / 2
+ if n%2 == 0 {
+ if k[m] >= -16 {
+ k[m]--
+ }
+ } else {
+ if k[m] < 16 {
+ k[m]++
+ }
+ }
+ }
+ }
+ byteCount++
+ }
+
+ }
+ return res, nil
+}
+
+func filterArm(buf []byte, offset int64) ([]byte, error) {
+ for i := 0; len(buf)-i > 3; i += 4 {
+ if buf[i+3] == 0xeb {
+ n := uint(buf[i])
+ n += uint(buf[i+1]) * 0x100
+ n += uint(buf[i+2]) * 0x10000
+ n -= (uint(offset) + uint(i)) / 4
+ buf[i] = byte(n)
+ buf[i+1] = byte(n >> 8)
+ buf[i+2] = byte(n >> 16)
+ }
+ }
+ return buf, nil
+}
+
+type vmFilter struct {
+ execCount uint32
+ global []byte
+ static []byte
+ code []command
+}
+
+// execute implements v3filter type for VM based RAR 3 filters.
+func (f *vmFilter) execute(r map[int]uint32, global, buf []byte, offset int64) ([]byte, error) {
+ if len(buf) > vmGlobalAddr {
+ return buf, errInvalidFilter
+ }
+ v := newVM(buf)
+
+ // register setup
+ v.r[3] = vmGlobalAddr
+ v.r[4] = uint32(len(buf))
+ v.r[5] = f.execCount
+ for i, n := range r {
+ v.r[i] = n
+ }
+
+ // vm global data memory block
+ vg := v.m[vmGlobalAddr : vmGlobalAddr+vmGlobalSize]
+
+ // initialize fixed global memory
+ for i, n := range v.r[:vmRegs-1] {
+ binary.LittleEndian.PutUint32(vg[i*4:], n)
+ }
+ binary.LittleEndian.PutUint32(vg[0x1c:], uint32(len(buf)))
+ binary.LittleEndian.PutUint64(vg[0x24:], uint64(offset))
+ binary.LittleEndian.PutUint32(vg[0x2c:], f.execCount)
+
+ // registers
+ v.r[6] = uint32(offset)
+
+ // copy program global memory
+ var n int
+ if len(f.global) > 0 {
+ n = copy(vg[vmFixedGlobalSize:], f.global) // use saved global instead
+ } else {
+ n = copy(vg[vmFixedGlobalSize:], global)
+ }
+ copy(vg[vmFixedGlobalSize+n:], f.static)
+
+ v.execute(f.code)
+
+ f.execCount++
+
+ // keep largest global buffer
+ if cap(global) > cap(f.global) {
+ f.global = global[:0]
+ } else if len(f.global) > 0 {
+ f.global = f.global[:0]
+ }
+
+ // check for global data to be saved for next program execution
+ globalSize := binary.LittleEndian.Uint32(vg[0x30:])
+ if globalSize > 0 {
+ if globalSize > vmGlobalSize-vmFixedGlobalSize {
+ globalSize = vmGlobalSize - vmFixedGlobalSize
+ }
+ if cap(f.global) < int(globalSize) {
+ f.global = make([]byte, globalSize)
+ } else {
+ f.global = f.global[:globalSize]
+ }
+ copy(f.global, vg[vmFixedGlobalSize:])
+ }
+
+ // find program output
+ length := binary.LittleEndian.Uint32(vg[0x1c:]) & vmMask
+ start := binary.LittleEndian.Uint32(vg[0x20:]) & vmMask
+ if start+length > vmSize {
+ // TODO: error
+ start = 0
+ length = 0
+ }
+ if start != 0 && cap(v.m) > cap(buf) {
+ // Initial buffer was to small for vm.
+ // Copy output to beginning of vm memory so that decodeReader
+ // will re-use the newly allocated vm memory and we will not
+ // have to reallocate again next time.
+ copy(v.m, v.m[start:start+length])
+ start = 0
+ }
+ return v.m[start : start+length], nil
+}
+
+// getV3Filter returns a V3 filter function from a code byte slice.
+func getV3Filter(code []byte) (v3Filter, error) {
+ // check if filter is a known standard filter
+ c := crc32.ChecksumIEEE(code)
+ for _, f := range standardV3Filters {
+ if f.crc == c && f.len == len(code) {
+ return f.f, nil
+ }
+ }
+
+ // create new vm filter
+ f := new(vmFilter)
+ r := newRarBitReader(bytes.NewReader(code[1:])) // skip first xor byte check
+
+ // read static data
+ n, err := r.readBits(1)
+ if err != nil {
+ return nil, err
+ }
+ if n > 0 {
+ m, err := r.readUint32()
+ if err != nil {
+ return nil, err
+ }
+ f.static = make([]byte, m+1)
+ err = r.readFull(f.static)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ f.code, err = readCommands(r)
+ if err == io.EOF {
+ err = nil
+ }
+
+ return f.execute, err
+}
diff --git a/vendor/github.com/nwaples/rardecode/go.mod b/vendor/github.com/nwaples/rardecode/go.mod
new file mode 100644
index 0000000000..b5e5df2180
--- /dev/null
+++ b/vendor/github.com/nwaples/rardecode/go.mod
@@ -0,0 +1 @@
+module github.com/nwaples/rardecode
diff --git a/vendor/github.com/nwaples/rardecode/huffman.go b/vendor/github.com/nwaples/rardecode/huffman.go
new file mode 100644
index 0000000000..eb289b40b4
--- /dev/null
+++ b/vendor/github.com/nwaples/rardecode/huffman.go
@@ -0,0 +1,208 @@
+package rardecode
+
+import (
+ "errors"
+ "io"
+)
+
+const (
+ maxCodeLength = 15 // maximum code length in bits
+ maxQuickBits = 10
+ maxQuickSize = 1 << maxQuickBits
+)
+
+var (
+ errHuffDecodeFailed = errors.New("rardecode: huffman decode failed")
+ errInvalidLengthTable = errors.New("rardecode: invalid huffman code length table")
+)
+
+type huffmanDecoder struct {
+ limit [maxCodeLength + 1]int
+ pos [maxCodeLength + 1]int
+ symbol []int
+ min uint
+ quickbits uint
+ quicklen [maxQuickSize]uint
+ quicksym [maxQuickSize]int
+}
+
+func (h *huffmanDecoder) init(codeLengths []byte) {
+ var count [maxCodeLength + 1]int
+
+ for _, n := range codeLengths {
+ if n == 0 {
+ continue
+ }
+ count[n]++
+ }
+
+ h.pos[0] = 0
+ h.limit[0] = 0
+ h.min = 0
+ for i := uint(1); i <= maxCodeLength; i++ {
+ h.limit[i] = h.limit[i-1] + count[i]<<(maxCodeLength-i)
+ h.pos[i] = h.pos[i-1] + count[i-1]
+ if h.min == 0 && h.limit[i] > 0 {
+ h.min = i
+ }
+ }
+
+ if cap(h.symbol) >= len(codeLengths) {
+ h.symbol = h.symbol[:len(codeLengths)]
+ for i := range h.symbol {
+ h.symbol[i] = 0
+ }
+ } else {
+ h.symbol = make([]int, len(codeLengths))
+ }
+
+ copy(count[:], h.pos[:])
+ for i, n := range codeLengths {
+ if n != 0 {
+ h.symbol[count[n]] = i
+ count[n]++
+ }
+ }
+
+ if len(codeLengths) >= 298 {
+ h.quickbits = maxQuickBits
+ } else {
+ h.quickbits = maxQuickBits - 3
+ }
+
+ bits := uint(1)
+ for i := 0; i < 1<<h.quickbits; i++ {
+ v := i << (maxCodeLength - h.quickbits)
+
+ for v >= h.limit[bits] && bits < maxCodeLength {
+ bits++
+ }
+ h.quicklen[i] = bits
+
+ dist := v - h.limit[bits-1]
+ dist >>= (maxCodeLength - bits)
+
+ pos := h.pos[bits] + dist
+ if pos < len(h.symbol) {
+ h.quicksym[i] = h.symbol[pos]
+ } else {
+ h.quicksym[i] = 0
+ }
+ }
+}
+
+func (h *huffmanDecoder) readSym(r bitReader) (int, error) {
+ bits := uint(maxCodeLength)
+ v, err := r.readBits(maxCodeLength)
+ if err != nil {
+ if err != io.EOF {
+ return 0, err
+ }
+ // fall back to 1 bit at a time if we read past EOF
+ for i := uint(1); i <= maxCodeLength; i++ {
+ b, err := r.readBits(1)
+ if err != nil {
+ return 0, err // not enough bits return error
+ }
+ v |= b << (maxCodeLength - i)
+ if v < h.limit[i] {
+ bits = i
+ break
+ }
+ }
+ } else {
+ if v < h.limit[h.quickbits] {
+ i := v >> (maxCodeLength - h.quickbits)
+ r.unreadBits(maxCodeLength - h.quicklen[i])
+ return h.quicksym[i], nil
+ }
+
+ for i, n := range h.limit[h.min:] {
+ if v < n {
+ bits = h.min + uint(i)
+ r.unreadBits(maxCodeLength - bits)
+ break
+ }
+ }
+ }
+
+ dist := v - h.limit[bits-1]
+ dist >>= maxCodeLength - bits
+
+ pos := h.pos[bits] + dist
+ if pos > len(h.symbol) {
+ return 0, errHuffDecodeFailed
+ }
+
+ return h.symbol[pos], nil
+}
+
+// readCodeLengthTable reads a new code length table into codeLength from br.
+// If addOld is set the old table is added to the new one.
+func readCodeLengthTable(br bitReader, codeLength []byte, addOld bool) error {
+ var bitlength [20]byte
+ for i := 0; i < len(bitlength); i++ {
+ n, err := br.readBits(4)
+ if err != nil {
+ return err
+ }
+ if n == 0xf {
+ cnt, err := br.readBits(4)
+ if err != nil {
+ return err
+ }
+ if cnt > 0 {
+ // array already zero'd dont need to explicitly set
+ i += cnt + 1
+ continue
+ }
+ }
+ bitlength[i] = byte(n)
+ }
+
+ var bl huffmanDecoder
+ bl.init(bitlength[:])
+
+ for i := 0; i < len(codeLength); i++ {
+ l, err := bl.readSym(br)
+ if err != nil {
+ return err
+ }
+
+ if l < 16 {
+ if addOld {
+ codeLength[i] = (codeLength[i] + byte(l)) & 0xf
+ } else {
+ codeLength[i] = byte(l)
+ }
+ continue
+ }
+
+ var count int
+ var value byte
+
+ switch l {
+ case 16, 18:
+ count, err = br.readBits(3)
+ count += 3
+ default:
+ count, err = br.readBits(7)
+ count += 11
+ }
+ if err != nil {
+ return err
+ }
+ if l < 18 {
+ if i == 0 {
+ return errInvalidLengthTable
+ }
+ value = codeLength[i-1]
+ }
+ for ; count > 0 && i < len(codeLength); i++ {
+ codeLength[i] = value
+ count--
+ }
+ i--
+ }
+ return nil
+}
diff --git a/vendor/github.com/nwaples/rardecode/ppm_model.go b/vendor/github.com/nwaples/rardecode/ppm_model.go
new file mode 100644
index 0000000000..58a545aa92
--- /dev/null
+++ b/vendor/github.com/nwaples/rardecode/ppm_model.go
@@ -0,0 +1,1096 @@
+package rardecode
+
+import (
+ "errors"
+ "io"
+)
+
+const (
+ rangeBottom = 1 << 15
+ rangeTop = 1 << 24
+
+ maxFreq = 124
+
+ intBits = 7
+ periodBits = 7
+ binScale = 1 << (intBits + periodBits)
+
+ n0 = 1
+ n1 = 4
+ n2 = 4
+ n3 = 4
+ n4 = (128 + 3 - 1*n1 - 2*n2 - 3*n3) / 4
+ nIndexes = n0 + n1 + n2 + n3 + n4
+
+ // memory is allocated in units. A unit contains unitSize number of bytes.
+ // A unit can store one context or two states.
+ unitSize = 12
+
+ maxUint16 = 1<<16 - 1
+ freeMark = -1
+)
+
+var (
+ errCorruptPPM = errors.New("rardecode: corrupt ppm data")
+
+ expEscape = []byte{25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2}
+ initBinEsc = []uint16{0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}
+
+ ns2Index [256]byte
+ ns2BSIndex [256]byte
+
+ // units2Index maps the number of units in a block to a freelist index
+ units2Index [128 + 1]byte
+ // index2Units maps a freelist index to the size of the block in units
+ index2Units [nIndexes]int32
+)
+
+func init() {
+ ns2BSIndex[0] = 2 * 0
+ ns2BSIndex[1] = 2 * 1
+ for i := 2; i < 11; i++ {
+ ns2BSIndex[i] = 2 * 2
+ }
+ for i := 11; i < 256; i++ {
+ ns2BSIndex[i] = 2 * 3
+ }
+
+ var j, n byte
+ for i := range ns2Index {
+ ns2Index[i] = n
+ if j <= 3 {
+ n++
+ j = n
+ } else {
+ j--
+ }
+ }
+
+ var ii byte
+ var iu, units int32
+ for i, n := range []int{n0, n1, n2, n3, n4} {
+ for j := 0; j < n; j++ {
+ units += int32(i)
+ index2Units[ii] = units
+ for iu <= units {
+ units2Index[iu] = ii
+ iu++
+ }
+ ii++
+ }
+ }
+}
+
+type rangeCoder struct {
+ br io.ByteReader
+ code uint32
+ low uint32
+ rnge uint32
+}
+
+func (r *rangeCoder) init(br io.ByteReader) error {
+ r.br = br
+ r.low = 0
+ r.rnge = ^uint32(0)
+ for i := 0; i < 4; i++ {
+ c, err := r.br.ReadByte()
+ if err != nil {
+ return err
+ }
+ r.code = r.code<<8 | uint32(c)
+ }
+ return nil
+}
+
+func (r *rangeCoder) currentCount(scale uint32) uint32 {
+ r.rnge /= scale
+ return (r.code - r.low) / r.rnge
+}
+
+func (r *rangeCoder) normalize() error {
+ for {
+ if r.low^(r.low+r.rnge) >= rangeTop {
+ if r.rnge >= rangeBottom {
+ return nil
+ }
+ r.rnge = -r.low & (rangeBottom - 1)
+ }
+ c, err := r.br.ReadByte()
+ if err != nil {
+ return err
+ }
+ r.code = r.code<<8 | uint32(c)
+ r.rnge <<= 8
+ r.low <<= 8
+ }
+}
+
+func (r *rangeCoder) decode(lowCount, highCount uint32) error {
+ r.low += r.rnge * lowCount
+ r.rnge *= highCount - lowCount
+
+ return r.normalize()
+}
+
+type see2Context struct {
+ summ uint16
+ shift byte
+ count byte
+}
+
+func newSee2Context(i uint16) see2Context {
+ return see2Context{i << (periodBits - 4), (periodBits - 4), 4}
+}
+
+func (s *see2Context) mean() uint32 {
+ if s == nil {
+ return 1
+ }
+ n := s.summ >> s.shift
+ if n == 0 {
+ return 1
+ }
+ s.summ -= n
+ return uint32(n)
+}
+
+func (s *see2Context) update() {
+ if s == nil || s.shift >= periodBits {
+ return
+ }
+ s.count--
+ if s.count == 0 {
+ s.summ += s.summ
+ s.count = 3 << s.shift
+ s.shift++
+ }
+}
+
+type state struct {
+ sym byte
+ freq byte
+
+ // succ can point to a context or byte in memory.
+ // A context pointer is a positive integer. It is an index into the states
+ // array that points to the first of two states which the context is
+ // marshalled into.
+ // A byte pointer is a negative integer. The magnitude represents the position
+ // in bytes from the bottom of the memory. As memory is modelled as an array of
+ // states, this is used to calculate which state, and where in the state the
+ // byte is stored.
+ // A zero value represents a nil pointer.
+ succ int32
+}
+
+// uint16 return a uint16 stored in the sym and freq fields of a state
+func (s state) uint16() uint16 { return uint16(s.sym) | uint16(s.freq)<<8 }
+
+// setUint16 stores a uint16 in the sym and freq fields of a state
+func (s *state) setUint16(n uint16) { s.sym = byte(n); s.freq = byte(n >> 8) }
+
+// A context is marshalled into a slice of two states.
+// The first state contains the number of states, and the suffix pointer.
+// If there is only one state, the second state contains that state.
+// If there is more than one state, the second state contains the summFreq
+// and the index to the slice of states.
+type context struct {
+ i int32 // index into the states array for context
+ s []state // slice of two states representing context
+ a *subAllocator
+}
+
+// succPtr returns a pointer value for the context to be stored in a state.succ
+func (c *context) succPtr() int32 { return c.i }
+
+func (c *context) numStates() int { return int(c.s[0].uint16()) }
+
+func (c *context) setNumStates(n int) { c.s[0].setUint16(uint16(n)) }
+
+func (c *context) statesIndex() int32 { return c.s[1].succ }
+
+func (c *context) setStatesIndex(n int32) { c.s[1].succ = n }
+
+func (c *context) suffix() *context { return c.a.succContext(c.s[0].succ) }
+
+func (c *context) setSuffix(sc *context) { c.s[0].succ = sc.i }
+
+func (c *context) summFreq() uint16 { return c.s[1].uint16() }
+
+func (c *context) setSummFreq(f uint16) { c.s[1].setUint16(f) }
+
+func (c *context) notEq(ctx *context) bool { return c.i != ctx.i }
+
+func (c *context) states() []state {
+ if ns := int32(c.s[0].uint16()); ns != 1 {
+ i := c.s[1].succ
+ return c.a.states[i : i+ns]
+ }
+ return c.s[1:]
+}
+
+// shrinkStates shrinks the state list down to size states
+func (c *context) shrinkStates(states []state, size int) []state {
+ i1 := units2Index[(len(states)+1)>>1]
+ i2 := units2Index[(size+1)>>1]
+
+ if size == 1 {
+ // store state in context, and free states block
+ n := c.statesIndex()
+ c.s[1] = states[0]
+ states = c.s[1:]
+ c.a.addFreeBlock(n, i1)
+ } else if i1 != i2 {
+ if n := c.a.removeFreeBlock(i2); n > 0 {
+ // allocate new block and copy
+ copy(c.a.states[n:], states[:size])
+ states = c.a.states[n:]
+ // free old block
+ c.a.addFreeBlock(c.statesIndex(), i1)
+ c.setStatesIndex(n)
+ } else {
+ // split current block, and free units not needed
+ n = c.statesIndex() + index2Units[i2]<<1
+ u := index2Units[i1] - index2Units[i2]
+ c.a.freeUnits(n, u)
+ }
+ }
+ c.setNumStates(size)
+ return states[:size]
+}
+
+// expandStates expands the states list by one
+func (c *context) expandStates() []state {
+ states := c.states()
+ ns := len(states)
+ if ns == 1 {
+ s := states[0]
+ n := c.a.allocUnits(1)
+ if n == 0 {
+ return nil
+ }
+ c.setStatesIndex(n)
+ states = c.a.states[n:]
+ states[0] = s
+ } else if ns&0x1 == 0 {
+ u := ns >> 1
+ i1 := units2Index[u]
+ i2 := units2Index[u+1]
+ if i1 != i2 {
+ n := c.a.allocUnits(i2)
+ if n == 0 {
+ return nil
+ }
+ copy(c.a.states[n:], states)
+ c.a.addFreeBlock(c.statesIndex(), i1)
+ c.setStatesIndex(n)
+ states = c.a.states[n:]
+ }
+ }
+ c.setNumStates(ns + 1)
+ return states[:ns+1]
+}
+
+type subAllocator struct {
+ // memory for allocation is split into two heaps
+
+ heap1MaxBytes int32 // maximum bytes available in heap1
+ heap1Lo int32 // heap1 bottom in number of bytes
+ heap1Hi int32 // heap1 top in number of bytes
+ heap2Lo int32 // heap2 bottom index in states
+ heap2Hi int32 // heap2 top index in states
+ glueCount int
+
+ // Each freeList entry contains an index into states for the beginning
+ // of a free block. The first state in that block may contain an index
+ // to another free block and so on. The size of the free block in units
+ // (2 states) for that freeList index can be determined from the
+ // index2Units array.
+ freeList [nIndexes]int32
+
+ // Instead of bytes, memory is represented by a slice of states.
+ // context's are marshalled to and from a pair of states.
+ // multiple bytes are stored in a state.
+ states []state
+}
+
+func (a *subAllocator) init(maxMB int) {
+ bytes := int32(maxMB) << 20
+ heap2Units := bytes / 8 / unitSize * 7
+ a.heap1MaxBytes = bytes - heap2Units*unitSize
+ // Add one for the case when bytes are not a multiple of unitSize
+ heap1Units := a.heap1MaxBytes/unitSize + 1
+ // Calculate total size in state's. Add 1 unit so we can reserve the first unit.
+ // This will allow us to use the zero index as a nil pointer.
+ n := int(1+heap1Units+heap2Units) * 2
+ if cap(a.states) > n {
+ a.states = a.states[:n]
+ } else {
+ a.states = make([]state, n)
+ }
+}
+
+func (a *subAllocator) restart() {
+ // Pad heap1 start by 1 unit and enough bytes so that there is no
+ // gap between heap1 end and heap2 start.
+ a.heap1Lo = unitSize + (unitSize - a.heap1MaxBytes%unitSize)
+ a.heap1Hi = unitSize + (a.heap1MaxBytes/unitSize+1)*unitSize
+ a.heap2Lo = a.heap1Hi / unitSize * 2
+ a.heap2Hi = int32(len(a.states))
+ a.glueCount = 0
+ for i := range a.freeList {
+ a.freeList[i] = 0
+ }
+ for i := range a.states {
+ a.states[i] = state{}
+ }
+}
+
+// pushByte puts a byte on the heap and returns a state.succ index that
+// can be used to retrieve it.
+func (a *subAllocator) pushByte(c byte) int32 {
+ si := a.heap1Lo / 6 // state index
+ oi := a.heap1Lo % 6 // byte position in state
+ switch oi {
+ case 0:
+ a.states[si].sym = c
+ case 1:
+ a.states[si].freq = c
+ default:
+ n := (uint(oi) - 2) * 8
+ mask := ^(uint32(0xFF) << n)
+ succ := uint32(a.states[si].succ) & mask
+ succ |= uint32(c) << n
+ a.states[si].succ = int32(succ)
+ }
+ a.heap1Lo++
+ if a.heap1Lo >= a.heap1Hi {
+ return 0
+ }
+ return -a.heap1Lo
+}
+
+// popByte reverses the previous pushByte
+func (a *subAllocator) popByte() { a.heap1Lo-- }
+
+// succByte returns a byte from the heap given a state.succ index
+func (a *subAllocator) succByte(i int32) byte {
+ i = -i
+ si := i / 6
+ oi := i % 6
+ switch oi {
+ case 0:
+ return a.states[si].sym
+ case 1:
+ return a.states[si].freq
+ default:
+ n := (uint(oi) - 2) * 8
+ succ := uint32(a.states[si].succ) >> n
+ return byte(succ & 0xff)
+ }
+}
+
+// succContext returns a context given a state.succ index
+func (a *subAllocator) succContext(i int32) *context {
+ if i <= 0 {
+ return nil
+ }
+ return &context{i: i, s: a.states[i : i+2 : i+2], a: a}
+}
+
+// succIsNil returns whether a state.succ points to nothing
+func (a *subAllocator) succIsNil(i int32) bool { return i == 0 }
+
+// nextByteAddr takes a state.succ value representing a pointer
+// to a byte, and returns the next bytes address
+func (a *subAllocator) nextByteAddr(n int32) int32 { return n - 1 }
+
+func (a *subAllocator) removeFreeBlock(i byte) int32 {
+ n := a.freeList[i]
+ if n != 0 {
+ a.freeList[i] = a.states[n].succ
+ a.states[n] = state{}
+ }
+ return n
+}
+
+func (a *subAllocator) addFreeBlock(n int32, i byte) {
+ a.states[n].succ = a.freeList[i]
+ a.freeList[i] = n
+}
+
+func (a *subAllocator) freeUnits(n, u int32) {
+ i := units2Index[u]
+ if u != index2Units[i] {
+ i--
+ a.addFreeBlock(n, i)
+ u -= index2Units[i]
+ n += index2Units[i] << 1
+ i = units2Index[u]
+ }
+ a.addFreeBlock(n, i)
+}
+
+func (a *subAllocator) glueFreeBlocks() {
+ var freeIndex int32
+
+ for i, n := range a.freeList {
+ s := state{succ: freeMark}
+ s.setUint16(uint16(index2Units[i]))
+ for n != 0 {
+ states := a.states[n:]
+ states[1].succ = freeIndex
+ freeIndex = n
+ n = states[0].succ
+ states[0] = s
+ }
+ a.freeList[i] = 0
+ }
+
+ for i := freeIndex; i != 0; i = a.states[i+1].succ {
+ if a.states[i].succ != freeMark {
+ continue
+ }
+ u := int32(a.states[i].uint16())
+ states := a.states[i+u<<1:]
+ for len(states) > 0 && states[0].succ == freeMark {
+ u += int32(states[0].uint16())
+ if u > maxUint16 {
+ break
+ }
+ states[0].succ = 0
+ a.states[i].setUint16(uint16(u))
+ states = a.states[i+u<<1:]
+ }
+ }
+
+ for n := freeIndex; n != 0; n = a.states[n+1].succ {
+ if a.states[n].succ != freeMark {
+ continue
+ }
+ a.states[n].succ = 0
+ u := int32(a.states[n].uint16())
+ m := n
+ for u > 128 {
+ a.addFreeBlock(m, nIndexes-1)
+ u -= 128
+ m += 256
+ }
+ a.freeUnits(m, u)
+ }
+}
+
+func (a *subAllocator) allocUnitsRare(index byte) int32 {
+ if a.glueCount == 0 {
+ a.glueCount = 255
+ a.glueFreeBlocks()
+ if n := a.removeFreeBlock(index); n > 0 {
+ return n
+ }
+ }
+ // try to find a larger free block and split it
+ for i := index + 1; i < nIndexes; i++ {
+ if n := a.removeFreeBlock(i); n > 0 {
+ u := index2Units[i] - index2Units[index]
+ a.freeUnits(n+index2Units[index]<<1, u)
+ return n
+ }
+ }
+ a.glueCount--
+
+ // try to allocate units from the top of heap1
+ n := a.heap1Hi - index2Units[index]*unitSize
+ if n > a.heap1Lo {
+ a.heap1Hi = n
+ return a.heap1Hi / unitSize * 2
+ }
+ return 0
+}
+
+func (a *subAllocator) allocUnits(i byte) int32 {
+ // try to allocate a free block
+ if n := a.removeFreeBlock(i); n > 0 {
+ return n
+ }
+ // try to allocate from the bottom of heap2
+ n := index2Units[i] << 1
+ if a.heap2Lo+n <= a.heap2Hi {
+ lo := a.heap2Lo
+ a.heap2Lo += n
+ return lo
+ }
+ return a.allocUnitsRare(i)
+}
+
+func (a *subAllocator) newContext(s state, suffix *context) *context {
+ var n int32
+ if a.heap2Lo < a.heap2Hi {
+ // allocate from top of heap2
+ a.heap2Hi -= 2
+ n = a.heap2Hi
+ } else if n = a.removeFreeBlock(1); n == 0 {
+ if n = a.allocUnitsRare(1); n == 0 {
+ return nil
+ }
+ }
+ c := &context{i: n, s: a.states[n : n+2 : n+2], a: a}
+ c.s[0] = state{}
+ c.setNumStates(1)
+ c.s[1] = s
+ if suffix != nil {
+ c.setSuffix(suffix)
+ }
+ return c
+}
+
+func (a *subAllocator) newContextSize(ns int) *context {
+ c := a.newContext(state{}, nil)
+ c.setNumStates(ns)
+ i := units2Index[(ns+1)>>1]
+ n := a.allocUnits(i)
+ c.setStatesIndex(n)
+ return c
+}
+
+type model struct {
+ maxOrder int
+ orderFall int
+ initRL int
+ runLength int
+ prevSuccess byte
+ escCount byte
+ prevSym byte
+ initEsc byte
+ minC *context
+ maxC *context
+ rc rangeCoder
+ a subAllocator
+ charMask [256]byte
+ binSumm [128][64]uint16
+ see2Cont [25][16]see2Context
+}
+
+func (m *model) restart() {
+ for i := range m.charMask {
+ m.charMask[i] = 0
+ }
+ m.escCount = 1
+
+ if m.maxOrder < 12 {
+ m.initRL = -m.maxOrder - 1
+ } else {
+ m.initRL = -12 - 1
+ }
+ m.orderFall = m.maxOrder
+ m.runLength = m.initRL
+ m.prevSuccess = 0
+
+ m.a.restart()
+
+ c := m.a.newContextSize(256)
+ c.setSummFreq(257)
+ states := c.states()
+ for i := range states {
+ states[i] = state{sym: byte(i), freq: 1}
+ }
+ m.minC = c
+ m.maxC = c
+ m.prevSym = 0
+
+ for i := range m.binSumm {
+ for j, esc := range initBinEsc {
+ n := binScale - esc/(uint16(i)+2)
+ for k := j; k < len(m.binSumm[i]); k += len(initBinEsc) {
+ m.binSumm[i][k] = n
+ }
+ }
+ }
+
+ for i := range m.see2Cont {
+ see := newSee2Context(5*uint16(i) + 10)
+ for j := range m.see2Cont[i] {
+ m.see2Cont[i][j] = see
+ }
+ }
+}
+
+func (m *model) init(br io.ByteReader, reset bool, maxOrder, maxMB int) error {
+ err := m.rc.init(br)
+ if err != nil {
+ return err
+ }
+ if !reset {
+ if m.minC == nil {
+ return errCorruptPPM
+ }
+ return nil
+ }
+
+ m.a.init(maxMB)
+
+ if maxOrder == 1 {
+ return errCorruptPPM
+ }
+ m.maxOrder = maxOrder
+ m.restart()
+ return nil
+}
+
+func (m *model) rescale(s *state) *state {
+ if s.freq <= maxFreq {
+ return s
+ }
+ c := m.minC
+
+ var summFreq uint16
+
+ s.freq += 4
+ states := c.states()
+ escFreq := c.summFreq() + 4
+
+ for i := range states {
+ f := states[i].freq
+ escFreq -= uint16(f)
+ if m.orderFall != 0 {
+ f++
+ }
+ f >>= 1
+ summFreq += uint16(f)
+ states[i].freq = f
+
+ if i == 0 || f <= states[i-1].freq {
+ continue
+ }
+ j := i - 1
+ for j > 0 && f > states[j-1].freq {
+ j--
+ }
+ t := states[i]
+ copy(states[j+1:i+1], states[j:i])
+ states[j] = t
+ }
+
+ i := len(states) - 1
+ for states[i].freq == 0 {
+ i--
+ escFreq++
+ }
+ if i != len(states)-1 {
+ states = c.shrinkStates(states, i+1)
+ }
+ s = &states[0]
+ if i == 0 {
+ for {
+ s.freq -= s.freq >> 1
+ escFreq >>= 1
+ if escFreq <= 1 {
+ return s
+ }
+ }
+ }
+ summFreq += escFreq - (escFreq >> 1)
+ c.setSummFreq(summFreq)
+ return s
+}
+
+func (m *model) decodeBinSymbol() (*state, error) {
+ c := m.minC
+ s := &c.states()[0]
+
+ ns := c.suffix().numStates()
+ i := m.prevSuccess + ns2BSIndex[ns-1] + byte(m.runLength>>26)&0x20
+ if m.prevSym >= 64 {
+ i += 8
+ }
+ if s.sym >= 64 {
+ i += 2 * 8
+ }
+ bs := &m.binSumm[s.freq-1][i]
+ mean := (*bs + 1<<(periodBits-2)) >> periodBits
+
+ if m.rc.currentCount(binScale) < uint32(*bs) {
+ err := m.rc.decode(0, uint32(*bs))
+ if s.freq < 128 {
+ s.freq++
+ }
+ *bs += 1<<intBits - mean
+ m.prevSuccess = 1
+ m.runLength++
+ return s, err
+ }
+ err := m.rc.decode(uint32(*bs), binScale)
+ *bs -= mean
+ m.initEsc = expEscape[*bs>>10]
+ m.charMask[s.sym] = m.escCount
+ m.prevSuccess = 0
+ return nil, err
+}
+
+func (m *model) decodeSymbol1() (*state, error) {
+ c := m.minC
+ states := c.states()
+ scale := uint32(c.summFreq())
+ // protect against divide by zero
+ // TODO: look at why this happens, may be problem elsewhere
+ if scale == 0 {
+ return nil, errCorruptPPM
+ }
+ count := m.rc.currentCount(scale)
+ m.prevSuccess = 0
+
+ var n uint32
+ for i := range states {
+ s := &states[i]
+ n += uint32(s.freq)
+ if n <= count {
+ continue
+ }
+ err := m.rc.decode(n-uint32(s.freq), n)
+ s.freq += 4
+ c.setSummFreq(uint16(scale + 4))
+ if i == 0 {
+ if 2*n > scale {
+ m.prevSuccess = 1
+ m.runLength++
+ }
+ } else {
+ if s.freq <= states[i-1].freq {
+ return s, err
+ }
+ states[i-1], states[i] = states[i], states[i-1]
+ s = &states[i-1]
+ }
+ return m.rescale(s), err
+ }
+
+ for _, s := range states {
+ m.charMask[s.sym] = m.escCount
+ }
+ return nil, m.rc.decode(n, scale)
+}
+
+func (m *model) makeEscFreq(c *context, numMasked int) *see2Context {
+ ns := c.numStates()
+ if ns == 256 {
+ return nil
+ }
+ diff := ns - numMasked
+
+ var i int
+ if m.prevSym >= 64 {
+ i = 8
+ }
+ if diff < c.suffix().numStates()-ns {
+ i++
+ }
+ if int(c.summFreq()) < 11*ns {
+ i += 2
+ }
+ if numMasked > diff {
+ i += 4
+ }
+ return &m.see2Cont[ns2Index[diff-1]][i]
+}
+
+func (m *model) decodeSymbol2(numMasked int) (*state, error) {
+ c := m.minC
+
+ see := m.makeEscFreq(c, numMasked)
+ scale := see.mean()
+
+ var i int
+ var hi uint32
+ states := c.states()
+ sl := make([]*state, len(states)-numMasked)
+ for j := range sl {
+ for m.charMask[states[i].sym] == m.escCount {
+ i++
+ }
+ hi += uint32(states[i].freq)
+ sl[j] = &states[i]
+ i++
+ }
+
+ scale += hi
+ count := m.rc.currentCount(scale)
+
+ if count >= scale {
+ return nil, errCorruptPPM
+ }
+ if count >= hi {
+ err := m.rc.decode(hi, scale)
+ if see != nil {
+ see.summ += uint16(scale)
+ }
+ for _, s := range sl {
+ m.charMask[s.sym] = m.escCount
+ }
+ return nil, err
+ }
+
+ hi = uint32(sl[0].freq)
+ for hi <= count {
+ sl = sl[1:]
+ hi += uint32(sl[0].freq)
+ }
+ s := sl[0]
+
+ err := m.rc.decode(hi-uint32(s.freq), hi)
+
+ see.update()
+
+ m.escCount++
+ m.runLength = m.initRL
+
+ s.freq += 4
+ c.setSummFreq(c.summFreq() + 4)
+ return m.rescale(s), err
+}
+
+func (c *context) findState(sym byte) *state {
+ var i int
+ states := c.states()
+ for i = range states {
+ if states[i].sym == sym {
+ break
+ }
+ }
+ return &states[i]
+}
+
+func (m *model) createSuccessors(s, ss *state) *context {
+ var sl []*state
+
+ if m.orderFall != 0 {
+ sl = append(sl, s)
+ }
+
+ c := m.minC
+ for suff := c.suffix(); suff != nil; suff = c.suffix() {
+ c = suff
+
+ if ss == nil {
+ ss = c.findState(s.sym)
+ }
+ if ss.succ != s.succ {
+ c = m.a.succContext(ss.succ)
+ break
+ }
+ sl = append(sl, ss)
+ ss = nil
+ }
+
+ if len(sl) == 0 {
+ return c
+ }
+
+ var up state
+ up.sym = m.a.succByte(s.succ)
+ up.succ = m.a.nextByteAddr(s.succ)
+
+ states := c.states()
+ if len(states) > 1 {
+ s = c.findState(up.sym)
+
+ cf := uint16(s.freq) - 1
+ s0 := c.summFreq() - uint16(len(states)) - cf
+
+ if 2*cf <= s0 {
+ if 5*cf > s0 {
+ up.freq = 2
+ } else {
+ up.freq = 1
+ }
+ } else {
+ up.freq = byte(1 + (2*cf+3*s0-1)/(2*s0))
+ }
+ } else {
+ up.freq = states[0].freq
+ }
+
+ for i := len(sl) - 1; i >= 0; i-- {
+ c = m.a.newContext(up, c)
+ if c == nil {
+ return nil
+ }
+ sl[i].succ = c.succPtr()
+ }
+ return c
+}
+
+func (m *model) update(s *state) {
+ if m.orderFall == 0 {
+ if c := m.a.succContext(s.succ); c != nil {
+ m.minC = c
+ m.maxC = c
+ return
+ }
+ }
+
+ if m.escCount == 0 {
+ m.escCount = 1
+ for i := range m.charMask {
+ m.charMask[i] = 0
+ }
+ }
+
+ var ss *state // matching minC.suffix state
+
+ if s.freq < maxFreq/4 && m.minC.suffix() != nil {
+ c := m.minC.suffix()
+ states := c.states()
+
+ var i int
+ if len(states) > 1 {
+ for states[i].sym != s.sym {
+ i++
+ }
+ if i > 0 && states[i].freq >= states[i-1].freq {
+ states[i-1], states[i] = states[i], states[i-1]
+ i--
+ }
+ if states[i].freq < maxFreq-9 {
+ states[i].freq += 2
+ c.setSummFreq(c.summFreq() + 2)
+ }
+ } else if states[0].freq < 32 {
+ states[0].freq++
+ }
+ ss = &states[i] // save later for createSuccessors
+ }
+
+ if m.orderFall == 0 {
+ c := m.createSuccessors(s, ss)
+ if c == nil {
+ m.restart()
+ } else {
+ m.minC = c
+ m.maxC = c
+ s.succ = c.succPtr()
+ }
+ return
+ }
+
+ succ := m.a.pushByte(s.sym)
+ if m.a.succIsNil(succ) {
+ m.restart()
+ return
+ }
+
+ var minC *context
+ if m.a.succIsNil(s.succ) {
+ s.succ = succ
+ minC = m.minC
+ } else {
+ minC = m.a.succContext(s.succ)
+ if minC == nil {
+ minC = m.createSuccessors(s, ss)
+ if minC == nil {
+ m.restart()
+ return
+ }
+ }
+ m.orderFall--
+ if m.orderFall == 0 {
+ succ = minC.succPtr()
+ if m.maxC.notEq(m.minC) {
+ m.a.popByte()
+ }
+ }
+ }
+
+ n := m.minC.numStates()
+ s0 := int(m.minC.summFreq()) - n - int(s.freq-1)
+ for c := m.maxC; c.notEq(m.minC); c = c.suffix() {
+ var summFreq uint16
+
+ states := c.expandStates()
+ if states == nil {
+ m.restart()
+ return
+ }
+ if ns := len(states) - 1; ns != 1 {
+ summFreq = c.summFreq()
+ if 4*ns <= n && int(summFreq) <= 8*ns {
+ summFreq += 2
+ }
+ if 2*ns < n {
+ summFreq++
+ }
+ } else {
+ p := &states[0]
+ if p.freq < maxFreq/4-1 {
+ p.freq += p.freq
+ } else {
+ p.freq = maxFreq - 4
+ }
+ summFreq = uint16(p.freq) + uint16(m.initEsc)
+ if n > 3 {
+ summFreq++
+ }
+ }
+
+ cf := 2 * int(s.freq) * int(summFreq+6)
+ sf := s0 + int(summFreq)
+ var freq byte
+ if cf >= 6*sf {
+ switch {
+ case cf >= 15*sf:
+ freq = 7
+ case cf >= 12*sf:
+ freq = 6
+ case cf >= 9*sf:
+ freq = 5
+ default:
+ freq = 4
+ }
+ summFreq += uint16(freq)
+ } else {
+ switch {
+ case cf >= 4*sf:
+ freq = 3
+ case cf > sf:
+ freq = 2
+ default:
+ freq = 1
+ }
+ summFreq += 3
+ }
+ states[len(states)-1] = state{sym: s.sym, freq: freq, succ: succ}
+ c.setSummFreq(summFreq)
+ }
+ m.minC = minC
+ m.maxC = minC
+}
+
+func (m *model) ReadByte() (byte, error) {
+ if m.minC == nil {
+ return 0, errCorruptPPM
+ }
+ var s *state
+ var err error
+ if m.minC.numStates() == 1 {
+ s, err = m.decodeBinSymbol()
+ } else {
+ s, err = m.decodeSymbol1()
+ }
+ for s == nil && err == nil {
+ n := m.minC.numStates()
+ for m.minC.numStates() == n {
+ m.orderFall++
+ m.minC = m.minC.suffix()
+ if m.minC == nil {
+ return 0, errCorruptPPM
+ }
+ }
+ s, err = m.decodeSymbol2(n)
+ }
+ if err != nil {
+ return 0, err
+ }
+
+ // save sym so it doesn't get overwritten by a possible restart()
+ sym := s.sym
+ m.update(s)
+ m.prevSym = sym
+ return sym, nil
+}
diff --git a/vendor/github.com/nwaples/rardecode/reader.go b/vendor/github.com/nwaples/rardecode/reader.go
new file mode 100644
index 0000000000..03e88a87b5
--- /dev/null
+++ b/vendor/github.com/nwaples/rardecode/reader.go
@@ -0,0 +1,369 @@
+package rardecode
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "io"
+ "io/ioutil"
+ "os"
+ "time"
+)
+
+// FileHeader HostOS types
+const (
+ HostOSUnknown = 0
+ HostOSMSDOS = 1
+ HostOSOS2 = 2
+ HostOSWindows = 3
+ HostOSUnix = 4
+ HostOSMacOS = 5
+ HostOSBeOS = 6
+)
+
+const (
+ maxPassword = 128
+)
+
+var (
+ errShortFile = errors.New("rardecode: decoded file too short")
+ errInvalidFileBlock = errors.New("rardecode: invalid file block")
+ errUnexpectedArcEnd = errors.New("rardecode: unexpected end of archive")
+ errBadFileChecksum = errors.New("rardecode: bad file checksum")
+)
+
+type byteReader interface {
+ io.Reader
+ io.ByteReader
+}
+
+type limitedReader struct {
+ r io.Reader
+ n int64 // bytes remaining
+ shortErr error // error returned when r returns io.EOF with n > 0
+}
+
+func (l *limitedReader) Read(p []byte) (int, error) {
+ if l.n <= 0 {
+ return 0, io.EOF
+ }
+ if int64(len(p)) > l.n {
+ p = p[0:l.n]
+ }
+ n, err := l.r.Read(p)
+ l.n -= int64(n)
+ if err == io.EOF && l.n > 0 {
+ return n, l.shortErr
+ }
+ return n, err
+}
+
+type limitedByteReader struct {
+ limitedReader
+ br io.ByteReader
+}
+
+func (l *limitedByteReader) ReadByte() (byte, error) {
+ if l.n <= 0 {
+ return 0, io.EOF
+ }
+ c, err := l.br.ReadByte()
+ if err == nil {
+ l.n--
+ } else if err == io.EOF && l.n > 0 {
+ return 0, l.shortErr
+ }
+ return c, err
+}
+
+// limitByteReader returns a limitedByteReader that reads from r and stops with
+// io.EOF after n bytes.
+// If r returns an io.EOF before reading n bytes, io.ErrUnexpectedEOF is returned.
+func limitByteReader(r byteReader, n int64) *limitedByteReader {
+ return &limitedByteReader{limitedReader{r, n, io.ErrUnexpectedEOF}, r}
+}
+
+// fileChecksum allows file checksum validations to be performed.
+// File contents must first be written to fileChecksum. Then valid is
+// called to perform the file checksum calculation to determine
+// if the file contents are valid or not.
+type fileChecksum interface {
+ io.Writer
+ valid() bool
+}
+
+// FileHeader represents a single file in a RAR archive.
+type FileHeader struct {
+ Name string // file name using '/' as the directory separator
+ IsDir bool // is a directory
+ HostOS byte // Host OS the archive was created on
+ Attributes int64 // Host OS specific file attributes
+ PackedSize int64 // packed file size (or first block if the file spans volumes)
+ UnPackedSize int64 // unpacked file size
+ UnKnownSize bool // unpacked file size is not known
+ ModificationTime time.Time // modification time (non-zero if set)
+ CreationTime time.Time // creation time (non-zero if set)
+ AccessTime time.Time // access time (non-zero if set)
+ Version int // file version
+}
+
+// Mode returns an os.FileMode for the file, calculated from the Attributes field.
+func (f *FileHeader) Mode() os.FileMode {
+ var m os.FileMode
+
+ if f.IsDir {
+ m = os.ModeDir
+ }
+ if f.HostOS == HostOSWindows {
+ if f.IsDir {
+ m |= 0777
+ } else if f.Attributes&1 > 0 {
+ m |= 0444 // readonly
+ } else {
+ m |= 0666
+ }
+ return m
+ }
+ // assume unix perms for all remaining os types
+ m |= os.FileMode(f.Attributes) & os.ModePerm
+
+ // only check other bits on unix host created archives
+ if f.HostOS != HostOSUnix {
+ return m
+ }
+
+ if f.Attributes&0x200 != 0 {
+ m |= os.ModeSticky
+ }
+ if f.Attributes&0x400 != 0 {
+ m |= os.ModeSetgid
+ }
+ if f.Attributes&0x800 != 0 {
+ m |= os.ModeSetuid
+ }
+
+ // Check for additional file types.
+ if f.Attributes&0xF000 == 0xA000 {
+ m |= os.ModeSymlink
+ }
+ return m
+}
+
+// fileBlockHeader represents a file block in a RAR archive.
+// Files may comprise one or more file blocks.
+// Solid files retain decode tables and dictionary from previous solid files in the archive.
+type fileBlockHeader struct {
+ first bool // first block in file
+ last bool // last block in file
+ solid bool // file is solid
+ winSize uint // log base 2 of decode window size
+ cksum fileChecksum // file checksum
+ decoder decoder // decoder to use for file
+ key []byte // key for AES, non-empty if file encrypted
+ iv []byte // iv for AES, non-empty if file encrypted
+ FileHeader
+}
+
+// fileBlockReader provides sequential access to file blocks in a RAR archive.
+type fileBlockReader interface {
+ io.Reader // Read's read data from the current file block
+ io.ByteReader // Read bytes from current file block
+ next() (*fileBlockHeader, error) // reads the next file block header at current position
+ reset() // resets encryption
+ isSolid() bool // is archive solid
+ version() int // returns current archive format version
+}
+
+// packedFileReader provides sequential access to packed files in a RAR archive.
+type packedFileReader struct {
+ r fileBlockReader
+ h *fileBlockHeader // current file header
+}
+
+// nextBlockInFile reads the next file block in the current file at the current
+// archive file position, or returns an error if there is a problem.
+// It is invalid to call this when already at the last block in the current file.
+func (f *packedFileReader) nextBlockInFile() error {
+ h, err := f.r.next()
+ if err != nil {
+ if err == io.EOF {
+ // archive ended, but file hasn't
+ return errUnexpectedArcEnd
+ }
+ return err
+ }
+ if h.first || h.Name != f.h.Name {
+ return errInvalidFileBlock
+ }
+ f.h = h
+ return nil
+}
+
+// next advances to the next packed file in the RAR archive.
+func (f *packedFileReader) next() (*fileBlockHeader, error) {
+ if f.h != nil {
+ // skip to last block in current file
+ for !f.h.last {
+ // discard remaining block data
+ if _, err := io.Copy(ioutil.Discard, f.r); err != nil {
+ return nil, err
+ }
+ if err := f.nextBlockInFile(); err != nil {
+ return nil, err
+ }
+ }
+ // discard last block data
+ if _, err := io.Copy(ioutil.Discard, f.r); err != nil {
+ return nil, err
+ }
+ }
+ var err error
+ f.h, err = f.r.next() // get next file block
+ if err != nil {
+ if err == errArchiveEnd {
+ return nil, io.EOF
+ }
+ return nil, err
+ }
+ if !f.h.first {
+ return nil, errInvalidFileBlock
+ }
+ return f.h, nil
+}
+
+// Read reads the packed data for the current file into p.
+func (f *packedFileReader) Read(p []byte) (int, error) {
+ n, err := f.r.Read(p) // read current block data
+ for err == io.EOF { // current block empty
+ if n > 0 {
+ return n, nil
+ }
+ if f.h == nil || f.h.last {
+ return 0, io.EOF // last block so end of file
+ }
+ if err := f.nextBlockInFile(); err != nil {
+ return 0, err
+ }
+ n, err = f.r.Read(p) // read new block data
+ }
+ return n, err
+}
+
+func (f *packedFileReader) ReadByte() (byte, error) {
+ c, err := f.r.ReadByte() // read current block data
+ for err == io.EOF && f.h != nil && !f.h.last { // current block empty
+ if err := f.nextBlockInFile(); err != nil {
+ return 0, err
+ }
+ c, err = f.r.ReadByte() // read new block data
+ }
+ return c, err
+}
+
+// Reader provides sequential access to files in a RAR archive.
+type Reader struct {
+ r io.Reader // reader for current unpacked file
+ pr packedFileReader // reader for current packed file
+ dr decodeReader // reader for decoding and filters if file is compressed
+ cksum fileChecksum // current file checksum
+ solidr io.Reader // reader for solid file
+}
+
+// Read reads from the current file in the RAR archive.
+func (r *Reader) Read(p []byte) (int, error) {
+ n, err := r.r.Read(p)
+ if err == io.EOF && r.cksum != nil && !r.cksum.valid() {
+ return n, errBadFileChecksum
+ }
+ return n, err
+}
+
+// Next advances to the next file in the archive.
+func (r *Reader) Next() (*FileHeader, error) {
+ if r.solidr != nil {
+ // solid files must be read fully to update decoder information
+ if _, err := io.Copy(ioutil.Discard, r.solidr); err != nil {
+ return nil, err
+ }
+ }
+
+ h, err := r.pr.next() // skip to next file
+ if err != nil {
+ return nil, err
+ }
+ r.solidr = nil
+
+ br := byteReader(&r.pr) // start with packed file reader
+
+ // check for encryption
+ if len(h.key) > 0 && len(h.iv) > 0 {
+ br = newAesDecryptReader(br, h.key, h.iv) // decrypt
+ }
+ r.r = br
+ // check for compression
+ if h.decoder != nil {
+ err = r.dr.init(br, h.decoder, h.winSize, !h.solid)
+ if err != nil {
+ return nil, err
+ }
+ r.r = &r.dr
+ if r.pr.r.isSolid() {
+ r.solidr = r.r
+ }
+ }
+ if h.UnPackedSize >= 0 && !h.UnKnownSize {
+ // Limit reading to UnPackedSize as there may be padding
+ r.r = &limitedReader{r.r, h.UnPackedSize, errShortFile}
+ }
+ r.cksum = h.cksum
+ if r.cksum != nil {
+ r.r = io.TeeReader(r.r, h.cksum) // write file data to checksum as it is read
+ }
+ fh := new(FileHeader)
+ *fh = h.FileHeader
+ return fh, nil
+}
+
+func (r *Reader) init(fbr fileBlockReader) {
+ r.r = bytes.NewReader(nil) // initial reads will always return EOF
+ r.pr.r = fbr
+}
+
+// NewReader creates a Reader reading from r.
+// NewReader only supports single volume archives.
+// Multi-volume archives must use OpenReader.
+func NewReader(r io.Reader, password string) (*Reader, error) {
+ br, ok := r.(*bufio.Reader)
+ if !ok {
+ br = bufio.NewReader(r)
+ }
+ fbr, err := newFileBlockReader(br, password)
+ if err != nil {
+ return nil, err
+ }
+ rr := new(Reader)
+ rr.init(fbr)
+ return rr, nil
+}
+
+type ReadCloser struct {
+ v *volume
+ Reader
+}
+
+// Close closes the rar file.
+func (rc *ReadCloser) Close() error {
+ return rc.v.Close()
+}
+
+// OpenReader opens a RAR archive specified by the name and returns a ReadCloser.
+func OpenReader(name, password string) (*ReadCloser, error) {
+ v, err := openVolume(name, password)
+ if err != nil {
+ return nil, err
+ }
+ rc := new(ReadCloser)
+ rc.v = v
+ rc.Reader.init(v)
+ return rc, nil
+}
diff --git a/vendor/github.com/nwaples/rardecode/vm.go b/vendor/github.com/nwaples/rardecode/vm.go
new file mode 100644
index 0000000000..fd26a5a0ae
--- /dev/null
+++ b/vendor/github.com/nwaples/rardecode/vm.go
@@ -0,0 +1,687 @@
+package rardecode
+
+import (
+ "encoding/binary"
+ "errors"
+)
+
+const (
+ // vm flag bits
+ flagC = 1 // Carry
+ flagZ = 2 // Zero
+ flagS = 0x80000000 // Sign
+
+ maxCommands = 25000000 // maximum number of commands that can be run in a program
+
+ vmRegs = 8 // number if registers
+ vmSize = 0x40000 // memory size
+ vmMask = vmSize - 1
+)
+
+var (
+ errInvalidVMInstruction = errors.New("rardecode: invalid vm instruction")
+)
+
+type vm struct {
+ ip uint32 // instruction pointer
+ ipMod bool // ip was modified
+ fl uint32 // flag bits
+ r [vmRegs]uint32 // registers
+ m []byte // memory
+}
+
+func (v *vm) setIP(ip uint32) {
+ v.ip = ip
+ v.ipMod = true
+}
+
+// execute runs a list of commands on the vm.
+func (v *vm) execute(cmd []command) {
+ v.ip = 0 // reset instruction pointer
+ for n := 0; n < maxCommands; n++ {
+ ip := v.ip
+ if ip >= uint32(len(cmd)) {
+ return
+ }
+ ins := cmd[ip]
+ ins.f(v, ins.bm, ins.op) // run cpu instruction
+ if v.ipMod {
+ // command modified ip, don't increment
+ v.ipMod = false
+ } else {
+ v.ip++ // increment ip for next command
+ }
+ }
+}
+
+// newVM creates a new RAR virtual machine using the byte slice as memory.
+func newVM(mem []byte) *vm {
+ v := new(vm)
+
+ if cap(mem) < vmSize+4 {
+ v.m = make([]byte, vmSize+4)
+ copy(v.m, mem)
+ } else {
+ v.m = mem[:vmSize+4]
+ for i := len(mem); i < len(v.m); i++ {
+ v.m[i] = 0
+ }
+ }
+ v.r[7] = vmSize
+ return v
+}
+
+type operand interface {
+ get(v *vm, byteMode bool) uint32
+ set(v *vm, byteMode bool, n uint32)
+}
+
+// Immediate Operand
+type opI uint32
+
+func (op opI) get(v *vm, bm bool) uint32 { return uint32(op) }
+func (op opI) set(v *vm, bm bool, n uint32) {}
+
+// Direct Operand
+type opD uint32
+
+func (op opD) get(v *vm, byteMode bool) uint32 {
+ if byteMode {
+ return uint32(v.m[op])
+ }
+ return binary.LittleEndian.Uint32(v.m[op:])
+}
+
+func (op opD) set(v *vm, byteMode bool, n uint32) {
+ if byteMode {
+ v.m[op] = byte(n)
+ } else {
+ binary.LittleEndian.PutUint32(v.m[op:], n)
+ }
+}
+
+// Register Operand
+type opR uint32
+
+func (op opR) get(v *vm, byteMode bool) uint32 {
+ if byteMode {
+ return v.r[op] & 0xFF
+ }
+ return v.r[op]
+}
+
+func (op opR) set(v *vm, byteMode bool, n uint32) {
+ if byteMode {
+ v.r[op] = (v.r[op] & 0xFFFFFF00) | (n & 0xFF)
+ } else {
+ v.r[op] = n
+ }
+}
+
+// Register Indirect Operand
+type opRI uint32
+
+func (op opRI) get(v *vm, byteMode bool) uint32 {
+ i := v.r[op] & vmMask
+ if byteMode {
+ return uint32(v.m[i])
+ }
+ return binary.LittleEndian.Uint32(v.m[i:])
+}
+func (op opRI) set(v *vm, byteMode bool, n uint32) {
+ i := v.r[op] & vmMask
+ if byteMode {
+ v.m[i] = byte(n)
+ } else {
+ binary.LittleEndian.PutUint32(v.m[i:], n)
+ }
+}
+
+// Base Plus Index Indirect Operand
+type opBI struct {
+ r uint32
+ i uint32
+}
+
+func (op opBI) get(v *vm, byteMode bool) uint32 {
+ i := (v.r[op.r] + op.i) & vmMask
+ if byteMode {
+ return uint32(v.m[i])
+ }
+ return binary.LittleEndian.Uint32(v.m[i:])
+}
+func (op opBI) set(v *vm, byteMode bool, n uint32) {
+ i := (v.r[op.r] + op.i) & vmMask
+ if byteMode {
+ v.m[i] = byte(n)
+ } else {
+ binary.LittleEndian.PutUint32(v.m[i:], n)
+ }
+}
+
+type commandFunc func(v *vm, byteMode bool, op []operand)
+
+type command struct {
+ f commandFunc
+ bm bool // is byte mode
+ op []operand
+}
+
+var (
+ ops = []struct {
+ f commandFunc
+ byteMode bool // supports byte mode
+ nops int // number of operands
+ jop bool // is a jump op
+ }{
+ {mov, true, 2, false},
+ {cmp, true, 2, false},
+ {add, true, 2, false},
+ {sub, true, 2, false},
+ {jz, false, 1, true},
+ {jnz, false, 1, true},
+ {inc, true, 1, false},
+ {dec, true, 1, false},
+ {jmp, false, 1, true},
+ {xor, true, 2, false},
+ {and, true, 2, false},
+ {or, true, 2, false},
+ {test, true, 2, false},
+ {js, false, 1, true},
+ {jns, false, 1, true},
+ {jb, false, 1, true},
+ {jbe, false, 1, true},
+ {ja, false, 1, true},
+ {jae, false, 1, true},
+ {push, false, 1, false},
+ {pop, false, 1, false},
+ {call, false, 1, true},
+ {ret, false, 0, false},
+ {not, true, 1, false},
+ {shl, true, 2, false},
+ {shr, true, 2, false},
+ {sar, true, 2, false},
+ {neg, true, 1, false},
+ {pusha, false, 0, false},
+ {popa, false, 0, false},
+ {pushf, false, 0, false},
+ {popf, false, 0, false},
+ {movzx, false, 2, false},
+ {movsx, false, 2, false},
+ {xchg, true, 2, false},
+ {mul, true, 2, false},
+ {div, true, 2, false},
+ {adc, true, 2, false},
+ {sbb, true, 2, false},
+ {print, false, 0, false},
+ }
+)
+
+func mov(v *vm, bm bool, op []operand) {
+ op[0].set(v, bm, op[1].get(v, bm))
+}
+
+func cmp(v *vm, bm bool, op []operand) {
+ v1 := op[0].get(v, bm)
+ r := v1 - op[1].get(v, bm)
+ if r == 0 {
+ v.fl = flagZ
+ } else {
+ v.fl = 0
+ if r > v1 {
+ v.fl = flagC
+ }
+ v.fl |= r & flagS
+ }
+}
+
+func add(v *vm, bm bool, op []operand) {
+ v1 := op[0].get(v, bm)
+ r := v1 + op[1].get(v, bm)
+ v.fl = 0
+ signBit := uint32(flagS)
+ if bm {
+ r &= 0xFF
+ signBit = 0x80
+ }
+ if r < v1 {
+ v.fl |= flagC
+ }
+ if r == 0 {
+ v.fl |= flagZ
+ } else if r&signBit > 0 {
+ v.fl |= flagS
+ }
+ op[0].set(v, bm, r)
+}
+
+func sub(v *vm, bm bool, op []operand) {
+ v1 := op[0].get(v, bm)
+ r := v1 - op[1].get(v, bm)
+ v.fl = 0
+
+ if r == 0 {
+ v.fl = flagZ
+ } else {
+ v.fl = 0
+ if r > v1 {
+ v.fl = flagC
+ }
+ v.fl |= r & flagS
+ }
+ op[0].set(v, bm, r)
+}
+
+func jz(v *vm, bm bool, op []operand) {
+ if v.fl&flagZ > 0 {
+ v.setIP(op[0].get(v, false))
+ }
+}
+
+func jnz(v *vm, bm bool, op []operand) {
+ if v.fl&flagZ == 0 {
+ v.setIP(op[0].get(v, false))
+ }
+}
+
+func inc(v *vm, bm bool, op []operand) {
+ r := op[0].get(v, bm) + 1
+ if bm {
+ r &= 0xFF
+ }
+ op[0].set(v, bm, r)
+ if r == 0 {
+ v.fl = flagZ
+ } else {
+ v.fl = r & flagS
+ }
+}
+
+func dec(v *vm, bm bool, op []operand) {
+ r := op[0].get(v, bm) - 1
+ op[0].set(v, bm, r)
+ if r == 0 {
+ v.fl = flagZ
+ } else {
+ v.fl = r & flagS
+ }
+}
+
+func jmp(v *vm, bm bool, op []operand) {
+ v.setIP(op[0].get(v, false))
+}
+
+func xor(v *vm, bm bool, op []operand) {
+ r := op[0].get(v, bm) ^ op[1].get(v, bm)
+ op[0].set(v, bm, r)
+ if r == 0 {
+ v.fl = flagZ
+ } else {
+ v.fl = r & flagS
+ }
+}
+
+func and(v *vm, bm bool, op []operand) {
+ r := op[0].get(v, bm) & op[1].get(v, bm)
+ op[0].set(v, bm, r)
+ if r == 0 {
+ v.fl = flagZ
+ } else {
+ v.fl = r & flagS
+ }
+}
+
+func or(v *vm, bm bool, op []operand) {
+ r := op[0].get(v, bm) | op[1].get(v, bm)
+ op[0].set(v, bm, r)
+ if r == 0 {
+ v.fl = flagZ
+ } else {
+ v.fl = r & flagS
+ }
+}
+
+func test(v *vm, bm bool, op []operand) {
+ r := op[0].get(v, bm) & op[1].get(v, bm)
+ if r == 0 {
+ v.fl = flagZ
+ } else {
+ v.fl = r & flagS
+ }
+}
+
+func js(v *vm, bm bool, op []operand) {
+ if v.fl&flagS > 0 {
+ v.setIP(op[0].get(v, false))
+ }
+}
+
+func jns(v *vm, bm bool, op []operand) {
+ if v.fl&flagS == 0 {
+ v.setIP(op[0].get(v, false))
+ }
+}
+
+func jb(v *vm, bm bool, op []operand) {
+ if v.fl&flagC > 0 {
+ v.setIP(op[0].get(v, false))
+ }
+}
+
+func jbe(v *vm, bm bool, op []operand) {
+ if v.fl&(flagC|flagZ) > 0 {
+ v.setIP(op[0].get(v, false))
+ }
+}
+
+func ja(v *vm, bm bool, op []operand) {
+ if v.fl&(flagC|flagZ) == 0 {
+ v.setIP(op[0].get(v, false))
+ }
+}
+
+func jae(v *vm, bm bool, op []operand) {
+ if v.fl&flagC == 0 {
+ v.setIP(op[0].get(v, false))
+ }
+}
+
+func push(v *vm, bm bool, op []operand) {
+ v.r[7] -= 4
+ opRI(7).set(v, false, op[0].get(v, false))
+
+}
+
+func pop(v *vm, bm bool, op []operand) {
+ op[0].set(v, false, opRI(7).get(v, false))
+ v.r[7] += 4
+}
+
+func call(v *vm, bm bool, op []operand) {
+ v.r[7] -= 4
+ opRI(7).set(v, false, v.ip+1)
+ v.setIP(op[0].get(v, false))
+}
+
+func ret(v *vm, bm bool, op []operand) {
+ r7 := v.r[7]
+ if r7 >= vmSize {
+ v.setIP(0xFFFFFFFF) // trigger end of program
+ } else {
+ v.setIP(binary.LittleEndian.Uint32(v.m[r7:]))
+ v.r[7] += 4
+ }
+}
+
+func not(v *vm, bm bool, op []operand) {
+ op[0].set(v, bm, ^op[0].get(v, bm))
+}
+
+func shl(v *vm, bm bool, op []operand) {
+ v1 := op[0].get(v, bm)
+ v2 := op[1].get(v, bm)
+ r := v1 << v2
+ op[0].set(v, bm, r)
+ if r == 0 {
+ v.fl = flagZ
+ } else {
+ v.fl = r & flagS
+ }
+ if (v1<<(v2-1))&0x80000000 > 0 {
+ v.fl |= flagC
+ }
+}
+
+func shr(v *vm, bm bool, op []operand) {
+ v1 := op[0].get(v, bm)
+ v2 := op[1].get(v, bm)
+ r := v1 >> v2
+ op[0].set(v, bm, r)
+ if r == 0 {
+ v.fl = flagZ
+ } else {
+ v.fl = r & flagS
+ }
+ if (v1>>(v2-1))&0x1 > 0 {
+ v.fl |= flagC
+ }
+}
+
+func sar(v *vm, bm bool, op []operand) {
+ v1 := op[0].get(v, bm)
+ v2 := op[1].get(v, bm)
+ r := uint32(int32(v1) >> v2)
+ op[0].set(v, bm, r)
+ if r == 0 {
+ v.fl = flagZ
+ } else {
+ v.fl = r & flagS
+ }
+ if (v1>>(v2-1))&0x1 > 0 {
+ v.fl |= flagC
+ }
+}
+
+func neg(v *vm, bm bool, op []operand) {
+ r := 0 - op[0].get(v, bm)
+ op[0].set(v, bm, r)
+ if r == 0 {
+ v.fl = flagZ
+ } else {
+ v.fl = r&flagS | flagC
+ }
+}
+
+func pusha(v *vm, bm bool, op []operand) {
+ sp := opD(v.r[7])
+ for _, r := range v.r {
+ sp = (sp - 4) & vmMask
+ sp.set(v, false, r)
+ }
+ v.r[7] = uint32(sp)
+}
+
+func popa(v *vm, bm bool, op []operand) {
+ sp := opD(v.r[7])
+ for i := 7; i >= 0; i-- {
+ v.r[i] = sp.get(v, false)
+ sp = (sp + 4) & vmMask
+ }
+}
+
+func pushf(v *vm, bm bool, op []operand) {
+ v.r[7] -= 4
+ opRI(7).set(v, false, v.fl)
+}
+
+func popf(v *vm, bm bool, op []operand) {
+ v.fl = opRI(7).get(v, false)
+ v.r[7] += 4
+}
+
+func movzx(v *vm, bm bool, op []operand) {
+ op[0].set(v, false, op[1].get(v, true))
+}
+
+func movsx(v *vm, bm bool, op []operand) {
+ op[0].set(v, false, uint32(int8(op[1].get(v, true))))
+}
+
+func xchg(v *vm, bm bool, op []operand) {
+ v1 := op[0].get(v, bm)
+ op[0].set(v, bm, op[1].get(v, bm))
+ op[1].set(v, bm, v1)
+}
+
+func mul(v *vm, bm bool, op []operand) {
+ r := op[0].get(v, bm) * op[1].get(v, bm)
+ op[0].set(v, bm, r)
+}
+
+func div(v *vm, bm bool, op []operand) {
+ div := op[1].get(v, bm)
+ if div != 0 {
+ r := op[0].get(v, bm) / div
+ op[0].set(v, bm, r)
+ }
+}
+
+func adc(v *vm, bm bool, op []operand) {
+ v1 := op[0].get(v, bm)
+ fc := v.fl & flagC
+ r := v1 + op[1].get(v, bm) + fc
+ if bm {
+ r &= 0xFF
+ }
+ op[0].set(v, bm, r)
+
+ if r == 0 {
+ v.fl = flagZ
+ } else {
+ v.fl = r & flagS
+ }
+ if r < v1 || (r == v1 && fc > 0) {
+ v.fl |= flagC
+ }
+}
+
+func sbb(v *vm, bm bool, op []operand) {
+ v1 := op[0].get(v, bm)
+ fc := v.fl & flagC
+ r := v1 - op[1].get(v, bm) - fc
+ if bm {
+ r &= 0xFF
+ }
+ op[0].set(v, bm, r)
+
+ if r == 0 {
+ v.fl = flagZ
+ } else {
+ v.fl = r & flagS
+ }
+ if r > v1 || (r == v1 && fc > 0) {
+ v.fl |= flagC
+ }
+}
+
+func print(v *vm, bm bool, op []operand) {
+ // TODO: ignore print for the moment
+}
+
+func decodeArg(br *rarBitReader, byteMode bool) (operand, error) {
+ n, err := br.readBits(1)
+ if err != nil {
+ return nil, err
+ }
+ if n > 0 { // Register
+ n, err = br.readBits(3)
+ return opR(n), err
+ }
+ n, err = br.readBits(1)
+ if err != nil {
+ return nil, err
+ }
+ if n == 0 { // Immediate
+ if byteMode {
+ n, err = br.readBits(8)
+ } else {
+ m, err := br.readUint32()
+ return opI(m), err
+ }
+ return opI(n), err
+ }
+ n, err = br.readBits(1)
+ if err != nil {
+ return nil, err
+ }
+ if n == 0 {
+ // Register Indirect
+ n, err = br.readBits(3)
+ return opRI(n), err
+ }
+ n, err = br.readBits(1)
+ if err != nil {
+ return nil, err
+ }
+ if n == 0 {
+ // Base + Index Indirect
+ n, err = br.readBits(3)
+ if err != nil {
+ return nil, err
+ }
+ i, err := br.readUint32()
+ return opBI{r: uint32(n), i: i}, err
+ }
+ // Direct addressing
+ m, err := br.readUint32()
+ return opD(m & vmMask), err
+}
+
+func fixJumpOp(op operand, off int) operand {
+ n, ok := op.(opI)
+ if !ok {
+ return op
+ }
+ if n >= 256 {
+ return n - 256
+ }
+ if n >= 136 {
+ n -= 264
+ } else if n >= 16 {
+ n -= 8
+ } else if n >= 8 {
+ n -= 16
+ }
+ return n + opI(off)
+}
+
+func readCommands(br *rarBitReader) ([]command, error) {
+ var cmds []command
+
+ for {
+ code, err := br.readBits(4)
+ if err != nil {
+ return cmds, err
+ }
+ if code&0x08 > 0 {
+ n, err := br.readBits(2)
+ if err != nil {
+ return cmds, err
+ }
+ code = (code<<2 | n) - 24
+ }
+
+ if code >= len(ops) {
+ return cmds, errInvalidVMInstruction
+ }
+ ins := ops[code]
+
+ var com command
+
+ if ins.byteMode {
+ n, err := br.readBits(1)
+ if err != nil {
+ return cmds, err
+ }
+ com.bm = n > 0
+ }
+ com.f = ins.f
+
+ if ins.nops > 0 {
+ com.op = make([]operand, ins.nops)
+ com.op[0], err = decodeArg(br, com.bm)
+ if err != nil {
+ return cmds, err
+ }
+ if ins.nops == 2 {
+ com.op[1], err = decodeArg(br, com.bm)
+ if err != nil {
+ return cmds, err
+ }
+ } else if ins.jop {
+ com.op[0] = fixJumpOp(com.op[0], len(cmds))
+ }
+ }
+ cmds = append(cmds, com)
+ }
+}