├── .travis.yml ├── LICENSE ├── README.md ├── benchmark_test.go ├── bencode_test.go ├── decode.go ├── go.mod ├── incswparse.go ├── parse.go └── struct.go /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - "1.10" 5 | - tip 6 | 7 | allowed_failures: 8 | - go: tip 9 | 10 | install: 11 | - go get -d -v . && go install -v . 12 | 13 | script: go test -v . 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2009 The Go Authors. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above 10 | // copyright notice, this list of conditions and the following disclaimer 11 | // in the documentation and/or other materials provided with the 12 | // distribution. 13 | // * Neither the name of Google Inc. nor the names of its 14 | // contributors may be used to endorse or promote products derived from 15 | // this software without specific prior written permission. 16 | // 17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bencode-go 2 | 3 | A Go language binding for encoding and decoding data in the bencode format that 4 | is used by the BitTorrent peer-to-peer file sharing protocol. 5 | 6 | ## Quick Start 7 | 8 | ### Get the package 9 | ```bash 10 | go get -u github.com/jackpal/bencode-go 11 | ``` 12 | 13 | ### Import the package 14 | ```go 15 | import bencode "github.com/jackpal/bencode-go" 16 | ``` 17 | 18 | ### Unmarshal a bencode stream into an object 19 | ```go 20 | data := myAwesomeObject{} 21 | err := bencode.Unmarshal(reader, &data) 22 | ``` 23 | 24 | ### Decode a bencode stream 25 | ```go 26 | data, err := bencode.Decode(reader) 27 | ``` 28 | 29 | ### Encode an object into a bencode stream 30 | ```go 31 | err := bencode.Marshal(writer, data) 32 | ``` 33 | 34 | ## Complete documentation 35 | 36 | http://godoc.org/github.com/jackpal/bencode-go 37 | 38 | ## License 39 | 40 | This project is licensed under the Go Authors standard license. (See the LICENSE 41 | file for details.) 42 | 43 | ## Version History 44 | 45 | | tag | Notes | 46 | | ------ | ----------------------------------------------------------- | 47 | | v1.0.2 | Added go module. | 48 | | v1.0.1 | Removed architecture specific test that was failing on ARM. | 49 | | v1.0.0 | First version. | 50 | -------------------------------------------------------------------------------- /benchmark_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Aleksey Lin (https://incsw.in) 2 | // MIT licence, see https://github.com/IncSW/go-bencode/LICENSE 3 | // Adapted from https://github.com/IncSW/go-bencode 4 | 5 | package bencode 6 | 7 | import ( 8 | "bytes" 9 | "testing" 10 | ) 11 | 12 | var marshalTestData = map[string]interface{}{ 13 | "announce": []byte("udp://tracker.publicbt.com:80/announce"), 14 | "announce-list": []interface{}{ 15 | []interface{}{[]byte("udp://tracker.publicbt.com:80/announce")}, 16 | []interface{}{[]byte("udp://tracker.openbittorrent.com:80/announce")}, 17 | }, 18 | "comment": []byte("Debian CD from cdimage.debian.org"), 19 | "info": map[string]interface{}{ 20 | "name": []byte("debian-8.8.0-arm64-netinst.iso"), 21 | "length": 170917888, 22 | "piece length": 262144, 23 | }, 24 | } 25 | 26 | var unmarshalTestData = []byte("d4:infod6:lengthi170917888e12:piece lengthi262144e4:name30:debian-8.8.0-arm64-netinst.isoe8:announce38:udp://tracker.publicbt.com:80/announce13:announce-listll38:udp://tracker.publicbt.com:80/announceel44:udp://tracker.openbittorrent.com:80/announceee7:comment33:Debian CD from cdimage.debian.orge") 27 | 28 | func BenchmarkBencodeMarshal(b *testing.B) { 29 | b.ReportAllocs() 30 | for n := 0; n < b.N; n++ { 31 | err := Marshal(bytes.NewBuffer(nil), marshalTestData) 32 | if err != nil { 33 | b.Errorf("Marshal returned %v", err) 34 | } 35 | } 36 | } 37 | 38 | func BenchmarkBencodeUnmarshal(b *testing.B) { 39 | b.ReportAllocs() 40 | for n := 0; n < b.N; n++ { 41 | result, err := Decode(bytes.NewReader(unmarshalTestData)) 42 | if err != nil { 43 | b.Errorf("Decode returned %+v, %v", result, err) 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /bencode_test.go: -------------------------------------------------------------------------------- 1 | package bencode 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "reflect" 8 | "testing" 9 | ) 10 | 11 | type any interface{} 12 | 13 | func checkMarshal(expected string, data any) (err error) { 14 | var b bytes.Buffer 15 | if err = Marshal(&b, data); err != nil { 16 | return 17 | } 18 | s := b.String() 19 | if expected != s { 20 | err = fmt.Errorf("Expected %s got %s", expected, s) 21 | return 22 | } 23 | return 24 | } 25 | 26 | func check(expected string, data any) (err error) { 27 | if err = checkMarshal(expected, data); err != nil { 28 | return 29 | } 30 | b2 := bytes.NewBufferString(expected) 31 | val, err := Decode(b2) 32 | if err != nil { 33 | err = errors.New(fmt.Sprint("Failed decoding ", expected, " ", err)) 34 | return 35 | } 36 | if err = checkFuzzyEqual(data, val); err != nil { 37 | return 38 | } 39 | return 40 | } 41 | 42 | func checkFuzzyEqual(a any, b any) (err error) { 43 | if !fuzzyEqual(a, b) { 44 | err = errors.New(fmt.Sprint(a, " != ", b, 45 | ": ", reflect.ValueOf(a), "!=", reflect.ValueOf(b))) 46 | } 47 | return 48 | } 49 | 50 | func fuzzyEqual(a, b any) bool { 51 | return fuzzyEqualValue(reflect.ValueOf(a), reflect.ValueOf(b)) 52 | } 53 | 54 | func checkFuzzyEqualValue(a, b reflect.Value) (err error) { 55 | if !fuzzyEqualValue(a, b) { 56 | err = fmt.Errorf("Wanted %v(%v) got %v(%v)", a, a.Interface(), b, b.Interface()) 57 | } 58 | return 59 | } 60 | 61 | func fuzzyEqualInt64(a int64, b reflect.Value) bool { 62 | switch vb := b; vb.Kind() { 63 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 64 | return a == (vb.Int()) 65 | } 66 | return false 67 | } 68 | 69 | func fuzzyEqualArrayOrSlice(va reflect.Value, b reflect.Value) bool { 70 | switch vb := b; vb.Kind() { 71 | case reflect.Array: 72 | return fuzzyEqualArrayOrSlice2(va, vb) 73 | case reflect.Slice: 74 | return fuzzyEqualArrayOrSlice2(va, vb) 75 | } 76 | return false 77 | } 78 | 79 | func deInterface(a reflect.Value) reflect.Value { 80 | switch va := a; va.Kind() { 81 | case reflect.Interface: 82 | return va.Elem() 83 | } 84 | return a 85 | } 86 | 87 | func fuzzyEqualArrayOrSlice2(a reflect.Value, b reflect.Value) bool { 88 | if a.Len() != b.Len() { 89 | return false 90 | } 91 | 92 | for i := 0; i < a.Len(); i++ { 93 | ea := deInterface(a.Index(i)) 94 | eb := deInterface(b.Index(i)) 95 | if !fuzzyEqualValue(ea, eb) { 96 | return false 97 | } 98 | } 99 | return true 100 | } 101 | 102 | func fuzzyEqualMap(a reflect.Value, b reflect.Value) bool { 103 | key := a.Type().Key() 104 | if key.Kind() != reflect.String { 105 | return false 106 | } 107 | key = b.Type().Key() 108 | if key.Kind() != reflect.String { 109 | return false 110 | } 111 | 112 | aKeys, bKeys := a.MapKeys(), b.MapKeys() 113 | 114 | if len(aKeys) != len(bKeys) { 115 | return false 116 | } 117 | 118 | for _, k := range aKeys { 119 | if !fuzzyEqualValue(a.MapIndex(k), b.MapIndex(k)) { 120 | return false 121 | } 122 | } 123 | return true 124 | } 125 | 126 | func fuzzyEqualStruct(a reflect.Value, b reflect.Value) bool { 127 | numA, numB := a.NumField(), b.NumField() 128 | if numA != numB { 129 | return false 130 | } 131 | 132 | for i := 0; i < numA; i++ { 133 | if !fuzzyEqualValue(a.Field(i), b.Field(i)) { 134 | return false 135 | } 136 | } 137 | return true 138 | } 139 | 140 | func fuzzyEqualValue(a, b reflect.Value) bool { 141 | switch va := a; va.Kind() { 142 | case reflect.String: 143 | switch vb := b; vb.Kind() { 144 | case reflect.String: 145 | return va.String() == vb.String() 146 | default: 147 | return false 148 | } 149 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 150 | return fuzzyEqualInt64(va.Int(), b) 151 | case reflect.Array: 152 | return fuzzyEqualArrayOrSlice(va, b) 153 | case reflect.Slice: 154 | return fuzzyEqualArrayOrSlice(va, b) 155 | case reflect.Map: 156 | switch vb := b; vb.Kind() { 157 | case reflect.Map: 158 | return fuzzyEqualMap(va, vb) 159 | default: 160 | return false 161 | } 162 | case reflect.Struct: 163 | switch vb := b; vb.Kind() { 164 | case reflect.Struct: 165 | return fuzzyEqualStruct(va, vb) 166 | default: 167 | return false 168 | } 169 | case reflect.Interface: 170 | switch vb := b; vb.Kind() { 171 | case reflect.Interface: 172 | return fuzzyEqualValue(va.Elem(), vb.Elem()) 173 | default: 174 | return false 175 | } 176 | } 177 | return false 178 | } 179 | 180 | func checkUnmarshal(expected string, data any) (err error) { 181 | dataValue := reflect.ValueOf(data) 182 | newOne := reflect.New(reflect.TypeOf(data)) 183 | buf := bytes.NewBufferString(expected) 184 | if err = unmarshalValue(buf, newOne); err != nil { 185 | return 186 | } 187 | if err = checkFuzzyEqualValue(dataValue, newOne.Elem()); err != nil { 188 | return 189 | } 190 | return 191 | } 192 | 193 | type SVPair struct { 194 | s string 195 | v any 196 | } 197 | 198 | var decodeTests = []SVPair{ 199 | SVPair{"i0e", int64(0)}, 200 | SVPair{"i0e", 0}, 201 | SVPair{"i100e", 100}, 202 | SVPair{"i-100e", -100}, 203 | SVPair{"1:a", "a"}, 204 | SVPair{"2:a\"", "a\""}, 205 | SVPair{"11:0123456789a", "0123456789a"}, 206 | SVPair{"le", []int64{}}, 207 | SVPair{"li1ei2ee", []int{1, 2}}, 208 | SVPair{"l3:abc3:defe", []string{"abc", "def"}}, 209 | SVPair{"li42e3:abce", []any{42, "abc"}}, 210 | SVPair{"de", map[string]any{}}, 211 | SVPair{"d3:cati1e3:dogi2ee", map[string]any{"cat": 1, "dog": 2}}, 212 | } 213 | 214 | func TestDecode(t *testing.T) { 215 | for _, sv := range decodeTests { 216 | if err := check(sv.s, sv.v); err != nil { 217 | t.Error(err.Error()) 218 | } 219 | } 220 | } 221 | 222 | func BenchmarkDecodeAll(b *testing.B) { 223 | for i := 0; i < b.N; i++ { 224 | for _, sv := range decodeTests { 225 | check(sv.s, sv.v) 226 | } 227 | } 228 | } 229 | 230 | type structA struct { 231 | A int "a" 232 | B string `example:"data" bencode:"b"` 233 | C string `example:"data2" bencode:"sea monster"` 234 | } 235 | 236 | type structNested struct { 237 | T string "t" 238 | Y string "y" 239 | Q string "q" 240 | A map[string]string "a" 241 | } 242 | 243 | var ( 244 | unmarshalInnerDict = map[string]string{"id": "abcdefghij0123456789"} 245 | unmarshalNestedDictionary = structNested{"aa", "q", "ping", unmarshalInnerDict} 246 | unmarshalTests = []SVPair{ 247 | SVPair{"i100e", 100}, 248 | SVPair{"i-100e", -100}, 249 | SVPair{"i7.5e", 7}, 250 | SVPair{"i-7.5e", -7}, 251 | SVPair{"i7.574E+2e", 757}, 252 | SVPair{"i-7.574E+2e", -757}, 253 | // This test is architecture specific. 254 | // See https://stackoverflow.com/a/70259392 255 | // SVPair{"i7.574E+20e", -9223372036854775808}, 256 | SVPair{"i-7.574E+20e", -9223372036854775808}, 257 | SVPair{"i7.574E-2e", 0}, 258 | SVPair{"i-7.574E-2e", 0}, 259 | SVPair{"i7.574E-20e", 0}, 260 | SVPair{"i-7.574E-20e", 0}, 261 | SVPair{"1:a", "a"}, 262 | SVPair{"2:a\"", "a\""}, 263 | SVPair{"11:0123456789a", "0123456789a"}, 264 | SVPair{"le", []int64{}}, 265 | SVPair{"li1ei2ee", []int{1, 2}}, 266 | SVPair{"l3:abc3:defe", []string{"abc", "def"}}, 267 | SVPair{"li42e3:abce", []any{42, "abc"}}, 268 | SVPair{"de", map[string]any{}}, 269 | SVPair{"d3:cati1e3:dogi2ee", map[string]any{"cat": 1, "dog": 2}}, 270 | SVPair{"d1:ai10e1:b3:foo11:sea monster3:bare", structA{10, "foo", "bar"}}, 271 | SVPair{"d1:ad2:id20:abcdefghij0123456789e1:q4:ping1:t2:aa1:y1:qe", unmarshalNestedDictionary}, 272 | } 273 | ) 274 | 275 | func TestUnmarshal(t *testing.T) { 276 | for _, sv := range unmarshalTests { 277 | if err := checkUnmarshal(sv.s, sv.v); err != nil { 278 | t.Error(err.Error()) 279 | } 280 | } 281 | } 282 | 283 | func BenchmarkUnmarshalAll(b *testing.B) { 284 | for i := 0; i < b.N; i++ { 285 | for _, sv := range unmarshalTests { 286 | checkUnmarshal(sv.s, sv.v) 287 | } 288 | } 289 | } 290 | 291 | type identity struct { 292 | Age int 293 | FirstName string 294 | Ignored string `bencode:"-"` 295 | LastName string 296 | } 297 | 298 | func TestMarshalWithIgnoredField(t *testing.T) { 299 | id := identity{42, "Jack", "Why are you ignoring me?", "Daniel"} 300 | var buf bytes.Buffer 301 | err := Marshal(&buf, id) 302 | if err != nil { 303 | t.Fatal(err) 304 | } 305 | var id2 identity 306 | err = Unmarshal(&buf, &id2) 307 | if err != nil { 308 | t.Fatal(err) 309 | } 310 | if id.Age != id2.Age { 311 | t.Fatalf("Age should be the same, expected %d, got %d", id.Age, id2.Age) 312 | } 313 | if id.FirstName != id2.FirstName { 314 | t.Fatalf("FirstName should be the same, expected %s, got %s", id.FirstName, id2.FirstName) 315 | } 316 | if id.LastName != id2.LastName { 317 | t.Fatalf("LastName should be the same, expected %s, got %s", id.LastName, id2.LastName) 318 | } 319 | if id2.Ignored != "" { 320 | t.Fatalf("Ignored should be empty, got %s", id2.Ignored) 321 | } 322 | } 323 | 324 | type omitEmpty struct { 325 | Age int 326 | Array []string `bencode:",omitempty"` 327 | FirstName string 328 | Ignored string `bencode:",omitempty"` 329 | LastName string 330 | Renamed string `bencode:"otherName,omitempty"` 331 | } 332 | 333 | func TestMarshalWithOmitEmptyFieldEmpty(t *testing.T) { 334 | oe := omitEmpty{42, []string{}, "Jack", "", "Daniel", ""} 335 | var buf bytes.Buffer 336 | err := Marshal(&buf, oe) 337 | if err != nil { 338 | t.Fatal(err) 339 | } 340 | buf2 := "d3:Agei42e9:FirstName4:Jack8:LastName6:Daniele" 341 | if string(buf.Bytes()) != buf2 { 342 | t.Fatalf("Wrong encoding, expected first line got second line\n`%s`\n`%s`\n", buf2, string(buf.Bytes())) 343 | } 344 | } 345 | 346 | func TestMarshalWithOmitEmptyFieldNonEmpty(t *testing.T) { 347 | oe := omitEmpty{42, []string{"first", "second"}, "Jack", "Not ignored", "Daniel", "Whisky"} 348 | var buf bytes.Buffer 349 | err := Marshal(&buf, oe) 350 | if err != nil { 351 | t.Fatal(err) 352 | } 353 | buf2 := "d3:Agei42e5:Arrayl5:first6:seconde9:FirstName4:Jack7:Ignored11:Not ignored8:LastName6:Daniel9:otherName6:Whiskye" 354 | if string(buf.Bytes()) != buf2 { 355 | t.Fatalf("Wrong encoding, expected first line got second line\n`%s`\n`%s`\n", buf2, string(buf.Bytes())) 356 | } 357 | } 358 | 359 | func TestMarshalDifferentTypes(t *testing.T) { 360 | 361 | buf := new(bytes.Buffer) 362 | Marshal(buf, []byte{'1', '2', '3'}) 363 | if buf.String() != "3:123" { 364 | t.Fatalf("Incorrectly encoded byte array, got %s", buf.String()) 365 | } 366 | 367 | buf = new(bytes.Buffer) 368 | Marshal(buf, []int{1, 2, 3}) 369 | if buf.String() != "li1ei2ei3ee" { 370 | t.Fatalf("Incorrectly encoded byte array, got %s", buf.String()) 371 | } 372 | } 373 | -------------------------------------------------------------------------------- /decode.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Represents bencode data structure using native Go types: booleans, floats, 6 | // strings, slices, and maps. 7 | 8 | package bencode 9 | 10 | import ( 11 | "bufio" 12 | "io" 13 | ) 14 | 15 | // Decode a bencode stream 16 | 17 | // Decode parses the stream r and returns the 18 | // generic bencode object representation. The object representation is a tree 19 | // of Go data types. The data return value may be one of string, 20 | // int64, uint64, []interface{} or map[string]interface{}. The slice and map 21 | // elements may in turn contain any of the types listed above and so on. 22 | // 23 | // If Decode encounters a syntax error, it returns with err set to an 24 | // instance of Error. 25 | func Decode(reader io.Reader) (data interface{}, err error) { 26 | // Check to see if the reader already fulfills the bufio.Reader interface. 27 | // Wrap it in a bufio.Reader if it doesn't. 28 | bufioReader, ok := reader.(*bufio.Reader) 29 | if !ok { 30 | bufioReader = newBufioReader(reader) 31 | defer bufioReaderPool.Put(bufioReader) 32 | } 33 | 34 | return decodeFromReader(bufioReader) 35 | } 36 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/jackpal/bencode-go 2 | 3 | go 1.21.4 4 | -------------------------------------------------------------------------------- /incswparse.go: -------------------------------------------------------------------------------- 1 | package bencode 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "errors" 7 | "strconv" 8 | ) 9 | 10 | // A relatively fast unmarshaler. 11 | // Adapted from https://github.com/IncSW/go-bencode/blob/master/unmarshaler.go 12 | // License: https://github.com/IncSW/go-bencode/blob/master/LICENSE 13 | 14 | // Differences from IncSW are for compatibility with the existing bencode-go API: 15 | // (a) Uses a bufio.Reader rather than a raw []byte 16 | // (b) Strings are returned as golang strings rather than as raw []byte arrays. 17 | 18 | func decodeFromReader(r *bufio.Reader) (data interface{}, err error) { 19 | result, err := unmarshal(r) 20 | if err != nil { 21 | return nil, err 22 | } 23 | 24 | return result, nil 25 | } 26 | 27 | func unmarshal(data *bufio.Reader) (interface{}, error) { 28 | ch, err := data.ReadByte() 29 | if err != nil { 30 | return nil, err 31 | } 32 | switch ch { 33 | case 'i': 34 | integerBuffer, err := optimisticReadBytes(data, 'e') 35 | if err != nil { 36 | return nil, err 37 | } 38 | integerBuffer = integerBuffer[:len(integerBuffer)-1] 39 | 40 | integer, err := strconv.ParseInt(string(integerBuffer), 10, 64) 41 | if err != nil { 42 | return nil, err 43 | } 44 | 45 | return integer, nil 46 | 47 | case 'l': 48 | list := []interface{}{} 49 | for { 50 | c, err2 := data.ReadByte() 51 | if err2 == nil { 52 | if c == 'e' { 53 | return list, nil 54 | } else { 55 | data.UnreadByte() 56 | } 57 | } 58 | 59 | value, err := unmarshal(data) 60 | if err != nil { 61 | return nil, err 62 | } 63 | 64 | list = append(list, value) 65 | } 66 | 67 | case 'd': 68 | dictionary := map[string]interface{}{} 69 | for { 70 | c, err2 := data.ReadByte() 71 | if err2 == nil { 72 | if c == 'e' { 73 | return dictionary, nil 74 | } else { 75 | data.UnreadByte() 76 | } 77 | } 78 | value, err := unmarshal(data) 79 | if err != nil { 80 | return nil, err 81 | } 82 | 83 | key, ok := value.(string) 84 | if !ok { 85 | return nil, errors.New("bencode: non-string dictionary key") 86 | } 87 | 88 | value, err = unmarshal(data) 89 | if err != nil { 90 | return nil, err 91 | } 92 | 93 | dictionary[key] = value 94 | } 95 | 96 | default: 97 | data.UnreadByte() 98 | stringLengthBuffer, err := optimisticReadBytes(data, ':') 99 | if err != nil { 100 | return nil, err 101 | } 102 | stringLengthBuffer = stringLengthBuffer[:len(stringLengthBuffer)-1] 103 | 104 | stringLength, err := strconv.ParseInt(string(stringLengthBuffer), 10, 64) 105 | if err != nil { 106 | return nil, err 107 | } 108 | 109 | buf := make([]byte, stringLength) 110 | 111 | _, err = readAtLeast(data, buf, int(stringLength)) 112 | 113 | return string(buf), err 114 | } 115 | } 116 | 117 | // Reads bytes out of local buffer if possible, which avoids an extra copy. 118 | // The result []byte is only guarenteed to be valid until the next call to a Read method. 119 | func optimisticReadBytes(data *bufio.Reader, delim byte) ([]byte, error) { 120 | buffered := data.Buffered() 121 | var buffer []byte 122 | var err error 123 | if buffer, err = data.Peek(buffered); err != nil { 124 | return nil, err 125 | } 126 | 127 | if i := bytes.IndexByte(buffer, delim); i >= 0 { 128 | return data.ReadSlice(delim) 129 | } 130 | return data.ReadBytes(delim) 131 | } 132 | -------------------------------------------------------------------------------- /parse.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // bencode parser. 6 | // See the bittorrent protocol 7 | 8 | package bencode 9 | 10 | import ( 11 | "bufio" 12 | "errors" 13 | "fmt" 14 | "io" 15 | "strconv" 16 | "sync" 17 | ) 18 | 19 | // Parser 20 | // 21 | // Implements parsing but not the actions. Those are 22 | // carried out by the implementation of the builder interface. 23 | // A builder represents the object being created. 24 | // Calling a method like Int64(i) sets that object to i. 25 | // Calling a method like Elem(i) or Key(s) creates a 26 | // new builder for a subpiece of the object (logically, 27 | // a slice element or a map key). 28 | // 29 | // There are two Builders, in other files. 30 | // The decoder builds a generic bencode structures 31 | // in which maps are maps. 32 | // The structBuilder copies data into a possibly 33 | // nested data structure, using the "map keys" 34 | // as struct field names. 35 | 36 | // A builder is an interface implemented by clients and passed 37 | // to the bencode parser. It gives clients full control over the 38 | // eventual representation returned by the parser. 39 | type builder interface { 40 | // Set value 41 | Int64(i int64) 42 | Uint64(i uint64) 43 | Float64(f float64) 44 | String(s string) 45 | Array() 46 | Map() 47 | 48 | // Create sub-Builders 49 | Elem(i int) builder 50 | Key(s string) builder 51 | 52 | // Flush changes to parent builder if necessary. 53 | Flush() 54 | } 55 | 56 | // Deprecated: This type is currently unused. It is exposed for backwards 57 | // compatability. The public API that previously used this type, 58 | // 59 | // Unmarshal(r Reader, val interface{}) (err error) 60 | // 61 | // is now 62 | // 63 | // Unmarshal(r io.Reader, val interface{}) (err error) 64 | // 65 | // Which is compatible, since any Reader is also an io.Reader. 66 | // Clients should drop their use of this type. It may be removed in the future. 67 | type Reader interface { 68 | io.Reader 69 | io.ByteScanner 70 | } 71 | 72 | func decodeInt64(r *bufio.Reader, delim byte) (data int64, err error) { 73 | buf, err := readSlice(r, delim) 74 | if err != nil { 75 | return 76 | } 77 | data, err = strconv.ParseInt(string(buf), 10, 64) 78 | return 79 | } 80 | 81 | // Read bytes up until delim, return slice without delimiter byte. 82 | func readSlice(r *bufio.Reader, delim byte) (data []byte, err error) { 83 | if data, err = r.ReadSlice(delim); err != nil { 84 | return 85 | } 86 | lenData := len(data) 87 | if lenData > 0 { 88 | data = data[:lenData-1] 89 | } else { 90 | panic("bad r.ReadSlice() length") 91 | } 92 | return 93 | } 94 | 95 | func decodeString(r *bufio.Reader) (data string, err error) { 96 | length, err := decodeInt64(r, ':') 97 | if err != nil { 98 | return 99 | } 100 | if length < 0 { 101 | err = errors.New("Bad string length") 102 | return 103 | } 104 | 105 | // Can we peek that much data out of r? 106 | if peekBuf, peekErr := r.Peek(int(length)); peekErr == nil { 107 | data = string(peekBuf) 108 | _, err = r.Discard(int(length)) 109 | return 110 | } 111 | 112 | var buf = make([]byte, length) 113 | _, err = readFull(r, buf) 114 | if err != nil { 115 | return 116 | } 117 | data = string(buf) 118 | return 119 | } 120 | 121 | // Like io.ReadFull, but takes a bufio.Reader. 122 | func readFull(r *bufio.Reader, buf []byte) (n int, err error) { 123 | return readAtLeast(r, buf, len(buf)) 124 | } 125 | 126 | // Like io.ReadAtLeast, but takes a bufio.Reader. 127 | func readAtLeast(r *bufio.Reader, buf []byte, min int) (n int, err error) { 128 | if len(buf) < min { 129 | return 0, io.ErrShortBuffer 130 | } 131 | for n < min && err == nil { 132 | var nn int 133 | nn, err = r.Read(buf[n:]) 134 | n += nn 135 | } 136 | if n >= min { 137 | err = nil 138 | } else if n > 0 && err == io.EOF { 139 | err = io.ErrUnexpectedEOF 140 | } 141 | return 142 | } 143 | 144 | func parseFromReader(r *bufio.Reader, build builder) (err error) { 145 | c, err := r.ReadByte() 146 | if err != nil { 147 | goto exit 148 | } 149 | switch { 150 | case c >= '0' && c <= '9': 151 | // String 152 | err = r.UnreadByte() 153 | if err != nil { 154 | goto exit 155 | } 156 | var str string 157 | str, err = decodeString(r) 158 | if err != nil { 159 | goto exit 160 | } 161 | build.String(str) 162 | 163 | case c == 'd': 164 | // dictionary 165 | 166 | build.Map() 167 | for { 168 | c, err = r.ReadByte() 169 | if err != nil { 170 | goto exit 171 | } 172 | if c == 'e' { 173 | break 174 | } 175 | err = r.UnreadByte() 176 | if err != nil { 177 | goto exit 178 | } 179 | var key string 180 | key, err = decodeString(r) 181 | if err != nil { 182 | goto exit 183 | } 184 | // TODO: in pendantic mode, check for keys in ascending order. 185 | err = parseFromReader(r, build.Key(key)) 186 | if err != nil { 187 | goto exit 188 | } 189 | } 190 | 191 | case c == 'i': 192 | var buf []byte 193 | buf, err = readSlice(r, 'e') 194 | if err != nil { 195 | goto exit 196 | } 197 | var str string 198 | var i int64 199 | var i2 uint64 200 | var f float64 201 | str = string(buf) 202 | // If the number is exactly an integer, use that. 203 | if i, err = strconv.ParseInt(str, 10, 64); err == nil { 204 | build.Int64(i) 205 | } else if i2, err = strconv.ParseUint(str, 10, 64); err == nil { 206 | build.Uint64(i2) 207 | } else if f, err = strconv.ParseFloat(str, 64); err == nil { 208 | build.Float64(f) 209 | } else { 210 | err = errors.New("Bad integer") 211 | } 212 | 213 | case c == 'l': 214 | // array 215 | build.Array() 216 | n := 0 217 | for { 218 | c, err = r.ReadByte() 219 | if err != nil { 220 | goto exit 221 | } 222 | if c == 'e' { 223 | break 224 | } 225 | err = r.UnreadByte() 226 | if err != nil { 227 | goto exit 228 | } 229 | err = parseFromReader(r, build.Elem(n)) 230 | if err != nil { 231 | goto exit 232 | } 233 | n++ 234 | } 235 | default: 236 | err = fmt.Errorf("Unexpected character: '%v'", c) 237 | } 238 | exit: 239 | build.Flush() 240 | return 241 | } 242 | 243 | // Parse parses the bencode stream and makes calls to 244 | // the builder to construct a parsed representation. 245 | func parse(reader io.Reader, builder builder) (err error) { 246 | // Check to see if the reader already fulfills the bufio.Reader interface. 247 | // Wrap it in a bufio.Reader if it doesn't. 248 | r, ok := reader.(*bufio.Reader) 249 | if !ok { 250 | r = newBufioReader(reader) 251 | defer bufioReaderPool.Put(r) 252 | } 253 | 254 | return parseFromReader(r, builder) 255 | } 256 | 257 | var bufioReaderPool sync.Pool 258 | 259 | func newBufioReader(r io.Reader) *bufio.Reader { 260 | if v := bufioReaderPool.Get(); v != nil { 261 | br := v.(*bufio.Reader) 262 | br.Reset(r) 263 | return br 264 | } 265 | return bufio.NewReader(r) 266 | } 267 | -------------------------------------------------------------------------------- /struct.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Marshalling and unmarshalling of 6 | // bit torrent bencode data into Go structs using reflection. 7 | // 8 | // Based upon the standard Go language JSON package. 9 | 10 | package bencode 11 | 12 | import ( 13 | "errors" 14 | "fmt" 15 | "io" 16 | "reflect" 17 | "sort" 18 | "strings" 19 | ) 20 | 21 | type structBuilder struct { 22 | val reflect.Value 23 | 24 | // if map_ != nil, write val to map_[key] on each change 25 | map_ reflect.Value 26 | key reflect.Value 27 | } 28 | 29 | var nobuilder *structBuilder 30 | 31 | func isfloat(v reflect.Value) bool { 32 | switch v.Kind() { 33 | case reflect.Float32, reflect.Float64: 34 | return true 35 | } 36 | return false 37 | } 38 | 39 | func setfloat(v reflect.Value, f float64) { 40 | switch v.Kind() { 41 | case reflect.Float32, reflect.Float64: 42 | v.SetFloat(f) 43 | } 44 | } 45 | 46 | func setint(val reflect.Value, i int64) { 47 | switch v := val; v.Kind() { 48 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 49 | v.SetInt(int64(i)) 50 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 51 | v.SetUint(uint64(i)) 52 | case reflect.Interface: 53 | v.Set(reflect.ValueOf(i)) 54 | default: 55 | panic("setint called for bogus type: " + val.Kind().String()) 56 | } 57 | } 58 | 59 | // If updating b.val is not enough to update the original, 60 | // copy a changed b.val out to the original. 61 | func (b *structBuilder) Flush() { 62 | if b == nil { 63 | return 64 | } 65 | if b.map_.IsValid() { 66 | b.map_.SetMapIndex(b.key, b.val) 67 | } 68 | } 69 | 70 | func (b *structBuilder) Int64(i int64) { 71 | if b == nil { 72 | return 73 | } 74 | if !b.val.CanSet() { 75 | x := 0 76 | b.val = reflect.ValueOf(&x).Elem() 77 | } 78 | v := b.val 79 | if isfloat(v) { 80 | setfloat(v, float64(i)) 81 | } else { 82 | setint(v, i) 83 | } 84 | } 85 | 86 | func (b *structBuilder) Uint64(i uint64) { 87 | if b == nil { 88 | return 89 | } 90 | if !b.val.CanSet() { 91 | x := uint64(0) 92 | b.val = reflect.ValueOf(&x).Elem() 93 | } 94 | v := b.val 95 | if isfloat(v) { 96 | setfloat(v, float64(i)) 97 | } else { 98 | setint(v, int64(i)) 99 | } 100 | } 101 | 102 | func (b *structBuilder) Float64(f float64) { 103 | if b == nil { 104 | return 105 | } 106 | if !b.val.CanSet() { 107 | x := float64(0) 108 | b.val = reflect.ValueOf(&x).Elem() 109 | } 110 | v := b.val 111 | if isfloat(v) { 112 | setfloat(v, f) 113 | } else { 114 | setint(v, int64(f)) 115 | } 116 | } 117 | 118 | func (b *structBuilder) String(s string) { 119 | if b == nil { 120 | return 121 | } 122 | 123 | switch b.val.Kind() { 124 | case reflect.String: 125 | if !b.val.CanSet() { 126 | x := "" 127 | b.val = reflect.ValueOf(&x).Elem() 128 | 129 | } 130 | b.val.SetString(s) 131 | case reflect.Interface: 132 | b.val.Set(reflect.ValueOf(s)) 133 | } 134 | } 135 | 136 | func (b *structBuilder) Array() { 137 | if b == nil { 138 | return 139 | } 140 | if v := b.val; v.Kind() == reflect.Slice { 141 | if v.IsNil() { 142 | v.Set(reflect.MakeSlice(v.Type(), 0, 8)) 143 | } 144 | } 145 | } 146 | 147 | func (b *structBuilder) Elem(i int) builder { 148 | if b == nil || i < 0 { 149 | return nobuilder 150 | } 151 | switch v := b.val; v.Kind() { 152 | case reflect.Array: 153 | if i < v.Len() { 154 | return &structBuilder{val: v.Index(i)} 155 | } 156 | case reflect.Slice: 157 | if i >= v.Cap() { 158 | n := v.Cap() 159 | if n < 8 { 160 | n = 8 161 | } 162 | for n <= i { 163 | n *= 2 164 | } 165 | nv := reflect.MakeSlice(v.Type(), v.Len(), n) 166 | reflect.Copy(nv, v) 167 | v.Set(nv) 168 | } 169 | if v.Len() <= i && i < v.Cap() { 170 | v.SetLen(i + 1) 171 | } 172 | if i < v.Len() { 173 | return &structBuilder{val: v.Index(i)} 174 | } 175 | } 176 | return nobuilder 177 | } 178 | 179 | func (b *structBuilder) Map() { 180 | if b == nil { 181 | return 182 | } 183 | if v := b.val; v.Kind() == reflect.Ptr { 184 | if v.IsNil() { 185 | v.Set(reflect.Zero(v.Type().Elem()).Addr()) 186 | b.Flush() 187 | } 188 | b.map_ = reflect.Value{} 189 | b.val = v.Elem() 190 | } 191 | if v := b.val; v.Kind() == reflect.Map && v.IsNil() { 192 | v.Set(reflect.MakeMap(v.Type())) 193 | } 194 | } 195 | 196 | func (b *structBuilder) Key(k string) builder { 197 | if b == nil { 198 | return nobuilder 199 | } 200 | switch v := reflect.Indirect(b.val); v.Kind() { 201 | case reflect.Struct: 202 | t := v.Type() 203 | // Case-insensitive field lookup. 204 | k = strings.ToLower(k) 205 | for i := 0; i < t.NumField(); i++ { 206 | field := t.Field(i) 207 | key := bencodeKey(field, nil) 208 | if strings.ToLower(key) == k || 209 | strings.ToLower(field.Name) == k { 210 | return &structBuilder{val: v.Field(i)} 211 | } 212 | } 213 | case reflect.Map: 214 | t := v.Type() 215 | if t.Key() != reflect.TypeOf(k) { 216 | break 217 | } 218 | key := reflect.ValueOf(k) 219 | elem := v.MapIndex(key) 220 | if !elem.IsValid() { 221 | v.SetMapIndex(key, reflect.Zero(t.Elem())) 222 | elem = v.MapIndex(key) 223 | } 224 | return &structBuilder{val: elem, map_: v, key: key} 225 | } 226 | return nobuilder 227 | } 228 | 229 | // Unmarshal reads and parses the bencode syntax data from r and fills in 230 | // an arbitrary struct or slice pointed at by val. 231 | // It uses the reflect package to assign to fields 232 | // and arrays embedded in val. Well-formed data that does not fit 233 | // into the struct is discarded. 234 | // 235 | // For example, given these definitions: 236 | // 237 | // type Email struct { 238 | // Where string; 239 | // Addr string; 240 | // } 241 | // 242 | // type Result struct { 243 | // Name string; 244 | // Phone string; 245 | // Email []Email 246 | // } 247 | // 248 | // var r = Result{ "name", "phone", nil } 249 | // 250 | // unmarshalling the bencode syntax string 251 | // 252 | // "d5:emailld5:where4:home4:addr15:gre@example.come\ 253 | // d5:where4:work4:addr12:gre@work.comee4:name14:Gr\ 254 | // ace R. Emlin7:address15:123 Main Streete" 255 | // 256 | // via Unmarshal(s, &r) is equivalent to assigning 257 | // 258 | // r = Result{ 259 | // "Grace R. Emlin", // name 260 | // "phone", // no phone given 261 | // []Email{ 262 | // Email{ "home", "gre@example.com" }, 263 | // Email{ "work", "gre@work.com" } 264 | // } 265 | // } 266 | // 267 | // Note that the field r.Phone has not been modified and 268 | // that the bencode field "address" was discarded. 269 | // 270 | // Because Unmarshal uses the reflect package, it can only 271 | // assign to upper case fields. Unmarshal uses a case-insensitive 272 | // comparison to match bencode field names to struct field names. 273 | // 274 | // If you provide a tag string for a struct member, the tag string 275 | // will be used as the bencode dictionary key for that member. 276 | // Bencode undestands both the original single-string and updated 277 | // list-of-key-value-pairs tag string syntax. The list-of-key-value 278 | // pairs syntax is assumed, with a fallback to the original single-string 279 | // syntax. The key for bencode values is bencode. 280 | // 281 | // To unmarshal a top-level bencode array, pass in a pointer to an empty 282 | // slice of the correct type. 283 | // 284 | func Unmarshal(r io.Reader, val interface{}) (err error) { 285 | // If e represents a value, the answer won't get back to the 286 | // caller. Make sure it's a pointer. 287 | if reflect.TypeOf(val).Kind() != reflect.Ptr { 288 | err = errors.New("Attempt to unmarshal into a non-pointer") 289 | return 290 | } 291 | err = unmarshalValue(r, reflect.Indirect(reflect.ValueOf(val))) 292 | return 293 | } 294 | 295 | func unmarshalValue(r io.Reader, v reflect.Value) (err error) { 296 | var b *structBuilder 297 | 298 | // XXX: Decide if the extra codnitions are needed. Affect map? 299 | if ptr := v; ptr.Kind() == reflect.Ptr { 300 | if slice := ptr.Elem(); slice.Kind() == reflect.Slice || slice.Kind() == reflect.Int || slice.Kind() == reflect.String { 301 | b = &structBuilder{val: slice} 302 | } 303 | } 304 | 305 | if b == nil { 306 | b = &structBuilder{val: v} 307 | } 308 | 309 | err = parse(r, b) 310 | return 311 | } 312 | 313 | type MarshalError struct { 314 | T reflect.Type 315 | } 316 | 317 | func (e *MarshalError) Error() string { 318 | return "bencode cannot encode value of type " + e.T.String() 319 | } 320 | 321 | func writeArrayOrSlice(w io.Writer, val reflect.Value) (err error) { 322 | _, err = fmt.Fprint(w, "l") 323 | if err != nil { 324 | return 325 | } 326 | for i := 0; i < val.Len(); i++ { 327 | if err := writeValue(w, val.Index(i)); err != nil { 328 | return err 329 | } 330 | } 331 | 332 | _, err = fmt.Fprint(w, "e") 333 | if err != nil { 334 | return 335 | } 336 | return nil 337 | } 338 | 339 | type stringValue struct { 340 | key string 341 | value reflect.Value 342 | omitEmpty bool 343 | } 344 | 345 | type stringValueArray []stringValue 346 | 347 | // Satisfy sort.Interface 348 | 349 | func (a stringValueArray) Len() int { return len(a) } 350 | 351 | func (a stringValueArray) Less(i, j int) bool { return a[i].key < a[j].key } 352 | 353 | func (a stringValueArray) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 354 | 355 | func writeSVList(w io.Writer, svList stringValueArray) (err error) { 356 | sort.Sort(svList) 357 | 358 | for _, sv := range svList { 359 | if sv.isValueNil() { 360 | continue // Skip null values 361 | } 362 | s := sv.key 363 | _, err = fmt.Fprintf(w, "%d:%s", len(s), s) 364 | if err != nil { 365 | return 366 | } 367 | 368 | if err = writeValue(w, sv.value); err != nil { 369 | return 370 | } 371 | } 372 | return 373 | } 374 | 375 | func writeMap(w io.Writer, val reflect.Value) (err error) { 376 | key := val.Type().Key() 377 | if key.Kind() != reflect.String { 378 | return &MarshalError{val.Type()} 379 | } 380 | _, err = fmt.Fprint(w, "d") 381 | if err != nil { 382 | return 383 | } 384 | 385 | keys := val.MapKeys() 386 | 387 | // Sort keys 388 | 389 | svList := make(stringValueArray, len(keys)) 390 | for i, key := range keys { 391 | svList[i].key = key.String() 392 | svList[i].value = val.MapIndex(key) 393 | } 394 | 395 | err = writeSVList(w, svList) 396 | if err != nil { 397 | return 398 | } 399 | 400 | _, err = fmt.Fprint(w, "e") 401 | if err != nil { 402 | return 403 | } 404 | return 405 | } 406 | 407 | func bencodeKey(field reflect.StructField, sv *stringValue) (key string) { 408 | key = field.Name 409 | tag := field.Tag 410 | if len(tag) > 0 { 411 | // Backwards compatability 412 | // If there's a bencode key/value entry in the tag, use it. 413 | var tagOpt tagOptions 414 | key, tagOpt = parseTag(tag.Get("bencode")) 415 | if len(key) == 0 { 416 | key = tag.Get("bencode") 417 | if len(key) == 0 && !strings.Contains(string(tag), ":") { 418 | // If there is no ":" in the tag, assume it is an old-style tag. 419 | key = string(tag) 420 | } else { 421 | key = field.Name 422 | } 423 | } 424 | if sv != nil && tagOpt.Contains("omitempty") { 425 | sv.omitEmpty = true 426 | } 427 | } 428 | if sv != nil { 429 | sv.key = key 430 | } 431 | return 432 | } 433 | 434 | // tagOptions is the string following a comma in a struct field's "bencode" 435 | // tag, or the empty string. It does not include the leading comma. 436 | type tagOptions string 437 | 438 | // parseTag splits a struct field's bencode tag into its name and 439 | // comma-separated options. 440 | func parseTag(tag string) (string, tagOptions) { 441 | if idx := strings.Index(tag, ","); idx != -1 { 442 | return tag[:idx], tagOptions(tag[idx+1:]) 443 | } 444 | return tag, tagOptions("") 445 | } 446 | 447 | // Contains reports whether a comma-separated list of options 448 | // contains a particular substr flag. substr must be surrounded by a 449 | // string boundary or commas. 450 | func (o tagOptions) Contains(optionName string) bool { 451 | if len(o) == 0 { 452 | return false 453 | } 454 | s := string(o) 455 | for s != "" { 456 | var next string 457 | i := strings.Index(s, ",") 458 | if i >= 0 { 459 | s, next = s[:i], s[i+1:] 460 | } 461 | if s == optionName { 462 | return true 463 | } 464 | s = next 465 | } 466 | return false 467 | } 468 | 469 | func writeStruct(w io.Writer, val reflect.Value) (err error) { 470 | _, err = fmt.Fprint(w, "d") 471 | if err != nil { 472 | return 473 | } 474 | 475 | typ := val.Type() 476 | 477 | numFields := val.NumField() 478 | svList := make(stringValueArray, numFields) 479 | 480 | for i := 0; i < numFields; i++ { 481 | field := typ.Field(i) 482 | bencodeKey(field, &svList[i]) 483 | // The tag `bencode:"-"` should mean that this field must be ignored 484 | // See https://golang.org/pkg/encoding/json/#Marshal or https://golang.org/pkg/encoding/xml/#Marshal 485 | // We set a zero value so that it is ignored by the writeSVList() function 486 | if svList[i].key == "-" { 487 | svList[i].value = reflect.Value{} 488 | } else { 489 | svList[i].value = val.Field(i) 490 | } 491 | } 492 | 493 | err = writeSVList(w, svList) 494 | if err != nil { 495 | return 496 | } 497 | 498 | _, err = fmt.Fprint(w, "e") 499 | if err != nil { 500 | return 501 | } 502 | return 503 | } 504 | 505 | func writeValue(w io.Writer, val reflect.Value) (err error) { 506 | if !val.IsValid() { 507 | err = errors.New("Can't write null value") 508 | return 509 | } 510 | 511 | switch v := val; v.Kind() { 512 | case reflect.String: 513 | s := v.String() 514 | _, err = fmt.Fprintf(w, "%d:%s", len(s), s) 515 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 516 | _, err = fmt.Fprintf(w, "i%de", v.Int()) 517 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 518 | _, err = fmt.Fprintf(w, "i%de", v.Uint()) 519 | case reflect.Array: 520 | err = writeArrayOrSlice(w, v) 521 | case reflect.Slice: 522 | switch val.Type().String() { 523 | case "[]uint8": 524 | // special case as byte-string 525 | s := string(v.Bytes()) 526 | _, err = fmt.Fprintf(w, "%d:%s", len(s), s) 527 | default: 528 | err = writeArrayOrSlice(w, v) 529 | } 530 | case reflect.Map: 531 | err = writeMap(w, v) 532 | case reflect.Struct: 533 | err = writeStruct(w, v) 534 | case reflect.Interface: 535 | err = writeValue(w, v.Elem()) 536 | default: 537 | err = &MarshalError{val.Type()} 538 | } 539 | return 540 | } 541 | 542 | func isEmptyValue(v reflect.Value) bool { 543 | switch v.Kind() { 544 | case reflect.Array, reflect.Map, reflect.Slice, reflect.String: 545 | return v.Len() == 0 546 | case reflect.Bool: 547 | return !v.Bool() 548 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 549 | return v.Int() == 0 550 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 551 | return v.Uint() == 0 552 | case reflect.Float32, reflect.Float64: 553 | return v.Float() == 0 554 | case reflect.Interface, reflect.Ptr: 555 | return v.IsNil() 556 | } 557 | return false 558 | } 559 | 560 | func (sv stringValue) isValueNil() bool { 561 | if !sv.value.IsValid() || (sv.omitEmpty && isEmptyValue(sv.value)) { 562 | return true 563 | } 564 | switch v := sv.value; v.Kind() { 565 | case reflect.Interface: 566 | return !v.Elem().IsValid() 567 | } 568 | return false 569 | } 570 | 571 | // Marshal writes the bencode encoding of val to w. 572 | // 573 | // Marshal traverses the value v recursively. 574 | // 575 | // Marshal uses the following type-dependent encodings: 576 | // 577 | // Floating point, integer, and Number values encode as bencode numbers. 578 | // 579 | // String values encode as bencode strings. 580 | // 581 | // Array and slice values encode as bencode arrays. 582 | // 583 | // Struct values encode as bencode maps. Each exported struct field 584 | // becomes a member of the object. 585 | // The object's default key string is the struct field name 586 | // but can be specified in the struct field's tag value. The text of 587 | // the struct field's tag value is the key name. Examples: 588 | // 589 | // // Field appears in bencode as key "Field". 590 | // Field int 591 | // 592 | // // Field appears in bencode as key "myName". 593 | // Field int "myName" 594 | // 595 | // Anonymous struct fields are ignored. 596 | // 597 | // Map values encode as bencode objects. 598 | // The map's key type must be string; the object keys are used directly 599 | // as map keys. 600 | // 601 | // Boolean, Pointer, Interface, Channel, complex, and function values cannot 602 | // be encoded in bencode. 603 | // Attempting to encode such a value causes Marshal to return 604 | // a MarshalError. 605 | // 606 | // Bencode cannot represent cyclic data structures and Marshal does not 607 | // handle them. Passing cyclic structures to Marshal will result in 608 | // an infinite recursion. 609 | // 610 | func Marshal(w io.Writer, val interface{}) error { 611 | return writeValue(w, reflect.ValueOf(val)) 612 | } 613 | --------------------------------------------------------------------------------