forked from forgejo/forgejo
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>
This commit is contained in:
parent
209b17c4e2
commit
684b7a999f
303 changed files with 301317 additions and 1183 deletions
23
vendor/github.com/nwaples/rardecode/LICENSE
generated
vendored
Normal file
23
vendor/github.com/nwaples/rardecode/LICENSE
generated
vendored
Normal file
|
@ -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.
|
4
vendor/github.com/nwaples/rardecode/README.md
generated
vendored
Normal file
4
vendor/github.com/nwaples/rardecode/README.md
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
# rardecode
|
||||
[](https://godoc.org/github.com/nwaples/rardecode)
|
||||
|
||||
A go package for reading RAR archives.
|
306
vendor/github.com/nwaples/rardecode/archive.go
generated
vendored
Normal file
306
vendor/github.com/nwaples/rardecode/archive.go
generated
vendored
Normal file
|
@ -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
|
||||
}
|
468
vendor/github.com/nwaples/rardecode/archive15.go
generated
vendored
Normal file
468
vendor/github.com/nwaples/rardecode/archive15.go
generated
vendored
Normal file
|
@ -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
|
||||
}
|
475
vendor/github.com/nwaples/rardecode/archive50.go
generated
vendored
Normal file
475
vendor/github.com/nwaples/rardecode/archive50.go
generated
vendored
Normal file
|
@ -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
|
||||
}
|
119
vendor/github.com/nwaples/rardecode/bit_reader.go
generated
vendored
Normal file
119
vendor/github.com/nwaples/rardecode/bit_reader.go
generated
vendored
Normal file
|
@ -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}
|
||||
}
|
264
vendor/github.com/nwaples/rardecode/decode29.go
generated
vendored
Normal file
264
vendor/github.com/nwaples/rardecode/decode29.go
generated
vendored
Normal file
|
@ -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
|
||||
}
|
247
vendor/github.com/nwaples/rardecode/decode29_lz.go
generated
vendored
Normal file
247
vendor/github.com/nwaples/rardecode/decode29_lz.go
generated
vendored
Normal file
|
@ -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
|
||||
}
|
132
vendor/github.com/nwaples/rardecode/decode29_ppm.go
generated
vendored
Normal file
132
vendor/github.com/nwaples/rardecode/decode29_ppm.go
generated
vendored
Normal file
|
@ -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
|
||||
}
|
294
vendor/github.com/nwaples/rardecode/decode50.go
generated
vendored
Normal file
294
vendor/github.com/nwaples/rardecode/decode50.go
generated
vendored
Normal file
|
@ -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
|
||||
}
|
290
vendor/github.com/nwaples/rardecode/decode_reader.go
generated
vendored
Normal file
290
vendor/github.com/nwaples/rardecode/decode_reader.go
generated
vendored
Normal file
|
@ -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
|
||||
}
|
126
vendor/github.com/nwaples/rardecode/decrypt_reader.go
generated
vendored
Normal file
126
vendor/github.com/nwaples/rardecode/decrypt_reader.go
generated
vendored
Normal file
|
@ -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)
|
||||
}
|
416
vendor/github.com/nwaples/rardecode/filters.go
generated
vendored
Normal file
416
vendor/github.com/nwaples/rardecode/filters.go
generated
vendored
Normal file
|
@ -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
|
||||
}
|
1
vendor/github.com/nwaples/rardecode/go.mod
generated
vendored
Normal file
1
vendor/github.com/nwaples/rardecode/go.mod
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
module github.com/nwaples/rardecode
|
208
vendor/github.com/nwaples/rardecode/huffman.go
generated
vendored
Normal file
208
vendor/github.com/nwaples/rardecode/huffman.go
generated
vendored
Normal file
|
@ -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
|
||||
}
|
1096
vendor/github.com/nwaples/rardecode/ppm_model.go
generated
vendored
Normal file
1096
vendor/github.com/nwaples/rardecode/ppm_model.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
369
vendor/github.com/nwaples/rardecode/reader.go
generated
vendored
Normal file
369
vendor/github.com/nwaples/rardecode/reader.go
generated
vendored
Normal file
|
@ -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
|
||||
}
|
687
vendor/github.com/nwaples/rardecode/vm.go
generated
vendored
Normal file
687
vendor/github.com/nwaples/rardecode/vm.go
generated
vendored
Normal file
|
@ -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)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue