From 712005219c6064071535aa7c410a23ee30bfcd6e Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Tue, 13 Oct 2020 09:40:39 +0200 Subject: [PATCH] Added filtering for MessagePack (closes #1298, closes #1394) --- CHANGELOG.md | 1 + extras/tests/JsonDeserializer/filter.cpp | 9 + .../tests/MsgPackDeserializer/CMakeLists.txt | 1 + extras/tests/MsgPackDeserializer/filter.cpp | 1119 +++++++++++++++++ src/ArduinoJson/Json/JsonDeserializer.hpp | 46 +- .../MsgPack/MsgPackDeserializer.hpp | 488 +++++-- 6 files changed, 1534 insertions(+), 130 deletions(-) create mode 100644 extras/tests/MsgPackDeserializer/filter.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 7facd64a..382f1497 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ HEAD * Added `DeserializationError::EmptyInput` which tells if the input was empty * Added `DeserializationError::f_str()` which returns a `const __FlashStringHelper*` (issue #846) * Added `operator|(JsonVariantConst, JsonVariantConst)` +* Added filtering for MessagePack (issue #1298, PR #1394 by Luca Passarella) * Moved float convertion tables to PROGMEM * Fixed `JsonVariant::set((char*)0)` which returned false instead of true (issue #1368) * Fixed error `No such file or directory #include ` (issue #1381) diff --git a/extras/tests/JsonDeserializer/filter.cpp b/extras/tests/JsonDeserializer/filter.cpp index 3e7867b9..5a9c30d5 100644 --- a/extras/tests/JsonDeserializer/filter.cpp +++ b/extras/tests/JsonDeserializer/filter.cpp @@ -62,6 +62,15 @@ TEST_CASE("Filtering") { "null", 0 }, + { + // Member is a string, but filter wants an array + "{\"example\":\"example\"}", + "{\"example\":[true]}", + 10, + DeserializationError::Ok, + "{\"example\":null}", + JSON_OBJECT_SIZE(1) + 8 + }, { // Input is an array, but filter wants an object "[\"hello\",\"world\"]", diff --git a/extras/tests/MsgPackDeserializer/CMakeLists.txt b/extras/tests/MsgPackDeserializer/CMakeLists.txt index 5052842d..a7c557ec 100644 --- a/extras/tests/MsgPackDeserializer/CMakeLists.txt +++ b/extras/tests/MsgPackDeserializer/CMakeLists.txt @@ -8,6 +8,7 @@ add_executable(MsgPackDeserializerTests deserializeStaticVariant.cpp deserializeVariant.cpp doubleToFloat.cpp + filter.cpp incompleteInput.cpp input_types.cpp misc.cpp diff --git a/extras/tests/MsgPackDeserializer/filter.cpp b/extras/tests/MsgPackDeserializer/filter.cpp new file mode 100644 index 00000000..3578450b --- /dev/null +++ b/extras/tests/MsgPackDeserializer/filter.cpp @@ -0,0 +1,1119 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#include +#include + +using namespace ARDUINOJSON_NAMESPACE; + +TEST_CASE("deserializeMsgPack() filter") { + StaticJsonDocument<4096> doc; + DeserializationError error; + + StaticJsonDocument<200> filter; + DeserializationOption::Filter filterOpt(filter); + + SECTION("root is fixmap") { + SECTION("filter = {include:true,ignore:false)") { + filter["include"] = true; + filter["ignore"] = false; + + SECTION("input truncated after ignored key") { + error = deserializeMsgPack(doc, "\x82\xA6ignore", 8, filterOpt); + + CHECK(error == DeserializationError::IncompleteInput); + CHECK(doc.as() == "{}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(0)); + } + + SECTION("input truncated after inside skipped uint 8") { + error = deserializeMsgPack(doc, "\x82\xA6ignore\xCC\x2A\xA7include\x2A", + 9, filterOpt); + + CHECK(error == DeserializationError::IncompleteInput); + CHECK(doc.as() == "{}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(0)); + } + + SECTION("input truncated after before skipped string size") { + error = deserializeMsgPack(doc, "\x82\xA6ignore\xd9", 9, filterOpt); + + CHECK(error == DeserializationError::IncompleteInput); + CHECK(doc.as() == "{}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(0)); + } + + SECTION("input truncated after before skipped ext size") { + error = deserializeMsgPack(doc, "\x82\xA6ignore\xC7", 9, filterOpt); + + CHECK(error == DeserializationError::IncompleteInput); + CHECK(doc.as() == "{}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(0)); + } + + SECTION("skip nil") { + error = deserializeMsgPack(doc, "\x82\xA6ignore\xC0\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("reject 0xc1") { + error = deserializeMsgPack(doc, "\x82\xA6ignore\xC1\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::InvalidInput); + } + + SECTION("skip false") { + error = deserializeMsgPack(doc, "\x82\xA6ignore\xC2\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip true") { + error = deserializeMsgPack(doc, "\x82\xA6ignore\xC3\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip positive fixint") { + error = deserializeMsgPack(doc, "\x82\xA6ignore\x2A\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip negative fixint") { + error = deserializeMsgPack(doc, "\x82\xA6ignore\xFF\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip uint 8") { + error = deserializeMsgPack(doc, "\x82\xA6ignore\xCC\x2A\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip int 8") { + error = deserializeMsgPack(doc, "\x82\xA6ignore\xD0\x2A\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip uint 16") { + error = deserializeMsgPack( + doc, "\x82\xA6ignore\xcd\x30\x39\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip int 16") { + error = deserializeMsgPack( + doc, "\x82\xA6ignore\xD1\xCF\xC7\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip uint 32") { + error = deserializeMsgPack( + doc, "\x82\xA6ignore\xCE\x12\x34\x56\x78\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip int 32") { + error = deserializeMsgPack( + doc, "\x82\xA6ignore\xD2\xB6\x69\xFD\x2E\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip uint 64") { + error = deserializeMsgPack( + doc, + "\x82\xA6ignore\xCF\x12\x34\x56\x78\x9A\xBC\xDE\xF0\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip int 64") { + error = deserializeMsgPack( + doc, + "\x82\xA6ignore\xD3\x12\x34\x56\x78\x9A\xBC\xDE\xF0\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip float 32") { + error = deserializeMsgPack( + doc, "\x82\xA6ignore\xCA\x40\x48\xF5\xC3\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip float 64") { + error = deserializeMsgPack( + doc, + "\x82\xA6ignore\xCB\x40\x09\x21\xCA\xC0\x83\x12\x6F\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip fixstr") { + error = deserializeMsgPack( + doc, "\x82\xA6ignore\xABhello world\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip str 8") { + error = deserializeMsgPack( + doc, "\x82\xA6ignore\xd9\x05hello\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip str 16") { + error = deserializeMsgPack( + doc, "\x82\xA6ignore\xda\x00\x05hello\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip str 32") { + error = deserializeMsgPack( + doc, "\x82\xA6ignore\xdb\x00\x00\x00\x05hello\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip bin 8") { + error = deserializeMsgPack( + doc, "\x82\xA6ignore\xC4\x05hello\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip bin 16") { + error = deserializeMsgPack( + doc, "\x82\xA6ignore\xC5\x00\x05hello\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip bin 32") { + error = deserializeMsgPack( + doc, "\x82\xA6ignore\xC6\x00\x00\x00\x05hello\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip fixarray") { + error = deserializeMsgPack( + doc, "\x82\xA6ignore\x92\x01\x02\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip array 16") { + error = deserializeMsgPack( + doc, "\x82\xA6ignore\xDC\x00\x02\xA5hello\xA5world\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip array 32") { + error = deserializeMsgPack( + doc, + "\x82\xA6ignore" + "\xDD\x00\x00\x00\x02\xCA\x00\x00\x00\x00\xCA\x40\x48\xF5\xC3" + "\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip fixmap") { + error = deserializeMsgPack( + doc, "\x82\xA6ignore\x82\xA3one\x01\xA3two\x02\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip map 16") { + error = deserializeMsgPack(doc, + "\x82\xA6ignore" + "\xDE\x00\x02\xA1H\xA5hello\xA1W\xA5world" + "\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip map 32") { + error = deserializeMsgPack(doc, + "\x82\xA6ignore" + "\xDF\x00\x00\x00\x02" + "\xA4zero\xCA\x00\x00\x00\x00" + "\xA2pi\xCA\x40\x48\xF5\xC3" + "\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip fixext 1") { + error = deserializeMsgPack(doc, + "\x82\xA6ignore" + "\xd4\x01\x02" + "\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip fixext 2") { + error = deserializeMsgPack(doc, + "\x82\xA6ignore" + "\xd5\x01\x02\x03" + "\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip fixext 4") { + error = deserializeMsgPack(doc, + "\x82\xA6ignore" + "\xd6\x01\x02\x03\x04\x05" + "\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip fixext 8") { + error = deserializeMsgPack(doc, + "\x82\xA6ignore" + "\xd7\x01\x02\x03\x04\x05\x06\x07\x08\x09" + "\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip fixext 16") { + error = + deserializeMsgPack(doc, + "\x82\xA6ignore" + "\xd8\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A" + "\x0B\x0C\x0D\x0E\x0F\x10\x11" + "\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip ext 8") { + error = deserializeMsgPack(doc, + "\x82\xA6ignore" + "\xc7\x02\x00\x01\x02" + "\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip ext 16") { + error = deserializeMsgPack(doc, + "\x82\xA6ignore" + "\xc8\x00\x02\x00\x01\x02" + "\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + + SECTION("skip ext 32") { + error = deserializeMsgPack(doc, + "\x82\xA6ignore" + "\xc9\x00\x00\x00\x02\x00\x01\x02" + "\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 8); + } + } + + SECTION("Filter = {arronly:[{measure:true}],include:true}") { + filter["onlyarr"][0]["measure"] = true; + filter["include"] = true; + + CAPTURE(filter.as()); + + SECTION("include fixarray") { + error = deserializeMsgPack(doc, + "\x82\xA7onlyarr\x92" + "\x82\xA8location\x01\xA7measure\x02" + "\x82\xA8location\x02\xA7measure\x04" + "\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == + "{\"onlyarr\":[{\"measure\":2},{\"measure\":4}],\"include\":42}"); + CHECK(doc.memoryUsage() == + JSON_ARRAY_SIZE(2) + 2 * JSON_OBJECT_SIZE(2) + 24); + } + + SECTION("include array 16") { + error = deserializeMsgPack(doc, + "\x82\xA7onlyarr" + "\xDC\x00\x02" + "\x82\xA8location\x01\xA7measure\x02" + "\x82\xA8location\x02\xA7measure\x04" + "\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == + "{\"onlyarr\":[{\"measure\":2},{\"measure\":4}],\"include\":42}"); + CHECK(doc.memoryUsage() == + JSON_ARRAY_SIZE(2) + 2 * JSON_OBJECT_SIZE(2) + 24); + } + + SECTION("include array 32") { + error = deserializeMsgPack(doc, + "\x82\xA7onlyarr" + "\xDD\x00\x00\x00\x02" + "\x82\xA8location\x01\xA7measure\x02" + "\x82\xA8location\x02\xA7measure\x04" + "\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == + "{\"onlyarr\":[{\"measure\":2},{\"measure\":4}],\"include\":42}"); + CHECK(doc.memoryUsage() == + JSON_ARRAY_SIZE(2) + 2 * JSON_OBJECT_SIZE(2) + 24); + } + + SECTION("skip null") { + error = deserializeMsgPack(doc, "\x82\xA7onlyarr\xC0\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyarr\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip false") { + error = deserializeMsgPack(doc, "\x82\xA7onlyarr\xC2\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyarr\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip true") { + error = deserializeMsgPack(doc, "\x82\xA7onlyarr\xC3\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyarr\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip positive fixint") { + error = deserializeMsgPack(doc, "\x82\xA7onlyarr\x2A\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyarr\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip negative fixint") { + error = deserializeMsgPack(doc, "\x82\xA7onlyarr\xFF\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyarr\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip uint 8") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyarr\xCC\x2A\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyarr\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip uint 16") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyarr\xcd\x30\x39\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyarr\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip uint 32") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyarr\xCE\x12\x34\x56\x78\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyarr\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip uint 64") { + error = deserializeMsgPack(doc, + "\x82\xA7onlyarr\xCF\x12\x34\x56\x78\x9A\xBC" + "\xDE\xF0\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyarr\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip int 8") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyarr\xD0\x2A\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyarr\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip int 16") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyarr\xD1\xCF\xC7\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyarr\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip int 32") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyarr\xD2\xB6\x69\xFD\x2E\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyarr\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip int 64") { + error = deserializeMsgPack(doc, + "\x82\xA7onlyarr\xD3\x12\x34\x56\x78\x9A\xBC" + "\xDE\xF0\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyarr\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip float 32") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyarr\xCA\x40\x48\xF5\xC3\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyarr\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip float 64") { + error = deserializeMsgPack(doc, + "\x82\xA7onlyarr\xCB\x40\x09\x21\xCA\xC0\x83" + "\x12\x6F\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyarr\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip fixstr") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyarr\xABhello world\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyarr\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip str 8") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyarr\xd9\x05hello\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + } + + SECTION("skip str 16") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyarr\xda\x00\x05hello\xA7include\x2A", filterOpt); + + CHECK(doc.as() == "{\"onlyarr\":null,\"include\":42}"); + } + + SECTION("skip str 32") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyarr\xdb\x00\x00\x00\x05hello\xA7include\x2A", + filterOpt); + + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip fixmap") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyarr\x82\xA3one\x01\xA3two\x02\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyarr\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip map 16") { + error = deserializeMsgPack(doc, + "\x82\xA7onlyarr" + "\xDE\x00\x02\xA1H\xA5hello\xA1W\xA5world" + "\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyarr\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip map 32") { + error = deserializeMsgPack(doc, + "\x82\xA7onlyarr" + "\xDF\x00\x00\x00\x02" + "\xA4zero\xCA\x00\x00\x00\x00" + "\xA2pi\xCA\x40\x48\xF5\xC3" + "\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyarr\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + } + } + + SECTION("root is fixarray") { + SECTION("filter = [false, true]") { + filter[0] = false; // only the first elment of the filter matters + filter[1] = true; // so this one is ignored + + SECTION("input = [1,2,3]") { + error = deserializeMsgPack(doc, "\x93\x01\x02\x03", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "[]"); + CHECK(doc.memoryUsage() == JSON_ARRAY_SIZE(0)); + } + } + + SECTION("filter = [true, false]") { + filter[0] = true; // only the first elment of the filter matters + filter[1] = false; // so this one is ignored + + SECTION("input = [1,2,3]") { + error = deserializeMsgPack(doc, "\x93\x01\x02\x03", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "[1,2,3]"); + CHECK(doc.memoryUsage() == JSON_ARRAY_SIZE(3)); + } + } + } + + SECTION("Filter = {onlyobj:{measure:true},include:true}") { + filter["onlyobj"]["measure"] = true; + filter["include"] = true; + + CAPTURE(filter.as()); + + SECTION("include fixmap") { + error = deserializeMsgPack(doc, + "\x82\xA7onlyobj" + "\x82\xA8location\x01\xA7measure\x02" + "\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == + "{\"onlyobj\":{\"measure\":2},\"include\":42}"); + CHECK(doc.memoryUsage() == + JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(1) + 24); + } + + SECTION("include map 16") { + error = deserializeMsgPack(doc, + "\x82\xA7onlyobj" + "\xDE\x00\x02\xA8location\x01\xA7measure\x02" + "\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == + "{\"onlyobj\":{\"measure\":2},\"include\":42}"); + CHECK(doc.memoryUsage() == + JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(1) + 24); + } + + SECTION("include map 32") { + error = deserializeMsgPack(doc, + "\x82\xA7onlyobj" + "\xDF\x00\x00\x00\x02" + "\xA8location\x01\xA7measure\x02" + "\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == + "{\"onlyobj\":{\"measure\":2},\"include\":42}"); + CHECK(doc.memoryUsage() == + JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(1) + 24); + } + + SECTION("skip null") { + error = deserializeMsgPack(doc, "\x82\xA7onlyobj\xC0\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyobj\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip false") { + error = deserializeMsgPack(doc, "\x82\xA7onlyobj\xC2\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyobj\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip true") { + error = deserializeMsgPack(doc, "\x82\xA7onlyobj\xC3\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyobj\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip positive fixint") { + error = deserializeMsgPack(doc, "\x82\xA7onlyobj\x2A\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyobj\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip negative fixint") { + error = deserializeMsgPack(doc, "\x82\xA7onlyobj\xFF\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyobj\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip uint 8") { + error = deserializeMsgPack(doc, "\x82\xA7onlyobj\xCC\x2A\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyobj\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip uint 16") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyobj\xcd\x30\x39\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyobj\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip uint 32") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyobj\xCE\x12\x34\x56\x78\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyobj\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip uint 64") { + error = deserializeMsgPack(doc, + "\x82\xA7onlyobj\xCF\x12\x34\x56\x78\x9A\xBC" + "\xDE\xF0\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyobj\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip int 8") { + error = deserializeMsgPack(doc, "\x82\xA7onlyobj\xD0\x2A\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyobj\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip int 16") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyobj\xD1\xCF\xC7\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyobj\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip int 32") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyobj\xD2\xB6\x69\xFD\x2E\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyobj\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip int 64") { + error = deserializeMsgPack(doc, + "\x82\xA7onlyobj\xD3\x12\x34\x56\x78\x9A\xBC" + "\xDE\xF0\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyobj\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip float 32") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyobj\xCA\x40\x48\xF5\xC3\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyobj\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip float 64") { + error = deserializeMsgPack(doc, + "\x82\xA7onlyobj\xCB\x40\x09\x21\xCA\xC0\x83" + "\x12\x6F\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyobj\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip fixstr") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyobj\xABhello world\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyobj\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip str 8") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyobj\xd9\x05hello\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + } + + SECTION("skip str 16") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyobj\xda\x00\x05hello\xA7include\x2A", filterOpt); + + CHECK(doc.as() == "{\"onlyobj\":null,\"include\":42}"); + } + + SECTION("skip str 32") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyobj\xdb\x00\x00\x00\x05hello\xA7include\x2A", + filterOpt); + + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip fixarray") { + error = deserializeMsgPack( + doc, "\x82\xA7onlyobj\x92\x01\x02\xA7include\x2A", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyobj\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip array 16") { + error = deserializeMsgPack(doc, + "\x82\xA7onlyobj\xDC\x00\x01\xA7" + "example\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyobj\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + + SECTION("skip array 32") { + error = deserializeMsgPack(doc, + "\x82\xA7onlyobj" + "\xDD\x00\x00\x00\x02\x01\x02" + "\xA7include\x2A", + filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.as() == "{\"onlyobj\":null,\"include\":42}"); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16); + } + } + + SECTION("filter = true") { + filter.set(true); + + error = deserializeMsgPack(doc, "\x90", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.is() == true); + CHECK(doc.size() == 0); + } + + SECTION("filter = false") { + filter.set(false); + + SECTION("input = fixarray") { + error = deserializeMsgPack(doc, "\x92\x01\x02", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.isNull() == true); + } + + SECTION("input = array 16") { + error = deserializeMsgPack(doc, "\xDC\x00\x02\x01\x02", filterOpt); + + CHECK(error == DeserializationError::Ok); + CHECK(doc.isNull() == true); + } + + SECTION("array too deep") { + error = deserializeMsgPack(doc, "\x91\x91\x91\x91\x91", 5, filterOpt, + DeserializationOption::NestingLimit(4)); + + CHECK(error == DeserializationError::TooDeep); + } + + SECTION("object too deep") { + error = deserializeMsgPack( + doc, "\x81\xA1z\x81\xA1z\x81\xA1z\x81\xA1z\x81\xA1z", 15, filterOpt, + DeserializationOption::NestingLimit(4)); + + CHECK(error == DeserializationError::TooDeep); + } + } +} + +TEST_CASE("Overloads") { + StaticJsonDocument<256> doc; + StaticJsonDocument<256> filter; + + using namespace DeserializationOption; + + // deserializeMsgPack(..., Filter) + + SECTION("const char*, Filter") { + deserializeMsgPack(doc, "{}", Filter(filter)); + } + + SECTION("const char*, size_t, Filter") { + deserializeMsgPack(doc, "{}", 2, Filter(filter)); + } + + SECTION("const std::string&, Filter") { + deserializeMsgPack(doc, std::string("{}"), Filter(filter)); + } + + SECTION("std::istream&, Filter") { + std::stringstream s("{}"); + deserializeMsgPack(doc, s, Filter(filter)); + } + +#ifdef HAS_VARIABLE_LENGTH_ARRAY + SECTION("char[n], Filter") { + int i = 4; + char vla[i]; + strcpy(vla, "{}"); + deserializeMsgPack(doc, vla, Filter(filter)); + } +#endif + + // deserializeMsgPack(..., Filter, NestingLimit) + + SECTION("const char*, Filter, NestingLimit") { + deserializeMsgPack(doc, "{}", Filter(filter), NestingLimit(5)); + } + + SECTION("const char*, size_t, Filter, NestingLimit") { + deserializeMsgPack(doc, "{}", 2, Filter(filter), NestingLimit(5)); + } + + SECTION("const std::string&, Filter, NestingLimit") { + deserializeMsgPack(doc, std::string("{}"), Filter(filter), NestingLimit(5)); + } + + SECTION("std::istream&, Filter, NestingLimit") { + std::stringstream s("{}"); + deserializeMsgPack(doc, s, Filter(filter), NestingLimit(5)); + } + +#ifdef HAS_VARIABLE_LENGTH_ARRAY + SECTION("char[n], Filter, NestingLimit") { + int i = 4; + char vla[i]; + strcpy(vla, "{}"); + deserializeMsgPack(doc, vla, Filter(filter), NestingLimit(5)); + } +#endif + + // deserializeMsgPack(..., NestingLimit, Filter) + + SECTION("const char*, NestingLimit, Filter") { + deserializeMsgPack(doc, "{}", NestingLimit(5), Filter(filter)); + } + + SECTION("const char*, size_t, NestingLimit, Filter") { + deserializeMsgPack(doc, "{}", 2, NestingLimit(5), Filter(filter)); + } + + SECTION("const std::string&, NestingLimit, Filter") { + deserializeMsgPack(doc, std::string("{}"), NestingLimit(5), Filter(filter)); + } + + SECTION("std::istream&, NestingLimit, Filter") { + std::stringstream s("{}"); + deserializeMsgPack(doc, s, NestingLimit(5), Filter(filter)); + } + +#ifdef HAS_VARIABLE_LENGTH_ARRAY + SECTION("char[n], NestingLimit, Filter") { + int i = 4; + char vla[i]; + strcpy(vla, "{}"); + deserializeMsgPack(doc, vla, NestingLimit(5), Filter(filter)); + } +#endif +} diff --git a/src/ArduinoJson/Json/JsonDeserializer.hpp b/src/ArduinoJson/Json/JsonDeserializer.hpp index 81eb40a0..a4de0f8e 100644 --- a/src/ArduinoJson/Json/JsonDeserializer.hpp +++ b/src/ArduinoJson/Json/JsonDeserializer.hpp @@ -637,47 +637,60 @@ class JsonDeserializer { DeserializationError _error; }; +// // deserializeJson(JsonDocument&, const std::string&, ...) -template +// +// ... = NestingLimit +template DeserializationError deserializeJson( - JsonDocument &doc, const TInput &input, + JsonDocument &doc, const TString &input, NestingLimit nestingLimit = NestingLimit()) { return deserialize(doc, input, nestingLimit, AllowAllFilter()); } -template +// ... = Filter, NestingLimit +template DeserializationError deserializeJson( - JsonDocument &doc, const TInput &input, Filter filter, + JsonDocument &doc, const TString &input, Filter filter, NestingLimit nestingLimit = NestingLimit()) { return deserialize(doc, input, nestingLimit, filter); } -template -DeserializationError deserializeJson(JsonDocument &doc, const TInput &input, +// ... = NestingLimit, Filter +template +DeserializationError deserializeJson(JsonDocument &doc, const TString &input, NestingLimit nestingLimit, Filter filter) { return deserialize(doc, input, nestingLimit, filter); } -// deserializeJson(JsonDocument&, const std::istream&, ...) -template +// +// deserializeJson(JsonDocument&, std::istream&, ...) +// +// ... = NestingLimit +template DeserializationError deserializeJson( - JsonDocument &doc, TInput &input, + JsonDocument &doc, TStream &input, NestingLimit nestingLimit = NestingLimit()) { return deserialize(doc, input, nestingLimit, AllowAllFilter()); } -template +// ... = Filter, NestingLimit +template DeserializationError deserializeJson( - JsonDocument &doc, TInput &input, Filter filter, + JsonDocument &doc, TStream &input, Filter filter, NestingLimit nestingLimit = NestingLimit()) { return deserialize(doc, input, nestingLimit, filter); } -template -DeserializationError deserializeJson(JsonDocument &doc, TInput &input, +// ... = NestingLimit, Filter +template +DeserializationError deserializeJson(JsonDocument &doc, TStream &input, NestingLimit nestingLimit, Filter filter) { return deserialize(doc, input, nestingLimit, filter); } +// // deserializeJson(JsonDocument&, char*, ...) +// +// ... = NestingLimit template DeserializationError deserializeJson( JsonDocument &doc, TChar *input, @@ -685,19 +698,24 @@ DeserializationError deserializeJson( return deserialize(doc, input, nestingLimit, AllowAllFilter()); } +// ... = Filter, NestingLimit template DeserializationError deserializeJson( JsonDocument &doc, TChar *input, Filter filter, NestingLimit nestingLimit = NestingLimit()) { return deserialize(doc, input, nestingLimit, filter); } +// ... = NestingLimit, Filter template DeserializationError deserializeJson(JsonDocument &doc, TChar *input, NestingLimit nestingLimit, Filter filter) { return deserialize(doc, input, nestingLimit, filter); } +// // deserializeJson(JsonDocument&, char*, size_t, ...) +// +// ... = NestingLimit template DeserializationError deserializeJson( JsonDocument &doc, TChar *input, size_t inputSize, @@ -705,6 +723,7 @@ DeserializationError deserializeJson( return deserialize(doc, input, inputSize, nestingLimit, AllowAllFilter()); } +// ... = Filter, NestingLimit template DeserializationError deserializeJson( JsonDocument &doc, TChar *input, size_t inputSize, Filter filter, @@ -712,6 +731,7 @@ DeserializationError deserializeJson( return deserialize(doc, input, inputSize, nestingLimit, filter); } +// ... = NestingLimit, Filter template DeserializationError deserializeJson(JsonDocument &doc, TChar *input, size_t inputSize, diff --git a/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp b/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp index 4365a4dc..f2d234ee 100644 --- a/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp +++ b/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp @@ -24,120 +24,241 @@ class MsgPackDeserializer { _error(DeserializationError::Ok), _foundSomething(false) {} - // TODO: add support for filter - DeserializationError parse(VariantData &variant, AllowAllFilter, + template + DeserializationError parse(VariantData &variant, TFilter filter, NestingLimit nestingLimit) { - parseVariant(variant, nestingLimit); + parseVariant(variant, filter, nestingLimit); return _foundSomething ? _error : DeserializationError::EmptyInput; } private: - bool parseVariant(VariantData &variant, NestingLimit nestingLimit) { - uint8_t code; + // Prevent VS warning "assignment operator could not be generated" + MsgPackDeserializer &operator=(const MsgPackDeserializer &); + + bool invalidInput() { + _error = DeserializationError::InvalidInput; + return false; + } + + bool notSupported() { + _error = DeserializationError::NotSupported; + 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; - if ((code & 0x80) == 0) { - variant.setUnsignedInteger(code); - return true; - } - - if ((code & 0xe0) == 0xe0) { - variant.setSignedInteger(static_cast(code)); - return true; - } - - if ((code & 0xe0) == 0xa0) { - return readString(variant, code & 0x1f); - } - - if ((code & 0xf0) == 0x90) { - return readArray(variant.toArray(), code & 0x0F, nestingLimit); - } - - if ((code & 0xf0) == 0x80) { - return readObject(variant.toObject(), code & 0x0F, nestingLimit); - } + bool allowValue = filter.allowValue(); switch (code) { case 0xc0: // already null return true; + case 0xc1: + return invalidInput(); + case 0xc2: - variant.setBoolean(false); + if (allowValue) + variant.setBoolean(false); return true; case 0xc3: - variant.setBoolean(true); + if (allowValue) + variant.setBoolean(true); return true; - case 0xcc: - return readInteger(variant); + case 0xc4: // bin 8 + if (allowValue) + return notSupported(); + else + return skipString(); - case 0xcd: - return readInteger(variant); + case 0xc5: // bin 16 + if (allowValue) + return notSupported(); + else + return skipString(); - case 0xce: - return readInteger(variant); + case 0xc6: // bin 32 + if (allowValue) + return notSupported(); + else + return skipString(); -#if ARDUINOJSON_USE_LONG_LONG - case 0xcf: - return readInteger(variant); -#endif + case 0xc7: // ext 8 + if (allowValue) + return notSupported(); + else + return skipExt(); - case 0xd0: - return readInteger(variant); + case 0xc8: // ext 16 + if (allowValue) + return notSupported(); + else + return skipExt(); - case 0xd1: - return readInteger(variant); - - case 0xd2: - return readInteger(variant); - -#if ARDUINOJSON_USE_LONG_LONG - case 0xd3: - return readInteger(variant); -#endif + case 0xc9: // ext 32 + if (allowValue) + return notSupported(); + else + return skipExt(); case 0xca: - return readFloat(variant); + if (allowValue) + return readFloat(variant); + else + return skipBytes(4); case 0xcb: - return readDouble(variant); + 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 (allowValue) +#if ARDUINOJSON_USE_LONG_LONG + return readInteger(variant); +#else + return notSupported(); +#endif + else + return skipBytes(8); + + 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 (allowValue) +#if ARDUINOJSON_USE_LONG_LONG + return readInteger(variant); +#else + return notSupported(); +#endif + else + return skipBytes(8); + + case 0xd4: // fixext 1 + if (allowValue) + return notSupported(); + else + return skipBytes(2); + + case 0xd5: // fixext 2 + if (allowValue) + return notSupported(); + else + return skipBytes(3); + + case 0xd6: // fixext 4 + if (allowValue) + return notSupported(); + else + return skipBytes(5); + + case 0xd7: // fixext 8 + if (allowValue) + return notSupported(); + else + return skipBytes(9); + + case 0xd8: // fixext 16 + if (allowValue) + return notSupported(); + else + return skipBytes(17); case 0xd9: - return readString(variant); + if (allowValue) + return readString(variant); + else + return skipString(); case 0xda: - return readString(variant); + if (allowValue) + return readString(variant); + else + return skipString(); case 0xdb: - return readString(variant); + if (allowValue) + return readString(variant); + else + return skipString(); case 0xdc: - return readArray(variant.toArray(), nestingLimit); + return readArray(variant, filter, nestingLimit); case 0xdd: - return readArray(variant.toArray(), nestingLimit); + return readArray(variant, filter, nestingLimit); case 0xde: - return readObject(variant.toObject(), nestingLimit); + return readObject(variant, filter, nestingLimit); case 0xdf: - return readObject(variant.toObject(), nestingLimit); - - default: - _error = DeserializationError::NotSupported; - return false; + return readObject(variant, filter, nestingLimit); } - } - private: - // Prevent VS warning "assignment operator could not be generated" - MsgPackDeserializer &operator=(const MsgPackDeserializer &); + 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(); @@ -161,6 +282,16 @@ class MsgPackDeserializer { 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)) @@ -223,22 +354,30 @@ class MsgPackDeserializer { } template - bool readString(const char *&str) { + bool readString() { T size; if (!readInteger(size)) return false; - return readString(str, size); + return readString(size); + } + + template + bool skipString() { + T size; + if (!readInteger(size)) + return false; + return skipBytes(size); } bool readString(VariantData &variant, size_t n) { - const char *s = 0; // <- mute "maybe-uninitialized" (+4 bytes on AVR) - if (!readString(s, n)) + if (!readString(n)) return false; - variant.setStringPointer(s, typename TStringStorage::storage_policy()); + variant.setStringPointer(_stringStorage.save(), + typename TStringStorage::storage_policy()); return true; } - bool readString(const char *&result, size_t n) { + bool readString(size_t n) { _stringStorage.startString(); for (; n; --n) { uint8_t c; @@ -252,96 +391,135 @@ class MsgPackDeserializer { return false; } - result = _stringStorage.save(); return true; } - template - bool readArray(CollectionData &array, NestingLimit nestingLimit) { + template + bool readArray(VariantData &variant, TFilter filter, + NestingLimit nestingLimit) { TSize size; if (!readInteger(size)) return false; - return readArray(array, size, nestingLimit); + return readArray(variant, size, filter, nestingLimit); } - bool readArray(CollectionData &array, size_t n, NestingLimit 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 = array.addElement(_pool); - if (!value) { - _error = DeserializationError::NoMemory; - return false; + VariantData *value; + + if (memberFilter.allow()) { + value = array->addElement(_pool); + if (!value) { + _error = DeserializationError::NoMemory; + return false; + } + } else { + value = 0; } - if (!parseVariant(*value, nestingLimit.decrement())) + if (!parseVariant(*value, memberFilter, nestingLimit.decrement())) return false; } return true; } - template - bool readObject(CollectionData &object, NestingLimit nestingLimit) { + template + bool readObject(VariantData &variant, TFilter filter, + NestingLimit nestingLimit) { TSize size; if (!readInteger(size)) return false; - return readObject(object, size, nestingLimit); + return readObject(variant, size, filter, nestingLimit); } - bool readObject(CollectionData &object, size_t n, NestingLimit 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) { - VariantSlot *slot = object.addSlot(_pool); - if (!slot) { - _error = DeserializationError::NoMemory; + 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; } - const char *key = 0; // <- mute "maybe-uninitialized" (+4 bytes on AVR) - if (!parseKey(key)) - return false; - - slot->setKey(key, typename TStringStorage::storage_policy()); - - if (!parseVariant(*slot->data(), nestingLimit.decrement())) + if (!parseVariant(*member, memberFilter, nestingLimit.decrement())) return false; } return true; } - bool parseKey(const char *&key) { + bool readKey() { uint8_t code; if (!readByte(code)) return false; if ((code & 0xe0) == 0xa0) - return readString(key, code & 0x1f); + return readString(code & 0x1f); switch (code) { case 0xd9: - return readString(key); + return readString(); case 0xda: - return readString(key); + return readString(); case 0xdb: - return readString(key); + return readString(); default: - _error = DeserializationError::NotSupported; - return false; + return notSupported(); } } + template + bool skipExt() { + T size; + if (!readInteger(size)) + return false; + return skipBytes(size + 1); + } + MemoryPool *_pool; TReader _reader; TStringStorage _stringStorage; @@ -349,35 +527,111 @@ class MsgPackDeserializer { bool _foundSomething; }; -template +// +// deserializeMsgPack(JsonDocument&, const std::string&, ...) +// +// ... = NestingLimit +template DeserializationError deserializeMsgPack( - JsonDocument &doc, const TInput &input, + JsonDocument &doc, const TString &input, NestingLimit nestingLimit = NestingLimit()) { return deserialize(doc, input, nestingLimit, AllowAllFilter()); } - -template +// ... = Filter, NestingLimit +template DeserializationError deserializeMsgPack( - JsonDocument &doc, TInput *input, + 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()); } - -template +// ... = Filter, NestingLimit +template DeserializationError deserializeMsgPack( - JsonDocument &doc, TInput *input, size_t inputSize, + 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()); } - -template +// ... = Filter, NestingLimit +template DeserializationError deserializeMsgPack( - JsonDocument &doc, TInput &input, + JsonDocument &doc, TChar *input, size_t inputSize, Filter filter, NestingLimit nestingLimit = NestingLimit()) { - return deserialize(doc, input, nestingLimit, - AllowAllFilter()); + 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