diff options
author | Daniel Friesel <daniel.friesel@uos.de> | 2021-05-12 09:12:09 +0200 |
---|---|---|
committer | Daniel Friesel <daniel.friesel@uos.de> | 2021-05-12 09:12:09 +0200 |
commit | 39895a677e5d370824e702cfe90ebc67737b8482 (patch) | |
tree | ff5b4cc9e373d33a795d50d9333e05549bd9f2b8 /include/lib/ArduinoJson/Json | |
parent | 42e7fdf01c3a5701bb51e93ad6c650c3dbbc5450 (diff) |
import ArduinoJson 6.18.0
Diffstat (limited to 'include/lib/ArduinoJson/Json')
-rw-r--r-- | include/lib/ArduinoJson/Json/EscapeSequence.hpp | 39 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Json/JsonDeserializer.hpp | 740 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Json/JsonSerializer.hpp | 137 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Json/Latch.hpp | 55 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Json/PrettyJsonSerializer.hpp | 89 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Json/TextFormatter.hpp | 163 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Json/Utf16.hpp | 67 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Json/Utf8.hpp | 46 |
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 |