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