ssob/decoder.go

69 lines
1.3 KiB
Go

package ssob
import (
"encoding/binary"
"errors"
"fmt"
"io"
"reflect"
"sync"
)
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) {
return dec.DecodeValue(reflect.ValueOf(e))
}
func (dec *Decoder) DecodeValue(value reflect.Value) (err error) {
if value.Type() == reflect.TypeOf(errors.New("")) || value.Type() == reflect.TypeOf((*error)(nil)) {
var errstr string
if err = dec.Decode(&errstr); err != nil {
return err
}
if errstr != "" {
*value.Interface().(*error) = errors.New(errstr)
}
return nil
}
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
}