From bd5f86a67cdc9c17b5bade36ffd2c3099e31741a Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Wed, 15 Jun 2016 23:10:32 +0200 Subject: Ugly, but works --- bencode/bencode.go | 104 +++++++++++++++++++++++++++++------------------- bencode/bencode_test.go | 10 ++++- 2 files changed, 71 insertions(+), 43 deletions(-) (limited to 'bencode') diff --git a/bencode/bencode.go b/bencode/bencode.go index 2c2bdfc..c8840fd 100644 --- a/bencode/bencode.go +++ b/bencode/bencode.go @@ -155,26 +155,35 @@ func (d *decodeState) unmarshalDict(v reflect.Value) { for d.data[d.off] != 'e' { key, n := parseString(d.data[d.off:]) d.off += n - t := v.Type() - for i := 0; i < t.NumField(); i++ { - f := t.Field(i) - tag := f.Tag.Get("bencode") - name, _ := parseTag(tag) - if name == key || f.Name == key { - if key == "info" { - infoOff = d.off - } - d.unmarshalField(v.Field(i)) - if key == "info" { - infoEnd = d.off + var has bool + if v.CanSet() { + t := v.Type() + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + tag := f.Tag.Get("bencode") + name, _ := parseTag(tag) + if name == key || f.Name == key { + if key == "info" { + infoOff = d.off + } + d.unmarshalField(v.Field(i)) + if key == "info" { + infoEnd = d.off + } + has = true + break } - break } } + if !has { + d.unmarshalField(reflect.Value{}) + } } - if ih := v.FieldByName("InfoHash"); ih.IsValid() && infoEnd > infoOff { - sum := sha1.Sum(d.data[infoOff:infoEnd]) - ih.SetBytes(sum[:]) + if v.CanSet() { + if ih := v.FieldByName("InfoHash"); ih.IsValid() && infoEnd > infoOff { + sum := sha1.Sum(d.data[infoOff:infoEnd]) + ih.SetBytes(sum[:]) + } } d.off++ } @@ -186,19 +195,23 @@ func (d *decodeState) unmarshalList(v reflect.Value) { d.off++ for i := 0; d.data[d.off] != 'e'; i++ { - if i >= v.Cap() { - newcap := v.Cap() + v.Cap()/2 - if newcap < 4 { - newcap = 4 + if v.CanSet() { + if i >= v.Cap() { + newcap := v.Cap() + v.Cap()/2 + if newcap < 4 { + newcap = 4 + } + newv := reflect.MakeSlice(v.Type(), v.Len(), newcap) + reflect.Copy(newv, v) + v.Set(newv) } - newv := reflect.MakeSlice(v.Type(), v.Len(), newcap) - reflect.Copy(newv, v) - v.Set(newv) - } - if i >= v.Len() { - v.SetLen(i + 1) + if i >= v.Len() { + v.SetLen(i + 1) + } + d.unmarshalField(v.Index(i)) + } else { + d.unmarshalField(reflect.Value{}) } - d.unmarshalField(v.Index(i)) } d.off++ } @@ -206,18 +219,25 @@ func (d *decodeState) unmarshalList(v reflect.Value) { func (d *decodeState) unmarshalString(v reflect.Value) { s, n := parseString(d.data[d.off:]) d.off += n - switch v.Kind() { - case reflect.Slice: - v.SetBytes([]byte(s)) - default: - v.SetString(s) + if v.CanSet() { + switch v.Kind() { + case reflect.Slice: + v.SetBytes([]byte(s)) + default: + v.SetString(s) + } } } func parseString(data []byte) (string, int) { + switch data[0] { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + default: + panic("not a string") + } i := bytes.IndexByte(data, ':') if i < 0 { - panic("not a string") + panic("not a string, separator missing") } size, err := strconv.Atoi(string(data[:i])) if err != nil { @@ -230,14 +250,16 @@ func parseString(data []byte) (string, int) { func (d *decodeState) unmarshalInt(v reflect.Value) { i, n := parseInt(d.data[d.off:]) d.off += n - switch v.Interface().(type) { - case time.Time: - t := time.Unix(i, 0) - v.Set(reflect.ValueOf(t)) - case bool: - v.SetBool(i == 1) - default: - v.SetInt(i) + if v.CanSet() { + switch v.Interface().(type) { + case time.Time: + t := time.Unix(i, 0) + v.Set(reflect.ValueOf(t)) + case bool: + v.SetBool(i == 1) + default: + v.SetInt(i) + } } } diff --git a/bencode/bencode_test.go b/bencode/bencode_test.go index 84fda69..8fb6856 100644 --- a/bencode/bencode_test.go +++ b/bencode/bencode_test.go @@ -69,6 +69,7 @@ var testCase = []struct { func TestUnmarshal(t *testing.T) { for _, tc := range testCase { + t.Log("Testing", tc.Torrent) var tor meta.Torrent body, err := ioutil.ReadFile(tc.Torrent) if err != nil { @@ -85,9 +86,13 @@ func TestUnmarshal(t *testing.T) { } } -func testUnmarshalPartial(t *testing.T) { +func TestUnmarshalPartial(t *testing.T) { for _, tc := range testCase { - var tor = struct{ Announce string }{} + t.Log("Testing", tc.Torrent) + var tor = struct { + Announce string `bencode:"announce"` + //Announce string + }{} body, err := ioutil.ReadFile(tc.Torrent) if err != nil { t.Error(err) @@ -96,6 +101,7 @@ func testUnmarshalPartial(t *testing.T) { if err != nil { t.Error(err) } + t.Log(tor.Announce) } } -- cgit v1.2.3