forked from bblanchon/ArduinoJson
serializeMsgPack(doc, p, n) doesn't add terminator anymore (fixes #1545)
This commit is contained in:
@ -16,6 +16,8 @@ HEAD
|
|||||||
* Simplified `JsonVariant::as<T>()` to always return `T` (see below)
|
* Simplified `JsonVariant::as<T>()` to always return `T` (see below)
|
||||||
* Updated folders list in `.mbedignore` (PR #1515 by @AGlass0fMilk)
|
* Updated folders list in `.mbedignore` (PR #1515 by @AGlass0fMilk)
|
||||||
* Fixed member-call-on-null-pointer in `getMember()` when array is empty
|
* Fixed member-call-on-null-pointer in `getMember()` when array is empty
|
||||||
|
* `serializeMsgPack(doc, buffer, size)` doesn't add null-terminator anymore (issue #1545)
|
||||||
|
* `serializeJson(doc, buffer, size)` adds null-terminator only if there is enough room
|
||||||
|
|
||||||
> ### BREAKING CHANGES
|
> ### BREAKING CHANGES
|
||||||
>
|
>
|
||||||
|
@ -8,12 +8,15 @@
|
|||||||
|
|
||||||
static void checkObject(const JsonObject obj, const std::string &expected) {
|
static void checkObject(const JsonObject obj, const std::string &expected) {
|
||||||
char actual[256];
|
char actual[256];
|
||||||
|
memset(actual, '!', sizeof(actual));
|
||||||
|
|
||||||
size_t actualLen = serializeJson(obj, actual);
|
size_t actualLen = serializeJson(obj, actual);
|
||||||
size_t measuredLen = measureJson(obj);
|
size_t measuredLen = measureJson(obj);
|
||||||
|
|
||||||
REQUIRE(expected == actual);
|
|
||||||
REQUIRE(expected.size() == actualLen);
|
|
||||||
REQUIRE(expected.size() == measuredLen);
|
REQUIRE(expected.size() == measuredLen);
|
||||||
|
REQUIRE(expected.size() == actualLen);
|
||||||
|
REQUIRE(actual[actualLen] == 0); // serializeJson() adds a null terminator
|
||||||
|
REQUIRE(expected == actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("serializeJson(JsonObject)") {
|
TEST_CASE("serializeJson(JsonObject)") {
|
||||||
|
@ -39,15 +39,15 @@ void common_tests(StringWriter& sb, const String& output) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("StaticStringWriter") {
|
TEST_CASE("StaticStringWriter") {
|
||||||
char output[20];
|
char output[20] = {0};
|
||||||
StaticStringWriter sb(output, sizeof(output));
|
StaticStringWriter sb(output, sizeof(output));
|
||||||
|
|
||||||
common_tests(sb, static_cast<const char*>(output));
|
common_tests(sb, static_cast<const char*>(output));
|
||||||
|
|
||||||
SECTION("OverCapacity") {
|
SECTION("OverCapacity") {
|
||||||
REQUIRE(19 == print(sb, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
|
REQUIRE(20 == print(sb, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
|
||||||
REQUIRE(0 == print(sb, "ABC"));
|
REQUIRE(0 == print(sb, "ABC"));
|
||||||
REQUIRE(std::string("ABCDEFGHIJKLMNOPQRS") == output);
|
REQUIRE("ABCDEFGHIJKLMNOPQRST" == std::string(output, 20));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,19 +29,31 @@ TEST_CASE("serialize MsgPack to various destination types") {
|
|||||||
REQUIRE(expected_length == len);
|
REQUIRE(expected_length == len);
|
||||||
} */
|
} */
|
||||||
|
|
||||||
SECTION("char[]") {
|
SECTION("char[] larger than needed") {
|
||||||
char result[64];
|
char result[64];
|
||||||
|
memset(result, 42, sizeof(result));
|
||||||
size_t len = serializeMsgPack(object, result);
|
size_t len = serializeMsgPack(object, result);
|
||||||
|
|
||||||
REQUIRE(std::string(expected_result) == result);
|
|
||||||
REQUIRE(expected_length == len);
|
REQUIRE(expected_length == len);
|
||||||
|
REQUIRE(std::string(expected_result, len) == std::string(result, len));
|
||||||
|
REQUIRE(result[len] == 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("char[] of the right size") { // #1545
|
||||||
|
char result[13];
|
||||||
|
size_t len = serializeMsgPack(object, result);
|
||||||
|
|
||||||
|
REQUIRE(expected_length == len);
|
||||||
|
REQUIRE(std::string(expected_result, len) == std::string(result, len));
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("char*") {
|
SECTION("char*") {
|
||||||
char result[64];
|
char result[64];
|
||||||
|
memset(result, 42, sizeof(result));
|
||||||
size_t len = serializeMsgPack(object, result, 64);
|
size_t len = serializeMsgPack(object, result, 64);
|
||||||
|
|
||||||
REQUIRE(std::string(expected_result) == result);
|
|
||||||
REQUIRE(expected_length == len);
|
REQUIRE(expected_length == len);
|
||||||
|
REQUIRE(std::string(expected_result, len) == std::string(result, len));
|
||||||
|
REQUIRE(result[len] == 42);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ using namespace ARDUINOJSON_NAMESPACE;
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void checkWriteInteger(T value, std::string expected) {
|
void checkWriteInteger(T value, std::string expected) {
|
||||||
char output[1024];
|
char output[64] = {0};
|
||||||
StaticStringWriter sb(output, sizeof(output));
|
StaticStringWriter sb(output, sizeof(output));
|
||||||
TextFormatter<StaticStringWriter> writer(sb);
|
TextFormatter<StaticStringWriter> writer(sb);
|
||||||
writer.writeInteger<T>(value);
|
writer.writeInteger<T>(value);
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
using namespace ARDUINOJSON_NAMESPACE;
|
using namespace ARDUINOJSON_NAMESPACE;
|
||||||
|
|
||||||
void check(const char* input, std::string expected) {
|
void check(const char* input, std::string expected) {
|
||||||
char output[1024];
|
char output[64] = {0};
|
||||||
StaticStringWriter sb(output, sizeof(output));
|
StaticStringWriter sb(output, sizeof(output));
|
||||||
TextFormatter<StaticStringWriter> writer(sb);
|
TextFormatter<StaticStringWriter> writer(sb);
|
||||||
writer.writeString(input);
|
writer.writeString(input);
|
||||||
|
@ -14,6 +14,8 @@ namespace ARDUINOJSON_NAMESPACE {
|
|||||||
template <typename TWriter>
|
template <typename TWriter>
|
||||||
class JsonSerializer : public Visitor<size_t> {
|
class JsonSerializer : public Visitor<size_t> {
|
||||||
public:
|
public:
|
||||||
|
static const bool producesText = true;
|
||||||
|
|
||||||
JsonSerializer(TWriter writer) : _formatter(writer) {}
|
JsonSerializer(TWriter writer) : _formatter(writer) {}
|
||||||
|
|
||||||
FORCE_INLINE size_t visitArray(const CollectionData &array) {
|
FORCE_INLINE size_t visitArray(const CollectionData &array) {
|
||||||
|
@ -16,7 +16,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
|||||||
typedef JsonSerializer<TWriter> base;
|
typedef JsonSerializer<TWriter> base;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PrettyJsonSerializer(TWriter &writer) : base(writer), _nesting(0) {}
|
PrettyJsonSerializer(TWriter writer) : base(writer), _nesting(0) {}
|
||||||
|
|
||||||
size_t visitArray(const CollectionData &array) {
|
size_t visitArray(const CollectionData &array) {
|
||||||
VariantSlot *slot = array.head();
|
VariantSlot *slot = array.head();
|
||||||
|
@ -17,6 +17,8 @@ namespace ARDUINOJSON_NAMESPACE {
|
|||||||
template <typename TWriter>
|
template <typename TWriter>
|
||||||
class MsgPackSerializer : public Visitor<size_t> {
|
class MsgPackSerializer : public Visitor<size_t> {
|
||||||
public:
|
public:
|
||||||
|
static const bool producesText = false;
|
||||||
|
|
||||||
MsgPackSerializer(TWriter writer) : _writer(writer) {}
|
MsgPackSerializer(TWriter writer) : _writer(writer) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -8,18 +8,14 @@
|
|||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
// A Print implementation that allows to write in a char[]
|
|
||||||
class StaticStringWriter {
|
class StaticStringWriter {
|
||||||
public:
|
public:
|
||||||
StaticStringWriter(char *buf, size_t size) : end(buf + size - 1), p(buf) {
|
StaticStringWriter(char *buf, size_t size) : end(buf + size), p(buf) {}
|
||||||
*p = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t write(uint8_t c) {
|
size_t write(uint8_t c) {
|
||||||
if (p >= end)
|
if (p >= end)
|
||||||
return 0;
|
return 0;
|
||||||
*p++ = static_cast<char>(c);
|
*p++ = static_cast<char>(c);
|
||||||
*p = '\0';
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +25,6 @@ class StaticStringWriter {
|
|||||||
*p++ = static_cast<char>(*s++);
|
*p++ = static_cast<char>(*s++);
|
||||||
n--;
|
n--;
|
||||||
}
|
}
|
||||||
*p = '\0';
|
|
||||||
return size_t(p - begin);
|
return size_t(p - begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,11 +23,23 @@ size_t serialize(const TSource &source, TDestination &destination) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <template <typename> class TSerializer, typename TSource>
|
template <template <typename> class TSerializer, typename TSource>
|
||||||
size_t serialize(const TSource &source, void *buffer, size_t bufferSize) {
|
typename enable_if<!TSerializer<StaticStringWriter>::producesText, size_t>::type
|
||||||
|
serialize(const TSource &source, void *buffer, size_t bufferSize) {
|
||||||
StaticStringWriter writer(reinterpret_cast<char *>(buffer), bufferSize);
|
StaticStringWriter writer(reinterpret_cast<char *>(buffer), bufferSize);
|
||||||
return doSerialize<TSerializer>(source, writer);
|
return doSerialize<TSerializer>(source, writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <template <typename> class TSerializer, typename TSource>
|
||||||
|
typename enable_if<TSerializer<StaticStringWriter>::producesText, size_t>::type
|
||||||
|
serialize(const TSource &source, void *buffer, size_t bufferSize) {
|
||||||
|
StaticStringWriter writer(reinterpret_cast<char *>(buffer), bufferSize);
|
||||||
|
size_t n = doSerialize<TSerializer>(source, writer);
|
||||||
|
// add null-terminator for text output (not counted in the size)
|
||||||
|
if (n < bufferSize)
|
||||||
|
reinterpret_cast<char *>(buffer)[n] = 0;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
template <template <typename> class TSerializer, typename TSource,
|
template <template <typename> class TSerializer, typename TSource,
|
||||||
typename TChar, size_t N>
|
typename TChar, size_t N>
|
||||||
#if defined _MSC_VER && _MSC_VER < 1900
|
#if defined _MSC_VER && _MSC_VER < 1900
|
||||||
@ -36,8 +48,7 @@ typename enable_if<sizeof(remove_reference<TChar>::type) == 1, size_t>::type
|
|||||||
typename enable_if<sizeof(TChar) == 1, size_t>::type
|
typename enable_if<sizeof(TChar) == 1, size_t>::type
|
||||||
#endif
|
#endif
|
||||||
serialize(const TSource &source, TChar (&buffer)[N]) {
|
serialize(const TSource &source, TChar (&buffer)[N]) {
|
||||||
StaticStringWriter writer(reinterpret_cast<char *>(buffer), N);
|
return serialize<TSerializer>(source, buffer, N);
|
||||||
return doSerialize<TSerializer>(source, writer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
Reference in New Issue
Block a user