gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

dbus.go (10847B)


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