diff options
Diffstat (limited to 'include/lib/ArduinoJson/MsgPack')
-rw-r--r-- | include/lib/ArduinoJson/MsgPack/MsgPackDeserializer.hpp | 599 | ||||
-rw-r--r-- | include/lib/ArduinoJson/MsgPack/MsgPackSerializer.hpp | 212 | ||||
-rw-r--r-- | include/lib/ArduinoJson/MsgPack/endianess.hpp | 41 | ||||
-rw-r--r-- | include/lib/ArduinoJson/MsgPack/ieee754.hpp | 18 |
4 files changed, 870 insertions, 0 deletions
diff --git a/include/lib/ArduinoJson/MsgPack/MsgPackDeserializer.hpp b/include/lib/ArduinoJson/MsgPack/MsgPackDeserializer.hpp new file mode 100644 index 0000000..49c6fd4 --- /dev/null +++ b/include/lib/ArduinoJson/MsgPack/MsgPackDeserializer.hpp @@ -0,0 +1,599 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Deserialization/deserialize.hpp> +#include <ArduinoJson/Memory/MemoryPool.hpp> +#include <ArduinoJson/MsgPack/endianess.hpp> +#include <ArduinoJson/MsgPack/ieee754.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Variant/VariantData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TReader, typename TStringStorage> +class MsgPackDeserializer { + public: + MsgPackDeserializer(MemoryPool &pool, TReader reader, + TStringStorage stringStorage) + : _pool(&pool), + _reader(reader), + _stringStorage(stringStorage), + _error(DeserializationError::Ok), + _foundSomething(false) {} + + template <typename TFilter> + DeserializationError parse(VariantData &variant, TFilter filter, + NestingLimit nestingLimit) { + parseVariant(&variant, filter, nestingLimit); + return _foundSomething ? _error : DeserializationError::EmptyInput; + } + + private: + // Prevent VS warning "assignment operator could not be generated" + MsgPackDeserializer &operator=(const MsgPackDeserializer &); + + bool invalidInput() { + _error = DeserializationError::InvalidInput; + return false; + } + + template <typename TFilter> + bool parseVariant(VariantData *variant, TFilter filter, + NestingLimit nestingLimit) { + uint8_t code = 0; // TODO: why do we need to initialize this variable? + if (!readByte(code)) + return false; + + _foundSomething = true; + + bool allowValue = filter.allowValue(); + + switch (code) { + case 0xc0: + // already null + return true; + + case 0xc1: + return invalidInput(); + + case 0xc2: + if (allowValue) + variant->setBoolean(false); + return true; + + case 0xc3: + if (allowValue) + variant->setBoolean(true); + return true; + + 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 true; + } + + bool readByte(uint8_t &value) { + int c = _reader.read(); + if (c < 0) { + _error = DeserializationError::IncompleteInput; + return false; + } + value = static_cast<uint8_t>(c); + return true; + } + + bool readBytes(uint8_t *p, size_t n) { + if (_reader.readBytes(reinterpret_cast<char *>(p), n) == n) + return true; + _error = DeserializationError::IncompleteInput; + return false; + } + + template <typename T> + bool readBytes(T &value) { + return readBytes(reinterpret_cast<uint8_t *>(&value), sizeof(value)); + } + + bool skipBytes(size_t n) { + for (; n; --n) { + if (_reader.read() < 0) { + _error = DeserializationError::IncompleteInput; + return false; + } + } + return true; + } + + template <typename T> + bool readInteger(T &value) { + if (!readBytes(value)) + return false; + fixEndianess(value); + return true; + } + + template <typename T> + bool readInteger(VariantData *variant) { + T value; + if (!readInteger(value)) + return false; + variant->setInteger(value); + return true; + } + + template <typename T> + typename enable_if<sizeof(T) == 4, bool>::type readFloat( + VariantData *variant) { + T value; + if (!readBytes(value)) + return false; + fixEndianess(value); + variant->setFloat(value); + return true; + } + + template <typename T> + typename enable_if<sizeof(T) == 8, bool>::type readDouble( + VariantData *variant) { + T value; + if (!readBytes(value)) + return false; + fixEndianess(value); + variant->setFloat(value); + return true; + } + + template <typename T> + typename enable_if<sizeof(T) == 4, bool>::type readDouble( + VariantData *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 false; + doubleToFloat(i, o); + fixEndianess(value); + variant->setFloat(value); + return true; + } + + template <typename T> + bool readString(VariantData *variant) { + T size; + if (!readInteger(size)) + return false; + return readString(variant, size); + } + + template <typename T> + bool readString() { + T size; + if (!readInteger(size)) + return false; + return readString(size); + } + + template <typename T> + bool skipString() { + T size; + if (!readInteger(size)) + return false; + return skipBytes(size); + } + + bool readString(VariantData *variant, size_t n) { + if (!readString(n)) + return false; + variant->setStringPointer(_stringStorage.save(), + typename TStringStorage::storage_policy()); + return true; + } + + bool readString(size_t n) { + _stringStorage.startString(); + for (; n; --n) { + uint8_t c; + if (!readBytes(c)) + return false; + _stringStorage.append(static_cast<char>(c)); + } + _stringStorage.append('\0'); + if (!_stringStorage.isValid()) { + _error = DeserializationError::NoMemory; + return false; + } + + return true; + } + + template <typename TSize, typename TFilter> + bool readArray(VariantData *variant, TFilter filter, + NestingLimit nestingLimit) { + TSize size; + if (!readInteger(size)) + return false; + return readArray(variant, size, filter, nestingLimit); + } + + template <typename TFilter> + bool readArray(VariantData *variant, size_t n, TFilter filter, + NestingLimit nestingLimit) { + if (nestingLimit.reached()) { + _error = DeserializationError::TooDeep; + return false; + } + + bool allowArray = filter.allowArray(); + + CollectionData *array = allowArray ? &variant->toArray() : 0; + + TFilter memberFilter = filter[0U]; + + for (; n; --n) { + VariantData *value; + + if (memberFilter.allow()) { + value = array->addElement(_pool); + if (!value) { + _error = DeserializationError::NoMemory; + return false; + } + } else { + value = 0; + } + + if (!parseVariant(value, memberFilter, nestingLimit.decrement())) + return false; + } + + return true; + } + + template <typename TSize, typename TFilter> + bool readObject(VariantData *variant, TFilter filter, + NestingLimit nestingLimit) { + TSize size; + if (!readInteger(size)) + return false; + return readObject(variant, size, filter, nestingLimit); + } + + template <typename TFilter> + bool readObject(VariantData *variant, size_t n, TFilter filter, + NestingLimit nestingLimit) { + if (nestingLimit.reached()) { + _error = DeserializationError::TooDeep; + return false; + } + + CollectionData *object = filter.allowObject() ? &variant->toObject() : 0; + + for (; n; --n) { + if (!readKey()) + return false; + + const char *key = _stringStorage.c_str(); + TFilter memberFilter = filter[key]; + VariantData *member; + + if (memberFilter.allow()) { + // Save key in memory pool. + // This MUST be done before adding the slot. + key = _stringStorage.save(); + + VariantSlot *slot = object->addSlot(_pool); + if (!slot) { + _error = DeserializationError::NoMemory; + return false; + } + + slot->setKey(key, typename TStringStorage::storage_policy()); + + member = slot->data(); + } else { + member = 0; + } + + if (!parseVariant(member, memberFilter, nestingLimit.decrement())) + return false; + } + + return true; + } + + bool readKey() { + uint8_t code; + if (!readByte(code)) + return false; + + 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 invalidInput(); + } + } + + template <typename T> + bool skipExt() { + T size; + if (!readInteger(size)) + return false; + return skipBytes(size + 1); + } + + MemoryPool *_pool; + TReader _reader; + TStringStorage _stringStorage; + DeserializationError _error; + bool _foundSomething; +}; + +// +// deserializeMsgPack(JsonDocument&, const std::string&, ...) +// +// ... = NestingLimit +template <typename TString> +DeserializationError deserializeMsgPack( + JsonDocument &doc, const TString &input, + NestingLimit nestingLimit = NestingLimit()) { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, + AllowAllFilter()); +} +// ... = Filter, NestingLimit +template <typename TString> +DeserializationError deserializeMsgPack( + JsonDocument &doc, const TString &input, Filter filter, + NestingLimit nestingLimit = NestingLimit()) { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); +} +// ... = NestingLimit, Filter +template <typename TString> +DeserializationError deserializeMsgPack(JsonDocument &doc, const TString &input, + NestingLimit nestingLimit, + Filter filter) { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); +} + +// +// deserializeMsgPack(JsonDocument&, std::istream&, ...) +// +// ... = NestingLimit +template <typename TStream> +DeserializationError deserializeMsgPack( + JsonDocument &doc, TStream &input, + NestingLimit nestingLimit = NestingLimit()) { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, + AllowAllFilter()); +} +// ... = Filter, NestingLimit +template <typename TStream> +DeserializationError deserializeMsgPack( + JsonDocument &doc, TStream &input, Filter filter, + NestingLimit nestingLimit = NestingLimit()) { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); +} +// ... = NestingLimit, Filter +template <typename TStream> +DeserializationError deserializeMsgPack(JsonDocument &doc, TStream &input, + NestingLimit nestingLimit, + Filter filter) { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); +} + +// +// deserializeMsgPack(JsonDocument&, char*, ...) +// +// ... = NestingLimit +template <typename TChar> +DeserializationError deserializeMsgPack( + JsonDocument &doc, TChar *input, + NestingLimit nestingLimit = NestingLimit()) { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, + AllowAllFilter()); +} +// ... = Filter, NestingLimit +template <typename TChar> +DeserializationError deserializeMsgPack( + JsonDocument &doc, TChar *input, Filter filter, + NestingLimit nestingLimit = NestingLimit()) { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); +} +// ... = NestingLimit, Filter +template <typename TChar> +DeserializationError deserializeMsgPack(JsonDocument &doc, TChar *input, + NestingLimit nestingLimit, + Filter filter) { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); +} + +// +// deserializeMsgPack(JsonDocument&, char*, size_t, ...) +// +// ... = NestingLimit +template <typename TChar> +DeserializationError deserializeMsgPack( + JsonDocument &doc, TChar *input, size_t inputSize, + NestingLimit nestingLimit = NestingLimit()) { + return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit, + AllowAllFilter()); +} +// ... = Filter, NestingLimit +template <typename TChar> +DeserializationError deserializeMsgPack( + JsonDocument &doc, TChar *input, size_t inputSize, Filter filter, + NestingLimit nestingLimit = NestingLimit()) { + return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit, + filter); +} +// ... = NestingLimit, Filter +template <typename TChar> +DeserializationError deserializeMsgPack(JsonDocument &doc, TChar *input, + size_t inputSize, + NestingLimit nestingLimit, + Filter filter) { + return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit, + filter); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/MsgPack/MsgPackSerializer.hpp b/include/lib/ArduinoJson/MsgPack/MsgPackSerializer.hpp new file mode 100644 index 0000000..b1cd872 --- /dev/null +++ b/include/lib/ArduinoJson/MsgPack/MsgPackSerializer.hpp @@ -0,0 +1,212 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/MsgPack/endianess.hpp> +#include <ArduinoJson/Polyfills/assert.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Serialization/CountingDecorator.hpp> +#include <ArduinoJson/Serialization/measure.hpp> +#include <ArduinoJson/Serialization/serialize.hpp> +#include <ArduinoJson/Variant/VariantData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TWriter> +class MsgPackSerializer : public Visitor<size_t> { + public: + static const bool producesText = false; + + MsgPackSerializer(TWriter writer) : _writer(writer) {} + + template <typename T> + typename enable_if<sizeof(T) == 4, size_t>::type visitFloat(T value32) { + writeByte(0xCA); + writeInteger(value32); + return bytesWritten(); + } + + template <typename T> + ARDUINOJSON_NO_SANITIZE("float-cast-overflow") + typename enable_if<sizeof(T) == 8, size_t>::type visitFloat(T value64) { + float value32 = float(value64); + if (value32 == value64) { + writeByte(0xCA); + writeInteger(value32); + } else { + writeByte(0xCB); + writeInteger(value64); + } + return bytesWritten(); + } + + size_t visitArray(const CollectionData& array) { + size_t n = array.size(); + if (n < 0x10) { + writeByte(uint8_t(0x90 + array.size())); + } else if (n < 0x10000) { + writeByte(0xDC); + writeInteger(uint16_t(n)); + } else { + writeByte(0xDD); + writeInteger(uint32_t(n)); + } + for (VariantSlot* slot = array.head(); slot; slot = slot->next()) { + slot->data()->accept(*this); + } + return bytesWritten(); + } + + size_t visitObject(const CollectionData& object) { + size_t n = object.size(); + if (n < 0x10) { + writeByte(uint8_t(0x80 + n)); + } else if (n < 0x10000) { + writeByte(0xDE); + writeInteger(uint16_t(n)); + } else { + writeByte(0xDF); + writeInteger(uint32_t(n)); + } + for (VariantSlot* slot = object.head(); slot; slot = slot->next()) { + visitString(slot->key()); + slot->data()->accept(*this); + } + return bytesWritten(); + } + + size_t visitString(const char* value) { + ARDUINOJSON_ASSERT(value != NULL); + + size_t n = strlen(value); + + if (n < 0x20) { + writeByte(uint8_t(0xA0 + n)); + } else if (n < 0x100) { + writeByte(0xD9); + writeInteger(uint8_t(n)); + } else if (n < 0x10000) { + writeByte(0xDA); + writeInteger(uint16_t(n)); + } else { + writeByte(0xDB); + writeInteger(uint32_t(n)); + } + writeBytes(reinterpret_cast<const uint8_t*>(value), n); + return bytesWritten(); + } + + size_t visitRawJson(const char* data, size_t size) { + writeBytes(reinterpret_cast<const uint8_t*>(data), size); + return bytesWritten(); + } + + size_t visitSignedInteger(Integer value) { + if (value > 0) { + visitUnsignedInteger(static_cast<UInt>(value)); + } else if (value >= -0x20) { + writeInteger(int8_t(value)); + } else if (value >= -0x80) { + writeByte(0xD0); + writeInteger(int8_t(value)); + } else if (value >= -0x8000) { + writeByte(0xD1); + writeInteger(int16_t(value)); + } +#if ARDUINOJSON_USE_LONG_LONG + else if (value >= -0x80000000LL) +#else + else +#endif + { + writeByte(0xD2); + writeInteger(int32_t(value)); + } +#if ARDUINOJSON_USE_LONG_LONG + else { + writeByte(0xD3); + writeInteger(int64_t(value)); + } +#endif + return bytesWritten(); + } + + size_t visitUnsignedInteger(UInt value) { + if (value <= 0x7F) { + writeInteger(uint8_t(value)); + } else if (value <= 0xFF) { + writeByte(0xCC); + writeInteger(uint8_t(value)); + } else if (value <= 0xFFFF) { + writeByte(0xCD); + writeInteger(uint16_t(value)); + } +#if ARDUINOJSON_USE_LONG_LONG + else if (value <= 0xFFFFFFFF) +#else + else +#endif + { + writeByte(0xCE); + writeInteger(uint32_t(value)); + } +#if ARDUINOJSON_USE_LONG_LONG + else { + writeByte(0xCF); + writeInteger(uint64_t(value)); + } +#endif + return bytesWritten(); + } + + size_t visitBoolean(bool value) { + writeByte(value ? 0xC3 : 0xC2); + return bytesWritten(); + } + + size_t visitNull() { + writeByte(0xC0); + return bytesWritten(); + } + + private: + size_t bytesWritten() const { + return _writer.count(); + } + + void writeByte(uint8_t c) { + _writer.write(c); + } + + void writeBytes(const uint8_t* p, size_t n) { + _writer.write(p, n); + } + + template <typename T> + void writeInteger(T value) { + fixEndianess(value); + writeBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value)); + } + + CountingDecorator<TWriter> _writer; +}; + +template <typename TSource, typename TDestination> +inline size_t serializeMsgPack(const TSource& source, TDestination& output) { + return serialize<MsgPackSerializer>(source, output); +} + +template <typename TSource> +inline size_t serializeMsgPack(const TSource& source, void* output, + size_t size) { + return serialize<MsgPackSerializer>(source, output, size); +} + +template <typename TSource> +inline size_t measureMsgPack(const TSource& source) { + return measure<MsgPackSerializer>(source); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/MsgPack/endianess.hpp b/include/lib/ArduinoJson/MsgPack/endianess.hpp new file mode 100644 index 0000000..74f7e9d --- /dev/null +++ b/include/lib/ArduinoJson/MsgPack/endianess.hpp @@ -0,0 +1,41 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Polyfills/utility.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +#if ARDUINOJSON_LITTLE_ENDIAN +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) { + fixEndianess(reinterpret_cast<uint8_t *>(&value), + integral_constant<size_t, sizeof(T)>()); +} +#else +template <typename T> +inline void fixEndianess(T &) {} +#endif + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/MsgPack/ieee754.hpp b/include/lib/ArduinoJson/MsgPack/ieee754.hpp new file mode 100644 index 0000000..016d533 --- /dev/null +++ b/include/lib/ArduinoJson/MsgPack/ieee754.hpp @@ -0,0 +1,18 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +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 ARDUINOJSON_NAMESPACE |