1 package dbus
2
3 import (
4 "bytes"
5 "encoding/binary"
6 "io"
7 "reflect"
8 "strings"
9 "unicode/utf8"
10 )
11
12
13 type encoder struct {
14 out io.Writer
15 fds []int
16 order binary.ByteOrder
17 pos int
18 }
19
20
21 func newEncoder(out io.Writer, order binary.ByteOrder, fds []int) *encoder {
22 enc := newEncoderAtOffset(out, 0, order, fds)
23 return enc
24 }
25
26
27
28
29 func newEncoderAtOffset(out io.Writer, offset int, order binary.ByteOrder, fds []int) *encoder {
30 enc := new(encoder)
31 enc.out = out
32 enc.order = order
33 enc.pos = offset
34 enc.fds = fds
35 return enc
36 }
37
38
39 func (enc *encoder) align(n int) {
40 pad := enc.padding(0, n)
41 if pad > 0 {
42 empty := make([]byte, pad)
43 if _, err := enc.out.Write(empty); err != nil {
44 panic(err)
45 }
46 enc.pos += pad
47 }
48 }
49
50
51
52 func (enc *encoder) padding(offset, algn int) int {
53 abs := enc.pos + offset
54 if abs%algn != 0 {
55 newabs := (abs + algn - 1) & ^(algn - 1)
56 return newabs - abs
57 }
58 return 0
59 }
60
61
62 func (enc *encoder) binwrite(v interface{}) {
63 if err := binary.Write(enc.out, enc.order, v); err != nil {
64 panic(err)
65 }
66 }
67
68
69
70 func (enc *encoder) Encode(vs ...interface{}) (err error) {
71 defer func() {
72 err, _ = recover().(error)
73 }()
74 for _, v := range vs {
75 enc.encode(reflect.ValueOf(v), 0)
76 }
77 return nil
78 }
79
80
81
82 func (enc *encoder) encode(v reflect.Value, depth int) {
83 if depth > 64 {
84 panic(FormatError("input exceeds depth limitation"))
85 }
86 enc.align(alignment(v.Type()))
87 switch v.Kind() {
88 case reflect.Uint8:
89 var b [1]byte
90 b[0] = byte(v.Uint())
91 if _, err := enc.out.Write(b[:]); err != nil {
92 panic(err)
93 }
94 enc.pos++
95 case reflect.Bool:
96 if v.Bool() {
97 enc.encode(reflect.ValueOf(uint32(1)), depth)
98 } else {
99 enc.encode(reflect.ValueOf(uint32(0)), depth)
100 }
101 case reflect.Int16:
102 enc.binwrite(int16(v.Int()))
103 enc.pos += 2
104 case reflect.Uint16:
105 enc.binwrite(uint16(v.Uint()))
106 enc.pos += 2
107 case reflect.Int, reflect.Int32:
108 if v.Type() == unixFDType {
109 fd := v.Int()
110 idx := len(enc.fds)
111 enc.fds = append(enc.fds, int(fd))
112 enc.binwrite(uint32(idx))
113 } else {
114 enc.binwrite(int32(v.Int()))
115 }
116 enc.pos += 4
117 case reflect.Uint, reflect.Uint32:
118 enc.binwrite(uint32(v.Uint()))
119 enc.pos += 4
120 case reflect.Int64:
121 enc.binwrite(v.Int())
122 enc.pos += 8
123 case reflect.Uint64:
124 enc.binwrite(v.Uint())
125 enc.pos += 8
126 case reflect.Float64:
127 enc.binwrite(v.Float())
128 enc.pos += 8
129 case reflect.String:
130 str := v.String()
131 if !utf8.ValidString(str) {
132 panic(FormatError("input has a not-utf8 char in string"))
133 }
134 if strings.IndexByte(str, byte(0)) != -1 {
135 panic(FormatError("input has a null char('\\000') in string"))
136 }
137 if v.Type() == objectPathType {
138 if !ObjectPath(str).IsValid() {
139 panic(FormatError("invalid object path"))
140 }
141 }
142 enc.encode(reflect.ValueOf(uint32(len(str))), depth)
143 b := make([]byte, v.Len()+1)
144 copy(b, str)
145 b[len(b)-1] = 0
146 n, err := enc.out.Write(b)
147 if err != nil {
148 panic(err)
149 }
150 enc.pos += n
151 case reflect.Ptr:
152 enc.encode(v.Elem(), depth)
153 case reflect.Slice, reflect.Array:
154
155
156 n := enc.padding(0, 4) + 4
157 offset := enc.pos + n + enc.padding(n, alignment(v.Type().Elem()))
158
159 var buf bytes.Buffer
160 bufenc := newEncoderAtOffset(&buf, offset, enc.order, enc.fds)
161
162 for i := 0; i < v.Len(); i++ {
163 bufenc.encode(v.Index(i), depth+1)
164 }
165
166 if buf.Len() > 1<<26 {
167 panic(FormatError("input exceeds array size limitation"))
168 }
169
170 enc.fds = bufenc.fds
171 enc.encode(reflect.ValueOf(uint32(buf.Len())), depth)
172 length := buf.Len()
173 enc.align(alignment(v.Type().Elem()))
174 if _, err := buf.WriteTo(enc.out); err != nil {
175 panic(err)
176 }
177 enc.pos += length
178 case reflect.Struct:
179 switch t := v.Type(); t {
180 case signatureType:
181 str := v.Field(0)
182 enc.encode(reflect.ValueOf(byte(str.Len())), depth)
183 b := make([]byte, str.Len()+1)
184 copy(b, str.String())
185 b[len(b)-1] = 0
186 n, err := enc.out.Write(b)
187 if err != nil {
188 panic(err)
189 }
190 enc.pos += n
191 case variantType:
192 variant := v.Interface().(Variant)
193 enc.encode(reflect.ValueOf(variant.sig), depth+1)
194 enc.encode(reflect.ValueOf(variant.value), depth+1)
195 default:
196 for i := 0; i < v.Type().NumField(); i++ {
197 field := t.Field(i)
198 if field.PkgPath == "" && field.Tag.Get("dbus") != "-" {
199 enc.encode(v.Field(i), depth+1)
200 }
201 }
202 }
203 case reflect.Map:
204
205
206 if !isKeyType(v.Type().Key()) {
207 panic(InvalidTypeError{v.Type()})
208 }
209 keys := v.MapKeys()
210
211
212 n := enc.padding(0, 4) + 4
213 offset := enc.pos + n + enc.padding(n, 8)
214
215 var buf bytes.Buffer
216 bufenc := newEncoderAtOffset(&buf, offset, enc.order, enc.fds)
217 for _, k := range keys {
218 bufenc.align(8)
219 bufenc.encode(k, depth+2)
220 bufenc.encode(v.MapIndex(k), depth+2)
221 }
222 enc.fds = bufenc.fds
223 enc.encode(reflect.ValueOf(uint32(buf.Len())), depth)
224 length := buf.Len()
225 enc.align(8)
226 if _, err := buf.WriteTo(enc.out); err != nil {
227 panic(err)
228 }
229 enc.pos += length
230 case reflect.Interface:
231 enc.encode(reflect.ValueOf(MakeVariant(v.Interface())), depth)
232 default:
233 panic(InvalidTypeError{v.Type()})
234 }
235 }
236
View as plain text