open-nomad/vendor/github.com/godbus/dbus/decoder.go

229 lines
5 KiB
Go
Raw Normal View History

2016-02-12 18:02:16 +00:00
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, int(length))
// Even for empty arrays, the correct padding must be included
dec.align(alignment(typeFor(s[1:])))
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)
}