aboutsummaryrefslogtreecommitdiff
path: root/bencode
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2016-06-15 23:10:32 +0200
committerDimitri Sokolyuk <demon@dim13.org>2016-06-15 23:10:32 +0200
commitbd5f86a67cdc9c17b5bade36ffd2c3099e31741a (patch)
treed1c7506151efac0677f71e7639d802c7ff5a01c5 /bencode
parentbaa16931fd93d3f927975a4d83c02e52a44a3abc (diff)
Ugly, but works
Diffstat (limited to 'bencode')
-rw-r--r--bencode/bencode.go104
-rw-r--r--bencode/bencode_test.go10
2 files changed, 71 insertions, 43 deletions
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)
}
}