-
Notifications
You must be signed in to change notification settings - Fork 0
/
decoder.go
152 lines (140 loc) · 3.3 KB
/
decoder.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package bencode
import "errors"
var (
// Error for when the user tries to read a specific type of bencode
// but the bencode doesn't provide that type
ErrInvalidType = errors.New("invalid bencode output type")
// Error indicating an invalid string length such as "-1:"
ErrInvalidStringLen = errors.New("invalid bencode: string length can't be negative")
)
// A generic bencode reader interface
type bencodeReader interface {
// Returns the next byte
readByte() (byte, error)
// Backtracks by 1 byte
//
// MUST only be called at most once immediately following a call to nextByte()
undoReadByte()
// Reads a number until an end byte
readIntTo(separator byte) (int, error)
// Returns a string of a given length
readString(length int) (string, error)
}
// A bencode decoder
type decoder struct {
bencodeReader
}
// Reads a single integer from the decoder.
func (d *decoder) AsInt() (int, error) {
if b, err := d.readByte(); err != nil {
return 0, err
} else if b != 'i' {
return 0, ErrInvalidType
}
return d.readIntTo('e')
}
// Reads a single string from the decoder.
func (d *decoder) AsString() (string, error) {
length, err := d.readIntTo(':')
if err != nil {
return "", err
}
if length < 0 {
return "", ErrInvalidStringLen
}
return d.readString(length)
}
// Reads a single list from the decoder.
// Assumes that the first 'l' has been read.
func (d *decoder) asList() ([]interface{}, error) {
list := []interface{}{}
for {
// Read type
t, err := d.readByte()
if err != nil {
return list, err
}
if t == 'e' {
break
}
// Read object
obj, err := d.asInterface(t)
if err != nil {
return list, err
}
// Add to list
list = append(list, obj)
}
return list, nil
}
// Reads a single list from the decoder.
func (d *decoder) AsList() ([]interface{}, error) {
if b, err := d.readByte(); err != nil {
return nil, err
} else if b != 'l' {
return nil, ErrInvalidType
}
return d.asList()
}
// Reads a single dictionary from the decoder.
// Assumes that the first 'd' has been read.
func (d *decoder) asDict() (map[string]interface{}, error) {
dict := map[string]interface{}{}
for {
// Check if end
if t, err := d.readByte(); err != nil {
return dict, err
} else if t == 'e' {
break
}
d.undoReadByte()
// Read key
key, err := d.AsString()
if err != nil {
return dict, err
}
// Read value's type
t, err := d.readByte()
if err != nil {
return dict, err
}
// Read value
value, err := d.asInterface(t)
if err != nil {
return dict, err
}
// Add to map
dict[key] = value
}
return dict, nil
}
// Reads a single dictionary from the decoder.
func (d *decoder) AsDict() (map[string]interface{}, error) {
if b, err := d.readByte(); err != nil {
return nil, err
} else if b != 'd' {
return nil, ErrInvalidType
}
return d.asDict()
}
// Reads from the decoder and returns an interface.
// Expects a type byte to be provided.
func (d *decoder) asInterface(t byte) (interface{}, error) {
if t == 'i' {
return d.readIntTo('e')
} else if t == 'l' {
return d.asList()
} else if t == 'd' {
return d.asDict()
}
d.undoReadByte()
return d.AsString()
}
// Reads from the decoder and returns an interface.
func (d *decoder) AsInterface() (interface{}, error) {
t, err := d.readByte()
if err != nil {
return nil, err
}
return d.asInterface(t)
}