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

This commit is contained in:
Benoit Blanchon
2017-01-22 15:42:47 +01:00
parent a096098c1f
commit d4f725d1fa
10 changed files with 394 additions and 31 deletions

View File

@ -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
------

View File

@ -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;
}
};
}
}

View File

@ -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);
}
};

View File

@ -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;
};
}
}

View File

@ -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

View File

@ -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> {};
}
}

View File

@ -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) {

View File

@ -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> {};
}
}

View File

@ -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
test/UnsignedChar_Tests.cpp Normal file
View File

@ -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);
}