diff options
Diffstat (limited to 'bencode/decode.go')
| -rw-r--r-- | bencode/decode.go | 84 |
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) } |
