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) }