mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 07:49:52 +03:00
local libs
This commit is contained in:
@@ -1,10 +1,43 @@
|
|||||||
ArduinoJson: change log
|
ArduinoJson: change log
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
HEAD
|
v6.16.1 (2020-08-04)
|
||||||
----
|
-------
|
||||||
|
|
||||||
|
* Fixed `deserializeJson()` that stopped reading after `{}` (issue #1335)
|
||||||
|
|
||||||
|
v6.16.0 (2020-08-01)
|
||||||
|
-------
|
||||||
|
|
||||||
|
* Added comparisons (`>`, `>=`, `==`, `!=`, `<`, and `<=`) between `JsonVariant`s
|
||||||
|
* Added string deduplication (issue #1303)
|
||||||
|
* Added `JsonString::operator!=`
|
||||||
|
* Set `ARDUINOJSON_DECODE_UNICODE` to `1` by default
|
||||||
|
* Fixed `copyArray()` not working with `String`, `ElementProxy`, and `MemberProxy`
|
||||||
|
* Fixed error `getOrAddElement is not a member of ElementProxy` (issue #1311)
|
||||||
|
* Fixed excessive stack usage when compiled with `-Og` (issues #1210 and #1314)
|
||||||
|
* Fixed `Warning[Pa093]: implicit conversion from floating point to integer` on IAR compiler (PR #1328 by @stawiski)
|
||||||
|
|
||||||
|
v6.15.2 (2020-05-15)
|
||||||
|
-------
|
||||||
|
|
||||||
|
* CMake: don't build tests when imported in another project
|
||||||
|
* CMake: made project arch-independent
|
||||||
|
* Visual Studio: fixed error C2766 with flag `/Zc:__cplusplus` (issue #1250)
|
||||||
|
* Added support for `JsonDocument` to `copyArray()` (issue #1255)
|
||||||
|
* Added support for `enum`s in `as<T>()` and `is<T>()` (issue #1256)
|
||||||
|
* Added `JsonVariant` as an input type for `deserializeXxx()`
|
||||||
|
For example, you can do: `deserializeJson(doc2, doc1["payload"])`
|
||||||
|
* Break the build if using 64-bit integers with ARDUINOJSON_USE_LONG_LONG==0
|
||||||
|
|
||||||
|
v6.15.1 (2020-04-08)
|
||||||
|
-------
|
||||||
|
|
||||||
* Fixed "maybe-uninitialized" warning (issue #1217)
|
* Fixed "maybe-uninitialized" warning (issue #1217)
|
||||||
|
* Fixed "statement is unreachable" warning on IAR (issue #1233)
|
||||||
|
* Fixed "pointless integer comparison" warning on IAR (issue #1233)
|
||||||
|
* Added CMake "install" target (issue #1209)
|
||||||
|
* Disabled alignment on AVR (issue #1231)
|
||||||
|
|
||||||
v6.15.0 (2020-03-22)
|
v6.15.0 (2020-03-22)
|
||||||
-------
|
-------
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[](https://www.ardu-badge.com/ArduinoJson/6.15.0)
|
[](https://www.ardu-badge.com/ArduinoJson/6.16.1)
|
||||||
[](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x)
|
[](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x)
|
||||||
[](https://travis-ci.org/bblanchon/ArduinoJson)
|
[](https://travis-ci.org/bblanchon/ArduinoJson)
|
||||||
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
|
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
|
||||||
@@ -17,7 +17,7 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
|
|||||||
* [Optionally decodes UTF-16 escape sequences to UTF-8](https://arduinojson.org/v6/api/config/decode_unicode/?utm_source=github&utm_medium=readme)
|
* [Optionally decodes UTF-16 escape sequences to UTF-8](https://arduinojson.org/v6/api/config/decode_unicode/?utm_source=github&utm_medium=readme)
|
||||||
* [Optionally stores links to the input buffer (zero-copy)](https://arduinojson.org/v6/api/json/deserializejson/?utm_source=github&utm_medium=readme)
|
* [Optionally stores links to the input buffer (zero-copy)](https://arduinojson.org/v6/api/json/deserializejson/?utm_source=github&utm_medium=readme)
|
||||||
* [Optionally supports comments in the input](https://arduinojson.org/v6/api/config/enable_comments/?utm_source=github&utm_medium=readme)
|
* [Optionally supports comments in the input](https://arduinojson.org/v6/api/config/enable_comments/?utm_source=github&utm_medium=readme)
|
||||||
* [Optionally filters the input to keep only desired values](https://arduinojson.org/v6/api/json/deserializejson/#filtering?utm_source=github&utm_medium=readme)
|
* [Optionally filters the input to keep only desired values](https://arduinojson.org/v6/api/json/deserializejson/?utm_source=github&utm_medium=readme#filtering)
|
||||||
* Supports single quotes as a string delimiter
|
* Supports single quotes as a string delimiter
|
||||||
* Compatible with NDJSON and JSON Lines
|
* Compatible with NDJSON and JSON Lines
|
||||||
* [JSON serialization](https://arduinojson.org/v6/api/json/serializejson/?utm_source=github&utm_medium=readme)
|
* [JSON serialization](https://arduinojson.org/v6/api/json/serializejson/?utm_source=github&utm_medium=readme)
|
||||||
@@ -31,12 +31,13 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
|
|||||||
* [Consumes roughly 10% less RAM than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/?utm_source=github&utm_medium=readme)
|
* [Consumes roughly 10% less RAM than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/?utm_source=github&utm_medium=readme)
|
||||||
* [Fixed memory allocation, no heap fragmentation](https://arduinojson.org/v6/api/jsondocument/?utm_source=github&utm_medium=readme)
|
* [Fixed memory allocation, no heap fragmentation](https://arduinojson.org/v6/api/jsondocument/?utm_source=github&utm_medium=readme)
|
||||||
* [Optionally works without heap memory (zero malloc)](https://arduinojson.org/v6/api/staticjsondocument/?utm_source=github&utm_medium=readme)
|
* [Optionally works without heap memory (zero malloc)](https://arduinojson.org/v6/api/staticjsondocument/?utm_source=github&utm_medium=readme)
|
||||||
|
* Deduplicates strings
|
||||||
* Versatile
|
* Versatile
|
||||||
* [Supports custom allocators (to use external RAM chip, for example)](https://arduinojson.org/v6/how-to/use-external-ram-on-esp32/?utm_source=github&utm_medium=readme)
|
* [Supports custom allocators (to use external RAM chip, for example)](https://arduinojson.org/v6/how-to/use-external-ram-on-esp32/?utm_source=github&utm_medium=readme)
|
||||||
* Supports [Arduino's `String`](https://arduinojson.org/v6/api/config/enable_arduino_string/) and [STL's `std::string`](https://arduinojson.org/v6/api/config/enable_std_string/?utm_source=github&utm_medium=readme)
|
* Supports [Arduino's `String`](https://arduinojson.org/v6/api/config/enable_arduino_string/) and [STL's `std::string`](https://arduinojson.org/v6/api/config/enable_std_string/?utm_source=github&utm_medium=readme)
|
||||||
* Supports Arduino's `Stream` and [STL's `std::istream`/`std::ostream`](https://arduinojson.org/v6/api/config/enable_std_stream/?utm_source=github&utm_medium=readme)
|
* Supports Arduino's `Stream` and [STL's `std::istream`/`std::ostream`](https://arduinojson.org/v6/api/config/enable_std_stream/?utm_source=github&utm_medium=readme)
|
||||||
* [Supports Flash strings](https://arduinojson.org/v6/api/config/enable_progmem/?utm_source=github&utm_medium=readme)
|
* [Supports Flash strings](https://arduinojson.org/v6/api/config/enable_progmem/?utm_source=github&utm_medium=readme)
|
||||||
* Supports [custom readers](https://arduinojson.org/v6/api/json/deserializejson/#custom-reader) and [custom writers](https://arduinojson.org/v6/api/json/serializejson/#custom-writer?utm_source=github&utm_medium=readme)
|
* Supports [custom readers](https://arduinojson.org/v6/api/json/deserializejson/?utm_source=github&utm_medium=readme#custom-reader) and [custom writers](https://arduinojson.org/v6/api/json/serializejson/?utm_source=github&utm_medium=readme#custom-writer)
|
||||||
* Portable
|
* Portable
|
||||||
* Usable on any C++ project (not limited to Arduino)
|
* Usable on any C++ project (not limited to Arduino)
|
||||||
* Compatible with C++98
|
* Compatible with C++98
|
||||||
@@ -62,14 +63,15 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
|
|||||||
* [Visual Micro](http://www.visualmicro.com/)
|
* [Visual Micro](http://www.visualmicro.com/)
|
||||||
* [Visual Studio](https://www.visualstudio.com/)
|
* [Visual Studio](https://www.visualstudio.com/)
|
||||||
* [Even works with online compilers like wandbox.org](https://wandbox.org/permlink/t7KP7I6dVuLhqzDl)
|
* [Even works with online compilers like wandbox.org](https://wandbox.org/permlink/t7KP7I6dVuLhqzDl)
|
||||||
|
* [CMake friendly](https://arduinojson.org/v6/how-to/use-arduinojson-with-cmake/?utm_source=github&utm_medium=readme)
|
||||||
* Well designed
|
* Well designed
|
||||||
* [Elegant API](http://127.0.0.1:4000/v6/example/)
|
* [Elegant API](http://arduinojson.org/v6/example/?utm_source=github&utm_medium=readme)
|
||||||
* [Thread-safe](https://en.wikipedia.org/wiki/Thread_safety)
|
* [Thread-safe](https://en.wikipedia.org/wiki/Thread_safety)
|
||||||
* Self-contained (no external dependency)
|
* Self-contained (no external dependency)
|
||||||
* `const` friendly
|
* `const` friendly
|
||||||
* [`for` friendly](https://arduinojson.org/v6/api/jsonobject/begin_end/?utm_source=github&utm_medium=readme)
|
* [`for` friendly](https://arduinojson.org/v6/api/jsonobject/begin_end/?utm_source=github&utm_medium=readme)
|
||||||
* [TMP friendly](https://en.wikipedia.org/wiki/Template_metaprogramming)
|
* [TMP friendly](https://en.wikipedia.org/wiki/Template_metaprogramming)
|
||||||
* Handles [integer overflows](https://arduinojson.org/v6/api/jsonvariant/as/#integer-overflows?utm_source=github&utm_medium=readme)
|
* Handles [integer overflows](https://arduinojson.org/v6/api/jsonvariant/as/?utm_source=github&utm_medium=readme#integer-overflows)
|
||||||
* Well tested
|
* Well tested
|
||||||
* [Unit test coverage close to 100%](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x)
|
* [Unit test coverage close to 100%](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x)
|
||||||
* Continuously tested on
|
* Continuously tested on
|
||||||
@@ -117,10 +119,8 @@ DynamicJsonDocument doc(1024);
|
|||||||
|
|
||||||
doc["sensor"] = "gps";
|
doc["sensor"] = "gps";
|
||||||
doc["time"] = 1351824120;
|
doc["time"] = 1351824120;
|
||||||
|
doc["data"][0] = 48.756080;
|
||||||
JsonArray data = doc.createNestedArray("data");
|
doc["data"][1] = 2.302038;
|
||||||
data.add(48.756080);
|
|
||||||
data.add(2.302038);
|
|
||||||
|
|
||||||
serializeJson(doc, Serial);
|
serializeJson(doc, Serial);
|
||||||
// This prints:
|
// This prints:
|
||||||
@@ -134,4 +134,4 @@ See the [tutorial on arduinojson.org](https://arduinojson.org/doc/encoding/?utm_
|
|||||||
Do you like this library? Please [star this project on GitHub](https://github.com/bblanchon/ArduinoJson/stargazers)!
|
Do you like this library? Please [star this project on GitHub](https://github.com/bblanchon/ArduinoJson/stargazers)!
|
||||||
|
|
||||||
What? You don't like it but you *love* it?
|
What? You don't like it but you *love* it?
|
||||||
We don't take donations anymore, but [we sell a book](https://arduinojson.org/book/?utm_source=github&utm_medium=readme), so you can help and learn at the same time?utm_source=github&utm_medium=readme!
|
We don't take donations anymore, but [we sell a book](https://arduinojson.org/book/?utm_source=github&utm_medium=readme), so you can help and learn at the same time.
|
||||||
154
lib/ArduinoJson/examples/JsonConfigFile/JsonConfigFile.ino
Normal file
154
lib/ArduinoJson/examples/JsonConfigFile/JsonConfigFile.ino
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
// ArduinoJson - arduinojson.org
|
||||||
|
// Copyright Benoit Blanchon 2014-2020
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// This example shows how to store your project configuration in a file.
|
||||||
|
// It uses the SD library but can be easily modified for any other file-system.
|
||||||
|
//
|
||||||
|
// The file contains a JSON document with the following content:
|
||||||
|
// {
|
||||||
|
// "hostname": "examples.com",
|
||||||
|
// "port": 2731
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// To run this program, you need an SD card connected to the SPI bus as follows:
|
||||||
|
// * MOSI <-> pin 11
|
||||||
|
// * MISO <-> pin 12
|
||||||
|
// * CLK <-> pin 13
|
||||||
|
// * CS <-> pin 4
|
||||||
|
//
|
||||||
|
// https://arduinojson.org/v6/example/config/
|
||||||
|
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <SD.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
|
||||||
|
// Our configuration structure.
|
||||||
|
//
|
||||||
|
// Never use a JsonDocument to store the configuration!
|
||||||
|
// A JsonDocument is *not* a permanent storage; it's only a temporary storage
|
||||||
|
// used during the serialization phase. See:
|
||||||
|
// https://arduinojson.org/v6/faq/why-must-i-create-a-separate-config-object/
|
||||||
|
struct Config {
|
||||||
|
char hostname[64];
|
||||||
|
int port;
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *filename = "/config.txt"; // <- SD library uses 8.3 filenames
|
||||||
|
Config config; // <- global configuration object
|
||||||
|
|
||||||
|
// Loads the configuration from a file
|
||||||
|
void loadConfiguration(const char *filename, Config &config) {
|
||||||
|
// Open file for reading
|
||||||
|
File file = SD.open(filename);
|
||||||
|
|
||||||
|
// Allocate a temporary JsonDocument
|
||||||
|
// Don't forget to change the capacity to match your requirements.
|
||||||
|
// Use arduinojson.org/v6/assistant to compute the capacity.
|
||||||
|
StaticJsonDocument<512> doc;
|
||||||
|
|
||||||
|
// Deserialize the JSON document
|
||||||
|
DeserializationError error = deserializeJson(doc, file);
|
||||||
|
if (error)
|
||||||
|
Serial.println(F("Failed to read file, using default configuration"));
|
||||||
|
|
||||||
|
// Copy values from the JsonDocument to the Config
|
||||||
|
config.port = doc["port"] | 2731;
|
||||||
|
strlcpy(config.hostname, // <- destination
|
||||||
|
doc["hostname"] | "example.com", // <- source
|
||||||
|
sizeof(config.hostname)); // <- destination's capacity
|
||||||
|
|
||||||
|
// Close the file (Curiously, File's destructor doesn't close the file)
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Saves the configuration to a file
|
||||||
|
void saveConfiguration(const char *filename, const Config &config) {
|
||||||
|
// Delete existing file, otherwise the configuration is appended to the file
|
||||||
|
SD.remove(filename);
|
||||||
|
|
||||||
|
// Open file for writing
|
||||||
|
File file = SD.open(filename, FILE_WRITE);
|
||||||
|
if (!file) {
|
||||||
|
Serial.println(F("Failed to create file"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate a temporary JsonDocument
|
||||||
|
// Don't forget to change the capacity to match your requirements.
|
||||||
|
// Use arduinojson.org/assistant to compute the capacity.
|
||||||
|
StaticJsonDocument<256> doc;
|
||||||
|
|
||||||
|
// Set the values in the document
|
||||||
|
doc["hostname"] = config.hostname;
|
||||||
|
doc["port"] = config.port;
|
||||||
|
|
||||||
|
// Serialize JSON to file
|
||||||
|
if (serializeJson(doc, file) == 0) {
|
||||||
|
Serial.println(F("Failed to write to file"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the file
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints the content of a file to the Serial
|
||||||
|
void printFile(const char *filename) {
|
||||||
|
// Open file for reading
|
||||||
|
File file = SD.open(filename);
|
||||||
|
if (!file) {
|
||||||
|
Serial.println(F("Failed to read file"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract each characters by one by one
|
||||||
|
while (file.available()) {
|
||||||
|
Serial.print((char)file.read());
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
// Close the file
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Initialize serial port
|
||||||
|
Serial.begin(9600);
|
||||||
|
while (!Serial) continue;
|
||||||
|
|
||||||
|
// Initialize SD library
|
||||||
|
const int chipSelect = 4;
|
||||||
|
while (!SD.begin(chipSelect)) {
|
||||||
|
Serial.println(F("Failed to initialize SD library"));
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should load default config if run for the first time
|
||||||
|
Serial.println(F("Loading configuration..."));
|
||||||
|
loadConfiguration(filename, config);
|
||||||
|
|
||||||
|
// Create configuration file
|
||||||
|
Serial.println(F("Saving configuration..."));
|
||||||
|
saveConfiguration(filename, config);
|
||||||
|
|
||||||
|
// Dump config file
|
||||||
|
Serial.println(F("Print config file..."));
|
||||||
|
printFile(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// not used in this example
|
||||||
|
}
|
||||||
|
|
||||||
|
// See also
|
||||||
|
// --------
|
||||||
|
//
|
||||||
|
// https://arduinojson.org/ contains the documentation for all the functions
|
||||||
|
// used above. It also includes an FAQ that will help you solve any
|
||||||
|
// serialization or deserialization problem.
|
||||||
|
//
|
||||||
|
// The book "Mastering ArduinoJson" contains a case study of a project that has
|
||||||
|
// a complex configuration with nested members.
|
||||||
|
// Contrary to this example, the project in the book uses the SPIFFS filesystem.
|
||||||
|
// Learn more at https://arduinojson.org/book/
|
||||||
|
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
// ArduinoJson - arduinojson.org
|
||||||
|
// Copyright Benoit Blanchon 2014-2020
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// This example shows how to use DeserializationOpion::Filter
|
||||||
|
//
|
||||||
|
// https://arduinojson.org/v6/example/filter/
|
||||||
|
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Initialize serial port
|
||||||
|
Serial.begin(9600);
|
||||||
|
while (!Serial) continue;
|
||||||
|
|
||||||
|
// The huge input: an extract from OpenWeatherMap response
|
||||||
|
const __FlashStringHelper* input_json = F(
|
||||||
|
"{\"cod\":\"200\",\"message\":0,\"list\":[{\"dt\":1581498000,\"main\":{"
|
||||||
|
"\"temp\":3.23,\"feels_like\":-3.63,\"temp_min\":3.23,\"temp_max\":4.62,"
|
||||||
|
"\"pressure\":1014,\"sea_level\":1014,\"grnd_level\":1010,\"humidity\":"
|
||||||
|
"58,\"temp_kf\":-1.39},\"weather\":[{\"id\":800,\"main\":\"Clear\","
|
||||||
|
"\"description\":\"clear "
|
||||||
|
"sky\",\"icon\":\"01d\"}],\"clouds\":{\"all\":0},\"wind\":{\"speed\":6."
|
||||||
|
"19,\"deg\":266},\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2020-02-12 "
|
||||||
|
"09:00:00\"},{\"dt\":1581508800,\"main\":{\"temp\":6.09,\"feels_like\":-"
|
||||||
|
"1.07,\"temp_min\":6.09,\"temp_max\":7.13,\"pressure\":1015,\"sea_"
|
||||||
|
"level\":1015,\"grnd_level\":1011,\"humidity\":48,\"temp_kf\":-1.04},"
|
||||||
|
"\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear "
|
||||||
|
"sky\",\"icon\":\"01d\"}],\"clouds\":{\"all\":9},\"wind\":{\"speed\":6."
|
||||||
|
"64,\"deg\":268},\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2020-02-12 "
|
||||||
|
"12:00:00\"}],\"city\":{\"id\":2643743,\"name\":\"London\",\"coord\":{"
|
||||||
|
"\"lat\":51.5085,\"lon\":-0.1257},\"country\":\"GB\",\"population\":"
|
||||||
|
"1000000,\"timezone\":0,\"sunrise\":1581492085,\"sunset\":1581527294}}");
|
||||||
|
|
||||||
|
// The filter: it contains "true" for each value we want to keep
|
||||||
|
StaticJsonDocument<200> filter;
|
||||||
|
filter["list"][0]["dt"] = true;
|
||||||
|
filter["list"][0]["main"]["temp"] = true;
|
||||||
|
|
||||||
|
// Deserialize the document
|
||||||
|
StaticJsonDocument<400> doc;
|
||||||
|
deserializeJson(doc, input_json, DeserializationOption::Filter(filter));
|
||||||
|
|
||||||
|
// Print the result
|
||||||
|
serializeJsonPretty(doc, Serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// not used in this example
|
||||||
|
}
|
||||||
|
|
||||||
|
// See also
|
||||||
|
// --------
|
||||||
|
//
|
||||||
|
// https://arduinojson.org/ contains the documentation for all the functions
|
||||||
|
// used above. It also includes an FAQ that will help you solve any
|
||||||
|
// deserialization problem.
|
||||||
|
//
|
||||||
|
// The book "Mastering ArduinoJson" contains a tutorial on deserialization.
|
||||||
|
// It begins with a simple example, like the one above, and then adds more
|
||||||
|
// features like deserializing directly from a file or an HTTP request.
|
||||||
|
// Learn more at https://arduinojson.org/book/
|
||||||
|
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤
|
||||||
@@ -3,11 +3,16 @@
|
|||||||
// MIT License
|
// MIT License
|
||||||
//
|
//
|
||||||
// This example shows how to generate a JSON document with ArduinoJson.
|
// This example shows how to generate a JSON document with ArduinoJson.
|
||||||
|
//
|
||||||
|
// https://arduinojson.org/v6/example/generator/
|
||||||
|
|
||||||
#include <iostream>
|
#include <ArduinoJson.h>
|
||||||
#include "ArduinoJson.h"
|
|
||||||
|
void setup() {
|
||||||
|
// Initialize Serial port
|
||||||
|
Serial.begin(9600);
|
||||||
|
while (!Serial) continue;
|
||||||
|
|
||||||
int main() {
|
|
||||||
// Allocate the JSON document
|
// Allocate the JSON document
|
||||||
//
|
//
|
||||||
// Inside the brackets, 200 is the RAM allocated to this document.
|
// Inside the brackets, 200 is the RAM allocated to this document.
|
||||||
@@ -20,11 +25,6 @@ int main() {
|
|||||||
//
|
//
|
||||||
// DynamicJsonDocument doc(200);
|
// DynamicJsonDocument doc(200);
|
||||||
|
|
||||||
// StaticJsonObject allocates memory on the stack, it can be
|
|
||||||
// replaced by DynamicJsonDocument which allocates in the heap.
|
|
||||||
//
|
|
||||||
// DynamicJsonDocument doc(200);
|
|
||||||
|
|
||||||
// Add values in the document
|
// Add values in the document
|
||||||
//
|
//
|
||||||
doc["sensor"] = "gps";
|
doc["sensor"] = "gps";
|
||||||
@@ -36,18 +36,18 @@ int main() {
|
|||||||
data.add(48.756080);
|
data.add(48.756080);
|
||||||
data.add(2.302038);
|
data.add(2.302038);
|
||||||
|
|
||||||
// Generate the minified JSON and send it to STDOUT
|
// Generate the minified JSON and send it to the Serial port.
|
||||||
//
|
//
|
||||||
serializeJson(doc, std::cout);
|
serializeJson(doc, Serial);
|
||||||
// The above line prints:
|
// The above line prints:
|
||||||
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
|
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
|
||||||
|
|
||||||
// Start a new line
|
// Start a new line
|
||||||
std::cout << std::endl;
|
Serial.println();
|
||||||
|
|
||||||
// Generate the prettified JSON and send it to STDOUT
|
// Generate the prettified JSON and send it to the Serial port.
|
||||||
//
|
//
|
||||||
serializeJsonPretty(doc, std::cout);
|
serializeJsonPretty(doc, Serial);
|
||||||
// The above line prints:
|
// The above line prints:
|
||||||
// {
|
// {
|
||||||
// "sensor": "gps",
|
// "sensor": "gps",
|
||||||
@@ -58,3 +58,20 @@ int main() {
|
|||||||
// ]
|
// ]
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// not used in this example
|
||||||
|
}
|
||||||
|
|
||||||
|
// See also
|
||||||
|
// --------
|
||||||
|
//
|
||||||
|
// https://arduinojson.org/ contains the documentation for all the functions
|
||||||
|
// used above. It also includes an FAQ that will help you solve any
|
||||||
|
// serialization problem.
|
||||||
|
//
|
||||||
|
// The book "Mastering ArduinoJson" contains a tutorial on serialization.
|
||||||
|
// It begins with a simple example, like the one above, and then adds more
|
||||||
|
// features like serializing directly to a file or an HTTP request.
|
||||||
|
// Learn more at https://arduinojson.org/book/
|
||||||
|
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤
|
||||||
116
lib/ArduinoJson/examples/JsonHttpClient/JsonHttpClient.ino
Normal file
116
lib/ArduinoJson/examples/JsonHttpClient/JsonHttpClient.ino
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
// ArduinoJson - arduinojson.org
|
||||||
|
// Copyright Benoit Blanchon 2014-2020
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// This example shows how to parse a JSON document in an HTTP response.
|
||||||
|
// It uses the Ethernet library, but can be easily adapted for Wifi.
|
||||||
|
//
|
||||||
|
// It performs a GET resquest on arduinojson.org/example.json
|
||||||
|
// Here is the expected response:
|
||||||
|
// {
|
||||||
|
// "sensor": "gps",
|
||||||
|
// "time": 1351824120,
|
||||||
|
// "data": [
|
||||||
|
// 48.756080,
|
||||||
|
// 2.302038
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// https://arduinojson.org/v6/example/http-client/
|
||||||
|
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <Ethernet.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Initialize Serial port
|
||||||
|
Serial.begin(9600);
|
||||||
|
while (!Serial) continue;
|
||||||
|
|
||||||
|
// Initialize Ethernet library
|
||||||
|
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
|
||||||
|
if (!Ethernet.begin(mac)) {
|
||||||
|
Serial.println(F("Failed to configure Ethernet"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
Serial.println(F("Connecting..."));
|
||||||
|
|
||||||
|
// Connect to HTTP server
|
||||||
|
EthernetClient client;
|
||||||
|
client.setTimeout(10000);
|
||||||
|
if (!client.connect("arduinojson.org", 80)) {
|
||||||
|
Serial.println(F("Connection failed"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println(F("Connected!"));
|
||||||
|
|
||||||
|
// Send HTTP request
|
||||||
|
client.println(F("GET /example.json HTTP/1.0"));
|
||||||
|
client.println(F("Host: arduinojson.org"));
|
||||||
|
client.println(F("Connection: close"));
|
||||||
|
if (client.println() == 0) {
|
||||||
|
Serial.println(F("Failed to send request"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check HTTP status
|
||||||
|
char status[32] = {0};
|
||||||
|
client.readBytesUntil('\r', status, sizeof(status));
|
||||||
|
// It should be "HTTP/1.0 200 OK" or "HTTP/1.1 200 OK"
|
||||||
|
if (strcmp(status + 9, "200 OK") != 0) {
|
||||||
|
Serial.print(F("Unexpected response: "));
|
||||||
|
Serial.println(status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip HTTP headers
|
||||||
|
char endOfHeaders[] = "\r\n\r\n";
|
||||||
|
if (!client.find(endOfHeaders)) {
|
||||||
|
Serial.println(F("Invalid response"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate the JSON document
|
||||||
|
// Use arduinojson.org/v6/assistant to compute the capacity.
|
||||||
|
const size_t capacity = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 60;
|
||||||
|
DynamicJsonDocument doc(capacity);
|
||||||
|
|
||||||
|
// Parse JSON object
|
||||||
|
DeserializationError error = deserializeJson(doc, client);
|
||||||
|
if (error) {
|
||||||
|
Serial.print(F("deserializeJson() failed: "));
|
||||||
|
Serial.println(error.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract values
|
||||||
|
Serial.println(F("Response:"));
|
||||||
|
Serial.println(doc["sensor"].as<char*>());
|
||||||
|
Serial.println(doc["time"].as<long>());
|
||||||
|
Serial.println(doc["data"][0].as<float>(), 6);
|
||||||
|
Serial.println(doc["data"][1].as<float>(), 6);
|
||||||
|
|
||||||
|
// Disconnect
|
||||||
|
client.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// not used in this example
|
||||||
|
}
|
||||||
|
|
||||||
|
// See also
|
||||||
|
// --------
|
||||||
|
//
|
||||||
|
// https://arduinojson.org/ contains the documentation for all the functions
|
||||||
|
// used above. It also includes an FAQ that will help you solve any
|
||||||
|
// serialization problem.
|
||||||
|
//
|
||||||
|
// The book "Mastering ArduinoJson" contains a tutorial on deserialization
|
||||||
|
// showing how to parse the response from GitHub's API. In the last chapter,
|
||||||
|
// it shows how to parse the huge documents from OpenWeatherMap
|
||||||
|
// and Reddit.
|
||||||
|
// Learn more at https://arduinojson.org/book/
|
||||||
|
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤
|
||||||
@@ -3,17 +3,22 @@
|
|||||||
// MIT License
|
// MIT License
|
||||||
//
|
//
|
||||||
// This example shows how to deserialize a JSON document with ArduinoJson.
|
// This example shows how to deserialize a JSON document with ArduinoJson.
|
||||||
|
//
|
||||||
|
// https://arduinojson.org/v6/example/parser/
|
||||||
|
|
||||||
#include <iostream>
|
#include <ArduinoJson.h>
|
||||||
#include "ArduinoJson.h"
|
|
||||||
|
void setup() {
|
||||||
|
// Initialize serial port
|
||||||
|
Serial.begin(9600);
|
||||||
|
while (!Serial) continue;
|
||||||
|
|
||||||
int main() {
|
|
||||||
// Allocate the JSON document
|
// Allocate the JSON document
|
||||||
//
|
//
|
||||||
// Inside the brackets, 200 is the capacity of the memory pool in bytes.
|
// Inside the brackets, 200 is the capacity of the memory pool in bytes.
|
||||||
// Don't forget to change this value to match your JSON document.
|
// Don't forget to change this value to match your JSON document.
|
||||||
// Use arduinojson.org/v6/assistant to compute the capacity.
|
// Use arduinojson.org/v6/assistant to compute the capacity.
|
||||||
StaticJsonDocument<300> doc;
|
StaticJsonDocument<200> doc;
|
||||||
|
|
||||||
// StaticJsonDocument<N> allocates memory on the stack, it can be
|
// StaticJsonDocument<N> allocates memory on the stack, it can be
|
||||||
// replaced by DynamicJsonDocument which allocates in the heap.
|
// replaced by DynamicJsonDocument which allocates in the heap.
|
||||||
@@ -36,8 +41,9 @@ int main() {
|
|||||||
|
|
||||||
// Test if parsing succeeds.
|
// Test if parsing succeeds.
|
||||||
if (error) {
|
if (error) {
|
||||||
std::cerr << "deserializeJson() failed: " << error.c_str() << std::endl;
|
Serial.print(F("deserializeJson() failed: "));
|
||||||
return 1;
|
Serial.println(error.c_str());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch values.
|
// Fetch values.
|
||||||
@@ -50,10 +56,25 @@ int main() {
|
|||||||
double longitude = doc["data"][1];
|
double longitude = doc["data"][1];
|
||||||
|
|
||||||
// Print values.
|
// Print values.
|
||||||
std::cout << sensor << std::endl;
|
Serial.println(sensor);
|
||||||
std::cout << time << std::endl;
|
Serial.println(time);
|
||||||
std::cout << latitude << std::endl;
|
Serial.println(latitude, 6);
|
||||||
std::cout << longitude << std::endl;
|
Serial.println(longitude, 6);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// not used in this example
|
||||||
|
}
|
||||||
|
|
||||||
|
// See also
|
||||||
|
// --------
|
||||||
|
//
|
||||||
|
// https://arduinojson.org/ contains the documentation for all the functions
|
||||||
|
// used above. It also includes an FAQ that will help you solve any
|
||||||
|
// deserialization problem.
|
||||||
|
//
|
||||||
|
// The book "Mastering ArduinoJson" contains a tutorial on deserialization.
|
||||||
|
// It begins with a simple example, like the one above, and then adds more
|
||||||
|
// features like deserializing directly from a file or an HTTP request.
|
||||||
|
// Learn more at https://arduinojson.org/book/
|
||||||
|
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤
|
||||||
110
lib/ArduinoJson/examples/JsonServer/JsonServer.ino
Normal file
110
lib/ArduinoJson/examples/JsonServer/JsonServer.ino
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
// ArduinoJson - arduinojson.org
|
||||||
|
// Copyright Benoit Blanchon 2014-2020
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// This example shows how to implement an HTTP server that sends a JSON document
|
||||||
|
// in the response.
|
||||||
|
// It uses the Ethernet library but can be easily adapted for Wifi.
|
||||||
|
//
|
||||||
|
// The JSON document contains the values of the analog and digital pins.
|
||||||
|
// It looks like that:
|
||||||
|
// {
|
||||||
|
// "analog": [0, 76, 123, 158, 192, 205],
|
||||||
|
// "digital": [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0]
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// https://arduinojson.org/v6/example/http-server/
|
||||||
|
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <Ethernet.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
|
||||||
|
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
|
||||||
|
EthernetServer server(80);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Initialize serial port
|
||||||
|
Serial.begin(9600);
|
||||||
|
while (!Serial) continue;
|
||||||
|
|
||||||
|
// Initialize Ethernet libary
|
||||||
|
if (!Ethernet.begin(mac)) {
|
||||||
|
Serial.println(F("Failed to initialize Ethernet library"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start to listen
|
||||||
|
server.begin();
|
||||||
|
|
||||||
|
Serial.println(F("Server is ready."));
|
||||||
|
Serial.print(F("Please connect to http://"));
|
||||||
|
Serial.println(Ethernet.localIP());
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// Wait for an incomming connection
|
||||||
|
EthernetClient client = server.available();
|
||||||
|
|
||||||
|
// Do we have a client?
|
||||||
|
if (!client) return;
|
||||||
|
|
||||||
|
Serial.println(F("New client"));
|
||||||
|
|
||||||
|
// Read the request (we ignore the content in this example)
|
||||||
|
while (client.available()) client.read();
|
||||||
|
|
||||||
|
// Allocate a temporary JsonDocument
|
||||||
|
// Use arduinojson.org/v6/assistant to compute the capacity.
|
||||||
|
StaticJsonDocument<500> doc;
|
||||||
|
|
||||||
|
// Create the "analog" array
|
||||||
|
JsonArray analogValues = doc.createNestedArray("analog");
|
||||||
|
for (int pin = 0; pin < 6; pin++) {
|
||||||
|
// Read the analog input
|
||||||
|
int value = analogRead(pin);
|
||||||
|
|
||||||
|
// Add the value at the end of the array
|
||||||
|
analogValues.add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the "digital" array
|
||||||
|
JsonArray digitalValues = doc.createNestedArray("digital");
|
||||||
|
for (int pin = 0; pin < 14; pin++) {
|
||||||
|
// Read the digital input
|
||||||
|
int value = digitalRead(pin);
|
||||||
|
|
||||||
|
// Add the value at the end of the array
|
||||||
|
digitalValues.add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.print(F("Sending: "));
|
||||||
|
serializeJson(doc, Serial);
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
// Write response headers
|
||||||
|
client.println(F("HTTP/1.0 200 OK"));
|
||||||
|
client.println(F("Content-Type: application/json"));
|
||||||
|
client.println(F("Connection: close"));
|
||||||
|
client.print(F("Content-Length: "));
|
||||||
|
client.println(measureJsonPretty(doc));
|
||||||
|
client.println();
|
||||||
|
|
||||||
|
// Write JSON document
|
||||||
|
serializeJsonPretty(doc, client);
|
||||||
|
|
||||||
|
// Disconnect
|
||||||
|
client.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// See also
|
||||||
|
// --------
|
||||||
|
//
|
||||||
|
// https://arduinojson.org/ contains the documentation for all the functions
|
||||||
|
// used above. It also includes an FAQ that will help you solve any
|
||||||
|
// serialization problem.
|
||||||
|
//
|
||||||
|
// The book "Mastering ArduinoJson" contains a tutorial on serialization.
|
||||||
|
// It begins with a simple example, then adds more features like serializing
|
||||||
|
// directly to a file or an HTTP client.
|
||||||
|
// Learn more at https://arduinojson.org/book/
|
||||||
|
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤
|
||||||
100
lib/ArduinoJson/examples/JsonUdpBeacon/JsonUdpBeacon.ino
Normal file
100
lib/ArduinoJson/examples/JsonUdpBeacon/JsonUdpBeacon.ino
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
// ArduinoJson - arduinojson.org
|
||||||
|
// Copyright Benoit Blanchon 2014-2020
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// This example shows how to send a JSON document to a UDP socket.
|
||||||
|
// At regular interval, it sends a UDP packet that contains the status of
|
||||||
|
// analog and digital pins.
|
||||||
|
// It looks like that:
|
||||||
|
// {
|
||||||
|
// "analog": [0, 76, 123, 158, 192, 205],
|
||||||
|
// "digital": [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0]
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// If you want to test this program, you need to be able to receive the UDP
|
||||||
|
// packets.
|
||||||
|
// For example, you can run netcat on your computer
|
||||||
|
// $ ncat -ulp 8888
|
||||||
|
// See https://nmap.org/ncat/
|
||||||
|
//
|
||||||
|
// https://arduinojson.org/v6/example/udp-beacon/
|
||||||
|
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <Ethernet.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
|
||||||
|
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
|
||||||
|
IPAddress remoteIp(192, 168, 0, 108); // <- EDIT!!!!
|
||||||
|
unsigned short remotePort = 8888;
|
||||||
|
unsigned short localPort = 8888;
|
||||||
|
EthernetUDP udp;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Initialize serial port
|
||||||
|
Serial.begin(9600);
|
||||||
|
while (!Serial) continue;
|
||||||
|
|
||||||
|
// Initialize Ethernet libary
|
||||||
|
if (!Ethernet.begin(mac)) {
|
||||||
|
Serial.println(F("Failed to initialize Ethernet library"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable UDP
|
||||||
|
udp.begin(localPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// Allocate a temporary JsonDocument
|
||||||
|
// Use arduinojson.org/v6/assistant to compute the capacity.
|
||||||
|
StaticJsonDocument<500> doc;
|
||||||
|
|
||||||
|
// Create the "analog" array
|
||||||
|
JsonArray analogValues = doc.createNestedArray("analog");
|
||||||
|
for (int pin = 0; pin < 6; pin++) {
|
||||||
|
// Read the analog input
|
||||||
|
int value = analogRead(pin);
|
||||||
|
|
||||||
|
// Add the value at the end of the array
|
||||||
|
analogValues.add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the "digital" array
|
||||||
|
JsonArray digitalValues = doc.createNestedArray("digital");
|
||||||
|
for (int pin = 0; pin < 14; pin++) {
|
||||||
|
// Read the digital input
|
||||||
|
int value = digitalRead(pin);
|
||||||
|
|
||||||
|
// Add the value at the end of the array
|
||||||
|
digitalValues.add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log
|
||||||
|
Serial.print(F("Sending to "));
|
||||||
|
Serial.print(remoteIp);
|
||||||
|
Serial.print(F(" on port "));
|
||||||
|
Serial.println(remotePort);
|
||||||
|
serializeJson(doc, Serial);
|
||||||
|
|
||||||
|
// Send UDP packet
|
||||||
|
udp.beginPacket(remoteIp, remotePort);
|
||||||
|
serializeJson(doc, udp);
|
||||||
|
udp.println();
|
||||||
|
udp.endPacket();
|
||||||
|
|
||||||
|
// Wait
|
||||||
|
delay(10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// See also
|
||||||
|
// --------
|
||||||
|
//
|
||||||
|
// https://arduinojson.org/ contains the documentation for all the functions
|
||||||
|
// used above. It also includes an FAQ that will help you solve any
|
||||||
|
// serialization problem.
|
||||||
|
//
|
||||||
|
// The book "Mastering ArduinoJson" contains a tutorial on serialization.
|
||||||
|
// It begins with a simple example, then adds more features like serializing
|
||||||
|
// directly to a file or any stream.
|
||||||
|
// Learn more at https://arduinojson.org/book/
|
||||||
|
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤
|
||||||
@@ -2,18 +2,24 @@
|
|||||||
// Copyright Benoit Blanchon 2014-2020
|
// Copyright Benoit Blanchon 2014-2020
|
||||||
// MIT License
|
// MIT License
|
||||||
//
|
//
|
||||||
// This example shows how to generate a JSON document with ArduinoJson.
|
// This example shows how to deserialize a MessagePack document with
|
||||||
|
// ArduinoJson.
|
||||||
|
//
|
||||||
|
// https://arduinojson.org/v6/example/msgpack-parser/
|
||||||
|
|
||||||
#include <iostream>
|
#include <ArduinoJson.h>
|
||||||
#include "ArduinoJson.h"
|
|
||||||
|
void setup() {
|
||||||
|
// Initialize serial port
|
||||||
|
Serial.begin(9600);
|
||||||
|
while (!Serial) continue;
|
||||||
|
|
||||||
int main() {
|
|
||||||
// Allocate the JSON document
|
// Allocate the JSON document
|
||||||
//
|
//
|
||||||
// Inside the brackets, 300 is the size of the memory pool in bytes.
|
// Inside the brackets, 200 is the capacity of the memory pool in bytes.
|
||||||
// Don't forget to change this value to match your JSON document.
|
// Don't forget to change this value to match your JSON document.
|
||||||
// Use arduinojson.org/assistant to compute the capacity.
|
// Use arduinojson.org/v6/assistant to compute the capacity.
|
||||||
StaticJsonDocument<300> doc;
|
StaticJsonDocument<200> doc;
|
||||||
|
|
||||||
// StaticJsonObject allocates memory on the stack, it can be
|
// StaticJsonObject allocates memory on the stack, it can be
|
||||||
// replaced by DynamicJsonObject which allocates in the heap.
|
// replaced by DynamicJsonObject which allocates in the heap.
|
||||||
@@ -22,9 +28,12 @@ int main() {
|
|||||||
|
|
||||||
// MessagePack input string.
|
// MessagePack input string.
|
||||||
//
|
//
|
||||||
// It's better to use a char[] as shown here.
|
// Using a char[], as shown here, enables the "zero-copy" mode. This mode uses
|
||||||
// If you use a const char* or a String, ArduinoJson will
|
// the minimal amount of memory because the JsonDocument stores pointers to
|
||||||
// have to make a copy of the input in the JsonBuffer.
|
// the input buffer.
|
||||||
|
// If you use another type of input, ArduinoJson must copy the strings from
|
||||||
|
// the input to the JsonDocument, so you need to increase the capacity of the
|
||||||
|
// JsonDocument.
|
||||||
uint8_t input[] = {131, 166, 115, 101, 110, 115, 111, 114, 163, 103, 112, 115,
|
uint8_t input[] = {131, 166, 115, 101, 110, 115, 111, 114, 163, 103, 112, 115,
|
||||||
164, 116, 105, 109, 101, 206, 80, 147, 50, 248, 164, 100,
|
164, 116, 105, 109, 101, 206, 80, 147, 50, 248, 164, 100,
|
||||||
97, 116, 97, 146, 203, 64, 72, 96, 199, 58, 188, 148,
|
97, 116, 97, 146, 203, 64, 72, 96, 199, 58, 188, 148,
|
||||||
@@ -36,17 +45,13 @@ int main() {
|
|||||||
// "data": [48.75608, 2.302038]
|
// "data": [48.75608, 2.302038]
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// doc of the object tree.
|
|
||||||
//
|
|
||||||
// It's a reference to the JsonObject, the actual bytes are inside the
|
|
||||||
// JsonBuffer with all the other nodes of the object tree.
|
|
||||||
// Memory is freed when jsonBuffer goes out of scope.
|
|
||||||
DeserializationError error = deserializeMsgPack(doc, input);
|
DeserializationError error = deserializeMsgPack(doc, input);
|
||||||
|
|
||||||
// Test if parsing succeeds.
|
// Test if parsing succeeded.
|
||||||
if (error) {
|
if (error) {
|
||||||
std::cerr << "deserializeMsgPack() failed: " << error.c_str() << std::endl;
|
Serial.print("deserializeMsgPack() failed: ");
|
||||||
return 1;
|
Serial.println(error.c_str());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch values.
|
// Fetch values.
|
||||||
@@ -59,10 +64,12 @@ int main() {
|
|||||||
double longitude = doc["data"][1];
|
double longitude = doc["data"][1];
|
||||||
|
|
||||||
// Print values.
|
// Print values.
|
||||||
std::cout << sensor << std::endl;
|
Serial.println(sensor);
|
||||||
std::cout << time << std::endl;
|
Serial.println(time);
|
||||||
std::cout << latitude << std::endl;
|
Serial.println(latitude, 6);
|
||||||
std::cout << longitude << std::endl;
|
Serial.println(longitude, 6);
|
||||||
|
}
|
||||||
return 0;
|
|
||||||
|
void loop() {
|
||||||
|
// not used in this example
|
||||||
}
|
}
|
||||||
72
lib/ArduinoJson/examples/ProgmemExample/ProgmemExample.ino
Normal file
72
lib/ArduinoJson/examples/ProgmemExample/ProgmemExample.ino
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
// ArduinoJson - arduinojson.org
|
||||||
|
// Copyright Benoit Blanchon 2014-2020
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// This example shows the different ways you can use Flash strings with
|
||||||
|
// ArduinoJson.
|
||||||
|
//
|
||||||
|
// Use Flash strings sparingly, because ArduinoJson duplicates them in the
|
||||||
|
// JsonDocument. Prefer plain old char*, as they are more efficient in term of
|
||||||
|
// code size, speed, and memory usage.
|
||||||
|
//
|
||||||
|
// https://arduinojson.org/v6/example/progmem/
|
||||||
|
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
#ifdef PROGMEM // <- check that Flash strings are supported
|
||||||
|
|
||||||
|
DynamicJsonDocument doc(1024);
|
||||||
|
|
||||||
|
// You can use a Flash String as your JSON input.
|
||||||
|
// WARNING: the strings in the input will be duplicated in the JsonDocument.
|
||||||
|
deserializeJson(doc, F("{\"sensor\":\"gps\",\"time\":1351824120,"
|
||||||
|
"\"data\":[48.756080,2.302038]}"));
|
||||||
|
JsonObject obj = doc.as<JsonObject>();
|
||||||
|
|
||||||
|
// You can use a Flash String to get an element of a JsonObject
|
||||||
|
// No duplication is done.
|
||||||
|
long time = obj[F("time")];
|
||||||
|
|
||||||
|
// You can use a Flash String to set an element of a JsonObject
|
||||||
|
// WARNING: the content of the Flash String will be duplicated in the
|
||||||
|
// JsonDocument.
|
||||||
|
obj[F("time")] = time;
|
||||||
|
|
||||||
|
// You can set a Flash String to a JsonObject or JsonArray:
|
||||||
|
// WARNING: the content of the Flash String will be duplicated in the
|
||||||
|
// JsonDocument.
|
||||||
|
obj["sensor"] = F("gps");
|
||||||
|
|
||||||
|
// It works with serialized() too:
|
||||||
|
obj["sensor"] = serialized(F("\"gps\""));
|
||||||
|
obj["sensor"] = serialized(F("\xA3gps"), 3);
|
||||||
|
|
||||||
|
// You can compare the content of a JsonVariant to a Flash String
|
||||||
|
if (obj["sensor"] == F("gps")) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#warning PROGMEM is not supported on this platform
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// not used in this example
|
||||||
|
}
|
||||||
|
|
||||||
|
// See also
|
||||||
|
// --------
|
||||||
|
//
|
||||||
|
// https://arduinojson.org/ contains the documentation for all the functions
|
||||||
|
// used above. It also includes an FAQ that will help you solve any memory
|
||||||
|
// problem.
|
||||||
|
//
|
||||||
|
// The book "Mastering ArduinoJson" contains a quick C++ course that explains
|
||||||
|
// how your microcontroller stores strings in memory. It also tells why you
|
||||||
|
// should not abuse Flash strings with ArduinoJson.
|
||||||
|
// Learn more at https://arduinojson.org/book/
|
||||||
|
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤
|
||||||
77
lib/ArduinoJson/examples/StringExample/StringExample.ino
Normal file
77
lib/ArduinoJson/examples/StringExample/StringExample.ino
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
// ArduinoJson - arduinojson.org
|
||||||
|
// Copyright Benoit Blanchon 2014-2020
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// This example shows the different ways you can use String with ArduinoJson.
|
||||||
|
//
|
||||||
|
// Use String objects sparingly, because ArduinoJson duplicates them in the
|
||||||
|
// JsonDocument. Prefer plain old char[], as they are more efficient in term of
|
||||||
|
// code size, speed, and memory usage.
|
||||||
|
//
|
||||||
|
// https://arduinojson.org/v6/example/string/
|
||||||
|
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
DynamicJsonDocument doc(1024);
|
||||||
|
|
||||||
|
// You can use a String as your JSON input.
|
||||||
|
// WARNING: the string in the input will be duplicated in the JsonDocument.
|
||||||
|
String input =
|
||||||
|
"{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
|
||||||
|
deserializeJson(doc, input);
|
||||||
|
JsonObject obj = doc.as<JsonObject>();
|
||||||
|
|
||||||
|
// You can use a String to get an element of a JsonObject
|
||||||
|
// No duplication is done.
|
||||||
|
long time = obj[String("time")];
|
||||||
|
|
||||||
|
// You can use a String to set an element of a JsonObject
|
||||||
|
// WARNING: the content of the String will be duplicated in the JsonDocument.
|
||||||
|
obj[String("time")] = time;
|
||||||
|
|
||||||
|
// You can get a String from a JsonObject or JsonArray:
|
||||||
|
// No duplication is done, at least not in the JsonDocument.
|
||||||
|
String sensor = obj["sensor"];
|
||||||
|
|
||||||
|
// Unfortunately, the following doesn't work (issue #118):
|
||||||
|
// sensor = obj["sensor"]; // <- error "ambiguous overload for 'operator='"
|
||||||
|
// As a workaround, you need to replace by:
|
||||||
|
sensor = obj["sensor"].as<String>();
|
||||||
|
|
||||||
|
// You can set a String to a JsonObject or JsonArray:
|
||||||
|
// WARNING: the content of the String will be duplicated in the JsonDocument.
|
||||||
|
obj["sensor"] = sensor;
|
||||||
|
|
||||||
|
// It works with serialized() too:
|
||||||
|
obj["sensor"] = serialized(sensor);
|
||||||
|
|
||||||
|
// You can also concatenate strings
|
||||||
|
// WARNING: the content of the String will be duplicated in the JsonDocument.
|
||||||
|
obj[String("sen") + "sor"] = String("gp") + "s";
|
||||||
|
|
||||||
|
// You can compare the content of a JsonObject with a String
|
||||||
|
if (obj["sensor"] == sensor) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lastly, you can print the resulting JSON to a String
|
||||||
|
String output;
|
||||||
|
serializeJson(doc, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// not used in this example
|
||||||
|
}
|
||||||
|
|
||||||
|
// See also
|
||||||
|
// --------
|
||||||
|
//
|
||||||
|
// https://arduinojson.org/ contains the documentation for all the functions
|
||||||
|
// used above. It also includes an FAQ that will help you solve any problem.
|
||||||
|
//
|
||||||
|
// The book "Mastering ArduinoJson" contains a quick C++ course that explains
|
||||||
|
// how your microcontroller stores strings in memory. On several occasions, it
|
||||||
|
// shows how you can avoid String in your program.
|
||||||
|
// Learn more at https://arduinojson.org/book/
|
||||||
|
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
name=ArduinoJson
|
name=ArduinoJson
|
||||||
version=6.15.0
|
version=6.16.1
|
||||||
author=Benoit Blanchon <blog.benoitblanchon.fr>
|
author=Benoit Blanchon <blog.benoitblanchon.fr>
|
||||||
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
|
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
|
||||||
sentence=A simple and efficient JSON library for embedded C++.
|
sentence=A simple and efficient JSON library for embedded C++.
|
||||||
@@ -28,6 +28,7 @@
|
|||||||
#include "ArduinoJson/Object/MemberProxy.hpp"
|
#include "ArduinoJson/Object/MemberProxy.hpp"
|
||||||
#include "ArduinoJson/Object/ObjectImpl.hpp"
|
#include "ArduinoJson/Object/ObjectImpl.hpp"
|
||||||
#include "ArduinoJson/Variant/VariantAsImpl.hpp"
|
#include "ArduinoJson/Variant/VariantAsImpl.hpp"
|
||||||
|
#include "ArduinoJson/Variant/VariantCompare.hpp"
|
||||||
#include "ArduinoJson/Variant/VariantImpl.hpp"
|
#include "ArduinoJson/Variant/VariantImpl.hpp"
|
||||||
|
|
||||||
#include "ArduinoJson/Json/JsonDeserializer.hpp"
|
#include "ArduinoJson/Json/JsonDeserializer.hpp"
|
||||||
@@ -5,7 +5,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ArduinoJson/Configuration.hpp>
|
#include <ArduinoJson/Configuration.hpp>
|
||||||
#include <ArduinoJson/Operators/VariantOperators.hpp>
|
#include <ArduinoJson/Variant/VariantOperators.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantShortcuts.hpp>
|
||||||
#include <ArduinoJson/Variant/VariantTo.hpp>
|
#include <ArduinoJson/Variant/VariantTo.hpp>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
@@ -17,6 +18,7 @@ namespace ARDUINOJSON_NAMESPACE {
|
|||||||
|
|
||||||
template <typename TArray>
|
template <typename TArray>
|
||||||
class ElementProxy : public VariantOperators<ElementProxy<TArray> >,
|
class ElementProxy : public VariantOperators<ElementProxy<TArray> >,
|
||||||
|
public VariantShortcuts<ElementProxy<TArray> >,
|
||||||
public Visitable {
|
public Visitable {
|
||||||
typedef ElementProxy<TArray> this_type;
|
typedef ElementProxy<TArray> this_type;
|
||||||
|
|
||||||
@@ -51,14 +53,6 @@ class ElementProxy : public VariantOperators<ElementProxy<TArray> >,
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE bool operator==(VariantConstRef rhs) const {
|
|
||||||
return static_cast<VariantConstRef>(getUpstreamElement()) == rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
FORCE_INLINE bool operator!=(VariantConstRef rhs) const {
|
|
||||||
return static_cast<VariantConstRef>(getUpstreamElement()) != rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
FORCE_INLINE void clear() const {
|
FORCE_INLINE void clear() const {
|
||||||
getUpstreamElement().clear();
|
getUpstreamElement().clear();
|
||||||
}
|
}
|
||||||
@@ -72,6 +66,11 @@ class ElementProxy : public VariantOperators<ElementProxy<TArray> >,
|
|||||||
return getUpstreamElement().template as<T>();
|
return getUpstreamElement().template as<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
FORCE_INLINE operator T() const {
|
||||||
|
return getUpstreamElement();
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
FORCE_INLINE bool is() const {
|
FORCE_INLINE bool is() const {
|
||||||
return getUpstreamElement().template is<T>();
|
return getUpstreamElement().template is<T>();
|
||||||
@@ -136,6 +135,10 @@ class ElementProxy : public VariantOperators<ElementProxy<TArray> >,
|
|||||||
return getOrAddUpstreamElement().getElement(index);
|
return getOrAddUpstreamElement().getElement(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VariantRef getOrAddElement(size_t index) const {
|
||||||
|
return getOrAddUpstreamElement().getOrAddElement(index);
|
||||||
|
}
|
||||||
|
|
||||||
FORCE_INLINE void remove(size_t index) const {
|
FORCE_INLINE void remove(size_t index) const {
|
||||||
getUpstreamElement().remove(index);
|
getUpstreamElement().remove(index);
|
||||||
}
|
}
|
||||||
150
lib/ArduinoJson/src/ArduinoJson/Array/Utilities.hpp
Normal file
150
lib/ArduinoJson/src/ArduinoJson/Array/Utilities.hpp
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
// ArduinoJson - arduinojson.org
|
||||||
|
// Copyright Benoit Blanchon 2014-2020
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Array/ArrayRef.hpp>
|
||||||
|
#include <ArduinoJson/Document/JsonDocument.hpp>
|
||||||
|
|
||||||
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
|
// Copy a 1D array to a JsonArray
|
||||||
|
template <typename T, size_t N, typename TDestination>
|
||||||
|
inline typename enable_if<!is_array<T>::value &&
|
||||||
|
!is_base_of<JsonDocument, TDestination>::value,
|
||||||
|
bool>::type
|
||||||
|
copyArray(T (&src)[N], const TDestination& dst) {
|
||||||
|
return copyArray(src, N, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy a 1D array to a JsonDocument
|
||||||
|
template <typename T, size_t N>
|
||||||
|
inline bool copyArray(T (&src)[N], JsonDocument& dst) {
|
||||||
|
return copyArray(src, dst.to<ArrayRef>());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy a 1D array to a JsonArray
|
||||||
|
template <typename T, typename TDestination>
|
||||||
|
inline typename enable_if<!is_array<T>::value &&
|
||||||
|
!is_base_of<JsonDocument, TDestination>::value,
|
||||||
|
bool>::type
|
||||||
|
copyArray(T* src, size_t len, const TDestination& dst) {
|
||||||
|
bool ok = true;
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
ok &= dst.add(src[i]);
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy a 1D array to a JsonDocument
|
||||||
|
template <typename T>
|
||||||
|
inline bool copyArray(T* src, size_t len, JsonDocument& dst) {
|
||||||
|
return copyArray(src, len, dst.to<ArrayRef>());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy a 2D array to a JsonArray
|
||||||
|
template <typename T, size_t N1, size_t N2, typename TDestination>
|
||||||
|
inline typename enable_if<!is_base_of<JsonDocument, TDestination>::value,
|
||||||
|
bool>::type
|
||||||
|
copyArray(T (&src)[N1][N2], const TDestination& dst) {
|
||||||
|
bool ok = true;
|
||||||
|
for (size_t i = 0; i < N1; i++) {
|
||||||
|
ArrayRef nestedArray = dst.createNestedArray();
|
||||||
|
for (size_t j = 0; j < N2; j++) {
|
||||||
|
ok &= nestedArray.add(src[i][j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy a 2D array to a JsonDocument
|
||||||
|
template <typename T, size_t N1, size_t N2>
|
||||||
|
inline bool copyArray(T (&src)[N1][N2], JsonDocument& dst) {
|
||||||
|
return copyArray(src, dst.to<ArrayRef>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class ArrayCopier1D {
|
||||||
|
public:
|
||||||
|
ArrayCopier1D(T* destination, size_t capacity)
|
||||||
|
: _destination(destination), _capacity(capacity), _size(0) {}
|
||||||
|
|
||||||
|
void visitArray(const CollectionData& array) {
|
||||||
|
VariantSlot* slot = array.head();
|
||||||
|
|
||||||
|
while (slot != 0 && _size < _capacity) {
|
||||||
|
_destination[_size++] = variantAs<T>(slot->data());
|
||||||
|
slot = slot->next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void visitObject(const CollectionData&) {}
|
||||||
|
void visitFloat(Float) {}
|
||||||
|
void visitString(const char*) {}
|
||||||
|
void visitRawJson(const char*, size_t) {}
|
||||||
|
void visitNegativeInteger(UInt) {}
|
||||||
|
void visitPositiveInteger(UInt) {}
|
||||||
|
void visitBoolean(bool) {}
|
||||||
|
void visitNull() {}
|
||||||
|
|
||||||
|
size_t result() const {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T* _destination;
|
||||||
|
size_t _capacity;
|
||||||
|
size_t _size;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, size_t N1, size_t N2>
|
||||||
|
class ArrayCopier2D {
|
||||||
|
public:
|
||||||
|
ArrayCopier2D(T (*destination)[N1][N2]) : _destination(destination) {}
|
||||||
|
|
||||||
|
void visitArray(const CollectionData& array) {
|
||||||
|
VariantSlot* slot = array.head();
|
||||||
|
size_t n = 0;
|
||||||
|
while (slot != 0 && n < N1) {
|
||||||
|
ArrayCopier1D<T> copier((*_destination)[n++], N2);
|
||||||
|
variantAccept(slot->data(), copier);
|
||||||
|
slot = slot->next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void visitObject(const CollectionData&) {}
|
||||||
|
void visitFloat(Float) {}
|
||||||
|
void visitString(const char*) {}
|
||||||
|
void visitRawJson(const char*, size_t) {}
|
||||||
|
void visitNegativeInteger(UInt) {}
|
||||||
|
void visitPositiveInteger(UInt) {}
|
||||||
|
void visitBoolean(bool) {}
|
||||||
|
void visitNull() {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T (*_destination)[N1][N2];
|
||||||
|
size_t _capacity1, _capacity2;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Copy a JsonArray to a 1D array
|
||||||
|
template <typename TSource, typename T, size_t N>
|
||||||
|
inline typename enable_if<!is_array<T>::value, size_t>::type copyArray(
|
||||||
|
const TSource& src, T (&dst)[N]) {
|
||||||
|
return copyArray(src, dst, N);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy a JsonArray to a 1D array
|
||||||
|
template <typename TSource, typename T>
|
||||||
|
inline size_t copyArray(const TSource& src, T* dst, size_t len) {
|
||||||
|
ArrayCopier1D<T> copier(dst, len);
|
||||||
|
src.accept(copier);
|
||||||
|
return copier.result();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy a JsonArray to a 2D array
|
||||||
|
template <typename TSource, typename T, size_t N1, size_t N2>
|
||||||
|
inline void copyArray(const TSource& src, T (&dst)[N1][N2]) {
|
||||||
|
ArrayCopier2D<T, N1, N2> copier(&dst);
|
||||||
|
src.accept(copier);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
@@ -9,6 +9,10 @@
|
|||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
|
inline bool variantEquals(const VariantData* a, const VariantData* b) {
|
||||||
|
return variantCompare(a, b) == COMPARE_RESULT_EQUAL;
|
||||||
|
}
|
||||||
|
|
||||||
inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) {
|
inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) {
|
||||||
VariantSlot* slot = pool->allocVariant();
|
VariantSlot* slot = pool->allocVariant();
|
||||||
if (!slot)
|
if (!slot)
|
||||||
@@ -4,12 +4,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#define ARDUINOJSON_HAS_INT64 1
|
|
||||||
#else
|
|
||||||
#define ARDUINOJSON_HAS_INT64 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __cplusplus >= 201103L
|
#if __cplusplus >= 201103L
|
||||||
#define ARDUINOJSON_HAS_LONG_LONG 1
|
#define ARDUINOJSON_HAS_LONG_LONG 1
|
||||||
#define ARDUINOJSON_HAS_NULLPTR 1
|
#define ARDUINOJSON_HAS_NULLPTR 1
|
||||||
@@ -20,6 +14,12 @@
|
|||||||
#define ARDUINOJSON_HAS_RVALUE_REFERENCES 0
|
#define ARDUINOJSON_HAS_RVALUE_REFERENCES 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !ARDUINOJSON_HAS_LONG_LONG
|
||||||
|
#define ARDUINOJSON_HAS_INT64 1
|
||||||
|
#else
|
||||||
|
#define ARDUINOJSON_HAS_INT64 0
|
||||||
|
#endif
|
||||||
|
|
||||||
// Small or big machine?
|
// Small or big machine?
|
||||||
#ifndef ARDUINOJSON_EMBEDDED_MODE
|
#ifndef ARDUINOJSON_EMBEDDED_MODE
|
||||||
#if defined(ARDUINO) /* Arduino*/ \
|
#if defined(ARDUINO) /* Arduino*/ \
|
||||||
@@ -164,7 +164,7 @@
|
|||||||
|
|
||||||
// Convert unicode escape sequence (\u0123) to UTF-8
|
// Convert unicode escape sequence (\u0123) to UTF-8
|
||||||
#ifndef ARDUINOJSON_DECODE_UNICODE
|
#ifndef ARDUINOJSON_DECODE_UNICODE
|
||||||
#define ARDUINOJSON_DECODE_UNICODE 0
|
#define ARDUINOJSON_DECODE_UNICODE 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Ignore comments in input
|
// Ignore comments in input
|
||||||
@@ -203,10 +203,22 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef ARDUINOJSON_ENABLE_ALIGNMENT
|
||||||
|
#if defined(__AVR)
|
||||||
|
#define ARDUINOJSON_ENABLE_ALIGNMENT 0
|
||||||
|
#else
|
||||||
|
#define ARDUINOJSON_ENABLE_ALIGNMENT 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef ARDUINOJSON_TAB
|
#ifndef ARDUINOJSON_TAB
|
||||||
#define ARDUINOJSON_TAB " "
|
#define ARDUINOJSON_TAB " "
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
|
||||||
|
#define ARDUINOJSON_ENABLE_STRING_DEDUPLICATION 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef ARDUINOJSON_STRING_BUFFER_SIZE
|
#ifndef ARDUINOJSON_STRING_BUFFER_SIZE
|
||||||
#define ARDUINOJSON_STRING_BUFFER_SIZE 32
|
#define ARDUINOJSON_STRING_BUFFER_SIZE 32
|
||||||
#endif
|
#endif
|
||||||
@@ -37,6 +37,7 @@ struct BoundedReader {
|
|||||||
|
|
||||||
#include <ArduinoJson/Deserialization/Readers/IteratorReader.hpp>
|
#include <ArduinoJson/Deserialization/Readers/IteratorReader.hpp>
|
||||||
#include <ArduinoJson/Deserialization/Readers/RamReader.hpp>
|
#include <ArduinoJson/Deserialization/Readers/RamReader.hpp>
|
||||||
|
#include <ArduinoJson/Deserialization/Readers/VariantReader.hpp>
|
||||||
|
|
||||||
#if ARDUINOJSON_ENABLE_ARDUINO_STREAM
|
#if ARDUINOJSON_ENABLE_ARDUINO_STREAM
|
||||||
#include <ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp>
|
#include <ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp>
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
// ArduinoJson - arduinojson.org
|
||||||
|
// Copyright Benoit Blanchon 2014-2020
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Object/MemberProxy.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantRef.hpp>
|
||||||
|
|
||||||
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
|
template <typename TArray>
|
||||||
|
struct Reader<ElementProxy<TArray>, void> : Reader<char*, void> {
|
||||||
|
explicit Reader(const ElementProxy<TArray>& x)
|
||||||
|
: Reader<char*, void>(x.template as<const char*>()) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TObject, typename TStringRef>
|
||||||
|
struct Reader<MemberProxy<TObject, TStringRef>, void> : Reader<char*, void> {
|
||||||
|
explicit Reader(const MemberProxy<TObject, TStringRef>& x)
|
||||||
|
: Reader<char*, void>(x.template as<const char*>()) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct Reader<VariantRef, void> : Reader<char*, void> {
|
||||||
|
explicit Reader(VariantRef x) : Reader<char*, void>(x.as<const char*>()) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct Reader<VariantConstRef, void> : Reader<char*, void> {
|
||||||
|
explicit Reader(VariantConstRef x)
|
||||||
|
: Reader<char*, void>(x.as<const char*>()) {}
|
||||||
|
};
|
||||||
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
@@ -32,9 +32,8 @@ deserialize(JsonDocument &doc, const TString &input, NestingLimit nestingLimit,
|
|||||||
TFilter filter) {
|
TFilter filter) {
|
||||||
Reader<TString> reader(input);
|
Reader<TString> reader(input);
|
||||||
doc.clear();
|
doc.clear();
|
||||||
return makeDeserializer<TDeserializer>(
|
return makeDeserializer<TDeserializer>(doc.memoryPool(), reader,
|
||||||
doc.memoryPool(), reader,
|
makeStringStorage(input))
|
||||||
makeStringStorage(doc.memoryPool(), input))
|
|
||||||
.parse(doc.data(), filter, nestingLimit);
|
.parse(doc.data(), filter, nestingLimit);
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
@@ -48,9 +47,8 @@ DeserializationError deserialize(JsonDocument &doc, TChar *input,
|
|||||||
TFilter filter) {
|
TFilter filter) {
|
||||||
BoundedReader<TChar *> reader(input, inputSize);
|
BoundedReader<TChar *> reader(input, inputSize);
|
||||||
doc.clear();
|
doc.clear();
|
||||||
return makeDeserializer<TDeserializer>(
|
return makeDeserializer<TDeserializer>(doc.memoryPool(), reader,
|
||||||
doc.memoryPool(), reader,
|
makeStringStorage(input))
|
||||||
makeStringStorage(doc.memoryPool(), input))
|
|
||||||
.parse(doc.data(), filter, nestingLimit);
|
.parse(doc.data(), filter, nestingLimit);
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
@@ -62,9 +60,8 @@ DeserializationError deserialize(JsonDocument &doc, TStream &input,
|
|||||||
NestingLimit nestingLimit, TFilter filter) {
|
NestingLimit nestingLimit, TFilter filter) {
|
||||||
Reader<TStream> reader(input);
|
Reader<TStream> reader(input);
|
||||||
doc.clear();
|
doc.clear();
|
||||||
return makeDeserializer<TDeserializer>(
|
return makeDeserializer<TDeserializer>(doc.memoryPool(), reader,
|
||||||
doc.memoryPool(), reader,
|
makeStringStorage(input))
|
||||||
makeStringStorage(doc.memoryPool(), input))
|
|
||||||
.parse(doc.data(), filter, nestingLimit);
|
.parse(doc.data(), filter, nestingLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,34 +19,25 @@ namespace ARDUINOJSON_NAMESPACE {
|
|||||||
|
|
||||||
template <typename TReader, typename TStringStorage>
|
template <typename TReader, typename TStringStorage>
|
||||||
class JsonDeserializer {
|
class JsonDeserializer {
|
||||||
typedef typename remove_reference<TStringStorage>::type::StringBuilder
|
|
||||||
StringBuilder;
|
|
||||||
|
|
||||||
struct StringOrError {
|
|
||||||
DeserializationError err;
|
|
||||||
const char *value;
|
|
||||||
|
|
||||||
StringOrError(DeserializationError e) : err(e) {}
|
|
||||||
StringOrError(DeserializationError::Code c) : err(c) {}
|
|
||||||
StringOrError(const char *s) : err(DeserializationError::Ok), value(s) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
JsonDeserializer(MemoryPool &pool, TReader reader,
|
JsonDeserializer(MemoryPool &pool, TReader reader,
|
||||||
TStringStorage stringStorage)
|
TStringStorage stringStorage)
|
||||||
: _pool(&pool), _stringStorage(stringStorage), _latch(reader) {}
|
: _stringStorage(stringStorage),
|
||||||
|
_latch(reader),
|
||||||
|
_pool(&pool),
|
||||||
|
_error(DeserializationError::Ok) {}
|
||||||
|
|
||||||
template <typename TFilter>
|
template <typename TFilter>
|
||||||
DeserializationError parse(VariantData &variant, TFilter filter,
|
DeserializationError parse(VariantData &variant, TFilter filter,
|
||||||
NestingLimit nestingLimit) {
|
NestingLimit nestingLimit) {
|
||||||
DeserializationError err = parseVariant(variant, filter, nestingLimit);
|
parseVariant(variant, filter, nestingLimit);
|
||||||
|
|
||||||
if (!err && _latch.last() != 0 && !variant.isEnclosed()) {
|
if (!_error && _latch.last() != 0 && !variant.isEnclosed()) {
|
||||||
// We don't detect trailing characters earlier, so we need to check now
|
// We don't detect trailing characters earlier, so we need to check now
|
||||||
err = DeserializationError::InvalidInput;
|
_error = DeserializationError::InvalidInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return _error;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -68,11 +59,10 @@ class JsonDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename TFilter>
|
template <typename TFilter>
|
||||||
DeserializationError parseVariant(VariantData &variant, TFilter filter,
|
bool parseVariant(VariantData &variant, TFilter filter,
|
||||||
NestingLimit nestingLimit) {
|
NestingLimit nestingLimit) {
|
||||||
DeserializationError err = skipSpacesAndComments();
|
if (!skipSpacesAndComments())
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
|
|
||||||
switch (current()) {
|
switch (current()) {
|
||||||
case '[':
|
case '[':
|
||||||
@@ -102,10 +92,9 @@ class JsonDeserializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError skipVariant(NestingLimit nestingLimit) {
|
bool skipVariant(NestingLimit nestingLimit) {
|
||||||
DeserializationError err = skipSpacesAndComments();
|
if (!skipSpacesAndComments())
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
|
|
||||||
switch (current()) {
|
switch (current()) {
|
||||||
case '[':
|
case '[':
|
||||||
@@ -124,23 +113,24 @@ class JsonDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename TFilter>
|
template <typename TFilter>
|
||||||
DeserializationError parseArray(CollectionData &array, TFilter filter,
|
bool parseArray(CollectionData &array, TFilter filter,
|
||||||
NestingLimit nestingLimit) {
|
NestingLimit nestingLimit) {
|
||||||
if (nestingLimit.reached())
|
if (nestingLimit.reached()) {
|
||||||
return DeserializationError::TooDeep;
|
_error = DeserializationError::TooDeep;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Skip opening braket
|
// Skip opening braket
|
||||||
ARDUINOJSON_ASSERT(current() == '[');
|
ARDUINOJSON_ASSERT(current() == '[');
|
||||||
move();
|
move();
|
||||||
|
|
||||||
// Skip spaces
|
// Skip spaces
|
||||||
DeserializationError err = skipSpacesAndComments();
|
if (!skipSpacesAndComments())
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
|
|
||||||
// Empty array?
|
// Empty array?
|
||||||
if (eat(']'))
|
if (eat(']'))
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
|
|
||||||
TFilter memberFilter = filter[0UL];
|
TFilter memberFilter = filter[0UL];
|
||||||
|
|
||||||
@@ -149,35 +139,38 @@ class JsonDeserializer {
|
|||||||
if (memberFilter.allow()) {
|
if (memberFilter.allow()) {
|
||||||
// Allocate slot in array
|
// Allocate slot in array
|
||||||
VariantData *value = array.addElement(_pool);
|
VariantData *value = array.addElement(_pool);
|
||||||
if (!value)
|
if (!value) {
|
||||||
return DeserializationError::NoMemory;
|
_error = DeserializationError::NoMemory;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// 1 - Parse value
|
// 1 - Parse value
|
||||||
err = parseVariant(*value, memberFilter, nestingLimit.decrement());
|
if (!parseVariant(*value, memberFilter, nestingLimit.decrement()))
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
} else {
|
} else {
|
||||||
err = skipVariant(nestingLimit.decrement());
|
if (!skipVariant(nestingLimit.decrement()))
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2 - Skip spaces
|
// 2 - Skip spaces
|
||||||
err = skipSpacesAndComments();
|
if (!skipSpacesAndComments())
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
|
|
||||||
// 3 - More values?
|
// 3 - More values?
|
||||||
if (eat(']'))
|
if (eat(']'))
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
if (!eat(','))
|
if (!eat(',')) {
|
||||||
return DeserializationError::InvalidInput;
|
_error = DeserializationError::InvalidInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError skipArray(NestingLimit nestingLimit) {
|
bool skipArray(NestingLimit nestingLimit) {
|
||||||
if (nestingLimit.reached())
|
if (nestingLimit.reached()) {
|
||||||
return DeserializationError::TooDeep;
|
_error = DeserializationError::TooDeep;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Skip opening braket
|
// Skip opening braket
|
||||||
ARDUINOJSON_ASSERT(current() == '[');
|
ARDUINOJSON_ASSERT(current() == '[');
|
||||||
@@ -186,153 +179,162 @@ class JsonDeserializer {
|
|||||||
// Read each value
|
// Read each value
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// 1 - Skip value
|
// 1 - Skip value
|
||||||
DeserializationError err = skipVariant(nestingLimit.decrement());
|
if (!skipVariant(nestingLimit.decrement()))
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
|
|
||||||
// 2 - Skip spaces
|
// 2 - Skip spaces
|
||||||
err = skipSpacesAndComments();
|
if (!skipSpacesAndComments())
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
|
|
||||||
// 3 - More values?
|
// 3 - More values?
|
||||||
if (eat(']'))
|
if (eat(']'))
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
if (!eat(','))
|
if (!eat(',')) {
|
||||||
return DeserializationError::InvalidInput;
|
_error = DeserializationError::InvalidInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TFilter>
|
template <typename TFilter>
|
||||||
DeserializationError parseObject(CollectionData &object, TFilter filter,
|
bool parseObject(CollectionData &object, TFilter filter,
|
||||||
NestingLimit nestingLimit) {
|
NestingLimit nestingLimit) {
|
||||||
if (nestingLimit.reached())
|
if (nestingLimit.reached()) {
|
||||||
return DeserializationError::TooDeep;
|
_error = DeserializationError::TooDeep;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Skip opening brace
|
// Skip opening brace
|
||||||
ARDUINOJSON_ASSERT(current() == '{');
|
ARDUINOJSON_ASSERT(current() == '{');
|
||||||
move();
|
move();
|
||||||
|
|
||||||
// Skip spaces
|
// Skip spaces
|
||||||
DeserializationError err = skipSpacesAndComments();
|
if (!skipSpacesAndComments())
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
|
|
||||||
// Empty object?
|
// Empty object?
|
||||||
if (eat('}'))
|
if (eat('}'))
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
|
|
||||||
// Read each key value pair
|
// Read each key value pair
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// Parse key
|
// Parse key
|
||||||
StringOrError key = parseKey();
|
if (!parseKey())
|
||||||
err = key.err; // <- this trick saves 62 bytes on AVR
|
return false;
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
// Skip spaces
|
// Skip spaces
|
||||||
err = skipSpacesAndComments();
|
if (!skipSpacesAndComments())
|
||||||
if (err)
|
return false;
|
||||||
return err; // Colon
|
|
||||||
if (!eat(':'))
|
|
||||||
return DeserializationError::InvalidInput;
|
|
||||||
|
|
||||||
TFilter memberFilter = filter[key.value];
|
// Colon
|
||||||
|
if (!eat(':')) {
|
||||||
|
_error = DeserializationError::InvalidInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *key = _stringStorage.c_str();
|
||||||
|
|
||||||
|
TFilter memberFilter = filter[key];
|
||||||
|
|
||||||
if (memberFilter.allow()) {
|
if (memberFilter.allow()) {
|
||||||
VariantData *variant = object.getMember(adaptString(key.value));
|
VariantData *variant = object.getMember(adaptString(key));
|
||||||
if (!variant) {
|
if (!variant) {
|
||||||
|
// Save key in memory pool.
|
||||||
|
// This MUST be done before adding the slot.
|
||||||
|
key = _stringStorage.save(_pool);
|
||||||
|
|
||||||
// Allocate slot in object
|
// Allocate slot in object
|
||||||
VariantSlot *slot = object.addSlot(_pool);
|
VariantSlot *slot = object.addSlot(_pool);
|
||||||
if (!slot)
|
if (!slot) {
|
||||||
return DeserializationError::NoMemory;
|
_error = DeserializationError::NoMemory;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
slot->setOwnedKey(make_not_null(key.value));
|
slot->setKey(key, typename TStringStorage::storage_policy());
|
||||||
|
|
||||||
variant = slot->data();
|
variant = slot->data();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse value
|
// Parse value
|
||||||
err = parseVariant(*variant, memberFilter, nestingLimit.decrement());
|
if (!parseVariant(*variant, memberFilter, nestingLimit.decrement()))
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
} else {
|
} else {
|
||||||
_stringStorage.reclaim(key.value);
|
if (!skipVariant(nestingLimit.decrement()))
|
||||||
err = skipVariant(nestingLimit.decrement());
|
return false;
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip spaces
|
// Skip spaces
|
||||||
err = skipSpacesAndComments();
|
if (!skipSpacesAndComments())
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
|
|
||||||
// More keys/values?
|
// More keys/values?
|
||||||
if (eat('}'))
|
if (eat('}'))
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
if (!eat(','))
|
if (!eat(',')) {
|
||||||
return DeserializationError::InvalidInput;
|
_error = DeserializationError::InvalidInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Skip spaces
|
// Skip spaces
|
||||||
err = skipSpacesAndComments();
|
if (!skipSpacesAndComments())
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError skipObject(NestingLimit nestingLimit) {
|
bool skipObject(NestingLimit nestingLimit) {
|
||||||
if (nestingLimit.reached())
|
if (nestingLimit.reached()) {
|
||||||
return DeserializationError::TooDeep;
|
_error = DeserializationError::TooDeep;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Skip opening brace
|
// Skip opening brace
|
||||||
ARDUINOJSON_ASSERT(current() == '{');
|
ARDUINOJSON_ASSERT(current() == '{');
|
||||||
move();
|
move();
|
||||||
|
|
||||||
// Skip spaces
|
// Skip spaces
|
||||||
DeserializationError err = skipSpacesAndComments();
|
if (!skipSpacesAndComments())
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
|
|
||||||
// Empty object?
|
// Empty object?
|
||||||
if (eat('}'))
|
if (eat('}'))
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
|
|
||||||
// Read each key value pair
|
// Read each key value pair
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// Skip key
|
// Skip key
|
||||||
err = skipVariant(nestingLimit.decrement());
|
if (!skipVariant(nestingLimit.decrement()))
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
|
|
||||||
// Skip spaces
|
// Skip spaces
|
||||||
err = skipSpacesAndComments();
|
if (!skipSpacesAndComments())
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
|
|
||||||
// Colon
|
// Colon
|
||||||
if (!eat(':'))
|
if (!eat(':')) {
|
||||||
return DeserializationError::InvalidInput;
|
_error = DeserializationError::InvalidInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Skip value
|
// Skip value
|
||||||
err = skipVariant(nestingLimit.decrement());
|
if (!skipVariant(nestingLimit.decrement()))
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
|
|
||||||
// Skip spaces
|
// Skip spaces
|
||||||
err = skipSpacesAndComments();
|
if (!skipSpacesAndComments())
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
|
|
||||||
// More keys/values?
|
// More keys/values?
|
||||||
if (eat('}'))
|
if (eat('}'))
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
if (!eat(','))
|
if (!eat(',')) {
|
||||||
return DeserializationError::InvalidInput;
|
_error = DeserializationError::InvalidInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StringOrError parseKey() {
|
bool parseKey() {
|
||||||
|
_stringStorage.startString(_pool);
|
||||||
if (isQuote(current())) {
|
if (isQuote(current())) {
|
||||||
return parseQuotedString();
|
return parseQuotedString();
|
||||||
} else {
|
} else {
|
||||||
@@ -340,16 +342,17 @@ class JsonDeserializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError parseStringValue(VariantData &variant) {
|
bool parseStringValue(VariantData &variant) {
|
||||||
StringOrError result = parseQuotedString();
|
_stringStorage.startString(_pool);
|
||||||
if (result.err)
|
if (!parseQuotedString())
|
||||||
return result.err;
|
return false;
|
||||||
variant.setOwnedString(make_not_null(result.value));
|
const char *value = _stringStorage.save(_pool);
|
||||||
return DeserializationError::Ok;
|
variant.setString(make_not_null(value),
|
||||||
|
typename TStringStorage::storage_policy());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringOrError parseQuotedString() {
|
bool parseQuotedString() {
|
||||||
StringBuilder builder = _stringStorage.startString();
|
|
||||||
#if ARDUINOJSON_DECODE_UNICODE
|
#if ARDUINOJSON_DECODE_UNICODE
|
||||||
Utf16::Codepoint codepoint;
|
Utf16::Codepoint codepoint;
|
||||||
#endif
|
#endif
|
||||||
@@ -362,66 +365,82 @@ class JsonDeserializer {
|
|||||||
if (c == stopChar)
|
if (c == stopChar)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (c == '\0')
|
if (c == '\0') {
|
||||||
return DeserializationError::IncompleteInput;
|
_error = DeserializationError::IncompleteInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (c == '\\') {
|
if (c == '\\') {
|
||||||
c = current();
|
c = current();
|
||||||
if (c == '\0')
|
|
||||||
return DeserializationError::IncompleteInput;
|
if (c == '\0') {
|
||||||
|
_error = DeserializationError::IncompleteInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (c == 'u') {
|
if (c == 'u') {
|
||||||
#if ARDUINOJSON_DECODE_UNICODE
|
#if ARDUINOJSON_DECODE_UNICODE
|
||||||
move();
|
move();
|
||||||
uint16_t codeunit;
|
uint16_t codeunit;
|
||||||
DeserializationError err = parseHex4(codeunit);
|
if (!parseHex4(codeunit))
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
if (codepoint.append(codeunit))
|
if (codepoint.append(codeunit))
|
||||||
Utf8::encodeCodepoint(codepoint.value(), builder);
|
Utf8::encodeCodepoint(codepoint.value(), _stringStorage);
|
||||||
continue;
|
continue;
|
||||||
#else
|
#else
|
||||||
return DeserializationError::NotSupported;
|
_error = DeserializationError::NotSupported;
|
||||||
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace char
|
// replace char
|
||||||
c = EscapeSequence::unescapeChar(c);
|
c = EscapeSequence::unescapeChar(c);
|
||||||
if (c == '\0')
|
if (c == '\0') {
|
||||||
return DeserializationError::InvalidInput;
|
_error = DeserializationError::InvalidInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
move();
|
move();
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.append(c);
|
_stringStorage.append(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *result = builder.complete();
|
_stringStorage.append('\0');
|
||||||
if (!result)
|
|
||||||
return DeserializationError::NoMemory;
|
if (!_stringStorage.isValid()) {
|
||||||
return result;
|
_error = DeserializationError::NoMemory;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringOrError parseNonQuotedString() {
|
return true;
|
||||||
StringBuilder builder = _stringStorage.startString();
|
}
|
||||||
|
|
||||||
|
bool parseNonQuotedString() {
|
||||||
char c = current();
|
char c = current();
|
||||||
ARDUINOJSON_ASSERT(c);
|
ARDUINOJSON_ASSERT(c);
|
||||||
|
|
||||||
if (canBeInNonQuotedString(c)) { // no quotes
|
if (canBeInNonQuotedString(c)) { // no quotes
|
||||||
do {
|
do {
|
||||||
move();
|
move();
|
||||||
builder.append(c);
|
_stringStorage.append(c);
|
||||||
c = current();
|
c = current();
|
||||||
} while (canBeInNonQuotedString(c));
|
} while (canBeInNonQuotedString(c));
|
||||||
} else {
|
} else {
|
||||||
return DeserializationError::InvalidInput;
|
_error = DeserializationError::InvalidInput;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *result = builder.complete();
|
_stringStorage.append('\0');
|
||||||
if (!result)
|
|
||||||
return DeserializationError::NoMemory;
|
if (!_stringStorage.isValid()) {
|
||||||
return result;
|
_error = DeserializationError::NoMemory;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError skipString() {
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool skipString() {
|
||||||
const char stopChar = current();
|
const char stopChar = current();
|
||||||
|
|
||||||
move();
|
move();
|
||||||
@@ -430,87 +449,104 @@ class JsonDeserializer {
|
|||||||
move();
|
move();
|
||||||
if (c == stopChar)
|
if (c == stopChar)
|
||||||
break;
|
break;
|
||||||
if (c == '\0')
|
if (c == '\0') {
|
||||||
return DeserializationError::IncompleteInput;
|
_error = DeserializationError::IncompleteInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (c == '\\') {
|
if (c == '\\') {
|
||||||
if (current() != '\0')
|
if (current() != '\0')
|
||||||
move();
|
move();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError parseNumericValue(VariantData &result) {
|
bool parseNumericValue(VariantData &result) {
|
||||||
char buffer[64];
|
|
||||||
uint8_t n = 0;
|
uint8_t n = 0;
|
||||||
|
|
||||||
char c = current();
|
char c = current();
|
||||||
while (canBeInNonQuotedString(c) && n < 63) {
|
while (canBeInNonQuotedString(c) && n < 63) {
|
||||||
move();
|
move();
|
||||||
buffer[n++] = c;
|
_buffer[n++] = c;
|
||||||
c = current();
|
c = current();
|
||||||
}
|
}
|
||||||
buffer[n] = 0;
|
_buffer[n] = 0;
|
||||||
|
|
||||||
c = buffer[0];
|
c = _buffer[0];
|
||||||
if (c == 't') { // true
|
if (c == 't') { // true
|
||||||
result.setBoolean(true);
|
result.setBoolean(true);
|
||||||
return n == 4 ? DeserializationError::Ok
|
if (n != 4) {
|
||||||
: DeserializationError::IncompleteInput;
|
_error = DeserializationError::IncompleteInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
if (c == 'f') { // false
|
if (c == 'f') { // false
|
||||||
result.setBoolean(false);
|
result.setBoolean(false);
|
||||||
return n == 5 ? DeserializationError::Ok
|
if (n != 5) {
|
||||||
: DeserializationError::IncompleteInput;
|
_error = DeserializationError::IncompleteInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
if (c == 'n') { // null
|
if (c == 'n') { // null
|
||||||
// the variant is already null
|
// the variant is already null
|
||||||
return n == 4 ? DeserializationError::Ok
|
if (n != 4) {
|
||||||
: DeserializationError::IncompleteInput;
|
_error = DeserializationError::IncompleteInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParsedNumber<Float, UInt> num = parseNumber<Float, UInt>(buffer);
|
ParsedNumber<Float, UInt> num;
|
||||||
|
parseNumber<Float, UInt>(_buffer, num);
|
||||||
|
|
||||||
switch (num.type()) {
|
switch (num.type()) {
|
||||||
case VALUE_IS_NEGATIVE_INTEGER:
|
case VALUE_IS_NEGATIVE_INTEGER:
|
||||||
result.setNegativeInteger(num.uintValue);
|
result.setNegativeInteger(num.uintValue);
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
|
|
||||||
case VALUE_IS_POSITIVE_INTEGER:
|
case VALUE_IS_POSITIVE_INTEGER:
|
||||||
result.setPositiveInteger(num.uintValue);
|
result.setPositiveInteger(num.uintValue);
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
|
|
||||||
case VALUE_IS_FLOAT:
|
case VALUE_IS_FLOAT:
|
||||||
result.setFloat(num.floatValue);
|
result.setFloat(num.floatValue);
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
_error = DeserializationError::InvalidInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return DeserializationError::InvalidInput;
|
bool skipNumericValue() {
|
||||||
}
|
|
||||||
|
|
||||||
DeserializationError skipNumericValue() {
|
|
||||||
char c = current();
|
char c = current();
|
||||||
while (canBeInNonQuotedString(c)) {
|
while (canBeInNonQuotedString(c)) {
|
||||||
move();
|
move();
|
||||||
c = current();
|
c = current();
|
||||||
}
|
}
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError parseHex4(uint16_t &result) {
|
bool parseHex4(uint16_t &result) {
|
||||||
result = 0;
|
result = 0;
|
||||||
for (uint8_t i = 0; i < 4; ++i) {
|
for (uint8_t i = 0; i < 4; ++i) {
|
||||||
char digit = current();
|
char digit = current();
|
||||||
if (!digit)
|
if (!digit) {
|
||||||
return DeserializationError::IncompleteInput;
|
_error = DeserializationError::IncompleteInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
uint8_t value = decodeHex(digit);
|
uint8_t value = decodeHex(digit);
|
||||||
if (value > 0x0F)
|
if (value > 0x0F) {
|
||||||
return DeserializationError::InvalidInput;
|
_error = DeserializationError::InvalidInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
result = uint16_t((result << 4) | value);
|
result = uint16_t((result << 4) | value);
|
||||||
move();
|
move();
|
||||||
}
|
}
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool isBetween(char c, char min, char max) {
|
static inline bool isBetween(char c, char min, char max) {
|
||||||
@@ -533,12 +569,13 @@ class JsonDeserializer {
|
|||||||
return uint8_t(c - 'A' + 10);
|
return uint8_t(c - 'A' + 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError skipSpacesAndComments() {
|
bool skipSpacesAndComments() {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
switch (current()) {
|
switch (current()) {
|
||||||
// end of string
|
// end of string
|
||||||
case '\0':
|
case '\0':
|
||||||
return DeserializationError::IncompleteInput;
|
_error = DeserializationError::IncompleteInput;
|
||||||
|
return false;
|
||||||
|
|
||||||
// spaces
|
// spaces
|
||||||
case ' ':
|
case ' ':
|
||||||
@@ -559,8 +596,10 @@ class JsonDeserializer {
|
|||||||
bool wasStar = false;
|
bool wasStar = false;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char c = current();
|
char c = current();
|
||||||
if (c == '\0')
|
if (c == '\0') {
|
||||||
return DeserializationError::IncompleteInput;
|
_error = DeserializationError::IncompleteInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (c == '/' && wasStar) {
|
if (c == '/' && wasStar) {
|
||||||
move();
|
move();
|
||||||
break;
|
break;
|
||||||
@@ -577,8 +616,10 @@ class JsonDeserializer {
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
move();
|
move();
|
||||||
char c = current();
|
char c = current();
|
||||||
if (c == '\0')
|
if (c == '\0') {
|
||||||
return DeserializationError::IncompleteInput;
|
_error = DeserializationError::IncompleteInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (c == '\n')
|
if (c == '\n')
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -586,20 +627,25 @@ class JsonDeserializer {
|
|||||||
|
|
||||||
// not a comment, just a '/'
|
// not a comment, just a '/'
|
||||||
default:
|
default:
|
||||||
return DeserializationError::InvalidInput;
|
_error = DeserializationError::InvalidInput;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryPool *_pool;
|
|
||||||
TStringStorage _stringStorage;
|
TStringStorage _stringStorage;
|
||||||
Latch<TReader> _latch;
|
Latch<TReader> _latch;
|
||||||
|
MemoryPool *_pool;
|
||||||
|
char _buffer[64]; // using a member instead of a local variable because it
|
||||||
|
// ended in the recursive path after compiler inlined the
|
||||||
|
// code
|
||||||
|
DeserializationError _error;
|
||||||
};
|
};
|
||||||
|
|
||||||
// deserializeJson(JsonDocument&, const std::string&, ...)
|
// deserializeJson(JsonDocument&, const std::string&, ...)
|
||||||
@@ -31,6 +31,8 @@ inline bool isLowSurrogate(uint16_t codeunit) {
|
|||||||
|
|
||||||
class Codepoint {
|
class Codepoint {
|
||||||
public:
|
public:
|
||||||
|
Codepoint() : _highSurrogate(0) {}
|
||||||
|
|
||||||
bool append(uint16_t codeunit) {
|
bool append(uint16_t codeunit) {
|
||||||
if (isHighSurrogate(codeunit)) {
|
if (isHighSurrogate(codeunit)) {
|
||||||
_highSurrogate = codeunit & 0x3FF;
|
_highSurrogate = codeunit & 0x3FF;
|
||||||
@@ -10,9 +10,11 @@
|
|||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
inline bool isAligned(void *ptr) {
|
#if ARDUINOJSON_ENABLE_ALIGNMENT
|
||||||
|
|
||||||
|
inline bool isAligned(size_t value) {
|
||||||
const size_t mask = sizeof(void *) - 1;
|
const size_t mask = sizeof(void *) - 1;
|
||||||
size_t addr = reinterpret_cast<size_t>(ptr);
|
size_t addr = value;
|
||||||
return (addr & mask) == 0;
|
return (addr & mask) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,16 +23,38 @@ inline size_t addPadding(size_t bytes) {
|
|||||||
return (bytes + mask) & ~mask;
|
return (bytes + mask) & ~mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline T *addPadding(T *p) {
|
|
||||||
size_t address = addPadding(reinterpret_cast<size_t>(p));
|
|
||||||
return reinterpret_cast<T *>(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <size_t bytes>
|
template <size_t bytes>
|
||||||
struct AddPadding {
|
struct AddPadding {
|
||||||
static const size_t mask = sizeof(void *) - 1;
|
static const size_t mask = sizeof(void *) - 1;
|
||||||
static const size_t value = (bytes + mask) & ~mask;
|
static const size_t value = (bytes + mask) & ~mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
inline bool isAligned(size_t) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t addPadding(size_t bytes) {
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t bytes>
|
||||||
|
struct AddPadding {
|
||||||
|
static const size_t value = bytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline bool isAligned(T *ptr) {
|
||||||
|
return isAligned(reinterpret_cast<size_t>(ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T *addPadding(T *p) {
|
||||||
|
size_t address = addPadding(reinterpret_cast<size_t>(p));
|
||||||
|
return reinterpret_cast<T *>(address);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
@@ -51,32 +51,43 @@ class MemoryPool {
|
|||||||
return allocRight<VariantSlot>();
|
return allocRight<VariantSlot>();
|
||||||
}
|
}
|
||||||
|
|
||||||
char* allocFrozenString(size_t n) {
|
template <typename TAdaptedString>
|
||||||
if (!canAlloc(n))
|
const char* saveString(const TAdaptedString& str) {
|
||||||
|
if (str.isNull())
|
||||||
return 0;
|
return 0;
|
||||||
char* s = _left;
|
|
||||||
_left += n;
|
#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
|
||||||
checkInvariants();
|
const char* existingCopy = findString(str.begin());
|
||||||
return s;
|
if (existingCopy)
|
||||||
|
return existingCopy;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t n = str.size();
|
||||||
|
|
||||||
|
char* newCopy = allocString(n + 1);
|
||||||
|
if (newCopy) {
|
||||||
|
str.copyTo(newCopy, n);
|
||||||
|
newCopy[n] = 0; // force null-terminator
|
||||||
|
}
|
||||||
|
return newCopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringSlot allocExpandableString() {
|
void getFreeZone(char** zoneStart, size_t* zoneSize) const {
|
||||||
StringSlot s;
|
*zoneStart = _left;
|
||||||
s.value = _left;
|
*zoneSize = size_t(_right - _left);
|
||||||
s.size = size_t(_right - _left);
|
|
||||||
_left = _right;
|
|
||||||
checkInvariants();
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void freezeString(StringSlot& s, size_t newSize) {
|
const char* saveStringFromFreeZone(size_t len) {
|
||||||
_left -= (s.size - newSize);
|
#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
|
||||||
s.size = newSize;
|
const char* dup = findString(_left);
|
||||||
checkInvariants();
|
if (dup)
|
||||||
}
|
return dup;
|
||||||
|
#endif
|
||||||
|
|
||||||
void reclaimLastString(const char* s) {
|
const char* str = _left;
|
||||||
_left = const_cast<char*>(s);
|
_left += len;
|
||||||
|
checkInvariants();
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
@@ -92,18 +103,6 @@ class MemoryPool {
|
|||||||
return _begin <= p && p < _end;
|
return _begin <= p && p < _end;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T* allocRight() {
|
|
||||||
return reinterpret_cast<T*>(allocRight(sizeof(T)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void* allocRight(size_t bytes) {
|
|
||||||
if (!canAlloc(bytes))
|
|
||||||
return 0;
|
|
||||||
_right -= bytes;
|
|
||||||
return _right;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Workaround for missing placement new
|
// Workaround for missing placement new
|
||||||
void* operator new(size_t, void* p) {
|
void* operator new(size_t, void* p) {
|
||||||
return p;
|
return p;
|
||||||
@@ -155,6 +154,46 @@ class MemoryPool {
|
|||||||
ARDUINOJSON_ASSERT(isAligned(_right));
|
ARDUINOJSON_ASSERT(isAligned(_right));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
|
||||||
|
template <typename TIterator>
|
||||||
|
const char* findString(TIterator str) {
|
||||||
|
for (char* next = _begin; next < _left; ++next) {
|
||||||
|
char* begin = next;
|
||||||
|
|
||||||
|
// try to match
|
||||||
|
for (TIterator it = str; *it == *next; ++it) {
|
||||||
|
if (*next++ == 0)
|
||||||
|
return begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
// jump to next terminator
|
||||||
|
while (*next) ++next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char* allocString(size_t n) {
|
||||||
|
if (!canAlloc(n))
|
||||||
|
return 0;
|
||||||
|
char* s = _left;
|
||||||
|
_left += n;
|
||||||
|
checkInvariants();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T* allocRight() {
|
||||||
|
return reinterpret_cast<T*>(allocRight(sizeof(T)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void* allocRight(size_t bytes) {
|
||||||
|
if (!canAlloc(bytes))
|
||||||
|
return 0;
|
||||||
|
_right -= bytes;
|
||||||
|
return _right;
|
||||||
|
}
|
||||||
|
|
||||||
char *_begin, *_left, *_right, *_end;
|
char *_begin, *_left, *_right, *_end;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#include <ArduinoJson/Namespace.hpp>
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
#define JSON_STRING_SIZE(SIZE) (SIZE)
|
#define JSON_STRING_SIZE(SIZE) (SIZE + 1)
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
@@ -15,32 +15,37 @@ namespace ARDUINOJSON_NAMESPACE {
|
|||||||
|
|
||||||
template <typename TReader, typename TStringStorage>
|
template <typename TReader, typename TStringStorage>
|
||||||
class MsgPackDeserializer {
|
class MsgPackDeserializer {
|
||||||
typedef typename remove_reference<TStringStorage>::type::StringBuilder
|
|
||||||
StringBuilder;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MsgPackDeserializer(MemoryPool &pool, TReader reader,
|
MsgPackDeserializer(MemoryPool &pool, TReader reader,
|
||||||
TStringStorage stringStorage)
|
TStringStorage stringStorage)
|
||||||
: _pool(&pool), _reader(reader), _stringStorage(stringStorage) {}
|
: _pool(&pool),
|
||||||
|
_reader(reader),
|
||||||
|
_stringStorage(stringStorage),
|
||||||
|
_error(DeserializationError::Ok) {}
|
||||||
|
|
||||||
|
// TODO: add support for filter
|
||||||
DeserializationError parse(VariantData &variant, AllowAllFilter,
|
DeserializationError parse(VariantData &variant, AllowAllFilter,
|
||||||
NestingLimit nestingLimit) {
|
NestingLimit nestingLimit) {
|
||||||
return parse(variant, nestingLimit);
|
parseVariant(variant, nestingLimit);
|
||||||
|
return _error;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError parse(VariantData &variant, NestingLimit nestingLimit) {
|
private:
|
||||||
|
bool parseVariant(VariantData &variant, NestingLimit nestingLimit) {
|
||||||
uint8_t code;
|
uint8_t code;
|
||||||
if (!readByte(code))
|
if (!readByte(code)) {
|
||||||
return DeserializationError::IncompleteInput;
|
_error = DeserializationError::IncompleteInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if ((code & 0x80) == 0) {
|
if ((code & 0x80) == 0) {
|
||||||
variant.setUnsignedInteger(code);
|
variant.setUnsignedInteger(code);
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((code & 0xe0) == 0xe0) {
|
if ((code & 0xe0) == 0xe0) {
|
||||||
variant.setSignedInteger(static_cast<int8_t>(code));
|
variant.setSignedInteger(static_cast<int8_t>(code));
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((code & 0xe0) == 0xa0) {
|
if ((code & 0xe0) == 0xa0) {
|
||||||
@@ -58,15 +63,15 @@ class MsgPackDeserializer {
|
|||||||
switch (code) {
|
switch (code) {
|
||||||
case 0xc0:
|
case 0xc0:
|
||||||
// already null
|
// already null
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
|
|
||||||
case 0xc2:
|
case 0xc2:
|
||||||
variant.setBoolean(false);
|
variant.setBoolean(false);
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
|
|
||||||
case 0xc3:
|
case 0xc3:
|
||||||
variant.setBoolean(true);
|
variant.setBoolean(true);
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
|
|
||||||
case 0xcc:
|
case 0xcc:
|
||||||
return readInteger<uint8_t>(variant);
|
return readInteger<uint8_t>(variant);
|
||||||
@@ -77,11 +82,9 @@ class MsgPackDeserializer {
|
|||||||
case 0xce:
|
case 0xce:
|
||||||
return readInteger<uint32_t>(variant);
|
return readInteger<uint32_t>(variant);
|
||||||
|
|
||||||
case 0xcf:
|
|
||||||
#if ARDUINOJSON_USE_LONG_LONG
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
|
case 0xcf:
|
||||||
return readInteger<uint64_t>(variant);
|
return readInteger<uint64_t>(variant);
|
||||||
#else
|
|
||||||
return DeserializationError::NotSupported;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case 0xd0:
|
case 0xd0:
|
||||||
@@ -93,11 +96,9 @@ class MsgPackDeserializer {
|
|||||||
case 0xd2:
|
case 0xd2:
|
||||||
return readInteger<int32_t>(variant);
|
return readInteger<int32_t>(variant);
|
||||||
|
|
||||||
case 0xd3:
|
|
||||||
#if ARDUINOJSON_USE_LONG_LONG
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
|
case 0xd3:
|
||||||
return readInteger<int64_t>(variant);
|
return readInteger<int64_t>(variant);
|
||||||
#else
|
|
||||||
return DeserializationError::NotSupported;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case 0xca:
|
case 0xca:
|
||||||
@@ -128,7 +129,8 @@ class MsgPackDeserializer {
|
|||||||
return readObject<uint32_t>(variant.toObject(), nestingLimit);
|
return readObject<uint32_t>(variant.toObject(), nestingLimit);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return DeserializationError::NotSupported;
|
_error = DeserializationError::NotSupported;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,14 +140,19 @@ class MsgPackDeserializer {
|
|||||||
|
|
||||||
bool readByte(uint8_t &value) {
|
bool readByte(uint8_t &value) {
|
||||||
int c = _reader.read();
|
int c = _reader.read();
|
||||||
if (c < 0)
|
if (c < 0) {
|
||||||
|
_error = DeserializationError::IncompleteInput;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
value = static_cast<uint8_t>(c);
|
value = static_cast<uint8_t>(c);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool readBytes(uint8_t *p, size_t n) {
|
bool readBytes(uint8_t *p, size_t n) {
|
||||||
return _reader.readBytes(reinterpret_cast<char *>(p), n) == n;
|
if (_reader.readBytes(reinterpret_cast<char *>(p), n) == n)
|
||||||
|
return true;
|
||||||
|
_error = DeserializationError::IncompleteInput;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -153,14 +160,6 @@ class MsgPackDeserializer {
|
|||||||
return readBytes(reinterpret_cast<uint8_t *>(&value), sizeof(value));
|
return readBytes(reinterpret_cast<uint8_t *>(&value), sizeof(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T readInteger() {
|
|
||||||
T value;
|
|
||||||
readBytes(value);
|
|
||||||
fixEndianess(value);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool readInteger(T &value) {
|
bool readInteger(T &value) {
|
||||||
if (!readBytes(value))
|
if (!readBytes(value))
|
||||||
@@ -170,152 +169,159 @@ class MsgPackDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
DeserializationError readInteger(VariantData &variant) {
|
bool readInteger(VariantData &variant) {
|
||||||
T value;
|
T value;
|
||||||
if (!readInteger(value))
|
if (!readInteger(value))
|
||||||
return DeserializationError::IncompleteInput;
|
return false;
|
||||||
variant.setInteger(value);
|
variant.setInteger(value);
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename enable_if<sizeof(T) == 4, DeserializationError>::type readFloat(
|
typename enable_if<sizeof(T) == 4, bool>::type readFloat(
|
||||||
VariantData &variant) {
|
VariantData &variant) {
|
||||||
T value;
|
T value;
|
||||||
if (!readBytes(value))
|
if (!readBytes(value))
|
||||||
return DeserializationError::IncompleteInput;
|
return false;
|
||||||
fixEndianess(value);
|
fixEndianess(value);
|
||||||
variant.setFloat(value);
|
variant.setFloat(value);
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename enable_if<sizeof(T) == 8, DeserializationError>::type readDouble(
|
typename enable_if<sizeof(T) == 8, bool>::type readDouble(
|
||||||
VariantData &variant) {
|
VariantData &variant) {
|
||||||
T value;
|
T value;
|
||||||
if (!readBytes(value))
|
if (!readBytes(value))
|
||||||
return DeserializationError::IncompleteInput;
|
return false;
|
||||||
fixEndianess(value);
|
fixEndianess(value);
|
||||||
variant.setFloat(value);
|
variant.setFloat(value);
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename enable_if<sizeof(T) == 4, DeserializationError>::type readDouble(
|
typename enable_if<sizeof(T) == 4, bool>::type readDouble(
|
||||||
VariantData &variant) {
|
VariantData &variant) {
|
||||||
uint8_t i[8]; // input is 8 bytes
|
uint8_t i[8]; // input is 8 bytes
|
||||||
T value; // output is 4 bytes
|
T value; // output is 4 bytes
|
||||||
uint8_t *o = reinterpret_cast<uint8_t *>(&value);
|
uint8_t *o = reinterpret_cast<uint8_t *>(&value);
|
||||||
if (!readBytes(i, 8))
|
if (!readBytes(i, 8))
|
||||||
return DeserializationError::IncompleteInput;
|
return false;
|
||||||
doubleToFloat(i, o);
|
doubleToFloat(i, o);
|
||||||
fixEndianess(value);
|
fixEndianess(value);
|
||||||
variant.setFloat(value);
|
variant.setFloat(value);
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
DeserializationError readString(VariantData &variant) {
|
bool readString(VariantData &variant) {
|
||||||
T size;
|
T size;
|
||||||
if (!readInteger(size))
|
if (!readInteger(size))
|
||||||
return DeserializationError::IncompleteInput;
|
return false;
|
||||||
return readString(variant, size);
|
return readString(variant, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
DeserializationError readString(const char *&str) {
|
bool readString(const char *&str) {
|
||||||
T size;
|
T size;
|
||||||
if (!readInteger(size))
|
if (!readInteger(size))
|
||||||
return DeserializationError::IncompleteInput;
|
return false;
|
||||||
return readString(str, size);
|
return readString(str, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError readString(VariantData &variant, size_t n) {
|
bool readString(VariantData &variant, size_t n) {
|
||||||
const char *s = 0; // <- mute "maybe-uninitialized" (+4 bytes on AVR)
|
const char *s = 0; // <- mute "maybe-uninitialized" (+4 bytes on AVR)
|
||||||
DeserializationError err = readString(s, n);
|
if (!readString(s, n))
|
||||||
if (!err)
|
return false;
|
||||||
variant.setOwnedString(make_not_null(s));
|
variant.setString(make_not_null(s),
|
||||||
return err;
|
typename TStringStorage::storage_policy());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError readString(const char *&result, size_t n) {
|
bool readString(const char *&result, size_t n) {
|
||||||
StringBuilder builder = _stringStorage.startString();
|
_stringStorage.startString(_pool);
|
||||||
for (; n; --n) {
|
for (; n; --n) {
|
||||||
uint8_t c;
|
uint8_t c;
|
||||||
if (!readBytes(c))
|
if (!readBytes(c))
|
||||||
return DeserializationError::IncompleteInput;
|
return false;
|
||||||
builder.append(static_cast<char>(c));
|
_stringStorage.append(static_cast<char>(c));
|
||||||
}
|
}
|
||||||
result = builder.complete();
|
_stringStorage.append('\0');
|
||||||
if (!result)
|
if (!_stringStorage.isValid()) {
|
||||||
return DeserializationError::NoMemory;
|
_error = DeserializationError::NoMemory;
|
||||||
return DeserializationError::Ok;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = _stringStorage.save(_pool);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TSize>
|
template <typename TSize>
|
||||||
DeserializationError readArray(CollectionData &array,
|
bool readArray(CollectionData &array, NestingLimit nestingLimit) {
|
||||||
NestingLimit nestingLimit) {
|
|
||||||
TSize size;
|
TSize size;
|
||||||
if (!readInteger(size))
|
if (!readInteger(size))
|
||||||
return DeserializationError::IncompleteInput;
|
return false;
|
||||||
return readArray(array, size, nestingLimit);
|
return readArray(array, size, nestingLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError readArray(CollectionData &array, size_t n,
|
bool readArray(CollectionData &array, size_t n, NestingLimit nestingLimit) {
|
||||||
NestingLimit nestingLimit) {
|
if (nestingLimit.reached()) {
|
||||||
if (nestingLimit.reached())
|
_error = DeserializationError::TooDeep;
|
||||||
return DeserializationError::TooDeep;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (; n; --n) {
|
for (; n; --n) {
|
||||||
VariantData *value = array.addElement(_pool);
|
VariantData *value = array.addElement(_pool);
|
||||||
if (!value)
|
if (!value) {
|
||||||
return DeserializationError::NoMemory;
|
_error = DeserializationError::NoMemory;
|
||||||
|
return false;
|
||||||
DeserializationError err = parse(*value, nestingLimit.decrement());
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return DeserializationError::Ok;
|
if (!parseVariant(*value, nestingLimit.decrement()))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TSize>
|
template <typename TSize>
|
||||||
DeserializationError readObject(CollectionData &object,
|
bool readObject(CollectionData &object, NestingLimit nestingLimit) {
|
||||||
NestingLimit nestingLimit) {
|
|
||||||
TSize size;
|
TSize size;
|
||||||
if (!readInteger(size))
|
if (!readInteger(size))
|
||||||
return DeserializationError::IncompleteInput;
|
return false;
|
||||||
return readObject(object, size, nestingLimit);
|
return readObject(object, size, nestingLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError readObject(CollectionData &object, size_t n,
|
bool readObject(CollectionData &object, size_t n, NestingLimit nestingLimit) {
|
||||||
NestingLimit nestingLimit) {
|
if (nestingLimit.reached()) {
|
||||||
if (nestingLimit.reached())
|
_error = DeserializationError::TooDeep;
|
||||||
return DeserializationError::TooDeep;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (; n; --n) {
|
for (; n; --n) {
|
||||||
VariantSlot *slot = object.addSlot(_pool);
|
VariantSlot *slot = object.addSlot(_pool);
|
||||||
if (!slot)
|
if (!slot) {
|
||||||
return DeserializationError::NoMemory;
|
_error = DeserializationError::NoMemory;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const char *key = 0; // <- mute "maybe-uninitialized" (+4 bytes on AVR)
|
const char *key = 0; // <- mute "maybe-uninitialized" (+4 bytes on AVR)
|
||||||
DeserializationError err = parseKey(key);
|
if (!parseKey(key))
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
slot->setOwnedKey(make_not_null(key));
|
|
||||||
|
|
||||||
err = parse(*slot->data(), nestingLimit.decrement());
|
slot->setKey(key, typename TStringStorage::storage_policy());
|
||||||
if (err)
|
|
||||||
return err;
|
if (!parseVariant(*slot->data(), nestingLimit.decrement()))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError parseKey(const char *&key) {
|
bool parseKey(const char *&key) {
|
||||||
uint8_t code;
|
uint8_t code;
|
||||||
if (!readByte(code))
|
if (!readByte(code))
|
||||||
return DeserializationError::IncompleteInput;
|
return false;
|
||||||
|
|
||||||
if ((code & 0xe0) == 0xa0)
|
if ((code & 0xe0) == 0xa0)
|
||||||
return readString(key, code & 0x1f);
|
return readString(key, code & 0x1f);
|
||||||
@@ -331,13 +337,15 @@ class MsgPackDeserializer {
|
|||||||
return readString<uint32_t>(key);
|
return readString<uint32_t>(key);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return DeserializationError::NotSupported;
|
_error = DeserializationError::NotSupported;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryPool *_pool;
|
MemoryPool *_pool;
|
||||||
TReader _reader;
|
TReader _reader;
|
||||||
TStringStorage _stringStorage;
|
TStringStorage _stringStorage;
|
||||||
|
DeserializationError _error;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TInput>
|
template <typename TInput>
|
||||||
@@ -125,7 +125,13 @@ class MsgPackSerializer {
|
|||||||
} else if (value <= 0xFFFF) {
|
} else if (value <= 0xFFFF) {
|
||||||
writeByte(0xCD);
|
writeByte(0xCD);
|
||||||
writeInteger(uint16_t(value));
|
writeInteger(uint16_t(value));
|
||||||
} else if (value <= 0xFFFFFFFF) {
|
}
|
||||||
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
|
else if (value <= 0xFFFFFFFF)
|
||||||
|
#else
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
writeByte(0xCE);
|
writeByte(0xCE);
|
||||||
writeInteger(uint32_t(value));
|
writeInteger(uint32_t(value));
|
||||||
}
|
}
|
||||||
49
lib/ArduinoJson/src/ArduinoJson/Namespace.hpp
Normal file
49
lib/ArduinoJson/src/ArduinoJson/Namespace.hpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// ArduinoJson - arduinojson.org
|
||||||
|
// Copyright Benoit Blanchon 2014-2020
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Configuration.hpp>
|
||||||
|
#include <ArduinoJson/version.hpp>
|
||||||
|
|
||||||
|
#ifndef ARDUINOJSON_NAMESPACE
|
||||||
|
|
||||||
|
#define ARDUINOJSON_HEX_DIGIT_0000() 0
|
||||||
|
#define ARDUINOJSON_HEX_DIGIT_0001() 1
|
||||||
|
#define ARDUINOJSON_HEX_DIGIT_0010() 2
|
||||||
|
#define ARDUINOJSON_HEX_DIGIT_0011() 3
|
||||||
|
#define ARDUINOJSON_HEX_DIGIT_0100() 4
|
||||||
|
#define ARDUINOJSON_HEX_DIGIT_0101() 5
|
||||||
|
#define ARDUINOJSON_HEX_DIGIT_0110() 6
|
||||||
|
#define ARDUINOJSON_HEX_DIGIT_0111() 7
|
||||||
|
#define ARDUINOJSON_HEX_DIGIT_1000() 8
|
||||||
|
#define ARDUINOJSON_HEX_DIGIT_1001() 9
|
||||||
|
#define ARDUINOJSON_HEX_DIGIT_1010() A
|
||||||
|
#define ARDUINOJSON_HEX_DIGIT_1011() B
|
||||||
|
#define ARDUINOJSON_HEX_DIGIT_1100() C
|
||||||
|
#define ARDUINOJSON_HEX_DIGIT_1101() D
|
||||||
|
#define ARDUINOJSON_HEX_DIGIT_1110() E
|
||||||
|
#define ARDUINOJSON_HEX_DIGIT_1111() F
|
||||||
|
#define ARDUINOJSON_HEX_DIGIT_(A, B, C, D) ARDUINOJSON_HEX_DIGIT_##A##B##C##D()
|
||||||
|
#define ARDUINOJSON_HEX_DIGIT(A, B, C, D) ARDUINOJSON_HEX_DIGIT_(A, B, C, D)
|
||||||
|
|
||||||
|
#define ARDUINOJSON_CONCAT_(A, B) A##B
|
||||||
|
#define ARDUINOJSON_CONCAT2(A, B) ARDUINOJSON_CONCAT_(A, B)
|
||||||
|
#define ARDUINOJSON_CONCAT4(A, B, C, D) \
|
||||||
|
ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT2(A, B), ARDUINOJSON_CONCAT2(C, D))
|
||||||
|
|
||||||
|
#define ARDUINOJSON_NAMESPACE \
|
||||||
|
ARDUINOJSON_CONCAT4( \
|
||||||
|
ARDUINOJSON_CONCAT4(ArduinoJson, ARDUINOJSON_VERSION_MAJOR, \
|
||||||
|
ARDUINOJSON_VERSION_MINOR, \
|
||||||
|
ARDUINOJSON_VERSION_REVISION), \
|
||||||
|
_, \
|
||||||
|
ARDUINOJSON_HEX_DIGIT(0, ARDUINOJSON_USE_LONG_LONG, \
|
||||||
|
ARDUINOJSON_USE_DOUBLE, \
|
||||||
|
ARDUINOJSON_ENABLE_STRING_DEDUPLICATION), \
|
||||||
|
ARDUINOJSON_HEX_DIGIT( \
|
||||||
|
ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY, \
|
||||||
|
ARDUINOJSON_ENABLE_COMMENTS, ARDUINOJSON_DECODE_UNICODE))
|
||||||
|
|
||||||
|
#endif
|
||||||
32
lib/ArduinoJson/src/ArduinoJson/Numbers/Integer.hpp
Normal file
32
lib/ArduinoJson/src/ArduinoJson/Numbers/Integer.hpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// ArduinoJson - arduinojson.org
|
||||||
|
// Copyright Benoit Blanchon 2014-2020
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Configuration.hpp>
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
#include <stdint.h> // int64_t
|
||||||
|
|
||||||
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
|
typedef int64_t Integer;
|
||||||
|
typedef uint64_t UInt;
|
||||||
|
#else
|
||||||
|
typedef long Integer;
|
||||||
|
typedef unsigned long UInt;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
|
||||||
|
#if ARDUINOJSON_HAS_LONG_LONG && !ARDUINOJSON_USE_LONG_LONG
|
||||||
|
#define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) \
|
||||||
|
static_assert(sizeof(T) <= sizeof(ARDUINOJSON_NAMESPACE::Integer), \
|
||||||
|
"To use 64-bit integers with ArduinoJson, you must set " \
|
||||||
|
"ARDUINOJSON_USE_LONG_LONG to 1. See " \
|
||||||
|
"https://arduinojson.org/v6/api/config/use_long_long/");
|
||||||
|
#else
|
||||||
|
#define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T)
|
||||||
|
#endif
|
||||||
121
lib/ArduinoJson/src/ArduinoJson/Numbers/arithmeticCompare.hpp
Normal file
121
lib/ArduinoJson/src/ArduinoJson/Numbers/arithmeticCompare.hpp
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
// ArduinoJson - arduinojson.org
|
||||||
|
// Copyright Benoit Blanchon 2014-2020
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Numbers/Integer.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||||
|
|
||||||
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
|
enum CompareResult {
|
||||||
|
COMPARE_RESULT_DIFFER = 0,
|
||||||
|
COMPARE_RESULT_EQUAL = 1,
|
||||||
|
COMPARE_RESULT_GREATER = 2,
|
||||||
|
COMPARE_RESULT_LESS = 4,
|
||||||
|
|
||||||
|
COMPARE_RESULT_GREATER_OR_EQUAL = 3,
|
||||||
|
COMPARE_RESULT_LESS_OR_EQUAL = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
CompareResult arithmeticCompare(const T &lhs, const T &rhs) {
|
||||||
|
if (lhs < rhs)
|
||||||
|
return COMPARE_RESULT_LESS;
|
||||||
|
else if (lhs > rhs)
|
||||||
|
return COMPARE_RESULT_GREATER;
|
||||||
|
else
|
||||||
|
return COMPARE_RESULT_EQUAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
CompareResult arithmeticCompare(
|
||||||
|
const T1 &lhs, const T2 &rhs,
|
||||||
|
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||||
|
sizeof(T1) < sizeof(T2),
|
||||||
|
int // Using int instead of void to avoid C2572 on
|
||||||
|
// Visual Studio 2012, 2013, and 2015
|
||||||
|
>::type * = 0) {
|
||||||
|
return arithmeticCompare<T2>(static_cast<T2>(lhs), rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
CompareResult arithmeticCompare(
|
||||||
|
const T1 &lhs, const T2 &rhs,
|
||||||
|
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||||
|
sizeof(T2) < sizeof(T1)>::type * = 0) {
|
||||||
|
return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
CompareResult arithmeticCompare(
|
||||||
|
const T1 &lhs, const T2 &rhs,
|
||||||
|
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||||
|
is_signed<T1>::value == is_signed<T2>::value &&
|
||||||
|
sizeof(T2) == sizeof(T1)>::type * = 0) {
|
||||||
|
return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
CompareResult arithmeticCompare(
|
||||||
|
const T1 &lhs, const T2 &rhs,
|
||||||
|
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||||
|
is_unsigned<T1>::value && is_signed<T2>::value &&
|
||||||
|
sizeof(T2) == sizeof(T1)>::type * = 0) {
|
||||||
|
if (rhs < 0)
|
||||||
|
return COMPARE_RESULT_GREATER;
|
||||||
|
return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
CompareResult arithmeticCompare(
|
||||||
|
const T1 &lhs, const T2 &rhs,
|
||||||
|
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||||
|
is_signed<T1>::value && is_unsigned<T2>::value &&
|
||||||
|
sizeof(T2) == sizeof(T1)>::type * = 0) {
|
||||||
|
if (lhs < 0)
|
||||||
|
return COMPARE_RESULT_LESS;
|
||||||
|
return arithmeticCompare<T2>(static_cast<T2>(lhs), rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
CompareResult arithmeticCompare(
|
||||||
|
const T1 &lhs, const T2 &rhs,
|
||||||
|
typename enable_if<is_floating_point<T1>::value ||
|
||||||
|
is_floating_point<T2>::value>::type * = 0) {
|
||||||
|
return arithmeticCompare<double>(static_cast<double>(lhs),
|
||||||
|
static_cast<double>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T2>
|
||||||
|
CompareResult arithmeticCompareNegateLeft(
|
||||||
|
UInt, const T2 &, typename enable_if<is_unsigned<T2>::value>::type * = 0) {
|
||||||
|
return COMPARE_RESULT_LESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T2>
|
||||||
|
CompareResult arithmeticCompareNegateLeft(
|
||||||
|
UInt lhs, const T2 &rhs,
|
||||||
|
typename enable_if<is_signed<T2>::value>::type * = 0) {
|
||||||
|
if (rhs > 0)
|
||||||
|
return COMPARE_RESULT_LESS;
|
||||||
|
return arithmeticCompare(-rhs, static_cast<T2>(lhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1>
|
||||||
|
CompareResult arithmeticCompareNegateRight(
|
||||||
|
const T1 &, UInt, typename enable_if<is_unsigned<T1>::value>::type * = 0) {
|
||||||
|
return COMPARE_RESULT_GREATER;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1>
|
||||||
|
CompareResult arithmeticCompareNegateRight(
|
||||||
|
const T1 &lhs, UInt rhs,
|
||||||
|
typename enable_if<is_signed<T1>::value>::type * = 0) {
|
||||||
|
if (lhs > 0)
|
||||||
|
return COMPARE_RESULT_GREATER;
|
||||||
|
return arithmeticCompare(static_cast<T1>(rhs), -lhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
@@ -13,6 +13,8 @@ template <typename T>
|
|||||||
inline T parseFloat(const char* s) {
|
inline T parseFloat(const char* s) {
|
||||||
// try to reuse the same parameters as JsonDeserializer
|
// try to reuse the same parameters as JsonDeserializer
|
||||||
typedef typename choose_largest<Float, T>::type TFloat;
|
typedef typename choose_largest<Float, T>::type TFloat;
|
||||||
return parseNumber<TFloat, UInt>(s).template as<T>();
|
ParsedNumber<TFloat, UInt> value;
|
||||||
|
parseNumber(s, value);
|
||||||
|
return value.template as<T>();
|
||||||
}
|
}
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
@@ -14,6 +14,8 @@ T parseInteger(const char *s) {
|
|||||||
// try to reuse the same parameters as JsonDeserializer
|
// try to reuse the same parameters as JsonDeserializer
|
||||||
typedef typename choose_largest<UInt, typename make_unsigned<T>::type>::type
|
typedef typename choose_largest<UInt, typename make_unsigned<T>::type>::type
|
||||||
TUInt;
|
TUInt;
|
||||||
return parseNumber<Float, TUInt>(s).template as<T>();
|
ParsedNumber<Float, TUInt> value;
|
||||||
|
parseNumber(s, value);
|
||||||
|
return value.template as<T>();
|
||||||
}
|
}
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
@@ -16,14 +16,18 @@ namespace ARDUINOJSON_NAMESPACE {
|
|||||||
|
|
||||||
template <typename TFloat, typename TUInt>
|
template <typename TFloat, typename TUInt>
|
||||||
struct ParsedNumber {
|
struct ParsedNumber {
|
||||||
ParsedNumber() : uintValue(0), floatValue(0), _type(VALUE_IS_NULL) {}
|
ParsedNumber() : _type(VALUE_IS_NULL) {}
|
||||||
|
|
||||||
ParsedNumber(TUInt value, bool is_negative)
|
void setInteger(TUInt value, bool is_negative) {
|
||||||
: uintValue(value),
|
uintValue = value;
|
||||||
floatValue(TFloat(value)),
|
_type = uint8_t(is_negative ? VALUE_IS_NEGATIVE_INTEGER
|
||||||
_type(uint8_t(is_negative ? VALUE_IS_NEGATIVE_INTEGER
|
: VALUE_IS_POSITIVE_INTEGER);
|
||||||
: VALUE_IS_POSITIVE_INTEGER)) {}
|
}
|
||||||
ParsedNumber(TFloat value) : floatValue(value), _type(VALUE_IS_FLOAT) {}
|
|
||||||
|
void setFloat(TFloat value) {
|
||||||
|
floatValue = value;
|
||||||
|
_type = VALUE_IS_FLOAT;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T as() const {
|
T as() const {
|
||||||
@@ -43,21 +47,22 @@ struct ParsedNumber {
|
|||||||
return _type;
|
return _type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
union {
|
||||||
TUInt uintValue;
|
TUInt uintValue;
|
||||||
TFloat floatValue;
|
TFloat floatValue;
|
||||||
|
};
|
||||||
uint8_t _type;
|
uint8_t _type;
|
||||||
};
|
}; // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
|
||||||
template <typename A, typename B>
|
template <typename A, typename B>
|
||||||
struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> {};
|
struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> {};
|
||||||
|
|
||||||
template <typename TFloat, typename TUInt>
|
template <typename TFloat, typename TUInt>
|
||||||
inline ParsedNumber<TFloat, TUInt> parseNumber(const char *s) {
|
inline void parseNumber(const char* s, ParsedNumber<TFloat, TUInt>& result) {
|
||||||
typedef FloatTraits<TFloat> traits;
|
typedef FloatTraits<TFloat> traits;
|
||||||
typedef typename choose_largest<typename traits::mantissa_type, TUInt>::type
|
typedef typename choose_largest<typename traits::mantissa_type, TUInt>::type
|
||||||
mantissa_t;
|
mantissa_t;
|
||||||
typedef typename traits::exponent_type exponent_t;
|
typedef typename traits::exponent_type exponent_t;
|
||||||
typedef ParsedNumber<TFloat, TUInt> return_type;
|
|
||||||
|
|
||||||
ARDUINOJSON_ASSERT(s != 0);
|
ARDUINOJSON_ASSERT(s != 0);
|
||||||
|
|
||||||
@@ -73,17 +78,22 @@ inline ParsedNumber<TFloat, TUInt> parseNumber(const char *s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if ARDUINOJSON_ENABLE_NAN
|
#if ARDUINOJSON_ENABLE_NAN
|
||||||
if (*s == 'n' || *s == 'N')
|
if (*s == 'n' || *s == 'N') {
|
||||||
return traits::nan();
|
result.setFloat(traits::nan());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ARDUINOJSON_ENABLE_INFINITY
|
#if ARDUINOJSON_ENABLE_INFINITY
|
||||||
if (*s == 'i' || *s == 'I')
|
if (*s == 'i' || *s == 'I') {
|
||||||
return is_negative ? -traits::inf() : traits::inf();
|
result.setFloat(is_negative ? -traits::inf() : traits::inf());
|
||||||
|
return;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!isdigit(*s) && *s != '.')
|
if (!isdigit(*s) && *s != '.')
|
||||||
return return_type();
|
return;
|
||||||
|
|
||||||
mantissa_t mantissa = 0;
|
mantissa_t mantissa = 0;
|
||||||
exponent_t exponent_offset = 0;
|
exponent_t exponent_offset = 0;
|
||||||
@@ -100,8 +110,10 @@ inline ParsedNumber<TFloat, TUInt> parseNumber(const char *s) {
|
|||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*s == '\0')
|
if (*s == '\0') {
|
||||||
return return_type(TUInt(mantissa), is_negative);
|
result.setInteger(TUInt(mantissa), is_negative);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// avoid mantissa overflow
|
// avoid mantissa overflow
|
||||||
while (mantissa > traits::mantissa_max) {
|
while (mantissa > traits::mantissa_max) {
|
||||||
@@ -141,9 +153,10 @@ inline ParsedNumber<TFloat, TUInt> parseNumber(const char *s) {
|
|||||||
exponent = exponent * 10 + (*s - '0');
|
exponent = exponent * 10 + (*s - '0');
|
||||||
if (exponent + exponent_offset > traits::exponent_max) {
|
if (exponent + exponent_offset > traits::exponent_max) {
|
||||||
if (negative_exponent)
|
if (negative_exponent)
|
||||||
return is_negative ? -0.0f : 0.0f;
|
result.setFloat(is_negative ? -0.0f : 0.0f);
|
||||||
else
|
else
|
||||||
return is_negative ? -traits::inf() : traits::inf();
|
result.setFloat(is_negative ? -traits::inf() : traits::inf());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
@@ -154,10 +167,11 @@ inline ParsedNumber<TFloat, TUInt> parseNumber(const char *s) {
|
|||||||
|
|
||||||
// we should be at the end of the string, otherwise it's an error
|
// we should be at the end of the string, otherwise it's an error
|
||||||
if (*s != '\0')
|
if (*s != '\0')
|
||||||
return return_type();
|
return;
|
||||||
|
|
||||||
TFloat result = traits::make_float(static_cast<TFloat>(mantissa), exponent);
|
TFloat final_result =
|
||||||
|
traits::make_float(static_cast<TFloat>(mantissa), exponent);
|
||||||
|
|
||||||
return is_negative ? -result : result;
|
result.setFloat(is_negative ? -final_result : final_result);
|
||||||
}
|
}
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
@@ -5,8 +5,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ArduinoJson/Configuration.hpp>
|
#include <ArduinoJson/Configuration.hpp>
|
||||||
#include <ArduinoJson/Operators/VariantOperators.hpp>
|
|
||||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantOperators.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantRef.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantShortcuts.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantTo.hpp>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
@@ -17,6 +20,7 @@ namespace ARDUINOJSON_NAMESPACE {
|
|||||||
|
|
||||||
template <typename TObject, typename TStringRef>
|
template <typename TObject, typename TStringRef>
|
||||||
class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >,
|
class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >,
|
||||||
|
public VariantShortcuts<MemberProxy<TObject, TStringRef> >,
|
||||||
public Visitable {
|
public Visitable {
|
||||||
typedef MemberProxy<TObject, TStringRef> this_type;
|
typedef MemberProxy<TObject, TStringRef> this_type;
|
||||||
|
|
||||||
@@ -52,14 +56,6 @@ class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >,
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE bool operator==(VariantConstRef rhs) const {
|
|
||||||
return static_cast<VariantConstRef>(getUpstreamMember()) == rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
FORCE_INLINE bool operator!=(VariantConstRef rhs) const {
|
|
||||||
return static_cast<VariantConstRef>(getUpstreamMember()) != rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
FORCE_INLINE void clear() const {
|
FORCE_INLINE void clear() const {
|
||||||
getUpstreamMember().clear();
|
getUpstreamMember().clear();
|
||||||
}
|
}
|
||||||
@@ -73,6 +69,11 @@ class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >,
|
|||||||
return getUpstreamMember().template as<TValue>();
|
return getUpstreamMember().template as<TValue>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
FORCE_INLINE operator T() const {
|
||||||
|
return getUpstreamMember();
|
||||||
|
}
|
||||||
|
|
||||||
template <typename TValue>
|
template <typename TValue>
|
||||||
FORCE_INLINE bool is() const {
|
FORCE_INLINE bool is() const {
|
||||||
return getUpstreamMember().template is<TValue>();
|
return getUpstreamMember().template is<TValue>();
|
||||||
@@ -12,6 +12,11 @@
|
|||||||
#pragma warning(disable : 4244)
|
#pragma warning(disable : 4244)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __ICCARM__
|
||||||
|
// Suppress IAR Compiler Warning[Pa093]: implicit conversion from floating point to integer
|
||||||
|
#pragma diag_suppress=Pa093
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
template <typename From, typename To>
|
template <typename From, typename To>
|
||||||
@@ -32,3 +37,7 @@ struct is_convertible {
|
|||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __ICCARM__
|
||||||
|
#pragma diag_default=Pa093
|
||||||
|
#endif
|
||||||
@@ -16,8 +16,7 @@ template <typename T>
|
|||||||
struct is_enum {
|
struct is_enum {
|
||||||
static const bool value = is_convertible<T, int>::value &&
|
static const bool value = is_convertible<T, int>::value &&
|
||||||
!is_class<T>::value && !is_integral<T>::value &&
|
!is_class<T>::value && !is_integral<T>::value &&
|
||||||
!is_floating_point<T>::value &&
|
!is_floating_point<T>::value;
|
||||||
!is_same<T, bool>::value;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user