diff --git a/extras/tests/JsonDeserializer/filter.cpp b/extras/tests/JsonDeserializer/filter.cpp index fc5ab699..ed85838c 100644 --- a/extras/tests/JsonDeserializer/filter.cpp +++ b/extras/tests/JsonDeserializer/filter.cpp @@ -445,6 +445,15 @@ TEST_CASE("Filtering") { "[]", JSON_ARRAY_SIZE(0) }, + { + // supports back-slash at the end of skipped string + "\"hell\\", + "false", + 1, + DeserializationError::IncompleteInput, + "null", + 0 + }, }; // clang-format on for (size_t i = 0; i < sizeof(testCases) / sizeof(testCases[0]); i++) { diff --git a/src/ArduinoJson/Json/JsonDeserializer.hpp b/src/ArduinoJson/Json/JsonDeserializer.hpp index f187add0..9c363d77 100644 --- a/src/ArduinoJson/Json/JsonDeserializer.hpp +++ b/src/ArduinoJson/Json/JsonDeserializer.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -24,20 +25,15 @@ class JsonDeserializer { JsonDeserializer(MemoryPool &pool, TReader reader, TStringStorage stringStorage, uint8_t nestingLimit) : _pool(&pool), - _reader(reader), _stringStorage(stringStorage), _nestingLimit(nestingLimit), - _loaded(false) { -#ifdef ARDUINOJSON_DEBUG - _ended = false; -#endif - } + _latch(reader) {} template DeserializationError parse(VariantData &variant, TFilter filter) { DeserializationError err = parseVariant(variant, filter); - if (!err && _current != 0 && !variant.isEnclosed()) { + if (!err && _latch.last() != 0 && !variant.isEnclosed()) { // We don't detect trailing characters earlier, so we need to check now err = DeserializationError::InvalidInput; } @@ -49,23 +45,14 @@ class JsonDeserializer { JsonDeserializer &operator=(const JsonDeserializer &); // non-copiable char current() { - if (!_loaded) { - ARDUINOJSON_ASSERT(!_ended); - int c = _reader.read(); -#ifdef ARDUINOJSON_DEBUG - if (c <= 0) _ended = true; -#endif - _current = static_cast(c > 0 ? c : 0); - _loaded = true; - } - return _current; + return _latch.current(); } void move() { - _loaded = false; + _latch.clear(); } - FORCE_INLINE bool eat(char charToSkip) { + bool eat(char charToSkip) { if (current() != charToSkip) return false; move(); return true; @@ -391,7 +378,9 @@ class JsonDeserializer { move(); if (c == stopChar) break; if (c == '\0') return DeserializationError::IncompleteInput; - if (c == '\\') _reader.read(); + if (c == '\\') { + if (current() != '\0') move(); + } } return DeserializationError::Ok; @@ -548,14 +537,9 @@ class JsonDeserializer { } MemoryPool *_pool; - TReader _reader; TStringStorage _stringStorage; uint8_t _nestingLimit; - char _current; - bool _loaded; -#ifdef ARDUINOJSON_DEBUG - bool _ended; -#endif + Latch _latch; }; // deserializeJson(JsonDocument&, const std::string&, ...) diff --git a/src/ArduinoJson/Json/Latch.hpp b/src/ArduinoJson/Json/Latch.hpp new file mode 100644 index 00000000..0fe5f5ec --- /dev/null +++ b/src/ArduinoJson/Json/Latch.hpp @@ -0,0 +1,54 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include + +namespace ARDUINOJSON_NAMESPACE { + +template +class Latch { + public: + Latch(TReader reader) : _reader(reader), _loaded(false) { +#ifdef ARDUINOJSON_DEBUG + _ended = false; +#endif + } + + void clear() { + _loaded = false; + } + + int last() const { + return _current; + } + + FORCE_INLINE char current() { + if (!_loaded) { + load(); + } + return _current; + } + + private: + void load() { + ARDUINOJSON_ASSERT(!_ended); + int c = _reader.read(); +#ifdef ARDUINOJSON_DEBUG + if (c <= 0) _ended = true; +#endif + _current = static_cast(c > 0 ? c : 0); + _loaded = true; + } + + TReader _reader; + char _current; + bool _loaded; +#ifdef ARDUINOJSON_DEBUG + bool _ended; +#endif +}; + +} // namespace ARDUINOJSON_NAMESPACE