-
-
Notifications
You must be signed in to change notification settings - Fork 4k
/
decode.go
84 lines (76 loc) · 1.95 KB
/
decode.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
package filename
import (
"bytes"
"encoding/base64"
"encoding/binary"
"errors"
"sync"
"github.com/klauspost/compress/huff0"
)
// ErrCorrupted is returned if a provided encoded filename cannot be decoded.
var ErrCorrupted = errors.New("file name corrupt")
// ErrUnsupported is returned if a provided encoding may come from a future version or the file name is corrupt.
var ErrUnsupported = errors.New("file name possibly generated by future version of rclone")
// Custom decoder for tableCustom types. Stateful, so must have lock.
var customDec huff0.Scratch
var customDecMu sync.Mutex
// Decode an encoded string.
func Decode(s string) (string, error) {
if len(s) < 1 {
return "", ErrCorrupted
}
table := decodeMap[s[0]]
if table == 0 {
return "", ErrCorrupted
}
table--
s = s[1:]
data := make([]byte, base64.URLEncoding.DecodedLen(len(s)))
n, err := base64.URLEncoding.Decode(data, ([]byte)(s))
if err != nil || n < 0 {
return "", ErrCorrupted
}
data = data[:n]
switch table {
case tableUncompressed:
return string(data), nil
case tableReserved:
return "", ErrUnsupported
case tableRLE:
if len(data) < 2 {
return "", ErrCorrupted
}
n, used := binary.Uvarint(data[:len(data)-1])
if used <= 0 || n > maxLength {
return "", ErrCorrupted
}
return string(bytes.Repeat(data[len(data)-1:], int(n))), nil
case tableCustom:
customDecMu.Lock()
defer customDecMu.Unlock()
_, data, err := huff0.ReadTable(data, &customDec)
if err != nil {
return "", ErrCorrupted
}
customDec.MaxDecodedSize = maxLength
decoded, err := customDec.Decompress1X(data)
if err != nil {
return "", ErrCorrupted
}
return string(decoded), nil
default:
if table >= byte(len(decTables)) {
return "", ErrCorrupted
}
dec := decTables[table]
if dec == nil {
return "", ErrUnsupported
}
var dst [maxLength]byte
name, err := dec.Decompress1X(dst[:0], data)
if err != nil {
return "", ErrCorrupted
}
return string(name), nil
}
}