summaryrefslogtreecommitdiff
path: root/rrdformat/unmarshal_binary.go
blob: 67dc4ff6073f9232ba9fa637ff5fcecc2a90a040 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package rrdformat

import (
	"encoding"
	"fmt"

	"git.lukeshu.com/go/librrd/rrdformat/rrdbinary"
)

type RRD struct {
	Architecture rrdbinary.Architecture `xml:"-"`
	Data         RRDv0005               `xml:",innerxml"`
}

func (rrd *RRD) UnmarshalBinary(data []byte) error {
	arch, err := SniffArchitecture(data)
	if err != nil {
		return err
	}

	decoder := rrdbinary.NewDecoder(arch, data)
	var parsed RRDv0005

	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.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)
	}
	vals := make([]Value, val_cnt)
	parsed.Values = vals
	// set up some of pointers
	for rra_i := range parsed.RRADefs {
		parsed.RRADefs[rra_i].CDPPrep = &parsed.CDPPreps[rra_i]
		parsed.RRADefs[rra_i].Database = make([][]Value, parsed.RRADefs[rra_i].RowCnt)
		for row_i := 0; row_i < int(parsed.RRADefs[rra_i].RowCnt); row_i++ {
			parsed.RRADefs[rra_i].Database[row_i] = vals[:parsed.Header.DSCnt]
			vals = vals[parsed.Header.DSCnt:]
		}
	}

	// resume decoding
	var lastUpdatedPtr interface{}
	switch parsed.Header.Version {
	case "0001", "0002":
		lastUpdatedPtr = &parsed.LastUpdated.Sec
	case "0003", "0004", "0005":
		lastUpdatedPtr = &parsed.LastUpdated
	default:
		// version number already validated by SniffArchitecture
		panic("should not happen")
	}
	if err := decoder.Decode(lastUpdatedPtr, ""); 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{
		Architecture: arch,
		Data:         parsed,
	}
	return nil
}

//var _ encoding.BinaryMarshaler = &RRD{}
var _ encoding.BinaryUnmarshaler = &RRD{}