Преглед изворни кода

Merge branch 'master' into 6.x

Benoit Blanchon пре 7 година
родитељ
комит
0139354780

+ 8 - 5
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
 -------
 

+ 2 - 0
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"

+ 7 - 1
src/ArduinoJson/JsonObject.hpp

@@ -256,15 +256,21 @@ class JsonObject : public Internals::ReferenceType,
 
   template <typename TStringRef, typename TValueRef>
   bool set_impl(TStringRef key, TValueRef value) {
+    // ignore null key
+    if (Internals::StringTraits<TStringRef>::is_null(key)) return false;
+
+    // search a matching key
     iterator it = findKey<TStringRef>(key);
     if (it == end()) {
+      // add the key
       it = Internals::List<JsonPair>::add();
       if (it == end()) return false;
-
       bool key_ok =
           Internals::ValueSaver<TStringRef>::save(_buffer, it->key, key);
       if (!key_ok) return false;
     }
+
+    // save the value
     return Internals::ValueSaver<TValueRef>::save(_buffer, it->value, value);
   }
 

+ 2 - 1
src/ArduinoJson/JsonVariantComparisons.hpp

@@ -129,7 +129,8 @@ class JsonVariantComparisons {
     if (is<JsonObject>() && right.template is<JsonObject>())
       return as<JsonObject>() == right.template as<JsonObject>();
     if (is<char *>() && right.template is<char *>())
-      return strcmp(as<char *>(), right.template as<char *>()) == 0;
+      return StringTraits<const char *>::equals(as<char *>(),
+                                                right.template as<char *>());
 
     return false;
   }

+ 3 - 1
src/ArduinoJson/Strings/CharPointer.hpp

@@ -10,7 +10,9 @@ namespace Internals {
 template <typename TChar>
 struct CharPointerTraits {
   static bool equals(const TChar* str, const char* expected) {
-    return strcmp(reinterpret_cast<const char*>(str), expected) == 0;
+    const char* actual = reinterpret_cast<const char*>(str);
+    if (!actual || !expected) return actual == expected;
+    return strcmp(actual, expected) == 0;
   }
 
   static bool is_null(const TChar* str) {

+ 5 - 3
src/ArduinoJson/Strings/FlashString.hpp

@@ -11,7 +11,9 @@ namespace Internals {
 template <>
 struct StringTraits<const __FlashStringHelper*, void> {
   static bool equals(const __FlashStringHelper* str, const char* expected) {
-    return strcmp_P(expected, (const char*)str) == 0;
+    const char* actual = reinterpret_cast<const char*>(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<const __FlashStringHelper*, void> {
   static const bool has_equals = true;
   static const bool should_duplicate = true;
 };
-}
-}
+}  // namespace Internals
+}  // namespace ArduinoJson
 
 #endif

+ 6 - 3
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<StringSumHelper, void> : StdStringTraits<StringSumHelper> {
 template <>
 struct StringTraits<std::string, void> : StdStringTraits<std::string> {};
 #endif
-}
-}
+}  // namespace Internals
+}  // namespace ArduinoJson
 
 #endif

+ 10 - 0
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

+ 11 - 0
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);
+  }
 }

+ 33 - 0
test/JsonVariant/compare.cpp

@@ -5,6 +5,8 @@
 #include <ArduinoJson.h>
 #include <catch.hpp>
 
+static const char* null = 0;
+
 template <typename T>
 void checkEquals(JsonVariant a, T b) {
   REQUIRE(b == a);
@@ -96,38 +98,69 @@ TEST_CASE("JsonVariant comparisons") {
     checkComparisons<unsigned short>(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<JsonVariant>();
 
+    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") {

+ 1 - 0
test/Misc/CMakeLists.txt

@@ -8,6 +8,7 @@ add_executable(MiscTests
 	StringTraits.cpp
 	TypeTraits.cpp
 	unsigned_char.cpp
+	version.cpp
 	vla.cpp
 )
 

+ 16 - 0
test/Misc/version.cpp

@@ -0,0 +1,16 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#include <ArduinoJson/version.hpp>
+#include <catch.hpp>
+#include <sstream>
+
+TEST_CASE("ARDUINOJSON_VERSION") {
+  std::stringstream version;
+
+  version << ARDUINOJSON_VERSION_MAJOR << "." << ARDUINOJSON_VERSION_MINOR
+          << "." << ARDUINOJSON_VERSION_REVISION;
+
+  REQUIRE(version.str() == ARDUINOJSON_VERSION);
+}