From 1e253b011f916544879ab3a2d3060c2e982a0c9d Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Sun, 2 Feb 2020 23:11:21 -0500 Subject: rrdbinary: Decode CDEF RPN tokens crammed in to Unival parameters --- rrdformat/rrdbinary/cdef.go | 29 +++++++++++++++++++++++++++++ rrdformat/rrdbinary/decode.go | 8 +++++++- rrdformat/rrdbinary/types.go | 17 +++++++++++++---- rrdformat/sniff.go | 10 ++++++++++ 4 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 rrdformat/rrdbinary/cdef.go diff --git a/rrdformat/rrdbinary/cdef.go b/rrdformat/rrdbinary/cdef.go new file mode 100644 index 0000000..5fbea4c --- /dev/null +++ b/rrdformat/rrdbinary/cdef.go @@ -0,0 +1,29 @@ +package rrdbinary + +// RPNToken is one of the things that can be stored in a Unival; used +// by DST_CDEF. +type RPNToken struct { + Op uint8 // rpn operator type + Val int32 // used by OP_NUMBER (0), OP_VARIABLE (1), and OP_PREV_OTHER (36) +} + +// AsRPNTokens returns 1 or 2 RPNTokens (depending on the +// Architecture.ShortSize). +func (u Unival) AsRPNTokens() []RPNToken { + var ret []RPNToken + data := u.data + for len(data) > 0 { + rpnpData := data[:u.arch.ShortAlign+u.arch.ShortWidth] + var rpnp RPNToken + rpnp.Op = rpnpData[0] + switch u.arch.ShortWidth { + case 2: + rpnp.Val = int32(int16(u.arch.ByteOrder.Uint16(rpnpData[u.arch.ShortAlign:]))) + case 4: + rpnp.Val = int32(u.arch.ByteOrder.Uint32(rpnpData[u.arch.ShortAlign:])) + } + ret = append(ret, rpnp) + data = data[len(rpnpData):] + } + return ret +} diff --git a/rrdformat/rrdbinary/decode.go b/rrdformat/rrdbinary/decode.go index 08c9141..c4f7760 100644 --- a/rrdformat/rrdbinary/decode.go +++ b/rrdformat/rrdbinary/decode.go @@ -251,6 +251,9 @@ func (obj *Unival) unmarshalRRD(d *Decoder, tag string) error { if d.arch.UnivalWidth != 8 { return archErrorf("rrdbinary does not support UnivalWidth=%d; only supports 8", d.arch.UnivalWidth) } + if d.arch.ShortWidth != 2 && d.arch.ShortWidth != 4 { + return archErrorf("rrdbinary does not support ShortWidth=%d; only supports 2 or 4", d.arch.ShortWidth) + } if tag != "" { return typeErrorf("invalid rrdbinary struct tag for unival: %q", tag) } @@ -270,7 +273,10 @@ func (obj *Unival) unmarshalRRD(d *Decoder, tag string) error { return d.binErrorf(d.arch.UnivalWidth, "unexpected end-of-file in %d-byte unival", d.arch.UnivalWidth) } - *obj = Unival(d.arch.ByteOrder.Uint64(data)) + *obj = Unival{ + arch: d.arch, + data: data, + } d.pos += padding + d.arch.UnivalWidth return nil } diff --git a/rrdformat/rrdbinary/types.go b/rrdformat/rrdbinary/types.go index e3011d5..b8001af 100644 --- a/rrdformat/rrdbinary/types.go +++ b/rrdformat/rrdbinary/types.go @@ -12,6 +12,9 @@ type Architecture struct { // C `double` DoubleWidth int // always 8 -- we assume IEEE 754 doubles DoubleAlign int + // C `short` + ShortWidth int + ShortAlign int // C `long` or `unsigned long` LongWidth int LongAlign int @@ -27,15 +30,21 @@ type String string // \0-terminated type Double float64 // 8 bytes type ULong uint64 // 4 or 8 bytes type Long int64 // 4 or 8 bytes -type Unival uint64 // 8 bytes type Time int64 // 4 or 8 bytes, only has second-precision type EOF struct{} // 0 bytes -func (u Unival) AsULong() ULong { return ULong(u) } -func (u Unival) AsDouble() Double { return Double(math.Float64frombits(uint64(u))) } +type Unival struct { + arch Architecture + data []byte // 8 bytes +} + +func (u Unival) AsULong() ULong { return ULong(u.arch.ByteOrder.Uint64(u.data)) } +func (u Unival) AsDouble() Double { + return Double(math.Float64frombits(u.arch.ByteOrder.Uint64(u.data))) +} func (u Unival) String() string { - return fmt.Sprintf("{ .ulong=%d; .double=%s }", u.AsULong(), u.AsDouble().String()) + return fmt.Sprintf("enum{ .ulong=%d; .double=%s; .cdefds=%v }", u.AsULong(), u.AsDouble(), u.AsRPNTokens()) } func (u Unival) MarshalText() ([]byte, error) { diff --git a/rrdformat/sniff.go b/rrdformat/sniff.go index d8b5eb3..a6a8c6d 100644 --- a/rrdformat/sniff.go +++ b/rrdformat/sniff.go @@ -128,5 +128,15 @@ func SniffArchitecture(data []byte) (rrdbinary.Architecture, error) { arch.TimeWidth = arch.LongWidth arch.TimeAlign = arch.LongAlign + // FIXME: Figure out how to sniff the sizeof(short). + // + // javascriptRRD doesn't deal with this at all (it only comes + // up in parsing the params for DST_CDEF). + // + // For now, just assume it's sizeof(long)/2, which is true on + // i686, x86_64, and arm. (It is not true on alpha or ia64.) + arch.ShortWidth = arch.LongWidth / 2 + arch.Shortalign = arch.LongAlign / 2 + return arch, nil } -- cgit v1.2.3