1package dbus 2 3import ( 4 "errors" 5 "fmt" 6 "reflect" 7 "strings" 8) 9 10var ( 11 byteType = reflect.TypeOf(byte(0)) 12 boolType = reflect.TypeOf(false) 13 uint8Type = reflect.TypeOf(uint8(0)) 14 int16Type = reflect.TypeOf(int16(0)) 15 uint16Type = reflect.TypeOf(uint16(0)) 16 intType = reflect.TypeOf(int(0)) 17 uintType = reflect.TypeOf(uint(0)) 18 int32Type = reflect.TypeOf(int32(0)) 19 uint32Type = reflect.TypeOf(uint32(0)) 20 int64Type = reflect.TypeOf(int64(0)) 21 uint64Type = reflect.TypeOf(uint64(0)) 22 float64Type = reflect.TypeOf(float64(0)) 23 stringType = reflect.TypeOf("") 24 signatureType = reflect.TypeOf(Signature{""}) 25 objectPathType = reflect.TypeOf(ObjectPath("")) 26 variantType = reflect.TypeOf(Variant{Signature{""}, nil}) 27 interfacesType = reflect.TypeOf([]interface{}{}) 28 interfaceType = reflect.TypeOf((*interface{})(nil)).Elem() 29 unixFDType = reflect.TypeOf(UnixFD(0)) 30 unixFDIndexType = reflect.TypeOf(UnixFDIndex(0)) 31) 32 33// An InvalidTypeError signals that a value which cannot be represented in the 34// D-Bus wire format was passed to a function. 35type InvalidTypeError struct { 36 Type reflect.Type 37} 38 39func (e InvalidTypeError) Error() string { 40 return "dbus: invalid type " + e.Type.String() 41} 42 43// Store copies the values contained in src to dest, which must be a slice of 44// pointers. It converts slices of interfaces from src to corresponding structs 45// in dest. An error is returned if the lengths of src and dest or the types of 46// their elements don't match. 47func Store(src []interface{}, dest ...interface{}) error { 48 if len(src) != len(dest) { 49 return errors.New("dbus.Store: length mismatch") 50 } 51 52 for i := range src { 53 if err := storeInterfaces(src[i], dest[i]); err != nil { 54 return err 55 } 56 } 57 return nil 58} 59 60func storeInterfaces(src, dest interface{}) error { 61 return store(reflect.ValueOf(dest), reflect.ValueOf(src)) 62} 63 64func store(dest, src reflect.Value) error { 65 if dest.Kind() == reflect.Ptr { 66 return store(dest.Elem(), src) 67 } 68 switch src.Kind() { 69 case reflect.Slice: 70 return storeSlice(dest, src) 71 case reflect.Map: 72 return storeMap(dest, src) 73 default: 74 return storeBase(dest, src) 75 } 76} 77 78func storeBase(dest, src reflect.Value) error { 79 return setDest(dest, src) 80} 81 82func setDest(dest, src reflect.Value) error { 83 if !isVariant(src.Type()) && isVariant(dest.Type()) { 84 //special conversion for dbus.Variant 85 dest.Set(reflect.ValueOf(MakeVariant(src.Interface()))) 86 return nil 87 } 88 if isVariant(src.Type()) && !isVariant(dest.Type()) { 89 src = getVariantValue(src) 90 } 91 if !src.Type().ConvertibleTo(dest.Type()) { 92 return fmt.Errorf( 93 "dbus.Store: type mismatch: cannot convert %s to %s", 94 src.Type(), dest.Type()) 95 } 96 dest.Set(src.Convert(dest.Type())) 97 return nil 98} 99 100func kindsAreCompatible(dest, src reflect.Type) bool { 101 switch { 102 case isVariant(dest): 103 return true 104 case dest.Kind() == reflect.Interface: 105 return true 106 default: 107 return dest.Kind() == src.Kind() 108 } 109} 110 111func isConvertibleTo(dest, src reflect.Type) bool { 112 switch { 113 case isVariant(dest): 114 return true 115 case dest.Kind() == reflect.Interface: 116 return true 117 case dest.Kind() == reflect.Slice: 118 return src.Kind() == reflect.Slice && 119 isConvertibleTo(dest.Elem(), src.Elem()) 120 case dest.Kind() == reflect.Struct: 121 return src == interfacesType 122 default: 123 return src.ConvertibleTo(dest) 124 } 125} 126 127func storeMap(dest, src reflect.Value) error { 128 switch { 129 case !kindsAreCompatible(dest.Type(), src.Type()): 130 return fmt.Errorf( 131 "dbus.Store: type mismatch: "+ 132 "map: cannot store a value of %s into %s", 133 src.Type(), dest.Type()) 134 case isVariant(dest.Type()): 135 return storeMapIntoVariant(dest, src) 136 case dest.Kind() == reflect.Interface: 137 return storeMapIntoInterface(dest, src) 138 case isConvertibleTo(dest.Type().Key(), src.Type().Key()) && 139 isConvertibleTo(dest.Type().Elem(), src.Type().Elem()): 140 return storeMapIntoMap(dest, src) 141 default: 142 return fmt.Errorf( 143 "dbus.Store: type mismatch: "+ 144 "map: cannot convert a value of %s into %s", 145 src.Type(), dest.Type()) 146 } 147} 148 149func storeMapIntoVariant(dest, src reflect.Value) error { 150 dv := reflect.MakeMap(src.Type()) 151 err := store(dv, src) 152 if err != nil { 153 return err 154 } 155 return storeBase(dest, dv) 156} 157 158func storeMapIntoInterface(dest, src reflect.Value) error { 159 var dv reflect.Value 160 if isVariant(src.Type().Elem()) { 161 //Convert variants to interface{} recursively when converting 162 //to interface{} 163 dv = reflect.MakeMap( 164 reflect.MapOf(src.Type().Key(), interfaceType)) 165 } else { 166 dv = reflect.MakeMap(src.Type()) 167 } 168 err := store(dv, src) 169 if err != nil { 170 return err 171 } 172 return storeBase(dest, dv) 173} 174 175func storeMapIntoMap(dest, src reflect.Value) error { 176 if dest.IsNil() { 177 dest.Set(reflect.MakeMap(dest.Type())) 178 } 179 keys := src.MapKeys() 180 for _, key := range keys { 181 dkey := key.Convert(dest.Type().Key()) 182 dval := reflect.New(dest.Type().Elem()).Elem() 183 err := store(dval, getVariantValue(src.MapIndex(key))) 184 if err != nil { 185 return err 186 } 187 dest.SetMapIndex(dkey, dval) 188 } 189 return nil 190} 191 192func storeSlice(dest, src reflect.Value) error { 193 switch { 194 case src.Type() == interfacesType && dest.Kind() == reflect.Struct: 195 //The decoder always decodes structs as slices of interface{} 196 return storeStruct(dest, src) 197 case !kindsAreCompatible(dest.Type(), src.Type()): 198 return fmt.Errorf( 199 "dbus.Store: type mismatch: "+ 200 "slice: cannot store a value of %s into %s", 201 src.Type(), dest.Type()) 202 case isVariant(dest.Type()): 203 return storeSliceIntoVariant(dest, src) 204 case dest.Kind() == reflect.Interface: 205 return storeSliceIntoInterface(dest, src) 206 case isConvertibleTo(dest.Type().Elem(), src.Type().Elem()): 207 return storeSliceIntoSlice(dest, src) 208 default: 209 return fmt.Errorf( 210 "dbus.Store: type mismatch: "+ 211 "slice: cannot convert a value of %s into %s", 212 src.Type(), dest.Type()) 213 } 214} 215 216func storeStruct(dest, src reflect.Value) error { 217 if isVariant(dest.Type()) { 218 return storeBase(dest, src) 219 } 220 dval := make([]interface{}, 0, dest.NumField()) 221 dtype := dest.Type() 222 for i := 0; i < dest.NumField(); i++ { 223 field := dest.Field(i) 224 ftype := dtype.Field(i) 225 if ftype.PkgPath != "" { 226 continue 227 } 228 if ftype.Tag.Get("dbus") == "-" { 229 continue 230 } 231 dval = append(dval, field.Addr().Interface()) 232 } 233 if src.Len() != len(dval) { 234 return fmt.Errorf( 235 "dbus.Store: type mismatch: "+ 236 "destination struct does not have "+ 237 "enough fields need: %d have: %d", 238 src.Len(), len(dval)) 239 } 240 return Store(src.Interface().([]interface{}), dval...) 241} 242 243func storeSliceIntoVariant(dest, src reflect.Value) error { 244 dv := reflect.MakeSlice(src.Type(), src.Len(), src.Cap()) 245 err := store(dv, src) 246 if err != nil { 247 return err 248 } 249 return storeBase(dest, dv) 250} 251 252func storeSliceIntoInterface(dest, src reflect.Value) error { 253 var dv reflect.Value 254 if isVariant(src.Type().Elem()) { 255 //Convert variants to interface{} recursively when converting 256 //to interface{} 257 dv = reflect.MakeSlice(reflect.SliceOf(interfaceType), 258 src.Len(), src.Cap()) 259 } else { 260 dv = reflect.MakeSlice(src.Type(), src.Len(), src.Cap()) 261 } 262 err := store(dv, src) 263 if err != nil { 264 return err 265 } 266 return storeBase(dest, dv) 267} 268 269func storeSliceIntoSlice(dest, src reflect.Value) error { 270 if dest.IsNil() || dest.Len() < src.Len() { 271 dest.Set(reflect.MakeSlice(dest.Type(), src.Len(), src.Cap())) 272 } 273 if dest.Len() != src.Len() { 274 return fmt.Errorf( 275 "dbus.Store: type mismatch: "+ 276 "slices are different lengths "+ 277 "need: %d have: %d", 278 src.Len(), dest.Len()) 279 } 280 for i := 0; i < src.Len(); i++ { 281 err := store(dest.Index(i), getVariantValue(src.Index(i))) 282 if err != nil { 283 return err 284 } 285 } 286 return nil 287} 288 289func getVariantValue(in reflect.Value) reflect.Value { 290 if isVariant(in.Type()) { 291 return reflect.ValueOf(in.Interface().(Variant).Value()) 292 } 293 return in 294} 295 296func isVariant(t reflect.Type) bool { 297 return t == variantType 298} 299 300// An ObjectPath is an object path as defined by the D-Bus spec. 301type ObjectPath string 302 303// IsValid returns whether the object path is valid. 304func (o ObjectPath) IsValid() bool { 305 s := string(o) 306 if len(s) == 0 { 307 return false 308 } 309 if s[0] != '/' { 310 return false 311 } 312 if s[len(s)-1] == '/' && len(s) != 1 { 313 return false 314 } 315 // probably not used, but technically possible 316 if s == "/" { 317 return true 318 } 319 split := strings.Split(s[1:], "/") 320 for _, v := range split { 321 if len(v) == 0 { 322 return false 323 } 324 for _, c := range v { 325 if !isMemberChar(c) { 326 return false 327 } 328 } 329 } 330 return true 331} 332 333// A UnixFD is a Unix file descriptor sent over the wire. See the package-level 334// documentation for more information about Unix file descriptor passsing. 335type UnixFD int32 336 337// A UnixFDIndex is the representation of a Unix file descriptor in a message. 338type UnixFDIndex uint32 339 340// alignment returns the alignment of values of type t. 341func alignment(t reflect.Type) int { 342 switch t { 343 case variantType: 344 return 1 345 case objectPathType: 346 return 4 347 case signatureType: 348 return 1 349 case interfacesType: 350 return 4 351 } 352 switch t.Kind() { 353 case reflect.Uint8: 354 return 1 355 case reflect.Uint16, reflect.Int16: 356 return 2 357 case reflect.Uint, reflect.Int, reflect.Uint32, reflect.Int32, reflect.String, reflect.Array, reflect.Slice, reflect.Map: 358 return 4 359 case reflect.Uint64, reflect.Int64, reflect.Float64, reflect.Struct: 360 return 8 361 case reflect.Ptr: 362 return alignment(t.Elem()) 363 } 364 return 1 365} 366 367// isKeyType returns whether t is a valid type for a D-Bus dict. 368func isKeyType(t reflect.Type) bool { 369 switch t.Kind() { 370 case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, 371 reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float64, 372 reflect.String, reflect.Uint, reflect.Int: 373 374 return true 375 } 376 return false 377} 378 379// isValidInterface returns whether s is a valid name for an interface. 380func isValidInterface(s string) bool { 381 if len(s) == 0 || len(s) > 255 || s[0] == '.' { 382 return false 383 } 384 elem := strings.Split(s, ".") 385 if len(elem) < 2 { 386 return false 387 } 388 for _, v := range elem { 389 if len(v) == 0 { 390 return false 391 } 392 if v[0] >= '0' && v[0] <= '9' { 393 return false 394 } 395 for _, c := range v { 396 if !isMemberChar(c) { 397 return false 398 } 399 } 400 } 401 return true 402} 403 404// isValidMember returns whether s is a valid name for a member. 405func isValidMember(s string) bool { 406 if len(s) == 0 || len(s) > 255 { 407 return false 408 } 409 i := strings.Index(s, ".") 410 if i != -1 { 411 return false 412 } 413 if s[0] >= '0' && s[0] <= '9' { 414 return false 415 } 416 for _, c := range s { 417 if !isMemberChar(c) { 418 return false 419 } 420 } 421 return true 422} 423 424func isMemberChar(c rune) bool { 425 return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || 426 (c >= 'a' && c <= 'z') || c == '_' 427} 428