Update dependencies
This commit is contained in:
381
vendor/github.com/godbus/dbus/v5/decoder.go
generated
vendored
Normal file
381
vendor/github.com/godbus/dbus/v5/decoder.go
generated
vendored
Normal file
@@ -0,0 +1,381 @@
|
||||
package dbus
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type decoder struct {
|
||||
in io.Reader
|
||||
order binary.ByteOrder
|
||||
pos int
|
||||
fds []int
|
||||
|
||||
// The following fields are used to reduce memory allocs.
|
||||
conv *stringConverter
|
||||
buf []byte
|
||||
d float64
|
||||
y [1]byte
|
||||
}
|
||||
|
||||
// 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, fds []int) *decoder {
|
||||
dec := new(decoder)
|
||||
dec.in = in
|
||||
dec.order = order
|
||||
dec.fds = fds
|
||||
dec.conv = newStringConverter(stringConverterBufferSize)
|
||||
return dec
|
||||
}
|
||||
|
||||
// Reset resets the decoder to be reading from in.
|
||||
func (dec *decoder) Reset(in io.Reader, order binary.ByteOrder, fds []int) {
|
||||
dec.in = in
|
||||
dec.order = order
|
||||
dec.pos = 0
|
||||
dec.fds = fds
|
||||
|
||||
if dec.conv == nil {
|
||||
dec.conv = newStringConverter(stringConverterBufferSize)
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
dec.read2buf(newpos - dec.pos)
|
||||
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, &depthCounter{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v := dec.decode(s[:len(s)-len(rem)], 0)
|
||||
vs = append(vs, v)
|
||||
s = rem
|
||||
}
|
||||
return vs, nil
|
||||
}
|
||||
|
||||
// read2buf reads exactly n bytes from the reader dec.in into the buffer dec.buf
|
||||
// to reduce memory allocs.
|
||||
// The buffer grows automatically.
|
||||
func (dec *decoder) read2buf(n int) {
|
||||
if cap(dec.buf) < n {
|
||||
dec.buf = make([]byte, n)
|
||||
} else {
|
||||
dec.buf = dec.buf[:n]
|
||||
}
|
||||
if _, err := io.ReadFull(dec.in, dec.buf); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// decodeU decodes uint32 obtained from the reader dec.in.
|
||||
// The goal is to reduce memory allocs.
|
||||
func (dec *decoder) decodeU() uint32 {
|
||||
dec.align(4)
|
||||
dec.read2buf(4)
|
||||
dec.pos += 4
|
||||
return dec.order.Uint32(dec.buf)
|
||||
}
|
||||
|
||||
func (dec *decoder) decode(s string, depth int) interface{} {
|
||||
dec.align(alignment(typeFor(s)))
|
||||
switch s[0] {
|
||||
case 'y':
|
||||
if _, err := dec.in.Read(dec.y[:]); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
dec.pos++
|
||||
return dec.y[0]
|
||||
case 'b':
|
||||
switch dec.decodeU() {
|
||||
case 0:
|
||||
return false
|
||||
case 1:
|
||||
return true
|
||||
default:
|
||||
panic(FormatError("invalid value for boolean"))
|
||||
}
|
||||
case 'n':
|
||||
dec.read2buf(2)
|
||||
dec.pos += 2
|
||||
return int16(dec.order.Uint16(dec.buf))
|
||||
case 'i':
|
||||
dec.read2buf(4)
|
||||
dec.pos += 4
|
||||
return int32(dec.order.Uint32(dec.buf))
|
||||
case 'x':
|
||||
dec.read2buf(8)
|
||||
dec.pos += 8
|
||||
return int64(dec.order.Uint64(dec.buf))
|
||||
case 'q':
|
||||
dec.read2buf(2)
|
||||
dec.pos += 2
|
||||
return dec.order.Uint16(dec.buf)
|
||||
case 'u':
|
||||
return dec.decodeU()
|
||||
case 't':
|
||||
dec.read2buf(8)
|
||||
dec.pos += 8
|
||||
return dec.order.Uint64(dec.buf)
|
||||
case 'd':
|
||||
dec.binread(&dec.d)
|
||||
dec.pos += 8
|
||||
return dec.d
|
||||
case 's':
|
||||
length := dec.decodeU()
|
||||
p := int(length) + 1
|
||||
dec.read2buf(p)
|
||||
dec.pos += p
|
||||
return dec.conv.String(dec.buf[:len(dec.buf)-1])
|
||||
case 'o':
|
||||
return ObjectPath(dec.decode("s", depth).(string))
|
||||
case 'g':
|
||||
length := dec.decode("y", depth).(byte)
|
||||
p := int(length) + 1
|
||||
dec.read2buf(p)
|
||||
dec.pos += p
|
||||
sig, err := ParseSignature(
|
||||
dec.conv.String(dec.buf[:len(dec.buf)-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, &depthCounter{})
|
||||
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':
|
||||
idx := dec.decodeU()
|
||||
if int(idx) < len(dec.fds) {
|
||||
return UnixFD(dec.fds[idx])
|
||||
}
|
||||
return UnixFDIndex(idx)
|
||||
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.decodeU()
|
||||
// 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"))
|
||||
}
|
||||
sig := s[1:]
|
||||
length := dec.decodeU()
|
||||
// capacity can be determined only for fixed-size element types
|
||||
var capacity int
|
||||
if s := sigByteSize(sig); s != 0 {
|
||||
capacity = int(length) / s
|
||||
}
|
||||
v := reflect.MakeSlice(reflect.SliceOf(typeFor(sig)), 0, capacity)
|
||||
// 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, &depthCounter{})
|
||||
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})
|
||||
}
|
||||
}
|
||||
|
||||
// sigByteSize tries to calculates size of the given signature in bytes.
|
||||
//
|
||||
// It returns zero when it can't, for example when it contains non-fixed size
|
||||
// types such as strings, maps and arrays that require reading of the transmitted
|
||||
// data, for that we would need to implement the unread method for Decoder first.
|
||||
func sigByteSize(sig string) int {
|
||||
var total int
|
||||
for offset := 0; offset < len(sig); {
|
||||
switch sig[offset] {
|
||||
case 'y':
|
||||
total += 1
|
||||
offset += 1
|
||||
case 'n', 'q':
|
||||
total += 2
|
||||
offset += 1
|
||||
case 'b', 'i', 'u', 'h':
|
||||
total += 4
|
||||
offset += 1
|
||||
case 'x', 't', 'd':
|
||||
total += 8
|
||||
offset += 1
|
||||
case '(':
|
||||
i := 1
|
||||
depth := 1
|
||||
for i < len(sig[offset:]) && depth != 0 {
|
||||
if sig[offset+i] == '(' {
|
||||
depth++
|
||||
} else if sig[offset+i] == ')' {
|
||||
depth--
|
||||
}
|
||||
i++
|
||||
}
|
||||
s := sigByteSize(sig[offset+1 : offset+i-1])
|
||||
if s == 0 {
|
||||
return 0
|
||||
}
|
||||
total += s
|
||||
offset += i
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
// A FormatError is an error in the wire format.
|
||||
type FormatError string
|
||||
|
||||
func (e FormatError) Error() string {
|
||||
return "dbus: wire format error: " + string(e)
|
||||
}
|
||||
|
||||
// stringConverterBufferSize defines the recommended buffer size of 4KB.
|
||||
// It showed good results in a benchmark when decoding 35KB message,
|
||||
// see https://github.com/marselester/systemd#testing.
|
||||
const stringConverterBufferSize = 4096
|
||||
|
||||
func newStringConverter(capacity int) *stringConverter {
|
||||
return &stringConverter{
|
||||
buf: make([]byte, 0, capacity),
|
||||
offset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// stringConverter converts bytes to strings with less allocs.
|
||||
// The idea is to accumulate bytes in a buffer with specified capacity
|
||||
// and create strings with unsafe package using bytes from a buffer.
|
||||
// For example, 10 "fizz" strings written to a 40-byte buffer
|
||||
// will result in 1 alloc instead of 10.
|
||||
//
|
||||
// Once a buffer is filled, a new one is created with the same capacity.
|
||||
// Old buffers will be eventually GC-ed
|
||||
// with no side effects to the returned strings.
|
||||
type stringConverter struct {
|
||||
// buf is a temporary buffer where decoded strings are batched.
|
||||
buf []byte
|
||||
// offset is a buffer position where the last string was written.
|
||||
offset int
|
||||
}
|
||||
|
||||
// String converts bytes to a string.
|
||||
func (c *stringConverter) String(b []byte) string {
|
||||
n := len(b)
|
||||
if n == 0 {
|
||||
return ""
|
||||
}
|
||||
// Must allocate because a string doesn't fit into the buffer.
|
||||
if n > cap(c.buf) {
|
||||
return string(b)
|
||||
}
|
||||
|
||||
if len(c.buf)+n > cap(c.buf) {
|
||||
c.buf = make([]byte, 0, cap(c.buf))
|
||||
c.offset = 0
|
||||
}
|
||||
c.buf = append(c.buf, b...)
|
||||
|
||||
b = c.buf[c.offset:]
|
||||
s := toString(b)
|
||||
c.offset += n
|
||||
return s
|
||||
}
|
||||
|
||||
// toString converts a byte slice to a string without allocating.
|
||||
// Starting from Go 1.20 you should use unsafe.String.
|
||||
func toString(b []byte) string {
|
||||
var s string
|
||||
h := (*reflect.StringHeader)(unsafe.Pointer(&s))
|
||||
h.Data = uintptr(unsafe.Pointer(&b[0]))
|
||||
h.Len = len(b)
|
||||
|
||||
return s
|
||||
}
|
||||
Reference in New Issue
Block a user