package serialize import ( "bytes" "fmt" "go.dtapp.net/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 }