// ArduinoJson - arduinojson.org // Copyright Benoit Blanchon 2014-2019 // MIT License #pragma once #ifdef __cplusplus #ifndef ARDUINOJSON_DEBUG #ifdef __clang__ #pragma clang system_header #elif defined __GNUC__ #pragma GCC system_header #endif #endif #define ARDUINOJSON_VERSION "6.11.1" #define ARDUINOJSON_VERSION_MAJOR 6 #define ARDUINOJSON_VERSION_MINOR 11 #define ARDUINOJSON_VERSION_REVISION 1 #if defined(_MSC_VER) #define ARDUINOJSON_HAS_INT64 1 #else #define ARDUINOJSON_HAS_INT64 0 #endif #if __cplusplus >= 201103L #define ARDUINOJSON_HAS_LONG_LONG 1 #define ARDUINOJSON_HAS_NULLPTR 1 #else #define ARDUINOJSON_HAS_LONG_LONG 0 #define ARDUINOJSON_HAS_NULLPTR 0 #endif #ifndef ARDUINOJSON_EMBEDDED_MODE #if defined(ARDUINO) || defined(__IAR_SYSTEMS_ICC__) || defined(__XC) || \ defined(__ARMCC_VERSION) #define ARDUINOJSON_EMBEDDED_MODE 1 #else #define ARDUINOJSON_EMBEDDED_MODE 0 #endif #endif #if ARDUINOJSON_EMBEDDED_MODE #ifndef ARDUINOJSON_USE_DOUBLE #define ARDUINOJSON_USE_DOUBLE 0 #endif #ifndef ARDUINOJSON_USE_LONG_LONG #define ARDUINOJSON_USE_LONG_LONG 0 #endif #ifndef ARDUINOJSON_ENABLE_STD_STRING #define ARDUINOJSON_ENABLE_STD_STRING 0 #endif #ifndef ARDUINOJSON_ENABLE_STD_STREAM #define ARDUINOJSON_ENABLE_STD_STREAM 0 #endif #ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT #define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10 #endif #else // ARDUINOJSON_EMBEDDED_MODE #ifndef ARDUINOJSON_USE_DOUBLE #define ARDUINOJSON_USE_DOUBLE 1 #endif #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 #ifndef ARDUINOJSON_ENABLE_STD_STRING #define ARDUINOJSON_ENABLE_STD_STRING 1 #endif #ifndef ARDUINOJSON_ENABLE_STD_STREAM #define ARDUINOJSON_ENABLE_STD_STREAM 1 #endif #ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT #define ARDUINOJSON_DEFAULT_NESTING_LIMIT 50 #endif #endif // ARDUINOJSON_EMBEDDED_MODE #ifdef ARDUINO #ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING #define ARDUINOJSON_ENABLE_ARDUINO_STRING 1 #endif #ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM #define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1 #endif #ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT #define ARDUINOJSON_ENABLE_ARDUINO_PRINT 1 #endif #else // ARDUINO #ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING #define ARDUINOJSON_ENABLE_ARDUINO_STRING 0 #endif #ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM #define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0 #endif #ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT #define ARDUINOJSON_ENABLE_ARDUINO_PRINT 0 #endif #endif // ARDUINO #ifndef ARDUINOJSON_ENABLE_PROGMEM #ifdef PROGMEM #define ARDUINOJSON_ENABLE_PROGMEM 1 #else #define ARDUINOJSON_ENABLE_PROGMEM 0 #endif #endif #ifndef ARDUINOJSON_DECODE_UNICODE #define ARDUINOJSON_DECODE_UNICODE 0 #endif #ifndef ARDUINOJSON_ENABLE_NAN #define ARDUINOJSON_ENABLE_NAN 0 #endif #ifndef ARDUINOJSON_ENABLE_INFINITY #define ARDUINOJSON_ENABLE_INFINITY 0 #endif #ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD #define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e7 #endif #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_TAB #define ARDUINOJSON_TAB " " #endif #define ARDUINOJSON_DO_CONCAT(A, B) A##B #define ARDUINOJSON_CONCAT2(A, B) ARDUINOJSON_DO_CONCAT(A, B) #define ARDUINOJSON_CONCAT3(A, B, C) \ ARDUINOJSON_CONCAT2(A, ARDUINOJSON_CONCAT2(B, C)) #define ARDUINOJSON_CONCAT4(A, B, C, D) \ ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT2(A, B), ARDUINOJSON_CONCAT2(C, D)) #define ARDUINOJSON_CONCAT8(A, B, C, D, E, F, G, H) \ ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT4(A, B, C, D), \ ARDUINOJSON_CONCAT4(E, F, G, H)) #define ARDUINOJSON_CONCAT10(A, B, C, D, E, F, G, H, I, J) \ ARDUINOJSON_CONCAT8(A, B, C, D, E, F, G, ARDUINOJSON_CONCAT3(H, I, J)) #define ARDUINOJSON_NAMESPACE \ ARDUINOJSON_CONCAT10( \ ArduinoJson, ARDUINOJSON_VERSION_MAJOR, ARDUINOJSON_VERSION_MINOR, \ ARDUINOJSON_VERSION_REVISION, _, ARDUINOJSON_USE_LONG_LONG, \ ARDUINOJSON_USE_DOUBLE, ARDUINOJSON_DECODE_UNICODE, \ ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY) #ifdef ARDUINOJSON_DEBUG #include #define ARDUINOJSON_ASSERT(X) assert(X) #else #define ARDUINOJSON_ASSERT(X) ((void)0) #endif #include // for size_t namespace ARDUINOJSON_NAMESPACE { template Y)> struct Max {}; template struct Max { static const size_t value = X; }; template struct Max { static const size_t value = Y; }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template class not_null { public: explicit not_null(T ptr) : _ptr(ptr) { ARDUINOJSON_ASSERT(ptr != NULL); } T get() const { ARDUINOJSON_ASSERT(_ptr != NULL); return _ptr; } private: T _ptr; }; template not_null make_not_null(T ptr) { ARDUINOJSON_ASSERT(ptr != NULL); return not_null(ptr); } } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template struct conditional { typedef TrueType type; }; template struct conditional { typedef FalseType type; }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template struct enable_if {}; template struct enable_if { typedef T type; }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template struct integral_constant { static const T value = v; }; typedef integral_constant true_type; typedef integral_constant false_type; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template struct is_array : false_type {}; template struct is_array : true_type {}; template struct is_array : true_type {}; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template 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(0))) == sizeof(Yes); }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template struct is_const : false_type {}; template struct is_const : true_type {}; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template struct is_floating_point : false_type {}; template <> struct is_floating_point : true_type {}; template <> struct is_floating_point : true_type {}; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template struct is_same : false_type {}; template struct is_same : true_type {}; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template struct is_integral { static const bool value = is_same::value || is_same::value || is_same::value || is_same::value || is_same::value || is_same::value || is_same::value || is_same::value || #if ARDUINOJSON_HAS_LONG_LONG is_same::value || is_same::value || #endif #if ARDUINOJSON_HAS_INT64 is_same::value || is_same::value || #endif is_same::value; }; template struct is_integral : is_integral {}; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template struct is_signed : false_type {}; template <> struct is_signed : true_type {}; template <> struct is_signed : true_type {}; template <> struct is_signed : true_type {}; template <> struct is_signed : true_type {}; template <> struct is_signed : true_type {}; template <> struct is_signed : true_type {}; template <> struct is_signed : true_type {}; #if ARDUINOJSON_HAS_LONG_LONG template <> struct is_signed : true_type {}; #endif #if ARDUINOJSON_HAS_INT64 template <> struct is_signed : true_type {}; #endif } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template struct is_unsigned : false_type {}; template <> struct is_unsigned : true_type {}; template <> struct is_unsigned : true_type {}; template <> struct is_unsigned : true_type {}; template <> struct is_unsigned : true_type {}; template <> struct is_unsigned : true_type {}; #if ARDUINOJSON_HAS_INT64 template <> struct is_unsigned : true_type {}; #endif #if ARDUINOJSON_HAS_LONG_LONG template <> struct is_unsigned : true_type {}; #endif } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template struct type_identity { typedef T type; }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template struct make_unsigned; template <> struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; #if ARDUINOJSON_HAS_LONG_LONG template <> struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; #endif #if ARDUINOJSON_HAS_INT64 template <> struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; #endif } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template struct remove_const { typedef T type; }; template struct remove_const { typedef T type; }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template struct remove_reference { typedef T type; }; template struct remove_reference { typedef T type; }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { class MemoryPool; class VariantData; class VariantSlot; class CollectionData { VariantSlot *_head; VariantSlot *_tail; public: VariantSlot *addSlot(MemoryPool *); VariantData *add(MemoryPool *pool); template VariantData *add(TAdaptedString key, MemoryPool *pool); void clear(); template bool containsKey(const TAdaptedString &key) const; bool copyFrom(const CollectionData &src, MemoryPool *pool); bool equalsArray(const CollectionData &other) const; bool equalsObject(const CollectionData &other) const; VariantData *get(size_t index) const; template VariantData *get(TAdaptedString key) const; VariantSlot *head() const { return _head; } void remove(size_t index); template void remove(TAdaptedString key) { remove(getSlot(key)); } void remove(VariantSlot *slot); size_t memoryUsage() const; size_t nesting() const; size_t size() const; private: VariantSlot *getSlot(size_t index) const; template VariantSlot *getSlot(TAdaptedString key) const; VariantSlot *getPreviousSlot(VariantSlot *) const; }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { #if ARDUINOJSON_USE_DOUBLE typedef double Float; #else typedef float Float; #endif } // namespace ARDUINOJSON_NAMESPACE #include // 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 namespace ARDUINOJSON_NAMESPACE { enum { VALUE_MASK = 0x7F, VALUE_IS_NULL = 0, VALUE_IS_LINKED_RAW = 0x01, VALUE_IS_OWNED_RAW = 0x02, VALUE_IS_LINKED_STRING = 0x03, VALUE_IS_OWNED_STRING = 0x04, VALUE_IS_BOOLEAN = 0x05, VALUE_IS_POSITIVE_INTEGER = 0x06, VALUE_IS_NEGATIVE_INTEGER = 0x07, VALUE_IS_FLOAT = 0x08, COLLECTION_MASK = 0x60, VALUE_IS_OBJECT = 0x20, VALUE_IS_ARRAY = 0x40, KEY_IS_OWNED = 0x80 }; struct RawData { const char *data; size_t size; }; union VariantContent { Float asFloat; UInt asInteger; CollectionData asCollection; const char *asString; struct { const char *data; size_t size; } asRaw; }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { typedef conditional::type VariantSlotDiff; class VariantSlot { VariantContent _content; uint8_t _flags; VariantSlotDiff _next; const char* _key; public: VariantData* data() { return reinterpret_cast(&_content); } const VariantData* data() const { return reinterpret_cast(&_content); } VariantSlot* next() { return _next ? this + _next : 0; } const VariantSlot* next() const { return const_cast(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(this)->next(distance); } void setNext(VariantSlot* slot) { _next = VariantSlotDiff(slot ? slot - this : 0); } void setNextNotNull(VariantSlot* slot) { ARDUINOJSON_ASSERT(slot != 0); _next = VariantSlotDiff(slot - this); } void setOwnedKey(not_null k) { _flags |= KEY_IS_OWNED; _key = k.get(); } void setLinkedKey(not_null k) { _flags &= VALUE_MASK; _key = k.get(); } const char* key() const { return _key; } bool ownsKey() const { return (_flags & KEY_IS_OWNED) != 0; } void clear() { _next = 0; _flags = 0; _key = 0; } }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { inline bool isAligned(void *ptr) { const size_t mask = sizeof(void *) - 1; size_t addr = reinterpret_cast(ptr); return (addr & mask) == 0; } inline size_t addPadding(size_t bytes) { const size_t mask = sizeof(void *) - 1; return (bytes + mask) & ~mask; } template struct AddPadding { static const size_t mask = sizeof(void *) - 1; static const size_t value = (bytes + mask) & ~mask; }; } // namespace ARDUINOJSON_NAMESPACE #define JSON_STRING_SIZE(SIZE) (SIZE) namespace ARDUINOJSON_NAMESPACE { struct StringSlot { char *value; size_t size; }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { class MemoryPool { public: MemoryPool(char* buf, size_t capa) : _begin(buf), _left(buf), _right(buf ? buf + capa : 0), _end(buf ? buf + capa : 0) { ARDUINOJSON_ASSERT(isAligned(_begin)); ARDUINOJSON_ASSERT(isAligned(_right)); ARDUINOJSON_ASSERT(isAligned(_end)); } void* buffer() { return _begin; } size_t capacity() const { return size_t(_end - _begin); } size_t size() const { return size_t(_left - _begin + _end - _right); } VariantSlot* allocVariant() { return allocRight(); } char* allocFrozenString(size_t n) { if (!canAlloc(n)) return 0; char* s = _left; _left += n; checkInvariants(); return s; } StringSlot allocExpandableString() { StringSlot s; s.value = _left; s.size = size_t(_right - _left); _left = _right; checkInvariants(); return s; } void freezeString(StringSlot& s, size_t newSize) { _left -= (s.size - newSize); s.size = newSize; checkInvariants(); } void clear() { _left = _begin; _right = _end; } bool canAlloc(size_t bytes) const { return _left + bytes <= _right; } bool owns(void* p) const { return _begin <= p && p < _end; } template T* allocRight() { return reinterpret_cast(allocRight(sizeof(T))); } void* allocRight(size_t bytes) { if (!canAlloc(bytes)) return 0; _right -= bytes; return _right; } void* operator new(size_t, void* p) { return p; } private: StringSlot* allocStringSlot() { return allocRight(); } void checkInvariants() { ARDUINOJSON_ASSERT(_begin <= _left); ARDUINOJSON_ASSERT(_left <= _right); ARDUINOJSON_ASSERT(_right <= _end); ARDUINOJSON_ASSERT(isAligned(_right)); } char *_begin, *_left, *_right, *_end; }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template struct IsString : false_type {}; template struct IsString : IsString {}; template struct IsString : IsString {}; } // namespace ARDUINOJSON_NAMESPACE #include // strcmp namespace ARDUINOJSON_NAMESPACE { inline int8_t safe_strcmp(const char* a, const char* b) { if (a == b) return 0; if (!a) return -1; if (!b) return 1; return static_cast(strcmp(a, b)); } inline int8_t 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 static_cast(strncmp(a, b, n)); } } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { class ConstRamStringAdapter { public: ConstRamStringAdapter(const char* str = 0) : _str(str) {} int8_t 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; } template char* save(TMemoryPool*) const { return 0; } size_t size() const { if (!_str) return 0; return strlen(_str); } const char* data() const { return _str; } bool isStatic() const { return true; } protected: const char* _str; }; inline ConstRamStringAdapter adaptString(const char* str) { return ConstRamStringAdapter(str); } } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { class RamStringAdapter : public ConstRamStringAdapter { public: RamStringAdapter(const char* str) : ConstRamStringAdapter(str) {} char* save(MemoryPool* pool) const { if (!_str) return NULL; size_t n = size() + 1; char* dup = pool->allocFrozenString(n); if (dup) memcpy(dup, _str, n); return dup; } bool isStatic() const { return false; } }; template inline RamStringAdapter adaptString(const TChar* str) { return RamStringAdapter(reinterpret_cast(str)); } inline RamStringAdapter adaptString(char* str) { return RamStringAdapter(str); } template struct IsString { static const bool value = sizeof(TChar) == 1; }; template <> struct IsString { static const bool value = false; }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { class SizedRamStringAdapter { public: SizedRamStringAdapter(const char* str, size_t n) : _str(str), _size(n) {} int8_t compare(const char* other) const { return safe_strncmp(_str, other, _size) == 0; } bool equals(const char* expected) const { return compare(expected) == 0; } bool isNull() const { return !_str; } char* save(MemoryPool* pool) const { if (!_str) return NULL; char* dup = pool->allocFrozenString(_size); if (dup) memcpy(dup, _str, _size); return dup; } size_t size() const { return _size; } bool isStatic() const { return false; } private: const char* _str; size_t _size; }; template inline SizedRamStringAdapter adaptString(const TChar* str, size_t size) { return SizedRamStringAdapter(reinterpret_cast(str), size); } } // namespace ARDUINOJSON_NAMESPACE #if ARDUINOJSON_ENABLE_STD_STRING #include namespace ARDUINOJSON_NAMESPACE { class StlStringAdapter { public: StlStringAdapter(const std::string& str) : _str(&str) {} char* save(MemoryPool* pool) const { size_t n = _str->length() + 1; char* dup = pool->allocFrozenString(n); if (dup) memcpy(dup, _str->c_str(), n); return dup; } bool isNull() const { return false; } int8_t compare(const char* other) const { if (!other) return 1; return static_cast(_str->compare(other)); } bool equals(const char* expected) const { if (!expected) return false; return *_str == expected; } const char* data() const { return _str->data(); } size_t size() const { return _str->size(); } bool isStatic() const { return false; } private: const std::string* _str; }; template <> struct IsString : true_type {}; inline StlStringAdapter adaptString(const std::string& str) { return StlStringAdapter(str); } } // namespace ARDUINOJSON_NAMESPACE #endif #if ARDUINOJSON_ENABLE_ARDUINO_STRING #include namespace ARDUINOJSON_NAMESPACE { class ArduinoStringAdapter { public: ArduinoStringAdapter(const ::String& str) : _str(&str) {} char* save(MemoryPool* pool) const { if (isNull()) return NULL; size_t n = _str->length() + 1; char* dup = pool->allocFrozenString(n); if (dup) memcpy(dup, _str->c_str(), n); return dup; } bool isNull() const { return !_str->c_str(); } int8_t compare(const char* other) const { const char* me = _str->c_str(); return safe_strcmp(me, other); } bool equals(const char* expected) const { return compare(expected) == 0; } const char* data() const { return _str->c_str(); } size_t size() const { return _str->length(); } bool isStatic() const { return false; } 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 #endif #if ARDUINOJSON_ENABLE_PROGMEM namespace ARDUINOJSON_NAMESPACE { class FlashStringAdapter { public: FlashStringAdapter(const __FlashStringHelper* str) : _str(str) {} int8_t compare(const char* other) const { if (!other && !_str) return 0; if (!_str) return -1; if (!other) return 1; return -strcmp_P(other, reinterpret_cast(_str)); } bool equals(const char* expected) const { return compare(expected) == 0; } bool isNull() const { return !_str; } char* save(MemoryPool* pool) const { if (!_str) return NULL; size_t n = size() + 1; // copy the terminator char* dup = pool->allocFrozenString(n); if (dup) memcpy_P(dup, reinterpret_cast(_str), n); return dup; } const char* data() const { return 0; } size_t size() const { if (!_str) return 0; return strlen_P(reinterpret_cast(_str)); } bool isStatic() const { return false; } private: const __FlashStringHelper* _str; }; inline FlashStringAdapter adaptString(const __FlashStringHelper* str) { return FlashStringAdapter(str); } template <> struct IsString : true_type {}; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { class SizedFlashStringAdapter { public: SizedFlashStringAdapter(const __FlashStringHelper* str, size_t sz) : _str(str), _size(sz) {} int8_t compare(const char* other) const { if (!other && !_str) return 0; if (!_str) return -1; if (!other) return 1; return -strncmp_P(other, reinterpret_cast(_str), _size); } bool equals(const char* expected) const { return compare(expected) == 0; } bool isNull() const { return !_str; } char* save(MemoryPool* pool) const { if (!_str) return NULL; char* dup = pool->allocFrozenString(_size); if (dup) memcpy_P(dup, (const char*)_str, _size); return dup; } size_t size() const { return _size; } bool isStatic() const { return false; } private: const __FlashStringHelper* _str; size_t _size; }; inline SizedFlashStringAdapter adaptString(const __FlashStringHelper* str, size_t sz) { return SizedFlashStringAdapter(str, sz); } } // namespace ARDUINOJSON_NAMESPACE #endif namespace ARDUINOJSON_NAMESPACE { template 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 { return _str.length(); } private: T _str; }; template class SerializedValue { 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 inline SerializedValue serialized(T str) { return SerializedValue(str); } template inline SerializedValue serialized(TChar* p) { return SerializedValue(p, adaptString(p).size()); } template inline SerializedValue serialized(TChar* p, size_t n) { return SerializedValue(p, n); } } // namespace ARDUINOJSON_NAMESPACE #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 #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4310) #endif namespace ARDUINOJSON_NAMESPACE { template struct numeric_limits; template struct numeric_limits::value>::type> { static T lowest() { return 0; } static T highest() { return T(-1); } }; template struct numeric_limits< T, typename enable_if::value && is_signed::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 #include // for size_t namespace ARDUINOJSON_NAMESPACE { #ifndef isnan template bool isnan(T x) { return x != x; } #endif #ifndef isinf template bool isinf(T x) { return x != 0.0 && x * 2 == x; } #endif } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template struct alias_cast_t { union { F raw; T data; }; }; template T alias_cast(F raw_data) { alias_cast_t ac; ac.raw = raw_data; return ac.data; } } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template struct FloatTraits {}; template struct FloatTraits { 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 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) { static T factors[] = { 1e1, 1e2, 1e4, 1e8, 1e16, forge(0x4693B8B5, 0xB5056E17), // 1e32 forge(0x4D384F03, 0xE93FF9F5), // 1e64 forge(0x5A827748, 0xF9301D32), // 1e128 forge(0x75154FDD, 0x7F73BF3C) // 1e256 }; return factors[index]; } static T negativeBinaryPowerOfTen(int index) { static T factors[] = { forge(0x3FB99999, 0x9999999A), // 1e-1 forge(0x3F847AE1, 0x47AE147B), // 1e-2 forge(0x3F1A36E2, 0xEB1C432D), // 1e-4 forge(0x3E45798E, 0xE2308C3A), // 1e-8 forge(0x3C9CD2B2, 0x97D889BC), // 1e-16 forge(0x3949F623, 0xD5A8A733), // 1e-32 forge(0x32A50FFD, 0x44F4A73D), // 1e-64 forge(0x255BBA08, 0xCF8C979D), // 1e-128 forge(0x0AC80628, 0x64AC6F43) // 1e-256 }; return factors[index]; } static T negativeBinaryPowerOfTenPlusOne(int index) { static T factors[] = { 1e0, forge(0x3FB99999, 0x9999999A), // 1e-1 forge(0x3F50624D, 0xD2F1A9FC), // 1e-3 forge(0x3E7AD7F2, 0x9ABCAF48), // 1e-7 forge(0x3CD203AF, 0x9EE75616), // 1e-15 forge(0x398039D6, 0x65896880), // 1e-31 forge(0x32DA53FC, 0x9631D10D), // 1e-63 forge(0x25915445, 0x81B7DEC2), // 1e-127 forge(0x0AFE07B2, 0x7DD78B14) // 1e-255 }; return factors[index]; } 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); } static T forge(uint32_t msb, uint32_t lsb) { return alias_cast((uint64_t(msb) << 32) | lsb); } }; template struct FloatTraits { 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 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) { static T factors[] = {1e1f, 1e2f, 1e4f, 1e8f, 1e16f, 1e32f}; return factors[index]; } static T negativeBinaryPowerOfTen(int index) { static T factors[] = {1e-1f, 1e-2f, 1e-4f, 1e-8f, 1e-16f, 1e-32f}; return factors[index]; } static T negativeBinaryPowerOfTenPlusOne(int index) { static T factors[] = {1e0f, 1e-1f, 1e-3f, 1e-7f, 1e-15f, 1e-31f}; return factors[index]; } static T forge(uint32_t bits) { return alias_cast(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 namespace ARDUINOJSON_NAMESPACE { template typename enable_if::value && sizeof(TOut) <= sizeof(TIn), bool>::type canStorePositiveInteger(TIn value) { return value <= TIn(numeric_limits::highest()); } template typename enable_if::value && sizeof(TIn) < sizeof(TOut), bool>::type canStorePositiveInteger(TIn) { return true; } template typename enable_if::value, bool>::type canStorePositiveInteger(TIn) { return true; } template typename enable_if::value, bool>::type canStoreNegativeInteger(TIn) { return true; } template typename enable_if::value && is_signed::value && sizeof(TOut) <= sizeof(TIn), bool>::type canStoreNegativeInteger(TIn value) { return value <= TIn(numeric_limits::highest()) + 1; } template typename enable_if::value && is_signed::value && sizeof(TIn) < sizeof(TOut), bool>::type canStoreNegativeInteger(TIn) { return true; } template typename enable_if::value && is_unsigned::value, bool>::type canStoreNegativeInteger(TIn) { return false; } template TOut convertPositiveInteger(TIn value) { return canStorePositiveInteger(value) ? TOut(value) : 0; } template TOut convertNegativeInteger(TIn value) { return canStoreNegativeInteger(value) ? TOut(~value + 1) : 0; } template typename enable_if::value, TOut>::type convertFloat( TIn value) { return TOut(value); } template typename enable_if::value, TOut>::type convertFloat( TIn value) { return value >= numeric_limits::lowest() && value <= numeric_limits::highest() ? 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 namespace ARDUINOJSON_NAMESPACE { class VariantData { VariantContent _content; // must be first to allow cast from array to variant uint8_t _flags; public: template void accept(Visitor &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_NEGATIVE_INTEGER: return visitor.visitNegativeInteger(_content.asInteger); case VALUE_IS_POSITIVE_INTEGER: return visitor.visitPositiveInteger(_content.asInteger); case VALUE_IS_BOOLEAN: return visitor.visitBoolean(_content.asInteger != 0); default: return visitor.visitNull(); } } template T asIntegral() const; template T asFloat() const; const char *asString() const; bool asBoolean() const; CollectionData *asArray() { return isArray() ? &_content.asCollection : 0; } const CollectionData *asArray() const { return const_cast(this)->asArray(); } CollectionData *asObject() { return isObject() ? &_content.asCollection : 0; } const CollectionData *asObject() const { return const_cast(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 setOwnedString(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 equals(const VariantData &other) const { if (type() != other.type()) return false; switch (type()) { case VALUE_IS_LINKED_STRING: case VALUE_IS_OWNED_STRING: return !strcmp(_content.asString, other._content.asString); case VALUE_IS_LINKED_RAW: case VALUE_IS_OWNED_RAW: return _content.asRaw.size == other._content.asRaw.size && !memcmp(_content.asRaw.data, other._content.asRaw.data, _content.asRaw.size); case VALUE_IS_BOOLEAN: case VALUE_IS_POSITIVE_INTEGER: case VALUE_IS_NEGATIVE_INTEGER: return _content.asInteger == other._content.asInteger; case VALUE_IS_ARRAY: return _content.asCollection.equalsArray(other._content.asCollection); case VALUE_IS_OBJECT: return _content.asCollection.equalsObject(other._content.asCollection); case VALUE_IS_FLOAT: return _content.asFloat == other._content.asFloat; case VALUE_IS_NULL: default: 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 bool isInteger() const { switch (type()) { case VALUE_IS_POSITIVE_INTEGER: return canStorePositiveInteger(_content.asInteger); case VALUE_IS_NEGATIVE_INTEGER: return canStoreNegativeInteger(_content.asInteger); default: return false; } } bool isFloat() const { return type() == VALUE_IS_FLOAT || type() == VALUE_IS_POSITIVE_INTEGER || type() == VALUE_IS_NEGATIVE_INTEGER; } 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 isCollection() || isString(); } void remove(size_t index) { if (isArray()) _content.asCollection.remove(index); } template void remove(TAdaptedString key) { if (isObject()) _content.asCollection.remove(key); } void setBoolean(bool value) { setType(VALUE_IS_BOOLEAN); _content.asInteger = static_cast(value); } void setFloat(Float value) { setType(VALUE_IS_FLOAT); _content.asFloat = value; } void setLinkedRaw(SerializedValue 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 bool setOwnedRaw(SerializedValue value, MemoryPool *pool) { char *dup = adaptString(value.data(), value.size()).save(pool); 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 enable_if::value>::type setInteger(T value) { setUnsignedInteger(value); } template typename enable_if::value>::type setInteger(T value) { setSignedInteger(value); } template void setSignedInteger(T value) { if (value >= 0) { setPositiveInteger(static_cast(value)); } else { setNegativeInteger(~static_cast(value) + 1); } } void setPositiveInteger(UInt value) { setType(VALUE_IS_POSITIVE_INTEGER); _content.asInteger = value; } void setNegativeInteger(UInt value) { setType(VALUE_IS_NEGATIVE_INTEGER); _content.asInteger = value; } void setLinkedString(const char *value) { if (value) { setType(VALUE_IS_LINKED_STRING); _content.asString = value; } else { setType(VALUE_IS_NULL); } } void setNull() { setType(VALUE_IS_NULL); } void setOwnedString(not_null s) { setType(VALUE_IS_OWNED_STRING); _content.asString = s.get(); } bool setOwnedString(const char *s) { if (s) { setOwnedString(make_not_null(s)); return true; } else { setType(VALUE_IS_NULL); return false; } } template bool setOwnedString(T value, MemoryPool *pool) { return setOwnedString(value.save(pool)); } void setUnsignedInteger(UInt value) { setType(VALUE_IS_POSITIVE_INTEGER); _content.asInteger = static_cast(value); } 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.add(pool); } VariantData *getElement(size_t index) const { return isArray() ? _content.asCollection.get(index) : 0; } template VariantData *getMember(TAdaptedString key) const { return isObject() ? _content.asCollection.get(key) : 0; } template VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool) { if (isNull()) toObject(); if (!isObject()) return 0; VariantData *var = _content.asCollection.get(key); if (var) return var; return _content.asCollection.add(key, pool); } private: uint8_t type() const { return _flags & VALUE_MASK; } void setType(uint8_t t) { _flags &= KEY_IS_OWNED; _flags |= t; } }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { inline VariantData *arrayAdd(CollectionData *arr, MemoryPool *pool) { return arr ? arr->add(pool) : 0; } template inline void arrayAccept(const CollectionData *arr, Visitor &visitor) { if (arr) visitor.visitArray(*arr); else 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 namespace ARDUINOJSON_NAMESPACE { template inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool) { if (!var) return false; if (key.isStatic()) { var->setLinkedKey(make_not_null(key.data())); } else { const char* dup = key.save(pool); if (!dup) return false; var->setOwnedKey(make_not_null(dup)); } 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(slot); } } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { struct Visitable { }; template struct IsVisitable : is_base_of {}; template struct IsVisitable : IsVisitable {}; } // namespace ARDUINOJSON_NAMESPACE #ifdef _MSC_VER // Visual Studio #define FORCE_INLINE // __forceinline causes C4714 when returning std::string #define NO_INLINE __declspec(noinline) #define DEPRECATED(msg) __declspec(deprecated(msg)) #elif defined(__GNUC__) // GCC or Clang #define FORCE_INLINE __attribute__((always_inline)) #define NO_INLINE __attribute__((noinline)) #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) #define DEPRECATED(msg) __attribute__((deprecated(msg))) #else #define DEPRECATED(msg) __attribute__((deprecated)) #endif #else // Other compilers #define FORCE_INLINE #define NO_INLINE #define DEPRECATED(msg) #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 namespace ARDUINOJSON_NAMESPACE { template class VariantCasts { public: template FORCE_INLINE operator T() const { return impl()->template as(); } private: const TImpl *impl() const { return static_cast(this); } }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template struct Comparer; template struct Comparer::value>::type> { T rhs; int result; explicit Comparer(T value) : rhs(value), result(1) {} void visitArray(const CollectionData &) {} void visitObject(const CollectionData &) {} void visitFloat(Float) {} void visitString(const char *lhs) { result = -adaptString(rhs).compare(lhs); } void visitRawJson(const char *, size_t) {} void visitNegativeInteger(UInt) {} void visitPositiveInteger(UInt) {} void visitBoolean(bool) {} void visitNull() { result = adaptString(rhs).compare(NULL); } }; template typename enable_if::value, int>::type sign(const T &value) { return value < 0 ? -1 : value > 0 ? 1 : 0; } template typename enable_if::value, int>::type sign(const T &value) { return value > 0 ? 1 : 0; } template struct Comparer::value || is_floating_point::value>::type> { T rhs; int result; explicit Comparer(T value) : rhs(value), result(1) {} void visitArray(const CollectionData &) {} void visitObject(const CollectionData &) {} void visitFloat(Float lhs) { result = sign(lhs - static_cast(rhs)); } void visitString(const char *) {} void visitRawJson(const char *, size_t) {} void visitNegativeInteger(UInt lhs) { result = -sign(static_cast(lhs) + rhs); } void visitPositiveInteger(UInt lhs) { result = static_cast(lhs) < rhs ? -1 : static_cast(lhs) > rhs ? 1 : 0; } void visitBoolean(bool) {} void visitNull() {} }; template <> struct Comparer { bool rhs; int result; explicit Comparer(bool value) : rhs(value), result(1) {} void visitArray(const CollectionData &) {} void visitObject(const CollectionData &) {} void visitFloat(Float) {} void visitString(const char *) {} void visitRawJson(const char *, size_t) {} void visitNegativeInteger(UInt) {} void visitPositiveInteger(UInt) {} void visitBoolean(bool lhs) { result = static_cast(lhs - rhs); } void visitNull() {} }; #if ARDUINOJSON_HAS_NULLPTR template <> struct Comparer { int result; explicit Comparer(decltype(nullptr)) : result(1) {} void visitArray(const CollectionData &) {} void visitObject(const CollectionData &) {} void visitFloat(Float) {} void visitString(const char *) {} void visitRawJson(const char *, size_t) {} void visitNegativeInteger(UInt) {} void visitPositiveInteger(UInt) {} void visitBoolean(bool) {} void visitNull() { result = 0; } }; #endif template class VariantComparisons { private: template static int compare(TVariant lhs, const T &rhs) { Comparer comparer(rhs); lhs.accept(comparer); return comparer.result; } public: template friend bool operator==(T *lhs, TVariant rhs) { return compare(rhs, lhs) == 0; } template friend bool operator==(const T &lhs, TVariant rhs) { return compare(rhs, lhs) == 0; } template friend bool operator==(TVariant lhs, T *rhs) { return compare(lhs, rhs) == 0; } template friend bool operator==(TVariant lhs, const T &rhs) { return compare(lhs, rhs) == 0; } template friend bool operator!=(T *lhs, TVariant rhs) { return compare(rhs, lhs) != 0; } template friend bool operator!=(const T &lhs, TVariant rhs) { return compare(rhs, lhs) != 0; } template friend bool operator!=(TVariant lhs, T *rhs) { return compare(lhs, rhs) != 0; } template friend bool operator!=(TVariant lhs, const T &rhs) { return compare(lhs, rhs) != 0; } template friend bool operator<(T *lhs, TVariant rhs) { return compare(rhs, lhs) > 0; } template friend bool operator<(const T &lhs, TVariant rhs) { return compare(rhs, lhs) > 0; } template friend bool operator<(TVariant lhs, T *rhs) { return compare(lhs, rhs) < 0; } template friend bool operator<(TVariant lhs, const T &rhs) { return compare(lhs, rhs) < 0; } template friend bool operator<=(T *lhs, TVariant rhs) { return compare(rhs, lhs) >= 0; } template friend bool operator<=(const T &lhs, TVariant rhs) { return compare(rhs, lhs) >= 0; } template friend bool operator<=(TVariant lhs, T *rhs) { return compare(lhs, rhs) <= 0; } template friend bool operator<=(TVariant lhs, const T &rhs) { return compare(lhs, rhs) <= 0; } template friend bool operator>(T *lhs, TVariant rhs) { return compare(rhs, lhs) < 0; } template friend bool operator>(const T &lhs, TVariant rhs) { return compare(rhs, lhs) < 0; } template friend bool operator>(TVariant lhs, T *rhs) { return compare(lhs, rhs) > 0; } template friend bool operator>(TVariant lhs, const T &rhs) { return compare(lhs, rhs) > 0; } template friend bool operator>=(T *lhs, TVariant rhs) { return compare(rhs, lhs) <= 0; } template friend bool operator>=(const T &lhs, TVariant rhs) { return compare(rhs, lhs) <= 0; } template friend bool operator>=(TVariant lhs, T *rhs) { return compare(lhs, rhs) >= 0; } template friend bool operator>=(TVariant lhs, const T &rhs) { return compare(lhs, rhs) >= 0; } }; } // namespace ARDUINOJSON_NAMESPACE #if ARDUINOJSON_ENABLE_ARDUINO_STRING #endif #if ARDUINOJSON_ENABLE_STD_STRING #endif namespace ARDUINOJSON_NAMESPACE { template struct IsWriteableString : false_type {}; template class DynamicStringWriter {}; #if ARDUINOJSON_ENABLE_ARDUINO_STRING template <> struct IsWriteableString : true_type {}; template <> class DynamicStringWriter { public: DynamicStringWriter(String &str) : _str(&str) {} size_t write(uint8_t c) { _str->operator+=(static_cast(c)); return 1; } size_t write(const uint8_t *s, size_t n) { _str->reserve(_str->length() + n); while (n > 0) { _str->operator+=(static_cast(*s++)); n--; } return n; } private: String *_str; }; #endif #if ARDUINOJSON_ENABLE_STD_STRING template <> struct IsWriteableString : true_type {}; template <> class DynamicStringWriter { public: DynamicStringWriter(std::string &str) : _str(&str) {} size_t write(uint8_t c) { _str->operator+=(static_cast(c)); return 1; } size_t write(const uint8_t *s, size_t n) { _str->append(reinterpret_cast(s), n); return n; } private: std::string *_str; }; #endif } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { class ArrayRef; class ArrayConstRef; class ObjectRef; class ObjectConstRef; class VariantRef; class VariantConstRef; template struct VariantAs { typedef T type; }; template <> struct VariantAs { typedef const char* type; }; template struct VariantConstAs { typedef typename VariantAs::type type; }; template <> struct VariantConstAs { typedef VariantConstRef type; }; template <> struct VariantConstAs { typedef ObjectConstRef type; }; template <> struct VariantConstAs { typedef ArrayConstRef type; }; template inline typename enable_if::value, T>::type variantAs( const VariantData* _data) { return _data != 0 ? _data->asIntegral() : T(0); } template inline typename enable_if::value, T>::type variantAs( const VariantData* _data) { return _data != 0 ? _data->asBoolean() : false; } template inline typename enable_if::value, T>::type variantAs( const VariantData* _data) { return _data != 0 ? _data->asFloat() : T(0); } template inline typename enable_if::value || is_same::value, const char*>::type variantAs(const VariantData* _data) { return _data != 0 ? _data->asString() : 0; } template inline typename enable_if::value, T>::type variantAs( const VariantData* _data); template inline typename enable_if::value, T>::type variantAs( const VariantData* _data); template inline typename enable_if::value, T>::type variantAs(const VariantData* _data); template inline typename enable_if::value, T>::type variantAs( const VariantData* _data); } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template class VariantOr { public: template T operator|(const T &defaultValue) const { if (impl()->template is()) return impl()->template as(); else return defaultValue; } const char *operator|(const char *defaultValue) const { const char *value = impl()->template as(); return value ? value : defaultValue; } private: const TImpl *impl() const { return static_cast(this); } }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template class ElementProxy; template class ArrayShortcuts { public: FORCE_INLINE ElementProxy operator[](size_t index) const; FORCE_INLINE ObjectRef createNestedObject() const; FORCE_INLINE ArrayRef createNestedArray() const; template FORCE_INLINE bool add(const T &value) const { return impl()->addElement().set(value); } template FORCE_INLINE bool add(T *value) const { return impl()->addElement().set(value); } private: const TArray *impl() const { return static_cast(this); } }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template class MemberProxy; template class ObjectShortcuts { public: template FORCE_INLINE typename enable_if::value, bool>::type containsKey(const TString &key) const; template FORCE_INLINE typename enable_if::value, bool>::type containsKey(TChar *key) const; template FORCE_INLINE typename enable_if::value, MemberProxy >::type operator[](const TString &key) const; template FORCE_INLINE typename enable_if::value, MemberProxy >::type operator[](TChar *key) const; template FORCE_INLINE ArrayRef createNestedArray(const TString &key) const; template FORCE_INLINE ArrayRef createNestedArray(TChar *key) const; template ObjectRef createNestedObject(const TString &key) const; template ObjectRef createNestedObject(TChar *key) const; private: const TObject *impl() const { return static_cast(this); } }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template class VariantShortcuts : public ObjectShortcuts, public ArrayShortcuts { public: using ArrayShortcuts::createNestedArray; using ArrayShortcuts::createNestedObject; using ArrayShortcuts::operator[]; using ObjectShortcuts::createNestedArray; using ObjectShortcuts::createNestedObject; using ObjectShortcuts::operator[]; }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template class VariantOperators : public VariantCasts, public VariantComparisons, public VariantOr, public VariantShortcuts {}; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template inline void variantAccept(const VariantData *var, Visitor &visitor) { if (var != 0) var->accept(visitor); else 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 bool variantEquals(const VariantData *a, const VariantData *b) { if (a == b) return true; if (!a || !b) return false; return a->equals(*b); } inline bool variantIsArray(const VariantData *var) { return var && var->isArray(); } inline bool variantIsBoolean(const VariantData *var) { return var && var->isBoolean(); } template inline bool variantIsInteger(const VariantData *var) { return var && var->isInteger(); } inline bool variantIsFloat(const VariantData *var) { return var && var->isFloat(); } inline bool variantIsString(const VariantData *var) { return var && var->isString(); } inline bool variantIsObject(const VariantData *var) { return var && var->isObject(); } inline bool variantIsNull(const VariantData *var) { return var == 0 || var->isNull(); } inline bool variantSetBoolean(VariantData *var, bool value) { if (!var) return false; var->setBoolean(value); return true; } inline bool variantSetFloat(VariantData *var, Float value) { if (!var) return false; var->setFloat(value); return true; } inline bool variantSetLinkedRaw(VariantData *var, SerializedValue value) { if (!var) return false; var->setLinkedRaw(value); return true; } template inline bool variantSetOwnedRaw(VariantData *var, SerializedValue value, MemoryPool *pool) { return var != 0 && var->setOwnedRaw(value, pool); } template inline bool variantSetSignedInteger(VariantData *var, T value) { if (!var) return false; var->setSignedInteger(value); return true; } inline bool variantSetLinkedString(VariantData *var, const char *value) { if (!var) return false; var->setLinkedString(value); return true; } inline void variantSetNull(VariantData *var) { if (!var) return; var->setNull(); } inline bool variantSetOwnedString(VariantData *var, char *value) { if (!var) return false; var->setOwnedString(value); return true; } template inline bool variantSetOwnedString(VariantData *var, T value, MemoryPool *pool) { return var != 0 && var->setOwnedString(value, pool); } inline bool variantSetUnsignedInteger(VariantData *var, UInt value) { if (!var) return false; var->setUnsignedInteger(value); return true; } 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 *variantAdd(VariantData *var, MemoryPool *pool) { return var != 0 ? var->addElement(pool) : 0; } template NO_INLINE VariantData *variantGetOrCreate(VariantData *var, TChar *key, MemoryPool *pool) { return var != 0 ? var->getOrAddMember(adaptString(key), pool) : 0; } template NO_INLINE VariantData *variantGetOrCreate(VariantData *var, const TString &key, MemoryPool *pool) { return var != 0 ? var->getOrAddMember(adaptString(key), pool) : 0; } } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { class ArrayRef; class ObjectRef; template class MemberProxy; template class VariantRefBase { public: template FORCE_INLINE typename enable_if::value, bool>::type is() const { return variantIsInteger(_data); } template FORCE_INLINE typename enable_if::value, bool>::type is() const { return variantIsFloat(_data); } template FORCE_INLINE typename enable_if::value, bool>::type is() const { return variantIsBoolean(_data); } template FORCE_INLINE typename enable_if::value || is_same::value || IsWriteableString::value, bool>::type is() const { return variantIsString(_data); } template FORCE_INLINE typename enable_if< is_same::type, ArrayRef>::value, bool>::type is() const { return variantIsArray(_data); } template FORCE_INLINE typename enable_if< is_same::type, ObjectRef>::value, bool>::type is() const { return variantIsObject(_data); } 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; }; class VariantRef : public VariantRefBase, public VariantOperators, public Visitable { typedef VariantRefBase base_type; friend class VariantConstRef; public: FORCE_INLINE VariantRef(MemoryPool *pool, VariantData *data) : base_type(data), _pool(pool) {} FORCE_INLINE VariantRef() : base_type(0), _pool(0) {} FORCE_INLINE void clear() const { return variantSetNull(_data); } FORCE_INLINE bool set(bool value) const { return variantSetBoolean(_data, value); } template FORCE_INLINE bool set( T value, typename enable_if::value>::type * = 0) const { return variantSetFloat(_data, static_cast(value)); } template FORCE_INLINE bool set( T value, typename enable_if::value && is_signed::value>::type * = 0) const { return variantSetSignedInteger(_data, value); } template FORCE_INLINE bool set( T value, typename enable_if::value && is_unsigned::value>::type * = 0) const { return variantSetUnsignedInteger(_data, static_cast(value)); } FORCE_INLINE bool set(SerializedValue value) const { return variantSetLinkedRaw(_data, value); } template FORCE_INLINE bool set( SerializedValue value, typename enable_if::value>::type * = 0) const { return variantSetOwnedRaw(_data, value, _pool); } template FORCE_INLINE bool set( const T &value, typename enable_if::value>::type * = 0) const { return variantSetOwnedString(_data, adaptString(value), _pool); } template FORCE_INLINE bool set( T *value, typename enable_if::value>::type * = 0) const { return variantSetOwnedString(_data, adaptString(value), _pool); } FORCE_INLINE bool set(const char *value) const { return variantSetLinkedString(_data, value); } template typename enable_if::value, bool>::type set( const TVariant &value) const; template FORCE_INLINE typename enable_if::value && !is_same::value && !is_same::value, typename VariantAs::type>::type as() const { return variantAs(_data); } template FORCE_INLINE typename enable_if::value, T>::type as() const; template FORCE_INLINE typename enable_if::value, T>::type as() const; template FORCE_INLINE typename enable_if::value, T>::type as() const { return *this; } template void accept(Visitor &visitor) const { variantAccept(_data, visitor); } FORCE_INLINE bool operator==(VariantRef lhs) const { return variantEquals(_data, lhs._data); } FORCE_INLINE bool operator!=(VariantRef lhs) const { return !variantEquals(_data, lhs._data); } template typename enable_if::value, ArrayRef>::type to() const; template typename enable_if::value, ObjectRef>::type to() const; template typename enable_if::value, VariantRef>::type to() const; VariantRef addElement() const; FORCE_INLINE VariantRef getElement(size_t) const; template FORCE_INLINE VariantRef getMember(TChar *) const; template FORCE_INLINE typename enable_if::value, VariantRef>::type getMember(const TString &) const; template FORCE_INLINE VariantRef getOrAddMember(TChar *) const; template FORCE_INLINE VariantRef getOrAddMember(const TString &) const; FORCE_INLINE void remove(size_t index) const { if (_data) _data->remove(index); } template FORCE_INLINE typename enable_if::value>::type remove( TChar *key) const { if (_data) _data->remove(adaptString(key)); } template FORCE_INLINE typename enable_if::value>::type remove( const TString &key) const { if (_data) _data->remove(adaptString(key)); } private: MemoryPool *_pool; }; // namespace ARDUINOJSON_NAMESPACE class VariantConstRef : public VariantRefBase, public VariantOperators, public Visitable { typedef VariantRefBase 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 void accept(Visitor &visitor) const { variantAccept(_data, visitor); } template FORCE_INLINE typename VariantConstAs::type as() const { return variantAs::type>(_data); } FORCE_INLINE VariantConstRef operator[](size_t index) const; template FORCE_INLINE typename enable_if::value, VariantConstRef>::type operator[](const TString &key) const { return VariantConstRef(objectGet(variantAsObject(_data), adaptString(key))); } template FORCE_INLINE typename enable_if::value, VariantConstRef>::type operator[](TChar *key) const { const CollectionData *obj = variantAsObject(_data); return VariantConstRef(obj ? obj->get(adaptString(key)) : 0); } }; } // namespace ARDUINOJSON_NAMESPACE 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 #define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \ ((NUMBER_OF_ELEMENTS) * sizeof(ARDUINOJSON_NAMESPACE::VariantSlot)) namespace ARDUINOJSON_NAMESPACE { class ObjectRef; template class ElementProxy; template class ArrayRefBase { public: operator VariantConstRef() const { const void* data = _data; // prevent warning cast-align return VariantConstRef(reinterpret_cast(data)); } template FORCE_INLINE void accept(Visitor& visitor) const { arrayAccept(_data, visitor); } FORCE_INLINE bool isNull() 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, public Visitable { friend class ArrayRef; typedef ArrayRefBase 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->get(index) : 0); } }; class ArrayRef : public ArrayRefBase, public ArrayShortcuts, public Visitable { typedef ArrayRefBase 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(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(); } 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); } FORCE_INLINE VariantRef getElement(size_t index) const { return VariantRef(_pool, _data ? _data->get(index) : 0); } FORCE_INLINE void remove(iterator it) const { if (!_data) return; _data->remove(it.internal()); } FORCE_INLINE void remove(size_t index) const { if (!_data) return; _data->remove(index); } private: MemoryPool* _pool; }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template void objectAccept(const CollectionData *obj, Visitor &visitor) { if (obj) visitor.visitObject(*obj); else 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 inline VariantData *objectGet(const CollectionData *obj, TAdaptedString key) { if (!obj) return 0; return obj->get(key); } template void objectRemove(CollectionData *obj, TAdaptedString key) { if (!obj) return; obj->remove(key); } template inline VariantData *objectGetOrCreate(CollectionData *obj, TAdaptedString key, MemoryPool *pool) { if (!obj) return 0; if (key.isNull()) return 0; VariantData *var = obj->get(key); if (var) return var; return obj->add(key, pool); } } // namespace ARDUINOJSON_NAMESPACE 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; } 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; } /* const char* save(MemoryPool* pool) const { if (_isStatic) return c_str(); return RamStringAdapter::save(pool); }*/ private: bool _isStatic; }; template <> struct IsString : true_type {}; inline StringAdapter adaptString(const String& str) { return StringAdapter(str); } } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { 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 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 #define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \ ((NUMBER_OF_ELEMENTS) * sizeof(ARDUINOJSON_NAMESPACE::VariantSlot)) namespace ARDUINOJSON_NAMESPACE { template class ObjectRefBase { public: operator VariantConstRef() const { const void* data = _data; // prevent warning cast-align return VariantConstRef(reinterpret_cast(data)); } template FORCE_INLINE void accept(Visitor& visitor) const { objectAccept(_data, visitor); } FORCE_INLINE bool isNull() 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, public Visitable { friend class ObjectRef; typedef ObjectRefBase 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(); } template FORCE_INLINE bool containsKey(const TString& key) const { return !getMember(key).isUndefined(); } template FORCE_INLINE bool containsKey(TChar* key) const { return !getMember(key).isUndefined(); } template FORCE_INLINE VariantConstRef getMember(const TString& key) const { return get_impl(adaptString(key)); } template FORCE_INLINE VariantConstRef getMember(TChar* key) const { return get_impl(adaptString(key)); } template FORCE_INLINE typename enable_if::value, VariantConstRef>::type operator[](const TString& key) const { return get_impl(adaptString(key)); } template FORCE_INLINE typename enable_if::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 FORCE_INLINE VariantConstRef get_impl(TAdaptedString key) const { return VariantConstRef(objectGet(_data, key)); } }; class ObjectRef : public ObjectRefBase, public ObjectShortcuts, public Visitable { typedef ObjectRefBase 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(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); } template FORCE_INLINE VariantRef getMember(const TString& key) const { return get_impl(adaptString(key)); } template FORCE_INLINE VariantRef getMember(TChar* key) const { return get_impl(adaptString(key)); } template FORCE_INLINE VariantRef getOrAddMember(const TString& key) const { return getOrCreate_impl(adaptString(key)); } template FORCE_INLINE VariantRef getOrAddMember(TChar* key) const { return getOrCreate_impl(adaptString(key)); } FORCE_INLINE bool operator==(ObjectRef rhs) const { return objectEquals(_data, rhs._data); } FORCE_INLINE void remove(iterator it) const { if (!_data) return; _data->remove(it.internal()); } template FORCE_INLINE void remove(const TString& key) const { objectRemove(_data, adaptString(key)); } template FORCE_INLINE void remove(TChar* key) const { objectRemove(_data, adaptString(key)); } private: template FORCE_INLINE VariantRef get_impl(TAdaptedString key) const { return VariantRef(_pool, objectGet(_data, key)); } template FORCE_INLINE VariantRef getOrCreate_impl(TAdaptedString key) const { return VariantRef(_pool, objectGetOrCreate(_data, key, _pool)); } MemoryPool* _pool; }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { class ArrayRef; class ObjectRef; class VariantRef; template struct VariantTo {}; template <> struct VariantTo { typedef ArrayRef type; }; template <> struct VariantTo { typedef ObjectRef type; }; template <> struct VariantTo { typedef VariantRef type; }; } // namespace ARDUINOJSON_NAMESPACE #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4522) #endif namespace ARDUINOJSON_NAMESPACE { template class ElementProxy : public VariantOperators >, public Visitable { typedef ElementProxy this_type; public: FORCE_INLINE ElementProxy(TArray array, size_t index) : _array(array), _index(index) {} FORCE_INLINE this_type& operator=(const this_type& src) { getUpstreamElement().set(src.as()); return *this; } template FORCE_INLINE this_type& operator=(const T& src) { getUpstreamElement().set(src); return *this; } template FORCE_INLINE this_type& operator=(T* src) { getUpstreamElement().set(src); return *this; } FORCE_INLINE void clear() const { getUpstreamElement().clear(); } FORCE_INLINE bool isNull() const { return getUpstreamElement().isNull(); } template FORCE_INLINE typename VariantAs::type as() const { return getUpstreamElement().template as(); } template FORCE_INLINE bool is() const { return getUpstreamElement().template is(); } template FORCE_INLINE typename VariantTo::type to() const { return getUpstreamElement().template to(); } template FORCE_INLINE bool set(const TValue& value) const { return getUpstreamElement().set(value); } template FORCE_INLINE bool set(TValue* value) const { return getUpstreamElement().set(value); } template void accept(Visitor& visitor) const { return getUpstreamElement().accept(visitor); } FORCE_INLINE size_t size() const { return getUpstreamElement().size(); } template VariantRef getMember(TNestedKey* key) const { return getUpstreamElement().getMember(key); } template VariantRef getMember(const TNestedKey& key) const { return getUpstreamElement().getMember(key); } template VariantRef getOrAddMember(TNestedKey* key) const { return getUpstreamElement().getOrAddMember(key); } template VariantRef getOrAddMember(const TNestedKey& key) const { return getUpstreamElement().getOrAddMember(key); } VariantRef addElement() const { return getUpstreamElement().addElement(); } VariantRef getElement(size_t index) const { return getUpstreamElement().getElement(index); } FORCE_INLINE void remove(size_t index) const { getUpstreamElement().remove(index); } template FORCE_INLINE typename enable_if::value>::type remove( TChar* key) const { getUpstreamElement().remove(key); } template FORCE_INLINE typename enable_if::value>::type remove( const TString& key) const { getUpstreamElement().remove(key); } private: FORCE_INLINE VariantRef getUpstreamElement() const { return _array.getElement(_index); } TArray _array; const size_t _index; }; template inline ElementProxy ArrayShortcuts::operator[]( size_t index) const { return ElementProxy(*impl(), index); } } // namespace ARDUINOJSON_NAMESPACE #ifdef _MSC_VER #pragma warning(pop) #endif #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4522) #endif namespace ARDUINOJSON_NAMESPACE { template class MemberProxy : public VariantOperators >, public Visitable { typedef MemberProxy this_type; public: FORCE_INLINE MemberProxy(TObject variant, TStringRef key) : _object(variant), _key(key) {} FORCE_INLINE operator VariantConstRef() const { return getUpstreamMember(); } FORCE_INLINE this_type &operator=(const this_type &src) { getOrAddUpstreamMember().set(src); return *this; } template FORCE_INLINE typename enable_if::value, this_type &>::type operator=(const TValue &src) { getOrAddUpstreamMember().set(src); return *this; } template 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 FORCE_INLINE typename VariantAs::type as() const { return getUpstreamMember().template as(); } template FORCE_INLINE bool is() const { return getUpstreamMember().template is(); } FORCE_INLINE size_t size() const { return getUpstreamMember().size(); } FORCE_INLINE void remove(size_t index) const { getUpstreamMember().remove(index); } template FORCE_INLINE typename enable_if::value>::type remove( TChar *key) const { getUpstreamMember().remove(key); } template FORCE_INLINE typename enable_if::value>::type remove( const TString &key) const { getUpstreamMember().remove(key); } template FORCE_INLINE typename VariantTo::type to() { return getOrAddUpstreamMember().template to(); } template FORCE_INLINE typename enable_if::value, bool>::type set( const TValue &value) { return getOrAddUpstreamMember().set(value); } template FORCE_INLINE bool set(const TChar *value) { return getOrAddUpstreamMember().set(value); } template void accept(Visitor &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); } template FORCE_INLINE VariantRef getMember(TChar *key) const { return getUpstreamMember().getMember(key); } template FORCE_INLINE VariantRef getMember(const TString &key) const { return getUpstreamMember().getMember(key); } template FORCE_INLINE VariantRef getOrAddMember(TChar *key) const { return getOrAddUpstreamMember().getOrAddMember(key); } template 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); } TObject _object; TStringRef _key; }; template template inline typename enable_if::value, MemberProxy >::type ObjectShortcuts::operator[](const TString &key) const { return MemberProxy(*impl(), key); } template template inline typename enable_if::value, MemberProxy >::type ObjectShortcuts::operator[](TString *key) const { return MemberProxy(*impl(), key); } } // namespace ARDUINOJSON_NAMESPACE #ifdef _MSC_VER #pragma warning(pop) #endif namespace ARDUINOJSON_NAMESPACE { class JsonDocument : public Visitable { public: template void accept(Visitor& visitor) const { return getVariant().accept(visitor); } template typename VariantAs::type as() { return getVariant().template as(); } template typename VariantConstAs::type as() const { return getVariant().template as(); } void clear() { _pool.clear(); _data.setNull(); } template bool is() const { return getVariant().template is(); } bool isNull() const { return getVariant().isNull(); } size_t memoryUsage() const { return _pool.size(); } 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().set(src.as()); } template typename enable_if::value, bool>::type set( const T& src) { return to().set(src); } template typename VariantTo::type to() { clear(); return getVariant().template to(); } MemoryPool& memoryPool() { return _pool; } VariantData& data() { return _data; } ArrayRef createNestedArray() { return addElement().to(); } template ArrayRef createNestedArray(TChar* key) { return getOrAddMember(key).template to(); } template ArrayRef createNestedArray(const TString& key) { return getOrAddMember(key).template to(); } ObjectRef createNestedObject() { return addElement().to(); } template ObjectRef createNestedObject(TChar* key) { return getOrAddMember(key).template to(); } template ObjectRef createNestedObject(const TString& key) { return getOrAddMember(key).template to(); } template bool containsKey(TChar* key) const { return !getMember(key).isUndefined(); } template bool containsKey(const TString& key) const { return !getMember(key).isUndefined(); } template FORCE_INLINE typename enable_if::value, MemberProxy >::type operator[](const TString& key) { return MemberProxy(*this, key); } template FORCE_INLINE typename enable_if::value, MemberProxy >::type operator[](TChar* key) { return MemberProxy(*this, key); } template FORCE_INLINE typename enable_if::value, VariantConstRef>::type operator[](const TString& key) const { return getMember(key); } template FORCE_INLINE typename enable_if::value, VariantConstRef>::type operator[](TChar* key) const { return getMember(key); } FORCE_INLINE ElementProxy operator[](size_t index) { return ElementProxy(*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)); } template FORCE_INLINE VariantConstRef getMember(TChar* key) const { return VariantConstRef(_data.getMember(adaptString(key))); } template FORCE_INLINE typename enable_if::value, VariantConstRef>::type getMember(const TString& key) const { return VariantConstRef(_data.getMember(adaptString(key))); } template FORCE_INLINE VariantRef getMember(TChar* key) { return VariantRef(&_pool, _data.getMember(adaptString(key))); } template FORCE_INLINE typename enable_if::value, VariantRef>::type getMember(const TString& key) { return VariantRef(&_pool, _data.getMember(adaptString(key))); } template FORCE_INLINE VariantRef getOrAddMember(TChar* key) { return VariantRef(&_pool, _data.getOrAddMember(adaptString(key), &_pool)); } template 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 FORCE_INLINE bool add(const TValue& value) { return addElement().set(value); } template FORCE_INLINE bool add(TChar* value) { return addElement().set(value); } FORCE_INLINE void remove(size_t index) { _data.remove(index); } template FORCE_INLINE typename enable_if::value>::type remove( TChar* key) { _data.remove(adaptString(key)); } template FORCE_INLINE typename enable_if::value>::type remove( const TString& key) { _data.remove(adaptString(key)); } protected: JsonDocument(MemoryPool pool) : _pool(pool) { _data.setNull(); } JsonDocument(char* buf, size_t capa) : _pool(buf, capa) { _data.setNull(); } void replacePool(MemoryPool pool) { _pool = pool; } private: VariantRef getVariant() { return VariantRef(&_pool, &_data); } VariantConstRef getVariant() const { return VariantConstRef(&_data); } MemoryPool _pool; VariantData _data; }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template class AllocatorOwner { protected: AllocatorOwner() {} AllocatorOwner(const AllocatorOwner& src) : _allocator(src._allocator) {} AllocatorOwner(TAllocator allocator) : _allocator(allocator) {} void* allocate(size_t n) { return _allocator.allocate(n); } void deallocate(void* p) { _allocator.deallocate(p); } private: TAllocator _allocator; }; template class BasicJsonDocument : AllocatorOwner, public JsonDocument { public: explicit BasicJsonDocument(size_t capa, TAllocator allocator = TAllocator()) : AllocatorOwner(allocator), JsonDocument(allocPool(capa)) {} BasicJsonDocument(const BasicJsonDocument& src) : AllocatorOwner(src), JsonDocument(allocPool(src.memoryUsage())) { set(src); } template BasicJsonDocument(const T& src, typename enable_if::value>::type* = 0) : JsonDocument(allocPool(src.memoryUsage())) { set(src); } BasicJsonDocument(VariantRef src) : JsonDocument(allocPool(src.memoryUsage())) { set(src); } ~BasicJsonDocument() { freePool(); } BasicJsonDocument& operator=(const BasicJsonDocument& src) { reallocPoolIfTooSmall(src.memoryUsage()); set(src); return *this; } template BasicJsonDocument& operator=(const T& src) { reallocPoolIfTooSmall(src.memoryUsage()); set(src); return *this; } private: MemoryPool allocPool(size_t requiredSize) { size_t capa = addPadding(requiredSize); return MemoryPool(reinterpret_cast(this->allocate(capa)), capa); } void reallocPoolIfTooSmall(size_t requiredSize) { if (requiredSize <= capacity()) return; freePool(); replacePool(allocPool(addPadding(requiredSize))); } void freePool() { this->deallocate(memoryPool().buffer()); } }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { struct DefaultAllocator { void* allocate(size_t n) { return malloc(n); } void deallocate(void* p) { free(p); } }; typedef BasicJsonDocument DynamicJsonDocument; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template class StaticJsonDocument : public JsonDocument { static const size_t _capacity = AddPadding::value>::value; public: StaticJsonDocument() : JsonDocument(_buffer, _capacity) {} StaticJsonDocument(const StaticJsonDocument& src) : JsonDocument(_buffer, _capacity) { set(src); } template StaticJsonDocument(const T& src, typename enable_if::value>::type* = 0) : JsonDocument(_buffer, _capacity) { set(src); } StaticJsonDocument(VariantRef src) : JsonDocument(_buffer, _capacity) { set(src); } StaticJsonDocument operator=(const StaticJsonDocument& src) { set(src); return *this; } template StaticJsonDocument operator=(const T& src) { set(src); return *this; } private: char _buffer[_capacity]; }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template inline ArrayRef ArrayShortcuts::createNestedArray() const { return impl()->addElement().template to(); } template inline ObjectRef ArrayShortcuts::createNestedObject() const { return impl()->addElement().template to(); } } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template inline bool copyArray(T (&src)[N], ArrayRef dst) { return copyArray(src, N, dst); } template inline bool copyArray(T* src, size_t len, ArrayRef dst) { bool ok = true; for (size_t i = 0; i < len; i++) { ok &= dst.add(src[i]); } return ok; } template inline bool copyArray(T (&src)[N1][N2], ArrayRef 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; } template inline size_t copyArray(ArrayConstRef src, T (&dst)[N]) { return copyArray(src, dst, N); } template inline size_t copyArray(ArrayConstRef src, T* dst, size_t len) { size_t i = 0; for (ArrayConstRef::iterator it = src.begin(); it != src.end() && i < len; ++it) dst[i++] = *it; return i; } template inline void copyArray(ArrayConstRef src, T (&dst)[N1][N2]) { size_t i = 0; for (ArrayConstRef::iterator it = src.begin(); it != src.end() && i < N1; ++it) { copyArray(it->as(), dst[i++]); } } } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { 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::add(MemoryPool* pool) { return slotData(addSlot(pool)); } template inline VariantData* CollectionData::add(TAdaptedString key, MemoryPool* pool) { VariantSlot* slot = addSlot(pool); if (!slotSetKey(slot, key, pool)) return 0; return slot->data(); } inline void CollectionData::clear() { _head = 0; _tail = 0; } template 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 = add(RamStringAdapter(s->key()), pool); else var = add(ConstRamStringAdapter(s->key()), pool); } else { var = add(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.get(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 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 { 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 inline VariantData* CollectionData::get(TAdaptedString key) const { VariantSlot* slot = getSlot(key); return slot ? slot->data() : 0; } inline VariantData* CollectionData::get(size_t index) const { VariantSlot* slot = getSlot(index); return slot ? slot->data() : 0; } inline void CollectionData::remove(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::remove(size_t index) { remove(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); } } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template template inline ArrayRef ObjectShortcuts::createNestedArray( const TString& key) const { return impl()->getOrAddMember(key).template to(); } template template inline ArrayRef ObjectShortcuts::createNestedArray(TChar* key) const { return impl()->getOrAddMember(key).template to(); } template template inline ObjectRef ObjectShortcuts::createNestedObject( const TString& key) const { return impl()->getOrAddMember(key).template to(); } template template inline ObjectRef ObjectShortcuts::createNestedObject( TChar* key) const { return impl()->getOrAddMember(key).template to(); } template template inline typename enable_if::value, bool>::type ObjectShortcuts::containsKey(const TString& key) const { return !impl()->getMember(key).isUndefined(); } template template inline typename enable_if::value, bool>::type ObjectShortcuts::containsKey(TChar* key) const { return !impl()->getMember(key).isUndefined(); } } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template inline typename enable_if::value, T>::type variantAs( const VariantData* _data) { return ArrayConstRef(variantAsArray(_data)); } template inline typename enable_if::value, T>::type variantAs( const VariantData* _data) { return ObjectConstRef(variantAsObject(_data)); } template inline typename enable_if::value, T>::type variantAs(const VariantData* _data) { return VariantConstRef(_data); } template inline typename enable_if::value, T>::type variantAs( const VariantData* _data) { const char* cstr = _data != 0 ? _data->asString() : 0; if (cstr) return T(cstr); T s; serializeJson(VariantConstRef(_data), s); return s; } } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { inline bool isdigit(char c) { return '0' <= c && c <= '9'; } inline bool issign(char c) { return '-' == c || c == '+'; } } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template struct ParsedNumber { ParsedNumber() : uintValue(0), floatValue(0), _type(VALUE_IS_NULL) {} ParsedNumber(TUInt value, bool is_negative) : uintValue(value), floatValue(TFloat(value)), _type(uint8_t(is_negative ? VALUE_IS_NEGATIVE_INTEGER : VALUE_IS_POSITIVE_INTEGER)) {} ParsedNumber(TFloat value) : floatValue(value), _type(VALUE_IS_FLOAT) {} template T as() const { switch (_type) { case VALUE_IS_NEGATIVE_INTEGER: return convertNegativeInteger(uintValue); case VALUE_IS_POSITIVE_INTEGER: return convertPositiveInteger(uintValue); case VALUE_IS_FLOAT: return convertFloat(floatValue); default: return 0; } } uint8_t type() const { return _type; } TUInt uintValue; TFloat floatValue; uint8_t _type; }; template struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> {}; template inline ParsedNumber parseNumber(const char *s) { typedef FloatTraits traits; typedef typename choose_largest::type mantissa_t; typedef typename traits::exponent_type exponent_t; typedef ParsedNumber return_type; 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') return traits::nan(); #endif #if ARDUINOJSON_ENABLE_INFINITY if (*s == 'i' || *s == 'I') return is_negative ? -traits::inf() : traits::inf(); #endif if (!isdigit(*s) && *s != '.') return return_type(); mantissa_t mantissa = 0; exponent_t exponent_offset = 0; const mantissa_t maxUint = TUInt(-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') return return_type(TUInt(mantissa), is_negative); while (mantissa > traits::mantissa_max) { mantissa /= 10; exponent_offset++; } 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) return is_negative ? -0.0f : 0.0f; else return is_negative ? -traits::inf() : traits::inf(); } s++; } if (negative_exponent) exponent = -exponent; } exponent += exponent_offset; if (*s != '\0') return return_type(); TFloat result = traits::make_float(static_cast(mantissa), exponent); return is_negative ? -result : result; } } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template inline T parseFloat(const char* s) { typedef typename choose_largest::type TFloat; return parseNumber(s).template as(); } } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template T parseInteger(const char *s) { typedef typename choose_largest::type>::type TUInt; return parseNumber(s).template as(); } } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template inline T VariantData::asIntegral() const { switch (type()) { case VALUE_IS_POSITIVE_INTEGER: case VALUE_IS_BOOLEAN: return convertPositiveInteger(_content.asInteger); case VALUE_IS_NEGATIVE_INTEGER: return convertNegativeInteger(_content.asInteger); case VALUE_IS_LINKED_STRING: case VALUE_IS_OWNED_STRING: return parseInteger(_content.asString); case VALUE_IS_FLOAT: return convertFloat(_content.asFloat); default: return 0; } } inline bool VariantData::asBoolean() const { switch (type()) { case VALUE_IS_POSITIVE_INTEGER: case VALUE_IS_BOOLEAN: case VALUE_IS_NEGATIVE_INTEGER: return _content.asInteger != 0; case VALUE_IS_FLOAT: return _content.asFloat != 0; case VALUE_IS_LINKED_STRING: case VALUE_IS_OWNED_STRING: return strcmp("true", _content.asString) == 0; default: return false; } } template inline T VariantData::asFloat() const { switch (type()) { case VALUE_IS_POSITIVE_INTEGER: case VALUE_IS_BOOLEAN: return static_cast(_content.asInteger); case VALUE_IS_NEGATIVE_INTEGER: return -static_cast(_content.asInteger); case VALUE_IS_LINKED_STRING: case VALUE_IS_OWNED_STRING: return parseFloat(_content.asString); case VALUE_IS_FLOAT: return static_cast(_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 enable_if::value, bool>::type VariantRef::set( const TVariant &value) const { VariantConstRef v = value; return variantCopyFrom(_data, v._data, _pool); } template inline typename enable_if::value, T>::type VariantRef::as() const { return ArrayRef(_pool, _data != 0 ? _data->asArray() : 0); } template inline typename enable_if::value, T>::type VariantRef::as() const { return ObjectRef(_pool, variantAsObject(_data)); } template inline typename enable_if::value, ArrayRef>::type VariantRef::to() const { return ArrayRef(_pool, variantToArray(_data)); } template typename enable_if::value, ObjectRef>::type VariantRef::to() const { return ObjectRef(_pool, variantToObject(_data)); } template typename enable_if::value, VariantRef>::type VariantRef::to() const { variantSetNull(_data); return *this; } inline VariantConstRef VariantConstRef::operator[](size_t index) const { return ArrayConstRef(_data != 0 ? _data->asArray() : 0)[index]; } inline VariantRef VariantRef::addElement() const { return VariantRef(_pool, variantAdd(_data, _pool)); } inline VariantRef VariantRef::getElement(size_t index) const { return VariantRef(_pool, _data != 0 ? _data->getElement(index) : 0); } template inline VariantRef VariantRef::getMember(TChar *key) const { return VariantRef(_pool, _data != 0 ? _data->getMember(adaptString(key)) : 0); } template inline typename enable_if::value, VariantRef>::type VariantRef::getMember(const TString &key) const { return VariantRef(_pool, _data != 0 ? _data->getMember(adaptString(key)) : 0); } template inline VariantRef VariantRef::getOrAddMember(TChar *key) const { return VariantRef(_pool, variantGetOrCreate(_data, key, _pool)); } template inline VariantRef VariantRef::getOrAddMember(const TString &key) const { return VariantRef(_pool, variantGetOrCreate(_data, key, _pool)); } } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { class StringBuilder { public: explicit StringBuilder(MemoryPool* parent) : _parent(parent), _size(0) { _slot = _parent->allocExpandableString(); } 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 (!_slot.value) return; if (_size >= _slot.size) { _slot.value = 0; return; } _slot.value[_size++] = c; } char* complete() { append('\0'); if (_slot.value) { _parent->freezeString(_slot, _size); } return _slot.value; } private: MemoryPool* _parent; size_t _size; StringSlot _slot; }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { class StringCopier { public: typedef ARDUINOJSON_NAMESPACE::StringBuilder StringBuilder; StringCopier(MemoryPool* pool) : _pool(pool) {} StringBuilder startString() { return StringBuilder(_pool); } private: MemoryPool* _pool; }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { class StringMover { public: class StringBuilder { public: StringBuilder(char** ptr) : _writePtr(ptr), _startPtr(*ptr) {} void append(char c) { *(*_writePtr)++ = char(c); } char* complete() const { *(*_writePtr)++ = 0; return _startPtr; } private: char** _writePtr; char* _startPtr; }; StringMover(char* ptr) : _ptr(ptr) {} StringBuilder startString() { return StringBuilder(&_ptr); } private: char* _ptr; }; } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { template struct StringStorage { typedef StringCopier type; static type create(MemoryPool& pool, TInput&) { return type(&pool); } }; template struct StringStorage::value>::type> { typedef StringMover type; static type create(MemoryPool&, TChar* input) { return type(reinterpret_cast(input)); } }; template typename StringStorage::type makeStringStorage(MemoryPool& pool, TInput& input) { return StringStorage::create(pool, input); } template typename StringStorage::type makeStringStorage(MemoryPool& pool, TChar* input) { return StringStorage::create(pool, input); } } // namespace ARDUINOJSON_NAMESPACE #if ARDUINOJSON_ENABLE_ARDUINO_STREAM #include namespace ARDUINOJSON_NAMESPACE { struct ArduinoStreamReader { Stream& _stream; public: explicit ArduinoStreamReader(Stream& stream) : _stream(stream) {} int read() { uint8_t c; return _stream.readBytes(&c, 1) ? c : -1; } }; inline ArduinoStreamReader makeReader(Stream& input) { return ArduinoStreamReader(input); } } // namespace ARDUINOJSON_NAMESPACE #endif namespace ARDUINOJSON_NAMESPACE { template struct IsCharOrVoid { static const bool value = is_same::value || is_same::value || is_same::value || is_same::value; }; template struct IsCharOrVoid : IsCharOrVoid {}; class UnsafeCharPointerReader { const char* _ptr; public: explicit UnsafeCharPointerReader(const char* ptr) : _ptr(ptr ? ptr : reinterpret_cast("")) {} int read() { return static_cast(*_ptr++); } }; class SafeCharPointerReader { const char* _ptr; const char* _end; public: explicit SafeCharPointerReader(const char* ptr, size_t len) : _ptr(ptr ? ptr : reinterpret_cast("")), _end(_ptr + len) {} int read() { if (_ptr < _end) return static_cast(*_ptr++); else return -1; } }; template inline typename enable_if::value, UnsafeCharPointerReader>::type makeReader(TChar* input) { return UnsafeCharPointerReader(reinterpret_cast(input)); } template inline typename enable_if::value, SafeCharPointerReader>::type makeReader(TChar* input, size_t n) { return SafeCharPointerReader(reinterpret_cast(input), n); } #if ARDUINOJSON_ENABLE_ARDUINO_STRING inline SafeCharPointerReader makeReader(const ::String& input) { return SafeCharPointerReader(input.c_str(), input.length()); } #endif } // namespace ARDUINOJSON_NAMESPACE #if ARDUINOJSON_ENABLE_STD_STREAM #include #endif namespace ARDUINOJSON_NAMESPACE { class DeserializationError { typedef void (DeserializationError::*bool_type)() const; void safeBoolHelper() const {} public: enum Code { Ok, IncompleteInput, InvalidInput, NoMemory, NotSupported, TooDeep }; DeserializationError() {} DeserializationError(Code c) : _code(c) {} 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; } 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; } operator bool_type() const { return _code != Ok ? &DeserializationError::safeBoolHelper : 0; } friend bool operator==(bool value, const DeserializationError& err) { return static_cast(err) == value; } friend bool operator==(const DeserializationError& err, bool value) { return static_cast(err) == value; } friend bool operator!=(bool value, const DeserializationError& err) { return static_cast(err) != value; } friend bool operator!=(const DeserializationError& err, bool value) { return static_cast(err) != value; } Code code() const { return _code; } const char* c_str() const { switch (_code) { case Ok: return "Ok"; case TooDeep: return "TooDeep"; case NoMemory: return "NoMemory"; case InvalidInput: return "InvalidInput"; case IncompleteInput: return "IncompleteInput"; case NotSupported: return "NotSupported"; default: return "???"; } } 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 #if ARDUINOJSON_ENABLE_PROGMEM namespace ARDUINOJSON_NAMESPACE { class UnsafeFlashStringReader { const char* _ptr; public: explicit UnsafeFlashStringReader(const __FlashStringHelper* ptr) : _ptr(reinterpret_cast(ptr)) {} int read() { return pgm_read_byte_near(_ptr++); } }; class SafeFlashStringReader { const char* _ptr; const char* _end; public: explicit SafeFlashStringReader(const __FlashStringHelper* ptr, size_t size) : _ptr(reinterpret_cast(ptr)), _end(_ptr + size) {} int read() { if (_ptr < _end) return pgm_read_byte_near(_ptr++); else return -1; } }; inline UnsafeFlashStringReader makeReader(const __FlashStringHelper* input) { return UnsafeFlashStringReader(input); } inline SafeFlashStringReader makeReader(const __FlashStringHelper* input, size_t size) { return SafeFlashStringReader(input, size); } } // namespace ARDUINOJSON_NAMESPACE #endif namespace ARDUINOJSON_NAMESPACE { template class IteratorReader { TIterator _ptr, _end; public: explicit IteratorReader(TIterator begin, TIterator end) : _ptr(begin), _end(end) {} int read() { if (_ptr < _end) return static_cast(*_ptr++); else return -1; } }; template inline IteratorReader makeReader( const TInput& input) { return IteratorReader(input.begin(), input.end()); } } // namespace ARDUINOJSON_NAMESPACE namespace ARDUINOJSON_NAMESPACE { struct NestingLimit { NestingLimit() : value(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {} explicit NestingLimit(uint8_t n) : value(n) {} uint8_t value; }; } // namespace ARDUINOJSON_NAMESPACE #if ARDUINOJSON_ENABLE_STD_STREAM #include namespace ARDUINOJSON_NAMESPACE { class StdStreamReader { std::istream& _stream; char _current; public: explicit StdStreamReader(std::istream& stream) : _stream(stream), _current(0) {} int read() { return _stream.get(); } private: StdStreamReader& operator=(const StdStreamReader&); // Visual Studio C4512 }; inline StdStreamReader makeReader(std::istream& input) { return StdStreamReader(input); } } // namespace ARDUINOJSON_NAMESPACE #endif namespace ARDUINOJSON_NAMESPACE { template