package ssob import ( "encoding/binary" "fmt" "math" "reflect" ) func UnmarshalString(in []byte) (ret string, n int, err error) { if len(in) < 4 { return "", 0, fmt.Errorf("ssob: Decoding string: %w", ErrTypeInvalid) } l := int32(binary.BigEndian.Uint32(in)) if len(in[4:]) < int(l) { return "", 0, fmt.Errorf("ssob: Invalid length of string: %w", ErrValueInvalid) } return string(in[4 : l+4]), int(l) + 4, nil } func UnmarshalBool(in []byte) (ret bool, n int, err error) { if len(in) < 1 { return false, 0, fmt.Errorf("ssob: Decoding bool: %w", ErrTypeInvalid) } if in[0] == byte(0) { return true, 1, nil } return false, 1, nil } func UnmarshalInt8(in []byte) (ret int8, n int, err error) { if len(in) < 1 { return 0, 0, fmt.Errorf("ssob: Decoding int8: %w", ErrTypeInvalid) } return int8(in[0]), 1, nil } func UnmarshalUint8(in []byte) (ret uint8, n int, err error) { if len(in) < 1 { return 0, 0, fmt.Errorf("ssob: Decoding uint8: %w", ErrTypeInvalid) } return uint8(in[0]), 1, nil } func UnmarshalInt16(in []byte) (ret int16, n int, err error) { if len(in) < 2 { return 0, 0, fmt.Errorf("ssob: Decoding int16: %w", ErrTypeInvalid) } return int16(binary.BigEndian.Uint16(in[0:2])), 2, nil } func UnmarshalUint16(in []byte) (ret uint16, n int, err error) { if len(in) < 2 { return 0, 0, fmt.Errorf("ssob: Decoding uint16: %w", ErrTypeInvalid) } return binary.BigEndian.Uint16(in[0:2]), 2, nil } func UnmarshalInt32(in []byte) (ret int32, n int, err error) { if len(in) < 4 { return 0, 0, fmt.Errorf("ssob: Decoding int32: %w", ErrTypeInvalid) } return int32(binary.BigEndian.Uint32(in[0:4])), 4, nil } func UnmarshalUint32(in []byte) (ret uint32, n int, err error) { if len(in) < 4 { return 0, 0, fmt.Errorf("ssob: Decoding uint32: %w", ErrTypeInvalid) } return binary.BigEndian.Uint32(in[0:4]), 4, nil } func UnmarshalFloat32(in []byte) (ret float32, n int, err error) { if len(in) < 4 { return 0, 0, fmt.Errorf("ssob: Decoding float32: %w", ErrTypeInvalid) } return float32(math.Float32frombits(binary.BigEndian.Uint32(in[0:4]))), 4, nil } func UnmarshalInt64(in []byte) (ret int64, n int, err error) { if len(in) < 8 { return 0, 0, fmt.Errorf("ssob: Decoding int64: %w", ErrTypeInvalid) } return int64(binary.BigEndian.Uint64(in[0:8])), 8, nil } func UnmarshalUint64(in []byte) (ret uint64, n int, err error) { if len(in) < 8 { return 0, 0, fmt.Errorf("ssob: Decoding uint64: %w", ErrTypeInvalid) } return binary.BigEndian.Uint64(in[0:8]), 8, nil } func UnmarshalFloat64(in []byte) (ret float64, n int, err error) { if len(in) < 8 { return 0, 0, fmt.Errorf("ssob: Decoding float64: %w", ErrTypeInvalid) } return float64(math.Float64frombits(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("bool", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*bool); ok { *i, n, err = UnmarshalBool(in) return n, err } return 0, fmt.Errorf("ssob: Incompatible type - expected bool: %w", ErrTypeMismatch) }) RegisterDecoder("int8", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*int8); ok { *i, n, err = UnmarshalInt8(in) return n, err } return 0, fmt.Errorf("ssob: Incompatible type - expected int8: %w", ErrTypeMismatch) }) RegisterDecoder("uint8", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*uint8); ok { *i, n, err = UnmarshalUint8(in) return n, err } return 0, fmt.Errorf("ssob: Incompatible type - expected uint8: %w", ErrTypeMismatch) }) RegisterDecoder("int16", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*int16); ok { *i, n, err = UnmarshalInt16(in) return n, err } return 0, fmt.Errorf("ssob: Incompatible type - expected int16: %w", ErrTypeMismatch) }) RegisterDecoder("uint16", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*uint16); ok { *i, n, err = UnmarshalUint16(in) return n, err } return 0, fmt.Errorf("ssob: Incompatible type - expected uint16: %w", ErrTypeMismatch) }) RegisterDecoder("int32", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*int32); ok { *i, n, err = UnmarshalInt32(in) return n, err } return 0, fmt.Errorf("ssob: Incompatible type - expected int32: %w", ErrTypeMismatch) }) RegisterDecoder("uint32", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*uint32); ok { *i, n, err = UnmarshalUint32(in) return n, err } return 0, fmt.Errorf("ssob: Incompatible type - expected uint32: %w", ErrTypeMismatch) }) RegisterDecoder("float32", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*float32); ok { *i, n, err = UnmarshalFloat32(in) return n, err } return 0, fmt.Errorf("ssob: Incompatible type - expected float32: %w", ErrTypeMismatch) }) RegisterDecoder("int64", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*int64); ok { *i, n, err = UnmarshalInt64(in) return n, err } return 0, fmt.Errorf("ssob: Incompatible type - expected int64: %w", ErrTypeMismatch) }) RegisterDecoder("uint64", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*uint64); ok { *i, n, err = UnmarshalUint64(in) return n, err } return 0, fmt.Errorf("ssob: Incompatible type - expected uint64: %w", ErrTypeMismatch) }) RegisterDecoder("float64", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*float64); ok { *i, n, err = UnmarshalFloat64(in) return n, err } return 0, fmt.Errorf("ssob: Incompatible type - expected float64: %w", ErrTypeMismatch) }) RegisterDecoder("string", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*string); ok { *i, n, err = UnmarshalString(in) return n, err } return 0, fmt.Errorf("ssob: Incompatible type - expected string: %w", ErrTypeMismatch) }) } func decRegister(e interface{}) (err error) { t := reflect.TypeOf(e) if t == nil { return fmt.Errorf("ssob: nil type: %w", ErrTypeInvalid) } switch t.Kind() { case reflect.Invalid: return fmt.Errorf("ssob: invalid type: %w", ErrTypeInvalid) case reflect.Array: 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, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid) } l, r, err := UnmarshalInt32(in) pos += r if err != nil { return pos, err } ti := v.Elem() if int(l) != ti.Len() { return pos, fmt.Errorf("ssob: Invalid array length. Expected %s got %s: %w", string(l), string(ti.Len()), ErrValueInvalid) } 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.Index(i).Set(reflect.Indirect(e)) } return pos, nil } decoderCache[string(t.Kind())] = f 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, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid) } 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 case reflect.Struct: zt := reflect.New(t) n := zt.Elem().NumField() mfields := []int{} for i := 0; i < n; i++ { if zt.Elem().Field(i).CanSet() { mfields = append(mfields, i) } } if len(mfields) == 0 { return fmt.Errorf("ssob: No exported fields for %s: %w", string(t.Name()), ErrParseFailed) } 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, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid) } vi := reflect.Indirect(v) for _, i := range mfields { 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: 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, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid) } l, r, err := UnmarshalInt32(in) pos += r if err != nil { return pos, err } 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)) } return pos, nil } decoderCache[string(t.Kind())] = f case reflect.Bool: f := func(e interface{}, in []byte) (n int, err error) { v := reflect.ValueOf(e) i := bool(false) pos := 0 r, err := unmarshalBaseType(&i, in[pos:]) pos += r if err != nil { return pos, err } v.Elem().SetBool(bool(i)) return pos, nil } decoderCache[t.Name()] = f case reflect.Uint8: f := func(e interface{}, in []byte) (n int, err error) { v := reflect.ValueOf(e) i := uint8(0) pos := 0 r, err := unmarshalBaseType(&i, in[pos:]) pos += r if err != nil { return pos, err } v.Elem().SetUint(uint64(i)) return pos, nil } decoderCache[t.Name()] = f case reflect.Uint16: f := func(e interface{}, in []byte) (n int, err error) { v := reflect.ValueOf(e) i := uint16(0) pos := 0 r, err := unmarshalBaseType(&i, in[pos:]) pos += r if err != nil { return pos, err } v.Elem().SetUint(uint64(i)) return pos, nil } decoderCache[t.Name()] = f case reflect.Uint32: f := func(e interface{}, in []byte) (n int, err error) { v := reflect.ValueOf(e) i := uint32(0) pos := 0 r, err := unmarshalBaseType(&i, in[pos:]) pos += r if err != nil { return pos, err } v.Elem().SetUint(uint64(i)) return pos, nil } decoderCache[t.Name()] = f case reflect.Uint64: f := func(e interface{}, in []byte) (n int, err error) { v := reflect.ValueOf(e) i := uint64(0) pos := 0 r, err := unmarshalBaseType(&i, in[pos:]) pos += r if err != nil { return pos, err } v.Elem().SetUint(uint64(i)) return pos, nil } decoderCache[t.Name()] = f case reflect.Int8: f := func(e interface{}, in []byte) (n int, err error) { v := reflect.ValueOf(e) i := int8(0) pos := 0 r, err := unmarshalBaseType(&i, in[pos:]) pos += r if err != nil { return pos, err } v.Elem().SetInt(int64(i)) return pos, nil } decoderCache[t.Name()] = f case reflect.Int16: f := func(e interface{}, in []byte) (n int, err error) { v := reflect.ValueOf(e) i := int16(0) pos := 0 r, err := unmarshalBaseType(&i, in[pos:]) pos += r if err != nil { return pos, err } v.Elem().SetInt(int64(i)) return pos, nil } decoderCache[t.Name()] = f case reflect.Int32: f := func(e interface{}, in []byte) (n int, err error) { v := reflect.ValueOf(e) i := int32(0) pos := 0 r, err := unmarshalBaseType(&i, in[pos:]) pos += r if err != nil { return pos, err } v.Elem().SetInt(int64(i)) return pos, nil } decoderCache[t.Name()] = f case reflect.Int64: f := func(e interface{}, in []byte) (n int, err error) { v := reflect.ValueOf(e) i := int64(0) pos := 0 r, err := unmarshalBaseType(&i, in[pos:]) pos += r if err != nil { return pos, err } v.Elem().SetInt(int64(i)) return pos, nil } decoderCache[t.Name()] = f case reflect.String: f := func(e interface{}, in []byte) (n int, err error) { v := reflect.ValueOf(e) i := string("") pos := 0 r, err := unmarshalBaseType(&i, in[pos:]) pos += r if err != nil { return pos, err } v.Elem().SetString(i) return pos, nil } decoderCache[t.Name()] = f default: return fmt.Errorf("ssob: %s: %w", string(t.Name()), ErrTypeUnknown) } return nil } func unmarshalBaseType(e interface{}, in []byte) (n int, err error) { switch t := e.(type) { case *bool: return decoderCache["bool"](t, in) 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, fmt.Errorf("ssob: No base type: %w", ErrTypeUnknown) } } func unmarshal(e interface{}, in []byte) (n int, err error) { n, err = unmarshalBaseType(e, in) if err == nil { return n, err } var key string t := reflect.TypeOf(e) v := reflect.ValueOf(e) if !v.IsValid() || t.Kind() != reflect.Ptr || v.IsNil() { return 0, fmt.Errorf("ssob: Need a pointer that is fully allocated for unmarshalling: %w", ErrValueInvalid) } p := reflect.Indirect(v) if p.Kind() != reflect.Ptr && p.Kind() != reflect.Interface { switch p.Kind() { case reflect.Bool, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.String, reflect.Struct: key = reflect.TypeOf(p.Interface()).Name() default: 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) } } if !p.Elem().IsValid() { err = allocType(v) if err != nil { return 0, err } p = reflect.Indirect(v) } return unmarshal(p.Interface(), in) } func RegisterDecoder(name string, f func(e interface{}, in []byte) (n int, err error)) { decoderCache[name] = f }