forked from nwaples/rardecode
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patharchive.go
130 lines (115 loc) · 3.85 KB
/
archive.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package rardecode
import (
"errors"
"hash"
)
const (
_ = iota
decode20Ver
decode29Ver
decode50Ver
decode70Ver
)
var (
ErrCorruptBlockHeader = errors.New("rardecode: corrupt block header")
ErrCorruptFileHeader = errors.New("rardecode: corrupt file header")
ErrBadHeaderCRC = errors.New("rardecode: bad header crc")
ErrUnknownDecoder = errors.New("rardecode: unknown decoder version")
ErrDecoderOutOfData = errors.New("rardecode: decoder expected more data than is in packed file")
ErrArchiveEncrypted = errors.New("rardecode: archive encrypted, password required")
ErrArchivedFileEncrypted = errors.New("rardecode: archived files encrypted, password required")
)
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) uint64() uint64 {
v := uint64((*b)[0]) | uint64((*b)[1])<<8 | uint64((*b)[2])<<16 | uint64((*b)[3])<<24 |
uint64((*b)[4])<<32 | uint64((*b)[5])<<40 | uint64((*b)[6])<<48 | uint64((*b)[7])<<56
*b = (*b)[8:]
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
}
// sliceReader implements the readSlice and peek functions.
// The slices returned are only valid till the next readSlice or peek call.
// If n bytes arent available no slice will be returned with the error value set.
// The error is io.EOF only of 0 bytes were found, otherwise io.ErrUnexpectedEOF
// will be returned on a short read.
// The capacity of the slice returned by readSlice must reflect how much data was read
// to return the n bytes (eg. an encrypted reader has to decrypt in multiples of a
// block size so may need to read more than n bytes).
type sliceReader interface {
readSlice(n int) ([]byte, error) // return the next n bytes
peek(n int) ([]byte, error) // return the next n bytes withough advancing reader
}
// 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
arcSolid bool // archive is solid
winSize int // decode window size
hash func() hash.Hash // hash used for file checksum
hashKey []byte // optional hmac key to be used calculate file checksum
sum []byte // expected checksum for file contents
decVer int // 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
genKeys func() error // generates key & iv fields
FileHeader
}
// fileBlockReader returns the next fileBlockHeader in a volume.
type fileBlockReader interface {
next(v *volume) (*fileBlockHeader, error) // reads the volume and returns the next fileBlockHeader
clone() fileBlockReader // makes a copy of the fileBlockReader
}
func newFileBlockReader(v *volume) (fileBlockReader, error) {
pass := v.opt.pass
if pass != nil {
runes := []rune(*pass)
if len(runes) > maxPassword {
pw := string(runes[:maxPassword])
pass = &pw
}
}
switch v.ver {
case 0:
return newArchive15(pass), nil
case 1:
return newArchive50(pass), nil
default:
return nil, ErrUnknownVersion
}
}