package dbus import ( "encoding/binary" "io" "reflect" ) type decoder struct { in io.Reader order binary.ByteOrder pos int } // newDecoder returns a new decoder that reads values from in. The input is // expected to be in the given byte order. func newDecoder(in io.Reader, order binary.ByteOrder) *decoder { dec := new(decoder) dec.in = in dec.order = order return dec } // align aligns the input to the given boundary and panics on error. func (dec *decoder) align(n int) { if dec.pos%n != 0 { newpos := (dec.pos + n - 1) & ^(n - 1) empty := make([]byte, newpos-dec.pos) if _, err := io.ReadFull(dec.in, empty); err != nil { panic(err) } dec.pos = newpos } } // Calls binary.Read(dec.in, dec.order, v) and panics on read errors. func (dec *decoder) binread(v interface{}) { if err := binary.Read(dec.in, dec.order, v); err != nil { panic(err) } } func (dec *decoder) Decode(sig Signature) (vs []interface{}, err error) { defer func() { var ok bool v := recover() if err, ok = v.(error); ok { if err == io.EOF || err == io.ErrUnexpectedEOF { err = FormatError("unexpected EOF") } } }() vs = make([]interface{}, 0) s := sig.str for s != "" { err, rem := validSingle(s, 0) if err != nil { return nil, err } v := dec.decode(s[:len(s)-len(rem)], 0) vs = append(vs, v) s = rem } return vs, nil } func (dec *decoder) decode(s string, depth int) interface{} { dec.align(alignment(typeFor(s))) switch s[0] { case 'y': var b [1]byte if _, err := dec.in.Read(b[:]); err != nil { panic(err) } dec.pos++ return b[0] case 'b': i := dec.decode("u", depth).(uint32) switch { case i == 0: return false case i == 1: return true default: panic(FormatError("invalid value for boolean")) } case 'n': var i int16 dec.binread(&i) dec.pos += 2 return i case 'i': var i int32 dec.binread(&i) dec.pos += 4 return i case 'x': var i int64 dec.binread(&i) dec.pos += 8 return i case 'q': var i uint16 dec.binread(&i) dec.pos += 2 return i case 'u': var i uint32 dec.binread(&i) dec.pos += 4 return i case 't': var i uint64 dec.binread(&i) dec.pos += 8 return i case 'd': var f float64 dec.binread(&f) dec.pos += 8 return f case 's': length := dec.decode("u", depth).(uint32) b := make([]byte, int(length)+1) if _, err := io.ReadFull(dec.in, b); err != nil { panic(err) } dec.pos += int(length) + 1 return string(b[:len(b)-1]) case 'o': return ObjectPath(dec.decode("s", depth).(string)) case 'g': length := dec.decode("y", depth).(byte) b := make([]byte, int(length)+1) if _, err := io.ReadFull(dec.in, b); err != nil { panic(err) } dec.pos += int(length) + 1 sig, err := ParseSignature(string(b[:len(b)-1])) if err != nil { panic(err) } return sig case 'v': if depth >= 64 { panic(FormatError("input exceeds container depth limit")) } var variant Variant sig := dec.decode("g", depth).(Signature) if len(sig.str) == 0 { panic(FormatError("variant signature is empty")) } err, rem := validSingle(sig.str, 0) if err != nil { panic(err) } if rem != "" { panic(FormatError("variant signature has multiple types")) } variant.sig = sig variant.value = dec.decode(sig.str, depth+1) return variant case 'h': return UnixFDIndex(dec.decode("u", depth).(uint32)) case 'a': if len(s) > 1 && s[1] == '{' { ksig := s[2:3] vsig := s[3 : len(s)-1] v := reflect.MakeMap(reflect.MapOf(typeFor(ksig), typeFor(vsig))) if depth >= 63 { panic(FormatError("input exceeds container depth limit")) } length := dec.decode("u", depth).(uint32) // Even for empty maps, the correct padding must be included dec.align(8) spos := dec.pos for dec.pos < spos+int(length) { dec.align(8) if !isKeyType(v.Type().Key()) { panic(InvalidTypeError{v.Type()}) } kv := dec.decode(ksig, depth+2) vv := dec.decode(vsig, depth+2) v.SetMapIndex(reflect.ValueOf(kv), reflect.ValueOf(vv)) } return v.Interface() } if depth >= 64 { panic(FormatError("input exceeds container depth limit")) } length := dec.decode("u", depth).(uint32) v := reflect.MakeSlice(reflect.SliceOf(typeFor(s[1:])), 0, 0) // Even for empty arrays, the correct padding must be included align := alignment(typeFor(s[1:])) if len(s) > 1 && s[1] == '(' { //Special case for arrays of structs //structs decode as a slice of interface{} values //but the dbus alignment does not match this align = 8 } dec.align(align) spos := dec.pos for dec.pos < spos+int(length) { ev := dec.decode(s[1:], depth+1) v = reflect.Append(v, reflect.ValueOf(ev)) } return v.Interface() case '(': if depth >= 64 { panic(FormatError("input exceeds container depth limit")) } dec.align(8) v := make([]interface{}, 0) s = s[1 : len(s)-1] for s != "" { err, rem := validSingle(s, 0) if err != nil { panic(err) } ev := dec.decode(s[:len(s)-len(rem)], depth+1) v = append(v, ev) s = rem } return v default: panic(SignatureError{Sig: s}) } } // A FormatError is an error in the wire format. type FormatError string func (e FormatError) Error() string { return "dbus: wire format error: " + string(e) }