Просмотр исходного кода

Fixed error with string of type `unsigned char*` (issue #428)

Benoit Blanchon 9 лет назад
Родитель
Сommit
d4f725d1fa

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

+ 12 - 0
include/ArduinoJson/Data/ValueSetter.hpp

@@ -37,5 +37,17 @@ struct ValueSetter<TSource, typename TypeTraits::EnableIf<StringTraits<
     return true;
   }
 };
+
+template <typename TSource>
+struct ValueSetter<TSource, typename TypeTraits::EnableIf<!StringTraits<
+                                TSource>::should_duplicate>::type> {
+  template <typename TDestination>
+  static bool set(JsonBuffer*, TDestination& destination,
+                  const TSource& source) {
+    // unsigned char* -> char*
+    destination = reinterpret_cast<const char*>(source);
+    return true;
+  }
+};
 }
 }

+ 11 - 7
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 <typename TJsonBuffer, typename TString>
+template <typename TJsonBuffer, typename TString, typename Enable = void>
 struct JsonParserBuilder {
   typedef typename Internals::StringTraits<TString>::Reader InputReader;
   typedef JsonParser<InputReader, TJsonBuffer &> TParser;
@@ -82,14 +83,17 @@ struct JsonParserBuilder {
   }
 };
 
-template <typename TJsonBuffer>
-struct JsonParserBuilder<TJsonBuffer, char *> {
-  typedef typename Internals::StringTraits<char *>::Reader InputReader;
-  typedef JsonParser<InputReader, StringWriter> TParser;
+template <typename TJsonBuffer, typename TChar>
+struct JsonParserBuilder<
+    TJsonBuffer, TChar *,
+    typename TypeTraits::EnableIf<!TypeTraits::IsConst<TChar>::value>::type> {
+  typedef typename Internals::StringTraits<TChar *>::Reader TReader;
+  typedef StringWriter<TChar> TWriter;
+  typedef JsonParser<TReader, TWriter> 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);
   }
 };
 

+ 8 - 7
include/ArduinoJson/Deserialization/StringWriter.hpp

@@ -10,34 +10,35 @@
 namespace ArduinoJson {
 namespace Internals {
 
+template <typename TChar>
 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<const char*>(_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;
 };
 }
 }

+ 10 - 2
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<JsonVariant> {
   }
 
   // Create a JsonVariant containing a string.
-  JsonVariant(const char *value) {
+  // JsonVariant(const char*);
+  // JsonVariant(const signed char*);
+  // JsonVariant(const unsigned char*);
+  template <typename TChar>
+  JsonVariant(
+      const TChar *value,
+      typename TypeTraits::EnableIf<TypeTraits::IsChar<TChar>::value>::type * =
+          0) {
     _type = Internals::JSON_STRING;
-    _content.asString = value;
+    _content.asString = reinterpret_cast<const char *>(value);
   }
 
   // Create a JsonVariant containing an unparsed string

+ 17 - 13
include/ArduinoJson/StringTraits/CharPointer.hpp

@@ -7,37 +7,42 @@
 
 #pragma once
 
+#include "../TypeTraits/EnableIf.hpp"
+#include "../TypeTraits/IsChar.hpp"
+
 namespace ArduinoJson {
 namespace Internals {
 
+template <typename TChar>
 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<const TChar*>("")) {}
 
     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<const char*>(str), expected) == 0;
   }
 
   template <typename Buffer>
-  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<const char*>(str)) + 1;
     void* dup = buffer->alloc(size);
     if (dup != NULL) memcpy(dup, str, size);
     return static_cast<char*>(dup);
@@ -48,10 +53,9 @@ struct CharPointerTraits {
   static const bool should_duplicate = false;
 };
 
-template <>
-struct StringTraits<const char*, void> : CharPointerTraits {};
-
-template <>
-struct StringTraits<char*, void> : CharPointerTraits {};
+template <typename TChar>
+struct StringTraits<TChar*, typename TypeTraits::EnableIf<
+                                TypeTraits::IsChar<TChar>::value>::type>
+    : CharPointerTraits<TChar> {};
 }
 }

+ 2 - 2
include/ArduinoJson/StringTraits/StdString.hpp

@@ -29,8 +29,8 @@ struct StdStringTraits {
     return static_cast<char*>(dup);
   }
 
-  struct Reader : CharPointerTraits::Reader {
-    Reader(const TString& str) : CharPointerTraits::Reader(str.c_str()) {}
+  struct Reader : CharPointerTraits<char>::Reader {
+    Reader(const TString& str) : CharPointerTraits<char>::Reader(str.c_str()) {}
   };
 
   static bool equals(const TString& str, const char* expected) {

+ 26 - 0
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 <typename T>
+struct IsChar {
+  static const bool value = IsSame<T, char>::value ||
+                            IsSame<T, signed char>::value ||
+                            IsSame<T, unsigned char>::value;
+};
+
+template <typename T>
+struct IsChar<const T> : IsChar<T> {};
+}
+}

+ 24 - 0
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 <typename T>
+struct IsConst {
+  static const bool value = false;
+};
+
+template <typename T>
+struct IsConst<const T> {
+  static const bool value = true;
+};
+}
+}

+ 283 - 0
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 <ArduinoJson.h>
+#include <gtest/gtest.h>
+
+#if defined(__clang__)
+#define CONFLICTS_WITH_BUILTIN_OPERATOR
+#endif
+
+TEST(UnsignedCharArray, ParseArray) {
+  unsigned char json[] = "[42]";
+
+  StaticJsonBuffer<JSON_ARRAY_SIZE(1)> jsonBuffer;
+  JsonArray& arr = jsonBuffer.parseArray(json);
+
+  EXPECT_TRUE(arr.success());
+}
+
+TEST(UnsignedCharArray, ParseObject) {
+  unsigned char json[] = "{\"a\":42}";
+
+  StaticJsonBuffer<JSON_OBJECT_SIZE(1)> 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<int>());
+}
+
+TEST(UnsignedCharArray, JsonVariant_Assign) {
+  unsigned char value[] = "42";
+
+  JsonVariant variant(666);
+  variant = value;
+
+  EXPECT_EQ(42, variant.as<int>());
+}
+
+#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<char*>(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<int>(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<const void*>(value), static_cast<const void*>(dup));
+  EXPECT_STREQ("world", dup);
+}