mirror of
https://github.com/kemko/nomad.git
synced 2026-01-07 10:55:42 +03:00
This PR switches the Nomad repository from using govendor to Go modules for managing dependencies. Aspects of the Nomad workflow remain pretty much the same. The usual Makefile targets should continue to work as they always did. The API submodule simply defers to the parent Nomad version on the repository, keeping the semantics of API versioning that currently exists.
236 lines
5.2 KiB
Go
236 lines
5.2 KiB
Go
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
|
|
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)
|
|
}
|