From 8576e5f207f9d3b7c6324ed71a3ca6a005f9ae7c Mon Sep 17 00:00:00 2001
From: Luke Shumaker <lukeshu@lukeshu.com>
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/binstruct')

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