diff options
author | PhilippHomann <homann.philipp@googlemail.com> | 2020-06-05 22:47:39 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-05 16:47:39 -0400 |
commit | 684b7a999f6e3b928ad4ae993f92a6b83e0c4486 (patch) | |
tree | 64cfa190c811053f0d111ef73ac8e31858db0624 /vendor/github.com/nwaples | |
parent | 209b17c4e25fe72d2fdf46f412fc388bc274a516 (diff) | |
download | gitea-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')
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) + } +} |