123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- package dbus
- import (
- "fmt"
- "reflect"
- "strings"
- )
- var sigToType = map[byte]reflect.Type{
- 'y': byteType,
- 'b': boolType,
- 'n': int16Type,
- 'q': uint16Type,
- 'i': int32Type,
- 'u': uint32Type,
- 'x': int64Type,
- 't': uint64Type,
- 'd': float64Type,
- 's': stringType,
- 'g': signatureType,
- 'o': objectPathType,
- 'v': variantType,
- 'h': unixFDIndexType,
- }
- // Signature represents a correct type signature as specified by the D-Bus
- // specification. The zero value represents the empty signature, "".
- type Signature struct {
- str string
- }
- // SignatureOf returns the concatenation of all the signatures of the given
- // values. It panics if one of them is not representable in D-Bus.
- func SignatureOf(vs ...interface{}) Signature {
- var s string
- for _, v := range vs {
- s += getSignature(reflect.TypeOf(v))
- }
- return Signature{s}
- }
- // SignatureOfType returns the signature of the given type. It panics if the
- // type is not representable in D-Bus.
- func SignatureOfType(t reflect.Type) Signature {
- return Signature{getSignature(t)}
- }
- // getSignature returns the signature of the given type and panics on unknown types.
- func getSignature(t reflect.Type) string {
- // handle simple types first
- switch t.Kind() {
- case reflect.Uint8:
- return "y"
- case reflect.Bool:
- return "b"
- case reflect.Int16:
- return "n"
- case reflect.Uint16:
- return "q"
- case reflect.Int32:
- if t == unixFDType {
- return "h"
- }
- return "i"
- case reflect.Uint32:
- if t == unixFDIndexType {
- return "h"
- }
- return "u"
- case reflect.Int64:
- return "x"
- case reflect.Uint64:
- return "t"
- case reflect.Float64:
- return "d"
- case reflect.Ptr:
- return getSignature(t.Elem())
- case reflect.String:
- if t == objectPathType {
- return "o"
- }
- return "s"
- case reflect.Struct:
- if t == variantType {
- return "v"
- } else if t == signatureType {
- return "g"
- }
- var s string
- for i := 0; i < t.NumField(); i++ {
- field := t.Field(i)
- if field.PkgPath == "" && field.Tag.Get("dbus") != "-" {
- s += getSignature(t.Field(i).Type)
- }
- }
- return "(" + s + ")"
- case reflect.Array, reflect.Slice:
- return "a" + getSignature(t.Elem())
- case reflect.Map:
- if !isKeyType(t.Key()) {
- panic(InvalidTypeError{t})
- }
- return "a{" + getSignature(t.Key()) + getSignature(t.Elem()) + "}"
- }
- panic(InvalidTypeError{t})
- }
- // ParseSignature returns the signature represented by this string, or a
- // SignatureError if the string is not a valid signature.
- func ParseSignature(s string) (sig Signature, err error) {
- if len(s) == 0 {
- return
- }
- if len(s) > 255 {
- return Signature{""}, SignatureError{s, "too long"}
- }
- sig.str = s
- for err == nil && len(s) != 0 {
- err, s = validSingle(s, 0)
- }
- if err != nil {
- sig = Signature{""}
- }
- return
- }
- // ParseSignatureMust behaves like ParseSignature, except that it panics if s
- // is not valid.
- func ParseSignatureMust(s string) Signature {
- sig, err := ParseSignature(s)
- if err != nil {
- panic(err)
- }
- return sig
- }
- // Empty retruns whether the signature is the empty signature.
- func (s Signature) Empty() bool {
- return s.str == ""
- }
- // Single returns whether the signature represents a single, complete type.
- func (s Signature) Single() bool {
- err, r := validSingle(s.str, 0)
- return err != nil && r == ""
- }
- // String returns the signature's string representation.
- func (s Signature) String() string {
- return s.str
- }
- // A SignatureError indicates that a signature passed to a function or received
- // on a connection is not a valid signature.
- type SignatureError struct {
- Sig string
- Reason string
- }
- func (e SignatureError) Error() string {
- return fmt.Sprintf("dbus: invalid signature: %q (%s)", e.Sig, e.Reason)
- }
- // Try to read a single type from this string. If it was successfull, err is nil
- // and rem is the remaining unparsed part. Otherwise, err is a non-nil
- // SignatureError and rem is "". depth is the current recursion depth which may
- // not be greater than 64 and should be given as 0 on the first call.
- func validSingle(s string, depth int) (err error, rem string) {
- if s == "" {
- return SignatureError{Sig: s, Reason: "empty signature"}, ""
- }
- if depth > 64 {
- return SignatureError{Sig: s, Reason: "container nesting too deep"}, ""
- }
- switch s[0] {
- case 'y', 'b', 'n', 'q', 'i', 'u', 'x', 't', 'd', 's', 'g', 'o', 'v', 'h':
- return nil, s[1:]
- case 'a':
- if len(s) > 1 && s[1] == '{' {
- i := findMatching(s[1:], '{', '}')
- if i == -1 {
- return SignatureError{Sig: s, Reason: "unmatched '{'"}, ""
- }
- i++
- rem = s[i+1:]
- s = s[2:i]
- if err, _ = validSingle(s[:1], depth+1); err != nil {
- return err, ""
- }
- err, nr := validSingle(s[1:], depth+1)
- if err != nil {
- return err, ""
- }
- if nr != "" {
- return SignatureError{Sig: s, Reason: "too many types in dict"}, ""
- }
- return nil, rem
- }
- return validSingle(s[1:], depth+1)
- case '(':
- i := findMatching(s, '(', ')')
- if i == -1 {
- return SignatureError{Sig: s, Reason: "unmatched ')'"}, ""
- }
- rem = s[i+1:]
- s = s[1:i]
- for err == nil && s != "" {
- err, s = validSingle(s, depth+1)
- }
- if err != nil {
- rem = ""
- }
- return
- }
- return SignatureError{Sig: s, Reason: "invalid type character"}, ""
- }
- func findMatching(s string, left, right rune) int {
- n := 0
- for i, v := range s {
- if v == left {
- n++
- } else if v == right {
- n--
- }
- if n == 0 {
- return i
- }
- }
- return -1
- }
- // typeFor returns the type of the given signature. It ignores any left over
- // characters and panics if s doesn't start with a valid type signature.
- func typeFor(s string) (t reflect.Type) {
- err, _ := validSingle(s, 0)
- if err != nil {
- panic(err)
- }
- if t, ok := sigToType[s[0]]; ok {
- return t
- }
- switch s[0] {
- case 'a':
- if s[1] == '{' {
- i := strings.LastIndex(s, "}")
- t = reflect.MapOf(sigToType[s[2]], typeFor(s[3:i]))
- } else {
- t = reflect.SliceOf(typeFor(s[1:]))
- }
- case '(':
- t = interfacesType
- }
- return
- }
|