1
0
Fork 0
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:
PhilippHomann 2020-06-05 22:47:39 +02:00 committed by GitHub
parent 209b17c4e2
commit 684b7a999f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
303 changed files with 301317 additions and 1183 deletions

23
vendor/github.com/nwaples/rardecode/LICENSE generated vendored Normal file
View 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
View file

@ -0,0 +1,4 @@
# rardecode
[![GoDoc](https://godoc.org/github.com/nwaples/rardecode?status.svg)](https://godoc.org/github.com/nwaples/rardecode)
A go package for reading RAR archives.

306
vendor/github.com/nwaples/rardecode/archive.go generated vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View file

@ -0,0 +1 @@
module github.com/nwaples/rardecode

208
vendor/github.com/nwaples/rardecode/huffman.go generated vendored Normal file
View 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

File diff suppressed because it is too large Load diff

369
vendor/github.com/nwaples/rardecode/reader.go generated vendored Normal file
View 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
View 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)
}
}