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