move bencode to subdirectory
making room for other packages
This commit is contained in:
parent
c104c8e258
commit
0eb8ce1253
7 changed files with 3 additions and 0 deletions
27
bencode/LICENSE
Normal file
27
bencode/LICENSE
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
1
bencode/README.md
Normal file
1
bencode/README.md
Normal file
|
@ -0,0 +1 @@
|
|||
this is a copy from code.google.com/p/bencode-go
|
266
bencode/bencode_test.go
Normal file
266
bencode/bencode_test.go
Normal file
|
@ -0,0 +1,266 @@
|
|||
package bencode
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type any interface{}
|
||||
|
||||
func checkMarshal(expected string, data any) (err error) {
|
||||
var b bytes.Buffer
|
||||
if err = Marshal(&b, data); err != nil {
|
||||
return
|
||||
}
|
||||
s := b.String()
|
||||
if expected != s {
|
||||
err = errors.New(fmt.Sprintf("Expected %s got %s", expected, s))
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func check(expected string, data any) (err error) {
|
||||
if err = checkMarshal(expected, data); err != nil {
|
||||
return
|
||||
}
|
||||
b2 := bytes.NewBufferString(expected)
|
||||
val, err := Decode(b2)
|
||||
if err != nil {
|
||||
err = errors.New(fmt.Sprint("Failed decoding ", expected, " ", err))
|
||||
return
|
||||
}
|
||||
if err = checkFuzzyEqual(data, val); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func checkFuzzyEqual(a any, b any) (err error) {
|
||||
if !fuzzyEqual(a, b) {
|
||||
err = errors.New(fmt.Sprint(a, " != ", b,
|
||||
": ", reflect.ValueOf(a), "!=", reflect.ValueOf(b)))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func fuzzyEqual(a, b any) bool {
|
||||
return fuzzyEqualValue(reflect.ValueOf(a), reflect.ValueOf(b))
|
||||
}
|
||||
|
||||
func checkFuzzyEqualValue(a, b reflect.Value) (err error) {
|
||||
if !fuzzyEqualValue(a, b) {
|
||||
err = fmt.Errorf("Wanted %v(%v) got %v(%v)", a, a.Interface(), b, b.Interface())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func fuzzyEqualInt64(a int64, b reflect.Value) bool {
|
||||
switch vb := b; vb.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return a == (vb.Int())
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func fuzzyEqualArrayOrSlice(va reflect.Value, b reflect.Value) bool {
|
||||
switch vb := b; vb.Kind() {
|
||||
case reflect.Array:
|
||||
return fuzzyEqualArrayOrSlice2(va, vb)
|
||||
case reflect.Slice:
|
||||
return fuzzyEqualArrayOrSlice2(va, vb)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func deInterface(a reflect.Value) reflect.Value {
|
||||
switch va := a; va.Kind() {
|
||||
case reflect.Interface:
|
||||
return va.Elem()
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func fuzzyEqualArrayOrSlice2(a reflect.Value, b reflect.Value) bool {
|
||||
if a.Len() != b.Len() {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 0; i < a.Len(); i++ {
|
||||
ea := deInterface(a.Index(i))
|
||||
eb := deInterface(b.Index(i))
|
||||
if !fuzzyEqualValue(ea, eb) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func fuzzyEqualMap(a reflect.Value, b reflect.Value) bool {
|
||||
key := a.Type().Key()
|
||||
if key.Kind() != reflect.String {
|
||||
return false
|
||||
}
|
||||
key = b.Type().Key()
|
||||
if key.Kind() != reflect.String {
|
||||
return false
|
||||
}
|
||||
|
||||
aKeys, bKeys := a.MapKeys(), b.MapKeys()
|
||||
|
||||
if len(aKeys) != len(bKeys) {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, k := range aKeys {
|
||||
if !fuzzyEqualValue(a.MapIndex(k), b.MapIndex(k)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func fuzzyEqualStruct(a reflect.Value, b reflect.Value) bool {
|
||||
numA, numB := a.NumField(), b.NumField()
|
||||
if numA != numB {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 0; i < numA; i++ {
|
||||
if !fuzzyEqualValue(a.Field(i), b.Field(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func fuzzyEqualValue(a, b reflect.Value) bool {
|
||||
switch va := a; va.Kind() {
|
||||
case reflect.String:
|
||||
switch vb := b; vb.Kind() {
|
||||
case reflect.String:
|
||||
return va.String() == vb.String()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return fuzzyEqualInt64(va.Int(), b)
|
||||
case reflect.Array:
|
||||
return fuzzyEqualArrayOrSlice(va, b)
|
||||
case reflect.Slice:
|
||||
return fuzzyEqualArrayOrSlice(va, b)
|
||||
case reflect.Map:
|
||||
switch vb := b; vb.Kind() {
|
||||
case reflect.Map:
|
||||
return fuzzyEqualMap(va, vb)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
case reflect.Struct:
|
||||
switch vb := b; vb.Kind() {
|
||||
case reflect.Struct:
|
||||
return fuzzyEqualStruct(va, vb)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
case reflect.Interface:
|
||||
switch vb := b; vb.Kind() {
|
||||
case reflect.Interface:
|
||||
return fuzzyEqualValue(va.Elem(), vb.Elem())
|
||||
default:
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func checkUnmarshal(expected string, data any) (err error) {
|
||||
if err = checkMarshal(expected, data); err != nil {
|
||||
return
|
||||
}
|
||||
dataValue := reflect.ValueOf(data)
|
||||
newOne := reflect.New(reflect.TypeOf(data))
|
||||
buf := bytes.NewBufferString(expected)
|
||||
if err = unmarshalValue(buf, newOne); err != nil {
|
||||
return
|
||||
}
|
||||
if err = checkFuzzyEqualValue(dataValue, newOne.Elem()); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type SVPair struct {
|
||||
s string
|
||||
v any
|
||||
}
|
||||
|
||||
func TestDecode(t *testing.T) {
|
||||
tests := []SVPair{
|
||||
SVPair{"i0e", int64(0)},
|
||||
SVPair{"i0e", 0},
|
||||
SVPair{"i100e", 100},
|
||||
SVPair{"i-100e", -100},
|
||||
SVPair{"1:a", "a"},
|
||||
SVPair{"2:a\"", "a\""},
|
||||
SVPair{"11:0123456789a", "0123456789a"},
|
||||
SVPair{"le", []int64{}},
|
||||
SVPair{"li1ei2ee", []int{1, 2}},
|
||||
SVPair{"l3:abc3:defe", []string{"abc", "def"}},
|
||||
SVPair{"li42e3:abce", []any{42, "abc"}},
|
||||
SVPair{"de", map[string]any{}},
|
||||
SVPair{"d3:cati1e3:dogi2ee", map[string]any{"cat": 1, "dog": 2}},
|
||||
}
|
||||
for _, sv := range tests {
|
||||
if err := check(sv.s, sv.v); err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type structA struct {
|
||||
A int "a"
|
||||
B string `example:"data" bencode:"b"`
|
||||
C string `example:"data2" bencode:"sea monster"`
|
||||
}
|
||||
|
||||
func TestUnmarshal(t *testing.T) {
|
||||
type structNested struct {
|
||||
T string "t"
|
||||
Y string "y"
|
||||
Q string "q"
|
||||
A map[string]string "a"
|
||||
}
|
||||
innerDict := map[string]string{"id": "abcdefghij0123456789"}
|
||||
nestedDictionary := structNested{"aa", "q", "ping", innerDict}
|
||||
|
||||
tests := []SVPair{
|
||||
SVPair{"i100e", 100},
|
||||
SVPair{"i-100e", -100},
|
||||
SVPair{"1:a", "a"},
|
||||
SVPair{"2:a\"", "a\""},
|
||||
SVPair{"11:0123456789a", "0123456789a"},
|
||||
SVPair{"le", []int64{}},
|
||||
SVPair{"li1ei2ee", []int{1, 2}},
|
||||
SVPair{"l3:abc3:defe", []string{"abc", "def"}},
|
||||
SVPair{"li42e3:abce", []any{42, "abc"}},
|
||||
SVPair{"de", map[string]any{}},
|
||||
SVPair{"d3:cati1e3:dogi2ee", map[string]any{"cat": 1, "dog": 2}},
|
||||
SVPair{"d1:ai10e1:b3:foo11:sea monster3:bare", structA{10, "foo", "bar"}},
|
||||
SVPair{"d1:ad2:id20:abcdefghij0123456789e1:q4:ping1:t2:aa1:y1:qe", nestedDictionary},
|
||||
}
|
||||
for _, sv := range tests {
|
||||
if err := checkUnmarshal(sv.s, sv.v); err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
106
bencode/decode.go
Normal file
106
bencode/decode.go
Normal file
|
@ -0,0 +1,106 @@
|
|||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Represents bencode data structure using native Go types: booleans, floats,
|
||||
// strings, slices, and maps.
|
||||
|
||||
package bencode
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// Decode a bencode stream
|
||||
|
||||
// Decode parses the stream r and returns the
|
||||
// generic bencode object representation. The object representation is a tree
|
||||
// of Go data types. The data return value may be one of string,
|
||||
// int64, uint64, []interface{} or map[string]interface{}. The slice and map
|
||||
// elements may in turn contain any of the types listed above and so on.
|
||||
//
|
||||
// If Decode encounters a syntax error, it returns with err set to an
|
||||
// instance of Error.
|
||||
func Decode(r io.Reader) (data interface{}, err error) {
|
||||
jb := newDecoder(nil, nil)
|
||||
err = parse(r, jb)
|
||||
if err == nil {
|
||||
data = jb.Copy()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type decoder struct {
|
||||
// A value being constructed.
|
||||
value interface{}
|
||||
// Container entity to flush into. Can be either []interface{} or
|
||||
// map[string]interface{}.
|
||||
container interface{}
|
||||
// The index into the container interface. Either int or string.
|
||||
index interface{}
|
||||
}
|
||||
|
||||
func newDecoder(container interface{}, key interface{}) *decoder {
|
||||
return &decoder{container: container, index: key}
|
||||
}
|
||||
|
||||
func (j *decoder) Int64(i int64) { j.value = int64(i) }
|
||||
|
||||
func (j *decoder) Uint64(i uint64) { j.value = uint64(i) }
|
||||
|
||||
func (j *decoder) Float64(f float64) { j.value = float64(f) }
|
||||
|
||||
func (j *decoder) String(s string) { j.value = s }
|
||||
|
||||
func (j *decoder) Bool(b bool) { j.value = b }
|
||||
|
||||
func (j *decoder) Null() { j.value = nil }
|
||||
|
||||
func (j *decoder) Array() { j.value = make([]interface{}, 0, 8) }
|
||||
|
||||
func (j *decoder) Map() { j.value = make(map[string]interface{}) }
|
||||
|
||||
func (j *decoder) Elem(i int) builder {
|
||||
v, ok := j.value.([]interface{})
|
||||
if !ok {
|
||||
v = make([]interface{}, 0, 8)
|
||||
j.value = v
|
||||
}
|
||||
/* XXX There is a bug in here somewhere, but append() works fine.
|
||||
lens := len(v)
|
||||
if cap(v) <= lens {
|
||||
news := make([]interface{}, 0, lens*2)
|
||||
copy(news, j.value.([]interface{}))
|
||||
v = news
|
||||
}
|
||||
v = v[0 : lens+1]
|
||||
*/
|
||||
v = append(v, nil)
|
||||
j.value = v
|
||||
return newDecoder(v, i)
|
||||
}
|
||||
|
||||
func (j *decoder) Key(s string) builder {
|
||||
m, ok := j.value.(map[string]interface{})
|
||||
if !ok {
|
||||
m = make(map[string]interface{})
|
||||
j.value = m
|
||||
}
|
||||
return newDecoder(m, s)
|
||||
}
|
||||
|
||||
func (j *decoder) Flush() {
|
||||
switch c := j.container.(type) {
|
||||
case []interface{}:
|
||||
index := j.index.(int)
|
||||
c[index] = j.Copy()
|
||||
case map[string]interface{}:
|
||||
index := j.index.(string)
|
||||
c[index] = j.Copy()
|
||||
}
|
||||
}
|
||||
|
||||
// Get the value built by this builder.
|
||||
func (j *decoder) Copy() interface{} {
|
||||
return j.value
|
||||
}
|
200
bencode/parse.go
Normal file
200
bencode/parse.go
Normal file
|
@ -0,0 +1,200 @@
|
|||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// bencode parser.
|
||||
// See the bittorrent protocol
|
||||
|
||||
package bencode
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Parser
|
||||
//
|
||||
// Implements parsing but not the actions. Those are
|
||||
// carried out by the implementation of the builder interface.
|
||||
// A builder represents the object being created.
|
||||
// Calling a method like Int64(i) sets that object to i.
|
||||
// Calling a method like Elem(i) or Key(s) creates a
|
||||
// new builder for a subpiece of the object (logically,
|
||||
// a slice element or a map key).
|
||||
//
|
||||
// There are two Builders, in other files.
|
||||
// The decoder builds a generic bencode structures
|
||||
// in which maps are maps.
|
||||
// The structBuilder copies data into a possibly
|
||||
// nested data structure, using the "map keys"
|
||||
// as struct field names.
|
||||
|
||||
// A builder is an interface implemented by clients and passed
|
||||
// to the bencode parser. It gives clients full control over the
|
||||
// eventual representation returned by the parser.
|
||||
type builder interface {
|
||||
// Set value
|
||||
Int64(i int64)
|
||||
Uint64(i uint64)
|
||||
String(s string)
|
||||
Array()
|
||||
Map()
|
||||
|
||||
// Create sub-Builders
|
||||
Elem(i int) builder
|
||||
Key(s string) builder
|
||||
|
||||
// Flush changes to parent builder if necessary.
|
||||
Flush()
|
||||
}
|
||||
|
||||
func collectInt(r *bufio.Reader, delim byte) (buf []byte, err error) {
|
||||
for {
|
||||
var c byte
|
||||
c, err = r.ReadByte()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if c == delim {
|
||||
return
|
||||
}
|
||||
if !(c == '-' || (c >= '0' && c <= '9')) {
|
||||
err = errors.New("expected digit")
|
||||
return
|
||||
}
|
||||
buf = append(buf, c)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func decodeInt64(r *bufio.Reader, delim byte) (data int64, err error) {
|
||||
buf, err := collectInt(r, delim)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
data, err = strconv.ParseInt(string(buf), 10, 64)
|
||||
return
|
||||
}
|
||||
|
||||
func decodeString(r *bufio.Reader) (data string, err error) {
|
||||
length, err := decodeInt64(r, ':')
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if length < 0 {
|
||||
err = errors.New("Bad string length")
|
||||
return
|
||||
}
|
||||
var buf = make([]byte, length)
|
||||
_, err = io.ReadFull(r, buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
data = string(buf)
|
||||
return
|
||||
}
|
||||
|
||||
func parseFromReader(r *bufio.Reader, build builder) (err error) {
|
||||
c, err := r.ReadByte()
|
||||
if err != nil {
|
||||
goto exit
|
||||
}
|
||||
switch {
|
||||
case c >= '0' && c <= '9':
|
||||
// String
|
||||
err = r.UnreadByte()
|
||||
if err != nil {
|
||||
goto exit
|
||||
}
|
||||
var str string
|
||||
str, err = decodeString(r)
|
||||
if err != nil {
|
||||
goto exit
|
||||
}
|
||||
build.String(str)
|
||||
|
||||
case c == 'd':
|
||||
// dictionary
|
||||
|
||||
build.Map()
|
||||
for {
|
||||
c, err = r.ReadByte()
|
||||
if err != nil {
|
||||
goto exit
|
||||
}
|
||||
if c == 'e' {
|
||||
break
|
||||
}
|
||||
err = r.UnreadByte()
|
||||
if err != nil {
|
||||
goto exit
|
||||
}
|
||||
var key string
|
||||
key, err = decodeString(r)
|
||||
if err != nil {
|
||||
goto exit
|
||||
}
|
||||
// TODO: in pendantic mode, check for keys in ascending order.
|
||||
err = parse(r, build.Key(key))
|
||||
if err != nil {
|
||||
goto exit
|
||||
}
|
||||
}
|
||||
|
||||
case c == 'i':
|
||||
var buf []byte
|
||||
buf, err = collectInt(r, 'e')
|
||||
if err != nil {
|
||||
goto exit
|
||||
}
|
||||
var str string
|
||||
var i int64
|
||||
var i2 uint64
|
||||
str = string(buf)
|
||||
// If the number is exactly an integer, use that.
|
||||
if i, err = strconv.ParseInt(str, 10, 64); err == nil {
|
||||
build.Int64(i)
|
||||
} else if i2, err = strconv.ParseUint(str, 10, 64); err == nil {
|
||||
build.Uint64(i2)
|
||||
} else {
|
||||
err = errors.New("Bad integer")
|
||||
}
|
||||
|
||||
case c == 'l':
|
||||
// array
|
||||
build.Array()
|
||||
n := 0
|
||||
for {
|
||||
c, err = r.ReadByte()
|
||||
if err != nil {
|
||||
goto exit
|
||||
}
|
||||
if c == 'e' {
|
||||
break
|
||||
}
|
||||
err = r.UnreadByte()
|
||||
if err != nil {
|
||||
goto exit
|
||||
}
|
||||
err = parseFromReader(r, build.Elem(n))
|
||||
if err != nil {
|
||||
goto exit
|
||||
}
|
||||
n++
|
||||
}
|
||||
default:
|
||||
err = errors.New(fmt.Sprintf("Unexpected character: '%v'", c))
|
||||
}
|
||||
exit:
|
||||
build.Flush()
|
||||
return
|
||||
}
|
||||
|
||||
// Parse parses the bencode stream and makes calls to
|
||||
// the builder to construct a parsed representation.
|
||||
func parse(r io.Reader, builder builder) (err error) {
|
||||
return parseFromReader(bufio.NewReader(r), builder)
|
||||
}
|
540
bencode/struct.go
Normal file
540
bencode/struct.go
Normal file
|
@ -0,0 +1,540 @@
|
|||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Marshalling and unmarshalling of
|
||||
// bit torrent bencode data into Go structs using reflection.
|
||||
//
|
||||
// Based upon the standard Go language JSON package.
|
||||
|
||||
package bencode
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type structBuilder struct {
|
||||
val reflect.Value
|
||||
|
||||
// if map_ != nil, write val to map_[key] on each change
|
||||
map_ reflect.Value
|
||||
key reflect.Value
|
||||
}
|
||||
|
||||
var nobuilder *structBuilder
|
||||
|
||||
func isfloat(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func setfloat(v reflect.Value, f float64) {
|
||||
switch v.Kind() {
|
||||
case reflect.Float32, reflect.Float64:
|
||||
v.SetFloat(f)
|
||||
}
|
||||
}
|
||||
|
||||
func setint(val reflect.Value, i int64) {
|
||||
switch v := val; v.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
v.SetInt(int64(i))
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
v.SetUint(uint64(i))
|
||||
case reflect.Interface:
|
||||
v.Set(reflect.ValueOf(i))
|
||||
default:
|
||||
panic("setint called for bogus type: " + val.Kind().String())
|
||||
}
|
||||
}
|
||||
|
||||
// If updating b.val is not enough to update the original,
|
||||
// copy a changed b.val out to the original.
|
||||
func (b *structBuilder) Flush() {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
if b.map_.IsValid() {
|
||||
b.map_.SetMapIndex(b.key, b.val)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *structBuilder) Int64(i int64) {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
if !b.val.CanSet() {
|
||||
x := 0
|
||||
b.val = reflect.ValueOf(&x).Elem()
|
||||
}
|
||||
v := b.val
|
||||
if isfloat(v) {
|
||||
setfloat(v, float64(i))
|
||||
} else {
|
||||
setint(v, i)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *structBuilder) Uint64(i uint64) {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
if !b.val.CanSet() {
|
||||
x := uint64(0)
|
||||
b.val = reflect.ValueOf(&x).Elem()
|
||||
}
|
||||
v := b.val
|
||||
if isfloat(v) {
|
||||
setfloat(v, float64(i))
|
||||
} else {
|
||||
setint(v, int64(i))
|
||||
}
|
||||
}
|
||||
|
||||
func (b *structBuilder) Float64(f float64) {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
if !b.val.CanSet() {
|
||||
x := float64(0)
|
||||
b.val = reflect.ValueOf(&x).Elem()
|
||||
}
|
||||
v := b.val
|
||||
if isfloat(v) {
|
||||
setfloat(v, f)
|
||||
} else {
|
||||
setint(v, int64(f))
|
||||
}
|
||||
}
|
||||
|
||||
func (b *structBuilder) String(s string) {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch b.val.Kind() {
|
||||
case reflect.String:
|
||||
if !b.val.CanSet() {
|
||||
x := ""
|
||||
b.val = reflect.ValueOf(&x).Elem()
|
||||
|
||||
}
|
||||
b.val.SetString(s)
|
||||
case reflect.Interface:
|
||||
b.val.Set(reflect.ValueOf(s))
|
||||
}
|
||||
}
|
||||
|
||||
func (b *structBuilder) Array() {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
if v := b.val; v.Kind() == reflect.Slice {
|
||||
if v.IsNil() {
|
||||
v.Set(reflect.MakeSlice(v.Type(), 0, 8))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *structBuilder) Elem(i int) builder {
|
||||
if b == nil || i < 0 {
|
||||
return nobuilder
|
||||
}
|
||||
switch v := b.val; v.Kind() {
|
||||
case reflect.Array:
|
||||
if i < v.Len() {
|
||||
return &structBuilder{val: v.Index(i)}
|
||||
}
|
||||
case reflect.Slice:
|
||||
if i >= v.Cap() {
|
||||
n := v.Cap()
|
||||
if n < 8 {
|
||||
n = 8
|
||||
}
|
||||
for n <= i {
|
||||
n *= 2
|
||||
}
|
||||
nv := reflect.MakeSlice(v.Type(), v.Len(), n)
|
||||
reflect.Copy(nv, v)
|
||||
v.Set(nv)
|
||||
}
|
||||
if v.Len() <= i && i < v.Cap() {
|
||||
v.SetLen(i + 1)
|
||||
}
|
||||
if i < v.Len() {
|
||||
return &structBuilder{val: v.Index(i)}
|
||||
}
|
||||
}
|
||||
return nobuilder
|
||||
}
|
||||
|
||||
func (b *structBuilder) Map() {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
if v := b.val; v.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
v.Set(reflect.Zero(v.Type().Elem()).Addr())
|
||||
b.Flush()
|
||||
}
|
||||
b.map_ = reflect.Value{}
|
||||
b.val = v.Elem()
|
||||
}
|
||||
if v := b.val; v.Kind() == reflect.Map && v.IsNil() {
|
||||
v.Set(reflect.MakeMap(v.Type()))
|
||||
}
|
||||
}
|
||||
|
||||
func (b *structBuilder) Key(k string) builder {
|
||||
if b == nil {
|
||||
return nobuilder
|
||||
}
|
||||
switch v := reflect.Indirect(b.val); v.Kind() {
|
||||
case reflect.Struct:
|
||||
t := v.Type()
|
||||
// Case-insensitive field lookup.
|
||||
k = strings.ToLower(k)
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
key := bencodeKey(field)
|
||||
if strings.ToLower(key) == k ||
|
||||
strings.ToLower(field.Name) == k {
|
||||
return &structBuilder{val: v.Field(i)}
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
t := v.Type()
|
||||
if t.Key() != reflect.TypeOf(k) {
|
||||
break
|
||||
}
|
||||
key := reflect.ValueOf(k)
|
||||
elem := v.MapIndex(key)
|
||||
if !elem.IsValid() {
|
||||
v.SetMapIndex(key, reflect.Zero(t.Elem()))
|
||||
elem = v.MapIndex(key)
|
||||
}
|
||||
return &structBuilder{val: elem, map_: v, key: key}
|
||||
}
|
||||
return nobuilder
|
||||
}
|
||||
|
||||
// Unmarshal reads and parses the bencode syntax data from r and fills in
|
||||
// an arbitrary struct or slice pointed at by val.
|
||||
// It uses the reflect package to assign to fields
|
||||
// and arrays embedded in val. Well-formed data that does not fit
|
||||
// into the struct is discarded.
|
||||
//
|
||||
// For example, given these definitions:
|
||||
//
|
||||
// type Email struct {
|
||||
// Where string;
|
||||
// Addr string;
|
||||
// }
|
||||
//
|
||||
// type Result struct {
|
||||
// Name string;
|
||||
// Phone string;
|
||||
// Email []Email
|
||||
// }
|
||||
//
|
||||
// var r = Result{ "name", "phone", nil }
|
||||
//
|
||||
// unmarshalling the bencode syntax string
|
||||
//
|
||||
// "d5:emailld5:where4:home4:addr15:gre@example.come\
|
||||
// d5:where4:work4:addr12:gre@work.comee4:name14:Gr\
|
||||
// ace R. Emlin7:address15:123 Main Streete"
|
||||
//
|
||||
// via Unmarshal(s, &r) is equivalent to assigning
|
||||
//
|
||||
// r = Result{
|
||||
// "Grace R. Emlin", // name
|
||||
// "phone", // no phone given
|
||||
// []Email{
|
||||
// Email{ "home", "gre@example.com" },
|
||||
// Email{ "work", "gre@work.com" }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Note that the field r.Phone has not been modified and
|
||||
// that the bencode field "address" was discarded.
|
||||
//
|
||||
// Because Unmarshal uses the reflect package, it can only
|
||||
// assign to upper case fields. Unmarshal uses a case-insensitive
|
||||
// comparison to match bencode field names to struct field names.
|
||||
//
|
||||
// If you provide a tag string for a struct member, the tag string
|
||||
// will be used as the bencode dictionary key for that member.
|
||||
// Bencode undestands both the original single-string and updated
|
||||
// list-of-key-value-pairs tag string syntax. The list-of-key-value
|
||||
// pairs syntax is assumed, with a fallback to the original single-string
|
||||
// syntax. The key for bencode values is bencode.
|
||||
//
|
||||
// To unmarshal a top-level bencode array, pass in a pointer to an empty
|
||||
// slice of the correct type.
|
||||
//
|
||||
func Unmarshal(r io.Reader, val interface{}) (err error) {
|
||||
// If e represents a value, the answer won't get back to the
|
||||
// caller. Make sure it's a pointer.
|
||||
if reflect.TypeOf(val).Kind() != reflect.Ptr {
|
||||
err = errors.New("Attempt to unmarshal into a non-pointer")
|
||||
return
|
||||
}
|
||||
err = unmarshalValue(r, reflect.Indirect(reflect.ValueOf(val)))
|
||||
return
|
||||
}
|
||||
|
||||
func unmarshalValue(r io.Reader, v reflect.Value) (err error) {
|
||||
var b *structBuilder
|
||||
|
||||
// XXX: Decide if the extra codnitions are needed. Affect map?
|
||||
if ptr := v; ptr.Kind() == reflect.Ptr {
|
||||
if slice := ptr.Elem(); slice.Kind() == reflect.Slice || slice.Kind() == reflect.Int || slice.Kind() == reflect.String {
|
||||
b = &structBuilder{val: slice}
|
||||
}
|
||||
}
|
||||
|
||||
if b == nil {
|
||||
b = &structBuilder{val: v}
|
||||
}
|
||||
|
||||
err = parse(r, b)
|
||||
return
|
||||
}
|
||||
|
||||
type MarshalError struct {
|
||||
T reflect.Type
|
||||
}
|
||||
|
||||
func (e *MarshalError) Error() string {
|
||||
return "bencode cannot encode value of type " + e.T.String()
|
||||
}
|
||||
|
||||
func writeArrayOrSlice(w io.Writer, val reflect.Value) (err error) {
|
||||
_, err = fmt.Fprint(w, "l")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
if err := writeValue(w, val.Index(i)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
_, err = fmt.Fprint(w, "e")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type stringValue struct {
|
||||
key string
|
||||
value reflect.Value
|
||||
}
|
||||
|
||||
type stringValueArray []stringValue
|
||||
|
||||
// Satisfy sort.Interface
|
||||
|
||||
func (a stringValueArray) Len() int { return len(a) }
|
||||
|
||||
func (a stringValueArray) Less(i, j int) bool { return a[i].key < a[j].key }
|
||||
|
||||
func (a stringValueArray) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
|
||||
func writeSVList(w io.Writer, svList stringValueArray) (err error) {
|
||||
sort.Sort(svList)
|
||||
|
||||
for _, sv := range svList {
|
||||
if isValueNil(sv.value) {
|
||||
continue // Skip null values
|
||||
}
|
||||
s := sv.key
|
||||
_, err = fmt.Fprintf(w, "%d:%s", len(s), s)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = writeValue(w, sv.value); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func writeMap(w io.Writer, val reflect.Value) (err error) {
|
||||
key := val.Type().Key()
|
||||
if key.Kind() != reflect.String {
|
||||
return &MarshalError{val.Type()}
|
||||
}
|
||||
_, err = fmt.Fprint(w, "d")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
keys := val.MapKeys()
|
||||
|
||||
// Sort keys
|
||||
|
||||
svList := make(stringValueArray, len(keys))
|
||||
for i, key := range keys {
|
||||
svList[i].key = key.String()
|
||||
svList[i].value = val.MapIndex(key)
|
||||
}
|
||||
|
||||
err = writeSVList(w, svList)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = fmt.Fprint(w, "e")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func bencodeKey(field reflect.StructField) (key string) {
|
||||
key = field.Name
|
||||
tag := field.Tag
|
||||
if len(tag) > 0 {
|
||||
// Backwards compatability
|
||||
// If there's a bencode key/value entry in the tag, use it.
|
||||
key = tag.Get("bencode")
|
||||
if len(key) == 0 {
|
||||
// If there is no ":" in the tag, assume it is an old-style tag.
|
||||
stringTag := string(tag)
|
||||
if !strings.Contains(stringTag, ":") {
|
||||
key = stringTag
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func writeStruct(w io.Writer, val reflect.Value) (err error) {
|
||||
_, err = fmt.Fprint(w, "d")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
typ := val.Type()
|
||||
|
||||
numFields := val.NumField()
|
||||
svList := make(stringValueArray, numFields)
|
||||
|
||||
for i := 0; i < numFields; i++ {
|
||||
field := typ.Field(i)
|
||||
svList[i].key = bencodeKey(field)
|
||||
svList[i].value = val.Field(i)
|
||||
}
|
||||
|
||||
err = writeSVList(w, svList)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = fmt.Fprint(w, "e")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func writeValue(w io.Writer, val reflect.Value) (err error) {
|
||||
if !val.IsValid() {
|
||||
err = errors.New("Can't write null value")
|
||||
return
|
||||
}
|
||||
|
||||
switch v := val; v.Kind() {
|
||||
case reflect.String:
|
||||
s := v.String()
|
||||
_, err = fmt.Fprintf(w, "%d:%s", len(s), s)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
_, err = fmt.Fprintf(w, "i%de", v.Int())
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
_, err = fmt.Fprintf(w, "i%de", v.Uint())
|
||||
case reflect.Array:
|
||||
err = writeArrayOrSlice(w, v)
|
||||
case reflect.Slice:
|
||||
err = writeArrayOrSlice(w, v)
|
||||
case reflect.Map:
|
||||
err = writeMap(w, v)
|
||||
case reflect.Struct:
|
||||
err = writeStruct(w, v)
|
||||
case reflect.Interface:
|
||||
err = writeValue(w, v.Elem())
|
||||
default:
|
||||
err = &MarshalError{val.Type()}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func isValueNil(val reflect.Value) bool {
|
||||
if !val.IsValid() {
|
||||
return true
|
||||
}
|
||||
switch v := val; v.Kind() {
|
||||
case reflect.Interface:
|
||||
return isValueNil(v.Elem())
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Marshal writes the bencode encoding of val to w.
|
||||
//
|
||||
// Marshal traverses the value v recursively.
|
||||
//
|
||||
// Marshal uses the following type-dependent encodings:
|
||||
//
|
||||
// Floating point, integer, and Number values encode as bencode numbers.
|
||||
//
|
||||
// String values encode as bencode strings.
|
||||
//
|
||||
// Array and slice values encode as bencode arrays.
|
||||
//
|
||||
// Struct values encode as bencode maps. Each exported struct field
|
||||
// becomes a member of the object.
|
||||
// The object's default key string is the struct field name
|
||||
// but can be specified in the struct field's tag value. The text of
|
||||
// the struct field's tag value is the key name. Examples:
|
||||
//
|
||||
// // Field appears in bencode as key "Field".
|
||||
// Field int
|
||||
//
|
||||
// // Field appears in bencode as key "myName".
|
||||
// Field int "myName"
|
||||
//
|
||||
// Anonymous struct fields are ignored.
|
||||
//
|
||||
// Map values encode as bencode objects.
|
||||
// The map's key type must be string; the object keys are used directly
|
||||
// as map keys.
|
||||
//
|
||||
// Boolean, Pointer, Interface, Channel, complex, and function values cannot
|
||||
// be encoded in bencode.
|
||||
// Attempting to encode such a value causes Marshal to return
|
||||
// a MarshalError.
|
||||
//
|
||||
// Bencode cannot represent cyclic data structures and Marshal does not
|
||||
// handle them. Passing cyclic structures to Marshal will result in
|
||||
// an infinite recursion.
|
||||
//
|
||||
func Marshal(w io.Writer, val interface{}) error {
|
||||
// TODO match other encoders, like encoding/json ...
|
||||
// func Marshal(v interface{}) ([]byte, error)
|
||||
return writeValue(w, reflect.ValueOf(val))
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue