package dbus import ( "bytes" "errors" "fmt" "io" "reflect" "strconv" "strings" "unicode/utf8" ) type varParser struct { tokens []varToken i int } func (p *varParser) backup() { p.i-- } func (p *varParser) next() varToken { if p.i < len(p.tokens) { t := p.tokens[p.i] p.i++ return t } return varToken{typ: tokEOF} } type varNode interface { Infer() (Signature, error) String() string Sigs() sigSet Value(Signature) (interface{}, error) } func varMakeNode(p *varParser) (varNode, error) { var sig Signature for { t := p.next() switch t.typ { case tokEOF: return nil, io.ErrUnexpectedEOF case tokError: return nil, errors.New(t.val) case tokNumber: return varMakeNumNode(t, sig) case tokString: return varMakeStringNode(t, sig) case tokBool: if sig.str != "" && sig.str != "b" { return nil, varTypeError{t.val, sig} } b, err := strconv.ParseBool(t.val) if err != nil { return nil, err } return boolNode(b), nil case tokArrayStart: return varMakeArrayNode(p, sig) case tokVariantStart: return varMakeVariantNode(p, sig) case tokDictStart: return varMakeDictNode(p, sig) case tokType: if sig.str != "" { return nil, errors.New("unexpected type annotation") } if t.val[0] == '@' { sig.str = t.val[1:] } else { sig.str = varTypeMap[t.val] } case tokByteString: if sig.str != "" && sig.str != "ay" { return nil, varTypeError{t.val, sig} } b, err := varParseByteString(t.val) if err != nil { return nil, err } return byteStringNode(b), nil default: return nil, fmt.Errorf("unexpected %q", t.val) } } } type varTypeError struct { val string sig Signature } func (e varTypeError) Error() string { return fmt.Sprintf("dbus: can't parse %q as type %q", e.val, e.sig.str) } type sigSet map[Signature]bool func (s sigSet) Empty() bool { return len(s) == 0 } func (s sigSet) Intersect(s2 sigSet) sigSet { r := make(sigSet) for k := range s { if s2[k] { r[k] = true } } return r } func (s sigSet) Single() (Signature, bool) { if len(s) == 1 { for k := range s { return k, true } } return Signature{}, false } func (s sigSet) ToArray() sigSet { r := make(sigSet, len(s)) for k := range s { r[Signature{"a" + k.str}] = true } return r } type numNode struct { sig Signature str string val interface{} } var numSigSet = sigSet{ Signature{"y"}: true, Signature{"n"}: true, Signature{"q"}: true, Signature{"i"}: true, Signature{"u"}: true, Signature{"x"}: true, Signature{"t"}: true, Signature{"d"}: true, } func (n numNode) Infer() (Signature, error) { if strings.ContainsAny(n.str, ".e") { return Signature{"d"}, nil } return Signature{"i"}, nil } func (n numNode) String() string { return n.str } func (n numNode) Sigs() sigSet { if n.sig.str != "" { return sigSet{n.sig: true} } if strings.ContainsAny(n.str, ".e") { return sigSet{Signature{"d"}: true} } return numSigSet } func (n numNode) Value(sig Signature) (interface{}, error) { if n.sig.str != "" && n.sig != sig { return nil, varTypeError{n.str, sig} } if n.val != nil { return n.val, nil } return varNumAs(n.str, sig) } func varMakeNumNode(tok varToken, sig Signature) (varNode, error) { if sig.str == "" { return numNode{str: tok.val}, nil } num, err := varNumAs(tok.val, sig) if err != nil { return nil, err } return numNode{sig: sig, val: num}, nil } func varNumAs(s string, sig Signature) (interface{}, error) { isUnsigned := false size := 32 switch sig.str { case "n": size = 16 case "i": case "x": size = 64 case "y": size = 8 isUnsigned = true case "q": size = 16 isUnsigned = true case "u": isUnsigned = true case "t": size = 64 isUnsigned = true case "d": d, err := strconv.ParseFloat(s, 64) if err != nil { return nil, err } return d, nil default: return nil, varTypeError{s, sig} } base := 10 if strings.HasPrefix(s, "0x") { base = 16 s = s[2:] } if strings.HasPrefix(s, "0") && len(s) != 1 { base = 8 s = s[1:] } if isUnsigned { i, err := strconv.ParseUint(s, base, size) if err != nil { return nil, err } var v interface{} = i switch sig.str { case "y": v = byte(i) case "q": v = uint16(i) case "u": v = uint32(i) } return v, nil } i, err := strconv.ParseInt(s, base, size) if err != nil { return nil, err } var v interface{} = i switch sig.str { case "n": v = int16(i) case "i": v = int32(i) } return v, nil } type stringNode struct { sig Signature str string // parsed val interface{} // has correct type } var stringSigSet = sigSet{ Signature{"s"}: true, Signature{"g"}: true, Signature{"o"}: true, } func (n stringNode) Infer() (Signature, error) { return Signature{"s"}, nil } func (n stringNode) String() string { return n.str } func (n stringNode) Sigs() sigSet { if n.sig.str != "" { return sigSet{n.sig: true} } return stringSigSet } func (n stringNode) Value(sig Signature) (interface{}, error) { if n.sig.str != "" && n.sig != sig { return nil, varTypeError{n.str, sig} } if n.val != nil { return n.val, nil } switch { case sig.str == "g": return Signature{n.str}, nil case sig.str == "o": return ObjectPath(n.str), nil case sig.str == "s": return n.str, nil default: return nil, varTypeError{n.str, sig} } } func varMakeStringNode(tok varToken, sig Signature) (varNode, error) { if sig.str != "" && sig.str != "s" && sig.str != "g" && sig.str != "o" { return nil, fmt.Errorf("invalid type %q for string", sig.str) } s, err := varParseString(tok.val) if err != nil { return nil, err } n := stringNode{str: s} if sig.str == "" { return stringNode{str: s}, nil } n.sig = sig switch sig.str { case "o": n.val = ObjectPath(s) case "g": n.val = Signature{s} case "s": n.val = s } return n, nil } func varParseString(s string) (string, error) { // quotes are guaranteed to be there s = s[1 : len(s)-1] buf := new(bytes.Buffer) for len(s) != 0 { r, size := utf8.DecodeRuneInString(s) if r == utf8.RuneError && size == 1 { return "", errors.New("invalid UTF-8") } s = s[size:] if r != '\\' { buf.WriteRune(r) continue } r, size = utf8.DecodeRuneInString(s) if r == utf8.RuneError && size == 1 { return "", errors.New("invalid UTF-8") } s = s[size:] switch r { case 'a': buf.WriteRune(0x7) case 'b': buf.WriteRune(0x8) case 'f': buf.WriteRune(0xc) case 'n': buf.WriteRune('\n') case 'r': buf.WriteRune('\r') case 't': buf.WriteRune('\t') case '\n': case 'u': if len(s) < 4 { return "", errors.New("short unicode escape") } r, err := strconv.ParseUint(s[:4], 16, 32) if err != nil { return "", err } buf.WriteRune(rune(r)) s = s[4:] case 'U': if len(s) < 8 { return "", errors.New("short unicode escape") } r, err := strconv.ParseUint(s[:8], 16, 32) if err != nil { return "", err } buf.WriteRune(rune(r)) s = s[8:] default: buf.WriteRune(r) } } return buf.String(), nil } var boolSigSet = sigSet{Signature{"b"}: true} type boolNode bool func (boolNode) Infer() (Signature, error) { return Signature{"b"}, nil } func (b boolNode) String() string { if b { return "true" } return "false" } func (boolNode) Sigs() sigSet { return boolSigSet } func (b boolNode) Value(sig Signature) (interface{}, error) { if sig.str != "b" { return nil, varTypeError{b.String(), sig} } return bool(b), nil } type arrayNode struct { set sigSet children []varNode val interface{} } func (n arrayNode) Infer() (Signature, error) { for _, v := range n.children { csig, err := varInfer(v) if err != nil { continue } return Signature{"a" + csig.str}, nil } return Signature{}, fmt.Errorf("can't infer type for %q", n.String()) } func (n arrayNode) String() string { s := "[" for i, v := range n.children { s += v.String() if i != len(n.children)-1 { s += ", " } } return s + "]" } func (n arrayNode) Sigs() sigSet { return n.set } func (n arrayNode) Value(sig Signature) (interface{}, error) { if n.set.Empty() { // no type information whatsoever, so this must be an empty slice return reflect.MakeSlice(typeFor(sig.str), 0, 0).Interface(), nil } if !n.set[sig] { return nil, varTypeError{n.String(), sig} } s := reflect.MakeSlice(typeFor(sig.str), len(n.children), len(n.children)) for i, v := range n.children { rv, err := v.Value(Signature{sig.str[1:]}) if err != nil { return nil, err } s.Index(i).Set(reflect.ValueOf(rv)) } return s.Interface(), nil } func varMakeArrayNode(p *varParser, sig Signature) (varNode, error) { var n arrayNode if sig.str != "" { n.set = sigSet{sig: true} } if t := p.next(); t.typ == tokArrayEnd { return n, nil } else { p.backup() } Loop: for { t := p.next() switch t.typ { case tokEOF: return nil, io.ErrUnexpectedEOF case tokError: return nil, errors.New(t.val) } p.backup() cn, err := varMakeNode(p) if err != nil { return nil, err } if cset := cn.Sigs(); !cset.Empty() { if n.set.Empty() { n.set = cset.ToArray() } else { nset := cset.ToArray().Intersect(n.set) if nset.Empty() { return nil, fmt.Errorf("can't parse %q with given type information", cn.String()) } n.set = nset } } n.children = append(n.children, cn) switch t := p.next(); t.typ { case tokEOF: return nil, io.ErrUnexpectedEOF case tokError: return nil, errors.New(t.val) case tokArrayEnd: break Loop case tokComma: continue default: return nil, fmt.Errorf("unexpected %q", t.val) } } return n, nil } type variantNode struct { n varNode } var variantSet = sigSet{ Signature{"v"}: true, } func (variantNode) Infer() (Signature, error) { return Signature{"v"}, nil } func (n variantNode) String() string { return "<" + n.n.String() + ">" } func (variantNode) Sigs() sigSet { return variantSet } func (n variantNode) Value(sig Signature) (interface{}, error) { if sig.str != "v" { return nil, varTypeError{n.String(), sig} } sig, err := varInfer(n.n) if err != nil { return nil, err } v, err := n.n.Value(sig) if err != nil { return nil, err } return MakeVariant(v), nil } func varMakeVariantNode(p *varParser, sig Signature) (varNode, error) { n, err := varMakeNode(p) if err != nil { return nil, err } if t := p.next(); t.typ != tokVariantEnd { return nil, fmt.Errorf("unexpected %q", t.val) } vn := variantNode{n} if sig.str != "" && sig.str != "v" { return nil, varTypeError{vn.String(), sig} } return variantNode{n}, nil } type dictEntry struct { key, val varNode } type dictNode struct { kset, vset sigSet children []dictEntry val interface{} } func (n dictNode) Infer() (Signature, error) { for _, v := range n.children { ksig, err := varInfer(v.key) if err != nil { continue } vsig, err := varInfer(v.val) if err != nil { continue } return Signature{"a{" + ksig.str + vsig.str + "}"}, nil } return Signature{}, fmt.Errorf("can't infer type for %q", n.String()) } func (n dictNode) String() string { s := "{" for i, v := range n.children { s += v.key.String() + ": " + v.val.String() if i != len(n.children)-1 { s += ", " } } return s + "}" } func (n dictNode) Sigs() sigSet { r := sigSet{} for k := range n.kset { for v := range n.vset { sig := "a{" + k.str + v.str + "}" r[Signature{sig}] = true } } return r } func (n dictNode) Value(sig Signature) (interface{}, error) { set := n.Sigs() if set.Empty() { // no type information -> empty dict return reflect.MakeMap(typeFor(sig.str)).Interface(), nil } if !set[sig] { return nil, varTypeError{n.String(), sig} } m := reflect.MakeMap(typeFor(sig.str)) ksig := Signature{sig.str[2:3]} vsig := Signature{sig.str[3 : len(sig.str)-1]} for _, v := range n.children { kv, err := v.key.Value(ksig) if err != nil { return nil, err } vv, err := v.val.Value(vsig) if err != nil { return nil, err } m.SetMapIndex(reflect.ValueOf(kv), reflect.ValueOf(vv)) } return m.Interface(), nil } func varMakeDictNode(p *varParser, sig Signature) (varNode, error) { var n dictNode if sig.str != "" { if len(sig.str) < 5 { return nil, fmt.Errorf("invalid signature %q for dict type", sig) } ksig := Signature{string(sig.str[2])} vsig := Signature{sig.str[3 : len(sig.str)-1]} n.kset = sigSet{ksig: true} n.vset = sigSet{vsig: true} } if t := p.next(); t.typ == tokDictEnd { return n, nil } else { p.backup() } Loop: for { t := p.next() switch t.typ { case tokEOF: return nil, io.ErrUnexpectedEOF case tokError: return nil, errors.New(t.val) } p.backup() kn, err := varMakeNode(p) if err != nil { return nil, err } if kset := kn.Sigs(); !kset.Empty() { if n.kset.Empty() { n.kset = kset } else { n.kset = kset.Intersect(n.kset) if n.kset.Empty() { return nil, fmt.Errorf("can't parse %q with given type information", kn.String()) } } } t = p.next() switch t.typ { case tokEOF: return nil, io.ErrUnexpectedEOF case tokError: return nil, errors.New(t.val) case tokColon: default: return nil, fmt.Errorf("unexpected %q", t.val) } t = p.next() switch t.typ { case tokEOF: return nil, io.ErrUnexpectedEOF case tokError: return nil, errors.New(t.val) } p.backup() vn, err := varMakeNode(p) if err != nil { return nil, err } if vset := vn.Sigs(); !vset.Empty() { if n.vset.Empty() { n.vset = vset } else { n.vset = n.vset.Intersect(vset) if n.vset.Empty() { return nil, fmt.Errorf("can't parse %q with given type information", vn.String()) } } } n.children = append(n.children, dictEntry{kn, vn}) t = p.next() switch t.typ { case tokEOF: return nil, io.ErrUnexpectedEOF case tokError: return nil, errors.New(t.val) case tokDictEnd: break Loop case tokComma: continue default: return nil, fmt.Errorf("unexpected %q", t.val) } } return n, nil } type byteStringNode []byte var byteStringSet = sigSet{ Signature{"ay"}: true, } func (byteStringNode) Infer() (Signature, error) { return Signature{"ay"}, nil } func (b byteStringNode) String() string { return string(b) } func (b byteStringNode) Sigs() sigSet { return byteStringSet } func (b byteStringNode) Value(sig Signature) (interface{}, error) { if sig.str != "ay" { return nil, varTypeError{b.String(), sig} } return []byte(b), nil } func varParseByteString(s string) ([]byte, error) { // quotes and b at start are guaranteed to be there b := make([]byte, 0, 1) s = s[2 : len(s)-1] for len(s) != 0 { c := s[0] s = s[1:] if c != '\\' { b = append(b, c) continue } c = s[0] s = s[1:] switch c { case 'a': b = append(b, 0x7) case 'b': b = append(b, 0x8) case 'f': b = append(b, 0xc) case 'n': b = append(b, '\n') case 'r': b = append(b, '\r') case 't': b = append(b, '\t') case 'x': if len(s) < 2 { return nil, errors.New("short escape") } n, err := strconv.ParseUint(s[:2], 16, 8) if err != nil { return nil, err } b = append(b, byte(n)) s = s[2:] case '0': if len(s) < 3 { return nil, errors.New("short escape") } n, err := strconv.ParseUint(s[:3], 8, 8) if err != nil { return nil, err } b = append(b, byte(n)) s = s[3:] default: b = append(b, c) } } return append(b, 0), nil } func varInfer(n varNode) (Signature, error) { if sig, ok := n.Sigs().Single(); ok { return sig, nil } return n.Infer() }