summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Friesel <derf@finalrewind.org>2018-09-17 10:02:07 +0200
committerDaniel Friesel <derf@finalrewind.org>2018-09-17 10:02:07 +0200
commit4f6253aa9fec99260b8bb7b9b2e9003f5259b600 (patch)
tree2d0a3fdd10e258ecce5fb220547b1c43b870d6d2
parent30c4f72770568749b4230a6b598e3fb87a065e91 (diff)
Import arduinojson and ubjson. Only partially working at the moment
-rw-r--r--include/lib/ArduinoJson.h19
-rw-r--r--include/lib/ArduinoJson/Configuration.hpp151
-rw-r--r--include/lib/ArduinoJson/Data/Encoding.hpp37
-rw-r--r--include/lib/ArduinoJson/Data/JsonBufferAllocated.hpp22
-rw-r--r--include/lib/ArduinoJson/Data/JsonFloat.hpp18
-rw-r--r--include/lib/ArduinoJson/Data/JsonInteger.hpp23
-rw-r--r--include/lib/ArduinoJson/Data/JsonVariantAs.hpp42
-rw-r--r--include/lib/ArduinoJson/Data/JsonVariantContent.hpp27
-rw-r--r--include/lib/ArduinoJson/Data/JsonVariantDefault.hpp23
-rw-r--r--include/lib/ArduinoJson/Data/JsonVariantType.hpp27
-rw-r--r--include/lib/ArduinoJson/Data/List.hpp94
-rw-r--r--include/lib/ArduinoJson/Data/ListConstIterator.hpp50
-rw-r--r--include/lib/ArduinoJson/Data/ListIterator.hpp60
-rw-r--r--include/lib/ArduinoJson/Data/ListNode.hpp24
-rw-r--r--include/lib/ArduinoJson/Data/NonCopyable.hpp23
-rw-r--r--include/lib/ArduinoJson/Data/ReferenceType.hpp24
-rw-r--r--include/lib/ArduinoJson/Data/ValueSaver.hpp52
-rw-r--r--include/lib/ArduinoJson/Deserialization/Comments.hpp61
-rw-r--r--include/lib/ArduinoJson/Deserialization/JsonParser.hpp102
-rw-r--r--include/lib/ArduinoJson/Deserialization/JsonParserImpl.hpp189
-rw-r--r--include/lib/ArduinoJson/Deserialization/StringWriter.hpp41
-rw-r--r--include/lib/ArduinoJson/DynamicJsonBuffer.hpp170
-rw-r--r--include/lib/ArduinoJson/JsonArray.hpp227
-rw-r--r--include/lib/ArduinoJson/JsonArrayImpl.hpp26
-rw-r--r--include/lib/ArduinoJson/JsonArraySubscript.hpp122
-rw-r--r--include/lib/ArduinoJson/JsonBuffer.hpp78
-rw-r--r--include/lib/ArduinoJson/JsonBufferBase.hpp127
-rw-r--r--include/lib/ArduinoJson/JsonBufferImpl.hpp17
-rw-r--r--include/lib/ArduinoJson/JsonObject.hpp328
-rw-r--r--include/lib/ArduinoJson/JsonObjectImpl.hpp28
-rw-r--r--include/lib/ArduinoJson/JsonObjectSubscript.hpp110
-rw-r--r--include/lib/ArduinoJson/JsonPair.hpp16
-rw-r--r--include/lib/ArduinoJson/JsonVariant.hpp355
-rw-r--r--include/lib/ArduinoJson/JsonVariantBase.hpp24
-rw-r--r--include/lib/ArduinoJson/JsonVariantCasts.hpp59
-rw-r--r--include/lib/ArduinoJson/JsonVariantComparisons.hpp139
-rw-r--r--include/lib/ArduinoJson/JsonVariantImpl.hpp126
-rw-r--r--include/lib/ArduinoJson/JsonVariantOr.hpp52
-rw-r--r--include/lib/ArduinoJson/JsonVariantSubscripts.hpp86
-rw-r--r--include/lib/ArduinoJson/Polyfills/attributes.hpp29
-rw-r--r--include/lib/ArduinoJson/Polyfills/ctype.hpp18
-rw-r--r--include/lib/ArduinoJson/Polyfills/isFloat.hpp38
-rw-r--r--include/lib/ArduinoJson/Polyfills/isInteger.hpp19
-rw-r--r--include/lib/ArduinoJson/Polyfills/math.hpp19
-rw-r--r--include/lib/ArduinoJson/Polyfills/parseFloat.hpp90
-rw-r--r--include/lib/ArduinoJson/Polyfills/parseInteger.hpp41
-rw-r--r--include/lib/ArduinoJson/RawJson.hpp46
-rw-r--r--include/lib/ArduinoJson/Serialization/DummyPrint.hpp22
-rw-r--r--include/lib/ArduinoJson/Serialization/DynamicStringBuilder.hpp35
-rw-r--r--include/lib/ArduinoJson/Serialization/FloatParts.hpp89
-rw-r--r--include/lib/ArduinoJson/Serialization/IndentedPrint.hpp68
-rw-r--r--include/lib/ArduinoJson/Serialization/JsonPrintable.hpp117
-rw-r--r--include/lib/ArduinoJson/Serialization/JsonSerializer.hpp32
-rw-r--r--include/lib/ArduinoJson/Serialization/JsonSerializerImpl.hpp103
-rw-r--r--include/lib/ArduinoJson/Serialization/JsonWriter.hpp155
-rw-r--r--include/lib/ArduinoJson/Serialization/Prettyfier.hpp133
-rw-r--r--include/lib/ArduinoJson/Serialization/StaticStringBuilder.hpp36
-rw-r--r--include/lib/ArduinoJson/Serialization/StreamPrintAdapter.hpp39
-rw-r--r--include/lib/ArduinoJson/StaticJsonBuffer.hpp126
-rw-r--r--include/lib/ArduinoJson/StringTraits/ArduinoStream.hpp61
-rw-r--r--include/lib/ArduinoJson/StringTraits/CharPointer.hpp64
-rw-r--r--include/lib/ArduinoJson/StringTraits/FlashString.hpp61
-rw-r--r--include/lib/ArduinoJson/StringTraits/StdStream.hpp60
-rw-r--r--include/lib/ArduinoJson/StringTraits/StdString.hpp77
-rw-r--r--include/lib/ArduinoJson/StringTraits/StringTraits.hpp36
-rw-r--r--include/lib/ArduinoJson/TypeTraits/EnableIf.hpp19
-rw-r--r--include/lib/ArduinoJson/TypeTraits/FloatTraits.hpp171
-rw-r--r--include/lib/ArduinoJson/TypeTraits/IsArray.hpp24
-rw-r--r--include/lib/ArduinoJson/TypeTraits/IsBaseOf.hpp27
-rw-r--r--include/lib/ArduinoJson/TypeTraits/IsChar.hpp23
-rw-r--r--include/lib/ArduinoJson/TypeTraits/IsConst.hpp21
-rw-r--r--include/lib/ArduinoJson/TypeTraits/IsFloatingPoint.hpp18
-rw-r--r--include/lib/ArduinoJson/TypeTraits/IsIntegral.hpp26
-rw-r--r--include/lib/ArduinoJson/TypeTraits/IsSame.hpp21
-rw-r--r--include/lib/ArduinoJson/TypeTraits/IsSignedIntegral.hpp28
-rw-r--r--include/lib/ArduinoJson/TypeTraits/IsUnsignedIntegral.hpp28
-rw-r--r--include/lib/ArduinoJson/TypeTraits/IsVariant.hpp17
-rw-r--r--include/lib/ArduinoJson/TypeTraits/RemoveConst.hpp20
-rw-r--r--include/lib/ArduinoJson/TypeTraits/RemoveReference.hpp20
-rw-r--r--include/lib/ArduinoJson/version.hpp10
-rw-r--r--include/lib/ubjson/ubj.h230
-rw-r--r--include/lib/ubjson/ubj_internal.h163
-rw-r--r--src/app/prototest/Makefile.inc3
-rw-r--r--src/app/prototest/main.cc30
-rw-r--r--src/lib/ubjson/ubjr.c516
-rw-r--r--src/lib/ubjson/ubjrw.c169
-rw-r--r--src/lib/ubjson/ubjw.c618
87 files changed, 7015 insertions, 0 deletions
diff --git a/include/lib/ArduinoJson.h b/include/lib/ArduinoJson.h
new file mode 100644
index 0000000..c493c06
--- /dev/null
+++ b/include/lib/ArduinoJson.h
@@ -0,0 +1,19 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "ArduinoJson/version.hpp"
+
+#include "ArduinoJson/DynamicJsonBuffer.hpp"
+#include "ArduinoJson/JsonArray.hpp"
+#include "ArduinoJson/JsonObject.hpp"
+#include "ArduinoJson/StaticJsonBuffer.hpp"
+
+#include "ArduinoJson/Deserialization/JsonParserImpl.hpp"
+#include "ArduinoJson/JsonArrayImpl.hpp"
+#include "ArduinoJson/JsonBufferImpl.hpp"
+#include "ArduinoJson/JsonObjectImpl.hpp"
+#include "ArduinoJson/JsonVariantImpl.hpp"
+#include "ArduinoJson/Serialization/JsonSerializerImpl.hpp"
diff --git a/include/lib/ArduinoJson/Configuration.hpp b/include/lib/ArduinoJson/Configuration.hpp
new file mode 100644
index 0000000..82483ad
--- /dev/null
+++ b/include/lib/ArduinoJson/Configuration.hpp
@@ -0,0 +1,151 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+// Small or big machine?
+#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
+
+// Store floats by default to reduce the memory usage (issue #134)
+#ifndef ARDUINOJSON_USE_DOUBLE
+#define ARDUINOJSON_USE_DOUBLE 0
+#endif
+
+// Store longs by default, because they usually match the size of a float.
+#ifndef ARDUINOJSON_USE_LONG_LONG
+#define ARDUINOJSON_USE_LONG_LONG 0
+#endif
+#ifndef ARDUINOJSON_USE_INT64
+#define ARDUINOJSON_USE_INT64 0
+#endif
+
+// Embedded systems usually don't have std::string
+#ifndef ARDUINOJSON_ENABLE_STD_STRING
+#define ARDUINOJSON_ENABLE_STD_STRING 0
+#endif
+
+// Embedded systems usually don't have std::stream
+#ifndef ARDUINOJSON_ENABLE_STD_STREAM
+#define ARDUINOJSON_ENABLE_STD_STREAM 0
+#endif
+
+// Limit nesting as the stack is likely to be small
+#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT
+#define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10
+#endif
+
+#else // ARDUINOJSON_EMBEDDED_MODE
+
+// On a computer we have plenty of memory so we can use doubles
+#ifndef ARDUINOJSON_USE_DOUBLE
+#define ARDUINOJSON_USE_DOUBLE 1
+#endif
+
+// Use long long when available
+#ifndef ARDUINOJSON_USE_LONG_LONG
+#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)
+#define ARDUINOJSON_USE_LONG_LONG 1
+#else
+#define ARDUINOJSON_USE_LONG_LONG 0
+#endif
+#endif
+
+// Use _int64 on old versions of Visual Studio
+#ifndef ARDUINOJSON_USE_INT64
+#if defined(_MSC_VER) && _MSC_VER <= 1700
+#define ARDUINOJSON_USE_INT64 1
+#else
+#define ARDUINOJSON_USE_INT64 0
+#endif
+#endif
+
+// On a computer, we can use std::string
+#ifndef ARDUINOJSON_ENABLE_STD_STRING
+#define ARDUINOJSON_ENABLE_STD_STRING 1
+#endif
+
+// On a computer, we can assume std::stream
+#ifndef ARDUINOJSON_ENABLE_STD_STREAM
+#define ARDUINOJSON_ENABLE_STD_STREAM 1
+#endif
+
+// On a computer, the stack is large so we can increase nesting limit
+#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT
+#define ARDUINOJSON_DEFAULT_NESTING_LIMIT 50
+#endif
+
+#endif // ARDUINOJSON_EMBEDDED_MODE
+
+#ifdef ARDUINO
+
+// Enable support for Arduino String
+#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
+#define ARDUINOJSON_ENABLE_ARDUINO_STRING 1
+#endif
+
+// Enable support for Arduino Stream
+#ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
+#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1
+#endif
+
+#else // ARDUINO
+
+// Disable support for Arduino String
+#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
+#define ARDUINOJSON_ENABLE_ARDUINO_STRING 0
+#endif
+
+// Disable support for Arduino Stream
+#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
+// alignment isn't needed for 8-bit AVR
+#define ARDUINOJSON_ENABLE_ALIGNMENT 0
+#else
+// but most processors need pointers to be align on word size
+#define ARDUINOJSON_ENABLE_ALIGNMENT 1
+#endif
+#endif
+
+// Enable deprecated functions by default
+#ifndef ARDUINOJSON_ENABLE_DEPRECATED
+#define ARDUINOJSON_ENABLE_DEPRECATED 1
+#endif
+
+// Control the exponentiation threshold for big numbers
+// CAUTION: cannot be more that 1e9 !!!!
+#ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD
+#define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e7
+#endif
+
+// Control the exponentiation threshold for small numbers
+#ifndef ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD
+#define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5
+#endif
+
+#if ARDUINOJSON_USE_LONG_LONG && ARDUINOJSON_USE_INT64
+#error ARDUINOJSON_USE_LONG_LONG and ARDUINOJSON_USE_INT64 cannot be set together
+#endif
diff --git a/include/lib/ArduinoJson/Data/Encoding.hpp b/include/lib/ArduinoJson/Data/Encoding.hpp
new file mode 100644
index 0000000..a0efa2c
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/Encoding.hpp
@@ -0,0 +1,37 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+class Encoding {
+ public:
+ // Optimized for code size on a 8-bit AVR
+ static char escapeChar(char c) {
+ const char *p = escapeTable(false);
+ while (p[0] && p[1] != c) {
+ p += 2;
+ }
+ return p[0];
+ }
+
+ // Optimized for code size on a 8-bit AVR
+ static char unescapeChar(char c) {
+ const char *p = escapeTable(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];
+ }
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/JsonBufferAllocated.hpp b/include/lib/ArduinoJson/Data/JsonBufferAllocated.hpp
new file mode 100644
index 0000000..443aae4
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/JsonBufferAllocated.hpp
@@ -0,0 +1,22 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../JsonBuffer.hpp"
+
+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();
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/JsonFloat.hpp b/include/lib/ArduinoJson/Data/JsonFloat.hpp
new file mode 100644
index 0000000..0ed4214
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/JsonFloat.hpp
@@ -0,0 +1,18 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../Configuration.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+#if ARDUINOJSON_USE_DOUBLE
+typedef double JsonFloat;
+#else
+typedef float JsonFloat;
+#endif
+}
+}
diff --git a/include/lib/ArduinoJson/Data/JsonInteger.hpp b/include/lib/ArduinoJson/Data/JsonInteger.hpp
new file mode 100644
index 0000000..c8ddd00
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/JsonInteger.hpp
@@ -0,0 +1,23 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../Configuration.hpp"
+
+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
+}
+}
diff --git a/include/lib/ArduinoJson/Data/JsonVariantAs.hpp b/include/lib/ArduinoJson/Data/JsonVariantAs.hpp
new file mode 100644
index 0000000..8f202c5
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/JsonVariantAs.hpp
@@ -0,0 +1,42 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A metafunction that returns the type of the value returned by
+// JsonVariant::as<T>()
+template <typename T>
+struct JsonVariantAs {
+ typedef T type;
+};
+
+template <>
+struct JsonVariantAs<char*> {
+ typedef const char* type;
+};
+
+template <>
+struct JsonVariantAs<JsonArray> {
+ typedef JsonArray& type;
+};
+
+template <>
+struct JsonVariantAs<const JsonArray> {
+ typedef const JsonArray& type;
+};
+
+template <>
+struct JsonVariantAs<JsonObject> {
+ typedef JsonObject& type;
+};
+
+template <>
+struct JsonVariantAs<const JsonObject> {
+ typedef const JsonObject& type;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/JsonVariantContent.hpp b/include/lib/ArduinoJson/Data/JsonVariantContent.hpp
new file mode 100644
index 0000000..c525a60
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/JsonVariantContent.hpp
@@ -0,0 +1,27 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "JsonFloat.hpp"
+#include "JsonInteger.hpp"
+
+namespace ArduinoJson {
+
+// Forward declarations
+class JsonArray;
+class JsonObject;
+
+namespace Internals {
+// A union that defines the actual content of a JsonVariant.
+// The enum JsonVariantType determines which member is in use.
+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
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/JsonVariantDefault.hpp b/include/lib/ArduinoJson/Data/JsonVariantDefault.hpp
new file mode 100644
index 0000000..57ecc83
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/JsonVariantDefault.hpp
@@ -0,0 +1,23 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename T>
+struct JsonVariantDefault {
+ static T get() {
+ return T();
+ }
+};
+
+template <typename T>
+struct JsonVariantDefault<const T> : JsonVariantDefault<T> {};
+
+template <typename T>
+struct JsonVariantDefault<T&> : JsonVariantDefault<T> {};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/JsonVariantType.hpp b/include/lib/ArduinoJson/Data/JsonVariantType.hpp
new file mode 100644
index 0000000..21f890e
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/JsonVariantType.hpp
@@ -0,0 +1,27 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+class JsonArray;
+class JsonObject;
+
+namespace Internals {
+
+// Enumerated type to know the current type of a JsonVariant.
+// The value determines which member of JsonVariantContent is used.
+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
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/List.hpp b/include/lib/ArduinoJson/Data/List.hpp
new file mode 100644
index 0000000..506308c
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/List.hpp
@@ -0,0 +1,94 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../JsonBuffer.hpp"
+#include "ListConstIterator.hpp"
+#include "ListIterator.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A singly linked list of T.
+// The linked list is composed of ListNode<T>.
+// It is derived by JsonArray and JsonObject
+template <typename T>
+class List {
+ public:
+ typedef T value_type;
+ typedef ListNode<T> node_type;
+ typedef ListIterator<T> iterator;
+ typedef ListConstIterator<T> const_iterator;
+
+ // Creates an empty List<T> attached to a JsonBuffer.
+ // The JsonBuffer allows to allocate new nodes.
+ // When buffer is NULL, the List is not able to grow and success() returns
+ // false. This is used to identify bad memory allocations and parsing
+ // failures.
+ explicit List(JsonBuffer *buffer) : _buffer(buffer), _firstNode(NULL) {}
+
+ // Returns true if the object is valid
+ // Would return false in the following situation:
+ // - the memory allocation failed (StaticJsonBuffer was too small)
+ // - the JSON parsing failed
+ bool success() const {
+ return _buffer != NULL;
+ }
+
+ // Returns the numbers of elements in the list.
+ // For a JsonObject, it would return the number of key-value pairs
+ 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;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/ListConstIterator.hpp b/include/lib/ArduinoJson/Data/ListConstIterator.hpp
new file mode 100644
index 0000000..a6af685
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/ListConstIterator.hpp
@@ -0,0 +1,50 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "ListNode.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A read-only forward itertor for List<T>
+template <typename T>
+class ListConstIterator {
+ public:
+ explicit ListConstIterator(const ListNode<T> *node = NULL) : _node(node) {}
+
+ const T &operator*() const {
+ return _node->content;
+ }
+ const T *operator->() {
+ return &_node->content;
+ }
+
+ bool operator==(const ListConstIterator<T> &other) const {
+ return _node == other._node;
+ }
+
+ bool operator!=(const ListConstIterator<T> &other) const {
+ return _node != other._node;
+ }
+
+ ListConstIterator<T> &operator++() {
+ if (_node) _node = _node->next;
+ return *this;
+ }
+
+ ListConstIterator<T> &operator+=(size_t distance) {
+ while (_node && distance) {
+ _node = _node->next;
+ --distance;
+ }
+ return *this;
+ }
+
+ private:
+ const ListNode<T> *_node;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/ListIterator.hpp b/include/lib/ArduinoJson/Data/ListIterator.hpp
new file mode 100644
index 0000000..01fa287
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/ListIterator.hpp
@@ -0,0 +1,60 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "ListConstIterator.hpp"
+#include "ListNode.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename T>
+class List;
+
+// A read-write forward iterator for List<T>
+template <typename T>
+class ListIterator {
+ friend class List<T>;
+
+ public:
+ explicit ListIterator(ListNode<T> *node = NULL) : _node(node) {}
+
+ T &operator*() const {
+ return _node->content;
+ }
+ T *operator->() {
+ return &_node->content;
+ }
+
+ bool operator==(const ListIterator<T> &other) const {
+ return _node == other._node;
+ }
+
+ bool operator!=(const ListIterator<T> &other) const {
+ return _node != other._node;
+ }
+
+ ListIterator<T> &operator++() {
+ if (_node) _node = _node->next;
+ return *this;
+ }
+
+ ListIterator<T> &operator+=(size_t distance) {
+ while (_node && distance) {
+ _node = _node->next;
+ --distance;
+ }
+ return *this;
+ }
+
+ operator ListConstIterator<T>() const {
+ return ListConstIterator<T>(_node);
+ }
+
+ private:
+ ListNode<T> *_node;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/ListNode.hpp b/include/lib/ArduinoJson/Data/ListNode.hpp
new file mode 100644
index 0000000..c090712
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/ListNode.hpp
@@ -0,0 +1,24 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include <stddef.h> // for NULL
+
+#include "JsonBufferAllocated.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A node for a singly-linked list.
+// Used by List<T> and its iterators.
+template <typename T>
+struct ListNode : public Internals::JsonBufferAllocated {
+ ListNode() throw() : next(NULL) {}
+
+ ListNode<T> *next;
+ T content;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/NonCopyable.hpp b/include/lib/ArduinoJson/Data/NonCopyable.hpp
new file mode 100644
index 0000000..73f3d8e
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/NonCopyable.hpp
@@ -0,0 +1,23 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A type that cannot be copied
+class NonCopyable {
+ protected:
+ NonCopyable() {}
+
+ private:
+ // copy constructor is private
+ NonCopyable(const NonCopyable&);
+
+ // copy operator is private
+ NonCopyable& operator=(const NonCopyable&);
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/ReferenceType.hpp b/include/lib/ArduinoJson/Data/ReferenceType.hpp
new file mode 100644
index 0000000..1e49117
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/ReferenceType.hpp
@@ -0,0 +1,24 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A type that is meant to be used by reference only (JsonArray and JsonObject)
+class ReferenceType {
+ public:
+ bool operator==(const ReferenceType& other) const {
+ // two JsonArray are equal if they are the same instance
+ // (we don't compare the content)
+ return this == &other;
+ }
+
+ bool operator!=(const ReferenceType& other) const {
+ return this != &other;
+ }
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/ValueSaver.hpp b/include/lib/ArduinoJson/Data/ValueSaver.hpp
new file mode 100644
index 0000000..9750f1a
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/ValueSaver.hpp
@@ -0,0 +1,52 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../JsonBuffer.hpp"
+#include "../JsonVariant.hpp"
+#include "../StringTraits/StringTraits.hpp"
+#include "../TypeTraits/EnableIf.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename Source, typename Enable = void>
+struct ValueSaver {
+ template <typename Destination>
+ static bool save(JsonBuffer*, Destination& destination, Source source) {
+ destination = source;
+ return true;
+ }
+};
+
+template <typename Source>
+struct ValueSaver<
+ Source, typename EnableIf<StringTraits<Source>::should_duplicate>::type> {
+ template <typename Destination>
+ static bool save(JsonBuffer* buffer, Destination& dest, Source source) {
+ if (!StringTraits<Source>::is_null(source)) {
+ typename StringTraits<Source>::duplicate_t dup =
+ StringTraits<Source>::duplicate(source, buffer);
+ if (!dup) return false;
+ dest = dup;
+ } else {
+ dest = reinterpret_cast<const char*>(0);
+ }
+ return true;
+ }
+};
+
+// const char*, const signed char*, const unsigned char*
+template <typename Char>
+struct ValueSaver<
+ Char*, typename EnableIf<!StringTraits<Char*>::should_duplicate>::type> {
+ template <typename Destination>
+ static bool save(JsonBuffer*, Destination& dest, Char* source) {
+ dest = reinterpret_cast<const char*>(source);
+ return true;
+ }
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Deserialization/Comments.hpp b/include/lib/ArduinoJson/Deserialization/Comments.hpp
new file mode 100644
index 0000000..c2c48eb
--- /dev/null
+++ b/include/lib/ArduinoJson/Deserialization/Comments.hpp
@@ -0,0 +1,61 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+template <typename TInput>
+void skipSpacesAndComments(TInput& input) {
+ for (;;) {
+ switch (input.current()) {
+ // spaces
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ input.move();
+ continue;
+
+ // comments
+ case '/':
+ switch (input.next()) {
+ // C-style block comment
+ case '*':
+ input.move(); // skip '/'
+ // no need to skip '*'
+ for (;;) {
+ input.move();
+ if (input.current() == '\0') return;
+ if (input.current() == '*' && input.next() == '/') {
+ input.move(); // skip '*'
+ input.move(); // skip '/'
+ break;
+ }
+ }
+ break;
+
+ // C++-style line comment
+ case '/':
+ // not need to skip "//"
+ for (;;) {
+ input.move();
+ if (input.current() == '\0') return;
+ if (input.current() == '\n') break;
+ }
+ break;
+
+ // not a comment, just a '/'
+ default:
+ return;
+ }
+ break;
+
+ default:
+ return;
+ }
+ }
+}
+}
+}
diff --git a/include/lib/ArduinoJson/Deserialization/JsonParser.hpp b/include/lib/ArduinoJson/Deserialization/JsonParser.hpp
new file mode 100644
index 0000000..4cbaf45
--- /dev/null
+++ b/include/lib/ArduinoJson/Deserialization/JsonParser.hpp
@@ -0,0 +1,102 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../JsonBuffer.hpp"
+#include "../JsonVariant.hpp"
+#include "../TypeTraits/IsConst.hpp"
+#include "StringWriter.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// Parse JSON string to create JsonArrays and JsonObjects
+// This internal class is not indended to be used directly.
+// Instead, use JsonBuffer.parseArray() or .parseObject()
+template <typename TReader, typename TWriter>
+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 <typename TJsonBuffer, typename TString, typename Enable = void>
+struct JsonParserBuilder {
+ typedef typename StringTraits<TString>::Reader InputReader;
+ typedef JsonParser<InputReader, TJsonBuffer &> TParser;
+
+ static TParser makeParser(TJsonBuffer *buffer, TString &json,
+ uint8_t nestingLimit) {
+ return TParser(buffer, InputReader(json), *buffer, nestingLimit);
+ }
+};
+
+template <typename TJsonBuffer, typename TChar>
+struct JsonParserBuilder<TJsonBuffer, TChar *,
+ typename EnableIf<!IsConst<TChar>::value>::type> {
+ typedef typename StringTraits<TChar *>::Reader TReader;
+ typedef StringWriter<TChar> TWriter;
+ typedef JsonParser<TReader, TWriter> TParser;
+
+ static TParser makeParser(TJsonBuffer *buffer, TChar *json,
+ uint8_t nestingLimit) {
+ return TParser(buffer, TReader(json), TWriter(json), nestingLimit);
+ }
+};
+
+template <typename TJsonBuffer, typename TString>
+inline typename JsonParserBuilder<TJsonBuffer, TString>::TParser makeParser(
+ TJsonBuffer *buffer, TString &json, uint8_t nestingLimit) {
+ return JsonParserBuilder<TJsonBuffer, TString>::makeParser(buffer, json,
+ nestingLimit);
+}
+} // namespace Internals
+} // namespace ArduinoJson
diff --git a/include/lib/ArduinoJson/Deserialization/JsonParserImpl.hpp b/include/lib/ArduinoJson/Deserialization/JsonParserImpl.hpp
new file mode 100644
index 0000000..5042673
--- /dev/null
+++ b/include/lib/ArduinoJson/Deserialization/JsonParserImpl.hpp
@@ -0,0 +1,189 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Comments.hpp"
+#include "JsonParser.hpp"
+
+template <typename TReader, typename TWriter>
+inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::eat(
+ TReader &reader, char charToSkip) {
+ skipSpacesAndComments(reader);
+ if (reader.current() != charToSkip) return false;
+ reader.move();
+ return true;
+}
+
+template <typename TReader, typename TWriter>
+inline bool
+ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseAnythingTo(
+ JsonVariant *destination) {
+ skipSpacesAndComments(_reader);
+
+ switch (_reader.current()) {
+ case '[':
+ return parseArrayTo(destination);
+
+ case '{':
+ return parseObjectTo(destination);
+
+ default:
+ return parseStringTo(destination);
+ }
+}
+
+template <typename TReader, typename TWriter>
+inline ArduinoJson::JsonArray &
+ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseArray() {
+ if (_nestingLimit == 0) return JsonArray::invalid();
+ _nestingLimit--;
+
+ // Create an empty array
+ JsonArray &array = _buffer->createArray();
+
+ // Check opening braket
+ if (!eat('[')) goto ERROR_MISSING_BRACKET;
+ if (eat(']')) goto SUCCESS_EMPTY_ARRAY;
+
+ // Read each value
+ for (;;) {
+ // 1 - Parse value
+ JsonVariant value;
+ if (!parseAnythingTo(&value)) goto ERROR_INVALID_VALUE;
+ if (!array.add(value)) goto ERROR_NO_MEMORY;
+
+ // 2 - More values?
+ 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 <typename TReader, typename TWriter>
+inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseArrayTo(
+ JsonVariant *destination) {
+ JsonArray &array = parseArray();
+ if (!array.success()) return false;
+
+ *destination = array;
+ return true;
+}
+
+template <typename TReader, typename TWriter>
+inline ArduinoJson::JsonObject &
+ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseObject() {
+ if (_nestingLimit == 0) return JsonObject::invalid();
+ _nestingLimit--;
+
+ // Create an empty object
+ JsonObject &object = _buffer->createObject();
+
+ // Check opening brace
+ if (!eat('{')) goto ERROR_MISSING_BRACE;
+ if (eat('}')) goto SUCCESS_EMPTY_OBJECT;
+
+ // Read each key value pair
+ for (;;) {
+ // 1 - Parse key
+ const char *key = parseString();
+ if (!key) goto ERROR_INVALID_KEY;
+ if (!eat(':')) goto ERROR_MISSING_COLON;
+
+ // 2 - Parse value
+ JsonVariant value;
+ if (!parseAnythingTo(&value)) goto ERROR_INVALID_VALUE;
+ if (!object.set(key, value)) goto ERROR_NO_MEMORY;
+
+ // 3 - More keys/values?
+ 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 <typename TReader, typename TWriter>
+inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseObjectTo(
+ JsonVariant *destination) {
+ JsonObject &object = parseObject();
+ if (!object.success()) return false;
+
+ *destination = object;
+ return true;
+}
+
+template <typename TReader, typename TWriter>
+inline const char *
+ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseString() {
+ typename RemoveReference<TWriter>::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 == '\\') {
+ // replace char
+ 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 <typename TReader, typename TWriter>
+inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::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;
+}
diff --git a/include/lib/ArduinoJson/Deserialization/StringWriter.hpp b/include/lib/ArduinoJson/Deserialization/StringWriter.hpp
new file mode 100644
index 0000000..fd5507e
--- /dev/null
+++ b/include/lib/ArduinoJson/Deserialization/StringWriter.hpp
@@ -0,0 +1,41 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename TChar>
+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<const char*>(_startPtr);
+ }
+
+ private:
+ TChar** _writePtr;
+ TChar* _startPtr;
+ };
+
+ StringWriter(TChar* buffer) : _ptr(buffer) {}
+
+ String startString() {
+ return String(&_ptr);
+ }
+
+ private:
+ TChar* _ptr;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/DynamicJsonBuffer.hpp b/include/lib/ArduinoJson/DynamicJsonBuffer.hpp
new file mode 100644
index 0000000..bdbd5dd
--- /dev/null
+++ b/include/lib/ArduinoJson/DynamicJsonBuffer.hpp
@@ -0,0 +1,170 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "JsonBufferBase.hpp"
+
+#include <stdlib.h>
+
+#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 <typename TAllocator>
+class DynamicJsonBufferBase
+ : public JsonBufferBase<DynamicJsonBufferBase<TAllocator> > {
+ 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();
+ }
+
+ // Gets the number of bytes occupied in the buffer
+ size_t size() const {
+ size_t total = 0;
+ for (const Block* b = _head; b; b = b->next) total += b->size;
+ return total;
+ }
+
+ // Allocates the specified amount of bytes in the buffer
+ virtual void* alloc(size_t bytes) {
+ alignNextAlloc();
+ return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes);
+ }
+
+ // Resets the buffer.
+ // USE WITH CAUTION: this invalidates all previously allocated data
+ 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<char*>(_parent->allocInHead(1));
+ *end = c;
+ if (_length == 0) _start = end;
+ } else {
+ char* newStart =
+ static_cast<char*>(_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<Block*>(_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;
+};
+}
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#elif defined(__GNUC__)
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+#pragma GCC diagnostic pop
+#endif
+#endif
+
+// Implements a JsonBuffer with dynamic memory allocation.
+// You are strongly encouraged to consider using StaticJsonBuffer which is much
+// more suitable for embedded systems.
+typedef Internals::DynamicJsonBufferBase<Internals::DefaultAllocator>
+ DynamicJsonBuffer;
+}
diff --git a/include/lib/ArduinoJson/JsonArray.hpp b/include/lib/ArduinoJson/JsonArray.hpp
new file mode 100644
index 0000000..2acd2a1
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonArray.hpp
@@ -0,0 +1,227 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Data/JsonBufferAllocated.hpp"
+#include "Data/List.hpp"
+#include "Data/ReferenceType.hpp"
+#include "Data/ValueSaver.hpp"
+#include "JsonVariant.hpp"
+#include "Serialization/JsonPrintable.hpp"
+#include "StringTraits/StringTraits.hpp"
+#include "TypeTraits/EnableIf.hpp"
+#include "TypeTraits/IsArray.hpp"
+#include "TypeTraits/IsFloatingPoint.hpp"
+#include "TypeTraits/IsSame.hpp"
+
+// Returns the size (in bytes) of an array with n elements.
+// Can be very handy to determine the size of a StaticJsonBuffer.
+#define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \
+ (sizeof(JsonArray) + (NUMBER_OF_ELEMENTS) * sizeof(JsonArray::node_type))
+
+namespace ArduinoJson {
+
+// Forward declarations
+class JsonObject;
+class JsonBuffer;
+namespace Internals {
+class JsonArraySubscript;
+}
+
+// An array of JsonVariant.
+//
+// The constructor is private, instances must be created via
+// JsonBuffer::createArray() or JsonBuffer::parseArray().
+// A JsonArray can be serialized to a JSON string via JsonArray::printTo().
+// It can also be deserialized from a JSON string via JsonBuffer::parseArray().
+class JsonArray : public Internals::JsonPrintable<JsonArray>,
+ public Internals::ReferenceType,
+ public Internals::NonCopyable,
+ public Internals::List<JsonVariant>,
+ public Internals::JsonBufferAllocated {
+ public:
+ // Create an empty JsonArray attached to the specified JsonBuffer.
+ // You should not call this constructor directly.
+ // Instead, use JsonBuffer::createArray() or JsonBuffer::parseArray().
+ explicit JsonArray(JsonBuffer *buffer) throw()
+ : Internals::List<JsonVariant>(buffer) {}
+
+ // Gets the value at the specified index
+ const Internals::JsonArraySubscript operator[](size_t index) const;
+
+ // Gets or sets the value at specified index
+ Internals::JsonArraySubscript operator[](size_t index);
+
+ // Adds the specified value at the end of the array.
+ //
+ // bool add(TValue);
+ // TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
+ // std::string, String, JsonArray, JsonObject
+ template <typename T>
+ bool add(const T &value) {
+ return add_impl<const T &>(value);
+ }
+ //
+ // bool add(TValue);
+ // TValue = char*, const char*, const FlashStringHelper*
+ template <typename T>
+ bool add(T *value) {
+ return add_impl<T *>(value);
+ }
+ //
+ // bool add(TValue value, uint8_t decimals);
+ // TValue = float, double
+ template <typename T>
+ DEPRECATED("Second argument is not supported anymore")
+ bool add(T value, uint8_t) {
+ return add_impl<const JsonVariant &>(JsonVariant(value));
+ }
+
+ // Sets the value at specified index.
+ //
+ // bool add(size_t index, const TValue&);
+ // TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
+ // std::string, String, JsonArray, JsonObject
+ template <typename T>
+ bool set(size_t index, const T &value) {
+ return set_impl<const T &>(index, value);
+ }
+ //
+ // bool add(size_t index, TValue);
+ // TValue = char*, const char*, const FlashStringHelper*
+ template <typename T>
+ bool set(size_t index, T *value) {
+ return set_impl<T *>(index, value);
+ }
+ //
+ // bool set(size_t index, TValue value, uint8_t decimals);
+ // TValue = float, double
+ template <typename T>
+ typename Internals::EnableIf<Internals::IsFloatingPoint<T>::value, bool>::type
+ set(size_t index, T value, uint8_t decimals) {
+ return set_impl<const JsonVariant &>(index, JsonVariant(value, decimals));
+ }
+
+ // Gets the value at the specified index.
+ template <typename T>
+ typename Internals::JsonVariantAs<T>::type get(size_t index) const {
+ const_iterator it = begin() += index;
+ return it != end() ? it->as<T>() : Internals::JsonVariantDefault<T>::get();
+ }
+
+ // Check the type of the value at specified index.
+ template <typename T>
+ bool is(size_t index) const {
+ const_iterator it = begin() += index;
+ return it != end() ? it->is<T>() : false;
+ }
+
+ // Creates a JsonArray and adds a reference at the end of the array.
+ // It's a shortcut for JsonBuffer::createArray() and JsonArray::add()
+ JsonArray &createNestedArray();
+
+ // Creates a JsonObject and adds a reference at the end of the array.
+ // It's a shortcut for JsonBuffer::createObject() and JsonArray::add()
+ JsonObject &createNestedObject();
+
+ // Removes element at specified index.
+ void remove(size_t index) {
+ remove(begin() += index);
+ }
+ using Internals::List<JsonVariant>::remove;
+
+ // Returns a reference an invalid JsonArray.
+ // This object is meant to replace a NULL pointer.
+ // This is used when memory allocation or JSON parsing fail.
+ static JsonArray &invalid() {
+ static JsonArray instance(NULL);
+ return instance;
+ }
+
+ // Imports a 1D array
+ template <typename T, size_t N>
+ bool copyFrom(T (&array)[N]) {
+ return copyFrom(array, N);
+ }
+
+ // Imports a 1D array
+ template <typename T>
+ bool copyFrom(T *array, size_t len) {
+ bool ok = true;
+ for (size_t i = 0; i < len; i++) {
+ ok &= add(array[i]);
+ }
+ return ok;
+ }
+
+ // Imports a 2D array
+ template <typename T, size_t N1, size_t N2>
+ 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;
+ }
+
+ // Exports a 1D array
+ template <typename T, size_t N>
+ size_t copyTo(T (&array)[N]) const {
+ return copyTo(array, N);
+ }
+
+ // Exports a 1D array
+ template <typename T>
+ 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;
+ }
+
+ // Exports a 2D array
+ template <typename T, size_t N1, size_t N2>
+ void copyTo(T (&array)[N1][N2]) const {
+ size_t i = 0;
+ for (const_iterator it = begin(); it != end() && i < N1; ++it) {
+ it->as<JsonArray>().copyTo(array[i++]);
+ }
+ }
+
+#if ARDUINOJSON_ENABLE_DEPRECATED
+ DEPRECATED("use remove() instead")
+ FORCE_INLINE void removeAt(size_t index) {
+ return remove(index);
+ }
+#endif
+
+ private:
+ template <typename TValueRef>
+ bool set_impl(size_t index, TValueRef value) {
+ iterator it = begin() += index;
+ if (it == end()) return false;
+ return Internals::ValueSaver<TValueRef>::save(_buffer, *it, value);
+ }
+
+ template <typename TValueRef>
+ bool add_impl(TValueRef value) {
+ iterator it = Internals::List<JsonVariant>::add();
+ if (it == end()) return false;
+ return Internals::ValueSaver<TValueRef>::save(_buffer, *it, value);
+ }
+};
+
+namespace Internals {
+template <>
+struct JsonVariantDefault<JsonArray> {
+ static JsonArray &get() {
+ return JsonArray::invalid();
+ }
+};
+}
+}
diff --git a/include/lib/ArduinoJson/JsonArrayImpl.hpp b/include/lib/ArduinoJson/JsonArrayImpl.hpp
new file mode 100644
index 0000000..924b7ea
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonArrayImpl.hpp
@@ -0,0 +1,26 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "JsonArray.hpp"
+#include "JsonArraySubscript.hpp"
+#include "JsonObject.hpp"
+
+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;
+}
+}
diff --git a/include/lib/ArduinoJson/JsonArraySubscript.hpp b/include/lib/ArduinoJson/JsonArraySubscript.hpp
new file mode 100644
index 0000000..afb4dc1
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonArraySubscript.hpp
@@ -0,0 +1,122 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Configuration.hpp"
+#include "JsonVariantBase.hpp"
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4522)
+#endif
+
+namespace ArduinoJson {
+namespace Internals {
+class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
+ 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;
+ }
+
+ // Replaces the value
+ //
+ // operator=(const TValue&)
+ // TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
+ // std::string, String, JsonArray, JsonObject
+ template <typename T>
+ FORCE_INLINE JsonArraySubscript& operator=(const T& src) {
+ _array.set(_index, src);
+ return *this;
+ }
+ //
+ // operator=(TValue)
+ // TValue = char*, const char*, const FlashStringHelper*
+ template <typename T>
+ FORCE_INLINE JsonArraySubscript& operator=(T* src) {
+ _array.set(_index, src);
+ return *this;
+ }
+
+ FORCE_INLINE bool success() const {
+ return _index < _array.size();
+ }
+
+ template <typename T>
+ FORCE_INLINE typename JsonVariantAs<T>::type as() const {
+ return _array.get<T>(_index);
+ }
+
+ template <typename T>
+ FORCE_INLINE bool is() const {
+ return _array.is<T>(_index);
+ }
+
+ // Replaces the value
+ //
+ // bool set(const TValue&)
+ // TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
+ // std::string, String, JsonArray, JsonObject
+ template <typename TValue>
+ FORCE_INLINE bool set(const TValue& value) {
+ return _array.set(_index, value);
+ }
+ //
+ // bool set(TValue)
+ // TValue = char*, const char*, const FlashStringHelper*
+ template <typename TValue>
+ FORCE_INLINE bool set(TValue* value) {
+ return _array.set(_index, value);
+ }
+ //
+ // bool set(TValue, uint8_t decimals);
+ // TValue = float, double
+ template <typename TValue>
+ 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 <typename TImpl>
+inline JsonArraySubscript JsonVariantSubscripts<TImpl>::operator[](
+ size_t index) {
+ return impl()->template as<JsonArray>()[index];
+}
+
+template <typename TImpl>
+inline const JsonArraySubscript JsonVariantSubscripts<TImpl>::operator[](
+ size_t index) const {
+ return impl()->template as<JsonArray>()[index];
+}
+
+#if ARDUINOJSON_ENABLE_STD_STREAM
+inline std::ostream& operator<<(std::ostream& os,
+ const JsonArraySubscript& source) {
+ return source.printTo(os);
+}
+#endif
+}
+
+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<JsonArray*>(this), index);
+}
+}
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
diff --git a/include/lib/ArduinoJson/JsonBuffer.hpp b/include/lib/ArduinoJson/JsonBuffer.hpp
new file mode 100644
index 0000000..26101e0
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonBuffer.hpp
@@ -0,0 +1,78 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint8_t
+#include <string.h>
+
+#include "Data/NonCopyable.hpp"
+#include "JsonVariant.hpp"
+#include "TypeTraits/EnableIf.hpp"
+#include "TypeTraits/IsArray.hpp"
+
+namespace ArduinoJson {
+class JsonArray;
+class JsonObject;
+
+// Entry point for using the library.
+//
+// Handle the memory management (done in derived classes) and calls the parser.
+// This abstract class is implemented by StaticJsonBuffer which implements a
+// fixed memory allocation.
+class JsonBuffer : Internals::NonCopyable {
+ public:
+ // Allocates an empty JsonArray.
+ //
+ // Returns a reference to the new JsonArray or JsonArray::invalid() if the
+ // allocation fails.
+ JsonArray &createArray();
+
+ // Allocates an empty JsonObject.
+ //
+ // Returns a reference to the new JsonObject or JsonObject::invalid() if the
+ // allocation fails.
+ JsonObject &createObject();
+
+ // Duplicates a string
+ //
+ // const char* strdup(TValue);
+ // TValue = const std::string&, const String&,
+ template <typename TString>
+ DEPRECATED("char* are duplicated, you don't need strdup() anymore")
+ typename Internals::EnableIf<!Internals::IsArray<TString>::value,
+ const char *>::type strdup(const TString &src) {
+ return Internals::StringTraits<TString>::duplicate(src, this);
+ }
+ //
+ // const char* strdup(TValue);
+ // TValue = char*, const char*, const FlashStringHelper*
+ template <typename TString>
+ DEPRECATED("char* are duplicated, you don't need strdup() anymore")
+ const char *strdup(TString *src) {
+ return Internals::StringTraits<TString *>::duplicate(src, this);
+ }
+
+ // Allocates n bytes in the JsonBuffer.
+ // Return a pointer to the allocated memory or NULL if allocation fails.
+ virtual void *alloc(size_t size) = 0;
+
+ protected:
+ // CAUTION: NO VIRTUAL DESTRUCTOR!
+ // If we add a virtual constructor the Arduino compiler will add malloc()
+ // and free() to the binary, adding 706 useless bytes.
+ ~JsonBuffer() {}
+
+ // Preserve aligment if necessary
+ 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
+ }
+};
+}
diff --git a/include/lib/ArduinoJson/JsonBufferBase.hpp b/include/lib/ArduinoJson/JsonBufferBase.hpp
new file mode 100644
index 0000000..1e771bf
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonBufferBase.hpp
@@ -0,0 +1,127 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Deserialization/JsonParser.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+template <typename TDerived>
+class JsonBufferBase : public JsonBuffer {
+ public:
+ // Allocates and populate a JsonArray from a JSON string.
+ //
+ // The First argument is a pointer to the JSON string, the memory must be
+ // writable
+ // because the parser will insert null-terminators and replace escaped chars.
+ //
+ // The second argument set the nesting limit
+ //
+ // Returns a reference to the new JsonObject or JsonObject::invalid() if the
+ // allocation fails.
+ // With this overload, the JsonBuffer will make a copy of the string
+ //
+ // JsonArray& parseArray(TString);
+ // TString = const std::string&, const String&
+ template <typename TString>
+ typename Internals::EnableIf<!Internals::IsArray<TString>::value,
+ JsonArray &>::type
+ parseArray(const TString &json,
+ uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+ return Internals::makeParser(that(), json, nestingLimit).parseArray();
+ }
+ //
+ // JsonArray& parseArray(TString);
+ // TString = const char*, const char[N], const FlashStringHelper*
+ template <typename TString>
+ JsonArray &parseArray(
+ TString *json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+ return Internals::makeParser(that(), json, nestingLimit).parseArray();
+ }
+ //
+ // JsonArray& parseArray(TString);
+ // TString = std::istream&, Stream&
+ template <typename TString>
+ JsonArray &parseArray(
+ TString &json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+ return Internals::makeParser(that(), json, nestingLimit).parseArray();
+ }
+
+ // Allocates and populate a JsonObject from a JSON string.
+ //
+ // The First argument is a pointer to the JSON string, the memory must be
+ // writable
+ // because the parser will insert null-terminators and replace escaped chars.
+ //
+ // The second argument set the nesting limit
+ //
+ // Returns a reference to the new JsonObject or JsonObject::invalid() if the
+ // allocation fails.
+ //
+ // JsonObject& parseObject(TString);
+ // TString = const std::string&, const String&
+ template <typename TString>
+ typename Internals::EnableIf<!Internals::IsArray<TString>::value,
+ JsonObject &>::type
+ parseObject(const TString &json,
+ uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+ return Internals::makeParser(that(), json, nestingLimit).parseObject();
+ }
+ //
+ // JsonObject& parseObject(TString);
+ // TString = const char*, const char[N], const FlashStringHelper*
+ template <typename TString>
+ JsonObject &parseObject(
+ TString *json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+ return Internals::makeParser(that(), json, nestingLimit).parseObject();
+ }
+ //
+ // JsonObject& parseObject(TString);
+ // TString = std::istream&, Stream&
+ template <typename TString>
+ JsonObject &parseObject(
+ TString &json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+ return Internals::makeParser(that(), json, nestingLimit).parseObject();
+ }
+
+ // Generalized version of parseArray() and parseObject(), also works for
+ // integral types.
+ //
+ // JsonVariant parse(TString);
+ // TString = const std::string&, const String&
+ template <typename TString>
+ typename Internals::EnableIf<!Internals::IsArray<TString>::value,
+ JsonVariant>::type
+ parse(const TString &json,
+ uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+ return Internals::makeParser(that(), json, nestingLimit).parseVariant();
+ }
+ //
+ // JsonVariant parse(TString);
+ // TString = const char*, const char[N], const FlashStringHelper*
+ template <typename TString>
+ JsonVariant parse(TString *json,
+ uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+ return Internals::makeParser(that(), json, nestingLimit).parseVariant();
+ }
+ //
+ // JsonVariant parse(TString);
+ // TString = std::istream&, Stream&
+ template <typename TString>
+ 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<TDerived *>(this);
+ }
+};
+}
+}
diff --git a/include/lib/ArduinoJson/JsonBufferImpl.hpp b/include/lib/ArduinoJson/JsonBufferImpl.hpp
new file mode 100644
index 0000000..cdea374
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonBufferImpl.hpp
@@ -0,0 +1,17 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Deserialization/JsonParser.hpp"
+
+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();
+}
diff --git a/include/lib/ArduinoJson/JsonObject.hpp b/include/lib/ArduinoJson/JsonObject.hpp
new file mode 100644
index 0000000..caf698a
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonObject.hpp
@@ -0,0 +1,328 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Data/JsonBufferAllocated.hpp"
+#include "Data/List.hpp"
+#include "Data/ReferenceType.hpp"
+#include "Data/ValueSaver.hpp"
+#include "JsonPair.hpp"
+#include "Serialization/JsonPrintable.hpp"
+#include "StringTraits/StringTraits.hpp"
+#include "TypeTraits/EnableIf.hpp"
+#include "TypeTraits/IsArray.hpp"
+#include "TypeTraits/IsFloatingPoint.hpp"
+#include "TypeTraits/IsSame.hpp"
+
+// Returns the size (in bytes) of an object with n elements.
+// Can be very handy to determine the size of a StaticJsonBuffer.
+#define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \
+ (sizeof(JsonObject) + (NUMBER_OF_ELEMENTS) * sizeof(JsonObject::node_type))
+
+namespace ArduinoJson {
+
+// Forward declarations
+class JsonArray;
+class JsonBuffer;
+namespace Internals {
+template <typename>
+class JsonObjectSubscript;
+}
+
+// A dictionary of JsonVariant indexed by string (char*)
+//
+// The constructor is private, instances must be created via
+// JsonBuffer::createObject() or JsonBuffer::parseObject().
+// A JsonObject can be serialized to a JSON string via JsonObject::printTo().
+// It can also be deserialized from a JSON string via JsonBuffer::parseObject().
+class JsonObject : public Internals::JsonPrintable<JsonObject>,
+ public Internals::ReferenceType,
+ public Internals::NonCopyable,
+ public Internals::List<JsonPair>,
+ public Internals::JsonBufferAllocated {
+ public:
+ // Create an empty JsonArray attached to the specified JsonBuffer.
+ // You should not use this constructor directly.
+ // Instead, use JsonBuffer::createObject() or JsonBuffer.parseObject().
+ explicit JsonObject(JsonBuffer* buffer) throw()
+ : Internals::List<JsonPair>(buffer) {}
+
+ // Gets or sets the value associated with the specified key.
+ //
+ // JsonObjectSubscript operator[](TKey)
+ // TKey = const std::string&, const String&
+ template <typename TString>
+ Internals::JsonObjectSubscript<const TString&> operator[](
+ const TString& key) {
+ return Internals::JsonObjectSubscript<const TString&>(*this, key);
+ }
+ //
+ // JsonObjectSubscript operator[](TKey)
+ // TKey = char*, const char*, char[], const char[N], const FlashStringHelper*
+ template <typename TString>
+ Internals::JsonObjectSubscript<TString*> operator[](TString* key) {
+ return Internals::JsonObjectSubscript<TString*>(*this, key);
+ }
+
+ // Gets the value associated with the specified key.
+ //
+ // const JsonObjectSubscript operator[](TKey) const;
+ // TKey = const std::string&, const String&
+ template <typename TString>
+ const Internals::JsonObjectSubscript<const TString&> operator[](
+ const TString& key) const {
+ return Internals::JsonObjectSubscript<const TString&>(
+ *const_cast<JsonObject*>(this), key);
+ }
+ //
+ // const JsonObjectSubscript operator[](TKey) const;
+ // TKey = const char*, const char[N], const FlashStringHelper*
+ template <typename TString>
+ const Internals::JsonObjectSubscript<TString*> operator[](
+ TString* key) const {
+ return Internals::JsonObjectSubscript<TString*>(
+ *const_cast<JsonObject*>(this), key);
+ }
+
+ // Sets the specified key with the specified value.
+ //
+ // bool set(TKey, TValue);
+ // TKey = const std::string&, const String&
+ // TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
+ // std::string, String, JsonArray, JsonObject
+ template <typename TValue, typename TString>
+ bool set(const TString& key, const TValue& value) {
+ return set_impl<const TString&, const TValue&>(key, value);
+ }
+ //
+ // bool set(TKey, TValue);
+ // TKey = const std::string&, const String&
+ // TValue = char*, const char*, const FlashStringHelper*
+ template <typename TValue, typename TString>
+ bool set(const TString& key, TValue* value) {
+ return set_impl<const TString&, TValue*>(key, value);
+ }
+ //
+ // bool set(TKey, const TValue&);
+ // TKey = char*, const char*, const FlashStringHelper*
+ // TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
+ // std::string, String, JsonArray, JsonObject
+ template <typename TValue, typename TString>
+ bool set(TString* key, const TValue& value) {
+ return set_impl<TString*, const TValue&>(key, value);
+ }
+ //
+ // bool set(TKey, TValue);
+ // TKey = char*, const char*, const FlashStringHelper*
+ // TValue = char*, const char*, const FlashStringHelper*
+ template <typename TValue, typename TString>
+ bool set(TString* key, TValue* value) {
+ return set_impl<TString*, TValue*>(key, value);
+ }
+ //
+ // bool set(TKey, TValue, uint8_t decimals);
+ // TKey = const std::string&, const String&
+ // TValue = float, double
+ template <typename TValue, typename TString>
+ DEPRECATED("Second argument is not supported anymore")
+ typename Internals::EnableIf<Internals::IsFloatingPoint<TValue>::value,
+ bool>::type
+ set(const TString& key, TValue value, uint8_t) {
+ return set_impl<const TString&, const JsonVariant&>(key,
+ JsonVariant(value));
+ }
+ //
+ // bool set(TKey, TValue, uint8_t decimals);
+ // TKey = char*, const char*, const FlashStringHelper*
+ // TValue = float, double
+ template <typename TValue, typename TString>
+ DEPRECATED("Second argument is not supported anymore")
+ typename Internals::EnableIf<Internals::IsFloatingPoint<TValue>::value,
+ bool>::type
+ set(TString* key, TValue value, uint8_t) {
+ return set_impl<TString*, const JsonVariant&>(key, JsonVariant(value));
+ }
+
+ // Gets the value associated with the specified key.
+ //
+ // TValue get<TValue>(TKey) const;
+ // TKey = const std::string&, const String&
+ // TValue = bool, char, long, int, short, float, double,
+ // std::string, String, JsonArray, JsonObject
+ template <typename TValue, typename TString>
+ typename Internals::JsonVariantAs<TValue>::type get(
+ const TString& key) const {
+ return get_impl<const TString&, TValue>(key);
+ }
+ //
+ // TValue get<TValue>(TKey) const;
+ // TKey = char*, const char*, const FlashStringHelper*
+ // TValue = bool, char, long, int, short, float, double,
+ // std::string, String, JsonArray, JsonObject
+ template <typename TValue, typename TString>
+ typename Internals::JsonVariantAs<TValue>::type get(TString* key) const {
+ return get_impl<TString*, TValue>(key);
+ }
+
+ // Checks the type of the value associated with the specified key.
+ //
+ //
+ // bool is<TValue>(TKey) const;
+ // TKey = const std::string&, const String&
+ // TValue = bool, char, long, int, short, float, double,
+ // std::string, String, JsonArray, JsonObject
+ template <typename TValue, typename TString>
+ bool is(const TString& key) const {
+ return is_impl<const TString&, TValue>(key);
+ }
+ //
+ // bool is<TValue>(TKey) const;
+ // TKey = char*, const char*, const FlashStringHelper*
+ // TValue = bool, char, long, int, short, float, double,
+ // std::string, String, JsonArray, JsonObject
+ template <typename TValue, typename TString>
+ bool is(TString* key) const {
+ return is_impl<TString*, TValue>(key);
+ }
+
+ // Creates and adds a JsonArray.
+ //
+ // JsonArray& createNestedArray(TKey);
+ // TKey = const std::string&, const String&
+ template <typename TString>
+ JsonArray& createNestedArray(const TString& key) {
+ return createNestedArray_impl<const TString&>(key);
+ }
+ // JsonArray& createNestedArray(TKey);
+ // TKey = char*, const char*, char[], const char[], const FlashStringHelper*
+ template <typename TString>
+ JsonArray& createNestedArray(TString* key) {
+ return createNestedArray_impl<TString*>(key);
+ }
+
+ // Creates and adds a JsonObject.
+ //
+ // JsonObject& createNestedObject(TKey);
+ // TKey = const std::string&, const String&
+ template <typename TString>
+ JsonObject& createNestedObject(const TString& key) {
+ return createNestedObject_impl<const TString&>(key);
+ }
+ //
+ // JsonObject& createNestedObject(TKey);
+ // TKey = char*, const char*, char[], const char[], const FlashStringHelper*
+ template <typename TString>
+ JsonObject& createNestedObject(TString* key) {
+ return createNestedObject_impl<TString*>(key);
+ }
+
+ // Tells weither the specified key is present and associated with a value.
+ //
+ // bool containsKey(TKey);
+ // TKey = const std::string&, const String&
+ template <typename TString>
+ bool containsKey(const TString& key) const {
+ return findKey<const TString&>(key) != end();
+ }
+ //
+ // bool containsKey(TKey);
+ // TKey = char*, const char*, char[], const char[], const FlashStringHelper*
+ template <typename TString>
+ bool containsKey(TString* key) const {
+ return findKey<TString*>(key) != end();
+ }
+
+ // Removes the specified key and the associated value.
+ //
+ // void remove(TKey);
+ // TKey = const std::string&, const String&
+ template <typename TString>
+ void remove(const TString& key) {
+ remove(findKey<const TString&>(key));
+ }
+ //
+ // void remove(TKey);
+ // TKey = char*, const char*, char[], const char[], const FlashStringHelper*
+ template <typename TString>
+ void remove(TString* key) {
+ remove(findKey<TString*>(key));
+ }
+ //
+ // void remove(iterator)
+ using Internals::List<JsonPair>::remove;
+
+ // Returns a reference an invalid JsonObject.
+ // This object is meant to replace a NULL pointer.
+ // This is used when memory allocation or JSON parsing fail.
+ static JsonObject& invalid() {
+ static JsonObject instance(NULL);
+ return instance;
+ }
+
+ private:
+ // Returns the list node that matches the specified key.
+ template <typename TStringRef>
+ iterator findKey(TStringRef key) {
+ iterator it;
+ for (it = begin(); it != end(); ++it) {
+ if (Internals::StringTraits<TStringRef>::equals(key, it->key)) break;
+ }
+ return it;
+ }
+ template <typename TStringRef>
+ const_iterator findKey(TStringRef key) const {
+ return const_cast<JsonObject*>(this)->findKey<TStringRef>(key);
+ }
+
+ template <typename TStringRef, typename TValue>
+ typename Internals::JsonVariantAs<TValue>::type get_impl(
+ TStringRef key) const {
+ const_iterator it = findKey<TStringRef>(key);
+ return it != end() ? it->value.as<TValue>()
+ : Internals::JsonVariantDefault<TValue>::get();
+ }
+
+ template <typename TStringRef, typename TValueRef>
+ bool set_impl(TStringRef key, TValueRef value) {
+ // ignore null key
+ if (Internals::StringTraits<TStringRef>::is_null(key)) return false;
+
+ // search a matching key
+ iterator it = findKey<TStringRef>(key);
+ if (it == end()) {
+ // add the key
+ it = Internals::List<JsonPair>::add();
+ if (it == end()) return false;
+ bool key_ok =
+ Internals::ValueSaver<TStringRef>::save(_buffer, it->key, key);
+ if (!key_ok) return false;
+ }
+
+ // save the value
+ return Internals::ValueSaver<TValueRef>::save(_buffer, it->value, value);
+ }
+
+ template <typename TStringRef, typename TValue>
+ bool is_impl(TStringRef key) const {
+ const_iterator it = findKey<TStringRef>(key);
+ return it != end() ? it->value.is<TValue>() : false;
+ }
+
+ template <typename TStringRef>
+ JsonArray& createNestedArray_impl(TStringRef key);
+
+ template <typename TStringRef>
+ JsonObject& createNestedObject_impl(TStringRef key);
+};
+
+namespace Internals {
+template <>
+struct JsonVariantDefault<JsonObject> {
+ static JsonObject& get() {
+ return JsonObject::invalid();
+ }
+};
+} // namespace Internals
+} // namespace ArduinoJson
diff --git a/include/lib/ArduinoJson/JsonObjectImpl.hpp b/include/lib/ArduinoJson/JsonObjectImpl.hpp
new file mode 100644
index 0000000..e7689b5
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonObjectImpl.hpp
@@ -0,0 +1,28 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "JsonArray.hpp"
+#include "JsonObject.hpp"
+#include "JsonObjectSubscript.hpp"
+
+namespace ArduinoJson {
+
+template <typename TStringRef>
+inline JsonArray &JsonObject::createNestedArray_impl(TStringRef key) {
+ if (!_buffer) return JsonArray::invalid();
+ JsonArray &array = _buffer->createArray();
+ set(key, array);
+ return array;
+}
+
+template <typename TStringRef>
+inline JsonObject &JsonObject::createNestedObject_impl(TStringRef key) {
+ if (!_buffer) return JsonObject::invalid();
+ JsonObject &object = _buffer->createObject();
+ set(key, object);
+ return object;
+}
+}
diff --git a/include/lib/ArduinoJson/JsonObjectSubscript.hpp b/include/lib/ArduinoJson/JsonObjectSubscript.hpp
new file mode 100644
index 0000000..6ac4763
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonObjectSubscript.hpp
@@ -0,0 +1,110 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Configuration.hpp"
+#include "JsonVariantBase.hpp"
+#include "TypeTraits/EnableIf.hpp"
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4522)
+#endif
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename TStringRef>
+class JsonObjectSubscript
+ : public JsonVariantBase<JsonObjectSubscript<TStringRef> > {
+ typedef JsonObjectSubscript<TStringRef> 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;
+ }
+
+ // Set the specified value
+ //
+ // operator=(const TValue&);
+ // TValue = bool, char, long, int, short, float, double,
+ // std::string, String, JsonArray, JsonObject
+ template <typename TValue>
+ FORCE_INLINE typename EnableIf<!IsArray<TValue>::value, this_type&>::type
+ operator=(const TValue& src) {
+ _object.set(_key, src);
+ return *this;
+ }
+ //
+ // operator=(TValue);
+ // TValue = char*, const char*, const FlashStringHelper*
+ template <typename TValue>
+ FORCE_INLINE this_type& operator=(TValue* src) {
+ _object.set(_key, src);
+ return *this;
+ }
+
+ FORCE_INLINE bool success() const {
+ return _object.containsKey(_key);
+ }
+
+ template <typename TValue>
+ FORCE_INLINE typename JsonVariantAs<TValue>::type as() const {
+ return _object.get<TValue>(_key);
+ }
+
+ template <typename TValue>
+ FORCE_INLINE bool is() const {
+ return _object.is<TValue>(_key);
+ }
+
+ // Sets the specified value.
+ //
+ // bool set(const TValue&);
+ // TValue = bool, char, long, int, short, float, double, RawJson, JsonVariant,
+ // std::string, String, JsonArray, JsonObject
+ template <typename TValue>
+ FORCE_INLINE typename EnableIf<!IsArray<TValue>::value, bool>::type set(
+ const TValue& value) {
+ return _object.set(_key, value);
+ }
+ //
+ // bool set(TValue);
+ // TValue = char*, const char, const FlashStringHelper*
+ template <typename TValue>
+ FORCE_INLINE bool set(const TValue* value) {
+ return _object.set(_key, value);
+ }
+ //
+ // bool set(TValue, uint8_t decimals);
+ // TValue = float, double
+ template <typename TValue>
+ 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 <typename TStringRef>
+inline std::ostream& operator<<(std::ostream& os,
+ const JsonObjectSubscript<TStringRef>& source) {
+ return source.printTo(os);
+}
+#endif
+}
+}
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
diff --git a/include/lib/ArduinoJson/JsonPair.hpp b/include/lib/ArduinoJson/JsonPair.hpp
new file mode 100644
index 0000000..4172430
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonPair.hpp
@@ -0,0 +1,16 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "JsonVariant.hpp"
+
+namespace ArduinoJson {
+
+// A key value pair for JsonObject.
+struct JsonPair {
+ const char* key;
+ JsonVariant value;
+};
+}
diff --git a/include/lib/ArduinoJson/JsonVariant.hpp b/include/lib/ArduinoJson/JsonVariant.hpp
new file mode 100644
index 0000000..8326cbe
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonVariant.hpp
@@ -0,0 +1,355 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h> // for uint8_t
+
+#include "Data/JsonVariantContent.hpp"
+#include "Data/JsonVariantDefault.hpp"
+#include "Data/JsonVariantType.hpp"
+#include "JsonVariantBase.hpp"
+#include "RawJson.hpp"
+#include "Serialization/JsonPrintable.hpp"
+#include "TypeTraits/EnableIf.hpp"
+#include "TypeTraits/IsChar.hpp"
+#include "TypeTraits/IsFloatingPoint.hpp"
+#include "TypeTraits/IsIntegral.hpp"
+#include "TypeTraits/IsSame.hpp"
+#include "TypeTraits/IsSignedIntegral.hpp"
+#include "TypeTraits/IsUnsignedIntegral.hpp"
+#include "TypeTraits/RemoveConst.hpp"
+#include "TypeTraits/RemoveReference.hpp"
+
+namespace ArduinoJson {
+
+// Forward declarations.
+class JsonArray;
+class JsonObject;
+
+// A variant that can be a any value serializable to a JSON value.
+//
+// It can be set to:
+// - a boolean
+// - a char, short, int or a long (signed or unsigned)
+// - a string (const char*)
+// - a reference to a JsonArray or JsonObject
+class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
+ template <typename Print>
+ friend class Internals::JsonSerializer;
+
+ public:
+ // Creates an uninitialized JsonVariant
+ JsonVariant() : _type(Internals::JSON_UNDEFINED) {}
+
+ // Create a JsonVariant containing a boolean value.
+ // It will be serialized as "true" or "false" in JSON.
+ JsonVariant(bool value) {
+ using namespace Internals;
+ _type = JSON_BOOLEAN;
+ _content.asInteger = static_cast<JsonUInt>(value);
+ }
+
+ // Create a JsonVariant containing a floating point value.
+ // JsonVariant(double value);
+ // JsonVariant(float value);
+ template <typename T>
+ JsonVariant(T value, typename Internals::EnableIf<
+ Internals::IsFloatingPoint<T>::value>::type * = 0) {
+ using namespace Internals;
+ _type = JSON_FLOAT;
+ _content.asFloat = static_cast<JsonFloat>(value);
+ }
+ template <typename T>
+ DEPRECATED("Second argument is not supported anymore")
+ JsonVariant(T value, uint8_t,
+ typename Internals::EnableIf<
+ Internals::IsFloatingPoint<T>::value>::type * = 0) {
+ using namespace Internals;
+ _type = JSON_FLOAT;
+ _content.asFloat = static_cast<JsonFloat>(value);
+ }
+
+ // Create a JsonVariant containing an integer value.
+ // JsonVariant(char)
+ // JsonVariant(signed short)
+ // JsonVariant(signed int)
+ // JsonVariant(signed long)
+ // JsonVariant(signed char)
+ template <typename T>
+ JsonVariant(
+ T value,
+ typename Internals::EnableIf<Internals::IsSignedIntegral<T>::value ||
+ Internals::IsSame<T, char>::value>::type * =
+ 0) {
+ using namespace Internals;
+ if (value >= 0) {
+ _type = JSON_POSITIVE_INTEGER;
+ _content.asInteger = static_cast<JsonUInt>(value);
+ } else {
+ _type = JSON_NEGATIVE_INTEGER;
+ _content.asInteger = static_cast<JsonUInt>(-value);
+ }
+ }
+ // JsonVariant(unsigned short)
+ // JsonVariant(unsigned int)
+ // JsonVariant(unsigned long)
+ template <typename T>
+ JsonVariant(T value,
+ typename Internals::EnableIf<
+ Internals::IsUnsignedIntegral<T>::value>::type * = 0) {
+ using namespace Internals;
+ _type = JSON_POSITIVE_INTEGER;
+ _content.asInteger = static_cast<JsonUInt>(value);
+ }
+
+ // Create a JsonVariant containing a string.
+ // JsonVariant(const char*);
+ // JsonVariant(const signed char*);
+ // JsonVariant(const unsigned char*);
+ template <typename TChar>
+ JsonVariant(
+ const TChar *value,
+ typename Internals::EnableIf<Internals::IsChar<TChar>::value>::type * =
+ 0) {
+ _type = Internals::JSON_STRING;
+ _content.asString = reinterpret_cast<const char *>(value);
+ }
+
+ // Create a JsonVariant containing an unparsed string
+ JsonVariant(Internals::RawJsonString<const char *> value) {
+ _type = Internals::JSON_UNPARSED;
+ _content.asString = value;
+ }
+
+ // Create a JsonVariant containing a reference to an array.
+ // CAUTION: we are lying about constness, because the array can be modified if
+ // the variant is converted back to a JsonArray&
+ JsonVariant(const JsonArray &array);
+
+ // Create a JsonVariant containing a reference to an object.
+ // CAUTION: we are lying about constness, because the object can be modified
+ // if the variant is converted back to a JsonObject&
+ JsonVariant(const JsonObject &object);
+
+ // Get the variant as the specified type.
+ //
+ // char as<char>() const;
+ // signed char as<signed char>() const;
+ // signed short as<signed short>() const;
+ // signed int as<signed int>() const;
+ // signed long as<signed long>() const;
+ // unsigned char as<unsigned char>() const;
+ // unsigned short as<unsigned short>() const;
+ // unsigned int as<unsigned int>() const;
+ // unsigned long as<unsigned long>() const;
+ template <typename T>
+ const typename Internals::EnableIf<Internals::IsIntegral<T>::value, T>::type
+ as() const {
+ return variantAsInteger<T>();
+ }
+ // bool as<bool>() const
+ template <typename T>
+ const typename Internals::EnableIf<Internals::IsSame<T, bool>::value, T>::type
+ as() const {
+ return variantAsInteger<int>() != 0;
+ }
+ //
+ // double as<double>() const;
+ // float as<float>() const;
+ template <typename T>
+ const typename Internals::EnableIf<Internals::IsFloatingPoint<T>::value,
+ T>::type
+ as() const {
+ return variantAsFloat<T>();
+ }
+ //
+ // const char* as<const char*>() const;
+ // const char* as<char*>() const;
+ template <typename T>
+ typename Internals::EnableIf<Internals::IsSame<T, const char *>::value ||
+ Internals::IsSame<T, char *>::value,
+ const char *>::type
+ as() const {
+ return variantAsString();
+ }
+ //
+ // std::string as<std::string>() const;
+ // String as<String>() const;
+ template <typename T>
+ typename Internals::EnableIf<Internals::StringTraits<T>::has_append, T>::type
+ as() const {
+ const char *cstr = variantAsString();
+ if (cstr) return T(cstr);
+ T s;
+ printTo(s);
+ return s;
+ }
+ //
+ // JsonArray& as<JsonArray> const;
+ // JsonArray& as<JsonArray&> const;
+ template <typename T>
+ typename Internals::EnableIf<
+ Internals::IsSame<typename Internals::RemoveReference<T>::type,
+ JsonArray>::value,
+ JsonArray &>::type
+ as() const {
+ return variantAsArray();
+ }
+ //
+ // const JsonArray& as<const JsonArray&> const;
+ template <typename T>
+ typename Internals::EnableIf<
+ Internals::IsSame<typename Internals::RemoveReference<T>::type,
+ const JsonArray>::value,
+ const JsonArray &>::type
+ as() const {
+ return variantAsArray();
+ }
+ //
+ // JsonObject& as<JsonObject> const;
+ // JsonObject& as<JsonObject&> const;
+ template <typename T>
+ typename Internals::EnableIf<
+ Internals::IsSame<typename Internals::RemoveReference<T>::type,
+ JsonObject>::value,
+ JsonObject &>::type
+ as() const {
+ return variantAsObject();
+ }
+ //
+ // JsonObject& as<const JsonObject> const;
+ // JsonObject& as<const JsonObject&> const;
+ template <typename T>
+ typename Internals::EnableIf<
+ Internals::IsSame<typename Internals::RemoveReference<T>::type,
+ const JsonObject>::value,
+ const JsonObject &>::type
+ as() const {
+ return variantAsObject();
+ }
+ //
+ // JsonVariant as<JsonVariant> const;
+ template <typename T>
+ typename Internals::EnableIf<Internals::IsSame<T, JsonVariant>::value,
+ T>::type
+ as() const {
+ return *this;
+ }
+
+ // Tells weither the variant has the specified type.
+ // Returns true if the variant has type type T, false otherwise.
+ //
+ // bool is<char>() const;
+ // bool is<signed char>() const;
+ // bool is<signed short>() const;
+ // bool is<signed int>() const;
+ // bool is<signed long>() const;
+ // bool is<unsigned char>() const;
+ // bool is<unsigned short>() const;
+ // bool is<unsigned int>() const;
+ // bool is<unsigned long>() const;
+ template <typename T>
+ typename Internals::EnableIf<Internals::IsIntegral<T>::value, bool>::type is()
+ const {
+ return variantIsInteger();
+ }
+ //
+ // bool is<double>() const;
+ // bool is<float>() const;
+ template <typename T>
+ typename Internals::EnableIf<Internals::IsFloatingPoint<T>::value, bool>::type
+ is() const {
+ return variantIsFloat();
+ }
+ //
+ // bool is<bool>() const
+ template <typename T>
+ typename Internals::EnableIf<Internals::IsSame<T, bool>::value, bool>::type
+ is() const {
+ return variantIsBoolean();
+ }
+ //
+ // bool is<const char*>() const;
+ // bool is<char*>() const;
+ template <typename T>
+ typename Internals::EnableIf<Internals::IsSame<T, const char *>::value ||
+ Internals::IsSame<T, char *>::value,
+ bool>::type
+ is() const {
+ return variantIsString();
+ }
+ //
+ // bool is<JsonArray> const;
+ // bool is<JsonArray&> const;
+ // bool is<const JsonArray&> const;
+ template <typename T>
+ typename Internals::EnableIf<
+ Internals::IsSame<typename Internals::RemoveConst<
+ typename Internals::RemoveReference<T>::type>::type,
+ JsonArray>::value,
+ bool>::type
+ is() const {
+ return variantIsArray();
+ }
+ //
+ // bool is<JsonObject> const;
+ // bool is<JsonObject&> const;
+ // bool is<const JsonObject&> const;
+ template <typename T>
+ typename Internals::EnableIf<
+ Internals::IsSame<typename Internals::RemoveConst<
+ typename Internals::RemoveReference<T>::type>::type,
+ JsonObject>::value,
+ bool>::type
+ is() const {
+ return variantIsObject();
+ }
+
+ // Returns true if the variant has a value
+ bool success() const {
+ return _type != Internals::JSON_UNDEFINED;
+ }
+
+ private:
+ JsonArray &variantAsArray() const;
+ JsonObject &variantAsObject() const;
+ const char *variantAsString() const;
+ template <typename T>
+ T variantAsFloat() const;
+ template <typename T>
+ 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));
+ }
+
+ // The current type of the variant
+ Internals::JsonVariantType _type;
+
+ // The various alternatives for the value of the variant.
+ 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);
+}
+}
diff --git a/include/lib/ArduinoJson/JsonVariantBase.hpp b/include/lib/ArduinoJson/JsonVariantBase.hpp
new file mode 100644
index 0000000..44acf2e
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonVariantBase.hpp
@@ -0,0 +1,24 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "JsonVariantCasts.hpp"
+#include "JsonVariantComparisons.hpp"
+#include "JsonVariantOr.hpp"
+#include "JsonVariantSubscripts.hpp"
+#include "Serialization/JsonPrintable.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename TImpl>
+class JsonVariantBase : public JsonPrintable<TImpl>,
+ public JsonVariantCasts<TImpl>,
+ public JsonVariantComparisons<TImpl>,
+ public JsonVariantOr<TImpl>,
+ public JsonVariantSubscripts<TImpl>,
+ public JsonVariantTag {};
+}
+}
diff --git a/include/lib/ArduinoJson/JsonVariantCasts.hpp b/include/lib/ArduinoJson/JsonVariantCasts.hpp
new file mode 100644
index 0000000..68f5bd7
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonVariantCasts.hpp
@@ -0,0 +1,59 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Data/JsonVariantAs.hpp"
+#include "Polyfills/attributes.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename TImpl>
+class JsonVariantCasts {
+ public:
+#if ARDUINOJSON_ENABLE_DEPRECATED
+ DEPRECATED("use as<JsonArray>() instead")
+ FORCE_INLINE JsonArray &asArray() const {
+ return impl()->template as<JsonArray>();
+ }
+
+ DEPRECATED("use as<JsonObject>() instead")
+ FORCE_INLINE JsonObject &asObject() const {
+ return impl()->template as<JsonObject>();
+ }
+
+ DEPRECATED("use as<char*>() instead")
+ FORCE_INLINE const char *asString() const {
+ return impl()->template as<const char *>();
+ }
+#endif
+
+ // Gets the variant as an array.
+ // Returns a reference to the JsonArray or JsonArray::invalid() if the
+ // variant
+ // is not an array.
+ FORCE_INLINE operator JsonArray &() const {
+ return impl()->template as<JsonArray &>();
+ }
+
+ // Gets the variant as an object.
+ // Returns a reference to the JsonObject or JsonObject::invalid() if the
+ // variant is not an object.
+ FORCE_INLINE operator JsonObject &() const {
+ return impl()->template as<JsonObject &>();
+ }
+
+ template <typename T>
+ FORCE_INLINE operator T() const {
+ return impl()->template as<T>();
+ }
+
+ private:
+ const TImpl *impl() const {
+ return static_cast<const TImpl *>(this);
+ }
+};
+}
+}
diff --git a/include/lib/ArduinoJson/JsonVariantComparisons.hpp b/include/lib/ArduinoJson/JsonVariantComparisons.hpp
new file mode 100644
index 0000000..47f9d63
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonVariantComparisons.hpp
@@ -0,0 +1,139 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "StringTraits/StringTraits.hpp"
+#include "TypeTraits/EnableIf.hpp"
+#include "TypeTraits/IsVariant.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename TImpl>
+class JsonVariantComparisons {
+ public:
+ template <typename TComparand>
+ friend bool operator==(const JsonVariantComparisons &variant,
+ TComparand comparand) {
+ return variant.equals(comparand);
+ }
+
+ template <typename TComparand>
+ friend typename EnableIf<!IsVariant<TComparand>::value, bool>::type
+ operator==(TComparand comparand, const JsonVariantComparisons &variant) {
+ return variant.equals(comparand);
+ }
+
+ template <typename TComparand>
+ friend bool operator!=(const JsonVariantComparisons &variant,
+ TComparand comparand) {
+ return !variant.equals(comparand);
+ }
+
+ template <typename TComparand>
+ friend typename EnableIf<!IsVariant<TComparand>::value, bool>::type
+ operator!=(TComparand comparand, const JsonVariantComparisons &variant) {
+ return !variant.equals(comparand);
+ }
+
+ template <typename TComparand>
+ friend bool operator<=(const JsonVariantComparisons &left, TComparand right) {
+ return left.as<TComparand>() <= right;
+ }
+
+ template <typename TComparand>
+ friend bool operator<=(TComparand comparand,
+ const JsonVariantComparisons &variant) {
+ return comparand <= variant.as<TComparand>();
+ }
+
+ template <typename TComparand>
+ friend bool operator>=(const JsonVariantComparisons &variant,
+ TComparand comparand) {
+ return variant.as<TComparand>() >= comparand;
+ }
+
+ template <typename TComparand>
+ friend bool operator>=(TComparand comparand,
+ const JsonVariantComparisons &variant) {
+ return comparand >= variant.as<TComparand>();
+ }
+
+ template <typename TComparand>
+ friend bool operator<(const JsonVariantComparisons &varian,
+ TComparand comparand) {
+ return varian.as<TComparand>() < comparand;
+ }
+
+ template <typename TComparand>
+ friend bool operator<(TComparand comparand,
+ const JsonVariantComparisons &variant) {
+ return comparand < variant.as<TComparand>();
+ }
+
+ template <typename TComparand>
+ friend bool operator>(const JsonVariantComparisons &variant,
+ TComparand comparand) {
+ return variant.as<TComparand>() > comparand;
+ }
+
+ template <typename TComparand>
+ friend bool operator>(TComparand comparand,
+ const JsonVariantComparisons &variant) {
+ return comparand > variant.as<TComparand>();
+ }
+
+ private:
+ const TImpl *impl() const {
+ return static_cast<const TImpl *>(this);
+ }
+
+ template <typename T>
+ const typename JsonVariantAs<T>::type as() const {
+ return impl()->template as<T>();
+ }
+
+ template <typename T>
+ bool is() const {
+ return impl()->template is<T>();
+ }
+
+ template <typename TString>
+ typename EnableIf<StringTraits<TString>::has_equals, bool>::type equals(
+ const TString &comparand) const {
+ const char *value = as<const char *>();
+ return StringTraits<TString>::equals(comparand, value);
+ }
+
+ template <typename TComparand>
+ typename EnableIf<!IsVariant<TComparand>::value &&
+ !StringTraits<TComparand>::has_equals,
+ bool>::type
+ equals(const TComparand &comparand) const {
+ return as<TComparand>() == comparand;
+ }
+
+ template <typename TVariant2>
+ bool equals(const JsonVariantComparisons<TVariant2> &right) const {
+ using namespace Internals;
+ if (is<bool>() && right.template is<bool>())
+ return as<bool>() == right.template as<bool>();
+ if (is<JsonInteger>() && right.template is<JsonInteger>())
+ return as<JsonInteger>() == right.template as<JsonInteger>();
+ if (is<JsonFloat>() && right.template is<JsonFloat>())
+ return as<JsonFloat>() == right.template as<JsonFloat>();
+ if (is<JsonArray>() && right.template is<JsonArray>())
+ return as<JsonArray>() == right.template as<JsonArray>();
+ if (is<JsonObject>() && right.template is<JsonObject>())
+ return as<JsonObject>() == right.template as<JsonObject>();
+ if (is<char *>() && right.template is<char *>())
+ return StringTraits<const char *>::equals(as<char *>(),
+ right.template as<char *>());
+
+ return false;
+ }
+};
+} // namespace Internals
+} // namespace ArduinoJson
diff --git a/include/lib/ArduinoJson/JsonVariantImpl.hpp b/include/lib/ArduinoJson/JsonVariantImpl.hpp
new file mode 100644
index 0000000..31f96ce
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonVariantImpl.hpp
@@ -0,0 +1,126 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Configuration.hpp"
+#include "JsonArray.hpp"
+#include "JsonObject.hpp"
+#include "JsonVariant.hpp"
+#include "Polyfills/isFloat.hpp"
+#include "Polyfills/isInteger.hpp"
+#include "Polyfills/parseFloat.hpp"
+#include "Polyfills/parseInteger.hpp"
+
+#include <string.h> // for strcmp
+
+namespace ArduinoJson {
+
+inline JsonVariant::JsonVariant(const JsonArray &array) {
+ if (array.success()) {
+ _type = Internals::JSON_ARRAY;
+ _content.asArray = const_cast<JsonArray *>(&array);
+ } else {
+ _type = Internals::JSON_UNDEFINED;
+ }
+}
+
+inline JsonVariant::JsonVariant(const JsonObject &object) {
+ if (object.success()) {
+ _type = Internals::JSON_OBJECT;
+ _content.asObject = const_cast<JsonObject *>(&object);
+ } else {
+ _type = Internals::JSON_UNDEFINED;
+ }
+}
+
+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 <typename T>
+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<T>(_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 <typename T>
+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<T>(_content.asInteger);
+ case JSON_NEGATIVE_INTEGER:
+ return -static_cast<T>(_content.asInteger);
+ case JSON_STRING:
+ case JSON_UNPARSED:
+ return parseFloat<T>(_content.asString);
+ default:
+ return static_cast<T>(_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
diff --git a/include/lib/ArduinoJson/JsonVariantOr.hpp b/include/lib/ArduinoJson/JsonVariantOr.hpp
new file mode 100644
index 0000000..d8022fc
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonVariantOr.hpp
@@ -0,0 +1,52 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Data/JsonVariantAs.hpp"
+#include "Polyfills/attributes.hpp"
+#include "TypeTraits/EnableIf.hpp"
+#include "TypeTraits/IsIntegral.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename TImpl>
+class JsonVariantOr {
+ public:
+ // Returns the default value if the JsonVariant is undefined of incompatible
+ template <typename T>
+ typename EnableIf<!IsIntegral<T>::value, T>::type operator|(
+ const T &defaultValue) const {
+ if (impl()->template is<T>())
+ return impl()->template as<T>();
+ else
+ return defaultValue;
+ }
+
+ // Returns the default value if the JsonVariant is undefined of incompatible
+ // Special case for string: null is treated as undefined
+ const char *operator|(const char *defaultValue) const {
+ const char *value = impl()->template as<const char *>();
+ return value ? value : defaultValue;
+ }
+
+ // Returns the default value if the JsonVariant is undefined of incompatible
+ // Special case for integers: we also accept double
+ template <typename Integer>
+ typename EnableIf<IsIntegral<Integer>::value, Integer>::type operator|(
+ const Integer &defaultValue) const {
+ if (impl()->template is<double>())
+ return impl()->template as<Integer>();
+ else
+ return defaultValue;
+ }
+
+ private:
+ const TImpl *impl() const {
+ return static_cast<const TImpl *>(this);
+ }
+};
+} // namespace Internals
+} // namespace ArduinoJson
diff --git a/include/lib/ArduinoJson/JsonVariantSubscripts.hpp b/include/lib/ArduinoJson/JsonVariantSubscripts.hpp
new file mode 100644
index 0000000..279ee01
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonVariantSubscripts.hpp
@@ -0,0 +1,86 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Data/JsonVariantAs.hpp"
+#include "Polyfills/attributes.hpp"
+#include "StringTraits/StringTraits.hpp"
+#include "TypeTraits/EnableIf.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// Forward declarations.
+class JsonArraySubscript;
+template <typename TKey>
+class JsonObjectSubscript;
+
+template <typename TImpl>
+class JsonVariantSubscripts {
+ public:
+ // Mimics an array or an object.
+ // Returns the size of the array or object if the variant has that type.
+ // Returns 0 if the variant is neither an array nor an object
+ size_t size() const {
+ return impl()->template as<JsonArray>().size() +
+ impl()->template as<JsonObject>().size();
+ }
+
+ // Mimics an array.
+ // Returns the element at specified index if the variant is an array.
+ // Returns JsonVariant::invalid() if the variant is not an array.
+ FORCE_INLINE const JsonArraySubscript operator[](size_t index) const;
+ FORCE_INLINE JsonArraySubscript operator[](size_t index);
+
+ // Mimics an object.
+ // Returns the value associated with the specified key if the variant is
+ // an object.
+ // Return JsonVariant::invalid() if the variant is not an object.
+ //
+ // const JsonObjectSubscript operator[](TKey) const;
+ // TKey = const std::string&, const String&
+ template <typename TString>
+ FORCE_INLINE
+ typename EnableIf<StringTraits<TString>::has_equals,
+ const JsonObjectSubscript<const TString &> >::type
+ operator[](const TString &key) const {
+ return impl()->template as<JsonObject>()[key];
+ }
+ //
+ // const JsonObjectSubscript operator[](TKey) const;
+ // TKey = const std::string&, const String&
+ template <typename TString>
+ FORCE_INLINE typename EnableIf<StringTraits<TString>::has_equals,
+ JsonObjectSubscript<const TString &> >::type
+ operator[](const TString &key) {
+ return impl()->template as<JsonObject>()[key];
+ }
+ //
+ // JsonObjectSubscript operator[](TKey);
+ // TKey = const char*, const char[N], const FlashStringHelper*
+ template <typename TString>
+ FORCE_INLINE typename EnableIf<StringTraits<const TString *>::has_equals,
+ JsonObjectSubscript<const TString *> >::type
+ operator[](const TString *key) {
+ return impl()->template as<JsonObject>()[key];
+ }
+ //
+ // JsonObjectSubscript operator[](TKey);
+ // TKey = const char*, const char[N], const FlashStringHelper*
+ template <typename TString>
+ FORCE_INLINE
+ typename EnableIf<StringTraits<TString *>::has_equals,
+ const JsonObjectSubscript<const TString *> >::type
+ operator[](const TString *key) const {
+ return impl()->template as<JsonObject>()[key];
+ }
+
+ private:
+ const TImpl *impl() const {
+ return static_cast<const TImpl *>(this);
+ }
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Polyfills/attributes.hpp b/include/lib/ArduinoJson/Polyfills/attributes.hpp
new file mode 100644
index 0000000..b49091d
--- /dev/null
+++ b/include/lib/ArduinoJson/Polyfills/attributes.hpp
@@ -0,0 +1,29 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#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
diff --git a/include/lib/ArduinoJson/Polyfills/ctype.hpp b/include/lib/ArduinoJson/Polyfills/ctype.hpp
new file mode 100644
index 0000000..2d52703
--- /dev/null
+++ b/include/lib/ArduinoJson/Polyfills/ctype.hpp
@@ -0,0 +1,18 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+inline bool isdigit(char c) {
+ return '0' <= c && c <= '9';
+}
+
+inline bool issign(char c) {
+ return '-' == c || c == '+';
+}
+}
+}
diff --git a/include/lib/ArduinoJson/Polyfills/isFloat.hpp b/include/lib/ArduinoJson/Polyfills/isFloat.hpp
new file mode 100644
index 0000000..973b89f
--- /dev/null
+++ b/include/lib/ArduinoJson/Polyfills/isFloat.hpp
@@ -0,0 +1,38 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include <string.h> // for strcmp
+#include "./ctype.hpp"
+
+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';
+}
+}
+}
diff --git a/include/lib/ArduinoJson/Polyfills/isInteger.hpp b/include/lib/ArduinoJson/Polyfills/isInteger.hpp
new file mode 100644
index 0000000..8049079
--- /dev/null
+++ b/include/lib/ArduinoJson/Polyfills/isInteger.hpp
@@ -0,0 +1,19 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "./ctype.hpp"
+
+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
diff --git a/include/lib/ArduinoJson/Polyfills/math.hpp b/include/lib/ArduinoJson/Polyfills/math.hpp
new file mode 100644
index 0000000..48773ed
--- /dev/null
+++ b/include/lib/ArduinoJson/Polyfills/math.hpp
@@ -0,0 +1,19 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+bool isNaN(T x) {
+ return x != x;
+}
+
+template <typename T>
+bool isInfinity(T x) {
+ return x != 0.0 && x * 2 == x;
+}
+}
+}
diff --git a/include/lib/ArduinoJson/Polyfills/parseFloat.hpp b/include/lib/ArduinoJson/Polyfills/parseFloat.hpp
new file mode 100644
index 0000000..49b0f6f
--- /dev/null
+++ b/include/lib/ArduinoJson/Polyfills/parseFloat.hpp
@@ -0,0 +1,90 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../TypeTraits/FloatTraits.hpp"
+#include "./ctype.hpp"
+#include "./math.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename T>
+inline T parseFloat(const char* s) {
+ typedef FloatTraits<T> 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<T>(mantissa), exponent);
+
+ return negative_result ? -result : result;
+}
+}
+}
diff --git a/include/lib/ArduinoJson/Polyfills/parseInteger.hpp b/include/lib/ArduinoJson/Polyfills/parseInteger.hpp
new file mode 100644
index 0000000..e8f1974
--- /dev/null
+++ b/include/lib/ArduinoJson/Polyfills/parseInteger.hpp
@@ -0,0 +1,41 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include <stdlib.h>
+
+#include "../Configuration.hpp"
+#include "./ctype.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+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;
+}
+}
+}
diff --git a/include/lib/ArduinoJson/RawJson.hpp b/include/lib/ArduinoJson/RawJson.hpp
new file mode 100644
index 0000000..4beb980
--- /dev/null
+++ b/include/lib/ArduinoJson/RawJson.hpp
@@ -0,0 +1,46 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+
+namespace Internals {
+// A special type of data that can be used to insert pregenerated JSON portions.
+template <typename T>
+class RawJsonString {
+ public:
+ explicit RawJsonString(T str) : _str(str) {}
+ operator T() const {
+ return _str;
+ }
+
+ private:
+ T _str;
+};
+
+template <typename String>
+struct StringTraits<RawJsonString<String>, void> {
+ static bool is_null(RawJsonString<String> source) {
+ return StringTraits<String>::is_null(static_cast<String>(source));
+ }
+
+ typedef RawJsonString<const char*> duplicate_t;
+
+ template <typename Buffer>
+ static duplicate_t duplicate(RawJsonString<String> source, Buffer* buffer) {
+ return duplicate_t(StringTraits<String>::duplicate(source, buffer));
+ }
+
+ static const bool has_append = false;
+ static const bool has_equals = false;
+ static const bool should_duplicate = StringTraits<String>::should_duplicate;
+};
+}
+
+template <typename T>
+inline Internals::RawJsonString<T> RawJson(T str) {
+ return Internals::RawJsonString<T>(str);
+}
+}
diff --git a/include/lib/ArduinoJson/Serialization/DummyPrint.hpp b/include/lib/ArduinoJson/Serialization/DummyPrint.hpp
new file mode 100644
index 0000000..9fdf2d6
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/DummyPrint.hpp
@@ -0,0 +1,22 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A dummy Print implementation used in JsonPrintable::measureLength()
+class DummyPrint {
+ public:
+ size_t print(char) {
+ return 1;
+ }
+
+ size_t print(const char* s) {
+ return strlen(s);
+ }
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Serialization/DynamicStringBuilder.hpp b/include/lib/ArduinoJson/Serialization/DynamicStringBuilder.hpp
new file mode 100644
index 0000000..41be639
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/DynamicStringBuilder.hpp
@@ -0,0 +1,35 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../StringTraits/StringTraits.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A Print implementation that allows to write in a String
+template <typename TString>
+class DynamicStringBuilder {
+ public:
+ DynamicStringBuilder(TString &str) : _str(str) {}
+
+ size_t print(char c) {
+ StringTraits<TString>::append(_str, c);
+ return 1;
+ }
+
+ size_t print(const char *s) {
+ size_t initialLen = _str.length();
+ StringTraits<TString>::append(_str, s);
+ return _str.length() - initialLen;
+ }
+
+ private:
+ DynamicStringBuilder &operator=(const DynamicStringBuilder &);
+
+ TString &_str;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Serialization/FloatParts.hpp b/include/lib/ArduinoJson/Serialization/FloatParts.hpp
new file mode 100644
index 0000000..c14e3b5
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/FloatParts.hpp
@@ -0,0 +1,89 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../Configuration.hpp"
+#include "../Polyfills/math.hpp"
+#include "../TypeTraits/FloatTraits.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename TFloat>
+struct FloatParts {
+ uint32_t integral;
+ uint32_t decimal;
+ int16_t exponent;
+ int8_t decimalPlaces;
+
+ FloatParts(TFloat value) {
+ uint32_t maxDecimalPart = sizeof(TFloat) >= 8 ? 1000000000 : 1000000;
+ decimalPlaces = sizeof(TFloat) >= 8 ? 9 : 6;
+
+ exponent = normalize(value);
+
+ integral = uint32_t(value);
+ // reduce number of decimal places by the number of integral places
+ for (uint32_t tmp = integral; tmp >= 10; tmp /= 10) {
+ maxDecimalPart /= 10;
+ decimalPlaces--;
+ }
+
+ TFloat remainder = (value - TFloat(integral)) * TFloat(maxDecimalPart);
+
+ decimal = uint32_t(remainder);
+ remainder = remainder - TFloat(decimal);
+
+ // rounding:
+ // increment by 1 if remainder >= 0.5
+ decimal += uint32_t(remainder * 2);
+ if (decimal >= maxDecimalPart) {
+ decimal = 0;
+ integral++;
+ if (exponent && integral >= 10) {
+ exponent++;
+ integral = 1;
+ }
+ }
+
+ // remove trailing zeros
+ while (decimal % 10 == 0 && decimalPlaces > 0) {
+ decimal /= 10;
+ decimalPlaces--;
+ }
+ }
+
+ static int16_t normalize(TFloat& value) {
+ typedef FloatTraits<TFloat> traits;
+ int16_t powersOf10 = 0;
+
+ int8_t index = sizeof(TFloat) == 8 ? 8 : 5;
+ int bit = 1 << index;
+
+ if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) {
+ for (; index >= 0; index--) {
+ if (value >= traits::positiveBinaryPowerOfTen(index)) {
+ value *= traits::negativeBinaryPowerOfTen(index);
+ powersOf10 = int16_t(powersOf10 + bit);
+ }
+ bit >>= 1;
+ }
+ }
+
+ if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) {
+ for (; index >= 0; index--) {
+ if (value < traits::negativeBinaryPowerOfTenPlusOne(index)) {
+ value *= traits::positiveBinaryPowerOfTen(index);
+ powersOf10 = int16_t(powersOf10 - bit);
+ }
+ bit >>= 1;
+ }
+ }
+
+ return powersOf10;
+ }
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Serialization/IndentedPrint.hpp b/include/lib/ArduinoJson/Serialization/IndentedPrint.hpp
new file mode 100644
index 0000000..864f9aa
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/IndentedPrint.hpp
@@ -0,0 +1,68 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// Decorator on top of Print to allow indented output.
+// This class is used by JsonPrintable::prettyPrintTo() but can also be used
+// for your own purpose, like logging.
+template <typename Print>
+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) {
+ // TODO: optimize
+ size_t n = 0;
+ while (*s) n += print(*s++);
+ return n;
+ }
+
+ // Adds one level of indentation
+ void indent() {
+ if (level < MAX_LEVEL) level++;
+ }
+
+ // Removes one level of indentation
+ void unindent() {
+ if (level > 0) level--;
+ }
+
+ // Set the number of space printed for each level of indentation
+ 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
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Serialization/JsonPrintable.hpp b/include/lib/ArduinoJson/Serialization/JsonPrintable.hpp
new file mode 100644
index 0000000..43d413a
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/JsonPrintable.hpp
@@ -0,0 +1,117 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../Configuration.hpp"
+#include "../TypeTraits/EnableIf.hpp"
+#include "DummyPrint.hpp"
+#include "DynamicStringBuilder.hpp"
+#include "IndentedPrint.hpp"
+#include "JsonSerializer.hpp"
+#include "JsonWriter.hpp"
+#include "Prettyfier.hpp"
+#include "StaticStringBuilder.hpp"
+
+#if ARDUINOJSON_ENABLE_STD_STREAM
+#include "StreamPrintAdapter.hpp"
+#endif
+
+namespace ArduinoJson {
+namespace Internals {
+
+// Implements all the overloads of printTo() and prettyPrintTo()
+// Caution: this class use a template parameter to avoid virtual methods.
+// This is a bit curious but allows to reduce the size of JsonVariant, JsonArray
+// and JsonObject.
+template <typename T>
+class JsonPrintable {
+ public:
+ template <typename Print>
+ typename EnableIf<!StringTraits<Print>::has_append, size_t>::type printTo(
+ Print &print) const {
+ JsonWriter<Print> writer(print);
+ JsonSerializer<JsonWriter<Print> >::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 N>
+ size_t printTo(char (&buffer)[N]) const {
+ return printTo(buffer, N);
+ }
+
+ template <typename TString>
+ typename EnableIf<StringTraits<TString>::has_append, size_t>::type printTo(
+ TString &str) const {
+ DynamicStringBuilder<TString> sb(str);
+ return printTo(sb);
+ }
+
+ template <typename Print>
+ size_t prettyPrintTo(IndentedPrint<Print> &print) const {
+ Prettyfier<Print> p(print);
+ return printTo(p);
+ }
+
+ size_t prettyPrintTo(char *buffer, size_t bufferSize) const {
+ StaticStringBuilder sb(buffer, bufferSize);
+ return prettyPrintTo(sb);
+ }
+
+ template <size_t N>
+ size_t prettyPrintTo(char (&buffer)[N]) const {
+ return prettyPrintTo(buffer, N);
+ }
+
+ template <typename Print>
+ typename EnableIf<!StringTraits<Print>::has_append, size_t>::type
+ prettyPrintTo(Print &print) const {
+ IndentedPrint<Print> indentedPrint(print);
+ return prettyPrintTo(indentedPrint);
+ }
+
+ template <typename TString>
+ typename EnableIf<StringTraits<TString>::has_append, size_t>::type
+ prettyPrintTo(TString &str) const {
+ DynamicStringBuilder<TString> 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<const T *>(this);
+ }
+};
+
+#if ARDUINOJSON_ENABLE_STD_STREAM
+template <typename T>
+inline std::ostream &operator<<(std::ostream &os, const JsonPrintable<T> &v) {
+ return v.printTo(os);
+}
+#endif
+}
+}
diff --git a/include/lib/ArduinoJson/Serialization/JsonSerializer.hpp b/include/lib/ArduinoJson/Serialization/JsonSerializer.hpp
new file mode 100644
index 0000000..0cb537f
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/JsonSerializer.hpp
@@ -0,0 +1,32 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "JsonWriter.hpp"
+
+namespace ArduinoJson {
+
+class JsonArray;
+class JsonObject;
+class JsonVariant;
+
+namespace Internals {
+
+class JsonArraySubscript;
+template <typename TKey>
+class JsonObjectSubscript;
+
+template <typename Writer>
+class JsonSerializer {
+ public:
+ static void serialize(const JsonArray &, Writer &);
+ static void serialize(const JsonArraySubscript &, Writer &);
+ static void serialize(const JsonObject &, Writer &);
+ template <typename TKey>
+ static void serialize(const JsonObjectSubscript<TKey> &, Writer &);
+ static void serialize(const JsonVariant &, Writer &);
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Serialization/JsonSerializerImpl.hpp b/include/lib/ArduinoJson/Serialization/JsonSerializerImpl.hpp
new file mode 100644
index 0000000..0faae27
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/JsonSerializerImpl.hpp
@@ -0,0 +1,103 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../JsonArray.hpp"
+#include "../JsonArraySubscript.hpp"
+#include "../JsonObject.hpp"
+#include "../JsonObjectSubscript.hpp"
+#include "../JsonVariant.hpp"
+#include "JsonSerializer.hpp"
+
+template <typename Writer>
+inline void ArduinoJson::Internals::JsonSerializer<Writer>::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 <typename Writer>
+inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
+ const JsonArraySubscript& arraySubscript, Writer& writer) {
+ serialize(arraySubscript.as<JsonVariant>(), writer);
+}
+
+template <typename Writer>
+inline void ArduinoJson::Internals::JsonSerializer<Writer>::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 <typename Writer>
+template <typename TKey>
+inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
+ const JsonObjectSubscript<TKey>& objectSubscript, Writer& writer) {
+ serialize(objectSubscript.template as<JsonVariant>(), writer);
+}
+
+template <typename Writer>
+inline void ArduinoJson::Internals::JsonSerializer<Writer>::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;
+ }
+}
diff --git a/include/lib/ArduinoJson/Serialization/JsonWriter.hpp b/include/lib/ArduinoJson/Serialization/JsonWriter.hpp
new file mode 100644
index 0000000..146d51d
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/JsonWriter.hpp
@@ -0,0 +1,155 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include <stdint.h>
+#include "../Data/Encoding.hpp"
+#include "../Data/JsonInteger.hpp"
+#include "../Polyfills/attributes.hpp"
+#include "../Serialization/FloatParts.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// Writes the JSON tokens to a Print implementation
+// This class is used by:
+// - JsonArray::writeTo()
+// - JsonObject::writeTo()
+// - JsonVariant::writeTo()
+// Its derived by PrettyJsonWriter that overrides some members to add
+// indentation.
+template <typename Print>
+class JsonWriter {
+ public:
+ explicit JsonWriter(Print &sink) : _sink(sink), _length(0) {}
+
+ // Returns the number of bytes sent to the Print implementation.
+ // This is very handy for implementations of printTo() that must return the
+ // number of bytes written.
+ 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 <typename TFloat>
+ void writeFloat(TFloat value) {
+ if (isNaN(value)) return writeRaw("NaN");
+
+ if (value < 0.0) {
+ writeRaw('-');
+ value = -value;
+ }
+
+ if (isInfinity(value)) return writeRaw("Infinity");
+
+ FloatParts<TFloat> 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 <typename UInt>
+ 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) {
+ // buffer should be big enough for all digits, the dot and the null
+ // terminator
+ char buffer[16];
+ char *ptr = buffer + sizeof(buffer) - 1;
+
+ // write the string in reverse order
+ *ptr = 0;
+ while (width--) {
+ *--ptr = char(value % 10 + '0');
+ value /= 10;
+ }
+ *--ptr = '.';
+
+ // and dump it in the right order
+ 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
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Serialization/Prettyfier.hpp b/include/lib/ArduinoJson/Serialization/Prettyfier.hpp
new file mode 100644
index 0000000..8b4f0d2
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/Prettyfier.hpp
@@ -0,0 +1,133 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "IndentedPrint.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// Converts a compact JSON string into an indented one.
+template <typename Print>
+class Prettyfier {
+ public:
+ explicit Prettyfier(IndentedPrint<Print>& 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) {
+ // TODO: optimize
+ 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<Print>& _sink;
+ bool _inString;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Serialization/StaticStringBuilder.hpp b/include/lib/ArduinoJson/Serialization/StaticStringBuilder.hpp
new file mode 100644
index 0000000..9617bbd
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/StaticStringBuilder.hpp
@@ -0,0 +1,36 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A Print implementation that allows to write in a char[]
+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;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Serialization/StreamPrintAdapter.hpp b/include/lib/ArduinoJson/Serialization/StreamPrintAdapter.hpp
new file mode 100644
index 0000000..60f0af4
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/StreamPrintAdapter.hpp
@@ -0,0 +1,39 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../Configuration.hpp"
+
+#if ARDUINOJSON_ENABLE_STD_STREAM
+
+#include <ostream>
+
+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:
+ // cannot be assigned
+ StreamPrintAdapter& operator=(const StreamPrintAdapter&);
+
+ std::ostream& _os;
+};
+}
+}
+
+#endif // ARDUINOJSON_ENABLE_STD_STREAM
diff --git a/include/lib/ArduinoJson/StaticJsonBuffer.hpp b/include/lib/ArduinoJson/StaticJsonBuffer.hpp
new file mode 100644
index 0000000..267d9d0
--- /dev/null
+++ b/include/lib/ArduinoJson/StaticJsonBuffer.hpp
@@ -0,0 +1,126 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "JsonBufferBase.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+class StaticJsonBufferBase : public JsonBufferBase<StaticJsonBufferBase> {
+ 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<char*>(_parent->doAlloc(1));
+ *last = c;
+ }
+ }
+
+ const char* c_str() const {
+ if (_parent->canAlloc(1)) {
+ char* last = static_cast<char*>(_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) {}
+
+ // Gets the capacity of the buffer in bytes
+ size_t capacity() const {
+ return _capacity;
+ }
+
+ // Gets the current usage of the buffer in bytes
+ size_t size() const {
+ return _size;
+ }
+
+ // Allocates the specified amount of bytes in the buffer
+ virtual void* alloc(size_t bytes) {
+ alignNextAlloc();
+ if (!canAlloc(bytes)) return NULL;
+ return doAlloc(bytes);
+ }
+
+ // Resets the buffer.
+ // USE WITH CAUTION: this invalidates all previously allocated data
+ 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;
+};
+}
+
+#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
+
+// Implements a JsonBuffer with fixed memory allocation.
+// The template paramenter CAPACITY specifies the capacity of the buffer in
+// bytes.
+template <size_t CAPACITY>
+class StaticJsonBuffer : public Internals::StaticJsonBufferBase {
+ public:
+ explicit StaticJsonBuffer()
+ : Internals::StaticJsonBufferBase(_buffer, CAPACITY) {}
+
+ private:
+ char _buffer[CAPACITY];
+};
+}
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#elif defined(__GNUC__)
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+#pragma GCC diagnostic pop
+#endif
+#endif
diff --git a/include/lib/ArduinoJson/StringTraits/ArduinoStream.hpp b/include/lib/ArduinoJson/StringTraits/ArduinoStream.hpp
new file mode 100644
index 0000000..5db0852
--- /dev/null
+++ b/include/lib/ArduinoJson/StringTraits/ArduinoStream.hpp
@@ -0,0 +1,61 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#if ARDUINOJSON_ENABLE_ARDUINO_STREAM
+
+#include <Stream.h>
+
+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() {
+ // assumes that current() has been called
+ if (!_next) _next = read();
+ return _next;
+ }
+
+ private:
+ char read() {
+ // don't use _stream.read() as it ignores the timeout
+ char c = 0;
+ _stream.readBytes(&c, 1);
+ return c;
+ }
+ };
+
+ static const bool has_append = false;
+ static const bool has_equals = false;
+};
+
+template <typename TStream>
+struct StringTraits<
+ TStream,
+ // match any type that is derived from Stream:
+ typename EnableIf<
+ IsBaseOf<Stream, typename RemoveReference<TStream>::type>::value>::type>
+ : ArduinoStreamTraits {};
+}
+}
+
+#endif
diff --git a/include/lib/ArduinoJson/StringTraits/CharPointer.hpp b/include/lib/ArduinoJson/StringTraits/CharPointer.hpp
new file mode 100644
index 0000000..98896cc
--- /dev/null
+++ b/include/lib/ArduinoJson/StringTraits/CharPointer.hpp
@@ -0,0 +1,64 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename TChar>
+struct CharPointerTraits {
+ class Reader {
+ const TChar* _ptr;
+
+ public:
+ Reader(const TChar* ptr)
+ : _ptr(ptr ? ptr : reinterpret_cast<const TChar*>("")) {}
+
+ 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<const char*>(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 <typename Buffer>
+ static duplicate_t duplicate(const TChar* str, Buffer* buffer) {
+ if (!str) return NULL;
+ size_t size = strlen(reinterpret_cast<const char*>(str)) + 1;
+ void* dup = buffer->alloc(size);
+ if (dup != NULL) memcpy(dup, str, size);
+ return static_cast<duplicate_t>(dup);
+ }
+
+ static const bool has_append = false;
+ static const bool has_equals = true;
+ static const bool should_duplicate = !IsConst<TChar>::value;
+};
+
+// char*, unsigned char*, signed char*
+// const char*, const unsigned char*, const signed char*
+template <typename TChar>
+struct StringTraits<TChar*, typename EnableIf<IsChar<TChar>::value>::type>
+ : CharPointerTraits<TChar> {};
+} // namespace Internals
+} // namespace ArduinoJson
diff --git a/include/lib/ArduinoJson/StringTraits/FlashString.hpp b/include/lib/ArduinoJson/StringTraits/FlashString.hpp
new file mode 100644
index 0000000..0701b9b
--- /dev/null
+++ b/include/lib/ArduinoJson/StringTraits/FlashString.hpp
@@ -0,0 +1,61 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#if ARDUINOJSON_ENABLE_PROGMEM
+
+namespace ArduinoJson {
+namespace Internals {
+template <>
+struct StringTraits<const __FlashStringHelper*, void> {
+ class Reader {
+ const char* _ptr;
+
+ public:
+ Reader(const __FlashStringHelper* ptr)
+ : _ptr(reinterpret_cast<const char*>(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<const char*>(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 <typename Buffer>
+ 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<duplicate_t>(dup);
+ }
+
+ static const bool has_append = false;
+ static const bool has_equals = true;
+ static const bool should_duplicate = true;
+};
+} // namespace Internals
+} // namespace ArduinoJson
+
+#endif
diff --git a/include/lib/ArduinoJson/StringTraits/StdStream.hpp b/include/lib/ArduinoJson/StringTraits/StdStream.hpp
new file mode 100644
index 0000000..227c744
--- /dev/null
+++ b/include/lib/ArduinoJson/StringTraits/StdStream.hpp
@@ -0,0 +1,60 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#if ARDUINOJSON_ENABLE_STD_STREAM
+
+#include <istream>
+
+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() {
+ // assumes that current() has been called
+ if (!_next) _next = read();
+ return _next;
+ }
+
+ private:
+ Reader& operator=(const Reader&); // Visual Studio C4512
+
+ char read() {
+ return _stream.eof() ? '\0' : static_cast<char>(_stream.get());
+ }
+ };
+
+ static const bool has_append = false;
+ static const bool has_equals = false;
+};
+
+template <typename TStream>
+struct StringTraits<
+ TStream,
+ // match any type that is derived from std::istream:
+ typename EnableIf<IsBaseOf<
+ std::istream, typename RemoveReference<TStream>::type>::value>::type>
+ : StdStreamTraits {};
+}
+}
+
+#endif
diff --git a/include/lib/ArduinoJson/StringTraits/StdString.hpp b/include/lib/ArduinoJson/StringTraits/StdString.hpp
new file mode 100644
index 0000000..35f4461
--- /dev/null
+++ b/include/lib/ArduinoJson/StringTraits/StdString.hpp
@@ -0,0 +1,77 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#if ARDUINOJSON_ENABLE_STD_STRING || ARDUINOJSON_ENABLE_ARDUINO_STRING
+
+#if ARDUINOJSON_ENABLE_ARDUINO_STRING
+#include <WString.h>
+#endif
+
+#if ARDUINOJSON_ENABLE_STD_STRING
+#include <string>
+#endif
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename TString>
+struct StdStringTraits {
+ typedef const char* duplicate_t;
+
+ template <typename Buffer>
+ 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<duplicate_t>(dup);
+ }
+
+ static bool is_null(const TString& str) {
+ // Arduino's String::c_str() can return NULL
+ return !str.c_str();
+ }
+
+ struct Reader : CharPointerTraits<char>::Reader {
+ Reader(const TString& str) : CharPointerTraits<char>::Reader(str.c_str()) {}
+ };
+
+ static bool equals(const TString& str, const char* expected) {
+ // Arduino's String::c_str() can return NULL
+ 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<String, void> : StdStringTraits<String> {};
+template <>
+struct StringTraits<StringSumHelper, void> : StdStringTraits<StringSumHelper> {
+};
+#endif
+
+#if ARDUINOJSON_ENABLE_STD_STRING
+template <>
+struct StringTraits<std::string, void> : StdStringTraits<std::string> {};
+#endif
+} // namespace Internals
+} // namespace ArduinoJson
+
+#endif
diff --git a/include/lib/ArduinoJson/StringTraits/StringTraits.hpp b/include/lib/ArduinoJson/StringTraits/StringTraits.hpp
new file mode 100644
index 0000000..dd5694b
--- /dev/null
+++ b/include/lib/ArduinoJson/StringTraits/StringTraits.hpp
@@ -0,0 +1,36 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include <string.h>
+#include "../Configuration.hpp"
+#include "../TypeTraits/EnableIf.hpp"
+#include "../TypeTraits/IsBaseOf.hpp"
+#include "../TypeTraits/IsChar.hpp"
+#include "../TypeTraits/IsConst.hpp"
+#include "../TypeTraits/RemoveReference.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename TString, typename Enable = void>
+struct StringTraits {
+ static const bool has_append = false;
+ static const bool has_equals = false;
+};
+
+template <typename TString>
+struct StringTraits<const TString, void> : StringTraits<TString> {};
+
+template <typename TString>
+struct StringTraits<TString&, void> : StringTraits<TString> {};
+}
+}
+
+#include "ArduinoStream.hpp"
+#include "CharPointer.hpp"
+#include "FlashString.hpp"
+#include "StdStream.hpp"
+#include "StdString.hpp"
diff --git a/include/lib/ArduinoJson/TypeTraits/EnableIf.hpp b/include/lib/ArduinoJson/TypeTraits/EnableIf.hpp
new file mode 100644
index 0000000..83fc5e0
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/EnableIf.hpp
@@ -0,0 +1,19 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that return the type T if Condition is true.
+template <bool Condition, typename T = void>
+struct EnableIf {};
+
+template <typename T>
+struct EnableIf<true, T> {
+ typedef T type;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/FloatTraits.hpp b/include/lib/ArduinoJson/TypeTraits/FloatTraits.hpp
new file mode 100644
index 0000000..648cc82
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/FloatTraits.hpp
@@ -0,0 +1,171 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include <stdint.h>
+#include <stdlib.h> // for size_t
+#include "../Configuration.hpp"
+#include "../Polyfills/math.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename T, size_t = sizeof(T)>
+struct FloatTraits {};
+
+template <typename T>
+struct FloatTraits<T, 8 /*64bits*/> {
+ typedef int64_t mantissa_type;
+ static const short mantissa_bits = 52;
+ static const mantissa_type mantissa_max =
+ (static_cast<mantissa_type>(1) << mantissa_bits) - 1;
+
+ typedef int16_t exponent_type;
+ static const exponent_type exponent_max = 308;
+
+ template <typename TExponent>
+ static T make_float(T m, TExponent e) {
+ if (e > 0) {
+ for (uint8_t index = 0; e != 0; index++) {
+ if (e & 1) m *= positiveBinaryPowerOfTen(index);
+ e >>= 1;
+ }
+ } else {
+ e = TExponent(-e);
+ for (uint8_t index = 0; e != 0; index++) {
+ if (e & 1) m *= negativeBinaryPowerOfTen(index);
+ e >>= 1;
+ }
+ }
+ return m;
+ }
+
+ static T positiveBinaryPowerOfTen(int index) {
+ 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);
+ }
+
+ // constructs a double floating point values from its binary representation
+ // we use this function to workaround platforms with single precision literals
+ // (for example, when -fsingle-precision-constant is passed to GCC)
+ static T forge(uint32_t msb, uint32_t lsb) {
+ union {
+ uint64_t integerBits;
+ T floatBits;
+ };
+ integerBits = (uint64_t(msb) << 32) | lsb;
+ return floatBits;
+ }
+};
+
+template <typename T>
+struct FloatTraits<T, 4 /*32bits*/> {
+ typedef int32_t mantissa_type;
+ static const short mantissa_bits = 23;
+ static const mantissa_type mantissa_max =
+ (static_cast<mantissa_type>(1) << mantissa_bits) - 1;
+
+ typedef int8_t exponent_type;
+ static const exponent_type exponent_max = 38;
+
+ template <typename TExponent>
+ static T make_float(T m, TExponent e) {
+ if (e > 0) {
+ for (uint8_t index = 0; e != 0; index++) {
+ if (e & 1) m *= positiveBinaryPowerOfTen(index);
+ e >>= 1;
+ }
+ } else {
+ e = -e;
+ for (uint8_t index = 0; e != 0; index++) {
+ if (e & 1) m *= negativeBinaryPowerOfTen(index);
+ e >>= 1;
+ }
+ }
+ return m;
+ }
+
+ static T positiveBinaryPowerOfTen(int index) {
+ 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) {
+ union {
+ uint32_t integerBits;
+ T floatBits;
+ };
+ integerBits = bits;
+ return floatBits;
+ }
+
+ static T nan() {
+ return forge(0x7fc00000);
+ }
+
+ static T inf() {
+ return forge(0x7f800000);
+ }
+};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/IsArray.hpp b/include/lib/ArduinoJson/TypeTraits/IsArray.hpp
new file mode 100644
index 0000000..2599231
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/IsArray.hpp
@@ -0,0 +1,24 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that return the type T without the const modifier
+template <typename T>
+struct IsArray {
+ static const bool value = false;
+};
+template <typename T>
+struct IsArray<T[]> {
+ static const bool value = true;
+};
+template <typename T, size_t N>
+struct IsArray<T[N]> {
+ static const bool value = true;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/IsBaseOf.hpp b/include/lib/ArduinoJson/TypeTraits/IsBaseOf.hpp
new file mode 100644
index 0000000..bf24e96
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/IsBaseOf.hpp
@@ -0,0 +1,27 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that returns true if Derived inherits from TBase is an
+// integral type.
+template <typename TBase, typename TDerived>
+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<TDerived *>(0))) == sizeof(Yes)
+ };
+};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/IsChar.hpp b/include/lib/ArduinoJson/TypeTraits/IsChar.hpp
new file mode 100644
index 0000000..d97cec2
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/IsChar.hpp
@@ -0,0 +1,23 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "IsSame.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that returns true if T is a charater
+template <typename T>
+struct IsChar {
+ static const bool value = IsSame<T, char>::value ||
+ IsSame<T, signed char>::value ||
+ IsSame<T, unsigned char>::value;
+};
+
+template <typename T>
+struct IsChar<const T> : IsChar<T> {};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/IsConst.hpp b/include/lib/ArduinoJson/TypeTraits/IsConst.hpp
new file mode 100644
index 0000000..512ee5c
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/IsConst.hpp
@@ -0,0 +1,21 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that return the type T without the const modifier
+template <typename T>
+struct IsConst {
+ static const bool value = false;
+};
+
+template <typename T>
+struct IsConst<const T> {
+ static const bool value = true;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/IsFloatingPoint.hpp b/include/lib/ArduinoJson/TypeTraits/IsFloatingPoint.hpp
new file mode 100644
index 0000000..e41a682
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/IsFloatingPoint.hpp
@@ -0,0 +1,18 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "IsSame.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that returns true if T is a floating point type
+template <typename T>
+struct IsFloatingPoint {
+ static const bool value = IsSame<T, float>::value || IsSame<T, double>::value;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/IsIntegral.hpp b/include/lib/ArduinoJson/TypeTraits/IsIntegral.hpp
new file mode 100644
index 0000000..17ae5f2
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/IsIntegral.hpp
@@ -0,0 +1,26 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "IsSame.hpp"
+#include "IsSignedIntegral.hpp"
+#include "IsUnsignedIntegral.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that returns true if T is an integral type.
+template <typename T>
+struct IsIntegral {
+ static const bool value = IsSignedIntegral<T>::value ||
+ IsUnsignedIntegral<T>::value ||
+ IsSame<T, char>::value;
+ // CAUTION: differs from std::is_integral as it doesn't include bool
+};
+
+template <typename T>
+struct IsIntegral<const T> : IsIntegral<T> {};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/IsSame.hpp b/include/lib/ArduinoJson/TypeTraits/IsSame.hpp
new file mode 100644
index 0000000..06567c9
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/IsSame.hpp
@@ -0,0 +1,21 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that returns true if types T and U are the same.
+template <typename T, typename U>
+struct IsSame {
+ static const bool value = false;
+};
+
+template <typename T>
+struct IsSame<T, T> {
+ static const bool value = true;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/IsSignedIntegral.hpp b/include/lib/ArduinoJson/TypeTraits/IsSignedIntegral.hpp
new file mode 100644
index 0000000..7334eb9
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/IsSignedIntegral.hpp
@@ -0,0 +1,28 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../Configuration.hpp"
+#include "IsSame.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that returns true if T is an integral type.
+template <typename T>
+struct IsSignedIntegral {
+ static const bool value =
+ IsSame<T, signed char>::value || IsSame<T, signed short>::value ||
+ IsSame<T, signed int>::value || IsSame<T, signed long>::value ||
+#if ARDUINOJSON_USE_LONG_LONG
+ IsSame<T, signed long long>::value ||
+#endif
+#if ARDUINOJSON_USE_INT64
+ IsSame<T, signed __int64>::value ||
+#endif
+ false;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/IsUnsignedIntegral.hpp b/include/lib/ArduinoJson/TypeTraits/IsUnsignedIntegral.hpp
new file mode 100644
index 0000000..938423f
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/IsUnsignedIntegral.hpp
@@ -0,0 +1,28 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../Configuration.hpp"
+#include "IsSame.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that returns true if T is an integral type.
+template <typename T>
+struct IsUnsignedIntegral {
+ static const bool value =
+ IsSame<T, unsigned char>::value || IsSame<T, unsigned short>::value ||
+ IsSame<T, unsigned int>::value || IsSame<T, unsigned long>::value ||
+#if ARDUINOJSON_USE_LONG_LONG
+ IsSame<T, unsigned long long>::value ||
+#endif
+#if ARDUINOJSON_USE_INT64
+ IsSame<T, unsigned __int64>::value ||
+#endif
+ false;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/IsVariant.hpp b/include/lib/ArduinoJson/TypeTraits/IsVariant.hpp
new file mode 100644
index 0000000..f8b299f
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/IsVariant.hpp
@@ -0,0 +1,17 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "IsBaseOf.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+class JsonVariantTag {};
+
+template <typename T>
+struct IsVariant : IsBaseOf<JsonVariantTag, T> {};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/RemoveConst.hpp b/include/lib/ArduinoJson/TypeTraits/RemoveConst.hpp
new file mode 100644
index 0000000..39d4cb5
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/RemoveConst.hpp
@@ -0,0 +1,20 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that return the type T without the const modifier
+template <typename T>
+struct RemoveConst {
+ typedef T type;
+};
+template <typename T>
+struct RemoveConst<const T> {
+ typedef T type;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/RemoveReference.hpp b/include/lib/ArduinoJson/TypeTraits/RemoveReference.hpp
new file mode 100644
index 0000000..395a128
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/RemoveReference.hpp
@@ -0,0 +1,20 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that return the type T without the reference modifier.
+template <typename T>
+struct RemoveReference {
+ typedef T type;
+};
+template <typename T>
+struct RemoveReference<T&> {
+ typedef T type;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/version.hpp b/include/lib/ArduinoJson/version.hpp
new file mode 100644
index 0000000..a71c3ab
--- /dev/null
+++ b/include/lib/ArduinoJson/version.hpp
@@ -0,0 +1,10 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#define ARDUINOJSON_VERSION "5.13.2"
+#define ARDUINOJSON_VERSION_MAJOR 5
+#define ARDUINOJSON_VERSION_MINOR 13
+#define ARDUINOJSON_VERSION_REVISION 2
diff --git a/include/lib/ubjson/ubj.h b/include/lib/ubjson/ubj.h
new file mode 100644
index 0000000..a65d104
--- /dev/null
+++ b/include/lib/ubjson/ubj.h
@@ -0,0 +1,230 @@
+#ifndef UBJ_H
+#define UBJ_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include<inttypes.h>
+#include<stdio.h>
+
+typedef enum
+{
+ UBJ_MIXED=0, //NOT a type...or the type is mixed
+
+ UBJ_NULLTYPE,
+ UBJ_NOOP,
+ UBJ_BOOL_TRUE,
+ UBJ_BOOL_FALSE,
+
+ UBJ_CHAR,
+ UBJ_STRING,
+ UBJ_HIGH_PRECISION,
+
+ UBJ_INT8,
+ UBJ_UINT8 ,
+ UBJ_INT16,
+ UBJ_INT32,
+ UBJ_INT64,
+ UBJ_FLOAT32 ,
+ UBJ_FLOAT64,
+
+ UBJ_ARRAY,
+ UBJ_OBJECT,
+
+ UBJ_NUM_TYPES //this is the size of how many types there are (chris' trick)
+} UBJ_TYPE;
+
+
+
+//////////here is the declarations for the writer API////////////////////////////////////
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+struct ubjw_context_t_s;
+typedef struct ubjw_context_t_s ubjw_context_t;
+
+ubjw_context_t* ubjw_open_callback(void* userdata,
+ size_t(*write_cb)(const void* data, size_t size, size_t count, void* userdata),
+ int(*close_cb)(void* userdata),
+ void(*error_cb)(const char* error_msg)
+ );
+ubjw_context_t* ubjw_open_file(FILE*);
+ubjw_context_t* ubjw_open_memory(uint8_t* dst_b, uint8_t* dst_e);
+
+size_t ubjw_close_context(ubjw_context_t* ctx);
+
+void ubjw_write_string(ubjw_context_t* dst, const char* out);
+void ubjw_write_char(ubjw_context_t* dst, char out);
+
+void ubjw_write_uint8(ubjw_context_t* dst, uint8_t out);
+void ubjw_write_int8(ubjw_context_t* dst, int8_t out);
+void ubjw_write_int16(ubjw_context_t* dst, int16_t out);
+void ubjw_write_int32(ubjw_context_t* dst, int32_t out);
+void ubjw_write_int64(ubjw_context_t* dst, int64_t out);
+void ubjw_write_high_precision(ubjw_context_t* dst, const char* hp);
+
+void ubjw_write_integer(ubjw_context_t* dst, int64_t out);
+UBJ_TYPE ubjw_min_integer_type(int64_t in);
+
+void ubjw_write_float32(ubjw_context_t* dst, float out);
+void ubjw_write_float64(ubjw_context_t* dst, double out);
+
+void ubjw_write_floating_point(ubjw_context_t* dst, double out);
+
+void ubjw_write_noop(ubjw_context_t* dst);
+void ubjw_write_null(ubjw_context_t* dst);
+void ubjw_write_bool(ubjw_context_t* dst, uint8_t out);
+
+void ubjw_begin_array(ubjw_context_t* dst, UBJ_TYPE type, size_t count);
+
+void ubjw_begin_object(ubjw_context_t* dst, UBJ_TYPE type, size_t count);
+void ubjw_write_key(ubjw_context_t* dst, const char* key);
+void ubjw_end(ubjw_context_t* dst);
+
+//output an efficient buffer of types
+void ubjw_write_buffer(ubjw_context_t* dst, const uint8_t* data, UBJ_TYPE type, size_t count);
+
+//Proposal for N-D arrays
+void ubjw_begin_ndarray(ubjw_context_t* dst, UBJ_TYPE type, const size_t* dims, uint8_t ndims);
+void ubjw_write_ndbuffer(ubjw_context_t* dst,const uint8_t* data, UBJ_TYPE type, const size_t* dims, uint8_t ndims);
+
+
+//////////here is the declarations for the reader API////////////////////////////////////
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+struct ubjr_context_t_s;
+typedef struct ubjr_context_t_s ubjr_context_t;
+
+//Open up a reader context for reading using a custom calllback
+ubjr_context_t* ubjr_open_callback(void* userdata,
+ size_t(*read_cb)(void* data, size_t size, size_t count, void* userdata),
+ int(*peek_cb)(void* userdata),
+ int(*close_cb)(void* userdata),
+ void(*error_cb)(const char* error_msg)
+ );
+
+//Open a context initialized to a UBJ file
+ubjr_context_t* ubjr_open_file(FILE*);
+
+//Open up a context initialized to a memory dump of a UBJ file (or a segment of a UBJ file)
+ubjr_context_t* ubjr_open_memory(const uint8_t* dst_b, const uint8_t* dst_e);
+
+//Close a reader context
+size_t ubjr_close_context(ubjr_context_t* ctx);
+
+typedef char* ubjr_string_t;
+
+//An array that you read from the stream
+typedef struct ubjr_array_t_s
+{
+ uint8_t originally_sized;
+ UBJ_TYPE type;
+ size_t size; //total number of elements
+ void* values;
+ uint8_t num_dims;
+ size_t* dims; //this could be faster if it was constant size, but would also make the size of the dynamic object a LOT bigger
+
+} ubjr_array_t;
+
+//a map that you read from the stream
+typedef struct ubjr_object_t_s
+{
+ uint8_t originally_sized;
+ UBJ_TYPE type;
+ size_t size;
+ void* values;
+ ubjr_string_t* keys;
+ void* metatable; //don't use this..only useful for computing object_lookup
+} ubjr_object_t;
+
+//a dynamic type that you parsed.
+typedef struct ubjr_dynamic_t_s
+{
+ UBJ_TYPE type;
+ union
+ {
+ uint8_t boolean;
+ double real;
+ int64_t integer;
+ ubjr_string_t string;
+ ubjr_array_t container_array;
+ ubjr_object_t container_object;
+ };
+} ubjr_dynamic_t;
+
+//Parse a dynamic object from the stream
+ubjr_dynamic_t ubjr_read_dynamic(ubjr_context_t* ctx);
+void ubjr_cleanup_dynamic(ubjr_dynamic_t* dyn);
+
+ubjr_dynamic_t ubjr_object_lookup(ubjr_object_t* obj, const char* key);
+size_t ubjr_local_type_size(UBJ_TYPE typ);//should be equivalent to sizeof()
+size_t ubjr_ndarray_index(const ubjr_array_t* arr, const size_t* indices);
+
+
+//output an efficient buffer of types
+///void ubjr_read_buffer(struct ubjr_context_t* dst, const uint8_t* data, UBJ_TYPE type, size_t count);
+
+void ubjr_cleanup_dynamic(ubjr_dynamic_t* dyn);
+void ubjr_cleanup_array(ubjr_array_t* arr);
+void ubjr_cleanup_object(ubjr_object_t* obj);
+
+
+
+///////UBJ_RW api
+
+void ubjrw_write_dynamic(ubjw_context_t* ctx, ubjr_dynamic_t dobj,uint8_t optimize);
+//ubjrw_append_object(ubjw_context_t* ctx, ubjr_dynamic_t dobj);
+//ubjrw_append_array(ubjw_context_t* ctx, ubjr_dynamic_t dobj);
+
+#ifdef __cplusplus
+}
+
+#include<iostream>
+
+static size_t write_os(const void* data, size_t size, size_t count, void* userdata)
+{
+ size_t n = size*count;
+ reinterpret_cast<std::ostream*>(userdata)->write(data, n);
+ return n;
+}
+static void close_os(void* userdata)
+{
+ reinterpret_cast<std::ostream*>(userdata)->close();
+}
+
+static size_t read_is(void* data, size_t size, size_t count, void* userdata)
+{
+ size_t n = size*count;
+ reinterpret_cast<std::istream*>(userdata)->read(data, n);
+ return n;
+}
+static int peek_is(void* userdata)
+{
+ return reinterpret_cast<std::istream*>(userdata)->peek();
+}
+static void close_is(void* userdata)
+{
+ reinterpret_cast<std::istream*>(userdata)->close();
+}
+
+static ubjw_context_t* ubjw_open_stream(std::ostream& outstream)
+{
+ return ubjw_open_callback((void*)&outstream, write_os, close_os, NULL);
+}
+
+static ubjr_context_t* ubjr_open_stream(std::istream& instream)
+{
+ return ubjr_open_callback((void*)&instream, read_is, peek_is, close_is, NULL);
+}
+
+
+
+#endif
+
+#endif
diff --git a/include/lib/ubjson/ubj_internal.h b/include/lib/ubjson/ubj_internal.h
new file mode 100644
index 0000000..fc61697
--- /dev/null
+++ b/include/lib/ubjson/ubj_internal.h
@@ -0,0 +1,163 @@
+#ifndef UBJ_INTERNAL_H
+#define UBJ_INTERNAL_H
+
+#include "ubj.h"
+#include <stdlib.h>
+#include <string.h>
+
+#if _MSC_VER
+#define inline __inline
+#endif
+
+
+static const uint8_t UBJI_TYPEC_convert[UBJ_NUM_TYPES] = "\x00ZNTFCSHiUIlLdD[{";
+
+static const int UBJI_TYPE_size[UBJ_NUM_TYPES] =
+ { -1, //MIXED
+ 0, //NULLTYPE
+ 0, //NOOP
+ 0, //BOOL_TRUE
+ 0, //BOOL_FALSE
+ 1, //CHAR
+ sizeof(const char*), //STRING
+ sizeof(const char*), //high-precision
+ 1, //INT8
+ 1, //UINT8
+ 2, //int16
+ 4, //int32
+ 8, //int64
+ 4, //float32
+ 8, //float64
+ -1, //array
+ -1 //object
+ };
+
+static const size_t UBJR_TYPE_localsize[UBJ_NUM_TYPES] =
+{
+ sizeof(ubjr_dynamic_t), //MIXED
+ 0, //NULLTYPE
+ 0, //NOOP
+ 0, //BOOL_TRUE
+ 0, //BOOL_FALSE
+ sizeof(ubjr_string_t), //CHAR
+ sizeof(ubjr_string_t), //STRING
+ sizeof(ubjr_string_t), //high-precision
+ sizeof(int8_t), //INT8
+ sizeof(uint8_t), //UINT8
+ sizeof(int16_t), //int16
+ sizeof(int32_t), //int32
+ sizeof(int64_t), //int64
+ sizeof(float), //float32
+ sizeof(double), //float64
+ sizeof(ubjr_array_t), //array
+ sizeof(ubjr_object_t) //object
+};
+
+static inline void _to_bigendian16(uint8_t* outbuffer, uint16_t input)
+{
+ *outbuffer++ = (input >> 8); // Get top order byte (guaranteed endian-independent since machine registers)
+ *outbuffer++ = input & 0xFF; // Get bottom order byte
+}
+static inline void _to_bigendian32(uint8_t* outbuffer, uint32_t input)
+{
+ _to_bigendian16(outbuffer, (uint16_t)(input >> 16)); // Get top order 2 bytes
+ _to_bigendian16(outbuffer + 2, (uint16_t)(input & 0xFFFF)); // Get bottom order 2 bytes
+}
+static inline void _to_bigendian64(uint8_t* outbuffer, uint64_t input)
+{
+ _to_bigendian32(outbuffer, (uint32_t)(input >> 32));
+ _to_bigendian32(outbuffer + 4, (uint32_t)(input & 0xFFFFFFFF));
+}
+
+static inline uint8_t _is_bigendian()
+{
+ int i = 1;
+ char *low = (char*)&i;
+ return *low ? 0 : 1;
+}
+
+#define BUF_BIG_ENDIAN_SWAP(type,func,ptr,num) \
+ { \
+ size_t i;type* d = (type*)ptr; \
+ for (i = 0; i < num; i++) \
+ { \
+ func((uint8_t*)&d[i], d[i]); \
+ } \
+ } \
+
+static inline void buf_endian_swap(uint8_t* buf, size_t sz, size_t n)
+{
+ if (!_is_bigendian())
+ {
+ switch (sz)
+ {
+ case 1:
+ case 0:
+ break;
+ case 2:
+ BUF_BIG_ENDIAN_SWAP(uint16_t, _to_bigendian16,buf,n);
+ break;
+ case 4:
+ BUF_BIG_ENDIAN_SWAP(uint32_t, _to_bigendian32,buf,n);
+ break;
+ case 8:
+ BUF_BIG_ENDIAN_SWAP(uint64_t, _to_bigendian64,buf,n);
+ break;
+ };
+ }
+}
+
+//warning...null-terminated strings are assumed...when this is not necessarily valid. FIXED: we don't use null-terminated strings in the reader (NOT FIXED...string type is awkward)
+static inline ubjr_dynamic_t priv_ubjr_pointer_to_dynamic(UBJ_TYPE typ, const void* dat)
+{
+ ubjr_dynamic_t outdyn;
+ outdyn.type = typ;
+ size_t n = 1;
+ switch (typ)
+ {
+ case UBJ_NULLTYPE:
+ case UBJ_NOOP:
+ break;
+ case UBJ_BOOL_TRUE:
+ case UBJ_BOOL_FALSE:
+ outdyn.boolean = (typ == UBJ_BOOL_TRUE ? 1 : 0);
+ break;
+ case UBJ_HIGH_PRECISION:
+ case UBJ_STRING:
+ case UBJ_CHAR://possibly if char allocate, otherwise don't
+ outdyn.string = *(const ubjr_string_t*)dat;
+ break;
+ case UBJ_INT8:
+ outdyn.integer = *(const int8_t*)dat;
+ break;
+ case UBJ_UINT8:
+ outdyn.integer = *(const uint8_t*)dat;
+ break;
+ case UBJ_INT16:
+ outdyn.integer = *(const int16_t*)dat;
+ break;
+ case UBJ_INT32:
+ outdyn.integer = *(const int32_t*)dat;
+ break;
+ case UBJ_INT64:
+ outdyn.integer = *(const int64_t*)dat;
+ break;
+ case UBJ_FLOAT32:
+ outdyn.real = *(const float*)dat;
+ break;
+ case UBJ_FLOAT64:
+ outdyn.real = *(const double*)dat;
+ break;
+ case UBJ_ARRAY:
+ outdyn.container_array = *(const ubjr_array_t*)dat;
+ break;
+ case UBJ_OBJECT:
+ outdyn.container_object = *(const ubjr_object_t*)dat;
+ break;
+ case UBJ_MIXED:
+ outdyn = *(const ubjr_dynamic_t*)dat;
+ };
+ return outdyn;
+}
+
+#endif \ No newline at end of file
diff --git a/src/app/prototest/Makefile.inc b/src/app/prototest/Makefile.inc
new file mode 100644
index 0000000..d501de1
--- /dev/null
+++ b/src/app/prototest/Makefile.inc
@@ -0,0 +1,3 @@
+loop ?= 1
+
+TARGETS += src/lib/ubjson/ubjr.c src/lib/ubjson/ubjw.c
diff --git a/src/app/prototest/main.cc b/src/app/prototest/main.cc
new file mode 100644
index 0000000..c7d0838
--- /dev/null
+++ b/src/app/prototest/main.cc
@@ -0,0 +1,30 @@
+#include "arch.h"
+#include "driver/gpio.h"
+#include "driver/stdout.h"
+#include "lib/ArduinoJson.h"
+
+void loop(void)
+{
+ char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
+ ArduinoJson::StaticJsonBuffer<200> jsonBuffer;
+ ArduinoJson::JsonObject& root = jsonBuffer.parseObject(json);
+ const char *sensor = root["sensor"];
+ kout << "sensor: " << sensor << endl;
+ gpio.led_toggle(1);
+#ifdef TIMER_S
+ kout << dec << uptime.get_s() << endl;
+#endif
+}
+
+int main(void)
+{
+ arch.setup();
+ gpio.setup();
+ kout.setup();
+
+ gpio.led_on(0);
+ kout << "Hello, World!" << endl;
+ arch.idle_loop();
+
+ return 0;
+}
diff --git a/src/lib/ubjson/ubjr.c b/src/lib/ubjson/ubjr.c
new file mode 100644
index 0000000..461459e
--- /dev/null
+++ b/src/lib/ubjson/ubjr.c
@@ -0,0 +1,516 @@
+#include "lib/ubjson/ubj.h"
+#include "lib/ubjson/ubj_internal.h"
+#include <stdlib.h>
+#include <string.h>
+
+#if _MSC_VER
+#define inline __inline
+#endif
+
+typedef struct ubjr_context_t_s
+{
+ size_t (*read_cb )(void* data, size_t size, size_t count, void* userdata);
+ int (*peek_cb )(void* userdata);
+ int (*close_cb)(void* userdata);
+ void (*error_cb)(const char* error_msg);
+
+ void* userdata;
+
+// struct _ubjr_container_t container_stack[CONTAINER_STACK_MAX];
+// struct _ubjr_container_t* head;
+
+ uint8_t ignore_container_flags;
+
+ uint16_t last_error_code;
+
+ size_t total_read;
+} ubjr_context_t;
+
+ubjr_context_t* ubjr_open_callback(void* userdata,
+ size_t(*read_cb)(void* data, size_t size, size_t count, void* userdata),
+ int(*peek_cb)(void* userdata),
+ int(*close_cb)(void* userdata),
+ void(*error_cb)(const char* error_msg)
+ )
+{
+ ubjr_context_t* ctx = (ubjr_context_t*)malloc(sizeof(ubjr_context_t));
+ ctx->userdata = userdata;
+ ctx->read_cb = read_cb;
+ ctx->peek_cb = peek_cb;
+ ctx->close_cb = close_cb;
+ ctx->error_cb = error_cb;
+
+
+/* ctx->head = ctx->container_stack;
+ ctx->head->flags = 0;
+ ctx->head->type = UBJ_MIXED;
+ ctx->head->elements_remaining = 0;
+
+ ctx->ignore_container_flags = 0;*/
+
+ ctx->last_error_code = 0;
+
+ ctx->total_read = 0;
+ return ctx;
+}
+
+size_t ubjr_close_context(ubjr_context_t* ctx)
+{
+ size_t n = ctx->total_read;
+ free(ctx);
+ return n;
+}
+
+static inline uint8_t priv_ubjr_context_getc(ubjr_context_t* ctx)
+{
+ uint8_t a;
+ ctx->total_read += 1;
+ ctx->read_cb(&a, 1, 1, ctx->userdata);
+ return a;
+}
+
+static int fpeek(void* fp)
+{
+ int c;
+ c = fgetc(fp);
+ ungetc(c, fp);
+
+ return c;
+}
+
+ubjr_context_t* ubjr_open_file(FILE* fd)
+{
+ return ubjr_open_callback(fd, (void*)fread,(void*)fpeek,(void*)fclose, NULL);
+}
+
+struct mem_r_fd
+{
+ const uint8_t *begin, *current, *end;
+};
+static int memclose(void* mfd)
+{
+ //free(mfd);
+ return 0;
+}
+static size_t memread(void* data, size_t size, size_t count, struct mem_r_fd* fp)
+{
+ size_t n = size*count;
+ size_t lim = fp->end - fp->current;
+ if (lim < n)
+ {
+ n = lim;
+ }
+ memcpy(data, fp->current, n);
+ fp->current += n;
+ return n;
+}
+static int mempeek(struct mem_r_fd* mfd)
+{
+ return *mfd->current;
+}
+
+ubjr_context_t* ubjr_open_memory(const uint8_t* be, const uint8_t* en)
+{
+ struct mem_r_fd* mfd = (struct mem_r_fd*)malloc(sizeof(struct mem_r_fd));
+ mfd->current = be;
+ mfd->begin = be;
+ mfd->end = en;
+ return ubjr_open_callback(mfd, (void*)memread, (void*)mempeek,(void*)memclose, NULL);
+}
+
+static inline int priv_ubjr_context_peek(ubjr_context_t* ctx)
+{
+ return ctx->peek_cb(ctx->userdata);
+}
+static inline size_t priv_ubjr_context_read(ubjr_context_t* ctx,uint8_t* dst,size_t n)
+{
+ size_t nr=ctx->read_cb(dst,n,1,ctx->userdata);
+ ctx->total_read+=nr;
+ return nr;
+}
+
+typedef struct priv_ubjr_sorted_key_t_s
+{
+ ubjr_string_t key;
+ const uint8_t* value;
+
+} priv_ubjr_sorted_key_t;
+
+static int _obj_key_cmp(const void* av, const void* bv)
+{
+ const priv_ubjr_sorted_key_t *a, *b;
+ a = (const priv_ubjr_sorted_key_t*)av;
+ b = (const priv_ubjr_sorted_key_t*)bv;
+ return strcmp(a->key,b->key);
+}
+
+static inline UBJ_TYPE priv_ubjr_type_from_char(uint8_t c)
+{
+ int i = 0; //TODO: Benchmark this and see if it should be a switch statement where the compiler implements fastest switch e.g. binary search (17 cases might be binary search fast)
+ for (i = 0; i < UBJ_NUM_TYPES && UBJI_TYPEC_convert[i] != c; i++);
+ return (UBJ_TYPE)i;
+}
+
+size_t ubjr_local_type_size(UBJ_TYPE typ)
+{
+ return UBJR_TYPE_localsize[typ];
+}
+
+
+static inline priv_ubjr_sorted_key_t* priv_ubjr_object_build_sorted_keys(ubjr_object_t* obj)
+{
+ priv_ubjr_sorted_key_t* sorted_keysmem = malloc(obj->size*sizeof(priv_ubjr_sorted_key_t));
+ size_t i;
+ for (i = 0; i < obj->size; i++)
+ {
+ sorted_keysmem[i].key = obj->keys[i];
+ sorted_keysmem[i].value = (const uint8_t*)obj->values + i*UBJR_TYPE_localsize[obj->type];
+ }
+ qsort(sorted_keysmem, obj->size, sizeof(priv_ubjr_sorted_key_t), _obj_key_cmp);
+ return sorted_keysmem;
+}
+
+static inline uint8_t priv_ubjr_read_1b(ubjr_context_t* ctx)
+{
+ return priv_ubjr_context_getc(ctx);
+}
+static inline uint16_t priv_ubjr_read_2b(ubjr_context_t* ctx)
+{
+ return (uint16_t)priv_ubjr_read_1b(ctx) << 8 | (uint16_t)priv_ubjr_read_1b(ctx);
+}
+static inline uint32_t priv_ubjr_read_4b(ubjr_context_t* ctx)
+{
+ return (uint32_t)priv_ubjr_read_2b(ctx) << 16 | (uint32_t)priv_ubjr_read_2b(ctx);
+}
+static inline uint64_t priv_ubjr_read_8b(ubjr_context_t* ctx)
+{
+ return (uint64_t)priv_ubjr_read_4b(ctx) << 32 | (uint64_t)priv_ubjr_read_4b(ctx);
+}
+
+static inline int64_t priv_ubjw_read_integer(ubjr_context_t* ctx)
+{
+ ubjr_dynamic_t d = ubjr_read_dynamic(ctx);
+ if (d.type >= UBJ_INT8 && d.type <= UBJ_INT64)
+ return d.integer;
+ return 0;//error
+}
+
+static inline ubjr_object_t priv_ubjr_read_raw_object(ubjr_context_t* ctx);
+static inline ubjr_array_t priv_ubjr_read_raw_array(ubjr_context_t* ctx);
+static inline void priv_ubjr_read_to_ptr(ubjr_context_t* ctx, uint8_t* dst, UBJ_TYPE typ)
+{
+ int64_t n = 1;
+ char *tstr;
+ switch (typ)
+ {
+ case UBJ_MIXED:
+ {
+ *(ubjr_dynamic_t*)dst = ubjr_read_dynamic(ctx);
+ break;
+ }
+ case UBJ_STRING:
+ case UBJ_HIGH_PRECISION:
+ {
+ n = priv_ubjw_read_integer(ctx);
+ }
+ case UBJ_CHAR:
+ {
+ tstr = malloc(n + 1);
+ priv_ubjr_context_read(ctx, tstr, n);
+ tstr[n] = 0;
+ *(ubjr_string_t*)dst = tstr;
+ break;
+ }
+ case UBJ_INT8:
+ case UBJ_UINT8:
+ {
+ *dst = priv_ubjr_read_1b(ctx);
+ break;
+ }
+ case UBJ_INT16:
+ {
+ *(uint16_t*)dst = priv_ubjr_read_2b(ctx);
+ break;
+ }
+ case UBJ_INT32:
+ case UBJ_FLOAT32:
+ {
+ *(uint32_t*)dst = priv_ubjr_read_4b(ctx);
+ break;
+ }
+ case UBJ_INT64:
+ case UBJ_FLOAT64:
+ {
+ *(uint64_t*)dst = priv_ubjr_read_8b(ctx);
+ break;
+ }
+ case UBJ_ARRAY:
+ {
+ *(ubjr_array_t*)dst = priv_ubjr_read_raw_array(ctx);
+ break;
+ }
+ case UBJ_OBJECT:
+ {
+ *(ubjr_object_t*)dst = priv_ubjr_read_raw_object(ctx);
+ break;
+ }
+ };
+}
+
+ubjr_dynamic_t ubjr_object_lookup(ubjr_object_t* obj, const char* key)
+{
+ if (obj->metatable == NULL)
+ {
+ //memcpy(obj->sorted_keys,obj->keys)
+ obj->metatable = priv_ubjr_object_build_sorted_keys(obj);
+ }
+ void* result=bsearch(key, obj->metatable,obj->size, sizeof(priv_ubjr_sorted_key_t),_obj_key_cmp);
+ if (result == NULL)
+ {
+ ubjr_dynamic_t nulldyn;
+ nulldyn.type = UBJ_NULLTYPE;
+ return nulldyn;
+ }
+ const priv_ubjr_sorted_key_t* result_key = (const priv_ubjr_sorted_key_t*)result;
+ return priv_ubjr_pointer_to_dynamic(obj->type,result_key->value);
+}
+
+size_t ubjr_ndarray_index(const ubjr_array_t* arr, const size_t* indices)
+{
+ //multi-dimensional array to linear array lookup
+ size_t cstride = 1;
+ size_t cdex = 0;
+ uint8_t i;
+ uint8_t nd = arr->num_dims;
+ const size_t* dims = arr->dims;
+ for (i = 0; i<nd; i++)
+ {
+ cdex += cstride*indices[i];
+ cstride *= dims[i];
+ }
+ return cdex;
+}
+
+
+
+ubjr_dynamic_t ubjr_read_dynamic(ubjr_context_t* ctx)
+{
+ ubjr_dynamic_t scratch; //scratch memory
+ UBJ_TYPE newtyp = priv_ubjr_type_from_char(priv_ubjr_context_getc(ctx));
+ priv_ubjr_read_to_ptr(ctx, (uint8_t*)&scratch, newtyp);
+ return priv_ubjr_pointer_to_dynamic(newtyp, &scratch);
+}
+
+static inline void priv_read_container_params(ubjr_context_t* ctx, UBJ_TYPE* typout, size_t* sizeout)
+{
+ int nextchar = priv_ubjr_context_peek(ctx);
+ if (nextchar == '$')
+ {
+ priv_ubjr_context_getc(ctx);
+ *typout = priv_ubjr_type_from_char(priv_ubjr_context_getc(ctx));
+ nextchar = priv_ubjr_context_peek(ctx);
+ }
+ else
+ {
+ *typout = UBJ_MIXED;
+ }
+
+ if (nextchar == '#')
+ {
+ priv_ubjr_context_getc(ctx);
+ *sizeout = priv_ubjw_read_integer(ctx);
+ }
+ else
+ {
+ *sizeout = 0;
+ }
+}
+//TODO: This can be reused for object
+
+static inline ubjr_array_t priv_ubjr_read_raw_array(ubjr_context_t* ctx)
+{
+ ubjr_array_t myarray;
+ priv_read_container_params(ctx,&myarray.type,&myarray.size);
+ myarray.num_dims = 1;
+ myarray.dims = NULL;
+ if (myarray.type != UBJ_MIXED && myarray.size==0) //params detected this is a typed array but no size was detected..possibly an N-D array?
+ {
+ if (priv_ubjr_context_peek(ctx) == '@')
+ {
+ uint8_t dselect;
+ priv_ubjr_context_getc(ctx);//skip over the '@' marker
+ myarray.num_dims = priv_ubjr_context_getc(ctx);//since max is 8, no type indicator needed...always a int7 type
+ myarray.dims = malloc(sizeof(size_t)*myarray.num_dims);
+ myarray.size = 1;
+ for (dselect = 0; dselect < myarray.num_dims; dselect++)
+ {
+ size_t d = priv_ubjw_read_integer(ctx);
+ myarray.dims[dselect] = d;
+ myarray.size *= d;
+ }
+ }
+ }
+
+ size_t ls = UBJR_TYPE_localsize[myarray.type];
+ if (myarray.size == 0)
+ {
+ myarray.originally_sized = 0;
+ size_t arrpot = 0;
+ myarray.values=malloc(1*ls+1); //the +1 is for memory for the 0-size elements
+ for (myarray.size = 0; priv_ubjr_context_peek(ctx) != ']'; myarray.size++)
+ {
+ if (myarray.size >= (1ULL << arrpot))
+ {
+ arrpot ++;
+ myarray.values = realloc(myarray.values, (1ULL << arrpot)*ls+1);
+ }
+ priv_ubjr_read_to_ptr(ctx,(uint8_t*)myarray.values + ls*myarray.size,myarray.type);
+ }
+ priv_ubjr_context_getc(ctx); // read the closing ']'
+ }
+ else
+ {
+ myarray.originally_sized = 1;
+ size_t i;
+ myarray.values = malloc(ls*myarray.size+1);
+ size_t sz = UBJI_TYPE_size[myarray.type];
+
+ if (sz >= 0 && myarray.type != UBJ_STRING && myarray.type != UBJ_HIGH_PRECISION && myarray.type != UBJ_CHAR && myarray.type != UBJ_MIXED) //constant size,fastread
+ {
+ priv_ubjr_context_read(ctx, myarray.values, sz*myarray.size);
+ buf_endian_swap(myarray.values, sz, myarray.size); //do nothing for 0-sized buffers
+ }
+ else
+ {
+ for (i = 0; i < myarray.size; i++)
+ {
+ priv_ubjr_read_to_ptr(ctx, (uint8_t*)myarray.values + ls*i, myarray.type);
+ }
+ }
+ }
+ if (myarray.dims == NULL)
+ {
+ myarray.dims = malloc(sizeof(size_t));
+ myarray.dims[0] = myarray.size;
+ }
+ return myarray;
+}
+
+static inline ubjr_object_t priv_ubjr_read_raw_object(ubjr_context_t* ctx)
+{
+ ubjr_object_t myobject;
+ myobject.metatable = NULL;
+ priv_read_container_params(ctx, &myobject.type, &myobject.size);
+
+ size_t ls = UBJR_TYPE_localsize[myobject.type];
+ if (myobject.size == 0)
+ {
+ myobject.originally_sized = 0;
+ size_t arrpot = 0;
+ myobject.values = malloc(1 * ls + 1); //the +1 is for memory for the 0-size elements
+ myobject.keys = malloc(1 * sizeof(ubjr_string_t));
+ for (myobject.size = 0; priv_ubjr_context_peek(ctx) != '}'; myobject.size++)
+ {
+ if (myobject.size >= (1ULL << arrpot))
+ {
+ arrpot++;
+ myobject.values = realloc(myobject.values, (1ULL << arrpot)*ls + 1);
+ myobject.keys = realloc((uint8_t*)myobject.keys, (1ULL << arrpot)*sizeof(ubjr_string_t));
+ }
+ priv_ubjr_read_to_ptr(ctx, (uint8_t*)(myobject.keys + myobject.size), UBJ_STRING);
+ priv_ubjr_read_to_ptr(ctx, (uint8_t*)myobject.values + ls*myobject.size, myobject.type);
+ }
+ priv_ubjr_context_getc(ctx); // read the closing '}'
+ }
+ else
+ {
+ size_t i;
+ myobject.originally_sized = 1;
+ myobject.values = malloc(ls*myobject.size + 1);
+ myobject.keys = malloc(myobject.size * sizeof(ubjr_string_t));
+
+ for (i = 0; i < myobject.size; i++)
+ {
+ priv_ubjr_read_to_ptr(ctx, (uint8_t*)(myobject.keys + i), UBJ_STRING);
+ priv_ubjr_read_to_ptr(ctx, (uint8_t*)myobject.values + ls*i, myobject.type);
+ }
+ }
+ return myobject;
+}
+static inline void priv_ubjr_cleanup_pointer(UBJ_TYPE typ,void* value);
+static inline priv_ubjr_cleanup_container(UBJ_TYPE type,size_t size,void* values)
+{
+ if(type == UBJ_MIXED || type == UBJ_ARRAY || type == UBJ_OBJECT || type == UBJ_STRING)
+ {
+ size_t ls=UBJR_TYPE_localsize[type];
+ uint8_t *viter,*vend;
+ viter=values;
+ vend=viter+ls*size;
+ for(;viter != vend;viter+=ls)
+ {
+ priv_ubjr_cleanup_pointer(type,(void*)viter);
+ }
+ }
+ free(values);
+}
+static inline void priv_ubjr_cleanup_pointer(UBJ_TYPE typ,void* value)
+{
+ switch(typ)
+ {
+ case UBJ_MIXED:
+ {
+ ubjr_dynamic_t* dyn=(ubjr_dynamic_t*)value;
+ switch(dyn->type)
+ {
+ case UBJ_STRING:
+ priv_ubjr_cleanup_pointer(UBJ_STRING,&dyn->string);
+ break;
+ case UBJ_ARRAY:
+ priv_ubjr_cleanup_pointer(UBJ_ARRAY,&dyn->container_array);
+ break;
+ case UBJ_OBJECT:
+ priv_ubjr_cleanup_pointer(UBJ_OBJECT,&dyn->container_object);
+ break;
+ };
+ break;
+ }
+ case UBJ_STRING:
+ {
+ ubjr_string_t* st=(ubjr_string_t*)value;
+ free((void*)*st);
+ break;
+ }
+ case UBJ_ARRAY:
+ {
+ ubjr_array_t* arr=(ubjr_array_t*)value;
+ priv_ubjr_cleanup_container(arr->type,arr->size,arr->values);
+ free(arr->dims);
+ break;
+ }
+ case UBJ_OBJECT:
+ {
+ ubjr_object_t* obj=(ubjr_object_t*)value;
+ priv_ubjr_cleanup_container(obj->type,obj->size,obj->values);
+ priv_ubjr_cleanup_container(UBJ_STRING,obj->size,obj->keys);
+ if(obj->metatable)
+ {
+ free(obj->metatable);
+ }
+ break;
+ }
+ };
+}
+
+void ubjr_cleanup_dynamic(ubjr_dynamic_t* dyn)
+{
+ priv_ubjr_cleanup_pointer(UBJ_MIXED,dyn);
+}
+void ubjr_cleanup_array(ubjr_array_t* arr)
+{
+ priv_ubjr_cleanup_pointer(UBJ_ARRAY,arr);
+}
+void ubjr_cleanup_object(ubjr_object_t* obj)
+{
+ priv_ubjr_cleanup_pointer(UBJ_OBJECT,obj);
+}
+
diff --git a/src/lib/ubjson/ubjrw.c b/src/lib/ubjson/ubjrw.c
new file mode 100644
index 0000000..5b8b102
--- /dev/null
+++ b/src/lib/ubjson/ubjrw.c
@@ -0,0 +1,169 @@
+#include "lib/ubjson/ubj_internal.h"
+
+static uint32_t compute_typemask(ubjr_dynamic_t* vals, size_t sz)
+{
+ uint32_t typemask = 0;
+ size_t i;
+ for (i = 0; i < sz; i++)
+ {
+ typemask |= 1UL << vals[i].type;
+ }
+ return typemask;
+}
+
+static inline UBJ_TYPE typemask2type(uint32_t v)
+{
+ unsigned int r = 0; // r will be lg(v)
+
+ while (v >>= 1) // unroll for more speed...
+ {
+ r++;
+ }
+ return (UBJ_TYPE)r;
+}
+static UBJ_TYPE compute_best_integer_type(ubjr_dynamic_t* vals, size_t sz)
+{
+ uint32_t typemask = 0;
+ size_t i;
+ for (i = 0; i < sz; i++)
+ {
+ typemask |= 1UL << ubjw_min_integer_type(vals[i].integer);
+ }
+ return typemask2type(typemask);
+}
+static uint32_t compute_best_string_type(ubjr_dynamic_t* vals, size_t sz)
+{
+ size_t i;
+ for (i = 0; i < sz; i++)
+ {
+ if (strlen(vals[i].string) > 1)
+ {
+ return UBJ_STRING;
+ }
+ }
+ return UBJ_CHAR;
+}
+static UBJ_TYPE optimize_type(UBJ_TYPE typein,ubjr_dynamic_t* vals, size_t sz)
+{
+ static const uint32_t intmask = (1 << UBJ_INT8) | (1 << UBJ_UINT8) | (1 << UBJ_INT16) | (1 << UBJ_INT32) | (1 << UBJ_INT64);
+ static const uint32_t stringmask = (1 << UBJ_STRING) | (1 << UBJ_CHAR);
+ if (typein != UBJ_MIXED)
+ return typein;
+ //integer optimization can be done here...
+ uint32_t tm = compute_typemask(vals, sz);
+ if ((tm & intmask) == tm) //if all values are integers
+ {
+ return compute_best_integer_type(vals,sz); //calculate the optimum type given the data
+ }
+ else if ((tm & stringmask) == tm)
+ {
+ return compute_best_string_type(vals,sz);
+ }
+ else if(tm && !(tm & (tm- 1))) //if only one bit is set in typemask
+ {
+ return typemask2type(tm); //figure out which bit is set.
+ }
+ else
+ {
+ return UBJ_MIXED;
+ }
+}
+
+void ubjrw_write_dynamic(ubjw_context_t* ctx, ubjr_dynamic_t dobj,uint8_t optimize)
+{
+ UBJ_TYPE ctyp,otyp;
+ size_t csize;
+ uint8_t* cvalues;
+ switch (dobj.type)
+ {
+ case UBJ_MIXED:
+ return;///error, can't be mixed
+ case UBJ_NULLTYPE:
+ ubjw_write_null(ctx);
+ return;
+ case UBJ_NOOP:
+ ubjw_write_noop(ctx);
+ return;
+ case UBJ_BOOL_FALSE:
+ ubjw_write_bool(ctx, 0);
+ return;
+ case UBJ_BOOL_TRUE:
+ ubjw_write_bool(ctx, 1);
+ return;
+ case UBJ_CHAR:
+ ubjw_write_char(ctx, *dobj.string);//first character of string
+ return;
+ case UBJ_STRING:
+ ubjw_write_string(ctx, dobj.string);
+ return;
+ case UBJ_HIGH_PRECISION:
+ ubjw_write_high_precision(ctx, dobj.string);
+ return;
+ case UBJ_INT8:
+ ubjw_write_int8(ctx, (int8_t)dobj.integer);
+ return;
+ case UBJ_UINT8:
+ ubjw_write_uint8(ctx, (uint8_t)dobj.integer);
+ return;
+ case UBJ_INT16:
+ ubjw_write_int16(ctx, (int16_t)dobj.integer);
+ return;
+ case UBJ_INT32:
+ ubjw_write_int32(ctx, (int32_t)dobj.integer);
+ return;
+ case UBJ_INT64:
+ ubjw_write_int64(ctx, dobj.integer);
+ return;
+ case UBJ_FLOAT32:
+ ubjw_write_float32(ctx, (float)dobj.real);
+ return;
+ case UBJ_FLOAT64:
+ ubjw_write_float64(ctx, dobj.real);
+ return;
+ case UBJ_ARRAY:
+ if ((dobj.container_array.originally_sized || optimize) //if we optimize an unsized array to a sized one or the original is sized
+ && dobj.container_array.type != UBJ_MIXED
+ && dobj.container_array.type != UBJ_OBJECT
+ && dobj.container_array.type != UBJ_ARRAY)
+ {
+ ubjw_write_buffer(ctx, dobj.container_array.values, dobj.container_array.type, dobj.container_array.size);
+ return;
+ }
+ else
+ {
+ ctyp = dobj.container_array.type;
+ csize = dobj.container_array.size;
+ cvalues = dobj.container_array.values;
+ otyp = optimize ? optimize_type(ctyp,(ubjr_dynamic_t*)cvalues,csize) : ctyp;
+ ubjw_begin_array(ctx, otyp, (dobj.container_array.originally_sized || optimize) ? csize : 0);
+ break;
+ }
+ case UBJ_OBJECT:
+ {
+ ctyp = dobj.container_object.type;
+ csize = dobj.container_object.size;
+ cvalues = dobj.container_object.values;
+ otyp = optimize ? optimize_type(ctyp, (ubjr_dynamic_t*)cvalues, csize) : ctyp;
+ ubjw_begin_object(ctx, otyp, (dobj.container_object.originally_sized || optimize) ? csize : 0);
+ break;
+ }
+ };
+ {
+ size_t i;
+ ubjr_dynamic_t scratch;
+ size_t ls = UBJR_TYPE_localsize[ctyp];
+
+ for (i = 0; i < csize; i++)
+ {
+ if (dobj.type == UBJ_OBJECT)
+ {
+ ubjw_write_key(ctx, dobj.container_object.keys[i]);
+ }
+ scratch = priv_ubjr_pointer_to_dynamic(ctyp, cvalues + ls*i);
+ scratch.type = (otyp == UBJ_MIXED ? scratch.type : otyp);
+ ubjrw_write_dynamic(ctx, scratch,optimize);
+ }
+ ubjw_end(ctx);
+ }
+
+}
diff --git a/src/lib/ubjson/ubjw.c b/src/lib/ubjson/ubjw.c
new file mode 100644
index 0000000..78eec83
--- /dev/null
+++ b/src/lib/ubjson/ubjw.c
@@ -0,0 +1,618 @@
+#include "lib/ubjson/ubj.h"
+#include "lib/ubjson/ubj_internal.h"
+
+#define CONTAINER_IS_SIZED 0x1
+#define CONTAINER_IS_TYPED 0x2
+#define CONTAINER_IS_UBJ_ARRAY 0x4
+#define CONTAINER_IS_UBJ_OBJECT 0x8
+
+#define CONTAINER_EXPECTS_KEY 0x10
+
+#define CONTAINER_STACK_MAX 64
+#define BUFFER_OUT_SIZE 1024
+
+#define MAX_DIMS 8
+
+
+struct priv_ubjw_container_t
+{
+ uint8_t flags;
+ UBJ_TYPE type;
+ size_t elements_remaining;
+};
+
+struct ubjw_context_t_s
+{
+ size_t(*write_cb)(const void* data, size_t size, size_t count, void* userdata);
+ int(*close_cb)(void* userdata);
+ void (*error_cb)(const char* error_msg);
+
+ void* userdata;
+
+ struct priv_ubjw_container_t container_stack[CONTAINER_STACK_MAX];
+ struct priv_ubjw_container_t* head;
+
+ uint8_t ignore_container_flags;
+
+ uint16_t last_error_code;
+
+ size_t total_written;
+};
+
+
+
+ubjw_context_t* ubjw_open_callback(void* userdata,
+ size_t(*write_cb)(const void* data, size_t size, size_t count, void* userdata),
+ int(*close_cb)(void* userdata),
+ void (*error_cb)(const char* error_msg)
+ )
+{
+ ubjw_context_t* ctx = (ubjw_context_t*)malloc(sizeof(ubjw_context_t));
+ ctx->userdata = userdata;
+ ctx->write_cb = write_cb;
+ ctx->close_cb = close_cb;
+ ctx->error_cb = error_cb;
+
+ ctx->head = ctx->container_stack;
+ ctx->head->flags = 0;
+ ctx->head->type = UBJ_MIXED;
+ ctx->head->elements_remaining = 0;
+ //ctx->head->num_dims=1;
+
+ ctx->ignore_container_flags = 0;
+
+ ctx->last_error_code = 0;
+
+ ctx->total_written = 0;
+ return ctx;
+}
+ubjw_context_t* ubjw_open_file(FILE* fd)
+{
+ return ubjw_open_callback(fd, (void*)fwrite,(void*)fclose,NULL);
+}
+
+struct mem_w_fd
+{
+ uint8_t *begin,*current, *end;
+};
+
+static int memclose(void* mfd)
+{
+ free(mfd);
+ return 0;
+}
+static size_t memwrite(const void* data, size_t size, size_t count, struct mem_w_fd* fp)
+{
+ size_t n = size*count;
+ size_t lim = fp->end - fp->current;
+ if (lim < n)
+ {
+ n = lim;
+ }
+ memcpy(fp->current, data, n);
+ fp->current += n;
+ return n;
+}
+
+ubjw_context_t* ubjw_open_memory(uint8_t* be, uint8_t* en)
+{
+ struct mem_w_fd* mfd = (struct mem_w_fd*)malloc(sizeof(struct mem_w_fd));
+ mfd->current = be;
+ mfd->begin = be;
+ mfd->end = en;
+ return ubjw_open_callback(mfd, (void*)memwrite, (void*)memclose,NULL);
+}
+
+static inline void priv_ubjw_context_append(ubjw_context_t* ctx, uint8_t a)
+{
+ ctx->total_written += 1;
+ ctx->write_cb(&a, 1, 1, ctx->userdata);
+}
+
+static inline void priv_disassembly_begin(ubjw_context_t* ctx)
+{
+#ifdef UBJW_DISASSEMBLY_MODE
+ priv_ubjw_context_append(ctx, (uint8_t)'[');
+#endif
+}
+static inline void priv_disassembly_end(ubjw_context_t* ctx)
+{
+#ifdef UBJW_DISASSEMBLY_MODE
+ priv_ubjw_context_append(ctx, (uint8_t)']');
+#endif
+}
+static inline void priv_disassembly_indent(ubjw_context_t* ctx)
+{
+#ifdef UBJW_DISASSEMBLY_MODE
+ int n = ctx->head - ctx->container_stack;
+ int i;
+ priv_ubjw_context_append(ctx, (uint8_t)'\n');
+ for (i = 0; i < n; i++)
+ {
+ priv_ubjw_context_append(ctx, (uint8_t)'\t');
+ }
+#endif
+}
+
+static inline void priv_ubjw_context_finish_container(ubjw_context_t* ctx, struct priv_ubjw_container_t* head)
+{
+ if (head->flags & CONTAINER_IS_SIZED)
+ {
+ if (head->elements_remaining > 0)
+ {
+ //error not all elements written
+ }
+ }
+ else
+ {
+ priv_disassembly_begin(ctx);
+ if (head->flags & CONTAINER_IS_UBJ_ARRAY)
+ {
+ priv_ubjw_context_append(ctx, (uint8_t)']');
+ }
+ else if (head->flags & CONTAINER_IS_UBJ_OBJECT)
+ {
+ priv_ubjw_context_append(ctx, (uint8_t)'}');
+ }
+ priv_disassembly_end(ctx);
+ }
+}
+
+static inline priv_ubjw_container_stack_push(ubjw_context_t* ctx, const struct priv_ubjw_container_t* cnt)
+{
+ size_t height = ctx->head-ctx->container_stack+1;
+ if(height < CONTAINER_STACK_MAX)
+ {
+ *(++(ctx->head))=*cnt;
+ }
+ else
+ {
+ //todo::error
+ }
+}
+static inline struct priv_ubjw_container_t priv_ubjw_container_stack_pop(ubjw_context_t* ctx)
+{
+ return *ctx->head--;
+}
+
+size_t ubjw_close_context(ubjw_context_t* ctx)
+{
+ while (ctx->head > ctx->container_stack)
+ {
+ struct priv_ubjw_container_t cnt = priv_ubjw_container_stack_pop(ctx);
+ priv_ubjw_context_finish_container(ctx, &cnt);
+ };
+ size_t n = ctx->total_written;
+ if (ctx->close_cb)
+ ctx->close_cb(ctx->userdata);
+ free(ctx);
+ return n;
+}
+
+
+static inline size_t priv_ubjw_context_write(ubjw_context_t* ctx, const uint8_t* data, size_t sz)
+{
+ ctx->total_written += sz;
+ return ctx->write_cb(data, 1, sz, ctx->userdata);
+}
+
+static inline void priv_ubjw_tag_public(ubjw_context_t* ctx, UBJ_TYPE tid)
+{
+ struct priv_ubjw_container_t* ch = ctx->head;
+ if (!ctx->ignore_container_flags)
+ {
+
+ /*if (
+ (!(ch->flags & (CONTAINER_IS_UBJ_ARRAY | CONTAINER_IS_UBJ_OBJECT))) &&
+ (tid != UBJ_ARRAY && tid !=UBJ_OBJECT))
+ {
+ //error, only array and object can be first written
+ }*/
+
+ if (ch->flags & CONTAINER_IS_UBJ_OBJECT)
+ {
+ if (ch->flags & CONTAINER_EXPECTS_KEY)
+ {
+ //error,a key expected
+ return;
+ }
+ ch->flags |= CONTAINER_EXPECTS_KEY; //set key expected next time in this context
+ }
+ else
+ {
+ priv_disassembly_indent(ctx);
+ }
+
+ if (ch->flags & CONTAINER_IS_SIZED)
+ {
+ ch->elements_remaining--; //todo: error if elements remaining is 0;
+ }
+
+ if ((ch->flags & CONTAINER_IS_TYPED) && ch->type == tid)
+ {
+ return;
+ }
+ }
+ priv_disassembly_begin(ctx);
+ priv_ubjw_context_append(ctx, UBJI_TYPEC_convert[tid]);
+ priv_disassembly_end(ctx);
+}
+
+static inline void priv_ubjw_write_raw_string(ubjw_context_t* ctx, const char* out)//TODO: possibly use a safe string
+{
+ size_t n = strlen(out);
+ ctx->ignore_container_flags = 1;
+ ubjw_write_integer(ctx, (int64_t)n);
+ ctx->ignore_container_flags = 0;
+ priv_disassembly_begin(ctx);
+ priv_ubjw_context_write(ctx, (const uint8_t*)out, n);
+ priv_disassembly_end(ctx);
+}
+void ubjw_write_string(ubjw_context_t* ctx, const char* out)
+{
+ priv_ubjw_tag_public(ctx,UBJ_STRING);
+ priv_ubjw_write_raw_string(ctx, out);
+}
+
+static inline void priv_ubjw_write_raw_char(ubjw_context_t* ctx, char out)
+{
+ priv_disassembly_begin(ctx);
+ priv_ubjw_context_append(ctx, (uint8_t)out);
+ priv_disassembly_end(ctx);
+}
+void ubjw_write_char(ubjw_context_t* ctx, char out)
+{
+ priv_ubjw_tag_public(ctx,UBJ_CHAR);
+ priv_ubjw_write_raw_char(ctx, out);
+}
+
+#ifndef min
+static inline size_t min(size_t x,size_t y)
+{
+ return x < y ? x : y;
+}
+#endif
+
+#ifdef UBJW_DISASSEMBLY_MODE
+#include <stdarg.h>
+#define DISASSEMBLY_PRINT_BUFFER_SIZE 1024
+
+static inline priv_disassembly_print(ubjw_context_t* ctx, const char* format,...)
+{
+ char buffer[DISASSEMBLY_PRINT_BUFFER_SIZE];
+ va_list args;
+ va_start(args, format);
+ int n=vsnprintf(buffer, DISASSEMBLY_PRINT_BUFFER_SIZE, format, args);
+ n = min(n, DISASSEMBLY_PRINT_BUFFER_SIZE);
+ priv_ubjw_context_write(ctx, buffer,n);
+ va_end(args);
+}
+#endif
+
+static inline void priv_ubjw_write_raw_uint8(ubjw_context_t* ctx, uint8_t out)
+{
+ priv_disassembly_begin(ctx);
+#ifndef UBJW_DISASSEMBLY_MODE
+ priv_ubjw_context_append(ctx, out);
+#else
+ priv_disassembly_print(ctx, "%hhu", out);
+#endif
+ priv_disassembly_end(ctx);
+}
+void ubjw_write_uint8(ubjw_context_t* ctx, uint8_t out)
+{
+ priv_ubjw_tag_public(ctx,UBJ_UINT8);
+ priv_ubjw_write_raw_uint8(ctx, out);
+}
+
+static inline void priv_ubjw_write_raw_int8(ubjw_context_t* ctx, int8_t out)
+{
+ priv_disassembly_begin(ctx);
+#ifndef UBJW_DISASSEMBLY_MODE
+ priv_ubjw_context_append(ctx, *(uint8_t*)&out);
+#else
+ priv_disassembly_print(ctx, "%hhd", out);
+#endif
+ priv_disassembly_end(ctx);
+}
+void ubjw_write_int8(ubjw_context_t* ctx, int8_t out)
+{
+ priv_ubjw_tag_public(ctx,UBJ_INT8);
+ priv_ubjw_write_raw_int8(ctx, out);
+}
+
+static inline void priv_ubjw_write_raw_int16(ubjw_context_t* ctx, int16_t out)
+{
+ priv_disassembly_begin(ctx);
+#ifndef UBJW_DISASSEMBLY_MODE
+ uint8_t buf[2];
+ _to_bigendian16(buf, *(uint16_t*)&out);
+ priv_ubjw_context_write(ctx, buf, 2);
+#else
+ priv_disassembly_print(ctx, "%hd", out);
+#endif
+ priv_disassembly_end(ctx);
+}
+void ubjw_write_int16(ubjw_context_t* ctx, int16_t out)
+{
+ priv_ubjw_tag_public(ctx,UBJ_INT16);
+ priv_ubjw_write_raw_int16(ctx, out);
+}
+static inline void priv_ubjw_write_raw_int32(ubjw_context_t* ctx, int32_t out)
+{
+ priv_disassembly_begin(ctx);
+#ifndef UBJW_DISASSEMBLY_MODE
+ uint8_t buf[4];
+ _to_bigendian32(buf, *(uint32_t*)&out);
+ priv_ubjw_context_write(ctx, buf, 4);
+#else
+ priv_disassembly_print(ctx, "%ld", out);
+#endif
+ priv_disassembly_end(ctx);
+}
+void ubjw_write_int32(ubjw_context_t* ctx, int32_t out)
+{
+ priv_ubjw_tag_public(ctx,UBJ_INT32);
+ priv_ubjw_write_raw_int32(ctx, out);
+}
+static inline void priv_ubjw_write_raw_int64(ubjw_context_t* ctx, int64_t out)
+{
+ priv_disassembly_begin(ctx);
+#ifndef UBJW_DISASSEMBLY_MODE
+ uint8_t buf[8];
+ _to_bigendian64(buf, *(uint64_t*)&out);
+ priv_ubjw_context_write(ctx, buf, 8);
+#else
+ priv_disassembly_print(ctx, "%lld", out);
+#endif
+ priv_disassembly_end(ctx);
+}
+void ubjw_write_int64(ubjw_context_t* ctx, int64_t out)
+{
+ priv_ubjw_tag_public(ctx,UBJ_INT64);
+ priv_ubjw_write_raw_int64(ctx, out);
+}
+
+void ubjw_write_high_precision(ubjw_context_t* ctx, const char* hp)
+{
+ priv_ubjw_tag_public(ctx,UBJ_HIGH_PRECISION);
+ priv_ubjw_write_raw_string(ctx, hp);
+}
+UBJ_TYPE ubjw_min_integer_type(int64_t in)
+{
+ uint64_t mc = llabs(in);
+ if (mc < 0x80)
+ {
+ return UBJ_INT8;
+ }
+ else if (in > 0 && mc < 0x100)
+ {
+ return UBJ_UINT8;
+ }
+ else if (mc < 0x8000)
+ {
+ return UBJ_INT16;
+ }
+ else if (mc < 0x80000000)
+ {
+ return UBJ_INT32;
+ }
+ else
+ {
+ return UBJ_INT64;
+ }
+}
+
+void ubjw_write_integer(ubjw_context_t* ctx, int64_t out)
+{
+ switch (ubjw_min_integer_type(out))
+ {
+ case UBJ_INT8:
+ ubjw_write_int8(ctx, (int8_t)out);
+ break;
+ case UBJ_UINT8:
+ ubjw_write_uint8(ctx, (uint8_t)out);
+ break;
+ case UBJ_INT16:
+ ubjw_write_int16(ctx, (int16_t)out);
+ break;
+ case UBJ_INT32:
+ ubjw_write_int32(ctx, (int32_t)out);
+ break;
+ default:
+ ubjw_write_int64(ctx, out);
+ break;
+ };
+}
+
+static inline void priv_ubjw_write_raw_float32(ubjw_context_t* ctx, float out)
+{
+ priv_disassembly_begin(ctx);
+#ifndef UBJW_DISASSEMBLY_MODE
+ uint32_t fout = *(uint32_t*)&out;
+ uint8_t outbuf[4];
+ _to_bigendian32(outbuf, fout);
+ priv_ubjw_context_write(ctx, outbuf, 4);
+#else
+ priv_disassembly_print(ctx, "%g", out);
+#endif
+ priv_disassembly_end(ctx);
+
+}
+void ubjw_write_float32(ubjw_context_t* ctx, float out)
+{
+ priv_ubjw_tag_public(ctx,UBJ_FLOAT32);
+ priv_ubjw_write_raw_float32(ctx, out);
+}
+static inline void priv_ubjw_write_raw_float64(ubjw_context_t* ctx, double out)
+{
+ priv_disassembly_begin(ctx);
+#ifndef UBJW_DISASSEMBLY_MODE
+ uint64_t fout = *(uint64_t*)&out;
+ uint8_t outbuf[8];
+ _to_bigendian64(outbuf, fout);
+ priv_ubjw_context_write(ctx, outbuf, 8);
+#else
+ priv_disassembly_print(ctx, "%g", out);
+#endif
+ priv_disassembly_end(ctx);
+}
+void ubjw_write_float64(ubjw_context_t* ctx, double out)
+{
+ priv_ubjw_tag_public(ctx,UBJ_FLOAT64);
+ priv_ubjw_write_raw_float64(ctx, out);
+}
+
+void ubjw_write_floating_point(ubjw_context_t* ctx, double out)
+{
+ //this may not be possible to implement correctly...for now we just write it as a float64'
+ ubjw_write_float64(ctx,out);
+}
+
+void ubjw_write_noop(ubjw_context_t* ctx)
+{
+ priv_ubjw_tag_public(ctx,UBJ_NOOP);
+}
+void ubjw_write_null(ubjw_context_t* ctx)
+{
+ priv_ubjw_tag_public(ctx,UBJ_NULLTYPE);
+}
+void ubjw_write_bool(ubjw_context_t* ctx, uint8_t out)
+{
+ priv_ubjw_tag_public(ctx,(out ? UBJ_BOOL_TRUE : UBJ_BOOL_FALSE));
+}
+
+void priv_ubjw_begin_container(struct priv_ubjw_container_t* cnt, ubjw_context_t* ctx, UBJ_TYPE typ, size_t count)
+{
+ cnt->flags=0;
+ cnt->elements_remaining = count;
+ cnt->type = typ;
+
+ if (typ != UBJ_MIXED)
+ {
+ if (count == 0)
+ {
+ //error and return;
+ }
+ priv_disassembly_begin(ctx);
+ priv_ubjw_context_append(ctx, '$');
+ priv_disassembly_end(ctx);
+
+ priv_disassembly_begin(ctx);
+ priv_ubjw_context_append(ctx, UBJI_TYPEC_convert[typ]);
+ priv_disassembly_end(ctx);
+
+ cnt->flags |= CONTAINER_IS_TYPED;
+ }
+ if (count != 0)
+ {
+ priv_disassembly_begin(ctx);
+ priv_ubjw_context_append(ctx, '#');
+ priv_disassembly_end(ctx);
+
+ ctx->ignore_container_flags = 1;
+ ubjw_write_integer(ctx, (int64_t)count);
+ ctx->ignore_container_flags = 0;
+
+ cnt->flags |= CONTAINER_IS_SIZED;
+ cnt->elements_remaining = count;
+ }
+}
+void ubjw_begin_array(ubjw_context_t* ctx, UBJ_TYPE type, size_t count)
+{
+ priv_ubjw_tag_public(ctx, UBJ_ARRAY); //todo: should this happen before any erro potential?
+ struct priv_ubjw_container_t ch;
+ priv_ubjw_begin_container(&ch, ctx, type, count);
+ ch.flags |= CONTAINER_IS_UBJ_ARRAY;
+ priv_ubjw_container_stack_push(ctx, &ch);
+}
+void ubjw_begin_ndarray(ubjw_context_t* dst, UBJ_TYPE type, const size_t* dims, uint8_t ndims);
+void ubjw_write_ndbuffer(ubjw_context_t* dst, const uint8_t* data, UBJ_TYPE type, const size_t* dims, uint8_t ndims);
+
+void ubjw_begin_object(ubjw_context_t* ctx, UBJ_TYPE type, size_t count)
+{
+ priv_ubjw_tag_public(ctx, UBJ_OBJECT);
+ struct priv_ubjw_container_t ch;
+ priv_ubjw_begin_container(&ch, ctx, type, count);
+ ch.flags |= CONTAINER_EXPECTS_KEY | CONTAINER_IS_UBJ_OBJECT;
+ priv_ubjw_container_stack_push(ctx, &ch);
+}
+void ubjw_write_key(ubjw_context_t* ctx, const char* key)
+{
+ if (ctx->head->flags & CONTAINER_EXPECTS_KEY && ctx->head->flags & CONTAINER_IS_UBJ_OBJECT)
+ {
+ priv_disassembly_indent(ctx);
+ priv_ubjw_write_raw_string(ctx, key);
+ ctx->head->flags ^= CONTAINER_EXPECTS_KEY; //turn off container
+ }
+ else
+ {
+ //error unexpected key
+ }
+}
+void ubjw_end(ubjw_context_t* ctx)
+{
+ struct priv_ubjw_container_t ch = priv_ubjw_container_stack_pop(ctx);
+ if ((ch.flags & CONTAINER_IS_UBJ_OBJECT) && !(ch.flags & CONTAINER_EXPECTS_KEY))
+ {
+ //error expected value
+ }
+ priv_disassembly_indent(ctx);
+ priv_ubjw_context_finish_container(ctx, &ch);
+}
+
+
+static inline void priv_ubjw_write_byteswap(ubjw_context_t* ctx, const uint8_t* data, int sz, size_t count)
+{
+ uint8_t buf[BUFFER_OUT_SIZE];
+
+ size_t i;
+ size_t nbytes = sz*count;
+ for (i = 0; i < nbytes; i+=BUFFER_OUT_SIZE)
+ {
+ size_t npass = min(nbytes - i, BUFFER_OUT_SIZE);
+ memcpy(buf, data + i, npass);
+ buf_endian_swap(buf, sz, npass/sz);
+ priv_ubjw_context_write(ctx, buf, npass);
+ }
+}
+void ubjw_write_buffer(ubjw_context_t* ctx, const uint8_t* data, UBJ_TYPE type, size_t count)
+{
+ int typesz = UBJI_TYPE_size[type];
+ if (typesz < 0)
+ {
+ //error cannot write an STC buffer of this type.
+ }
+ ubjw_begin_array(ctx, type, count);
+ if (type == UBJ_STRING || type == UBJ_HIGH_PRECISION)
+ {
+ const char** databufs = (const char**)data;
+ size_t i;
+ for (i = 0; i < count; i++)
+ {
+ priv_ubjw_write_raw_string(ctx, databufs[i]);
+ }
+ }
+#ifndef UBJW_DISASSEMBLY_MODE
+ else if (typesz == 1 || _is_bigendian())
+ {
+ size_t n = typesz*count;
+ priv_ubjw_context_write(ctx, data, typesz*count);
+ }
+ else if (typesz > 1) //and not big-endian
+ {
+ priv_ubjw_write_byteswap(ctx, data,typesz,count);
+ }
+#else
+ else
+ {
+ size_t i;
+ for (i = 0; i < count; i++)
+ {
+ ubjr_dynamic_t dyn = priv_ubjr_pointer_to_dynamic(type, data + i*typesz);
+ ubjrw_write_dynamic(ctx, dyn, 0);
+ }
+ }
+#endif
+ ubjw_end(ctx);
+}