diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2022-07-10 13:18:30 -0600 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2022-07-10 13:35:20 -0600 |
commit | 27401b6ea459921a6152ab1744da1618358465f4 (patch) | |
tree | 2c4f9c096f1a593e65d7f824901e815ca48bfaf0 /lib/binstruct/unmarshal.go | |
parent | 42f6f78e0a32ba0eda707154f8e1ffb4579604ee (diff) |
Rename the module, mv pkg lib
Diffstat (limited to 'lib/binstruct/unmarshal.go')
-rw-r--r-- | lib/binstruct/unmarshal.go | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/lib/binstruct/unmarshal.go b/lib/binstruct/unmarshal.go new file mode 100644 index 0000000..1959d45 --- /dev/null +++ b/lib/binstruct/unmarshal.go @@ -0,0 +1,54 @@ +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) + } + return UnmarshalWithoutInterface(dat, dstPtr) +} + +func UnmarshalWithoutInterface(dat []byte, dstPtr any) (int, error) { + _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.Uint8, reflect.Int8, reflect.Uint16, reflect.Int16, reflect.Uint32, reflect.Int32, reflect.Uint64, reflect.Int64: + typ := intKind2Type[dst.Kind()] + newDstPtr := reflect.New(typ) + n, err := Unmarshal(dat, newDstPtr.Interface()) + dst.Set(newDstPtr.Elem().Convert(dst.Type())) + return n, err + case reflect.Ptr: + elemPtr := reflect.New(dst.Type().Elem()) + n, err := Unmarshal(dat, elemPtr.Interface()) + 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: + return getStructHandler(dst.Type()).Unmarshal(dat, dst) + default: + panic(fmt.Errorf("type=%v does not implement binfmt.Unmarshaler and kind=%v is not a supported statically-sized kind", + dst.Type(), dst.Kind())) + } +} |