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
27
28 type Signature struct {
29 str string
30 }
31
32
33
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
43
44 func SignatureOfType(t reflect.Type) Signature {
45 return Signature{getSignature(t, &depthCounter{})}
46 }
47
48
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
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
122
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
142
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
152 func (s Signature) Empty() bool {
153 return s.str == ""
154 }
155
156
157 func (s Signature) Single() bool {
158 err, r := validSingle(s.str, &depthCounter{})
159 return err != nil && r == ""
160 }
161
162
163 func (s Signature) String() string {
164 return s.str
165 }
166
167
168
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
202
203
204
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
271
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
View as plain text