1package dbus
2
3import (
4	"bytes"
5	"encoding/binary"
6	"io"
7	"reflect"
8)
9
10// An encoder encodes values to the D-Bus wire format.
11type encoder struct {
12	out   io.Writer
13	order binary.ByteOrder
14	pos   int
15}
16
17// NewEncoder returns a new encoder that writes to out in the given byte order.
18func newEncoder(out io.Writer, order binary.ByteOrder) *encoder {
19	enc := new(encoder)
20	enc.out = out
21	enc.order = order
22	return enc
23}
24
25// Aligns the next output to be on a multiple of n. Panics on write errors.
26func (enc *encoder) align(n int) {
27	if enc.pos%n != 0 {
28		newpos := (enc.pos + n - 1) & ^(n - 1)
29		empty := make([]byte, newpos-enc.pos)
30		if _, err := enc.out.Write(empty); err != nil {
31			panic(err)
32		}
33		enc.pos = newpos
34	}
35}
36
37// Calls binary.Write(enc.out, enc.order, v) and panics on write errors.
38func (enc *encoder) binwrite(v interface{}) {
39	if err := binary.Write(enc.out, enc.order, v); err != nil {
40		panic(err)
41	}
42}
43
44// Encode encodes the given values to the underyling reader. All written values
45// are aligned properly as required by the D-Bus spec.
46func (enc *encoder) Encode(vs ...interface{}) (err error) {
47	defer func() {
48		err, _ = recover().(error)
49	}()
50	for _, v := range vs {
51		enc.encode(reflect.ValueOf(v), 0)
52	}
53	return nil
54}
55
56// encode encodes the given value to the writer and panics on error. depth holds
57// the depth of the container nesting.
58func (enc *encoder) encode(v reflect.Value, depth int) {
59	enc.align(alignment(v.Type()))
60	switch v.Kind() {
61	case reflect.Uint8:
62		var b [1]byte
63		b[0] = byte(v.Uint())
64		if _, err := enc.out.Write(b[:]); err != nil {
65			panic(err)
66		}
67		enc.pos++
68	case reflect.Bool:
69		if v.Bool() {
70			enc.encode(reflect.ValueOf(uint32(1)), depth)
71		} else {
72			enc.encode(reflect.ValueOf(uint32(0)), depth)
73		}
74	case reflect.Int16:
75		enc.binwrite(int16(v.Int()))
76		enc.pos += 2
77	case reflect.Uint16:
78		enc.binwrite(uint16(v.Uint()))
79		enc.pos += 2
80	case reflect.Int32:
81		enc.binwrite(int32(v.Int()))
82		enc.pos += 4
83	case reflect.Uint32:
84		enc.binwrite(uint32(v.Uint()))
85		enc.pos += 4
86	case reflect.Int64:
87		enc.binwrite(v.Int())
88		enc.pos += 8
89	case reflect.Uint64:
90		enc.binwrite(v.Uint())
91		enc.pos += 8
92	case reflect.Float64:
93		enc.binwrite(v.Float())
94		enc.pos += 8
95	case reflect.String:
96		enc.encode(reflect.ValueOf(uint32(len(v.String()))), depth)
97		b := make([]byte, v.Len()+1)
98		copy(b, v.String())
99		b[len(b)-1] = 0
100		n, err := enc.out.Write(b)
101		if err != nil {
102			panic(err)
103		}
104		enc.pos += n
105	case reflect.Ptr:
106		enc.encode(v.Elem(), depth)
107	case reflect.Slice, reflect.Array:
108		if depth >= 64 {
109			panic(FormatError("input exceeds container depth limit"))
110		}
111		var buf bytes.Buffer
112		bufenc := newEncoder(&buf, enc.order)
113
114		for i := 0; i < v.Len(); i++ {
115			bufenc.encode(v.Index(i), depth+1)
116		}
117		enc.encode(reflect.ValueOf(uint32(buf.Len())), depth)
118		length := buf.Len()
119		enc.align(alignment(v.Type().Elem()))
120		if _, err := buf.WriteTo(enc.out); err != nil {
121			panic(err)
122		}
123		enc.pos += length
124	case reflect.Struct:
125		if depth >= 64 && v.Type() != signatureType {
126			panic(FormatError("input exceeds container depth limit"))
127		}
128		switch t := v.Type(); t {
129		case signatureType:
130			str := v.Field(0)
131			enc.encode(reflect.ValueOf(byte(str.Len())), depth+1)
132			b := make([]byte, str.Len()+1)
133			copy(b, str.String())
134			b[len(b)-1] = 0
135			n, err := enc.out.Write(b)
136			if err != nil {
137				panic(err)
138			}
139			enc.pos += n
140		case variantType:
141			variant := v.Interface().(Variant)
142			enc.encode(reflect.ValueOf(variant.sig), depth+1)
143			enc.encode(reflect.ValueOf(variant.value), depth+1)
144		default:
145			for i := 0; i < v.Type().NumField(); i++ {
146				field := t.Field(i)
147				if field.PkgPath == "" && field.Tag.Get("dbus") != "-" {
148					enc.encode(v.Field(i), depth+1)
149				}
150			}
151		}
152	case reflect.Map:
153		// Maps are arrays of structures, so they actually increase the depth by
154		// 2.
155		if depth >= 63 {
156			panic(FormatError("input exceeds container depth limit"))
157		}
158		if !isKeyType(v.Type().Key()) {
159			panic(InvalidTypeError{v.Type()})
160		}
161		keys := v.MapKeys()
162		var buf bytes.Buffer
163		bufenc := newEncoder(&buf, enc.order)
164		for _, k := range keys {
165			bufenc.align(8)
166			bufenc.encode(k, depth+2)
167			bufenc.encode(v.MapIndex(k), depth+2)
168		}
169		enc.encode(reflect.ValueOf(uint32(buf.Len())), depth)
170		length := buf.Len()
171		enc.align(8)
172		if _, err := buf.WriteTo(enc.out); err != nil {
173			panic(err)
174		}
175		enc.pos += length
176	default:
177		panic(InvalidTypeError{v.Type()})
178	}
179}
180