Fixed ignored Stream timeout and made sure we don't read more that necessary (issue #422)

This commit is contained in:
Benoit Blanchon
2017-01-22 10:31:05 +01:00
parent fb554071dc
commit cc8c0472ca
10 changed files with 89 additions and 71 deletions

View File

@ -5,6 +5,8 @@ HEAD
---- ----
* Fixed parsing of comments (issue #421) * Fixed parsing of comments (issue #421)
* Fixed ignored `Stream` timeout (issue #422)
* Made sure we don't read more that necessary (issue #422)
v5.8.1 v5.8.1
------ ------

View File

@ -9,7 +9,6 @@
#include "../JsonBuffer.hpp" #include "../JsonBuffer.hpp"
#include "../JsonVariant.hpp" #include "../JsonVariant.hpp"
#include "StringReader.hpp"
#include "StringWriter.hpp" #include "StringWriter.hpp"
namespace ArduinoJson { namespace ArduinoJson {
@ -74,23 +73,23 @@ class JsonParser {
template <typename TJsonBuffer, typename TString> template <typename TJsonBuffer, typename TString>
struct JsonParserBuilder { struct JsonParserBuilder {
typedef typename Internals::StringTraits<TString>::Iterator InputIterator; typedef typename Internals::StringTraits<TString>::Reader InputReader;
typedef JsonParser<StringReader<InputIterator>, TJsonBuffer &> TParser; typedef JsonParser<InputReader, TJsonBuffer &> TParser;
static TParser makeParser(TJsonBuffer *buffer, TString &json, static TParser makeParser(TJsonBuffer *buffer, TString &json,
uint8_t nestingLimit) { uint8_t nestingLimit) {
return TParser(buffer, InputIterator(json), *buffer, nestingLimit); return TParser(buffer, InputReader(json), *buffer, nestingLimit);
} }
}; };
template <typename TJsonBuffer> template <typename TJsonBuffer>
struct JsonParserBuilder<TJsonBuffer, char *> { struct JsonParserBuilder<TJsonBuffer, char *> {
typedef typename Internals::StringTraits<char *>::Iterator InputIterator; typedef typename Internals::StringTraits<char *>::Reader InputReader;
typedef JsonParser<StringReader<InputIterator>, StringWriter> TParser; typedef JsonParser<InputReader, StringWriter> TParser;
static TParser makeParser(TJsonBuffer *buffer, char *json, static TParser makeParser(TJsonBuffer *buffer, char *json,
uint8_t nestingLimit) { uint8_t nestingLimit) {
return TParser(buffer, InputIterator(json), json, nestingLimit); return TParser(buffer, InputReader(json), json, nestingLimit);
} }
}; };

View File

@ -16,7 +16,6 @@ inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::eat(
skipSpacesAndComments(reader); skipSpacesAndComments(reader);
if (reader.current() != charToSkip) return false; if (reader.current() != charToSkip) return false;
reader.move(); reader.move();
skipSpacesAndComments(reader);
return true; return true;
} }
@ -148,6 +147,7 @@ ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseString() {
typename TypeTraits::RemoveReference<TWriter>::type::String str = typename TypeTraits::RemoveReference<TWriter>::type::String str =
_writer.startString(); _writer.startString();
skipSpacesAndComments(_reader);
char c = _reader.current(); char c = _reader.current();
if (isQuote(c)) { // quotes if (isQuote(c)) { // quotes

View File

@ -1,41 +0,0 @@
// 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 Internals {
// Parse JSON string to create JsonArrays and JsonObjects
// This internal class is not indended to be used directly.
// Instead, use JsonBuffer.parseArray() or .parseObject()
template <typename TIterator>
class StringReader {
TIterator _input;
char _current, _next;
public:
StringReader(const TIterator& input) : _input(input) {
_current = _input.next();
_next = _input.next();
}
void move() {
_current = _next;
_next = _input.next();
}
char current() const {
return _current;
}
char next() const {
return _next;
}
};
}
}

View File

@ -17,15 +17,35 @@ namespace ArduinoJson {
namespace Internals { namespace Internals {
struct ArduinoStreamTraits { struct ArduinoStreamTraits {
class Iterator { class Reader {
Stream& _stream; Stream& _stream;
char _current, _next;
public: public:
Iterator(Stream& stream) : _stream(stream) {} Reader(Stream& stream) : _stream(stream), _current(0), _next(0) {}
void move() {
_current = _next;
_next = 0;
}
char current() {
if (!_current) _current = read();
return _current;
}
char next() { char next() {
int n = _stream.read(); // assumes that current() has been called
return n >= 0 ? static_cast<char>(n) : '\0'; if (!_next) _next = read();
return _next;
}
private:
char read() {
// don't use _stream.read() as it ignores the timeout
char c = 0;
_stream.readBytes(&c, 1);
return c;
} }
}; };
}; };

View File

@ -11,16 +11,22 @@ namespace ArduinoJson {
namespace Internals { namespace Internals {
struct CharPointerTraits { struct CharPointerTraits {
class Iterator { class Reader {
const char* _ptr; const char* _ptr;
public: public:
Iterator(const char* ptr) : _ptr(ptr ? ptr : "") {} Reader(const char* ptr) : _ptr(ptr ? ptr : "") {}
char next() { void move() {
char c = *_ptr; ++_ptr;
if (c) ++_ptr; }
return c;
char current() const {
return _ptr[0];
}
char next() const {
return _ptr[1];
} }
}; };

View File

@ -11,15 +11,23 @@ namespace ArduinoJson {
namespace Internals { namespace Internals {
template <> template <>
struct StringTraits<const __FlashStringHelper*, void> { struct StringTraits<const __FlashStringHelper*, void> {
class Iterator { class Reader {
const char* _ptr; const char* _ptr;
public: public:
Iterator(const __FlashStringHelper* ptr) Reader(const __FlashStringHelper* ptr)
: _ptr(reinterpret_cast<const char*>(ptr)) {} : _ptr(reinterpret_cast<const char*>(ptr)) {}
char next() { void move() {
return pgm_read_byte_near(_ptr++); _ptr++;
}
char current() const {
return pgm_read_byte_near(_ptr);
}
char next() const {
return pgm_read_byte_near(_ptr + 1);
} }
}; };

View File

@ -16,18 +16,35 @@ namespace ArduinoJson {
namespace Internals { namespace Internals {
struct StdStreamTraits { struct StdStreamTraits {
class Iterator { class Reader {
std::istream& _stream; std::istream& _stream;
char _current, _next;
public: public:
Iterator(std::istream& stream) : _stream(stream) {} Reader(std::istream& stream) : _stream(stream), _current(0), _next(0) {}
void move() {
_current = _next;
_next = 0;
}
char current() {
if (!_current) _current = read();
return _current;
}
char next() { char next() {
return _stream.eof() ? '\0' : static_cast<char>(_stream.get()); // assumes that current() has been called
if (!_next) _next = read();
return _next;
} }
private: private:
Iterator& operator=(const Iterator&); // Visual Studio C4512 Reader& operator=(const Reader&); // Visual Studio C4512
char read() {
return _stream.eof() ? '\0' : static_cast<char>(_stream.get());
}
}; };
}; };

View File

@ -29,8 +29,8 @@ struct StdStringTraits {
return static_cast<char*>(dup); return static_cast<char*>(dup);
} }
struct Iterator : CharPointerTraits::Iterator { struct Reader : CharPointerTraits::Reader {
Iterator(const TString& str) : CharPointerTraits::Iterator(str.c_str()) {} Reader(const TString& str) : CharPointerTraits::Reader(str.c_str()) {}
}; };
static bool equals(const TString& str, const char* expected) { static bool equals(const TString& str, const char* expected) {

View File

@ -60,7 +60,7 @@ TEST(StdStream_Tests, JsonArraySubscript) {
} }
TEST(StdStream_Tests, ParseArray) { TEST(StdStream_Tests, ParseArray) {
std::istringstream json("[42]"); std::istringstream json(" [ 42 /* comment */ ] ");
DynamicJsonBuffer jsonBuffer; DynamicJsonBuffer jsonBuffer;
JsonArray& arr = jsonBuffer.parseArray(json); JsonArray& arr = jsonBuffer.parseArray(json);
ASSERT_TRUE(arr.success()); ASSERT_TRUE(arr.success());
@ -69,10 +69,17 @@ TEST(StdStream_Tests, ParseArray) {
} }
TEST(StdStream_Tests, ParseObject) { TEST(StdStream_Tests, ParseObject) {
std::istringstream json("{hello:world}"); std::istringstream json(" { hello : world // comment\n }");
DynamicJsonBuffer jsonBuffer; DynamicJsonBuffer jsonBuffer;
JsonObject& obj = jsonBuffer.parseObject(json); JsonObject& obj = jsonBuffer.parseObject(json);
ASSERT_TRUE(obj.success()); ASSERT_TRUE(obj.success());
ASSERT_EQ(1, obj.size()); ASSERT_EQ(1, obj.size());
ASSERT_STREQ("world", obj["hello"]); ASSERT_STREQ("world", obj["hello"]);
} }
TEST(StdStream_Tests, ShouldNotReadPastTheEnd) {
std::istringstream json("{}123");
DynamicJsonBuffer jsonBuffer;
jsonBuffer.parseObject(json);
ASSERT_EQ('1', json.get());
}