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 | |
parent | 42e7fdf01c3a5701bb51e93ad6c650c3dbbc5450 (diff) |
import ArduinoJson 6.18.0
Diffstat (limited to 'include/lib')
136 files changed, 10934 insertions, 0 deletions
diff --git a/include/lib/ArduinoJson.h b/include/lib/ArduinoJson.h new file mode 100644 index 0000000..28d42ee --- /dev/null +++ b/include/lib/ArduinoJson.h @@ -0,0 +1,73 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include "ArduinoJson/Configuration.hpp" + +#if !ARDUINOJSON_DEBUG +#ifdef __clang__ +#pragma clang system_header +#elif defined __GNUC__ +#pragma GCC system_header +#endif +#endif + +#include "ArduinoJson/Array/ArrayRef.hpp" +#include "ArduinoJson/Object/ObjectRef.hpp" +#include "ArduinoJson/Variant/VariantRef.hpp" + +#include "ArduinoJson/Document/DynamicJsonDocument.hpp" +#include "ArduinoJson/Document/StaticJsonDocument.hpp" + +#include "ArduinoJson/Array/ArrayImpl.hpp" +#include "ArduinoJson/Array/ElementProxy.hpp" +#include "ArduinoJson/Array/Utilities.hpp" +#include "ArduinoJson/Collection/CollectionImpl.hpp" +#include "ArduinoJson/Object/MemberProxy.hpp" +#include "ArduinoJson/Object/ObjectImpl.hpp" +#include "ArduinoJson/Variant/ConverterImpl.hpp" +#include "ArduinoJson/Variant/VariantCompare.hpp" +#include "ArduinoJson/Variant/VariantImpl.hpp" + +#include "ArduinoJson/Json/JsonDeserializer.hpp" +#include "ArduinoJson/Json/JsonSerializer.hpp" +#include "ArduinoJson/Json/PrettyJsonSerializer.hpp" +#include "ArduinoJson/MsgPack/MsgPackDeserializer.hpp" +#include "ArduinoJson/MsgPack/MsgPackSerializer.hpp" + +#include "ArduinoJson/compatibility.hpp" + +namespace ArduinoJson { +typedef ARDUINOJSON_NAMESPACE::ArrayConstRef JsonArrayConst; +typedef ARDUINOJSON_NAMESPACE::ArrayRef JsonArray; +typedef ARDUINOJSON_NAMESPACE::Float JsonFloat; +typedef ARDUINOJSON_NAMESPACE::Integer JsonInteger; +typedef ARDUINOJSON_NAMESPACE::ObjectConstRef JsonObjectConst; +typedef ARDUINOJSON_NAMESPACE::ObjectRef JsonObject; +typedef ARDUINOJSON_NAMESPACE::Pair JsonPair; +typedef ARDUINOJSON_NAMESPACE::PairConst JsonPairConst; +typedef ARDUINOJSON_NAMESPACE::String JsonString; +typedef ARDUINOJSON_NAMESPACE::UInt JsonUInt; +typedef ARDUINOJSON_NAMESPACE::VariantConstRef JsonVariantConst; +typedef ARDUINOJSON_NAMESPACE::VariantRef JsonVariant; +using ARDUINOJSON_NAMESPACE::BasicJsonDocument; +using ARDUINOJSON_NAMESPACE::copyArray; +using ARDUINOJSON_NAMESPACE::DeserializationError; +using ARDUINOJSON_NAMESPACE::deserializeJson; +using ARDUINOJSON_NAMESPACE::deserializeMsgPack; +using ARDUINOJSON_NAMESPACE::DynamicJsonDocument; +using ARDUINOJSON_NAMESPACE::JsonDocument; +using ARDUINOJSON_NAMESPACE::measureJson; +using ARDUINOJSON_NAMESPACE::serialized; +using ARDUINOJSON_NAMESPACE::serializeJson; +using ARDUINOJSON_NAMESPACE::serializeJsonPretty; +using ARDUINOJSON_NAMESPACE::serializeMsgPack; +using ARDUINOJSON_NAMESPACE::StaticJsonDocument; + +namespace DeserializationOption { +using ARDUINOJSON_NAMESPACE::Filter; +using ARDUINOJSON_NAMESPACE::NestingLimit; +} // namespace DeserializationOption +} // namespace ArduinoJson diff --git a/include/lib/ArduinoJson/Array/ArrayFunctions.hpp b/include/lib/ArduinoJson/Array/ArrayFunctions.hpp new file mode 100644 index 0000000..e7cdc4c --- /dev/null +++ b/include/lib/ArduinoJson/Array/ArrayFunctions.hpp @@ -0,0 +1,31 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Collection/CollectionData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +inline VariantData *arrayAdd(CollectionData *arr, MemoryPool *pool) { + return arr ? arr->addElement(pool) : 0; +} + +template <typename TVisitor> +inline typename TVisitor::result_type arrayAccept(const CollectionData *arr, + TVisitor &visitor) { + if (arr) + return visitor.visitArray(*arr); + else + return visitor.visitNull(); +} + +inline bool arrayEquals(const CollectionData *lhs, const CollectionData *rhs) { + if (lhs == rhs) + return true; + if (!lhs || !rhs) + return false; + return lhs->equalsArray(*rhs); +} +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Array/ArrayImpl.hpp b/include/lib/ArduinoJson/Array/ArrayImpl.hpp new file mode 100644 index 0000000..ae06b20 --- /dev/null +++ b/include/lib/ArduinoJson/Array/ArrayImpl.hpp @@ -0,0 +1,28 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Array/ArrayRef.hpp> +#include <ArduinoJson/Object/ObjectRef.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TArray> +inline ArrayRef ArrayShortcuts<TArray>::createNestedArray() const { + return impl()->addElement().template to<ArrayRef>(); +} + +template <typename TArray> +inline ObjectRef ArrayShortcuts<TArray>::createNestedObject() const { + return impl()->addElement().template to<ObjectRef>(); +} + +template <typename TArray> +inline ElementProxy<TArray> ArrayShortcuts<TArray>::operator[]( + size_t index) const { + return ElementProxy<TArray>(*impl(), index); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Array/ArrayIterator.hpp b/include/lib/ArduinoJson/Array/ArrayIterator.hpp new file mode 100644 index 0000000..fcacc6b --- /dev/null +++ b/include/lib/ArduinoJson/Array/ArrayIterator.hpp @@ -0,0 +1,121 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Variant/SlotFunctions.hpp> +#include <ArduinoJson/Variant/VariantRef.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +class VariantPtr { + public: + VariantPtr(MemoryPool *pool, VariantData *data) : _variant(pool, data) {} + + VariantRef *operator->() { + return &_variant; + } + + VariantRef &operator*() { + return _variant; + } + + private: + VariantRef _variant; +}; + +class ArrayIterator { + public: + ArrayIterator() : _slot(0) {} + explicit ArrayIterator(MemoryPool *pool, VariantSlot *slot) + : _pool(pool), _slot(slot) {} + + VariantRef operator*() const { + return VariantRef(_pool, _slot->data()); + } + VariantPtr operator->() { + return VariantPtr(_pool, _slot->data()); + } + + bool operator==(const ArrayIterator &other) const { + return _slot == other._slot; + } + + bool operator!=(const ArrayIterator &other) const { + return _slot != other._slot; + } + + ArrayIterator &operator++() { + _slot = _slot->next(); + return *this; + } + + ArrayIterator &operator+=(size_t distance) { + _slot = _slot->next(distance); + return *this; + } + + VariantSlot *internal() { + return _slot; + } + + private: + MemoryPool *_pool; + VariantSlot *_slot; +}; + +class VariantConstPtr { + public: + VariantConstPtr(const VariantData *data) : _variant(data) {} + + VariantConstRef *operator->() { + return &_variant; + } + + VariantConstRef &operator*() { + return _variant; + } + + private: + VariantConstRef _variant; +}; + +class ArrayConstRefIterator { + public: + ArrayConstRefIterator() : _slot(0) {} + explicit ArrayConstRefIterator(const VariantSlot *slot) : _slot(slot) {} + + VariantConstRef operator*() const { + return VariantConstRef(_slot->data()); + } + VariantConstPtr operator->() { + return VariantConstPtr(_slot->data()); + } + + bool operator==(const ArrayConstRefIterator &other) const { + return _slot == other._slot; + } + + bool operator!=(const ArrayConstRefIterator &other) const { + return _slot != other._slot; + } + + ArrayConstRefIterator &operator++() { + _slot = _slot->next(); + return *this; + } + + ArrayConstRefIterator &operator+=(size_t distance) { + _slot = _slot->next(distance); + return *this; + } + + const VariantSlot *internal() { + return _slot; + } + + private: + const VariantSlot *_slot; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Array/ArrayRef.hpp b/include/lib/ArduinoJson/Array/ArrayRef.hpp new file mode 100644 index 0000000..a991db0 --- /dev/null +++ b/include/lib/ArduinoJson/Array/ArrayRef.hpp @@ -0,0 +1,205 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Array/ArrayFunctions.hpp> +#include <ArduinoJson/Array/ArrayIterator.hpp> +#include <ArduinoJson/Variant/VariantData.hpp> + +// Returns the size (in bytes) of an array with n elements. +// Can be very handy to determine the size of a StaticMemoryPool. +#define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \ + ((NUMBER_OF_ELEMENTS) * sizeof(ARDUINOJSON_NAMESPACE::VariantSlot)) + +namespace ARDUINOJSON_NAMESPACE { + +class ObjectRef; +template <typename> +class ElementProxy; + +template <typename TData> +class ArrayRefBase { + public: + operator VariantConstRef() const { + const void* data = _data; // prevent warning cast-align + return VariantConstRef(reinterpret_cast<const VariantData*>(data)); + } + + template <typename TVisitor> + FORCE_INLINE typename TVisitor::result_type accept(TVisitor& visitor) const { + return arrayAccept(_data, visitor); + } + + FORCE_INLINE bool isNull() const { + return _data == 0; + } + + FORCE_INLINE operator bool() const { + return _data != 0; + } + + FORCE_INLINE size_t memoryUsage() const { + return _data ? _data->memoryUsage() : 0; + } + + FORCE_INLINE size_t nesting() const { + return _data ? _data->nesting() : 0; + } + + FORCE_INLINE size_t size() const { + return _data ? _data->size() : 0; + } + + protected: + ArrayRefBase(TData* data) : _data(data) {} + TData* _data; +}; + +class ArrayConstRef : public ArrayRefBase<const CollectionData>, + public Visitable { + friend class ArrayRef; + typedef ArrayRefBase<const CollectionData> base_type; + + public: + typedef ArrayConstRefIterator iterator; + + FORCE_INLINE iterator begin() const { + if (!_data) + return iterator(); + return iterator(_data->head()); + } + + FORCE_INLINE iterator end() const { + return iterator(); + } + + FORCE_INLINE ArrayConstRef() : base_type(0) {} + FORCE_INLINE ArrayConstRef(const CollectionData* data) : base_type(data) {} + + FORCE_INLINE bool operator==(ArrayConstRef rhs) const { + return arrayEquals(_data, rhs._data); + } + + FORCE_INLINE VariantConstRef operator[](size_t index) const { + return getElement(index); + } + + FORCE_INLINE VariantConstRef getElement(size_t index) const { + return VariantConstRef(_data ? _data->getElement(index) : 0); + } +}; + +class ArrayRef : public ArrayRefBase<CollectionData>, + public ArrayShortcuts<ArrayRef>, + public Visitable { + typedef ArrayRefBase<CollectionData> base_type; + + public: + typedef ArrayIterator iterator; + + FORCE_INLINE ArrayRef() : base_type(0), _pool(0) {} + FORCE_INLINE ArrayRef(MemoryPool* pool, CollectionData* data) + : base_type(data), _pool(pool) {} + + operator VariantRef() { + void* data = _data; // prevent warning cast-align + return VariantRef(_pool, reinterpret_cast<VariantData*>(data)); + } + + operator ArrayConstRef() const { + return ArrayConstRef(_data); + } + + VariantRef addElement() const { + return VariantRef(_pool, arrayAdd(_data, _pool)); + } + + FORCE_INLINE iterator begin() const { + if (!_data) + return iterator(); + return iterator(_pool, _data->head()); + } + + FORCE_INLINE iterator end() const { + return iterator(); + } + + // Copy a ArrayRef + FORCE_INLINE bool set(ArrayConstRef src) const { + if (!_data || !src._data) + return false; + return _data->copyFrom(*src._data, _pool); + } + + FORCE_INLINE bool operator==(ArrayRef rhs) const { + return arrayEquals(_data, rhs._data); + } + + // Internal use + FORCE_INLINE VariantRef getOrAddElement(size_t index) const { + return VariantRef(_pool, _data ? _data->getOrAddElement(index, _pool) : 0); + } + + // Gets the value at the specified index. + FORCE_INLINE VariantRef getElement(size_t index) const { + return VariantRef(_pool, _data ? _data->getElement(index) : 0); + } + + // Removes element at specified position. + FORCE_INLINE void remove(iterator it) const { + if (!_data) + return; + _data->removeSlot(it.internal()); + } + + // Removes element at specified index. + FORCE_INLINE void remove(size_t index) const { + if (!_data) + return; + _data->removeElement(index); + } + + private: + MemoryPool* _pool; +}; + +template <> +struct Converter<ArrayConstRef> { + static bool toJson(VariantConstRef src, VariantRef dst) { + return variantCopyFrom(getData(dst), getData(src), getPool(dst)); + } + + static ArrayConstRef fromJson(VariantConstRef src) { + return ArrayConstRef(variantAsArray(getData(src))); + } + + static bool checkJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data && data->isArray(); + } +}; + +template <> +struct Converter<ArrayRef> { + static bool toJson(VariantConstRef src, VariantRef dst) { + return variantCopyFrom(getData(dst), getData(src), getPool(dst)); + } + + static ArrayRef fromJson(VariantRef src) { + VariantData* data = getData(src); + MemoryPool* pool = getPool(src); + return ArrayRef(pool, data != 0 ? data->asArray() : 0); + } + + static bool checkJson(VariantConstRef) { + return false; + } + + static bool checkJson(VariantRef src) { + VariantData* data = getData(src); + return data && data->isArray(); + } +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Array/ArrayShortcuts.hpp b/include/lib/ArduinoJson/Array/ArrayShortcuts.hpp new file mode 100644 index 0000000..fd26d04 --- /dev/null +++ b/include/lib/ArduinoJson/Array/ArrayShortcuts.hpp @@ -0,0 +1,49 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/attributes.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> + +namespace ARDUINOJSON_NAMESPACE { +// Forward declarations. +class ArrayRef; +class ObjectRef; +template <typename> +class ElementProxy; + +template <typename TArray> +class ArrayShortcuts { + public: + // Returns the element at specified index if the variant is an array. + FORCE_INLINE ElementProxy<TArray> operator[](size_t index) const; + + FORCE_INLINE ObjectRef createNestedObject() const; + + FORCE_INLINE ArrayRef createNestedArray() const; + + // Adds the specified value at the end of the array. + // + // bool add(TValue); + // TValue = bool, long, int, short, float, double, serialized, VariantRef, + // std::string, String, ObjectRef + template <typename T> + FORCE_INLINE bool add(const T &value) const { + return impl()->addElement().set(value); + } + // + // bool add(TValue); + // TValue = char*, const char*, const __FlashStringHelper* + template <typename T> + FORCE_INLINE bool add(T *value) const { + return impl()->addElement().set(value); + } + + private: + const TArray *impl() const { + return static_cast<const TArray *>(this); + } +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Array/ElementProxy.hpp b/include/lib/ArduinoJson/Array/ElementProxy.hpp new file mode 100644 index 0000000..c6062e4 --- /dev/null +++ b/include/lib/ArduinoJson/Array/ElementProxy.hpp @@ -0,0 +1,193 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Variant/VariantOperators.hpp> +#include <ArduinoJson/Variant/VariantShortcuts.hpp> +#include <ArduinoJson/Variant/VariantTo.hpp> + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4522) +#endif + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TArray> +class ElementProxy : public VariantOperators<ElementProxy<TArray> >, + public VariantShortcuts<ElementProxy<TArray> >, + public Visitable, + public VariantTag { + typedef ElementProxy<TArray> this_type; + + public: + typedef VariantRef variant_type; + + FORCE_INLINE ElementProxy(TArray array, size_t index) + : _array(array), _index(index) {} + + FORCE_INLINE ElementProxy(const ElementProxy& src) + : _array(src._array), _index(src._index) {} + + FORCE_INLINE this_type& operator=(const this_type& src) { + getOrAddUpstreamElement().set(src.as<VariantConstRef>()); + return *this; + } + + // Replaces the value + // + // operator=(const TValue&) + // TValue = bool, long, int, short, float, double, serialized, VariantRef, + // std::string, String, ArrayRef, ObjectRef + template <typename T> + FORCE_INLINE this_type& operator=(const T& src) { + getOrAddUpstreamElement().set(src); + return *this; + } + // + // operator=(TValue) + // TValue = char*, const char*, const __FlashStringHelper* + template <typename T> + FORCE_INLINE this_type& operator=(T* src) { + getOrAddUpstreamElement().set(src); + return *this; + } + + FORCE_INLINE void clear() const { + getUpstreamElement().clear(); + } + + FORCE_INLINE bool isNull() const { + return getUpstreamElement().isNull(); + } + + template <typename T> + FORCE_INLINE typename enable_if<!is_same<T, char*>::value, T>::type as() + const { + return getUpstreamElement().template as<T>(); + } + + template <typename T> + FORCE_INLINE typename enable_if<is_same<T, char*>::value, const char*>::type + ARDUINOJSON_DEPRECATED("Replace as<char*>() with as<const char*>()") + as() const { + return as<const char*>(); + } + + template <typename T> + FORCE_INLINE operator T() const { + return getUpstreamElement(); + } + + template <typename T> + FORCE_INLINE bool is() const { + return getUpstreamElement().template is<T>(); + } + + template <typename T> + FORCE_INLINE typename VariantTo<T>::type to() const { + return getOrAddUpstreamElement().template to<T>(); + } + + // Replaces the value + // + // bool set(const TValue&) + // TValue = bool, long, int, short, float, double, serialized, VariantRef, + // std::string, String, ArrayRef, ObjectRef + template <typename TValue> + FORCE_INLINE bool set(const TValue& value) const { + return getOrAddUpstreamElement().set(value); + } + // + // bool set(TValue) + // TValue = char*, const char*, const __FlashStringHelper* + template <typename TValue> + FORCE_INLINE bool set(TValue* value) const { + return getOrAddUpstreamElement().set(value); + } + + template <typename TVisitor> + typename TVisitor::result_type accept(TVisitor& visitor) const { + return getUpstreamElement().accept(visitor); + } + + FORCE_INLINE size_t size() const { + return getUpstreamElement().size(); + } + + template <typename TNestedKey> + VariantRef getMember(TNestedKey* key) const { + return getUpstreamElement().getMember(key); + } + + template <typename TNestedKey> + VariantRef getMember(const TNestedKey& key) const { + return getUpstreamElement().getMember(key); + } + + template <typename TNestedKey> + VariantRef getOrAddMember(TNestedKey* key) const { + return getOrAddUpstreamElement().getOrAddMember(key); + } + + template <typename TNestedKey> + VariantRef getOrAddMember(const TNestedKey& key) const { + return getOrAddUpstreamElement().getOrAddMember(key); + } + + VariantRef addElement() const { + return getOrAddUpstreamElement().addElement(); + } + + VariantRef getElement(size_t index) const { + return getOrAddUpstreamElement().getElement(index); + } + + VariantRef getOrAddElement(size_t index) const { + return getOrAddUpstreamElement().getOrAddElement(index); + } + + FORCE_INLINE void remove(size_t index) const { + getUpstreamElement().remove(index); + } + // remove(char*) const + // remove(const char*) const + // remove(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE typename enable_if<IsString<TChar*>::value>::type remove( + TChar* key) const { + getUpstreamElement().remove(key); + } + // remove(const std::string&) const + // remove(const String&) const + template <typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove( + const TString& key) const { + getUpstreamElement().remove(key); + } + + private: + FORCE_INLINE VariantRef getUpstreamElement() const { + return _array.getElement(_index); + } + + FORCE_INLINE VariantRef getOrAddUpstreamElement() const { + return _array.getOrAddElement(_index); + } + + friend bool convertToJson(const this_type& src, VariantRef dst) { + return dst.set(src.getUpstreamElement()); + } + + TArray _array; + const size_t _index; +}; + +} // namespace ARDUINOJSON_NAMESPACE + +#ifdef _MSC_VER +#pragma warning(pop) +#endif diff --git a/include/lib/ArduinoJson/Array/Utilities.hpp b/include/lib/ArduinoJson/Array/Utilities.hpp new file mode 100644 index 0000000..619b91d --- /dev/null +++ b/include/lib/ArduinoJson/Array/Utilities.hpp @@ -0,0 +1,133 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Array/ArrayRef.hpp> +#include <ArduinoJson/Document/JsonDocument.hpp> +#include <ArduinoJson/Variant/Visitor.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +// Copy a 1D array to a JsonArray +template <typename T, size_t N, typename TDestination> +inline typename enable_if<!is_array<T>::value && + !is_base_of<JsonDocument, TDestination>::value, + bool>::type +copyArray(T (&src)[N], const TDestination& dst) { + return copyArray(src, N, dst); +} + +// Copy a 1D array to a JsonDocument +template <typename T, size_t N> +inline bool copyArray(T (&src)[N], JsonDocument& dst) { + return copyArray(src, dst.to<ArrayRef>()); +} + +// Copy a 1D array to a JsonArray +template <typename T, typename TDestination> +inline typename enable_if<!is_array<T>::value && + !is_base_of<JsonDocument, TDestination>::value, + bool>::type +copyArray(T* src, size_t len, const TDestination& dst) { + bool ok = true; + for (size_t i = 0; i < len; i++) { + ok &= dst.add(src[i]); + } + return ok; +} + +// Copy a 1D array to a JsonDocument +template <typename T> +inline bool copyArray(T* src, size_t len, JsonDocument& dst) { + return copyArray(src, len, dst.to<ArrayRef>()); +} + +// Copy a 2D array to a JsonArray +template <typename T, size_t N1, size_t N2, typename TDestination> +inline typename enable_if<!is_base_of<JsonDocument, TDestination>::value, + bool>::type +copyArray(T (&src)[N1][N2], const TDestination& dst) { + bool ok = true; + for (size_t i = 0; i < N1; i++) { + ArrayRef nestedArray = dst.createNestedArray(); + for (size_t j = 0; j < N2; j++) { + ok &= nestedArray.add(src[i][j]); + } + } + return ok; +} + +// Copy a 2D array to a JsonDocument +template <typename T, size_t N1, size_t N2> +inline bool copyArray(T (&src)[N1][N2], JsonDocument& dst) { + return copyArray(src, dst.to<ArrayRef>()); +} + +template <typename T> +class ArrayCopier1D : public Visitor<size_t> { + public: + ArrayCopier1D(T* destination, size_t capacity) + : _destination(destination), _capacity(capacity) {} + + size_t visitArray(const CollectionData& array) { + size_t size = 0; + VariantSlot* slot = array.head(); + + while (slot != 0 && size < _capacity) { + _destination[size++] = + Converter<T>::fromJson(VariantConstRef(slot->data())); + slot = slot->next(); + } + return size; + } + + private: + T* _destination; + size_t _capacity; +}; + +template <typename T, size_t N1, size_t N2> +class ArrayCopier2D : public Visitor<void> { + public: + ArrayCopier2D(T (*destination)[N1][N2]) : _destination(destination) {} + + void visitArray(const CollectionData& array) { + VariantSlot* slot = array.head(); + size_t n = 0; + while (slot != 0 && n < N1) { + ArrayCopier1D<T> copier((*_destination)[n++], N2); + variantAccept(slot->data(), copier); + slot = slot->next(); + } + } + + private: + T (*_destination)[N1][N2]; + size_t _capacity1, _capacity2; +}; + +// Copy a JsonArray to a 1D array +template <typename TSource, typename T, size_t N> +inline typename enable_if<!is_array<T>::value, size_t>::type copyArray( + const TSource& src, T (&dst)[N]) { + return copyArray(src, dst, N); +} + +// Copy a JsonArray to a 1D array +template <typename TSource, typename T> +inline size_t copyArray(const TSource& src, T* dst, size_t len) { + ArrayCopier1D<T> copier(dst, len); + + return src.accept(copier); +} + +// Copy a JsonArray to a 2D array +template <typename TSource, typename T, size_t N1, size_t N2> +inline void copyArray(const TSource& src, T (&dst)[N1][N2]) { + ArrayCopier2D<T, N1, N2> copier(&dst); + src.accept(copier); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Collection/CollectionData.hpp b/include/lib/ArduinoJson/Collection/CollectionData.hpp new file mode 100644 index 0000000..d2bca45 --- /dev/null +++ b/include/lib/ArduinoJson/Collection/CollectionData.hpp @@ -0,0 +1,88 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Polyfills/assert.hpp> + +#include <stddef.h> // size_t + +namespace ARDUINOJSON_NAMESPACE { + +class MemoryPool; +class VariantData; +class VariantSlot; + +class CollectionData { + VariantSlot *_head; + VariantSlot *_tail; + + public: + // Must be a POD! + // - no constructor + // - no destructor + // - no virtual + // - no inheritance + + // Array only + + VariantData *addElement(MemoryPool *pool); + + VariantData *getElement(size_t index) const; + + VariantData *getOrAddElement(size_t index, MemoryPool *pool); + + void removeElement(size_t index); + + bool equalsArray(const CollectionData &other) const; + + // Object only + + template <typename TAdaptedString> + VariantData *addMember(TAdaptedString key, MemoryPool *pool); + + template <typename TAdaptedString> + VariantData *getMember(TAdaptedString key) const; + + template <typename TAdaptedString> + VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool); + + template <typename TAdaptedString> + void removeMember(TAdaptedString key) { + removeSlot(getSlot(key)); + } + + template <typename TAdaptedString> + bool containsKey(const TAdaptedString &key) const; + + bool equalsObject(const CollectionData &other) const; + + // Generic + + void clear(); + size_t memoryUsage() const; + size_t nesting() const; + size_t size() const; + + VariantSlot *addSlot(MemoryPool *); + void removeSlot(VariantSlot *slot); + + bool copyFrom(const CollectionData &src, MemoryPool *pool); + + VariantSlot *head() const { + return _head; + } + + void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance); + + private: + VariantSlot *getSlot(size_t index) const; + + template <typename TAdaptedString> + VariantSlot *getSlot(TAdaptedString key) const; + + VariantSlot *getPreviousSlot(VariantSlot *) const; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Collection/CollectionImpl.hpp b/include/lib/ArduinoJson/Collection/CollectionImpl.hpp new file mode 100644 index 0000000..49a24be --- /dev/null +++ b/include/lib/ArduinoJson/Collection/CollectionImpl.hpp @@ -0,0 +1,234 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Collection/CollectionData.hpp> +#include <ArduinoJson/Variant/VariantData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +inline bool variantEquals(const VariantData* a, const VariantData* b) { + return variantCompare(a, b) == COMPARE_RESULT_EQUAL; +} + +inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) { + VariantSlot* slot = pool->allocVariant(); + if (!slot) + return 0; + + if (_tail) { + _tail->setNextNotNull(slot); + _tail = slot; + } else { + _head = slot; + _tail = slot; + } + + slot->clear(); + return slot; +} + +inline VariantData* CollectionData::addElement(MemoryPool* pool) { + return slotData(addSlot(pool)); +} + +template <typename TAdaptedString> +inline VariantData* CollectionData::addMember(TAdaptedString key, + MemoryPool* pool) { + VariantSlot* slot = addSlot(pool); + if (!slotSetKey(slot, key, pool)) { + removeSlot(slot); + return 0; + } + return slot->data(); +} + +inline void CollectionData::clear() { + _head = 0; + _tail = 0; +} + +template <typename TAdaptedString> +inline bool CollectionData::containsKey(const TAdaptedString& key) const { + return getSlot(key) != 0; +} + +inline bool CollectionData::copyFrom(const CollectionData& src, + MemoryPool* pool) { + clear(); + for (VariantSlot* s = src._head; s; s = s->next()) { + VariantData* var; + if (s->key() != 0) { + if (s->ownsKey()) + var = addMember(RamStringAdapter(s->key()), pool); + else + var = addMember(ConstRamStringAdapter(s->key()), pool); + } else { + var = addElement(pool); + } + if (!var) + return false; + if (!var->copyFrom(*s->data(), pool)) + return false; + } + return true; +} + +inline bool CollectionData::equalsObject(const CollectionData& other) const { + size_t count = 0; + for (VariantSlot* slot = _head; slot; slot = slot->next()) { + VariantData* v1 = slot->data(); + VariantData* v2 = other.getMember(adaptString(slot->key())); + if (!variantEquals(v1, v2)) + return false; + count++; + } + return count == other.size(); +} + +inline bool CollectionData::equalsArray(const CollectionData& other) const { + VariantSlot* s1 = _head; + VariantSlot* s2 = other._head; + for (;;) { + if (s1 == s2) + return true; + if (!s1 || !s2) + return false; + if (!variantEquals(s1->data(), s2->data())) + return false; + s1 = s1->next(); + s2 = s2->next(); + } +} + +template <typename TAdaptedString> +inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const { + VariantSlot* slot = _head; + while (slot) { + if (key.equals(slot->key())) + break; + slot = slot->next(); + } + return slot; +} + +inline VariantSlot* CollectionData::getSlot(size_t index) const { + if (!_head) + return 0; + return _head->next(index); +} + +inline VariantSlot* CollectionData::getPreviousSlot(VariantSlot* target) const { + VariantSlot* current = _head; + while (current) { + VariantSlot* next = current->next(); + if (next == target) + return current; + current = next; + } + return 0; +} + +template <typename TAdaptedString> +inline VariantData* CollectionData::getMember(TAdaptedString key) const { + VariantSlot* slot = getSlot(key); + return slot ? slot->data() : 0; +} + +template <typename TAdaptedString> +inline VariantData* CollectionData::getOrAddMember(TAdaptedString key, + MemoryPool* pool) { + // ignore null key + if (key.isNull()) + return 0; + + // search a matching key + VariantSlot* slot = getSlot(key); + if (slot) + return slot->data(); + + return addMember(key, pool); +} + +inline VariantData* CollectionData::getElement(size_t index) const { + VariantSlot* slot = getSlot(index); + return slot ? slot->data() : 0; +} + +inline VariantData* CollectionData::getOrAddElement(size_t index, + MemoryPool* pool) { + VariantSlot* slot = _head; + while (slot && index > 0) { + slot = slot->next(); + index--; + } + if (!slot) + index++; + while (index > 0) { + slot = addSlot(pool); + index--; + } + return slotData(slot); +} + +inline void CollectionData::removeSlot(VariantSlot* slot) { + if (!slot) + return; + VariantSlot* prev = getPreviousSlot(slot); + VariantSlot* next = slot->next(); + if (prev) + prev->setNext(next); + else + _head = next; + if (!next) + _tail = prev; +} + +inline void CollectionData::removeElement(size_t index) { + removeSlot(getSlot(index)); +} + +inline size_t CollectionData::memoryUsage() const { + size_t total = 0; + for (VariantSlot* s = _head; s; s = s->next()) { + total += sizeof(VariantSlot) + s->data()->memoryUsage(); + if (s->ownsKey()) + total += strlen(s->key()) + 1; + } + return total; +} + +inline size_t CollectionData::nesting() const { + size_t maxChildNesting = 0; + for (VariantSlot* s = _head; s; s = s->next()) { + size_t childNesting = s->data()->nesting(); + if (childNesting > maxChildNesting) + maxChildNesting = childNesting; + } + return maxChildNesting + 1; +} + +inline size_t CollectionData::size() const { + return slotSize(_head); +} + +template <typename T> +inline void movePointer(T*& p, ptrdiff_t offset) { + if (!p) + return; + p = reinterpret_cast<T*>( + reinterpret_cast<void*>(reinterpret_cast<char*>(p) + offset)); + ARDUINOJSON_ASSERT(isAligned(p)); +} + +inline void CollectionData::movePointers(ptrdiff_t stringDistance, + ptrdiff_t variantDistance) { + movePointer(_head, variantDistance); + movePointer(_tail, variantDistance); + for (VariantSlot* slot = _head; slot; slot = slot->next()) + slot->movePointers(stringDistance, variantDistance); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Configuration.hpp b/include/lib/ArduinoJson/Configuration.hpp new file mode 100644 index 0000000..0c0d4c4 --- /dev/null +++ b/include/lib/ArduinoJson/Configuration.hpp @@ -0,0 +1,255 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#if __cplusplus >= 201103L +#define ARDUINOJSON_HAS_LONG_LONG 1 +#define ARDUINOJSON_HAS_NULLPTR 1 +#define ARDUINOJSON_HAS_RVALUE_REFERENCES 1 +#else +#define ARDUINOJSON_HAS_LONG_LONG 0 +#define ARDUINOJSON_HAS_NULLPTR 0 +#define ARDUINOJSON_HAS_RVALUE_REFERENCES 0 +#endif + +#if defined(_MSC_VER) && !ARDUINOJSON_HAS_LONG_LONG +#define ARDUINOJSON_HAS_INT64 1 +#else +#define ARDUINOJSON_HAS_INT64 0 +#endif + +// Small or big machine? +#ifndef ARDUINOJSON_EMBEDDED_MODE +#if defined(ARDUINO) /* Arduino*/ \ + || defined(__IAR_SYSTEMS_ICC__) /* IAR Embedded Workbench */ \ + || defined(__XC) /* MPLAB XC compiler */ \ + || defined(__ARMCC_VERSION) /* Keil ARM Compiler */ \ + || defined(__AVR) /* Atmel AVR8/GNU C Compiler */ +#define ARDUINOJSON_EMBEDDED_MODE 1 +#else +#define ARDUINOJSON_EMBEDDED_MODE 0 +#endif +#endif + +// Auto enable std::stream if the right headers are here and no conflicting +// macro is defined +#if !defined(ARDUINOJSON_ENABLE_STD_STREAM) && defined(__has_include) +#if __has_include(<istream>) && \ + __has_include(<ostream>) && \ + !defined(min) && \ + !defined(max) +#define ARDUINOJSON_ENABLE_STD_STREAM 1 +#else +#define ARDUINOJSON_ENABLE_STD_STREAM 0 +#endif +#endif + +// Auto enable std::string if the right header is here and no conflicting +// macro is defined +#if !defined(ARDUINOJSON_ENABLE_STD_STRING) && defined(__has_include) +#if __has_include(<string>) && !defined(min) && !defined(max) +#define ARDUINOJSON_ENABLE_STD_STRING 1 +#else +#define ARDUINOJSON_ENABLE_STD_STRING 0 +#endif +#endif + +#if ARDUINOJSON_EMBEDDED_MODE + +// Store floats by default to reduce the memory usage (issue #134) +#ifndef ARDUINOJSON_USE_DOUBLE +#define ARDUINOJSON_USE_DOUBLE 0 +#endif + +// Store longs by default, because they usually match the size of a float. +#ifndef ARDUINOJSON_USE_LONG_LONG +#define ARDUINOJSON_USE_LONG_LONG 0 +#endif + +// Embedded systems usually don't have std::string +#ifndef ARDUINOJSON_ENABLE_STD_STRING +#define ARDUINOJSON_ENABLE_STD_STRING 0 +#endif + +// Embedded systems usually don't have std::stream +#ifndef ARDUINOJSON_ENABLE_STD_STREAM +#define ARDUINOJSON_ENABLE_STD_STREAM 0 +#endif + +// Limit nesting as the stack is likely to be small +#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT +#define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10 +#endif + +// Number of bits to store the pointer to next node +// (saves RAM but limits the number of values in a document) +#ifndef ARDUINOJSON_SLOT_OFFSET_SIZE +#if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 2 +// Address space == 16-bit => max 127 values +#define ARDUINOJSON_SLOT_OFFSET_SIZE 1 +#else +// Address space > 16-bit => max 32767 values +#define ARDUINOJSON_SLOT_OFFSET_SIZE 2 +#endif +#endif + +#else // ARDUINOJSON_EMBEDDED_MODE + +// On a computer we have plenty of memory so we can use doubles +#ifndef ARDUINOJSON_USE_DOUBLE +#define ARDUINOJSON_USE_DOUBLE 1 +#endif + +// Use long long when available +#ifndef ARDUINOJSON_USE_LONG_LONG +#if ARDUINOJSON_HAS_LONG_LONG || ARDUINOJSON_HAS_INT64 +#define ARDUINOJSON_USE_LONG_LONG 1 +#else +#define ARDUINOJSON_USE_LONG_LONG 0 +#endif +#endif + +// On a computer, we can use std::string +#ifndef ARDUINOJSON_ENABLE_STD_STRING +#define ARDUINOJSON_ENABLE_STD_STRING 1 +#endif + +// On a computer, we can assume std::stream +#ifndef ARDUINOJSON_ENABLE_STD_STREAM +#define ARDUINOJSON_ENABLE_STD_STREAM 1 +#endif + +// On a computer, the stack is large so we can increase nesting limit +#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT +#define ARDUINOJSON_DEFAULT_NESTING_LIMIT 50 +#endif + +// Number of bits to store the pointer to next node +#ifndef ARDUINOJSON_SLOT_OFFSET_SIZE +#define ARDUINOJSON_SLOT_OFFSET_SIZE 4 +#endif + +#endif // ARDUINOJSON_EMBEDDED_MODE + +#ifdef ARDUINO + +#include <Arduino.h> + +// Enable support for Arduino's String class +#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING +#define ARDUINOJSON_ENABLE_ARDUINO_STRING 1 +#endif + +// Enable support for Arduino's Stream class +#ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM +#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1 +#endif + +// Enable support for Arduino's Print class +#ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT +#define ARDUINOJSON_ENABLE_ARDUINO_PRINT 1 +#endif + +#else // ARDUINO + +// Disable support for Arduino's String class +#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING +#define ARDUINOJSON_ENABLE_ARDUINO_STRING 0 +#endif + +// Disable support for Arduino's Stream class +#ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM +#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0 +#endif + +// Disable support for Arduino's Print class +#ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT +#define ARDUINOJSON_ENABLE_ARDUINO_PRINT 0 +#endif + +#endif // ARDUINO + +#ifndef ARDUINOJSON_ENABLE_PROGMEM +#if defined(PROGMEM) && defined(pgm_read_byte) && defined(pgm_read_dword) && \ + defined(pgm_read_ptr) && defined(pgm_read_float) +#define ARDUINOJSON_ENABLE_PROGMEM 1 +#else +#define ARDUINOJSON_ENABLE_PROGMEM 0 +#endif +#endif + +// Convert unicode escape sequence (\u0123) to UTF-8 +#ifndef ARDUINOJSON_DECODE_UNICODE +#define ARDUINOJSON_DECODE_UNICODE 1 +#endif + +// Ignore comments in input +#ifndef ARDUINOJSON_ENABLE_COMMENTS +#define ARDUINOJSON_ENABLE_COMMENTS 0 +#endif + +// Support NaN in JSON +#ifndef ARDUINOJSON_ENABLE_NAN +#define ARDUINOJSON_ENABLE_NAN 0 +#endif + +// Support Infinity in JSON +#ifndef ARDUINOJSON_ENABLE_INFINITY +#define ARDUINOJSON_ENABLE_INFINITY 0 +#endif + +// Control the exponentiation threshold for big numbers +// CAUTION: cannot be more that 1e9 !!!! +#ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD +#define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e7 +#endif + +// Control the exponentiation threshold for small numbers +#ifndef ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD +#define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5 +#endif + +#ifndef ARDUINOJSON_LITTLE_ENDIAN +#if defined(_MSC_VER) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \ + defined(__LITTLE_ENDIAN__) || defined(__i386) || defined(__x86_64) +#define ARDUINOJSON_LITTLE_ENDIAN 1 +#else +#define ARDUINOJSON_LITTLE_ENDIAN 0 +#endif +#endif + +#ifndef ARDUINOJSON_ENABLE_ALIGNMENT +#if defined(__AVR) +#define ARDUINOJSON_ENABLE_ALIGNMENT 0 +#else +#define ARDUINOJSON_ENABLE_ALIGNMENT 1 +#endif +#endif + +#ifndef ARDUINOJSON_TAB +#define ARDUINOJSON_TAB " " +#endif + +#ifndef ARDUINOJSON_ENABLE_STRING_DEDUPLICATION +#define ARDUINOJSON_ENABLE_STRING_DEDUPLICATION 1 +#endif + +#ifndef ARDUINOJSON_STRING_BUFFER_SIZE +#define ARDUINOJSON_STRING_BUFFER_SIZE 32 +#endif + +#ifndef ARDUINOJSON_DEBUG +#ifdef __PLATFORMIO_BUILD_DEBUG__ +#define ARDUINOJSON_DEBUG 1 +#else +#define ARDUINOJSON_DEBUG 0 +#endif +#endif + +#if ARDUINOJSON_HAS_NULLPTR && defined(nullptr) +#error nullptr is defined as a macro. Remove the faulty #define or #undef nullptr +// See https://github.com/bblanchon/ArduinoJson/issues/1355 +#endif diff --git a/include/lib/ArduinoJson/Deserialization/DeserializationError.hpp b/include/lib/ArduinoJson/Deserialization/DeserializationError.hpp new file mode 100644 index 0000000..7b61711 --- /dev/null +++ b/include/lib/ArduinoJson/Deserialization/DeserializationError.hpp @@ -0,0 +1,122 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Polyfills/preprocessor.hpp> +#include <ArduinoJson/Polyfills/static_array.hpp> + +#if ARDUINOJSON_ENABLE_STD_STREAM +#include <ostream> +#endif + +namespace ARDUINOJSON_NAMESPACE { + +class DeserializationError { + // safe bool idiom + typedef void (DeserializationError::*bool_type)() const; + void safeBoolHelper() const {} + + public: + enum Code { + Ok, + EmptyInput, + IncompleteInput, + InvalidInput, + NoMemory, + TooDeep + }; + + DeserializationError() {} + DeserializationError(Code c) : _code(c) {} + + // Compare with DeserializationError + friend bool operator==(const DeserializationError& lhs, + const DeserializationError& rhs) { + return lhs._code == rhs._code; + } + friend bool operator!=(const DeserializationError& lhs, + const DeserializationError& rhs) { + return lhs._code != rhs._code; + } + + // Compare with Code + friend bool operator==(const DeserializationError& lhs, Code rhs) { + return lhs._code == rhs; + } + friend bool operator==(Code lhs, const DeserializationError& rhs) { + return lhs == rhs._code; + } + friend bool operator!=(const DeserializationError& lhs, Code rhs) { + return lhs._code != rhs; + } + friend bool operator!=(Code lhs, const DeserializationError& rhs) { + return lhs != rhs._code; + } + + // Behaves like a bool + operator bool_type() const { + return _code != Ok ? &DeserializationError::safeBoolHelper : 0; + } + friend bool operator==(bool value, const DeserializationError& err) { + return static_cast<bool>(err) == value; + } + friend bool operator==(const DeserializationError& err, bool value) { + return static_cast<bool>(err) == value; + } + friend bool operator!=(bool value, const DeserializationError& err) { + return static_cast<bool>(err) != value; + } + friend bool operator!=(const DeserializationError& err, bool value) { + return static_cast<bool>(err) != value; + } + + // Returns internal enum, useful for switch statement + Code code() const { + return _code; + } + + const char* c_str() const { + static const char* messages[] = { + "Ok", "EmptyInput", "IncompleteInput", + "InvalidInput", "NoMemory", "TooDeep"}; + ARDUINOJSON_ASSERT(static_cast<size_t>(_code) < + sizeof(messages) / sizeof(messages[0])); + return messages[_code]; + } + +#if ARDUINOJSON_ENABLE_PROGMEM + const __FlashStringHelper* f_str() const { + ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s0, "Ok"); + ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s1, "EmptyInput"); + ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s2, "IncompleteInput"); + ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s3, "InvalidInput"); + ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s4, "NoMemory"); + ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s5, "TooDeep"); + ARDUINOJSON_DEFINE_STATIC_ARRAY( + const char*, messages, ARDUINOJSON_EXPAND6({s0, s1, s2, s3, s4, s5})); + return ARDUINOJSON_READ_STATIC_ARRAY(const __FlashStringHelper*, messages, + _code); + } +#endif + + private: + Code _code; +}; + +#if ARDUINOJSON_ENABLE_STD_STREAM +inline std::ostream& operator<<(std::ostream& s, + const DeserializationError& e) { + s << e.c_str(); + return s; +} + +inline std::ostream& operator<<(std::ostream& s, DeserializationError::Code c) { + s << DeserializationError(c).c_str(); + return s; +} +#endif + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Deserialization/Filter.hpp b/include/lib/ArduinoJson/Deserialization/Filter.hpp new file mode 100644 index 0000000..7ea3078 --- /dev/null +++ b/include/lib/ArduinoJson/Deserialization/Filter.hpp @@ -0,0 +1,66 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +class Filter { + public: + explicit Filter(VariantConstRef v) : _variant(v) {} + + bool allow() const { + return _variant; + } + + bool allowArray() const { + return _variant == true || _variant.is<ArrayConstRef>(); + } + + bool allowObject() const { + return _variant == true || _variant.is<ObjectConstRef>(); + } + + bool allowValue() const { + return _variant == true; + } + + template <typename TKey> + Filter operator[](const TKey& key) const { + if (_variant == true) // "true" means "allow recursively" + return *this; + else + return Filter(_variant[key] | _variant["*"]); + } + + private: + VariantConstRef _variant; +}; + +struct AllowAllFilter { + bool allow() const { + return true; + } + + bool allowArray() const { + return true; + } + + bool allowObject() const { + return true; + } + + bool allowValue() const { + return true; + } + + template <typename TKey> + AllowAllFilter operator[](const TKey&) const { + return AllowAllFilter(); + } +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Deserialization/NestingLimit.hpp b/include/lib/ArduinoJson/Deserialization/NestingLimit.hpp new file mode 100644 index 0000000..06964b4 --- /dev/null +++ b/include/lib/ArduinoJson/Deserialization/NestingLimit.hpp @@ -0,0 +1,29 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Polyfills/assert.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +class NestingLimit { + public: + NestingLimit() : _value(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {} + explicit NestingLimit(uint8_t n) : _value(n) {} + + NestingLimit decrement() const { + ARDUINOJSON_ASSERT(_value > 0); + return NestingLimit(static_cast<uint8_t>(_value - 1)); + } + + bool reached() const { + return _value == 0; + } + + private: + uint8_t _value; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Deserialization/Reader.hpp b/include/lib/ArduinoJson/Deserialization/Reader.hpp new file mode 100644 index 0000000..e965c82 --- /dev/null +++ b/include/lib/ArduinoJson/Deserialization/Reader.hpp @@ -0,0 +1,56 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +#include <stdlib.h> // for size_t + +namespace ARDUINOJSON_NAMESPACE { + +// The default reader is a simple wrapper for Readers that are not copiable +template <typename TSource, typename Enable = void> +struct Reader { + public: + Reader(TSource& source) : _source(&source) {} + + int read() { + return _source->read(); + } + + size_t readBytes(char* buffer, size_t length) { + return _source->readBytes(buffer, length); + } + + private: + TSource* _source; +}; + +template <typename TSource, typename Enable = void> +struct BoundedReader { + // no default implementation because we need to pass the size to the + // constructor +}; +} // namespace ARDUINOJSON_NAMESPACE + +#include <ArduinoJson/Deserialization/Readers/IteratorReader.hpp> +#include <ArduinoJson/Deserialization/Readers/RamReader.hpp> +#include <ArduinoJson/Deserialization/Readers/VariantReader.hpp> + +#if ARDUINOJSON_ENABLE_ARDUINO_STREAM +#include <ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp> +#endif + +#if ARDUINOJSON_ENABLE_ARDUINO_STRING +#include <ArduinoJson/Deserialization/Readers/ArduinoStringReader.hpp> +#endif + +#if ARDUINOJSON_ENABLE_PROGMEM +#include <ArduinoJson/Deserialization/Readers/FlashReader.hpp> +#endif + +#if ARDUINOJSON_ENABLE_STD_STREAM +#include <ArduinoJson/Deserialization/Readers/StdStreamReader.hpp> +#endif diff --git a/include/lib/ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp b/include/lib/ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp new file mode 100644 index 0000000..724638f --- /dev/null +++ b/include/lib/ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp @@ -0,0 +1,31 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <Arduino.h> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TSource> +struct Reader<TSource, + typename enable_if<is_base_of<Stream, TSource>::value>::type> { + public: + explicit Reader(Stream& stream) : _stream(&stream) {} + + int read() { + // don't use _stream.read() as it ignores the timeout + char c; + return _stream->readBytes(&c, 1) ? static_cast<unsigned char>(c) : -1; + } + + size_t readBytes(char* buffer, size_t length) { + return _stream->readBytes(buffer, length); + } + + private: + Stream* _stream; +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Deserialization/Readers/ArduinoStringReader.hpp b/include/lib/ArduinoJson/Deserialization/Readers/ArduinoStringReader.hpp new file mode 100644 index 0000000..71571d4 --- /dev/null +++ b/include/lib/ArduinoJson/Deserialization/Readers/ArduinoStringReader.hpp @@ -0,0 +1,17 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TSource> +struct Reader<TSource, + typename enable_if<is_base_of< ::String, TSource>::value>::type> + : BoundedReader<const char*> { + explicit Reader(const ::String& s) + : BoundedReader<const char*>(s.c_str(), s.length()) {} +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Deserialization/Readers/FlashReader.hpp b/include/lib/ArduinoJson/Deserialization/Readers/FlashReader.hpp new file mode 100644 index 0000000..7eca134 --- /dev/null +++ b/include/lib/ArduinoJson/Deserialization/Readers/FlashReader.hpp @@ -0,0 +1,53 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +namespace ARDUINOJSON_NAMESPACE { + +template <> +struct Reader<const __FlashStringHelper*, void> { + const char* _ptr; + + public: + explicit Reader(const __FlashStringHelper* ptr) + : _ptr(reinterpret_cast<const char*>(ptr)) {} + + int read() { + return pgm_read_byte(_ptr++); + } + + size_t readBytes(char* buffer, size_t length) { + memcpy_P(buffer, _ptr, length); + _ptr += length; + return length; + } +}; + +template <> +struct BoundedReader<const __FlashStringHelper*, void> { + const char* _ptr; + const char* _end; + + public: + explicit BoundedReader(const __FlashStringHelper* ptr, size_t size) + : _ptr(reinterpret_cast<const char*>(ptr)), _end(_ptr + size) {} + + int read() { + if (_ptr < _end) + return pgm_read_byte(_ptr++); + else + return -1; + } + + size_t readBytes(char* buffer, size_t length) { + size_t available = static_cast<size_t>(_end - _ptr); + if (available < length) + length = available; + memcpy_P(buffer, _ptr, length); + _ptr += length; + return length; + } +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Deserialization/Readers/IteratorReader.hpp b/include/lib/ArduinoJson/Deserialization/Readers/IteratorReader.hpp new file mode 100644 index 0000000..37c3c31 --- /dev/null +++ b/include/lib/ArduinoJson/Deserialization/Readers/IteratorReader.hpp @@ -0,0 +1,43 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TIterator> +class IteratorReader { + TIterator _ptr, _end; + + public: + explicit IteratorReader(TIterator begin, TIterator end) + : _ptr(begin), _end(end) {} + + int read() { + if (_ptr < _end) + return static_cast<unsigned char>(*_ptr++); + else + return -1; + } + + size_t readBytes(char* buffer, size_t length) { + size_t i = 0; + while (i < length && _ptr < _end) buffer[i++] = *_ptr++; + return i; + } +}; + +template <typename T> +struct void_ { + typedef void type; +}; + +template <typename TSource> +struct Reader<TSource, typename void_<typename TSource::const_iterator>::type> + : IteratorReader<typename TSource::const_iterator> { + explicit Reader(const TSource& source) + : IteratorReader<typename TSource::const_iterator>(source.begin(), + source.end()) {} +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Deserialization/Readers/RamReader.hpp b/include/lib/ArduinoJson/Deserialization/Readers/RamReader.hpp new file mode 100644 index 0000000..67cf682 --- /dev/null +++ b/include/lib/ArduinoJson/Deserialization/Readers/RamReader.hpp @@ -0,0 +1,50 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/type_traits.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename T> +struct IsCharOrVoid { + static const bool value = + is_same<T, void>::value || is_same<T, char>::value || + is_same<T, unsigned char>::value || is_same<T, signed char>::value; +}; + +template <typename T> +struct IsCharOrVoid<const T> : IsCharOrVoid<T> {}; + +template <typename TSource> +struct Reader<TSource*, + typename enable_if<IsCharOrVoid<TSource>::value>::type> { + const char* _ptr; + + public: + explicit Reader(const void* ptr) + : _ptr(ptr ? reinterpret_cast<const char*>(ptr) : "") {} + + int read() { + return static_cast<unsigned char>(*_ptr++); + } + + size_t readBytes(char* buffer, size_t length) { + for (size_t i = 0; i < length; i++) buffer[i] = *_ptr++; + return length; + } +}; + +template <typename TSource> +struct BoundedReader<TSource*, + typename enable_if<IsCharOrVoid<TSource>::value>::type> + : public IteratorReader<const char*> { + public: + explicit BoundedReader(const void* ptr, size_t len) + : IteratorReader<const char*>(reinterpret_cast<const char*>(ptr), + reinterpret_cast<const char*>(ptr) + len) {} +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Deserialization/Readers/StdStreamReader.hpp b/include/lib/ArduinoJson/Deserialization/Readers/StdStreamReader.hpp new file mode 100644 index 0000000..eebaa2c --- /dev/null +++ b/include/lib/ArduinoJson/Deserialization/Readers/StdStreamReader.hpp @@ -0,0 +1,29 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <istream> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TSource> +struct Reader<TSource, typename enable_if< + is_base_of<std::istream, TSource>::value>::type> { + public: + explicit Reader(std::istream& stream) : _stream(&stream) {} + + int read() { + return _stream->get(); + } + + size_t readBytes(char* buffer, size_t length) { + _stream->read(buffer, static_cast<std::streamsize>(length)); + return static_cast<size_t>(_stream->gcount()); + } + + private: + std::istream* _stream; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Deserialization/Readers/VariantReader.hpp b/include/lib/ArduinoJson/Deserialization/Readers/VariantReader.hpp new file mode 100644 index 0000000..e56e262 --- /dev/null +++ b/include/lib/ArduinoJson/Deserialization/Readers/VariantReader.hpp @@ -0,0 +1,34 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Object/MemberProxy.hpp> +#include <ArduinoJson/Variant/VariantRef.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TArray> +struct Reader<ElementProxy<TArray>, void> : Reader<char*, void> { + explicit Reader(const ElementProxy<TArray>& x) + : Reader<char*, void>(x.template as<const char*>()) {} +}; + +template <typename TObject, typename TStringRef> +struct Reader<MemberProxy<TObject, TStringRef>, void> : Reader<char*, void> { + explicit Reader(const MemberProxy<TObject, TStringRef>& x) + : Reader<char*, void>(x.template as<const char*>()) {} +}; + +template <> +struct Reader<VariantRef, void> : Reader<char*, void> { + explicit Reader(VariantRef x) : Reader<char*, void>(x.as<const char*>()) {} +}; + +template <> +struct Reader<VariantConstRef, void> : Reader<char*, void> { + explicit Reader(VariantConstRef x) + : Reader<char*, void>(x.as<const char*>()) {} +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Deserialization/deserialize.hpp b/include/lib/ArduinoJson/Deserialization/deserialize.hpp new file mode 100644 index 0000000..2329542 --- /dev/null +++ b/include/lib/ArduinoJson/Deserialization/deserialize.hpp @@ -0,0 +1,71 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Deserialization/DeserializationError.hpp> +#include <ArduinoJson/Deserialization/Filter.hpp> +#include <ArduinoJson/Deserialization/NestingLimit.hpp> +#include <ArduinoJson/Deserialization/Reader.hpp> +#include <ArduinoJson/StringStorage/StringStorage.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <template <typename, typename> class TDeserializer, typename TReader, + typename TWriter> +TDeserializer<TReader, TWriter> makeDeserializer(MemoryPool &pool, + TReader reader, + TWriter writer) { + return TDeserializer<TReader, TWriter>(pool, reader, writer); +} + +// deserialize(JsonDocument&, const std::string&, NestingLimit, Filter); +// deserialize(JsonDocument&, const String&, NestingLimit, Filter); +// deserialize(JsonDocument&, char*, NestingLimit, Filter); +// deserialize(JsonDocument&, const char*, NestingLimit, Filter); +// deserialize(JsonDocument&, const __FlashStringHelper*, NestingLimit, Filter); +template <template <typename, typename> class TDeserializer, typename TString, + typename TFilter> +typename enable_if<!is_array<TString>::value, DeserializationError>::type +deserialize(JsonDocument &doc, const TString &input, NestingLimit nestingLimit, + TFilter filter) { + Reader<TString> reader(input); + doc.clear(); + return makeDeserializer<TDeserializer>( + doc.memoryPool(), reader, + makeStringStorage(input, doc.memoryPool())) + .parse(doc.data(), filter, nestingLimit); +} +// +// deserialize(JsonDocument&, char*, size_t, NestingLimit, Filter); +// deserialize(JsonDocument&, const char*, size_t, NestingLimit, Filter); +// deserialize(JsonDocument&, const __FlashStringHelper*, size_t, NL, Filter); +template <template <typename, typename> class TDeserializer, typename TChar, + typename TFilter> +DeserializationError deserialize(JsonDocument &doc, TChar *input, + size_t inputSize, NestingLimit nestingLimit, + TFilter filter) { + BoundedReader<TChar *> reader(input, inputSize); + doc.clear(); + return makeDeserializer<TDeserializer>( + doc.memoryPool(), reader, + makeStringStorage(input, doc.memoryPool())) + .parse(doc.data(), filter, nestingLimit); +} +// +// deserialize(JsonDocument&, std::istream&, NestingLimit, Filter); +// deserialize(JsonDocument&, Stream&, NestingLimit, Filter); +template <template <typename, typename> class TDeserializer, typename TStream, + typename TFilter> +DeserializationError deserialize(JsonDocument &doc, TStream &input, + NestingLimit nestingLimit, TFilter filter) { + Reader<TStream> reader(input); + doc.clear(); + return makeDeserializer<TDeserializer>( + doc.memoryPool(), reader, + makeStringStorage(input, doc.memoryPool())) + .parse(doc.data(), filter, nestingLimit); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Document/BasicJsonDocument.hpp b/include/lib/ArduinoJson/Document/BasicJsonDocument.hpp new file mode 100644 index 0000000..5c85d8a --- /dev/null +++ b/include/lib/ArduinoJson/Document/BasicJsonDocument.hpp @@ -0,0 +1,164 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Document/JsonDocument.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +// Helper to implement the "base-from-member" idiom +// (we need to store the allocator before constructing JsonDocument) +template <typename TAllocator> +class AllocatorOwner { + public: + AllocatorOwner() {} + AllocatorOwner(const AllocatorOwner& src) : _allocator(src._allocator) {} + AllocatorOwner(TAllocator a) : _allocator(a) {} + + void* allocate(size_t size) { + return _allocator.allocate(size); + } + + void deallocate(void* ptr) { + if (ptr) + _allocator.deallocate(ptr); + } + + void* reallocate(void* ptr, size_t new_size) { + return _allocator.reallocate(ptr, new_size); + } + + TAllocator& allocator() { + return _allocator; + } + + private: + TAllocator _allocator; +}; + +template <typename TAllocator> +class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument { + public: + explicit BasicJsonDocument(size_t capa, TAllocator alloc = TAllocator()) + : AllocatorOwner<TAllocator>(alloc), JsonDocument(allocPool(capa)) {} + + // Copy-constructor + BasicJsonDocument(const BasicJsonDocument& src) + : AllocatorOwner<TAllocator>(src), JsonDocument() { + copyAssignFrom(src); + } + + // Move-constructor +#if ARDUINOJSON_HAS_RVALUE_REFERENCES + BasicJsonDocument(BasicJsonDocument&& src) : AllocatorOwner<TAllocator>(src) { + moveAssignFrom(src); + } +#endif + + BasicJsonDocument(const JsonDocument& src) { + copyAssignFrom(src); + } + + // Construct from variant, array, or object + template <typename T> + BasicJsonDocument( + const T& src, + typename enable_if< + is_same<T, VariantRef>::value || is_same<T, VariantConstRef>::value || + is_same<T, ArrayRef>::value || is_same<T, ArrayConstRef>::value || + is_same<T, ObjectRef>::value || + is_same<T, ObjectConstRef>::value>::type* = 0) + : JsonDocument(allocPool(src.memoryUsage())) { + set(src); + } + + // disambiguate + BasicJsonDocument(VariantRef src) + : JsonDocument(allocPool(src.memoryUsage())) { + set(src); + } + + ~BasicJsonDocument() { + freePool(); + } + + BasicJsonDocument& operator=(const BasicJsonDocument& src) { + copyAssignFrom(src); + return *this; + } + +#if ARDUINOJSON_HAS_RVALUE_REFERENCES + BasicJsonDocument& operator=(BasicJsonDocument&& src) { + moveAssignFrom(src); + return *this; + } +#endif + + template <typename T> + BasicJsonDocument& operator=(const T& src) { + reallocPoolIfTooSmall(src.memoryUsage()); + set(src); + return *this; + } + + void shrinkToFit() { + ptrdiff_t bytes_reclaimed = _pool.squash(); + if (bytes_reclaimed == 0) + return; + + void* old_ptr = _pool.buffer(); + void* new_ptr = this->reallocate(old_ptr, _pool.capacity()); + + ptrdiff_t ptr_offset = + static_cast<char*>(new_ptr) - static_cast<char*>(old_ptr); + + _pool.movePointers(ptr_offset); + _data.movePointers(ptr_offset, ptr_offset - bytes_reclaimed); + } + + bool garbageCollect() { + // make a temporary clone and move assign + BasicJsonDocument tmp(*this); + if (!tmp.capacity()) + return false; + tmp.set(*this); + moveAssignFrom(tmp); + return true; + } + + using AllocatorOwner<TAllocator>::allocator; + + private: + MemoryPool allocPool(size_t requiredSize) { + size_t capa = addPadding(requiredSize); + return MemoryPool(reinterpret_cast<char*>(this->allocate(capa)), capa); + } + + void reallocPoolIfTooSmall(size_t requiredSize) { + if (requiredSize <= capacity()) + return; + freePool(); + replacePool(allocPool(addPadding(requiredSize))); + } + + void freePool() { + this->deallocate(memoryPool().buffer()); + } + + void copyAssignFrom(const JsonDocument& src) { + reallocPoolIfTooSmall(src.capacity()); + set(src); + } + + void moveAssignFrom(BasicJsonDocument& src) { + freePool(); + _data = src._data; + _pool = src._pool; + src._data.setNull(); + src._pool = MemoryPool(0, 0); + } +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Document/DynamicJsonDocument.hpp b/include/lib/ArduinoJson/Document/DynamicJsonDocument.hpp new file mode 100644 index 0000000..de6f411 --- /dev/null +++ b/include/lib/ArduinoJson/Document/DynamicJsonDocument.hpp @@ -0,0 +1,29 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Document/BasicJsonDocument.hpp> + +#include <stdlib.h> // malloc, free + +namespace ARDUINOJSON_NAMESPACE { + +struct DefaultAllocator { + void* allocate(size_t size) { + return malloc(size); + } + + void deallocate(void* ptr) { + free(ptr); + } + + void* reallocate(void* ptr, size_t new_size) { + return realloc(ptr, new_size); + } +}; + +typedef BasicJsonDocument<DefaultAllocator> DynamicJsonDocument; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Document/JsonDocument.hpp b/include/lib/ArduinoJson/Document/JsonDocument.hpp new file mode 100644 index 0000000..d67d934 --- /dev/null +++ b/include/lib/ArduinoJson/Document/JsonDocument.hpp @@ -0,0 +1,344 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Array/ElementProxy.hpp> +#include <ArduinoJson/Memory/MemoryPool.hpp> +#include <ArduinoJson/Object/MemberProxy.hpp> +#include <ArduinoJson/Object/ObjectRef.hpp> +#include <ArduinoJson/Variant/VariantRef.hpp> +#include <ArduinoJson/Variant/VariantTo.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +class JsonDocument : public Visitable { + public: + template <typename TVisitor> + typename TVisitor::result_type accept(TVisitor& visitor) const { + return getVariant().accept(visitor); + } + + template <typename T> + T as() { + return getVariant().template as<T>(); + } + + template <typename T> + T as() const { + return getVariant().template as<T>(); + } + + void clear() { + _pool.clear(); + _data.setNull(); + } + + template <typename T> + bool is() { + return getVariant().template is<T>(); + } + + template <typename T> + bool is() const { + return getVariant().template is<T>(); + } + + bool isNull() const { + return getVariant().isNull(); + } + + size_t memoryUsage() const { + return _pool.size(); + } + + bool overflowed() const { + return _pool.overflowed(); + } + + size_t nesting() const { + return _data.nesting(); + } + + size_t capacity() const { + return _pool.capacity(); + } + + size_t size() const { + return _data.size(); + } + + bool set(const JsonDocument& src) { + return to<VariantRef>().set(src.as<VariantConstRef>()); + } + + template <typename T> + typename enable_if<!is_base_of<JsonDocument, T>::value, bool>::type set( + const T& src) { + return to<VariantRef>().set(src); + } + + template <typename T> + typename VariantTo<T>::type to() { + clear(); + return getVariant().template to<T>(); + } + + // for internal use only + MemoryPool& memoryPool() { + return _pool; + } + + // for internal use only + VariantData& data() { + return _data; + } + + ArrayRef createNestedArray() { + return addElement().to<ArrayRef>(); + } + + // createNestedArray(char*) + // createNestedArray(const char*) + // createNestedArray(const __FlashStringHelper*) + template <typename TChar> + ArrayRef createNestedArray(TChar* key) { + return getOrAddMember(key).template to<ArrayRef>(); + } + + // createNestedArray(const std::string&) + // createNestedArray(const String&) + template <typename TString> + ArrayRef createNestedArray(const TString& key) { + return getOrAddMember(key).template to<ArrayRef>(); + } + + ObjectRef createNestedObject() { + return addElement().to<ObjectRef>(); + } + + // createNestedObject(char*) + // createNestedObject(const char*) + // createNestedObject(const __FlashStringHelper*) + template <typename TChar> + ObjectRef createNestedObject(TChar* key) { + return getOrAddMember(key).template to<ObjectRef>(); + } + + // createNestedObject(const std::string&) + // createNestedObject(const String&) + template <typename TString> + ObjectRef createNestedObject(const TString& key) { + return getOrAddMember(key).template to<ObjectRef>(); + } + + // containsKey(char*) const + // containsKey(const char*) const + // containsKey(const __FlashStringHelper*) const + template <typename TChar> + bool containsKey(TChar* key) const { + return !getMember(key).isUndefined(); + } + + // containsKey(const std::string&) const + // containsKey(const String&) const + template <typename TString> + bool containsKey(const TString& key) const { + return !getMember(key).isUndefined(); + } + + // operator[](const std::string&) + // operator[](const String&) + template <typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value, + MemberProxy<JsonDocument&, TString> >::type + operator[](const TString& key) { + return MemberProxy<JsonDocument&, TString>(*this, key); + } + + // operator[](char*) + // operator[](const char*) + // operator[](const __FlashStringHelper*) + template <typename TChar> + FORCE_INLINE typename enable_if<IsString<TChar*>::value, + MemberProxy<JsonDocument&, TChar*> >::type + operator[](TChar* key) { + return MemberProxy<JsonDocument&, TChar*>(*this, key); + } + + // operator[](const std::string&) const + // operator[](const String&) const + template <typename TString> + FORCE_INLINE + typename enable_if<IsString<TString>::value, VariantConstRef>::type + operator[](const TString& key) const { + return getMember(key); + } + + // operator[](char*) const + // operator[](const char*) const + // operator[](const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE + typename enable_if<IsString<TChar*>::value, VariantConstRef>::type + operator[](TChar* key) const { + return getMember(key); + } + + FORCE_INLINE ElementProxy<JsonDocument&> operator[](size_t index) { + return ElementProxy<JsonDocument&>(*this, index); + } + + FORCE_INLINE VariantConstRef operator[](size_t index) const { + return getElement(index); + } + + FORCE_INLINE VariantRef getElement(size_t index) { + return VariantRef(&_pool, _data.getElement(index)); + } + + FORCE_INLINE VariantConstRef getElement(size_t index) const { + return VariantConstRef(_data.getElement(index)); + } + + FORCE_INLINE VariantRef getOrAddElement(size_t index) { + return VariantRef(&_pool, _data.getOrAddElement(index, &_pool)); + } + + // JsonVariantConst getMember(char*) const + // JsonVariantConst getMember(const char*) const + // JsonVariantConst getMember(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE VariantConstRef getMember(TChar* key) const { + return VariantConstRef(_data.getMember(adaptString(key))); + } + + // JsonVariantConst getMember(const std::string&) const + // JsonVariantConst getMember(const String&) const + template <typename TString> + FORCE_INLINE + typename enable_if<IsString<TString>::value, VariantConstRef>::type + getMember(const TString& key) const { + return VariantConstRef(_data.getMember(adaptString(key))); + } + + // JsonVariant getMember(char*) + // JsonVariant getMember(const char*) + // JsonVariant getMember(const __FlashStringHelper*) + template <typename TChar> + FORCE_INLINE VariantRef getMember(TChar* key) { + return VariantRef(&_pool, _data.getMember(adaptString(key))); + } + + // JsonVariant getMember(const std::string&) + // JsonVariant getMember(const String&) + template <typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value, VariantRef>::type + getMember(const TString& key) { + return VariantRef(&_pool, _data.getMember(adaptString(key))); + } + + // getOrAddMember(char*) + // getOrAddMember(const char*) + // getOrAddMember(const __FlashStringHelper*) + template <typename TChar> + FORCE_INLINE VariantRef getOrAddMember(TChar* key) { + return VariantRef(&_pool, _data.getOrAddMember(adaptString(key), &_pool)); + } + + // getOrAddMember(const std::string&) + // getOrAddMember(const String&) + template <typename TString> + FORCE_INLINE VariantRef getOrAddMember(const TString& key) { + return VariantRef(&_pool, _data.getOrAddMember(adaptString(key), &_pool)); + } + + FORCE_INLINE VariantRef addElement() { + return VariantRef(&_pool, _data.addElement(&_pool)); + } + + template <typename TValue> + FORCE_INLINE bool add(const TValue& value) { + return addElement().set(value); + } + + // add(char*) const + // add(const char*) const + // add(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE bool add(TChar* value) { + return addElement().set(value); + } + + FORCE_INLINE void remove(size_t index) { + _data.remove(index); + } + // remove(char*) + // remove(const char*) + // remove(const __FlashStringHelper*) + template <typename TChar> + FORCE_INLINE typename enable_if<IsString<TChar*>::value>::type remove( + TChar* key) { + _data.remove(adaptString(key)); + } + // remove(const std::string&) + // remove(const String&) + template <typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove( + const TString& key) { + _data.remove(adaptString(key)); + } + + FORCE_INLINE operator VariantConstRef() const { + return VariantConstRef(&_data); + } + + bool operator==(VariantConstRef rhs) const { + return getVariant() == rhs; + } + + bool operator!=(VariantConstRef rhs) const { + return getVariant() != rhs; + } + + protected: + JsonDocument() : _pool(0, 0) { + _data.setNull(); + } + + JsonDocument(MemoryPool pool) : _pool(pool) { + _data.setNull(); + } + + JsonDocument(char* buf, size_t capa) : _pool(buf, capa) { + _data.setNull(); + } + + ~JsonDocument() {} + + void replacePool(MemoryPool pool) { + _pool = pool; + } + + VariantRef getVariant() { + return VariantRef(&_pool, &_data); + } + + VariantConstRef getVariant() const { + return VariantConstRef(&_data); + } + + MemoryPool _pool; + VariantData _data; + + private: + JsonDocument(const JsonDocument&); + JsonDocument& operator=(const JsonDocument&); +}; + +inline bool convertToJson(const JsonDocument& src, VariantRef dst) { + return dst.set(src.as<VariantConstRef>()); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Document/StaticJsonDocument.hpp b/include/lib/ArduinoJson/Document/StaticJsonDocument.hpp new file mode 100644 index 0000000..fbbadd4 --- /dev/null +++ b/include/lib/ArduinoJson/Document/StaticJsonDocument.hpp @@ -0,0 +1,56 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Document/JsonDocument.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <size_t desiredCapacity> +class StaticJsonDocument : public JsonDocument { + static const size_t _capacity = + AddPadding<Max<1, desiredCapacity>::value>::value; + + public: + StaticJsonDocument() : JsonDocument(_buffer, _capacity) {} + + StaticJsonDocument(const StaticJsonDocument& src) + : JsonDocument(_buffer, _capacity) { + set(src); + } + + template <typename T> + StaticJsonDocument(const T& src, + typename enable_if<IsVisitable<T>::value>::type* = 0) + : JsonDocument(_buffer, _capacity) { + set(src); + } + + // disambiguate + StaticJsonDocument(VariantRef src) : JsonDocument(_buffer, _capacity) { + set(src); + } + + StaticJsonDocument operator=(const StaticJsonDocument& src) { + set(src); + return *this; + } + + template <typename T> + StaticJsonDocument operator=(const T& src) { + set(src); + return *this; + } + + void garbageCollect() { + StaticJsonDocument tmp(*this); + set(tmp); + } + + private: + char _buffer[_capacity]; +}; + +} // namespace ARDUINOJSON_NAMESPACE 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 diff --git a/include/lib/ArduinoJson/Memory/Alignment.hpp b/include/lib/ArduinoJson/Memory/Alignment.hpp new file mode 100644 index 0000000..bf16798 --- /dev/null +++ b/include/lib/ArduinoJson/Memory/Alignment.hpp @@ -0,0 +1,60 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +#include <stddef.h> // size_t + +namespace ARDUINOJSON_NAMESPACE { + +#if ARDUINOJSON_ENABLE_ALIGNMENT + +inline bool isAligned(size_t value) { + const size_t mask = sizeof(void *) - 1; + size_t addr = value; + return (addr & mask) == 0; +} + +inline size_t addPadding(size_t bytes) { + const size_t mask = sizeof(void *) - 1; + return (bytes + mask) & ~mask; +} + +template <size_t bytes> +struct AddPadding { + static const size_t mask = sizeof(void *) - 1; + static const size_t value = (bytes + mask) & ~mask; +}; + +#else + +inline bool isAligned(size_t) { + return true; +} + +inline size_t addPadding(size_t bytes) { + return bytes; +} + +template <size_t bytes> +struct AddPadding { + static const size_t value = bytes; +}; + +#endif + +template <typename T> +inline bool isAligned(T *ptr) { + return isAligned(reinterpret_cast<size_t>(ptr)); +} + +template <typename T> +inline T *addPadding(T *p) { + size_t address = addPadding(reinterpret_cast<size_t>(p)); + return reinterpret_cast<T *>(address); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Memory/MemoryPool.hpp b/include/lib/ArduinoJson/Memory/MemoryPool.hpp new file mode 100644 index 0000000..49debf8 --- /dev/null +++ b/include/lib/ArduinoJson/Memory/MemoryPool.hpp @@ -0,0 +1,212 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Memory/Alignment.hpp> +#include <ArduinoJson/Polyfills/assert.hpp> +#include <ArduinoJson/Polyfills/mpl/max.hpp> +#include <ArduinoJson/Variant/VariantSlot.hpp> + +#include <string.h> // memmove + +#define JSON_STRING_SIZE(SIZE) (SIZE + 1) + +namespace ARDUINOJSON_NAMESPACE { + +// _begin _end +// v v +// +-------------+--------------+--------------+ +// | strings... | (free) | ...variants | +// +-------------+--------------+--------------+ +// ^ ^ +// _left _right + +class MemoryPool { + public: + MemoryPool(char* buf, size_t capa) + : _begin(buf), + _left(buf), + _right(buf ? buf + capa : 0), + _end(buf ? buf + capa : 0), + _overflowed(false) { + ARDUINOJSON_ASSERT(isAligned(_begin)); + ARDUINOJSON_ASSERT(isAligned(_right)); + ARDUINOJSON_ASSERT(isAligned(_end)); + } + + void* buffer() { + return _begin; + } + + // Gets the capacity of the memoryPool in bytes + size_t capacity() const { + return size_t(_end - _begin); + } + + size_t size() const { + return size_t(_left - _begin + _end - _right); + } + + bool overflowed() const { + return _overflowed; + } + + VariantSlot* allocVariant() { + return allocRight<VariantSlot>(); + } + + template <typename TAdaptedString> + const char* saveString(const TAdaptedString& str) { + if (str.isNull()) + return 0; + +#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION + const char* existingCopy = findString(str.begin()); + if (existingCopy) + return existingCopy; +#endif + + size_t n = str.size(); + + char* newCopy = allocString(n + 1); + if (newCopy) { + str.copyTo(newCopy, n); + newCopy[n] = 0; // force null-terminator + } + return newCopy; + } + + void getFreeZone(char** zoneStart, size_t* zoneSize) const { + *zoneStart = _left; + *zoneSize = size_t(_right - _left); + } + + const char* saveStringFromFreeZone(size_t len) { +#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION + const char* dup = findString(_left); + if (dup) + return dup; +#endif + + const char* str = _left; + _left += len; + checkInvariants(); + return str; + } + + void markAsOverflowed() { + _overflowed = true; + } + + void clear() { + _left = _begin; + _right = _end; + _overflowed = false; + } + + bool canAlloc(size_t bytes) const { + return _left + bytes <= _right; + } + + bool owns(void* p) const { + return _begin <= p && p < _end; + } + + // Workaround for missing placement new + void* operator new(size_t, void* p) { + return p; + } + + // Squash the free space between strings and variants + // + // _begin _end + // v v + // +-------------+--------------+ + // | strings... | ...variants | + // +-------------+--------------+ + // ^ + // _left _right + // + // This funcion is called before a realloc. + ptrdiff_t squash() { + char* new_right = addPadding(_left); + if (new_right >= _right) + return 0; + + size_t right_size = static_cast<size_t>(_end - _right); + memmove(new_right, _right, right_size); + + ptrdiff_t bytes_reclaimed = _right - new_right; + _right = new_right; + _end = new_right + right_size; + return bytes_reclaimed; + } + + // Move all pointers together + // This funcion is called after a realloc. + void movePointers(ptrdiff_t offset) { + _begin += offset; + _left += offset; + _right += offset; + _end += offset; + } + + private: + void checkInvariants() { + ARDUINOJSON_ASSERT(_begin <= _left); + ARDUINOJSON_ASSERT(_left <= _right); + ARDUINOJSON_ASSERT(_right <= _end); + ARDUINOJSON_ASSERT(isAligned(_right)); + } + +#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION + template <typename TIterator> + const char* findString(TIterator str) { + for (char* next = _begin; next < _left; ++next) { + char* begin = next; + + // try to match + for (TIterator it = str; *it == *next; ++it) { + if (*next++ == 0) + return begin; + } + + // jump to next terminator + while (*next) ++next; + } + return 0; + } +#endif + + char* allocString(size_t n) { + if (!canAlloc(n)) { + _overflowed = true; + return 0; + } + char* s = _left; + _left += n; + checkInvariants(); + return s; + } + + template <typename T> + T* allocRight() { + return reinterpret_cast<T*>(allocRight(sizeof(T))); + } + + void* allocRight(size_t bytes) { + if (!canAlloc(bytes)) { + _overflowed = true; + return 0; + } + _right -= bytes; + return _right; + } + + char *_begin, *_left, *_right, *_end; + bool _overflowed; +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Misc/SerializedValue.hpp b/include/lib/ArduinoJson/Misc/SerializedValue.hpp new file mode 100644 index 0000000..30173bf --- /dev/null +++ b/include/lib/ArduinoJson/Misc/SerializedValue.hpp @@ -0,0 +1,68 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Strings/StringAdapters.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +// A special type of data that can be used to insert pregenerated JSON portions. +template <typename T> +class SerializedValue { + public: + explicit SerializedValue(T str) : _str(str) {} + operator T() const { + return _str; + } + + const char* data() const { + return _str.c_str(); + } + + size_t size() const { + // CAUTION: the old Arduino String doesn't have size() + return _str.length(); + } + + private: + T _str; +}; + +template <typename TChar> +class SerializedValue<TChar*> { + public: + explicit SerializedValue(TChar* p, size_t n) : _data(p), _size(n) {} + operator TChar*() const { + return _data; + } + + TChar* data() const { + return _data; + } + + size_t size() const { + return _size; + } + + private: + TChar* _data; + size_t _size; +}; + +template <typename T> +inline SerializedValue<T> serialized(T str) { + return SerializedValue<T>(str); +} + +template <typename TChar> +inline SerializedValue<TChar*> serialized(TChar* p) { + return SerializedValue<TChar*>(p, adaptString(p).size()); +} + +template <typename TChar> +inline SerializedValue<TChar*> serialized(TChar* p, size_t n) { + return SerializedValue<TChar*>(p, n); +} +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Misc/Visitable.hpp b/include/lib/ArduinoJson/Misc/Visitable.hpp new file mode 100644 index 0000000..f25d12f --- /dev/null +++ b/include/lib/ArduinoJson/Misc/Visitable.hpp @@ -0,0 +1,21 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/type_traits.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +struct Visitable { + // template<Visitor> + // void accept(Visitor&) const; +}; + +template <typename T> +struct IsVisitable : is_base_of<Visitable, T> {}; + +template <typename T> +struct IsVisitable<T &> : IsVisitable<T> {}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/MsgPack/MsgPackDeserializer.hpp b/include/lib/ArduinoJson/MsgPack/MsgPackDeserializer.hpp new file mode 100644 index 0000000..49c6fd4 --- /dev/null +++ b/include/lib/ArduinoJson/MsgPack/MsgPackDeserializer.hpp @@ -0,0 +1,599 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Deserialization/deserialize.hpp> +#include <ArduinoJson/Memory/MemoryPool.hpp> +#include <ArduinoJson/MsgPack/endianess.hpp> +#include <ArduinoJson/MsgPack/ieee754.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Variant/VariantData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TReader, typename TStringStorage> +class MsgPackDeserializer { + public: + MsgPackDeserializer(MemoryPool &pool, TReader reader, + TStringStorage stringStorage) + : _pool(&pool), + _reader(reader), + _stringStorage(stringStorage), + _error(DeserializationError::Ok), + _foundSomething(false) {} + + template <typename TFilter> + DeserializationError parse(VariantData &variant, TFilter filter, + NestingLimit nestingLimit) { + parseVariant(&variant, filter, nestingLimit); + return _foundSomething ? _error : DeserializationError::EmptyInput; + } + + private: + // Prevent VS warning "assignment operator could not be generated" + MsgPackDeserializer &operator=(const MsgPackDeserializer &); + + bool invalidInput() { + _error = DeserializationError::InvalidInput; + return false; + } + + template <typename TFilter> + bool parseVariant(VariantData *variant, TFilter filter, + NestingLimit nestingLimit) { + uint8_t code = 0; // TODO: why do we need to initialize this variable? + if (!readByte(code)) + return false; + + _foundSomething = true; + + bool allowValue = filter.allowValue(); + + switch (code) { + case 0xc0: + // already null + return true; + + case 0xc1: + return invalidInput(); + + case 0xc2: + if (allowValue) + variant->setBoolean(false); + return true; + + case 0xc3: + if (allowValue) + variant->setBoolean(true); + return true; + + case 0xc4: // bin 8 (not supported) + return skipString<uint8_t>(); + + case 0xc5: // bin 16 (not supported) + return skipString<uint16_t>(); + + case 0xc6: // bin 32 (not supported) + return skipString<uint32_t>(); + + case 0xc7: // ext 8 (not supported) + return skipExt<uint8_t>(); + + case 0xc8: // ext 16 (not supported) + return skipExt<uint16_t>(); + + case 0xc9: // ext 32 (not supported) + return skipExt<uint32_t>(); + + case 0xca: + if (allowValue) + return readFloat<float>(variant); + else + return skipBytes(4); + + case 0xcb: + if (allowValue) + return readDouble<double>(variant); + else + return skipBytes(8); + + case 0xcc: + if (allowValue) + return readInteger<uint8_t>(variant); + else + return skipBytes(1); + + case 0xcd: + if (allowValue) + return readInteger<uint16_t>(variant); + else + return skipBytes(2); + + case 0xce: + if (allowValue) + return readInteger<uint32_t>(variant); + else + return skipBytes(4); + + case 0xcf: +#if ARDUINOJSON_USE_LONG_LONG + if (allowValue) + return readInteger<uint64_t>(variant); + else + return skipBytes(8); +#else + return skipBytes(8); // not supported +#endif + + case 0xd0: + if (allowValue) + return readInteger<int8_t>(variant); + else + return skipBytes(1); + + case 0xd1: + if (allowValue) + return readInteger<int16_t>(variant); + else + return skipBytes(2); + + case 0xd2: + if (allowValue) + return readInteger<int32_t>(variant); + else + return skipBytes(4); + + case 0xd3: +#if ARDUINOJSON_USE_LONG_LONG + if (allowValue) + return readInteger<int64_t>(variant); + else + return skipBytes(8); // not supported +#else + return skipBytes(8); +#endif + + case 0xd4: // fixext 1 (not supported) + return skipBytes(2); + + case 0xd5: // fixext 2 (not supported) + return skipBytes(3); + + case 0xd6: // fixext 4 (not supported) + return skipBytes(5); + + case 0xd7: // fixext 8 (not supported) + return skipBytes(9); + + case 0xd8: // fixext 16 (not supported) + return skipBytes(17); + + case 0xd9: + if (allowValue) + return readString<uint8_t>(variant); + else + return skipString<uint8_t>(); + + case 0xda: + if (allowValue) + return readString<uint16_t>(variant); + else + return skipString<uint16_t>(); + + case 0xdb: + if (allowValue) + return readString<uint32_t>(variant); + else + return skipString<uint32_t>(); + + case 0xdc: + return readArray<uint16_t>(variant, filter, nestingLimit); + + case 0xdd: + return readArray<uint32_t>(variant, filter, nestingLimit); + + case 0xde: + return readObject<uint16_t>(variant, filter, nestingLimit); + + case 0xdf: + return readObject<uint32_t>(variant, filter, nestingLimit); + } + + switch (code & 0xf0) { + case 0x80: + return readObject(variant, code & 0x0F, filter, nestingLimit); + + case 0x90: + return readArray(variant, code & 0x0F, filter, nestingLimit); + } + + if ((code & 0xe0) == 0xa0) { + if (allowValue) + return readString(variant, code & 0x1f); + else + return skipBytes(code & 0x1f); + } + + if (allowValue) + variant->setInteger(static_cast<int8_t>(code)); + + return true; + } + + bool readByte(uint8_t &value) { + int c = _reader.read(); + if (c < 0) { + _error = DeserializationError::IncompleteInput; + return false; + } + value = static_cast<uint8_t>(c); + return true; + } + + bool readBytes(uint8_t *p, size_t n) { + if (_reader.readBytes(reinterpret_cast<char *>(p), n) == n) + return true; + _error = DeserializationError::IncompleteInput; + return false; + } + + template <typename T> + bool readBytes(T &value) { + return readBytes(reinterpret_cast<uint8_t *>(&value), sizeof(value)); + } + + bool skipBytes(size_t n) { + for (; n; --n) { + if (_reader.read() < 0) { + _error = DeserializationError::IncompleteInput; + return false; + } + } + return true; + } + + template <typename T> + bool readInteger(T &value) { + if (!readBytes(value)) + return false; + fixEndianess(value); + return true; + } + + template <typename T> + bool readInteger(VariantData *variant) { + T value; + if (!readInteger(value)) + return false; + variant->setInteger(value); + return true; + } + + template <typename T> + typename enable_if<sizeof(T) == 4, bool>::type readFloat( + VariantData *variant) { + T value; + if (!readBytes(value)) + return false; + fixEndianess(value); + variant->setFloat(value); + return true; + } + + template <typename T> + typename enable_if<sizeof(T) == 8, bool>::type readDouble( + VariantData *variant) { + T value; + if (!readBytes(value)) + return false; + fixEndianess(value); + variant->setFloat(value); + return true; + } + + template <typename T> + typename enable_if<sizeof(T) == 4, bool>::type readDouble( + VariantData *variant) { + uint8_t i[8]; // input is 8 bytes + T value; // output is 4 bytes + uint8_t *o = reinterpret_cast<uint8_t *>(&value); + if (!readBytes(i, 8)) + return false; + doubleToFloat(i, o); + fixEndianess(value); + variant->setFloat(value); + return true; + } + + template <typename T> + bool readString(VariantData *variant) { + T size; + if (!readInteger(size)) + return false; + return readString(variant, size); + } + + template <typename T> + bool readString() { + T size; + if (!readInteger(size)) + return false; + return readString(size); + } + + template <typename T> + bool skipString() { + T size; + if (!readInteger(size)) + return false; + return skipBytes(size); + } + + bool readString(VariantData *variant, size_t n) { + if (!readString(n)) + return false; + variant->setStringPointer(_stringStorage.save(), + typename TStringStorage::storage_policy()); + return true; + } + + bool readString(size_t n) { + _stringStorage.startString(); + for (; n; --n) { + uint8_t c; + if (!readBytes(c)) + return false; + _stringStorage.append(static_cast<char>(c)); + } + _stringStorage.append('\0'); + if (!_stringStorage.isValid()) { + _error = DeserializationError::NoMemory; + return false; + } + + return true; + } + + template <typename TSize, typename TFilter> + bool readArray(VariantData *variant, TFilter filter, + NestingLimit nestingLimit) { + TSize size; + if (!readInteger(size)) + return false; + return readArray(variant, size, filter, nestingLimit); + } + + template <typename TFilter> + bool readArray(VariantData *variant, size_t n, TFilter filter, + NestingLimit nestingLimit) { + if (nestingLimit.reached()) { + _error = DeserializationError::TooDeep; + return false; + } + + bool allowArray = filter.allowArray(); + + CollectionData *array = allowArray ? &variant->toArray() : 0; + + TFilter memberFilter = filter[0U]; + + for (; n; --n) { + VariantData *value; + + if (memberFilter.allow()) { + value = array->addElement(_pool); + if (!value) { + _error = DeserializationError::NoMemory; + return false; + } + } else { + value = 0; + } + + if (!parseVariant(value, memberFilter, nestingLimit.decrement())) + return false; + } + + return true; + } + + template <typename TSize, typename TFilter> + bool readObject(VariantData *variant, TFilter filter, + NestingLimit nestingLimit) { + TSize size; + if (!readInteger(size)) + return false; + return readObject(variant, size, filter, nestingLimit); + } + + template <typename TFilter> + bool readObject(VariantData *variant, size_t n, TFilter filter, + NestingLimit nestingLimit) { + if (nestingLimit.reached()) { + _error = DeserializationError::TooDeep; + return false; + } + + CollectionData *object = filter.allowObject() ? &variant->toObject() : 0; + + for (; n; --n) { + if (!readKey()) + return false; + + const char *key = _stringStorage.c_str(); + TFilter memberFilter = filter[key]; + VariantData *member; + + if (memberFilter.allow()) { + // Save key in memory pool. + // This MUST be done before adding the slot. + key = _stringStorage.save(); + + VariantSlot *slot = object->addSlot(_pool); + if (!slot) { + _error = DeserializationError::NoMemory; + return false; + } + + slot->setKey(key, typename TStringStorage::storage_policy()); + + member = slot->data(); + } else { + member = 0; + } + + if (!parseVariant(member, memberFilter, nestingLimit.decrement())) + return false; + } + + return true; + } + + bool readKey() { + uint8_t code; + if (!readByte(code)) + return false; + + if ((code & 0xe0) == 0xa0) + return readString(code & 0x1f); + + switch (code) { + case 0xd9: + return readString<uint8_t>(); + + case 0xda: + return readString<uint16_t>(); + + case 0xdb: + return readString<uint32_t>(); + + default: + return invalidInput(); + } + } + + template <typename T> + bool skipExt() { + T size; + if (!readInteger(size)) + return false; + return skipBytes(size + 1); + } + + MemoryPool *_pool; + TReader _reader; + TStringStorage _stringStorage; + DeserializationError _error; + bool _foundSomething; +}; + +// +// deserializeMsgPack(JsonDocument&, const std::string&, ...) +// +// ... = NestingLimit +template <typename TString> +DeserializationError deserializeMsgPack( + JsonDocument &doc, const TString &input, + NestingLimit nestingLimit = NestingLimit()) { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, + AllowAllFilter()); +} +// ... = Filter, NestingLimit +template <typename TString> +DeserializationError deserializeMsgPack( + JsonDocument &doc, const TString &input, Filter filter, + NestingLimit nestingLimit = NestingLimit()) { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); +} +// ... = NestingLimit, Filter +template <typename TString> +DeserializationError deserializeMsgPack(JsonDocument &doc, const TString &input, + NestingLimit nestingLimit, + Filter filter) { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); +} + +// +// deserializeMsgPack(JsonDocument&, std::istream&, ...) +// +// ... = NestingLimit +template <typename TStream> +DeserializationError deserializeMsgPack( + JsonDocument &doc, TStream &input, + NestingLimit nestingLimit = NestingLimit()) { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, + AllowAllFilter()); +} +// ... = Filter, NestingLimit +template <typename TStream> +DeserializationError deserializeMsgPack( + JsonDocument &doc, TStream &input, Filter filter, + NestingLimit nestingLimit = NestingLimit()) { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); +} +// ... = NestingLimit, Filter +template <typename TStream> +DeserializationError deserializeMsgPack(JsonDocument &doc, TStream &input, + NestingLimit nestingLimit, + Filter filter) { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); +} + +// +// deserializeMsgPack(JsonDocument&, char*, ...) +// +// ... = NestingLimit +template <typename TChar> +DeserializationError deserializeMsgPack( + JsonDocument &doc, TChar *input, + NestingLimit nestingLimit = NestingLimit()) { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, + AllowAllFilter()); +} +// ... = Filter, NestingLimit +template <typename TChar> +DeserializationError deserializeMsgPack( + JsonDocument &doc, TChar *input, Filter filter, + NestingLimit nestingLimit = NestingLimit()) { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); +} +// ... = NestingLimit, Filter +template <typename TChar> +DeserializationError deserializeMsgPack(JsonDocument &doc, TChar *input, + NestingLimit nestingLimit, + Filter filter) { + return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); +} + +// +// deserializeMsgPack(JsonDocument&, char*, size_t, ...) +// +// ... = NestingLimit +template <typename TChar> +DeserializationError deserializeMsgPack( + JsonDocument &doc, TChar *input, size_t inputSize, + NestingLimit nestingLimit = NestingLimit()) { + return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit, + AllowAllFilter()); +} +// ... = Filter, NestingLimit +template <typename TChar> +DeserializationError deserializeMsgPack( + JsonDocument &doc, TChar *input, size_t inputSize, Filter filter, + NestingLimit nestingLimit = NestingLimit()) { + return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit, + filter); +} +// ... = NestingLimit, Filter +template <typename TChar> +DeserializationError deserializeMsgPack(JsonDocument &doc, TChar *input, + size_t inputSize, + NestingLimit nestingLimit, + Filter filter) { + return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit, + filter); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/MsgPack/MsgPackSerializer.hpp b/include/lib/ArduinoJson/MsgPack/MsgPackSerializer.hpp new file mode 100644 index 0000000..b1cd872 --- /dev/null +++ b/include/lib/ArduinoJson/MsgPack/MsgPackSerializer.hpp @@ -0,0 +1,212 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/MsgPack/endianess.hpp> +#include <ArduinoJson/Polyfills/assert.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Serialization/CountingDecorator.hpp> +#include <ArduinoJson/Serialization/measure.hpp> +#include <ArduinoJson/Serialization/serialize.hpp> +#include <ArduinoJson/Variant/VariantData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TWriter> +class MsgPackSerializer : public Visitor<size_t> { + public: + static const bool producesText = false; + + MsgPackSerializer(TWriter writer) : _writer(writer) {} + + template <typename T> + typename enable_if<sizeof(T) == 4, size_t>::type visitFloat(T value32) { + writeByte(0xCA); + writeInteger(value32); + return bytesWritten(); + } + + template <typename T> + ARDUINOJSON_NO_SANITIZE("float-cast-overflow") + typename enable_if<sizeof(T) == 8, size_t>::type visitFloat(T value64) { + float value32 = float(value64); + if (value32 == value64) { + writeByte(0xCA); + writeInteger(value32); + } else { + writeByte(0xCB); + writeInteger(value64); + } + return bytesWritten(); + } + + size_t visitArray(const CollectionData& array) { + size_t n = array.size(); + if (n < 0x10) { + writeByte(uint8_t(0x90 + array.size())); + } else if (n < 0x10000) { + writeByte(0xDC); + writeInteger(uint16_t(n)); + } else { + writeByte(0xDD); + writeInteger(uint32_t(n)); + } + for (VariantSlot* slot = array.head(); slot; slot = slot->next()) { + slot->data()->accept(*this); + } + return bytesWritten(); + } + + size_t visitObject(const CollectionData& object) { + size_t n = object.size(); + if (n < 0x10) { + writeByte(uint8_t(0x80 + n)); + } else if (n < 0x10000) { + writeByte(0xDE); + writeInteger(uint16_t(n)); + } else { + writeByte(0xDF); + writeInteger(uint32_t(n)); + } + for (VariantSlot* slot = object.head(); slot; slot = slot->next()) { + visitString(slot->key()); + slot->data()->accept(*this); + } + return bytesWritten(); + } + + size_t visitString(const char* value) { + ARDUINOJSON_ASSERT(value != NULL); + + size_t n = strlen(value); + + if (n < 0x20) { + writeByte(uint8_t(0xA0 + n)); + } else if (n < 0x100) { + writeByte(0xD9); + writeInteger(uint8_t(n)); + } else if (n < 0x10000) { + writeByte(0xDA); + writeInteger(uint16_t(n)); + } else { + writeByte(0xDB); + writeInteger(uint32_t(n)); + } + writeBytes(reinterpret_cast<const uint8_t*>(value), n); + return bytesWritten(); + } + + size_t visitRawJson(const char* data, size_t size) { + writeBytes(reinterpret_cast<const uint8_t*>(data), size); + return bytesWritten(); + } + + size_t visitSignedInteger(Integer value) { + if (value > 0) { + visitUnsignedInteger(static_cast<UInt>(value)); + } else if (value >= -0x20) { + writeInteger(int8_t(value)); + } else if (value >= -0x80) { + writeByte(0xD0); + writeInteger(int8_t(value)); + } else if (value >= -0x8000) { + writeByte(0xD1); + writeInteger(int16_t(value)); + } +#if ARDUINOJSON_USE_LONG_LONG + else if (value >= -0x80000000LL) +#else + else +#endif + { + writeByte(0xD2); + writeInteger(int32_t(value)); + } +#if ARDUINOJSON_USE_LONG_LONG + else { + writeByte(0xD3); + writeInteger(int64_t(value)); + } +#endif + return bytesWritten(); + } + + size_t visitUnsignedInteger(UInt value) { + if (value <= 0x7F) { + writeInteger(uint8_t(value)); + } else if (value <= 0xFF) { + writeByte(0xCC); + writeInteger(uint8_t(value)); + } else if (value <= 0xFFFF) { + writeByte(0xCD); + writeInteger(uint16_t(value)); + } +#if ARDUINOJSON_USE_LONG_LONG + else if (value <= 0xFFFFFFFF) +#else + else +#endif + { + writeByte(0xCE); + writeInteger(uint32_t(value)); + } +#if ARDUINOJSON_USE_LONG_LONG + else { + writeByte(0xCF); + writeInteger(uint64_t(value)); + } +#endif + return bytesWritten(); + } + + size_t visitBoolean(bool value) { + writeByte(value ? 0xC3 : 0xC2); + return bytesWritten(); + } + + size_t visitNull() { + writeByte(0xC0); + return bytesWritten(); + } + + private: + size_t bytesWritten() const { + return _writer.count(); + } + + void writeByte(uint8_t c) { + _writer.write(c); + } + + void writeBytes(const uint8_t* p, size_t n) { + _writer.write(p, n); + } + + template <typename T> + void writeInteger(T value) { + fixEndianess(value); + writeBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value)); + } + + CountingDecorator<TWriter> _writer; +}; + +template <typename TSource, typename TDestination> +inline size_t serializeMsgPack(const TSource& source, TDestination& output) { + return serialize<MsgPackSerializer>(source, output); +} + +template <typename TSource> +inline size_t serializeMsgPack(const TSource& source, void* output, + size_t size) { + return serialize<MsgPackSerializer>(source, output, size); +} + +template <typename TSource> +inline size_t measureMsgPack(const TSource& source) { + return measure<MsgPackSerializer>(source); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/MsgPack/endianess.hpp b/include/lib/ArduinoJson/MsgPack/endianess.hpp new file mode 100644 index 0000000..74f7e9d --- /dev/null +++ b/include/lib/ArduinoJson/MsgPack/endianess.hpp @@ -0,0 +1,41 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Polyfills/utility.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +#if ARDUINOJSON_LITTLE_ENDIAN +inline void fixEndianess(uint8_t *p, integral_constant<size_t, 8>) { + swap(p[0], p[7]); + swap(p[1], p[6]); + swap(p[2], p[5]); + swap(p[3], p[4]); +} + +inline void fixEndianess(uint8_t *p, integral_constant<size_t, 4>) { + swap(p[0], p[3]); + swap(p[1], p[2]); +} + +inline void fixEndianess(uint8_t *p, integral_constant<size_t, 2>) { + swap(p[0], p[1]); +} + +inline void fixEndianess(uint8_t *, integral_constant<size_t, 1>) {} + +template <typename T> +inline void fixEndianess(T &value) { + fixEndianess(reinterpret_cast<uint8_t *>(&value), + integral_constant<size_t, sizeof(T)>()); +} +#else +template <typename T> +inline void fixEndianess(T &) {} +#endif + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/MsgPack/ieee754.hpp b/include/lib/ArduinoJson/MsgPack/ieee754.hpp new file mode 100644 index 0000000..016d533 --- /dev/null +++ b/include/lib/ArduinoJson/MsgPack/ieee754.hpp @@ -0,0 +1,18 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +inline void doubleToFloat(const uint8_t d[8], uint8_t f[4]) { + f[0] = uint8_t((d[0] & 0xC0) | (d[0] << 3 & 0x3f) | (d[1] >> 5)); + f[1] = uint8_t((d[1] << 3) | (d[2] >> 5)); + f[2] = uint8_t((d[2] << 3) | (d[3] >> 5)); + f[3] = uint8_t((d[3] << 3) | (d[4] >> 5)); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Namespace.hpp b/include/lib/ArduinoJson/Namespace.hpp new file mode 100644 index 0000000..2d85440 --- /dev/null +++ b/include/lib/ArduinoJson/Namespace.hpp @@ -0,0 +1,26 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Polyfills/preprocessor.hpp> +#include <ArduinoJson/version.hpp> + +#ifndef ARDUINOJSON_NAMESPACE + +#define ARDUINOJSON_NAMESPACE \ + ARDUINOJSON_CONCAT4( \ + ARDUINOJSON_CONCAT4(ArduinoJson, ARDUINOJSON_VERSION_MAJOR, \ + ARDUINOJSON_VERSION_MINOR, \ + ARDUINOJSON_VERSION_REVISION), \ + _, \ + ARDUINOJSON_HEX_DIGIT(ARDUINOJSON_ENABLE_PROGMEM, \ + ARDUINOJSON_USE_LONG_LONG, ARDUINOJSON_USE_DOUBLE, \ + ARDUINOJSON_ENABLE_STRING_DEDUPLICATION), \ + ARDUINOJSON_HEX_DIGIT( \ + ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY, \ + ARDUINOJSON_ENABLE_COMMENTS, ARDUINOJSON_DECODE_UNICODE)) + +#endif diff --git a/include/lib/ArduinoJson/Numbers/Float.hpp b/include/lib/ArduinoJson/Numbers/Float.hpp new file mode 100644 index 0000000..bbaca04 --- /dev/null +++ b/include/lib/ArduinoJson/Numbers/Float.hpp @@ -0,0 +1,17 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +#if ARDUINOJSON_USE_DOUBLE +typedef double Float; +#else +typedef float Float; +#endif +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Numbers/FloatParts.hpp b/include/lib/ArduinoJson/Numbers/FloatParts.hpp new file mode 100644 index 0000000..4e53add --- /dev/null +++ b/include/lib/ArduinoJson/Numbers/FloatParts.hpp @@ -0,0 +1,87 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Numbers/FloatTraits.hpp> +#include <ArduinoJson/Polyfills/math.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TFloat> +struct FloatParts { + uint32_t integral; + uint32_t decimal; + int16_t exponent; + int8_t decimalPlaces; + + FloatParts(TFloat value) { + uint32_t maxDecimalPart = sizeof(TFloat) >= 8 ? 1000000000 : 1000000; + decimalPlaces = sizeof(TFloat) >= 8 ? 9 : 6; + + exponent = normalize(value); + + integral = uint32_t(value); + // reduce number of decimal places by the number of integral places + for (uint32_t tmp = integral; tmp >= 10; tmp /= 10) { + maxDecimalPart /= 10; + decimalPlaces--; + } + + TFloat remainder = (value - TFloat(integral)) * TFloat(maxDecimalPart); + + decimal = uint32_t(remainder); + remainder = remainder - TFloat(decimal); + + // rounding: + // increment by 1 if remainder >= 0.5 + decimal += uint32_t(remainder * 2); + if (decimal >= maxDecimalPart) { + decimal = 0; + integral++; + if (exponent && integral >= 10) { + exponent++; + integral = 1; + } + } + + // remove trailing zeros + while (decimal % 10 == 0 && decimalPlaces > 0) { + decimal /= 10; + decimalPlaces--; + } + } + + static int16_t normalize(TFloat& value) { + typedef FloatTraits<TFloat> traits; + int16_t powersOf10 = 0; + + int8_t index = sizeof(TFloat) == 8 ? 8 : 5; + int bit = 1 << index; + + if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) { + for (; index >= 0; index--) { + if (value >= traits::positiveBinaryPowerOfTen(index)) { + value *= traits::negativeBinaryPowerOfTen(index); + powersOf10 = int16_t(powersOf10 + bit); + } + bit >>= 1; + } + } + + if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) { + for (; index >= 0; index--) { + if (value < traits::negativeBinaryPowerOfTenPlusOne(index)) { + value *= traits::positiveBinaryPowerOfTen(index); + powersOf10 = int16_t(powersOf10 - bit); + } + bit >>= 1; + } + } + + return powersOf10; + } +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Numbers/FloatTraits.hpp b/include/lib/ArduinoJson/Numbers/FloatTraits.hpp new file mode 100644 index 0000000..60b1dfd --- /dev/null +++ b/include/lib/ArduinoJson/Numbers/FloatTraits.hpp @@ -0,0 +1,201 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <stddef.h> // for size_t +#include <stdint.h> + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Polyfills/alias_cast.hpp> +#include <ArduinoJson/Polyfills/math.hpp> +#include <ArduinoJson/Polyfills/preprocessor.hpp> +#include <ArduinoJson/Polyfills/static_array.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename T, size_t = sizeof(T)> +struct FloatTraits {}; + +template <typename T> +struct FloatTraits<T, 8 /*64bits*/> { + typedef uint64_t mantissa_type; + static const short mantissa_bits = 52; + static const mantissa_type mantissa_max = + (mantissa_type(1) << mantissa_bits) - 1; + + typedef int16_t exponent_type; + static const exponent_type exponent_max = 308; + + template <typename TExponent> + static T make_float(T m, TExponent e) { + if (e > 0) { + for (uint8_t index = 0; e != 0; index++) { + if (e & 1) + m *= positiveBinaryPowerOfTen(index); + e >>= 1; + } + } else { + e = TExponent(-e); + for (uint8_t index = 0; e != 0; index++) { + if (e & 1) + m *= negativeBinaryPowerOfTen(index); + e >>= 1; + } + } + return m; + } + + static T positiveBinaryPowerOfTen(int index) { + ARDUINOJSON_DEFINE_STATIC_ARRAY( // + uint32_t, factors, + ARDUINOJSON_EXPAND18({ + 0x40240000, 0x00000000, // 1e1 + 0x40590000, 0x00000000, // 1e2 + 0x40C38800, 0x00000000, // 1e4 + 0x4197D784, 0x00000000, // 1e8 + 0x4341C379, 0x37E08000, // 1e16 + 0x4693B8B5, 0xB5056E17, // 1e32 + 0x4D384F03, 0xE93FF9F5, // 1e64 + 0x5A827748, 0xF9301D32, // 1e128 + 0x75154FDD, 0x7F73BF3C // 1e256 + })); + return forge( + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); + } + + static T negativeBinaryPowerOfTen(int index) { + ARDUINOJSON_DEFINE_STATIC_ARRAY( // + uint32_t, factors, + ARDUINOJSON_EXPAND18({ + 0x3FB99999, 0x9999999A, // 1e-1 + 0x3F847AE1, 0x47AE147B, // 1e-2 + 0x3F1A36E2, 0xEB1C432D, // 1e-4 + 0x3E45798E, 0xE2308C3A, // 1e-8 + 0x3C9CD2B2, 0x97D889BC, // 1e-16 + 0x3949F623, 0xD5A8A733, // 1e-32 + 0x32A50FFD, 0x44F4A73D, // 1e-64 + 0x255BBA08, 0xCF8C979D, // 1e-128 + 0x0AC80628, 0x64AC6F43 // 1e-256 + })); + return forge( + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); + } + + static T negativeBinaryPowerOfTenPlusOne(int index) { + ARDUINOJSON_DEFINE_STATIC_ARRAY( // + uint32_t, factors, + ARDUINOJSON_EXPAND18({ + 0x3FF00000, 0x00000000, // 1e0 + 0x3FB99999, 0x9999999A, // 1e-1 + 0x3F50624D, 0xD2F1A9FC, // 1e-3 + 0x3E7AD7F2, 0x9ABCAF48, // 1e-7 + 0x3CD203AF, 0x9EE75616, // 1e-15 + 0x398039D6, 0x65896880, // 1e-31 + 0x32DA53FC, 0x9631D10D, // 1e-63 + 0x25915445, 0x81B7DEC2, // 1e-127 + 0x0AFE07B2, 0x7DD78B14 // 1e-255 + })); + return forge( + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); + } + + static T nan() { + return forge(0x7ff80000, 0x00000000); + } + + static T inf() { + return forge(0x7ff00000, 0x00000000); + } + + static T highest() { + return forge(0x7FEFFFFF, 0xFFFFFFFF); + } + + static T lowest() { + return forge(0xFFEFFFFF, 0xFFFFFFFF); + } + + // constructs a double floating point values from its binary representation + // we use this function to workaround platforms with single precision literals + // (for example, when -fsingle-precision-constant is passed to GCC) + static T forge(uint32_t msb, uint32_t lsb) { + return alias_cast<T>((uint64_t(msb) << 32) | lsb); + } +}; + +template <typename T> +struct FloatTraits<T, 4 /*32bits*/> { + typedef uint32_t mantissa_type; + static const short mantissa_bits = 23; + static const mantissa_type mantissa_max = + (mantissa_type(1) << mantissa_bits) - 1; + + typedef int8_t exponent_type; + static const exponent_type exponent_max = 38; + + template <typename TExponent> + static T make_float(T m, TExponent e) { + if (e > 0) { + for (uint8_t index = 0; e != 0; index++) { + if (e & 1) + m *= positiveBinaryPowerOfTen(index); + e >>= 1; + } + } else { + e = -e; + for (uint8_t index = 0; e != 0; index++) { + if (e & 1) + m *= negativeBinaryPowerOfTen(index); + e >>= 1; + } + } + return m; + } + + static T positiveBinaryPowerOfTen(int index) { + ARDUINOJSON_DEFINE_STATIC_ARRAY( + T, factors, + ARDUINOJSON_EXPAND6({1e1f, 1e2f, 1e4f, 1e8f, 1e16f, 1e32f})); + return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); + } + + static T negativeBinaryPowerOfTen(int index) { + ARDUINOJSON_DEFINE_STATIC_ARRAY( + T, factors, + ARDUINOJSON_EXPAND6({1e-1f, 1e-2f, 1e-4f, 1e-8f, 1e-16f, 1e-32f})); + return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); + } + + static T negativeBinaryPowerOfTenPlusOne(int index) { + ARDUINOJSON_DEFINE_STATIC_ARRAY( + T, factors, + ARDUINOJSON_EXPAND6({1e0f, 1e-1f, 1e-3f, 1e-7f, 1e-15f, 1e-31f})); + return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); + } + + static T forge(uint32_t bits) { + return alias_cast<T>(bits); + } + + static T nan() { + return forge(0x7fc00000); + } + + static T inf() { + return forge(0x7f800000); + } + + static T highest() { + return forge(0x7f7fffff); + } + + static T lowest() { + return forge(0xFf7fffff); + } +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Numbers/Integer.hpp b/include/lib/ArduinoJson/Numbers/Integer.hpp new file mode 100644 index 0000000..fb656a7 --- /dev/null +++ b/include/lib/ArduinoJson/Numbers/Integer.hpp @@ -0,0 +1,32 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Namespace.hpp> + +#include <stdint.h> // int64_t + +namespace ARDUINOJSON_NAMESPACE { + +#if ARDUINOJSON_USE_LONG_LONG +typedef int64_t Integer; +typedef uint64_t UInt; +#else +typedef long Integer; +typedef unsigned long UInt; +#endif + +} // namespace ARDUINOJSON_NAMESPACE + +#if ARDUINOJSON_HAS_LONG_LONG && !ARDUINOJSON_USE_LONG_LONG +#define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) \ + static_assert(sizeof(T) <= sizeof(ARDUINOJSON_NAMESPACE::Integer), \ + "To use 64-bit integers with ArduinoJson, you must set " \ + "ARDUINOJSON_USE_LONG_LONG to 1. See " \ + "https://arduinojson.org/v6/api/config/use_long_long/"); +#else +#define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) +#endif diff --git a/include/lib/ArduinoJson/Numbers/arithmeticCompare.hpp b/include/lib/ArduinoJson/Numbers/arithmeticCompare.hpp new file mode 100644 index 0000000..bfd41d5 --- /dev/null +++ b/include/lib/ArduinoJson/Numbers/arithmeticCompare.hpp @@ -0,0 +1,121 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Numbers/Integer.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +enum CompareResult { + COMPARE_RESULT_DIFFER = 0, + COMPARE_RESULT_EQUAL = 1, + COMPARE_RESULT_GREATER = 2, + COMPARE_RESULT_LESS = 4, + + COMPARE_RESULT_GREATER_OR_EQUAL = 3, + COMPARE_RESULT_LESS_OR_EQUAL = 5 +}; + +template <typename T> +CompareResult arithmeticCompare(const T &lhs, const T &rhs) { + if (lhs < rhs) + return COMPARE_RESULT_LESS; + else if (lhs > rhs) + return COMPARE_RESULT_GREATER; + else + return COMPARE_RESULT_EQUAL; +} + +template <typename T1, typename T2> +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if<is_integral<T1>::value && is_integral<T2>::value && + sizeof(T1) < sizeof(T2), + int // Using int instead of void to avoid C2572 on + // Visual Studio 2012, 2013, and 2015 + >::type * = 0) { + return arithmeticCompare<T2>(static_cast<T2>(lhs), rhs); +} + +template <typename T1, typename T2> +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if<is_integral<T1>::value && is_integral<T2>::value && + sizeof(T2) < sizeof(T1)>::type * = 0) { + return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs)); +} + +template <typename T1, typename T2> +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if<is_integral<T1>::value && is_integral<T2>::value && + is_signed<T1>::value == is_signed<T2>::value && + sizeof(T2) == sizeof(T1)>::type * = 0) { + return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs)); +} + +template <typename T1, typename T2> +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if<is_integral<T1>::value && is_integral<T2>::value && + is_unsigned<T1>::value && is_signed<T2>::value && + sizeof(T2) == sizeof(T1)>::type * = 0) { + if (rhs < 0) + return COMPARE_RESULT_GREATER; + return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs)); +} + +template <typename T1, typename T2> +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if<is_integral<T1>::value && is_integral<T2>::value && + is_signed<T1>::value && is_unsigned<T2>::value && + sizeof(T2) == sizeof(T1)>::type * = 0) { + if (lhs < 0) + return COMPARE_RESULT_LESS; + return arithmeticCompare<T2>(static_cast<T2>(lhs), rhs); +} + +template <typename T1, typename T2> +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if<is_floating_point<T1>::value || + is_floating_point<T2>::value>::type * = 0) { + return arithmeticCompare<double>(static_cast<double>(lhs), + static_cast<double>(rhs)); +} + +template <typename T2> +CompareResult arithmeticCompareNegateLeft( + UInt, const T2 &, typename enable_if<is_unsigned<T2>::value>::type * = 0) { + return COMPARE_RESULT_LESS; +} + +template <typename T2> +CompareResult arithmeticCompareNegateLeft( + UInt lhs, const T2 &rhs, + typename enable_if<is_signed<T2>::value>::type * = 0) { + if (rhs > 0) + return COMPARE_RESULT_LESS; + return arithmeticCompare(-rhs, static_cast<T2>(lhs)); +} + +template <typename T1> +CompareResult arithmeticCompareNegateRight( + const T1 &, UInt, typename enable_if<is_unsigned<T1>::value>::type * = 0) { + return COMPARE_RESULT_GREATER; +} + +template <typename T1> +CompareResult arithmeticCompareNegateRight( + const T1 &lhs, UInt rhs, + typename enable_if<is_signed<T1>::value>::type * = 0) { + if (lhs > 0) + return COMPARE_RESULT_GREATER; + return arithmeticCompare(static_cast<T1>(rhs), -lhs); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Numbers/convertNumber.hpp b/include/lib/ArduinoJson/Numbers/convertNumber.hpp new file mode 100644 index 0000000..02bbefa --- /dev/null +++ b/include/lib/ArduinoJson/Numbers/convertNumber.hpp @@ -0,0 +1,107 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" +#elif defined(__GNUC__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +#pragma GCC diagnostic push +#endif +#pragma GCC diagnostic ignored "-Wconversion" +#endif + +#include <ArduinoJson/Numbers/Float.hpp> +#include <ArduinoJson/Polyfills/limits.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +// uint32 -> int32 +// uint64 -> int32 +template <typename TOut, typename TIn> +typename enable_if<is_integral<TIn>::value && is_unsigned<TIn>::value && + is_integral<TOut>::value && sizeof(TOut) <= sizeof(TIn), + bool>::type +canConvertNumber(TIn value) { + return value <= TIn(numeric_limits<TOut>::highest()); +} + +// uint32 -> int64 +template <typename TOut, typename TIn> +typename enable_if<is_integral<TIn>::value && is_unsigned<TIn>::value && + is_integral<TOut>::value && sizeof(TIn) < sizeof(TOut), + bool>::type +canConvertNumber(TIn) { + return true; +} + +// uint32 -> float +// int32 -> float +template <typename TOut, typename TIn> +typename enable_if<is_integral<TIn>::value && is_floating_point<TOut>::value, + bool>::type +canConvertNumber(TIn) { + return true; +} + +// int64 -> int32 +template <typename TOut, typename TIn> +typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value && + is_integral<TOut>::value && is_signed<TOut>::value && + sizeof(TOut) < sizeof(TIn), + bool>::type +canConvertNumber(TIn value) { + return value >= TIn(numeric_limits<TOut>::lowest()) && + value <= TIn(numeric_limits<TOut>::highest()); +} + +// int32 -> int32 +// int32 -> int64 +template <typename TOut, typename TIn> +typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value && + is_integral<TOut>::value && is_signed<TOut>::value && + sizeof(TIn) <= sizeof(TOut), + bool>::type +canConvertNumber(TIn) { + return true; +} + +// int32 -> uint32 +template <typename TOut, typename TIn> +typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value && + is_integral<TOut>::value && is_unsigned<TOut>::value, + bool>::type +canConvertNumber(TIn value) { + if (value < 0) + return false; + return value <= TIn(numeric_limits<TOut>::highest()); +} + +// float -> int32 +// float -> int64 +template <typename TOut, typename TIn> +typename enable_if<is_floating_point<TIn>::value && + !is_floating_point<TOut>::value, + bool>::type +canConvertNumber(TIn value) { + return value >= numeric_limits<TOut>::lowest() && + value <= numeric_limits<TOut>::highest(); +} + +template <typename TOut, typename TIn> +TOut convertNumber(TIn value) { + return canConvertNumber<TOut>(value) ? TOut(value) : 0; +} +} // namespace ARDUINOJSON_NAMESPACE + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +#pragma GCC diagnostic pop +#endif +#endif diff --git a/include/lib/ArduinoJson/Numbers/parseNumber.hpp b/include/lib/ArduinoJson/Numbers/parseNumber.hpp new file mode 100644 index 0000000..cf050c7 --- /dev/null +++ b/include/lib/ArduinoJson/Numbers/parseNumber.hpp @@ -0,0 +1,153 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Numbers/FloatTraits.hpp> +#include <ArduinoJson/Numbers/convertNumber.hpp> +#include <ArduinoJson/Polyfills/assert.hpp> +#include <ArduinoJson/Polyfills/ctype.hpp> +#include <ArduinoJson/Polyfills/math.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Variant/Converter.hpp> +#include <ArduinoJson/Variant/VariantData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename A, typename B> +struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> {}; + +inline bool parseNumber(const char* s, VariantData& result) { + typedef FloatTraits<Float> traits; + typedef choose_largest<traits::mantissa_type, UInt>::type mantissa_t; + typedef traits::exponent_type exponent_t; + + ARDUINOJSON_ASSERT(s != 0); + + bool is_negative = false; + switch (*s) { + case '-': + is_negative = true; + s++; + break; + case '+': + s++; + break; + } + +#if ARDUINOJSON_ENABLE_NAN + if (*s == 'n' || *s == 'N') { + result.setFloat(traits::nan()); + return true; + } +#endif + +#if ARDUINOJSON_ENABLE_INFINITY + if (*s == 'i' || *s == 'I') { + result.setFloat(is_negative ? -traits::inf() : traits::inf()); + return true; + } +#endif + + if (!isdigit(*s) && *s != '.') + return false; + + mantissa_t mantissa = 0; + exponent_t exponent_offset = 0; + const mantissa_t maxUint = UInt(-1); + + while (isdigit(*s)) { + uint8_t digit = uint8_t(*s - '0'); + if (mantissa > maxUint / 10) + break; + mantissa *= 10; + if (mantissa > maxUint - digit) + break; + mantissa += digit; + s++; + } + + if (*s == '\0') { + if (is_negative) { + const mantissa_t sintMantissaMax = mantissa_t(1) + << (sizeof(Integer) * 8 - 1); + if (mantissa <= sintMantissaMax) { + result.setInteger(Integer(~mantissa + 1)); + return true; + } + } else { + result.setInteger(UInt(mantissa)); + return true; + } + } + + // avoid mantissa overflow + while (mantissa > traits::mantissa_max) { + mantissa /= 10; + exponent_offset++; + } + + // remaing digits can't fit in the mantissa + while (isdigit(*s)) { + exponent_offset++; + s++; + } + + if (*s == '.') { + s++; + while (isdigit(*s)) { + if (mantissa < traits::mantissa_max / 10) { + mantissa = mantissa * 10 + uint8_t(*s - '0'); + exponent_offset--; + } + s++; + } + } + + int exponent = 0; + if (*s == 'e' || *s == 'E') { + s++; + bool negative_exponent = false; + if (*s == '-') { + negative_exponent = true; + s++; + } else if (*s == '+') { + s++; + } + + while (isdigit(*s)) { + exponent = exponent * 10 + (*s - '0'); + if (exponent + exponent_offset > traits::exponent_max) { + if (negative_exponent) + result.setFloat(is_negative ? -0.0f : 0.0f); + else + result.setFloat(is_negative ? -traits::inf() : traits::inf()); + return true; + } + s++; + } + if (negative_exponent) + exponent = -exponent; + } + exponent += exponent_offset; + + // we should be at the end of the string, otherwise it's an error + if (*s != '\0') + return false; + + Float final_result = + traits::make_float(static_cast<Float>(mantissa), exponent); + + result.setFloat(is_negative ? -final_result : final_result); + return true; +} + +template <typename T> +inline T parseNumber(const char* s) { + VariantData value; + value.init(); // VariantData is a POD, so it has no constructor + parseNumber(s, value); + return Converter<T>::fromJson(VariantConstRef(&value)); +} +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Object/MemberProxy.hpp b/include/lib/ArduinoJson/Object/MemberProxy.hpp new file mode 100644 index 0000000..0bee84b --- /dev/null +++ b/include/lib/ArduinoJson/Object/MemberProxy.hpp @@ -0,0 +1,202 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Variant/VariantOperators.hpp> +#include <ArduinoJson/Variant/VariantRef.hpp> +#include <ArduinoJson/Variant/VariantShortcuts.hpp> +#include <ArduinoJson/Variant/VariantTo.hpp> + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4522) +#endif + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TObject, typename TStringRef> +class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >, + public VariantShortcuts<MemberProxy<TObject, TStringRef> >, + public Visitable, + public VariantTag { + typedef MemberProxy<TObject, TStringRef> this_type; + + public: + typedef VariantRef variant_type; + + FORCE_INLINE MemberProxy(TObject variant, TStringRef key) + : _object(variant), _key(key) {} + + FORCE_INLINE MemberProxy(const MemberProxy &src) + : _object(src._object), _key(src._key) {} + + FORCE_INLINE operator VariantConstRef() const { + return getUpstreamMember(); + } + + FORCE_INLINE this_type &operator=(const this_type &src) { + getOrAddUpstreamMember().set(src); + return *this; + } + + template <typename TValue> + FORCE_INLINE typename enable_if<!is_array<TValue>::value, this_type &>::type + operator=(const TValue &src) { + getOrAddUpstreamMember().set(src); + return *this; + } + + // operator=(char*) + // operator=(const char*) + // operator=(const __FlashStringHelper*) + template <typename TChar> + FORCE_INLINE this_type &operator=(TChar *src) { + getOrAddUpstreamMember().set(src); + return *this; + } + + FORCE_INLINE void clear() const { + getUpstreamMember().clear(); + } + + FORCE_INLINE bool isNull() const { + return getUpstreamMember().isNull(); + } + + template <typename T> + FORCE_INLINE typename enable_if<!is_same<T, char *>::value, T>::type as() + const { + return getUpstreamMember().template as<T>(); + } + + template <typename T> + FORCE_INLINE typename enable_if<is_same<T, char *>::value, const char *>::type + ARDUINOJSON_DEPRECATED("Replace as<char*>() with as<const char*>()") + as() const { + return as<const char *>(); + } + + template <typename T> + FORCE_INLINE operator T() const { + return getUpstreamMember(); + } + + template <typename TValue> + FORCE_INLINE bool is() const { + return getUpstreamMember().template is<TValue>(); + } + + FORCE_INLINE size_t size() const { + return getUpstreamMember().size(); + } + + FORCE_INLINE void remove(size_t index) const { + getUpstreamMember().remove(index); + } + // remove(char*) const + // remove(const char*) const + // remove(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE typename enable_if<IsString<TChar *>::value>::type remove( + TChar *key) const { + getUpstreamMember().remove(key); + } + // remove(const std::string&) const + // remove(const String&) const + template <typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove( + const TString &key) const { + getUpstreamMember().remove(key); + } + + template <typename TValue> + FORCE_INLINE typename VariantTo<TValue>::type to() { + return getOrAddUpstreamMember().template to<TValue>(); + } + + template <typename TValue> + FORCE_INLINE bool set(const TValue &value) { + return getOrAddUpstreamMember().set(value); + } + + // set(char*) const + // set(const char*) const + // set(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE bool set(TChar *value) { + return getOrAddUpstreamMember().set(value); + } + + template <typename TVisitor> + typename TVisitor::result_type accept(TVisitor &visitor) const { + return getUpstreamMember().accept(visitor); + } + + FORCE_INLINE VariantRef addElement() const { + return getOrAddUpstreamMember().addElement(); + } + + FORCE_INLINE VariantRef getElement(size_t index) const { + return getUpstreamMember().getElement(index); + } + + FORCE_INLINE VariantRef getOrAddElement(size_t index) const { + return getOrAddUpstreamMember().getOrAddElement(index); + } + + // getMember(char*) const + // getMember(const char*) const + // getMember(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE VariantRef getMember(TChar *key) const { + return getUpstreamMember().getMember(key); + } + + // getMember(const std::string&) const + // getMember(const String&) const + template <typename TString> + FORCE_INLINE VariantRef getMember(const TString &key) const { + return getUpstreamMember().getMember(key); + } + + // getOrAddMember(char*) const + // getOrAddMember(const char*) const + // getOrAddMember(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE VariantRef getOrAddMember(TChar *key) const { + return getOrAddUpstreamMember().getOrAddMember(key); + } + + // getOrAddMember(const std::string&) const + // getOrAddMember(const String&) const + template <typename TString> + FORCE_INLINE VariantRef getOrAddMember(const TString &key) const { + return getOrAddUpstreamMember().getOrAddMember(key); + } + + private: + FORCE_INLINE VariantRef getUpstreamMember() const { + return _object.getMember(_key); + } + + FORCE_INLINE VariantRef getOrAddUpstreamMember() const { + return _object.getOrAddMember(_key); + } + + friend bool convertToJson(const this_type &src, VariantRef dst) { + return dst.set(src.getUpstreamMember()); + } + + TObject _object; + TStringRef _key; +}; + +} // namespace ARDUINOJSON_NAMESPACE + +#ifdef _MSC_VER +#pragma warning(pop) +#endif diff --git a/include/lib/ArduinoJson/Object/ObjectFunctions.hpp b/include/lib/ArduinoJson/Object/ObjectFunctions.hpp new file mode 100644 index 0000000..1b46e84 --- /dev/null +++ b/include/lib/ArduinoJson/Object/ObjectFunctions.hpp @@ -0,0 +1,51 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Collection/CollectionData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TVisitor> +typename TVisitor::result_type objectAccept(const CollectionData *obj, + TVisitor &visitor) { + if (obj) + return visitor.visitObject(*obj); + else + return visitor.visitNull(); +} + +inline bool objectEquals(const CollectionData *lhs, const CollectionData *rhs) { + if (lhs == rhs) + return true; + if (!lhs || !rhs) + return false; + return lhs->equalsObject(*rhs); +} + +template <typename TAdaptedString> +inline VariantData *objectGetMember(const CollectionData *obj, + TAdaptedString key) { + if (!obj) + return 0; + return obj->getMember(key); +} + +template <typename TAdaptedString> +void objectRemove(CollectionData *obj, TAdaptedString key) { + if (!obj) + return; + obj->removeMember(key); +} + +template <typename TAdaptedString> +inline VariantData *objectGetOrAddMember(CollectionData *obj, + TAdaptedString key, MemoryPool *pool) { + if (!obj) + return 0; + + return obj->getOrAddMember(key, pool); +} +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Object/ObjectImpl.hpp b/include/lib/ArduinoJson/Object/ObjectImpl.hpp new file mode 100644 index 0000000..d66b61c --- /dev/null +++ b/include/lib/ArduinoJson/Object/ObjectImpl.hpp @@ -0,0 +1,69 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Array/ArrayRef.hpp> +#include <ArduinoJson/Object/ObjectRef.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TObject> +template <typename TString> +inline ArrayRef ObjectShortcuts<TObject>::createNestedArray( + const TString& key) const { + return impl()->getOrAddMember(key).template to<ArrayRef>(); +} + +template <typename TObject> +template <typename TChar> +inline ArrayRef ObjectShortcuts<TObject>::createNestedArray(TChar* key) const { + return impl()->getOrAddMember(key).template to<ArrayRef>(); +} + +template <typename TObject> +template <typename TString> +inline ObjectRef ObjectShortcuts<TObject>::createNestedObject( + const TString& key) const { + return impl()->getOrAddMember(key).template to<ObjectRef>(); +} + +template <typename TObject> +template <typename TChar> +inline ObjectRef ObjectShortcuts<TObject>::createNestedObject( + TChar* key) const { + return impl()->getOrAddMember(key).template to<ObjectRef>(); +} + +template <typename TObject> +template <typename TString> +inline typename enable_if<IsString<TString>::value, bool>::type +ObjectShortcuts<TObject>::containsKey(const TString& key) const { + return !impl()->getMember(key).isUndefined(); +} + +template <typename TObject> +template <typename TChar> +inline typename enable_if<IsString<TChar*>::value, bool>::type +ObjectShortcuts<TObject>::containsKey(TChar* key) const { + return !impl()->getMember(key).isUndefined(); +} + +template <typename TObject> +template <typename TString> +inline typename enable_if<IsString<TString*>::value, + MemberProxy<TObject, TString*> >::type +ObjectShortcuts<TObject>::operator[](TString* key) const { + return MemberProxy<TObject, TString*>(*impl(), key); +} + +template <typename TObject> +template <typename TString> +inline typename enable_if<IsString<TString>::value, + MemberProxy<TObject, TString> >::type +ObjectShortcuts<TObject>::operator[](const TString& key) const { + return MemberProxy<TObject, TString>(*impl(), key); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Object/ObjectIterator.hpp b/include/lib/ArduinoJson/Object/ObjectIterator.hpp new file mode 100644 index 0000000..d729459 --- /dev/null +++ b/include/lib/ArduinoJson/Object/ObjectIterator.hpp @@ -0,0 +1,123 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Object/Pair.hpp> +#include <ArduinoJson/Variant/SlotFunctions.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +class PairPtr { + public: + PairPtr(MemoryPool *pool, VariantSlot *slot) : _pair(pool, slot) {} + + const Pair *operator->() const { + return &_pair; + } + + const Pair &operator*() const { + return _pair; + } + + private: + Pair _pair; +}; + +class ObjectIterator { + public: + ObjectIterator() : _slot(0) {} + + explicit ObjectIterator(MemoryPool *pool, VariantSlot *slot) + : _pool(pool), _slot(slot) {} + + Pair operator*() const { + return Pair(_pool, _slot); + } + PairPtr operator->() { + return PairPtr(_pool, _slot); + } + + bool operator==(const ObjectIterator &other) const { + return _slot == other._slot; + } + + bool operator!=(const ObjectIterator &other) const { + return _slot != other._slot; + } + + ObjectIterator &operator++() { + _slot = _slot->next(); + return *this; + } + + ObjectIterator &operator+=(size_t distance) { + _slot = _slot->next(distance); + return *this; + } + + VariantSlot *internal() { + return _slot; + } + + private: + MemoryPool *_pool; + VariantSlot *_slot; +}; + +class PairConstPtr { + public: + PairConstPtr(const VariantSlot *slot) : _pair(slot) {} + + const PairConst *operator->() const { + return &_pair; + } + + const PairConst &operator*() const { + return _pair; + } + + private: + PairConst _pair; +}; + +class ObjectConstIterator { + public: + ObjectConstIterator() : _slot(0) {} + + explicit ObjectConstIterator(const VariantSlot *slot) : _slot(slot) {} + + PairConst operator*() const { + return PairConst(_slot); + } + PairConstPtr operator->() { + return PairConstPtr(_slot); + } + + bool operator==(const ObjectConstIterator &other) const { + return _slot == other._slot; + } + + bool operator!=(const ObjectConstIterator &other) const { + return _slot != other._slot; + } + + ObjectConstIterator &operator++() { + _slot = _slot->next(); + return *this; + } + + ObjectConstIterator &operator+=(size_t distance) { + _slot = _slot->next(distance); + return *this; + } + + const VariantSlot *internal() { + return _slot; + } + + private: + const VariantSlot *_slot; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Object/ObjectRef.hpp b/include/lib/ArduinoJson/Object/ObjectRef.hpp new file mode 100644 index 0000000..c945fb6 --- /dev/null +++ b/include/lib/ArduinoJson/Object/ObjectRef.hpp @@ -0,0 +1,277 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Object/ObjectFunctions.hpp> +#include <ArduinoJson/Object/ObjectIterator.hpp> + +// Returns the size (in bytes) of an object with n elements. +// Can be very handy to determine the size of a StaticMemoryPool. +#define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \ + ((NUMBER_OF_ELEMENTS) * sizeof(ARDUINOJSON_NAMESPACE::VariantSlot)) + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TData> +class ObjectRefBase { + public: + operator VariantConstRef() const { + const void* data = _data; // prevent warning cast-align + return VariantConstRef(reinterpret_cast<const VariantData*>(data)); + } + + template <typename TVisitor> + typename TVisitor::result_type accept(TVisitor& visitor) const { + return objectAccept(_data, visitor); + } + + FORCE_INLINE bool isNull() const { + return _data == 0; + } + + FORCE_INLINE operator bool() const { + return _data != 0; + } + + FORCE_INLINE size_t memoryUsage() const { + return _data ? _data->memoryUsage() : 0; + } + + FORCE_INLINE size_t nesting() const { + return _data ? _data->nesting() : 0; + } + + FORCE_INLINE size_t size() const { + return _data ? _data->size() : 0; + } + + protected: + ObjectRefBase(TData* data) : _data(data) {} + TData* _data; +}; + +class ObjectConstRef : public ObjectRefBase<const CollectionData>, + public Visitable { + friend class ObjectRef; + typedef ObjectRefBase<const CollectionData> base_type; + + public: + typedef ObjectConstIterator iterator; + + ObjectConstRef() : base_type(0) {} + ObjectConstRef(const CollectionData* data) : base_type(data) {} + + FORCE_INLINE iterator begin() const { + if (!_data) + return iterator(); + return iterator(_data->head()); + } + + FORCE_INLINE iterator end() const { + return iterator(); + } + + // containsKey(const std::string&) const + // containsKey(const String&) const + template <typename TString> + FORCE_INLINE bool containsKey(const TString& key) const { + return !getMember(key).isUndefined(); + } + + // containsKey(char*) const + // containsKey(const char*) const + // containsKey(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE bool containsKey(TChar* key) const { + return !getMember(key).isUndefined(); + } + + // getMember(const std::string&) const + // getMember(const String&) const + template <typename TString> + FORCE_INLINE VariantConstRef getMember(const TString& key) const { + return get_impl(adaptString(key)); + } + + // getMember(char*) const + // getMember(const char*) const + // getMember(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE VariantConstRef getMember(TChar* key) const { + return get_impl(adaptString(key)); + } + + // operator[](const std::string&) const + // operator[](const String&) const + template <typename TString> + FORCE_INLINE + typename enable_if<IsString<TString>::value, VariantConstRef>::type + operator[](const TString& key) const { + return get_impl(adaptString(key)); + } + + // operator[](char*) const + // operator[](const char*) const + // operator[](const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE + typename enable_if<IsString<TChar*>::value, VariantConstRef>::type + operator[](TChar* key) const { + return get_impl(adaptString(key)); + } + + FORCE_INLINE bool operator==(ObjectConstRef rhs) const { + return objectEquals(_data, rhs._data); + } + + private: + template <typename TAdaptedString> + FORCE_INLINE VariantConstRef get_impl(TAdaptedString key) const { + return VariantConstRef(objectGetMember(_data, key)); + } +}; + +class ObjectRef : public ObjectRefBase<CollectionData>, + public ObjectShortcuts<ObjectRef>, + public Visitable { + typedef ObjectRefBase<CollectionData> base_type; + + public: + typedef ObjectIterator iterator; + + FORCE_INLINE ObjectRef() : base_type(0), _pool(0) {} + FORCE_INLINE ObjectRef(MemoryPool* buf, CollectionData* data) + : base_type(data), _pool(buf) {} + + operator VariantRef() const { + void* data = _data; // prevent warning cast-align + return VariantRef(_pool, reinterpret_cast<VariantData*>(data)); + } + + operator ObjectConstRef() const { + return ObjectConstRef(_data); + } + + FORCE_INLINE iterator begin() const { + if (!_data) + return iterator(); + return iterator(_pool, _data->head()); + } + + FORCE_INLINE iterator end() const { + return iterator(); + } + + void clear() const { + if (!_data) + return; + _data->clear(); + } + + FORCE_INLINE bool set(ObjectConstRef src) { + if (!_data || !src._data) + return false; + return _data->copyFrom(*src._data, _pool); + } + + // getMember(const std::string&) const + // getMember(const String&) const + template <typename TString> + FORCE_INLINE VariantRef getMember(const TString& key) const { + return VariantRef(_pool, objectGetMember(_data, adaptString(key))); + } + + // getMember(char*) const + // getMember(const char*) const + // getMember(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE VariantRef getMember(TChar* key) const { + return VariantRef(_pool, objectGetMember(_data, adaptString(key))); + } + + // getOrAddMember(const std::string&) const + // getOrAddMember(const String&) const + template <typename TString> + FORCE_INLINE VariantRef getOrAddMember(const TString& key) const { + return VariantRef(_pool, + objectGetOrAddMember(_data, adaptString(key), _pool)); + } + + // getOrAddMember(char*) const + // getOrAddMember(const char*) const + // getOrAddMember(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE VariantRef getOrAddMember(TChar* key) const { + return VariantRef(_pool, + objectGetOrAddMember(_data, adaptString(key), _pool)); + } + + FORCE_INLINE bool operator==(ObjectRef rhs) const { + return objectEquals(_data, rhs._data); + } + + FORCE_INLINE void remove(iterator it) const { + if (!_data) + return; + _data->removeSlot(it.internal()); + } + + // remove(const std::string&) const + // remove(const String&) const + template <typename TString> + FORCE_INLINE void remove(const TString& key) const { + objectRemove(_data, adaptString(key)); + } + + // remove(char*) const + // remove(const char*) const + // remove(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE void remove(TChar* key) const { + objectRemove(_data, adaptString(key)); + } + + private: + MemoryPool* _pool; +}; + +template <> +struct Converter<ObjectConstRef> { + static bool toJson(VariantConstRef src, VariantRef dst) { + return variantCopyFrom(getData(dst), getData(src), getPool(dst)); + } + + static ObjectConstRef fromJson(VariantConstRef src) { + return ObjectConstRef(variantAsObject(getData(src))); + } + + static bool checkJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data && data->isObject(); + } +}; + +template <> +struct Converter<ObjectRef> { + static bool toJson(VariantConstRef src, VariantRef dst) { + return variantCopyFrom(getData(dst), getData(src), getPool(dst)); + } + + static ObjectRef fromJson(VariantRef src) { + VariantData* data = getData(src); + MemoryPool* pool = getPool(src); + return ObjectRef(pool, data != 0 ? data->asObject() : 0); + } + + static bool checkJson(VariantConstRef) { + return false; + } + + static bool checkJson(VariantRef src) { + VariantData* data = getData(src); + return data && data->isObject(); + } +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Object/ObjectShortcuts.hpp b/include/lib/ArduinoJson/Object/ObjectShortcuts.hpp new file mode 100644 index 0000000..0f3409f --- /dev/null +++ b/include/lib/ArduinoJson/Object/ObjectShortcuts.hpp @@ -0,0 +1,73 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/attributes.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Strings/StringAdapters.hpp> + +namespace ARDUINOJSON_NAMESPACE { +template <typename TParent, typename TStringRef> +class MemberProxy; + +template <typename TObject> +class ObjectShortcuts { + public: + // containsKey(const std::string&) const + // containsKey(const String&) const + template <typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value, bool>::type + containsKey(const TString &key) const; + + // containsKey(char*) const + // containsKey(const char*) const + // containsKey(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE typename enable_if<IsString<TChar *>::value, bool>::type + containsKey(TChar *key) const; + + // operator[](const std::string&) const + // operator[](const String&) const + template <typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value, + MemberProxy<TObject, TString> >::type + operator[](const TString &key) const; + + // operator[](char*) const + // operator[](const char*) const + // operator[](const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE typename enable_if<IsString<TChar *>::value, + MemberProxy<TObject, TChar *> >::type + operator[](TChar *key) const; + + // createNestedArray(const std::string&) const + // createNestedArray(const String&) const + template <typename TString> + FORCE_INLINE ArrayRef createNestedArray(const TString &key) const; + + // createNestedArray(char*) const + // createNestedArray(const char*) const + // createNestedArray(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE ArrayRef createNestedArray(TChar *key) const; + + // createNestedObject(const std::string&) const + // createNestedObject(const String&) const + template <typename TString> + ObjectRef createNestedObject(const TString &key) const; + + // createNestedObject(char*) const + // createNestedObject(const char*) const + // createNestedObject(const __FlashStringHelper*) const + template <typename TChar> + ObjectRef createNestedObject(TChar *key) const; + + private: + const TObject *impl() const { + return static_cast<const TObject *>(this); + } +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Object/Pair.hpp b/include/lib/ArduinoJson/Object/Pair.hpp new file mode 100644 index 0000000..44fce75 --- /dev/null +++ b/include/lib/ArduinoJson/Object/Pair.hpp @@ -0,0 +1,55 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Strings/String.hpp> +#include <ArduinoJson/Variant/VariantRef.hpp> + +namespace ARDUINOJSON_NAMESPACE { +// A key value pair for CollectionData. +class Pair { + public: + Pair(MemoryPool* pool, VariantSlot* slot) { + if (slot) { + _key = String(slot->key(), !slot->ownsKey()); + _value = VariantRef(pool, slot->data()); + } + } + + String key() const { + return _key; + } + + VariantRef value() const { + return _value; + } + + private: + String _key; + VariantRef _value; +}; + +class PairConst { + public: + PairConst(const VariantSlot* slot) { + if (slot) { + _key = String(slot->key(), !slot->ownsKey()); + _value = VariantConstRef(slot->data()); + } + } + + String key() const { + return _key; + } + + VariantConstRef value() const { + return _value; + } + + private: + String _key; + VariantConstRef _value; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/alias_cast.hpp b/include/lib/ArduinoJson/Polyfills/alias_cast.hpp new file mode 100644 index 0000000..8f8e277 --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/alias_cast.hpp @@ -0,0 +1,29 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <stdint.h> +#include <stdlib.h> // for size_t + +#include <ArduinoJson/Configuration.hpp> +#include "math.hpp" + +namespace ARDUINOJSON_NAMESPACE { + +template <typename T, typename F> +struct alias_cast_t { + union { + F raw; + T data; + }; +}; + +template <typename T, typename F> +T alias_cast(F raw_data) { + alias_cast_t<T, F> ac; + ac.raw = raw_data; + return ac.data; +} +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/assert.hpp b/include/lib/ArduinoJson/Polyfills/assert.hpp new file mode 100644 index 0000000..1030ec6 --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/assert.hpp @@ -0,0 +1,14 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> + +#if ARDUINOJSON_DEBUG +#include <assert.h> +#define ARDUINOJSON_ASSERT(X) assert(X) +#else +#define ARDUINOJSON_ASSERT(X) ((void)0) +#endif diff --git a/include/lib/ArduinoJson/Polyfills/attributes.hpp b/include/lib/ArduinoJson/Polyfills/attributes.hpp new file mode 100644 index 0000000..f04c9ac --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/attributes.hpp @@ -0,0 +1,54 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#ifdef _MSC_VER // Visual Studio + +#define FORCE_INLINE // __forceinline causes C4714 when returning std::string +#define NO_INLINE __declspec(noinline) + +#ifndef ARDUINOJSON_DEPRECATED +#define ARDUINOJSON_DEPRECATED(msg) __declspec(deprecated(msg)) +#endif + +#elif defined(__GNUC__) // GCC or Clang + +#define FORCE_INLINE __attribute__((always_inline)) +#define NO_INLINE __attribute__((noinline)) + +#ifndef ARDUINOJSON_DEPRECATED +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) +#define ARDUINOJSON_DEPRECATED(msg) __attribute__((deprecated(msg))) +#else +#define ARDUINOJSON_DEPRECATED(msg) __attribute__((deprecated)) +#endif +#endif + +#else // Other compilers + +#define FORCE_INLINE +#define NO_INLINE + +#ifndef ARDUINOJSON_DEPRECATED +#define ARDUINOJSON_DEPRECATED(msg) +#endif + +#endif + +#if __cplusplus >= 201103L +#define NOEXCEPT noexcept +#else +#define NOEXCEPT throw() +#endif + +#if defined(__has_attribute) +#if __has_attribute(no_sanitize) +#define ARDUINOJSON_NO_SANITIZE(check) __attribute__((no_sanitize(check))) +#else +#define ARDUINOJSON_NO_SANITIZE(check) +#endif +#else +#define ARDUINOJSON_NO_SANITIZE(check) +#endif diff --git a/include/lib/ArduinoJson/Polyfills/ctype.hpp b/include/lib/ArduinoJson/Polyfills/ctype.hpp new file mode 100644 index 0000000..bd7a8cc --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/ctype.hpp @@ -0,0 +1,20 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +#ifndef isdigit +inline bool isdigit(char c) { + return '0' <= c && c <= '9'; +} +#endif + +inline bool issign(char c) { + return '-' == c || c == '+'; +} +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/integer.hpp b/include/lib/ArduinoJson/Polyfills/integer.hpp new file mode 100644 index 0000000..066c7b8 --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/integer.hpp @@ -0,0 +1,30 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <stdint.h> // int8_t, int16_t + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <int Bits> +struct int_t; + +template <> +struct int_t<8> { + typedef int8_t type; +}; + +template <> +struct int_t<16> { + typedef int16_t type; +}; + +template <> +struct int_t<32> { + typedef int32_t type; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/limits.hpp b/include/lib/ArduinoJson/Polyfills/limits.hpp new file mode 100644 index 0000000..8004828 --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/limits.hpp @@ -0,0 +1,45 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include "type_traits.hpp" + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4310) +#endif + +namespace ARDUINOJSON_NAMESPACE { + +// Differs from standard because we can't use the symbols "min" and "max" +template <typename T, typename Enable = void> +struct numeric_limits; + +template <typename T> +struct numeric_limits<T, typename enable_if<is_unsigned<T>::value>::type> { + static T lowest() { + return 0; + } + static T highest() { + return T(-1); + } +}; + +template <typename T> +struct numeric_limits< + T, typename enable_if<is_integral<T>::value && is_signed<T>::value>::type> { + static T lowest() { + return T(T(1) << (sizeof(T) * 8 - 1)); + } + static T highest() { + return T(~lowest()); + } +}; + +} // namespace ARDUINOJSON_NAMESPACE + +#ifdef _MSC_VER +#pragma warning(pop) +#endif diff --git a/include/lib/ArduinoJson/Polyfills/math.hpp b/include/lib/ArduinoJson/Polyfills/math.hpp new file mode 100644 index 0000000..eff272a --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/math.hpp @@ -0,0 +1,27 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +// Some libraries #define isnan() and isinf() so we need to check before +// using this name + +#ifndef isnan +template <typename T> +bool isnan(T x) { + return x != x; +} +#endif + +#ifndef isinf +template <typename T> +bool isinf(T x) { + return x != 0.0 && x * 2 == x; +} +#endif +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/mpl/max.hpp b/include/lib/ArduinoJson/Polyfills/mpl/max.hpp new file mode 100644 index 0000000..9ac47a5 --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/mpl/max.hpp @@ -0,0 +1,26 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +#include <stddef.h> // for size_t + +namespace ARDUINOJSON_NAMESPACE { + +// A meta-function that returns the highest value +template <size_t X, size_t Y, bool MaxIsX = (X > Y)> +struct Max {}; + +template <size_t X, size_t Y> +struct Max<X, Y, true> { + static const size_t value = X; +}; + +template <size_t X, size_t Y> +struct Max<X, Y, false> { + static const size_t value = Y; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/pgmspace.hpp b/include/lib/ArduinoJson/Polyfills/pgmspace.hpp new file mode 100644 index 0000000..f253818 --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/pgmspace.hpp @@ -0,0 +1,79 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Polyfills/assert.hpp> + +namespace ARDUINOJSON_NAMESPACE { +// Wraps a const char* so that the our functions are picked only if the +// originals are missing +struct pgm_p { + pgm_p(const char* p) : address(p) {} + const char* address; +}; +} // namespace ARDUINOJSON_NAMESPACE + +#ifndef strlen_P +inline size_t strlen_P(ARDUINOJSON_NAMESPACE::pgm_p s) { + const char* p = s.address; + ARDUINOJSON_ASSERT(p != NULL); + while (pgm_read_byte(p)) p++; + return size_t(p - s.address); +} +#endif + +#ifndef strncmp_P +inline int strncmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b, size_t n) { + const char* s1 = a; + const char* s2 = b.address; + ARDUINOJSON_ASSERT(s1 != NULL); + ARDUINOJSON_ASSERT(s2 != NULL); + while (n-- > 0) { + char c1 = *s1++; + char c2 = static_cast<char>(pgm_read_byte(s2++)); + if (c1 < c2) + return -1; + if (c1 > c2) + return 1; + if (c1 == 0 /* and c2 as well */) + return 0; + } + return 0; +} +#endif + +#ifndef strcmp_P +inline int strcmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b) { + const char* s1 = a; + const char* s2 = b.address; + ARDUINOJSON_ASSERT(s1 != NULL); + ARDUINOJSON_ASSERT(s2 != NULL); + for (;;) { + char c1 = *s1++; + char c2 = static_cast<char>(pgm_read_byte(s2++)); + if (c1 < c2) + return -1; + if (c1 > c2) + return 1; + if (c1 == 0 /* and c2 as well */) + return 0; + } +} +#endif + +#ifndef memcpy_P +inline void* memcpy_P(void* dst, ARDUINOJSON_NAMESPACE::pgm_p src, size_t n) { + uint8_t* d = reinterpret_cast<uint8_t*>(dst); + const char* s = src.address; + ARDUINOJSON_ASSERT(d != NULL); + ARDUINOJSON_ASSERT(s != NULL); + while (n-- > 0) { + *d++ = pgm_read_byte(s++); + } + return dst; +} +#endif diff --git a/include/lib/ArduinoJson/Polyfills/pgmspace_generic.hpp b/include/lib/ArduinoJson/Polyfills/pgmspace_generic.hpp new file mode 100644 index 0000000..f5bbd85 --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/pgmspace_generic.hpp @@ -0,0 +1,32 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename T> +typename enable_if<is_pointer<T>::value, T>::type pgm_read(const void* p) { + return reinterpret_cast<T>(pgm_read_ptr(p)); +} + +template <typename T> +typename enable_if<is_floating_point<T>::value && + sizeof(T) == sizeof(float), // on AVR sizeof(double) == + // sizeof(float) + T>::type +pgm_read(const void* p) { + return pgm_read_float(p); +} + +template <typename T> +typename enable_if<is_same<T, uint32_t>::value, T>::type pgm_read( + const void* p) { + return pgm_read_dword(p); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/preprocessor.hpp b/include/lib/ArduinoJson/Polyfills/preprocessor.hpp new file mode 100644 index 0000000..488654b --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/preprocessor.hpp @@ -0,0 +1,35 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#define ARDUINOJSON_EXPAND6(a, b, c, d, e, f) a, b, c, d, e, f +#define ARDUINOJSON_EXPAND9(a, b, c, d, e, f, g, h, i) a, b, c, d, e, f, g, h, i +#define ARDUINOJSON_EXPAND18(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, \ + q, r) \ + a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r + +#define ARDUINOJSON_CONCAT_(A, B) A##B +#define ARDUINOJSON_CONCAT2(A, B) ARDUINOJSON_CONCAT_(A, B) +#define ARDUINOJSON_CONCAT4(A, B, C, D) \ + ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT2(A, B), ARDUINOJSON_CONCAT2(C, D)) + +#define ARDUINOJSON_HEX_DIGIT_0000() 0 +#define ARDUINOJSON_HEX_DIGIT_0001() 1 +#define ARDUINOJSON_HEX_DIGIT_0010() 2 +#define ARDUINOJSON_HEX_DIGIT_0011() 3 +#define ARDUINOJSON_HEX_DIGIT_0100() 4 +#define ARDUINOJSON_HEX_DIGIT_0101() 5 +#define ARDUINOJSON_HEX_DIGIT_0110() 6 +#define ARDUINOJSON_HEX_DIGIT_0111() 7 +#define ARDUINOJSON_HEX_DIGIT_1000() 8 +#define ARDUINOJSON_HEX_DIGIT_1001() 9 +#define ARDUINOJSON_HEX_DIGIT_1010() A +#define ARDUINOJSON_HEX_DIGIT_1011() B +#define ARDUINOJSON_HEX_DIGIT_1100() C +#define ARDUINOJSON_HEX_DIGIT_1101() D +#define ARDUINOJSON_HEX_DIGIT_1110() E +#define ARDUINOJSON_HEX_DIGIT_1111() F +#define ARDUINOJSON_HEX_DIGIT_(A, B, C, D) ARDUINOJSON_HEX_DIGIT_##A##B##C##D() +#define ARDUINOJSON_HEX_DIGIT(A, B, C, D) ARDUINOJSON_HEX_DIGIT_(A, B, C, D) diff --git a/include/lib/ArduinoJson/Polyfills/safe_strcmp.hpp b/include/lib/ArduinoJson/Polyfills/safe_strcmp.hpp new file mode 100644 index 0000000..e017b5d --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/safe_strcmp.hpp @@ -0,0 +1,32 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +#include <stdint.h> // int8_t + +namespace ARDUINOJSON_NAMESPACE { + +inline int safe_strcmp(const char* a, const char* b) { + if (a == b) + return 0; + if (!a) + return -1; + if (!b) + return 1; + return strcmp(a, b); +} + +inline int safe_strncmp(const char* a, const char* b, size_t n) { + if (a == b) + return 0; + if (!a) + return -1; + if (!b) + return 1; + return strncmp(a, b, n); +} +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/static_array.hpp b/include/lib/ArduinoJson/Polyfills/static_array.hpp new file mode 100644 index 0000000..a877b4c --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/static_array.hpp @@ -0,0 +1,34 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> + +#if ARDUINOJSON_ENABLE_PROGMEM + +#include <ArduinoJson/Polyfills/pgmspace_generic.hpp> + +#ifndef ARDUINOJSON_DEFINE_STATIC_ARRAY +#define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) \ + static type const name[] PROGMEM = value; +#endif + +#ifndef ARDUINOJSON_READ_STATIC_ARRAY +#define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) \ + pgm_read<type>(name + index) +#endif + +#else // i.e. ARDUINOJSON_ENABLE_PROGMEM == 0 + +#ifndef ARDUINOJSON_DEFINE_STATIC_ARRAY +#define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) \ + static type const name[] = value; +#endif + +#ifndef ARDUINOJSON_READ_STATIC_ARRAY +#define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) name[index] +#endif + +#endif diff --git a/include/lib/ArduinoJson/Polyfills/type_traits.hpp b/include/lib/ArduinoJson/Polyfills/type_traits.hpp new file mode 100644 index 0000000..4a8ff4b --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/type_traits.hpp @@ -0,0 +1,24 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include "type_traits/conditional.hpp" +#include "type_traits/enable_if.hpp" +#include "type_traits/integral_constant.hpp" +#include "type_traits/is_array.hpp" +#include "type_traits/is_base_of.hpp" +#include "type_traits/is_class.hpp" +#include "type_traits/is_const.hpp" +#include "type_traits/is_convertible.hpp" +#include "type_traits/is_enum.hpp" +#include "type_traits/is_floating_point.hpp" +#include "type_traits/is_integral.hpp" +#include "type_traits/is_pointer.hpp" +#include "type_traits/is_same.hpp" +#include "type_traits/is_signed.hpp" +#include "type_traits/is_unsigned.hpp" +#include "type_traits/make_unsigned.hpp" +#include "type_traits/remove_const.hpp" +#include "type_traits/remove_reference.hpp" diff --git a/include/lib/ArduinoJson/Polyfills/type_traits/conditional.hpp b/include/lib/ArduinoJson/Polyfills/type_traits/conditional.hpp new file mode 100644 index 0000000..e42d1bb --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/type_traits/conditional.hpp @@ -0,0 +1,20 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <bool Condition, class TrueType, class FalseType> +struct conditional { + typedef TrueType type; +}; + +template <class TrueType, class FalseType> +struct conditional<false, TrueType, FalseType> { + typedef FalseType type; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/type_traits/declval.hpp b/include/lib/ArduinoJson/Polyfills/type_traits/declval.hpp new file mode 100644 index 0000000..8708112 --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/type_traits/declval.hpp @@ -0,0 +1,14 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename T> +T declval(); + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/type_traits/enable_if.hpp b/include/lib/ArduinoJson/Polyfills/type_traits/enable_if.hpp new file mode 100644 index 0000000..cc29b33 --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/type_traits/enable_if.hpp @@ -0,0 +1,19 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +// A meta-function that return the type T if Condition is true. +template <bool Condition, typename T = void> +struct enable_if {}; + +template <typename T> +struct enable_if<true, T> { + typedef T type; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/type_traits/integral_constant.hpp b/include/lib/ArduinoJson/Polyfills/type_traits/integral_constant.hpp new file mode 100644 index 0000000..b53d711 --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/type_traits/integral_constant.hpp @@ -0,0 +1,19 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename T, T v> +struct integral_constant { + static const T value = v; +}; + +typedef integral_constant<bool, true> true_type; +typedef integral_constant<bool, false> false_type; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/type_traits/is_array.hpp b/include/lib/ArduinoJson/Polyfills/type_traits/is_array.hpp new file mode 100644 index 0000000..ee739a7 --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/type_traits/is_array.hpp @@ -0,0 +1,21 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +#include <stddef.h> // size_t + +namespace ARDUINOJSON_NAMESPACE { + +template <typename T> +struct is_array : false_type {}; + +template <typename T> +struct is_array<T[]> : true_type {}; + +template <typename T, size_t N> +struct is_array<T[N]> : true_type {}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/type_traits/is_base_of.hpp b/include/lib/ArduinoJson/Polyfills/type_traits/is_base_of.hpp new file mode 100644 index 0000000..32b41cd --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/type_traits/is_base_of.hpp @@ -0,0 +1,26 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +// A meta-function that returns true if Derived inherits from TBase is an +// integral type. +template <typename TBase, typename TDerived> +class is_base_of { + protected: // <- to avoid GCC's "all member functions in class are private" + typedef char Yes[1]; + typedef char No[2]; + + static Yes &probe(const TBase *); + static No &probe(...); + + public: + static const bool value = + sizeof(probe(reinterpret_cast<TDerived *>(0))) == sizeof(Yes); +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/type_traits/is_class.hpp b/include/lib/ArduinoJson/Polyfills/type_traits/is_class.hpp new file mode 100644 index 0000000..a3808f3 --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/type_traits/is_class.hpp @@ -0,0 +1,26 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include "declval.hpp" + +namespace ARDUINOJSON_NAMESPACE { + +template <typename T> +struct is_class { + protected: // <- to avoid GCC's "all member functions in class are private" + typedef char Yes[1]; + typedef char No[2]; + + template <typename U> + static Yes &probe(void (U::*)(void)); + template <typename> + static No &probe(...); + + public: + static const bool value = sizeof(probe<T>(0)) == sizeof(Yes); +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/type_traits/is_const.hpp b/include/lib/ArduinoJson/Polyfills/type_traits/is_const.hpp new file mode 100644 index 0000000..32e758c --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/type_traits/is_const.hpp @@ -0,0 +1,17 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include "integral_constant.hpp" + +namespace ARDUINOJSON_NAMESPACE { + +// A meta-function that return the type T without the const modifier +template <typename T> +struct is_const : false_type {}; + +template <typename T> +struct is_const<const T> : true_type {}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/type_traits/is_convertible.hpp b/include/lib/ArduinoJson/Polyfills/type_traits/is_convertible.hpp new file mode 100644 index 0000000..847525a --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/type_traits/is_convertible.hpp @@ -0,0 +1,47 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include "declval.hpp" + +#ifdef _MSC_VER +#pragma warning(push) +// conversion from 'T' to 'To', possible loss of data +#pragma warning(disable : 4244) +#endif + +// clang-format off +#ifdef __ICCARM__ +// Suppress IAR Compiler Warning[Pa093]: implicit conversion from floating point to integer +#pragma diag_suppress=Pa093 +#endif +// clang-format on + +namespace ARDUINOJSON_NAMESPACE { + +template <typename From, typename To> +struct is_convertible { + protected: // <- to avoid GCC's "all member functions in class are private" + typedef char Yes[1]; + typedef char No[2]; + + static Yes &probe(To); + static No &probe(...); + + public: + static const bool value = sizeof(probe(declval<From>())) == sizeof(Yes); +}; + +} // namespace ARDUINOJSON_NAMESPACE + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// clang-format off +#ifdef __ICCARM__ +#pragma diag_default=Pa093 +#endif +// clang-format on diff --git a/include/lib/ArduinoJson/Polyfills/type_traits/is_enum.hpp b/include/lib/ArduinoJson/Polyfills/type_traits/is_enum.hpp new file mode 100644 index 0000000..26aec1d --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/type_traits/is_enum.hpp @@ -0,0 +1,22 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include "is_class.hpp" +#include "is_convertible.hpp" +#include "is_floating_point.hpp" +#include "is_integral.hpp" +#include "is_same.hpp" + +namespace ARDUINOJSON_NAMESPACE { + +template <typename T> +struct is_enum { + static const bool value = is_convertible<T, int>::value && + !is_class<T>::value && !is_integral<T>::value && + !is_floating_point<T>::value; +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/type_traits/is_floating_point.hpp b/include/lib/ArduinoJson/Polyfills/type_traits/is_floating_point.hpp new file mode 100644 index 0000000..b7e9d3d --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/type_traits/is_floating_point.hpp @@ -0,0 +1,19 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include "integral_constant.hpp" + +namespace ARDUINOJSON_NAMESPACE { + +template <typename> +struct is_floating_point : false_type {}; + +template <> +struct is_floating_point<float> : true_type {}; + +template <> +struct is_floating_point<double> : true_type {}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/type_traits/is_integral.hpp b/include/lib/ArduinoJson/Polyfills/type_traits/is_integral.hpp new file mode 100644 index 0000000..26e895c --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/type_traits/is_integral.hpp @@ -0,0 +1,33 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include "is_same.hpp" + +namespace ARDUINOJSON_NAMESPACE { + +// A meta-function that returns true if T is an integral type. +template <typename T> +struct is_integral { + static const bool value = + is_same<T, signed char>::value || is_same<T, unsigned char>::value || + is_same<T, signed short>::value || is_same<T, unsigned short>::value || + is_same<T, signed int>::value || is_same<T, unsigned int>::value || + is_same<T, signed long>::value || is_same<T, unsigned long>::value || +#if ARDUINOJSON_HAS_LONG_LONG + is_same<T, signed long long>::value || + is_same<T, unsigned long long>::value || +#endif +#if ARDUINOJSON_HAS_INT64 + is_same<T, signed __int64>::value || + is_same<T, unsigned __int64>::value || +#endif + is_same<T, char>::value || is_same<T, bool>::value; +}; + +template <typename T> +struct is_integral<const T> : is_integral<T> {}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/type_traits/is_pointer.hpp b/include/lib/ArduinoJson/Polyfills/type_traits/is_pointer.hpp new file mode 100644 index 0000000..a249539 --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/type_traits/is_pointer.hpp @@ -0,0 +1,16 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include "integral_constant.hpp" + +namespace ARDUINOJSON_NAMESPACE { + +template <typename T> +struct is_pointer : false_type {}; + +template <typename T> +struct is_pointer<T*> : true_type {}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/type_traits/is_same.hpp b/include/lib/ArduinoJson/Polyfills/type_traits/is_same.hpp new file mode 100644 index 0000000..db5da9b --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/type_traits/is_same.hpp @@ -0,0 +1,17 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include "integral_constant.hpp" + +namespace ARDUINOJSON_NAMESPACE { + +// A meta-function that returns true if types T and U are the same. +template <typename T, typename U> +struct is_same : false_type {}; + +template <typename T> +struct is_same<T, T> : true_type {}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/type_traits/is_signed.hpp b/include/lib/ArduinoJson/Polyfills/type_traits/is_signed.hpp new file mode 100644 index 0000000..fbb701c --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/type_traits/is_signed.hpp @@ -0,0 +1,43 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include "integral_constant.hpp" +namespace ARDUINOJSON_NAMESPACE { + +template <typename> +struct is_signed : false_type {}; + +template <> +struct is_signed<char> : true_type {}; + +template <> +struct is_signed<signed char> : true_type {}; + +template <> +struct is_signed<signed short> : true_type {}; + +template <> +struct is_signed<signed int> : true_type {}; + +template <> +struct is_signed<signed long> : true_type {}; + +template <> +struct is_signed<float> : true_type {}; + +template <> +struct is_signed<double> : true_type {}; + +#if ARDUINOJSON_HAS_LONG_LONG +template <> +struct is_signed<signed long long> : true_type {}; +#endif + +#if ARDUINOJSON_HAS_INT64 +template <> +struct is_signed<signed __int64> : true_type {}; +#endif +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/type_traits/is_unsigned.hpp b/include/lib/ArduinoJson/Polyfills/type_traits/is_unsigned.hpp new file mode 100644 index 0000000..be26498 --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/type_traits/is_unsigned.hpp @@ -0,0 +1,37 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include "integral_constant.hpp" +namespace ARDUINOJSON_NAMESPACE { + +template <typename> +struct is_unsigned : false_type {}; + +template <> +struct is_unsigned<bool> : true_type {}; + +template <> +struct is_unsigned<unsigned char> : true_type {}; + +template <> +struct is_unsigned<unsigned short> : true_type {}; + +template <> +struct is_unsigned<unsigned int> : true_type {}; + +template <> +struct is_unsigned<unsigned long> : true_type {}; + +#if ARDUINOJSON_HAS_INT64 +template <> +struct is_unsigned<unsigned __int64> : true_type {}; +#endif + +#if ARDUINOJSON_HAS_LONG_LONG +template <> +struct is_unsigned<unsigned long long> : true_type {}; +#endif +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/type_traits/make_unsigned.hpp b/include/lib/ArduinoJson/Polyfills/type_traits/make_unsigned.hpp new file mode 100644 index 0000000..4cf2d08 --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/type_traits/make_unsigned.hpp @@ -0,0 +1,49 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include "type_identity.hpp" +namespace ARDUINOJSON_NAMESPACE { + +template <typename T> +struct make_unsigned; + +template <> +struct make_unsigned<char> : type_identity<unsigned char> {}; + +template <> +struct make_unsigned<signed char> : type_identity<unsigned char> {}; +template <> +struct make_unsigned<unsigned char> : type_identity<unsigned char> {}; + +template <> +struct make_unsigned<signed short> : type_identity<unsigned short> {}; +template <> +struct make_unsigned<unsigned short> : type_identity<unsigned short> {}; + +template <> +struct make_unsigned<signed int> : type_identity<unsigned int> {}; +template <> +struct make_unsigned<unsigned int> : type_identity<unsigned int> {}; + +template <> +struct make_unsigned<signed long> : type_identity<unsigned long> {}; +template <> +struct make_unsigned<unsigned long> : type_identity<unsigned long> {}; + +#if ARDUINOJSON_HAS_LONG_LONG +template <> +struct make_unsigned<signed long long> : type_identity<unsigned long long> {}; +template <> +struct make_unsigned<unsigned long long> : type_identity<unsigned long long> {}; +#endif + +#if ARDUINOJSON_HAS_INT64 +template <> +struct make_unsigned<signed __int64> : type_identity<unsigned __int64> {}; +template <> +struct make_unsigned<unsigned __int64> : type_identity<unsigned __int64> {}; +#endif +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/type_traits/remove_const.hpp b/include/lib/ArduinoJson/Polyfills/type_traits/remove_const.hpp new file mode 100644 index 0000000..5a19eb1 --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/type_traits/remove_const.hpp @@ -0,0 +1,20 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +// A meta-function that return the type T without the const modifier +template <typename T> +struct remove_const { + typedef T type; +}; +template <typename T> +struct remove_const<const T> { + typedef T type; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/type_traits/remove_reference.hpp b/include/lib/ArduinoJson/Polyfills/type_traits/remove_reference.hpp new file mode 100644 index 0000000..1812850 --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/type_traits/remove_reference.hpp @@ -0,0 +1,20 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +// A meta-function that return the type T without the reference modifier. +template <typename T> +struct remove_reference { + typedef T type; +}; +template <typename T> +struct remove_reference<T&> { + typedef T type; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/type_traits/type_identity.hpp b/include/lib/ArduinoJson/Polyfills/type_traits/type_identity.hpp new file mode 100644 index 0000000..c464a47 --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/type_traits/type_identity.hpp @@ -0,0 +1,15 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include "integral_constant.hpp" + +namespace ARDUINOJSON_NAMESPACE { + +template <typename T> +struct type_identity { + typedef T type; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Polyfills/utility.hpp b/include/lib/ArduinoJson/Polyfills/utility.hpp new file mode 100644 index 0000000..c99bc99 --- /dev/null +++ b/include/lib/ArduinoJson/Polyfills/utility.hpp @@ -0,0 +1,28 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include "type_traits.hpp" + +namespace ARDUINOJSON_NAMESPACE { +template <typename T> +inline void swap(T& a, T& b) { + T t(a); + a = b; + b = t; +} + +#if ARDUINOJSON_HAS_RVALUE_REFERENCES +template <typename T> +typename remove_reference<T>::type&& move(T&& t) { + return static_cast<typename remove_reference<T>::type&&>(t); +} +#else +template <typename T> +T& move(T& t) { + return t; +} +#endif +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Serialization/CountingDecorator.hpp b/include/lib/ArduinoJson/Serialization/CountingDecorator.hpp new file mode 100644 index 0000000..3d89fb1 --- /dev/null +++ b/include/lib/ArduinoJson/Serialization/CountingDecorator.hpp @@ -0,0 +1,33 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TWriter> +class CountingDecorator { + public: + explicit CountingDecorator(TWriter& writer) : _writer(writer), _count(0) {} + + void write(uint8_t c) { + _count += _writer.write(c); + } + + void write(const uint8_t* s, size_t n) { + _count += _writer.write(s, n); + } + + size_t count() const { + return _count; + } + + private: + TWriter _writer; + size_t _count; +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Serialization/Writer.hpp b/include/lib/ArduinoJson/Serialization/Writer.hpp new file mode 100644 index 0000000..52bd117 --- /dev/null +++ b/include/lib/ArduinoJson/Serialization/Writer.hpp @@ -0,0 +1,47 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +// The default writer is a simple wrapper for Writers that are not copiable +template <typename TDestination, typename Enable = void> +class Writer { + public: + explicit Writer(TDestination& dest) : _dest(&dest) {} + + size_t write(uint8_t c) { + return _dest->write(c); + } + + size_t write(const uint8_t* s, size_t n) { + return _dest->write(s, n); + } + + private: + TDestination* _dest; +}; + +} // namespace ARDUINOJSON_NAMESPACE + +#include <ArduinoJson/Serialization/Writers/StaticStringWriter.hpp> + +#if ARDUINOJSON_ENABLE_STD_STRING +#include <ArduinoJson/Serialization/Writers/StdStringWriter.hpp> +#endif + +#if ARDUINOJSON_ENABLE_ARDUINO_STRING +#include <ArduinoJson/Serialization/Writers/ArduinoStringWriter.hpp> +#endif + +#if ARDUINOJSON_ENABLE_STD_STREAM +#include <ArduinoJson/Serialization/Writers/StdStreamWriter.hpp> +#endif + +#if ARDUINOJSON_ENABLE_ARDUINO_PRINT +#include <ArduinoJson/Serialization/Writers/PrintWriter.hpp> +#endif diff --git a/include/lib/ArduinoJson/Serialization/Writers/ArduinoStringWriter.hpp b/include/lib/ArduinoJson/Serialization/Writers/ArduinoStringWriter.hpp new file mode 100644 index 0000000..5efa6e4 --- /dev/null +++ b/include/lib/ArduinoJson/Serialization/Writers/ArduinoStringWriter.hpp @@ -0,0 +1,52 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <Arduino.h> + +namespace ARDUINOJSON_NAMESPACE { + +template <> +class Writer< ::String, void> { + static const size_t bufferCapacity = ARDUINOJSON_STRING_BUFFER_SIZE; + + public: + explicit Writer(::String &str) : _destination(&str) { + _size = 0; + } + + ~Writer() { + flush(); + } + + size_t write(uint8_t c) { + ARDUINOJSON_ASSERT(_size < bufferCapacity); + _buffer[_size++] = static_cast<char>(c); + if (_size + 1 >= bufferCapacity) + flush(); + return 1; + } + + size_t write(const uint8_t *s, size_t n) { + for (size_t i = 0; i < n; i++) { + write(s[i]); + } + return n; + } + + private: + void flush() { + ARDUINOJSON_ASSERT(_size < bufferCapacity); + _buffer[_size] = 0; + *_destination += _buffer; + _size = 0; + } + + ::String *_destination; + char _buffer[bufferCapacity]; + size_t _size; +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Serialization/Writers/DummyWriter.hpp b/include/lib/ArduinoJson/Serialization/Writers/DummyWriter.hpp new file mode 100644 index 0000000..a26a1f1 --- /dev/null +++ b/include/lib/ArduinoJson/Serialization/Writers/DummyWriter.hpp @@ -0,0 +1,21 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +class DummyWriter { + public: + size_t write(uint8_t) { + return 1; + } + + size_t write(const uint8_t*, size_t n) { + return n; + } +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Serialization/Writers/PrintWriter.hpp b/include/lib/ArduinoJson/Serialization/Writers/PrintWriter.hpp new file mode 100644 index 0000000..13a6491 --- /dev/null +++ b/include/lib/ArduinoJson/Serialization/Writers/PrintWriter.hpp @@ -0,0 +1,28 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TDestination> +class Writer< + TDestination, + typename enable_if<is_base_of< ::Print, TDestination>::value>::type> { + public: + explicit Writer(::Print& print) : _print(&print) {} + + size_t write(uint8_t c) { + return _print->write(c); + } + + size_t write(const uint8_t* s, size_t n) { + return _print->write(s, n); + } + + private: + ::Print* _print; +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Serialization/Writers/StaticStringWriter.hpp b/include/lib/ArduinoJson/Serialization/Writers/StaticStringWriter.hpp new file mode 100644 index 0000000..1a4213b --- /dev/null +++ b/include/lib/ArduinoJson/Serialization/Writers/StaticStringWriter.hpp @@ -0,0 +1,35 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +class StaticStringWriter { + public: + StaticStringWriter(char *buf, size_t size) : end(buf + size), p(buf) {} + + size_t write(uint8_t c) { + if (p >= end) + return 0; + *p++ = static_cast<char>(c); + return 1; + } + + size_t write(const uint8_t *s, size_t n) { + char *begin = p; + while (p < end && n > 0) { + *p++ = static_cast<char>(*s++); + n--; + } + return size_t(p - begin); + } + + private: + char *end; + char *p; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Serialization/Writers/StdStreamWriter.hpp b/include/lib/ArduinoJson/Serialization/Writers/StdStreamWriter.hpp new file mode 100644 index 0000000..e08ba4d --- /dev/null +++ b/include/lib/ArduinoJson/Serialization/Writers/StdStreamWriter.hpp @@ -0,0 +1,32 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ostream> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TDestination> +class Writer< + TDestination, + typename enable_if<is_base_of<std::ostream, TDestination>::value>::type> { + public: + explicit Writer(std::ostream& os) : _os(&os) {} + + size_t write(uint8_t c) { + _os->put(static_cast<char>(c)); + return 1; + } + + size_t write(const uint8_t* s, size_t n) { + _os->write(reinterpret_cast<const char*>(s), + static_cast<std::streamsize>(n)); + return n; + } + + private: + std::ostream* _os; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Serialization/Writers/StdStringWriter.hpp b/include/lib/ArduinoJson/Serialization/Writers/StdStringWriter.hpp new file mode 100644 index 0000000..c1f7cc0 --- /dev/null +++ b/include/lib/ArduinoJson/Serialization/Writers/StdStringWriter.hpp @@ -0,0 +1,40 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> + +#include <string> + +namespace ARDUINOJSON_NAMESPACE { + +template <class T> +struct is_std_string : false_type {}; + +template <class TCharTraits, class TAllocator> +struct is_std_string<std::basic_string<char, TCharTraits, TAllocator> > + : true_type {}; + +template <typename TDestination> +class Writer<TDestination, + typename enable_if<is_std_string<TDestination>::value>::type> { + public: + Writer(TDestination &str) : _str(&str) {} + + size_t write(uint8_t c) { + _str->operator+=(static_cast<char>(c)); + return 1; + } + + size_t write(const uint8_t *s, size_t n) { + _str->append(reinterpret_cast<const char *>(s), n); + return n; + } + + private: + TDestination *_str; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Serialization/measure.hpp b/include/lib/ArduinoJson/Serialization/measure.hpp new file mode 100644 index 0000000..6d19994 --- /dev/null +++ b/include/lib/ArduinoJson/Serialization/measure.hpp @@ -0,0 +1,18 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Serialization/Writers/DummyWriter.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <template <typename> class TSerializer, typename TSource> +size_t measure(const TSource &source) { + DummyWriter dp; + TSerializer<DummyWriter> serializer(dp); + return source.accept(serializer); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Serialization/serialize.hpp b/include/lib/ArduinoJson/Serialization/serialize.hpp new file mode 100644 index 0000000..16d2e4e --- /dev/null +++ b/include/lib/ArduinoJson/Serialization/serialize.hpp @@ -0,0 +1,54 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Serialization/Writer.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <template <typename> class TSerializer, typename TSource, + typename TWriter> +size_t doSerialize(const TSource &source, TWriter writer) { + TSerializer<TWriter> serializer(writer); + return source.accept(serializer); +} + +template <template <typename> class TSerializer, typename TSource, + typename TDestination> +size_t serialize(const TSource &source, TDestination &destination) { + Writer<TDestination> writer(destination); + return doSerialize<TSerializer>(source, writer); +} + +template <template <typename> class TSerializer, typename TSource> +typename enable_if<!TSerializer<StaticStringWriter>::producesText, size_t>::type +serialize(const TSource &source, void *buffer, size_t bufferSize) { + StaticStringWriter writer(reinterpret_cast<char *>(buffer), bufferSize); + return doSerialize<TSerializer>(source, writer); +} + +template <template <typename> class TSerializer, typename TSource> +typename enable_if<TSerializer<StaticStringWriter>::producesText, size_t>::type +serialize(const TSource &source, void *buffer, size_t bufferSize) { + StaticStringWriter writer(reinterpret_cast<char *>(buffer), bufferSize); + size_t n = doSerialize<TSerializer>(source, writer); + // add null-terminator for text output (not counted in the size) + if (n < bufferSize) + reinterpret_cast<char *>(buffer)[n] = 0; + return n; +} + +template <template <typename> class TSerializer, typename TSource, + typename TChar, size_t N> +#if defined _MSC_VER && _MSC_VER < 1900 +typename enable_if<sizeof(remove_reference<TChar>::type) == 1, size_t>::type +#else +typename enable_if<sizeof(TChar) == 1, size_t>::type +#endif +serialize(const TSource &source, TChar (&buffer)[N]) { + return serialize<TSerializer>(source, buffer, N); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/StringStorage/StringCopier.hpp b/include/lib/ArduinoJson/StringStorage/StringCopier.hpp new file mode 100644 index 0000000..8b1104b --- /dev/null +++ b/include/lib/ArduinoJson/StringStorage/StringCopier.hpp @@ -0,0 +1,62 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Memory/MemoryPool.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +class StringCopier { + public: + StringCopier(MemoryPool& pool) : _pool(&pool) {} + + void startString() { + _pool->getFreeZone(&_ptr, &_capacity); + _size = 0; + } + + const char* save() { + ARDUINOJSON_ASSERT(_ptr); + return _pool->saveStringFromFreeZone(_size); + } + + void append(const char* s) { + while (*s) append(*s++); + } + + void append(const char* s, size_t n) { + while (n-- > 0) append(*s++); + } + + void append(char c) { + if (!_ptr) + return; + + if (_size >= _capacity) { + _ptr = 0; + _pool->markAsOverflowed(); + return; + } + + _ptr[_size++] = c; + } + + bool isValid() { + return _ptr != 0; + } + + const char* c_str() { + return _ptr; + } + + typedef storage_policies::store_by_copy storage_policy; + + private: + MemoryPool* _pool; + char* _ptr; + size_t _size; + size_t _capacity; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/StringStorage/StringMover.hpp b/include/lib/ArduinoJson/StringStorage/StringMover.hpp new file mode 100644 index 0000000..f727a7d --- /dev/null +++ b/include/lib/ArduinoJson/StringStorage/StringMover.hpp @@ -0,0 +1,42 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Strings/StoragePolicy.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +class StringMover { + public: + StringMover(char* ptr) : _writePtr(ptr) {} + + void startString() { + _startPtr = _writePtr; + } + + const char* save() const { + return _startPtr; + } + + void append(char c) { + *_writePtr++ = c; + } + + bool isValid() const { + return true; + } + + const char* c_str() const { + return _startPtr; + } + + typedef storage_policies::store_by_address storage_policy; + + private: + char* _writePtr; + char* _startPtr; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/StringStorage/StringStorage.hpp b/include/lib/ArduinoJson/StringStorage/StringStorage.hpp new file mode 100644 index 0000000..36e6326 --- /dev/null +++ b/include/lib/ArduinoJson/StringStorage/StringStorage.hpp @@ -0,0 +1,23 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/StringStorage/StringCopier.hpp> +#include <ArduinoJson/StringStorage/StringMover.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TInput> +StringCopier makeStringStorage(TInput&, MemoryPool& pool) { + return StringCopier(pool); +} + +template <typename TChar> +StringMover makeStringStorage( + TChar* input, MemoryPool&, + typename enable_if<!is_const<TChar>::value>::type* = 0) { + return StringMover(reinterpret_cast<char*>(input)); +} +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Strings/ArduinoStringAdapter.hpp b/include/lib/ArduinoJson/Strings/ArduinoStringAdapter.hpp new file mode 100644 index 0000000..24646cc --- /dev/null +++ b/include/lib/ArduinoJson/Strings/ArduinoStringAdapter.hpp @@ -0,0 +1,62 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <Arduino.h> + +#include <ArduinoJson/Polyfills/safe_strcmp.hpp> +#include <ArduinoJson/Strings/IsString.hpp> +#include <ArduinoJson/Strings/StoragePolicy.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +class ArduinoStringAdapter { + public: + ArduinoStringAdapter(const ::String& str) : _str(&str) {} + + void copyTo(char* p, size_t n) const { + memcpy(p, _str->c_str(), n); + } + + bool isNull() const { + // Arduino's String::c_str() can return NULL + return !_str->c_str(); + } + + int compare(const char* other) const { + // Arduino's String::c_str() can return NULL + const char* me = _str->c_str(); + return safe_strcmp(me, other); + } + + bool equals(const char* expected) const { + return compare(expected) == 0; + } + + size_t size() const { + return _str->length(); + } + + const char* begin() const { + return _str->c_str(); + } + + typedef storage_policies::store_by_copy storage_policy; + + private: + const ::String* _str; +}; + +template <> +struct IsString< ::String> : true_type {}; + +template <> +struct IsString< ::StringSumHelper> : true_type {}; + +inline ArduinoStringAdapter adaptString(const ::String& str) { + return ArduinoStringAdapter(str); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Strings/ConstRamStringAdapter.hpp b/include/lib/ArduinoJson/Strings/ConstRamStringAdapter.hpp new file mode 100644 index 0000000..ec7d53a --- /dev/null +++ b/include/lib/ArduinoJson/Strings/ConstRamStringAdapter.hpp @@ -0,0 +1,62 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <stddef.h> // size_t +#include <string.h> // strcmp + +#include <ArduinoJson/Polyfills/safe_strcmp.hpp> +#include <ArduinoJson/Strings/IsString.hpp> +#include <ArduinoJson/Strings/StoragePolicy.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +class ConstRamStringAdapter { + public: + ConstRamStringAdapter(const char* str = 0) : _str(str) {} + + int compare(const char* other) const { + return safe_strcmp(_str, other); + } + + bool equals(const char* expected) const { + return compare(expected) == 0; + } + + bool isNull() const { + return !_str; + } + + size_t size() const { + if (!_str) + return 0; + return strlen(_str); + } + + const char* data() const { + return _str; + } + + const char* begin() const { + return _str; + } + + typedef storage_policies::store_by_address storage_policy; + + protected: + const char* _str; +}; + +template <> +struct IsString<const char*> : true_type {}; + +template <int N> +struct IsString<const char[N]> : true_type {}; + +inline ConstRamStringAdapter adaptString(const char* str) { + return ConstRamStringAdapter(str); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Strings/FlashStringAdapter.hpp b/include/lib/ArduinoJson/Strings/FlashStringAdapter.hpp new file mode 100644 index 0000000..292e348 --- /dev/null +++ b/include/lib/ArduinoJson/Strings/FlashStringAdapter.hpp @@ -0,0 +1,62 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/pgmspace.hpp> +#include <ArduinoJson/Strings/FlashStringIterator.hpp> +#include <ArduinoJson/Strings/IsString.hpp> +#include <ArduinoJson/Strings/StoragePolicy.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +class FlashStringAdapter { + public: + FlashStringAdapter(const __FlashStringHelper* str) : _str(str) {} + + int compare(const char* other) const { + if (!other && !_str) + return 0; + if (!_str) + return -1; + if (!other) + return 1; + return -strcmp_P(other, reinterpret_cast<const char*>(_str)); + } + + bool equals(const char* expected) const { + return compare(expected) == 0; + } + + bool isNull() const { + return !_str; + } + + void copyTo(char* p, size_t n) const { + memcpy_P(p, reinterpret_cast<const char*>(_str), n); + } + + size_t size() const { + if (!_str) + return 0; + return strlen_P(reinterpret_cast<const char*>(_str)); + } + + FlashStringIterator begin() const { + return FlashStringIterator(_str); + } + + typedef storage_policies::store_by_copy storage_policy; + + private: + const __FlashStringHelper* _str; +}; + +inline FlashStringAdapter adaptString(const __FlashStringHelper* str) { + return FlashStringAdapter(str); +} + +template <> +struct IsString<const __FlashStringHelper*> : true_type {}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Strings/FlashStringIterator.hpp b/include/lib/ArduinoJson/Strings/FlashStringIterator.hpp new file mode 100644 index 0000000..9a97f32 --- /dev/null +++ b/include/lib/ArduinoJson/Strings/FlashStringIterator.hpp @@ -0,0 +1,44 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +namespace ARDUINOJSON_NAMESPACE { + +class FlashStringIterator { + public: + explicit FlashStringIterator(const __FlashStringHelper* ptr) + : _ptr(reinterpret_cast<const char*>(ptr)) {} + + explicit FlashStringIterator(const char* ptr) : _ptr(ptr) {} + + FlashStringIterator operator+(ptrdiff_t d) const { + return FlashStringIterator(_ptr + d); + } + + ptrdiff_t operator-(FlashStringIterator other) const { + return _ptr - other._ptr; + } + + FlashStringIterator operator++(int) { + return FlashStringIterator(_ptr++); + } + + FlashStringIterator operator++() { + return FlashStringIterator(++_ptr); + } + + bool operator!=(FlashStringIterator other) const { + return _ptr != other._ptr; + } + + char operator*() const { + return char(pgm_read_byte(_ptr)); + } + + private: + const char* _ptr; +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Strings/IsString.hpp b/include/lib/ArduinoJson/Strings/IsString.hpp new file mode 100644 index 0000000..af5a91a --- /dev/null +++ b/include/lib/ArduinoJson/Strings/IsString.hpp @@ -0,0 +1,18 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/type_traits.hpp> + +namespace ARDUINOJSON_NAMESPACE { +template <typename> +struct IsString : false_type {}; + +template <typename T> +struct IsString<const T> : IsString<T> {}; + +template <typename T> +struct IsString<T&> : IsString<T> {}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Strings/IsWriteableString.hpp b/include/lib/ArduinoJson/Strings/IsWriteableString.hpp new file mode 100644 index 0000000..32039e3 --- /dev/null +++ b/include/lib/ArduinoJson/Strings/IsWriteableString.hpp @@ -0,0 +1,37 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> + +#if ARDUINOJSON_ENABLE_ARDUINO_STRING +#include <Arduino.h> +#endif + +#if ARDUINOJSON_ENABLE_STD_STRING +#include <string> +#endif + +namespace ARDUINOJSON_NAMESPACE { + +template <typename> +struct IsWriteableString : false_type {}; + +#if ARDUINOJSON_ENABLE_ARDUINO_STRING + +template <> +struct IsWriteableString< ::String> : true_type {}; + +#endif + +#if ARDUINOJSON_ENABLE_STD_STRING + +template <typename TCharTraits, typename TAllocator> +struct IsWriteableString<std::basic_string<char, TCharTraits, TAllocator> > + : true_type {}; + +#endif +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Strings/RamStringAdapter.hpp b/include/lib/ArduinoJson/Strings/RamStringAdapter.hpp new file mode 100644 index 0000000..eded6c9 --- /dev/null +++ b/include/lib/ArduinoJson/Strings/RamStringAdapter.hpp @@ -0,0 +1,43 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Strings/ConstRamStringAdapter.hpp> +#include <ArduinoJson/Strings/IsString.hpp> +#include <ArduinoJson/Strings/StoragePolicy.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +class RamStringAdapter : public ConstRamStringAdapter { + public: + RamStringAdapter(const char* str) : ConstRamStringAdapter(str) {} + + void copyTo(char* p, size_t n) const { + memcpy(p, _str, n); + } + + typedef ARDUINOJSON_NAMESPACE::storage_policies::store_by_copy storage_policy; +}; + +template <typename TChar> +inline RamStringAdapter adaptString(const TChar* str) { + return RamStringAdapter(reinterpret_cast<const char*>(str)); +} + +inline RamStringAdapter adaptString(char* str) { + return RamStringAdapter(str); +} + +template <typename TChar> +struct IsString<TChar*> { + static const bool value = sizeof(TChar) == 1; +}; + +template <> +struct IsString<void*> { + static const bool value = false; +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Strings/SizedFlashStringAdapter.hpp b/include/lib/ArduinoJson/Strings/SizedFlashStringAdapter.hpp new file mode 100644 index 0000000..b9cc0bf --- /dev/null +++ b/include/lib/ArduinoJson/Strings/SizedFlashStringAdapter.hpp @@ -0,0 +1,60 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Strings/FlashStringIterator.hpp> +#include <ArduinoJson/Strings/IsString.hpp> +#include <ArduinoJson/Strings/StoragePolicy.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +class SizedFlashStringAdapter { + public: + SizedFlashStringAdapter(const __FlashStringHelper* str, size_t sz) + : _str(str), _size(sz) {} + + int compare(const char* other) const { + if (!other && !_str) + return 0; + if (!_str) + return -1; + if (!other) + return 1; + return -strncmp_P(other, reinterpret_cast<const char*>(_str), _size); + } + + bool equals(const char* expected) const { + return compare(expected) == 0; + } + + bool isNull() const { + return !_str; + } + + void copyTo(char* p, size_t n) const { + memcpy_P(p, reinterpret_cast<const char*>(_str), n); + } + + size_t size() const { + return _size; + } + + FlashStringIterator begin() const { + return FlashStringIterator(_str); + } + + typedef storage_policies::store_by_copy storage_policy; + + private: + const __FlashStringHelper* _str; + size_t _size; +}; + +inline SizedFlashStringAdapter adaptString(const __FlashStringHelper* str, + size_t sz) { + return SizedFlashStringAdapter(str, sz); +} +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Strings/SizedRamStringAdapter.hpp b/include/lib/ArduinoJson/Strings/SizedRamStringAdapter.hpp new file mode 100644 index 0000000..fe23408 --- /dev/null +++ b/include/lib/ArduinoJson/Strings/SizedRamStringAdapter.hpp @@ -0,0 +1,55 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Strings/IsString.hpp> +#include <ArduinoJson/Strings/StoragePolicy.hpp> + +#include <string.h> // strcmp + +namespace ARDUINOJSON_NAMESPACE { + +class SizedRamStringAdapter { + public: + SizedRamStringAdapter(const char* str, size_t n) : _str(str), _size(n) {} + + int compare(const char* other) const { + return safe_strncmp(_str, other, _size); + } + + bool equals(const char* expected) const { + return compare(expected) == 0; + } + + bool isNull() const { + return !_str; + } + + void copyTo(char* p, size_t n) const { + memcpy(p, _str, n); + } + + size_t size() const { + return _size; + } + + const char* begin() const { + return _str; + } + + typedef storage_policies::store_by_copy storage_policy; + + private: + const char* _str; + size_t _size; +}; + +template <typename TChar> +inline SizedRamStringAdapter adaptString(const TChar* str, size_t size) { + return SizedRamStringAdapter(reinterpret_cast<const char*>(str), size); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Strings/StdStringAdapter.hpp b/include/lib/ArduinoJson/Strings/StdStringAdapter.hpp new file mode 100644 index 0000000..ebf4c39 --- /dev/null +++ b/include/lib/ArduinoJson/Strings/StdStringAdapter.hpp @@ -0,0 +1,65 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Strings/IsString.hpp> +#include <ArduinoJson/Strings/StoragePolicy.hpp> + +#include <string> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TString> +class StdStringAdapter { + public: + StdStringAdapter(const TString& str) : _str(&str) {} + + void copyTo(char* p, size_t n) const { + memcpy(p, _str->c_str(), n); + } + + bool isNull() const { + return false; + } + + int compare(const char* other) const { + if (!other) + return 1; + return _str->compare(other); + } + + bool equals(const char* expected) const { + if (!expected) + return false; + return *_str == expected; + } + + size_t size() const { + return _str->size(); + } + + const char* begin() const { + return _str->c_str(); + } + + typedef storage_policies::store_by_copy storage_policy; + + private: + const TString* _str; +}; + +template <typename TCharTraits, typename TAllocator> +struct IsString<std::basic_string<char, TCharTraits, TAllocator> > : true_type { +}; + +template <typename TCharTraits, typename TAllocator> +inline StdStringAdapter<std::basic_string<char, TCharTraits, TAllocator> > +adaptString(const std::basic_string<char, TCharTraits, TAllocator>& str) { + return StdStringAdapter<std::basic_string<char, TCharTraits, TAllocator> >( + str); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Strings/StoragePolicy.hpp b/include/lib/ArduinoJson/Strings/StoragePolicy.hpp new file mode 100644 index 0000000..df0d62b --- /dev/null +++ b/include/lib/ArduinoJson/Strings/StoragePolicy.hpp @@ -0,0 +1,15 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +namespace ARDUINOJSON_NAMESPACE { + +namespace storage_policies { +struct store_by_address {}; +struct store_by_copy {}; +struct decide_at_runtime {}; +} // namespace storage_policies + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Strings/String.hpp b/include/lib/ArduinoJson/Strings/String.hpp new file mode 100644 index 0000000..4f2abde --- /dev/null +++ b/include/lib/ArduinoJson/Strings/String.hpp @@ -0,0 +1,77 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Strings/ConstRamStringAdapter.hpp> +#include <ArduinoJson/Strings/IsString.hpp> +#include <ArduinoJson/Strings/StoragePolicy.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +class String { + public: + String() : _data(0), _isStatic(true) {} + String(const char* data, bool isStaticData = true) + : _data(data), _isStatic(isStaticData) {} + + const char* c_str() const { + return _data; + } + + bool isNull() const { + return !_data; + } + + bool isStatic() const { + return _isStatic; + } + + friend bool operator==(String lhs, String rhs) { + if (lhs._data == rhs._data) + return true; + if (!lhs._data) + return false; + if (!rhs._data) + return false; + return strcmp(lhs._data, rhs._data) == 0; + } + + friend bool operator!=(String lhs, String rhs) { + if (lhs._data == rhs._data) + return false; + if (!lhs._data) + return true; + if (!rhs._data) + return true; + return strcmp(lhs._data, rhs._data) != 0; + } + + private: + const char* _data; + bool _isStatic; +}; + +class StringAdapter : public RamStringAdapter { + public: + StringAdapter(const String& str) + : RamStringAdapter(str.c_str()), _isStatic(str.isStatic()) {} + + bool isStatic() const { + return _isStatic; + } + + typedef storage_policies::decide_at_runtime storage_policy; + + private: + bool _isStatic; +}; + +template <> +struct IsString<String> : true_type {}; + +inline StringAdapter adaptString(const String& str) { + return StringAdapter(str); +} +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Strings/StringAdapters.hpp b/include/lib/ArduinoJson/Strings/StringAdapters.hpp new file mode 100644 index 0000000..3d294d2 --- /dev/null +++ b/include/lib/ArduinoJson/Strings/StringAdapters.hpp @@ -0,0 +1,22 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Strings/ConstRamStringAdapter.hpp> +#include <ArduinoJson/Strings/RamStringAdapter.hpp> +#include <ArduinoJson/Strings/SizedRamStringAdapter.hpp> + +#if ARDUINOJSON_ENABLE_STD_STRING +#include <ArduinoJson/Strings/StdStringAdapter.hpp> +#endif + +#if ARDUINOJSON_ENABLE_ARDUINO_STRING +#include <ArduinoJson/Strings/ArduinoStringAdapter.hpp> +#endif + +#if ARDUINOJSON_ENABLE_PROGMEM +#include <ArduinoJson/Strings/FlashStringAdapter.hpp> +#include <ArduinoJson/Strings/SizedFlashStringAdapter.hpp> +#endif diff --git a/include/lib/ArduinoJson/Variant/Converter.hpp b/include/lib/ArduinoJson/Variant/Converter.hpp new file mode 100644 index 0000000..476ca8f --- /dev/null +++ b/include/lib/ArduinoJson/Variant/Converter.hpp @@ -0,0 +1,12 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +namespace ARDUINOJSON_NAMESPACE { + +template <typename T, typename Enable = void> +struct Converter; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/ConverterImpl.hpp b/include/lib/ArduinoJson/Variant/ConverterImpl.hpp new file mode 100644 index 0000000..34e12bb --- /dev/null +++ b/include/lib/ArduinoJson/Variant/ConverterImpl.hpp @@ -0,0 +1,268 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Strings/IsWriteableString.hpp> +#include <ArduinoJson/Variant/VariantFunctions.hpp> +#include <ArduinoJson/Variant/VariantRef.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename T, typename Enable> +struct Converter { + static bool toJson(const T& src, VariantRef dst) { + // clang-format off + return convertToJson(src, dst); // Error here? See https://arduinojson.org/v6/unsupported-set/ + // clang-format on + } + + static T fromJson(VariantConstRef src) { + // clang-format off + T result; // Error here? See https://arduinojson.org/v6/non-default-constructible/ + convertFromJson(src, result); // Error here? See https://arduinojson.org/v6/unsupported-as/ + // clang-format on + return result; + } + + static bool checkJson(VariantConstRef src) { + T dummy; + // clang-format off + return canConvertFromJson(src, dummy); // Error here? See https://arduinojson.org/v6/unsupported-is/ + // clang-format on + } +}; + +template <typename T> +struct Converter< + T, typename enable_if<is_integral<T>::value && !is_same<bool, T>::value && + !is_same<char, T>::value>::type> { + static bool toJson(T src, VariantRef dst) { + VariantData* data = getData(dst); + ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); + if (!data) + return false; + data->setInteger(src); + return true; + } + + static T fromJson(VariantConstRef src) { + ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); + const VariantData* data = getData(src); + return data ? data->asIntegral<T>() : T(); + } + + static bool checkJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data && data->isInteger<T>(); + } +}; + +template <typename T> +struct Converter<T, typename enable_if<is_enum<T>::value>::type> { + static bool toJson(T src, VariantRef dst) { + return dst.set(static_cast<Integer>(src)); + } + + static T fromJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data ? static_cast<T>(data->asIntegral<int>()) : T(); + } + + static bool checkJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data && data->isInteger<int>(); + } +}; + +template <> +struct Converter<bool> { + static bool toJson(bool src, VariantRef dst) { + VariantData* data = getData(dst); + if (!data) + return false; + data->setBoolean(src); + return true; + } + + static bool fromJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data ? data->asBoolean() : false; + } + + static bool checkJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data && data->isBoolean(); + } +}; + +template <typename T> +struct Converter<T, typename enable_if<is_floating_point<T>::value>::type> { + static bool toJson(T src, VariantRef dst) { + VariantData* data = getData(dst); + if (!data) + return false; + data->setFloat(static_cast<Float>(src)); + return true; + } + + static T fromJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data ? data->asFloat<T>() : false; + } + + static bool checkJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data && data->isFloat(); + } +}; + +template <> +struct Converter<const char*> { + static bool toJson(const char* src, VariantRef dst) { + return variantSetString(getData(dst), adaptString(src), getPool(dst)); + } + + static const char* fromJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data ? data->asString() : 0; + } + + static bool checkJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data && data->isString(); + } +}; + +template <typename T> +inline typename enable_if<IsString<T>::value, bool>::type convertToJson( + const T& src, VariantRef dst) { + VariantData* data = getData(dst); + MemoryPool* pool = getPool(dst); + return variantSetString(data, adaptString(src), pool); +} + +template <typename T> +inline typename enable_if<IsWriteableString<T>::value>::type convertFromJson( + VariantConstRef src, T& dst) { + const VariantData* data = getData(src); + const char* cstr = data != 0 ? data->asString() : 0; + if (cstr) + dst = cstr; + else + serializeJson(src, dst); +} + +template <typename T> +inline typename enable_if<IsWriteableString<T>::value, bool>::type +canConvertFromJson(VariantConstRef src, const T&) { + const VariantData* data = getData(src); + return data && data->isString(); +} + +template <> +struct Converter<SerializedValue<const char*> > { + static bool toJson(SerializedValue<const char*> src, VariantRef dst) { + VariantData* data = getData(dst); + if (!data) + return false; + data->setLinkedRaw(src); + return true; + } +}; + +// SerializedValue<std::string> +// SerializedValue<String> +// SerializedValue<const __FlashStringHelper*> +template <typename T> +struct Converter<SerializedValue<T>, + typename enable_if<!is_same<const char*, T>::value>::type> { + static bool toJson(SerializedValue<T> src, VariantRef dst) { + VariantData* data = getData(dst); + MemoryPool* pool = getPool(dst); + return data != 0 && data->setOwnedRaw(src, pool); + } +}; + +#if ARDUINOJSON_HAS_NULLPTR + +template <> +struct Converter<decltype(nullptr)> { + static bool toJson(decltype(nullptr), VariantRef dst) { + variantSetNull(getData(dst)); + return true; + } + static decltype(nullptr) fromJson(VariantConstRef) { + return nullptr; + } + static bool checkJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data == 0 || data->isNull(); + } +}; + +#endif + +#if ARDUINOJSON_ENABLE_ARDUINO_STREAM + +class MemoryPoolPrint : public Print { + public: + MemoryPoolPrint(MemoryPool* pool) : _pool(pool), _size(0) { + pool->getFreeZone(&_string, &_capacity); + } + + const char* c_str() { + _string[_size++] = 0; + ARDUINOJSON_ASSERT(_size <= _capacity); + return _pool->saveStringFromFreeZone(_size); + } + + size_t write(uint8_t c) { + if (_size >= _capacity) + return 0; + + _string[_size++] = char(c); + return 1; + } + + size_t write(const uint8_t* buffer, size_t size) { + if (_size + size >= _capacity) { + _size = _capacity; // mark as overflowed + return 0; + } + memcpy(&_string[_size], buffer, size); + _size += size; + return size; + } + + bool overflowed() const { + return _size >= _capacity; + } + + private: + MemoryPool* _pool; + size_t _size; + char* _string; + size_t _capacity; +}; + +inline bool convertToJson(const ::Printable& src, VariantRef dst) { + MemoryPool* pool = getPool(dst); + VariantData* data = getData(dst); + if (!pool || !data) + return false; + MemoryPoolPrint print(pool); + src.printTo(print); + if (print.overflowed()) { + pool->markAsOverflowed(); + data->setNull(); + return false; + } + data->setStringPointer(print.c_str(), storage_policies::store_by_copy()); + return true; +} + +#endif + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/SlotFunctions.hpp b/include/lib/ArduinoJson/Variant/SlotFunctions.hpp new file mode 100644 index 0000000..74ac5a7 --- /dev/null +++ b/include/lib/ArduinoJson/Variant/SlotFunctions.hpp @@ -0,0 +1,60 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/assert.hpp> +#include <ArduinoJson/Variant/VariantData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TAdaptedString> +inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool) { + if (!var) + return false; + return slotSetKey(var, key, pool, typename TAdaptedString::storage_policy()); +} + +template <typename TAdaptedString> +inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool, + storage_policies::decide_at_runtime) { + if (key.isStatic()) { + return slotSetKey(var, key, pool, storage_policies::store_by_address()); + } else { + return slotSetKey(var, key, pool, storage_policies::store_by_copy()); + } +} + +template <typename TAdaptedString> +inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool*, + storage_policies::store_by_address) { + ARDUINOJSON_ASSERT(var); + var->setKey(key.data(), storage_policies::store_by_address()); + return true; +} + +template <typename TAdaptedString> +inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool, + storage_policies::store_by_copy) { + const char* dup = pool->saveString(key); + if (!dup) + return false; + ARDUINOJSON_ASSERT(var); + var->setKey(dup, storage_policies::store_by_copy()); + return true; +} + +inline size_t slotSize(const VariantSlot* var) { + size_t n = 0; + while (var) { + n++; + var = var->next(); + } + return n; +} + +inline VariantData* slotData(VariantSlot* slot) { + return reinterpret_cast<VariantData*>(slot); +} +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/VariantCompare.hpp b/include/lib/ArduinoJson/Variant/VariantCompare.hpp new file mode 100644 index 0000000..025ef90 --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantCompare.hpp @@ -0,0 +1,208 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Misc/Visitable.hpp> +#include <ArduinoJson/Numbers/arithmeticCompare.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Strings/IsString.hpp> +#include <ArduinoJson/Variant/Visitor.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +class CollectionData; + +struct ComparerBase : Visitor<CompareResult> {}; + +template <typename T, typename Enable = void> +struct Comparer; + +template <typename T> +struct Comparer<T, typename enable_if<IsString<T>::value>::type> + : ComparerBase { + T rhs; + + explicit Comparer(T value) : rhs(value) {} + + CompareResult visitString(const char *lhs) { + int i = adaptString(rhs).compare(lhs); + if (i < 0) + return COMPARE_RESULT_GREATER; + else if (i > 0) + return COMPARE_RESULT_LESS; + else + return COMPARE_RESULT_EQUAL; + } + + CompareResult visitNull() { + if (adaptString(rhs).isNull()) + return COMPARE_RESULT_EQUAL; + else + return COMPARE_RESULT_DIFFER; + } +}; + +template <typename T> +struct Comparer<T, typename enable_if<is_integral<T>::value || + is_floating_point<T>::value>::type> + : ComparerBase { + T rhs; + + explicit Comparer(T value) : rhs(value) {} + + CompareResult visitFloat(Float lhs) { + return arithmeticCompare(lhs, rhs); + } + + CompareResult visitSignedInteger(Integer lhs) { + return arithmeticCompare(lhs, rhs); + } + + CompareResult visitUnsignedInteger(UInt lhs) { + return arithmeticCompare(lhs, rhs); + } + + CompareResult visitBoolean(bool lhs) { + return visitUnsignedInteger(static_cast<UInt>(lhs)); + } +}; + +struct NullComparer : ComparerBase { + CompareResult visitNull() { + return COMPARE_RESULT_EQUAL; + } +}; + +#if ARDUINOJSON_HAS_NULLPTR +template <> +struct Comparer<decltype(nullptr), void> : NullComparer { + explicit Comparer(decltype(nullptr)) : NullComparer() {} +}; +#endif + +struct ArrayComparer : ComparerBase { + const CollectionData *_rhs; + + explicit ArrayComparer(const CollectionData &rhs) : _rhs(&rhs) {} + + CompareResult visitArray(const CollectionData &lhs) { + if (lhs.equalsArray(*_rhs)) + return COMPARE_RESULT_EQUAL; + else + return COMPARE_RESULT_DIFFER; + } +}; + +struct ObjectComparer : ComparerBase { + const CollectionData *_rhs; + + explicit ObjectComparer(const CollectionData &rhs) : _rhs(&rhs) {} + + CompareResult visitObject(const CollectionData &lhs) { + if (lhs.equalsObject(*_rhs)) + return COMPARE_RESULT_EQUAL; + else + return COMPARE_RESULT_DIFFER; + } +}; + +struct RawComparer : ComparerBase { + const char *_rhsData; + size_t _rhsSize; + + explicit RawComparer(const char *rhsData, size_t rhsSize) + : _rhsData(rhsData), _rhsSize(rhsSize) {} + + CompareResult visitRawJson(const char *lhsData, size_t lhsSize) { + size_t size = _rhsSize < lhsSize ? _rhsSize : lhsSize; + int n = memcmp(lhsData, _rhsData, size); + if (n < 0) + return COMPARE_RESULT_LESS; + else if (n > 0) + return COMPARE_RESULT_GREATER; + else + return COMPARE_RESULT_EQUAL; + } +}; + +template <typename T> +struct Comparer<T, typename enable_if<IsVisitable<T>::value>::type> + : ComparerBase { + T rhs; + + explicit Comparer(T value) : rhs(value) {} + + CompareResult visitArray(const CollectionData &lhs) { + ArrayComparer comparer(lhs); + return accept(comparer); + } + + CompareResult visitObject(const CollectionData &lhs) { + ObjectComparer comparer(lhs); + return accept(comparer); + } + + CompareResult visitFloat(Float lhs) { + Comparer<Float> comparer(lhs); + return accept(comparer); + } + + CompareResult visitString(const char *lhs) { + Comparer<const char *> comparer(lhs); + return accept(comparer); + } + + CompareResult visitRawJson(const char *lhsData, size_t lhsSize) { + RawComparer comparer(lhsData, lhsSize); + return accept(comparer); + } + + CompareResult visitSignedInteger(Integer lhs) { + Comparer<Integer> comparer(lhs); + return accept(comparer); + } + + CompareResult visitUnsignedInteger(UInt lhs) { + Comparer<UInt> comparer(lhs); + return accept(comparer); + } + + CompareResult visitBoolean(bool lhs) { + Comparer<bool> comparer(lhs); + return accept(comparer); + } + + CompareResult visitNull() { + NullComparer comparer; + return accept(comparer); + } + + private: + template <typename TComparer> + CompareResult accept(TComparer &comparer) { + CompareResult reversedResult = rhs.accept(comparer); + switch (reversedResult) { + case COMPARE_RESULT_GREATER: + return COMPARE_RESULT_LESS; + case COMPARE_RESULT_LESS: + return COMPARE_RESULT_GREATER; + default: + return reversedResult; + } + } +}; + +template <typename T1, typename T2> +CompareResult compare(const T1 &lhs, const T2 &rhs) { + Comparer<T2> comparer(rhs); + return lhs.accept(comparer); +} + +inline int variantCompare(const VariantData *a, const VariantData *b) { + return compare(VariantConstRef(a), VariantConstRef(b)); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/VariantContent.hpp b/include/lib/ArduinoJson/Variant/VariantContent.hpp new file mode 100644 index 0000000..47bf09c --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantContent.hpp @@ -0,0 +1,59 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <stddef.h> // size_t + +#include <ArduinoJson/Collection/CollectionData.hpp> +#include <ArduinoJson/Numbers/Float.hpp> +#include <ArduinoJson/Numbers/Integer.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +// +enum { + VALUE_MASK = 0x7F, + + OWNED_VALUE_BIT = 0x01, + VALUE_IS_NULL = 0, + VALUE_IS_LINKED_RAW = 0x02, + VALUE_IS_OWNED_RAW = 0x03, + VALUE_IS_LINKED_STRING = 0x04, + VALUE_IS_OWNED_STRING = 0x05, + + // CAUTION: no OWNED_VALUE_BIT below + + VALUE_IS_BOOLEAN = 0x06, + + NUMBER_BIT = 0x08, + VALUE_IS_UNSIGNED_INTEGER = 0x08, + VALUE_IS_SIGNED_INTEGER = 0x0A, + VALUE_IS_FLOAT = 0x0C, + + COLLECTION_MASK = 0x60, + VALUE_IS_OBJECT = 0x20, + VALUE_IS_ARRAY = 0x40, + + OWNED_KEY_BIT = 0x80 +}; + +struct RawData { + const char *data; + size_t size; +}; + +union VariantContent { + Float asFloat; + bool asBoolean; + UInt asUnsignedInteger; + Integer asSignedInteger; + CollectionData asCollection; + const char *asString; + struct { + const char *data; + size_t size; + } asRaw; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/VariantData.hpp b/include/lib/ArduinoJson/Variant/VariantData.hpp new file mode 100644 index 0000000..82ae745 --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantData.hpp @@ -0,0 +1,368 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Memory/MemoryPool.hpp> +#include <ArduinoJson/Misc/SerializedValue.hpp> +#include <ArduinoJson/Numbers/convertNumber.hpp> +#include <ArduinoJson/Strings/RamStringAdapter.hpp> +#include <ArduinoJson/Variant/VariantContent.hpp> + +// VariantData can't have a constructor (to be a POD), so we have no way to fix +// this warning +#if defined(__GNUC__) +#if __GNUC__ >= 7 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#pragma GCC diagnostic ignored "-Wuninitialized" +#endif +#endif + +namespace ARDUINOJSON_NAMESPACE { + +class VariantData { + VariantContent _content; // must be first to allow cast from array to variant + uint8_t _flags; + + public: + // Must be a POD! + // - no constructor + // - no destructor + // - no virtual + // - no inheritance + void init() { + _flags = 0; + } + + template <typename TVisitor> + typename TVisitor::result_type accept(TVisitor &visitor) const { + switch (type()) { + case VALUE_IS_FLOAT: + return visitor.visitFloat(_content.asFloat); + + case VALUE_IS_ARRAY: + return visitor.visitArray(_content.asCollection); + + case VALUE_IS_OBJECT: + return visitor.visitObject(_content.asCollection); + + case VALUE_IS_LINKED_STRING: + case VALUE_IS_OWNED_STRING: + return visitor.visitString(_content.asString); + + case VALUE_IS_OWNED_RAW: + case VALUE_IS_LINKED_RAW: + return visitor.visitRawJson(_content.asRaw.data, _content.asRaw.size); + + case VALUE_IS_SIGNED_INTEGER: + return visitor.visitSignedInteger(_content.asSignedInteger); + + case VALUE_IS_UNSIGNED_INTEGER: + return visitor.visitUnsignedInteger(_content.asUnsignedInteger); + + case VALUE_IS_BOOLEAN: + return visitor.visitBoolean(_content.asBoolean != 0); + + default: + return visitor.visitNull(); + } + } + + template <typename T> + T asIntegral() const; + + template <typename T> + T asFloat() const; + + const char *asString() const; + + bool asBoolean() const; + + CollectionData *asArray() { + return isArray() ? &_content.asCollection : 0; + } + + const CollectionData *asArray() const { + return const_cast<VariantData *>(this)->asArray(); + } + + CollectionData *asObject() { + return isObject() ? &_content.asCollection : 0; + } + + const CollectionData *asObject() const { + return const_cast<VariantData *>(this)->asObject(); + } + + bool copyFrom(const VariantData &src, MemoryPool *pool) { + switch (src.type()) { + case VALUE_IS_ARRAY: + return toArray().copyFrom(src._content.asCollection, pool); + case VALUE_IS_OBJECT: + return toObject().copyFrom(src._content.asCollection, pool); + case VALUE_IS_OWNED_STRING: + return setString(RamStringAdapter(src._content.asString), pool); + case VALUE_IS_OWNED_RAW: + return setOwnedRaw( + serialized(src._content.asRaw.data, src._content.asRaw.size), pool); + default: + setType(src.type()); + _content = src._content; + return true; + } + } + + bool isArray() const { + return (_flags & VALUE_IS_ARRAY) != 0; + } + + bool isBoolean() const { + return type() == VALUE_IS_BOOLEAN; + } + + bool isCollection() const { + return (_flags & COLLECTION_MASK) != 0; + } + + template <typename T> + bool isInteger() const { + switch (type()) { + case VALUE_IS_UNSIGNED_INTEGER: + return canConvertNumber<T>(_content.asUnsignedInteger); + + case VALUE_IS_SIGNED_INTEGER: + return canConvertNumber<T>(_content.asSignedInteger); + + default: + return false; + } + } + + bool isFloat() const { + return (_flags & NUMBER_BIT) != 0; + } + + bool isString() const { + return type() == VALUE_IS_LINKED_STRING || type() == VALUE_IS_OWNED_STRING; + } + + bool isObject() const { + return (_flags & VALUE_IS_OBJECT) != 0; + } + + bool isNull() const { + return type() == VALUE_IS_NULL; + } + + bool isEnclosed() const { + return !isFloat(); + } + + void remove(size_t index) { + if (isArray()) + _content.asCollection.removeElement(index); + } + + template <typename TAdaptedString> + void remove(TAdaptedString key) { + if (isObject()) + _content.asCollection.removeMember(key); + } + + void setBoolean(bool value) { + setType(VALUE_IS_BOOLEAN); + _content.asBoolean = value; + } + + void setFloat(Float value) { + setType(VALUE_IS_FLOAT); + _content.asFloat = value; + } + + void setLinkedRaw(SerializedValue<const char *> value) { + if (value.data()) { + setType(VALUE_IS_LINKED_RAW); + _content.asRaw.data = value.data(); + _content.asRaw.size = value.size(); + } else { + setType(VALUE_IS_NULL); + } + } + + template <typename T> + bool setOwnedRaw(SerializedValue<T> value, MemoryPool *pool) { + const char *dup = pool->saveString(adaptString(value.data(), value.size())); + if (dup) { + setType(VALUE_IS_OWNED_RAW); + _content.asRaw.data = dup; + _content.asRaw.size = value.size(); + return true; + } else { + setType(VALUE_IS_NULL); + return false; + } + } + + template <typename T> + typename enable_if<is_unsigned<T>::value>::type setInteger(T value) { + setType(VALUE_IS_UNSIGNED_INTEGER); + _content.asUnsignedInteger = static_cast<UInt>(value); + } + + template <typename T> + typename enable_if<is_signed<T>::value>::type setInteger(T value) { + setType(VALUE_IS_SIGNED_INTEGER); + _content.asSignedInteger = value; + } + + void setNull() { + setType(VALUE_IS_NULL); + } + + void setStringPointer(const char *s, storage_policies::store_by_copy) { + ARDUINOJSON_ASSERT(s != 0); + setType(VALUE_IS_OWNED_STRING); + _content.asString = s; + } + + void setStringPointer(const char *s, storage_policies::store_by_address) { + ARDUINOJSON_ASSERT(s != 0); + setType(VALUE_IS_LINKED_STRING); + _content.asString = s; + } + + template <typename TAdaptedString> + bool setString(TAdaptedString value, MemoryPool *pool) { + return storeString(value, pool, typename TAdaptedString::storage_policy()); + } + + CollectionData &toArray() { + setType(VALUE_IS_ARRAY); + _content.asCollection.clear(); + return _content.asCollection; + } + + CollectionData &toObject() { + setType(VALUE_IS_OBJECT); + _content.asCollection.clear(); + return _content.asCollection; + } + + size_t memoryUsage() const { + switch (type()) { + case VALUE_IS_OWNED_STRING: + return strlen(_content.asString) + 1; + case VALUE_IS_OWNED_RAW: + return _content.asRaw.size; + case VALUE_IS_OBJECT: + case VALUE_IS_ARRAY: + return _content.asCollection.memoryUsage(); + default: + return 0; + } + } + + size_t nesting() const { + return isCollection() ? _content.asCollection.nesting() : 0; + } + + size_t size() const { + return isCollection() ? _content.asCollection.size() : 0; + } + + VariantData *addElement(MemoryPool *pool) { + if (isNull()) + toArray(); + if (!isArray()) + return 0; + return _content.asCollection.addElement(pool); + } + + VariantData *getElement(size_t index) const { + return isArray() ? _content.asCollection.getElement(index) : 0; + } + + VariantData *getOrAddElement(size_t index, MemoryPool *pool) { + if (isNull()) + toArray(); + if (!isArray()) + return 0; + return _content.asCollection.getOrAddElement(index, pool); + } + + template <typename TAdaptedString> + VariantData *getMember(TAdaptedString key) const { + return isObject() ? _content.asCollection.getMember(key) : 0; + } + + template <typename TAdaptedString> + VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool) { + if (isNull()) + toObject(); + if (!isObject()) + return 0; + return _content.asCollection.getOrAddMember(key, pool); + } + + void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) { + if (_flags & OWNED_VALUE_BIT) + _content.asString += stringDistance; + if (_flags & COLLECTION_MASK) + _content.asCollection.movePointers(stringDistance, variantDistance); + } + + uint8_t type() const { + return _flags & VALUE_MASK; + } + + private: + void setType(uint8_t t) { + _flags &= OWNED_KEY_BIT; + _flags |= t; + } + + template <typename TAdaptedString> + inline bool storeString(TAdaptedString value, MemoryPool *pool, + storage_policies::decide_at_runtime) { + if (value.isStatic()) + return storeString(value, pool, storage_policies::store_by_address()); + else + return storeString(value, pool, storage_policies::store_by_copy()); + } + + template <typename TAdaptedString> + inline bool storeString(TAdaptedString value, MemoryPool *, + storage_policies::store_by_address) { + if (value.isNull()) + setNull(); + else + setStringPointer(value.data(), storage_policies::store_by_address()); + return true; + } + + template <typename TAdaptedString> + inline bool storeString(TAdaptedString value, MemoryPool *pool, + storage_policies::store_by_copy) { + if (value.isNull()) { + setNull(); + return true; + } + const char *copy = pool->saveString(value); + if (!copy) { + setNull(); + return false; + } + setStringPointer(copy, storage_policies::store_by_copy()); + return true; + } +}; + +} // namespace ARDUINOJSON_NAMESPACE + +#if defined(__GNUC__) +#if __GNUC__ >= 8 +#pragma GCC diagnostic pop +#endif +#endif diff --git a/include/lib/ArduinoJson/Variant/VariantFunctions.hpp b/include/lib/ArduinoJson/Variant/VariantFunctions.hpp new file mode 100644 index 0000000..3fc9cbb --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantFunctions.hpp @@ -0,0 +1,104 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/attributes.hpp> +#include <ArduinoJson/Variant/VariantData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TVisitor> +inline typename TVisitor::result_type variantAccept(const VariantData *var, + TVisitor &visitor) { + if (var != 0) + return var->accept(visitor); + else + return visitor.visitNull(); +} + +inline const CollectionData *variantAsArray(const VariantData *var) { + return var != 0 ? var->asArray() : 0; +} + +inline const CollectionData *variantAsObject(const VariantData *var) { + return var != 0 ? var->asObject() : 0; +} + +inline CollectionData *variantAsObject(VariantData *var) { + return var != 0 ? var->asObject() : 0; +} + +inline bool variantCopyFrom(VariantData *dst, const VariantData *src, + MemoryPool *pool) { + if (!dst) + return false; + if (!src) { + dst->setNull(); + return true; + } + return dst->copyFrom(*src, pool); +} + +inline int variantCompare(const VariantData *a, const VariantData *b); + +inline void variantSetNull(VariantData *var) { + if (!var) + return; + var->setNull(); +} + +template <typename TAdaptedString> +inline bool variantSetString(VariantData *var, TAdaptedString value, + MemoryPool *pool) { + if (!var) + return false; + return var->setString(value, pool); +} + +inline size_t variantSize(const VariantData *var) { + return var != 0 ? var->size() : 0; +} + +inline CollectionData *variantToArray(VariantData *var) { + if (!var) + return 0; + return &var->toArray(); +} + +inline CollectionData *variantToObject(VariantData *var) { + if (!var) + return 0; + return &var->toObject(); +} + +inline NO_INLINE VariantData *variantAddElement(VariantData *var, + MemoryPool *pool) { + return var != 0 ? var->addElement(pool) : 0; +} + +inline NO_INLINE VariantData *variantGetOrAddElement(VariantData *var, + size_t index, + MemoryPool *pool) { + return var != 0 ? var->getOrAddElement(index, pool) : 0; +} + +template <typename TChar> +NO_INLINE VariantData *variantGetOrAddMember(VariantData *var, TChar *key, + MemoryPool *pool) { + return var != 0 ? var->getOrAddMember(adaptString(key), pool) : 0; +} + +template <typename TString> +NO_INLINE VariantData *variantGetOrAddMember(VariantData *var, + const TString &key, + MemoryPool *pool) { + return var != 0 ? var->getOrAddMember(adaptString(key), pool) : 0; +} + +inline bool variantIsNull(const VariantData *var) { + return var == 0 || var->isNull(); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/VariantImpl.hpp b/include/lib/ArduinoJson/Variant/VariantImpl.hpp new file mode 100644 index 0000000..b91e584 --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantImpl.hpp @@ -0,0 +1,143 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Array/ArrayRef.hpp> +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Numbers/convertNumber.hpp> +#include <ArduinoJson/Numbers/parseNumber.hpp> +#include <ArduinoJson/Object/ObjectRef.hpp> +#include <ArduinoJson/Variant/VariantRef.hpp> + +#include <string.h> // for strcmp + +namespace ARDUINOJSON_NAMESPACE { + +template <typename T> +inline T VariantData::asIntegral() const { + switch (type()) { + case VALUE_IS_BOOLEAN: + return _content.asBoolean; + case VALUE_IS_UNSIGNED_INTEGER: + return convertNumber<T>(_content.asUnsignedInteger); + case VALUE_IS_SIGNED_INTEGER: + return convertNumber<T>(_content.asSignedInteger); + case VALUE_IS_LINKED_STRING: + case VALUE_IS_OWNED_STRING: + return parseNumber<T>(_content.asString); + case VALUE_IS_FLOAT: + return convertNumber<T>(_content.asFloat); + default: + return 0; + } +} + +inline bool VariantData::asBoolean() const { + switch (type()) { + case VALUE_IS_BOOLEAN: + return _content.asBoolean; + case VALUE_IS_SIGNED_INTEGER: + case VALUE_IS_UNSIGNED_INTEGER: + return _content.asUnsignedInteger != 0; + case VALUE_IS_FLOAT: + return _content.asFloat != 0; + case VALUE_IS_NULL: + return false; + default: + return true; + } +} + +// T = float/double +template <typename T> +inline T VariantData::asFloat() const { + switch (type()) { + case VALUE_IS_BOOLEAN: + return static_cast<T>(_content.asBoolean); + case VALUE_IS_UNSIGNED_INTEGER: + return static_cast<T>(_content.asUnsignedInteger); + case VALUE_IS_SIGNED_INTEGER: + return static_cast<T>(_content.asSignedInteger); + case VALUE_IS_LINKED_STRING: + case VALUE_IS_OWNED_STRING: + return parseNumber<T>(_content.asString); + case VALUE_IS_FLOAT: + return static_cast<T>(_content.asFloat); + default: + return 0; + } +} + +inline const char *VariantData::asString() const { + switch (type()) { + case VALUE_IS_LINKED_STRING: + case VALUE_IS_OWNED_STRING: + return _content.asString; + default: + return 0; + } +} + +template <typename T> +inline typename enable_if<is_same<T, ArrayRef>::value, ArrayRef>::type +VariantRef::to() const { + return ArrayRef(_pool, variantToArray(_data)); +} + +template <typename T> +typename enable_if<is_same<T, ObjectRef>::value, ObjectRef>::type +VariantRef::to() const { + return ObjectRef(_pool, variantToObject(_data)); +} + +template <typename T> +typename enable_if<is_same<T, VariantRef>::value, VariantRef>::type +VariantRef::to() const { + variantSetNull(_data); + return *this; +} + +inline VariantConstRef VariantConstRef::getElement(size_t index) const { + return ArrayConstRef(_data != 0 ? _data->asArray() : 0)[index]; +} + +inline VariantRef VariantRef::addElement() const { + return VariantRef(_pool, variantAddElement(_data, _pool)); +} + +inline VariantRef VariantRef::getElement(size_t index) const { + return VariantRef(_pool, _data != 0 ? _data->getElement(index) : 0); +} + +inline VariantRef VariantRef::getOrAddElement(size_t index) const { + return VariantRef(_pool, variantGetOrAddElement(_data, index, _pool)); +} + +template <typename TChar> +inline VariantRef VariantRef::getMember(TChar *key) const { + return VariantRef(_pool, _data != 0 ? _data->getMember(adaptString(key)) : 0); +} + +template <typename TString> +inline typename enable_if<IsString<TString>::value, VariantRef>::type +VariantRef::getMember(const TString &key) const { + return VariantRef(_pool, _data != 0 ? _data->getMember(adaptString(key)) : 0); +} + +template <typename TChar> +inline VariantRef VariantRef::getOrAddMember(TChar *key) const { + return VariantRef(_pool, variantGetOrAddMember(_data, key, _pool)); +} + +template <typename TString> +inline VariantRef VariantRef::getOrAddMember(const TString &key) const { + return VariantRef(_pool, variantGetOrAddMember(_data, key, _pool)); +} + +inline VariantConstRef operator|(VariantConstRef preferedValue, + VariantConstRef defaultValue) { + return preferedValue ? preferedValue : defaultValue; +} +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/VariantOperators.hpp b/include/lib/ArduinoJson/Variant/VariantOperators.hpp new file mode 100644 index 0000000..54174a4 --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantOperators.hpp @@ -0,0 +1,180 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Misc/Visitable.hpp> +#include <ArduinoJson/Numbers/arithmeticCompare.hpp> +#include <ArduinoJson/Polyfills/attributes.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Variant/VariantTag.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename T1, typename T2> +CompareResult compare(const T1 &lhs, const T2 &rhs); // VariantCompare.cpp + +template <typename TVariant> +struct VariantOperators { + // Returns the default value if the VariantRef is undefined or incompatible + // + // int operator|(JsonVariant, int) + // float operator|(JsonVariant, float) + // bool operator|(JsonVariant, bool) + template <typename T> + friend + typename enable_if<!IsVariant<T>::value && !is_array<T>::value, T>::type + operator|(const TVariant &variant, const T &defaultValue) { + if (variant.template is<T>()) + return variant.template as<T>(); + else + return defaultValue; + } + // + // const char* operator|(JsonVariant, const char*) + friend const char *operator|(const TVariant &variant, + const char *defaultValue) { + if (variant.template is<const char *>()) + return variant.template as<const char *>(); + else + return defaultValue; + } + // + // JsonVariant operator|(JsonVariant, JsonVariant) + template <typename T> + friend typename enable_if<IsVariant<T>::value, typename T::variant_type>::type + operator|(const TVariant &variant, T defaultValue) { + if (variant) + return variant; + else + return defaultValue; + } + + // value == TVariant + template <typename T> + friend bool operator==(T *lhs, TVariant rhs) { + return compare(rhs, lhs) == COMPARE_RESULT_EQUAL; + } + template <typename T> + friend bool operator==(const T &lhs, TVariant rhs) { + return compare(rhs, lhs) == COMPARE_RESULT_EQUAL; + } + + // TVariant == value + template <typename T> + friend bool operator==(TVariant lhs, T *rhs) { + return compare(lhs, rhs) == COMPARE_RESULT_EQUAL; + } + template <typename T> + friend typename enable_if<!IsVisitable<T>::value, bool>::type operator==( + TVariant lhs, const T &rhs) { + return compare(lhs, rhs) == COMPARE_RESULT_EQUAL; + } + + // value != TVariant + template <typename T> + friend bool operator!=(T *lhs, TVariant rhs) { + return compare(rhs, lhs) != COMPARE_RESULT_EQUAL; + } + template <typename T> + friend bool operator!=(const T &lhs, TVariant rhs) { + return compare(rhs, lhs) != COMPARE_RESULT_EQUAL; + } + + // TVariant != value + template <typename T> + friend bool operator!=(TVariant lhs, T *rhs) { + return compare(lhs, rhs) != COMPARE_RESULT_EQUAL; + } + template <typename T> + friend typename enable_if<!IsVisitable<T>::value, bool>::type operator!=( + TVariant lhs, const T &rhs) { + return compare(lhs, rhs) != COMPARE_RESULT_EQUAL; + } + + // value < TVariant + template <typename T> + friend bool operator<(T *lhs, TVariant rhs) { + return compare(rhs, lhs) == COMPARE_RESULT_GREATER; + } + template <typename T> + friend bool operator<(const T &lhs, TVariant rhs) { + return compare(rhs, lhs) == COMPARE_RESULT_GREATER; + } + + // TVariant < value + template <typename T> + friend bool operator<(TVariant lhs, T *rhs) { + return compare(lhs, rhs) == COMPARE_RESULT_LESS; + } + template <typename T> + friend typename enable_if<!IsVisitable<T>::value, bool>::type operator<( + TVariant lhs, const T &rhs) { + return compare(lhs, rhs) == COMPARE_RESULT_LESS; + } + + // value <= TVariant + template <typename T> + friend bool operator<=(T *lhs, TVariant rhs) { + return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; + } + template <typename T> + friend bool operator<=(const T &lhs, TVariant rhs) { + return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; + } + + // TVariant <= value + template <typename T> + friend bool operator<=(TVariant lhs, T *rhs) { + return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; + } + template <typename T> + friend typename enable_if<!IsVisitable<T>::value, bool>::type operator<=( + TVariant lhs, const T &rhs) { + return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; + } + + // value > TVariant + template <typename T> + friend bool operator>(T *lhs, TVariant rhs) { + return compare(rhs, lhs) == COMPARE_RESULT_LESS; + } + template <typename T> + friend bool operator>(const T &lhs, TVariant rhs) { + return compare(rhs, lhs) == COMPARE_RESULT_LESS; + } + + // TVariant > value + template <typename T> + friend bool operator>(TVariant lhs, T *rhs) { + return compare(lhs, rhs) == COMPARE_RESULT_GREATER; + } + template <typename T> + friend typename enable_if<!IsVisitable<T>::value, bool>::type operator>( + TVariant lhs, const T &rhs) { + return compare(lhs, rhs) == COMPARE_RESULT_GREATER; + } + + // value >= TVariant + template <typename T> + friend bool operator>=(T *lhs, TVariant rhs) { + return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; + } + template <typename T> + friend bool operator>=(const T &lhs, TVariant rhs) { + return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; + } + + // TVariant >= value + template <typename T> + friend bool operator>=(TVariant lhs, T *rhs) { + return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; + } + template <typename T> + friend typename enable_if<!IsVisitable<T>::value, bool>::type operator>=( + TVariant lhs, const T &rhs) { + return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; + } +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/VariantRef.hpp b/include/lib/ArduinoJson/Variant/VariantRef.hpp new file mode 100644 index 0000000..8d4c410 --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantRef.hpp @@ -0,0 +1,375 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <stddef.h> +#include <stdint.h> // for uint8_t + +#include <ArduinoJson/Memory/MemoryPool.hpp> +#include <ArduinoJson/Misc/Visitable.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Strings/StringAdapters.hpp> +#include <ArduinoJson/Variant/Converter.hpp> +#include <ArduinoJson/Variant/VariantFunctions.hpp> +#include <ArduinoJson/Variant/VariantOperators.hpp> +#include <ArduinoJson/Variant/VariantRef.hpp> +#include <ArduinoJson/Variant/VariantShortcuts.hpp> +#include <ArduinoJson/Variant/VariantTag.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +// Forward declarations. +class ArrayRef; +class ObjectRef; + +// Contains the methods shared by VariantRef and VariantConstRef +template <typename TData> +class VariantRefBase : public VariantTag { + public: + FORCE_INLINE bool isNull() const { + return variantIsNull(_data); + } + + FORCE_INLINE bool isUndefined() const { + return !_data; + } + + FORCE_INLINE size_t memoryUsage() const { + return _data ? _data->memoryUsage() : 0; + } + + FORCE_INLINE size_t nesting() const { + return _data ? _data->nesting() : 0; + } + + size_t size() const { + return variantSize(_data); + } + + protected: + VariantRefBase(TData *data) : _data(data) {} + TData *_data; + + friend TData *getData(const VariantRefBase &variant) { + return variant._data; + } +}; + +// A variant that can be a any value serializable to a JSON value. +// +// It can be set to: +// - a boolean +// - a char, short, int or a long (signed or unsigned) +// - a string (const char*) +// - a reference to a ArrayRef or ObjectRef +class VariantRef : public VariantRefBase<VariantData>, + public VariantOperators<VariantRef>, + public VariantShortcuts<VariantRef>, + public Visitable { + typedef VariantRefBase<VariantData> base_type; + friend class VariantConstRef; + + public: + // Intenal use only + FORCE_INLINE VariantRef(MemoryPool *pool, VariantData *data) + : base_type(data), _pool(pool) {} + + // Creates an uninitialized VariantRef + FORCE_INLINE VariantRef() : base_type(0), _pool(0) {} + + FORCE_INLINE void clear() const { + return variantSetNull(_data); + } + + template <typename T> + FORCE_INLINE bool set(const T &value) const { + return Converter<T>::toJson(value, *this); + } + + FORCE_INLINE bool ARDUINOJSON_DEPRECATED( + "Support for char is deprecated, use int8_t or uint8_t instead") + set(char value) const { + return set<signed char>(value); + } + + template <typename T> + FORCE_INLINE bool set(T *value) const { + return Converter<T *>::toJson(value, *this); + } + + template <typename T> + FORCE_INLINE + typename enable_if<!is_same<T, char *>::value && !is_same<T, char>::value, + T>::type + as() const { + return Converter<T>::fromJson(*this); + } + + template <typename T> + FORCE_INLINE typename enable_if<is_same<T, char *>::value, const char *>::type + ARDUINOJSON_DEPRECATED("Replace as<char*>() with as<const char*>()") + as() const { + return as<const char *>(); + } + + template <typename T> + FORCE_INLINE typename enable_if<is_same<T, char>::value, char>::type + ARDUINOJSON_DEPRECATED( + "Support for char is deprecated, use int8_t or uint8_t instead") + as() const { + return as<signed char>(); + } + + template <typename T> + FORCE_INLINE + typename enable_if<!is_same<T, char *>::value && !is_same<T, char>::value, + bool>::type + is() const { + return Converter<T>::checkJson(*this); + } + + template <typename T> + FORCE_INLINE typename enable_if<is_same<T, char *>::value, bool>::type + ARDUINOJSON_DEPRECATED("Replace is<char*>() with is<const char*>()") + is() const { + return is<const char *>(); + } + + template <typename T> + FORCE_INLINE typename enable_if<is_same<T, char>::value, bool>::type + ARDUINOJSON_DEPRECATED( + "Support for char is deprecated, use int8_t or uint8_t instead") + is() const { + return is<signed char>(); + } + + template <typename T> + FORCE_INLINE operator T() const { + return as<T>(); + } + + template <typename TVisitor> + typename TVisitor::result_type accept(TVisitor &visitor) const { + return variantAccept(_data, visitor); + } + + // Change the type of the variant + // + // ArrayRef to<ArrayRef>() + template <typename T> + typename enable_if<is_same<T, ArrayRef>::value, ArrayRef>::type to() const; + // + // ObjectRef to<ObjectRef>() + template <typename T> + typename enable_if<is_same<T, ObjectRef>::value, ObjectRef>::type to() const; + // + // ObjectRef to<VariantRef>() + template <typename T> + typename enable_if<is_same<T, VariantRef>::value, VariantRef>::type to() + const; + + VariantRef addElement() const; + + FORCE_INLINE VariantRef getElement(size_t) const; + + FORCE_INLINE VariantRef getOrAddElement(size_t) const; + + // getMember(const char*) const + // getMember(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE VariantRef getMember(TChar *) const; + + // getMember(const std::string&) const + // getMember(const String&) const + template <typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value, VariantRef>::type + getMember(const TString &) const; + + // getOrAddMember(char*) const + // getOrAddMember(const char*) const + // getOrAddMember(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE VariantRef getOrAddMember(TChar *) const; + + // getOrAddMember(const std::string&) const + // getOrAddMember(const String&) const + template <typename TString> + FORCE_INLINE VariantRef getOrAddMember(const TString &) const; + + FORCE_INLINE void remove(size_t index) const { + if (_data) + _data->remove(index); + } + // remove(char*) const + // remove(const char*) const + // remove(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE typename enable_if<IsString<TChar *>::value>::type remove( + TChar *key) const { + if (_data) + _data->remove(adaptString(key)); + } + // remove(const std::string&) const + // remove(const String&) const + template <typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove( + const TString &key) const { + if (_data) + _data->remove(adaptString(key)); + } + + private: + MemoryPool *_pool; + + friend MemoryPool *getPool(const VariantRef &variant) { + return variant._pool; + } +}; + +class VariantConstRef : public VariantRefBase<const VariantData>, + public VariantOperators<VariantConstRef>, + public VariantShortcuts<VariantConstRef>, + public Visitable { + typedef VariantRefBase<const VariantData> base_type; + friend class VariantRef; + + public: + VariantConstRef() : base_type(0) {} + VariantConstRef(const VariantData *data) : base_type(data) {} + VariantConstRef(VariantRef var) : base_type(var._data) {} + + template <typename TVisitor> + typename TVisitor::result_type accept(TVisitor &visitor) const { + return variantAccept(_data, visitor); + } + + template <typename T> + FORCE_INLINE + typename enable_if<!is_same<T, char *>::value && !is_same<T, char>::value, + T>::type + as() const { + return Converter<T>::fromJson(*this); + } + + template <typename T> + FORCE_INLINE typename enable_if<is_same<T, char *>::value, const char *>::type + ARDUINOJSON_DEPRECATED("Replace as<char*>() with as<const char*>()") + as() const { + return as<const char *>(); + } + + template <typename T> + FORCE_INLINE typename enable_if<is_same<T, char>::value, char>::type + ARDUINOJSON_DEPRECATED( + "Support for char is deprecated, use int8_t or uint8_t instead") + as() const { + return as<signed char>(); + } + + template <typename T> + FORCE_INLINE + typename enable_if<!is_same<T, char *>::value && !is_same<T, char>::value, + bool>::type + is() const { + return Converter<T>::checkJson(*this); + } + + template <typename T> + FORCE_INLINE typename enable_if<is_same<T, char *>::value, bool>::type + ARDUINOJSON_DEPRECATED("Replace is<char*>() with is<const char*>()") + is() const { + return is<const char *>(); + } + + template <typename T> + FORCE_INLINE typename enable_if<is_same<T, char>::value, bool>::type + ARDUINOJSON_DEPRECATED( + "Support for char is deprecated, use int8_t or uint8_t instead") + is() const { + return is<signed char>(); + } + + template <typename T> + FORCE_INLINE operator T() const { + return as<T>(); + } + + FORCE_INLINE VariantConstRef getElement(size_t) const; + + FORCE_INLINE VariantConstRef operator[](size_t index) const { + return getElement(index); + } + + // getMember(const std::string&) const + // getMember(const String&) const + template <typename TString> + FORCE_INLINE VariantConstRef getMember(const TString &key) const { + return VariantConstRef( + objectGetMember(variantAsObject(_data), adaptString(key))); + } + + // getMember(char*) const + // getMember(const char*) const + // getMember(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE VariantConstRef getMember(TChar *key) const { + const CollectionData *obj = variantAsObject(_data); + return VariantConstRef(obj ? obj->getMember(adaptString(key)) : 0); + } + + // operator[](const std::string&) const + // operator[](const String&) const + template <typename TString> + FORCE_INLINE + typename enable_if<IsString<TString>::value, VariantConstRef>::type + operator[](const TString &key) const { + return getMember(key); + } + + // operator[](char*) const + // operator[](const char*) const + // operator[](const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE + typename enable_if<IsString<TChar *>::value, VariantConstRef>::type + operator[](TChar *key) const { + return getMember(key); + } +}; + +template <> +struct Converter<VariantRef> { + static bool toJson(VariantRef src, VariantRef dst) { + return variantCopyFrom(getData(dst), getData(src), getPool(dst)); + } + static VariantRef fromJson(VariantRef src) { + return src; + } + static bool checkJson(VariantRef src) { + VariantData *data = getData(src); + return !!data; + } + static bool checkJson(VariantConstRef) { + return false; + } +}; + +template <> +struct Converter<VariantConstRef> { + static bool toJson(VariantConstRef src, VariantRef dst) { + return variantCopyFrom(getData(dst), getData(src), getPool(dst)); + } + + static VariantConstRef fromJson(VariantConstRef src) { + return VariantConstRef(getData(src)); + } + + static bool checkJson(VariantConstRef src) { + const VariantData *data = getData(src); + return !!data; + } +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/VariantShortcuts.hpp b/include/lib/ArduinoJson/Variant/VariantShortcuts.hpp new file mode 100644 index 0000000..e62847f --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantShortcuts.hpp @@ -0,0 +1,23 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Array/ArrayShortcuts.hpp> +#include <ArduinoJson/Object/ObjectShortcuts.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TVariant> +class VariantShortcuts : public ObjectShortcuts<TVariant>, + public ArrayShortcuts<TVariant> { + public: + using ArrayShortcuts<TVariant>::createNestedArray; + using ArrayShortcuts<TVariant>::createNestedObject; + using ArrayShortcuts<TVariant>::operator[]; + using ObjectShortcuts<TVariant>::createNestedArray; + using ObjectShortcuts<TVariant>::createNestedObject; + using ObjectShortcuts<TVariant>::operator[]; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/VariantSlot.hpp b/include/lib/ArduinoJson/Variant/VariantSlot.hpp new file mode 100644 index 0000000..a271c1e --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantSlot.hpp @@ -0,0 +1,116 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/integer.hpp> +#include <ArduinoJson/Polyfills/limits.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Strings/StoragePolicy.hpp> +#include <ArduinoJson/Variant/VariantContent.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +typedef int_t<ARDUINOJSON_SLOT_OFFSET_SIZE * 8>::type VariantSlotDiff; + +class VariantSlot { + // CAUTION: same layout as VariantData + // we cannot use composition because it adds padding + // (+20% on ESP8266 for example) + VariantContent _content; + uint8_t _flags; + VariantSlotDiff _next; + const char* _key; + + public: + // Must be a POD! + // - no constructor + // - no destructor + // - no virtual + // - no inheritance + + VariantData* data() { + return reinterpret_cast<VariantData*>(&_content); + } + + const VariantData* data() const { + return reinterpret_cast<const VariantData*>(&_content); + } + + VariantSlot* next() { + return _next ? this + _next : 0; + } + + const VariantSlot* next() const { + return const_cast<VariantSlot*>(this)->next(); + } + + VariantSlot* next(size_t distance) { + VariantSlot* slot = this; + while (distance--) { + if (!slot->_next) + return 0; + slot += slot->_next; + } + return slot; + } + + const VariantSlot* next(size_t distance) const { + return const_cast<VariantSlot*>(this)->next(distance); + } + + void setNext(VariantSlot* slot) { + ARDUINOJSON_ASSERT(!slot || slot - this >= + numeric_limits<VariantSlotDiff>::lowest()); + ARDUINOJSON_ASSERT(!slot || slot - this <= + numeric_limits<VariantSlotDiff>::highest()); + _next = VariantSlotDiff(slot ? slot - this : 0); + } + + void setNextNotNull(VariantSlot* slot) { + ARDUINOJSON_ASSERT(slot != 0); + ARDUINOJSON_ASSERT(slot - this >= + numeric_limits<VariantSlotDiff>::lowest()); + ARDUINOJSON_ASSERT(slot - this <= + numeric_limits<VariantSlotDiff>::highest()); + _next = VariantSlotDiff(slot - this); + } + + void setKey(const char* k, storage_policies::store_by_copy) { + ARDUINOJSON_ASSERT(k != NULL); + _flags |= OWNED_KEY_BIT; + _key = k; + } + + void setKey(const char* k, storage_policies::store_by_address) { + ARDUINOJSON_ASSERT(k != NULL); + _flags &= VALUE_MASK; + _key = k; + } + + const char* key() const { + return _key; + } + + bool ownsKey() const { + return (_flags & OWNED_KEY_BIT) != 0; + } + + void clear() { + _next = 0; + _flags = 0; + _key = 0; + } + + void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) { + if (_flags & OWNED_KEY_BIT) + _key += stringDistance; + if (_flags & OWNED_VALUE_BIT) + _content.asString += stringDistance; + if (_flags & COLLECTION_MASK) + _content.asCollection.movePointers(stringDistance, variantDistance); + } +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/VariantTag.hpp b/include/lib/ArduinoJson/Variant/VariantTag.hpp new file mode 100644 index 0000000..7164164 --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantTag.hpp @@ -0,0 +1,16 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +struct VariantTag {}; + +template <typename T> +struct IsVariant : is_base_of<VariantTag, T> {}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/VariantTo.hpp b/include/lib/ArduinoJson/Variant/VariantTo.hpp new file mode 100644 index 0000000..352ecba --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantTo.hpp @@ -0,0 +1,32 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { +class ArrayRef; +class ObjectRef; +class VariantRef; + +// A metafunction that returns the type of the value returned by +// VariantRef::to<T>() +template <typename T> +struct VariantTo {}; + +template <> +struct VariantTo<ArrayRef> { + typedef ArrayRef type; +}; +template <> +struct VariantTo<ObjectRef> { + typedef ObjectRef type; +}; +template <> +struct VariantTo<VariantRef> { + typedef VariantRef type; +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/Visitor.hpp b/include/lib/ArduinoJson/Variant/Visitor.hpp new file mode 100644 index 0000000..33237dd --- /dev/null +++ b/include/lib/ArduinoJson/Variant/Visitor.hpp @@ -0,0 +1,54 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Collection/CollectionData.hpp> +#include <ArduinoJson/Numbers/Float.hpp> +#include <ArduinoJson/Numbers/Integer.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TResult> +struct Visitor { + typedef TResult result_type; + + TResult visitArray(const CollectionData &) { + return TResult(); + } + + TResult visitBoolean(bool) { + return TResult(); + } + + TResult visitFloat(Float) { + return TResult(); + } + + TResult visitSignedInteger(Integer) { + return TResult(); + } + + TResult visitNull() { + return TResult(); + } + + TResult visitObject(const CollectionData &) { + return TResult(); + } + + TResult visitUnsignedInteger(UInt) { + return TResult(); + } + + TResult visitRawJson(const char *, size_t) { + return TResult(); + } + + TResult visitString(const char *) { + return TResult(); + } +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/compatibility.hpp b/include/lib/ArduinoJson/compatibility.hpp new file mode 100644 index 0000000..cca477e --- /dev/null +++ b/include/lib/ArduinoJson/compatibility.hpp @@ -0,0 +1,23 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License +// +// clang-format off + +#ifdef __GNUC__ + +#define ARDUINOJSON_PRAGMA(x) _Pragma(#x) + +#define ARDUINOJSON_COMPILE_ERROR(msg) ARDUINOJSON_PRAGMA(GCC error msg) + +#define ARDUINOJSON_STRINGIFY(S) #S + +#define ARDUINOJSON_DEPRECATION_ERROR(X, Y) \ + ARDUINOJSON_COMPILE_ERROR(ARDUINOJSON_STRINGIFY(X is a Y from ArduinoJson 5. Please see https:/\/arduinojson.org/upgrade to learn how to upgrade your program to ArduinoJson version 6)) + +#define StaticJsonBuffer ARDUINOJSON_DEPRECATION_ERROR(StaticJsonBuffer, class) +#define DynamicJsonBuffer ARDUINOJSON_DEPRECATION_ERROR(DynamicJsonBuffer, class) +#define JsonBuffer ARDUINOJSON_DEPRECATION_ERROR(JsonBuffer, class) +#define RawJson ARDUINOJSON_DEPRECATION_ERROR(RawJson, function) + +#endif diff --git a/include/lib/ArduinoJson/version.hpp b/include/lib/ArduinoJson/version.hpp new file mode 100644 index 0000000..d8aaf77 --- /dev/null +++ b/include/lib/ArduinoJson/version.hpp @@ -0,0 +1,10 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#define ARDUINOJSON_VERSION "6.18.0" +#define ARDUINOJSON_VERSION_MAJOR 6 +#define ARDUINOJSON_VERSION_MINOR 18 +#define ARDUINOJSON_VERSION_REVISION 0 |