Files
EMS-ESP32/lib/ArduinoJson/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp
2024-02-10 09:50:32 +01:00

587 lines
14 KiB
C++
Executable File

// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Deserialization/deserialize.hpp>
#include <ArduinoJson/Memory/ResourceManager.hpp>
#include <ArduinoJson/MsgPack/endianess.hpp>
#include <ArduinoJson/MsgPack/ieee754.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Variant/VariantData.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TReader>
class MsgPackDeserializer {
public:
MsgPackDeserializer(ResourceManager* resources, TReader reader)
: resources_(resources),
reader_(reader),
stringBuilder_(resources),
foundSomething_(false) {}
template <typename TFilter>
DeserializationError parse(VariantData& variant, TFilter filter,
DeserializationOption::NestingLimit nestingLimit) {
DeserializationError::Code err;
err = parseVariant(&variant, filter, nestingLimit);
return foundSomething_ ? err : DeserializationError::EmptyInput;
}
private:
template <typename TFilter>
DeserializationError::Code parseVariant(
VariantData* variant, TFilter filter,
DeserializationOption::NestingLimit nestingLimit) {
DeserializationError::Code err;
uint8_t code = 0; // TODO: why do we need to initialize this variable?
err = readByte(code);
if (err)
return err;
foundSomething_ = true;
bool allowValue = filter.allowValue();
if (allowValue) {
// callers pass a null pointer only when value must be ignored
ARDUINOJSON_ASSERT(variant != 0);
}
switch (code) {
case 0xc0:
// already null
return DeserializationError::Ok;
case 0xc1:
return DeserializationError::InvalidInput;
case 0xc2:
if (allowValue)
variant->setBoolean(false);
return DeserializationError::Ok;
case 0xc3:
if (allowValue)
variant->setBoolean(true);
return DeserializationError::Ok;
case 0xc4: // bin 8 (not supported)
return skipString<uint8_t>();
case 0xc5: // bin 16 (not supported)
return skipString<uint16_t>();
case 0xc6: // bin 32 (not supported)
return skipString<uint32_t>();
case 0xc7: // ext 8 (not supported)
return skipExt<uint8_t>();
case 0xc8: // ext 16 (not supported)
return skipExt<uint16_t>();
case 0xc9: // ext 32 (not supported)
return skipExt<uint32_t>();
case 0xca:
if (allowValue)
return readFloat<float>(variant);
else
return skipBytes(4);
case 0xcb:
if (allowValue)
return readDouble<double>(variant);
else
return skipBytes(8);
case 0xcc:
if (allowValue)
return readInteger<uint8_t>(variant);
else
return skipBytes(1);
case 0xcd:
if (allowValue)
return readInteger<uint16_t>(variant);
else
return skipBytes(2);
case 0xce:
if (allowValue)
return readInteger<uint32_t>(variant);
else
return skipBytes(4);
case 0xcf:
#if ARDUINOJSON_USE_LONG_LONG
if (allowValue)
return readInteger<uint64_t>(variant);
else
return skipBytes(8);
#else
return skipBytes(8); // not supported
#endif
case 0xd0:
if (allowValue)
return readInteger<int8_t>(variant);
else
return skipBytes(1);
case 0xd1:
if (allowValue)
return readInteger<int16_t>(variant);
else
return skipBytes(2);
case 0xd2:
if (allowValue)
return readInteger<int32_t>(variant);
else
return skipBytes(4);
case 0xd3:
#if ARDUINOJSON_USE_LONG_LONG
if (allowValue)
return readInteger<int64_t>(variant);
else
return skipBytes(8); // not supported
#else
return skipBytes(8);
#endif
case 0xd4: // fixext 1 (not supported)
return skipBytes(2);
case 0xd5: // fixext 2 (not supported)
return skipBytes(3);
case 0xd6: // fixext 4 (not supported)
return skipBytes(5);
case 0xd7: // fixext 8 (not supported)
return skipBytes(9);
case 0xd8: // fixext 16 (not supported)
return skipBytes(17);
case 0xd9:
if (allowValue)
return readString<uint8_t>(variant);
else
return skipString<uint8_t>();
case 0xda:
if (allowValue)
return readString<uint16_t>(variant);
else
return skipString<uint16_t>();
case 0xdb:
if (allowValue)
return readString<uint32_t>(variant);
else
return skipString<uint32_t>();
case 0xdc:
return readArray<uint16_t>(variant, filter, nestingLimit);
case 0xdd:
return readArray<uint32_t>(variant, filter, nestingLimit);
case 0xde:
return readObject<uint16_t>(variant, filter, nestingLimit);
case 0xdf:
return readObject<uint32_t>(variant, filter, nestingLimit);
}
switch (code & 0xf0) {
case 0x80:
return readObject(variant, code & 0x0F, filter, nestingLimit);
case 0x90:
return readArray(variant, code & 0x0F, filter, nestingLimit);
}
if ((code & 0xe0) == 0xa0) {
if (allowValue)
return readString(variant, code & 0x1f);
else
return skipBytes(code & 0x1f);
}
if (allowValue)
variant->setInteger(static_cast<int8_t>(code));
return DeserializationError::Ok;
}
DeserializationError::Code readByte(uint8_t& value) {
int c = reader_.read();
if (c < 0)
return DeserializationError::IncompleteInput;
value = static_cast<uint8_t>(c);
return DeserializationError::Ok;
}
DeserializationError::Code readBytes(uint8_t* p, size_t n) {
if (reader_.readBytes(reinterpret_cast<char*>(p), n) == n)
return DeserializationError::Ok;
return DeserializationError::IncompleteInput;
}
template <typename T>
DeserializationError::Code readBytes(T& value) {
return readBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
}
DeserializationError::Code skipBytes(size_t n) {
for (; n; --n) {
if (reader_.read() < 0)
return DeserializationError::IncompleteInput;
}
return DeserializationError::Ok;
}
template <typename T>
DeserializationError::Code readInteger(T& value) {
DeserializationError::Code err;
err = readBytes(value);
if (err)
return err;
fixEndianess(value);
return DeserializationError::Ok;
}
template <typename T>
DeserializationError::Code readInteger(VariantData* variant) {
DeserializationError::Code err;
T value;
err = readInteger(value);
if (err)
return err;
variant->setInteger(value);
return DeserializationError::Ok;
}
template <typename T>
typename enable_if<sizeof(T) == 4, DeserializationError::Code>::type
readFloat(VariantData* variant) {
DeserializationError::Code err;
T value;
err = readBytes(value);
if (err)
return err;
fixEndianess(value);
variant->setFloat(value);
return DeserializationError::Ok;
}
template <typename T>
typename enable_if<sizeof(T) == 8, DeserializationError::Code>::type
readDouble(VariantData* variant) {
DeserializationError::Code err;
T value;
err = readBytes(value);
if (err)
return err;
fixEndianess(value);
variant->setFloat(value);
return DeserializationError::Ok;
}
template <typename T>
typename enable_if<sizeof(T) == 4, DeserializationError::Code>::type
readDouble(VariantData* variant) {
DeserializationError::Code err;
uint8_t i[8]; // input is 8 bytes
T value; // output is 4 bytes
uint8_t* o = reinterpret_cast<uint8_t*>(&value);
err = readBytes(i, 8);
if (err)
return err;
doubleToFloat(i, o);
fixEndianess(value);
variant->setFloat(value);
return DeserializationError::Ok;
}
template <typename T>
DeserializationError::Code readString(VariantData* variant) {
DeserializationError::Code err;
T size;
err = readInteger(size);
if (err)
return err;
return readString(variant, size);
}
template <typename T>
DeserializationError::Code readString() {
DeserializationError::Code err;
T size;
err = readInteger(size);
if (err)
return err;
return readString(size);
}
template <typename T>
DeserializationError::Code skipString() {
DeserializationError::Code err;
T size;
err = readInteger(size);
if (err)
return err;
return skipBytes(size);
}
DeserializationError::Code readString(VariantData* variant, size_t n) {
DeserializationError::Code err;
err = readString(n);
if (err)
return err;
variant->setOwnedString(stringBuilder_.save());
return DeserializationError::Ok;
}
DeserializationError::Code readString(size_t n) {
DeserializationError::Code err;
stringBuilder_.startString();
for (; n; --n) {
uint8_t c;
err = readBytes(c);
if (err)
return err;
stringBuilder_.append(static_cast<char>(c));
}
if (!stringBuilder_.isValid())
return DeserializationError::NoMemory;
return DeserializationError::Ok;
}
template <typename TSize, typename TFilter>
DeserializationError::Code readArray(
VariantData* variant, TFilter filter,
DeserializationOption::NestingLimit nestingLimit) {
DeserializationError::Code err;
TSize size;
err = readInteger(size);
if (err)
return err;
return readArray(variant, size, filter, nestingLimit);
}
template <typename TFilter>
DeserializationError::Code readArray(
VariantData* variant, size_t n, TFilter filter,
DeserializationOption::NestingLimit nestingLimit) {
DeserializationError::Code err;
if (nestingLimit.reached())
return DeserializationError::TooDeep;
bool allowArray = filter.allowArray();
ArrayData* array;
if (allowArray) {
ARDUINOJSON_ASSERT(variant != 0);
array = &variant->toArray();
} else {
array = 0;
}
TFilter elementFilter = filter[0U];
for (; n; --n) {
VariantData* value;
if (elementFilter.allow()) {
ARDUINOJSON_ASSERT(array != 0);
value = array->addElement(resources_);
if (!value)
return DeserializationError::NoMemory;
} else {
value = 0;
}
err = parseVariant(value, elementFilter, nestingLimit.decrement());
if (err)
return err;
}
return DeserializationError::Ok;
}
template <typename TSize, typename TFilter>
DeserializationError::Code readObject(
VariantData* variant, TFilter filter,
DeserializationOption::NestingLimit nestingLimit) {
DeserializationError::Code err;
TSize size;
err = readInteger(size);
if (err)
return err;
return readObject(variant, size, filter, nestingLimit);
}
template <typename TFilter>
DeserializationError::Code readObject(
VariantData* variant, size_t n, TFilter filter,
DeserializationOption::NestingLimit nestingLimit) {
DeserializationError::Code err;
if (nestingLimit.reached())
return DeserializationError::TooDeep;
ObjectData* object;
if (filter.allowObject()) {
ARDUINOJSON_ASSERT(variant != 0);
object = &variant->toObject();
} else {
object = 0;
}
for (; n; --n) {
err = readKey();
if (err)
return err;
JsonString key = stringBuilder_.str();
TFilter memberFilter = filter[key.c_str()];
VariantData* member;
if (memberFilter.allow()) {
ARDUINOJSON_ASSERT(object != 0);
// Save key in memory pool.
auto savedKey = stringBuilder_.save();
member = object->addMember(savedKey, resources_);
if (!member)
return DeserializationError::NoMemory;
} else {
member = 0;
}
err = parseVariant(member, memberFilter, nestingLimit.decrement());
if (err)
return err;
}
return DeserializationError::Ok;
}
DeserializationError::Code readKey() {
DeserializationError::Code err;
uint8_t code;
err = readByte(code);
if (err)
return err;
if ((code & 0xe0) == 0xa0)
return readString(code & 0x1f);
switch (code) {
case 0xd9:
return readString<uint8_t>();
case 0xda:
return readString<uint16_t>();
case 0xdb:
return readString<uint32_t>();
default:
return DeserializationError::InvalidInput;
}
}
template <typename T>
DeserializationError::Code skipExt() {
DeserializationError::Code err;
T size;
err = readInteger(size);
if (err)
return err;
return skipBytes(size + 1U);
}
ResourceManager* resources_;
TReader reader_;
StringBuilder stringBuilder_;
bool foundSomething_;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// Parses a MessagePack input and puts the result in a JsonDocument.
// https://arduinojson.org/v7/api/msgpack/deserializemsgpack/
template <typename TDestination, typename... Args>
typename detail::enable_if<
detail::is_deserialize_destination<TDestination>::value,
DeserializationError>::type
deserializeMsgPack(TDestination&& dst, Args&&... args) {
using namespace detail;
return deserialize<MsgPackDeserializer>(detail::forward<TDestination>(dst),
detail::forward<Args>(args)...);
}
// Parses a MessagePack input and puts the result in a JsonDocument.
// https://arduinojson.org/v7/api/msgpack/deserializemsgpack/
template <typename TDestination, typename TChar, typename... Args>
typename detail::enable_if<
detail::is_deserialize_destination<TDestination>::value,
DeserializationError>::type
deserializeMsgPack(TDestination&& dst, TChar* input, Args&&... args) {
using namespace detail;
return deserialize<MsgPackDeserializer>(detail::forward<TDestination>(dst),
input,
detail::forward<Args>(args)...);
}
ARDUINOJSON_END_PUBLIC_NAMESPACE