123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- package dbus
- import (
- "errors"
- "reflect"
- "strings"
- )
- 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))
- 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(Signature{""})
- objectPathType = reflect.TypeOf(ObjectPath(""))
- variantType = reflect.TypeOf(Variant{Signature{""}, nil})
- interfacesType = reflect.TypeOf([]interface{}{})
- unixFDType = reflect.TypeOf(UnixFD(0))
- unixFDIndexType = reflect.TypeOf(UnixFDIndex(0))
- )
- // An InvalidTypeError signals that a value which cannot be represented in the
- // D-Bus wire format was passed to a function.
- type InvalidTypeError struct {
- Type reflect.Type
- }
- func (e InvalidTypeError) Error() string {
- return "dbus: invalid type " + e.Type.String()
- }
- // Store copies the values contained in src to dest, which must be a slice of
- // pointers. It converts slices of interfaces from src to corresponding structs
- // in dest. An error is returned if the lengths of src and dest or the types of
- // their elements don't match.
- func Store(src []interface{}, dest ...interface{}) error {
- if len(src) != len(dest) {
- return errors.New("dbus.Store: length mismatch")
- }
- for i := range src {
- if err := store(src[i], dest[i]); err != nil {
- return err
- }
- }
- return nil
- }
- func store(src, dest interface{}) error {
- if reflect.TypeOf(dest).Elem() == reflect.TypeOf(src) {
- reflect.ValueOf(dest).Elem().Set(reflect.ValueOf(src))
- return nil
- } else if hasStruct(dest) {
- rv := reflect.ValueOf(dest).Elem()
- switch rv.Kind() {
- case reflect.Struct:
- vs, ok := src.([]interface{})
- if !ok {
- return errors.New("dbus.Store: type mismatch")
- }
- t := rv.Type()
- ndest := make([]interface{}, 0, rv.NumField())
- for i := 0; i < rv.NumField(); i++ {
- field := t.Field(i)
- if field.PkgPath == "" && field.Tag.Get("dbus") != "-" {
- ndest = append(ndest, rv.Field(i).Addr().Interface())
- }
- }
- if len(vs) != len(ndest) {
- return errors.New("dbus.Store: type mismatch")
- }
- err := Store(vs, ndest...)
- if err != nil {
- return errors.New("dbus.Store: type mismatch")
- }
- case reflect.Slice:
- sv := reflect.ValueOf(src)
- if sv.Kind() != reflect.Slice {
- return errors.New("dbus.Store: type mismatch")
- }
- rv.Set(reflect.MakeSlice(rv.Type(), sv.Len(), sv.Len()))
- for i := 0; i < sv.Len(); i++ {
- if err := store(sv.Index(i).Interface(), rv.Index(i).Addr().Interface()); err != nil {
- return err
- }
- }
- case reflect.Map:
- sv := reflect.ValueOf(src)
- if sv.Kind() != reflect.Map {
- return errors.New("dbus.Store: type mismatch")
- }
- keys := sv.MapKeys()
- rv.Set(reflect.MakeMap(sv.Type()))
- for _, key := range keys {
- v := reflect.New(sv.Type().Elem())
- if err := store(v, sv.MapIndex(key).Interface()); err != nil {
- return err
- }
- rv.SetMapIndex(key, v.Elem())
- }
- default:
- return errors.New("dbus.Store: type mismatch")
- }
- return nil
- } else {
- return errors.New("dbus.Store: type mismatch")
- }
- }
- func hasStruct(v interface{}) bool {
- t := reflect.TypeOf(v)
- for {
- switch t.Kind() {
- case reflect.Struct:
- return true
- case reflect.Slice, reflect.Ptr, reflect.Map:
- t = t.Elem()
- default:
- return false
- }
- }
- }
- // An ObjectPath is an object path as defined by the D-Bus spec.
- type ObjectPath string
- // IsValid returns whether the object path is valid.
- func (o ObjectPath) IsValid() bool {
- s := string(o)
- if len(s) == 0 {
- return false
- }
- if s[0] != '/' {
- return false
- }
- if s[len(s)-1] == '/' && len(s) != 1 {
- return false
- }
- // probably not used, but technically possible
- if s == "/" {
- return true
- }
- split := strings.Split(s[1:], "/")
- for _, v := range split {
- if len(v) == 0 {
- return false
- }
- for _, c := range v {
- if !isMemberChar(c) {
- return false
- }
- }
- }
- return true
- }
- // A UnixFD is a Unix file descriptor sent over the wire. See the package-level
- // documentation for more information about Unix file descriptor passsing.
- type UnixFD int32
- // A UnixFDIndex is the representation of a Unix file descriptor in a message.
- type UnixFDIndex uint32
- // alignment returns the alignment of values of type t.
- func alignment(t reflect.Type) int {
- switch t {
- case variantType:
- return 1
- case objectPathType:
- return 4
- case signatureType:
- return 1
- case interfacesType: // sometimes used for structs
- return 8
- }
- switch t.Kind() {
- case reflect.Uint8:
- return 1
- case reflect.Uint16, reflect.Int16:
- return 2
- case reflect.Uint32, reflect.Int32, reflect.String, reflect.Array, reflect.Slice, reflect.Map:
- return 4
- case reflect.Uint64, reflect.Int64, reflect.Float64, reflect.Struct:
- return 8
- case reflect.Ptr:
- return alignment(t.Elem())
- }
- return 1
- }
- // isKeyType returns whether t is a valid type for a D-Bus dict.
- func isKeyType(t reflect.Type) bool {
- switch t.Kind() {
- case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
- reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float64,
- reflect.String:
- return true
- }
- return false
- }
- // isValidInterface returns whether s is a valid name for an interface.
- func isValidInterface(s string) bool {
- if len(s) == 0 || len(s) > 255 || s[0] == '.' {
- return false
- }
- elem := strings.Split(s, ".")
- if len(elem) < 2 {
- return false
- }
- for _, v := range elem {
- if len(v) == 0 {
- return false
- }
- if v[0] >= '0' && v[0] <= '9' {
- return false
- }
- for _, c := range v {
- if !isMemberChar(c) {
- return false
- }
- }
- }
- return true
- }
- // isValidMember returns whether s is a valid name for a member.
- func isValidMember(s string) bool {
- if len(s) == 0 || len(s) > 255 {
- return false
- }
- i := strings.Index(s, ".")
- if i != -1 {
- return false
- }
- if s[0] >= '0' && s[0] <= '9' {
- return false
- }
- for _, c := range s {
- if !isMemberChar(c) {
- return false
- }
- }
- return true
- }
- func isMemberChar(c rune) bool {
- return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
- (c >= 'a' && c <= 'z') || c == '_'
- }
|