mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	Made deserializeJson() more picky about trailing characters (closes #980)
				
					
				
			This commit is contained in:
		| @@ -6,6 +6,7 @@ HEAD | |||||||
|  |  | ||||||
| * Fixed `deserializeJson()` silently accepting a `Stream*` (issue #978) | * Fixed `deserializeJson()` silently accepting a `Stream*` (issue #978) | ||||||
| * Fixed invalid result from `operator|` (issue #981) | * Fixed invalid result from `operator|` (issue #981) | ||||||
|  | * Made `deserializeJson()` more picky about trailing characters (issue #980) | ||||||
|  |  | ||||||
| > ### BREAKING CHANGE | > ### BREAKING CHANGE | ||||||
| >  | >  | ||||||
|   | |||||||
| @@ -12,22 +12,14 @@ namespace ARDUINOJSON_NAMESPACE { | |||||||
|  |  | ||||||
| struct ArduinoStreamReader { | struct ArduinoStreamReader { | ||||||
|   Stream& _stream; |   Stream& _stream; | ||||||
|   char _current; |  | ||||||
|   bool _ended; |  | ||||||
|  |  | ||||||
|  public: |  public: | ||||||
|   explicit ArduinoStreamReader(Stream& stream) |   explicit ArduinoStreamReader(Stream& stream) : _stream(stream) {} | ||||||
|       : _stream(stream), _current(0), _ended(false) {} |  | ||||||
|  |  | ||||||
|   char read() { |   int read() { | ||||||
|     // don't use _stream.read() as it ignores the timeout |     // don't use _stream.read() as it ignores the timeout | ||||||
|     char c = 0; |     uint8_t c; | ||||||
|     _ended = _stream.readBytes(&c, 1) == 0; |     return _stream.readBytes(&c, 1) ? c : -1; | ||||||
|     return c; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   bool ended() const { |  | ||||||
|     return _ended; |  | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -23,13 +23,8 @@ class UnsafeCharPointerReader { | |||||||
|   explicit UnsafeCharPointerReader(const char* ptr) |   explicit UnsafeCharPointerReader(const char* ptr) | ||||||
|       : _ptr(ptr ? ptr : reinterpret_cast<const char*>("")) {} |       : _ptr(ptr ? ptr : reinterpret_cast<const char*>("")) {} | ||||||
|  |  | ||||||
|   char read() { |   int read() { | ||||||
|     return static_cast<char>(*_ptr++); |     return static_cast<unsigned char>(*_ptr++); | ||||||
|   } |  | ||||||
|  |  | ||||||
|   bool ended() const { |  | ||||||
|     // we cannot know, that's why it's unsafe |  | ||||||
|     return false; |  | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -41,12 +36,11 @@ class SafeCharPointerReader { | |||||||
|   explicit SafeCharPointerReader(const char* ptr, size_t len) |   explicit SafeCharPointerReader(const char* ptr, size_t len) | ||||||
|       : _ptr(ptr ? ptr : reinterpret_cast<const char*>("")), _end(_ptr + len) {} |       : _ptr(ptr ? ptr : reinterpret_cast<const char*>("")), _end(_ptr + len) {} | ||||||
|  |  | ||||||
|   char read() { |   int read() { | ||||||
|     return static_cast<char>(*_ptr++); |     if (_ptr < _end) | ||||||
|   } |       return static_cast<unsigned char>(*_ptr++); | ||||||
|  |     else | ||||||
|   bool ended() const { |       return -1; | ||||||
|     return _ptr == _end; |  | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -14,14 +14,9 @@ class UnsafeFlashStringReader { | |||||||
|   explicit UnsafeFlashStringReader(const __FlashStringHelper* ptr) |   explicit UnsafeFlashStringReader(const __FlashStringHelper* ptr) | ||||||
|       : _ptr(reinterpret_cast<const char*>(ptr)) {} |       : _ptr(reinterpret_cast<const char*>(ptr)) {} | ||||||
|  |  | ||||||
|   char read() { |   int read() { | ||||||
|     return pgm_read_byte_near(_ptr++); |     return pgm_read_byte_near(_ptr++); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   bool ended() const { |  | ||||||
|     // this reader cannot detect the end |  | ||||||
|     return false; |  | ||||||
|   } |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class SafeFlashStringReader { | class SafeFlashStringReader { | ||||||
| @@ -32,12 +27,11 @@ class SafeFlashStringReader { | |||||||
|   explicit SafeFlashStringReader(const __FlashStringHelper* ptr, size_t size) |   explicit SafeFlashStringReader(const __FlashStringHelper* ptr, size_t size) | ||||||
|       : _ptr(reinterpret_cast<const char*>(ptr)), _end(_ptr + size) {} |       : _ptr(reinterpret_cast<const char*>(ptr)), _end(_ptr + size) {} | ||||||
|  |  | ||||||
|   char read() { |   int read() { | ||||||
|     return pgm_read_byte_near(_ptr++); |     if (_ptr < _end) | ||||||
|   } |       return pgm_read_byte_near(_ptr++); | ||||||
|  |     else | ||||||
|   bool ended() const { |       return -1; | ||||||
|     return _ptr == _end; |  | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -14,12 +14,11 @@ class IteratorReader { | |||||||
|   explicit IteratorReader(TIterator begin, TIterator end) |   explicit IteratorReader(TIterator begin, TIterator end) | ||||||
|       : _ptr(begin), _end(end) {} |       : _ptr(begin), _end(end) {} | ||||||
|  |  | ||||||
|   bool ended() const { |   int read() { | ||||||
|     return _ptr == _end; |     if (_ptr < _end) | ||||||
|   } |       return static_cast<unsigned char>(*_ptr++); | ||||||
|  |     else | ||||||
|   char read() { |       return -1; | ||||||
|     return char(*_ptr++); |  | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -18,12 +18,8 @@ class StdStreamReader { | |||||||
|   explicit StdStreamReader(std::istream& stream) |   explicit StdStreamReader(std::istream& stream) | ||||||
|       : _stream(stream), _current(0) {} |       : _stream(stream), _current(0) {} | ||||||
|  |  | ||||||
|   bool ended() const { |   int read() { | ||||||
|     return _stream.eof(); |     return _stream.get(); | ||||||
|   } |  | ||||||
|  |  | ||||||
|   char read() { |  | ||||||
|     return static_cast<char>(_stream.get()); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  private: |  private: | ||||||
|   | |||||||
| @@ -28,19 +28,14 @@ class JsonDeserializer { | |||||||
|         _nestingLimit(nestingLimit), |         _nestingLimit(nestingLimit), | ||||||
|         _loaded(false) {} |         _loaded(false) {} | ||||||
|   DeserializationError parse(VariantData &variant) { |   DeserializationError parse(VariantData &variant) { | ||||||
|     DeserializationError err = skipSpacesAndComments(); |     DeserializationError err = parseVariant(variant); | ||||||
|     if (err) return err; |  | ||||||
|  |  | ||||||
|     switch (current()) { |     if (!err && _current != 0 && !variant.isEnclosed()) { | ||||||
|       case '[': |       // We don't detect trailing characters earlier, so we need to check now | ||||||
|         return parseArray(variant.toArray()); |       err = DeserializationError::InvalidInput; | ||||||
|  |  | ||||||
|       case '{': |  | ||||||
|         return parseObject(variant.toObject()); |  | ||||||
|  |  | ||||||
|       default: |  | ||||||
|         return parseValue(variant); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     return err; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  private: |  private: | ||||||
| @@ -48,10 +43,8 @@ class JsonDeserializer { | |||||||
|  |  | ||||||
|   char current() { |   char current() { | ||||||
|     if (!_loaded) { |     if (!_loaded) { | ||||||
|       if (_reader.ended()) |       int c = _reader.read(); | ||||||
|         _current = 0; |       _current = static_cast<char>(c > 0 ? c : 0); | ||||||
|       else |  | ||||||
|         _current = _reader.read(); |  | ||||||
|       _loaded = true; |       _loaded = true; | ||||||
|     } |     } | ||||||
|     return _current; |     return _current; | ||||||
| @@ -67,6 +60,26 @@ class JsonDeserializer { | |||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   DeserializationError parseVariant(VariantData &variant) { | ||||||
|  |     DeserializationError err = skipSpacesAndComments(); | ||||||
|  |     if (err) return err; | ||||||
|  |  | ||||||
|  |     switch (current()) { | ||||||
|  |       case '[': | ||||||
|  |         return parseArray(variant.toArray()); | ||||||
|  |  | ||||||
|  |       case '{': | ||||||
|  |         return parseObject(variant.toObject()); | ||||||
|  |  | ||||||
|  |       case '\"': | ||||||
|  |       case '\'': | ||||||
|  |         return parseStringValue(variant); | ||||||
|  |  | ||||||
|  |       default: | ||||||
|  |         return parseNumericValue(variant); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|   DeserializationError parseArray(CollectionData &array) { |   DeserializationError parseArray(CollectionData &array) { | ||||||
|     if (_nestingLimit == 0) return DeserializationError::TooDeep; |     if (_nestingLimit == 0) return DeserializationError::TooDeep; | ||||||
|  |  | ||||||
| @@ -88,7 +101,7 @@ class JsonDeserializer { | |||||||
|  |  | ||||||
|       // 1 - Parse value |       // 1 - Parse value | ||||||
|       _nestingLimit--; |       _nestingLimit--; | ||||||
|       err = parse(*value); |       err = parseVariant(*value); | ||||||
|       _nestingLimit++; |       _nestingLimit++; | ||||||
|       if (err) return err; |       if (err) return err; | ||||||
|  |  | ||||||
| @@ -134,7 +147,7 @@ class JsonDeserializer { | |||||||
|  |  | ||||||
|       // Parse value |       // Parse value | ||||||
|       _nestingLimit--; |       _nestingLimit--; | ||||||
|       err = parse(*slot->data()); |       err = parseVariant(*slot->data()); | ||||||
|       _nestingLimit++; |       _nestingLimit++; | ||||||
|       if (err) return err; |       if (err) return err; | ||||||
|  |  | ||||||
| @@ -152,14 +165,6 @@ class JsonDeserializer { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   DeserializationError parseValue(VariantData &variant) { |  | ||||||
|     if (isQuote(current())) { |  | ||||||
|       return parseStringValue(variant); |  | ||||||
|     } else { |  | ||||||
|       return parseNumericValue(variant); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   DeserializationError parseKey(const char *&key) { |   DeserializationError parseKey(const char *&key) { | ||||||
|     if (isQuote(current())) { |     if (isQuote(current())) { | ||||||
|       return parseQuotedString(key); |       return parseQuotedString(key); | ||||||
|   | |||||||
| @@ -134,17 +134,10 @@ class MsgPackDeserializer { | |||||||
|   // Prevent VS warning "assignment operator could not be generated" |   // Prevent VS warning "assignment operator could not be generated" | ||||||
|   MsgPackDeserializer &operator=(const MsgPackDeserializer &); |   MsgPackDeserializer &operator=(const MsgPackDeserializer &); | ||||||
|  |  | ||||||
|   bool skip(uint8_t n) { |  | ||||||
|     while (n--) { |  | ||||||
|       if (_reader.ended()) return false; |  | ||||||
|       _reader.read(); |  | ||||||
|     } |  | ||||||
|     return true; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   bool readByte(uint8_t &value) { |   bool readByte(uint8_t &value) { | ||||||
|     if (_reader.ended()) return false; |     int c = _reader.read(); | ||||||
|     value = static_cast<uint8_t>(_reader.read()); |     if (c < 0) return false; | ||||||
|  |     value = static_cast<uint8_t>(c); | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -177,6 +177,10 @@ class VariantData { | |||||||
|     return type() == VALUE_IS_NULL; |     return type() == VALUE_IS_NULL; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   bool isEnclosed() const { | ||||||
|  |     return isCollection() || isString(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   void remove(size_t index) { |   void remove(size_t index) { | ||||||
|     if (isArray()) _content.asCollection.remove(index); |     if (isArray()) _content.asCollection.remove(index); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -8,7 +8,8 @@ | |||||||
|  |  | ||||||
| TEST_CASE("Invalid JSON input") { | TEST_CASE("Invalid JSON input") { | ||||||
|   const char* testCases[] = {"'\\u'",     "'\\u000g'", "'\\u000'", "'\\u000G'", |   const char* testCases[] = {"'\\u'",     "'\\u000g'", "'\\u000'", "'\\u000G'", | ||||||
|                              "'\\u000/'", "\\x1234",   "6a9"}; |                              "'\\u000/'", "\\x1234",   "6a9",      "1,", | ||||||
|  |                              "2]",        "3}"}; | ||||||
|   const size_t testCount = sizeof(testCases) / sizeof(testCases[0]); |   const size_t testCount = sizeof(testCases) / sizeof(testCases[0]); | ||||||
|  |  | ||||||
|   DynamicJsonDocument doc(4096); |   DynamicJsonDocument doc(4096); | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ | |||||||
| add_executable(MiscTests | add_executable(MiscTests | ||||||
| 	conflicts.cpp | 	conflicts.cpp | ||||||
| 	FloatParts.cpp | 	FloatParts.cpp | ||||||
|  | 	StreamReader.cpp | ||||||
| 	StringWriter.cpp | 	StringWriter.cpp | ||||||
| 	TypeTraits.cpp | 	TypeTraits.cpp | ||||||
| 	unsigned_char.cpp | 	unsigned_char.cpp | ||||||
|   | |||||||
							
								
								
									
										33
									
								
								test/Misc/StreamReader.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								test/Misc/StreamReader.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | // ArduinoJson - arduinojson.org | ||||||
|  | // Copyright Benoit Blanchon 2014-2019 | ||||||
|  | // MIT License | ||||||
|  |  | ||||||
|  | #include <ArduinoJson.h> | ||||||
|  | #include <catch.hpp> | ||||||
|  |  | ||||||
|  | using namespace ARDUINOJSON_NAMESPACE; | ||||||
|  |  | ||||||
|  | TEST_CASE("StdStreamReader") { | ||||||
|  |   std::istringstream src("\x01\xFF"); | ||||||
|  |   StdStreamReader reader(src); | ||||||
|  |  | ||||||
|  |   REQUIRE(reader.read() == 0x01); | ||||||
|  |   REQUIRE(reader.read() == 0xFF); | ||||||
|  |   REQUIRE(reader.read() == -1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TEST_CASE("SafeCharPointerReader") { | ||||||
|  |   SafeCharPointerReader reader("\x01\xFF", 2); | ||||||
|  |  | ||||||
|  |   REQUIRE(reader.read() == 0x01); | ||||||
|  |   REQUIRE(reader.read() == 0xFF); | ||||||
|  |   REQUIRE(reader.read() == -1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TEST_CASE("UnsafeCharPointerReader") { | ||||||
|  |   UnsafeCharPointerReader reader("\x01\xFF"); | ||||||
|  |  | ||||||
|  |   REQUIRE(reader.read() == 0x01); | ||||||
|  |   REQUIRE(reader.read() == 0xFF); | ||||||
|  |   REQUIRE(reader.read() == 0); | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user