ssob/unmarshal.go

357 lines
9.0 KiB
Go
Raw Normal View History

2019-10-04 12:28:45 +02:00
package ssob
import (
"encoding/binary"
"errors"
"reflect"
)
func UnmarshalString(in []byte) (ret string, n int, err error) {
if len(in) < 4 {
2019-10-04 12:28:45 +02:00
return "", 0, errors.New("ssob: Invalid input to decode string")
}
l := int32(binary.BigEndian.Uint32(in))
2019-10-04 12:28:45 +02:00
if len(in[4:]) < int(l) {
2019-10-04 12:28:45 +02:00
return "", 0, errors.New("ssob: Invalid length of string")
}
return string(in[4 : l+4]), int(l) + 4, nil
2019-10-04 12:28:45 +02:00
}
func UnmarshalInt8(in []byte) (ret int8, n int, err error) {
2019-10-04 12:28:45 +02:00
if len(in) < 1 {
return 0, 0, errors.New("ssob: Invalid input to decode int8")
}
return int8(in[0]), 1, nil
}
func UnmarshalUint8(in []byte) (ret uint8, n int, err error) {
2019-10-04 12:28:45 +02:00
if len(in) < 1 {
return 0, 0, errors.New("ssob: Invalid input to decode uint8")
}
return uint8(in[0]), 1, nil
}
func UnmarshalInt16(in []byte) (ret int16, n int, err error) {
2019-10-04 12:28:45 +02:00
if len(in) < 2 {
return 0, 0, errors.New("ssob: Invalid input to decode int16")
}
return int16(binary.BigEndian.Uint16(in[0:2])), 2, nil
}
func UnmarshalUint16(in []byte) (ret uint16, n int, err error) {
2019-10-04 12:28:45 +02:00
if len(in) < 2 {
return 0, 0, errors.New("ssob: Invalid input to decode uint16")
}
return binary.BigEndian.Uint16(in[0:1]), 2, nil
}
func UnmarshalInt32(in []byte) (ret int32, n int, err error) {
2019-10-04 12:28:45 +02:00
if len(in) < 4 {
return 0, 0, errors.New("ssob: Invalid input to decode int32")
}
return int32(binary.BigEndian.Uint32(in[0:4])), 4, nil
}
func UnmarshalUint32(in []byte) (ret uint32, n int, err error) {
2019-10-04 12:28:45 +02:00
if len(in) < 4 {
return 0, 0, errors.New("ssob: Invalid input to decode uint32")
}
return binary.BigEndian.Uint32(in[0:4]), 4, nil
}
func UnmarshalFloat32(in []byte) (ret float32, n int, err error) {
2019-10-04 12:28:45 +02:00
if len(in) < 4 {
return 0, 0, errors.New("ssob: Invalid input to decode float32")
}
return float32(binary.BigEndian.Uint64(in[0:4])), 4, nil
}
func UnmarshalInt64(in []byte) (ret int64, n int, err error) {
2019-10-04 12:28:45 +02:00
if len(in) < 8 {
return 0, 0, errors.New("ssob: Invalid input to decode int64")
}
return int64(binary.BigEndian.Uint64(in[0:8])), 8, nil
}
func UnmarshalUint64(in []byte) (ret uint64, n int, err error) {
2019-10-04 12:28:45 +02:00
if len(in) < 8 {
return 0, 0, errors.New("ssob: Invalid input to decode uint64")
}
return binary.BigEndian.Uint64(in[0:8]), 8, nil
}
func UnmarshalFloat64(in []byte) (ret float64, n int, err error) {
2019-10-04 12:28:45 +02:00
if len(in) < 8 {
return 0, 0, errors.New("ssob: Invalid input to decode float64")
}
return float64(binary.BigEndian.Uint64(in[0:8])), 8, nil
}
type unmarshalFunc func(e interface{}, in []byte) (n int, err error)
var decoderCache map[string]unmarshalFunc
func init() {
decoderCache = make(map[string]unmarshalFunc)
RegisterDecoder("int8", func(e interface{}, in []byte) (n int, err error) {
if i, ok := e.(*int8); ok {
*i, n, err = UnmarshalInt8(in)
return n, nil
}
return 0, errors.New("ssob: Incompatible type - expected int8")
})
RegisterDecoder("uint8", func(e interface{}, in []byte) (n int, err error) {
if i, ok := e.(*uint8); ok {
*i, n, err = UnmarshalUint8(in)
return n, nil
}
return 0, errors.New("ssob: Incompatible type - expected uint8")
})
RegisterDecoder("int16", func(e interface{}, in []byte) (n int, err error) {
if i, ok := e.(*int16); ok {
*i, n, err = UnmarshalInt16(in)
return n, nil
}
return 0, errors.New("ssob: Incompatible type - expected int16")
})
RegisterDecoder("uint16", func(e interface{}, in []byte) (n int, err error) {
if i, ok := e.(*uint16); ok {
*i, n, err = UnmarshalUint16(in)
return n, nil
}
return 0, errors.New("ssob: Incompatible type - expected uint16")
})
RegisterDecoder("int32", func(e interface{}, in []byte) (n int, err error) {
if i, ok := e.(*int32); ok {
*i, n, err = UnmarshalInt32(in)
return n, nil
}
return 0, errors.New("ssob: Incompatible type - expected int32")
})
RegisterDecoder("uint32", func(e interface{}, in []byte) (n int, err error) {
if i, ok := e.(*uint32); ok {
*i, n, err = UnmarshalUint32(in)
return n, nil
}
return 0, errors.New("ssob: Incompatible type - expected uint32")
})
RegisterDecoder("float32", func(e interface{}, in []byte) (n int, err error) {
if i, ok := e.(*float32); ok {
*i, n, err = UnmarshalFloat32(in)
return n, nil
}
return 0, errors.New("ssob: Incompatible type - expected float32")
})
RegisterDecoder("int64", func(e interface{}, in []byte) (n int, err error) {
if i, ok := e.(*int64); ok {
*i, n, err = UnmarshalInt64(in)
return n, nil
}
return 0, errors.New("ssob: Incompatible type - expected int64")
})
RegisterDecoder("uint64", func(e interface{}, in []byte) (n int, err error) {
if i, ok := e.(*uint64); ok {
*i, n, err = UnmarshalUint64(in)
return n, nil
}
return 0, errors.New("ssob: Incompatible type - expected uint64")
})
RegisterDecoder("float64", func(e interface{}, in []byte) (n int, err error) {
if i, ok := e.(*float64); ok {
*i, n, err = UnmarshalFloat64(in)
return n, nil
}
return 0, errors.New("ssob: Incompatible type - expected float64")
})
RegisterDecoder("string", func(e interface{}, in []byte) (n int, err error) {
if i, ok := e.(*string); ok {
*i, n, err = UnmarshalString(in)
return n, nil
}
return 0, errors.New("ssob: Incompatible type - expected string")
})
2019-10-04 12:28:45 +02:00
}
func decRegister(e interface{}) (err error) {
t := reflect.TypeOf(e)
v := reflect.ValueOf(e)
switch t.Kind() {
case reflect.Invalid:
return errors.New("ssob: Invalid type")
case reflect.Slice:
f := func(e interface{}, in []byte) (n int, err error) {
t := reflect.TypeOf(e)
v := reflect.ValueOf(e)
pos := 0
if t.Kind() != reflect.Ptr || v.IsNil() {
return 0, errors.New("ssob: Cannot unmarshal to nil pointer")
}
l, r, err := UnmarshalInt32(in)
pos += r
if err != nil {
return pos, err
}
ti := v.Elem()
ti.Set(reflect.MakeSlice(reflect.TypeOf(ti.Interface()), 0, ti.Cap()))
for i := 0; i < int(l); i++ {
e := reflect.New(reflect.TypeOf(ti.Interface()).Elem())
r, err := unmarshal(e.Interface(), in[pos:])
pos += r
if err != nil {
return pos, err
}
ti.Set(reflect.Append(ti, reflect.Indirect(e)))
}
return pos, nil
}
decoderCache[string(t.Kind())] = f
2019-10-04 12:28:45 +02:00
case reflect.Struct:
f := func(e interface{}, in []byte) (n int, err error) {
t := reflect.TypeOf(e)
v := reflect.ValueOf(e)
pos := 0
if t.Kind() != reflect.Ptr || v.IsNil() {
return 0, errors.New("ssob: Cannot unmarshal to nil pointer")
}
vi := reflect.Indirect(v)
l := vi.NumField()
for i := 0; i < l; i++ {
ni, err := unmarshal(vi.Field(i).Addr().Interface(), in[pos:])
pos += ni
if err != nil {
return pos, err
}
}
return pos, nil
}
decoderCache[t.Name()] = f
case reflect.Map:
2019-10-05 13:40:18 +02:00
f := func(e interface{}, in []byte) (n int, err error) {
t := reflect.TypeOf(e)
v := reflect.ValueOf(e)
pos := 0
2019-10-05 13:40:18 +02:00
if t.Kind() != reflect.Ptr || v.IsNil() {
return 0, errors.New("ssob: Cannot unmarshal to nil pointer")
}
l, r, err := UnmarshalInt32(in)
pos += r
if err != nil {
return pos, err
}
2019-10-05 13:40:18 +02:00
vi := reflect.Indirect(v)
vt := reflect.TypeOf(vi.Interface())
tk := vt.Key()
tv := vt.Elem()
for i := int32(0); i < l; i++ {
ek := reflect.New(tk)
ev := reflect.New(tv)
r, err := unmarshal(ek.Interface(), in[pos:])
pos += r
if err != nil {
return pos, err
}
r, err = unmarshal(ev.Interface(), in[pos:])
pos += r
if err != nil {
return pos, err
}
vi.SetMapIndex(reflect.Indirect(ek), reflect.Indirect(ev))
}
2019-10-05 13:40:18 +02:00
return pos, nil
}
decoderCache[string(t.Kind())] = f
2019-10-04 12:28:45 +02:00
default:
return errors.New("ssob: Unknown type " + string(v.Kind()))
}
return nil
}
func unmarshalBaseType(e interface{}, in []byte) (n int, err error) {
switch t := e.(type) {
case *int8:
return decoderCache["int8"](t, in)
case *uint8:
return decoderCache["uint8"](t, in)
case *int16:
return decoderCache["int16"](t, in)
case *uint16:
return decoderCache["uint16"](t, in)
case *int32:
return decoderCache["int32"](t, in)
case *uint32:
return decoderCache["uint32"](t, in)
case *int64:
return decoderCache["int64"](t, in)
case *uint64:
return decoderCache["uint64"](t, in)
case *float32:
return decoderCache["float32"](t, in)
case *float64:
return decoderCache["float64"](t, in)
case *string:
return decoderCache["string"](t, in)
default:
return 0, errors.New("ssob: No base type")
}
}
2019-10-04 12:28:45 +02:00
func unmarshal(e interface{}, in []byte) (n int, err error) {
n, err = unmarshalBaseType(e, in)
if err == nil {
return n, err
}
2019-10-04 12:28:45 +02:00
var key string
t := reflect.TypeOf(e)
v := reflect.ValueOf(e)
if t.Kind() != reflect.Ptr || v.IsNil() {
return 0, errors.New("ssob: Need a pointer that is fully allocated for unmarshalling")
}
p := reflect.Indirect(v)
if p.Kind() != reflect.Ptr {
if p.Kind() == reflect.Struct {
key = reflect.TypeOf(p.Interface()).Name()
} else {
key = string(p.Kind())
}
if f, ok := decoderCache[key]; ok {
return f(v.Interface(), in)
} else {
err = decRegister(p.Interface())
if err != nil {
return 0, err
}
}
}
return unmarshal(e, in)
}
func RegisterDecoder(name string, f func(e interface{}, in []byte) (n int, err error)) {
decoderCache[name] = f
}