mirror of
https://github.com/netsampler/goflow2.git
synced 2024-05-06 15:54:52 +00:00
129 lines
2.6 KiB
Go
129 lines
2.6 KiB
Go
package utils
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"errors"
|
|
"io"
|
|
"reflect"
|
|
)
|
|
|
|
type BytesBuffer interface {
|
|
io.Reader
|
|
Next(int) []byte
|
|
}
|
|
|
|
func BinaryDecoder(payload *bytes.Buffer, dests ...interface{}) error {
|
|
for _, dest := range dests {
|
|
err := BinaryRead(payload, binary.BigEndian, dest)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
func BinaryRead(payload BytesBuffer, order binary.ByteOrder, data any) error {
|
|
// Fast path for basic types and slices.
|
|
if n := intDataSize(data); n != 0 {
|
|
bs := payload.Next(n)
|
|
if len(bs) < n {
|
|
return io.ErrUnexpectedEOF
|
|
}
|
|
switch data := data.(type) {
|
|
case *bool:
|
|
*data = bs[0] != 0
|
|
case *int8:
|
|
*data = int8(bs[0])
|
|
case *uint8:
|
|
*data = bs[0]
|
|
case *int16:
|
|
*data = int16(order.Uint16(bs))
|
|
case *uint16:
|
|
*data = order.Uint16(bs)
|
|
case *int32:
|
|
*data = int32(order.Uint32(bs))
|
|
case *uint32:
|
|
*data = order.Uint32(bs)
|
|
case *int64:
|
|
*data = int64(order.Uint64(bs))
|
|
case *uint64:
|
|
*data = order.Uint64(bs)
|
|
case []bool:
|
|
for i, x := range bs { // Easier to loop over the input for 8-bit values.
|
|
data[i] = x != 0
|
|
}
|
|
case []int8:
|
|
for i, x := range bs {
|
|
data[i] = int8(x)
|
|
}
|
|
case []uint8:
|
|
copy(data, bs)
|
|
case []int16:
|
|
for i := range data {
|
|
data[i] = int16(order.Uint16(bs[2*i:]))
|
|
}
|
|
case []uint16:
|
|
for i := range data {
|
|
data[i] = order.Uint16(bs[2*i:])
|
|
}
|
|
case []int32:
|
|
for i := range data {
|
|
data[i] = int32(order.Uint32(bs[4*i:]))
|
|
}
|
|
case []uint32:
|
|
for i := range data {
|
|
data[i] = order.Uint32(bs[4*i:])
|
|
}
|
|
case []int64:
|
|
for i := range data {
|
|
data[i] = int64(order.Uint64(bs[8*i:]))
|
|
}
|
|
case []uint64:
|
|
for i := range data {
|
|
data[i] = order.Uint64(bs[8*i:])
|
|
}
|
|
default:
|
|
n = 0 // fast path doesn't apply
|
|
}
|
|
if n != 0 {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
return errors.New("binary.Read: invalid type " + reflect.TypeOf(data).String())
|
|
}
|
|
|
|
// intDataSize returns the size of the data required to represent the data when encoded.
|
|
// It returns zero if the type cannot be implemented by the fast path in Read or Write.
|
|
func intDataSize(data any) int {
|
|
switch data := data.(type) {
|
|
case bool, int8, uint8, *bool, *int8, *uint8:
|
|
return 1
|
|
case []bool:
|
|
return len(data)
|
|
case []int8:
|
|
return len(data)
|
|
case []uint8:
|
|
return len(data)
|
|
case int16, uint16, *int16, *uint16:
|
|
return 2
|
|
case []int16:
|
|
return 2 * len(data)
|
|
case []uint16:
|
|
return 2 * len(data)
|
|
case int32, uint32, *int32, *uint32:
|
|
return 4
|
|
case []int32:
|
|
return 4 * len(data)
|
|
case []uint32:
|
|
return 4 * len(data)
|
|
case int64, uint64, *int64, *uint64:
|
|
return 8
|
|
case []int64:
|
|
return 8 * len(data)
|
|
case []uint64:
|
|
return 8 * len(data)
|
|
}
|
|
return 0
|
|
}
|