go-tg-screenshot-bot

Форк
0
293 строки · 6.8 Кб
1
package dbus
2

3
import (
4
	"fmt"
5
	"reflect"
6
	"strings"
7
)
8

9
var sigToType = map[byte]reflect.Type{
10
	'y': byteType,
11
	'b': boolType,
12
	'n': int16Type,
13
	'q': uint16Type,
14
	'i': int32Type,
15
	'u': uint32Type,
16
	'x': int64Type,
17
	't': uint64Type,
18
	'd': float64Type,
19
	's': stringType,
20
	'g': signatureType,
21
	'o': objectPathType,
22
	'v': variantType,
23
	'h': unixFDIndexType,
24
}
25

26
// Signature represents a correct type signature as specified by the D-Bus
27
// specification. The zero value represents the empty signature, "".
28
type Signature struct {
29
	str string
30
}
31

32
// SignatureOf returns the concatenation of all the signatures of the given
33
// values. It panics if one of them is not representable in D-Bus.
34
func SignatureOf(vs ...interface{}) Signature {
35
	var s string
36
	for _, v := range vs {
37
		s += getSignature(reflect.TypeOf(v), &depthCounter{})
38
	}
39
	return Signature{s}
40
}
41

42
// SignatureOfType returns the signature of the given type. It panics if the
43
// type is not representable in D-Bus.
44
func SignatureOfType(t reflect.Type) Signature {
45
	return Signature{getSignature(t, &depthCounter{})}
46
}
47

48
// getSignature returns the signature of the given type and panics on unknown types.
49
func getSignature(t reflect.Type, depth *depthCounter) (sig string) {
50
	if !depth.Valid() {
51
		panic("container nesting too deep")
52
	}
53
	defer func() {
54
		if len(sig) > 255 {
55
			panic("signature exceeds the length limitation")
56
		}
57
	}()
58
	// handle simple types first
59
	switch t.Kind() {
60
	case reflect.Uint8:
61
		return "y"
62
	case reflect.Bool:
63
		return "b"
64
	case reflect.Int16:
65
		return "n"
66
	case reflect.Uint16:
67
		return "q"
68
	case reflect.Int, reflect.Int32:
69
		if t == unixFDType {
70
			return "h"
71
		}
72
		return "i"
73
	case reflect.Uint, reflect.Uint32:
74
		if t == unixFDIndexType {
75
			return "h"
76
		}
77
		return "u"
78
	case reflect.Int64:
79
		return "x"
80
	case reflect.Uint64:
81
		return "t"
82
	case reflect.Float64:
83
		return "d"
84
	case reflect.Ptr:
85
		return getSignature(t.Elem(), depth)
86
	case reflect.String:
87
		if t == objectPathType {
88
			return "o"
89
		}
90
		return "s"
91
	case reflect.Struct:
92
		if t == variantType {
93
			return "v"
94
		} else if t == signatureType {
95
			return "g"
96
		}
97
		var s string
98
		for i := 0; i < t.NumField(); i++ {
99
			field := t.Field(i)
100
			if field.PkgPath == "" && field.Tag.Get("dbus") != "-" {
101
				s += getSignature(t.Field(i).Type, depth.EnterStruct())
102
			}
103
		}
104
		if len(s) == 0 {
105
			panic(InvalidTypeError{t})
106
		}
107
		return "(" + s + ")"
108
	case reflect.Array, reflect.Slice:
109
		return "a" + getSignature(t.Elem(), depth.EnterArray())
110
	case reflect.Map:
111
		if !isKeyType(t.Key()) {
112
			panic(InvalidTypeError{t})
113
		}
114
		return "a{" + getSignature(t.Key(), depth.EnterArray().EnterDictEntry()) + getSignature(t.Elem(), depth.EnterArray().EnterDictEntry()) + "}"
115
	case reflect.Interface:
116
		return "v"
117
	}
118
	panic(InvalidTypeError{t})
119
}
120

121
// ParseSignature returns the signature represented by this string, or a
122
// SignatureError if the string is not a valid signature.
123
func ParseSignature(s string) (sig Signature, err error) {
124
	if len(s) == 0 {
125
		return
126
	}
127
	if len(s) > 255 {
128
		return Signature{""}, SignatureError{s, "too long"}
129
	}
130
	sig.str = s
131
	for err == nil && len(s) != 0 {
132
		err, s = validSingle(s, &depthCounter{})
133
	}
134
	if err != nil {
135
		sig = Signature{""}
136
	}
137

138
	return
139
}
140

141
// ParseSignatureMust behaves like ParseSignature, except that it panics if s
142
// is not valid.
143
func ParseSignatureMust(s string) Signature {
144
	sig, err := ParseSignature(s)
145
	if err != nil {
146
		panic(err)
147
	}
148
	return sig
149
}
150

151
// Empty returns whether the signature is the empty signature.
152
func (s Signature) Empty() bool {
153
	return s.str == ""
154
}
155

156
// Single returns whether the signature represents a single, complete type.
157
func (s Signature) Single() bool {
158
	err, r := validSingle(s.str, &depthCounter{})
159
	return err != nil && r == ""
160
}
161

162
// String returns the signature's string representation.
163
func (s Signature) String() string {
164
	return s.str
165
}
166

167
// A SignatureError indicates that a signature passed to a function or received
168
// on a connection is not a valid signature.
169
type SignatureError struct {
170
	Sig    string
171
	Reason string
172
}
173

174
func (e SignatureError) Error() string {
175
	return fmt.Sprintf("dbus: invalid signature: %q (%s)", e.Sig, e.Reason)
176
}
177

178
type depthCounter struct {
179
	arrayDepth, structDepth, dictEntryDepth int
180
}
181

182
func (cnt *depthCounter) Valid() bool {
183
	return cnt.arrayDepth <= 32 && cnt.structDepth <= 32 && cnt.dictEntryDepth <= 32
184
}
185

186
func (cnt depthCounter) EnterArray() *depthCounter {
187
	cnt.arrayDepth++
188
	return &cnt
189
}
190

191
func (cnt depthCounter) EnterStruct() *depthCounter {
192
	cnt.structDepth++
193
	return &cnt
194
}
195

196
func (cnt depthCounter) EnterDictEntry() *depthCounter {
197
	cnt.dictEntryDepth++
198
	return &cnt
199
}
200

201
// Try to read a single type from this string. If it was successful, err is nil
202
// and rem is the remaining unparsed part. Otherwise, err is a non-nil
203
// SignatureError and rem is "". depth is the current recursion depth which may
204
// not be greater than 64 and should be given as 0 on the first call.
205
func validSingle(s string, depth *depthCounter) (err error, rem string) {
206
	if s == "" {
207
		return SignatureError{Sig: s, Reason: "empty signature"}, ""
208
	}
209
	if !depth.Valid() {
210
		return SignatureError{Sig: s, Reason: "container nesting too deep"}, ""
211
	}
212
	switch s[0] {
213
	case 'y', 'b', 'n', 'q', 'i', 'u', 'x', 't', 'd', 's', 'g', 'o', 'v', 'h':
214
		return nil, s[1:]
215
	case 'a':
216
		if len(s) > 1 && s[1] == '{' {
217
			i := findMatching(s[1:], '{', '}')
218
			if i == -1 {
219
				return SignatureError{Sig: s, Reason: "unmatched '{'"}, ""
220
			}
221
			i++
222
			rem = s[i+1:]
223
			s = s[2:i]
224
			if err, _ = validSingle(s[:1], depth.EnterArray().EnterDictEntry()); err != nil {
225
				return err, ""
226
			}
227
			err, nr := validSingle(s[1:], depth.EnterArray().EnterDictEntry())
228
			if err != nil {
229
				return err, ""
230
			}
231
			if nr != "" {
232
				return SignatureError{Sig: s, Reason: "too many types in dict"}, ""
233
			}
234
			return nil, rem
235
		}
236
		return validSingle(s[1:], depth.EnterArray())
237
	case '(':
238
		i := findMatching(s, '(', ')')
239
		if i == -1 {
240
			return SignatureError{Sig: s, Reason: "unmatched ')'"}, ""
241
		}
242
		rem = s[i+1:]
243
		s = s[1:i]
244
		for err == nil && s != "" {
245
			err, s = validSingle(s, depth.EnterStruct())
246
		}
247
		if err != nil {
248
			rem = ""
249
		}
250
		return
251
	}
252
	return SignatureError{Sig: s, Reason: "invalid type character"}, ""
253
}
254

255
func findMatching(s string, left, right rune) int {
256
	n := 0
257
	for i, v := range s {
258
		if v == left {
259
			n++
260
		} else if v == right {
261
			n--
262
		}
263
		if n == 0 {
264
			return i
265
		}
266
	}
267
	return -1
268
}
269

270
// typeFor returns the type of the given signature. It ignores any left over
271
// characters and panics if s doesn't start with a valid type signature.
272
func typeFor(s string) (t reflect.Type) {
273
	err, _ := validSingle(s, &depthCounter{})
274
	if err != nil {
275
		panic(err)
276
	}
277

278
	if t, ok := sigToType[s[0]]; ok {
279
		return t
280
	}
281
	switch s[0] {
282
	case 'a':
283
		if s[1] == '{' {
284
			i := strings.LastIndex(s, "}")
285
			t = reflect.MapOf(sigToType[s[2]], typeFor(s[3:i]))
286
		} else {
287
			t = reflect.SliceOf(typeFor(s[1:]))
288
		}
289
	case '(':
290
		t = interfacesType
291
	}
292
	return
293
}
294

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.