diff options
-rw-r--r-- | rrdformat/format.go | 1 | ||||
-rw-r--r-- | rrdformat/rrdbinary/decode.go (renamed from rrdformat/rrdbinary/unmarshal.go) | 38 | ||||
-rw-r--r-- | rrdformat/unmarshal_binary.go | 79 |
3 files changed, 76 insertions, 42 deletions
diff --git a/rrdformat/format.go b/rrdformat/format.go index f9b8504..2900ce8 100644 --- a/rrdformat/format.go +++ b/rrdformat/format.go @@ -70,7 +70,6 @@ type TimeWithUsec struct { type TimeWithoutUsec struct { Sec rrdbinary.Time - Usec rrdbinary.Int `rrdbinary:"-"` } type PDPPrep struct { diff --git a/rrdformat/rrdbinary/unmarshal.go b/rrdformat/rrdbinary/decode.go index 00f1222..f3ae80e 100644 --- a/rrdformat/rrdbinary/unmarshal.go +++ b/rrdformat/rrdbinary/decode.go @@ -15,21 +15,27 @@ type Decoder struct { data []byte } +func NewDecoder(arch Architecture, data []byte) *Decoder { + return &Decoder{ + arch: arch, + pos: 0, + data: data, + } +} + type unmarshaler interface { unmarshalRRD(d *Decoder, tag string) error } func Unmarshal(arch Architecture, data []byte, ptr interface{}) error { - ptrValue := reflect.ValueOf(ptr) - if ptrValue.Kind() != reflect.Ptr { - return typeErrorf("ptr is a %v, not a pointer", ptrValue.Kind()) + decoder := NewDecoder(arch, data) + if err := decoder.Decode(ptr, ""); err != nil { + return err } - decoder := &Decoder{ - arch: arch, - pos: 0, - data: data, + if err := decoder.Decode(&EOF{}, ""); err != nil { + return err } - return decoder.Decode(ptrValue, "") + return nil } func (d *Decoder) binError(ctxLen int, msg string) error { @@ -40,7 +46,15 @@ func (d *Decoder) binErrorf(ctxLen int, format string, a ...interface{}) error { return d.binError(ctxLen, fmt.Sprintf(format, a...)) } -func (d *Decoder) Decode(v reflect.Value, tag string) error { +func (d *Decoder) Decode(ptr interface{}, tag string) error { + ptrValue := reflect.ValueOf(ptr) + if ptrValue.Kind() != reflect.Ptr { + return typeErrorf("ptr is a %v, not a pointer", ptrValue.Kind()) + } + return d.decode(ptrValue, tag) +} + +func (d *Decoder) decode(v reflect.Value, tag string) error { if v.CanInterface() { if u, ok := v.Interface().(unmarshaler); ok { return u.unmarshalRRD(d, tag) @@ -52,7 +66,7 @@ func (d *Decoder) Decode(v reflect.Value, tag string) error { case reflect.Array, reflect.Slice: return d.decodeList(v, tag) default: - return typeErrorf("invalid type for rrdbinary.Decoder.Decode: %v", v.Type()) + return typeErrorf("invalid type for rrdbinary.Decoder: %v", v.Type()) } } @@ -70,7 +84,7 @@ func (d *Decoder) decodeStruct(v reflect.Value, tag string) error { if tag == "-" { continue } - if err := d.Decode(v.Field(i), tag); err != nil { + if err := d.decode(v.Field(i), tag); err != nil { return fmt.Errorf("field %s: %w", fieldInfo.Name, err) } } @@ -82,7 +96,7 @@ func (d *Decoder) decodeList(v reflect.Value, tag string) error { panicUnless(v.CanSet()) for i := 0; i < v.Len(); i++ { - if err := d.Decode(v.Index(i), tag); err != nil { + if err := d.decode(v.Index(i), tag); err != nil { return fmt.Errorf("index %d: %w", i, err) } } diff --git a/rrdformat/unmarshal_binary.go b/rrdformat/unmarshal_binary.go index b9bafde..70c06b7 100644 --- a/rrdformat/unmarshal_binary.go +++ b/rrdformat/unmarshal_binary.go @@ -2,6 +2,7 @@ package rrdformat import ( "encoding" + "fmt" "git.lukeshu.com/go/librrd/rrdformat/rrdbinary" ) @@ -16,44 +17,64 @@ func (rrd *RRD) UnmarshalBinary(data []byte) error { if err != nil { return err } - var header Header - if err := rrdbinary.Unmarshal(arch, data, &header); err != nil { - return err - } + decoder := rrdbinary.NewDecoder(arch, data) 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 { + if err := decoder.Decode(&parsed.Header, ""); err != nil { + return fmt.Errorf("field %s: %w", "Header", err) + } + // allocate memory based on .Header values + parsed.DSDefs = make([]DSDef, parsed.Header.DSCnt) + parsed.DSDefs = make([]DSDef, parsed.Header.DSCnt) + parsed.RRADefs = make([]RRADef, parsed.Header.RRACnt) + parsed.PDPPreps = make([]PDPPrep, parsed.Header.DSCnt) + parsed.CDPPreps = make([]CDPPrep, parsed.Header.DSCnt*parsed.Header.RRACnt) + parsed.RRAPtrs = make([]RRAPtr, parsed.Header.RRACnt) + // resume decoding + if err := decoder.Decode(&parsed.DSDefs, ""); err != nil { + return fmt.Errorf("field %s: %w", "DSDefs", err) + } + if err := decoder.Decode(&parsed.RRADefs, ""); err != nil { + return fmt.Errorf("field %s: %w", "RRADefs", err) + } + // allocate memory based on .RRADefs + val_cnt := 0 + for i := range parsed.RRADefs { + val_cnt += int(parsed.RRADefs[i].RowCnt * parsed.Header.DSCnt) + } + parsed.Values = make([]RRDValue, val_cnt) + // resume decoding + var lastUpdatedPtr interface{} + switch parsed.Header.Version { case "0001", "0002": - _parsed := &RRDv0001{} //(*RRDv0001)(&parsed) - if err := rrdbinary.Unmarshal(arch, data, _parsed); err != nil { - return err - } + lastUpdatedPtr = &parsed.LastUpdated.Sec case "0003", "0004", "0005": - if err := rrdbinary.Unmarshal(arch, data, &parsed); err != nil { - return err - } + lastUpdatedPtr = &parsed.LastUpdated default: - // version number already validated by - // SniffArchitecture + // 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) + if err := decoder.Decode(lastUpdatedPtr, ""); err != nil { + return fmt.Errorf("field %s: %w", "LastUpdated", err) } - parsed.Values = make([]RRDValue, val_cnt) - if err := rrdbinary.Unmarshal(arch, data, &parsed.Values); err != nil { - return err + if err := decoder.Decode(&parsed.LastUpdated, ""); err != nil { + return fmt.Errorf("field %s: %w", "LastUpdated", err) + } + if err := decoder.Decode(&parsed.PDPPreps, ""); err != nil { + return fmt.Errorf("field %s: %w", "PDPPreps", err) + } + if err := decoder.Decode(&parsed.CDPPreps, ""); err != nil { + return fmt.Errorf("field %s: %w", "CDPPreps", err) + } + if err := decoder.Decode(&parsed.RRAPtrs, ""); err != nil { + return fmt.Errorf("field %s: %w", "RRAPtrs", err) + } + if err := decoder.Decode(&parsed.Values, ""); err != nil { + return fmt.Errorf("field %s: %w", "Values", err) + } + if err := decoder.Decode(&rrdbinary.EOF{}, ""); err != nil { + return fmt.Errorf("field %s: %w", "EOF", err) } *rrd = RRD{ |