mirror of
https://github.com/eledio-devices/thirdparty-ArduinoJson.git
synced 2025-11-01 00:38:27 +01:00
357 lines
9.4 KiB
C++
357 lines
9.4 KiB
C++
// ArduinoJson - arduinojson.org
|
|
// Copyright Benoit Blanchon 2014-2018
|
|
// MIT License
|
|
|
|
#pragma once
|
|
|
|
#include "../Deserialization/deserialize.hpp"
|
|
#include "../Memory/MemoryPool.hpp"
|
|
#include "../Polyfills/type_traits.hpp"
|
|
#include "../Variant/VariantRef.hpp"
|
|
#include "endianess.hpp"
|
|
#include "ieee754.hpp"
|
|
|
|
namespace ARDUINOJSON_NAMESPACE {
|
|
|
|
template <typename TReader, typename TStringStorage>
|
|
class MsgPackDeserializer {
|
|
typedef typename remove_reference<TStringStorage>::type::StringBuilder
|
|
StringBuilder;
|
|
typedef typename StringBuilder::StringType StringType;
|
|
|
|
public:
|
|
MsgPackDeserializer(MemoryPool &memoryPool, TReader reader,
|
|
TStringStorage stringStorage, uint8_t nestingLimit)
|
|
: _memoryPool(&memoryPool),
|
|
_reader(reader),
|
|
_stringStorage(stringStorage),
|
|
_nestingLimit(nestingLimit) {}
|
|
|
|
DeserializationError parse(VariantRef variant) {
|
|
uint8_t code;
|
|
if (!readByte(code)) return DeserializationError::IncompleteInput;
|
|
|
|
if ((code & 0x80) == 0) {
|
|
variant.set(code);
|
|
return DeserializationError::Ok;
|
|
}
|
|
|
|
if ((code & 0xe0) == 0xe0) {
|
|
variant.set(static_cast<int8_t>(code));
|
|
return DeserializationError::Ok;
|
|
}
|
|
|
|
if ((code & 0xe0) == 0xa0) {
|
|
return readString(variant, code & 0x1f);
|
|
}
|
|
|
|
if ((code & 0xf0) == 0x90) return readArray(variant, code & 0x0F);
|
|
|
|
if ((code & 0xf0) == 0x80) return readObject(variant, code & 0x0F);
|
|
|
|
switch (code) {
|
|
case 0xc0:
|
|
// already null
|
|
return DeserializationError::Ok;
|
|
|
|
case 0xc2:
|
|
variant.set(false);
|
|
return DeserializationError::Ok;
|
|
|
|
case 0xc3:
|
|
variant.set(true);
|
|
return DeserializationError::Ok;
|
|
|
|
case 0xcc:
|
|
return readInteger<uint8_t>(variant);
|
|
|
|
case 0xcd:
|
|
return readInteger<uint16_t>(variant);
|
|
|
|
case 0xce:
|
|
return readInteger<uint32_t>(variant);
|
|
|
|
case 0xcf:
|
|
#if ARDUINOJSON_USE_LONG_LONG
|
|
return readInteger<uint64_t>(variant);
|
|
#else
|
|
readInteger<uint32_t>();
|
|
return readInteger<uint32_t>(variant);
|
|
#endif
|
|
|
|
case 0xd0:
|
|
return readInteger<int8_t>(variant);
|
|
|
|
case 0xd1:
|
|
return readInteger<int16_t>(variant);
|
|
|
|
case 0xd2:
|
|
return readInteger<int32_t>(variant);
|
|
|
|
case 0xd3:
|
|
#if ARDUINOJSON_USE_LONG_LONG
|
|
return readInteger<int64_t>(variant);
|
|
#else
|
|
if (!skip(4)) return DeserializationError::IncompleteInput;
|
|
return readInteger<int32_t>(variant);
|
|
#endif
|
|
|
|
case 0xca:
|
|
return readFloat<float>(variant);
|
|
|
|
case 0xcb:
|
|
return readDouble<double>(variant);
|
|
|
|
case 0xd9:
|
|
return readString<uint8_t>(variant);
|
|
|
|
case 0xda:
|
|
return readString<uint16_t>(variant);
|
|
|
|
case 0xdb:
|
|
return readString<uint32_t>(variant);
|
|
|
|
case 0xdc:
|
|
return readArray<uint16_t>(variant);
|
|
|
|
case 0xdd:
|
|
return readArray<uint32_t>(variant);
|
|
|
|
case 0xde:
|
|
return readObject<uint16_t>(variant);
|
|
|
|
case 0xdf:
|
|
return readObject<uint32_t>(variant);
|
|
|
|
default:
|
|
return DeserializationError::NotSupported;
|
|
}
|
|
}
|
|
|
|
private:
|
|
// Prevent VS warning "assignment operator could not be generated"
|
|
MsgPackDeserializer &operator=(const MsgPackDeserializer &);
|
|
|
|
bool skip(uint8_t n) {
|
|
while (n--) {
|
|
if (_reader.ended()) return false;
|
|
_reader.read();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool readByte(uint8_t &value) {
|
|
if (_reader.ended()) return false;
|
|
value = static_cast<uint8_t>(_reader.read());
|
|
return true;
|
|
}
|
|
|
|
bool readBytes(uint8_t *p, size_t n) {
|
|
for (size_t i = 0; i < n; i++) {
|
|
if (!readByte(p[i])) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <typename T>
|
|
bool readBytes(T &value) {
|
|
return readBytes(reinterpret_cast<uint8_t *>(&value), sizeof(value));
|
|
}
|
|
|
|
template <typename T>
|
|
T readInteger() {
|
|
T value;
|
|
readBytes(value);
|
|
fixEndianess(value);
|
|
return value;
|
|
}
|
|
|
|
template <typename T>
|
|
bool readInteger(T &value) {
|
|
if (!readBytes(value)) return false;
|
|
fixEndianess(value);
|
|
return true;
|
|
}
|
|
|
|
template <typename T>
|
|
DeserializationError readInteger(VariantRef variant) {
|
|
T value;
|
|
if (!readInteger(value)) return DeserializationError::IncompleteInput;
|
|
variant.set(value);
|
|
return DeserializationError::Ok;
|
|
}
|
|
|
|
template <typename T>
|
|
typename enable_if<sizeof(T) == 4, DeserializationError>::type readFloat(
|
|
VariantRef variant) {
|
|
T value;
|
|
if (!readBytes(value)) return DeserializationError::IncompleteInput;
|
|
fixEndianess(value);
|
|
variant.set(value);
|
|
return DeserializationError::Ok;
|
|
}
|
|
|
|
template <typename T>
|
|
typename enable_if<sizeof(T) == 8, DeserializationError>::type readDouble(
|
|
VariantRef variant) {
|
|
T value;
|
|
if (!readBytes(value)) return DeserializationError::IncompleteInput;
|
|
fixEndianess(value);
|
|
variant.set(value);
|
|
return DeserializationError::Ok;
|
|
}
|
|
|
|
template <typename T>
|
|
typename enable_if<sizeof(T) == 4, DeserializationError>::type readDouble(
|
|
VariantRef variant) {
|
|
uint8_t i[8]; // input is 8 bytes
|
|
T value; // output is 4 bytes
|
|
uint8_t *o = reinterpret_cast<uint8_t *>(&value);
|
|
if (!readBytes(i, 8)) return DeserializationError::IncompleteInput;
|
|
doubleToFloat(i, o);
|
|
fixEndianess(value);
|
|
variant.set(value);
|
|
return DeserializationError::Ok;
|
|
}
|
|
|
|
template <typename T>
|
|
DeserializationError readString(VariantRef variant) {
|
|
T size;
|
|
if (!readInteger(size)) return DeserializationError::IncompleteInput;
|
|
return readString(variant, size);
|
|
}
|
|
|
|
template <typename T>
|
|
DeserializationError readString(StringType &str) {
|
|
T size;
|
|
if (!readInteger(size)) return DeserializationError::IncompleteInput;
|
|
return readString(str, size);
|
|
}
|
|
|
|
DeserializationError readString(VariantRef variant, size_t n) {
|
|
StringType s;
|
|
DeserializationError err = readString(s, n);
|
|
if (!err) variant.set(s);
|
|
return err;
|
|
}
|
|
|
|
DeserializationError readString(StringType &s, size_t n) {
|
|
StringBuilder builder = _stringStorage.startString();
|
|
for (; n; --n) {
|
|
uint8_t c;
|
|
if (!readBytes(c)) return DeserializationError::IncompleteInput;
|
|
builder.append(static_cast<char>(c));
|
|
}
|
|
s = builder.complete();
|
|
if (s.isNull()) return DeserializationError::NoMemory;
|
|
return DeserializationError::Ok;
|
|
}
|
|
|
|
template <typename TSize>
|
|
DeserializationError readArray(VariantRef variant) {
|
|
TSize size;
|
|
if (!readInteger(size)) return DeserializationError::IncompleteInput;
|
|
return readArray(variant, size);
|
|
}
|
|
|
|
DeserializationError readArray(VariantRef variant, size_t n) {
|
|
ArrayRef array = variant.to<ArrayRef>();
|
|
if (array.isNull()) return DeserializationError::NoMemory;
|
|
return readArray(array, n);
|
|
}
|
|
|
|
DeserializationError readArray(ArrayRef array, size_t n) {
|
|
if (_nestingLimit == 0) return DeserializationError::TooDeep;
|
|
--_nestingLimit;
|
|
for (; n; --n) {
|
|
VariantRef value = array.add();
|
|
if (value.isInvalid()) return DeserializationError::NoMemory;
|
|
|
|
DeserializationError err = parse(value);
|
|
if (err) return err;
|
|
}
|
|
++_nestingLimit;
|
|
return DeserializationError::Ok;
|
|
}
|
|
|
|
template <typename TSize>
|
|
DeserializationError readObject(VariantRef variant) {
|
|
TSize size;
|
|
if (!readInteger(size)) return DeserializationError::IncompleteInput;
|
|
return readObject(variant, size);
|
|
}
|
|
|
|
DeserializationError readObject(VariantRef variant, size_t n) {
|
|
ObjectRef object = variant.to<ObjectRef>();
|
|
if (object.isNull()) return DeserializationError::NoMemory;
|
|
|
|
return readObject(object, n);
|
|
}
|
|
|
|
DeserializationError readObject(ObjectRef object, size_t n) {
|
|
if (_nestingLimit == 0) return DeserializationError::TooDeep;
|
|
--_nestingLimit;
|
|
for (; n; --n) {
|
|
StringType key;
|
|
DeserializationError err = parseKey(key);
|
|
if (err) return err;
|
|
|
|
VariantRef value = object.set(key);
|
|
if (value.isInvalid()) return DeserializationError::NoMemory;
|
|
|
|
err = parse(value);
|
|
if (err) return err;
|
|
}
|
|
++_nestingLimit;
|
|
return DeserializationError::Ok;
|
|
}
|
|
|
|
DeserializationError parseKey(StringType &key) {
|
|
uint8_t code;
|
|
if (!readByte(code)) return DeserializationError::IncompleteInput;
|
|
|
|
if ((code & 0xe0) == 0xa0) return readString(key, code & 0x1f);
|
|
|
|
switch (code) {
|
|
case 0xd9:
|
|
return readString<uint8_t>(key);
|
|
|
|
case 0xda:
|
|
return readString<uint16_t>(key);
|
|
|
|
case 0xdb:
|
|
return readString<uint32_t>(key);
|
|
|
|
default:
|
|
return DeserializationError::NotSupported;
|
|
}
|
|
}
|
|
|
|
MemoryPool *_memoryPool;
|
|
TReader _reader;
|
|
TStringStorage _stringStorage;
|
|
uint8_t _nestingLimit;
|
|
};
|
|
|
|
template <typename TDocument, typename TInput>
|
|
DeserializationError deserializeMsgPack(TDocument &doc, const TInput &input) {
|
|
return deserialize<MsgPackDeserializer>(doc, input);
|
|
}
|
|
|
|
template <typename TDocument, typename TInput>
|
|
DeserializationError deserializeMsgPack(TDocument &doc, TInput *input) {
|
|
return deserialize<MsgPackDeserializer>(doc, input);
|
|
}
|
|
|
|
template <typename TDocument, typename TInput>
|
|
DeserializationError deserializeMsgPack(TDocument &doc, TInput *input,
|
|
size_t inputSize) {
|
|
return deserialize<MsgPackDeserializer>(doc, input, inputSize);
|
|
}
|
|
|
|
template <typename TDocument, typename TInput>
|
|
DeserializationError deserializeMsgPack(TDocument &doc, TInput &input) {
|
|
return deserialize<MsgPackDeserializer>(doc, input);
|
|
}
|
|
} // namespace ARDUINOJSON_NAMESPACE
|