From ef63757b1a7526d1efcc29f3e47d679aa253bc97 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Tue, 29 Oct 2019 14:17:11 +0100 Subject: [PATCH] Fixed deserializer that stopped reading at the first 0xFF (closes #1118) --- CHANGELOG.md | 1 + extras/tests/Helpers/Stream.h | 14 +++++ extras/tests/Misc/Readers.cpp | 59 +++++++++++++++++++ .../Readers/ArduinoStreamReader.hpp | 11 ++-- 4 files changed, 80 insertions(+), 5 deletions(-) create mode 100644 extras/tests/Helpers/Stream.h diff --git a/CHANGELOG.md b/CHANGELOG.md index f47f752f..b3910925 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ HEAD * Fixed `deserializeJson()` when input contains duplicate keys (issue #1095) * Improved `deserializeMsgPack()` speed by reading several bytes at once * Added detection of Atmel AVR8/GNU C Compiler (issue #1112) +* Fixed deserializer that stopped reading at the first `0xFF` (PR #1118 by @mikee47) v6.12.0 (2019-09-05) ------- diff --git a/extras/tests/Helpers/Stream.h b/extras/tests/Helpers/Stream.h new file mode 100644 index 00000000..283c8276 --- /dev/null +++ b/extras/tests/Helpers/Stream.h @@ -0,0 +1,14 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2019 +// MIT License + +#pragma once + +// Reproduces Arduino's Stream class +class Stream // : public Print +{ + public: + virtual ~Stream() {} + virtual int read() = 0; + virtual size_t readBytes(char *buffer, size_t length) = 0; +}; diff --git a/extras/tests/Misc/Readers.cpp b/extras/tests/Misc/Readers.cpp index 6e22d1b1..1fb509a0 100644 --- a/extras/tests/Misc/Readers.cpp +++ b/extras/tests/Misc/Readers.cpp @@ -2,6 +2,7 @@ // Copyright Benoit Blanchon 2014-2019 // MIT License +#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1 #include #include @@ -164,3 +165,61 @@ TEST_CASE("IteratorReader") { REQUIRE(buffer[6] == 'g'); } } + +class StreamStub : public Stream { + public: + StreamStub(const char* s) : _stream(s) {} + + int read() { + return _stream.get(); + } + + size_t readBytes(char* buffer, size_t length) { + _stream.read(buffer, static_cast(length)); + return static_cast(_stream.gcount()); + } + + private: + std::istringstream _stream; +}; + +TEST_CASE("Reader") { + SECTION("read()") { + StreamStub src("\x01\xFF"); + Reader reader(src); + + REQUIRE(reader.read() == 0x01); + REQUIRE(reader.read() == 0xFF); + REQUIRE(reader.read() == -1); + } + + SECTION("readBytes() all at once") { + StreamStub src("ABC"); + Reader reader(src); + + char buffer[8] = "abcd"; + REQUIRE(reader.readBytes(buffer, 4) == 3); + + REQUIRE(buffer[0] == 'A'); + REQUIRE(buffer[1] == 'B'); + REQUIRE(buffer[2] == 'C'); + REQUIRE(buffer[3] == 'd'); + } + + SECTION("readBytes() in two parts") { + StreamStub src("ABCDEF"); + Reader reader(src); + + char buffer[12] = "abcdefg"; + REQUIRE(reader.readBytes(buffer, 4) == 4); + REQUIRE(reader.readBytes(buffer + 4, 4) == 2); + + REQUIRE(buffer[0] == 'A'); + REQUIRE(buffer[1] == 'B'); + REQUIRE(buffer[2] == 'C'); + REQUIRE(buffer[3] == 'D'); + REQUIRE(buffer[4] == 'E'); + REQUIRE(buffer[5] == 'F'); + REQUIRE(buffer[6] == 'g'); + } +} diff --git a/src/ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp b/src/ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp index dac436bf..9a49e18f 100644 --- a/src/ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp +++ b/src/ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp @@ -11,20 +11,21 @@ namespace ARDUINOJSON_NAMESPACE { template struct Reader::value>::type> { - Stream& _stream; - public: - explicit Reader(Stream& stream) : _stream(stream) {} + explicit Reader(Stream& stream) : _stream(&stream) {} int read() { // don't use _stream.read() as it ignores the timeout char c; - return _stream.readBytes(&c, 1) ? c : -1; + return _stream->readBytes(&c, 1) ? static_cast(c) : -1; } size_t readBytes(char* buffer, size_t length) { - return _stream.readBytes(buffer, length); + return _stream->readBytes(buffer, length); } + + private: + Stream* _stream; }; } // namespace ARDUINOJSON_NAMESPACE