forked from bblanchon/ArduinoJson
Fixed ignored Stream
timeout and made sure we don't read more that necessary (issue #422)
This commit is contained in:
@ -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
|
||||||
------
|
------
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -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];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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());
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user