// ArduinoJson - https://arduinojson.org // Copyright Benoit Blanchon 2014-2021 // MIT License #pragma once #include "lib/ArduinoJson/Deserialization/deserialize.hpp" #include "lib/ArduinoJson/Memory/MemoryPool.hpp" #include "lib/ArduinoJson/MsgPack/endianess.hpp" #include "lib/ArduinoJson/MsgPack/ieee754.hpp" #include "lib/ArduinoJson/Polyfills/type_traits.hpp" #include "lib/ArduinoJson/Variant/VariantData.hpp" namespace ARDUINOJSON_NAMESPACE { template class MsgPackDeserializer { public: MsgPackDeserializer(MemoryPool &pool, TReader reader, TStringStorage stringStorage) : _pool(&pool), _reader(reader), _stringStorage(stringStorage), _error(DeserializationError::Ok), _foundSomething(false) {} template 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 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(); case 0xc5: // bin 16 (not supported) return skipString(); case 0xc6: // bin 32 (not supported) return skipString(); case 0xc7: // ext 8 (not supported) return skipExt(); case 0xc8: // ext 16 (not supported) return skipExt(); case 0xc9: // ext 32 (not supported) return skipExt(); case 0xca: if (allowValue) return readFloat(variant); else return skipBytes(4); case 0xcb: if (allowValue) return readDouble(variant); else return skipBytes(8); case 0xcc: if (allowValue) return readInteger(variant); else return skipBytes(1); case 0xcd: if (allowValue) return readInteger(variant); else return skipBytes(2); case 0xce: if (allowValue) return readInteger(variant); else return skipBytes(4); case 0xcf: #if ARDUINOJSON_USE_LONG_LONG if (allowValue) return readInteger(variant); else return skipBytes(8); #else return skipBytes(8); // not supported #endif case 0xd0: if (allowValue) return readInteger(variant); else return skipBytes(1); case 0xd1: if (allowValue) return readInteger(variant); else return skipBytes(2); case 0xd2: if (allowValue) return readInteger(variant); else return skipBytes(4); case 0xd3: #if ARDUINOJSON_USE_LONG_LONG if (allowValue) return readInteger(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(variant); else return skipString(); case 0xda: if (allowValue) return readString(variant); else return skipString(); case 0xdb: if (allowValue) return readString(variant); else return skipString(); case 0xdc: return readArray(variant, filter, nestingLimit); case 0xdd: return readArray(variant, filter, nestingLimit); case 0xde: return readObject(variant, filter, nestingLimit); case 0xdf: return readObject(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(code)); return true; } bool readByte(uint8_t &value) { int c = _reader.read(); if (c < 0) { _error = DeserializationError::IncompleteInput; return false; } value = static_cast(c); return true; } bool readBytes(uint8_t *p, size_t n) { if (_reader.readBytes(reinterpret_cast(p), n) == n) return true; _error = DeserializationError::IncompleteInput; return false; } template bool readBytes(T &value) { return readBytes(reinterpret_cast(&value), sizeof(value)); } bool skipBytes(size_t n) { for (; n; --n) { if (_reader.read() < 0) { _error = DeserializationError::IncompleteInput; return false; } } return true; } template bool readInteger(T &value) { if (!readBytes(value)) return false; fixEndianess(value); return true; } template bool readInteger(VariantData *variant) { T value; if (!readInteger(value)) return false; variant->setInteger(value); return true; } template typename enable_if::type readFloat( VariantData *variant) { T value; if (!readBytes(value)) return false; fixEndianess(value); variant->setFloat(value); return true; } template typename enable_if::type readDouble( VariantData *variant) { T value; if (!readBytes(value)) return false; fixEndianess(value); variant->setFloat(value); return true; } template typename enable_if::type readDouble( VariantData *variant) { uint8_t i[8]; // input is 8 bytes T value; // output is 4 bytes uint8_t *o = reinterpret_cast(&value); if (!readBytes(i, 8)) return false; doubleToFloat(i, o); fixEndianess(value); variant->setFloat(value); return true; } template bool readString(VariantData *variant) { T size; if (!readInteger(size)) return false; return readString(variant, size); } template bool readString() { T size; if (!readInteger(size)) return false; return readString(size); } template 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(c)); } _stringStorage.append('\0'); if (!_stringStorage.isValid()) { _error = DeserializationError::NoMemory; return false; } return true; } template bool readArray(VariantData *variant, TFilter filter, NestingLimit nestingLimit) { TSize size; if (!readInteger(size)) return false; return readArray(variant, size, filter, nestingLimit); } template 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 bool readObject(VariantData *variant, TFilter filter, NestingLimit nestingLimit) { TSize size; if (!readInteger(size)) return false; return readObject(variant, size, filter, nestingLimit); } template 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(); case 0xda: return readString(); case 0xdb: return readString(); default: return invalidInput(); } } template 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 DeserializationError deserializeMsgPack( JsonDocument &doc, const TString &input, NestingLimit nestingLimit = NestingLimit()) { return deserialize(doc, input, nestingLimit, AllowAllFilter()); } // ... = Filter, NestingLimit template DeserializationError deserializeMsgPack( JsonDocument &doc, const TString &input, Filter filter, NestingLimit nestingLimit = NestingLimit()) { return deserialize(doc, input, nestingLimit, filter); } // ... = NestingLimit, Filter template DeserializationError deserializeMsgPack(JsonDocument &doc, const TString &input, NestingLimit nestingLimit, Filter filter) { return deserialize(doc, input, nestingLimit, filter); } // // deserializeMsgPack(JsonDocument&, std::istream&, ...) // // ... = NestingLimit template DeserializationError deserializeMsgPack( JsonDocument &doc, TStream &input, NestingLimit nestingLimit = NestingLimit()) { return deserialize(doc, input, nestingLimit, AllowAllFilter()); } // ... = Filter, NestingLimit template DeserializationError deserializeMsgPack( JsonDocument &doc, TStream &input, Filter filter, NestingLimit nestingLimit = NestingLimit()) { return deserialize(doc, input, nestingLimit, filter); } // ... = NestingLimit, Filter template DeserializationError deserializeMsgPack(JsonDocument &doc, TStream &input, NestingLimit nestingLimit, Filter filter) { return deserialize(doc, input, nestingLimit, filter); } // // deserializeMsgPack(JsonDocument&, char*, ...) // // ... = NestingLimit template DeserializationError deserializeMsgPack( JsonDocument &doc, TChar *input, NestingLimit nestingLimit = NestingLimit()) { return deserialize(doc, input, nestingLimit, AllowAllFilter()); } // ... = Filter, NestingLimit template DeserializationError deserializeMsgPack( JsonDocument &doc, TChar *input, Filter filter, NestingLimit nestingLimit = NestingLimit()) { return deserialize(doc, input, nestingLimit, filter); } // ... = NestingLimit, Filter template DeserializationError deserializeMsgPack(JsonDocument &doc, TChar *input, NestingLimit nestingLimit, Filter filter) { return deserialize(doc, input, nestingLimit, filter); } // // deserializeMsgPack(JsonDocument&, char*, size_t, ...) // // ... = NestingLimit template DeserializationError deserializeMsgPack( JsonDocument &doc, TChar *input, size_t inputSize, NestingLimit nestingLimit = NestingLimit()) { return deserialize(doc, input, inputSize, nestingLimit, AllowAllFilter()); } // ... = Filter, NestingLimit template DeserializationError deserializeMsgPack( JsonDocument &doc, TChar *input, size_t inputSize, Filter filter, NestingLimit nestingLimit = NestingLimit()) { return deserialize(doc, input, inputSize, nestingLimit, filter); } // ... = NestingLimit, Filter template DeserializationError deserializeMsgPack(JsonDocument &doc, TChar *input, size_t inputSize, NestingLimit nestingLimit, Filter filter) { return deserialize(doc, input, inputSize, nestingLimit, filter); } } // namespace ARDUINOJSON_NAMESPACE