mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	Merge branch 'master' into 6.x
# Conflicts: # CHANGELOG.md # src/ArduinoJson/Deserialization/JsonParser.hpp # src/ArduinoJson/Deserialization/JsonParserImpl.hpp # test/JsonBuffer/nestingLimit.cpp
This commit is contained in:
		| @@ -4,6 +4,8 @@ ArduinoJson: change log | ||||
| HEAD | ||||
| ---- | ||||
|  | ||||
| * Fixed `JsonBuffer::parse()` not respecting nesting limit correctly (issue #693) | ||||
| * Fixed inconsistencies in nesting level counting (PR #695 from Zhenyu Wu) | ||||
| * Added `DynamicJsonArray` and `StaticJsonArray` | ||||
| * Added `DynamicJsonObject` and `StaticJsonObject` | ||||
| * Added `DynamicJsonVariant` and `StaticJsonVariant` | ||||
|   | ||||
| @@ -38,12 +38,9 @@ class JsonParser { | ||||
|   } | ||||
|  | ||||
|   const char *parseString(); | ||||
|   JsonError parseAnythingTo(JsonVariant *destination); | ||||
|   FORCE_INLINE JsonError parseAnythingToUnsafe(JsonVariant *destination); | ||||
|  | ||||
|   inline JsonError parseArrayTo(JsonVariant *destination); | ||||
|   inline JsonError parseObjectTo(JsonVariant *destination); | ||||
|   inline JsonError parseStringTo(JsonVariant *destination); | ||||
|   JsonError parseArray(JsonVariant &variant); | ||||
|   JsonError parseObject(JsonVariant &variant); | ||||
|   JsonError parseValue(JsonVariant &variant); | ||||
|  | ||||
|   static inline bool isBetween(char c, char min, char max) { | ||||
|     return min <= c && c <= max; | ||||
|   | ||||
| @@ -17,38 +17,11 @@ inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::eat( | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| template <typename TReader, typename TWriter> | ||||
| inline ArduinoJson::JsonError | ||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseAnythingTo( | ||||
|     JsonVariant *destination) { | ||||
|   if (_nestingLimit == 0) return JsonError::TooDeep; | ||||
|   _nestingLimit--; | ||||
|   JsonError error = parseAnythingToUnsafe(destination); | ||||
|   _nestingLimit++; | ||||
|   return error; | ||||
| } | ||||
|  | ||||
| template <typename TReader, typename TWriter> | ||||
| inline ArduinoJson::JsonError | ||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseAnythingToUnsafe( | ||||
|     JsonVariant *destination) { | ||||
|   skipSpacesAndComments(_reader); | ||||
|  | ||||
|   switch (_reader.current()) { | ||||
|     case '[': | ||||
|       return parseArrayTo(destination); | ||||
|  | ||||
|     case '{': | ||||
|       return parseObjectTo(destination); | ||||
|  | ||||
|     default: | ||||
|       return parseStringTo(destination); | ||||
|   } | ||||
| } | ||||
|  | ||||
| template <typename TReader, typename TWriter> | ||||
| inline ArduinoJson::JsonError | ||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parse(JsonArray &array) { | ||||
|   if (_nestingLimit == 0) return JsonError::TooDeep; | ||||
|  | ||||
|   // Check opening braket | ||||
|   if (!eat('[')) return JsonError::OpeningBracketExpected; | ||||
|   if (eat(']')) return JsonError::Ok; | ||||
| @@ -57,7 +30,9 @@ ArduinoJson::Internals::JsonParser<TReader, TWriter>::parse(JsonArray &array) { | ||||
|   for (;;) { | ||||
|     // 1 - Parse value | ||||
|     JsonVariant value; | ||||
|     JsonError error = parseAnythingTo(&value); | ||||
|     _nestingLimit--; | ||||
|     JsonError error = parse(value); | ||||
|     _nestingLimit++; | ||||
|     if (error != JsonError::Ok) return error; | ||||
|     if (!array.add(value)) return JsonError::NoMemory; | ||||
|  | ||||
| @@ -71,6 +46,8 @@ template <typename TReader, typename TWriter> | ||||
| inline ArduinoJson::JsonError | ||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parse( | ||||
|     JsonObject &object) { | ||||
|   if (_nestingLimit == 0) return JsonError::TooDeep; | ||||
|  | ||||
|   // Check opening brace | ||||
|   if (!eat('{')) return JsonError::OpeningBraceExpected; | ||||
|   if (eat('}')) return JsonError::Ok; | ||||
| @@ -84,7 +61,9 @@ ArduinoJson::Internals::JsonParser<TReader, TWriter>::parse( | ||||
|  | ||||
|     // 2 - Parse value | ||||
|     JsonVariant value; | ||||
|     JsonError error = parseAnythingTo(&value); | ||||
|     _nestingLimit--; | ||||
|     JsonError error = parse(value); | ||||
|     _nestingLimit++; | ||||
|     if (error != JsonError::Ok) return error; | ||||
|     if (!object.set(key, value)) return JsonError::NoMemory; | ||||
|  | ||||
| @@ -98,29 +77,55 @@ template <typename TReader, typename TWriter> | ||||
| inline ArduinoJson::JsonError | ||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parse( | ||||
|     JsonVariant &variant) { | ||||
|   return parseAnythingTo(&variant); | ||||
|   skipSpacesAndComments(_reader); | ||||
|  | ||||
|   switch (_reader.current()) { | ||||
|     case '[': | ||||
|       return parseArray(variant); | ||||
|  | ||||
|     case '{': | ||||
|       return parseObject(variant); | ||||
|  | ||||
|     default: | ||||
|       return parseValue(variant); | ||||
|   } | ||||
| } | ||||
|  | ||||
| template <typename TReader, typename TWriter> | ||||
| inline ArduinoJson::JsonError | ||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseArrayTo( | ||||
|     JsonVariant *destination) { | ||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseArray( | ||||
|     JsonVariant &variant) { | ||||
|   JsonArray *array = new (_buffer) JsonArray(_buffer); | ||||
|   if (!array) return JsonError::NoMemory; | ||||
|   *destination = array; | ||||
|   variant = array; | ||||
|   return parse(*array); | ||||
| } | ||||
|  | ||||
| template <typename TReader, typename TWriter> | ||||
| inline ArduinoJson::JsonError | ||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseObjectTo( | ||||
|     JsonVariant *destination) { | ||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseObject( | ||||
|     JsonVariant &variant) { | ||||
|   JsonObject *object = new (_buffer) JsonObject(_buffer); | ||||
|   if (!object) return JsonError::NoMemory; | ||||
|   *destination = object; | ||||
|   variant = object; | ||||
|   return parse(*object); | ||||
| } | ||||
|  | ||||
| template <typename TReader, typename TWriter> | ||||
| inline ArduinoJson::JsonError | ||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseValue( | ||||
|     JsonVariant &variant) { | ||||
|   bool hasQuotes = isQuote(_reader.current()); | ||||
|   const char *value = parseString(); | ||||
|   if (value == NULL) return JsonError::NoMemory; | ||||
|   if (hasQuotes) { | ||||
|     variant = value; | ||||
|   } else { | ||||
|     variant = RawJson(value); | ||||
|   } | ||||
|   return JsonError::Ok; | ||||
| } | ||||
|  | ||||
| template <typename TReader, typename TWriter> | ||||
| inline const char * | ||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseString() { | ||||
| @@ -159,18 +164,3 @@ ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseString() { | ||||
|  | ||||
|   return str.c_str(); | ||||
| } | ||||
|  | ||||
| template <typename TReader, typename TWriter> | ||||
| inline ArduinoJson::JsonError | ||||
| ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseStringTo( | ||||
|     JsonVariant *destination) { | ||||
|   bool hasQuotes = isQuote(_reader.current()); | ||||
|   const char *value = parseString(); | ||||
|   if (value == NULL) return JsonError::NoMemory; | ||||
|   if (hasQuotes) { | ||||
|     *destination = value; | ||||
|   } else { | ||||
|     *destination = RawJson(value); | ||||
|   } | ||||
|   return JsonError::Ok; | ||||
| } | ||||
|   | ||||
| @@ -21,12 +21,20 @@ class JsonError { | ||||
|  | ||||
|   JsonError(Code code) : _code(code) {} | ||||
|  | ||||
|   bool operator==(Code code) const { | ||||
|     return _code == code; | ||||
|   friend bool operator==(const JsonError& err, Code code) { | ||||
|     return err._code == code; | ||||
|   } | ||||
|  | ||||
|   bool operator!=(Code code) const { | ||||
|     return _code != code; | ||||
|   friend bool operator==(Code code, const JsonError& err) { | ||||
|     return err._code == code; | ||||
|   } | ||||
|  | ||||
|   friend bool operator!=(const JsonError& err, Code code) { | ||||
|     return err._code != code; | ||||
|   } | ||||
|  | ||||
|   friend bool operator!=(Code code, const JsonError& err) { | ||||
|     return err._code != code; | ||||
|   } | ||||
|  | ||||
|   operator bool() const { | ||||
|   | ||||
| @@ -5,45 +5,66 @@ | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| JsonError tryParseArray(const char *json, uint8_t nestingLimit) { | ||||
|   DynamicJsonArray array; | ||||
|   return deserializeJson(array, json, nestingLimit); | ||||
| } | ||||
|  | ||||
| JsonError tryParseObject(const char *json, uint8_t nestingLimit) { | ||||
|   DynamicJsonObject obj; | ||||
|   return deserializeJson(obj, json, nestingLimit); | ||||
| } | ||||
| #define SHOULD_WORK(expression) REQUIRE(JsonError::Ok == expression); | ||||
| #define SHOULD_FAIL(expression) REQUIRE(JsonError::TooDeep == expression); | ||||
|  | ||||
| TEST_CASE("JsonParser nestingLimit") { | ||||
|   SECTION("ParseArrayWithNestingLimit0") { | ||||
|     REQUIRE(tryParseArray("[]", 0) == JsonError::Ok); | ||||
|     REQUIRE(tryParseArray("[[]]", 0) == JsonError::TooDeep); | ||||
|   SECTION("deserializeJson(JsonArray&)") { | ||||
|     DynamicJsonArray arr; | ||||
|  | ||||
|     SECTION("limit = 0") { | ||||
|       SHOULD_FAIL(deserializeJson(arr, "[]", 0)); | ||||
|     } | ||||
|  | ||||
|     SECTION("limit = 1") { | ||||
|       SHOULD_WORK(deserializeJson(arr, "[]", 1)); | ||||
|       SHOULD_FAIL(deserializeJson(arr, "[[]]", 1)); | ||||
|     } | ||||
|  | ||||
|     SECTION("limit = 2") { | ||||
|       SHOULD_WORK(deserializeJson(arr, "[[]]", 2)); | ||||
|       SHOULD_FAIL(deserializeJson(arr, "[[[]]]", 2)); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("ParseArrayWithNestingLimit1") { | ||||
|     REQUIRE(tryParseArray("[[]]", 1) == JsonError::Ok); | ||||
|     REQUIRE(tryParseArray("[[[]]]", 1) == JsonError::TooDeep); | ||||
|   SECTION("deserializeJson(JsonObject&)") { | ||||
|     DynamicJsonObject obj; | ||||
|  | ||||
|     SECTION("limit = 0") { | ||||
|       SHOULD_FAIL(deserializeJson(obj, "{}", 0)); | ||||
|     } | ||||
|  | ||||
|     SECTION("limit = 1") { | ||||
|       SHOULD_WORK(deserializeJson(obj, "{\"key\":42}", 1)); | ||||
|       SHOULD_FAIL(deserializeJson(obj, "{\"key\":{\"key\":42}}", 1)); | ||||
|     } | ||||
|  | ||||
|     SECTION("limit = 2") { | ||||
|       SHOULD_WORK(deserializeJson(obj, "{\"key\":{\"key\":42}}", 2)); | ||||
|       SHOULD_FAIL(deserializeJson(obj, "{\"key\":{\"key\":{\"key\":42}}}", 2)); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("ParseArrayWithNestingLimit2") { | ||||
|     REQUIRE(tryParseArray("[[[]]]", 2) == JsonError::Ok); | ||||
|     REQUIRE(tryParseArray("[[[[]]]]", 2) == JsonError::TooDeep); | ||||
|   } | ||||
|   SECTION("deserializeJson(JsonVariant&)") { | ||||
|     DynamicJsonVariant var; | ||||
|  | ||||
|   SECTION("ParseObjectWithNestingLimit0") { | ||||
|     REQUIRE(tryParseObject("{}", 0) == JsonError::Ok); | ||||
|     REQUIRE(tryParseObject("{\"key\":{}}", 0) == JsonError::TooDeep); | ||||
|   } | ||||
|     SECTION("limit = 0") { | ||||
|       SHOULD_WORK(deserializeJson(var, "\"toto\"", 0)); | ||||
|       SHOULD_WORK(deserializeJson(var, "123", 0)); | ||||
|       SHOULD_WORK(deserializeJson(var, "true", 0)); | ||||
|       SHOULD_FAIL(deserializeJson(var, "[]", 0)); | ||||
|       SHOULD_FAIL(deserializeJson(var, "{}", 0)); | ||||
|       SHOULD_FAIL(deserializeJson(var, "[\"toto\"]", 0)); | ||||
|       SHOULD_FAIL(deserializeJson(var, "{\"toto\":1}", 0)); | ||||
|     } | ||||
|  | ||||
|   SECTION("ParseObjectWithNestingLimit1") { | ||||
|     REQUIRE(tryParseObject("{\"key\":{}}", 1) == JsonError::Ok); | ||||
|     REQUIRE(tryParseObject("{\"key\":{\"key\":{}}}", 1) == JsonError::TooDeep); | ||||
|   } | ||||
|  | ||||
|   SECTION("ParseObjectWithNestingLimit2") { | ||||
|     REQUIRE(tryParseObject("{\"key\":{\"key\":{}}}", 2) == JsonError::Ok); | ||||
|     REQUIRE(tryParseObject("{\"key\":{\"key\":{\"key\":{}}}}", 2) == | ||||
|             JsonError::TooDeep); | ||||
|     SECTION("limit = 1") { | ||||
|       SHOULD_WORK(deserializeJson(var, "[\"toto\"]", 1)); | ||||
|       SHOULD_WORK(deserializeJson(var, "{\"toto\":1}", 1)); | ||||
|       SHOULD_FAIL(deserializeJson(var, "{\"toto\":{}}", 1)); | ||||
|       SHOULD_FAIL(deserializeJson(var, "{\"toto\":[]}", 1)); | ||||
|       SHOULD_FAIL(deserializeJson(var, "[[\"toto\"]]", 1)); | ||||
|       SHOULD_FAIL(deserializeJson(var, "[{\"toto\":1}]", 1)); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user