...

Source file src/github.com/godbus/dbus/v5/dbus.go

Documentation: github.com/godbus/dbus/v5

     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.Ptr:
   126  		dest = dest.Elem()
   127  		return isConvertibleTo(dest, src)
   128  	case dest.Kind() == reflect.Struct:
   129  		return src == interfacesType || dest.Kind() == src.Kind()
   130  	default:
   131  		return src.ConvertibleTo(dest)
   132  	}
   133  }
   134  
   135  func storeMap(dest, src reflect.Value) error {
   136  	switch {
   137  	case !kindsAreCompatible(dest.Type(), src.Type()):
   138  		return fmt.Errorf(
   139  			"dbus.Store: type mismatch: "+
   140  				"map: cannot store a value of %s into %s",
   141  			src.Type(), dest.Type())
   142  	case isVariant(dest.Type()):
   143  		return storeMapIntoVariant(dest, src)
   144  	case dest.Kind() == reflect.Interface:
   145  		return storeMapIntoInterface(dest, src)
   146  	case isConvertibleTo(dest.Type().Key(), src.Type().Key()) &&
   147  		isConvertibleTo(dest.Type().Elem(), src.Type().Elem()):
   148  		return storeMapIntoMap(dest, src)
   149  	default:
   150  		return fmt.Errorf(
   151  			"dbus.Store: type mismatch: "+
   152  				"map: cannot convert a value of %s into %s",
   153  			src.Type(), dest.Type())
   154  	}
   155  }
   156  
   157  func storeMapIntoVariant(dest, src reflect.Value) error {
   158  	dv := reflect.MakeMap(src.Type())
   159  	err := store(dv, src)
   160  	if err != nil {
   161  		return err
   162  	}
   163  	return storeBase(dest, dv)
   164  }
   165  
   166  func storeMapIntoInterface(dest, src reflect.Value) error {
   167  	var dv reflect.Value
   168  	if isVariant(src.Type().Elem()) {
   169  		//Convert variants to interface{} recursively when converting
   170  		//to interface{}
   171  		dv = reflect.MakeMap(
   172  			reflect.MapOf(src.Type().Key(), interfaceType))
   173  	} else {
   174  		dv = reflect.MakeMap(src.Type())
   175  	}
   176  	err := store(dv, src)
   177  	if err != nil {
   178  		return err
   179  	}
   180  	return storeBase(dest, dv)
   181  }
   182  
   183  func storeMapIntoMap(dest, src reflect.Value) error {
   184  	if dest.IsNil() {
   185  		dest.Set(reflect.MakeMap(dest.Type()))
   186  	}
   187  	keys := src.MapKeys()
   188  	for _, key := range keys {
   189  		dkey := key.Convert(dest.Type().Key())
   190  		dval := reflect.New(dest.Type().Elem()).Elem()
   191  		err := store(dval, getVariantValue(src.MapIndex(key)))
   192  		if err != nil {
   193  			return err
   194  		}
   195  		dest.SetMapIndex(dkey, dval)
   196  	}
   197  	return nil
   198  }
   199  
   200  func storeSlice(dest, src reflect.Value) error {
   201  	switch {
   202  	case src.Type() == interfacesType && dest.Kind() == reflect.Struct:
   203  		//The decoder always decodes structs as slices of interface{}
   204  		return storeStruct(dest, src)
   205  	case !kindsAreCompatible(dest.Type(), src.Type()):
   206  		return fmt.Errorf(
   207  			"dbus.Store: type mismatch: "+
   208  				"slice: cannot store a value of %s into %s",
   209  			src.Type(), dest.Type())
   210  	case isVariant(dest.Type()):
   211  		return storeSliceIntoVariant(dest, src)
   212  	case dest.Kind() == reflect.Interface:
   213  		return storeSliceIntoInterface(dest, src)
   214  	case isConvertibleTo(dest.Type().Elem(), src.Type().Elem()):
   215  		return storeSliceIntoSlice(dest, src)
   216  	default:
   217  		return fmt.Errorf(
   218  			"dbus.Store: type mismatch: "+
   219  				"slice: cannot convert a value of %s into %s",
   220  			src.Type(), dest.Type())
   221  	}
   222  }
   223  
   224  func storeStruct(dest, src reflect.Value) error {
   225  	if isVariant(dest.Type()) {
   226  		return storeBase(dest, src)
   227  	}
   228  	dval := make([]interface{}, 0, dest.NumField())
   229  	dtype := dest.Type()
   230  	for i := 0; i < dest.NumField(); i++ {
   231  		field := dest.Field(i)
   232  		ftype := dtype.Field(i)
   233  		if ftype.PkgPath != "" {
   234  			continue
   235  		}
   236  		if ftype.Tag.Get("dbus") == "-" {
   237  			continue
   238  		}
   239  		dval = append(dval, field.Addr().Interface())
   240  	}
   241  	if src.Len() != len(dval) {
   242  		return fmt.Errorf(
   243  			"dbus.Store: type mismatch: "+
   244  				"destination struct does not have "+
   245  				"enough fields need: %d have: %d",
   246  			src.Len(), len(dval))
   247  	}
   248  	return Store(src.Interface().([]interface{}), dval...)
   249  }
   250  
   251  func storeSliceIntoVariant(dest, src reflect.Value) error {
   252  	dv := reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
   253  	err := store(dv, src)
   254  	if err != nil {
   255  		return err
   256  	}
   257  	return storeBase(dest, dv)
   258  }
   259  
   260  func storeSliceIntoInterface(dest, src reflect.Value) error {
   261  	var dv reflect.Value
   262  	if isVariant(src.Type().Elem()) {
   263  		//Convert variants to interface{} recursively when converting
   264  		//to interface{}
   265  		dv = reflect.MakeSlice(reflect.SliceOf(interfaceType),
   266  			src.Len(), src.Cap())
   267  	} else {
   268  		dv = reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
   269  	}
   270  	err := store(dv, src)
   271  	if err != nil {
   272  		return err
   273  	}
   274  	return storeBase(dest, dv)
   275  }
   276  
   277  func storeSliceIntoSlice(dest, src reflect.Value) error {
   278  	if dest.IsNil() || dest.Len() < src.Len() {
   279  		dest.Set(reflect.MakeSlice(dest.Type(), src.Len(), src.Cap()))
   280  	} else if dest.Len() > src.Len() {
   281  		dest.Set(dest.Slice(0, src.Len()))
   282  	}
   283  	for i := 0; i < src.Len(); i++ {
   284  		err := store(dest.Index(i), getVariantValue(src.Index(i)))
   285  		if err != nil {
   286  			return err
   287  		}
   288  	}
   289  	return nil
   290  }
   291  
   292  func getVariantValue(in reflect.Value) reflect.Value {
   293  	if isVariant(in.Type()) {
   294  		return reflect.ValueOf(in.Interface().(Variant).Value())
   295  	}
   296  	return in
   297  }
   298  
   299  func isVariant(t reflect.Type) bool {
   300  	return t == variantType
   301  }
   302  
   303  // An ObjectPath is an object path as defined by the D-Bus spec.
   304  type ObjectPath string
   305  
   306  // IsValid returns whether the object path is valid.
   307  func (o ObjectPath) IsValid() bool {
   308  	s := string(o)
   309  	if len(s) == 0 {
   310  		return false
   311  	}
   312  	if s[0] != '/' {
   313  		return false
   314  	}
   315  	if s[len(s)-1] == '/' && len(s) != 1 {
   316  		return false
   317  	}
   318  	// probably not used, but technically possible
   319  	if s == "/" {
   320  		return true
   321  	}
   322  	split := strings.Split(s[1:], "/")
   323  	for _, v := range split {
   324  		if len(v) == 0 {
   325  			return false
   326  		}
   327  		for _, c := range v {
   328  			if !isMemberChar(c) {
   329  				return false
   330  			}
   331  		}
   332  	}
   333  	return true
   334  }
   335  
   336  // A UnixFD is a Unix file descriptor sent over the wire. See the package-level
   337  // documentation for more information about Unix file descriptor passsing.
   338  type UnixFD int32
   339  
   340  // A UnixFDIndex is the representation of a Unix file descriptor in a message.
   341  type UnixFDIndex uint32
   342  
   343  // alignment returns the alignment of values of type t.
   344  func alignment(t reflect.Type) int {
   345  	switch t {
   346  	case variantType:
   347  		return 1
   348  	case objectPathType:
   349  		return 4
   350  	case signatureType:
   351  		return 1
   352  	case interfacesType:
   353  		return 4
   354  	}
   355  	switch t.Kind() {
   356  	case reflect.Uint8:
   357  		return 1
   358  	case reflect.Uint16, reflect.Int16:
   359  		return 2
   360  	case reflect.Uint, reflect.Int, reflect.Uint32, reflect.Int32, reflect.String, reflect.Array, reflect.Slice, reflect.Map:
   361  		return 4
   362  	case reflect.Uint64, reflect.Int64, reflect.Float64, reflect.Struct:
   363  		return 8
   364  	case reflect.Ptr:
   365  		return alignment(t.Elem())
   366  	}
   367  	return 1
   368  }
   369  
   370  // isKeyType returns whether t is a valid type for a D-Bus dict.
   371  func isKeyType(t reflect.Type) bool {
   372  	switch t.Kind() {
   373  	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
   374  		reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float64,
   375  		reflect.String, reflect.Uint, reflect.Int:
   376  
   377  		return true
   378  	}
   379  	return false
   380  }
   381  
   382  // isValidInterface returns whether s is a valid name for an interface.
   383  func isValidInterface(s string) bool {
   384  	if len(s) == 0 || len(s) > 255 || s[0] == '.' {
   385  		return false
   386  	}
   387  	elem := strings.Split(s, ".")
   388  	if len(elem) < 2 {
   389  		return false
   390  	}
   391  	for _, v := range elem {
   392  		if len(v) == 0 {
   393  			return false
   394  		}
   395  		if v[0] >= '0' && v[0] <= '9' {
   396  			return false
   397  		}
   398  		for _, c := range v {
   399  			if !isMemberChar(c) {
   400  				return false
   401  			}
   402  		}
   403  	}
   404  	return true
   405  }
   406  
   407  // isValidMember returns whether s is a valid name for a member.
   408  func isValidMember(s string) bool {
   409  	if len(s) == 0 || len(s) > 255 {
   410  		return false
   411  	}
   412  	i := strings.Index(s, ".")
   413  	if i != -1 {
   414  		return false
   415  	}
   416  	if s[0] >= '0' && s[0] <= '9' {
   417  		return false
   418  	}
   419  	for _, c := range s {
   420  		if !isMemberChar(c) {
   421  			return false
   422  		}
   423  	}
   424  	return true
   425  }
   426  
   427  func isMemberChar(c rune) bool {
   428  	return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
   429  		(c >= 'a' && c <= 'z') || c == '_'
   430  }
   431  

View as plain text