From d4f725d1faa9aeb608998f68f8ad8bc9e3b74e2a Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Sun, 22 Jan 2017 15:42:47 +0100 Subject: [PATCH] Fixed error with string of type `unsigned char*` (issue #428) --- CHANGELOG.md | 1 + include/ArduinoJson/Data/ValueSetter.hpp | 12 + .../Deserialization/JsonParser.hpp | 18 +- .../Deserialization/StringWriter.hpp | 15 +- include/ArduinoJson/JsonVariant.hpp | 12 +- .../ArduinoJson/StringTraits/CharPointer.hpp | 30 +- .../ArduinoJson/StringTraits/StdString.hpp | 4 +- include/ArduinoJson/TypeTraits/IsChar.hpp | 26 ++ include/ArduinoJson/TypeTraits/IsConst.hpp | 24 ++ test/UnsignedChar_Tests.cpp | 283 ++++++++++++++++++ 10 files changed, 394 insertions(+), 31 deletions(-) create mode 100644 include/ArduinoJson/TypeTraits/IsChar.hpp create mode 100644 include/ArduinoJson/TypeTraits/IsConst.hpp create mode 100644 test/UnsignedChar_Tests.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 370be3ef..9b2b0943 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ HEAD * Made sure we don't read more that necessary (issue #422) * Fixed error when the key of a `JsonObject` is a `char[]` (issue #423) * Reduced code size when using `const` references +* Fixed error with string of type `unsigned char*` (issue #428) v5.8.1 ------ diff --git a/include/ArduinoJson/Data/ValueSetter.hpp b/include/ArduinoJson/Data/ValueSetter.hpp index 3898a536..81be5839 100644 --- a/include/ArduinoJson/Data/ValueSetter.hpp +++ b/include/ArduinoJson/Data/ValueSetter.hpp @@ -37,5 +37,17 @@ struct ValueSetter +struct ValueSetter::should_duplicate>::type> { + template + static bool set(JsonBuffer*, TDestination& destination, + const TSource& source) { + // unsigned char* -> char* + destination = reinterpret_cast(source); + return true; + } +}; } } diff --git a/include/ArduinoJson/Deserialization/JsonParser.hpp b/include/ArduinoJson/Deserialization/JsonParser.hpp index ef8a428e..5448bfc3 100644 --- a/include/ArduinoJson/Deserialization/JsonParser.hpp +++ b/include/ArduinoJson/Deserialization/JsonParser.hpp @@ -9,6 +9,7 @@ #include "../JsonBuffer.hpp" #include "../JsonVariant.hpp" +#include "../TypeTraits/IsConst.hpp" #include "StringWriter.hpp" namespace ArduinoJson { @@ -71,7 +72,7 @@ class JsonParser { uint8_t _nestingLimit; }; -template +template struct JsonParserBuilder { typedef typename Internals::StringTraits::Reader InputReader; typedef JsonParser TParser; @@ -82,14 +83,17 @@ struct JsonParserBuilder { } }; -template -struct JsonParserBuilder { - typedef typename Internals::StringTraits::Reader InputReader; - typedef JsonParser TParser; +template +struct JsonParserBuilder< + TJsonBuffer, TChar *, + typename TypeTraits::EnableIf::value>::type> { + typedef typename Internals::StringTraits::Reader TReader; + typedef StringWriter TWriter; + typedef JsonParser TParser; - static TParser makeParser(TJsonBuffer *buffer, char *json, + static TParser makeParser(TJsonBuffer *buffer, TChar *json, uint8_t nestingLimit) { - return TParser(buffer, InputReader(json), json, nestingLimit); + return TParser(buffer, TReader(json), TWriter(json), nestingLimit); } }; diff --git a/include/ArduinoJson/Deserialization/StringWriter.hpp b/include/ArduinoJson/Deserialization/StringWriter.hpp index 44e6434a..7ebfabaa 100644 --- a/include/ArduinoJson/Deserialization/StringWriter.hpp +++ b/include/ArduinoJson/Deserialization/StringWriter.hpp @@ -10,34 +10,35 @@ namespace ArduinoJson { namespace Internals { +template class StringWriter { public: class String { public: - String(char** ptr) : _writePtr(ptr), _startPtr(*ptr) {} + String(TChar** ptr) : _writePtr(ptr), _startPtr(*ptr) {} - void append(char c) { + void append(TChar c) { *(*_writePtr)++ = c; } const char* c_str() const { *(*_writePtr)++ = 0; - return _startPtr; + return reinterpret_cast(_startPtr); } private: - char** _writePtr; - char* _startPtr; + TChar** _writePtr; + TChar* _startPtr; }; - StringWriter(char* buffer) : _ptr(buffer) {} + StringWriter(TChar* buffer) : _ptr(buffer) {} String startString() { return String(&_ptr); } private: - char* _ptr; + TChar* _ptr; }; } } diff --git a/include/ArduinoJson/JsonVariant.hpp b/include/ArduinoJson/JsonVariant.hpp index 6a066045..a41baeea 100644 --- a/include/ArduinoJson/JsonVariant.hpp +++ b/include/ArduinoJson/JsonVariant.hpp @@ -17,6 +17,7 @@ #include "RawJson.hpp" #include "Serialization/JsonPrintable.hpp" #include "TypeTraits/EnableIf.hpp" +#include "TypeTraits/IsChar.hpp" #include "TypeTraits/IsFloatingPoint.hpp" #include "TypeTraits/IsIntegral.hpp" #include "TypeTraits/IsSame.hpp" @@ -98,9 +99,16 @@ class JsonVariant : public JsonVariantBase { } // Create a JsonVariant containing a string. - JsonVariant(const char *value) { + // JsonVariant(const char*); + // JsonVariant(const signed char*); + // JsonVariant(const unsigned char*); + template + JsonVariant( + const TChar *value, + typename TypeTraits::EnableIf::value>::type * = + 0) { _type = Internals::JSON_STRING; - _content.asString = value; + _content.asString = reinterpret_cast(value); } // Create a JsonVariant containing an unparsed string diff --git a/include/ArduinoJson/StringTraits/CharPointer.hpp b/include/ArduinoJson/StringTraits/CharPointer.hpp index fde25faa..6eb280b3 100644 --- a/include/ArduinoJson/StringTraits/CharPointer.hpp +++ b/include/ArduinoJson/StringTraits/CharPointer.hpp @@ -7,37 +7,42 @@ #pragma once +#include "../TypeTraits/EnableIf.hpp" +#include "../TypeTraits/IsChar.hpp" + namespace ArduinoJson { namespace Internals { +template struct CharPointerTraits { class Reader { - const char* _ptr; + const TChar* _ptr; public: - Reader(const char* ptr) : _ptr(ptr ? ptr : "") {} + Reader(const TChar* ptr) + : _ptr(ptr ? ptr : reinterpret_cast("")) {} void move() { ++_ptr; } - char current() const { + TChar current() const { return _ptr[0]; } - char next() const { + TChar next() const { return _ptr[1]; } }; - static bool equals(const char* str, const char* expected) { - return strcmp(str, expected) == 0; + static bool equals(const TChar* str, const char* expected) { + return strcmp(reinterpret_cast(str), expected) == 0; } template - static char* duplicate(const char* str, Buffer* buffer) { + static char* duplicate(const TChar* str, Buffer* buffer) { if (!str) return NULL; - size_t size = strlen(str) + 1; + size_t size = strlen(reinterpret_cast(str)) + 1; void* dup = buffer->alloc(size); if (dup != NULL) memcpy(dup, str, size); return static_cast(dup); @@ -48,10 +53,9 @@ struct CharPointerTraits { static const bool should_duplicate = false; }; -template <> -struct StringTraits : CharPointerTraits {}; - -template <> -struct StringTraits : CharPointerTraits {}; +template +struct StringTraits::value>::type> + : CharPointerTraits {}; } } diff --git a/include/ArduinoJson/StringTraits/StdString.hpp b/include/ArduinoJson/StringTraits/StdString.hpp index 613b0272..78ec5967 100644 --- a/include/ArduinoJson/StringTraits/StdString.hpp +++ b/include/ArduinoJson/StringTraits/StdString.hpp @@ -29,8 +29,8 @@ struct StdStringTraits { return static_cast(dup); } - struct Reader : CharPointerTraits::Reader { - Reader(const TString& str) : CharPointerTraits::Reader(str.c_str()) {} + struct Reader : CharPointerTraits::Reader { + Reader(const TString& str) : CharPointerTraits::Reader(str.c_str()) {} }; static bool equals(const TString& str, const char* expected) { diff --git a/include/ArduinoJson/TypeTraits/IsChar.hpp b/include/ArduinoJson/TypeTraits/IsChar.hpp new file mode 100644 index 00000000..536e9880 --- /dev/null +++ b/include/ArduinoJson/TypeTraits/IsChar.hpp @@ -0,0 +1,26 @@ +// Copyright Benoit Blanchon 2014-2017 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +#include "IsSame.hpp" + +namespace ArduinoJson { +namespace TypeTraits { + +// A meta-function that returns true if T is a charater +template +struct IsChar { + static const bool value = IsSame::value || + IsSame::value || + IsSame::value; +}; + +template +struct IsChar : IsChar {}; +} +} diff --git a/include/ArduinoJson/TypeTraits/IsConst.hpp b/include/ArduinoJson/TypeTraits/IsConst.hpp new file mode 100644 index 00000000..cf748e4c --- /dev/null +++ b/include/ArduinoJson/TypeTraits/IsConst.hpp @@ -0,0 +1,24 @@ +// Copyright Benoit Blanchon 2014-2017 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#pragma once + +namespace ArduinoJson { +namespace TypeTraits { + +// A meta-function that return the type T without the const modifier +template +struct IsConst { + static const bool value = false; +}; + +template +struct IsConst { + static const bool value = true; +}; +} +} diff --git a/test/UnsignedChar_Tests.cpp b/test/UnsignedChar_Tests.cpp new file mode 100644 index 00000000..5f10dd48 --- /dev/null +++ b/test/UnsignedChar_Tests.cpp @@ -0,0 +1,283 @@ +// Copyright Benoit Blanchon 2014-2017 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson +// If you like this project, please add a star! + +#include +#include + +#if defined(__clang__) +#define CONFLICTS_WITH_BUILTIN_OPERATOR +#endif + +TEST(UnsignedCharArray, ParseArray) { + unsigned char json[] = "[42]"; + + StaticJsonBuffer jsonBuffer; + JsonArray& arr = jsonBuffer.parseArray(json); + + EXPECT_TRUE(arr.success()); +} + +TEST(UnsignedCharArray, ParseObject) { + unsigned char json[] = "{\"a\":42}"; + + StaticJsonBuffer jsonBuffer; + JsonObject& obj = jsonBuffer.parseObject(json); + + EXPECT_TRUE(obj.success()); +} + +TEST(UnsignedCharArray, JsonVariant_Constructor) { + unsigned char value[] = "42"; + + JsonVariant variant(value); + + EXPECT_EQ(42, variant.as()); +} + +TEST(UnsignedCharArray, JsonVariant_Assign) { + unsigned char value[] = "42"; + + JsonVariant variant(666); + variant = value; + + EXPECT_EQ(42, variant.as()); +} + +#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR +TEST(UnsignedCharArray, JsonVariant_Subscript) { + unsigned char key[] = "hello"; + + DynamicJsonBuffer jsonBuffer; + JsonVariant variant = jsonBuffer.parseObject("{\"hello\":\"world\"}"); + + EXPECT_STREQ("world", variant[key]); +} +#endif + +#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR +TEST(UnsignedCharArray, JsonVariant_Subscript_Const) { + unsigned char key[] = "hello"; + + DynamicJsonBuffer jsonBuffer; + const JsonVariant variant = jsonBuffer.parseObject("{\"hello\":\"world\"}"); + + EXPECT_STREQ("world", variant[key]); +} +#endif + +TEST(UnsignedCharArray, JsonVariant_Equals) { + unsigned char comparand[] = "hello"; + + DynamicJsonBuffer jsonBuffer; + const JsonVariant variant = "hello"; + + EXPECT_TRUE(comparand == variant); + EXPECT_TRUE(variant == comparand); + EXPECT_FALSE(comparand != variant); + EXPECT_FALSE(variant != comparand); +} + +TEST(UnsignedCharArray, JsonVariant_Differs) { + unsigned char comparand[] = "hello"; + + DynamicJsonBuffer jsonBuffer; + const JsonVariant variant = "world"; + + EXPECT_TRUE(comparand != variant); + EXPECT_TRUE(variant != comparand); + EXPECT_FALSE(comparand == variant); + EXPECT_FALSE(variant == comparand); +} + +#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR +TEST(UnsignedCharArray, JsonObject_Subscript) { + unsigned char key[] = "hello"; + + DynamicJsonBuffer jsonBuffer; + JsonObject& obj = jsonBuffer.createObject(); + obj[key] = "world"; + + EXPECT_STREQ("world", obj["hello"]); +} +#endif + +TEST(UnsignedCharArray, JsonObject_Subscript_Assign) { // issue #416 + unsigned char value[] = "world"; + + DynamicJsonBuffer jsonBuffer; + JsonObject& obj = jsonBuffer.createObject(); + obj["hello"] = value; + + EXPECT_STREQ("world", obj["hello"]); +} + +TEST(UnsignedCharArray, JsonObject_Subscript_Set) { + unsigned char value[] = "world"; + + DynamicJsonBuffer jsonBuffer; + JsonObject& obj = jsonBuffer.createObject(); + obj["hello"].set(value); + + EXPECT_STREQ("world", obj["hello"]); +} + +#ifndef CONFLICTS_WITH_BUILTIN_OPERATOR +TEST(UnsignedCharArray, JsonObject_Subscript_Const) { + unsigned char key[] = "hello"; + + DynamicJsonBuffer jsonBuffer; + const JsonObject& obj = jsonBuffer.parseObject("{\"hello\":\"world\"}"); + + EXPECT_STREQ("world", obj[key]); +} +#endif + +TEST(UnsignedCharArray, JsonObject_Get) { + unsigned char key[] = "hello"; + + DynamicJsonBuffer jsonBuffer; + JsonObject& obj = jsonBuffer.parseObject("{\"hello\":\"world\"}"); + + EXPECT_STREQ("world", obj.get(key)); +} + +TEST(UnsignedCharArray, JsonObject_Set_Key) { + unsigned char key[] = "hello"; + + DynamicJsonBuffer jsonBuffer; + JsonObject& obj = jsonBuffer.createObject(); + obj.set(key, "world"); + + EXPECT_STREQ("world", obj["hello"]); +} + +TEST(UnsignedCharArray, JsonObject_Set_Value) { + unsigned char value[] = "world"; + + DynamicJsonBuffer jsonBuffer; + JsonObject& obj = jsonBuffer.createObject(); + obj.set("hello", value); + + EXPECT_STREQ("world", obj["hello"]); +} + +TEST(UnsignedCharArray, JsonObject_Set_Key_WithDecimals) { + unsigned char key[] = "hello"; + + DynamicJsonBuffer jsonBuffer; + JsonObject& obj = jsonBuffer.createObject(); + obj.set(key, 3.14, 2); + + EXPECT_EQ(3.14, obj["hello"]); +} + +TEST(UnsignedCharArray, JsonObject_Set_KeyAndValue) { + unsigned char key[] = "world"; + + DynamicJsonBuffer jsonBuffer; + JsonObject& obj = jsonBuffer.createObject(); + obj.set(key, key); + + EXPECT_STREQ("world", obj["world"]); +} + +TEST(UnsignedCharArray, JsonObject_ContainsKey) { + unsigned char key[] = "hello"; + + DynamicJsonBuffer jsonBuffer; + const JsonObject& obj = jsonBuffer.parseObject("{\"hello\":\"world\"}"); + + EXPECT_TRUE(obj.containsKey(key)); +} + +TEST(UnsignedCharArray, JsonObject_Remove) { + unsigned char key[] = "hello"; + + DynamicJsonBuffer jsonBuffer; + JsonObject& obj = jsonBuffer.parseObject("{\"hello\":\"world\"}"); + obj.remove(key); + + EXPECT_EQ(0, obj.size()); +} + +TEST(UnsignedCharArray, JsonObject_Is) { + unsigned char key[] = "hello"; + + DynamicJsonBuffer jsonBuffer; + JsonObject& obj = jsonBuffer.parseObject("{\"hello\":42}"); + + EXPECT_TRUE(obj.is(key)); +} + +TEST(UnsignedCharArray, JsonObject_CreateNestedArray) { + unsigned char key[] = "hello"; + + DynamicJsonBuffer jsonBuffer; + JsonObject& obj = jsonBuffer.createObject(); + obj.createNestedArray(key); +} + +TEST(UnsignedCharArray, JsonObject_CreateNestedObject) { + unsigned char key[] = "hello"; + + DynamicJsonBuffer jsonBuffer; + JsonObject& obj = jsonBuffer.createObject(); + obj.createNestedObject(key); +} + +TEST(UnsignedCharArray, JsonArray_Add) { + unsigned char value[] = "world"; + + DynamicJsonBuffer jsonBuffer; + JsonArray& arr = jsonBuffer.createArray(); + arr.add(value); + + EXPECT_STREQ("world", arr[0]); +} + +TEST(UnsignedCharArray, JsonArray_Set) { + unsigned char value[] = "world"; + + DynamicJsonBuffer jsonBuffer; + JsonArray& arr = jsonBuffer.createArray(); + arr.add("hello"); + arr.set(0, value); + + EXPECT_STREQ("world", arr[0]); +} + +TEST(UnsignedCharArray, JsonArraySubscript_Set) { + unsigned char value[] = "world"; + + DynamicJsonBuffer jsonBuffer; + JsonArray& arr = jsonBuffer.createArray(); + arr.add("hello"); + arr[0].set(value); + + EXPECT_STREQ("world", arr[0]); +} + +TEST(UnsignedCharArray, JsonArraySubscript_Assign) { + unsigned char value[] = "world"; + + DynamicJsonBuffer jsonBuffer; + JsonArray& arr = jsonBuffer.createArray(); + arr.add("hello"); + arr[0] = value; + + EXPECT_STREQ("world", arr[0]); +} + +TEST(UnsignedCharArray, JsonBuffer_strdup) { + unsigned char value[] = "world"; + + DynamicJsonBuffer jsonBuffer; + const char* dup = jsonBuffer.strdup(value); + + EXPECT_NE(static_cast(value), static_cast(dup)); + EXPECT_STREQ("world", dup); +}