]> Sergey Matveev's repositories - btrtrc.git/commitdiff
bencode: Support parsing strings into bool v1.49.0
authorMatt Joiner <anacrolix@gmail.com>
Sun, 19 Mar 2023 23:50:22 +0000 (10:50 +1100)
committerMatt Joiner <anacrolix@gmail.com>
Sun, 19 Mar 2023 23:50:22 +0000 (10:50 +1100)
bencode/decode.go
bencode/decode_test.go

index c171221f85610bf52e803df90c57f99cc7f3e6dc..6300f5cd7a02ad11e8288680faa1a7f1412759cc 100644 (file)
@@ -10,6 +10,7 @@ import (
        "runtime"
        "strconv"
        "sync"
+       "unsafe"
 )
 
 // The default bencode string length limit. This is a poor attempt to prevent excessive memory
@@ -246,13 +247,25 @@ func (d *Decoder) parseString(v reflect.Value) error {
                if v.Type().Elem().Kind() != reflect.Uint8 {
                        break
                }
-               d.buf.Grow(int(length))
+               d.buf.Grow(length)
                b := d.buf.Bytes()[:length]
                read(b)
                reflect.Copy(v, reflect.ValueOf(b))
                return nil
+       case reflect.Bool:
+               d.buf.Grow(length)
+               b := d.buf.Bytes()[:length]
+               read(b)
+               x, err := strconv.ParseBool(unsafe.String(unsafe.SliceData(b), len(b)))
+               if err != nil {
+                       x = length != 0
+               }
+               v.SetBool(x)
+               return nil
        }
-       d.buf.Grow(int(length))
+       // Can't move this into default clause because some cases above fail through to here after
+       // additional checks.
+       d.buf.Grow(length)
        read(d.buf.Bytes()[:length])
        // I believe we return here to support "ignore_unmarshal_type_error".
        return &UnmarshalTypeError{
index d06da8d380d94d1773170652a1617d13b0c6fdd9..4d05d2b332d77bedf6fc043076c62d306150dded 100644 (file)
@@ -234,3 +234,34 @@ func TestDecodeMaxStrLen(t *testing.T) {
                Hi []byte `bencode:"420"`
        }), 69)
 }
+
+// This is for the "github.com/anacrolix/torrent/metainfo".Info.Private field.
+func TestDecodeStringIntoBoolPtr(t *testing.T) {
+       var m struct {
+               Private *bool `bencode:"private,omitempty"`
+       }
+       c := qt.New(t)
+       check := func(msg string, expectNil, expectTrue bool) {
+               m.Private = nil
+               c.Check(Unmarshal([]byte(msg), &m), qt.IsNil, qt.Commentf("%q", msg))
+               if expectNil {
+                       c.Check(m.Private, qt.IsNil)
+               } else {
+                       if c.Check(m.Private, qt.IsNotNil, qt.Commentf("%q", msg)) {
+                               c.Check(*m.Private, qt.Equals, expectTrue, qt.Commentf("%q", msg))
+                       }
+               }
+       }
+       check("d7:privatei1ee", false, true)
+       check("d7:privatei0ee", false, false)
+       check("d7:privatei42ee", false, true)
+       // This is a weird case. We could not allocate the bool to indicate it was bad (maybe a bad
+       // serializer which isn't uncommon), but that requires reworking the decoder to handle
+       // automatically. I think if we cared enough we'd create a custom Unmarshaler. Also if we were
+       // worried enough about performance I'd completely rewrite this package.
+       check("d7:private0:e", false, false)
+       check("d7:private1:te", false, true)
+       check("d7:private5:falsee", false, false)
+       check("d7:private1:Fe", false, false)
+       check("d7:private11:bunnyfoofooe", false, true)
+}