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