summaryrefslogtreecommitdiff
path: root/include/lib/ArduinoJson/Json
diff options
context:
space:
mode:
Diffstat (limited to 'include/lib/ArduinoJson/Json')
-rw-r--r--include/lib/ArduinoJson/Json/EscapeSequence.hpp39
-rw-r--r--include/lib/ArduinoJson/Json/JsonDeserializer.hpp740
-rw-r--r--include/lib/ArduinoJson/Json/JsonSerializer.hpp137
-rw-r--r--include/lib/ArduinoJson/Json/Latch.hpp55
-rw-r--r--include/lib/ArduinoJson/Json/PrettyJsonSerializer.hpp89
-rw-r--r--include/lib/ArduinoJson/Json/TextFormatter.hpp163
-rw-r--r--include/lib/ArduinoJson/Json/Utf16.hpp67
-rw-r--r--include/lib/ArduinoJson/Json/Utf8.hpp46
8 files changed, 1336 insertions, 0 deletions
diff --git a/include/lib/ArduinoJson/Json/EscapeSequence.hpp b/include/lib/ArduinoJson/Json/EscapeSequence.hpp
new file mode 100644
index 0000000..811e825
--- /dev/null
+++ b/include/lib/ArduinoJson/Json/EscapeSequence.hpp
@@ -0,0 +1,39 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Namespace.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+class EscapeSequence {
+ public:
+ // Optimized for code size on a 8-bit AVR
+ static char escapeChar(char c) {
+ const char *p = escapeTable(true);
+ while (p[0] && p[1] != c) {
+ p += 2;
+ }
+ return p[0];
+ }
+
+ // Optimized for code size on a 8-bit AVR
+ static char unescapeChar(char c) {
+ const char *p = escapeTable(false);
+ for (;;) {
+ if (p[0] == '\0')
+ return 0;
+ if (p[0] == c)
+ return p[1];
+ p += 2;
+ }
+ }
+
+ private:
+ static const char *escapeTable(bool excludeSolidus) {
+ return &"//\"\"\\\\b\bf\fn\nr\rt\t"[excludeSolidus ? 2 : 0];
+ }
+};
+} // namespace ARDUINOJSON_NAMESPACE
diff --git a/include/lib/ArduinoJson/Json/JsonDeserializer.hpp b/include/lib/ArduinoJson/Json/JsonDeserializer.hpp
new file mode 100644
index 0000000..1a07be8
--- /dev/null
+++ b/include/lib/ArduinoJson/Json/JsonDeserializer.hpp
@@ -0,0 +1,740 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Deserialization/deserialize.hpp>
+#include <ArduinoJson/Json/EscapeSequence.hpp>
+#include <ArduinoJson/Json/Latch.hpp>
+#include <ArduinoJson/Json/Utf16.hpp>
+#include <ArduinoJson/Json/Utf8.hpp>
+#include <ArduinoJson/Memory/MemoryPool.hpp>
+#include <ArduinoJson/Numbers/parseNumber.hpp>
+#include <ArduinoJson/Polyfills/assert.hpp>
+#include <ArduinoJson/Polyfills/type_traits.hpp>
+#include <ArduinoJson/Variant/VariantData.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+template <typename TReader, typename TStringStorage>
+class JsonDeserializer {
+ public:
+ JsonDeserializer(MemoryPool &pool, TReader reader,
+ TStringStorage stringStorage)
+ : _stringStorage(stringStorage),
+ _foundSomething(false),
+ _latch(reader),
+ _pool(&pool),
+ _error(DeserializationError::Ok) {}
+
+ template <typename TFilter>
+ DeserializationError parse(VariantData &variant, TFilter filter,
+ NestingLimit nestingLimit) {
+ parseVariant(variant, filter, nestingLimit);
+
+ if (!_error && _latch.last() != 0 && !variant.isEnclosed()) {
+ // We don't detect trailing characters earlier, so we need to check now
+ return DeserializationError::InvalidInput;
+ }
+
+ return _error;
+ }
+
+ private:
+ char current() {
+ return _latch.current();
+ }
+
+ void move() {
+ _latch.clear();
+ }
+
+ bool eat(char charToSkip) {
+ if (current() != charToSkip)
+ return false;
+ move();
+ return true;
+ }
+
+ template <typename TFilter>
+ bool parseVariant(VariantData &variant, TFilter filter,
+ NestingLimit nestingLimit) {
+ if (!skipSpacesAndComments())
+ return false;
+
+ switch (current()) {
+ case '[':
+ if (filter.allowArray())
+ return parseArray(variant.toArray(), filter, nestingLimit);
+ else
+ return skipArray(nestingLimit);
+
+ case '{':
+ if (filter.allowObject())
+ return parseObject(variant.toObject(), filter, nestingLimit);
+ else
+ return skipObject(nestingLimit);
+
+ case '\"':
+ case '\'':
+ if (filter.allowValue())
+ return parseStringValue(variant);
+ else
+ return skipString();
+
+ default:
+ if (filter.allowValue())
+ return parseNumericValue(variant);
+ else
+ return skipNumericValue();
+ }
+ }
+
+ bool skipVariant(NestingLimit nestingLimit) {
+ if (!skipSpacesAndComments())
+ return false;
+
+ switch (current()) {
+ case '[':
+ return skipArray(nestingLimit);
+
+ case '{':
+ return skipObject(nestingLimit);
+
+ case '\"':
+ case '\'':
+ return skipString();
+
+ default:
+ return skipNumericValue();
+ }
+ }
+
+ template <typename TFilter>
+ bool parseArray(CollectionData &array, TFilter filter,
+ NestingLimit nestingLimit) {
+ if (nestingLimit.reached()) {
+ _error = DeserializationError::TooDeep;
+ return false;
+ }
+
+ // Skip opening braket
+ ARDUINOJSON_ASSERT(current() == '[');
+ move();
+
+ // Skip spaces
+ if (!skipSpacesAndComments())
+ return false;
+
+ // Empty array?
+ if (eat(']'))
+ return true;
+
+ TFilter memberFilter = filter[0UL];
+
+ // Read each value
+ for (;;) {
+ if (memberFilter.allow()) {
+ // Allocate slot in array
+ VariantData *value = array.addElement(_pool);
+ if (!value) {
+ _error = DeserializationError::NoMemory;
+ return false;
+ }
+
+ // 1 - Parse value
+ if (!parseVariant(*value, memberFilter, nestingLimit.decrement()))
+ return false;
+ } else {
+ if (!skipVariant(nestingLimit.decrement()))
+ return false;
+ }
+
+ // 2 - Skip spaces
+ if (!skipSpacesAndComments())
+ return false;
+
+ // 3 - More values?
+ if (eat(']'))
+ return true;
+ if (!eat(',')) {
+ _error = DeserializationError::InvalidInput;
+ return false;
+ }
+ }
+ }
+
+ bool skipArray(NestingLimit nestingLimit) {
+ if (nestingLimit.reached()) {
+ _error = DeserializationError::TooDeep;
+ return false;
+ }
+
+ // Skip opening braket
+ ARDUINOJSON_ASSERT(current() == '[');
+ move();
+
+ // Read each value
+ for (;;) {
+ // 1 - Skip value
+ if (!skipVariant(nestingLimit.decrement()))
+ return false;
+
+ // 2 - Skip spaces
+ if (!skipSpacesAndComments())
+ return false;
+
+ // 3 - More values?
+ if (eat(']'))
+ return true;
+ if (!eat(',')) {
+ _error = DeserializationError::InvalidInput;
+ return false;
+ }
+ }
+ }
+
+ template <typename TFilter>
+ bool parseObject(CollectionData &object, TFilter filter,
+ NestingLimit nestingLimit) {
+ if (nestingLimit.reached()) {
+ _error = DeserializationError::TooDeep;
+ return false;
+ }
+
+ // Skip opening brace
+ ARDUINOJSON_ASSERT(current() == '{');
+ move();
+
+ // Skip spaces
+ if (!skipSpacesAndComments())
+ return false;
+
+ // Empty object?
+ if (eat('}'))
+ return true;
+
+ // Read each key value pair
+ for (;;) {
+ // Parse key
+ if (!parseKey())
+ return false;
+
+ // Skip spaces
+ if (!skipSpacesAndComments())
+ return false;
+
+ // Colon
+ if (!eat(':')) {
+ _error = DeserializationError::InvalidInput;
+ return false;
+ }
+
+ const char *key = _stringStorage.c_str();
+
+ TFilter memberFilter = filter[key];
+
+ if (memberFilter.allow()) {
+ VariantData *variant = object.getMember(adaptString(key));
+ if (!variant) {
+ // Save key in memory pool.
+ // This MUST be done before adding the slot.
+ key = _stringStorage.save();
+
+ // Allocate slot in object
+ VariantSlot *slot = object.addSlot(_pool);
+ if (!slot) {
+ _error = DeserializationError::NoMemory;
+ return false;
+ }
+
+ slot->setKey(key, typename TStringStorage::storage_policy());
+
+ variant = slot->data();
+ }
+
+ // Parse value
+ if (!parseVariant(*variant, memberFilter, nestingLimit.decrement()))
+ return false;
+ } else {
+ if (!skipVariant(nestingLimit.decrement()))
+ return false;
+ }
+
+ // Skip spaces
+ if (!skipSpacesAndComments())
+ return false;
+
+ // More keys/values?
+ if (eat('}'))
+ return true;
+ if (!eat(',')) {
+ _error = DeserializationError::InvalidInput;
+ return false;
+ }
+
+ // Skip spaces
+ if (!skipSpacesAndComments())
+ return false;
+ }
+ }
+
+ bool skipObject(NestingLimit nestingLimit) {
+ if (nestingLimit.reached()) {
+ _error = DeserializationError::TooDeep;
+ return false;
+ }
+
+ // Skip opening brace
+ ARDUINOJSON_ASSERT(current() == '{');
+ move();
+
+ // Skip spaces
+ if (!skipSpacesAndComments())
+ return false;
+
+ // Empty object?
+ if (eat('}'))
+ return true;
+
+ // Read each key value pair
+ for (;;) {
+ // Skip key
+ if (!skipVariant(nestingLimit.decrement()))
+ return false;
+
+ // Skip spaces
+ if (!skipSpacesAndComments())
+ return false;
+
+ // Colon
+ if (!eat(':')) {
+ _error = DeserializationError::InvalidInput;
+ return false;
+ }
+
+ // Skip value
+ if (!skipVariant(nestingLimit.decrement()))
+ return false;
+
+ // Skip spaces
+ if (!skipSpacesAndComments())
+ return false;
+
+ // More keys/values?
+ if (eat('}'))
+ return true;
+ if (!eat(',')) {
+ _error = DeserializationError::InvalidInput;
+ return false;
+ }
+ }
+ }
+
+ bool parseKey() {
+ _stringStorage.startString();
+ if (isQuote(current())) {
+ return parseQuotedString();
+ } else {
+ return parseNonQuotedString();
+ }
+ }
+
+ bool parseStringValue(VariantData &variant) {
+ _stringStorage.startString();
+ if (!parseQuotedString())
+ return false;
+ const char *value = _stringStorage.save();
+ variant.setStringPointer(value, typename TStringStorage::storage_policy());
+ return true;
+ }
+
+ bool parseQuotedString() {
+#if ARDUINOJSON_DECODE_UNICODE
+ Utf16::Codepoint codepoint;
+#endif
+ const char stopChar = current();
+
+ move();
+ for (;;) {
+ char c = current();
+ move();
+ if (c == stopChar)
+ break;
+
+ if (c == '\0') {
+ _error = DeserializationError::IncompleteInput;
+ return false;
+ }
+
+ if (c == '\\') {
+ c = current();
+
+ if (c == '\0') {
+ _error = DeserializationError::IncompleteInput;
+ return false;
+ }
+
+ if (c == 'u') {
+#if ARDUINOJSON_DECODE_UNICODE
+ move();
+ uint16_t codeunit;
+ if (!parseHex4(codeunit))
+ return false;
+ if (codepoint.append(codeunit))
+ Utf8::encodeCodepoint(codepoint.value(), _stringStorage);
+#else
+ _stringStorage.append('\\');
+#endif
+ continue;
+ }
+
+ // replace char
+ c = EscapeSequence::unescapeChar(c);
+ if (c == '\0') {
+ _error = DeserializationError::InvalidInput;
+ return false;
+ }
+ move();
+ }
+
+ _stringStorage.append(c);
+ }
+
+ _stringStorage.append('\0');
+
+ if (!_stringStorage.isValid()) {
+ _error = DeserializationError::NoMemory;
+ return false;
+ }
+
+ return true;
+ }
+
+ bool parseNonQuotedString() {
+ char c = current();
+ ARDUINOJSON_ASSERT(c);
+
+ if (canBeInNonQuotedString(c)) { // no quotes
+ do {
+ move();
+ _stringStorage.append(c);
+ c = current();
+ } while (canBeInNonQuotedString(c));
+ } else {
+ _error = DeserializationError::InvalidInput;
+ return false;
+ }
+
+ _stringStorage.append('\0');
+
+ if (!_stringStorage.isValid()) {
+ _error = DeserializationError::NoMemory;
+ return false;
+ }
+
+ return true;
+ }
+
+ bool skipString() {
+ const char stopChar = current();
+
+ move();
+ for (;;) {
+ char c = current();
+ move();
+ if (c == stopChar)
+ break;
+ if (c == '\0') {
+ _error = DeserializationError::IncompleteInput;
+ return false;
+ }
+ if (c == '\\') {
+ if (current() != '\0')
+ move();
+ }
+ }
+
+ return true;
+ }
+
+ bool parseNumericValue(VariantData &result) {
+ uint8_t n = 0;
+
+ char c = current();
+ while (canBeInNonQuotedString(c) && n < 63) {
+ move();
+ _buffer[n++] = c;
+ c = current();
+ }
+ _buffer[n] = 0;
+
+ c = _buffer[0];
+ if (c == 't') { // true
+ result.setBoolean(true);
+ if (n != 4) {
+ _error = DeserializationError::IncompleteInput;
+ return false;
+ }
+ return true;
+ }
+ if (c == 'f') { // false
+ result.setBoolean(false);
+ if (n != 5) {
+ _error = DeserializationError::IncompleteInput;
+ return false;
+ }
+ return true;
+ }
+ if (c == 'n') { // null
+ // the variant is already null
+ if (n != 4) {
+ _error = DeserializationError::IncompleteInput;
+ return false;
+ }
+ return true;
+ }
+
+ if (!parseNumber(_buffer, result)) {
+ _error = DeserializationError::InvalidInput;
+ return false;
+ }
+
+ return true;
+ }
+
+ bool skipNumericValue() {
+ char c = current();
+ while (canBeInNonQuotedString(c)) {
+ move();
+ c = current();
+ }
+ return true;
+ }
+
+ bool parseHex4(uint16_t &result) {
+ result = 0;
+ for (uint8_t i = 0; i < 4; ++i) {
+ char digit = current();
+ if (!digit) {
+ _error = DeserializationError::IncompleteInput;
+ return false;
+ }
+ uint8_t value = decodeHex(digit);
+ if (value > 0x0F) {
+ _error = DeserializationError::InvalidInput;
+ return false;
+ }
+ result = uint16_t((result << 4) | value);
+ move();
+ }
+ return true;
+ }
+
+ static inline bool isBetween(char c, char min, char max) {
+ return min <= c && c <= max;
+ }
+
+ static inline bool canBeInNonQuotedString(char c) {
+ return isBetween(c, '0', '9') || isBetween(c, '_', 'z') ||
+ isBetween(c, 'A', 'Z') || c == '+' || c == '-' || c == '.';
+ }
+
+ static inline bool isQuote(char c) {
+ return c == '\'' || c == '\"';
+ }
+
+ static inline uint8_t decodeHex(char c) {
+ if (c < 'A')
+ return uint8_t(c - '0');
+ c = char(c & ~0x20); // uppercase
+ return uint8_t(c - 'A' + 10);
+ }
+
+ bool skipSpacesAndComments() {
+ for (;;) {
+ switch (current()) {
+ // end of string
+ case '\0':
+ _error = _foundSomething ? DeserializationError::IncompleteInput
+ : DeserializationError::EmptyInput;
+ return false;
+
+ // spaces
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ move();
+ continue;
+
+#if ARDUINOJSON_ENABLE_COMMENTS
+ // comments
+ case '/':
+ move(); // skip '/'
+ switch (current()) {
+ // block comment
+ case '*': {
+ move(); // skip '*'
+ bool wasStar = false;
+ for (;;) {
+ char c = current();
+ if (c == '\0') {
+ _error = DeserializationError::IncompleteInput;
+ return false;
+ }
+ if (c == '/' && wasStar) {
+ move();
+ break;
+ }
+ wasStar = c == '*';
+ move();
+ }
+ break;
+ }
+
+ // trailing comment
+ case '/':
+ // no need to skip "//"
+ for (;;) {
+ move();
+ char c = current();
+ if (c == '\0') {
+ _error = DeserializationError::IncompleteInput;
+ return false;
+ }
+ if (c == '\n')
+ break;
+ }
+ break;
+
+ // not a comment, just a '/'
+ default:
+ _error = DeserializationError::InvalidInput;
+ return false;
+ }
+ break;
+#endif
+
+ default:
+ _foundSomething = true;
+ return true;
+ }
+ }
+ }
+
+ TStringStorage _stringStorage;
+ bool _foundSomething;
+ Latch<TReader> _latch;
+ MemoryPool *_pool;
+ char _buffer[64]; // using a member instead of a local variable because it
+ // ended in the recursive path after compiler inlined the
+ // code
+ DeserializationError _error;
+};
+
+//
+// deserializeJson(JsonDocument&, const std::string&, ...)
+//
+// ... = NestingLimit
+template <typename TString>
+DeserializationError deserializeJson(
+ JsonDocument &doc, const TString &input,
+ NestingLimit nestingLimit = NestingLimit()) {
+ return deserialize<JsonDeserializer>(doc, input, nestingLimit,
+ AllowAllFilter());
+}
+// ... = Filter, NestingLimit
+template <typename TString>
+DeserializationError deserializeJson(
+ JsonDocument &doc, const TString &input, Filter filter,
+ NestingLimit nestingLimit = NestingLimit()) {
+ return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
+}
+// ... = NestingLimit, Filter
+template <typename TString>
+DeserializationError deserializeJson(JsonDocument &doc, const TString &input,
+ NestingLimit nestingLimit, Filter filter) {
+ return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
+}
+
+//
+// deserializeJson(JsonDocument&, std::istream&, ...)
+//
+// ... = NestingLimit
+template <typename TStream>
+DeserializationError deserializeJson(
+ JsonDocument &doc, TStream &input,
+ NestingLimit nestingLimit = NestingLimit()) {
+ return deserialize<JsonDeserializer>(doc, input, nestingLimit,
+ AllowAllFilter());
+}
+// ... = Filter, NestingLimit
+template <typename TStream>
+DeserializationError deserializeJson(
+ JsonDocument &doc, TStream &input, Filter filter,
+ NestingLimit nestingLimit = NestingLimit()) {
+ return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
+}
+// ... = NestingLimit, Filter
+template <typename TStream>
+DeserializationError deserializeJson(JsonDocument &doc, TStream &input,
+ NestingLimit nestingLimit, Filter filter) {
+ return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
+}
+
+//
+// deserializeJson(JsonDocument&, char*, ...)
+//
+// ... = NestingLimit
+template <typename TChar>
+DeserializationError deserializeJson(
+ JsonDocument &doc, TChar *input,
+ NestingLimit nestingLimit = NestingLimit()) {
+ return deserialize<JsonDeserializer>(doc, input, nestingLimit,
+ AllowAllFilter());
+}
+// ... = Filter, NestingLimit
+template <typename TChar>
+DeserializationError deserializeJson(
+ JsonDocument &doc, TChar *input, Filter filter,
+ NestingLimit nestingLimit = NestingLimit()) {
+ return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
+}
+// ... = NestingLimit, Filter
+template <typename TChar>
+DeserializationError deserializeJson(JsonDocument &doc, TChar *input,
+ NestingLimit nestingLimit, Filter filter) {
+ return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
+}
+
+//
+// deserializeJson(JsonDocument&, char*, size_t, ...)
+//
+// ... = NestingLimit
+template <typename TChar>
+DeserializationError deserializeJson(
+ JsonDocument &doc, TChar *input, size_t inputSize,
+ NestingLimit nestingLimit = NestingLimit()) {
+ return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit,
+ AllowAllFilter());
+}
+// ... = Filter, NestingLimit
+template <typename TChar>
+DeserializationError deserializeJson(
+ JsonDocument &doc, TChar *input, size_t inputSize, Filter filter,
+ NestingLimit nestingLimit = NestingLimit()) {
+ return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit,
+ filter);
+}
+// ... = NestingLimit, Filter
+template <typename TChar>
+DeserializationError deserializeJson(JsonDocument &doc, TChar *input,
+ size_t inputSize,
+ NestingLimit nestingLimit, Filter filter) {
+ return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit,
+ filter);
+}
+
+} // namespace ARDUINOJSON_NAMESPACE
diff --git a/include/lib/ArduinoJson/Json/JsonSerializer.hpp b/include/lib/ArduinoJson/Json/JsonSerializer.hpp
new file mode 100644
index 0000000..5cb9aa2
--- /dev/null
+++ b/include/lib/ArduinoJson/Json/JsonSerializer.hpp
@@ -0,0 +1,137 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Json/TextFormatter.hpp>
+#include <ArduinoJson/Misc/Visitable.hpp>
+#include <ArduinoJson/Serialization/measure.hpp>
+#include <ArduinoJson/Serialization/serialize.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+template <typename TWriter>
+class JsonSerializer : public Visitor<size_t> {
+ public:
+ static const bool producesText = true;
+
+ JsonSerializer(TWriter writer) : _formatter(writer) {}
+
+ FORCE_INLINE size_t visitArray(const CollectionData &array) {
+ write('[');
+
+ VariantSlot *slot = array.head();
+
+ while (slot != 0) {
+ slot->data()->accept(*this);
+
+ slot = slot->next();
+ if (slot == 0)
+ break;
+
+ write(',');
+ }
+
+ write(']');
+ return bytesWritten();
+ }
+
+ size_t visitObject(const CollectionData &object) {
+ write('{');
+
+ VariantSlot *slot = object.head();
+
+ while (slot != 0) {
+ _formatter.writeString(slot->key());
+ write(':');
+ slot->data()->accept(*this);
+
+ slot = slot->next();
+ if (slot == 0)
+ break;
+
+ write(',');
+ }
+
+ write('}');
+ return bytesWritten();
+ }
+
+ size_t visitFloat(Float value) {
+ _formatter.writeFloat(value);
+ return bytesWritten();
+ }
+
+ size_t visitString(const char *value) {
+ _formatter.writeString(value);
+ return bytesWritten();
+ }
+
+ size_t visitRawJson(const char *data, size_t n) {
+ _formatter.writeRaw(data, n);
+ return bytesWritten();
+ }
+
+ size_t visitSignedInteger(Integer value) {
+ _formatter.writeInteger(value);
+ return bytesWritten();
+ }
+
+ size_t visitUnsignedInteger(UInt value) {
+ _formatter.writeInteger(value);
+ return bytesWritten();
+ }
+
+ size_t visitBoolean(bool value) {
+ _formatter.writeBoolean(value);
+ return bytesWritten();
+ }
+
+ size_t visitNull() {
+ _formatter.writeRaw("null");
+ return bytesWritten();
+ }
+
+ protected:
+ size_t bytesWritten() const {
+ return _formatter.bytesWritten();
+ }
+
+ void write(char c) {
+ _formatter.writeRaw(c);
+ }
+
+ void write(const char *s) {
+ _formatter.writeRaw(s);
+ }
+
+ private:
+ TextFormatter<TWriter> _formatter;
+};
+
+template <typename TSource, typename TDestination>
+size_t serializeJson(const TSource &source, TDestination &destination) {
+ return serialize<JsonSerializer>(source, destination);
+}
+
+template <typename TSource>
+size_t serializeJson(const TSource &source, void *buffer, size_t bufferSize) {
+ return serialize<JsonSerializer>(source, buffer, bufferSize);
+}
+
+template <typename TSource>
+size_t measureJson(const TSource &source) {
+ return measure<JsonSerializer>(source);
+}
+
+#if ARDUINOJSON_ENABLE_STD_STREAM
+template <typename T>
+inline typename enable_if<IsVisitable<T>::value, std::ostream &>::type
+operator<<(std::ostream &os, const T &source) {
+ serializeJson(source, os);
+ return os;
+}
+#endif
+
+} // namespace ARDUINOJSON_NAMESPACE
diff --git a/include/lib/ArduinoJson/Json/Latch.hpp b/include/lib/ArduinoJson/Json/Latch.hpp
new file mode 100644
index 0000000..aef1fe3
--- /dev/null
+++ b/include/lib/ArduinoJson/Json/Latch.hpp
@@ -0,0 +1,55 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Polyfills/assert.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+template <typename TReader>
+class Latch {
+ public:
+ Latch(TReader reader) : _reader(reader), _loaded(false) {
+#if 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();
+#if ARDUINOJSON_DEBUG
+ if (c <= 0)
+ _ended = true;
+#endif
+ _current = static_cast<char>(c > 0 ? c : 0);
+ _loaded = true;
+ }
+
+ TReader _reader;
+ char _current;
+ bool _loaded;
+#if ARDUINOJSON_DEBUG
+ bool _ended;
+#endif
+};
+
+} // namespace ARDUINOJSON_NAMESPACE
diff --git a/include/lib/ArduinoJson/Json/PrettyJsonSerializer.hpp b/include/lib/ArduinoJson/Json/PrettyJsonSerializer.hpp
new file mode 100644
index 0000000..dbb0c17
--- /dev/null
+++ b/include/lib/ArduinoJson/Json/PrettyJsonSerializer.hpp
@@ -0,0 +1,89 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Configuration.hpp>
+#include <ArduinoJson/Json/JsonSerializer.hpp>
+#include <ArduinoJson/Serialization/measure.hpp>
+#include <ArduinoJson/Serialization/serialize.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+template <typename TWriter>
+class PrettyJsonSerializer : public JsonSerializer<TWriter> {
+ typedef JsonSerializer<TWriter> base;
+
+ public:
+ PrettyJsonSerializer(TWriter writer) : base(writer), _nesting(0) {}
+
+ size_t visitArray(const CollectionData &array) {
+ VariantSlot *slot = array.head();
+ if (slot) {
+ base::write("[\r\n");
+ _nesting++;
+ while (slot != 0) {
+ indent();
+ slot->data()->accept(*this);
+
+ slot = slot->next();
+ base::write(slot ? ",\r\n" : "\r\n");
+ }
+ _nesting--;
+ indent();
+ base::write("]");
+ } else {
+ base::write("[]");
+ }
+ return this->bytesWritten();
+ }
+
+ size_t visitObject(const CollectionData &object) {
+ VariantSlot *slot = object.head();
+ if (slot) {
+ base::write("{\r\n");
+ _nesting++;
+ while (slot != 0) {
+ indent();
+ base::visitString(slot->key());
+ base::write(": ");
+ slot->data()->accept(*this);
+
+ slot = slot->next();
+ base::write(slot ? ",\r\n" : "\r\n");
+ }
+ _nesting--;
+ indent();
+ base::write("}");
+ } else {
+ base::write("{}");
+ }
+ return this->bytesWritten();
+ }
+
+ private:
+ void indent() {
+ for (uint8_t i = 0; i < _nesting; i++) base::write(ARDUINOJSON_TAB);
+ }
+
+ uint8_t _nesting;
+};
+
+template <typename TSource, typename TDestination>
+size_t serializeJsonPretty(const TSource &source, TDestination &destination) {
+ return serialize<PrettyJsonSerializer>(source, destination);
+}
+
+template <typename TSource>
+size_t serializeJsonPretty(const TSource &source, void *buffer,
+ size_t bufferSize) {
+ return serialize<PrettyJsonSerializer>(source, buffer, bufferSize);
+}
+
+template <typename TSource>
+size_t measureJsonPretty(const TSource &source) {
+ return measure<PrettyJsonSerializer>(source);
+}
+
+} // namespace ARDUINOJSON_NAMESPACE
diff --git a/include/lib/ArduinoJson/Json/TextFormatter.hpp b/include/lib/ArduinoJson/Json/TextFormatter.hpp
new file mode 100644
index 0000000..18694f1
--- /dev/null
+++ b/include/lib/ArduinoJson/Json/TextFormatter.hpp
@@ -0,0 +1,163 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <stdint.h>
+#include <string.h> // for strlen
+
+#include <ArduinoJson/Json/EscapeSequence.hpp>
+#include <ArduinoJson/Numbers/FloatParts.hpp>
+#include <ArduinoJson/Numbers/Integer.hpp>
+#include <ArduinoJson/Polyfills/assert.hpp>
+#include <ArduinoJson/Polyfills/attributes.hpp>
+#include <ArduinoJson/Polyfills/type_traits.hpp>
+#include <ArduinoJson/Serialization/CountingDecorator.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+template <typename TWriter>
+class TextFormatter {
+ public:
+ explicit TextFormatter(TWriter writer) : _writer(writer) {}
+
+ // Returns the number of bytes sent to the TWriter implementation.
+ size_t bytesWritten() const {
+ return _writer.count();
+ }
+
+ void writeBoolean(bool value) {
+ if (value)
+ writeRaw("true");
+ else
+ writeRaw("false");
+ }
+
+ void writeString(const char *value) {
+ ARDUINOJSON_ASSERT(value != NULL);
+ writeRaw('\"');
+ while (*value) writeChar(*value++);
+ writeRaw('\"');
+ }
+
+ void writeChar(char c) {
+ char specialChar = EscapeSequence::escapeChar(c);
+ if (specialChar) {
+ writeRaw('\\');
+ writeRaw(specialChar);
+ } else {
+ writeRaw(c);
+ }
+ }
+
+ template <typename T>
+ void writeFloat(T value) {
+ if (isnan(value))
+ return writeRaw(ARDUINOJSON_ENABLE_NAN ? "NaN" : "null");
+
+#if ARDUINOJSON_ENABLE_INFINITY
+ if (value < 0.0) {
+ writeRaw('-');
+ value = -value;
+ }
+
+ if (isinf(value))
+ return writeRaw("Infinity");
+#else
+ if (isinf(value))
+ return writeRaw("null");
+
+ if (value < 0.0) {
+ writeRaw('-');
+ value = -value;
+ }
+#endif
+
+ FloatParts<T> parts(value);
+
+ writeInteger(parts.integral);
+ if (parts.decimalPlaces)
+ writeDecimals(parts.decimal, parts.decimalPlaces);
+
+ if (parts.exponent) {
+ writeRaw('e');
+ writeInteger(parts.exponent);
+ }
+ }
+
+ template <typename T>
+ typename enable_if<is_signed<T>::value>::type writeInteger(T value) {
+ typedef typename make_unsigned<T>::type unsigned_type;
+ unsigned_type unsigned_value;
+ if (value < 0) {
+ writeRaw('-');
+ unsigned_value = unsigned_type(unsigned_type(~value) + 1);
+ } else {
+ unsigned_value = unsigned_type(value);
+ }
+ writeInteger(unsigned_value);
+ }
+
+ template <typename T>
+ typename enable_if<is_unsigned<T>::value>::type writeInteger(T value) {
+ char buffer[22];
+ char *end = buffer + sizeof(buffer);
+ char *begin = end;
+
+ // write the string in reverse order
+ do {
+ *--begin = char(value % 10 + '0');
+ value = T(value / 10);
+ } while (value);
+
+ // and dump it in the right order
+ writeRaw(begin, end);
+ }
+
+ void writeDecimals(uint32_t value, int8_t width) {
+ // buffer should be big enough for all digits and the dot
+ char buffer[16];
+ char *end = buffer + sizeof(buffer);
+ char *begin = end;
+
+ // write the string in reverse order
+ while (width--) {
+ *--begin = char(value % 10 + '0');
+ value /= 10;
+ }
+ *--begin = '.';
+
+ // and dump it in the right order
+ writeRaw(begin, end);
+ }
+
+ void writeRaw(const char *s) {
+ _writer.write(reinterpret_cast<const uint8_t *>(s), strlen(s));
+ }
+
+ void writeRaw(const char *s, size_t n) {
+ _writer.write(reinterpret_cast<const uint8_t *>(s), n);
+ }
+
+ void writeRaw(const char *begin, const char *end) {
+ _writer.write(reinterpret_cast<const uint8_t *>(begin),
+ static_cast<size_t>(end - begin));
+ }
+
+ template <size_t N>
+ void writeRaw(const char (&s)[N]) {
+ _writer.write(reinterpret_cast<const uint8_t *>(s), N - 1);
+ }
+ void writeRaw(char c) {
+ _writer.write(static_cast<uint8_t>(c));
+ }
+
+ protected:
+ CountingDecorator<TWriter> _writer;
+ size_t _length;
+
+ private:
+ TextFormatter &operator=(const TextFormatter &); // cannot be assigned
+};
+} // namespace ARDUINOJSON_NAMESPACE
diff --git a/include/lib/ArduinoJson/Json/Utf16.hpp b/include/lib/ArduinoJson/Json/Utf16.hpp
new file mode 100644
index 0000000..4e2750f
--- /dev/null
+++ b/include/lib/ArduinoJson/Json/Utf16.hpp
@@ -0,0 +1,67 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Namespace.hpp>
+
+#include <stdint.h> // uint16_t, uint32_t
+
+// The high surrogate may be uninitialized if the pair is invalid,
+// we choose to ignore the problem to reduce the size of the code
+// Garbage in => Garbage out
+#if defined(__GNUC__)
+#if __GNUC__ >= 7
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+#endif
+
+namespace ARDUINOJSON_NAMESPACE {
+
+namespace Utf16 {
+inline bool isHighSurrogate(uint16_t codeunit) {
+ return codeunit >= 0xD800 && codeunit < 0xDC00;
+}
+
+inline bool isLowSurrogate(uint16_t codeunit) {
+ return codeunit >= 0xDC00 && codeunit < 0xE000;
+}
+
+class Codepoint {
+ public:
+ Codepoint() : _highSurrogate(0) {}
+
+ bool append(uint16_t codeunit) {
+ if (isHighSurrogate(codeunit)) {
+ _highSurrogate = codeunit & 0x3FF;
+ return false;
+ }
+
+ if (isLowSurrogate(codeunit)) {
+ _codepoint =
+ uint32_t(0x10000 + ((_highSurrogate << 10) | (codeunit & 0x3FF)));
+ return true;
+ }
+
+ _codepoint = codeunit;
+ return true;
+ }
+
+ uint32_t value() const {
+ return _codepoint;
+ }
+
+ private:
+ uint16_t _highSurrogate;
+ uint32_t _codepoint;
+};
+} // namespace Utf16
+} // namespace ARDUINOJSON_NAMESPACE
+
+#if defined(__GNUC__)
+#if __GNUC__ >= 8
+#pragma GCC diagnostic pop
+#endif
+#endif
diff --git a/include/lib/ArduinoJson/Json/Utf8.hpp b/include/lib/ArduinoJson/Json/Utf8.hpp
new file mode 100644
index 0000000..a30f77a
--- /dev/null
+++ b/include/lib/ArduinoJson/Json/Utf8.hpp
@@ -0,0 +1,46 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright Benoit Blanchon 2014-2021
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Namespace.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+namespace Utf8 {
+template <typename TStringBuilder>
+inline void encodeCodepoint(uint32_t codepoint32, TStringBuilder& str) {
+ // this function was optimize for code size on AVR
+
+ // a buffer to store the string in reverse
+ char buf[5];
+ char* p = buf;
+
+ *(p++) = 0;
+ if (codepoint32 < 0x80) {
+ *(p++) = char((codepoint32));
+ } else {
+ *(p++) = char((codepoint32 | 0x80) & 0xBF);
+ uint16_t codepoint16 = uint16_t(codepoint32 >> 6);
+ if (codepoint16 < 0x20) { // 0x800
+ *(p++) = char(codepoint16 | 0xC0);
+ } else {
+ *(p++) = char((codepoint16 | 0x80) & 0xBF);
+ codepoint16 = uint16_t(codepoint16 >> 6);
+ if (codepoint16 < 0x10) { // 0x10000
+ *(p++) = char(codepoint16 | 0xE0);
+ } else {
+ *(p++) = char((codepoint16 | 0x80) & 0xBF);
+ codepoint16 = uint16_t(codepoint16 >> 6);
+ *(p++) = char(codepoint16 | 0xF0);
+ }
+ }
+ }
+
+ while (*(--p)) {
+ str.append(*p);
+ }
+}
+} // namespace Utf8
+} // namespace ARDUINOJSON_NAMESPACE