You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
228 lines
5.2 KiB
228 lines
5.2 KiB
package serialize
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"github.com/dtapps/go-library/utils/gostring"
|
|
"strconv"
|
|
)
|
|
|
|
const UnserializableObjectMaxLen = int64(10 * 1024 * 1024 * 1024)
|
|
|
|
func UnMarshal(data []byte) (interface{}, error) {
|
|
reader := bytes.NewReader(data)
|
|
return unMarshalByReader(reader)
|
|
}
|
|
|
|
func unMarshalByReader(reader *bytes.Reader) (interface{}, error) {
|
|
for {
|
|
if token, _, err := reader.ReadRune(); err == nil {
|
|
switch token {
|
|
default:
|
|
return nil, fmt.Errorf("UnMarshal: Unknown token %#U", token)
|
|
case 'N':
|
|
return unMarshalNil(reader)
|
|
case 'b':
|
|
return unMarshalBool(reader)
|
|
case 'i':
|
|
return unMarshalNumber(reader, false)
|
|
case 'd':
|
|
return unMarshalNumber(reader, true)
|
|
case 's':
|
|
return unMarshalString(reader, true)
|
|
case 'a':
|
|
return unMarshalArray(reader)
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
}
|
|
|
|
func unMarshalNil(reader *bytes.Reader) (interface{}, error) {
|
|
err := expect(reader, ';')
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func unMarshalBool(reader *bytes.Reader) (interface{}, error) {
|
|
var (
|
|
raw rune
|
|
err error
|
|
)
|
|
err = expect(reader, ':')
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if raw, _, err = reader.ReadRune(); err != nil {
|
|
return nil, fmt.Errorf("UnMarshal: Error while reading bool value: %v", err)
|
|
}
|
|
err = expect(reader, ';')
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return raw == '1', nil
|
|
}
|
|
|
|
func unMarshalNumber(reader *bytes.Reader, isFloat bool) (interface{}, error) {
|
|
var (
|
|
raw string
|
|
err error
|
|
val interface{}
|
|
)
|
|
err = expect(reader, ':')
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if raw, err = readUntil(reader, ';'); err != nil {
|
|
return nil, fmt.Errorf("UnMarshal: Error while reading number value: %v", err)
|
|
} else {
|
|
if isFloat {
|
|
if val, err = strconv.ParseFloat(raw, 64); err != nil {
|
|
return nil, fmt.Errorf("UnMarshal: Unable to convert %s to float: %v", raw, err)
|
|
}
|
|
} else {
|
|
if val, err = strconv.Atoi(raw); err != nil {
|
|
return nil, fmt.Errorf("UnMarshal: Unable to convert %s to int: %v", raw, err)
|
|
}
|
|
}
|
|
}
|
|
return val, nil
|
|
}
|
|
|
|
func unMarshalString(reader *bytes.Reader, isFinal bool) (interface{}, error) {
|
|
var (
|
|
err error
|
|
val interface{}
|
|
strLen int
|
|
readLen int
|
|
)
|
|
strLen, err = readLength(reader)
|
|
err = expect(reader, '"')
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if strLen > 0 {
|
|
buf := make([]byte, strLen, strLen)
|
|
if readLen, err = reader.Read(buf); err != nil {
|
|
return nil, fmt.Errorf("UnMarshal: Error while reading string value: %v", err)
|
|
} else {
|
|
if readLen != strLen {
|
|
return nil, fmt.Errorf("UnMarshal: Unable to read string. Expected %d but have got %d bytes", strLen, readLen)
|
|
} else {
|
|
val = string(buf)
|
|
}
|
|
}
|
|
}
|
|
err = expect(reader, '"')
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if isFinal {
|
|
err = expect(reader, ';')
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return val, nil
|
|
}
|
|
|
|
func unMarshalArray(reader *bytes.Reader) (interface{}, error) {
|
|
var arrLen int
|
|
var err error
|
|
val := make(map[string]interface{})
|
|
arrLen, err = readLength(reader)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = expect(reader, '{')
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
indexLen := 0
|
|
for i := 0; i < arrLen; i++ {
|
|
k, err := unMarshalByReader(reader)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
v, err := unMarshalByReader(reader)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
switch t := k.(type) {
|
|
default:
|
|
return nil, fmt.Errorf("UnMarshal: Unexpected key type %T", t)
|
|
case string:
|
|
stringKey, _ := k.(string)
|
|
val[stringKey] = v
|
|
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
|
|
stringKey, _ := gostring.NumericalToString(k)
|
|
val[stringKey] = v
|
|
if i == k {
|
|
indexLen++
|
|
}
|
|
}
|
|
}
|
|
err = expect(reader, '}')
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if indexLen == arrLen {
|
|
var slice []interface{}
|
|
for _, row := range val {
|
|
slice = append(slice, row)
|
|
}
|
|
return slice, nil
|
|
}
|
|
return val, nil
|
|
}
|
|
|
|
func expect(reader *bytes.Reader, expected rune) error {
|
|
if token, _, err := reader.ReadRune(); err != nil {
|
|
return fmt.Errorf("UnMarshal: Error while reading expected rune %#U: %v", expected, err)
|
|
} else if token != expected {
|
|
return fmt.Errorf("UnMarshal: Expected %#U but have got %#U", expected, token)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func readUntil(reader *bytes.Reader, stop rune) (string, error) {
|
|
var (
|
|
token rune
|
|
err error
|
|
)
|
|
buf := bytes.NewBuffer([]byte{})
|
|
for {
|
|
if token, _, err = reader.ReadRune(); err != nil || token == stop {
|
|
break
|
|
} else {
|
|
buf.WriteRune(token)
|
|
}
|
|
}
|
|
return buf.String(), err
|
|
}
|
|
|
|
func readLength(reader *bytes.Reader) (int, error) {
|
|
var (
|
|
raw string
|
|
err error
|
|
val int
|
|
)
|
|
err = expect(reader, ':')
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if raw, err = readUntil(reader, ':'); err != nil {
|
|
return 0, fmt.Errorf("UnMarshal: Error while reading length of value: %v", err)
|
|
} else {
|
|
if val, err = strconv.Atoi(raw); err != nil {
|
|
return 0, fmt.Errorf("UnMarshal: Unable to convert %s to int: %v", raw, err)
|
|
} else if int64(val) > UnserializableObjectMaxLen {
|
|
return 0, fmt.Errorf("UnMarshal: Unserializable object length looks too big(%d). If you are sure you wanna unserialise it, please increase UNSERIALIZABLE_OBJECT_MAX_LEN const", val)
|
|
val = 0
|
|
}
|
|
}
|
|
return val, nil
|
|
}
|