ssob/unmarshal.go

458 lines
9.1 KiB
Go

package ssob
import (
"encoding/binary"
"fmt"
"math"
"reflect"
"gitea.olznet.de/OlzNet/slog"
)
func unmarshalBool(e []byte) (ie []byte, ret bool, err error) {
if len(e) < 1 {
return e, ret, ErrValueInvalid
}
if e[0] == 0 {
ret = true
} else {
ret = false
}
return e[1:], ret, err
}
func unmarshalUint8(e []byte) (ie []byte, ret uint8, err error) {
if len(e) < 1 {
return e, ret, ErrValueInvalid
}
return e[1:], uint8(byte(e[0])), err
}
func unmarshalUint16(e []byte) (ie []byte, ret uint16, err error) {
if len(e) < 2 {
return e, ret, ErrValueInvalid
}
return e[2:], binary.BigEndian.Uint16(e), err
}
func unmarshalUint32(e []byte) (ie []byte, ret uint32, err error) {
if len(e) < 4 {
return e, ret, ErrValueInvalid
}
return e[4:], binary.BigEndian.Uint32(e), err
}
func unmarshalUint64(e []byte) (ie []byte, ret uint64, err error) {
if len(e) < 8 {
return e, ret, ErrValueInvalid
}
return e[8:], binary.BigEndian.Uint64(e), err
}
func unmarshalInt8(e []byte) (ie []byte, ret int8, err error) {
if len(e) < 1 {
return e, ret, ErrValueInvalid
}
return e[1:], int8(byte(e[0])), err
}
func unmarshalInt16(e []byte) (ie []byte, ret int16, err error) {
if len(e) < 2 {
return e, ret, ErrValueInvalid
}
return e[2:], int16(binary.BigEndian.Uint16(e)), err
}
func unmarshalInt32(e []byte) (ie []byte, ret int32, err error) {
if len(e) < 4 {
return e, ret, ErrValueInvalid
}
return e[4:], int32(binary.BigEndian.Uint32(e)), err
}
func unmarshalInt64(e []byte) (ie []byte, ret int64, err error) {
if len(e) < 4 {
return e, ret, ErrValueInvalid
}
return e[8:], int64(binary.BigEndian.Uint64(e)), err
}
func unmarshalFloat32(e []byte) (ie []byte, ret float32, err error) {
if len(e) < 4 {
return e, ret, ErrValueInvalid
}
return e[4:], float32(math.Float32frombits(binary.BigEndian.Uint32(e))), err
}
func unmarshalFloat64(e []byte) (ie []byte, ret float64, err error) {
if len(e) < 8 {
return e, ret, ErrValueInvalid
}
return e[8:], float64(math.Float64frombits(binary.BigEndian.Uint64(e))), err
}
func unmarshalString(e []byte) (ie []byte, ret string, err error) {
ie = e
if len(ie) < 4 {
return ie, ret, ErrValueInvalid
}
slen := binary.BigEndian.Uint32(e)
ie = ie[4:]
if len(ie) < int(slen) {
return ie, ret, ErrValueInvalid
}
ret = string(ie[:slen])
ie = ie[slen:]
return ie, ret, err
}
func unmarshalNil(e []byte) (ie []byte, ret uint16, err error) {
return unmarshalUint16(e)
}
func unmarshalPtrIfNil(e []byte, ntype *NType) (ie []byte, ret interface{}, isNil bool, err error) {
if ntype.Indirection == 0 {
return e, nil, false, err
}
ret = ntype.alloc()
var nl uint16
ie, eId, err := unmarshalTypeId(e)
if err != nil {
return ie, ret, isNil, err
}
if eId == ST_NIL {
ie, nl, err = unmarshalNil(ie)
if err != nil {
return ie, ret, isNil, err
}
err = setTypeNil(ret, int(nl))
return ie, ret, true, err
}
if ntype.ValType == ST_ERROR {
return e, ret, false, err
}
if eId != ntype.ValType {
return ie, ret, false, ErrTypeInvalid
}
return ie, ret, false, err
}
func unmarshalError(e []byte, ntype *NType) (ie []byte, ret interface{}, err error) {
ret = ntype.alloc()
var nl uint16
ie, eId, err := unmarshalTypeId(e)
if err != nil {
return ie, ret, err
}
if eId == ST_NIL {
ie, nl, err = unmarshalNil(ie)
if err != nil {
return ie, ret, err
}
err = setTypeNil(ret, int(nl))
return ie, ret, err
}
if eId != ST_STRING {
return ie, ret, ErrTypeInvalid
}
ie, v, err := unmarshalString(ie)
if err != nil {
return ie, ret, err
}
err = setTypeVal(ret, fmt.Errorf(v), ntype)
return ie, ret, err
}
func unmarshalTypeId(e []byte) (ie []byte, ret uint32, err error) {
return unmarshalUint32(e)
}
func unmarshalCommon(e []byte, ntype *NType) (ie []byte, ret interface{}, err error) {
ctype := getTypeById(ntype.ValType)
if ctype == nil {
return e, ret, ErrTypeUnknown
}
// pointer could be nil
ie, ptrNil, isNil, err := unmarshalPtrIfNil(e, ntype)
if err != nil {
return ie, ret, err
}
if ptrNil != nil {
if isNil {
return ie, ptrNil, err
}
ret = ptrNil
}
if ret == nil {
ret = ntype.alloc()
}
switch ctype.Id {
case ST_BOOL:
var v bool
ie, v, err = unmarshalBool(ie)
if err != nil {
return ie, ret, err
}
setTypeVal(ret, v, ntype)
return ie, ret, err
case ST_UINT8:
var v uint8
ie, v, err = unmarshalUint8(ie)
if err != nil {
return ie, ret, err
}
setTypeVal(ret, v, ntype)
return ie, ret, err
case ST_UINT16:
var v uint16
ie, v, err = unmarshalUint16(ie)
if err != nil {
return ie, ret, err
}
setTypeVal(ret, v, ntype)
return ie, ret, err
case ST_UINT32:
var v uint32
ie, v, err = unmarshalUint32(ie)
if err != nil {
return ie, ret, err
}
setTypeVal(ret, v, ntype)
return ie, ret, err
case ST_UINT64:
var v uint64
ie, v, err = unmarshalUint64(ie)
if err != nil {
return ie, ret, err
}
setTypeVal(ret, v, ntype)
return ie, ret, err
case ST_INT8:
var v int8
ie, v, err = unmarshalInt8(ie)
if err != nil {
return ie, ret, err
}
setTypeVal(ret, v, ntype)
return ie, ret, err
case ST_INT16:
var v int16
ie, v, err = unmarshalInt16(ie)
if err != nil {
return ie, ret, err
}
setTypeVal(ret, v, ntype)
return ie, ret, err
case ST_INT32:
var v int32
ie, v, err = unmarshalInt32(ie)
if err != nil {
return ie, ret, err
}
setTypeVal(ret, v, ntype)
return ie, ret, err
case ST_INT64:
var v int64
ie, v, err = unmarshalInt64(ie)
if err != nil {
return ie, ret, err
}
setTypeVal(ret, v, ntype)
return ie, ret, err
case ST_FLOAT32:
var v float32
ie, v, err = unmarshalFloat32(ie)
if err != nil {
return ie, ret, err
}
setTypeVal(ret, v, ntype)
return ie, ret, err
case ST_FLOAT64:
var v float64
ie, v, err = unmarshalFloat64(ie)
if err != nil {
return ie, ret, err
}
setTypeVal(ret, v, ntype)
return ie, ret, err
case ST_STRING:
var v string
ie, v, err = unmarshalString(ie)
if err != nil {
return ie, ret, err
}
setTypeVal(ret, v, ntype)
return ie, ret, err
case ST_ERROR:
return unmarshalError(ie, ntype)
default:
return ie, ret, ErrTypeUnknown
}
}
func unmarshalSlice(e []byte, ntype *NType) (ie []byte, ret interface{}, err error) {
ret = ntype.alloc()
rv := getVal(ret)
rv = traverseValuePtr(rv)
ie, l, err := unmarshalUint32(e)
if err != nil {
return ie, ret, err
}
stype := getTypeById(ntype.ValType)
if stype == nil {
return ie, ret, ErrTypeUnknown
}
var v interface{}
for i := 0; i < int(l); i++ {
ie, v, err = unmarshalType(ie, stype)
if err != nil {
return ie, ret, err
}
// TODO: checks?
rv.Set(reflect.Append(rv, getVal(v)))
}
return ie, ret, err
}
func unmarshalArray(e []byte, ntype *NType) (ie []byte, ret interface{}, err error) {
ret = ntype.alloc()
rv := getVal(ret)
rv = traverseValuePtr(rv)
stype := getTypeById(ntype.ValType)
if stype == nil {
return ie, ret, ErrTypeUnknown
}
var v interface{}
ie = e
for i := 0; i < ntype.arrayLen; i++ {
ie, v, err = unmarshalType(ie, stype)
if err != nil {
return ie, ret, err
}
// TODO: checks?
rv.Index(i).Set(getVal(v))
}
return ie, ret, err
}
func unmarshalStruct(e []byte, ntype *NType) (ie []byte, ret interface{}, err error) {
ret = ntype.alloc()
rv := getVal(ret)
rv = traverseValuePtr(rv)
ie = e
stype := getTypeById(ntype.ValType)
if stype == nil {
return ie, ret, ErrTypeUnknown
}
var v interface{}
for i, field := range stype.structFields {
if field.SId > rv.NumField() {
return ie, ret, ErrTypeInvalid
}
if rv.Field(field.SId).CanSet() {
ftype := getTypeById(field.Id)
if ftype == nil {
return ie, ret, ErrTypeUnknown
}
ie, v, err = unmarshalType(ie, ftype)
if err != nil {
return ie, ret, err
}
// TODO: checks?
slog.LOG_DEBUGFLN("v: %v", reflect.TypeOf(v))
rv.Field(i).Set(getVal(v))
}
}
return ie, ret, err
}
func unmarshalInterface(e []byte, ntype *NType) (ie []byte, ret interface{}, err error) {
return unmarshalVal(e)
}
func unmarshalType(e []byte, ntype *NType) (ie []byte, ret interface{}, err error) {
switch ntype.MainTypeId {
case ST_COMMON:
return unmarshalCommon(e, ntype)
case ST_SLICE:
return unmarshalSlice(e, ntype)
case ST_ARRAY:
return unmarshalArray(e, ntype)
case ST_STRUCT:
return unmarshalStruct(e, ntype)
case ST_INTERFACE:
return unmarshalInterface(e, ntype)
default:
return e, ret, ErrTypeUnknown
}
}
func unmarshalVal(e []byte) (ie []byte, ret interface{}, err error) {
if len(e) < ST_ID_SIZE {
return ie, ret, ErrValueInvalid
}
// type id
var tid uint32
ie, tid, err = unmarshalTypeId(e)
if err != nil {
return ie, ret, err
}
vt := getTypeById(tid)
if vt == nil {
return ie, ret, ErrTypeUnknown
}
// alloc
ret = vt.alloc()
// check for nil
if len(ie) < 1 {
return ie, ret, ErrValueInvalid
}
ie, isNil, err := unmarshalBool(ie)
if err != nil {
return ie, ret, err
}
if isNil {
if len(ie) < 2 {
return ie, ret, ErrValueInvalid
}
ie, nl, err := unmarshalNil(ie)
if err != nil {
return ie, ret, err
}
if int(nl) > vt.Indirection {
return ie, ret, ErrValueInvalid
}
err = setTypeNil(ret, int(nl))
return ie, ret, err
}
return unmarshalType(ie, vt)
}