ssob/decoder.go

98 lines
1.9 KiB
Go

package ssob
import (
"encoding/binary"
"errors"
"fmt"
"io"
"reflect"
"sync"
"gitea.olznet.de/OlzNet/slog"
)
type Decoder struct {
mutex sync.Mutex
r io.Reader
}
func NewDecoder(r io.Reader) *Decoder {
dec := new(Decoder)
dec.r = r
return dec
}
func (dec *Decoder) Decode(e interface{}) (err error) {
t := reflect.TypeOf(e)
slog.LOG_DEBUGFLN("Dec: %v", t)
if t == reflect.TypeOf(errors.New("")) || t == reflect.TypeOf((*error)(nil)) {
var errstr string
if err = dec.Decode(&errstr); err != nil {
return err
}
if errstr != "" {
*e.(*error) = errors.New(errstr)
}
return nil
}
return dec.DecodeValue(reflect.ValueOf(e))
}
func (dec *Decoder) DecodeValue(value reflect.Value) (err error) {
if value.Kind() == reflect.Invalid {
return fmt.Errorf("ssob: Cannot decode nil: %w", ErrValueInvalid)
}
if value.Kind() == reflect.Ptr && value.IsNil() {
return fmt.Errorf("ssob: Cannot decode nil of type %s: %w", value.Type().String(), ErrValueInvalid)
}
dec.mutex.Lock()
defer dec.mutex.Unlock()
lb := make([]byte, 4)
err = binary.Read(dec.r, binary.BigEndian, lb)
if err != nil {
return err
}
l, n, err := UnmarshalInt32(lb)
if err != nil || n != 4 {
return err
}
bb := make([]byte, l)
err = binary.Read(dec.r, binary.BigEndian, bb)
if err != nil {
return err
}
_, err = unmarshal(value.Interface(), bb)
return err
}
func (dec *Decoder) NDecode() (ret interface{}, err error) {
st := make([]byte, ST_ID_SIZE)
dec.mutex.Lock()
defer dec.mutex.Unlock()
if err = binary.Read(dec.r, binary.BigEndian, st); err != nil {
return nil, err
}
l := binary.BigEndian.Uint32(st)
b := make([]byte, l)
var rl int
if rl, err = dec.r.Read(b); err != nil || rl != int(l) {
return nil, fmt.Errorf("ssob: Cannot decode value: %w", err)
}
_, ret, err = unmarshalVal(b)
if err != nil {
return ret, err
}
return getVal(ret).Interface(), err
}