diff --git a/.travis.yml b/.travis.yml index 7c9131df..43ac52a4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,8 +8,8 @@ addons: packages: - g++-4.8 env: -- ARDUINO_VERSION=1.6.9 ARDUINO_ESP8266_VERSION=2.3.0 LIB_NEOPIXEL_VERSION=v1.0.5 LIB_GFX_VERSION=v1.1.5 LIB_SSD1306_VERSION=1.1.0 LIB_JSON_VERSION=v5.11.2 ARDUINO_ROOT=${HOME}/arduino-${ARDUINO_VERSION} ARDUINO_ESP8266_ROOT=${ARDUINO_ROOT}/hardware/esp8266com/esp8266 ARDUINO_HOME=${HOME}/Arduino -- ARDUINO_VERSION=nightly ARDUINO_ESP8266_VERSION=master LIB_NEOPIXEL_VERSION=master LIB_GFX_VERSION=master LIB_SSD1306_VERSION=master LIB_JSON_VERSION=master ARDUINO_ROOT=${HOME}/arduino-${ARDUINO_VERSION} ARDUINO_ESP8266_ROOT=${ARDUINO_ROOT}/hardware/esp8266com/esp8266 ARDUINO_HOME=${HOME}/Arduino +- ARDUINO_VERSION=1.6.9 ARDUINO_ESP8266_VERSION=2.3.0 LIB_NEOPIXEL_VERSION=v1.0.5 LIB_GFX_VERSION=v1.1.5 LIB_SSD1306_VERSION=1.1.0 ARDUINO_ROOT=${HOME}/arduino-${ARDUINO_VERSION} ARDUINO_ESP8266_ROOT=${ARDUINO_ROOT}/hardware/esp8266com/esp8266 ARDUINO_HOME=${HOME}/Arduino +- ARDUINO_VERSION=nightly ARDUINO_ESP8266_VERSION=master LIB_NEOPIXEL_VERSION=master LIB_GFX_VERSION=master LIB_SSD1306_VERSION=master ARDUINO_ROOT=${HOME}/arduino-${ARDUINO_VERSION} ARDUINO_ESP8266_ROOT=${ARDUINO_ROOT}/hardware/esp8266com/esp8266 ARDUINO_HOME=${HOME}/Arduino install: - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi - ( cd ${HOME} && wget https://downloads.arduino.cc/arduino-${ARDUINO_VERSION}-linux64.tar.xz && tar xf arduino-${ARDUINO_VERSION}-linux64.tar.xz ) @@ -17,13 +17,12 @@ install: - ( LIB=Adafruit_NeoPixel VERSION=${LIB_NEOPIXEL_VERSION} && cd ${HOME} && wget https://github.com/adafruit/${LIB}/archive/${VERSION}.zip -q -O ${LIB}.zip && unzip -q ${LIB}.zip && rm ${LIB}.zip && mv ${LIB}-* ${LIB} ) - ( LIB=Adafruit-GFX-Library VERSION=${LIB_GFX_VERSION} && cd ${HOME} && wget https://github.com/adafruit/${LIB}/archive/${VERSION}.zip -q -O ${LIB}.zip && unzip -q ${LIB}.zip && rm ${LIB}.zip && mv ${LIB}-* ${LIB} ) - ( LIB=Adafruit_SSD1306 VERSION=${LIB_SSD1306_VERSION} && cd ${HOME} && wget https://github.com/adafruit/${LIB}/archive/${VERSION}.zip -q -O ${LIB}.zip && unzip -q ${LIB}.zip && rm ${LIB}.zip && mv ${LIB}-* ${LIB} ) -- ( LIB=ArduinoJson VERSION=${LIB_JSON_VERSION} && cd ${HOME} && wget https://github.com/bblanchon/${LIB}/archive/${VERSION}.zip -q -O ${LIB}.zip && unzip -q ${LIB}.zip && rm ${LIB}.zip && mv ${LIB}-* ${LIB} ) - git clone --branch ${ARDUINO_ESP8266_VERSION} https://github.com/esp8266/Arduino.git ${ARDUINO_ESP8266_ROOT} - git submodule init && git submodule update - ( cd ${ARDUINO_ESP8266_ROOT}/tools && python get.py ) before_script: - mkdir -p ${ARDUINO_HOME}/libraries -- ( cd ${ARDUINO_HOME}/libraries && ln -s ${TRAVIS_BUILD_DIR} firebase-arduino && ln -s ${HOME}/SoftwareSerial ./ && ln -s ${HOME}/Adafruit_NeoPixel ./ && ln -s ${HOME}/Adafruit-GFX-Library ./ && ln -s ${HOME}/Adafruit_SSD1306 ./ && ln -s ${HOME}/ArduinoJson ./) +- ( cd ${ARDUINO_HOME}/libraries && ln -s ${TRAVIS_BUILD_DIR} firebase-arduino && ln -s ${HOME}/SoftwareSerial ./ && ln -s ${HOME}/Adafruit_NeoPixel ./ && ln -s ${HOME}/Adafruit-GFX-Library ./ && ln -s ${HOME}/Adafruit_SSD1306 ./) script: - ${ARDUINO_ROOT}/arduino-builder -verbose -hardware ${ARDUINO_ROOT}/hardware/ -tools ${ARDUINO_ESP8266_ROOT}/tools/ -tools ${ARDUINO_ROOT}/tools-builder/ -fqbn esp8266com:esp8266:nodemcuv2 -libraries ${ARDUINO_HOME}/libraries/ -prefs build.flash_ld=${ARDUINO_ESP8266_ROOT}/tools/sdk/ld/eagle.flash.4m.ld -prefs build.flash_freq=40 -prefs build.flash_size=4M -prefs build.f_cpu=80000000 examples/FirebaseDemo_ESP8266/FirebaseDemo_ESP8266.ino - ${ARDUINO_ROOT}/arduino-builder -verbose -hardware ${ARDUINO_ROOT}/hardware/ -tools ${ARDUINO_ESP8266_ROOT}/tools/ -tools ${ARDUINO_ROOT}/tools-builder/ -fqbn esp8266com:esp8266:nodemcuv2 -libraries ${ARDUINO_HOME}/libraries/ -prefs build.flash_ld=${ARDUINO_ESP8266_ROOT}/tools/sdk/ld/eagle.flash.4m.ld -prefs build.flash_freq=40 -prefs build.flash_size=4M -prefs build.f_cpu=80000000 examples/FirebaseNeoPixel_ESP8266/FirebaseNeoPixel_ESP8266.ino diff --git a/README.md b/README.md index 62836a1f..944a0070 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,6 @@ If you maintain a fork of this repository that you believe is healthier than the - [FirebaseArduino API Reference](http://firebase-arduino.readthedocs.io/) ## Dependencies -- FirebaseArduino now depends on [ArduinoJson library](https://github.com/bblanchon/ArduinoJson) instead of containing it's own version of it. Please either use Library Manager or download specific version of the library from github. We recommend that ArduinoJson is at least version [5.13.1](https://github.com/bblanchon/ArduinoJson/tree/v5.13.1) - ESP8266 Core SDK. We recommend using officially tagged releases and it should be at least [2.4.1](https://github.com/esp8266/Arduino/tree/2.4.1) diff --git a/README.rst b/README.rst index 3b34df98..632e8000 100644 --- a/README.rst +++ b/README.rst @@ -4,8 +4,4 @@ arduino clients. It is a full abstraction of Firebase's REST API exposed through C++ calls in a wiring friendly way. -ArduinoJson is no longer part of this library and you will have to install latest version -in Arduino environment yourself. (through Board manager or download+unpack from master: -https://github.com/bblanchon/ArduinoJson) - ---------------------------------- diff --git a/contrib/src/thing/Config.cpp b/contrib/src/thing/Config.cpp index 133c527a..8109822f 100644 --- a/contrib/src/thing/Config.cpp +++ b/contrib/src/thing/Config.cpp @@ -1,6 +1,6 @@ #include "Arduino.h" #include "thing/Config.h" -#include +#include "ArduinoJson-v5.13.5.h" namespace thing { diff --git a/contrib/src/thing/Config.h b/contrib/src/thing/Config.h index 0cabf61c..8d8cb685 100644 --- a/contrib/src/thing/Config.h +++ b/contrib/src/thing/Config.h @@ -4,7 +4,7 @@ #include "Arduino.h" #include #include -#include +#include "ArduinoJson-v5.13.5.h" namespace thing { diff --git a/contrib/src/thing/Portal.cpp b/contrib/src/thing/Portal.cpp index 5a105a79..f396a22d 100644 --- a/contrib/src/thing/Portal.cpp +++ b/contrib/src/thing/Portal.cpp @@ -1,5 +1,5 @@ #include "thing/Portal.h" -#include +#include "ArduinoJson-v5.13.5.h" namespace thing { diff --git a/contrib/test/Makefile b/contrib/test/Makefile index f9063cb6..b80e5e45 100644 --- a/contrib/test/Makefile +++ b/contrib/test/Makefile @@ -16,7 +16,6 @@ FIREBASE_DIR=../.. GTEST_DIR=googletest/googletest -ARDUINOJSON_DIR=${ARDUINO_HOME}/libraries/ArduinoJson FIREBASE_SRCS=${FIREBASE_DIR}/src/FirebaseObject.cpp GTEST_SRCS=${GTEST_DIR}/src/gtest-all.cpp @@ -27,7 +26,7 @@ SRCS=FirebaseArduino_test.cpp\ OBJS=${SRCS:.cpp=.o} -CXXFLAGS=-I. -I${FIREBASE_DIR}/src -I${ARDUINOJSON_DIR}/src -Igoogletest/googletest/include -Igoogletest/googletest -std=c++11 -g +CXXFLAGS=-I. -I${FIREBASE_DIR}/src -Igoogletest/googletest/include -Igoogletest/googletest -std=c++11 -g LDFLAGS=-lpthread all: check diff --git a/contrib/test/modem/Makefile b/contrib/test/modem/Makefile index bda22d32..4cedc9f5 100644 --- a/contrib/test/modem/Makefile +++ b/contrib/test/modem/Makefile @@ -34,7 +34,6 @@ FIREBASE_ROOT = ../../.. PROJECT_ROOT = ../.. SRC_ROOT = $(PROJECT_ROOT)/src FIREBASE_SRC_ROOT = $(FIREBASE_ROOT)/src -ARDUINOJSON_DIR=$(ARDUINO_HOME)/libraries/ArduinoJson # Flags passed to the preprocessor. # Set Google Test and Google Mock's header directories as system @@ -46,7 +45,6 @@ CPPFLAGS += -isystem $(GTEST_DIR)/include -isystem $(GMOCK_DIR)/include \ -I$(PROJECT_ROOT)/test/dummies \ -I$(PROJECT_ROOT)/src \ -I$(FIREBASE_ROOT)/src \ - -I$(ARDUINOJSON_DIR)/src \ -I$(PROJECT_ROOT) # Flags passed to the C++ compiler. diff --git a/src/ArduinoJson-v5.13.5.h b/src/ArduinoJson-v5.13.5.h new file mode 100644 index 00000000..1728af0c --- /dev/null +++ b/src/ArduinoJson-v5.13.5.h @@ -0,0 +1,3429 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2019 +// MIT License + +#pragma once + +#ifdef __cplusplus + +#define ARDUINOJSON_VERSION "5.13.5" +#define ARDUINOJSON_VERSION_MAJOR 5 +#define ARDUINOJSON_VERSION_MINOR 13 +#define ARDUINOJSON_VERSION_REVISION 5 +#include // for size_t +#include // for uint8_t +#include +namespace ArduinoJson { +namespace Internals { +class NonCopyable { + protected: + NonCopyable() {} + private: + NonCopyable(const NonCopyable&); + NonCopyable& operator=(const NonCopyable&); +}; +} // namespace Internals +} // namespace ArduinoJson +#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_USE_INT64 +#define ARDUINOJSON_USE_INT64 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 __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800) +#define ARDUINOJSON_USE_LONG_LONG 1 +#else +#define ARDUINOJSON_USE_LONG_LONG 0 +#endif +#endif +#ifndef ARDUINOJSON_USE_INT64 +#if defined(_MSC_VER) && _MSC_VER <= 1700 +#define ARDUINOJSON_USE_INT64 1 +#else +#define ARDUINOJSON_USE_INT64 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 +#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 +#endif // ARDUINO +#ifndef ARDUINOJSON_ENABLE_PROGMEM +#ifdef PROGMEM +#define ARDUINOJSON_ENABLE_PROGMEM 1 +#else +#define ARDUINOJSON_ENABLE_PROGMEM 0 +#endif +#endif +#ifndef ARDUINOJSON_ENABLE_ALIGNMENT +#ifdef ARDUINO_ARCH_AVR +#define ARDUINOJSON_ENABLE_ALIGNMENT 0 +#else +#define ARDUINOJSON_ENABLE_ALIGNMENT 1 +#endif +#endif +#ifndef ARDUINOJSON_ENABLE_DEPRECATED +#define ARDUINOJSON_ENABLE_DEPRECATED 1 +#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 +#if ARDUINOJSON_USE_LONG_LONG && ARDUINOJSON_USE_INT64 +#error ARDUINOJSON_USE_LONG_LONG and ARDUINOJSON_USE_INT64 cannot be set together +#endif +namespace ArduinoJson { +namespace Internals { +#if ARDUINOJSON_USE_DOUBLE +typedef double JsonFloat; +#else +typedef float JsonFloat; +#endif +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +#if ARDUINOJSON_USE_LONG_LONG +typedef long long JsonInteger; +typedef unsigned long long JsonUInt; +#elif ARDUINOJSON_USE_INT64 +typedef __int64 JsonInteger; +typedef unsigned _int64 JsonUInt; +#else +typedef long JsonInteger; +typedef unsigned long JsonUInt; +#endif +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +class JsonArray; +class JsonObject; +namespace Internals { +union JsonVariantContent { + JsonFloat asFloat; // used for double and float + JsonUInt asInteger; // used for bool, char, short, int and longs + const char* asString; // asString can be null + JsonArray* asArray; // asArray cannot be null + JsonObject* asObject; // asObject cannot be null +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +struct JsonVariantDefault { + static T get() { + return T(); + } +}; +template +struct JsonVariantDefault : JsonVariantDefault {}; +template +struct JsonVariantDefault : JsonVariantDefault {}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +class JsonArray; +class JsonObject; +namespace Internals { +enum JsonVariantType { + JSON_UNDEFINED, // JsonVariant has not been initialized + JSON_UNPARSED, // JsonVariant contains an unparsed string + JSON_STRING, // JsonVariant stores a const char* + JSON_BOOLEAN, // JsonVariant stores a bool + JSON_POSITIVE_INTEGER, // JsonVariant stores an JsonUInt + JSON_NEGATIVE_INTEGER, // JsonVariant stores an JsonUInt that must be negated + JSON_ARRAY, // JsonVariant stores a pointer to a JsonArray + JSON_OBJECT, // JsonVariant stores a pointer to a JsonObject + JSON_FLOAT // JsonVariant stores a JsonFloat +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +struct JsonVariantAs { + typedef T type; +}; +template <> +struct JsonVariantAs { + typedef const char* type; +}; +template <> +struct JsonVariantAs { + typedef JsonArray& type; +}; +template <> +struct JsonVariantAs { + typedef const JsonArray& type; +}; +template <> +struct JsonVariantAs { + typedef JsonObject& type; +}; +template <> +struct JsonVariantAs { + typedef const JsonObject& type; +}; +} // namespace Internals +} // namespace ArduinoJson +#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 +namespace ArduinoJson { +namespace Internals { +template +class JsonVariantCasts { + public: +#if ARDUINOJSON_ENABLE_DEPRECATED + DEPRECATED("use as() instead") + FORCE_INLINE JsonArray &asArray() const { + return impl()->template as(); + } + DEPRECATED("use as() instead") + FORCE_INLINE JsonObject &asObject() const { + return impl()->template as(); + } + DEPRECATED("use as() instead") + FORCE_INLINE const char *asString() const { + return impl()->template as(); + } +#endif + FORCE_INLINE operator JsonArray &() const { + return impl()->template as(); + } + FORCE_INLINE operator JsonObject &() const { + return impl()->template as(); + } + template + FORCE_INLINE operator T() const { + return impl()->template as(); + } + private: + const TImpl *impl() const { + return static_cast(this); + } +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +struct EnableIf {}; +template +struct EnableIf { + typedef T type; +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +class IsBaseOf { + 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: + enum { + value = sizeof(probe(reinterpret_cast(0))) == sizeof(Yes) + }; +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +struct IsSame { + static const bool value = false; +}; +template +struct IsSame { + static const bool value = true; +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +struct IsChar { + static const bool value = IsSame::value || + IsSame::value || + IsSame::value; +}; +template +struct IsChar : IsChar {}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +struct IsConst { + static const bool value = false; +}; +template +struct IsConst { + static const bool value = true; +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +struct RemoveReference { + typedef T type; +}; +template +struct RemoveReference { + typedef T type; +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +struct StringTraits { + static const bool has_append = false; + static const bool has_equals = false; +}; +template +struct StringTraits : StringTraits {}; +template +struct StringTraits : StringTraits {}; +} // namespace Internals +} // namespace ArduinoJson +#if ARDUINOJSON_ENABLE_ARDUINO_STREAM +#include +namespace ArduinoJson { +namespace Internals { +struct ArduinoStreamTraits { + class Reader { + Stream& _stream; + char _current, _next; + public: + Reader(Stream& stream) : _stream(stream), _current(0), _next(0) {} + void move() { + _current = _next; + _next = 0; + } + char current() { + if (!_current) _current = read(); + return _current; + } + char next() { + if (!_next) _next = read(); + return _next; + } + private: + char read() { + char c = 0; + _stream.readBytes(&c, 1); + return c; + } + }; + static const bool has_append = false; + static const bool has_equals = false; +}; +template +struct StringTraits< + TStream, + typename EnableIf< + IsBaseOf::type>::value>::type> + : ArduinoStreamTraits {}; +} // namespace Internals +} // namespace ArduinoJson +#endif +namespace ArduinoJson { +namespace Internals { +template +struct CharPointerTraits { + class Reader { + const TChar* _ptr; + public: + Reader(const TChar* ptr) + : _ptr(ptr ? ptr : reinterpret_cast("")) {} + void move() { + ++_ptr; + } + char current() const { + return char(_ptr[0]); + } + char next() const { + return char(_ptr[1]); + } + }; + static bool equals(const TChar* str, const char* expected) { + const char* actual = reinterpret_cast(str); + if (!actual || !expected) return actual == expected; + return strcmp(actual, expected) == 0; + } + static bool is_null(const TChar* str) { + return !str; + } + typedef const char* duplicate_t; + template + static duplicate_t duplicate(const TChar* str, Buffer* buffer) { + if (!str) return NULL; + size_t size = strlen(reinterpret_cast(str)) + 1; + void* dup = buffer->alloc(size); + if (dup != NULL) memcpy(dup, str, size); + return static_cast(dup); + } + static const bool has_append = false; + static const bool has_equals = true; + static const bool should_duplicate = !IsConst::value; +}; +template +struct StringTraits::value>::type> + : CharPointerTraits {}; +} // namespace Internals +} // namespace ArduinoJson +#if ARDUINOJSON_ENABLE_PROGMEM +namespace ArduinoJson { +namespace Internals { +template <> +struct StringTraits { + class Reader { + const char* _ptr; + public: + Reader(const __FlashStringHelper* ptr) + : _ptr(reinterpret_cast(ptr)) {} + void move() { + _ptr++; + } + char current() const { + return pgm_read_byte_near(_ptr); + } + char next() const { + return pgm_read_byte_near(_ptr + 1); + } + }; + static bool equals(const __FlashStringHelper* str, const char* expected) { + const char* actual = reinterpret_cast(str); + if (!actual || !expected) return actual == expected; + return strcmp_P(expected, actual) == 0; + } + static bool is_null(const __FlashStringHelper* str) { + return !str; + } + typedef const char* duplicate_t; + template + static duplicate_t duplicate(const __FlashStringHelper* str, Buffer* buffer) { + if (!str) return NULL; + size_t size = strlen_P((const char*)str) + 1; + void* dup = buffer->alloc(size); + if (dup != NULL) memcpy_P(dup, (const char*)str, size); + return static_cast(dup); + } + static const bool has_append = false; + static const bool has_equals = true; + static const bool should_duplicate = true; +}; +} // namespace Internals +} // namespace ArduinoJson +#endif +#if ARDUINOJSON_ENABLE_STD_STREAM +#include +namespace ArduinoJson { +namespace Internals { +struct StdStreamTraits { + class Reader { + std::istream& _stream; + char _current, _next; + public: + Reader(std::istream& stream) : _stream(stream), _current(0), _next(0) {} + void move() { + _current = _next; + _next = 0; + } + char current() { + if (!_current) _current = read(); + return _current; + } + char next() { + if (!_next) _next = read(); + return _next; + } + private: + Reader& operator=(const Reader&); // Visual Studio C4512 + char read() { + return _stream.eof() ? '\0' : static_cast(_stream.get()); + } + }; + static const bool has_append = false; + static const bool has_equals = false; +}; +template +struct StringTraits< + TStream, + typename EnableIf::type>::value>::type> + : StdStreamTraits {}; +} // namespace Internals +} // namespace ArduinoJson +#endif +#if ARDUINOJSON_ENABLE_STD_STRING || ARDUINOJSON_ENABLE_ARDUINO_STRING +#if ARDUINOJSON_ENABLE_ARDUINO_STRING +#include +#endif +#if ARDUINOJSON_ENABLE_STD_STRING +#include +#endif +namespace ArduinoJson { +namespace Internals { +template +struct StdStringTraits { + typedef const char* duplicate_t; + template + static duplicate_t duplicate(const TString& str, Buffer* buffer) { + if (!str.c_str()) return NULL; // <- Arduino string can return NULL + size_t size = str.length() + 1; + void* dup = buffer->alloc(size); + if (dup != NULL) memcpy(dup, str.c_str(), size); + return static_cast(dup); + } + static bool is_null(const TString& str) { + return !str.c_str(); + } + struct Reader : CharPointerTraits::Reader { + Reader(const TString& str) : CharPointerTraits::Reader(str.c_str()) {} + }; + static bool equals(const TString& str, const char* expected) { + const char* actual = str.c_str(); + if (!actual || !expected) return actual == expected; + return 0 == strcmp(actual, expected); + } + static void append(TString& str, char c) { + str += c; + } + static void append(TString& str, const char* s) { + str += s; + } + static const bool has_append = true; + static const bool has_equals = true; + static const bool should_duplicate = true; +}; +#if ARDUINOJSON_ENABLE_ARDUINO_STRING +template <> +struct StringTraits : StdStringTraits {}; +template <> +struct StringTraits : StdStringTraits { +}; +#endif +#if ARDUINOJSON_ENABLE_STD_STRING +template <> +struct StringTraits : StdStringTraits {}; +#endif +} // namespace Internals +} // namespace ArduinoJson +#endif +namespace ArduinoJson { +namespace Internals { +class JsonVariantTag {}; +template +struct IsVariant : IsBaseOf {}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +class JsonVariantComparisons { + public: + template + friend bool operator==(const JsonVariantComparisons &variant, + TComparand comparand) { + return variant.equals(comparand); + } + template + friend typename EnableIf::value, bool>::type + operator==(TComparand comparand, const JsonVariantComparisons &variant) { + return variant.equals(comparand); + } + template + friend bool operator!=(const JsonVariantComparisons &variant, + TComparand comparand) { + return !variant.equals(comparand); + } + template + friend typename EnableIf::value, bool>::type + operator!=(TComparand comparand, const JsonVariantComparisons &variant) { + return !variant.equals(comparand); + } + template + friend bool operator<=(const JsonVariantComparisons &left, TComparand right) { + return left.as() <= right; + } + template + friend bool operator<=(TComparand comparand, + const JsonVariantComparisons &variant) { + return comparand <= variant.as(); + } + template + friend bool operator>=(const JsonVariantComparisons &variant, + TComparand comparand) { + return variant.as() >= comparand; + } + template + friend bool operator>=(TComparand comparand, + const JsonVariantComparisons &variant) { + return comparand >= variant.as(); + } + template + friend bool operator<(const JsonVariantComparisons &varian, + TComparand comparand) { + return varian.as() < comparand; + } + template + friend bool operator<(TComparand comparand, + const JsonVariantComparisons &variant) { + return comparand < variant.as(); + } + template + friend bool operator>(const JsonVariantComparisons &variant, + TComparand comparand) { + return variant.as() > comparand; + } + template + friend bool operator>(TComparand comparand, + const JsonVariantComparisons &variant) { + return comparand > variant.as(); + } + private: + const TImpl *impl() const { + return static_cast(this); + } + template + const typename JsonVariantAs::type as() const { + return impl()->template as(); + } + template + bool is() const { + return impl()->template is(); + } + template + typename EnableIf::has_equals, bool>::type equals( + const TString &comparand) const { + const char *value = as(); + return StringTraits::equals(comparand, value); + } + template + typename EnableIf::value && + !StringTraits::has_equals, + bool>::type + equals(const TComparand &comparand) const { + return as() == comparand; + } + template + bool equals(const JsonVariantComparisons &right) const { + using namespace Internals; + if (is() && right.template is()) + return as() == right.template as(); + if (is() && right.template is()) + return as() == right.template as(); + if (is() && right.template is()) + return as() == right.template as(); + if (is() && right.template is()) + return as() == right.template as(); + if (is() && right.template is()) + return as() == right.template as(); + if (is() && right.template is()) + return StringTraits::equals(as(), + right.template as()); + return false; + } +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +struct IsSignedIntegral { + static const bool value = + IsSame::value || IsSame::value || + IsSame::value || IsSame::value || +#if ARDUINOJSON_USE_LONG_LONG + IsSame::value || +#endif +#if ARDUINOJSON_USE_INT64 + IsSame::value || +#endif + false; +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +struct IsUnsignedIntegral { + static const bool value = + IsSame::value || IsSame::value || + IsSame::value || IsSame::value || +#if ARDUINOJSON_USE_LONG_LONG + IsSame::value || +#endif +#if ARDUINOJSON_USE_INT64 + IsSame::value || +#endif + false; +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +struct IsIntegral { + static const bool value = IsSignedIntegral::value || + IsUnsignedIntegral::value || + IsSame::value; +}; +template +struct IsIntegral : IsIntegral {}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +class JsonVariantOr { + public: + template + typename EnableIf::value, T>::type 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; + } + template + typename EnableIf::value, Integer>::type operator|( + const Integer &defaultValue) const { + if (impl()->template is()) + return impl()->template as(); + else + return defaultValue; + } + private: + const TImpl *impl() const { + return static_cast(this); + } +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +class JsonArraySubscript; +template +class JsonObjectSubscript; +template +class JsonVariantSubscripts { + public: + size_t size() const { + return impl()->template as().size() + + impl()->template as().size(); + } + FORCE_INLINE const JsonArraySubscript operator[](size_t index) const; + FORCE_INLINE JsonArraySubscript operator[](size_t index); + template + FORCE_INLINE + typename EnableIf::has_equals, + const JsonObjectSubscript >::type + operator[](const TString &key) const { + return impl()->template as()[key]; + } + template + FORCE_INLINE typename EnableIf::has_equals, + JsonObjectSubscript >::type + operator[](const TString &key) { + return impl()->template as()[key]; + } + template + FORCE_INLINE typename EnableIf::has_equals, + JsonObjectSubscript >::type + operator[](const TString *key) { + return impl()->template as()[key]; + } + template + FORCE_INLINE + typename EnableIf::has_equals, + const JsonObjectSubscript >::type + operator[](const TString *key) const { + return impl()->template as()[key]; + } + private: + const TImpl *impl() const { + return static_cast(this); + } +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +class DummyPrint { + public: + size_t print(char) { + return 1; + } + size_t print(const char* s) { + return strlen(s); + } +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +class DynamicStringBuilder { + public: + DynamicStringBuilder(TString &str) : _str(str) {} + size_t print(char c) { + StringTraits::append(_str, c); + return 1; + } + size_t print(const char *s) { + size_t initialLen = _str.length(); + StringTraits::append(_str, s); + return _str.length() - initialLen; + } + private: + DynamicStringBuilder &operator=(const DynamicStringBuilder &); + TString &_str; +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +class IndentedPrint { + public: + explicit IndentedPrint(Print &p) : sink(&p) { + level = 0; + tabSize = 2; + isNewLine = true; + } + size_t print(char c) { + size_t n = 0; + if (isNewLine) n += writeTabs(); + n += sink->print(c); + isNewLine = c == '\n'; + return n; + } + size_t print(const char *s) { + size_t n = 0; + while (*s) n += print(*s++); + return n; + } + void indent() { + if (level < MAX_LEVEL) level++; + } + void unindent() { + if (level > 0) level--; + } + void setTabSize(uint8_t n) { + if (n < MAX_TAB_SIZE) tabSize = n & MAX_TAB_SIZE; + } + private: + Print *sink; + uint8_t level : 4; + uint8_t tabSize : 3; + bool isNewLine : 1; + size_t writeTabs() { + size_t n = 0; + for (int i = 0; i < level * tabSize; i++) n += sink->print(' '); + return n; + } + static const int MAX_LEVEL = 15; // because it's only 4 bits + static const int MAX_TAB_SIZE = 7; // because it's only 3 bits +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +class Encoding { + public: + static char escapeChar(char c) { + const char *p = escapeTable(false); + while (p[0] && p[1] != c) { + p += 2; + } + return p[0]; + } + static char unescapeChar(char c) { + const char *p = escapeTable(true); + for (;;) { + if (p[0] == '\0') return c; + if (p[0] == c) return p[1]; + p += 2; + } + } + private: + static const char *escapeTable(bool excludeIdenticals) { + return &"\"\"\\\\b\bf\fn\nr\rt\t"[excludeIdenticals ? 4 : 0]; + } +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +bool isNaN(T x) { + return x != x; +} +template +bool isInfinity(T x) { + return x != 0.0 && x * 2 == x; +} +} // namespace Internals +} // namespace ArduinoJson +#include // for size_t +namespace ArduinoJson { +namespace Internals { +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 Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +struct FloatTraits {}; +template +struct FloatTraits { + typedef int64_t mantissa_type; + static const short mantissa_bits = 52; + static const mantissa_type mantissa_max = + (static_cast(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 forge(uint32_t msb, uint32_t lsb) { + return alias_cast((uint64_t(msb) << 32) | lsb); + } +}; +template +struct FloatTraits { + typedef int32_t mantissa_type; + static const short mantissa_bits = 23; + static const mantissa_type mantissa_max = + (static_cast(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); + } +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +struct FloatParts { + uint32_t integral; + uint32_t decimal; + int16_t exponent; + int8_t decimalPlaces; + FloatParts(TFloat value) { + uint32_t maxDecimalPart = sizeof(TFloat) >= 8 ? 1000000000 : 1000000; + decimalPlaces = sizeof(TFloat) >= 8 ? 9 : 6; + exponent = normalize(value); + integral = uint32_t(value); + for (uint32_t tmp = integral; tmp >= 10; tmp /= 10) { + maxDecimalPart /= 10; + decimalPlaces--; + } + TFloat remainder = (value - TFloat(integral)) * TFloat(maxDecimalPart); + decimal = uint32_t(remainder); + remainder = remainder - TFloat(decimal); + decimal += uint32_t(remainder * 2); + if (decimal >= maxDecimalPart) { + decimal = 0; + integral++; + if (exponent && integral >= 10) { + exponent++; + integral = 1; + } + } + while (decimal % 10 == 0 && decimalPlaces > 0) { + decimal /= 10; + decimalPlaces--; + } + } + static int16_t normalize(TFloat& value) { + typedef FloatTraits traits; + int16_t powersOf10 = 0; + int8_t index = sizeof(TFloat) == 8 ? 8 : 5; + int bit = 1 << index; + if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) { + for (; index >= 0; index--) { + if (value >= traits::positiveBinaryPowerOfTen(index)) { + value *= traits::negativeBinaryPowerOfTen(index); + powersOf10 = int16_t(powersOf10 + bit); + } + bit >>= 1; + } + } + if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) { + for (; index >= 0; index--) { + if (value < traits::negativeBinaryPowerOfTenPlusOne(index)) { + value *= traits::positiveBinaryPowerOfTen(index); + powersOf10 = int16_t(powersOf10 - bit); + } + bit >>= 1; + } + } + return powersOf10; + } +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +class JsonWriter { + public: + explicit JsonWriter(Print &sink) : _sink(sink), _length(0) {} + size_t bytesWritten() const { + return _length; + } + void beginArray() { + writeRaw('['); + } + void endArray() { + writeRaw(']'); + } + void beginObject() { + writeRaw('{'); + } + void endObject() { + writeRaw('}'); + } + void writeColon() { + writeRaw(':'); + } + void writeComma() { + writeRaw(','); + } + void writeBoolean(bool value) { + writeRaw(value ? "true" : "false"); + } + void writeString(const char *value) { + if (!value) { + writeRaw("null"); + } else { + writeRaw('\"'); + while (*value) writeChar(*value++); + writeRaw('\"'); + } + } + void writeChar(char c) { + char specialChar = Encoding::escapeChar(c); + if (specialChar) { + writeRaw('\\'); + writeRaw(specialChar); + } else { + writeRaw(c); + } + } + template + void writeFloat(TFloat value) { + if (isNaN(value)) return writeRaw("NaN"); + if (value < 0.0) { + writeRaw('-'); + value = -value; + } + if (isInfinity(value)) return writeRaw("Infinity"); + FloatParts parts(value); + writeInteger(parts.integral); + if (parts.decimalPlaces) writeDecimals(parts.decimal, parts.decimalPlaces); + if (parts.exponent < 0) { + writeRaw("e-"); + writeInteger(-parts.exponent); + } + if (parts.exponent > 0) { + writeRaw('e'); + writeInteger(parts.exponent); + } + } + template + void writeInteger(UInt value) { + char buffer[22]; + char *end = buffer + sizeof(buffer) - 1; + char *ptr = end; + *ptr = 0; + do { + *--ptr = char(value % 10 + '0'); + value = UInt(value / 10); + } while (value); + writeRaw(ptr); + } + void writeDecimals(uint32_t value, int8_t width) { + char buffer[16]; + char *ptr = buffer + sizeof(buffer) - 1; + *ptr = 0; + while (width--) { + *--ptr = char(value % 10 + '0'); + value /= 10; + } + *--ptr = '.'; + writeRaw(ptr); + } + void writeRaw(const char *s) { + _length += _sink.print(s); + } + void writeRaw(char c) { + _length += _sink.print(c); + } + protected: + Print &_sink; + size_t _length; + private: + JsonWriter &operator=(const JsonWriter &); // cannot be assigned +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +class JsonArray; +class JsonObject; +class JsonVariant; +namespace Internals { +class JsonArraySubscript; +template +class JsonObjectSubscript; +template +class JsonSerializer { + public: + static void serialize(const JsonArray &, Writer &); + static void serialize(const JsonArraySubscript &, Writer &); + static void serialize(const JsonObject &, Writer &); + template + static void serialize(const JsonObjectSubscript &, Writer &); + static void serialize(const JsonVariant &, Writer &); +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +class Prettyfier { + public: + explicit Prettyfier(IndentedPrint& p) : _sink(p) { + _previousChar = 0; + _inString = false; + } + size_t print(char c) { + size_t n = _inString ? handleStringChar(c) : handleMarkupChar(c); + _previousChar = c; + return n; + } + size_t print(const char* s) { + size_t n = 0; + while (*s) n += print(*s++); + return n; + } + private: + Prettyfier& operator=(const Prettyfier&); // cannot be assigned + bool inEmptyBlock() { + return _previousChar == '{' || _previousChar == '['; + } + size_t handleStringChar(char c) { + bool isQuote = c == '"' && _previousChar != '\\'; + if (isQuote) _inString = false; + return _sink.print(c); + } + size_t handleMarkupChar(char c) { + switch (c) { + case '{': + case '[': + return writeBlockOpen(c); + case '}': + case ']': + return writeBlockClose(c); + case ':': + return writeColon(); + case ',': + return writeComma(); + case '"': + return writeQuoteOpen(); + default: + return writeNormalChar(c); + } + } + size_t writeBlockClose(char c) { + size_t n = 0; + n += unindentIfNeeded(); + n += _sink.print(c); + return n; + } + size_t writeBlockOpen(char c) { + size_t n = 0; + n += indentIfNeeded(); + n += _sink.print(c); + return n; + } + size_t writeColon() { + size_t n = 0; + n += _sink.print(": "); + return n; + } + size_t writeComma() { + size_t n = 0; + n += _sink.print(",\r\n"); + return n; + } + size_t writeQuoteOpen() { + _inString = true; + size_t n = 0; + n += indentIfNeeded(); + n += _sink.print('"'); + return n; + } + size_t writeNormalChar(char c) { + size_t n = 0; + n += indentIfNeeded(); + n += _sink.print(c); + return n; + } + size_t indentIfNeeded() { + if (!inEmptyBlock()) return 0; + _sink.indent(); + return _sink.print("\r\n"); + } + size_t unindentIfNeeded() { + if (inEmptyBlock()) return 0; + _sink.unindent(); + return _sink.print("\r\n"); + } + char _previousChar; + IndentedPrint& _sink; + bool _inString; +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +class StaticStringBuilder { + public: + StaticStringBuilder(char *buf, size_t size) : end(buf + size - 1), p(buf) { + *p = '\0'; + } + size_t print(char c) { + if (p >= end) return 0; + *p++ = c; + *p = '\0'; + return 1; + } + size_t print(const char *s) { + char *begin = p; + while (p < end && *s) *p++ = *s++; + *p = '\0'; + return size_t(p - begin); + } + private: + char *end; + char *p; +}; +} // namespace Internals +} // namespace ArduinoJson +#if ARDUINOJSON_ENABLE_STD_STREAM +#if ARDUINOJSON_ENABLE_STD_STREAM +#include +namespace ArduinoJson { +namespace Internals { +class StreamPrintAdapter { + public: + explicit StreamPrintAdapter(std::ostream& os) : _os(os) {} + size_t print(char c) { + _os << c; + return 1; + } + size_t print(const char* s) { + _os << s; + return strlen(s); + } + private: + StreamPrintAdapter& operator=(const StreamPrintAdapter&); + std::ostream& _os; +}; +} // namespace Internals +} // namespace ArduinoJson +#endif // ARDUINOJSON_ENABLE_STD_STREAM +#endif +namespace ArduinoJson { +namespace Internals { +template +class JsonPrintable { + public: + template + typename EnableIf::has_append, size_t>::type printTo( + Print &print) const { + JsonWriter writer(print); + JsonSerializer >::serialize(downcast(), writer); + return writer.bytesWritten(); + } +#if ARDUINOJSON_ENABLE_STD_STREAM + std::ostream &printTo(std::ostream &os) const { + StreamPrintAdapter adapter(os); + printTo(adapter); + return os; + } +#endif + size_t printTo(char *buffer, size_t bufferSize) const { + StaticStringBuilder sb(buffer, bufferSize); + return printTo(sb); + } + template + size_t printTo(char (&buffer)[N]) const { + return printTo(buffer, N); + } + template + typename EnableIf::has_append, size_t>::type printTo( + TString &str) const { + DynamicStringBuilder sb(str); + return printTo(sb); + } + template + size_t prettyPrintTo(IndentedPrint &print) const { + Prettyfier p(print); + return printTo(p); + } + size_t prettyPrintTo(char *buffer, size_t bufferSize) const { + StaticStringBuilder sb(buffer, bufferSize); + return prettyPrintTo(sb); + } + template + size_t prettyPrintTo(char (&buffer)[N]) const { + return prettyPrintTo(buffer, N); + } + template + typename EnableIf::has_append, size_t>::type + prettyPrintTo(Print &print) const { + IndentedPrint indentedPrint(print); + return prettyPrintTo(indentedPrint); + } + template + typename EnableIf::has_append, size_t>::type + prettyPrintTo(TString &str) const { + DynamicStringBuilder sb(str); + return prettyPrintTo(sb); + } + size_t measureLength() const { + DummyPrint dp; + return printTo(dp); + } + size_t measurePrettyLength() const { + DummyPrint dp; + return prettyPrintTo(dp); + } + private: + const T &downcast() const { + return *static_cast(this); + } +}; +#if ARDUINOJSON_ENABLE_STD_STREAM +template +inline std::ostream &operator<<(std::ostream &os, const JsonPrintable &v) { + return v.printTo(os); +} +#endif +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +class JsonVariantBase : public JsonPrintable, + public JsonVariantCasts, + public JsonVariantComparisons, + public JsonVariantOr, + public JsonVariantSubscripts, + public JsonVariantTag {}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +class RawJsonString { + public: + explicit RawJsonString(T str) : _str(str) {} + operator T() const { + return _str; + } + private: + T _str; +}; +template +struct StringTraits, void> { + static bool is_null(RawJsonString source) { + return StringTraits::is_null(static_cast(source)); + } + typedef RawJsonString duplicate_t; + template + static duplicate_t duplicate(RawJsonString source, Buffer* buffer) { + return duplicate_t(StringTraits::duplicate(source, buffer)); + } + static const bool has_append = false; + static const bool has_equals = false; + static const bool should_duplicate = StringTraits::should_duplicate; +}; +} // namespace Internals +template +inline Internals::RawJsonString RawJson(T str) { + return Internals::RawJsonString(str); +} +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +struct IsFloatingPoint { + static const bool value = IsSame::value || IsSame::value; +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +struct RemoveConst { + typedef T type; +}; +template +struct RemoveConst { + typedef T type; +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +class JsonArray; +class JsonObject; +class JsonVariant : public Internals::JsonVariantBase { + template + friend class Internals::JsonSerializer; + public: + JsonVariant() : _type(Internals::JSON_UNDEFINED) {} + JsonVariant(bool value) { + using namespace Internals; + _type = JSON_BOOLEAN; + _content.asInteger = static_cast(value); + } + template + JsonVariant(T value, typename Internals::EnableIf< + Internals::IsFloatingPoint::value>::type * = 0) { + using namespace Internals; + _type = JSON_FLOAT; + _content.asFloat = static_cast(value); + } + template + DEPRECATED("Second argument is not supported anymore") + JsonVariant(T value, uint8_t, + typename Internals::EnableIf< + Internals::IsFloatingPoint::value>::type * = 0) { + using namespace Internals; + _type = JSON_FLOAT; + _content.asFloat = static_cast(value); + } + template + JsonVariant( + T value, + typename Internals::EnableIf::value || + Internals::IsSame::value>::type * = + 0) { + using namespace Internals; + if (value >= 0) { + _type = JSON_POSITIVE_INTEGER; + _content.asInteger = static_cast(value); + } else { + _type = JSON_NEGATIVE_INTEGER; + _content.asInteger = static_cast(-value); + } + } + template + JsonVariant(T value, + typename Internals::EnableIf< + Internals::IsUnsignedIntegral::value>::type * = 0) { + using namespace Internals; + _type = JSON_POSITIVE_INTEGER; + _content.asInteger = static_cast(value); + } + template + JsonVariant( + const TChar *value, + typename Internals::EnableIf::value>::type * = + 0) { + _type = Internals::JSON_STRING; + _content.asString = reinterpret_cast(value); + } + JsonVariant(Internals::RawJsonString value) { + _type = Internals::JSON_UNPARSED; + _content.asString = value; + } + JsonVariant(const JsonArray &array); + JsonVariant(const JsonObject &object); + template + const typename Internals::EnableIf::value, T>::type + as() const { + return variantAsInteger(); + } + template + const typename Internals::EnableIf::value, T>::type + as() const { + return variantAsInteger() != 0; + } + template + const typename Internals::EnableIf::value, + T>::type + as() const { + return variantAsFloat(); + } + template + typename Internals::EnableIf::value || + Internals::IsSame::value, + const char *>::type + as() const { + return variantAsString(); + } + template + typename Internals::EnableIf::has_append, T>::type + as() const { + const char *cstr = variantAsString(); + if (cstr) return T(cstr); + T s; + printTo(s); + return s; + } + template + typename Internals::EnableIf< + Internals::IsSame::type, + JsonArray>::value, + JsonArray &>::type + as() const { + return variantAsArray(); + } + template + typename Internals::EnableIf< + Internals::IsSame::type, + const JsonArray>::value, + const JsonArray &>::type + as() const { + return variantAsArray(); + } + template + typename Internals::EnableIf< + Internals::IsSame::type, + JsonObject>::value, + JsonObject &>::type + as() const { + return variantAsObject(); + } + template + typename Internals::EnableIf< + Internals::IsSame::type, + const JsonObject>::value, + const JsonObject &>::type + as() const { + return variantAsObject(); + } + template + typename Internals::EnableIf::value, + T>::type + as() const { + return *this; + } + template + typename Internals::EnableIf::value, bool>::type is() + const { + return variantIsInteger(); + } + template + typename Internals::EnableIf::value, bool>::type + is() const { + return variantIsFloat(); + } + template + typename Internals::EnableIf::value, bool>::type + is() const { + return variantIsBoolean(); + } + template + typename Internals::EnableIf::value || + Internals::IsSame::value || + Internals::StringTraits::has_append, + bool>::type + is() const { + return variantIsString(); + } + template + typename Internals::EnableIf< + Internals::IsSame::type>::type, + JsonArray>::value, + bool>::type + is() const { + return variantIsArray(); + } + template + typename Internals::EnableIf< + Internals::IsSame::type>::type, + JsonObject>::value, + bool>::type + is() const { + return variantIsObject(); + } + bool success() const { + return _type != Internals::JSON_UNDEFINED; + } + private: + JsonArray &variantAsArray() const; + JsonObject &variantAsObject() const; + const char *variantAsString() const; + template + T variantAsFloat() const; + template + T variantAsInteger() const; + bool variantIsBoolean() const; + bool variantIsFloat() const; + bool variantIsInteger() const; + bool variantIsArray() const { + return _type == Internals::JSON_ARRAY; + } + bool variantIsObject() const { + return _type == Internals::JSON_OBJECT; + } + bool variantIsString() const { + return _type == Internals::JSON_STRING || + (_type == Internals::JSON_UNPARSED && _content.asString && + !strcmp("null", _content.asString)); + } + Internals::JsonVariantType _type; + Internals::JsonVariantContent _content; +}; +DEPRECATED("Decimal places are ignored, use the float value instead") +inline JsonVariant float_with_n_digits(float value, uint8_t) { + return JsonVariant(value); +} +DEPRECATED("Decimal places are ignored, use the double value instead") +inline JsonVariant double_with_n_digits(double value, uint8_t) { + return JsonVariant(value); +} +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +struct IsArray { + static const bool value = false; +}; +template +struct IsArray { + static const bool value = true; +}; +template +struct IsArray { + static const bool value = true; +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +class JsonArray; +class JsonObject; +class JsonBuffer : Internals::NonCopyable { + public: + JsonArray &createArray(); + JsonObject &createObject(); + template + DEPRECATED("char* are duplicated, you don't need strdup() anymore") + typename Internals::EnableIf::value, + const char *>::type strdup(const TString &src) { + return Internals::StringTraits::duplicate(src, this); + } + template + DEPRECATED("char* are duplicated, you don't need strdup() anymore") + const char *strdup(TString *src) { + return Internals::StringTraits::duplicate(src, this); + } + virtual void *alloc(size_t size) = 0; + protected: + ~JsonBuffer() {} + static FORCE_INLINE size_t round_size_up(size_t bytes) { +#if ARDUINOJSON_ENABLE_ALIGNMENT + const size_t x = sizeof(void *) - 1; + return (bytes + x) & ~x; +#else + return bytes; +#endif + } +}; +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +class StringWriter { + public: + class String { + public: + String(TChar** ptr) : _writePtr(ptr), _startPtr(*ptr) {} + void append(char c) { + *(*_writePtr)++ = TChar(c); + } + const char* c_str() const { + *(*_writePtr)++ = 0; + return reinterpret_cast(_startPtr); + } + private: + TChar** _writePtr; + TChar* _startPtr; + }; + StringWriter(TChar* buffer) : _ptr(buffer) {} + String startString() { + return String(&_ptr); + } + private: + TChar* _ptr; +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +class JsonParser { + public: + JsonParser(JsonBuffer *buffer, TReader reader, TWriter writer, + uint8_t nestingLimit) + : _buffer(buffer), + _reader(reader), + _writer(writer), + _nestingLimit(nestingLimit) {} + JsonArray &parseArray(); + JsonObject &parseObject(); + JsonVariant parseVariant() { + JsonVariant result; + parseAnythingTo(&result); + return result; + } + private: + JsonParser &operator=(const JsonParser &); // non-copiable + static bool eat(TReader &, char charToSkip); + FORCE_INLINE bool eat(char charToSkip) { + return eat(_reader, charToSkip); + } + const char *parseString(); + bool parseAnythingTo(JsonVariant *destination); + inline bool parseArrayTo(JsonVariant *destination); + inline bool parseObjectTo(JsonVariant *destination); + inline bool parseStringTo(JsonVariant *destination); + static inline bool isBetween(char c, char min, char max) { + return min <= c && c <= max; + } + static inline bool canBeInNonQuotedString(char c) { + return isBetween(c, '0', '9') || isBetween(c, '_', 'z') || + isBetween(c, 'A', 'Z') || c == '+' || c == '-' || c == '.'; + } + static inline bool isQuote(char c) { + return c == '\'' || c == '\"'; + } + JsonBuffer *_buffer; + TReader _reader; + TWriter _writer; + uint8_t _nestingLimit; +}; +template +struct JsonParserBuilder { + typedef typename StringTraits::Reader InputReader; + typedef JsonParser TParser; + static TParser makeParser(TJsonBuffer *buffer, TString &json, + uint8_t nestingLimit) { + return TParser(buffer, InputReader(json), *buffer, nestingLimit); + } +}; +template +struct JsonParserBuilder::value>::type> { + typedef typename StringTraits::Reader TReader; + typedef StringWriter TWriter; + typedef JsonParser TParser; + static TParser makeParser(TJsonBuffer *buffer, TChar *json, + uint8_t nestingLimit) { + return TParser(buffer, TReader(json), TWriter(json), nestingLimit); + } +}; +template +inline typename JsonParserBuilder::TParser makeParser( + TJsonBuffer *buffer, TString &json, uint8_t nestingLimit) { + return JsonParserBuilder::makeParser(buffer, json, + nestingLimit); +} +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +class JsonBufferBase : public JsonBuffer { + public: + template + typename Internals::EnableIf::value, + JsonArray &>::type + parseArray(const TString &json, + uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { + return Internals::makeParser(that(), json, nestingLimit).parseArray(); + } + template + JsonArray &parseArray( + TString *json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { + return Internals::makeParser(that(), json, nestingLimit).parseArray(); + } + template + JsonArray &parseArray( + TString &json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { + return Internals::makeParser(that(), json, nestingLimit).parseArray(); + } + template + typename Internals::EnableIf::value, + JsonObject &>::type + parseObject(const TString &json, + uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { + return Internals::makeParser(that(), json, nestingLimit).parseObject(); + } + template + JsonObject &parseObject( + TString *json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { + return Internals::makeParser(that(), json, nestingLimit).parseObject(); + } + template + JsonObject &parseObject( + TString &json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { + return Internals::makeParser(that(), json, nestingLimit).parseObject(); + } + template + typename Internals::EnableIf::value, + JsonVariant>::type + parse(const TString &json, + uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { + return Internals::makeParser(that(), json, nestingLimit).parseVariant(); + } + template + JsonVariant parse(TString *json, + uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { + return Internals::makeParser(that(), json, nestingLimit).parseVariant(); + } + template + JsonVariant parse(TString &json, + uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) { + return Internals::makeParser(that(), json, nestingLimit).parseVariant(); + } + protected: + ~JsonBufferBase() {} + private: + TDerived *that() { + return static_cast(this); + } +}; +} // namespace Internals +} // namespace ArduinoJson +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#elif defined(__GNUC__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +#pragma GCC diagnostic push +#endif +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#endif +namespace ArduinoJson { +namespace Internals { +class DefaultAllocator { + public: + void* allocate(size_t size) { + return malloc(size); + } + void deallocate(void* pointer) { + free(pointer); + } +}; +template +class DynamicJsonBufferBase + : public JsonBufferBase > { + struct Block; + struct EmptyBlock { + Block* next; + size_t capacity; + size_t size; + }; + struct Block : EmptyBlock { + uint8_t data[1]; + }; + public: + enum { EmptyBlockSize = sizeof(EmptyBlock) }; + DynamicJsonBufferBase(size_t initialSize = 256) + : _head(NULL), _nextBlockCapacity(initialSize) {} + ~DynamicJsonBufferBase() { + clear(); + } + size_t size() const { + size_t total = 0; + for (const Block* b = _head; b; b = b->next) total += b->size; + return total; + } + virtual void* alloc(size_t bytes) { + alignNextAlloc(); + return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes); + } + void clear() { + Block* currentBlock = _head; + while (currentBlock != NULL) { + _nextBlockCapacity = currentBlock->capacity; + Block* nextBlock = currentBlock->next; + _allocator.deallocate(currentBlock); + currentBlock = nextBlock; + } + _head = 0; + } + class String { + public: + String(DynamicJsonBufferBase* parent) + : _parent(parent), _start(NULL), _length(0) {} + void append(char c) { + if (_parent->canAllocInHead(1)) { + char* end = static_cast(_parent->allocInHead(1)); + *end = c; + if (_length == 0) _start = end; + } else { + char* newStart = + static_cast(_parent->allocInNewBlock(_length + 1)); + if (_start && newStart) memcpy(newStart, _start, _length); + if (newStart) newStart[_length] = c; + _start = newStart; + } + _length++; + } + const char* c_str() { + append(0); + return _start; + } + private: + DynamicJsonBufferBase* _parent; + char* _start; + size_t _length; + }; + String startString() { + return String(this); + } + private: + void alignNextAlloc() { + if (_head) _head->size = this->round_size_up(_head->size); + } + bool canAllocInHead(size_t bytes) const { + return _head != NULL && _head->size + bytes <= _head->capacity; + } + void* allocInHead(size_t bytes) { + void* p = _head->data + _head->size; + _head->size += bytes; + return p; + } + void* allocInNewBlock(size_t bytes) { + size_t capacity = _nextBlockCapacity; + if (bytes > capacity) capacity = bytes; + if (!addNewBlock(capacity)) return NULL; + _nextBlockCapacity *= 2; + return allocInHead(bytes); + } + bool addNewBlock(size_t capacity) { + size_t bytes = EmptyBlockSize + capacity; + Block* block = static_cast(_allocator.allocate(bytes)); + if (block == NULL) return false; + block->capacity = capacity; + block->size = 0; + block->next = _head; + _head = block; + return true; + } + TAllocator _allocator; + Block* _head; + size_t _nextBlockCapacity; +}; +} // namespace Internals +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +#pragma GCC diagnostic pop +#endif +#endif +typedef Internals::DynamicJsonBufferBase + DynamicJsonBuffer; +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +class JsonBufferAllocated { + public: + void *operator new(size_t n, JsonBuffer *jsonBuffer) throw() { + if (!jsonBuffer) return NULL; + return jsonBuffer->alloc(n); + } + void operator delete(void *, JsonBuffer *)throw(); +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +struct ListNode : public Internals::JsonBufferAllocated { + ListNode() throw() : next(NULL) {} + ListNode *next; + T content; +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +class ListConstIterator { + public: + explicit ListConstIterator(const ListNode *node = NULL) : _node(node) {} + const T &operator*() const { + return _node->content; + } + const T *operator->() { + return &_node->content; + } + bool operator==(const ListConstIterator &other) const { + return _node == other._node; + } + bool operator!=(const ListConstIterator &other) const { + return _node != other._node; + } + ListConstIterator &operator++() { + if (_node) _node = _node->next; + return *this; + } + ListConstIterator &operator+=(size_t distance) { + while (_node && distance) { + _node = _node->next; + --distance; + } + return *this; + } + private: + const ListNode *_node; +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +class List; +template +class ListIterator { + friend class List; + public: + explicit ListIterator(ListNode *node = NULL) : _node(node) {} + T &operator*() const { + return _node->content; + } + T *operator->() { + return &_node->content; + } + bool operator==(const ListIterator &other) const { + return _node == other._node; + } + bool operator!=(const ListIterator &other) const { + return _node != other._node; + } + ListIterator &operator++() { + if (_node) _node = _node->next; + return *this; + } + ListIterator &operator+=(size_t distance) { + while (_node && distance) { + _node = _node->next; + --distance; + } + return *this; + } + operator ListConstIterator() const { + return ListConstIterator(_node); + } + private: + ListNode *_node; +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +class List { + public: + typedef T value_type; + typedef ListNode node_type; + typedef ListIterator iterator; + typedef ListConstIterator const_iterator; + explicit List(JsonBuffer *buffer) : _buffer(buffer), _firstNode(NULL) {} + bool success() const { + return _buffer != NULL; + } + size_t size() const { + size_t nodeCount = 0; + for (node_type *node = _firstNode; node; node = node->next) nodeCount++; + return nodeCount; + } + iterator add() { + node_type *newNode = new (_buffer) node_type(); + if (_firstNode) { + node_type *lastNode = _firstNode; + while (lastNode->next) lastNode = lastNode->next; + lastNode->next = newNode; + } else { + _firstNode = newNode; + } + return iterator(newNode); + } + iterator begin() { + return iterator(_firstNode); + } + iterator end() { + return iterator(NULL); + } + const_iterator begin() const { + return const_iterator(_firstNode); + } + const_iterator end() const { + return const_iterator(NULL); + } + void remove(iterator it) { + node_type *nodeToRemove = it._node; + if (!nodeToRemove) return; + if (nodeToRemove == _firstNode) { + _firstNode = nodeToRemove->next; + } else { + for (node_type *node = _firstNode; node; node = node->next) + if (node->next == nodeToRemove) node->next = nodeToRemove->next; + } + } + protected: + JsonBuffer *_buffer; + private: + node_type *_firstNode; +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +class ReferenceType { + public: + bool operator==(const ReferenceType& other) const { + return this == &other; + } + bool operator!=(const ReferenceType& other) const { + return this != &other; + } +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +struct ValueSaver { + template + static bool save(JsonBuffer*, Destination& destination, Source source) { + destination = source; + return true; + } +}; +template +struct ValueSaver< + Source, typename EnableIf::should_duplicate>::type> { + template + static bool save(JsonBuffer* buffer, Destination& dest, Source source) { + if (!StringTraits::is_null(source)) { + typename StringTraits::duplicate_t dup = + StringTraits::duplicate(source, buffer); + if (!dup) return false; + dest = dup; + } else { + dest = reinterpret_cast(0); + } + return true; + } +}; +template +struct ValueSaver< + Char*, typename EnableIf::should_duplicate>::type> { + template + static bool save(JsonBuffer*, Destination& dest, Char* source) { + dest = reinterpret_cast(source); + return true; + } +}; +} // namespace Internals +} // namespace ArduinoJson +#define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \ + (sizeof(JsonArray) + (NUMBER_OF_ELEMENTS) * sizeof(JsonArray::node_type)) +namespace ArduinoJson { +class JsonObject; +class JsonBuffer; +namespace Internals { +class JsonArraySubscript; +} +class JsonArray : public Internals::JsonPrintable, + public Internals::ReferenceType, + public Internals::NonCopyable, + public Internals::List, + public Internals::JsonBufferAllocated { + public: + explicit JsonArray(JsonBuffer *buffer) throw() + : Internals::List(buffer) {} + const Internals::JsonArraySubscript operator[](size_t index) const; + Internals::JsonArraySubscript operator[](size_t index); + template + bool add(const T &value) { + return add_impl(value); + } + template + bool add(T *value) { + return add_impl(value); + } + template + DEPRECATED("Second argument is not supported anymore") + bool add(T value, uint8_t) { + return add_impl(JsonVariant(value)); + } + template + bool set(size_t index, const T &value) { + return set_impl(index, value); + } + template + bool set(size_t index, T *value) { + return set_impl(index, value); + } + template + typename Internals::EnableIf::value, bool>::type + set(size_t index, T value, uint8_t decimals) { + return set_impl(index, JsonVariant(value, decimals)); + } + template + typename Internals::JsonVariantAs::type get(size_t index) const { + const_iterator it = begin() += index; + return it != end() ? it->as() : Internals::JsonVariantDefault::get(); + } + template + bool is(size_t index) const { + const_iterator it = begin() += index; + return it != end() ? it->is() : false; + } + JsonArray &createNestedArray(); + JsonObject &createNestedObject(); + void remove(size_t index) { + remove(begin() += index); + } + using Internals::List::remove; + static JsonArray &invalid() { + static JsonArray instance(NULL); + return instance; + } + template + bool copyFrom(T (&array)[N]) { + return copyFrom(array, N); + } + template + bool copyFrom(T *array, size_t len) { + bool ok = true; + for (size_t i = 0; i < len; i++) { + ok &= add(array[i]); + } + return ok; + } + template + bool copyFrom(T (&array)[N1][N2]) { + bool ok = true; + for (size_t i = 0; i < N1; i++) { + JsonArray &nestedArray = createNestedArray(); + for (size_t j = 0; j < N2; j++) { + ok &= nestedArray.add(array[i][j]); + } + } + return ok; + } + template + size_t copyTo(T (&array)[N]) const { + return copyTo(array, N); + } + template + size_t copyTo(T *array, size_t len) const { + size_t i = 0; + for (const_iterator it = begin(); it != end() && i < len; ++it) + array[i++] = *it; + return i; + } + template + void copyTo(T (&array)[N1][N2]) const { + size_t i = 0; + for (const_iterator it = begin(); it != end() && i < N1; ++it) { + it->as().copyTo(array[i++]); + } + } +#if ARDUINOJSON_ENABLE_DEPRECATED + DEPRECATED("use remove() instead") + FORCE_INLINE void removeAt(size_t index) { + return remove(index); + } +#endif + private: + template + bool set_impl(size_t index, TValueRef value) { + iterator it = begin() += index; + if (it == end()) return false; + return Internals::ValueSaver::save(_buffer, *it, value); + } + template + bool add_impl(TValueRef value) { + iterator it = Internals::List::add(); + if (it == end()) return false; + return Internals::ValueSaver::save(_buffer, *it, value); + } +}; +namespace Internals { +template <> +struct JsonVariantDefault { + static JsonArray &get() { + return JsonArray::invalid(); + } +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +struct JsonPair { + const char* key; + JsonVariant value; +}; +} // namespace ArduinoJson +#define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \ + (sizeof(JsonObject) + (NUMBER_OF_ELEMENTS) * sizeof(JsonObject::node_type)) +namespace ArduinoJson { +class JsonArray; +class JsonBuffer; +namespace Internals { +template +class JsonObjectSubscript; +} +class JsonObject : public Internals::JsonPrintable, + public Internals::ReferenceType, + public Internals::NonCopyable, + public Internals::List, + public Internals::JsonBufferAllocated { + public: + explicit JsonObject(JsonBuffer* buffer) throw() + : Internals::List(buffer) {} + template + Internals::JsonObjectSubscript operator[]( + const TString& key) { + return Internals::JsonObjectSubscript(*this, key); + } + template + Internals::JsonObjectSubscript operator[](TString* key) { + return Internals::JsonObjectSubscript(*this, key); + } + template + const Internals::JsonObjectSubscript operator[]( + const TString& key) const { + return Internals::JsonObjectSubscript( + *const_cast(this), key); + } + template + const Internals::JsonObjectSubscript operator[]( + TString* key) const { + return Internals::JsonObjectSubscript( + *const_cast(this), key); + } + template + bool set(const TString& key, const TValue& value) { + return set_impl(key, value); + } + template + bool set(const TString& key, TValue* value) { + return set_impl(key, value); + } + template + bool set(TString* key, const TValue& value) { + return set_impl(key, value); + } + template + bool set(TString* key, TValue* value) { + return set_impl(key, value); + } + template + DEPRECATED("Second argument is not supported anymore") + typename Internals::EnableIf::value, + bool>::type + set(const TString& key, TValue value, uint8_t) { + return set_impl(key, + JsonVariant(value)); + } + template + DEPRECATED("Second argument is not supported anymore") + typename Internals::EnableIf::value, + bool>::type + set(TString* key, TValue value, uint8_t) { + return set_impl(key, JsonVariant(value)); + } + template + typename Internals::JsonVariantAs::type get( + const TString& key) const { + return get_impl(key); + } + template + typename Internals::JsonVariantAs::type get(TString* key) const { + return get_impl(key); + } + template + bool is(const TString& key) const { + return is_impl(key); + } + template + bool is(TString* key) const { + return is_impl(key); + } + template + JsonArray& createNestedArray(const TString& key) { + return createNestedArray_impl(key); + } + template + JsonArray& createNestedArray(TString* key) { + return createNestedArray_impl(key); + } + template + JsonObject& createNestedObject(const TString& key) { + return createNestedObject_impl(key); + } + template + JsonObject& createNestedObject(TString* key) { + return createNestedObject_impl(key); + } + template + bool containsKey(const TString& key) const { + return findKey(key) != end(); + } + template + bool containsKey(TString* key) const { + return findKey(key) != end(); + } + template + void remove(const TString& key) { + remove(findKey(key)); + } + template + void remove(TString* key) { + remove(findKey(key)); + } + using Internals::List::remove; + static JsonObject& invalid() { + static JsonObject instance(NULL); + return instance; + } + private: + template + iterator findKey(TStringRef key) { + iterator it; + for (it = begin(); it != end(); ++it) { + if (Internals::StringTraits::equals(key, it->key)) break; + } + return it; + } + template + const_iterator findKey(TStringRef key) const { + return const_cast(this)->findKey(key); + } + template + typename Internals::JsonVariantAs::type get_impl( + TStringRef key) const { + const_iterator it = findKey(key); + return it != end() ? it->value.as() + : Internals::JsonVariantDefault::get(); + } + template + bool set_impl(TStringRef key, TValueRef value) { + if (Internals::StringTraits::is_null(key)) return false; + iterator it = findKey(key); + if (it == end()) { + it = Internals::List::add(); + if (it == end()) return false; + bool key_ok = + Internals::ValueSaver::save(_buffer, it->key, key); + if (!key_ok) return false; + } + return Internals::ValueSaver::save(_buffer, it->value, value); + } + template + bool is_impl(TStringRef key) const { + const_iterator it = findKey(key); + return it != end() ? it->value.is() : false; + } + template + JsonArray& createNestedArray_impl(TStringRef key); + template + JsonObject& createNestedObject_impl(TStringRef key); +}; +namespace Internals { +template <> +struct JsonVariantDefault { + static JsonObject& get() { + return JsonObject::invalid(); + } +}; +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +class StaticJsonBufferBase : public JsonBufferBase { + public: + class String { + public: + String(StaticJsonBufferBase* parent) : _parent(parent) { + _start = parent->_buffer + parent->_size; + } + void append(char c) { + if (_parent->canAlloc(1)) { + char* last = static_cast(_parent->doAlloc(1)); + *last = c; + } + } + const char* c_str() const { + if (_parent->canAlloc(1)) { + char* last = static_cast(_parent->doAlloc(1)); + *last = '\0'; + return _start; + } else { + return NULL; + } + } + private: + StaticJsonBufferBase* _parent; + char* _start; + }; + StaticJsonBufferBase(char* buffer, size_t capa) + : _buffer(buffer), _capacity(capa), _size(0) {} + size_t capacity() const { + return _capacity; + } + size_t size() const { + return _size; + } + virtual void* alloc(size_t bytes) { + alignNextAlloc(); + if (!canAlloc(bytes)) return NULL; + return doAlloc(bytes); + } + void clear() { + _size = 0; + } + String startString() { + return String(this); + } + protected: + ~StaticJsonBufferBase() {} + private: + void alignNextAlloc() { + _size = round_size_up(_size); + } + bool canAlloc(size_t bytes) const { + return _size + bytes <= _capacity; + } + void* doAlloc(size_t bytes) { + void* p = &_buffer[_size]; + _size += bytes; + return p; + } + char* _buffer; + size_t _capacity; + size_t _size; +}; +} // namespace Internals +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#elif defined(__GNUC__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +#pragma GCC diagnostic push +#endif +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#endif +template +class StaticJsonBuffer : public Internals::StaticJsonBufferBase { + public: + explicit StaticJsonBuffer() + : Internals::StaticJsonBufferBase(_buffer, CAPACITY) {} + private: + char _buffer[CAPACITY]; +}; +} // namespace ArduinoJson +#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 Internals { +template +void skipSpacesAndComments(TInput& input) { + for (;;) { + switch (input.current()) { + case ' ': + case '\t': + case '\r': + case '\n': + input.move(); + continue; + case '/': + switch (input.next()) { + case '*': + input.move(); // skip '/' + for (;;) { + input.move(); + if (input.current() == '\0') return; + if (input.current() == '*' && input.next() == '/') { + input.move(); // skip '*' + input.move(); // skip '/' + break; + } + } + break; + case '/': + for (;;) { + input.move(); + if (input.current() == '\0') return; + if (input.current() == '\n') break; + } + break; + default: + return; + } + break; + default: + return; + } + } +} +} // namespace Internals +} // namespace ArduinoJson +template +inline bool ArduinoJson::Internals::JsonParser::eat( + TReader &reader, char charToSkip) { + skipSpacesAndComments(reader); + if (reader.current() != charToSkip) return false; + reader.move(); + return true; +} +template +inline bool +ArduinoJson::Internals::JsonParser::parseAnythingTo( + JsonVariant *destination) { + skipSpacesAndComments(_reader); + switch (_reader.current()) { + case '[': + return parseArrayTo(destination); + case '{': + return parseObjectTo(destination); + default: + return parseStringTo(destination); + } +} +template +inline ArduinoJson::JsonArray & +ArduinoJson::Internals::JsonParser::parseArray() { + if (_nestingLimit == 0) return JsonArray::invalid(); + _nestingLimit--; + JsonArray &array = _buffer->createArray(); + if (!eat('[')) goto ERROR_MISSING_BRACKET; + if (eat(']')) goto SUCCESS_EMPTY_ARRAY; + for (;;) { + JsonVariant value; + if (!parseAnythingTo(&value)) goto ERROR_INVALID_VALUE; + if (!array.add(value)) goto ERROR_NO_MEMORY; + if (eat(']')) goto SUCCES_NON_EMPTY_ARRAY; + if (!eat(',')) goto ERROR_MISSING_COMMA; + } +SUCCESS_EMPTY_ARRAY: +SUCCES_NON_EMPTY_ARRAY: + _nestingLimit++; + return array; +ERROR_INVALID_VALUE: +ERROR_MISSING_BRACKET: +ERROR_MISSING_COMMA: +ERROR_NO_MEMORY: + return JsonArray::invalid(); +} +template +inline bool ArduinoJson::Internals::JsonParser::parseArrayTo( + JsonVariant *destination) { + JsonArray &array = parseArray(); + if (!array.success()) return false; + *destination = array; + return true; +} +template +inline ArduinoJson::JsonObject & +ArduinoJson::Internals::JsonParser::parseObject() { + if (_nestingLimit == 0) return JsonObject::invalid(); + _nestingLimit--; + JsonObject &object = _buffer->createObject(); + if (!eat('{')) goto ERROR_MISSING_BRACE; + if (eat('}')) goto SUCCESS_EMPTY_OBJECT; + for (;;) { + const char *key = parseString(); + if (!key) goto ERROR_INVALID_KEY; + if (!eat(':')) goto ERROR_MISSING_COLON; + JsonVariant value; + if (!parseAnythingTo(&value)) goto ERROR_INVALID_VALUE; + if (!object.set(key, value)) goto ERROR_NO_MEMORY; + if (eat('}')) goto SUCCESS_NON_EMPTY_OBJECT; + if (!eat(',')) goto ERROR_MISSING_COMMA; + } +SUCCESS_EMPTY_OBJECT: +SUCCESS_NON_EMPTY_OBJECT: + _nestingLimit++; + return object; +ERROR_INVALID_KEY: +ERROR_INVALID_VALUE: +ERROR_MISSING_BRACE: +ERROR_MISSING_COLON: +ERROR_MISSING_COMMA: +ERROR_NO_MEMORY: + return JsonObject::invalid(); +} +template +inline bool ArduinoJson::Internals::JsonParser::parseObjectTo( + JsonVariant *destination) { + JsonObject &object = parseObject(); + if (!object.success()) return false; + *destination = object; + return true; +} +template +inline const char * +ArduinoJson::Internals::JsonParser::parseString() { + typename RemoveReference::type::String str = _writer.startString(); + skipSpacesAndComments(_reader); + char c = _reader.current(); + if (isQuote(c)) { // quotes + _reader.move(); + char stopChar = c; + for (;;) { + c = _reader.current(); + if (c == '\0') break; + _reader.move(); + if (c == stopChar) break; + if (c == '\\') { + c = Encoding::unescapeChar(_reader.current()); + if (c == '\0') break; + _reader.move(); + } + str.append(c); + } + } else { // no quotes + for (;;) { + if (!canBeInNonQuotedString(c)) break; + _reader.move(); + str.append(c); + c = _reader.current(); + } + } + return str.c_str(); +} +template +inline bool ArduinoJson::Internals::JsonParser::parseStringTo( + JsonVariant *destination) { + bool hasQuotes = isQuote(_reader.current()); + const char *value = parseString(); + if (value == NULL) return false; + if (hasQuotes) { + *destination = value; + } else { + *destination = RawJson(value); + } + return true; +} +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4522) +#endif +namespace ArduinoJson { +namespace Internals { +class JsonArraySubscript : public JsonVariantBase { + public: + FORCE_INLINE JsonArraySubscript(JsonArray& array, size_t index) + : _array(array), _index(index) {} + FORCE_INLINE JsonArraySubscript& operator=(const JsonArraySubscript& src) { + _array.set(_index, src); + return *this; + } + template + FORCE_INLINE JsonArraySubscript& operator=(const T& src) { + _array.set(_index, src); + return *this; + } + template + FORCE_INLINE JsonArraySubscript& operator=(T* src) { + _array.set(_index, src); + return *this; + } + FORCE_INLINE bool success() const { + return _index < _array.size(); + } + template + FORCE_INLINE typename JsonVariantAs::type as() const { + return _array.get(_index); + } + template + FORCE_INLINE bool is() const { + return _array.is(_index); + } + template + FORCE_INLINE bool set(const TValue& value) { + return _array.set(_index, value); + } + template + FORCE_INLINE bool set(TValue* value) { + return _array.set(_index, value); + } + template + DEPRECATED("Second argument is not supported anymore") + FORCE_INLINE bool set(const TValue& value, uint8_t) { + return _array.set(_index, value); + } + private: + JsonArray& _array; + const size_t _index; +}; +template +inline JsonArraySubscript JsonVariantSubscripts::operator[]( + size_t index) { + return impl()->template as()[index]; +} +template +inline const JsonArraySubscript JsonVariantSubscripts::operator[]( + size_t index) const { + return impl()->template as()[index]; +} +#if ARDUINOJSON_ENABLE_STD_STREAM +inline std::ostream& operator<<(std::ostream& os, + const JsonArraySubscript& source) { + return source.printTo(os); +} +#endif +} // namespace Internals +inline Internals::JsonArraySubscript JsonArray::operator[](size_t index) { + return Internals::JsonArraySubscript(*this, index); +} +inline const Internals::JsonArraySubscript JsonArray::operator[]( + size_t index) const { + return Internals::JsonArraySubscript(*const_cast(this), index); +} +} // namespace ArduinoJson +#ifdef _MSC_VER +#pragma warning(pop) +#endif +namespace ArduinoJson { +inline JsonArray &JsonArray::createNestedArray() { + if (!_buffer) return JsonArray::invalid(); + JsonArray &array = _buffer->createArray(); + add(array); + return array; +} +inline JsonObject &JsonArray::createNestedObject() { + if (!_buffer) return JsonObject::invalid(); + JsonObject &object = _buffer->createObject(); + add(object); + return object; +} +} // namespace ArduinoJson +inline ArduinoJson::JsonArray &ArduinoJson::JsonBuffer::createArray() { + JsonArray *ptr = new (this) JsonArray(this); + return ptr ? *ptr : JsonArray::invalid(); +} +inline ArduinoJson::JsonObject &ArduinoJson::JsonBuffer::createObject() { + JsonObject *ptr = new (this) JsonObject(this); + return ptr ? *ptr : JsonObject::invalid(); +} +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4522) +#endif +namespace ArduinoJson { +namespace Internals { +template +class JsonObjectSubscript + : public JsonVariantBase > { + typedef JsonObjectSubscript this_type; + public: + FORCE_INLINE JsonObjectSubscript(JsonObject& object, TStringRef key) + : _object(object), _key(key) {} + FORCE_INLINE this_type& operator=(const this_type& src) { + _object.set(_key, src); + return *this; + } + template + FORCE_INLINE typename EnableIf::value, this_type&>::type + operator=(const TValue& src) { + _object.set(_key, src); + return *this; + } + template + FORCE_INLINE this_type& operator=(TValue* src) { + _object.set(_key, src); + return *this; + } + FORCE_INLINE bool success() const { + return _object.containsKey(_key); + } + template + FORCE_INLINE typename JsonVariantAs::type as() const { + return _object.get(_key); + } + template + FORCE_INLINE bool is() const { + return _object.is(_key); + } + template + FORCE_INLINE typename EnableIf::value, bool>::type set( + const TValue& value) { + return _object.set(_key, value); + } + template + FORCE_INLINE bool set(const TValue* value) { + return _object.set(_key, value); + } + template + DEPRECATED("Second argument is not supported anymore") + FORCE_INLINE bool set(const TValue& value, uint8_t) { + return _object.set(_key, value); + } + private: + JsonObject& _object; + TStringRef _key; +}; +#if ARDUINOJSON_ENABLE_STD_STREAM +template +inline std::ostream& operator<<(std::ostream& os, + const JsonObjectSubscript& source) { + return source.printTo(os); +} +#endif +} // namespace Internals +} // namespace ArduinoJson +#ifdef _MSC_VER +#pragma warning(pop) +#endif +namespace ArduinoJson { +template +inline JsonArray &JsonObject::createNestedArray_impl(TStringRef key) { + if (!_buffer) return JsonArray::invalid(); + JsonArray &array = _buffer->createArray(); + set(key, array); + return array; +} +template +inline JsonObject &JsonObject::createNestedObject_impl(TStringRef key) { + if (!_buffer) return JsonObject::invalid(); + JsonObject &object = _buffer->createObject(); + set(key, object); + return object; +} +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +inline bool isdigit(char c) { + return '0' <= c && c <= '9'; +} +inline bool issign(char c) { + return '-' == c || c == '+'; +} +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +inline bool isFloat(const char* s) { + if (!s) return false; + if (!strcmp(s, "NaN")) return true; + if (issign(*s)) s++; + if (!strcmp(s, "Infinity")) return true; + if (*s == '\0') return false; + while (isdigit(*s)) s++; + if (*s == '.') { + s++; + while (isdigit(*s)) s++; + } + if (*s == 'e' || *s == 'E') { + s++; + if (issign(*s)) s++; + if (!isdigit(*s)) return false; + while (isdigit(*s)) s++; + } + return *s == '\0'; +} +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +inline bool isInteger(const char* s) { + if (!s || !*s) return false; + if (issign(*s)) s++; + while (isdigit(*s)) s++; + return *s == '\0'; +} +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +inline T parseFloat(const char* s) { + typedef FloatTraits traits; + typedef typename traits::mantissa_type mantissa_t; + typedef typename traits::exponent_type exponent_t; + if (!s) return 0; // NULL + bool negative_result = false; + switch (*s) { + case '-': + negative_result = true; + s++; + break; + case '+': + s++; + break; + } + if (*s == 't') return 1; // true + if (*s == 'n' || *s == 'N') return traits::nan(); + if (*s == 'i' || *s == 'I') + return negative_result ? -traits::inf() : traits::inf(); + mantissa_t mantissa = 0; + exponent_t exponent_offset = 0; + while (isdigit(*s)) { + if (mantissa < traits::mantissa_max / 10) + mantissa = mantissa * 10 + (*s - '0'); + else + exponent_offset++; + s++; + } + if (*s == '.') { + s++; + while (isdigit(*s)) { + if (mantissa < traits::mantissa_max / 10) { + mantissa = mantissa * 10 + (*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 negative_result ? -0.0f : 0.0f; + else + return negative_result ? -traits::inf() : traits::inf(); + } + s++; + } + if (negative_exponent) exponent = -exponent; + } + exponent += exponent_offset; + T result = traits::make_float(static_cast(mantissa), exponent); + return negative_result ? -result : result; +} +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +namespace Internals { +template +T parseInteger(const char *s) { + if (!s) return 0; // NULL + if (*s == 't') return 1; // "true" + T result = 0; + bool negative_result = false; + switch (*s) { + case '-': + negative_result = true; + s++; + break; + case '+': + s++; + break; + } + while (isdigit(*s)) { + result = T(result * 10 + T(*s - '0')); + s++; + } + return negative_result ? T(~result + 1) : result; +} +} // namespace Internals +} // namespace ArduinoJson +namespace ArduinoJson { +inline JsonVariant::JsonVariant(const JsonArray &array) { + if (array.success()) { + _type = Internals::JSON_ARRAY; + _content.asArray = const_cast(&array); + } else { + _type = Internals::JSON_UNDEFINED; + _content.asArray = 0; // <- prevent warning 'maybe-uninitialized' + } +} +inline JsonVariant::JsonVariant(const JsonObject &object) { + if (object.success()) { + _type = Internals::JSON_OBJECT; + _content.asObject = const_cast(&object); + } else { + _type = Internals::JSON_UNDEFINED; + _content.asObject = 0; // <- prevent warning 'maybe-uninitialized' + } +} +inline JsonArray &JsonVariant::variantAsArray() const { + if (_type == Internals::JSON_ARRAY) return *_content.asArray; + return JsonArray::invalid(); +} +inline JsonObject &JsonVariant::variantAsObject() const { + if (_type == Internals::JSON_OBJECT) return *_content.asObject; + return JsonObject::invalid(); +} +template +inline T JsonVariant::variantAsInteger() const { + using namespace Internals; + switch (_type) { + case JSON_UNDEFINED: + return 0; + case JSON_POSITIVE_INTEGER: + case JSON_BOOLEAN: + return T(_content.asInteger); + case JSON_NEGATIVE_INTEGER: + return T(~_content.asInteger + 1); + case JSON_STRING: + case JSON_UNPARSED: + return parseInteger(_content.asString); + default: + return T(_content.asFloat); + } +} +inline const char *JsonVariant::variantAsString() const { + using namespace Internals; + if (_type == JSON_UNPARSED && _content.asString && + !strcmp("null", _content.asString)) + return NULL; + if (_type == JSON_STRING || _type == JSON_UNPARSED) return _content.asString; + return NULL; +} +template +inline T JsonVariant::variantAsFloat() const { + using namespace Internals; + switch (_type) { + case JSON_UNDEFINED: + return 0; + case JSON_POSITIVE_INTEGER: + case JSON_BOOLEAN: + return static_cast(_content.asInteger); + case JSON_NEGATIVE_INTEGER: + return -static_cast(_content.asInteger); + case JSON_STRING: + case JSON_UNPARSED: + return parseFloat(_content.asString); + default: + return static_cast(_content.asFloat); + } +} +inline bool JsonVariant::variantIsBoolean() const { + using namespace Internals; + if (_type == JSON_BOOLEAN) return true; + if (_type != JSON_UNPARSED || _content.asString == NULL) return false; + return !strcmp(_content.asString, "true") || + !strcmp(_content.asString, "false"); +} +inline bool JsonVariant::variantIsInteger() const { + using namespace Internals; + return _type == JSON_POSITIVE_INTEGER || _type == JSON_NEGATIVE_INTEGER || + (_type == JSON_UNPARSED && isInteger(_content.asString)); +} +inline bool JsonVariant::variantIsFloat() const { + using namespace Internals; + return _type == JSON_FLOAT || _type == JSON_POSITIVE_INTEGER || + _type == JSON_NEGATIVE_INTEGER || + (_type == JSON_UNPARSED && isFloat(_content.asString)); +} +#if ARDUINOJSON_ENABLE_STD_STREAM +inline std::ostream &operator<<(std::ostream &os, const JsonVariant &source) { + return source.printTo(os); +} +#endif +} // namespace ArduinoJson +template +inline void ArduinoJson::Internals::JsonSerializer::serialize( + const JsonArray& array, Writer& writer) { + writer.beginArray(); + JsonArray::const_iterator it = array.begin(); + while (it != array.end()) { + serialize(*it, writer); + ++it; + if (it == array.end()) break; + writer.writeComma(); + } + writer.endArray(); +} +template +inline void ArduinoJson::Internals::JsonSerializer::serialize( + const JsonArraySubscript& arraySubscript, Writer& writer) { + serialize(arraySubscript.as(), writer); +} +template +inline void ArduinoJson::Internals::JsonSerializer::serialize( + const JsonObject& object, Writer& writer) { + writer.beginObject(); + JsonObject::const_iterator it = object.begin(); + while (it != object.end()) { + writer.writeString(it->key); + writer.writeColon(); + serialize(it->value, writer); + ++it; + if (it == object.end()) break; + writer.writeComma(); + } + writer.endObject(); +} +template +template +inline void ArduinoJson::Internals::JsonSerializer::serialize( + const JsonObjectSubscript& objectSubscript, Writer& writer) { + serialize(objectSubscript.template as(), writer); +} +template +inline void ArduinoJson::Internals::JsonSerializer::serialize( + const JsonVariant& variant, Writer& writer) { + switch (variant._type) { + case JSON_FLOAT: + writer.writeFloat(variant._content.asFloat); + return; + case JSON_ARRAY: + serialize(*variant._content.asArray, writer); + return; + case JSON_OBJECT: + serialize(*variant._content.asObject, writer); + return; + case JSON_STRING: + writer.writeString(variant._content.asString); + return; + case JSON_UNPARSED: + writer.writeRaw(variant._content.asString); + return; + case JSON_NEGATIVE_INTEGER: + writer.writeRaw('-'); // Falls through. + case JSON_POSITIVE_INTEGER: + writer.writeInteger(variant._content.asInteger); + return; + case JSON_BOOLEAN: + writer.writeBoolean(variant._content.asInteger != 0); + return; + default: // JSON_UNDEFINED + return; + } +} +#ifdef __GNUC__ +#define ARDUINOJSON_PRAGMA(x) _Pragma(#x) +#define ARDUINOJSON_COMPILE_ERROR(msg) ARDUINOJSON_PRAGMA(GCC error msg) +#define ARDUINOJSON_STRINGIFY(S) #S +#define ARDUINOJSON_DEPRECATION_ERROR(X, Y) \ + ARDUINOJSON_COMPILE_ERROR(ARDUINOJSON_STRINGIFY(X is a Y from ArduinoJson 6 but version 5 is installed. Visit arduinojson.org to get more information.)) +#define StaticJsonDocument ARDUINOJSON_DEPRECATION_ERROR(StaticJsonDocument, class) +#define DynamicJsonDocument ARDUINOJSON_DEPRECATION_ERROR(DynamicJsonDocument, class) +#define JsonDocument ARDUINOJSON_DEPRECATION_ERROR(JsonDocument, class) +#define DeserializationError ARDUINOJSON_DEPRECATION_ERROR(DeserializationError, class) +#define deserializeJson ARDUINOJSON_DEPRECATION_ERROR(deserializeJson, function) +#define deserializeMsgPack ARDUINOJSON_DEPRECATION_ERROR(deserializeMsgPack, function) +#define serializeJson ARDUINOJSON_DEPRECATION_ERROR(serializeJson, function) +#define serializeMsgPack ARDUINOJSON_DEPRECATION_ERROR(serializeMsgPack, function) +#define serializeJsonPretty ARDUINOJSON_DEPRECATION_ERROR(serializeJsonPretty, function) +#define measureMsgPack ARDUINOJSON_DEPRECATION_ERROR(measureMsgPack, function) +#define measureJson ARDUINOJSON_DEPRECATION_ERROR(measureJson, function) +#define measureJsonPretty ARDUINOJSON_DEPRECATION_ERROR(measureJsonPretty, function) +#endif + +using namespace ArduinoJson; + +#else + +#error ArduinoJson requires a C++ compiler, please change file extension to .cc or .cpp + +#endif diff --git a/src/Firebase.h b/src/Firebase.h index 44450557..936eeebb 100644 --- a/src/Firebase.h +++ b/src/Firebase.h @@ -23,7 +23,7 @@ #include "WString.h" #include #include -#include +#include "ArduinoJson-v5.13.5.h" #include "FirebaseHttpClient.h" #include "FirebaseError.h" diff --git a/src/FirebaseCloudMessaging.h b/src/FirebaseCloudMessaging.h index 519946c6..17143529 100644 --- a/src/FirebaseCloudMessaging.h +++ b/src/FirebaseCloudMessaging.h @@ -26,7 +26,7 @@ #include #include "FirebaseHttpClient.h" #include "FirebaseError.h" -#include +#include "ArduinoJson-v5.13.5.h" // Defines the actual message to the client, for more detail on // options and settings see: diff --git a/src/FirebaseObject.h b/src/FirebaseObject.h index 01caeb5c..5997e0c6 100644 --- a/src/FirebaseObject.h +++ b/src/FirebaseObject.h @@ -21,7 +21,7 @@ #include "WString.h" #include -#include +#include "ArduinoJson-v5.13.5.h" #ifndef FIREBASE_JSONBUFFER_SIZE