Skip to content

Commit f0d3ac3

Browse files
committed
update unmarshaler
1 parent f2c8682 commit f0d3ac3

File tree

2 files changed

+69
-71
lines changed

2 files changed

+69
-71
lines changed

unmarshaler.go

Lines changed: 53 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,101 @@
11
package bencode
22

33
import (
4+
"bytes"
45
"errors"
56
"strconv"
67
)
78

8-
func readUntil(data []byte, symbol byte) ([]byte, int, bool) {
9-
for i, b := range data {
10-
if b == symbol {
11-
return data[:i], i, true
12-
}
13-
}
14-
return nil, 0, false
9+
func Unmarshal(data []byte) (interface{}, error) {
10+
return (&unmarshaler{
11+
data: data,
12+
length: len(data),
13+
}).unmarshal()
1514
}
1615

17-
func Unmarshal(data []byte) (interface{}, error) {
18-
result, _, err := unmarshal(data)
19-
if err != nil {
20-
return nil, err
21-
}
22-
return result, nil
16+
type unmarshaler struct {
17+
data []byte
18+
length int
19+
cursor int
2320
}
2421

25-
func unmarshal(data []byte) (interface{}, int, error) {
26-
switch data[0] {
22+
func (u *unmarshaler) unmarshal() (interface{}, error) {
23+
switch u.data[u.cursor] {
2724
case 'i':
28-
integerBuffer, length, ok := readUntil(data[1:], 'e')
29-
if !ok {
30-
return nil, 0, errors.New("bencode: invalid integer field")
25+
u.cursor += 1
26+
index := bytes.IndexByte(u.data[u.cursor:], 'e')
27+
if index == -1 {
28+
return nil, errors.New("bencode: invalid integer field")
3129
}
32-
integer, err := strconv.ParseInt(b2s(integerBuffer), 10, 64)
30+
index += u.cursor
31+
integer, err := strconv.ParseInt(b2s(u.data[u.cursor:index]), 10, 64)
3332
if err != nil {
34-
return nil, 0, err
33+
return nil, err
3534
}
36-
return integer, length + 2, nil
35+
u.cursor = index + 1
36+
return integer, nil
3737

3838
case 'l':
39+
u.cursor += 1
3940
list := []interface{}{}
40-
totalLength := 2
41-
data = data[1:]
4241
for {
43-
if len(data) == 0 {
44-
return nil, 0, errors.New("bencode: invalid list field")
42+
if u.cursor == u.length {
43+
return nil, errors.New("bencode: invalid list field")
4544
}
46-
if data[0] == 'e' {
47-
return list, totalLength, nil
45+
if u.data[u.cursor] == 'e' {
46+
u.cursor += 1
47+
return list, nil
4848
}
49-
value, length, err := unmarshal(data)
49+
value, err := u.unmarshal()
5050
if err != nil {
51-
return nil, 0, err
51+
return nil, err
5252
}
5353
list = append(list, value)
54-
data = data[length:]
55-
totalLength += length
5654
}
5755

5856
case 'd':
57+
u.cursor += 1
5958
dictionary := map[string]interface{}{}
60-
totalLength := 2
61-
data = data[1:]
6259
for {
63-
if len(data) == 0 {
64-
return nil, 0, errors.New("bencode: invalid dictionary field")
60+
if u.cursor == u.length {
61+
return nil, errors.New("bencode: invalid dictionary field")
6562
}
66-
if data[0] == 'e' {
67-
return dictionary, totalLength, nil
63+
if u.data[u.cursor] == 'e' {
64+
u.cursor += 1
65+
return dictionary, nil
6866
}
69-
value, length, err := unmarshal(data)
67+
value, err := u.unmarshal()
7068
if err != nil {
71-
return nil, 0, err
69+
return nil, err
7270
}
7371
key, ok := value.([]byte)
7472
if !ok {
75-
return nil, 0, errors.New("bencode: non-string dictionary key")
73+
return nil, errors.New("bencode: non-string dictionary key")
7674
}
77-
data = data[length:]
78-
totalLength += length
79-
value, length, err = unmarshal(data)
75+
value, err = u.unmarshal()
8076
if err != nil {
81-
return nil, 0, err
77+
return nil, err
8278
}
8379
dictionary[b2s(key)] = value
84-
data = data[length:]
85-
totalLength += length
8680
}
8781

8882
default:
89-
stringLengthBuffer, length, ok := readUntil(data, ':')
90-
if !ok {
91-
return nil, 0, errors.New("bencode: invalid string field")
83+
index := bytes.IndexByte(u.data[u.cursor:], ':')
84+
if index == -1 {
85+
return nil, errors.New("bencode: invalid string field")
9286
}
93-
stringLength, err := strconv.ParseInt(b2s(stringLengthBuffer), 10, 64)
87+
index += u.cursor
88+
stringLength, err := strconv.ParseInt(b2s(u.data[u.cursor:index]), 10, 64)
9489
if err != nil {
95-
return nil, 0, err
90+
return nil, err
9691
}
97-
endPosition := length + 1 + int(stringLength)
98-
if endPosition > len(data) {
99-
return nil, 0, errors.New("bencode: not a valid bencoded string")
92+
index += 1
93+
endIndex := index + int(stringLength)
94+
if endIndex > u.length {
95+
return nil, errors.New("bencode: not a valid bencoded string")
10096
}
101-
return data[length+1 : endPosition], endPosition, nil
97+
value := u.data[index:endIndex]
98+
u.cursor = endIndex
99+
return value, nil
102100
}
103101
}

unmarshaler_test.go

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,13 @@ var (
1414
func TestUnmarshal(t *testing.T) {
1515
assert := assert.New(t)
1616

17-
_, err := Unmarshal(unmarshalTestData)
18-
if !assert.NoError(err) {
19-
return
20-
}
21-
22-
_, err = Unmarshal(unmarshalWrongTestData)
23-
if !assert.Error(err) || !assert.Equal("bencode: not a valid bencoded string", err.Error()) {
24-
return
25-
}
26-
27-
data, length, ok := readUntil([]byte("38:udp://tracker.publicbt.com:80/announce"), ':')
28-
if !assert.True(ok) || !assert.Equal(2, length) || !assert.Equal([]byte("38"), data) {
29-
return
30-
}
31-
3217
result, err := Unmarshal([]byte("i38e"))
3318
if !assert.NoError(err) || !assert.Equal(int64(38), result) {
3419
return
3520
}
3621

3722
result, err = Unmarshal([]byte("38:udp://tracker.publicbt.com:80/announce"))
38-
if !assert.NoError(err) || !assert.Equal([]byte("udp://tracker.publicbt.com:80/announce"), result) {
23+
if !assert.NoError(err) || !assert.Equal("udp://tracker.publicbt.com:80/announce", string(result.([]byte))) {
3924
return
4025
}
4126

@@ -58,6 +43,16 @@ func TestUnmarshal(t *testing.T) {
5843
return
5944
}
6045

46+
_, err = Unmarshal(unmarshalTestData)
47+
if !assert.NoError(err) {
48+
return
49+
}
50+
51+
_, err = Unmarshal(unmarshalWrongTestData)
52+
if !assert.Error(err) || !assert.Equal("bencode: not a valid bencoded string", err.Error()) {
53+
return
54+
}
55+
6156
result, err = Unmarshal([]byte("i38"))
6257
if !assert.Error(err) || !assert.Nil(result) || !assert.Equal("bencode: invalid integer field", err.Error()) {
6358
return
@@ -87,6 +82,11 @@ func TestUnmarshal(t *testing.T) {
8782
if !assert.Error(err) || !assert.Nil(result) || !assert.Equal("bencode: invalid string field", err.Error()) {
8883
return
8984
}
85+
86+
result, err = Unmarshal([]byte("10:wasd"))
87+
if !assert.Error(err) || !assert.Nil(result) || !assert.Equal("bencode: not a valid bencoded string", err.Error()) {
88+
return
89+
}
9090
}
9191

9292
func BenchmarkUnmarshal(b *testing.B) {

0 commit comments

Comments
 (0)