aboutsummaryrefslogtreecommitdiff
path: root/bencode/decode.go
diff options
context:
space:
mode:
Diffstat (limited to 'bencode/decode.go')
-rw-r--r--bencode/decode.go84
1 files changed, 39 insertions, 45 deletions
diff --git a/bencode/decode.go b/bencode/decode.go
index 2e356c2..29b60f7 100644
--- a/bencode/decode.go
+++ b/bencode/decode.go
@@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"strconv"
- "unicode/utf8"
)
// Decode decodes a bencoded string to string, int, list or map.
@@ -14,53 +13,52 @@ func Decode(data []byte) (r interface{}, err error) {
}
// DecodeString decodes a string from a given index
-// It returns the string and the position of the last character
-// or the offset at the point of error
-func DecodeString(data []byte, start int) (r string, end int, err error) {
+// It returns the string, the number of bytes successfully read
+func DecodeString(data []byte, start int) (r string, n int, err error) {
if start >= len(data) || data[start] < '0' || data[start] > '9' {
err = errors.New("bencode: invalid string length")
- return r, 0, err
+ return r, 1, err
}
prefix, i, err := readUntil(data, start, ':')
+ end := start + i
if err != nil {
- return r, i, err
+ return r, end - start, err
}
length, err := strconv.ParseInt(string(prefix), 10, 0)
if err != nil {
- return r, 0, err
+ return r, end - start, err
}
-
- end = i + int(length)
+ end = end + int(length)
if end > len(data) || end < i {
err = errors.New("bencode: string length out of range")
- return r, end, err
+ return r, end - start, err
}
- return string(data[i:end]), end - 1, nil
+ return string(data[start+i : end]), end - start, nil
}
// DecodeInt decodes an integer value
-// It returns the integer and the position of the last character
+// It returns the integer and the number of bytes successfully read
func DecodeInt(data []byte, start int) (r int64, end int, err error) {
if start >= len(data) || data[start] != 'i' {
err = errors.New("bencode: invalid integer")
return r, end, err
}
- prefix, end, err := readUntil(data, start, 'e')
+ prefix, n, err := readUntil(data, start, 'e')
if err != nil {
- return r, end, err
+ return r, n, err
}
r, err = strconv.ParseInt(string(prefix[1:]), 10, 64)
- return r, end - 1, err
+ return r, n, err
}
// DecodeList decodes a list value
-// It returns the array and the position of the last character
+// It returns the array and the number of bytes successfully read
func DecodeList(data []byte, start int) (r []interface{}, end int, err error) {
if start >= len(data) {
return r, end, errors.New("bencode: list range error")
@@ -73,22 +71,22 @@ func DecodeList(data []byte, start int) (r []interface{}, end int, err error) {
// Empty list
if data[end] == 'e' {
- return r, end, nil
+ return r, 2, nil
}
var item interface{}
+ var n int
for end < len(data) {
- item, end, err = decodeItem(data, end)
+ item, n, err = decodeItem(data, end)
+ end = end + n
if err != nil {
- return r, end, err
+ return r, end - start, err
}
r = append(r, item)
- end++
- char, _ := utf8.DecodeRune(data[end:])
- if char == 'e' {
- return r, end, nil
+ if data[end] == 'e' {
+ return r, end - start + 1, nil
}
}
@@ -97,28 +95,27 @@ func DecodeList(data []byte, start int) (r []interface{}, end int, err error) {
// DecodeDict decodes a dict as a map
// It returns the map and the position of the last character
-func DecodeDict(data []byte, start int) (r map[string]interface{}, end int, err error) {
+func DecodeDict(data []byte, start int) (map[string]interface{}, int, error) {
+ r := make(map[string]interface{})
+
if start >= len(data) {
- return r, end, errors.New("bencode: dict range error")
+ return r, 0, errors.New("bencode: dict range error")
}
if data[start] != 'd' {
- return r, end, errors.New("bencode: invalid dict")
+ return r, 1, errors.New("bencode: invalid dict")
}
- end = start + 1
+ end := start + 1
// Empty dict
if data[end] == 'e' {
- return r, end, nil
+ return r, 2, nil
}
- var item interface{}
- var key string
- r = make(map[string]interface{})
-
for end < len(data) {
- key, end, err = DecodeString(data, end)
+ key, n, err := DecodeString(data, end)
+ end = end + n
if err != nil {
return r, end, errors.New("bencode: invalid dict key")
}
@@ -127,26 +124,24 @@ func DecodeDict(data []byte, start int) (r map[string]interface{}, end int, err
return r, end, errors.New("bencode: dict range error")
}
- end++
- item, end, err = decodeItem(data, end)
+ item, n, err := decodeItem(data, end)
+ end = end + n
+
if err != nil {
return r, end, err
}
r[key] = item
- end++
- char, _ := utf8.DecodeRune(data[end:])
- if char == 'e' {
- return r, end, nil
+ if data[end] == 'e' {
+ return r, end - start + 1, nil
}
}
return r, end, errors.New("bencode: invalid dict termination")
}
// decodeItem decodes the next type at the given index
-// It returns the index of the last character decoded
-func decodeItem(data []byte, start int) (r interface{}, end int, err error) {
+func decodeItem(data []byte, start int) (r interface{}, n int, err error) {
switch data[start] {
case 'l':
return DecodeList(data, start)
@@ -160,14 +155,13 @@ func decodeItem(data []byte, start int) (r interface{}, end int, err error) {
}
// Read until the given character
-// Returns the slice before the character and the index of the next character
-// or the offset at the point of error
+// Returns the slice before the character and the number of bytes successfully read
func readUntil(data []byte, start int, c byte) ([]byte, int, error) {
i := start
for ; i < len(data); i++ {
if data[i] == c {
- return data[start:i], i + 1, nil
+ return data[start:i], i - start + 1, nil
}
}
- return data, i, fmt.Errorf("bencode: '%b' not found", c)
+ return data, i - start, fmt.Errorf("bencode: '%b' not found", c)
}