summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2020-02-02 23:11:21 -0500
committerLuke Shumaker <lukeshu@lukeshu.com>2020-02-02 23:11:21 -0500
commit1e253b011f916544879ab3a2d3060c2e982a0c9d (patch)
treec96b1de5d159b9b4a29ba22e00e6f45d2fd1a037
parentb3d7493f5e8b20378ec2e41a10459e4339d538e9 (diff)
rrdbinary: Decode CDEF RPN tokens crammed in to Unival parameters
-rw-r--r--rrdformat/rrdbinary/cdef.go29
-rw-r--r--rrdformat/rrdbinary/decode.go8
-rw-r--r--rrdformat/rrdbinary/types.go17
-rw-r--r--rrdformat/sniff.go10
4 files changed, 59 insertions, 5 deletions
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
}