summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2022-05-30 12:00:39 -0400
committerLuke Shumaker <lukeshu@lukeshu.com>2022-05-30 12:00:39 -0400
commit8576e5f207f9d3b7c6324ed71a3ca6a005f9ae7c (patch)
tree1ff3001f73011a96aa603ec2eda7d29ce4885d47 /pkg
parent04d6677e52352a7e3ec791e3e817cfe3865e7d6d (diff)
ahhhh
Diffstat (limited to 'pkg')
-rw-r--r--pkg/binstruct/builtins.go241
-rw-r--r--pkg/binstruct/l1.go6
-rw-r--r--pkg/binstruct/l2.go3
-rw-r--r--pkg/binstruct/l3.go3
-rw-r--r--pkg/binstruct/marshal.go36
-rw-r--r--pkg/binstruct/size.go36
-rw-r--r--pkg/binstruct/structs.go11
-rw-r--r--pkg/binstruct/unmarshal.go44
8 files changed, 377 insertions, 3 deletions
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()))
+ }
+}