From 12fb9fc75cecd4dd4845b34d923015ce3765900b Mon Sep 17 00:00:00 2001 From: jimmys01 Date: Fri, 2 Oct 2020 14:44:26 +0300 Subject: [PATCH] Update ArduJSON From 6.15.2 to 6.16.1 --- lib/ArduinoJson-6.x/.travis.yml | 35 +- lib/ArduinoJson-6.x/CHANGELOG.md | 25 + lib/ArduinoJson-6.x/CMakeLists.txt | 2 +- lib/ArduinoJson-6.x/README.md | 3 +- lib/ArduinoJson-6.x/appveyor.yml | 2 +- .../JsonHttpClient/JsonHttpClient.ino | 2 +- .../JsonParserExample/JsonParserExample.ino | 2 +- .../examples/MsgPackParser/MsgPackParser.ino | 2 +- lib/ArduinoJson-6.x/extras/ci/fuzz.sh | 30 +- lib/ArduinoJson-6.x/extras/ci/test.sh | 2 - .../extras/fuzzing/CMakeLists.txt | 66 ++- .../{fuzzer_main.cpp => reproducer.cpp} | 0 .../extras/scripts/build-arduino-package.sh | 1 + lib/ArduinoJson-6.x/extras/scripts/publish.sh | 2 +- .../extras/tests/ElementProxy/CMakeLists.txt | 1 + .../extras/tests/ElementProxy/subscript.cpp | 2 +- .../extras/tests/Helpers/Arduino.h | 8 + .../extras/tests/Helpers/{ => api}/Stream.h | 0 .../tests/Helpers/{WString.h => api/String.h} | 3 + .../tests/Helpers/progmem_emulation.hpp | 23 +- .../extras/tests/JsonArray/copyArray.cpp | 218 ++++++--- .../extras/tests/JsonArray/remove.cpp | 11 + .../JsonDeserializer/DeserializationError.cpp | 21 +- .../extras/tests/JsonDeserializer/filter.cpp | 32 +- .../tests/JsonDeserializer/input_types.cpp | 16 + .../extras/tests/JsonDeserializer/misc.cpp | 8 +- .../extras/tests/JsonDeserializer/object.cpp | 6 + .../extras/tests/JsonDeserializer/string.cpp | 8 +- .../extras/tests/JsonDocument/CMakeLists.txt | 1 + .../tests/JsonDocument/StaticJsonDocument.cpp | 2 +- .../extras/tests/JsonDocument/overflowed.cpp | 79 ++++ .../extras/tests/JsonVariant/or.cpp | 51 +- .../extras/tests/JsonVariant/set.cpp | 103 ++-- .../extras/tests/MemoryPool/CMakeLists.txt | 4 +- .../extras/tests/MemoryPool/StringBuilder.cpp | 41 -- .../extras/tests/MemoryPool/StringCopier.cpp | 84 ++++ .../extras/tests/MemoryPool/allocString.cpp | 67 --- .../extras/tests/MemoryPool/clear.cpp | 5 +- .../extras/tests/MemoryPool/saveString.cpp | 81 ++++ .../extras/tests/MemoryPool/size.cpp | 23 - .../extras/tests/Misc/CMakeLists.txt | 3 +- .../extras/tests/Misc/JsonString.cpp | 60 +++ .../extras/tests/Misc/StringAdapters.cpp | 22 +- .../extras/tests/Misc/Utf8.cpp | 6 +- .../tests/MixedConfiguration/CMakeLists.txt | 2 + .../MixedConfiguration/enable_comments_1.cpp | 10 +- .../MixedConfiguration/enable_progmem_1.cpp | 53 ++- .../enable_string_deduplication_0.cpp | 125 +++++ .../enable_string_deduplication_1.cpp | 124 +++++ .../tests/MsgPackDeserializer/CMakeLists.txt | 1 + .../extras/tests/MsgPackDeserializer/misc.cpp | 24 + .../extras/tests/Numbers/CMakeLists.txt | 1 + .../extras/tests/Numbers/parseDouble.cpp | 97 ++++ .../extras/tests/Numbers/parseFloat.cpp | 162 ++----- .../extras/tests/Numbers/parseInteger.cpp | 15 +- .../extras/tests/Numbers/parseNumber.cpp | 27 +- lib/ArduinoJson-6.x/library.json | 2 +- lib/ArduinoJson-6.x/library.properties | 2 +- .../src/ArduinoJson/Array/ArrayFunctions.hpp | 9 +- .../src/ArduinoJson/Array/ArrayRef.hpp | 6 +- .../src/ArduinoJson/Array/ElementProxy.hpp | 8 +- .../src/ArduinoJson/Array/Utilities.hpp | 142 ++++-- .../src/ArduinoJson/Configuration.hpp | 11 +- .../Deserialization/DeserializationError.hpp | 42 +- .../ArduinoJson/Deserialization/Filter.hpp | 2 +- .../Readers/ArduinoStreamReader.hpp | 2 +- .../Deserialization/deserialize.hpp | 6 +- .../src/ArduinoJson/Document/JsonDocument.hpp | 9 +- .../src/ArduinoJson/Json/JsonDeserializer.hpp | 441 ++++++++++-------- .../src/ArduinoJson/Json/JsonSerializer.hpp | 31 +- .../ArduinoJson/Json/PrettyJsonSerializer.hpp | 60 +-- .../src/ArduinoJson/Json/TextFormatter.hpp | 19 +- .../src/ArduinoJson/Json/Utf16.hpp | 2 + .../src/ArduinoJson/Memory/MemoryPool.hpp | 132 ++++-- .../src/ArduinoJson/Memory/StringBuilder.hpp | 51 -- .../src/ArduinoJson/Misc/Visitable.hpp | 5 + .../MsgPack/MsgPackDeserializer.hpp | 191 ++++---- .../ArduinoJson/MsgPack/MsgPackSerializer.hpp | 50 +- .../src/ArduinoJson/Namespace.hpp | 31 +- .../src/ArduinoJson/Numbers/FloatTraits.hpp | 104 +++-- .../src/ArduinoJson/Numbers/parseFloat.hpp | 18 - .../src/ArduinoJson/Numbers/parseInteger.hpp | 19 - .../src/ArduinoJson/Numbers/parseNumber.hpp | 94 ++-- .../src/ArduinoJson/Object/MemberProxy.hpp | 4 +- .../ArduinoJson/Object/ObjectFunctions.hpp | 9 +- .../src/ArduinoJson/Object/ObjectRef.hpp | 6 +- .../ArduinoJson/Polyfills/gsl/not_null.hpp | 34 -- .../src/ArduinoJson/Polyfills/pgmspace.hpp | 1 + .../Polyfills/pgmspace_generic.hpp | 28 ++ .../ArduinoJson/Polyfills/preprocessor.hpp | 36 ++ .../ArduinoJson/Polyfills/static_array.hpp | 34 ++ .../src/ArduinoJson/Polyfills/type_traits.hpp | 1 + .../Polyfills/type_traits/is_convertible.hpp | 9 + .../type_traits/is_pointer.hpp} | 15 +- .../Serialization/CountingDecorator.hpp | 33 ++ .../Writers/ArduinoStringWriter.hpp | 2 +- .../src/ArduinoJson/Serialization/measure.hpp | 3 +- .../ArduinoJson/Serialization/serialize.hpp | 3 +- .../StringStorage/StringCopier.hpp | 49 +- .../ArduinoJson/StringStorage/StringMover.hpp | 47 +- .../StringStorage/StringStorage.hpp | 31 +- .../Strings/ArduinoStringAdapter.hpp | 6 +- .../Strings/ConstRamStringAdapter.hpp | 4 + .../Strings/FlashStringAdapter.hpp | 5 + .../Strings/FlashStringIterator.hpp | 44 ++ .../ArduinoJson/Strings/IsWriteableString.hpp | 2 +- .../Strings/SizedFlashStringAdapter.hpp | 5 + .../Strings/SizedRamStringAdapter.hpp | 4 + ...StringAdapter.hpp => StdStringAdapter.hpp} | 12 +- .../src/ArduinoJson/Strings/String.hpp | 10 + .../ArduinoJson/Strings/StringAdapters.hpp | 2 +- .../src/ArduinoJson/Variant/SlotFunctions.hpp | 4 +- .../ArduinoJson/Variant/VariantCompare.hpp | 166 ++++--- .../src/ArduinoJson/Variant/VariantData.hpp | 77 +-- .../ArduinoJson/Variant/VariantFunctions.hpp | 59 +-- .../src/ArduinoJson/Variant/VariantImpl.hpp | 14 +- .../ArduinoJson/Variant/VariantOperators.hpp | 8 +- .../src/ArduinoJson/Variant/VariantRef.hpp | 12 +- .../src/ArduinoJson/Variant/VariantSlot.hpp | 18 +- .../src/ArduinoJson/version.hpp | 6 +- 120 files changed, 2640 insertions(+), 1456 deletions(-) rename lib/ArduinoJson-6.x/extras/fuzzing/{fuzzer_main.cpp => reproducer.cpp} (100%) create mode 100644 lib/ArduinoJson-6.x/extras/tests/Helpers/Arduino.h rename lib/ArduinoJson-6.x/extras/tests/Helpers/{ => api}/Stream.h (100%) rename lib/ArduinoJson-6.x/extras/tests/Helpers/{WString.h => api/String.h} (92%) create mode 100644 lib/ArduinoJson-6.x/extras/tests/JsonDocument/overflowed.cpp delete mode 100644 lib/ArduinoJson-6.x/extras/tests/MemoryPool/StringBuilder.cpp create mode 100644 lib/ArduinoJson-6.x/extras/tests/MemoryPool/StringCopier.cpp delete mode 100644 lib/ArduinoJson-6.x/extras/tests/MemoryPool/allocString.cpp create mode 100644 lib/ArduinoJson-6.x/extras/tests/MemoryPool/saveString.cpp create mode 100644 lib/ArduinoJson-6.x/extras/tests/Misc/JsonString.cpp create mode 100644 lib/ArduinoJson-6.x/extras/tests/MixedConfiguration/enable_string_deduplication_0.cpp create mode 100644 lib/ArduinoJson-6.x/extras/tests/MixedConfiguration/enable_string_deduplication_1.cpp create mode 100644 lib/ArduinoJson-6.x/extras/tests/MsgPackDeserializer/misc.cpp create mode 100644 lib/ArduinoJson-6.x/extras/tests/Numbers/parseDouble.cpp delete mode 100644 lib/ArduinoJson-6.x/src/ArduinoJson/Memory/StringBuilder.hpp delete mode 100644 lib/ArduinoJson-6.x/src/ArduinoJson/Numbers/parseFloat.hpp delete mode 100644 lib/ArduinoJson-6.x/src/ArduinoJson/Numbers/parseInteger.hpp delete mode 100644 lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/gsl/not_null.hpp create mode 100644 lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/pgmspace_generic.hpp create mode 100644 lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/preprocessor.hpp create mode 100644 lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/static_array.hpp rename lib/ArduinoJson-6.x/src/ArduinoJson/{Memory/StringSlot.hpp => Polyfills/type_traits/is_pointer.hpp} (51%) create mode 100644 lib/ArduinoJson-6.x/src/ArduinoJson/Serialization/CountingDecorator.hpp create mode 100644 lib/ArduinoJson-6.x/src/ArduinoJson/Strings/FlashStringIterator.hpp rename lib/ArduinoJson-6.x/src/ArduinoJson/Strings/{StlStringAdapter.hpp => StdStringAdapter.hpp} (81%) diff --git a/lib/ArduinoJson-6.x/.travis.yml b/lib/ArduinoJson-6.x/.travis.yml index f58bdd3b6..6cf281f8b 100644 --- a/lib/ArduinoJson-6.x/.travis.yml +++ b/lib/ArduinoJson-6.x/.travis.yml @@ -21,17 +21,17 @@ matrix: apt: sources: ['ubuntu-toolchain-r-test'] packages: ['g++-4.8'] - env: SCRIPT=test _CC=gcc-4.8 _CXX=g++-4.8 SANITIZE=address + env: SCRIPT=test _CC=gcc-4.8 _CXX=g++-4.8 - addons: apt: sources: ['ubuntu-toolchain-r-test'] packages: ['g++-4.9'] - env: SCRIPT=test _CC=gcc-4.9 _CXX=g++-4.9 SANITIZE=leak + env: SCRIPT=test _CC=gcc-4.9 _CXX=g++-4.9 - addons: apt: sources: ['ubuntu-toolchain-r-test'] packages: ['g++-5'] - env: SCRIPT=test _CC=gcc-5 _CXX=g++-5 # SANITIZE=undefined + env: SCRIPT=test _CC=gcc-5 _CXX=g++-5 - addons: apt: sources: ['ubuntu-toolchain-r-test'] @@ -41,17 +41,17 @@ matrix: apt: sources: ['ubuntu-toolchain-r-test'] packages: ['g++-7'] - env: SCRIPT=test _CC=gcc-7 _CXX=g++-7 + env: SCRIPT=test _CC=gcc-7 _CXX=g++-7 CXXFLAGS="-fsanitize=leak" - addons: apt: sources: ['ubuntu-toolchain-r-test'] packages: ['g++-8'] - env: SCRIPT=test _CC=gcc-8 _CXX=g++-8 + env: SCRIPT=test _CC=gcc-8 _CXX=g++-8 CXXFLAGS="-fsanitize=undefined" LDFLAGS="-fuse-ld=gold" - addons: apt: sources: ['ubuntu-toolchain-r-test'] packages: ['g++-9'] - env: SCRIPT=test _CC=gcc-9 _CXX=g++-9 + env: SCRIPT=test _CC=gcc-9 _CXX=g++-9 CXXFLAGS="-fsanitize=address" - addons: apt: packages: ['g++-arm-linux-gnueabihf'] @@ -61,12 +61,12 @@ matrix: apt: sources: ['ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5'] packages: ['clang-3.5'] - env: SCRIPT=test _CC=clang-3.5 _CXX=clang++-3.5 SANITIZE=address + env: SCRIPT=test _CC=clang-3.5 _CXX=clang++-3.5 CXXFLAGS="-fsanitize=address" - addons: apt: sources: ['ubuntu-toolchain-r-test','llvm-toolchain-precise-3.6'] packages: ['clang-3.6'] - env: SCRIPT=test _CC=clang-3.6 _CXX=clang++-3.6 SANITIZE=leak + env: SCRIPT=test _CC=clang-3.6 _CXX=clang++-3.6 CXXFLAGS="-fsanitize=leak" - addons: apt: sources: ['ubuntu-toolchain-r-test','llvm-toolchain-precise-3.7'] @@ -76,7 +76,7 @@ matrix: apt: sources: ['ubuntu-toolchain-r-test','llvm-toolchain-precise-3.8'] packages: ['clang-3.8'] - env: SCRIPT=test _CC=clang-3.8 _CXX=clang++-3.8 SANITIZE=undefined + env: SCRIPT=test _CC=clang-3.8 _CXX=clang++-3.8 CXXFLAGS="-fsanitize=undefined" - addons: apt: sources: ['ubuntu-toolchain-r-test','llvm-toolchain-trusty-3.9'] @@ -107,10 +107,14 @@ matrix: sources: ['ubuntu-toolchain-r-test','llvm-toolchain-trusty-8'] packages: ['clang-8'] env: SCRIPT=test _CC=clang-8 _CXX=clang++-8 + - addons: + apt: + sources: + - sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main' + key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' + packages: ['clang-9'] + env: SCRIPT=test _CC=clang-9 _CXX=clang++-9 - env: SCRIPT=coverage - - os: osx - osx_image: xcode7.3 - env: SCRIPT=test - os: osx osx_image: xcode8.3 env: SCRIPT=test @@ -119,16 +123,11 @@ matrix: env: SCRIPT=test - os: osx osx_image: xcode10 - env: SCRIPT=test SANITIZE=address + env: SCRIPT=test CXXFLAGS="-fsanitize=address" - env: SCRIPT=arduino VERSION=1.6.7 BOARD=arduino:avr:uno - env: SCRIPT=arduino VERSION=1.8.2 BOARD=arduino:samd:mkr1000 - env: SCRIPT=platformio BOARD=uno - env: SCRIPT=platformio BOARD=esp01 - - addons: - apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['clang-6.0','llvm-6.0'] - env: SCRIPT=fuzz CLANG=6.0 cache: directories: - "~/.platformio" diff --git a/lib/ArduinoJson-6.x/CHANGELOG.md b/lib/ArduinoJson-6.x/CHANGELOG.md index f3c049f16..22fc4f2c5 100644 --- a/lib/ArduinoJson-6.x/CHANGELOG.md +++ b/lib/ArduinoJson-6.x/CHANGELOG.md @@ -4,7 +4,32 @@ ArduinoJson: change log HEAD ---- +* Added a build failure when nullptr is defined as a macro (issue #1355) +* Added `JsonDocument::overflowed()` which tells if the memory pool was too small (issue #1358) +* 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)` +* 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) + +v6.16.1 (2020-08-04) +------- + +* Fixed `deserializeJson()` that stopped reading after `{}` (issue #1335) + +v6.16.0 (2020-08-01) +------- + * Added comparisons (`>`, `>=`, `==`, `!=`, `<`, and `<=`) between `JsonVariant`s +* Added string deduplication (issue #1303) +* Added `JsonString::operator!=` +* Added wildcard key (`*`) for filters (issue #1309) +* Set `ARDUINOJSON_DECODE_UNICODE` to `1` by default +* Fixed `copyArray()` not working with `String`, `ElementProxy`, and `MemberProxy` +* Fixed error `getOrAddElement is not a member of ElementProxy` (issue #1311) +* Fixed excessive stack usage when compiled with `-Og` (issues #1210 and #1314) +* Fixed `Warning[Pa093]: implicit conversion from floating point to integer` on IAR compiler (PR #1328 by @stawiski) v6.15.2 (2020-05-15) ------- diff --git a/lib/ArduinoJson-6.x/CMakeLists.txt b/lib/ArduinoJson-6.x/CMakeLists.txt index d854fdb99..a018fcf1c 100644 --- a/lib/ArduinoJson-6.x/CMakeLists.txt +++ b/lib/ArduinoJson-6.x/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.0) -project(ArduinoJson VERSION 6.15.1) +project(ArduinoJson VERSION 6.16.1) if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) include(CTest) diff --git a/lib/ArduinoJson-6.x/README.md b/lib/ArduinoJson-6.x/README.md index ae2e2960f..3005c0d49 100644 --- a/lib/ArduinoJson-6.x/README.md +++ b/lib/ArduinoJson-6.x/README.md @@ -2,7 +2,7 @@ --- -[![arduino-library-badge](https://www.ardu-badge.com/badge/ArduinoJson.svg?version=6.15.2)](https://www.ardu-badge.com/ArduinoJson/6.15.2) +[![arduino-library-badge](https://www.ardu-badge.com/badge/ArduinoJson.svg?version=6.16.1)](https://www.ardu-badge.com/ArduinoJson/6.16.1) [![Build Status](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/6.x?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x) [![Build Status](https://travis-ci.org/bblanchon/ArduinoJson.svg?branch=6.x)](https://travis-ci.org/bblanchon/ArduinoJson) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/arduinojson.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson) @@ -31,6 +31,7 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things). * [Consumes roughly 10% less RAM than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/?utm_source=github&utm_medium=readme) * [Fixed memory allocation, no heap fragmentation](https://arduinojson.org/v6/api/jsondocument/?utm_source=github&utm_medium=readme) * [Optionally works without heap memory (zero malloc)](https://arduinojson.org/v6/api/staticjsondocument/?utm_source=github&utm_medium=readme) + * Deduplicates strings * Versatile * [Supports custom allocators (to use external RAM chip, for example)](https://arduinojson.org/v6/how-to/use-external-ram-on-esp32/?utm_source=github&utm_medium=readme) * Supports [Arduino's `String`](https://arduinojson.org/v6/api/config/enable_arduino_string/) and [STL's `std::string`](https://arduinojson.org/v6/api/config/enable_std_string/?utm_source=github&utm_medium=readme) diff --git a/lib/ArduinoJson-6.x/appveyor.yml b/lib/ArduinoJson-6.x/appveyor.yml index ca4bc858c..0a00f59bc 100644 --- a/lib/ArduinoJson-6.x/appveyor.yml +++ b/lib/ArduinoJson-6.x/appveyor.yml @@ -1,4 +1,4 @@ -version: 6.15.2.{build} +version: 6.16.1.{build} environment: matrix: - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 diff --git a/lib/ArduinoJson-6.x/examples/JsonHttpClient/JsonHttpClient.ino b/lib/ArduinoJson-6.x/examples/JsonHttpClient/JsonHttpClient.ino index 5c894c44a..b4ade88cc 100644 --- a/lib/ArduinoJson-6.x/examples/JsonHttpClient/JsonHttpClient.ino +++ b/lib/ArduinoJson-6.x/examples/JsonHttpClient/JsonHttpClient.ino @@ -82,7 +82,7 @@ void setup() { DeserializationError error = deserializeJson(doc, client); if (error) { Serial.print(F("deserializeJson() failed: ")); - Serial.println(error.c_str()); + Serial.println(error.f_str()); return; } diff --git a/lib/ArduinoJson-6.x/examples/JsonParserExample/JsonParserExample.ino b/lib/ArduinoJson-6.x/examples/JsonParserExample/JsonParserExample.ino index d6c82b432..6324630c1 100644 --- a/lib/ArduinoJson-6.x/examples/JsonParserExample/JsonParserExample.ino +++ b/lib/ArduinoJson-6.x/examples/JsonParserExample/JsonParserExample.ino @@ -42,7 +42,7 @@ void setup() { // Test if parsing succeeds. if (error) { Serial.print(F("deserializeJson() failed: ")); - Serial.println(error.c_str()); + Serial.println(error.f_str()); return; } diff --git a/lib/ArduinoJson-6.x/examples/MsgPackParser/MsgPackParser.ino b/lib/ArduinoJson-6.x/examples/MsgPackParser/MsgPackParser.ino index 2596cc5eb..dd262ed4c 100644 --- a/lib/ArduinoJson-6.x/examples/MsgPackParser/MsgPackParser.ino +++ b/lib/ArduinoJson-6.x/examples/MsgPackParser/MsgPackParser.ino @@ -50,7 +50,7 @@ void setup() { // Test if parsing succeeded. if (error) { Serial.print("deserializeMsgPack() failed: "); - Serial.println(error.c_str()); + Serial.println(error.f_str()); return; } diff --git a/lib/ArduinoJson-6.x/extras/ci/fuzz.sh b/lib/ArduinoJson-6.x/extras/ci/fuzz.sh index ba3385e94..6e6998045 100644 --- a/lib/ArduinoJson-6.x/extras/ci/fuzz.sh +++ b/lib/ArduinoJson-6.x/extras/ci/fuzz.sh @@ -1,26 +1,22 @@ #!/bin/bash -eux ROOT_DIR=$(dirname $0)/../../ -INCLUDE_DIR=${ROOT_DIR}/src/ FUZZING_DIR=${ROOT_DIR}/extras/fuzzing/ -CXXFLAGS="-g -fprofile-instr-generate -fcoverage-mapping -fsanitize=address,undefined,fuzzer -fno-sanitize-recover=all" -fuzz() { - NAME="$1" - FUZZER="${NAME}_fuzzer" - FUZZER_CPP="${FUZZING_DIR}/${NAME}_fuzzer.cpp" - CORPUS_DIR="${FUZZING_DIR}/${NAME}_corpus" - SEED_CORPUS_DIR="${FUZZING_DIR}/${NAME}_seed_corpus" +export CC="clang-${CLANG}" +export CXX="clang++-${CLANG}" +cmake -DCMAKE_BUILD_TYPE=Debug . - clang++-${CLANG} ${CXXFLAGS} -o ${FUZZER} -I$INCLUDE_DIR ${FUZZER_CPP} +FUZZER_TARGET="${FUZZER}_fuzzer" +FUZZER_PATH="extras/fuzzing/${FUZZER_TARGET}" +CORPUS_DIR="${FUZZING_DIR}/${FUZZER}_corpus" +SEED_CORPUS_DIR="${FUZZING_DIR}/${FUZZER}_seed_corpus" - export ASAN_OPTIONS="detect_leaks=0" - export LLVM_PROFILE_FILE="${FUZZER}.profraw" - ./${FUZZER} "$CORPUS_DIR" "$SEED_CORPUS_DIR" -max_total_time=30 -timeout=1 +cmake --build . --target $FUZZER_TARGET - llvm-profdata-${CLANG} merge -sparse ${LLVM_PROFILE_FILE} -o ${FUZZER}.profdata - llvm-cov-${CLANG} report ./${FUZZER} -instr-profile=${FUZZER}.profdata -} +export ASAN_OPTIONS="detect_leaks=0" +export LLVM_PROFILE_FILE="${FUZZER_TARGET}.profraw" +${FUZZER_PATH} "$CORPUS_DIR" "$SEED_CORPUS_DIR" -max_total_time=60 -timeout=1 -fuzz json -fuzz msgpack +llvm-profdata-${CLANG} merge -sparse ${LLVM_PROFILE_FILE} -o ${FUZZER_TARGET}.profdata +llvm-cov-${CLANG} report ./${FUZZER_PATH} -instr-profile=${FUZZER_TARGET}.profdata diff --git a/lib/ArduinoJson-6.x/extras/ci/test.sh b/lib/ArduinoJson-6.x/extras/ci/test.sh index ce76eb698..661623060 100644 --- a/lib/ArduinoJson-6.x/extras/ci/test.sh +++ b/lib/ArduinoJson-6.x/extras/ci/test.sh @@ -3,8 +3,6 @@ export CC="$_CC" export CXX="$_CXX" -[ -n "$SANITIZE" ] && export CXXFLAGS="-fsanitize=$SANITIZE" - cmake -DCMAKE_BUILD_TYPE=Debug . cmake --build . ctest --output-on-failure . diff --git a/lib/ArduinoJson-6.x/extras/fuzzing/CMakeLists.txt b/lib/ArduinoJson-6.x/extras/fuzzing/CMakeLists.txt index f890786a4..cfc0fd89b 100644 --- a/lib/ArduinoJson-6.x/extras/fuzzing/CMakeLists.txt +++ b/lib/ArduinoJson-6.x/extras/fuzzing/CMakeLists.txt @@ -6,18 +6,72 @@ if(MSVC) add_compile_options(-D_CRT_SECURE_NO_WARNINGS) endif() -add_executable(msgpack_fuzzer +add_executable(msgpack_reproducer msgpack_fuzzer.cpp - fuzzer_main.cpp + reproducer.cpp ) -target_link_libraries(msgpack_fuzzer +target_link_libraries(msgpack_reproducer ArduinoJson ) -add_executable(json_fuzzer +add_executable(json_reproducer json_fuzzer.cpp - fuzzer_main.cpp + reproducer.cpp ) -target_link_libraries(json_fuzzer +target_link_libraries(json_reproducer ArduinoJson ) + +# Infer path of llvm-symbolizer from the path of clang +string(REPLACE "clang++" "llvm-symbolizer" LLVM_SYMBOLIZER ${CMAKE_CXX_COMPILER}) + +macro(add_fuzzer name mode) + set(FUZZER "${name}_${mode}_fuzzer") + set(CORPUS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${name}_corpus") + set(SEED_CORPUS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${name}_seed_corpus") + add_executable("${FUZZER}" + "${name}_fuzzer.cpp" + ) + target_link_libraries("${FUZZER}" + ArduinoJson + ) + set_target_properties("${FUZZER}" + PROPERTIES + COMPILE_FLAGS + "-fprofile-instr-generate -fcoverage-mapping -fsanitize=${mode},fuzzer -fno-sanitize-recover=all" + LINK_FLAGS + "-fprofile-instr-generate -fcoverage-mapping -fsanitize=${mode},fuzzer -fno-sanitize-recover=all" + ) + + add_test( + NAME + "${FUZZER}" + COMMAND + "${FUZZER}" "${CORPUS_DIR}" "${SEED_CORPUS_DIR}" -max_total_time=5 -timeout=1 + ) + + set_tests_properties("${FUZZER}" + PROPERTIES + ENVIRONMENT + ASAN_SYMBOLIZER_PATH=${LLVM_SYMBOLIZER} + ENVIRONMENT + LLVM_SYMBOLIZER_PATH=${LLVM_SYMBOLIZER} + ENVIRONMENT + MSAN_SYMBOLIZER_PATH=${LLVM_SYMBOLIZER} + ENVIRONMENT + UBSAN_SYMBOLIZER_PATH=${LLVM_SYMBOLIZER} + ) +endmacro() + +if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 6) + add_fuzzer(json address) + add_fuzzer(json undefined) + add_fuzzer(msgpack address) + add_fuzzer(msgpack undefined) +endif() + +if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7) + # We're getting false positive with Clang 6 + add_fuzzer(json memory) + add_fuzzer(msgpack memory) +endif() diff --git a/lib/ArduinoJson-6.x/extras/fuzzing/fuzzer_main.cpp b/lib/ArduinoJson-6.x/extras/fuzzing/reproducer.cpp similarity index 100% rename from lib/ArduinoJson-6.x/extras/fuzzing/fuzzer_main.cpp rename to lib/ArduinoJson-6.x/extras/fuzzing/reproducer.cpp diff --git a/lib/ArduinoJson-6.x/extras/scripts/build-arduino-package.sh b/lib/ArduinoJson-6.x/extras/scripts/build-arduino-package.sh index f79abe0f0..440672058 100644 --- a/lib/ArduinoJson-6.x/extras/scripts/build-arduino-package.sh +++ b/lib/ArduinoJson-6.x/extras/scripts/build-arduino-package.sh @@ -10,6 +10,7 @@ rm -f $OUTPUT # create zip 7z a $OUTPUT \ + -xr!.vs \ ArduinoJson/CHANGELOG.md \ ArduinoJson/examples \ ArduinoJson/src \ diff --git a/lib/ArduinoJson-6.x/extras/scripts/publish.sh b/lib/ArduinoJson-6.x/extras/scripts/publish.sh index caad1394b..15069f4bc 100644 --- a/lib/ArduinoJson-6.x/extras/scripts/publish.sh +++ b/lib/ArduinoJson-6.x/extras/scripts/publish.sh @@ -41,7 +41,7 @@ update_version_in_source () { } commit_new_version () { - git add src/ArduinoJson/version.hpp README.md CHANGELOG.md library.json library.properties appveyor.yml + git add src/ArduinoJson/version.hpp README.md CHANGELOG.md library.json library.properties appveyor.yml CMakeLists.txt git commit -m "Set version to $VERSION" } diff --git a/lib/ArduinoJson-6.x/extras/tests/ElementProxy/CMakeLists.txt b/lib/ArduinoJson-6.x/extras/tests/ElementProxy/CMakeLists.txt index f86d6bb0c..d0c3f4531 100644 --- a/lib/ArduinoJson-6.x/extras/tests/ElementProxy/CMakeLists.txt +++ b/lib/ArduinoJson-6.x/extras/tests/ElementProxy/CMakeLists.txt @@ -9,6 +9,7 @@ add_executable(ElementProxyTests remove.cpp set.cpp size.cpp + subscript.cpp ) add_test(ElementProxy ElementProxyTests) diff --git a/lib/ArduinoJson-6.x/extras/tests/ElementProxy/subscript.cpp b/lib/ArduinoJson-6.x/extras/tests/ElementProxy/subscript.cpp index 70bf273a8..04034f536 100644 --- a/lib/ArduinoJson-6.x/extras/tests/ElementProxy/subscript.cpp +++ b/lib/ArduinoJson-6.x/extras/tests/ElementProxy/subscript.cpp @@ -7,7 +7,7 @@ using namespace ARDUINOJSON_NAMESPACE; -TEST_CASE("MemberProxy::operator[]") { +TEST_CASE("ElementProxy::operator[]") { DynamicJsonDocument doc(4096); ElementProxy ep = doc[1]; diff --git a/lib/ArduinoJson-6.x/extras/tests/Helpers/Arduino.h b/lib/ArduinoJson-6.x/extras/tests/Helpers/Arduino.h new file mode 100644 index 000000000..51b5987f0 --- /dev/null +++ b/lib/ArduinoJson-6.x/extras/tests/Helpers/Arduino.h @@ -0,0 +1,8 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include "api/Stream.h" +#include "api/String.h" diff --git a/lib/ArduinoJson-6.x/extras/tests/Helpers/Stream.h b/lib/ArduinoJson-6.x/extras/tests/Helpers/api/Stream.h similarity index 100% rename from lib/ArduinoJson-6.x/extras/tests/Helpers/Stream.h rename to lib/ArduinoJson-6.x/extras/tests/Helpers/api/Stream.h diff --git a/lib/ArduinoJson-6.x/extras/tests/Helpers/WString.h b/lib/ArduinoJson-6.x/extras/tests/Helpers/api/String.h similarity index 92% rename from lib/ArduinoJson-6.x/extras/tests/Helpers/WString.h rename to lib/ArduinoJson-6.x/extras/tests/Helpers/api/String.h index 18122f7ee..5999ebf47 100644 --- a/lib/ArduinoJson-6.x/extras/tests/Helpers/WString.h +++ b/lib/ArduinoJson-6.x/extras/tests/Helpers/api/String.h @@ -9,6 +9,9 @@ // Reproduces Arduino's String class class String { public: + String() {} + explicit String(const char* s) : _str(s) {} + String& operator+=(const char* rhs) { _str += rhs; return *this; diff --git a/lib/ArduinoJson-6.x/extras/tests/Helpers/progmem_emulation.hpp b/lib/ArduinoJson-6.x/extras/tests/Helpers/progmem_emulation.hpp index 4a7f17990..bd882bb2a 100644 --- a/lib/ArduinoJson-6.x/extras/tests/Helpers/progmem_emulation.hpp +++ b/lib/ArduinoJson-6.x/extras/tests/Helpers/progmem_emulation.hpp @@ -5,6 +5,8 @@ #include // uint8_t #include // strcmp, strlen... +#define PROGMEM + class __FlashStringHelper; inline const void* convertPtrToFlash(const void* s) { @@ -15,9 +17,26 @@ inline const void* convertFlashToPtr(const void* s) { return reinterpret_cast(s) - 42; } -#define F(X) reinterpret_cast(convertPtrToFlash(X)) -#define FC(X) reinterpret_cast(convertPtrToFlash(X)) +#define PSTR(X) reinterpret_cast(convertPtrToFlash(X)) +#define F(X) reinterpret_cast(PSTR(X)) inline uint8_t pgm_read_byte(const void* p) { return *reinterpret_cast(convertFlashToPtr(p)); } + +inline void* pgm_read_ptr(const void* p) { + return *reinterpret_cast(convertFlashToPtr(p)); +} + +inline float pgm_read_float(const void* p) { + return *reinterpret_cast(convertFlashToPtr(p)); +} + +inline uint32_t pgm_read_dword(const void* p) { + return *reinterpret_cast(convertFlashToPtr(p)); +} + +#define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) \ + static type const ARDUINOJSON_CONCAT2(name, _progmem)[] = value; \ + static type const* name = reinterpret_cast( \ + convertPtrToFlash(ARDUINOJSON_CONCAT2(name, _progmem))); diff --git a/lib/ArduinoJson-6.x/extras/tests/JsonArray/copyArray.cpp b/lib/ArduinoJson-6.x/extras/tests/JsonArray/copyArray.cpp index 7455f8fe5..ac655dd58 100644 --- a/lib/ArduinoJson-6.x/extras/tests/JsonArray/copyArray.cpp +++ b/lib/ArduinoJson-6.x/extras/tests/JsonArray/copyArray.cpp @@ -6,32 +6,57 @@ #include TEST_CASE("copyArray()") { - SECTION("1D -> JsonArray") { + SECTION("int[] -> JsonArray") { DynamicJsonDocument doc(4096); JsonArray array = doc.to(); char json[32]; int source[] = {1, 2, 3}; bool ok = copyArray(source, array); - REQUIRE(ok); + CHECK(ok); - serializeJson(array, json, sizeof(json)); - REQUIRE(std::string("[1,2,3]") == json); + serializeJson(array, json); + CHECK(std::string("[1,2,3]") == json); } - SECTION("1D -> JsonDocument") { + SECTION("std::string[] -> JsonArray") { + DynamicJsonDocument doc(4096); + JsonArray array = doc.to(); + char json[32]; + std::string source[] = {"a", "b", "c"}; + + bool ok = copyArray(source, array); + CHECK(ok); + + serializeJson(array, json); + CHECK(std::string("[\"a\",\"b\",\"c\"]") == json); + } + + SECTION("int[] -> JsonDocument") { DynamicJsonDocument doc(4096); char json[32]; int source[] = {1, 2, 3}; bool ok = copyArray(source, doc); - REQUIRE(ok); + CHECK(ok); - serializeJson(doc, json, sizeof(json)); - REQUIRE(std::string("[1,2,3]") == json); + serializeJson(doc, json); + CHECK(std::string("[1,2,3]") == json); } - SECTION("1D -> JsonArray, but not enough memory") { + SECTION("int[] -> MemberProxy") { + DynamicJsonDocument doc(4096); + char json[32]; + int source[] = {1, 2, 3}; + + bool ok = copyArray(source, doc["data"]); + CHECK(ok); + + serializeJson(doc, json); + CHECK(std::string("{\"data\":[1,2,3]}") == json); + } + + SECTION("int[] -> JsonArray, but not enough memory") { const size_t SIZE = JSON_ARRAY_SIZE(2); StaticJsonDocument doc; JsonArray array = doc.to(); @@ -41,36 +66,48 @@ TEST_CASE("copyArray()") { bool ok = copyArray(source, array); REQUIRE_FALSE(ok); - serializeJson(array, json, sizeof(json)); - REQUIRE(std::string("[1,2]") == json); + serializeJson(array, json); + CHECK(std::string("[1,2]") == json); } - SECTION("2D -> JsonArray") { + SECTION("int[][] -> JsonArray") { DynamicJsonDocument doc(4096); JsonArray array = doc.to(); char json[32]; int source[][3] = {{1, 2, 3}, {4, 5, 6}}; bool ok = copyArray(source, array); - REQUIRE(ok); + CHECK(ok); - serializeJson(array, json, sizeof(json)); - REQUIRE(std::string("[[1,2,3],[4,5,6]]") == json); + serializeJson(array, json); + CHECK(std::string("[[1,2,3],[4,5,6]]") == json); } - SECTION("2D -> JsonDocument") { + SECTION("int[][] -> MemberProxy") { + DynamicJsonDocument doc(4096); + char json[32]; + int source[][3] = {{1, 2, 3}, {4, 5, 6}}; + + bool ok = copyArray(source, doc["data"]); + CHECK(ok); + + serializeJson(doc, json); + CHECK(std::string("{\"data\":[[1,2,3],[4,5,6]]}") == json); + } + + SECTION("int[][] -> JsonDocument") { DynamicJsonDocument doc(4096); char json[32]; int source[][3] = {{1, 2, 3}, {4, 5, 6}}; bool ok = copyArray(source, doc); - REQUIRE(ok); + CHECK(ok); - serializeJson(doc, json, sizeof(json)); - REQUIRE(std::string("[[1,2,3],[4,5,6]]") == json); + serializeJson(doc, json); + CHECK(std::string("[[1,2,3],[4,5,6]]") == json); } - SECTION("2D -> JsonArray, but not enough memory") { + SECTION("int[][] -> JsonArray, but not enough memory") { const size_t SIZE = JSON_ARRAY_SIZE(2) + JSON_ARRAY_SIZE(3) + JSON_ARRAY_SIZE(2); StaticJsonDocument doc; @@ -84,92 +121,159 @@ TEST_CASE("copyArray()") { CAPTURE(doc.memoryUsage()); CHECK_FALSE(ok); - serializeJson(array, json, sizeof(json)); - REQUIRE(std::string("[[1,2,3],[4,5]]") == json); + serializeJson(array, json); + CHECK(std::string("[[1,2,3],[4,5]]") == json); } - SECTION("JsonArray -> 1D, with more space than needed") { + SECTION("JsonArray -> int[], with more space than needed") { DynamicJsonDocument doc(4096); char json[] = "[1,2,3]"; DeserializationError err = deserializeJson(doc, json); - REQUIRE(err == DeserializationError::Ok); + CHECK(err == DeserializationError::Ok); JsonArray array = doc.as(); int destination[4] = {0}; size_t result = copyArray(array, destination); - REQUIRE(3 == result); - REQUIRE(1 == destination[0]); - REQUIRE(2 == destination[1]); - REQUIRE(3 == destination[2]); - REQUIRE(0 == destination[3]); + CHECK(3 == result); + CHECK(1 == destination[0]); + CHECK(2 == destination[1]); + CHECK(3 == destination[2]); + CHECK(0 == destination[3]); } - SECTION("JsonArray -> 1D, without enough space") { + SECTION("JsonArray -> int[], without enough space") { DynamicJsonDocument doc(4096); char json[] = "[1,2,3]"; DeserializationError err = deserializeJson(doc, json); - REQUIRE(err == DeserializationError::Ok); + CHECK(err == DeserializationError::Ok); JsonArray array = doc.as(); int destination[2] = {0}; size_t result = copyArray(array, destination); - REQUIRE(2 == result); - REQUIRE(1 == destination[0]); - REQUIRE(2 == destination[1]); + CHECK(2 == result); + CHECK(1 == destination[0]); + CHECK(2 == destination[1]); } - SECTION("JsonDocument -> 1D") { + SECTION("JsonArray -> std::string[]") { + DynamicJsonDocument doc(4096); + char json[] = "[\"a\",\"b\",\"c\"]"; + DeserializationError err = deserializeJson(doc, json); + CHECK(err == DeserializationError::Ok); + JsonArray array = doc.as(); + + std::string destination[4]; + size_t result = copyArray(array, destination); + + CHECK(3 == result); + CHECK("a" == destination[0]); + CHECK("b" == destination[1]); + CHECK("c" == destination[2]); + CHECK("" == destination[3]); + } + + SECTION("JsonDocument -> int[]") { DynamicJsonDocument doc(4096); char json[] = "[1,2,3]"; DeserializationError err = deserializeJson(doc, json); - REQUIRE(err == DeserializationError::Ok); + CHECK(err == DeserializationError::Ok); int destination[4] = {0}; size_t result = copyArray(doc, destination); - REQUIRE(3 == result); - REQUIRE(1 == destination[0]); - REQUIRE(2 == destination[1]); - REQUIRE(3 == destination[2]); - REQUIRE(0 == destination[3]); + CHECK(3 == result); + CHECK(1 == destination[0]); + CHECK(2 == destination[1]); + CHECK(3 == destination[2]); + CHECK(0 == destination[3]); } - SECTION("JsonArray -> 2D") { + SECTION("MemberProxy -> int[]") { + DynamicJsonDocument doc(4096); + char json[] = "{\"data\":[1,2,3]}"; + DeserializationError err = deserializeJson(doc, json); + CHECK(err == DeserializationError::Ok); + + int destination[4] = {0}; + size_t result = copyArray(doc["data"], destination); + + CHECK(3 == result); + CHECK(1 == destination[0]); + CHECK(2 == destination[1]); + CHECK(3 == destination[2]); + CHECK(0 == destination[3]); + } + + SECTION("ElementProxy -> int[]") { + DynamicJsonDocument doc(4096); + char json[] = "[[1,2,3]]"; + DeserializationError err = deserializeJson(doc, json); + CHECK(err == DeserializationError::Ok); + + int destination[4] = {0}; + size_t result = copyArray(doc[0], destination); + + CHECK(3 == result); + CHECK(1 == destination[0]); + CHECK(2 == destination[1]); + CHECK(3 == destination[2]); + CHECK(0 == destination[3]); + } + + SECTION("JsonArray -> int[][]") { DynamicJsonDocument doc(4096); char json[] = "[[1,2],[3],[4]]"; DeserializationError err = deserializeJson(doc, json); - REQUIRE(err == DeserializationError::Ok); + CHECK(err == DeserializationError::Ok); JsonArray array = doc.as(); int destination[3][2] = {{0}}; copyArray(array, destination); - REQUIRE(1 == destination[0][0]); - REQUIRE(2 == destination[0][1]); - REQUIRE(3 == destination[1][0]); - REQUIRE(0 == destination[1][1]); - REQUIRE(4 == destination[2][0]); - REQUIRE(0 == destination[2][1]); + CHECK(1 == destination[0][0]); + CHECK(2 == destination[0][1]); + CHECK(3 == destination[1][0]); + CHECK(0 == destination[1][1]); + CHECK(4 == destination[2][0]); + CHECK(0 == destination[2][1]); } - SECTION("JsonDocument -> 2D") { + SECTION("JsonDocument -> int[][]") { DynamicJsonDocument doc(4096); char json[] = "[[1,2],[3],[4]]"; DeserializationError err = deserializeJson(doc, json); - REQUIRE(err == DeserializationError::Ok); + CHECK(err == DeserializationError::Ok); int destination[3][2] = {{0}}; copyArray(doc, destination); - REQUIRE(1 == destination[0][0]); - REQUIRE(2 == destination[0][1]); - REQUIRE(3 == destination[1][0]); - REQUIRE(0 == destination[1][1]); - REQUIRE(4 == destination[2][0]); - REQUIRE(0 == destination[2][1]); + CHECK(1 == destination[0][0]); + CHECK(2 == destination[0][1]); + CHECK(3 == destination[1][0]); + CHECK(0 == destination[1][1]); + CHECK(4 == destination[2][0]); + CHECK(0 == destination[2][1]); + } + + SECTION("MemberProxy -> int[][]") { + DynamicJsonDocument doc(4096); + char json[] = "{\"data\":[[1,2],[3],[4]]}"; + + DeserializationError err = deserializeJson(doc, json); + CHECK(err == DeserializationError::Ok); + + int destination[3][2] = {{0}}; + copyArray(doc["data"], destination); + + CHECK(1 == destination[0][0]); + CHECK(2 == destination[0][1]); + CHECK(3 == destination[1][0]); + CHECK(0 == destination[1][1]); + CHECK(4 == destination[2][0]); + CHECK(0 == destination[2][1]); } } diff --git a/lib/ArduinoJson-6.x/extras/tests/JsonArray/remove.cpp b/lib/ArduinoJson-6.x/extras/tests/JsonArray/remove.cpp index 20203148d..4113d71ed 100644 --- a/lib/ArduinoJson-6.x/extras/tests/JsonArray/remove.cpp +++ b/lib/ArduinoJson-6.x/extras/tests/JsonArray/remove.cpp @@ -65,4 +65,15 @@ TEST_CASE("JsonArray::remove()") { REQUIRE(_array[0] == 1); REQUIRE(_array[1] == 2); } + + SECTION("In a loop") { + for (JsonArray::iterator it = _array.begin(); it != _array.end(); ++it) { + if (*it == 2) + _array.remove(it); + } + + REQUIRE(2 == _array.size()); + REQUIRE(_array[0] == 1); + REQUIRE(_array[1] == 3); + } } diff --git a/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/DeserializationError.cpp b/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/DeserializationError.cpp index a04f25a19..332d06c4d 100644 --- a/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/DeserializationError.cpp +++ b/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/DeserializationError.cpp @@ -30,20 +30,22 @@ void testBoolification(DeserializationError error, bool expected) { TEST_CASE("DeserializationError") { SECTION("c_str()") { TEST_STRINGIFICATION(Ok); - TEST_STRINGIFICATION(TooDeep); - TEST_STRINGIFICATION(NoMemory); - TEST_STRINGIFICATION(InvalidInput); + TEST_STRINGIFICATION(EmptyInput); TEST_STRINGIFICATION(IncompleteInput); + TEST_STRINGIFICATION(InvalidInput); + TEST_STRINGIFICATION(NoMemory); TEST_STRINGIFICATION(NotSupported); + TEST_STRINGIFICATION(TooDeep); } SECTION("as boolean") { TEST_BOOLIFICATION(Ok, false); - TEST_BOOLIFICATION(TooDeep, true); - TEST_BOOLIFICATION(NoMemory, true); - TEST_BOOLIFICATION(InvalidInput, true); + TEST_BOOLIFICATION(EmptyInput, true); TEST_BOOLIFICATION(IncompleteInput, true); + TEST_BOOLIFICATION(InvalidInput, true); + TEST_BOOLIFICATION(NoMemory, true); TEST_BOOLIFICATION(NotSupported, true); + TEST_BOOLIFICATION(TooDeep, true); } SECTION("ostream DeserializationError") { @@ -58,13 +60,6 @@ TEST_CASE("DeserializationError") { REQUIRE(s.str() == "InvalidInput"); } - SECTION("out of range") { - int code = 666; - DeserializationError err( - *reinterpret_cast(&code)); - REQUIRE(err.c_str() == std::string("???")); - } - SECTION("switch") { DeserializationError err = DeserializationError::InvalidInput; switch (err.code()) { diff --git a/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/filter.cpp b/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/filter.cpp index 7296e8860..3e7867b9e 100644 --- a/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/filter.cpp +++ b/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/filter.cpp @@ -214,6 +214,15 @@ TEST_CASE("Filtering") { "{\"example\":{\"outcome\":42}}", 2 * JSON_OBJECT_SIZE(1) + 16 }, + { + // wildcard + "{\"example\":{\"type\":\"int\",\"outcome\":42}}", + "{\"*\":{\"outcome\":true}}", + 10, + DeserializationError::Ok, + "{\"example\":{\"outcome\":42}}", + 2 * JSON_OBJECT_SIZE(1) + 16 + }, { // only the first element of array counts "[1,2,3]", @@ -239,7 +248,7 @@ TEST_CASE("Filtering") { 10, DeserializationError::Ok, "[{\"example\":1},{\"example\":3}]", - JSON_ARRAY_SIZE(2) + 2 * JSON_OBJECT_SIZE(1) + 16 + JSON_ARRAY_SIZE(2) + 2 * JSON_OBJECT_SIZE(1) + 8 }, { "[',2,3]", @@ -525,7 +534,7 @@ TEST_CASE("Filtering") { 10, DeserializationError::InvalidInput, "{}", - JSON_OBJECT_SIZE(0) + 8 + JSON_OBJECT_SIZE(0) }, { // incomplete comment after key @@ -534,7 +543,7 @@ TEST_CASE("Filtering") { 10, DeserializationError::IncompleteInput, "{}", - JSON_OBJECT_SIZE(0) + 8 + JSON_OBJECT_SIZE(0) }, { // invalid comment after colon @@ -730,20 +739,3 @@ TEST_CASE("Overloads") { } #endif } - -TEST_CASE("StringMover::reclaim()") { - StaticJsonDocument<200> filter; - filter["a"] = true; - filter["c"] = true; - char input[] = "{\"a\":1,\"b\":2,\"c\":1}"; - - StaticJsonDocument<200> doc; - deserializeJson(doc, input, DeserializationOption::Filter(filter)); - - REQUIRE(doc.as() == "{\"a\":1,\"c\":1}"); - - CHECK(input[0] == 'a'); - CHECK(input[1] == 0); - CHECK(input[2] == 'c'); - CHECK(input[3] == 0); -} diff --git a/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/input_types.cpp b/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/input_types.cpp index d367e1ad2..2ec7e6985 100644 --- a/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/input_types.cpp +++ b/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/input_types.cpp @@ -3,11 +3,27 @@ // MIT License #include + #include #include #include "CustomReader.hpp" +TEST_CASE("deserializeJson(char*)") { + StaticJsonDocument<1024> doc; + + SECTION("should not duplicate strings") { + char input[] = "{\"hello\":\"world\"}"; + + DeserializationError err = deserializeJson(doc, input); + + REQUIRE(err == DeserializationError::Ok); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1)); + CHECK(doc.as().memoryUsage() == + JSON_OBJECT_SIZE(1)); // issue #1318 + } +} + TEST_CASE("deserializeJson(const std::string&)") { DynamicJsonDocument doc(4096); diff --git a/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/misc.cpp b/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/misc.cpp index 0fe0e9413..1d0cf2d0a 100644 --- a/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/misc.cpp +++ b/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/misc.cpp @@ -27,7 +27,13 @@ TEST_CASE("deserializeJson(DynamicJsonDocument&)") { SECTION("Empty input") { DeserializationError err = deserializeJson(doc, ""); - REQUIRE(err == DeserializationError::IncompleteInput); + REQUIRE(err == DeserializationError::EmptyInput); + } + + SECTION("Only spaces") { + DeserializationError err = deserializeJson(doc, " \t\n\r"); + + REQUIRE(err == DeserializationError::EmptyInput); } SECTION("issue #628") { diff --git a/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/object.cpp b/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/object.cpp index d6981d417..61d8fc3dd 100644 --- a/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/object.cpp +++ b/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/object.cpp @@ -290,4 +290,10 @@ TEST_CASE("deserialize JSON object") { REQUIRE(obj.size() == 0); REQUIRE(doc.memoryUsage() == JSON_OBJECT_SIZE(0)); } + + SECTION("Issue #1335") { + std::string json("{\"a\":{},\"b\":{}}"); + deserializeJson(doc, json); + CHECK(doc.as() == json); + } } diff --git a/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/string.cpp b/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/string.cpp index 7b5fdbfb0..70a26e07a 100644 --- a/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/string.cpp +++ b/lib/ArduinoJson-6.x/extras/tests/JsonDeserializer/string.cpp @@ -74,16 +74,16 @@ TEST_CASE("Invalid JSON string") { } } -TEST_CASE("Not enough room to duplicate the string") { - DynamicJsonDocument doc(JSON_OBJECT_SIZE(0)); +TEST_CASE("Not enough room to save the key") { + DynamicJsonDocument doc(JSON_OBJECT_SIZE(1) + 8); SECTION("Quoted string") { - REQUIRE(deserializeJson(doc, "{\"example\":1}") == + REQUIRE(deserializeJson(doc, "{\"accuracy\":1}") == DeserializationError::NoMemory); } SECTION("Non-quoted string") { - REQUIRE(deserializeJson(doc, "{example:1}") == + REQUIRE(deserializeJson(doc, "{accuracy:1}") == DeserializationError::NoMemory); } } diff --git a/lib/ArduinoJson-6.x/extras/tests/JsonDocument/CMakeLists.txt b/lib/ArduinoJson-6.x/extras/tests/JsonDocument/CMakeLists.txt index 5a083a688..ce00ab2fe 100644 --- a/lib/ArduinoJson-6.x/extras/tests/JsonDocument/CMakeLists.txt +++ b/lib/ArduinoJson-6.x/extras/tests/JsonDocument/CMakeLists.txt @@ -11,6 +11,7 @@ add_executable(JsonDocumentTests DynamicJsonDocument.cpp isNull.cpp nesting.cpp + overflowed.cpp remove.cpp shrinkToFit.cpp size.cpp diff --git a/lib/ArduinoJson-6.x/extras/tests/JsonDocument/StaticJsonDocument.cpp b/lib/ArduinoJson-6.x/extras/tests/JsonDocument/StaticJsonDocument.cpp index dc6a1d41a..e60aaf705 100644 --- a/lib/ArduinoJson-6.x/extras/tests/JsonDocument/StaticJsonDocument.cpp +++ b/lib/ArduinoJson-6.x/extras/tests/JsonDocument/StaticJsonDocument.cpp @@ -212,7 +212,7 @@ TEST_CASE("StaticJsonDocument") { SECTION("garbageCollect()") { StaticJsonDocument<256> doc; - doc[std::string("example")] = std::string("example"); + doc[std::string("example")] = std::string("jukebox"); doc.remove("example"); REQUIRE(doc.memoryUsage() == JSON_OBJECT_SIZE(1) + 16); diff --git a/lib/ArduinoJson-6.x/extras/tests/JsonDocument/overflowed.cpp b/lib/ArduinoJson-6.x/extras/tests/JsonDocument/overflowed.cpp new file mode 100644 index 000000000..74aa5716e --- /dev/null +++ b/lib/ArduinoJson-6.x/extras/tests/JsonDocument/overflowed.cpp @@ -0,0 +1,79 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#include +#include + +TEST_CASE("JsonDocument::overflowed()") { + SECTION("returns false on a fresh object") { + StaticJsonDocument<0> doc; + CHECK(doc.overflowed() == false); + } + + SECTION("returns true after a failed insertion") { + StaticJsonDocument<0> doc; + doc.add(0); + CHECK(doc.overflowed() == true); + } + + SECTION("returns false after successful insertion") { + StaticJsonDocument doc; + doc.add(0); + CHECK(doc.overflowed() == false); + } + + SECTION("returns true after a failed string copy") { + StaticJsonDocument doc; + doc.add(std::string("example")); + CHECK(doc.overflowed() == true); + } + + SECTION("returns false after a successful string copy") { + StaticJsonDocument doc; + doc.add(std::string("example")); + CHECK(doc.overflowed() == false); + } + + SECTION("returns true after a failed deserialization") { + StaticJsonDocument doc; + deserializeJson(doc, "[\"example\"]"); + CHECK(doc.overflowed() == true); + } + + SECTION("returns false after a successful deserialization") { + StaticJsonDocument doc; + deserializeJson(doc, "[\"example\"]"); + CHECK(doc.overflowed() == false); + } + + SECTION("returns false after clear()") { + StaticJsonDocument<0> doc; + doc.add(0); + doc.clear(); + CHECK(doc.overflowed() == false); + } + + SECTION("remains false after shrinkToFit()") { + DynamicJsonDocument doc(JSON_ARRAY_SIZE(1)); + doc.add(0); + doc.shrinkToFit(); + CHECK(doc.overflowed() == false); + } + + SECTION("remains true after shrinkToFit()") { + DynamicJsonDocument doc(JSON_ARRAY_SIZE(1)); + doc.add(0); + doc.add(0); + doc.shrinkToFit(); + CHECK(doc.overflowed() == true); + } + + SECTION("return false after garbageCollect()") { + DynamicJsonDocument doc(JSON_ARRAY_SIZE(1)); + doc.add(0); + doc.add(0); + doc.garbageCollect(); + CHECK(doc.overflowed() == false); + } +} diff --git a/lib/ArduinoJson-6.x/extras/tests/JsonVariant/or.cpp b/lib/ArduinoJson-6.x/extras/tests/JsonVariant/or.cpp index de1cc6166..f28e2d8e8 100644 --- a/lib/ArduinoJson-6.x/extras/tests/JsonVariant/or.cpp +++ b/lib/ArduinoJson-6.x/extras/tests/JsonVariant/or.cpp @@ -7,7 +7,7 @@ TEST_CASE("JsonVariant::operator|()") { DynamicJsonDocument doc(4096); - JsonVariant variant = doc.to(); + JsonVariant variant = doc["value"].to(); SECTION("undefined") { SECTION("undefined | const char*") { @@ -24,6 +24,27 @@ TEST_CASE("JsonVariant::operator|()") { bool result = variant | true; REQUIRE(result == true); } + + SECTION("undefined | ElementProxy") { + doc["array"][0] = 42; + + JsonVariantConst result = variant | doc["array"][0]; + REQUIRE(result == 42); + } + + SECTION("undefined | MemberProxy") { + doc["other"] = 42; + + JsonVariantConst result = variant | doc["other"]; + REQUIRE(result == 42); + } + + SECTION("ElementProxy | ElementProxy") { + doc["array"][0] = 42; + + JsonVariantConst result = doc["array"][1] | doc["array"][0]; + REQUIRE(result == 42); + } } SECTION("null") { @@ -43,6 +64,20 @@ TEST_CASE("JsonVariant::operator|()") { bool result = variant | true; REQUIRE(result == true); } + + SECTION("null | ElementProxy") { + doc["array"][0] = 42; + + JsonVariantConst result = variant | doc["array"][0]; + REQUIRE(result == 42); + } + + SECTION("null | MemberProxy") { + doc["other"] = 42; + + JsonVariantConst result = variant | doc["other"]; + REQUIRE(result == 42); + } } SECTION("int | const char*") { @@ -57,6 +92,20 @@ TEST_CASE("JsonVariant::operator|()") { REQUIRE(result == 42); } + SECTION("int | ElementProxy") { + variant.set(42); + doc["array"][0] = 666; + JsonVariantConst result = variant | doc["array"][0]; + REQUIRE(result == 42); + } + + SECTION("int | MemberProxy") { + variant.set(42); + doc["other"] = 666; + JsonVariantConst result = variant | doc["other"]; + REQUIRE(result == 42); + } + SECTION("int | int") { variant.set(0); int result = variant | 666; diff --git a/lib/ArduinoJson-6.x/extras/tests/JsonVariant/set.cpp b/lib/ArduinoJson-6.x/extras/tests/JsonVariant/set.cpp index eeb9088be..0baa22d27 100644 --- a/lib/ArduinoJson-6.x/extras/tests/JsonVariant/set.cpp +++ b/lib/ArduinoJson-6.x/extras/tests/JsonVariant/set.cpp @@ -7,115 +7,150 @@ enum ErrorCode { ERROR_01 = 1, ERROR_10 = 10 }; -TEST_CASE("JsonVariant and strings") { +TEST_CASE("JsonVariant::set() when there is enough memory") { DynamicJsonDocument doc(4096); JsonVariant variant = doc.to(); - SECTION("stores const char* by reference") { + SECTION("const char*") { char str[16]; strcpy(str, "hello"); - variant.set(static_cast(str)); + bool result = variant.set(static_cast(str)); strcpy(str, "world"); - REQUIRE(variant == "world"); + REQUIRE(result == true); + REQUIRE(variant == "world"); // stores by pointer } - SECTION("stores char* by copy") { - char str[16]; + SECTION("(const char*)0") { + bool result = variant.set(static_cast(0)); - strcpy(str, "hello"); - variant.set(str); - strcpy(str, "world"); - - REQUIRE(variant == "hello"); + REQUIRE(result == true); + REQUIRE(variant.isNull()); } - SECTION("stores unsigned char* by copy") { + SECTION("char*") { char str[16]; strcpy(str, "hello"); - variant.set(reinterpret_cast(str)); + bool result = variant.set(str); strcpy(str, "world"); - REQUIRE(variant == "hello"); + REQUIRE(result == true); + REQUIRE(variant == "hello"); // stores by copy } - SECTION("stores signed char* by copy") { + SECTION("(char*)0") { + bool result = variant.set(static_cast(0)); + + REQUIRE(result == true); + REQUIRE(variant.isNull()); + } + + SECTION("unsigned char*") { char str[16]; strcpy(str, "hello"); - variant.set(reinterpret_cast(str)); + bool result = variant.set(reinterpret_cast(str)); strcpy(str, "world"); - REQUIRE(variant == "hello"); + REQUIRE(result == true); + REQUIRE(variant == "hello"); // stores by copy + } + + SECTION("signed char*") { + char str[16]; + + strcpy(str, "hello"); + bool result = variant.set(reinterpret_cast(str)); + strcpy(str, "world"); + + REQUIRE(result == true); + REQUIRE(variant == "hello"); // stores by copy } #ifdef HAS_VARIABLE_LENGTH_ARRAY - SECTION("stores VLA by copy") { + SECTION("VLA") { int n = 16; char str[n]; strcpy(str, "hello"); - variant.set(str); + bool result = variant.set(str); strcpy(str, "world"); - REQUIRE(variant == "hello"); + REQUIRE(result == true); + REQUIRE(variant == "hello"); // stores by copy } #endif - SECTION("stores std::string by copy") { + SECTION("std::string") { std::string str; str = "hello"; - variant.set(str); + bool result = variant.set(str); str.replace(0, 5, "world"); - REQUIRE(variant == "hello"); + REQUIRE(result == true); + REQUIRE(variant == "hello"); // stores by copy } - SECTION("stores static JsonString by reference") { + SECTION("static JsonString") { char str[16]; strcpy(str, "hello"); - variant.set(JsonString(str, true)); + bool result = variant.set(JsonString(str, true)); strcpy(str, "world"); - REQUIRE(variant == "world"); + REQUIRE(result == true); + REQUIRE(variant == "world"); // stores by pointer } - SECTION("stores non-static JsonString by copy") { + SECTION("non-static JsonString") { char str[16]; strcpy(str, "hello"); - variant.set(JsonString(str, false)); + bool result = variant.set(JsonString(str, false)); strcpy(str, "world"); - REQUIRE(variant == "hello"); + REQUIRE(result == true); + REQUIRE(variant == "hello"); // stores by copy } - SECTION("stores an enum as an integer") { + SECTION("enum") { ErrorCode code = ERROR_10; - variant.set(code); + bool result = variant.set(code); + REQUIRE(result == true); REQUIRE(variant.is() == true); REQUIRE(variant.as() == 10); } } -TEST_CASE("JsonVariant with not enough memory") { +TEST_CASE("JsonVariant::set() with not enough memory") { StaticJsonDocument<1> doc; JsonVariant v = doc.to(); SECTION("std::string") { - v.set(std::string("hello world!!")); + bool result = v.set(std::string("hello world!!")); + + REQUIRE(result == false); REQUIRE(v.isNull()); } SECTION("Serialized") { - v.set(serialized(std::string("hello world!!"))); + bool result = v.set(serialized(std::string("hello world!!"))); + + REQUIRE(result == false); + REQUIRE(v.isNull()); + } + + SECTION("char*") { + char s[] = "hello world!!"; + bool result = v.set(s); + + REQUIRE(result == false); REQUIRE(v.isNull()); } } diff --git a/lib/ArduinoJson-6.x/extras/tests/MemoryPool/CMakeLists.txt b/lib/ArduinoJson-6.x/extras/tests/MemoryPool/CMakeLists.txt index 1ff0c0db2..ec1b989bb 100644 --- a/lib/ArduinoJson-6.x/extras/tests/MemoryPool/CMakeLists.txt +++ b/lib/ArduinoJson-6.x/extras/tests/MemoryPool/CMakeLists.txt @@ -4,10 +4,10 @@ add_executable(MemoryPoolTests allocVariant.cpp - allocString.cpp clear.cpp + saveString.cpp size.cpp - StringBuilder.cpp + StringCopier.cpp ) add_test(MemoryPool MemoryPoolTests) diff --git a/lib/ArduinoJson-6.x/extras/tests/MemoryPool/StringBuilder.cpp b/lib/ArduinoJson-6.x/extras/tests/MemoryPool/StringBuilder.cpp deleted file mode 100644 index 57810ce63..000000000 --- a/lib/ArduinoJson-6.x/extras/tests/MemoryPool/StringBuilder.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2020 -// MIT License - -#include -#include -#include - -using namespace ARDUINOJSON_NAMESPACE; - -TEST_CASE("StringBuilder") { - char buffer[4096]; - - SECTION("Works when buffer is big enough") { - MemoryPool pool(buffer, addPadding(JSON_STRING_SIZE(6))); - - StringBuilder str(&pool); - str.append("hello"); - - REQUIRE(str.complete() == std::string("hello")); - } - - SECTION("Returns null when too small") { - MemoryPool pool(buffer, sizeof(void*)); - - StringBuilder str(&pool); - str.append("hello world!"); - - REQUIRE(str.complete() == 0); - } - - SECTION("Increases size of memory pool") { - MemoryPool pool(buffer, addPadding(JSON_STRING_SIZE(6))); - - StringBuilder str(&pool); - str.append('h'); - str.complete(); - - REQUIRE(JSON_STRING_SIZE(1) == pool.size()); - } -} diff --git a/lib/ArduinoJson-6.x/extras/tests/MemoryPool/StringCopier.cpp b/lib/ArduinoJson-6.x/extras/tests/MemoryPool/StringCopier.cpp new file mode 100644 index 000000000..a4d387134 --- /dev/null +++ b/lib/ArduinoJson-6.x/extras/tests/MemoryPool/StringCopier.cpp @@ -0,0 +1,84 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#include +#include + +using namespace ARDUINOJSON_NAMESPACE; + +TEST_CASE("StringCopier") { + char buffer[4096]; + + SECTION("Works when buffer is big enough") { + MemoryPool pool(buffer, addPadding(JSON_STRING_SIZE(6))); + StringCopier str(pool); + + str.startString(); + str.append("hello"); + str.append('\0'); + + REQUIRE(str.isValid() == true); + REQUIRE(str.c_str() == std::string("hello")); + } + + SECTION("Returns null when too small") { + MemoryPool pool(buffer, sizeof(void*)); + StringCopier str(pool); + + str.startString(); + str.append("hello world!"); + + REQUIRE(str.isValid() == false); + } + + SECTION("Increases size of memory pool") { + MemoryPool pool(buffer, addPadding(JSON_STRING_SIZE(6))); + StringCopier str(pool); + + str.startString(); + str.append('h'); + str.save(); + + REQUIRE(1 == pool.size()); + } +} + +static const char* addStringToPool(MemoryPool& pool, const char* s) { + StringCopier str(pool); + str.startString(); + str.append(s); + str.append('\0'); + return str.save(); +} + +TEST_CASE("StringCopier::save() deduplicates strings") { + char buffer[4096]; + MemoryPool pool(buffer, 4096); + + SECTION("Basic") { + const char* s1 = addStringToPool(pool, "hello"); + const char* s2 = addStringToPool(pool, "world"); + const char* s3 = addStringToPool(pool, "hello"); + + REQUIRE(s1 == s3); + REQUIRE(s2 != s3); + REQUIRE(pool.size() == 12); + } + + SECTION("Requires terminator") { + const char* s1 = addStringToPool(pool, "hello world"); + const char* s2 = addStringToPool(pool, "hello"); + + REQUIRE(s2 != s1); + REQUIRE(pool.size() == 12 + 6); + } + + SECTION("Don't overrun") { + const char* s1 = addStringToPool(pool, "hello world"); + const char* s2 = addStringToPool(pool, "wor"); + + REQUIRE(s2 != s1); + REQUIRE(pool.size() == 12 + 4); + } +} diff --git a/lib/ArduinoJson-6.x/extras/tests/MemoryPool/allocString.cpp b/lib/ArduinoJson-6.x/extras/tests/MemoryPool/allocString.cpp deleted file mode 100644 index c93f45640..000000000 --- a/lib/ArduinoJson-6.x/extras/tests/MemoryPool/allocString.cpp +++ /dev/null @@ -1,67 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2020 -// MIT License - -#include -#include - -using namespace ARDUINOJSON_NAMESPACE; - -TEST_CASE("MemoryPool::allocFrozenString()") { - const size_t poolCapacity = 64; - const size_t longestString = poolCapacity; - char buffer[poolCapacity]; - MemoryPool pool(buffer, poolCapacity); - - SECTION("Returns different addresses") { - char *a = pool.allocFrozenString(1); - char *b = pool.allocFrozenString(1); - REQUIRE(a != b); - } - - SECTION("Returns NULL when full") { - void *p1 = pool.allocFrozenString(longestString); - REQUIRE(p1 != 0); - - void *p2 = pool.allocFrozenString(1); - REQUIRE(p2 == 0); - } - - SECTION("Returns NULL when pool is too small") { - void *p = pool.allocFrozenString(longestString + 1); - REQUIRE(0 == p); - } - - SECTION("Returns NULL when buffer is NULL") { - MemoryPool pool2(0, poolCapacity); - REQUIRE(0 == pool2.allocFrozenString(2)); - } - - SECTION("Returns NULL when capacity is 0") { - MemoryPool pool2(buffer, 0); - REQUIRE(0 == pool2.allocFrozenString(2)); - } - - SECTION("Returns same address after clear()") { - void *a = pool.allocFrozenString(1); - pool.clear(); - void *b = pool.allocFrozenString(1); - - REQUIRE(a == b); - } - - SECTION("Can use full capacity when fresh") { - void *a = pool.allocFrozenString(longestString); - - REQUIRE(a != 0); - } - - SECTION("Can use full capacity after clear") { - pool.allocFrozenString(longestString); - pool.clear(); - - void *a = pool.allocFrozenString(longestString); - - REQUIRE(a != 0); - } -} diff --git a/lib/ArduinoJson-6.x/extras/tests/MemoryPool/clear.cpp b/lib/ArduinoJson-6.x/extras/tests/MemoryPool/clear.cpp index 2eb3b4871..52666a6b6 100644 --- a/lib/ArduinoJson-6.x/extras/tests/MemoryPool/clear.cpp +++ b/lib/ArduinoJson-6.x/extras/tests/MemoryPool/clear.cpp @@ -3,6 +3,7 @@ // MIT License #include +#include #include using namespace ARDUINOJSON_NAMESPACE; @@ -21,8 +22,8 @@ TEST_CASE("MemoryPool::clear()") { } SECTION("Discards allocated strings") { - pool.allocFrozenString(10); - REQUIRE(pool.size() > 0); + pool.saveString(adaptString(const_cast("123456789"))); + REQUIRE(pool.size() == 10); pool.clear(); diff --git a/lib/ArduinoJson-6.x/extras/tests/MemoryPool/saveString.cpp b/lib/ArduinoJson-6.x/extras/tests/MemoryPool/saveString.cpp new file mode 100644 index 000000000..56836fa26 --- /dev/null +++ b/lib/ArduinoJson-6.x/extras/tests/MemoryPool/saveString.cpp @@ -0,0 +1,81 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#include +#include +#include + +using namespace ARDUINOJSON_NAMESPACE; + +static const char *saveString(MemoryPool &pool, const char *s) { + return pool.saveString(adaptString(const_cast(s))); +} + +TEST_CASE("MemoryPool::saveString()") { + char buffer[32]; + MemoryPool pool(buffer, 32); + + SECTION("Duplicates different strings") { + const char *a = saveString(pool, "hello"); + const char *b = saveString(pool, "world"); + REQUIRE(a != b); + REQUIRE(pool.size() == 6 + 6); + } + + SECTION("Deduplicates identical strings") { + const char *a = saveString(pool, "hello"); + const char *b = saveString(pool, "hello"); + REQUIRE(a == b); + REQUIRE(pool.size() == 6); + } + + SECTION("Returns NULL when full") { + REQUIRE(pool.capacity() == 32); + + const void *p1 = saveString(pool, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + REQUIRE(p1 != 0); + REQUIRE(pool.size() == 32); + + const void *p2 = saveString(pool, "b"); + REQUIRE(p2 == 0); + } + + SECTION("Returns NULL when pool is too small") { + const void *p = saveString(pool, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + REQUIRE(0 == p); + } + + SECTION("Returns NULL when buffer is NULL") { + MemoryPool pool2(0, 32); + REQUIRE(0 == saveString(pool2, "a")); + } + + SECTION("Returns NULL when capacity is 0") { + MemoryPool pool2(buffer, 0); + REQUIRE(0 == saveString(pool2, "a")); + } + + SECTION("Returns same address after clear()") { + const void *a = saveString(pool, "hello"); + pool.clear(); + const void *b = saveString(pool, "world"); + + REQUIRE(a == b); + } + + SECTION("Can use full capacity when fresh") { + const void *a = saveString(pool, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + + REQUIRE(a != 0); + } + + SECTION("Can use full capacity after clear") { + saveString(pool, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + pool.clear(); + + const void *a = saveString(pool, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); + + REQUIRE(a != 0); + } +} diff --git a/lib/ArduinoJson-6.x/extras/tests/MemoryPool/size.cpp b/lib/ArduinoJson-6.x/extras/tests/MemoryPool/size.cpp index 0ab6e9007..0e141df6e 100644 --- a/lib/ArduinoJson-6.x/extras/tests/MemoryPool/size.cpp +++ b/lib/ArduinoJson-6.x/extras/tests/MemoryPool/size.cpp @@ -22,29 +22,6 @@ TEST_CASE("MemoryPool::size()") { REQUIRE(0 == pool.size()); } - SECTION("size() == capacity() after allocExpandableString()") { - pool.allocExpandableString(); - REQUIRE(pool.size() == pool.capacity()); - } - - SECTION("Decreases after freezeString()") { - StringSlot a = pool.allocExpandableString(); - pool.freezeString(a, 1); - REQUIRE(pool.size() == 1); - - StringSlot b = pool.allocExpandableString(); - pool.freezeString(b, 1); - REQUIRE(pool.size() == 2); - } - - SECTION("Increases after allocFrozenString()") { - pool.allocFrozenString(1); - REQUIRE(pool.size() == 1); - - pool.allocFrozenString(2); - REQUIRE(pool.size() == 3); - } - SECTION("Doesn't grow when memory pool is full") { const size_t variantCount = sizeof(buffer) / sizeof(VariantSlot); diff --git a/lib/ArduinoJson-6.x/extras/tests/Misc/CMakeLists.txt b/lib/ArduinoJson-6.x/extras/tests/Misc/CMakeLists.txt index 042264a45..2723e6639 100644 --- a/lib/ArduinoJson-6.x/extras/tests/Misc/CMakeLists.txt +++ b/lib/ArduinoJson-6.x/extras/tests/Misc/CMakeLists.txt @@ -6,13 +6,14 @@ add_executable(MiscTests arithmeticCompare.cpp conflicts.cpp FloatParts.cpp + JsonString.cpp Readers.cpp StringAdapters.cpp StringWriter.cpp TypeTraits.cpp unsigned_char.cpp - Utf8.cpp Utf16.cpp + Utf8.cpp version.cpp ) diff --git a/lib/ArduinoJson-6.x/extras/tests/Misc/JsonString.cpp b/lib/ArduinoJson-6.x/extras/tests/Misc/JsonString.cpp new file mode 100644 index 000000000..a0c6d3ae2 --- /dev/null +++ b/lib/ArduinoJson-6.x/extras/tests/Misc/JsonString.cpp @@ -0,0 +1,60 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#include +#include + +TEST_CASE("JsonString") { + SECTION("Default constructor creates a null JsonString") { + JsonString s; + + CHECK(s.isNull() == true); + CHECK(s.c_str() == 0); + CHECK(s.isStatic() == true); + } + + SECTION("Compare null with null") { + JsonString a, b; + + CHECK(a == b); + CHECK_FALSE(a != b); + } + + SECTION("Compare null with non-null") { + JsonString a(0), b("hello"); + + CHECK_FALSE(a == b); + CHECK(a != b); + } + + SECTION("Compare non-null with null") { + JsonString a("hello"), b(0); + + CHECK_FALSE(a == b); + CHECK(a != b); + } + + SECTION("Compare different strings") { + JsonString a("hello"), b("world"); + + CHECK_FALSE(a == b); + CHECK(a != b); + } + + SECTION("Compare identical by pointer") { + JsonString a("hello"), b("hello"); + + CHECK(a == b); + CHECK_FALSE(a != b); + } + + SECTION("Compare identical by value") { + char s1[] = "hello"; + char s2[] = "hello"; + JsonString a(s1), b(s2); + + CHECK(a == b); + CHECK_FALSE(a != b); + } +} diff --git a/lib/ArduinoJson-6.x/extras/tests/Misc/StringAdapters.cpp b/lib/ArduinoJson-6.x/extras/tests/Misc/StringAdapters.cpp index c299bef96..2567a282e 100644 --- a/lib/ArduinoJson-6.x/extras/tests/Misc/StringAdapters.cpp +++ b/lib/ArduinoJson-6.x/extras/tests/Misc/StringAdapters.cpp @@ -6,10 +6,11 @@ #include "progmem_emulation.hpp" #include "weird_strcmp.hpp" +#include #include #include #include -#include +#include #include @@ -101,7 +102,22 @@ TEST_CASE("FlashStringAdapter") { TEST_CASE("std::string") { std::string str("bravo"); - StlStringAdapter adapter = adaptString(str); + StdStringAdapter adapter = adaptString(str); + + CHECK(adapter.compare(NULL) > 0); + CHECK(adapter.compare("alpha") > 0); + CHECK(adapter.compare("bravo") == 0); + CHECK(adapter.compare("charlie") < 0); + + CHECK(adapter.equals("bravo")); + CHECK_FALSE(adapter.equals("charlie")); + + CHECK(adapter.size() == 5); +} + +TEST_CASE("Arduino String") { + ::String str("bravo"); + ArduinoStringAdapter adapter = adaptString(str); CHECK(adapter.compare(NULL) > 0); CHECK(adapter.compare("alpha") > 0); @@ -116,7 +132,7 @@ TEST_CASE("std::string") { TEST_CASE("custom_string") { custom_string str("bravo"); - StlStringAdapter adapter = adaptString(str); + StdStringAdapter adapter = adaptString(str); CHECK(adapter.compare(NULL) > 0); CHECK(adapter.compare("alpha") > 0); diff --git a/lib/ArduinoJson-6.x/extras/tests/Misc/Utf8.cpp b/lib/ArduinoJson-6.x/extras/tests/Misc/Utf8.cpp index 1c7e1b321..cb0464c12 100644 --- a/lib/ArduinoJson-6.x/extras/tests/Misc/Utf8.cpp +++ b/lib/ArduinoJson-6.x/extras/tests/Misc/Utf8.cpp @@ -12,12 +12,14 @@ using namespace ARDUINOJSON_NAMESPACE; static void testCodepoint(uint32_t codepoint, std::string expected) { char buffer[4096]; MemoryPool pool(buffer, 4096); - StringBuilder str(&pool); + StringCopier str(pool); + str.startString(); CAPTURE(codepoint); Utf8::encodeCodepoint(codepoint, str); - REQUIRE(str.complete() == expected); + str.append('\0'); + REQUIRE(str.c_str() == expected); } TEST_CASE("Utf8::encodeCodepoint()") { diff --git a/lib/ArduinoJson-6.x/extras/tests/MixedConfiguration/CMakeLists.txt b/lib/ArduinoJson-6.x/extras/tests/MixedConfiguration/CMakeLists.txt index 650b244cf..812276379 100644 --- a/lib/ArduinoJson-6.x/extras/tests/MixedConfiguration/CMakeLists.txt +++ b/lib/ArduinoJson-6.x/extras/tests/MixedConfiguration/CMakeLists.txt @@ -18,6 +18,8 @@ add_executable(MixedConfigurationTests enable_nan_0.cpp enable_nan_1.cpp enable_progmem_1.cpp + enable_string_deduplication_0.cpp + enable_string_deduplication_1.cpp use_double_0.cpp use_double_1.cpp use_long_long_0.cpp diff --git a/lib/ArduinoJson-6.x/extras/tests/MixedConfiguration/enable_comments_1.cpp b/lib/ArduinoJson-6.x/extras/tests/MixedConfiguration/enable_comments_1.cpp index 7e59bb03d..5d223e529 100644 --- a/lib/ArduinoJson-6.x/extras/tests/MixedConfiguration/enable_comments_1.cpp +++ b/lib/ArduinoJson-6.x/extras/tests/MixedConfiguration/enable_comments_1.cpp @@ -373,16 +373,22 @@ TEST_CASE("Comments in objects") { TEST_CASE("Comments alone") { DynamicJsonDocument doc(2048); - SECTION("Just a trailing comment") { + SECTION("Just a trailing comment with no line break") { DeserializationError err = deserializeJson(doc, "// comment"); REQUIRE(err == DeserializationError::IncompleteInput); } + SECTION("Just a trailing comment with no a break") { + DeserializationError err = deserializeJson(doc, "// comment\n"); + + REQUIRE(err == DeserializationError::EmptyInput); + } + SECTION("Just a block comment") { DeserializationError err = deserializeJson(doc, "/*comment*/"); - REQUIRE(err == DeserializationError::IncompleteInput); + REQUIRE(err == DeserializationError::EmptyInput); } SECTION("Just a slash") { diff --git a/lib/ArduinoJson-6.x/extras/tests/MixedConfiguration/enable_progmem_1.cpp b/lib/ArduinoJson-6.x/extras/tests/MixedConfiguration/enable_progmem_1.cpp index 5f30b58b8..a1d4249e2 100644 --- a/lib/ArduinoJson-6.x/extras/tests/MixedConfiguration/enable_progmem_1.cpp +++ b/lib/ArduinoJson-6.x/extras/tests/MixedConfiguration/enable_progmem_1.cpp @@ -53,33 +53,33 @@ TEST_CASE("Flash strings") { } TEST_CASE("strlen_P") { - CHECK(strlen_P(FC("")) == 0); - CHECK(strlen_P(FC("a")) == 1); - CHECK(strlen_P(FC("ac")) == 2); + CHECK(strlen_P(PSTR("")) == 0); + CHECK(strlen_P(PSTR("a")) == 1); + CHECK(strlen_P(PSTR("ac")) == 2); } TEST_CASE("strncmp_P") { - CHECK(strncmp_P("a", FC("b"), 0) == 0); - CHECK(strncmp_P("a", FC("b"), 1) == -1); - CHECK(strncmp_P("b", FC("a"), 1) == 1); - CHECK(strncmp_P("a", FC("a"), 0) == 0); - CHECK(strncmp_P("a", FC("b"), 2) == -1); - CHECK(strncmp_P("b", FC("a"), 2) == 1); - CHECK(strncmp_P("a", FC("a"), 2) == 0); + CHECK(strncmp_P("a", PSTR("b"), 0) == 0); + CHECK(strncmp_P("a", PSTR("b"), 1) == -1); + CHECK(strncmp_P("b", PSTR("a"), 1) == 1); + CHECK(strncmp_P("a", PSTR("a"), 0) == 0); + CHECK(strncmp_P("a", PSTR("b"), 2) == -1); + CHECK(strncmp_P("b", PSTR("a"), 2) == 1); + CHECK(strncmp_P("a", PSTR("a"), 2) == 0); } TEST_CASE("strcmp_P") { - CHECK(strcmp_P("a", FC("b")) == -1); - CHECK(strcmp_P("b", FC("a")) == 1); - CHECK(strcmp_P("a", FC("a")) == 0); - CHECK(strcmp_P("aa", FC("ab")) == -1); - CHECK(strcmp_P("ab", FC("aa")) == 1); - CHECK(strcmp_P("aa", FC("aa")) == 0); + CHECK(strcmp_P("a", PSTR("b")) == -1); + CHECK(strcmp_P("b", PSTR("a")) == 1); + CHECK(strcmp_P("a", PSTR("a")) == 0); + CHECK(strcmp_P("aa", PSTR("ab")) == -1); + CHECK(strcmp_P("ab", PSTR("aa")) == 1); + CHECK(strcmp_P("aa", PSTR("aa")) == 0); } TEST_CASE("memcpy_P") { char dst[4]; - CHECK(memcpy_P(dst, FC("ABC"), 4) == dst); + CHECK(memcpy_P(dst, PSTR("ABC"), 4) == dst); CHECK(dst[0] == 'A'); CHECK(dst[1] == 'B'); CHECK(dst[2] == 'C'); @@ -165,3 +165,22 @@ TEST_CASE("Reader") { REQUIRE(buffer[6] == 'g'); } } + +static void testStringification(DeserializationError error, + std::string expected) { + const __FlashStringHelper* s = error.f_str(); + CHECK(reinterpret_cast(convertFlashToPtr(s)) == expected); +} + +#define TEST_STRINGIFICATION(symbol) \ + testStringification(DeserializationError::symbol, #symbol) + +TEST_CASE("DeserializationError::f_str()") { + TEST_STRINGIFICATION(Ok); + TEST_STRINGIFICATION(EmptyInput); + TEST_STRINGIFICATION(IncompleteInput); + TEST_STRINGIFICATION(InvalidInput); + TEST_STRINGIFICATION(NoMemory); + TEST_STRINGIFICATION(NotSupported); + TEST_STRINGIFICATION(TooDeep); +} diff --git a/lib/ArduinoJson-6.x/extras/tests/MixedConfiguration/enable_string_deduplication_0.cpp b/lib/ArduinoJson-6.x/extras/tests/MixedConfiguration/enable_string_deduplication_0.cpp new file mode 100644 index 000000000..d040dbab3 --- /dev/null +++ b/lib/ArduinoJson-6.x/extras/tests/MixedConfiguration/enable_string_deduplication_0.cpp @@ -0,0 +1,125 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#include "progmem_emulation.hpp" + +#define ARDUINOJSON_ENABLE_ARDUINO_STRING 1 +#define ARDUINOJSON_ENABLE_PROGMEM 1 +#define ARDUINOJSON_ENABLE_STRING_DEDUPLICATION 0 +#include + +#include + +TEST_CASE("ARDUINOJSON_ENABLE_STRING_DEDUPLICATION = 0") { + StaticJsonDocument<1024> doc; + + SECTION("deserializeJson()") { + SECTION("Deduplicate values") { + deserializeJson(doc, "[\"example\",\"example\"]"); + + CHECK(doc.memoryUsage() == JSON_ARRAY_SIZE(2) + 16); + CHECK(doc[0].as() != doc[1].as()); + } + + SECTION("Deduplicate keys") { + deserializeJson(doc, "[{\"example\":1},{\"example\":2}]"); + + CHECK(doc.memoryUsage() == + 2 * JSON_OBJECT_SIZE(1) + JSON_ARRAY_SIZE(2) + 16); + + const char* key1 = doc[0].as().begin()->key().c_str(); + const char* key2 = doc[1].as().begin()->key().c_str(); + + CHECK(key1 != key2); + } + } + + SECTION("JsonDocument") { + SECTION("values") { + SECTION("std::string") { + doc.add(std::string("example")); + doc.add(std::string("example")); + + CHECK(doc.memoryUsage() == JSON_ARRAY_SIZE(2) + 16); + CHECK(doc[0].as() != doc[1].as()); + } + + SECTION("char*") { + char value[] = "example"; + doc.add(value); + doc.add(value); + + CHECK(doc.memoryUsage() == JSON_ARRAY_SIZE(2) + 16); + CHECK(doc[0].as() != doc[1].as()); + } + + SECTION("Arduino String") { + doc.add(String("example")); + doc.add(String("example")); + + CHECK(doc.memoryUsage() == JSON_ARRAY_SIZE(2) + 16); + CHECK(doc[0].as() != doc[1].as()); + } + + SECTION("Flash string") { + doc.add(F("example")); + doc.add(F("example")); + + CHECK(doc.memoryUsage() == JSON_ARRAY_SIZE(2) + 16); + CHECK(doc[0].as() != doc[1].as()); + } + } + + SECTION("keys") { + SECTION("std::string") { + doc[0][std::string("example")] = 1; + doc[1][std::string("example")] = 2; + + CHECK(doc.memoryUsage() == + JSON_ARRAY_SIZE(2) + 2 * JSON_OBJECT_SIZE(1) + 16); + + const char* key1 = doc[0].as().begin()->key().c_str(); + const char* key2 = doc[1].as().begin()->key().c_str(); + CHECK(key1 != key2); + } + + SECTION("char*") { + char key[] = "example"; + doc[0][key] = 1; + doc[1][key] = 2; + + CHECK(doc.memoryUsage() == + JSON_ARRAY_SIZE(2) + 2 * JSON_OBJECT_SIZE(1) + 16); + + const char* key1 = doc[0].as().begin()->key().c_str(); + const char* key2 = doc[1].as().begin()->key().c_str(); + CHECK(key1 != key2); + } + + SECTION("Arduino String") { + doc[0][String("example")] = 1; + doc[1][String("example")] = 2; + + CHECK(doc.memoryUsage() == + JSON_ARRAY_SIZE(2) + 2 * JSON_OBJECT_SIZE(1) + 16); + + const char* key1 = doc[0].as().begin()->key().c_str(); + const char* key2 = doc[1].as().begin()->key().c_str(); + CHECK(key1 != key2); + } + + SECTION("Flash string") { + doc[0][F("example")] = 1; + doc[1][F("example")] = 2; + + CHECK(doc.memoryUsage() == + JSON_ARRAY_SIZE(2) + 2 * JSON_OBJECT_SIZE(1) + 16); + + const char* key1 = doc[0].as().begin()->key().c_str(); + const char* key2 = doc[1].as().begin()->key().c_str(); + CHECK(key1 != key2); + } + } + } +} diff --git a/lib/ArduinoJson-6.x/extras/tests/MixedConfiguration/enable_string_deduplication_1.cpp b/lib/ArduinoJson-6.x/extras/tests/MixedConfiguration/enable_string_deduplication_1.cpp new file mode 100644 index 000000000..6971cb6ab --- /dev/null +++ b/lib/ArduinoJson-6.x/extras/tests/MixedConfiguration/enable_string_deduplication_1.cpp @@ -0,0 +1,124 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#include "progmem_emulation.hpp" + +#define ARDUINOJSON_ENABLE_ARDUINO_STRING 1 +#define ARDUINOJSON_ENABLE_PROGMEM 1 +#define ARDUINOJSON_ENABLE_STRING_DEDUPLICATION 1 +#include + +#include + +TEST_CASE("ARDUINOJSON_ENABLE_STRING_DEDUPLICATION = 1") { + StaticJsonDocument<1024> doc; + + SECTION("deserializeJson()") { + SECTION("Deduplicate values") { + deserializeJson(doc, "[\"example\",\"example\"]"); + + CHECK(doc.memoryUsage() == JSON_ARRAY_SIZE(2) + 8); + CHECK(doc[0].as() == doc[1].as()); + } + + SECTION("Deduplicate keys") { + deserializeJson(doc, "[{\"example\":1},{\"example\":2}]"); + + CHECK(doc.memoryUsage() == + 2 * JSON_OBJECT_SIZE(1) + JSON_ARRAY_SIZE(2) + 8); + + const char* key1 = doc[0].as().begin()->key().c_str(); + const char* key2 = doc[1].as().begin()->key().c_str(); + CHECK(key1 == key2); + } + } + + SECTION("JsonDocument") { + SECTION("values") { + SECTION("std::string") { + doc.add(std::string("example")); + doc.add(std::string("example")); + + CHECK(doc.memoryUsage() == JSON_ARRAY_SIZE(2) + 8); + CHECK(doc[0].as() == doc[1].as()); + } + + SECTION("char*") { + char value[] = "example"; + doc.add(value); + doc.add(value); + + CHECK(doc.memoryUsage() == JSON_ARRAY_SIZE(2) + 8); + CHECK(doc[0].as() == doc[1].as()); + } + + SECTION("Arduino String") { + doc.add(String("example")); + doc.add(String("example")); + + CHECK(doc.memoryUsage() == JSON_ARRAY_SIZE(2) + 8); + CHECK(doc[0].as() == doc[1].as()); + } + + SECTION("Flash string") { + doc.add(F("example")); + doc.add(F("example")); + + CHECK(doc.memoryUsage() == JSON_ARRAY_SIZE(2) + 8); + CHECK(doc[0].as() == doc[1].as()); + } + } + + SECTION("keys") { + SECTION("std::string") { + doc[0][std::string("example")] = 1; + doc[1][std::string("example")] = 2; + + CHECK(doc.memoryUsage() == + JSON_ARRAY_SIZE(2) + 2 * JSON_OBJECT_SIZE(1) + 8); + + const char* key1 = doc[0].as().begin()->key().c_str(); + const char* key2 = doc[1].as().begin()->key().c_str(); + CHECK(key1 == key2); + } + + SECTION("char*") { + char key[] = "example"; + doc[0][key] = 1; + doc[1][key] = 2; + + CHECK(doc.memoryUsage() == + JSON_ARRAY_SIZE(2) + 2 * JSON_OBJECT_SIZE(1) + 8); + + const char* key1 = doc[0].as().begin()->key().c_str(); + const char* key2 = doc[1].as().begin()->key().c_str(); + CHECK(key1 == key2); + } + + SECTION("Arduino String") { + doc[0][String("example")] = 1; + doc[1][String("example")] = 2; + + CHECK(doc.memoryUsage() == + JSON_ARRAY_SIZE(2) + 2 * JSON_OBJECT_SIZE(1) + 8); + + const char* key1 = doc[0].as().begin()->key().c_str(); + const char* key2 = doc[1].as().begin()->key().c_str(); + CHECK(key1 == key2); + } + + SECTION("Flash string") { + doc[0][F("example")] = 1; + doc[1][F("example")] = 2; + + CHECK(doc.memoryUsage() == + JSON_ARRAY_SIZE(2) + 2 * JSON_OBJECT_SIZE(1) + 8); + + const char* key1 = doc[0].as().begin()->key().c_str(); + const char* key2 = doc[1].as().begin()->key().c_str(); + CHECK(key1 == key2); + } + } + } +} diff --git a/lib/ArduinoJson-6.x/extras/tests/MsgPackDeserializer/CMakeLists.txt b/lib/ArduinoJson-6.x/extras/tests/MsgPackDeserializer/CMakeLists.txt index f3f52f086..5052842d1 100644 --- a/lib/ArduinoJson-6.x/extras/tests/MsgPackDeserializer/CMakeLists.txt +++ b/lib/ArduinoJson-6.x/extras/tests/MsgPackDeserializer/CMakeLists.txt @@ -10,6 +10,7 @@ add_executable(MsgPackDeserializerTests doubleToFloat.cpp incompleteInput.cpp input_types.cpp + misc.cpp nestingLimit.cpp notSupported.cpp ) diff --git a/lib/ArduinoJson-6.x/extras/tests/MsgPackDeserializer/misc.cpp b/lib/ArduinoJson-6.x/extras/tests/MsgPackDeserializer/misc.cpp new file mode 100644 index 000000000..0035c02f0 --- /dev/null +++ b/lib/ArduinoJson-6.x/extras/tests/MsgPackDeserializer/misc.cpp @@ -0,0 +1,24 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#include +#include + +TEST_CASE("deserializeMsgPack() returns EmptyInput") { + StaticJsonDocument<100> doc; + + SECTION("from sized buffer") { + DeserializationError err = deserializeMsgPack(doc, "", 0); + + REQUIRE(err == DeserializationError::EmptyInput); + } + + SECTION("from stream") { + std::istringstream input(""); + + DeserializationError err = deserializeMsgPack(doc, input); + + REQUIRE(err == DeserializationError::EmptyInput); + } +} diff --git a/lib/ArduinoJson-6.x/extras/tests/Numbers/CMakeLists.txt b/lib/ArduinoJson-6.x/extras/tests/Numbers/CMakeLists.txt index 50ab51353..30c123cdd 100644 --- a/lib/ArduinoJson-6.x/extras/tests/Numbers/CMakeLists.txt +++ b/lib/ArduinoJson-6.x/extras/tests/Numbers/CMakeLists.txt @@ -4,6 +4,7 @@ add_executable(NumbersTests parseFloat.cpp + parseDouble.cpp parseInteger.cpp parseNumber.cpp ) diff --git a/lib/ArduinoJson-6.x/extras/tests/Numbers/parseDouble.cpp b/lib/ArduinoJson-6.x/extras/tests/Numbers/parseDouble.cpp new file mode 100644 index 000000000..da57357b6 --- /dev/null +++ b/lib/ArduinoJson-6.x/extras/tests/Numbers/parseDouble.cpp @@ -0,0 +1,97 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#define ARDUINOJSON_USE_DOUBLE 1 +#define ARDUINOJSON_ENABLE_NAN 1 +#define ARDUINOJSON_ENABLE_INFINITY 1 + +#include +#include +#include + +using namespace ARDUINOJSON_NAMESPACE; + +void checkDouble(const char* input, double expected) { + CAPTURE(input); + REQUIRE(parseNumber(input) == Approx(expected)); +} + +void checkDoubleNaN(const char* input) { + CAPTURE(input); + double result = parseNumber(input); + REQUIRE(result != result); +} + +void checkDoubleInf(const char* input, bool negative) { + CAPTURE(input); + double x = parseNumber(input); + if (negative) + REQUIRE(x < 0); + else + REQUIRE(x > 0); + REQUIRE(x == x); // not a NaN + REQUIRE(x * 2 == x); // a property of infinity +} + +TEST_CASE("parseNumber()") { + SECTION("Short_NoExponent") { + checkDouble("3.14", 3.14); + checkDouble("-3.14", -3.14); + checkDouble("+3.14", +3.14); + } + + SECTION("Short_NoDot") { + checkDouble("1E+308", 1E+308); + checkDouble("-1E+308", -1E+308); + checkDouble("+1E-308", +1E-308); + checkDouble("+1e+308", +1e+308); + checkDouble("-1e-308", -1e-308); + } + + SECTION("Max") { + checkDouble(".017976931348623147e+310", 1.7976931348623147e+308); + checkDouble(".17976931348623147e+309", 1.7976931348623147e+308); + checkDouble("1.7976931348623147e+308", 1.7976931348623147e+308); + checkDouble("17.976931348623147e+307", 1.7976931348623147e+308); + checkDouble("179.76931348623147e+306", 1.7976931348623147e+308); + } + + SECTION("Min") { + checkDouble(".022250738585072014e-306", 2.2250738585072014e-308); + checkDouble(".22250738585072014e-307", 2.2250738585072014e-308); + checkDouble("2.2250738585072014e-308", 2.2250738585072014e-308); + checkDouble("22.250738585072014e-309", 2.2250738585072014e-308); + checkDouble("222.50738585072014e-310", 2.2250738585072014e-308); + } + + SECTION("VeryLong") { + checkDouble("0.00000000000000000000000000000001", 1e-32); + checkDouble("100000000000000000000000000000000.0", 1e+32); + checkDouble( + "100000000000000000000000000000000.00000000000000000000000000000", + 1e+32); + } + + SECTION("MantissaTooLongToFit") { + checkDouble("0.179769313486231571111111111111", 0.17976931348623157); + checkDouble("17976931348623157.11111111111111", 17976931348623157.0); + checkDouble("1797693.134862315711111111111111", 1797693.1348623157); + + checkDouble("-0.179769313486231571111111111111", -0.17976931348623157); + checkDouble("-17976931348623157.11111111111111", -17976931348623157.0); + checkDouble("-1797693.134862315711111111111111", -1797693.1348623157); + } + + SECTION("ExponentTooBig") { + checkDoubleInf("1e309", false); + checkDoubleInf("-1e309", true); + checkDoubleInf("1e65535", false); + checkDouble("1e-65535", 0.0); + } + + SECTION("NaN") { + checkDoubleNaN("NaN"); + checkDoubleNaN("nan"); + } +} diff --git a/lib/ArduinoJson-6.x/extras/tests/Numbers/parseFloat.cpp b/lib/ArduinoJson-6.x/extras/tests/Numbers/parseFloat.cpp index f79d69761..84085fe80 100644 --- a/lib/ArduinoJson-6.x/extras/tests/Numbers/parseFloat.cpp +++ b/lib/ArduinoJson-6.x/extras/tests/Numbers/parseFloat.cpp @@ -6,28 +6,26 @@ #define ARDUINOJSON_ENABLE_NAN 1 #define ARDUINOJSON_ENABLE_INFINITY 1 -#include +#include +#include #include using namespace ARDUINOJSON_NAMESPACE; -template -void checkFloat(const char* input, T expected) { +void checkFloat(const char* input, float expected) { CAPTURE(input); - REQUIRE(parseFloat(input) == Approx(expected)); + REQUIRE(parseNumber(input) == Approx(expected)); } -template -void checkNaN(const char* input) { +void checkFloatNaN(const char* input) { CAPTURE(input); - T result = parseFloat(input); + float result = parseNumber(input); REQUIRE(result != result); } -template -void checkInf(const char* input, bool negative) { +void checkFloatInf(const char* input, bool negative) { CAPTURE(input); - T x = parseFloat(input); + float x = parseNumber(input); if (negative) REQUIRE(x < 0); else @@ -36,137 +34,69 @@ void checkInf(const char* input, bool negative) { REQUIRE(x * 2 == x); // a property of infinity } -TEST_CASE("parseFloat()") { +TEST_CASE("parseNumber()") { SECTION("Float_Short_NoExponent") { - checkFloat("3.14", 3.14f); - checkFloat("-3.14", -3.14f); - checkFloat("+3.14", +3.14f); + checkFloat("3.14", 3.14f); + checkFloat("-3.14", -3.14f); + checkFloat("+3.14", +3.14f); } SECTION("Short_NoDot") { - checkFloat("1E+38", 1E+38f); - checkFloat("-1E+38", -1E+38f); - checkFloat("+1E-38", +1E-38f); - checkFloat("+1e+38", +1e+38f); - checkFloat("-1e-38", -1e-38f); + checkFloat("1E+38", 1E+38f); + checkFloat("-1E+38", -1E+38f); + checkFloat("+1E-38", +1E-38f); + checkFloat("+1e+38", +1e+38f); + checkFloat("-1e-38", -1e-38f); } SECTION("Max") { - checkFloat("340.2823e+36", 3.402823e+38f); - checkFloat("34.02823e+37", 3.402823e+38f); - checkFloat("3.402823e+38", 3.402823e+38f); - checkFloat("0.3402823e+39", 3.402823e+38f); - checkFloat("0.03402823e+40", 3.402823e+38f); - checkFloat("0.003402823e+41", 3.402823e+38f); + checkFloat("340.2823e+36", 3.402823e+38f); + checkFloat("34.02823e+37", 3.402823e+38f); + checkFloat("3.402823e+38", 3.402823e+38f); + checkFloat("0.3402823e+39", 3.402823e+38f); + checkFloat("0.03402823e+40", 3.402823e+38f); + checkFloat("0.003402823e+41", 3.402823e+38f); } SECTION("VeryLong") { - checkFloat("0.00000000000000000000000000000001", 1e-32f); - checkFloat("100000000000000000000000000000000.0", 1e+32f); - checkFloat( + checkFloat("0.00000000000000000000000000000001", 1e-32f); + checkFloat("100000000000000000000000000000000.0", 1e+32f); + checkFloat( "100000000000000000000000000000000.00000000000000000000000000000", 1e+32f); } SECTION("MantissaTooLongToFit") { - checkFloat("0.340282346638528861111111111111", 0.34028234663852886f); - checkFloat("34028234663852886.11111111111111", 34028234663852886.0f); - checkFloat("34028234.66385288611111111111111", 34028234.663852886f); + checkFloat("0.340282346638528861111111111111", 0.34028234663852886f); + checkFloat("34028234663852886.11111111111111", 34028234663852886.0f); + checkFloat("34028234.66385288611111111111111", 34028234.663852886f); - checkFloat("-0.340282346638528861111111111111", - -0.34028234663852886f); - checkFloat("-34028234663852886.11111111111111", - -34028234663852886.0f); - checkFloat("-34028234.66385288611111111111111", - -34028234.663852886f); + checkFloat("-0.340282346638528861111111111111", -0.34028234663852886f); + checkFloat("-34028234663852886.11111111111111", -34028234663852886.0f); + checkFloat("-34028234.66385288611111111111111", -34028234.663852886f); } SECTION("ExponentTooBig") { - checkInf("1e39", false); - checkInf("-1e39", true); - checkInf("1e255", false); - checkFloat("1e-255", 0.0f); + checkFloatInf("1e39", false); + checkFloatInf("-1e39", true); + checkFloatInf("1e255", false); + checkFloat("1e-255", 0.0f); } SECTION("NaN") { - checkNaN("NaN"); - checkNaN("nan"); + checkFloatNaN("NaN"); + checkFloatNaN("nan"); } SECTION("Infinity") { - checkInf("Infinity", false); - checkInf("+Infinity", false); - checkInf("-Infinity", true); - checkInf("inf", false); - checkInf("+inf", false); - checkInf("-inf", true); + checkFloatInf("Infinity", false); + checkFloatInf("+Infinity", false); + checkFloatInf("-Infinity", true); + checkFloatInf("inf", false); + checkFloatInf("+inf", false); + checkFloatInf("-inf", true); - checkInf("1e300", false); - checkInf("-1e300", true); - } -} - -TEST_CASE("parseFloat()") { - SECTION("Short_NoExponent") { - checkFloat("3.14", 3.14); - checkFloat("-3.14", -3.14); - checkFloat("+3.14", +3.14); - } - - SECTION("Short_NoDot") { - checkFloat("1E+308", 1E+308); - checkFloat("-1E+308", -1E+308); - checkFloat("+1E-308", +1E-308); - checkFloat("+1e+308", +1e+308); - checkFloat("-1e-308", -1e-308); - } - - SECTION("Max") { - checkFloat(".017976931348623147e+310", 1.7976931348623147e+308); - checkFloat(".17976931348623147e+309", 1.7976931348623147e+308); - checkFloat("1.7976931348623147e+308", 1.7976931348623147e+308); - checkFloat("17.976931348623147e+307", 1.7976931348623147e+308); - checkFloat("179.76931348623147e+306", 1.7976931348623147e+308); - } - - SECTION("Min") { - checkFloat(".022250738585072014e-306", 2.2250738585072014e-308); - checkFloat(".22250738585072014e-307", 2.2250738585072014e-308); - checkFloat("2.2250738585072014e-308", 2.2250738585072014e-308); - checkFloat("22.250738585072014e-309", 2.2250738585072014e-308); - checkFloat("222.50738585072014e-310", 2.2250738585072014e-308); - } - - SECTION("VeryLong") { - checkFloat("0.00000000000000000000000000000001", 1e-32); - checkFloat("100000000000000000000000000000000.0", 1e+32); - checkFloat( - "100000000000000000000000000000000.00000000000000000000000000000", - 1e+32); - } - - SECTION("MantissaTooLongToFit") { - checkFloat("0.179769313486231571111111111111", 0.17976931348623157); - checkFloat("17976931348623157.11111111111111", 17976931348623157.0); - checkFloat("1797693.134862315711111111111111", 1797693.1348623157); - - checkFloat("-0.179769313486231571111111111111", - -0.17976931348623157); - checkFloat("-17976931348623157.11111111111111", - -17976931348623157.0); - checkFloat("-1797693.134862315711111111111111", - -1797693.1348623157); - } - - SECTION("ExponentTooBig") { - checkInf("1e309", false); - checkInf("-1e309", true); - checkInf("1e65535", false); - checkFloat("1e-65535", 0.0); - } - - SECTION("NaN") { - checkNaN("NaN"); - checkNaN("nan"); + checkFloatInf("1e300", false); + checkFloatInf("-1e300", true); } } diff --git a/lib/ArduinoJson-6.x/extras/tests/Numbers/parseInteger.cpp b/lib/ArduinoJson-6.x/extras/tests/Numbers/parseInteger.cpp index 44f4a182b..745356cb0 100644 --- a/lib/ArduinoJson-6.x/extras/tests/Numbers/parseInteger.cpp +++ b/lib/ArduinoJson-6.x/extras/tests/Numbers/parseInteger.cpp @@ -3,7 +3,8 @@ // MIT License #include -#include +#include +#include #include using namespace ARDUINOJSON_NAMESPACE; @@ -11,11 +12,11 @@ using namespace ARDUINOJSON_NAMESPACE; template void checkInteger(const char* input, T expected) { CAPTURE(input); - T actual = parseInteger(input); + T actual = parseNumber(input); REQUIRE(expected == actual); } -TEST_CASE("parseInteger()") { +TEST_CASE("parseNumber()") { checkInteger("-128", -128); checkInteger("127", 127); checkInteger("+127", 127); @@ -25,7 +26,7 @@ TEST_CASE("parseInteger()") { checkInteger("-129", 0); // overflow } -TEST_CASE("parseInteger()") { +TEST_CASE("parseNumber()") { checkInteger("-32768", -32768); checkInteger("32767", 32767); checkInteger("+32767", 32767); @@ -35,7 +36,7 @@ TEST_CASE("parseInteger()") { checkInteger("32768", 0); // overflow } -TEST_CASE("parseInteger()") { +TEST_CASE("parseNumber()") { checkInteger("-2147483648", (-2147483647 - 1)); checkInteger("2147483647", 2147483647); checkInteger("+2147483647", 2147483647); @@ -45,7 +46,7 @@ TEST_CASE("parseInteger()") { checkInteger("2147483648", 0); // overflow } -TEST_CASE("parseInteger()") { +TEST_CASE("parseNumber()") { checkInteger("0", 0); checkInteger("255", 255); checkInteger("+255", 255); @@ -55,7 +56,7 @@ TEST_CASE("parseInteger()") { checkInteger("256", 0); } -TEST_CASE("parseInteger()") { +TEST_CASE("parseNumber()") { checkInteger("0", 0); checkInteger("65535", 65535); checkInteger("+65535", 65535); diff --git a/lib/ArduinoJson-6.x/extras/tests/Numbers/parseNumber.cpp b/lib/ArduinoJson-6.x/extras/tests/Numbers/parseNumber.cpp index 01b53cae6..9e8a2cb79 100644 --- a/lib/ArduinoJson-6.x/extras/tests/Numbers/parseNumber.cpp +++ b/lib/ArduinoJson-6.x/extras/tests/Numbers/parseNumber.cpp @@ -2,23 +2,38 @@ // Copyright Benoit Blanchon 2014-2020 // MIT License +#include #include +#include #include using namespace ARDUINOJSON_NAMESPACE; -TEST_CASE("Test uint32_t overflow") { - ParsedNumber first = - parseNumber("4294967295"); - ParsedNumber second = - parseNumber("4294967296"); +TEST_CASE("Test unsigned integer overflow") { + VariantData first, second; + first.init(); + second.init(); + + // Avoids MSVC warning C4127 (conditional expression is constant) + size_t integerSize = sizeof(Integer); + + if (integerSize == 8) { + parseNumber("18446744073709551615", first); + parseNumber("18446744073709551616", second); + } else { + parseNumber("4294967295", first); + parseNumber("4294967296", second); + } REQUIRE(first.type() == uint8_t(VALUE_IS_POSITIVE_INTEGER)); REQUIRE(second.type() == uint8_t(VALUE_IS_FLOAT)); } TEST_CASE("Invalid value") { - ParsedNumber result = parseNumber("6a3"); + VariantData result; + result.init(); + + parseNumber("6a3", result); REQUIRE(result.type() == uint8_t(VALUE_IS_NULL)); } diff --git a/lib/ArduinoJson-6.x/library.json b/lib/ArduinoJson-6.x/library.json index a50d9cdf8..bfb972e70 100644 --- a/lib/ArduinoJson-6.x/library.json +++ b/lib/ArduinoJson-6.x/library.json @@ -7,7 +7,7 @@ "type": "git", "url": "https://github.com/bblanchon/ArduinoJson.git" }, - "version": "6.15.2", + "version": "6.16.1", "authors": { "name": "Benoit Blanchon", "url": "https://blog.benoitblanchon.fr" diff --git a/lib/ArduinoJson-6.x/library.properties b/lib/ArduinoJson-6.x/library.properties index 71e7c385f..7ab851782 100644 --- a/lib/ArduinoJson-6.x/library.properties +++ b/lib/ArduinoJson-6.x/library.properties @@ -1,5 +1,5 @@ name=ArduinoJson -version=6.15.2 +version=6.16.1 author=Benoit Blanchon maintainer=Benoit Blanchon sentence=A simple and efficient JSON library for embedded C++. diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Array/ArrayFunctions.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Array/ArrayFunctions.hpp index c8335d289..517d0b89e 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Array/ArrayFunctions.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Array/ArrayFunctions.hpp @@ -12,12 +12,13 @@ inline VariantData *arrayAdd(CollectionData *arr, MemoryPool *pool) { return arr ? arr->addElement(pool) : 0; } -template -inline void arrayAccept(const CollectionData *arr, Visitor &visitor) { +template +inline typename TVisitor::result_type arrayAccept(const CollectionData *arr, + TVisitor &visitor) { if (arr) - visitor.visitArray(*arr); + return visitor.visitArray(*arr); else - visitor.visitNull(); + return visitor.visitNull(); } inline bool arrayEquals(const CollectionData *lhs, const CollectionData *rhs) { diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Array/ArrayRef.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Array/ArrayRef.hpp index bb2fbaa7c..2e8e7bfda 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Array/ArrayRef.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Array/ArrayRef.hpp @@ -27,9 +27,9 @@ class ArrayRefBase { return VariantConstRef(reinterpret_cast(data)); } - template - FORCE_INLINE void accept(Visitor& visitor) const { - arrayAccept(_data, visitor); + template + FORCE_INLINE typename TVisitor::result_type accept(TVisitor& visitor) const { + return arrayAccept(_data, visitor); } FORCE_INLINE bool isNull() const { diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Array/ElementProxy.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Array/ElementProxy.hpp index 0d0c821e8..6d47ef371 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Array/ElementProxy.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Array/ElementProxy.hpp @@ -98,8 +98,8 @@ class ElementProxy : public VariantOperators >, return getOrAddUpstreamElement().set(value); } - template - void accept(Visitor& visitor) const { + template + typename TVisitor::result_type accept(TVisitor& visitor) const { return getUpstreamElement().accept(visitor); } @@ -135,6 +135,10 @@ class ElementProxy : public VariantOperators >, return getOrAddUpstreamElement().getElement(index); } + VariantRef getOrAddElement(size_t index) const { + return getOrAddUpstreamElement().getOrAddElement(index); + } + FORCE_INLINE void remove(size_t index) const { getUpstreamElement().remove(index); } diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Array/Utilities.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Array/Utilities.hpp index a2895fd76..cd84eb808 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Array/Utilities.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Array/Utilities.hpp @@ -10,8 +10,11 @@ namespace ARDUINOJSON_NAMESPACE { // Copy a 1D array to a JsonArray -template -inline bool copyArray(T (&src)[N], ArrayRef dst) { +template +inline typename enable_if::value && + !is_base_of::value, + bool>::type +copyArray(T (&src)[N], const TDestination& dst) { return copyArray(src, N, dst); } @@ -22,8 +25,11 @@ inline bool copyArray(T (&src)[N], JsonDocument& dst) { } // Copy a 1D array to a JsonArray -template -inline bool copyArray(T* src, size_t len, ArrayRef dst) { +template +inline typename enable_if::value && + !is_base_of::value, + bool>::type +copyArray(T* src, size_t len, const TDestination& dst) { bool ok = true; for (size_t i = 0; i < len; i++) { ok &= dst.add(src[i]); @@ -38,8 +44,10 @@ inline bool copyArray(T* src, size_t len, JsonDocument& dst) { } // Copy a 2D array to a JsonArray -template -inline bool copyArray(T (&src)[N1][N2], ArrayRef dst) { +template +inline typename enable_if::value, + bool>::type +copyArray(T (&src)[N1][N2], const TDestination& dst) { bool ok = true; for (size_t i = 0; i < N1; i++) { ArrayRef nestedArray = dst.createNestedArray(); @@ -56,42 +64,108 @@ inline bool copyArray(T (&src)[N1][N2], JsonDocument& dst) { return copyArray(src, dst.to()); } +template +class ArrayCopier1D : public Visitor { + public: + ArrayCopier1D(T* destination, size_t capacity) + : _destination(destination), _capacity(capacity) {} + + size_t visitArray(const CollectionData& array) { + size_t size = 0; + VariantSlot* slot = array.head(); + + while (slot != 0 && size < _capacity) { + _destination[size++] = variantAs(slot->data()); + slot = slot->next(); + } + return size; + } + + size_t visitObject(const CollectionData&) { + return 0; + } + + size_t visitFloat(Float) { + return 0; + } + + size_t visitString(const char*) { + return 0; + } + + size_t visitRawJson(const char*, size_t) { + return 0; + } + + size_t visitNegativeInteger(UInt) { + return 0; + } + + size_t visitPositiveInteger(UInt) { + return 0; + } + + size_t visitBoolean(bool) { + return 0; + } + + size_t visitNull() { + return 0; + } + + private: + T* _destination; + size_t _capacity; +}; + +template +class ArrayCopier2D : public Visitor { + public: + ArrayCopier2D(T (*destination)[N1][N2]) : _destination(destination) {} + + void visitArray(const CollectionData& array) { + VariantSlot* slot = array.head(); + size_t n = 0; + while (slot != 0 && n < N1) { + ArrayCopier1D copier((*_destination)[n++], N2); + variantAccept(slot->data(), copier); + slot = slot->next(); + } + } + void visitObject(const CollectionData&) {} + void visitFloat(Float) {} + void visitString(const char*) {} + void visitRawJson(const char*, size_t) {} + void visitNegativeInteger(UInt) {} + void visitPositiveInteger(UInt) {} + void visitBoolean(bool) {} + void visitNull() {} + + private: + T (*_destination)[N1][N2]; + size_t _capacity1, _capacity2; +}; + // Copy a JsonArray to a 1D array -template -inline size_t copyArray(ArrayConstRef src, T (&dst)[N]) { +template +inline typename enable_if::value, size_t>::type copyArray( + const TSource& src, T (&dst)[N]) { return copyArray(src, dst, N); } -// Copy a JsonDocument to a 1D array -template -inline size_t copyArray(const JsonDocument& src, T (&dst)[N]) { - return copyArray(src.as(), dst, N); -} - // Copy a JsonArray to a 1D array -template -inline size_t copyArray(ArrayConstRef src, T* dst, size_t len) { - size_t i = 0; - for (ArrayConstRef::iterator it = src.begin(); it != src.end() && i < len; - ++it) - dst[i++] = *it; - return i; +template +inline size_t copyArray(const TSource& src, T* dst, size_t len) { + ArrayCopier1D copier(dst, len); + + return src.accept(copier); } // Copy a JsonArray to a 2D array -template -inline void copyArray(ArrayConstRef src, T (&dst)[N1][N2]) { - size_t i = 0; - for (ArrayConstRef::iterator it = src.begin(); it != src.end() && i < N1; - ++it) { - copyArray(it->as(), dst[i++]); - } -} - -// Copy a JsonDocument to a 2D array -template -inline void copyArray(const JsonDocument& src, T (&dst)[N1][N2]) { - copyArray(src.as(), dst); +template +inline void copyArray(const TSource& src, T (&dst)[N1][N2]) { + ArrayCopier2D copier(&dst); + src.accept(copier); } } // namespace ARDUINOJSON_NAMESPACE diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Configuration.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Configuration.hpp index a73a2c5d5..42ba498ef 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Configuration.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Configuration.hpp @@ -164,7 +164,7 @@ // Convert unicode escape sequence (\u0123) to UTF-8 #ifndef ARDUINOJSON_DECODE_UNICODE -#define ARDUINOJSON_DECODE_UNICODE 0 +#define ARDUINOJSON_DECODE_UNICODE 1 #endif // Ignore comments in input @@ -215,6 +215,10 @@ #define ARDUINOJSON_TAB " " #endif +#ifndef ARDUINOJSON_ENABLE_STRING_DEDUPLICATION +#define ARDUINOJSON_ENABLE_STRING_DEDUPLICATION 1 +#endif + #ifndef ARDUINOJSON_STRING_BUFFER_SIZE #define ARDUINOJSON_STRING_BUFFER_SIZE 32 #endif @@ -226,3 +230,8 @@ #define ARDUINOJSON_DEBUG 0 #endif #endif + +#if ARDUINOJSON_HAS_NULLPTR && defined(nullptr) +#error nullptr is defined as a macro. Remove the faulty #define or #undef nullptr +// See https://github.com/bblanchon/ArduinoJson/issues/1355 +#endif diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Deserialization/DeserializationError.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Deserialization/DeserializationError.hpp index 9ffd0de94..e8902f09c 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Deserialization/DeserializationError.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Deserialization/DeserializationError.hpp @@ -5,6 +5,8 @@ #pragma once #include +#include +#include #if ARDUINOJSON_ENABLE_STD_STREAM #include @@ -20,6 +22,7 @@ class DeserializationError { public: enum Code { Ok, + EmptyInput, IncompleteInput, InvalidInput, NoMemory, @@ -77,24 +80,31 @@ class DeserializationError { } const char* c_str() const { - switch (_code) { - case Ok: - return "Ok"; - case TooDeep: - return "TooDeep"; - case NoMemory: - return "NoMemory"; - case InvalidInput: - return "InvalidInput"; - case IncompleteInput: - return "IncompleteInput"; - case NotSupported: - return "NotSupported"; - default: - return "???"; - } + static const char* messages[] = { + "Ok", "EmptyInput", "IncompleteInput", "InvalidInput", + "NoMemory", "NotSupported", "TooDeep"}; + ARDUINOJSON_ASSERT(static_cast(_code) < + sizeof(messages) / sizeof(messages[0])); + return messages[_code]; } +#if ARDUINOJSON_ENABLE_PROGMEM + const __FlashStringHelper* f_str() const { + ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s0, "Ok"); + ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s1, "EmptyInput"); + ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s2, "IncompleteInput"); + ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s3, "InvalidInput"); + ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s4, "NoMemory"); + ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s5, "NotSupported"); + ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s6, "TooDeep"); + ARDUINOJSON_DEFINE_STATIC_ARRAY( + const char*, messages, + ARDUINOJSON_EXPAND7({s0, s1, s2, s3, s4, s5, s6})); + return ARDUINOJSON_READ_STATIC_ARRAY(const __FlashStringHelper*, messages, + _code); + } +#endif + private: Code _code; }; diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Deserialization/Filter.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Deserialization/Filter.hpp index 252488799..63e06a563 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Deserialization/Filter.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Deserialization/Filter.hpp @@ -33,7 +33,7 @@ class Filter { if (_variant == true) // "true" means "allow recursively" return *this; else - return Filter(_variant[key]); + return Filter(_variant[key] | _variant["*"]); } private: diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp index 06352585c..6c46d5d85 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp @@ -4,7 +4,7 @@ #pragma once -#include +#include namespace ARDUINOJSON_NAMESPACE { diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Deserialization/deserialize.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Deserialization/deserialize.hpp index f80f587bf..7b15e2dac 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Deserialization/deserialize.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Deserialization/deserialize.hpp @@ -34,7 +34,7 @@ deserialize(JsonDocument &doc, const TString &input, NestingLimit nestingLimit, doc.clear(); return makeDeserializer( doc.memoryPool(), reader, - makeStringStorage(doc.memoryPool(), input)) + makeStringStorage(input, doc.memoryPool())) .parse(doc.data(), filter, nestingLimit); } // @@ -50,7 +50,7 @@ DeserializationError deserialize(JsonDocument &doc, TChar *input, doc.clear(); return makeDeserializer( doc.memoryPool(), reader, - makeStringStorage(doc.memoryPool(), input)) + makeStringStorage(input, doc.memoryPool())) .parse(doc.data(), filter, nestingLimit); } // @@ -64,7 +64,7 @@ DeserializationError deserialize(JsonDocument &doc, TStream &input, doc.clear(); return makeDeserializer( doc.memoryPool(), reader, - makeStringStorage(doc.memoryPool(), input)) + makeStringStorage(input, doc.memoryPool())) .parse(doc.data(), filter, nestingLimit); } diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Document/JsonDocument.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Document/JsonDocument.hpp index cad933182..13cb49110 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Document/JsonDocument.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Document/JsonDocument.hpp @@ -15,8 +15,8 @@ namespace ARDUINOJSON_NAMESPACE { class JsonDocument : public Visitable { public: - template - void accept(Visitor& visitor) const { + template + typename TVisitor::result_type accept(TVisitor& visitor) const { return getVariant().accept(visitor); } @@ -48,6 +48,10 @@ class JsonDocument : public Visitable { return _pool.size(); } + bool overflowed() const { + return _pool.overflowed(); + } + size_t nesting() const { return _data.nesting(); } @@ -81,6 +85,7 @@ class JsonDocument : public Visitable { return _pool; } + // for internal use only VariantData& data() { return _data; } diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Json/JsonDeserializer.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Json/JsonDeserializer.hpp index 276a30a7f..81eb40a05 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Json/JsonDeserializer.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Json/JsonDeserializer.hpp @@ -19,34 +19,26 @@ namespace ARDUINOJSON_NAMESPACE { template class JsonDeserializer { - typedef typename remove_reference::type::StringBuilder - StringBuilder; - - struct StringOrError { - DeserializationError err; - const char *value; - - StringOrError(DeserializationError e) : err(e) {} - StringOrError(DeserializationError::Code c) : err(c) {} - StringOrError(const char *s) : err(DeserializationError::Ok), value(s) {} - }; - public: JsonDeserializer(MemoryPool &pool, TReader reader, TStringStorage stringStorage) - : _pool(&pool), _stringStorage(stringStorage), _latch(reader) {} + : _stringStorage(stringStorage), + _foundSomething(false), + _latch(reader), + _pool(&pool), + _error(DeserializationError::Ok) {} template DeserializationError parse(VariantData &variant, TFilter filter, NestingLimit nestingLimit) { - DeserializationError err = parseVariant(variant, filter, nestingLimit); + parseVariant(variant, filter, nestingLimit); - if (!err && _latch.last() != 0 && !variant.isEnclosed()) { + if (!_error && _latch.last() != 0 && !variant.isEnclosed()) { // We don't detect trailing characters earlier, so we need to check now - err = DeserializationError::InvalidInput; + return DeserializationError::InvalidInput; } - return err; + return _error; } private: @@ -68,11 +60,10 @@ class JsonDeserializer { } template - DeserializationError parseVariant(VariantData &variant, TFilter filter, - NestingLimit nestingLimit) { - DeserializationError err = skipSpacesAndComments(); - if (err) - return err; + bool parseVariant(VariantData &variant, TFilter filter, + NestingLimit nestingLimit) { + if (!skipSpacesAndComments()) + return false; switch (current()) { case '[': @@ -102,10 +93,9 @@ class JsonDeserializer { } } - DeserializationError skipVariant(NestingLimit nestingLimit) { - DeserializationError err = skipSpacesAndComments(); - if (err) - return err; + bool skipVariant(NestingLimit nestingLimit) { + if (!skipSpacesAndComments()) + return false; switch (current()) { case '[': @@ -124,23 +114,24 @@ class JsonDeserializer { } template - DeserializationError parseArray(CollectionData &array, TFilter filter, - NestingLimit nestingLimit) { - if (nestingLimit.reached()) - return DeserializationError::TooDeep; + bool parseArray(CollectionData &array, TFilter filter, + NestingLimit nestingLimit) { + if (nestingLimit.reached()) { + _error = DeserializationError::TooDeep; + return false; + } // Skip opening braket ARDUINOJSON_ASSERT(current() == '['); move(); // Skip spaces - DeserializationError err = skipSpacesAndComments(); - if (err) - return err; + if (!skipSpacesAndComments()) + return false; // Empty array? if (eat(']')) - return DeserializationError::Ok; + return true; TFilter memberFilter = filter[0UL]; @@ -149,35 +140,38 @@ class JsonDeserializer { if (memberFilter.allow()) { // Allocate slot in array VariantData *value = array.addElement(_pool); - if (!value) - return DeserializationError::NoMemory; + if (!value) { + _error = DeserializationError::NoMemory; + return false; + } // 1 - Parse value - err = parseVariant(*value, memberFilter, nestingLimit.decrement()); - if (err) - return err; + if (!parseVariant(*value, memberFilter, nestingLimit.decrement())) + return false; } else { - err = skipVariant(nestingLimit.decrement()); - if (err) - return err; + if (!skipVariant(nestingLimit.decrement())) + return false; } // 2 - Skip spaces - err = skipSpacesAndComments(); - if (err) - return err; + if (!skipSpacesAndComments()) + return false; // 3 - More values? if (eat(']')) - return DeserializationError::Ok; - if (!eat(',')) - return DeserializationError::InvalidInput; + return true; + if (!eat(',')) { + _error = DeserializationError::InvalidInput; + return false; + } } } - DeserializationError skipArray(NestingLimit nestingLimit) { - if (nestingLimit.reached()) - return DeserializationError::TooDeep; + bool skipArray(NestingLimit nestingLimit) { + if (nestingLimit.reached()) { + _error = DeserializationError::TooDeep; + return false; + } // Skip opening braket ARDUINOJSON_ASSERT(current() == '['); @@ -186,153 +180,162 @@ class JsonDeserializer { // Read each value for (;;) { // 1 - Skip value - DeserializationError err = skipVariant(nestingLimit.decrement()); - if (err) - return err; + if (!skipVariant(nestingLimit.decrement())) + return false; // 2 - Skip spaces - err = skipSpacesAndComments(); - if (err) - return err; + if (!skipSpacesAndComments()) + return false; // 3 - More values? if (eat(']')) - return DeserializationError::Ok; - if (!eat(',')) - return DeserializationError::InvalidInput; + return true; + if (!eat(',')) { + _error = DeserializationError::InvalidInput; + return false; + } } } template - DeserializationError parseObject(CollectionData &object, TFilter filter, - NestingLimit nestingLimit) { - if (nestingLimit.reached()) - return DeserializationError::TooDeep; + bool parseObject(CollectionData &object, TFilter filter, + NestingLimit nestingLimit) { + if (nestingLimit.reached()) { + _error = DeserializationError::TooDeep; + return false; + } // Skip opening brace ARDUINOJSON_ASSERT(current() == '{'); move(); // Skip spaces - DeserializationError err = skipSpacesAndComments(); - if (err) - return err; + if (!skipSpacesAndComments()) + return false; // Empty object? if (eat('}')) - return DeserializationError::Ok; + return true; // Read each key value pair for (;;) { // Parse key - StringOrError key = parseKey(); - err = key.err; // <- this trick saves 62 bytes on AVR - if (err) - return err; + if (!parseKey()) + return false; // Skip spaces - err = skipSpacesAndComments(); - if (err) - return err; // Colon - if (!eat(':')) - return DeserializationError::InvalidInput; + if (!skipSpacesAndComments()) + return false; - TFilter memberFilter = filter[key.value]; + // Colon + if (!eat(':')) { + _error = DeserializationError::InvalidInput; + return false; + } + + const char *key = _stringStorage.c_str(); + + TFilter memberFilter = filter[key]; if (memberFilter.allow()) { - VariantData *variant = object.getMember(adaptString(key.value)); + VariantData *variant = object.getMember(adaptString(key)); if (!variant) { + // Save key in memory pool. + // This MUST be done before adding the slot. + key = _stringStorage.save(); + // Allocate slot in object VariantSlot *slot = object.addSlot(_pool); - if (!slot) - return DeserializationError::NoMemory; + if (!slot) { + _error = DeserializationError::NoMemory; + return false; + } - slot->setOwnedKey(make_not_null(key.value)); + slot->setKey(key, typename TStringStorage::storage_policy()); variant = slot->data(); } // Parse value - err = parseVariant(*variant, memberFilter, nestingLimit.decrement()); - if (err) - return err; + if (!parseVariant(*variant, memberFilter, nestingLimit.decrement())) + return false; } else { - _stringStorage.reclaim(key.value); - err = skipVariant(nestingLimit.decrement()); - if (err) - return err; + if (!skipVariant(nestingLimit.decrement())) + return false; } // Skip spaces - err = skipSpacesAndComments(); - if (err) - return err; + if (!skipSpacesAndComments()) + return false; // More keys/values? if (eat('}')) - return DeserializationError::Ok; - if (!eat(',')) - return DeserializationError::InvalidInput; + return true; + if (!eat(',')) { + _error = DeserializationError::InvalidInput; + return false; + } // Skip spaces - err = skipSpacesAndComments(); - if (err) - return err; + if (!skipSpacesAndComments()) + return false; } } - DeserializationError skipObject(NestingLimit nestingLimit) { - if (nestingLimit.reached()) - return DeserializationError::TooDeep; + bool skipObject(NestingLimit nestingLimit) { + if (nestingLimit.reached()) { + _error = DeserializationError::TooDeep; + return false; + } // Skip opening brace ARDUINOJSON_ASSERT(current() == '{'); move(); // Skip spaces - DeserializationError err = skipSpacesAndComments(); - if (err) - return err; + if (!skipSpacesAndComments()) + return false; // Empty object? if (eat('}')) - return DeserializationError::Ok; + return true; // Read each key value pair for (;;) { // Skip key - err = skipVariant(nestingLimit.decrement()); - if (err) - return err; + if (!skipVariant(nestingLimit.decrement())) + return false; // Skip spaces - err = skipSpacesAndComments(); - if (err) - return err; + if (!skipSpacesAndComments()) + return false; // Colon - if (!eat(':')) - return DeserializationError::InvalidInput; + if (!eat(':')) { + _error = DeserializationError::InvalidInput; + return false; + } // Skip value - err = skipVariant(nestingLimit.decrement()); - if (err) - return err; + if (!skipVariant(nestingLimit.decrement())) + return false; // Skip spaces - err = skipSpacesAndComments(); - if (err) - return err; + if (!skipSpacesAndComments()) + return false; // More keys/values? if (eat('}')) - return DeserializationError::Ok; - if (!eat(',')) - return DeserializationError::InvalidInput; + return true; + if (!eat(',')) { + _error = DeserializationError::InvalidInput; + return false; + } } } - StringOrError parseKey() { + bool parseKey() { + _stringStorage.startString(); if (isQuote(current())) { return parseQuotedString(); } else { @@ -340,16 +343,16 @@ class JsonDeserializer { } } - DeserializationError parseStringValue(VariantData &variant) { - StringOrError result = parseQuotedString(); - if (result.err) - return result.err; - variant.setOwnedString(make_not_null(result.value)); - return DeserializationError::Ok; + bool parseStringValue(VariantData &variant) { + _stringStorage.startString(); + if (!parseQuotedString()) + return false; + const char *value = _stringStorage.save(); + variant.setStringPointer(value, typename TStringStorage::storage_policy()); + return true; } - StringOrError parseQuotedString() { - StringBuilder builder = _stringStorage.startString(); + bool parseQuotedString() { #if ARDUINOJSON_DECODE_UNICODE Utf16::Codepoint codepoint; #endif @@ -362,66 +365,82 @@ class JsonDeserializer { if (c == stopChar) break; - if (c == '\0') - return DeserializationError::IncompleteInput; + if (c == '\0') { + _error = DeserializationError::IncompleteInput; + return false; + } if (c == '\\') { c = current(); - if (c == '\0') - return DeserializationError::IncompleteInput; + + if (c == '\0') { + _error = DeserializationError::IncompleteInput; + return false; + } + if (c == 'u') { #if ARDUINOJSON_DECODE_UNICODE move(); uint16_t codeunit; - DeserializationError err = parseHex4(codeunit); - if (err) - return err; + if (!parseHex4(codeunit)) + return false; if (codepoint.append(codeunit)) - Utf8::encodeCodepoint(codepoint.value(), builder); + Utf8::encodeCodepoint(codepoint.value(), _stringStorage); continue; #else - return DeserializationError::NotSupported; + _error = DeserializationError::NotSupported; + return false; #endif } + // replace char c = EscapeSequence::unescapeChar(c); - if (c == '\0') - return DeserializationError::InvalidInput; + if (c == '\0') { + _error = DeserializationError::InvalidInput; + return false; + } move(); } - builder.append(c); + _stringStorage.append(c); } - const char *result = builder.complete(); - if (!result) - return DeserializationError::NoMemory; - return result; + _stringStorage.append('\0'); + + if (!_stringStorage.isValid()) { + _error = DeserializationError::NoMemory; + return false; + } + + return true; } - StringOrError parseNonQuotedString() { - StringBuilder builder = _stringStorage.startString(); - + bool parseNonQuotedString() { char c = current(); ARDUINOJSON_ASSERT(c); if (canBeInNonQuotedString(c)) { // no quotes do { move(); - builder.append(c); + _stringStorage.append(c); c = current(); } while (canBeInNonQuotedString(c)); } else { - return DeserializationError::InvalidInput; + _error = DeserializationError::InvalidInput; + return false; } - const char *result = builder.complete(); - if (!result) - return DeserializationError::NoMemory; - return result; + _stringStorage.append('\0'); + + if (!_stringStorage.isValid()) { + _error = DeserializationError::NoMemory; + return false; + } + + return true; } - DeserializationError skipString() { + bool skipString() { const char stopChar = current(); move(); @@ -430,87 +449,90 @@ class JsonDeserializer { move(); if (c == stopChar) break; - if (c == '\0') - return DeserializationError::IncompleteInput; + if (c == '\0') { + _error = DeserializationError::IncompleteInput; + return false; + } if (c == '\\') { if (current() != '\0') move(); } } - return DeserializationError::Ok; + return true; } - DeserializationError parseNumericValue(VariantData &result) { - char buffer[64]; + bool parseNumericValue(VariantData &result) { uint8_t n = 0; char c = current(); while (canBeInNonQuotedString(c) && n < 63) { move(); - buffer[n++] = c; + _buffer[n++] = c; c = current(); } - buffer[n] = 0; + _buffer[n] = 0; - c = buffer[0]; + c = _buffer[0]; if (c == 't') { // true result.setBoolean(true); - return n == 4 ? DeserializationError::Ok - : DeserializationError::IncompleteInput; + if (n != 4) { + _error = DeserializationError::IncompleteInput; + return false; + } + return true; } if (c == 'f') { // false result.setBoolean(false); - return n == 5 ? DeserializationError::Ok - : DeserializationError::IncompleteInput; + if (n != 5) { + _error = DeserializationError::IncompleteInput; + return false; + } + return true; } if (c == 'n') { // null // the variant is already null - return n == 4 ? DeserializationError::Ok - : DeserializationError::IncompleteInput; + if (n != 4) { + _error = DeserializationError::IncompleteInput; + return false; + } + return true; } - ParsedNumber num = parseNumber(buffer); - - switch (num.type()) { - case VALUE_IS_NEGATIVE_INTEGER: - result.setNegativeInteger(num.uintValue); - return DeserializationError::Ok; - - case VALUE_IS_POSITIVE_INTEGER: - result.setPositiveInteger(num.uintValue); - return DeserializationError::Ok; - - case VALUE_IS_FLOAT: - result.setFloat(num.floatValue); - return DeserializationError::Ok; + if (!parseNumber(_buffer, result)) { + _error = DeserializationError::InvalidInput; + return false; } - return DeserializationError::InvalidInput; + return true; } - DeserializationError skipNumericValue() { + bool skipNumericValue() { char c = current(); while (canBeInNonQuotedString(c)) { move(); c = current(); } - return DeserializationError::Ok; + return true; } - DeserializationError parseHex4(uint16_t &result) { + bool parseHex4(uint16_t &result) { result = 0; for (uint8_t i = 0; i < 4; ++i) { char digit = current(); - if (!digit) - return DeserializationError::IncompleteInput; + if (!digit) { + _error = DeserializationError::IncompleteInput; + return false; + } uint8_t value = decodeHex(digit); - if (value > 0x0F) - return DeserializationError::InvalidInput; + if (value > 0x0F) { + _error = DeserializationError::InvalidInput; + return false; + } result = uint16_t((result << 4) | value); move(); } - return DeserializationError::Ok; + return true; } static inline bool isBetween(char c, char min, char max) { @@ -533,12 +555,14 @@ class JsonDeserializer { return uint8_t(c - 'A' + 10); } - DeserializationError skipSpacesAndComments() { + bool skipSpacesAndComments() { for (;;) { switch (current()) { // end of string case '\0': - return DeserializationError::IncompleteInput; + _error = _foundSomething ? DeserializationError::IncompleteInput + : DeserializationError::EmptyInput; + return false; // spaces case ' ': @@ -559,8 +583,10 @@ class JsonDeserializer { bool wasStar = false; for (;;) { char c = current(); - if (c == '\0') - return DeserializationError::IncompleteInput; + if (c == '\0') { + _error = DeserializationError::IncompleteInput; + return false; + } if (c == '/' && wasStar) { move(); break; @@ -577,8 +603,10 @@ class JsonDeserializer { for (;;) { move(); char c = current(); - if (c == '\0') - return DeserializationError::IncompleteInput; + if (c == '\0') { + _error = DeserializationError::IncompleteInput; + return false; + } if (c == '\n') break; } @@ -586,20 +614,27 @@ class JsonDeserializer { // not a comment, just a '/' default: - return DeserializationError::InvalidInput; + _error = DeserializationError::InvalidInput; + return false; } break; #endif default: - return DeserializationError::Ok; + _foundSomething = true; + return true; } } } - MemoryPool *_pool; TStringStorage _stringStorage; + bool _foundSomething; Latch _latch; + MemoryPool *_pool; + char _buffer[64]; // using a member instead of a local variable because it + // ended in the recursive path after compiler inlined the + // code + DeserializationError _error; }; // deserializeJson(JsonDocument&, const std::string&, ...) diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Json/JsonSerializer.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Json/JsonSerializer.hpp index df0cac689..0baf3c528 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Json/JsonSerializer.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Json/JsonSerializer.hpp @@ -12,11 +12,11 @@ namespace ARDUINOJSON_NAMESPACE { template -class JsonSerializer { +class JsonSerializer : public Visitor { public: JsonSerializer(TWriter writer) : _formatter(writer) {} - FORCE_INLINE void visitArray(const CollectionData &array) { + FORCE_INLINE size_t visitArray(const CollectionData &array) { write('['); VariantSlot *slot = array.head(); @@ -32,9 +32,10 @@ class JsonSerializer { } write(']'); + return bytesWritten(); } - void visitObject(const CollectionData &object) { + size_t visitObject(const CollectionData &object) { write('{'); VariantSlot *slot = object.head(); @@ -52,41 +53,49 @@ class JsonSerializer { } write('}'); + return bytesWritten(); } - void visitFloat(Float value) { + size_t visitFloat(Float value) { _formatter.writeFloat(value); + return bytesWritten(); } - void visitString(const char *value) { + size_t visitString(const char *value) { _formatter.writeString(value); + return bytesWritten(); } - void visitRawJson(const char *data, size_t n) { + size_t visitRawJson(const char *data, size_t n) { _formatter.writeRaw(data, n); + return bytesWritten(); } - void visitNegativeInteger(UInt value) { + size_t visitNegativeInteger(UInt value) { _formatter.writeNegativeInteger(value); + return bytesWritten(); } - void visitPositiveInteger(UInt value) { + size_t visitPositiveInteger(UInt value) { _formatter.writePositiveInteger(value); + return bytesWritten(); } - void visitBoolean(bool value) { + size_t visitBoolean(bool value) { _formatter.writeBoolean(value); + return bytesWritten(); } - void visitNull() { + size_t visitNull() { _formatter.writeRaw("null"); + return bytesWritten(); } + protected: size_t bytesWritten() const { return _formatter.bytesWritten(); } - protected: void write(char c) { _formatter.writeRaw(c); } diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Json/PrettyJsonSerializer.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Json/PrettyJsonSerializer.hpp index 96315d816..b53b920c0 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Json/PrettyJsonSerializer.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Json/PrettyJsonSerializer.hpp @@ -18,44 +18,48 @@ class PrettyJsonSerializer : public JsonSerializer { public: PrettyJsonSerializer(TWriter &writer) : base(writer), _nesting(0) {} - void visitArray(const CollectionData &array) { + size_t visitArray(const CollectionData &array) { VariantSlot *slot = array.head(); - if (!slot) - return base::write("[]"); + if (slot) { + base::write("[\r\n"); + _nesting++; + while (slot != 0) { + indent(); + slot->data()->accept(*this); - base::write("[\r\n"); - _nesting++; - while (slot != 0) { + slot = slot->next(); + base::write(slot ? ",\r\n" : "\r\n"); + } + _nesting--; indent(); - slot->data()->accept(*this); - - slot = slot->next(); - base::write(slot ? ",\r\n" : "\r\n"); + base::write("]"); + } else { + base::write("[]"); } - _nesting--; - indent(); - base::write("]"); + return this->bytesWritten(); } - void visitObject(const CollectionData &object) { + size_t visitObject(const CollectionData &object) { VariantSlot *slot = object.head(); - if (!slot) - return base::write("{}"); + if (slot) { + base::write("{\r\n"); + _nesting++; + while (slot != 0) { + indent(); + base::visitString(slot->key()); + base::write(": "); + slot->data()->accept(*this); - base::write("{\r\n"); - _nesting++; - while (slot != 0) { + slot = slot->next(); + base::write(slot ? ",\r\n" : "\r\n"); + } + _nesting--; indent(); - base::visitString(slot->key()); - base::write(": "); - slot->data()->accept(*this); - - slot = slot->next(); - base::write(slot ? ",\r\n" : "\r\n"); + base::write("}"); + } else { + base::write("{}"); } - _nesting--; - indent(); - base::write("}"); + return this->bytesWritten(); } private: diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Json/TextFormatter.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Json/TextFormatter.hpp index 6e0ca70dd..eceef9e06 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Json/TextFormatter.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Json/TextFormatter.hpp @@ -12,17 +12,18 @@ #include #include #include +#include namespace ARDUINOJSON_NAMESPACE { template class TextFormatter { public: - explicit TextFormatter(TWriter writer) : _writer(writer), _length(0) {} + explicit TextFormatter(TWriter writer) : _writer(writer) {} // Returns the number of bytes sent to the TWriter implementation. size_t bytesWritten() const { - return _length; + return _writer.count(); } void writeBoolean(bool value) { @@ -128,28 +129,28 @@ class TextFormatter { } void writeRaw(const char *s) { - _length += _writer.write(reinterpret_cast(s), strlen(s)); + _writer.write(reinterpret_cast(s), strlen(s)); } void writeRaw(const char *s, size_t n) { - _length += _writer.write(reinterpret_cast(s), n); + _writer.write(reinterpret_cast(s), n); } void writeRaw(const char *begin, const char *end) { - _length += _writer.write(reinterpret_cast(begin), - static_cast(end - begin)); + _writer.write(reinterpret_cast(begin), + static_cast(end - begin)); } template void writeRaw(const char (&s)[N]) { - _length += _writer.write(reinterpret_cast(s), N - 1); + _writer.write(reinterpret_cast(s), N - 1); } void writeRaw(char c) { - _length += _writer.write(static_cast(c)); + _writer.write(static_cast(c)); } protected: - TWriter _writer; + CountingDecorator _writer; size_t _length; private: diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Json/Utf16.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Json/Utf16.hpp index 33721a635..67fb5baec 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Json/Utf16.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Json/Utf16.hpp @@ -31,6 +31,8 @@ inline bool isLowSurrogate(uint16_t codeunit) { class Codepoint { public: + Codepoint() : _highSurrogate(0) {} + bool append(uint16_t codeunit) { if (isHighSurrogate(codeunit)) { _highSurrogate = codeunit & 0x3FF; diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Memory/MemoryPool.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Memory/MemoryPool.hpp index 439b5baf8..135d8ee53 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Memory/MemoryPool.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Memory/MemoryPool.hpp @@ -5,13 +5,14 @@ #pragma once #include -#include #include #include #include #include // memmove +#define JSON_STRING_SIZE(SIZE) (SIZE + 1) + namespace ARDUINOJSON_NAMESPACE { // _begin _end @@ -28,7 +29,8 @@ class MemoryPool { : _begin(buf), _left(buf), _right(buf ? buf + capa : 0), - _end(buf ? buf + capa : 0) { + _end(buf ? buf + capa : 0), + _overflowed(false) { ARDUINOJSON_ASSERT(isAligned(_begin)); ARDUINOJSON_ASSERT(isAligned(_right)); ARDUINOJSON_ASSERT(isAligned(_end)); @@ -47,54 +49,61 @@ class MemoryPool { return size_t(_left - _begin + _end - _right); } + bool overflowed() const { + return _overflowed; + } + VariantSlot* allocVariant() { return allocRight(); } - char* allocFrozenString(size_t n) { - if (!canAlloc(n)) - return 0; - char* s = _left; - _left += n; - checkInvariants(); - return s; - } - template - char* saveString(const TAdaptedString& str) { + const char* saveString(const TAdaptedString& str) { if (str.isNull()) return 0; + +#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION + const char* existingCopy = findString(str.begin()); + if (existingCopy) + return existingCopy; +#endif + size_t n = str.size(); - char* dup = allocFrozenString(n + 1); - if (dup) { - str.copyTo(dup, n); - dup[n] = 0; // force null-terminator + + char* newCopy = allocString(n + 1); + if (newCopy) { + str.copyTo(newCopy, n); + newCopy[n] = 0; // force null-terminator } - return dup; + return newCopy; } - StringSlot allocExpandableString() { - StringSlot s; - s.value = _left; - s.size = size_t(_right - _left); - _left = _right; + void getFreeZone(char** zoneStart, size_t* zoneSize) const { + *zoneStart = _left; + *zoneSize = size_t(_right - _left); + } + + const char* saveStringFromFreeZone(size_t len) { +#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION + const char* dup = findString(_left); + if (dup) + return dup; +#endif + + const char* str = _left; + _left += len; checkInvariants(); - return s; + return str; } - void freezeString(StringSlot& s, size_t newSize) { - _left -= (s.size - newSize); - s.size = newSize; - checkInvariants(); - } - - void reclaimLastString(const char* s) { - _left = const_cast(s); + void markAsOverflowed() { + _overflowed = true; } void clear() { _left = _begin; _right = _end; + _overflowed = false; } bool canAlloc(size_t bytes) const { @@ -105,18 +114,6 @@ class MemoryPool { return _begin <= p && p < _end; } - template - T* allocRight() { - return reinterpret_cast(allocRight(sizeof(T))); - } - - void* allocRight(size_t bytes) { - if (!canAlloc(bytes)) - return 0; - _right -= bytes; - return _right; - } - // Workaround for missing placement new void* operator new(size_t, void* p) { return p; @@ -157,10 +154,6 @@ class MemoryPool { } private: - StringSlot* allocStringSlot() { - return allocRight(); - } - void checkInvariants() { ARDUINOJSON_ASSERT(_begin <= _left); ARDUINOJSON_ASSERT(_left <= _right); @@ -168,7 +161,52 @@ class MemoryPool { ARDUINOJSON_ASSERT(isAligned(_right)); } +#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION + template + const char* findString(TIterator str) { + for (char* next = _begin; next < _left; ++next) { + char* begin = next; + + // try to match + for (TIterator it = str; *it == *next; ++it) { + if (*next++ == 0) + return begin; + } + + // jump to next terminator + while (*next) ++next; + } + return 0; + } +#endif + + char* allocString(size_t n) { + if (!canAlloc(n)) { + _overflowed = true; + return 0; + } + char* s = _left; + _left += n; + checkInvariants(); + return s; + } + + template + T* allocRight() { + return reinterpret_cast(allocRight(sizeof(T))); + } + + void* allocRight(size_t bytes) { + if (!canAlloc(bytes)) { + _overflowed = true; + return 0; + } + _right -= bytes; + return _right; + } + char *_begin, *_left, *_right, *_end; + bool _overflowed; }; } // namespace ARDUINOJSON_NAMESPACE diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Memory/StringBuilder.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Memory/StringBuilder.hpp deleted file mode 100644 index 28ffa268f..000000000 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Memory/StringBuilder.hpp +++ /dev/null @@ -1,51 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2020 -// MIT License - -#pragma once - -#include - -namespace ARDUINOJSON_NAMESPACE { - -class StringBuilder { - public: - explicit StringBuilder(MemoryPool* parent) : _parent(parent), _size(0) { - _slot = _parent->allocExpandableString(); - } - - void append(const char* s) { - while (*s) append(*s++); - } - - void append(const char* s, size_t n) { - while (n-- > 0) append(*s++); - } - - void append(char c) { - if (!_slot.value) - return; - - if (_size >= _slot.size) { - _slot.value = 0; - return; - } - - _slot.value[_size++] = c; - } - - char* complete() { - append('\0'); - if (_slot.value) { - _parent->freezeString(_slot, _size); - } - return _slot.value; - } - - private: - MemoryPool* _parent; - size_t _size; - StringSlot _slot; -}; - -} // namespace ARDUINOJSON_NAMESPACE diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Misc/Visitable.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Misc/Visitable.hpp index f259ae5a1..65e2d8e6f 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Misc/Visitable.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Misc/Visitable.hpp @@ -8,6 +8,11 @@ namespace ARDUINOJSON_NAMESPACE { +template +struct Visitor { + typedef TResult result_type; +}; + struct Visitable { // template // void accept(Visitor&) const; diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp index ed328913a..4365a4dc5 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp @@ -15,34 +15,38 @@ namespace ARDUINOJSON_NAMESPACE { template class MsgPackDeserializer { - typedef typename remove_reference::type::StringBuilder - StringBuilder; - public: MsgPackDeserializer(MemoryPool &pool, TReader reader, TStringStorage stringStorage) - : _pool(&pool), _reader(reader), _stringStorage(stringStorage) {} + : _pool(&pool), + _reader(reader), + _stringStorage(stringStorage), + _error(DeserializationError::Ok), + _foundSomething(false) {} // TODO: add support for filter DeserializationError parse(VariantData &variant, AllowAllFilter, NestingLimit nestingLimit) { - return parse(variant, nestingLimit); + parseVariant(variant, nestingLimit); + return _foundSomething ? _error : DeserializationError::EmptyInput; } - DeserializationError parse(VariantData &variant, NestingLimit nestingLimit) { + private: + bool parseVariant(VariantData &variant, NestingLimit nestingLimit) { uint8_t code; if (!readByte(code)) - return DeserializationError::IncompleteInput; + return false; + + _foundSomething = true; if ((code & 0x80) == 0) { variant.setUnsignedInteger(code); - return DeserializationError::Ok; + return true; } if ((code & 0xe0) == 0xe0) { - // TODO: add setNegativeInteger() variant.setSignedInteger(static_cast(code)); - return DeserializationError::Ok; + return true; } if ((code & 0xe0) == 0xa0) { @@ -60,15 +64,15 @@ class MsgPackDeserializer { switch (code) { case 0xc0: // already null - return DeserializationError::Ok; + return true; case 0xc2: variant.setBoolean(false); - return DeserializationError::Ok; + return true; case 0xc3: variant.setBoolean(true); - return DeserializationError::Ok; + return true; case 0xcc: return readInteger(variant); @@ -79,11 +83,9 @@ class MsgPackDeserializer { case 0xce: return readInteger(variant); - case 0xcf: #if ARDUINOJSON_USE_LONG_LONG + case 0xcf: return readInteger(variant); -#else - return DeserializationError::NotSupported; #endif case 0xd0: @@ -95,11 +97,9 @@ class MsgPackDeserializer { case 0xd2: return readInteger(variant); - case 0xd3: #if ARDUINOJSON_USE_LONG_LONG + case 0xd3: return readInteger(variant); -#else - return DeserializationError::NotSupported; #endif case 0xca: @@ -130,7 +130,8 @@ class MsgPackDeserializer { return readObject(variant.toObject(), nestingLimit); default: - return DeserializationError::NotSupported; + _error = DeserializationError::NotSupported; + return false; } } @@ -140,14 +141,19 @@ class MsgPackDeserializer { bool readByte(uint8_t &value) { int c = _reader.read(); - if (c < 0) + if (c < 0) { + _error = DeserializationError::IncompleteInput; return false; + } value = static_cast(c); return true; } bool readBytes(uint8_t *p, size_t n) { - return _reader.readBytes(reinterpret_cast(p), n) == n; + if (_reader.readBytes(reinterpret_cast(p), n) == n) + return true; + _error = DeserializationError::IncompleteInput; + return false; } template @@ -155,14 +161,6 @@ class MsgPackDeserializer { return readBytes(reinterpret_cast(&value), sizeof(value)); } - template - T readInteger() { - T value; - readBytes(value); - fixEndianess(value); - return value; - } - template bool readInteger(T &value) { if (!readBytes(value)) @@ -172,152 +170,158 @@ class MsgPackDeserializer { } template - DeserializationError readInteger(VariantData &variant) { + bool readInteger(VariantData &variant) { T value; if (!readInteger(value)) - return DeserializationError::IncompleteInput; + return false; variant.setInteger(value); - return DeserializationError::Ok; + return true; } template - typename enable_if::type readFloat( + typename enable_if::type readFloat( VariantData &variant) { T value; if (!readBytes(value)) - return DeserializationError::IncompleteInput; + return false; fixEndianess(value); variant.setFloat(value); - return DeserializationError::Ok; + return true; } template - typename enable_if::type readDouble( + typename enable_if::type readDouble( VariantData &variant) { T value; if (!readBytes(value)) - return DeserializationError::IncompleteInput; + return false; fixEndianess(value); variant.setFloat(value); - return DeserializationError::Ok; + return true; } template - typename enable_if::type readDouble( + 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 DeserializationError::IncompleteInput; + return false; doubleToFloat(i, o); fixEndianess(value); variant.setFloat(value); - return DeserializationError::Ok; + return true; } template - DeserializationError readString(VariantData &variant) { + bool readString(VariantData &variant) { T size; if (!readInteger(size)) - return DeserializationError::IncompleteInput; + return false; return readString(variant, size); } template - DeserializationError readString(const char *&str) { + bool readString(const char *&str) { T size; if (!readInteger(size)) - return DeserializationError::IncompleteInput; + return false; return readString(str, size); } - DeserializationError readString(VariantData &variant, size_t n) { + bool readString(VariantData &variant, size_t n) { const char *s = 0; // <- mute "maybe-uninitialized" (+4 bytes on AVR) - DeserializationError err = readString(s, n); - if (!err) - variant.setOwnedString(make_not_null(s)); - return err; + if (!readString(s, n)) + return false; + variant.setStringPointer(s, typename TStringStorage::storage_policy()); + return true; } - DeserializationError readString(const char *&result, size_t n) { - StringBuilder builder = _stringStorage.startString(); + bool readString(const char *&result, size_t n) { + _stringStorage.startString(); for (; n; --n) { uint8_t c; if (!readBytes(c)) - return DeserializationError::IncompleteInput; - builder.append(static_cast(c)); + return false; + _stringStorage.append(static_cast(c)); } - result = builder.complete(); - if (!result) - return DeserializationError::NoMemory; - return DeserializationError::Ok; + _stringStorage.append('\0'); + if (!_stringStorage.isValid()) { + _error = DeserializationError::NoMemory; + return false; + } + + result = _stringStorage.save(); + return true; } template - DeserializationError readArray(CollectionData &array, - NestingLimit nestingLimit) { + bool readArray(CollectionData &array, NestingLimit nestingLimit) { TSize size; if (!readInteger(size)) - return DeserializationError::IncompleteInput; + return false; return readArray(array, size, nestingLimit); } - DeserializationError readArray(CollectionData &array, size_t n, - NestingLimit nestingLimit) { - if (nestingLimit.reached()) - return DeserializationError::TooDeep; + bool readArray(CollectionData &array, size_t n, NestingLimit nestingLimit) { + if (nestingLimit.reached()) { + _error = DeserializationError::TooDeep; + return false; + } for (; n; --n) { VariantData *value = array.addElement(_pool); - if (!value) - return DeserializationError::NoMemory; + if (!value) { + _error = DeserializationError::NoMemory; + return false; + } - DeserializationError err = parse(*value, nestingLimit.decrement()); - if (err) - return err; + if (!parseVariant(*value, nestingLimit.decrement())) + return false; } - return DeserializationError::Ok; + return true; } template - DeserializationError readObject(CollectionData &object, - NestingLimit nestingLimit) { + bool readObject(CollectionData &object, NestingLimit nestingLimit) { TSize size; if (!readInteger(size)) - return DeserializationError::IncompleteInput; + return false; return readObject(object, size, nestingLimit); } - DeserializationError readObject(CollectionData &object, size_t n, - NestingLimit nestingLimit) { - if (nestingLimit.reached()) - return DeserializationError::TooDeep; + bool readObject(CollectionData &object, size_t n, NestingLimit nestingLimit) { + if (nestingLimit.reached()) { + _error = DeserializationError::TooDeep; + return false; + } for (; n; --n) { VariantSlot *slot = object.addSlot(_pool); - if (!slot) - return DeserializationError::NoMemory; + if (!slot) { + _error = DeserializationError::NoMemory; + return false; + } const char *key = 0; // <- mute "maybe-uninitialized" (+4 bytes on AVR) - DeserializationError err = parseKey(key); - if (err) - return err; - slot->setOwnedKey(make_not_null(key)); + if (!parseKey(key)) + return false; - err = parse(*slot->data(), nestingLimit.decrement()); - if (err) - return err; + slot->setKey(key, typename TStringStorage::storage_policy()); + + if (!parseVariant(*slot->data(), nestingLimit.decrement())) + return false; } - return DeserializationError::Ok; + return true; } - DeserializationError parseKey(const char *&key) { + bool parseKey(const char *&key) { uint8_t code; if (!readByte(code)) - return DeserializationError::IncompleteInput; + return false; if ((code & 0xe0) == 0xa0) return readString(key, code & 0x1f); @@ -333,13 +337,16 @@ class MsgPackDeserializer { return readString(key); default: - return DeserializationError::NotSupported; + _error = DeserializationError::NotSupported; + return false; } } MemoryPool *_pool; TReader _reader; TStringStorage _stringStorage; + DeserializationError _error; + bool _foundSomething; }; template diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp index b803241de..e1086367a 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -14,19 +15,20 @@ namespace ARDUINOJSON_NAMESPACE { template -class MsgPackSerializer { +class MsgPackSerializer : public Visitor { public: - MsgPackSerializer(TWriter writer) : _writer(writer), _bytesWritten(0) {} + MsgPackSerializer(TWriter writer) : _writer(writer) {} template - typename enable_if::type visitFloat(T value32) { + typename enable_if::type visitFloat(T value32) { writeByte(0xCA); writeInteger(value32); + return bytesWritten(); } template ARDUINOJSON_NO_SANITIZE("float-cast-overflow") - typename enable_if::type visitFloat(T value64) { + typename enable_if::type visitFloat(T value64) { float value32 = float(value64); if (value32 == value64) { writeByte(0xCA); @@ -35,9 +37,10 @@ class MsgPackSerializer { writeByte(0xCB); writeInteger(value64); } + return bytesWritten(); } - void visitArray(const CollectionData& array) { + size_t visitArray(const CollectionData& array) { size_t n = array.size(); if (n < 0x10) { writeByte(uint8_t(0x90 + array.size())); @@ -51,9 +54,10 @@ class MsgPackSerializer { for (VariantSlot* slot = array.head(); slot; slot = slot->next()) { slot->data()->accept(*this); } + return bytesWritten(); } - void visitObject(const CollectionData& object) { + size_t visitObject(const CollectionData& object) { size_t n = object.size(); if (n < 0x10) { writeByte(uint8_t(0x80 + n)); @@ -68,9 +72,10 @@ class MsgPackSerializer { visitString(slot->key()); slot->data()->accept(*this); } + return bytesWritten(); } - void visitString(const char* value) { + size_t visitString(const char* value) { ARDUINOJSON_ASSERT(value != NULL); size_t n = strlen(value); @@ -88,13 +93,15 @@ class MsgPackSerializer { writeInteger(uint32_t(n)); } writeBytes(reinterpret_cast(value), n); + return bytesWritten(); } - void visitRawJson(const char* data, size_t size) { + size_t visitRawJson(const char* data, size_t size) { writeBytes(reinterpret_cast(data), size); + return bytesWritten(); } - void visitNegativeInteger(UInt value) { + size_t visitNegativeInteger(UInt value) { UInt negated = UInt(~value + 1); if (value <= 0x20) { writeInteger(int8_t(negated)); @@ -114,9 +121,10 @@ class MsgPackSerializer { writeInteger(int64_t(negated)); } #endif + return bytesWritten(); } - void visitPositiveInteger(UInt value) { + size_t visitPositiveInteger(UInt value) { if (value <= 0x7F) { writeInteger(uint8_t(value)); } else if (value <= 0xFF) { @@ -141,27 +149,30 @@ class MsgPackSerializer { writeInteger(uint64_t(value)); } #endif + return bytesWritten(); } - void visitBoolean(bool value) { + size_t visitBoolean(bool value) { writeByte(value ? 0xC3 : 0xC2); + return bytesWritten(); } - void visitNull() { + size_t visitNull() { writeByte(0xC0); - } - - size_t bytesWritten() const { - return _bytesWritten; + return bytesWritten(); } private: + size_t bytesWritten() const { + return _writer.count(); + } + void writeByte(uint8_t c) { - _bytesWritten += _writer.write(c); + _writer.write(c); } void writeBytes(const uint8_t* p, size_t n) { - _bytesWritten += _writer.write(p, n); + _writer.write(p, n); } template @@ -170,8 +181,7 @@ class MsgPackSerializer { writeBytes(reinterpret_cast(&value), sizeof(value)); } - TWriter _writer; - size_t _bytesWritten; + CountingDecorator _writer; }; template diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Namespace.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Namespace.hpp index 92cc58884..085ac2739 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Namespace.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Namespace.hpp @@ -5,27 +5,22 @@ #pragma once #include +#include #include #ifndef ARDUINOJSON_NAMESPACE -#define ARDUINOJSON_DO_CONCAT(A, B) A##B -#define ARDUINOJSON_CONCAT2(A, B) ARDUINOJSON_DO_CONCAT(A, B) -#define ARDUINOJSON_CONCAT4(A, B, C, D) \ - ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT2(A, B), ARDUINOJSON_CONCAT2(C, D)) -#define ARDUINOJSON_CONCAT8(A, B, C, D, E, F, G, H) \ - ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT4(A, B, C, D), \ - ARDUINOJSON_CONCAT4(E, F, G, H)) -#define ARDUINOJSON_CONCAT12(A, B, C, D, E, F, G, H, I, J, K, L) \ - ARDUINOJSON_CONCAT8(A, B, C, D, E, F, G, \ - ARDUINOJSON_CONCAT4(H, I, J, ARDUINOJSON_CONCAT2(K, L))) - -#define ARDUINOJSON_NAMESPACE \ - ARDUINOJSON_CONCAT12( \ - ArduinoJson, ARDUINOJSON_VERSION_MAJOR, ARDUINOJSON_VERSION_MINOR, \ - ARDUINOJSON_VERSION_REVISION, _, ARDUINOJSON_USE_LONG_LONG, \ - ARDUINOJSON_USE_DOUBLE, ARDUINOJSON_DECODE_UNICODE, \ - ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY, \ - ARDUINOJSON_ENABLE_PROGMEM, ARDUINOJSON_ENABLE_COMMENTS) +#define ARDUINOJSON_NAMESPACE \ + ARDUINOJSON_CONCAT4( \ + ARDUINOJSON_CONCAT4(ArduinoJson, ARDUINOJSON_VERSION_MAJOR, \ + ARDUINOJSON_VERSION_MINOR, \ + ARDUINOJSON_VERSION_REVISION), \ + _, \ + ARDUINOJSON_HEX_DIGIT(ARDUINOJSON_ENABLE_PROGMEM, \ + ARDUINOJSON_USE_LONG_LONG, ARDUINOJSON_USE_DOUBLE, \ + ARDUINOJSON_ENABLE_STRING_DEDUPLICATION), \ + ARDUINOJSON_HEX_DIGIT( \ + ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY, \ + ARDUINOJSON_ENABLE_COMMENTS, ARDUINOJSON_DECODE_UNICODE)) #endif diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Numbers/FloatTraits.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Numbers/FloatTraits.hpp index 6f4df596a..78bf617ca 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Numbers/FloatTraits.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Numbers/FloatTraits.hpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include namespace ARDUINOJSON_NAMESPACE { @@ -46,48 +48,60 @@ struct FloatTraits { } static T positiveBinaryPowerOfTen(int index) { - static T factors[] = { - 1e1, - 1e2, - 1e4, - 1e8, - 1e16, - forge(0x4693B8B5, 0xB5056E17), // 1e32 - forge(0x4D384F03, 0xE93FF9F5), // 1e64 - forge(0x5A827748, 0xF9301D32), // 1e128 - forge(0x75154FDD, 0x7F73BF3C) // 1e256 - }; - return factors[index]; + ARDUINOJSON_DEFINE_STATIC_ARRAY( // + uint32_t, factors, + ARDUINOJSON_EXPAND18({ + 0x40240000, 0x00000000, // 1e1 + 0x40590000, 0x00000000, // 1e2 + 0x40C38800, 0x00000000, // 1e4 + 0x4197D784, 0x00000000, // 1e8 + 0x4341C379, 0x37E08000, // 1e16 + 0x4693B8B5, 0xB5056E17, // 1e32 + 0x4D384F03, 0xE93FF9F5, // 1e64 + 0x5A827748, 0xF9301D32, // 1e128 + 0x75154FDD, 0x7F73BF3C // 1e256 + })); + return forge( + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); } static T negativeBinaryPowerOfTen(int index) { - static T factors[] = { - forge(0x3FB99999, 0x9999999A), // 1e-1 - forge(0x3F847AE1, 0x47AE147B), // 1e-2 - forge(0x3F1A36E2, 0xEB1C432D), // 1e-4 - forge(0x3E45798E, 0xE2308C3A), // 1e-8 - forge(0x3C9CD2B2, 0x97D889BC), // 1e-16 - forge(0x3949F623, 0xD5A8A733), // 1e-32 - forge(0x32A50FFD, 0x44F4A73D), // 1e-64 - forge(0x255BBA08, 0xCF8C979D), // 1e-128 - forge(0x0AC80628, 0x64AC6F43) // 1e-256 - }; - return factors[index]; + ARDUINOJSON_DEFINE_STATIC_ARRAY( // + uint32_t, factors, + ARDUINOJSON_EXPAND18({ + 0x3FB99999, 0x9999999A, // 1e-1 + 0x3F847AE1, 0x47AE147B, // 1e-2 + 0x3F1A36E2, 0xEB1C432D, // 1e-4 + 0x3E45798E, 0xE2308C3A, // 1e-8 + 0x3C9CD2B2, 0x97D889BC, // 1e-16 + 0x3949F623, 0xD5A8A733, // 1e-32 + 0x32A50FFD, 0x44F4A73D, // 1e-64 + 0x255BBA08, 0xCF8C979D, // 1e-128 + 0x0AC80628, 0x64AC6F43 // 1e-256 + })); + return forge( + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); } static T negativeBinaryPowerOfTenPlusOne(int index) { - static T factors[] = { - 1e0, - forge(0x3FB99999, 0x9999999A), // 1e-1 - forge(0x3F50624D, 0xD2F1A9FC), // 1e-3 - forge(0x3E7AD7F2, 0x9ABCAF48), // 1e-7 - forge(0x3CD203AF, 0x9EE75616), // 1e-15 - forge(0x398039D6, 0x65896880), // 1e-31 - forge(0x32DA53FC, 0x9631D10D), // 1e-63 - forge(0x25915445, 0x81B7DEC2), // 1e-127 - forge(0x0AFE07B2, 0x7DD78B14) // 1e-255 - }; - return factors[index]; + ARDUINOJSON_DEFINE_STATIC_ARRAY( // + uint32_t, factors, + ARDUINOJSON_EXPAND18({ + 0x3FF00000, 0x00000000, // 1e0 + 0x3FB99999, 0x9999999A, // 1e-1 + 0x3F50624D, 0xD2F1A9FC, // 1e-3 + 0x3E7AD7F2, 0x9ABCAF48, // 1e-7 + 0x3CD203AF, 0x9EE75616, // 1e-15 + 0x398039D6, 0x65896880, // 1e-31 + 0x32DA53FC, 0x9631D10D, // 1e-63 + 0x25915445, 0x81B7DEC2, // 1e-127 + 0x0AFE07B2, 0x7DD78B14 // 1e-255 + })); + return forge( + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); } static T nan() { @@ -144,18 +158,24 @@ struct FloatTraits { } static T positiveBinaryPowerOfTen(int index) { - static T factors[] = {1e1f, 1e2f, 1e4f, 1e8f, 1e16f, 1e32f}; - return factors[index]; + ARDUINOJSON_DEFINE_STATIC_ARRAY( + T, factors, + ARDUINOJSON_EXPAND6({1e1f, 1e2f, 1e4f, 1e8f, 1e16f, 1e32f})); + return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); } static T negativeBinaryPowerOfTen(int index) { - static T factors[] = {1e-1f, 1e-2f, 1e-4f, 1e-8f, 1e-16f, 1e-32f}; - return factors[index]; + ARDUINOJSON_DEFINE_STATIC_ARRAY( + T, factors, + ARDUINOJSON_EXPAND6({1e-1f, 1e-2f, 1e-4f, 1e-8f, 1e-16f, 1e-32f})); + return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); } static T negativeBinaryPowerOfTenPlusOne(int index) { - static T factors[] = {1e0f, 1e-1f, 1e-3f, 1e-7f, 1e-15f, 1e-31f}; - return factors[index]; + ARDUINOJSON_DEFINE_STATIC_ARRAY( + T, factors, + ARDUINOJSON_EXPAND6({1e0f, 1e-1f, 1e-3f, 1e-7f, 1e-15f, 1e-31f})); + return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); } static T forge(uint32_t bits) { diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Numbers/parseFloat.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Numbers/parseFloat.hpp deleted file mode 100644 index bfc303c4e..000000000 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Numbers/parseFloat.hpp +++ /dev/null @@ -1,18 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2020 -// MIT License - -#pragma once - -#include -#include - -namespace ARDUINOJSON_NAMESPACE { - -template -inline T parseFloat(const char* s) { - // try to reuse the same parameters as JsonDeserializer - typedef typename choose_largest::type TFloat; - return parseNumber(s).template as(); -} -} // namespace ARDUINOJSON_NAMESPACE diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Numbers/parseInteger.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Numbers/parseInteger.hpp deleted file mode 100644 index 8da434e64..000000000 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Numbers/parseInteger.hpp +++ /dev/null @@ -1,19 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2020 -// MIT License - -#pragma once - -#include -#include -#include - -namespace ARDUINOJSON_NAMESPACE { -template -T parseInteger(const char *s) { - // try to reuse the same parameters as JsonDeserializer - typedef typename choose_largest::type>::type - TUInt; - return parseNumber(s).template as(); -} -} // namespace ARDUINOJSON_NAMESPACE diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Numbers/parseNumber.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Numbers/parseNumber.hpp index ad493a3c6..2bd18227f 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Numbers/parseNumber.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Numbers/parseNumber.hpp @@ -10,54 +10,18 @@ #include #include #include -#include +#include +#include namespace ARDUINOJSON_NAMESPACE { -template -struct ParsedNumber { - ParsedNumber() : uintValue(0), floatValue(0), _type(VALUE_IS_NULL) {} - - ParsedNumber(TUInt value, bool is_negative) - : uintValue(value), - floatValue(TFloat(value)), - _type(uint8_t(is_negative ? VALUE_IS_NEGATIVE_INTEGER - : VALUE_IS_POSITIVE_INTEGER)) {} - ParsedNumber(TFloat value) : floatValue(value), _type(VALUE_IS_FLOAT) {} - - template - T as() const { - switch (_type) { - case VALUE_IS_NEGATIVE_INTEGER: - return convertNegativeInteger(uintValue); - case VALUE_IS_POSITIVE_INTEGER: - return convertPositiveInteger(uintValue); - case VALUE_IS_FLOAT: - return convertFloat(floatValue); - default: - return 0; - } - } - - uint8_t type() const { - return _type; - } - - TUInt uintValue; - TFloat floatValue; - uint8_t _type; -}; - template struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> {}; -template -inline ParsedNumber parseNumber(const char *s) { - typedef FloatTraits traits; - typedef typename choose_largest::type - mantissa_t; - typedef typename traits::exponent_type exponent_t; - typedef ParsedNumber return_type; +inline bool parseNumber(const char* s, VariantData& result) { + typedef FloatTraits traits; + typedef choose_largest::type mantissa_t; + typedef traits::exponent_type exponent_t; ARDUINOJSON_ASSERT(s != 0); @@ -73,21 +37,25 @@ inline ParsedNumber parseNumber(const char *s) { } #if ARDUINOJSON_ENABLE_NAN - if (*s == 'n' || *s == 'N') - return traits::nan(); + if (*s == 'n' || *s == 'N') { + result.setFloat(traits::nan()); + return true; + } #endif #if ARDUINOJSON_ENABLE_INFINITY - if (*s == 'i' || *s == 'I') - return is_negative ? -traits::inf() : traits::inf(); + if (*s == 'i' || *s == 'I') { + result.setFloat(is_negative ? -traits::inf() : traits::inf()); + return true; + } #endif if (!isdigit(*s) && *s != '.') - return return_type(); + return false; mantissa_t mantissa = 0; exponent_t exponent_offset = 0; - const mantissa_t maxUint = TUInt(-1); + const mantissa_t maxUint = UInt(-1); while (isdigit(*s)) { uint8_t digit = uint8_t(*s - '0'); @@ -100,8 +68,13 @@ inline ParsedNumber parseNumber(const char *s) { s++; } - if (*s == '\0') - return return_type(TUInt(mantissa), is_negative); + if (*s == '\0') { + if (is_negative) + result.setNegativeInteger(UInt(mantissa)); + else + result.setPositiveInteger(UInt(mantissa)); + return true; + } // avoid mantissa overflow while (mantissa > traits::mantissa_max) { @@ -141,9 +114,10 @@ inline ParsedNumber parseNumber(const char *s) { exponent = exponent * 10 + (*s - '0'); if (exponent + exponent_offset > traits::exponent_max) { if (negative_exponent) - return is_negative ? -0.0f : 0.0f; + result.setFloat(is_negative ? -0.0f : 0.0f); else - return is_negative ? -traits::inf() : traits::inf(); + result.setFloat(is_negative ? -traits::inf() : traits::inf()); + return true; } s++; } @@ -154,10 +128,20 @@ inline ParsedNumber parseNumber(const char *s) { // we should be at the end of the string, otherwise it's an error if (*s != '\0') - return return_type(); + return false; - TFloat result = traits::make_float(static_cast(mantissa), exponent); + Float final_result = + traits::make_float(static_cast(mantissa), exponent); - return is_negative ? -result : result; + result.setFloat(is_negative ? -final_result : final_result); + return true; +} + +template +inline T parseNumber(const char* s) { + VariantData value; + value.init(); // VariantData is a POD, so it has no constructor + parseNumber(s, value); + return variantAs(&value); } } // namespace ARDUINOJSON_NAMESPACE diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Object/MemberProxy.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Object/MemberProxy.hpp index 46f4beab3..a9ee6034f 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Object/MemberProxy.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Object/MemberProxy.hpp @@ -120,8 +120,8 @@ class MemberProxy : public VariantOperators >, return getOrAddUpstreamMember().set(value); } - template - void accept(Visitor &visitor) const { + template + typename TVisitor::result_type accept(TVisitor &visitor) const { return getUpstreamMember().accept(visitor); } diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Object/ObjectFunctions.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Object/ObjectFunctions.hpp index 0c754eb3b..1c7d5f3e6 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Object/ObjectFunctions.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Object/ObjectFunctions.hpp @@ -8,12 +8,13 @@ namespace ARDUINOJSON_NAMESPACE { -template -void objectAccept(const CollectionData *obj, Visitor &visitor) { +template +typename TVisitor::result_type objectAccept(const CollectionData *obj, + TVisitor &visitor) { if (obj) - visitor.visitObject(*obj); + return visitor.visitObject(*obj); else - visitor.visitNull(); + return visitor.visitNull(); } inline bool objectEquals(const CollectionData *lhs, const CollectionData *rhs) { diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Object/ObjectRef.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Object/ObjectRef.hpp index 599a2ae90..e57e088e1 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Object/ObjectRef.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Object/ObjectRef.hpp @@ -22,9 +22,9 @@ class ObjectRefBase { return VariantConstRef(reinterpret_cast(data)); } - template - FORCE_INLINE void accept(Visitor& visitor) const { - objectAccept(_data, visitor); + template + typename TVisitor::result_type accept(TVisitor& visitor) const { + return objectAccept(_data, visitor); } FORCE_INLINE bool isNull() const { diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/gsl/not_null.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/gsl/not_null.hpp deleted file mode 100644 index 79df0a1d2..000000000 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/gsl/not_null.hpp +++ /dev/null @@ -1,34 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2020 -// MIT License - -#pragma once - -#include -#include - -namespace ARDUINOJSON_NAMESPACE { - -template -class not_null { - public: - explicit not_null(T ptr) : _ptr(ptr) { - ARDUINOJSON_ASSERT(ptr != NULL); - } - - T get() const { - ARDUINOJSON_ASSERT(_ptr != NULL); - return _ptr; - } - - private: - T _ptr; -}; - -template -not_null make_not_null(T ptr) { - ARDUINOJSON_ASSERT(ptr != NULL); - return not_null(ptr); -} - -} // namespace ARDUINOJSON_NAMESPACE diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/pgmspace.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/pgmspace.hpp index ffeffd184..0cdc5cb72 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/pgmspace.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/pgmspace.hpp @@ -4,6 +4,7 @@ #pragma once +#include #include #include diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/pgmspace_generic.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/pgmspace_generic.hpp new file mode 100644 index 000000000..70f715fd3 --- /dev/null +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/pgmspace_generic.hpp @@ -0,0 +1,28 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include +#include + +namespace ARDUINOJSON_NAMESPACE { + +template +typename enable_if::value, T>::type pgm_read(const void* p) { + return reinterpret_cast(pgm_read_ptr(p)); +} + +template +typename enable_if::value, T>::type pgm_read(const void* p) { + return pgm_read_float(p); +} + +template +typename enable_if::value, T>::type pgm_read( + const void* p) { + return pgm_read_dword(p); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/preprocessor.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/preprocessor.hpp new file mode 100644 index 000000000..4df13d8bc --- /dev/null +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/preprocessor.hpp @@ -0,0 +1,36 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#define ARDUINOJSON_EXPAND6(a, b, c, d, e, f) a, b, c, d, e, f +#define ARDUINOJSON_EXPAND7(a, b, c, d, e, f, g) a, b, c, d, e, f, g +#define ARDUINOJSON_EXPAND9(a, b, c, d, e, f, g, h, i) a, b, c, d, e, f, g, h, i +#define ARDUINOJSON_EXPAND18(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, \ + q, r) \ + a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r + +#define ARDUINOJSON_CONCAT_(A, B) A##B +#define ARDUINOJSON_CONCAT2(A, B) ARDUINOJSON_CONCAT_(A, B) +#define ARDUINOJSON_CONCAT4(A, B, C, D) \ + ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT2(A, B), ARDUINOJSON_CONCAT2(C, D)) + +#define ARDUINOJSON_HEX_DIGIT_0000() 0 +#define ARDUINOJSON_HEX_DIGIT_0001() 1 +#define ARDUINOJSON_HEX_DIGIT_0010() 2 +#define ARDUINOJSON_HEX_DIGIT_0011() 3 +#define ARDUINOJSON_HEX_DIGIT_0100() 4 +#define ARDUINOJSON_HEX_DIGIT_0101() 5 +#define ARDUINOJSON_HEX_DIGIT_0110() 6 +#define ARDUINOJSON_HEX_DIGIT_0111() 7 +#define ARDUINOJSON_HEX_DIGIT_1000() 8 +#define ARDUINOJSON_HEX_DIGIT_1001() 9 +#define ARDUINOJSON_HEX_DIGIT_1010() A +#define ARDUINOJSON_HEX_DIGIT_1011() B +#define ARDUINOJSON_HEX_DIGIT_1100() C +#define ARDUINOJSON_HEX_DIGIT_1101() D +#define ARDUINOJSON_HEX_DIGIT_1110() E +#define ARDUINOJSON_HEX_DIGIT_1111() F +#define ARDUINOJSON_HEX_DIGIT_(A, B, C, D) ARDUINOJSON_HEX_DIGIT_##A##B##C##D() +#define ARDUINOJSON_HEX_DIGIT(A, B, C, D) ARDUINOJSON_HEX_DIGIT_(A, B, C, D) diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/static_array.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/static_array.hpp new file mode 100644 index 000000000..c642b2705 --- /dev/null +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/static_array.hpp @@ -0,0 +1,34 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include + +#if ARDUINOJSON_ENABLE_PROGMEM + +#include + +#ifndef ARDUINOJSON_DEFINE_STATIC_ARRAY +#define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) \ + static type const name[] PROGMEM = value; +#endif + +#ifndef ARDUINOJSON_READ_STATIC_ARRAY +#define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) \ + pgm_read(name + index) +#endif + +#else // i.e. ARDUINOJSON_ENABLE_PROGMEM == 0 + +#ifndef ARDUINOJSON_DEFINE_STATIC_ARRAY +#define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) \ + static type const name[] = value; +#endif + +#ifndef ARDUINOJSON_READ_STATIC_ARRAY +#define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) name[index] +#endif + +#endif diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/type_traits.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/type_traits.hpp index 324f1444a..43dc4e01c 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/type_traits.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/type_traits.hpp @@ -15,6 +15,7 @@ #include "type_traits/is_enum.hpp" #include "type_traits/is_floating_point.hpp" #include "type_traits/is_integral.hpp" +#include "type_traits/is_pointer.hpp" #include "type_traits/is_same.hpp" #include "type_traits/is_signed.hpp" #include "type_traits/is_unsigned.hpp" diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/type_traits/is_convertible.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/type_traits/is_convertible.hpp index e0232aaeb..61cd7caac 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/type_traits/is_convertible.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/type_traits/is_convertible.hpp @@ -12,6 +12,11 @@ #pragma warning(disable : 4244) #endif +#ifdef __ICCARM__ +// Suppress IAR Compiler Warning[Pa093]: implicit conversion from floating point to integer +#pragma diag_suppress=Pa093 +#endif + namespace ARDUINOJSON_NAMESPACE { template @@ -32,3 +37,7 @@ struct is_convertible { #ifdef _MSC_VER #pragma warning(pop) #endif + +#ifdef __ICCARM__ +#pragma diag_default=Pa093 +#endif diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Memory/StringSlot.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/type_traits/is_pointer.hpp similarity index 51% rename from lib/ArduinoJson-6.x/src/ArduinoJson/Memory/StringSlot.hpp rename to lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/type_traits/is_pointer.hpp index 47a2eb5fc..92ba098aa 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Memory/StringSlot.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Polyfills/type_traits/is_pointer.hpp @@ -4,16 +4,13 @@ #pragma once -#include // for size_t - -#include - -#define JSON_STRING_SIZE(SIZE) (SIZE + 1) +#include "integral_constant.hpp" namespace ARDUINOJSON_NAMESPACE { -struct StringSlot { - char *value; - size_t size; -}; +template +struct is_pointer : false_type {}; + +template +struct is_pointer : true_type {}; } // namespace ARDUINOJSON_NAMESPACE diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Serialization/CountingDecorator.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Serialization/CountingDecorator.hpp new file mode 100644 index 000000000..140ada713 --- /dev/null +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Serialization/CountingDecorator.hpp @@ -0,0 +1,33 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include + +namespace ARDUINOJSON_NAMESPACE { + +template +class CountingDecorator { + public: + explicit CountingDecorator(TWriter& writer) : _writer(writer), _count(0) {} + + void write(uint8_t c) { + _count += _writer.write(c); + } + + void write(const uint8_t* s, size_t n) { + _count += _writer.write(s, n); + } + + size_t count() const { + return _count; + } + + private: + TWriter _writer; + size_t _count; +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Serialization/Writers/ArduinoStringWriter.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Serialization/Writers/ArduinoStringWriter.hpp index 1fac26027..801cb86cc 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Serialization/Writers/ArduinoStringWriter.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Serialization/Writers/ArduinoStringWriter.hpp @@ -4,7 +4,7 @@ #pragma once -#include +#include namespace ARDUINOJSON_NAMESPACE { diff --git a/lib/ArduinoJson-6.x/src/ArduinoJson/Serialization/measure.hpp b/lib/ArduinoJson-6.x/src/ArduinoJson/Serialization/measure.hpp index e24340422..00f790776 100644 --- a/lib/ArduinoJson-6.x/src/ArduinoJson/Serialization/measure.hpp +++ b/lib/ArduinoJson-6.x/src/ArduinoJson/Serialization/measure.hpp @@ -12,8 +12,7 @@ template