diff options
Diffstat (limited to 'rrdformat/rrdbinary/unmarshal.go')
-rw-r--r-- | rrdformat/rrdbinary/unmarshal.go | 305 |
1 files changed, 0 insertions, 305 deletions
diff --git a/rrdformat/rrdbinary/unmarshal.go b/rrdformat/rrdbinary/unmarshal.go deleted file mode 100644 index 00f1222..0000000 --- a/rrdformat/rrdbinary/unmarshal.go +++ /dev/null @@ -1,305 +0,0 @@ -package rrdbinary - -import ( - "bytes" - "fmt" - "math" - "reflect" - "strconv" - "strings" -) - -type Decoder struct { - arch Architecture - pos int - data []byte -} - -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 := &Decoder{ - arch: arch, - pos: 0, - data: data, - } - return decoder.Decode(ptrValue, "") -} - -func (d *Decoder) binError(ctxLen int, msg string) error { - return NewBinError(msg, d.data, d.pos, ctxLen) -} - -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 { - if v.CanInterface() { - if u, ok := v.Interface().(unmarshaler); ok { - return u.unmarshalRRD(d, tag) - } - } - switch v.Type().Kind() { - case reflect.Struct: - return d.decodeStruct(v, tag) - case reflect.Array, reflect.Slice: - return d.decodeList(v, tag) - default: - return typeErrorf("invalid type for rrdbinary.Decoder.Decode: %v", v.Type()) - } -} - -func (d *Decoder) decodeStruct(v reflect.Value, tag string) error { - panicUnless(v.Kind() == reflect.Struct) - panicUnless(v.CanSet()) - - if tag != "" { - return typeErrorf("invalid rrdbinary struct tag for struct: %q", tag) - } - - for i := 0; i < v.NumField(); i++ { - fieldInfo := v.Type().Field(i) - tag := fieldInfo.Tag.Get("rrdbinary") - if tag == "-" { - continue - } - if err := d.Decode(v.Field(i), tag); err != nil { - return fmt.Errorf("field %s: %w", fieldInfo.Name, err) - } - } - return nil -} - -func (d *Decoder) decodeList(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++ { - if err := d.Decode(v.Index(i), tag); err != nil { - return fmt.Errorf("index %d: %w", i, err) - } - } - return nil -} - -func (obj *String) unmarshalRRD(d *Decoder, tag string) error { - size := 0 - switch { - case tag == "": - // do nothing - case strings.HasPrefix(tag, "size="): - var err error - size, err = strconv.Atoi(strings.TrimPrefix(tag, "size=")) - if err != nil { - return typeErrorf("invalid rrdbinary struct tag for string: %q", tag) - } - default: - return typeErrorf("invalid rrdbinary struct tag for string: %q", tag) - } - - data := d.data[d.pos:] - if size > 0 { - if len(data) < size { - return d.binErrorf(size, "unexpected end-of-file in %d-byte string", size) - } - data = data[:size] - } - - nul := bytes.IndexByte(data, 0) - if nul < 0 { - if size > 0 { - return d.binErrorf(size, "missing null-terminator on %d-byte string", size) - } else { - return d.binErrorf(16, "unexpected end-of-file looking for null-terminator on string") - } - } - - if size > 0 { - for _, byte := range data[nul:] { - if byte != 0 { - return d.binErrorf(size, "garbage data after null-terminator on fixed %d-byte string", size) - } - } - } else { - size = nul + 1 - } - - *obj = String(data[:nul]) - d.pos += size - return nil -} - -func (obj *Float) unmarshalRRD(d *Decoder, tag string) error { - if d.arch.FloatWidth != 8 { - return archErrorf("rrdbinary does not support FloatWidth=%d; only supports 8", d.arch.FloatWidth) - } - if tag != "" { - return typeErrorf("invalid rrdbinary struct tag for float: %q", tag) - } - - data := d.data[d.pos:] - - padding := 0 - if d.pos%d.arch.FloatAlign != 0 { - padding = d.arch.FloatAlign - (d.pos % d.arch.FloatAlign) - } - if len(data) < padding { - return d.binErrorf(padding+d.arch.FloatWidth, "unexpected end-of-file in %d-byte padding-before-float", padding) - } - data = data[padding:] - - if len(data) < d.arch.FloatWidth { - return d.binErrorf(d.arch.FloatWidth, "unexpected end-of-file in %d-byte float", d.arch.FloatWidth) - } - - *obj = Float(math.Float64frombits(d.arch.ByteOrder.Uint64(data))) - d.pos += padding + d.arch.FloatWidth - return nil -} - -func (obj *Uint) unmarshalRRD(d *Decoder, tag string) error { - if d.arch.IntWidth != 4 && d.arch.IntWidth != 8 { - return archErrorf("rrdbinary does not support IntWidth=%d; only supports 4 or 8", d.arch.IntWidth) - } - if tag != "" { - return typeErrorf("invalid rrdbinary struct tag for uint: %q", tag) - } - - data := d.data[d.pos:] - - padding := 0 - if d.pos%d.arch.IntAlign != 0 { - padding = d.arch.IntAlign - (d.pos % d.arch.IntAlign) - } - if len(data) < padding { - return d.binErrorf(padding+d.arch.IntWidth, "unexpected end-of-file in %d-byte padding-before-uint", padding) - } - data = data[padding:] - - if len(data) < d.arch.IntWidth { - return d.binErrorf(d.arch.IntWidth, "unexpected end-of-file in %d-byte uint", d.arch.IntWidth) - } - - switch d.arch.IntWidth { - case 4: - *obj = Uint(d.arch.ByteOrder.Uint32(data)) - case 8: - *obj = Uint(d.arch.ByteOrder.Uint64(data)) - } - d.pos += padding + d.arch.IntWidth - return nil -} - -func (obj *Int) unmarshalRRD(d *Decoder, tag string) error { - if d.arch.IntWidth != 4 && d.arch.IntWidth != 8 { - return archErrorf("rrdbinary does not support IntWidth=%d; only supports 4 or 8", d.arch.IntWidth) - } - if tag != "" { - return typeErrorf("invalid rrdbinary struct tag for int: %q", tag) - } - - data := d.data[d.pos:] - - padding := 0 - if d.pos%d.arch.IntAlign != 0 { - padding = d.arch.IntAlign - (d.pos % d.arch.IntAlign) - } - if len(data) < padding { - return d.binErrorf(padding+d.arch.IntWidth, "unexpected end-of-file in %d-byte padding-before-int", padding) - } - data = data[padding:] - - if len(data) < d.arch.IntWidth { - return d.binErrorf(d.arch.IntWidth, "unexpected end-of-file in %d-byte int", d.arch.IntWidth) - } - - switch d.arch.IntWidth { - case 4: - *obj = Int(int32(d.arch.ByteOrder.Uint32(data))) - case 8: - *obj = Int(d.arch.ByteOrder.Uint64(data)) - } - d.pos += padding + d.arch.IntWidth - return nil -} - -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 tag != "" { - return typeErrorf("invalid rrdbinary struct tag for unival: %q", tag) - } - - data := d.data[d.pos:] - - padding := 0 - if d.pos%d.arch.UnivalAlign != 0 { - padding = d.arch.UnivalAlign - (d.pos % d.arch.UnivalAlign) - } - if len(data) < padding { - return d.binErrorf(padding+d.arch.UnivalWidth, "unexpected end-of-file in %d-byte padding-before-unival", padding) - } - data = data[padding:] - - if len(data) < d.arch.UnivalWidth { - return d.binErrorf(d.arch.UnivalWidth, "unexpected end-of-file in %d-byte unival", d.arch.UnivalWidth) - } - - *obj = Unival(d.arch.ByteOrder.Uint64(data)) - d.pos += padding + d.arch.UnivalWidth - return nil -} - -func (obj *Time) unmarshalRRD(d *Decoder, tag string) error { - if d.arch.TimeWidth != 4 && d.arch.TimeWidth != 8 { - return archErrorf("rrdbinary does not support TimeWidth=%d; only supports 4 or 8", d.arch.TimeWidth) - } - if tag != "" { - return typeErrorf("invalid rrdbinary struct tag for time: %q", tag) - } - - data := d.data[d.pos:] - - padding := 0 - if d.pos%d.arch.TimeAlign != 0 { - padding = d.arch.TimeAlign - (d.pos % d.arch.TimeAlign) - } - if len(data) < padding { - return d.binErrorf(padding+d.arch.TimeWidth, "unexpected end-of-file in %d-byte padding-before-time", padding) - } - data = data[padding:] - - if len(data) < d.arch.TimeWidth { - return d.binErrorf(d.arch.TimeWidth, "unexpected end-of-file in %d-byte time", d.arch.TimeWidth) - } - - switch d.arch.TimeWidth { - case 4: - *obj = Time(int32(d.arch.ByteOrder.Uint32(data))) - case 8: - *obj = Time(d.arch.ByteOrder.Uint64(data)) - } - d.pos += padding + d.arch.TimeWidth - return nil -} - -func (_ *EOF) unmarshalRRD(d *Decoder, tag string) error { - if tag != "" { - return typeErrorf("invalid rrdbinary struct tag for eof: %q", tag) - } - - 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 -} |