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