|
1 | 1 | package decoder |
2 | 2 |
|
3 | 3 | import ( |
4 | | - "bytes" |
5 | 4 | "errors" |
6 | | - "strconv" |
| 5 | + _ "unsafe" |
7 | 6 |
|
8 | 7 | "github.com/IncSW/go-bencode/internal" |
9 | 8 | ) |
10 | 9 |
|
11 | | -func Unmarshal(data []byte) (interface{}, error) { |
12 | | - return (&unmarshaler{ |
13 | | - data: data, |
14 | | - length: len(data), |
15 | | - }).unmarshal() |
16 | | -} |
17 | | - |
18 | | -type unmarshaler struct { |
| 10 | +type Decoder struct { |
19 | 11 | data []byte |
20 | 12 | length int |
21 | 13 | cursor int |
22 | 14 | } |
23 | 15 |
|
24 | | -func (u *unmarshaler) unmarshal() (interface{}, error) { |
25 | | - switch u.data[u.cursor] { |
26 | | - case 'i': |
27 | | - u.cursor += 1 |
28 | | - index := bytes.IndexByte(u.data[u.cursor:], 'e') |
29 | | - if index == -1 { |
30 | | - return nil, errors.New("bencode: invalid integer field") |
31 | | - } |
32 | | - index += u.cursor |
33 | | - integer, err := strconv.ParseInt(internal.B2S(u.data[u.cursor:index]), 10, 64) |
34 | | - if err != nil { |
35 | | - return nil, err |
36 | | - } |
37 | | - u.cursor = index + 1 |
38 | | - return integer, nil |
| 16 | +func (d *Decoder) Decode(data []byte) (interface{}, error) { |
| 17 | + d.data = data |
| 18 | + d.length = len(data) |
| 19 | + return d.decode() |
| 20 | +} |
39 | 21 |
|
| 22 | +func (d *Decoder) decode() (interface{}, error) { |
| 23 | + switch d.data[d.cursor] { |
| 24 | + case 'i': |
| 25 | + return d.decodeInt() |
40 | 26 | case 'l': |
41 | | - u.cursor += 1 |
| 27 | + d.cursor += 1 |
42 | 28 | list := []interface{}{} |
43 | 29 | for { |
44 | | - if u.cursor == u.length { |
| 30 | + if d.cursor == d.length { |
45 | 31 | return nil, errors.New("bencode: invalid list field") |
46 | 32 | } |
47 | | - if u.data[u.cursor] == 'e' { |
48 | | - u.cursor += 1 |
| 33 | + if d.data[d.cursor] == 'e' { |
| 34 | + d.cursor += 1 |
49 | 35 | return list, nil |
50 | 36 | } |
51 | | - value, err := u.unmarshal() |
| 37 | + value, err := d.decode() |
52 | 38 | if err != nil { |
53 | 39 | return nil, err |
54 | 40 | } |
55 | 41 | list = append(list, value) |
56 | 42 | } |
57 | | - |
58 | 43 | case 'd': |
59 | | - u.cursor += 1 |
| 44 | + d.cursor += 1 |
60 | 45 | dictionary := map[string]interface{}{} |
61 | 46 | for { |
62 | | - if u.cursor == u.length { |
| 47 | + if d.cursor == d.length { |
63 | 48 | return nil, errors.New("bencode: invalid dictionary field") |
64 | 49 | } |
65 | | - if u.data[u.cursor] == 'e' { |
66 | | - u.cursor += 1 |
| 50 | + if d.data[d.cursor] == 'e' { |
| 51 | + d.cursor += 1 |
67 | 52 | return dictionary, nil |
68 | 53 | } |
69 | | - key, err := u.unmarshalString() |
| 54 | + key, err := d.decodeBytes() |
70 | 55 | if err != nil { |
71 | 56 | return nil, errors.New("bencode: non-string dictionary key") |
72 | 57 | } |
73 | | - value, err := u.unmarshal() |
| 58 | + value, err := d.decode() |
74 | 59 | if err != nil { |
75 | 60 | return nil, err |
76 | 61 | } |
77 | 62 | dictionary[internal.B2S(key)] = value |
78 | 63 | } |
79 | | - |
80 | 64 | default: |
81 | | - return u.unmarshalString() |
82 | | - } |
83 | | -} |
84 | | - |
85 | | -func (u *unmarshaler) unmarshalString() ([]byte, error) { |
86 | | - if u.data[u.cursor] < '0' || u.data[u.cursor] > '9' { |
87 | | - return nil, errors.New("bencode: invalid string field") |
88 | | - } |
89 | | - index := bytes.IndexByte(u.data[u.cursor:], ':') |
90 | | - if index == -1 { |
91 | | - return nil, errors.New("bencode: invalid string field") |
92 | | - } |
93 | | - index += u.cursor |
94 | | - stringLength, err := strconv.ParseInt(internal.B2S(u.data[u.cursor:index]), 10, 64) |
95 | | - if err != nil { |
96 | | - return nil, err |
97 | | - } |
98 | | - index += 1 |
99 | | - endIndex := index + int(stringLength) |
100 | | - if endIndex > u.length { |
101 | | - return nil, errors.New("bencode: not a valid bencoded string") |
| 65 | + return d.decodeBytes() |
102 | 66 | } |
103 | | - value := u.data[index:endIndex] |
104 | | - u.cursor = endIndex |
105 | | - return value, nil |
106 | 67 | } |
0 commit comments