Added deserializeMsgPack() (issue #358)

This commit is contained in:
Benoit Blanchon
2018-04-10 17:43:27 +02:00
parent 923d3e8a84
commit cb723840d9
58 changed files with 1311 additions and 89 deletions

View File

@@ -0,0 +1,328 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "../JsonVariant.hpp"
#include "../Memory/JsonBuffer.hpp"
#include "../Strings/StringWriter.hpp"
#include "../TypeTraits/IsConst.hpp"
#include "./MsgPackError.hpp"
#include "./endianess.hpp"
#include "./ieee754.hpp"
namespace ArduinoJson {
namespace Internals {
// Parse JSON string to create JsonArrays and JsonObjects
// This internal class is not indended to be used directly.
// Instead, use JsonBuffer.parseArray() or .parseObject()
template <typename TReader, typename TWriter>
class MsgPackDeserializer {
public:
MsgPackDeserializer(JsonBuffer *buffer, TReader reader, TWriter writer,
uint8_t nestingLimit)
: _buffer(buffer),
_reader(reader),
_writer(writer),
_nestingLimit(nestingLimit) {}
MsgPackError parse(JsonArray &array) {
uint8_t c = readOne();
size_t n;
if ((c & 0xF0) == 0x90) {
n = c & 0x0F;
} else if (c == 0xdc) {
n = readInteger<uint16_t>();
} else if (c == 0xdd) {
n = readInteger<uint32_t>();
} else {
return MsgPackError::NotAnArray;
}
return readArray(array, n);
}
MsgPackError parse(JsonObject &object) {
uint8_t c = readOne();
size_t n;
if ((c & 0xf0) == 0x80) {
n = c & 0x0f;
} else if (c == 0xde) {
n = readInteger<uint16_t>();
} else if (c == 0xdf) {
n = readInteger<uint32_t>();
} else {
return MsgPackError::NotAnObject;
}
return readObject(object, n);
}
MsgPackError parse(JsonVariant &variant) {
uint8_t c = readOne();
if ((c & 0x80) == 0) {
variant = c;
return MsgPackError::Ok;
}
if ((c & 0xe0) == 0xe0) {
variant = static_cast<int8_t>(c);
return MsgPackError::Ok;
}
if ((c & 0xe0) == 0xa0) {
return readString(variant, c & 0x1f);
}
if ((c & 0xf0) == 0x90) return readArray(variant, c & 0x0F);
if ((c & 0xf0) == 0x80) return readObject(variant, c & 0x0F);
switch (c) {
case 0xc0:
variant = static_cast<char *>(0);
return MsgPackError::Ok;
case 0xc2:
variant = false;
return MsgPackError::Ok;
case 0xc3:
variant = true;
return MsgPackError::Ok;
case 0xcc:
variant = readInteger<uint8_t>();
return MsgPackError::Ok;
case 0xcd:
variant = readInteger<uint16_t>();
return MsgPackError::Ok;
case 0xce:
variant = readInteger<uint32_t>();
return MsgPackError::Ok;
case 0xcf:
#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
variant = readInteger<uint64_t>();
#else
readInteger<uint32_t>();
variant = readInteger<uint32_t>();
#endif
return MsgPackError::Ok;
case 0xd0:
variant = readInteger<int8_t>();
return MsgPackError::Ok;
case 0xd1:
variant = readInteger<int16_t>();
return MsgPackError::Ok;
case 0xd2:
variant = readInteger<int32_t>();
return MsgPackError::Ok;
case 0xd3:
#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
variant = readInteger<int64_t>();
#else
readInteger<int32_t>();
variant = readInteger<int32_t>();
#endif
return MsgPackError::Ok;
case 0xca:
variant = readFloat<float>();
return MsgPackError::Ok;
case 0xcb:
variant = readDouble<double>();
return MsgPackError::Ok;
case 0xd9: {
uint8_t n = readInteger<uint8_t>();
return readString(variant, n);
}
case 0xda: {
uint16_t n = readInteger<uint16_t>();
return readString(variant, n);
}
case 0xdb: {
uint32_t n = readInteger<uint32_t>();
return readString(variant, n);
}
case 0xdc:
return readArray(variant, readInteger<uint16_t>());
case 0xdd:
return readArray(variant, readInteger<uint32_t>());
case 0xde:
return readObject(variant, readInteger<uint16_t>());
case 0xdf:
return readObject(variant, readInteger<uint32_t>());
default:
return MsgPackError::NotSupported;
}
}
private:
// Prevent VS warning "assignment operator could not be generated"
MsgPackDeserializer &operator=(const MsgPackDeserializer &);
uint8_t readOne() {
char c = _reader.current();
_reader.move();
return static_cast<uint8_t>(c);
}
void read(uint8_t *p, size_t n) {
for (size_t i = 0; i < n; i++) p[i] = readOne();
}
template <typename T>
void read(T &value) {
read(reinterpret_cast<uint8_t *>(&value), sizeof(value));
}
template <typename T>
T readInteger() {
T value;
read(value);
fixEndianess(value);
return value;
}
template <typename T>
typename EnableIf<sizeof(T) == 4, T>::type readFloat() {
T value;
read(value);
fixEndianess(value);
return value;
}
template <typename T>
typename EnableIf<sizeof(T) == 8, T>::type readDouble() {
T value;
read(value);
fixEndianess(value);
return value;
}
template <typename T>
typename EnableIf<sizeof(T) == 4, T>::type readDouble() {
uint8_t i[8]; // input is 8 bytes
T value; // output is 4 bytes
uint8_t *o = reinterpret_cast<uint8_t *>(&value);
read(i, 8);
doubleToFloat(i, o);
fixEndianess(value);
return value;
}
MsgPackError readString(JsonVariant &variant, size_t n) {
typename RemoveReference<TWriter>::type::String str = _writer.startString();
for (; n; --n) str.append(static_cast<char>(readOne()));
const char *s = str.c_str();
if (s == NULL) return MsgPackError::NoMemory;
variant = s;
return MsgPackError::Ok;
}
MsgPackError readArray(JsonVariant &variant, size_t n) {
JsonArray *array = new (_buffer) JsonArray(_buffer);
if (!array) return MsgPackError::NoMemory;
variant = array;
return readArray(*array, n);
}
MsgPackError readArray(JsonArray &array, size_t n) {
if (_nestingLimit == 0) return MsgPackError::TooDeep;
--_nestingLimit;
for (; n; --n) {
JsonVariant variant;
MsgPackError err = parse(variant);
if (err) return err;
if (!array.add(variant)) return MsgPackError::NoMemory;
}
++_nestingLimit;
return MsgPackError::Ok;
}
MsgPackError readObject(JsonVariant &variant, size_t n) {
JsonObject *object = new (_buffer) JsonObject(_buffer);
if (!object) return MsgPackError::NoMemory;
variant = object;
return readObject(*object, n);
}
MsgPackError readObject(JsonObject &object, size_t n) {
if (_nestingLimit == 0) return MsgPackError::TooDeep;
--_nestingLimit;
for (; n; --n) {
MsgPackError err;
JsonVariant variant;
err = parse(variant);
if (err) return err;
const char *key = variant.as<char *>();
if (!key) return MsgPackError::NotSupported;
err = parse(variant);
if (err) return err;
if (!object.set(key, variant)) return MsgPackError::NoMemory;
}
++_nestingLimit;
return MsgPackError::Ok;
}
JsonBuffer *_buffer;
TReader _reader;
TWriter _writer;
uint8_t _nestingLimit;
};
template <typename TJsonBuffer, typename TString, typename Enable = void>
struct MsgPackDeserializerBuilder {
typedef typename StringTraits<TString>::Reader InputReader;
typedef MsgPackDeserializer<InputReader, TJsonBuffer &> TParser;
static TParser makeMsgPackDeserializer(TJsonBuffer *buffer, TString &json,
uint8_t nestingLimit) {
return TParser(buffer, InputReader(json), *buffer, nestingLimit);
}
};
template <typename TJsonBuffer, typename TChar>
struct MsgPackDeserializerBuilder<
TJsonBuffer, TChar *, typename EnableIf<!IsConst<TChar>::value>::type> {
typedef typename StringTraits<TChar *>::Reader TReader;
typedef StringWriter<TChar> TWriter;
typedef MsgPackDeserializer<TReader, TWriter> TParser;
static TParser makeMsgPackDeserializer(TJsonBuffer *buffer, TChar *json,
uint8_t nestingLimit) {
return TParser(buffer, TReader(json), TWriter(json), nestingLimit);
}
};
template <typename TJsonBuffer, typename TString>
inline typename MsgPackDeserializerBuilder<TJsonBuffer, TString>::TParser
makeMsgPackDeserializer(TJsonBuffer *buffer, TString &json,
uint8_t nestingLimit) {
return MsgPackDeserializerBuilder<
TJsonBuffer, TString>::makeMsgPackDeserializer(buffer, json,
nestingLimit);
}
} // namespace Internals
} // namespace ArduinoJson

View File

@@ -0,0 +1,67 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
class MsgPackError {
public:
enum Code { Ok, NotSupported, NoMemory, NotAnArray, NotAnObject, TooDeep };
MsgPackError() {}
MsgPackError(Code code) : _code(code) {}
operator bool() const {
return _code != Ok;
}
friend bool operator==(const MsgPackError& err, Code code) {
return err._code == code;
}
friend bool operator==(Code code, const MsgPackError& err) {
return err._code == code;
}
friend bool operator!=(const MsgPackError& err, Code code) {
return err._code != code;
}
friend bool operator!=(Code code, const MsgPackError& err) {
return err._code != code;
}
const char* c_str() const {
switch (_code) {
case Ok:
return "Ok";
case NotSupported:
return "NotSupported";
case NoMemory:
return "NoMemory";
case NotAnArray:
return "NotAnArray";
case NotAnObject:
return "NotAnObject";
case TooDeep:
return "TooDeep";
default:
return "???";
}
}
private:
Code _code;
};
#if ARDUINOJSON_ENABLE_STD_STREAM
inline std::ostream& operator<<(std::ostream& os, const MsgPackError& err) {
os << err.c_str();
return os;
}
#endif
} // namespace ArduinoJson

View File

@@ -0,0 +1,47 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
template <class T, T v>
struct integral_constant {};
template <typename T>
inline void swap(T& a, T& b) {
T t(a);
a = b;
b = t;
}
inline void fixEndianess(uint8_t* p, integral_constant<size_t, 8>) {
swap(p[0], p[7]);
swap(p[1], p[6]);
swap(p[2], p[5]);
swap(p[3], p[4]);
}
inline void fixEndianess(uint8_t* p, integral_constant<size_t, 4>) {
swap(p[0], p[3]);
swap(p[1], p[2]);
}
inline void fixEndianess(uint8_t* p, integral_constant<size_t, 2>) {
swap(p[0], p[1]);
}
inline void fixEndianess(uint8_t*, integral_constant<size_t, 1>) {}
template <typename T>
inline void fixEndianess(T& value) {
#if ARDUINOJSON_LITTLE_ENDIAN
fixEndianess(reinterpret_cast<uint8_t*>(&value),
integral_constant<size_t, sizeof(T)>());
#endif
}
} // namespace Internals
} // namespace ArduinoJson

View File

@@ -0,0 +1,18 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
inline void doubleToFloat(const uint8_t d[8], uint8_t f[4]) {
f[0] = uint8_t((d[0] & 0xC0) | (d[0] << 3 & 0x3f) | (d[1] >> 5));
f[1] = uint8_t((d[1] << 3) | (d[2] >> 5));
f[2] = uint8_t((d[2] << 3) | (d[3] >> 5));
f[3] = uint8_t((d[3] << 3) | (d[4] >> 5));
}
} // namespace Internals
} // namespace ArduinoJson