Ver Fonte

serializeMsgPack(doc, p, n) doesn't add terminator anymore (fixes #1545)

Benoit Blanchon há 4 anos atrás
pai
commit
2be528a3fa

+ 2 - 0
CHANGELOG.md

@@ -16,6 +16,8 @@ HEAD
 * Simplified `JsonVariant::as<T>()` to always return `T` (see below)
 * Updated folders list in `.mbedignore` (PR #1515 by @AGlass0fMilk)
 * 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
 >

+ 5 - 2
extras/tests/JsonSerializer/JsonObject.cpp

@@ -8,12 +8,15 @@
 
 static void checkObject(const JsonObject obj, const std::string &expected) {
   char actual[256];
+  memset(actual, '!', sizeof(actual));
+
   size_t actualLen = serializeJson(obj, actual);
   size_t measuredLen = measureJson(obj);
 
-  REQUIRE(expected == actual);
-  REQUIRE(expected.size() == actualLen);
   REQUIRE(expected.size() == measuredLen);
+  REQUIRE(expected.size() == actualLen);
+  REQUIRE(actual[actualLen] == 0);  // serializeJson() adds a null terminator
+  REQUIRE(expected == actual);
 }
 
 TEST_CASE("serializeJson(JsonObject)") {

+ 3 - 3
extras/tests/Misc/StringWriter.cpp

@@ -39,15 +39,15 @@ void common_tests(StringWriter& sb, const String& output) {
 }
 
 TEST_CASE("StaticStringWriter") {
-  char output[20];
+  char output[20] = {0};
   StaticStringWriter sb(output, sizeof(output));
 
   common_tests(sb, static_cast<const char*>(output));
 
   SECTION("OverCapacity") {
-    REQUIRE(19 == print(sb, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
+    REQUIRE(20 == print(sb, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
     REQUIRE(0 == print(sb, "ABC"));
-    REQUIRE(std::string("ABCDEFGHIJKLMNOPQRS") == output);
+    REQUIRE("ABCDEFGHIJKLMNOPQRST" == std::string(output, 20));
   }
 }
 

+ 15 - 3
extras/tests/MsgPackSerializer/destination_types.cpp

@@ -29,19 +29,31 @@ TEST_CASE("serialize MsgPack to various destination types") {
     REQUIRE(expected_length == len);
     } */
 
-  SECTION("char[]") {
+  SECTION("char[] larger than needed") {
     char result[64];
+    memset(result, 42, sizeof(result));
     size_t len = serializeMsgPack(object, result);
 
-    REQUIRE(std::string(expected_result) == result);
     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*") {
     char result[64];
+    memset(result, 42, sizeof(result));
     size_t len = serializeMsgPack(object, result, 64);
 
-    REQUIRE(std::string(expected_result) == result);
     REQUIRE(expected_length == len);
+    REQUIRE(std::string(expected_result, len) == std::string(result, len));
+    REQUIRE(result[len] == 42);
   }
 }

+ 1 - 1
extras/tests/TextFormatter/writeInteger.cpp

@@ -13,7 +13,7 @@ using namespace ARDUINOJSON_NAMESPACE;
 
 template <typename T>
 void checkWriteInteger(T value, std::string expected) {
-  char output[1024];
+  char output[64] = {0};
   StaticStringWriter sb(output, sizeof(output));
   TextFormatter<StaticStringWriter> writer(sb);
   writer.writeInteger<T>(value);

+ 1 - 1
extras/tests/TextFormatter/writeString.cpp

@@ -10,7 +10,7 @@
 using namespace ARDUINOJSON_NAMESPACE;
 
 void check(const char* input, std::string expected) {
-  char output[1024];
+  char output[64] = {0};
   StaticStringWriter sb(output, sizeof(output));
   TextFormatter<StaticStringWriter> writer(sb);
   writer.writeString(input);

+ 2 - 0
src/ArduinoJson/Json/JsonSerializer.hpp

@@ -14,6 +14,8 @@ namespace ARDUINOJSON_NAMESPACE {
 template <typename TWriter>
 class JsonSerializer : public Visitor<size_t> {
  public:
+  static const bool producesText = true;
+
   JsonSerializer(TWriter writer) : _formatter(writer) {}
 
   FORCE_INLINE size_t visitArray(const CollectionData &array) {

+ 1 - 1
src/ArduinoJson/Json/PrettyJsonSerializer.hpp

@@ -16,7 +16,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
   typedef JsonSerializer<TWriter> base;
 
  public:
-  PrettyJsonSerializer(TWriter &writer) : base(writer), _nesting(0) {}
+  PrettyJsonSerializer(TWriter writer) : base(writer), _nesting(0) {}
 
   size_t visitArray(const CollectionData &array) {
     VariantSlot *slot = array.head();

+ 2 - 0
src/ArduinoJson/MsgPack/MsgPackSerializer.hpp

@@ -17,6 +17,8 @@ namespace ARDUINOJSON_NAMESPACE {
 template <typename TWriter>
 class MsgPackSerializer : public Visitor<size_t> {
  public:
+  static const bool producesText = false;
+
   MsgPackSerializer(TWriter writer) : _writer(writer) {}
 
   template <typename T>

+ 1 - 6
src/ArduinoJson/Serialization/Writers/StaticStringWriter.hpp

@@ -8,18 +8,14 @@
 
 namespace ARDUINOJSON_NAMESPACE {
 
-// A Print implementation that allows to write in a char[]
 class StaticStringWriter {
  public:
-  StaticStringWriter(char *buf, size_t size) : end(buf + size - 1), p(buf) {
-    *p = '\0';
-  }
+  StaticStringWriter(char *buf, size_t size) : end(buf + size), p(buf) {}
 
   size_t write(uint8_t c) {
     if (p >= end)
       return 0;
     *p++ = static_cast<char>(c);
-    *p = '\0';
     return 1;
   }
 
@@ -29,7 +25,6 @@ class StaticStringWriter {
       *p++ = static_cast<char>(*s++);
       n--;
     }
-    *p = '\0';
     return size_t(p - begin);
   }
 

+ 14 - 3
src/ArduinoJson/Serialization/serialize.hpp

@@ -23,11 +23,23 @@ size_t serialize(const TSource &source, TDestination &destination) {
 }
 
 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);
   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,
           typename TChar, size_t N>
 #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
 #endif
 serialize(const TSource &source, TChar (&buffer)[N]) {
-  StaticStringWriter writer(reinterpret_cast<char *>(buffer), N);
-  return doSerialize<TSerializer>(source, writer);
+  return serialize<TSerializer>(source, buffer, N);
 }
 
 }  // namespace ARDUINOJSON_NAMESPACE