1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
package main
import (
"reflect"
"strings"
"github.com/godbus/dbus"
)
// copy from github.com/godbus/dbus/sig.go
var (
byteType = reflect.TypeOf(byte(0))
boolType = reflect.TypeOf(false)
uint8Type = reflect.TypeOf(uint8(0))
int16Type = reflect.TypeOf(int16(0))
uint16Type = reflect.TypeOf(uint16(0))
intType = reflect.TypeOf(int(0))
uintType = reflect.TypeOf(uint(0))
int32Type = reflect.TypeOf(int32(0))
uint32Type = reflect.TypeOf(uint32(0))
int64Type = reflect.TypeOf(int64(0))
uint64Type = reflect.TypeOf(uint64(0))
float64Type = reflect.TypeOf(float64(0))
stringType = reflect.TypeOf("")
signatureType = reflect.TypeOf(dbus.Signature{})
objectPathType = reflect.TypeOf(dbus.ObjectPath(""))
variantType = reflect.TypeOf(dbus.Variant{})
interfacesType = reflect.TypeOf([]interface{}{})
interfaceType = reflect.TypeOf((*interface{})(nil)).Elem()
unixFDType = reflect.TypeOf(dbus.UnixFD(0))
unixFDIndexType = reflect.TypeOf(dbus.UnixFDIndex(0))
)
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': unixFDType,
}
// Try to read a single type from this string. If it was successful, 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 dbus.SignatureError{Sig: s, Reason: "empty signature"}, ""
}
if depth > 64 {
return dbus.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 dbus.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 dbus.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 dbus.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 dbus.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
}
func TypeFor(s string) reflect.Type {
return typeFor(s)
}
|