From 8576e5f207f9d3b7c6324ed71a3ca6a005f9ae7c Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Mon, 30 May 2022 12:00:39 -0400 Subject: ahhhh --- pkg/binstruct/builtins.go | 241 +++++++++++++++++++++++++++++++++++++++++++++ pkg/binstruct/l1.go | 6 +- pkg/binstruct/l2.go | 3 + pkg/binstruct/l3.go | 3 + pkg/binstruct/marshal.go | 36 +++++++ pkg/binstruct/size.go | 36 +++++++ pkg/binstruct/structs.go | 11 +++ pkg/binstruct/unmarshal.go | 44 +++++++++ 8 files changed, 377 insertions(+), 3 deletions(-) create mode 100644 pkg/binstruct/builtins.go create mode 100644 pkg/binstruct/marshal.go create mode 100644 pkg/binstruct/size.go create mode 100644 pkg/binstruct/structs.go create mode 100644 pkg/binstruct/unmarshal.go (limited to 'pkg') diff --git a/pkg/binstruct/builtins.go b/pkg/binstruct/builtins.go new file mode 100644 index 0000000..c791640 --- /dev/null +++ b/pkg/binstruct/builtins.go @@ -0,0 +1,241 @@ +package binstruct + +import ( + "encoding/binary" + "fmt" +) + +func needNBytes(t interface{}, dat []byte, n int) error { + if len(dat) < n { + return fmt.Errorf("%T.UnmarshalBinary: need at least %d bytes, only have %d", t, n, len(dat)) + } + return nil +} + +// unsigned + +type u8 uint8 + +func (u8) BinaryStaticSize() int { return 1 } +func (x u8) MarshalBinary() ([]byte, error) { return []byte{byte(x)}, nil } +func (x *u8) UnmarshalBinary(dat []byte) (int, error) { + if err := needNBytes(*x, dat, 1); err != nil { + return 0, err + } + *x = u8(dat[0]) + return 1, nil +} + +// unsigned little endian + +type u16le uint16 + +func (u16le) BinaryStaticSize() int { return 2 } +func (x u16le) MarshalBinary() ([]byte, error) { + var buf [2]byte + binary.LittleEndian.PutUint16(buf[:], uint16(x)) + return buf[:], nil +} +func (x *u16le) UnmarshalBinary(dat []byte) (int, error) { + if err := needNBytes(*x, dat, 2); err != nil { + return 0, err + } + *x = u16le(binary.LittleEndian.Uint16(dat)) + return 2, nil +} + +type u32le uint32 + +func (u32le) BinaryStaticSize() int { return 4 } +func (x u32le) MarshalBinary() ([]byte, error) { + var buf [4]byte + binary.LittleEndian.PutUint32(buf[:], uint32(x)) + return buf[:], nil +} +func (x *u32le) UnmarshalBinary(dat []byte) (int, error) { + if err := needNBytes(*x, dat, 4); err != nil { + return 0, err + } + *x = u32le(binary.LittleEndian.Uint32(dat)) + return 2, nil +} + +type u64le uint64 + +func (u64le) BinaryStaticSize() int { return 8 } +func (x u64le) MarshalBinary() ([]byte, error) { + var buf [8]byte + binary.LittleEndian.PutUint64(buf[:], uint64(x)) + return buf[:], nil +} +func (x *u64le) UnmarshalBinary(dat []byte) (int, error) { + if err := needNBytes(*x, dat, 8); err != nil { + return 0, err + } + *x = u64le(binary.LittleEndian.Uint64(dat)) + return 2, nil +} + +// unsigned big endian + +type u16be uint16 + +func (u16be) BinaryStaticSize() int { return 2 } +func (x u16be) MarshalBinary() ([]byte, error) { + var buf [2]byte + binary.BigEndian.PutUint16(buf[:], uint16(x)) + return buf[:], nil +} +func (x *u16be) UnmarshalBinary(dat []byte) (int, error) { + if err := needNBytes(*x, dat, 2); err != nil { + return 0, err + } + *x = u16be(binary.BigEndian.Uint16(dat)) + return 2, nil +} + +type u32be uint32 + +func (u32be) BinaryStaticSize() int { return 4 } +func (x u32be) MarshalBinary() ([]byte, error) { + var buf [4]byte + binary.BigEndian.PutUint32(buf[:], uint32(x)) + return buf[:], nil +} +func (x *u32be) UnmarshalBinary(dat []byte) (int, error) { + if err := needNBytes(*x, dat, 4); err != nil { + return 0, err + } + *x = u32be(binary.BigEndian.Uint32(dat)) + return 2, nil +} + +type u64be uint64 + +func (u64be) BinaryStaticSize() int { return 8 } +func (x u64be) MarshalBinary() ([]byte, error) { + var buf [8]byte + binary.BigEndian.PutUint64(buf[:], uint64(x)) + return buf[:], nil +} +func (x *u64be) UnmarshalBinary(dat []byte) (int, error) { + if err := needNBytes(*x, dat, 8); err != nil { + return 0, err + } + *x = u64be(binary.BigEndian.Uint64(dat)) + return 2, nil +} + +// signed + +type i8 int8 + +func (i8) BinaryStaticSize() int { return 1 } +func (x i8) MarshalBinary() ([]byte, error) { return []byte{byte(x)}, nil } +func (x *i8) UnmarshalBinary(dat []byte) (int, error) { + if err := needNBytes(*x, dat, 1); err != nil { + return 0, err + } + *x = i8(dat[0]) + return 1, nil +} + +// signed little endian + +type i16le int16 + +func (i16le) BinaryStaticSize() int { return 2 } +func (x i16le) MarshalBinary() ([]byte, error) { + var buf [2]byte + binary.LittleEndian.PutUint16(buf[:], uint16(x)) + return buf[:], nil +} +func (x *i16le) UnmarshalBinary(dat []byte) (int, error) { + if err := needNBytes(*x, dat, 2); err != nil { + return 0, err + } + *x = i16le(binary.LittleEndian.Uint16(dat)) + return 2, nil +} + +type i32le int32 + +func (i32le) BinaryStaticSize() int { return 4 } +func (x i32le) MarshalBinary() ([]byte, error) { + var buf [4]byte + binary.LittleEndian.PutUint32(buf[:], uint32(x)) + return buf[:], nil +} +func (x *i32le) UnmarshalBinary(dat []byte) (int, error) { + if err := needNBytes(*x, dat, 4); err != nil { + return 0, err + } + *x = i32le(binary.LittleEndian.Uint32(dat)) + return 2, nil +} + +type i64le int64 + +func (i64le) BinaryStaticSize() int { return 8 } +func (x i64le) MarshalBinary() ([]byte, error) { + var buf [8]byte + binary.LittleEndian.PutUint64(buf[:], uint64(x)) + return buf[:], nil +} +func (x *i64le) UnmarshalBinary(dat []byte) (int, error) { + if err := needNBytes(*x, dat, 8); err != nil { + return 0, err + } + *x = i64le(binary.LittleEndian.Uint64(dat)) + return 2, nil +} + +// signed big endian + +type i16be int16 + +func (i16be) BinaryStaticSize() int { return 2 } +func (x i16be) MarshalBinary() ([]byte, error) { + var buf [2]byte + binary.BigEndian.PutUint16(buf[:], uint16(x)) + return buf[:], nil +} +func (x *i16be) UnmarshalBinary(dat []byte) (int, error) { + if err := needNBytes(*x, dat, 2); err != nil { + return 0, err + } + *x = i16be(binary.BigEndian.Uint16(dat)) + return 2, nil +} + +type i32be int32 + +func (i32be) BinaryStaticSize() int { return 4 } +func (x i32be) MarshalBinary() ([]byte, error) { + var buf [4]byte + binary.BigEndian.PutUint32(buf[:], uint32(x)) + return buf[:], nil +} +func (x *i32be) UnmarshalBinary(dat []byte) (int, error) { + if err := needNBytes(*x, dat, 4); err != nil { + return 0, err + } + *x = i32be(binary.BigEndian.Uint32(dat)) + return 2, nil +} + +type i64be int64 + +func (i64be) BinaryStaticSize() int { return 8 } +func (x i64be) MarshalBinary() ([]byte, error) { + var buf [8]byte + binary.BigEndian.PutUint64(buf[:], uint64(x)) + return buf[:], nil +} +func (x *i64be) UnmarshalBinary(dat []byte) (int, error) { + if err := needNBytes(*x, dat, 8); err != nil { + return 0, err + } + *x = i64be(binary.BigEndian.Uint64(dat)) + return 2, nil +} diff --git a/pkg/binstruct/l1.go b/pkg/binstruct/l1.go index 367dd28..4464f51 100644 --- a/pkg/binstruct/l1.go +++ b/pkg/binstruct/l1.go @@ -1,3 +1,6 @@ +//go:build old +// +build old + package binstruct import ( @@ -7,19 +10,16 @@ import ( ) type Marshaler interface { - BinarySize() int64 MarshalBinary() []byte } type Unmarshaler interface { - Marshaler UnmarshalBinary([]byte) } type handler interface { Unmarshal(dat []byte) interface{} Marshal(val interface{}) []byte - Size() int64 } type extHandler struct { diff --git a/pkg/binstruct/l2.go b/pkg/binstruct/l2.go index c9b9a9c..4f05d96 100644 --- a/pkg/binstruct/l2.go +++ b/pkg/binstruct/l2.go @@ -1,3 +1,6 @@ +//go:build old +// +build old + package binstruct import ( diff --git a/pkg/binstruct/l3.go b/pkg/binstruct/l3.go index 1ccaaf0..93919d8 100644 --- a/pkg/binstruct/l3.go +++ b/pkg/binstruct/l3.go @@ -1,3 +1,6 @@ +//go:build old +// +build old + package binstruct import ( diff --git a/pkg/binstruct/marshal.go b/pkg/binstruct/marshal.go new file mode 100644 index 0000000..c8158a4 --- /dev/null +++ b/pkg/binstruct/marshal.go @@ -0,0 +1,36 @@ +package binstruct + +import ( + "fmt" + "reflect" +) + +type Marshaler interface { + MarshalBinary() ([]byte, error) +} + +func Marshal(obj any) ([]byte, error) { + if mar, ok := obj.(Marshaler); ok { + return mar.MarshalBinary() + } + val := reflect.ValueOf(obj) + switch val.Kind() { + case reflect.Ptr: + return Marshal(val.Elem().Interface()) + case reflect.Array: + var ret []byte + for i := 0; i < val.Len(); i++ { + bs, err := Marshal(val.Index(i).Interface()) + ret = append(ret, bs...) + if err != nil { + return ret, err + } + } + return ret, nil + case reflect.Struct: + // TODO + default: + panic(fmt.Errorf("type=%v does not implement binfmt.Marshaler and kind=%v is not a supported statically-sized kind", + val.Type(), val.Kind())) + } +} diff --git a/pkg/binstruct/size.go b/pkg/binstruct/size.go new file mode 100644 index 0000000..519c2fe --- /dev/null +++ b/pkg/binstruct/size.go @@ -0,0 +1,36 @@ +package binstruct + +import ( + "fmt" + "reflect" +) + +type StaticSizer interface { + BinaryStaticSize() int +} + +func StaticSize(obj any) int { + return staticSize(reflect.TypeOf(obj)) +} + +var staticSizerType = reflect.TypeOf((*StaticSizer)(nil)).Elem() + +func staticSize(typ reflect.Type) int { + if typ.Implements(staticSizerType) { + return reflect.New(typ).Elem().Interface().(StaticSizer).BinaryStaticSize() + } + if szer, ok := obj.(StaticSizer); ok { + return szer.BinaryStaticSize() + } + switch typ.Kind() { + case reflect.Ptr: + return StaticSize(typ.Elem()) + case reflect.Array: + return StaticSize(typ.Elem()) * typ.Len() + case reflect.Struct: + // TODO + default: + panic(fmt.Errorf("type=%v does not implement binfmt.StaticSizer and kind=%v is not a supported statically-sized kind", + typ, typ.Kind())) + } +} diff --git a/pkg/binstruct/structs.go b/pkg/binstruct/structs.go new file mode 100644 index 0000000..6f971d5 --- /dev/null +++ b/pkg/binstruct/structs.go @@ -0,0 +1,11 @@ +package binstruct + +import ( + "reflect" +) + +type structHandler struct { +} + +func getStructHandler(typ reflect.Type) structHandler { +} diff --git a/pkg/binstruct/unmarshal.go b/pkg/binstruct/unmarshal.go new file mode 100644 index 0000000..4810d78 --- /dev/null +++ b/pkg/binstruct/unmarshal.go @@ -0,0 +1,44 @@ +package binstruct + +import ( + "fmt" + "reflect" +) + +type Unmarshaler interface { + UnmarshalBinary([]byte) (int, error) +} + +func Unmarshal(dat []byte, dstPtr any) (int, error) { + if unmar, ok := dstPtr.(Unmarshaler); ok { + return unmar.UnmarshalBinary(dat) + } + _dstPtr := reflect.ValueOf(dstPtr) + if _dstPtr.Kind() != reflect.Ptr { + return 0, fmt.Errorf("not a pointer: %v", _dstPtr.Type()) + } + dst := _dstPtr.Elem() + + switch dst.Kind() { + case reflect.Ptr: + elemPtr := reflect.New(dst.Type().Elem()).Interface() + n, err := Unmarshal(dat, elemPtr) + dst.Set(elemPtr.Convert(dst.Type())) + return n, err + case reflect.Array: + var n int + for i := 0; i < dst.Len(); i++ { + _n, err := Unmarshal(dat[n:], dst.Index(i).Addr().Interface()) + n += _n + if err != nil { + return n, err + } + } + return n, nil + case reflect.Struct: + // TODO + default: + panic(fmt.Errorf("type=%v does not implement binfmt.Unmarshaler and kind=%v is not a supported statically-sized kind", + val.Type(), val.Kind())) + } +} -- cgit v1.2.3-2-g168b