diff --git a/CHANGELOG.md b/CHANGELOG.md index 817a380a..0e98234f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,6 @@ ArduinoJson: change log ======================= -HEAD ----- - -* Fixed `JsonBuffer::parse()` not respecting nesting limit correctly (issue #693) -* Fixed inconsistencies in nesting level counting (PR #695 from Zhenyu Wu) * Added `DynamicJsonDocument` and `StaticJsonDocument` * Added `deserializeJson()` * Added `serializeJson()` and `serializeJsonPretty()` @@ -64,6 +59,14 @@ HEAD > serializeJson(doc, Serial); > ``` +v5.13.2 +------- + +* Fixed `JsonBuffer::parse()` not respecting nesting limit correctly (issue #693) +* Fixed inconsistencies in nesting level counting (PR #695 from Zhenyu Wu) +* Fixed null values that could be pass to `strcmp()` (PR #745 from Mike Karlesky) +* Added macros `ARDUINOJSON_VERSION`, `ARDUINOJSON_VERSION_MAJOR`... + v5.13.1 ------- diff --git a/src/ArduinoJson.hpp b/src/ArduinoJson.hpp index bbe94a3c..cf7e2023 100644 --- a/src/ArduinoJson.hpp +++ b/src/ArduinoJson.hpp @@ -4,6 +4,8 @@ #pragma once +#include "ArduinoJson/version.hpp" + #include "ArduinoJson/DynamicJsonDocument.hpp" #include "ArduinoJson/Json/JsonDeserializer.hpp" #include "ArduinoJson/Json/JsonSerializer.hpp" diff --git a/src/ArduinoJson/JsonObject.hpp b/src/ArduinoJson/JsonObject.hpp index c123b7a2..0bb050c7 100644 --- a/src/ArduinoJson/JsonObject.hpp +++ b/src/ArduinoJson/JsonObject.hpp @@ -256,15 +256,21 @@ class JsonObject : public Internals::ReferenceType, template bool set_impl(TStringRef key, TValueRef value) { + // ignore null key + if (Internals::StringTraits::is_null(key)) return false; + + // search a matching key iterator it = findKey(key); if (it == end()) { + // add the key it = Internals::List::add(); if (it == end()) return false; - bool key_ok = Internals::ValueSaver::save(_buffer, it->key, key); if (!key_ok) return false; } + + // save the value return Internals::ValueSaver::save(_buffer, it->value, value); } diff --git a/src/ArduinoJson/JsonVariantComparisons.hpp b/src/ArduinoJson/JsonVariantComparisons.hpp index 39317a67..79d0c219 100644 --- a/src/ArduinoJson/JsonVariantComparisons.hpp +++ b/src/ArduinoJson/JsonVariantComparisons.hpp @@ -129,7 +129,8 @@ class JsonVariantComparisons { if (is() && right.template is()) return as() == right.template as(); if (is() && right.template is()) - return strcmp(as(), right.template as()) == 0; + return StringTraits::equals(as(), + right.template as()); return false; } diff --git a/src/ArduinoJson/Strings/CharPointer.hpp b/src/ArduinoJson/Strings/CharPointer.hpp index 07a08284..c16f681a 100644 --- a/src/ArduinoJson/Strings/CharPointer.hpp +++ b/src/ArduinoJson/Strings/CharPointer.hpp @@ -10,7 +10,9 @@ namespace Internals { template struct CharPointerTraits { static bool equals(const TChar* str, const char* expected) { - return strcmp(reinterpret_cast(str), expected) == 0; + const char* actual = reinterpret_cast(str); + if (!actual || !expected) return actual == expected; + return strcmp(actual, expected) == 0; } static bool is_null(const TChar* str) { diff --git a/src/ArduinoJson/Strings/FlashString.hpp b/src/ArduinoJson/Strings/FlashString.hpp index f5edbdc6..155fb284 100644 --- a/src/ArduinoJson/Strings/FlashString.hpp +++ b/src/ArduinoJson/Strings/FlashString.hpp @@ -11,7 +11,9 @@ namespace Internals { template <> struct StringTraits { static bool equals(const __FlashStringHelper* str, const char* expected) { - return strcmp_P(expected, (const char*)str) == 0; + const char* actual = reinterpret_cast(str); + if (!actual || !expected) return actual == expected; + return strcmp_P(expected, actual) == 0; } static bool is_null(const __FlashStringHelper* str) { @@ -33,7 +35,7 @@ struct StringTraits { static const bool has_equals = true; static const bool should_duplicate = true; }; -} -} +} // namespace Internals +} // namespace ArduinoJson #endif diff --git a/src/ArduinoJson/Strings/StdString.hpp b/src/ArduinoJson/Strings/StdString.hpp index aa521e58..f37378a5 100644 --- a/src/ArduinoJson/Strings/StdString.hpp +++ b/src/ArduinoJson/Strings/StdString.hpp @@ -36,7 +36,10 @@ struct StdStringTraits { } static bool equals(const TString& str, const char* expected) { - return 0 == strcmp(str.c_str(), expected); + // Arduino's String::c_str() can return NULL + const char* actual = str.c_str(); + if (!actual || !expected) return actual == expected; + return 0 == strcmp(actual, expected); } static void append(TString& str, char c) { @@ -64,7 +67,7 @@ struct StringTraits : StdStringTraits { template <> struct StringTraits : StdStringTraits {}; #endif -} -} +} // namespace Internals +} // namespace ArduinoJson #endif diff --git a/src/ArduinoJson/version.hpp b/src/ArduinoJson/version.hpp new file mode 100644 index 00000000..a71c3ab4 --- /dev/null +++ b/src/ArduinoJson/version.hpp @@ -0,0 +1,10 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#pragma once + +#define ARDUINOJSON_VERSION "5.13.2" +#define ARDUINOJSON_VERSION_MAJOR 5 +#define ARDUINOJSON_VERSION_MINOR 13 +#define ARDUINOJSON_VERSION_REVISION 2 diff --git a/test/JsonObject/subscript.cpp b/test/JsonObject/subscript.cpp index 1ac365cd..98747f09 100644 --- a/test/JsonObject/subscript.cpp +++ b/test/JsonObject/subscript.cpp @@ -152,4 +152,15 @@ TEST_CASE("JsonObject::operator[]") { const size_t expectedSize = JSON_OBJECT_SIZE(1) + 12; REQUIRE(expectedSize <= doc.memoryUsage()); } + + SECTION("should ignore null key") { + // object must have a value to make a call to strcmp() + obj["dummy"] = 42; + + const char* null = 0; + obj[null] = 666; + + REQUIRE(obj.size() == 1); + REQUIRE(obj[null] == 0); + } } diff --git a/test/JsonVariant/compare.cpp b/test/JsonVariant/compare.cpp index 85010a5e..4411fe02 100644 --- a/test/JsonVariant/compare.cpp +++ b/test/JsonVariant/compare.cpp @@ -5,6 +5,8 @@ #include #include +static const char* null = 0; + template void checkEquals(JsonVariant a, T b) { REQUIRE(b == a); @@ -96,38 +98,69 @@ TEST_CASE("JsonVariant comparisons") { checkComparisons(122, 123, 124); } + SECTION("null") { + JsonVariant variant = null; + + REQUIRE(variant == variant); + REQUIRE_FALSE(variant != variant); + + REQUIRE(variant == null); + REQUIRE_FALSE(variant != null); + + REQUIRE(variant != "null"); + REQUIRE_FALSE(variant == "null"); + } + SECTION("StringLiteral") { DynamicJsonDocument doc; deserializeJson(doc, "\"hello\""); JsonVariant variant = doc.as(); + REQUIRE(variant == variant); + REQUIRE_FALSE(variant != variant); + REQUIRE(variant == "hello"); REQUIRE_FALSE(variant != "hello"); REQUIRE(variant != "world"); REQUIRE_FALSE(variant == "world"); + REQUIRE(variant != null); + REQUIRE_FALSE(variant == null); + REQUIRE("hello" == variant); REQUIRE_FALSE("hello" != variant); REQUIRE("world" != variant); REQUIRE_FALSE("world" == variant); + + REQUIRE(null != variant); + REQUIRE_FALSE(null == variant); } SECTION("String") { JsonVariant variant = "hello"; + REQUIRE(variant == variant); + REQUIRE_FALSE(variant != variant); + REQUIRE(variant == std::string("hello")); REQUIRE_FALSE(variant != std::string("hello")); REQUIRE(variant != std::string("world")); REQUIRE_FALSE(variant == std::string("world")); + REQUIRE(variant != null); + REQUIRE_FALSE(variant == null); + REQUIRE(std::string("hello") == variant); REQUIRE_FALSE(std::string("hello") != variant); REQUIRE(std::string("world") != variant); REQUIRE_FALSE(std::string("world") == variant); + + REQUIRE(null != variant); + REQUIRE_FALSE(null == variant); } SECTION("IntegerInVariant") { diff --git a/test/Misc/CMakeLists.txt b/test/Misc/CMakeLists.txt index 69db9af7..cd10edec 100644 --- a/test/Misc/CMakeLists.txt +++ b/test/Misc/CMakeLists.txt @@ -8,6 +8,7 @@ add_executable(MiscTests StringTraits.cpp TypeTraits.cpp unsigned_char.cpp + version.cpp vla.cpp ) diff --git a/test/Misc/version.cpp b/test/Misc/version.cpp new file mode 100644 index 00000000..a9bbbe72 --- /dev/null +++ b/test/Misc/version.cpp @@ -0,0 +1,16 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#include +#include +#include + +TEST_CASE("ARDUINOJSON_VERSION") { + std::stringstream version; + + version << ARDUINOJSON_VERSION_MAJOR << "." << ARDUINOJSON_VERSION_MINOR + << "." << ARDUINOJSON_VERSION_REVISION; + + REQUIRE(version.str() == ARDUINOJSON_VERSION); +}