From 629cb407c10743b0033fdc648a3c876f244cf558 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Sun, 26 Jan 2020 23:13:22 -0500 Subject: UnmarshalBinary, EOF --- rrdformat/format.go | 47 ++++++++++------------------ rrdformat/marshal_xml.go | 19 ++++++++++++ rrdformat/rrdbinary/types.go | 1 + rrdformat/rrdbinary/unmarshal.go | 21 ++++++++++--- rrdformat/unmarshal_binary.go | 67 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 120 insertions(+), 35 deletions(-) create mode 100644 rrdformat/marshal_xml.go create mode 100644 rrdformat/unmarshal_binary.go diff --git a/rrdformat/format.go b/rrdformat/format.go index 8898ffd..f9b8504 100644 --- a/rrdformat/format.go +++ b/rrdformat/format.go @@ -1,9 +1,6 @@ package rrdformat import ( - //"encoding" - "encoding/xml" - "git.lukeshu.com/go/librrd/rrdformat/rrdbinary" ) @@ -66,11 +63,16 @@ type RRADef struct { PDPCnt rrdbinary.Uint } -type Time struct { +type TimeWithUsec struct { Sec rrdbinary.Time Usec rrdbinary.Int // signed, but always >= 0 } +type TimeWithoutUsec struct { + Sec rrdbinary.Time + Usec rrdbinary.Int `rrdbinary:"-"` +} + type PDPPrep struct { LastDS rrdbinary.String `rrdbinary:"size=30"` Scratch [10]rrdbinary.Unival @@ -91,11 +93,11 @@ type RRDv0003 struct { Header Header DSDefs []DSDef // .Header.DSCnt RRADefs []RRADef // .Header.RRACnt - LastUpdated Time - PDPPrep []PDPPrep // .Header.DSCnt - CDPPrep []CDPPrep // .Header.DSCnt * .Header.RRACnt - RRAPtr []RRAPtr // .Header.RRACnt - Values []RRDValue // Σ .RRADefs[i].RowCnt*.Header.DsCnt + LastUpdated TimeWithUsec + PDPPreps []PDPPrep // .Header.DSCnt + CDPPreps []CDPPrep // .Header.DSCnt * .Header.RRACnt + RRAPtrs []RRAPtr // .Header.RRACnt + Values []RRDValue // Σ .RRADefs[i].RowCnt*.Header.DSCnt } type RRDv0002 = RRDv0001 @@ -104,26 +106,9 @@ type RRDv0001 struct { Header Header DSDefs []DSDef // .Header.DSCnt RRADefs []RRADef // .Header.RRACnt - LastUpdated rrdbinary.Time - PDPPrep []PDPPrep // .Header.DSCnt - CDPPrep []CDPPrep // .Header.DSCnt * .Header.RRACnt - RRAPtr []RRAPtr // .Header.RRACnt - Values []RRDValue // Σ .RRADefs[i].RowCnt*.Header.DsCnt + LastUpdated TimeWithoutUsec + PDPPreps []PDPPrep // .Header.DSCnt + CDPPreps []CDPPrep // .Header.DSCnt * .Header.RRACnt + RRAPtrs []RRAPtr // .Header.RRACnt + Values []RRDValue // Σ .RRADefs[i].RowCnt*.Header.DSCnt } - -func (h *Header) MarshalXML(e *xml.Encoder, start xml.StartElement) error { - if err := e.EncodeElement(h.Version, xml.StartElement{Name: xml.Name{Local: "version", Space: XMLNS}}); err != nil { - return err - } - if err := e.EncodeElement(h.PDPStep, xml.StartElement{Name: xml.Name{Local: "step", Space: XMLNS}}); err != nil { - return err - } - return nil -} - -//var _ encoding.BinaryMarshaler = &Header{} -//var _ encoding.BinaryUnmarshaler = &Header{} - -var _ xml.Marshaler = &Header{} - -//var _ xml.Unmarshaler = &Header{} diff --git a/rrdformat/marshal_xml.go b/rrdformat/marshal_xml.go new file mode 100644 index 0000000..dfb0556 --- /dev/null +++ b/rrdformat/marshal_xml.go @@ -0,0 +1,19 @@ +package rrdformat + +import ( + "encoding/xml" +) + +func (h *Header) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + if err := e.EncodeElement(h.Version, xml.StartElement{Name: xml.Name{Local: "version", Space: XMLNS}}); err != nil { + return err + } + if err := e.EncodeElement(h.PDPStep, xml.StartElement{Name: xml.Name{Local: "step", Space: XMLNS}}); err != nil { + return err + } + return nil +} + +var _ xml.Marshaler = &Header{} + +//var _ xml.Unmarshaler = &Header{} diff --git a/rrdformat/rrdbinary/types.go b/rrdformat/rrdbinary/types.go index a036d5d..006af3c 100644 --- a/rrdformat/rrdbinary/types.go +++ b/rrdformat/rrdbinary/types.go @@ -27,6 +27,7 @@ type Uint uint64 // 4 or 8 bytes type Int 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) AsUint64() uint64 { return uint64(u) } func (u Unival) AsFloat64() float64 { return math.Float64frombits(uint64(u)) } diff --git a/rrdformat/rrdbinary/unmarshal.go b/rrdformat/rrdbinary/unmarshal.go index 1cfee34..142ee9f 100644 --- a/rrdformat/rrdbinary/unmarshal.go +++ b/rrdformat/rrdbinary/unmarshal.go @@ -50,12 +50,14 @@ func (d *unmarshaler) unmarshal(v reflect.Value, tag string) error { return d.unmarshalUnival(v, tag) case reflect.TypeOf(Time(0)): return d.unmarshalTime(v, tag) + case reflect.TypeOf(EOF{}): + return d.unmarshalEOF(v, tag) default: switch v.Type().Kind() { case reflect.Struct: return d.unmarshalStruct(v, tag) - case reflect.Array: - return d.unmarshalArray(v, tag) + case reflect.Array, reflect.Slice: + return d.unmarshalList(v, tag) default: return typeErrorf("invalid type for rrdbinary.Unmarshal: %v", v.Type()) } @@ -83,8 +85,8 @@ func (d *unmarshaler) unmarshalStruct(v reflect.Value, tag string) error { return nil } -func (d *unmarshaler) unmarshalArray(v reflect.Value, tag string) error { - panicUnless(v.Kind() == reflect.Array) +func (d *unmarshaler) unmarshalList(v reflect.Value, tag string) error { + panicUnless(v.Kind() == reflect.Array || v.Kind() == reflect.Slice) panicUnless(v.CanSet()) for i := 0; i < v.Len(); i++ { @@ -314,3 +316,14 @@ func (d *unmarshaler) unmarshalTime(v reflect.Value, tag string) error { d.pos += padding + d.arch.TimeWidth return nil } + +func (d *unmarshaler) unmarshalEOF(v reflect.Value, tag string) error { + panicUnless(v.Type() == reflect.TypeOf(EOF{})) + + data := d.data[d.pos:] + if len(data) > 0 { + return d.binErrorf(16, "extra %d bytes of data after expected end-of-file", len(data)) + } + + return nil +} diff --git a/rrdformat/unmarshal_binary.go b/rrdformat/unmarshal_binary.go new file mode 100644 index 0000000..b9bafde --- /dev/null +++ b/rrdformat/unmarshal_binary.go @@ -0,0 +1,67 @@ +package rrdformat + +import ( + "encoding" + + "git.lukeshu.com/go/librrd/rrdformat/rrdbinary" +) + +type RRD struct { + Architecture rrdbinary.Architecture + Data RRDv0005 +} + +func (rrd *RRD) UnmarshalBinary(data []byte) error { + arch, err := SniffArchitecture(data) + if err != nil { + return err + } + var header Header + if err := rrdbinary.Unmarshal(arch, data, &header); err != nil { + return err + } + + var parsed RRDv0005 + parsed.DSDefs = make([]DSDef, header.DSCnt) + parsed.DSDefs = make([]DSDef, header.DSCnt) + parsed.RRADefs = make([]RRADef, header.RRACnt) + //LastUpdated + parsed.PDPPreps = make([]PDPPrep, header.DSCnt) + parsed.CDPPreps = make([]CDPPrep, header.DSCnt*header.RRACnt) + parsed.RRAPtrs = make([]RRAPtr, header.RRACnt) + //Values + + switch header.Version { + case "0001", "0002": + _parsed := &RRDv0001{} //(*RRDv0001)(&parsed) + if err := rrdbinary.Unmarshal(arch, data, _parsed); err != nil { + return err + } + case "0003", "0004", "0005": + if err := rrdbinary.Unmarshal(arch, data, &parsed); err != nil { + return err + } + default: + // version number already validated by + // SniffArchitecture + panic("should not happen") + } + + val_cnt := 0 + for i := range parsed.RRADefs { + val_cnt += int(parsed.RRADefs[i].RowCnt * header.DSCnt) + } + parsed.Values = make([]RRDValue, val_cnt) + if err := rrdbinary.Unmarshal(arch, data, &parsed.Values); err != nil { + return err + } + + *rrd = RRD{ + Architecture: arch, + Data: parsed, + } + return nil +} + +//var _ encoding.BinaryMarshaler = &RRD{} +var _ encoding.BinaryUnmarshaler = &RRD{} -- cgit v1.2.3