Skip to content

Commit

Permalink
Fixed deserializer that stopped reading at the first 0xFF (closes #1118)
Browse files Browse the repository at this point in the history
  • Loading branch information
bblanchon committed Oct 29, 2019
1 parent 3a169df commit ef63757
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
-------
Expand Down
14 changes: 14 additions & 0 deletions extras/tests/Helpers/Stream.h
Original file line number Diff line number Diff line change
@@ -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;
};
59 changes: 59 additions & 0 deletions extras/tests/Misc/Readers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Copyright Benoit Blanchon 2014-2019
// MIT License

#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1
#include <ArduinoJson/Deserialization/Reader.hpp>
#include <catch.hpp>

Expand Down Expand Up @@ -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<std::streamsize>(length));
return static_cast<size_t>(_stream.gcount());
}

private:
std::istringstream _stream;
};

TEST_CASE("Reader<Stream>") {
SECTION("read()") {
StreamStub src("\x01\xFF");
Reader<StreamStub> reader(src);

REQUIRE(reader.read() == 0x01);
REQUIRE(reader.read() == 0xFF);
REQUIRE(reader.read() == -1);
}

SECTION("readBytes() all at once") {
StreamStub src("ABC");
Reader<StreamStub> 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<StreamStub> 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');
}
}
11 changes: 6 additions & 5 deletions src/ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,21 @@ namespace ARDUINOJSON_NAMESPACE {
template <typename TSource>
struct Reader<TSource,
typename enable_if<is_base_of<Stream, TSource>::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<unsigned char>(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

0 comments on commit ef63757

Please sign in to comment.