1package zerobus
2
3import (
4 "encoding/binary"
5 "errors"
6 "math"
7 "strings"
8 "unicode/utf8"
9 "unsafe"
10)
11
12const (
13 maxMessage = 128 << 20 // the D-Bus limit for a whole message
14 maxArray = 64 << 20 // the D-Bus limit for one array
15 maxNest = 32 // array or struct levels in one signature
16 maxDepth = 64 // total levels in a value, variants included
17)
18
19var (
20 // ErrMalformed reports bytes that do not follow the D-Bus wire format.
21 ErrMalformed = errors.New("zerobus: malformed message")
22 // ErrTooLarge reports a message or array over the D-Bus size limits.
23 ErrTooLarge = errors.New("zerobus: message too large")
24 // ErrInvalid reports an outgoing value D-Bus does not allow, such as a
25 // string with a NUL byte or a body that does not match its signature.
26 ErrInvalid = errors.New("zerobus: invalid value")
27)
28
29// alignOf returns the alignment of the type that starts with signature byte c.
30func alignOf(c byte) int {
31 switch c {
32 case 'n', 'q':
33 return 2
34 case 'b', 'i', 'u', 'h', 's', 'o', 'a':
35 return 4
36 case 'x', 't', 'd', '(', '{':
37 return 8
38 }
39 return 1 // y, g, v
40}
41
42// pad rounds off up to a multiple of n, a power of two.
43func pad(off, n int) int { return (off + n - 1) &^ (n - 1) }
44
45// sigEnd returns the index just after the single complete type that starts
46// at sig[i], or -1 if there is none.
47func sigEnd(sig string, i int) int { return typeEnd(sig, i, 0, 0) }
48
49// typeEnd is sigEnd with the array and struct nesting so far. The spec
50// limits each to 32 levels; dict entries count as structs.
51func typeEnd(sig string, i, arrays, structs int) int {
52 if i >= len(sig) || arrays > maxNest || structs > maxNest {
53 return -1
54 }
55 switch sig[i] {
56 case 'y', 'b', 'n', 'q', 'i', 'u', 'x', 't', 'd', 'h', 's', 'o', 'g', 'v':
57 return i + 1
58 case 'a':
59 if i+1 < len(sig) && sig[i+1] == '{' {
60 return dictEnd(sig, i+1, arrays+1, structs+1)
61 }
62 return typeEnd(sig, i+1, arrays+1, structs)
63 case '(':
64 j := i + 1
65 if j < len(sig) && sig[j] == ')' {
66 return -1 // empty structs are not allowed
67 }
68 for j < len(sig) && sig[j] != ')' {
69 if j = typeEnd(sig, j, arrays, structs+1); j < 0 {
70 return -1
71 }
72 }
73 if j >= len(sig) {
74 return -1
75 }
76 return j + 1
77 }
78 return -1 // includes '{': a dict entry is only valid as an array element
79}
80
81// dictEnd returns the index just after the dict entry type at sig[i] ('{').
82// Its key must be a basic type and it holds exactly two types.
83func dictEnd(sig string, i, arrays, structs int) int {
84 j := i + 1
85 if j >= len(sig) || !basic(sig[j]) || structs > maxNest {
86 return -1
87 }
88 if j = typeEnd(sig, j+1, arrays, structs); j < 0 || j >= len(sig) || sig[j] != '}' {
89 return -1
90 }
91 return j + 1
92}
93
94func basic(c byte) bool {
95 switch c {
96 case 'y', 'b', 'n', 'q', 'i', 'u', 'x', 't', 'd', 'h', 's', 'o', 'g':
97 return true
98 }
99 return false
100}
101
102// validSignature reports whether sig is a list of complete types that fits
103// in a D-Bus signature.
104func validSignature(sig string) bool {
105 if len(sig) > 255 {
106 return false
107 }
108 for i := 0; i < len(sig); {
109 if i = sigEnd(sig, i); i < 0 {
110 return false
111 }
112 }
113 return true
114}
115
116// validPath reports whether p is a valid object path.
117func validPath(p string) bool {
118 if p == "/" {
119 return true
120 }
121 if len(p) < 2 || p[0] != '/' || p[len(p)-1] == '/' {
122 return false
123 }
124 for i := 1; i < len(p); i++ {
125 c := p[i]
126 switch {
127 case c == '/':
128 if p[i-1] == '/' {
129 return false
130 }
131 case c >= 'a' && c <= 'z', c >= 'A' && c <= 'Z', c >= '0' && c <= '9', c == '_':
132 default:
133 return false
134 }
135 }
136 return true
137}
138
139// validMember reports whether s is a valid member name: letters, digits and
140// '_', not starting with a digit.
141func validMember(s string) bool {
142 if s == "" || len(s) > 255 || s[0] >= '0' && s[0] <= '9' {
143 return false
144 }
145 for i := 0; i < len(s); i++ {
146 if !nameChar(s[i]) {
147 return false
148 }
149 }
150 return true
151}
152
153// nameChar reports whether c may appear in a member or interface name.
154func nameChar(c byte) bool {
155 return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '_'
156}
157
158// validInterface reports whether s is a valid interface or error name: two
159// or more member-like elements separated by dots.
160func validInterface(s string) bool {
161 if len(s) > 255 {
162 return false
163 }
164 // strings.Cut, not SplitSeq: before Go 1.25 the iterator allocates.
165 n := 0
166 for more := true; more; n++ {
167 var e string
168 e, s, more = strings.Cut(s, ".")
169 if !validMember(e) {
170 return false
171 }
172 }
173 return n >= 2
174}
175
176// validBusName reports whether s is a valid unique (":1.42") or well-known
177// ("org.example.App") bus name.
178func validBusName(s string) bool {
179 if s == "" || len(s) > 255 {
180 return false
181 }
182 unique := s[0] == ':'
183 if unique {
184 s = s[1:]
185 }
186 n := 0
187 for more := true; more; n++ {
188 var e string
189 e, s, more = strings.Cut(s, ".")
190 if e == "" || !unique && e[0] >= '0' && e[0] <= '9' {
191 return false
192 }
193 for i := 0; i < len(e); i++ {
194 if !nameChar(e[i]) && e[i] != '-' {
195 return false
196 }
197 }
198 }
199 return n >= 2
200}
201
202// Reader decodes D-Bus values in place.
203//
204// Strings and byte slices it returns point into the message buffer: they are
205// valid only until the next Conn.ReadMessage. Copy them (strings.Clone,
206// bytes.Clone) to keep them longer.
207//
208// Read values in the order of the message signature. Errors are sticky:
209// after the first one, every read returns a zero value and Err reports it.
210type Reader struct {
211 buf []byte
212 off int
213 big bool
214 err error
215}
216
217// Err returns the first error the reader met, or nil.
218func (r *Reader) Err() error { return r.err }
219
220// Done reports whether every byte was read without error.
221func (r *Reader) Done() bool { return r.err == nil && r.off == len(r.buf) }
222
223func (r *Reader) fail() {
224 if r.err == nil {
225 r.err = ErrMalformed
226 }
227}
228
229// take aligns to align and returns the next size bytes.
230func (r *Reader) take(align, size int) []byte {
231 if r.err != nil {
232 return nil
233 }
234 off := pad(r.off, align)
235 if off > len(r.buf)-size {
236 r.fail()
237 return nil
238 }
239 r.off = off + size
240 return r.buf[off:r.off]
241}
242
243// Byte reads a BYTE (y).
244func (r *Reader) Byte() byte {
245 if b := r.take(1, 1); b != nil {
246 return b[0]
247 }
248 return 0
249}
250
251// Bool reads a BOOLEAN (b).
252func (r *Reader) Bool() bool {
253 v := r.Uint32()
254 if v > 1 {
255 r.fail()
256 return false
257 }
258 return v == 1
259}
260
261// Int16 reads an INT16 (n).
262func (r *Reader) Int16() int16 { return int16(r.Uint16()) }
263
264// Uint16 reads a UINT16 (q).
265func (r *Reader) Uint16() uint16 {
266 b := r.take(2, 2)
267 if b == nil {
268 return 0
269 }
270 if r.big {
271 return binary.BigEndian.Uint16(b)
272 }
273 return binary.LittleEndian.Uint16(b)
274}
275
276// Int32 reads an INT32 (i).
277func (r *Reader) Int32() int32 { return int32(r.Uint32()) }
278
279// Uint32 reads a UINT32 (u).
280func (r *Reader) Uint32() uint32 {
281 b := r.take(4, 4)
282 if b == nil {
283 return 0
284 }
285 if r.big {
286 return binary.BigEndian.Uint32(b)
287 }
288 return binary.LittleEndian.Uint32(b)
289}
290
291// UnixFD reads a UNIX_FD (h): an index into the fds sent with the message.
292// zerobus does not receive file descriptors, so the index has nothing to
293// point to; it is only read so the following values can be.
294func (r *Reader) UnixFD() uint32 { return r.Uint32() }
295
296// Int64 reads an INT64 (x).
297func (r *Reader) Int64() int64 { return int64(r.Uint64()) }
298
299// Uint64 reads a UINT64 (t).
300func (r *Reader) Uint64() uint64 {
301 b := r.take(8, 8)
302 if b == nil {
303 return 0
304 }
305 if r.big {
306 return binary.BigEndian.Uint64(b)
307 }
308 return binary.LittleEndian.Uint64(b)
309}
310
311// Float64 reads a DOUBLE (d).
312func (r *Reader) Float64() float64 { return math.Float64frombits(r.Uint64()) }
313
314// Str reads a STRING (s). The result points into the message buffer.
315func (r *Reader) Str() string { return r.str(int(r.Uint32())) }
316
317// ObjectPath reads an OBJECT_PATH (o). The result points into the message
318// buffer.
319func (r *Reader) ObjectPath() string { return r.Str() }
320
321// Signature reads a SIGNATURE (g). The result points into the message buffer.
322func (r *Reader) Signature() string { return r.str(int(r.Byte())) }
323
324// str returns the next n bytes as a string and skips the NUL after them.
325func (r *Reader) str(n int) string {
326 if r.err != nil {
327 return ""
328 }
329 if n < 0 || n > len(r.buf)-r.off-1 || r.buf[r.off+n] != 0 {
330 r.fail()
331 return ""
332 }
333 s := unsafe.String(unsafe.SliceData(r.buf[r.off:]), n)
334 r.off += n + 1
335 return s
336}
337
338// Variant reads the signature of a VARIANT (v) and returns it. Read the
339// value that follows with the matching method, or skip it with Skip.
340func (r *Reader) Variant() string {
341 sig := r.Signature()
342 if r.err == nil && sigEnd(sig, 0) != len(sig) {
343 r.fail()
344 return ""
345 }
346 return sig
347}
348
349// Struct aligns the reader to the start of a STRUCT or DICT_ENTRY. Call it
350// before reading the first field.
351func (r *Reader) Struct() { r.take(8, 0) }
352
353// Array reads the header of an ARRAY whose element type starts with the
354// signature byte elem, and returns the offset where the array ends. Read the
355// elements while More returns true:
356//
357// end := r.Array('s')
358// for r.More(end) {
359// name := r.Str()
360// }
361func (r *Reader) Array(elem byte) int {
362 n := r.Uint32()
363 if r.err != nil {
364 return r.off
365 }
366 if n > maxArray {
367 r.fail()
368 return r.off
369 }
370 off := pad(r.off, alignOf(elem))
371 if off > len(r.buf)-int(n) {
372 r.fail()
373 return r.off
374 }
375 r.off = off
376 return off + int(n)
377}
378
379// More reports whether the array that ends at end has another element.
380func (r *Reader) More(end int) bool {
381 if r.err != nil {
382 return false
383 }
384 if r.off < end {
385 return true
386 }
387 if r.off > end {
388 r.fail()
389 }
390 return false
391}
392
393// SkipTo moves to end, the value returned by Array. Use it to leave an array
394// before its last element.
395func (r *Reader) SkipTo(end int) {
396 if r.err != nil {
397 return
398 }
399 if end < r.off || end > len(r.buf) {
400 r.fail()
401 return
402 }
403 r.off = end
404}
405
406// ByteArray reads an ARRAY of BYTE (ay). The result points into the message
407// buffer.
408func (r *Reader) ByteArray() []byte {
409 end := r.Array('y')
410 if r.err != nil {
411 return nil
412 }
413 b := r.buf[r.off:end:end]
414 r.off = end
415 return b
416}
417
418// Skip reads past values of the given signature. Arrays are skipped by their
419// length, without reading their elements.
420func (r *Reader) Skip(sig string) { r.skip(sig, 0, false) }
421
422// check reads every value of sig, array elements included, and fails on any
423// value the bus would reject. It proves an outgoing body matches its
424// signature.
425func (r *Reader) check(sig string) { r.skip(sig, 0, true) }
426
427func (r *Reader) skip(sig string, depth int, strict bool) {
428 for i := 0; i < len(sig) && r.err == nil; {
429 i = r.skipOne(sig, i, depth, strict)
430 }
431}
432
433// skipOne skips the value of the type at sig[i] and returns the index of the
434// next type. In strict mode it also reads array elements and checks values.
435func (r *Reader) skipOne(sig string, i, depth int, strict bool) int {
436 if depth > maxDepth {
437 r.fail()
438 return len(sig)
439 }
440 switch c := sig[i]; c {
441 case 'y':
442 r.take(1, 1)
443 case 'n', 'q':
444 r.take(2, 2)
445 case 'b':
446 r.Bool()
447 case 'i', 'u', 'h':
448 r.take(4, 4)
449 case 'x', 't', 'd':
450 r.take(8, 8)
451 case 's', 'o':
452 s := r.Str()
453 if strict && (!utf8.ValidString(s) || c == 'o' && !validPath(s)) {
454 r.fail()
455 }
456 case 'g':
457 if s := r.Signature(); strict && !validSignature(s) {
458 r.fail()
459 }
460 case 'v':
461 r.skip(r.Variant(), depth+1, strict)
462 case 'a':
463 next := sigEnd(sig, i)
464 if next < 0 {
465 r.fail()
466 return len(sig)
467 }
468 end := r.Array(sig[i+1])
469 if !strict {
470 r.SkipTo(end)
471 return next
472 }
473 for r.More(end) {
474 r.skipOne(sig, i+1, depth+1, true)
475 }
476 return next
477 case '(', '{':
478 closer := byte(')')
479 if c == '{' {
480 closer = '}'
481 }
482 r.Struct()
483 j := i + 1
484 for j < len(sig) && sig[j] != closer && r.err == nil {
485 j = r.skipOne(sig, j, depth+1, strict)
486 }
487 if j >= len(sig) {
488 r.fail()
489 return len(sig)
490 }
491 return j + 1
492 default:
493 r.fail()
494 return len(sig)
495 }
496 return i + 1
497}
498
499// Encoder appends D-Bus values to an outgoing message. Get one from
500// Conn.NewCall, Conn.Signal, Conn.Reply or Conn.Error, write the body values
501// in the order of the message signature, then call Conn.Send.
502//
503// Errors are sticky and reported by Conn.Send.
504type Encoder struct {
505 buf []byte
506 body int // offset of the body; 0 when no message is being built
507 sig string // body signature, checked by finish
508 err error
509}
510
511func (e *Encoder) invalid() {
512 if e.err == nil {
513 e.err = ErrInvalid
514 }
515}
516
517func (e *Encoder) pad(n int) {
518 for len(e.buf)&(n-1) != 0 {
519 e.buf = append(e.buf, 0)
520 }
521}
522
523// Byte writes a BYTE (y).
524func (e *Encoder) Byte(v byte) { e.buf = append(e.buf, v) }
525
526// Bool writes a BOOLEAN (b).
527func (e *Encoder) Bool(v bool) {
528 var u uint32
529 if v {
530 u = 1
531 }
532 e.Uint32(u)
533}
534
535// Int16 writes an INT16 (n).
536func (e *Encoder) Int16(v int16) { e.Uint16(uint16(v)) }
537
538// Uint16 writes a UINT16 (q).
539func (e *Encoder) Uint16(v uint16) {
540 e.pad(2)
541 e.buf = binary.LittleEndian.AppendUint16(e.buf, v)
542}
543
544// Int32 writes an INT32 (i).
545func (e *Encoder) Int32(v int32) { e.Uint32(uint32(v)) }
546
547// Uint32 writes a UINT32 (u).
548func (e *Encoder) Uint32(v uint32) {
549 e.pad(4)
550 e.buf = binary.LittleEndian.AppendUint32(e.buf, v)
551}
552
553// Int64 writes an INT64 (x).
554func (e *Encoder) Int64(v int64) { e.Uint64(uint64(v)) }
555
556// Uint64 writes a UINT64 (t).
557func (e *Encoder) Uint64(v uint64) {
558 e.pad(8)
559 e.buf = binary.LittleEndian.AppendUint64(e.buf, v)
560}
561
562// Float64 writes a DOUBLE (d).
563func (e *Encoder) Float64(v float64) { e.Uint64(math.Float64bits(v)) }
564
565// Str writes a STRING (s).
566func (e *Encoder) Str(s string) {
567 e.Uint32(uint32(len(s)))
568 e.text(s)
569}
570
571// ObjectPath writes an OBJECT_PATH (o).
572func (e *Encoder) ObjectPath(p string) {
573 if !validPath(p) {
574 e.invalid()
575 }
576 e.Str(p)
577}
578
579// Signature writes a SIGNATURE (g).
580func (e *Encoder) Signature(sig string) {
581 if !validSignature(sig) {
582 e.invalid()
583 }
584 e.Byte(byte(len(sig)))
585 e.text(sig)
586}
587
588// text appends s and its NUL terminator.
589func (e *Encoder) text(s string) {
590 // The bus disconnects a client that sends a NUL or invalid UTF-8.
591 if strings.IndexByte(s, 0) >= 0 || !utf8.ValidString(s) {
592 e.invalid()
593 }
594 e.buf = append(e.buf, s...)
595 e.buf = append(e.buf, 0)
596}
597
598// Variant writes the signature of a VARIANT (v). Write its value next.
599func (e *Encoder) Variant(sig string) {
600 if sigEnd(sig, 0) != len(sig) {
601 e.invalid()
602 }
603 e.Signature(sig)
604}
605
606// Struct aligns the encoder to the start of a STRUCT or DICT_ENTRY. Call it
607// before writing the first field.
608func (e *Encoder) Struct() { e.pad(8) }
609
610// ArrayMark is an array being written; pass it to EndArray.
611type ArrayMark struct{ at, start int }
612
613// BeginArray starts an ARRAY whose element type starts with the signature
614// byte elem. Write the elements, then call EndArray:
615//
616// a := e.BeginArray('s')
617// e.Str("one")
618// e.Str("two")
619// e.EndArray(a)
620func (e *Encoder) BeginArray(elem byte) ArrayMark {
621 e.pad(4)
622 at := len(e.buf)
623 e.buf = append(e.buf, 0, 0, 0, 0)
624 e.pad(alignOf(elem))
625 return ArrayMark{at: at, start: len(e.buf)}
626}
627
628// EndArray finishes the array started by BeginArray.
629func (e *Encoder) EndArray(a ArrayMark) {
630 n := len(e.buf) - a.start
631 if n > maxArray {
632 e.invalid()
633 return
634 }
635 binary.LittleEndian.PutUint32(e.buf[a.at:], uint32(n))
636}
637
638// ByteArray writes an ARRAY of BYTE (ay).
639func (e *Encoder) ByteArray(b []byte) {
640 e.Uint32(uint32(len(b)))
641 e.buf = append(e.buf, b...)
642}
643
644// SetFlags sets the flags of the message being built.
645func (e *Encoder) SetFlags(f Flags) {
646 if e.body != 0 {
647 e.buf[2] = byte(f)
648 }
649}