commit 0804ed19200da354cd821861fbb261e81521e74f Author: Jack Palevich Date: Wed Jan 6 23:38:33 2010 +0800 Initial commit diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7ed1c06 --- /dev/null +++ b/LICENSE @@ -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. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a95aed8 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +include $(GOROOT)/src/Make.$(GOARCH) + +TARG=jackpal/bencode +GOFILES=\ + decode.go\ + parse.go\ + struct.go\ + + +include $(GOROOT)/src/Make.pkg \ No newline at end of file diff --git a/decode.go b/decode.go new file mode 100644 index 0000000..fe89215 --- /dev/null +++ b/decode.go @@ -0,0 +1,104 @@ +// 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 JSON data structure using native Go types: booleans, floats, +// strings, arrays, and maps. + +package bencode + +import ( + "container/vector" + "io" + "os" +) + +// 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 array 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 ParseError. See ParseError documentation for details. +func Decode(r io.Reader) (data interface{}, err os.Error) { + jb := newDecoder(nil, nil) + err = Parse(r, jb) + if err == nil { + data = jb.Data() + } + return +} + +type decoder struct { + // A value being constructed. + value interface{} + // Container entity to flush into. Can be either vector.Vector 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 = new(vector.Vector) } + +func (j *decoder) Map() { j.value = make(map[string]interface{}) } + +func (j *decoder) Elem(i int) Builder { + v, ok := j.value.(*vector.Vector) + if !ok { + v = new(vector.Vector) + j.value = v + } + if v.Len() <= i { + v.Resize(i+1, (i+1)*2) + } + 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 *vector.Vector: + index := j.index.(int) + c.Set(index, j.Data()) + case map[string]interface{}: + index := j.index.(string) + c[index] = j.Data() + } +} + +// Get the value built by this builder. +func (j *decoder) Data() interface{} { + switch v := j.value.(type) { + case *vector.Vector: + return v.Data() + } + return j.value +} diff --git a/parse.go b/parse.go new file mode 100644 index 0000000..fdf7f3b --- /dev/null +++ b/parse.go @@ -0,0 +1,205 @@ +// 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" + "bytes" + "io" + "os" + "strconv" +) + +type Reader interface { + io.Reader + ReadByte() (c byte, err os.Error) + UnreadByte() os.Error +} + +// 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, +// an array 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 Reader, delim byte) (buf []byte, err os.Error) { + for { + c, err := r.ReadByte() + if err != nil { + return + } + if c == delim { + return + } + if !(c == '-' || (c >= '0' && c <= '9')) { + err = os.NewError("expected digit") + return + } + buf = bytes.AddByte(buf, c) + } + return +} + +func decodeInt64(r Reader, delim byte) (data int64, err os.Error) { + buf, err := collectInt(r, delim) + if err != nil { + return + } + data, err = strconv.Atoi64(string(buf)) + return +} + +func decodeString(r Reader) (data string, err os.Error) { + len, err := decodeInt64(r, ':') + if err != nil { + return + } + if len < 0 { + err = os.NewError("Bad string length") + return + } + var buf = make([]byte, len) + _, err = io.ReadFull(r, buf) + if err != nil { + return + } + data = string(buf) + return +} + +func parse(r Reader, build Builder) (err os.Error) { +Switch: + c, err := r.ReadByte() + if err != nil { + return + } + switch { + case c >= '1' && c <= '9': + // String + err = r.UnreadByte() + if err != nil { + return + } + str, err := decodeString(r) + if err != nil { + return + } + build.String(str) + + case c == 'd': + // dictionary + + build.Map() + for { + c, err := r.ReadByte() + if err != nil { + return + } + if c == 'e' { + break + } + err = r.UnreadByte() + if err != nil { + return + } + key, err := decodeString(r) + if err != nil { + return + } + // TODO: in pendantic mode, check for keys in ascending order. + err = parse(r, build.Key(key)) + if err != nil { + return + } + } + + case c == 'i': + buf, err := collectInt(r, 'e') + if err != nil { + return + } + str := string(buf) + // If the number is exactly an integer, use that. + if i, err := strconv.Atoi64(str); err == nil { + build.Int64(i) + } else if i, err := strconv.Atoui64(str); err == nil { + build.Uint64(i) + } else { + err = os.NewError("Bad integer") + } + + case c == 'l': + // array + build.Array() + n := 0 + for { + c, err := r.ReadByte() + if err != nil { + return + } + if c == 'e' { + break + } + err = r.UnreadByte() + if err != nil { + return + } + err = parse(r, build.Elem(n)) + if err != nil { + return + } + n++ + } + default: + err = os.NewError("Unexpected character") + } + + 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 os.Error) { + rr, ok := r.(Reader) + if !ok { + rr = bufio.NewReader(r) + } + return parse(rr, builder) +} diff --git a/struct.go b/struct.go new file mode 100644 index 0000000..9daa55a --- /dev/null +++ b/struct.go @@ -0,0 +1,467 @@ +// 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 ( + "fmt" + "io" + "os" + "reflect" + "sort" + "strings" +) + +type structBuilder struct { + val reflect.Value + + // if map_ != nil, write val to map_[key] on each change + map_ *reflect.MapValue + key reflect.Value +} + +var nobuilder *structBuilder + +func isfloat(v reflect.Value) bool { + switch v.(type) { + case *reflect.FloatValue, *reflect.Float32Value, *reflect.Float64Value: + return true + } + return false +} + +func setfloat(v reflect.Value, f float64) { + switch v := v.(type) { + case *reflect.FloatValue: + v.Set(float(f)) + case *reflect.Float32Value: + v.Set(float32(f)) + case *reflect.Float64Value: + v.Set(float64(f)) + } +} + +func setint(val reflect.Value, i int64) { + switch v := val.(type) { + case *reflect.IntValue: + v.Set(int(i)) + case *reflect.Int8Value: + v.Set(int8(i)) + case *reflect.Int16Value: + v.Set(int16(i)) + case *reflect.Int32Value: + v.Set(int32(i)) + case *reflect.Int64Value: + v.Set(int64(i)) + case *reflect.UintValue: + v.Set(uint(i)) + case *reflect.Uint8Value: + v.Set(uint8(i)) + case *reflect.Uint16Value: + v.Set(uint16(i)) + case *reflect.Uint32Value: + v.Set(uint32(i)) + case *reflect.Uint64Value: + v.Set(uint64(i)) + case *reflect.InterfaceValue: + v.Set(reflect.NewValue(i)) + } +} + +// 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_ != nil { + b.map_.SetElem(b.key, b.val) + } +} + +func (b *structBuilder) Int64(i int64) { + if b == nil { + return + } + v := b.val + if isfloat(v) { + setfloat(v, float64(i)) + } else { + setint(v, i) + } +} + +func (b *structBuilder) Uint64(i uint64) { + if b == nil { + return + } + 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 + } + 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 v := b.val.(type) { + case *reflect.StringValue: + v.Set(s) + case *reflect.InterfaceValue: + v.Set(reflect.NewValue(s)) + } +} + +func (b *structBuilder) Array() { + if b == nil { + return + } + if v, ok := b.val.(*reflect.SliceValue); ok { + if v.IsNil() { + v.Set(reflect.MakeSlice(v.Type().(*reflect.SliceType), 0, 8)) + } + } +} + +func (b *structBuilder) Elem(i int) Builder { + if b == nil || i < 0 { + return nobuilder + } + switch v := b.val.(type) { + case *reflect.ArrayValue: + if i < v.Len() { + return &structBuilder{val: v.Elem(i)} + } + case *reflect.SliceValue: + if i >= v.Cap() { + n := v.Cap() + if n < 8 { + n = 8 + } + for n <= i { + n *= 2 + } + nv := reflect.MakeSlice(v.Type().(*reflect.SliceType), v.Len(), n) + reflect.ArrayCopy(nv, v) + v.Set(nv) + } + if v.Len() <= i && i < v.Cap() { + v.SetLen(i + 1) + } + if i < v.Len() { + return &structBuilder{val: v.Elem(i)} + } + } + return nobuilder +} + +func (b *structBuilder) Map() { + if b == nil { + return + } + if v, ok := b.val.(*reflect.PtrValue); ok && v.IsNil() { + if v.IsNil() { + v.PointTo(reflect.MakeZero(v.Type().(*reflect.PtrType).Elem())) + b.Flush() + } + b.map_ = nil + b.val = v.Elem() + } + if v, ok := b.val.(*reflect.MapValue); ok && v.IsNil() { + v.Set(reflect.MakeMap(v.Type().(*reflect.MapType))) + } +} + +func (b *structBuilder) Key(k string) Builder { + if b == nil { + return nobuilder + } + switch v := reflect.Indirect(b.val).(type) { + case *reflect.StructValue: + t := v.Type().(*reflect.StructType) + // Case-insensitive field lookup. + k = strings.ToLower(k) + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + if strings.ToLower(field.Tag) == k || + strings.ToLower(field.Name) == k { + return &structBuilder{val: v.Field(i)} + } + } + case *reflect.MapValue: + t := v.Type().(*reflect.MapType) + if t.Key() != reflect.Typeof(k) { + break + } + key := reflect.NewValue(k) + elem := v.Elem(key) + if elem == nil { + v.SetElem(key, reflect.MakeZero(t.Elem())) + elem = v.Elem(key) + } + return &structBuilder{val: elem, map_: v, key: key} + } + return nobuilder +} + +// Unmarshal parses the bencode syntax string s 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. +// +// 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 os.Error) { + err = UnmarshalValue(r, reflect.NewValue(val)) + return +} + +// This API is public primarily to make testing easier, but it is available if you +// have a use for it. + +func UnmarshalValue(r io.Reader, v reflect.Value) (err os.Error) { + var b *structBuilder + + // If val is a pointer to a slice, we append to the slice. + if ptr, ok := v.(*reflect.PtrValue); ok { + if slice, ok := ptr.Elem().(*reflect.SliceValue); ok { + 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) String() string { + return "bencode cannot encode value of type " + e.T.String() +} + +func writeArrayOrSlice(w io.Writer, val reflect.ArrayOrSliceValue) (err os.Error) { + _, err = fmt.Fprint(w, "l") + if err != nil { + return + } + for i := 0; i < val.Len(); i++ { + if err := writeValue(w, val.Elem(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 os.Error) { + sort.Sort(svList) + + for _, sv := range (svList) { + 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.MapValue) (err os.Error) { + key := val.Type().(*reflect.MapType).Key() + if _, ok := key.(*reflect.StringType); !ok { + return &MarshalError{val.Type()} + } + _, err = fmt.Fprint(w, "d") + if err != nil { + return + } + + keys := val.Keys() + + // Sort keys + + svList := make(StringValueArray, len(keys)) + for i, key := range (keys) { + svList[i].key = key.(*reflect.StringValue).Get() + svList[i].value = val.Elem(key) + } + + err = writeSVList(w, svList) + if err != nil { + return + } + + _, err = fmt.Fprint(w, "e") + if err != nil { + return + } + return +} + +func writeStruct(w io.Writer, val *reflect.StructValue) (err os.Error) { + _, err = fmt.Fprint(w, "d") + if err != nil { + return + } + + typ := val.Type().(*reflect.StructType) + + numFields := val.NumField() + svList := make(StringValueArray, numFields) + + for i := 0; i < numFields; i++ { + field := typ.Field(i) + key := field.Name + if len(field.Tag) > 0 { + key = field.Tag + } + svList[i].key = key + 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 os.Error) { + if val == nil { + err = os.NewError("Can't write null value") + return + } + + switch v := val.(type) { + case *reflect.StringValue: + s := v.Get() + _, err = fmt.Fprintf(w, "%d:%s", len(s), s) + case *reflect.IntValue: + _, err = fmt.Fprintf(w, "i%de", v.Get()) + case *reflect.UintValue: + _, err = fmt.Fprintf(w, "i%de", v.Get()) + case *reflect.Int64Value: + _, err = fmt.Fprintf(w, "i%de", v.Get()) + case *reflect.Uint64Value: + _, err = fmt.Fprintf(w, "i%de", v.Get()) + case *reflect.ArrayValue: + err = writeArrayOrSlice(w, v) + case *reflect.SliceValue: + err = writeArrayOrSlice(w, v) + case *reflect.MapValue: + err = writeMap(w, v) + case *reflect.StructValue: + err = writeStruct(w, v) + case *reflect.InterfaceValue: + err = writeValue(w, v.Elem()) + default: + err = &MarshalError{val.Type()} + } + return +} + +func Marshal(w io.Writer, val interface{}) os.Error { + return writeValue(w, reflect.NewValue(val)) +}