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 IPAddress: copy(data, bs) case MacAddress: 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 IPAddress: return len(data) case MacAddress: 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 }