sig.go (5985B)
1 package dbus 2 3 import ( 4 "fmt" 5 "reflect" 6 "strings" 7 ) 8 9 var sigToType = map[byte]reflect.Type{ 10 'y': byteType, 11 'b': boolType, 12 'n': int16Type, 13 'q': uint16Type, 14 'i': int32Type, 15 'u': uint32Type, 16 'x': int64Type, 17 't': uint64Type, 18 'd': float64Type, 19 's': stringType, 20 'g': signatureType, 21 'o': objectPathType, 22 'v': variantType, 23 'h': unixFDIndexType, 24 } 25 26 // Signature represents a correct type signature as specified by the D-Bus 27 // specification. The zero value represents the empty signature, "". 28 type Signature struct { 29 str string 30 } 31 32 // SignatureOf returns the concatenation of all the signatures of the given 33 // values. It panics if one of them is not representable in D-Bus. 34 func SignatureOf(vs ...interface{}) Signature { 35 var s string 36 for _, v := range vs { 37 s += getSignature(reflect.TypeOf(v)) 38 } 39 return Signature{s} 40 } 41 42 // SignatureOfType returns the signature of the given type. It panics if the 43 // type is not representable in D-Bus. 44 func SignatureOfType(t reflect.Type) Signature { 45 return Signature{getSignature(t)} 46 } 47 48 // getSignature returns the signature of the given type and panics on unknown types. 49 func getSignature(t reflect.Type) string { 50 // handle simple types first 51 switch t.Kind() { 52 case reflect.Uint8: 53 return "y" 54 case reflect.Bool: 55 return "b" 56 case reflect.Int16: 57 return "n" 58 case reflect.Uint16: 59 return "q" 60 case reflect.Int, reflect.Int32: 61 if t == unixFDType { 62 return "h" 63 } 64 return "i" 65 case reflect.Uint, reflect.Uint32: 66 if t == unixFDIndexType { 67 return "h" 68 } 69 return "u" 70 case reflect.Int64: 71 return "x" 72 case reflect.Uint64: 73 return "t" 74 case reflect.Float64: 75 return "d" 76 case reflect.Ptr: 77 return getSignature(t.Elem()) 78 case reflect.String: 79 if t == objectPathType { 80 return "o" 81 } 82 return "s" 83 case reflect.Struct: 84 if t == variantType { 85 return "v" 86 } else if t == signatureType { 87 return "g" 88 } 89 var s string 90 for i := 0; i < t.NumField(); i++ { 91 field := t.Field(i) 92 if field.PkgPath == "" && field.Tag.Get("dbus") != "-" { 93 s += getSignature(t.Field(i).Type) 94 } 95 } 96 return "(" + s + ")" 97 case reflect.Array, reflect.Slice: 98 return "a" + getSignature(t.Elem()) 99 case reflect.Map: 100 if !isKeyType(t.Key()) { 101 panic(InvalidTypeError{t}) 102 } 103 return "a{" + getSignature(t.Key()) + getSignature(t.Elem()) + "}" 104 case reflect.Interface: 105 return "v" 106 } 107 panic(InvalidTypeError{t}) 108 } 109 110 // ParseSignature returns the signature represented by this string, or a 111 // SignatureError if the string is not a valid signature. 112 func ParseSignature(s string) (sig Signature, err error) { 113 if len(s) == 0 { 114 return 115 } 116 if len(s) > 255 { 117 return Signature{""}, SignatureError{s, "too long"} 118 } 119 sig.str = s 120 for err == nil && len(s) != 0 { 121 err, s = validSingle(s, 0) 122 } 123 if err != nil { 124 sig = Signature{""} 125 } 126 127 return 128 } 129 130 // ParseSignatureMust behaves like ParseSignature, except that it panics if s 131 // is not valid. 132 func ParseSignatureMust(s string) Signature { 133 sig, err := ParseSignature(s) 134 if err != nil { 135 panic(err) 136 } 137 return sig 138 } 139 140 // Empty returns whether the signature is the empty signature. 141 func (s Signature) Empty() bool { 142 return s.str == "" 143 } 144 145 // Single returns whether the signature represents a single, complete type. 146 func (s Signature) Single() bool { 147 err, r := validSingle(s.str, 0) 148 return err != nil && r == "" 149 } 150 151 // String returns the signature's string representation. 152 func (s Signature) String() string { 153 return s.str 154 } 155 156 // A SignatureError indicates that a signature passed to a function or received 157 // on a connection is not a valid signature. 158 type SignatureError struct { 159 Sig string 160 Reason string 161 } 162 163 func (e SignatureError) Error() string { 164 return fmt.Sprintf("dbus: invalid signature: %q (%s)", e.Sig, e.Reason) 165 } 166 167 // Try to read a single type from this string. If it was successful, err is nil 168 // and rem is the remaining unparsed part. Otherwise, err is a non-nil 169 // SignatureError and rem is "". depth is the current recursion depth which may 170 // not be greater than 64 and should be given as 0 on the first call. 171 func validSingle(s string, depth int) (err error, rem string) { 172 if s == "" { 173 return SignatureError{Sig: s, Reason: "empty signature"}, "" 174 } 175 if depth > 64 { 176 return SignatureError{Sig: s, Reason: "container nesting too deep"}, "" 177 } 178 switch s[0] { 179 case 'y', 'b', 'n', 'q', 'i', 'u', 'x', 't', 'd', 's', 'g', 'o', 'v', 'h': 180 return nil, s[1:] 181 case 'a': 182 if len(s) > 1 && s[1] == '{' { 183 i := findMatching(s[1:], '{', '}') 184 if i == -1 { 185 return SignatureError{Sig: s, Reason: "unmatched '{'"}, "" 186 } 187 i++ 188 rem = s[i+1:] 189 s = s[2:i] 190 if err, _ = validSingle(s[:1], depth+1); err != nil { 191 return err, "" 192 } 193 err, nr := validSingle(s[1:], depth+1) 194 if err != nil { 195 return err, "" 196 } 197 if nr != "" { 198 return SignatureError{Sig: s, Reason: "too many types in dict"}, "" 199 } 200 return nil, rem 201 } 202 return validSingle(s[1:], depth+1) 203 case '(': 204 i := findMatching(s, '(', ')') 205 if i == -1 { 206 return SignatureError{Sig: s, Reason: "unmatched ')'"}, "" 207 } 208 rem = s[i+1:] 209 s = s[1:i] 210 for err == nil && s != "" { 211 err, s = validSingle(s, depth+1) 212 } 213 if err != nil { 214 rem = "" 215 } 216 return 217 } 218 return SignatureError{Sig: s, Reason: "invalid type character"}, "" 219 } 220 221 func findMatching(s string, left, right rune) int { 222 n := 0 223 for i, v := range s { 224 if v == left { 225 n++ 226 } else if v == right { 227 n-- 228 } 229 if n == 0 { 230 return i 231 } 232 } 233 return -1 234 } 235 236 // typeFor returns the type of the given signature. It ignores any left over 237 // characters and panics if s doesn't start with a valid type signature. 238 func typeFor(s string) (t reflect.Type) { 239 err, _ := validSingle(s, 0) 240 if err != nil { 241 panic(err) 242 } 243 244 if t, ok := sigToType[s[0]]; ok { 245 return t 246 } 247 switch s[0] { 248 case 'a': 249 if s[1] == '{' { 250 i := strings.LastIndex(s, "}") 251 t = reflect.MapOf(sigToType[s[2]], typeFor(s[3:i])) 252 } else { 253 t = reflect.SliceOf(typeFor(s[1:])) 254 } 255 case '(': 256 t = interfacesType 257 } 258 return 259 }