upgrade arduinojson to 6.17.0

This commit is contained in:
proddy
2020-10-19 23:15:16 +02:00
parent 5235faefff
commit 4fc26dbb44
156 changed files with 10929 additions and 11466 deletions

View File

@@ -1,6 +1,19 @@
ArduinoJson: change log ArduinoJson: change log
======================= =======================
v6.17.0 (2020-10-19)
-------
* Added a build failure when nullptr is defined as a macro (issue #1355)
* Added `JsonDocument::overflowed()` which tells if the memory pool was too small (issue #1358)
* Added `DeserializationError::EmptyInput` which tells if the input was empty
* Added `DeserializationError::f_str()` which returns a `const __FlashStringHelper*` (issue #846)
* Added `operator|(JsonVariantConst, JsonVariantConst)`
* Added filtering for MessagePack (issue #1298, PR #1394 by Luca Passarella)
* Moved float convertion tables to PROGMEM
* Fixed `JsonVariant::set((char*)0)` which returned false instead of true (issue #1368)
* Fixed error `No such file or directory #include <WString.h>` (issue #1381)
v6.16.1 (2020-08-04) v6.16.1 (2020-08-04)
------- -------
@@ -12,6 +25,7 @@ v6.16.0 (2020-08-01)
* Added comparisons (`>`, `>=`, `==`, `!=`, `<`, and `<=`) between `JsonVariant`s * Added comparisons (`>`, `>=`, `==`, `!=`, `<`, and `<=`) between `JsonVariant`s
* Added string deduplication (issue #1303) * Added string deduplication (issue #1303)
* Added `JsonString::operator!=` * Added `JsonString::operator!=`
* Added wildcard key (`*`) for filters (issue #1309)
* Set `ARDUINOJSON_DECODE_UNICODE` to `1` by default * Set `ARDUINOJSON_DECODE_UNICODE` to `1` by default
* Fixed `copyArray()` not working with `String`, `ElementProxy`, and `MemberProxy` * Fixed `copyArray()` not working with `String`, `ElementProxy`, and `MemberProxy`
* Fixed error `getOrAddElement is not a member of ElementProxy` (issue #1311) * Fixed error `getOrAddElement is not a member of ElementProxy` (issue #1311)

View File

@@ -2,7 +2,7 @@
--- ---
[![arduino-library-badge](https://www.ardu-badge.com/badge/ArduinoJson.svg?version=6.16.1)](https://www.ardu-badge.com/ArduinoJson/6.16.1) [![arduino-library-badge](https://www.ardu-badge.com/badge/ArduinoJson.svg?version=6.17.0)](https://www.ardu-badge.com/ArduinoJson/6.17.0)
[![Build Status](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/6.x?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x) [![Build Status](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/6.x?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x)
[![Build Status](https://travis-ci.org/bblanchon/ArduinoJson.svg?branch=6.x)](https://travis-ci.org/bblanchon/ArduinoJson) [![Build Status](https://travis-ci.org/bblanchon/ArduinoJson.svg?branch=6.x)](https://travis-ci.org/bblanchon/ArduinoJson)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/arduinojson.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/arduinojson.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)

View File

@@ -0,0 +1,27 @@
# ArduinoJson Support
First off, thank you very much for using ArduinoJson.
We'll be very happy to help you, but first please read the following.
## Before asking for help
1. Read the [FAQ](https://arduinojson.org/faq/?utm_source=github&utm_medium=support)
2. Search in the [API Reference](https://arduinojson.org/api/?utm_source=github&utm_medium=support)
If you did not find the answer, please create a [new issue on GitHub](https://github.com/bblanchon/ArduinoJson/issues/new).
It is OK to add a comment to a currently opened issue, but please avoid adding comments to a closed issue.
## Before hitting the Submit button
Please provide all the relevant information:
* Good title
* Short description of the problem
* Target platform
* Compiler model and version
* [MVCE](https://stackoverflow.com/help/mcve)
* Compiler output
Good questions get fast answers!

View File

@@ -1,154 +0,0 @@
// 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 ❤❤❤❤❤

View File

@@ -1,63 +0,0 @@
// 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 ❤❤❤❤❤

View File

@@ -1,77 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2020
// MIT License
//
// This example shows how to generate a JSON document with ArduinoJson.
//
// https://arduinojson.org/v6/example/generator/
#include <ArduinoJson.h>
void setup() {
// Initialize Serial port
Serial.begin(9600);
while (!Serial) continue;
// Allocate the JSON document
//
// Inside the brackets, 200 is the RAM allocated to this document.
// Don't forget to change this value to match your requirement.
// Use arduinojson.org/v6/assistant to compute the capacity.
StaticJsonDocument<200> doc;
// 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
//
doc["sensor"] = "gps";
doc["time"] = 1351824120;
// Add an array.
//
JsonArray data = doc.createNestedArray("data");
data.add(48.756080);
data.add(2.302038);
// Generate the minified JSON and send it to the Serial port.
//
serializeJson(doc, Serial);
// The above line prints:
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
// Start a new line
Serial.println();
// Generate the prettified JSON and send it to the Serial port.
//
serializeJsonPretty(doc, Serial);
// The above line prints:
// {
// "sensor": "gps",
// "time": 1351824120,
// "data": [
// 48.756080,
// 2.302038
// ]
// }
}
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 ❤❤❤❤❤

View File

@@ -1,116 +0,0 @@
// 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 ❤❤❤❤❤

View File

@@ -1,80 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2020
// MIT License
//
// This example shows how to deserialize a JSON document with ArduinoJson.
//
// https://arduinojson.org/v6/example/parser/
#include <ArduinoJson.h>
void setup() {
// Initialize serial port
Serial.begin(9600);
while (!Serial) continue;
// Allocate the JSON document
//
// 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.
// Use arduinojson.org/v6/assistant to compute the capacity.
StaticJsonDocument<200> doc;
// StaticJsonDocument<N> allocates memory on the stack, it can be
// replaced by DynamicJsonDocument which allocates in the heap.
//
// DynamicJsonDocument doc(200);
// JSON input string.
//
// Using a char[], as shown here, enables the "zero-copy" mode. This mode uses
// the minimal amount of memory because the JsonDocument stores pointers to
// 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.
char json[] =
"{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
// Deserialize the JSON document
DeserializationError error = deserializeJson(doc, json);
// Test if parsing succeeds.
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.c_str());
return;
}
// Fetch values.
//
// Most of the time, you can rely on the implicit casts.
// In other case, you can do doc["time"].as<long>();
const char* sensor = doc["sensor"];
long time = doc["time"];
double latitude = doc["data"][0];
double longitude = doc["data"][1];
// Print values.
Serial.println(sensor);
Serial.println(time);
Serial.println(latitude, 6);
Serial.println(longitude, 6);
}
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 ❤❤❤❤❤

View File

@@ -1,110 +0,0 @@
// 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 ❤❤❤❤❤

View File

@@ -1,100 +0,0 @@
// 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 ❤❤❤❤❤

View File

@@ -1,75 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2020
// MIT License
//
// This example shows how to deserialize a MessagePack document with
// ArduinoJson.
//
// https://arduinojson.org/v6/example/msgpack-parser/
#include <ArduinoJson.h>
void setup() {
// Initialize serial port
Serial.begin(9600);
while (!Serial) continue;
// Allocate the JSON document
//
// 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.
// Use arduinojson.org/v6/assistant to compute the capacity.
StaticJsonDocument<200> doc;
// StaticJsonObject allocates memory on the stack, it can be
// replaced by DynamicJsonObject which allocates in the heap.
//
// DynamicJsonObject doc(200);
// MessagePack input string.
//
// Using a char[], as shown here, enables the "zero-copy" mode. This mode uses
// the minimal amount of memory because the JsonDocument stores pointers to
// 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,
164, 116, 105, 109, 101, 206, 80, 147, 50, 248, 164, 100,
97, 116, 97, 146, 203, 64, 72, 96, 199, 58, 188, 148,
112, 203, 64, 2, 106, 146, 230, 33, 49, 169};
// This MessagePack document contains:
// {
// "sensor": "gps",
// "time": 1351824120,
// "data": [48.75608, 2.302038]
// }
DeserializationError error = deserializeMsgPack(doc, input);
// Test if parsing succeeded.
if (error) {
Serial.print("deserializeMsgPack() failed: ");
Serial.println(error.c_str());
return;
}
// Fetch values.
//
// Most of the time, you can rely on the implicit casts.
// In other case, you can do doc["time"].as<long>();
const char* sensor = doc["sensor"];
long time = doc["time"];
double latitude = doc["data"][0];
double longitude = doc["data"][1];
// Print values.
Serial.println(sensor);
Serial.println(time);
Serial.println(latitude, 6);
Serial.println(longitude, 6);
}
void loop() {
// not used in this example
}

View File

@@ -1,72 +0,0 @@
// 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 ❤❤❤❤❤

View File

@@ -1,77 +0,0 @@
// 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 ❤❤❤❤❤

View File

@@ -1,39 +0,0 @@
# Macros
JSON_ARRAY_SIZE KEYWORD2
JSON_OBJECT_SIZE KEYWORD2
JSON_STRING_SIZE KEYWORD2
# Free functions
deserializeJson KEYWORD2
deserializeMsgPack KEYWORD2
serialized KEYWORD2
serializeJson KEYWORD2
serializeJsonPretty KEYWORD2
serializeMsgPack KEYWORD2
measureJson KEYWORD2
measureJsonPretty KEYWORD2
measureMsgPack KEYWORD2
# Methods
add KEYWORD2
as KEYWORD2
createNestedArray KEYWORD2
createNestedObject KEYWORD2
get KEYWORD2
set KEYWORD2
to KEYWORD2
# Type names
DeserializationError KEYWORD1 DATA_TYPE
DynamicJsonDocument KEYWORD1 DATA_TYPE
JsonArray KEYWORD1 DATA_TYPE
JsonArrayConst KEYWORD1 DATA_TYPE
JsonFloat KEYWORD1 DATA_TYPE
JsonInteger KEYWORD1 DATA_TYPE
JsonObject KEYWORD1 DATA_TYPE
JsonObjectConst KEYWORD1 DATA_TYPE
JsonString KEYWORD1 DATA_TYPE
JsonUInt KEYWORD1 DATA_TYPE
JsonVariant KEYWORD1 DATA_TYPE
JsonVariantConst KEYWORD1 DATA_TYPE
StaticJsonDocument KEYWORD1 DATA_TYPE

View File

@@ -1,11 +0,0 @@
name=ArduinoJson
version=6.16.1
author=Benoit Blanchon <blog.benoitblanchon.fr>
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
sentence=A simple and efficient JSON library for embedded C++.
paragraph=ArduinoJson supports ✔ serialization, ✔ deserialization, ✔ MessagePack, ✔ fixed allocation, ✔ zero-copy, ✔ streams, ✔ filtering, and more. It is the most popular Arduino library on GitHub ❤❤❤❤❤. Check out arduinojson.org for a comprehensive documentation.
category=Data Processing
url=https://arduinojson.org/?utm_source=meta&utm_medium=library.properties
architectures=*
repository=https://github.com/bblanchon/ArduinoJson.git
license=MIT

View File

@@ -12,12 +12,13 @@ inline VariantData *arrayAdd(CollectionData *arr, MemoryPool *pool) {
return arr ? arr->addElement(pool) : 0; return arr ? arr->addElement(pool) : 0;
} }
template <typename Visitor> template <typename TVisitor>
inline void arrayAccept(const CollectionData *arr, Visitor &visitor) { inline typename TVisitor::result_type arrayAccept(const CollectionData *arr,
TVisitor &visitor) {
if (arr) if (arr)
visitor.visitArray(*arr); return visitor.visitArray(*arr);
else else
visitor.visitNull(); return visitor.visitNull();
} }
inline bool arrayEquals(const CollectionData *lhs, const CollectionData *rhs) { inline bool arrayEquals(const CollectionData *lhs, const CollectionData *rhs) {

View File

@@ -27,9 +27,9 @@ class ArrayRefBase {
return VariantConstRef(reinterpret_cast<const VariantData*>(data)); return VariantConstRef(reinterpret_cast<const VariantData*>(data));
} }
template <typename Visitor> template <typename TVisitor>
FORCE_INLINE void accept(Visitor& visitor) const { FORCE_INLINE typename TVisitor::result_type accept(TVisitor& visitor) const {
arrayAccept(_data, visitor); return arrayAccept(_data, visitor);
} }
FORCE_INLINE bool isNull() const { FORCE_INLINE bool isNull() const {

View File

@@ -98,8 +98,8 @@ class ElementProxy : public VariantOperators<ElementProxy<TArray> >,
return getOrAddUpstreamElement().set(value); return getOrAddUpstreamElement().set(value);
} }
template <typename Visitor> template <typename TVisitor>
void accept(Visitor& visitor) const { typename TVisitor::result_type accept(TVisitor& visitor) const {
return getUpstreamElement().accept(visitor); return getUpstreamElement().accept(visitor);
} }

View File

@@ -65,40 +65,61 @@ inline bool copyArray(T (&src)[N1][N2], JsonDocument& dst) {
} }
template <typename T> template <typename T>
class ArrayCopier1D { class ArrayCopier1D : public Visitor<size_t> {
public: public:
ArrayCopier1D(T* destination, size_t capacity) ArrayCopier1D(T* destination, size_t capacity)
: _destination(destination), _capacity(capacity), _size(0) {} : _destination(destination), _capacity(capacity) {}
void visitArray(const CollectionData& array) { size_t visitArray(const CollectionData& array) {
size_t size = 0;
VariantSlot* slot = array.head(); VariantSlot* slot = array.head();
while (slot != 0 && _size < _capacity) { while (slot != 0 && size < _capacity) {
_destination[_size++] = variantAs<T>(slot->data()); _destination[size++] = variantAs<T>(slot->data());
slot = slot->next(); slot = slot->next();
} }
return size;
} }
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 { size_t visitObject(const CollectionData&) {
return _size; return 0;
}
size_t visitFloat(Float) {
return 0;
}
size_t visitString(const char*) {
return 0;
}
size_t visitRawJson(const char*, size_t) {
return 0;
}
size_t visitNegativeInteger(UInt) {
return 0;
}
size_t visitPositiveInteger(UInt) {
return 0;
}
size_t visitBoolean(bool) {
return 0;
}
size_t visitNull() {
return 0;
} }
private: private:
T* _destination; T* _destination;
size_t _capacity; size_t _capacity;
size_t _size;
}; };
template <typename T, size_t N1, size_t N2> template <typename T, size_t N1, size_t N2>
class ArrayCopier2D { class ArrayCopier2D : public Visitor<void> {
public: public:
ArrayCopier2D(T (*destination)[N1][N2]) : _destination(destination) {} ArrayCopier2D(T (*destination)[N1][N2]) : _destination(destination) {}
@@ -136,8 +157,8 @@ inline typename enable_if<!is_array<T>::value, size_t>::type copyArray(
template <typename TSource, typename T> template <typename TSource, typename T>
inline size_t copyArray(const TSource& src, T* dst, size_t len) { inline size_t copyArray(const TSource& src, T* dst, size_t len) {
ArrayCopier1D<T> copier(dst, len); ArrayCopier1D<T> copier(dst, len);
src.accept(copier);
return copier.result(); return src.accept(copier);
} }
// Copy a JsonArray to a 2D array // Copy a JsonArray to a 2D array

View File

@@ -230,3 +230,8 @@
#define ARDUINOJSON_DEBUG 0 #define ARDUINOJSON_DEBUG 0
#endif #endif
#endif #endif
#if ARDUINOJSON_HAS_NULLPTR && defined(nullptr)
#error nullptr is defined as a macro. Remove the faulty #define or #undef nullptr
// See https://github.com/bblanchon/ArduinoJson/issues/1355
#endif

View File

@@ -5,6 +5,8 @@
#pragma once #pragma once
#include <ArduinoJson/Namespace.hpp> #include <ArduinoJson/Namespace.hpp>
#include <ArduinoJson/Polyfills/preprocessor.hpp>
#include <ArduinoJson/Polyfills/static_array.hpp>
#if ARDUINOJSON_ENABLE_STD_STREAM #if ARDUINOJSON_ENABLE_STD_STREAM
#include <ostream> #include <ostream>
@@ -20,6 +22,7 @@ class DeserializationError {
public: public:
enum Code { enum Code {
Ok, Ok,
EmptyInput,
IncompleteInput, IncompleteInput,
InvalidInput, InvalidInput,
NoMemory, NoMemory,
@@ -77,23 +80,30 @@ class DeserializationError {
} }
const char* c_str() const { const char* c_str() const {
switch (_code) { static const char* messages[] = {
case Ok: "Ok", "EmptyInput", "IncompleteInput", "InvalidInput",
return "Ok"; "NoMemory", "NotSupported", "TooDeep"};
case TooDeep: ARDUINOJSON_ASSERT(static_cast<size_t>(_code) <
return "TooDeep"; sizeof(messages) / sizeof(messages[0]));
case NoMemory: return messages[_code];
return "NoMemory";
case InvalidInput:
return "InvalidInput";
case IncompleteInput:
return "IncompleteInput";
case NotSupported:
return "NotSupported";
default:
return "???";
} }
#if ARDUINOJSON_ENABLE_PROGMEM
const __FlashStringHelper* f_str() const {
ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s0, "Ok");
ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s1, "EmptyInput");
ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s2, "IncompleteInput");
ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s3, "InvalidInput");
ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s4, "NoMemory");
ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s5, "NotSupported");
ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s6, "TooDeep");
ARDUINOJSON_DEFINE_STATIC_ARRAY(
const char*, messages,
ARDUINOJSON_EXPAND7({s0, s1, s2, s3, s4, s5, s6}));
return ARDUINOJSON_READ_STATIC_ARRAY(const __FlashStringHelper*, messages,
_code);
} }
#endif
private: private:
Code _code; Code _code;

View File

@@ -33,7 +33,7 @@ class Filter {
if (_variant == true) // "true" means "allow recursively" if (_variant == true) // "true" means "allow recursively"
return *this; return *this;
else else
return Filter(_variant[key]); return Filter(_variant[key] | _variant["*"]);
} }
private: private:

View File

@@ -4,7 +4,7 @@
#pragma once #pragma once
#include <Stream.h> #include <Arduino.h>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {

View File

@@ -32,8 +32,9 @@ 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>(doc.memoryPool(), reader, return makeDeserializer<TDeserializer>(
makeStringStorage(input)) doc.memoryPool(), reader,
makeStringStorage(input, doc.memoryPool()))
.parse(doc.data(), filter, nestingLimit); .parse(doc.data(), filter, nestingLimit);
} }
// //
@@ -47,8 +48,9 @@ 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>(doc.memoryPool(), reader, return makeDeserializer<TDeserializer>(
makeStringStorage(input)) doc.memoryPool(), reader,
makeStringStorage(input, doc.memoryPool()))
.parse(doc.data(), filter, nestingLimit); .parse(doc.data(), filter, nestingLimit);
} }
// //
@@ -60,8 +62,9 @@ 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>(doc.memoryPool(), reader, return makeDeserializer<TDeserializer>(
makeStringStorage(input)) doc.memoryPool(), reader,
makeStringStorage(input, doc.memoryPool()))
.parse(doc.data(), filter, nestingLimit); .parse(doc.data(), filter, nestingLimit);
} }

View File

@@ -15,8 +15,8 @@ namespace ARDUINOJSON_NAMESPACE {
class JsonDocument : public Visitable { class JsonDocument : public Visitable {
public: public:
template <typename Visitor> template <typename TVisitor>
void accept(Visitor& visitor) const { typename TVisitor::result_type accept(TVisitor& visitor) const {
return getVariant().accept(visitor); return getVariant().accept(visitor);
} }
@@ -48,6 +48,10 @@ class JsonDocument : public Visitable {
return _pool.size(); return _pool.size();
} }
bool overflowed() const {
return _pool.overflowed();
}
size_t nesting() const { size_t nesting() const {
return _data.nesting(); return _data.nesting();
} }
@@ -81,6 +85,7 @@ class JsonDocument : public Visitable {
return _pool; return _pool;
} }
// for internal use only
VariantData& data() { VariantData& data() {
return _data; return _data;
} }

View File

@@ -23,6 +23,7 @@ class JsonDeserializer {
JsonDeserializer(MemoryPool &pool, TReader reader, JsonDeserializer(MemoryPool &pool, TReader reader,
TStringStorage stringStorage) TStringStorage stringStorage)
: _stringStorage(stringStorage), : _stringStorage(stringStorage),
_foundSomething(false),
_latch(reader), _latch(reader),
_pool(&pool), _pool(&pool),
_error(DeserializationError::Ok) {} _error(DeserializationError::Ok) {}
@@ -34,7 +35,7 @@ class JsonDeserializer {
if (!_error && _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
_error = DeserializationError::InvalidInput; return DeserializationError::InvalidInput;
} }
return _error; return _error;
@@ -241,7 +242,7 @@ class JsonDeserializer {
if (!variant) { if (!variant) {
// Save key in memory pool. // Save key in memory pool.
// This MUST be done before adding the slot. // This MUST be done before adding the slot.
key = _stringStorage.save(_pool); key = _stringStorage.save();
// Allocate slot in object // Allocate slot in object
VariantSlot *slot = object.addSlot(_pool); VariantSlot *slot = object.addSlot(_pool);
@@ -334,7 +335,7 @@ class JsonDeserializer {
} }
bool parseKey() { bool parseKey() {
_stringStorage.startString(_pool); _stringStorage.startString();
if (isQuote(current())) { if (isQuote(current())) {
return parseQuotedString(); return parseQuotedString();
} else { } else {
@@ -343,12 +344,11 @@ class JsonDeserializer {
} }
bool parseStringValue(VariantData &variant) { bool parseStringValue(VariantData &variant) {
_stringStorage.startString(_pool); _stringStorage.startString();
if (!parseQuotedString()) if (!parseQuotedString())
return false; return false;
const char *value = _stringStorage.save(_pool); const char *value = _stringStorage.save();
variant.setString(make_not_null(value), variant.setStringPointer(value, typename TStringStorage::storage_policy());
typename TStringStorage::storage_policy());
return true; return true;
} }
@@ -499,26 +499,12 @@ class JsonDeserializer {
return true; return true;
} }
ParsedNumber<Float, UInt> num; if (!parseNumber(_buffer, result)) {
parseNumber<Float, UInt>(_buffer, num);
switch (num.type()) {
case VALUE_IS_NEGATIVE_INTEGER:
result.setNegativeInteger(num.uintValue);
return true;
case VALUE_IS_POSITIVE_INTEGER:
result.setPositiveInteger(num.uintValue);
return true;
case VALUE_IS_FLOAT:
result.setFloat(num.floatValue);
return true;
default:
_error = DeserializationError::InvalidInput; _error = DeserializationError::InvalidInput;
return false; return false;
} }
return true;
} }
bool skipNumericValue() { bool skipNumericValue() {
@@ -574,7 +560,8 @@ class JsonDeserializer {
switch (current()) { switch (current()) {
// end of string // end of string
case '\0': case '\0':
_error = DeserializationError::IncompleteInput; _error = _foundSomething ? DeserializationError::IncompleteInput
: DeserializationError::EmptyInput;
return false; return false;
// spaces // spaces
@@ -634,12 +621,14 @@ class JsonDeserializer {
#endif #endif
default: default:
_foundSomething = true;
return true; return true;
} }
} }
} }
TStringStorage _stringStorage; TStringStorage _stringStorage;
bool _foundSomething;
Latch<TReader> _latch; Latch<TReader> _latch;
MemoryPool *_pool; MemoryPool *_pool;
char _buffer[64]; // using a member instead of a local variable because it char _buffer[64]; // using a member instead of a local variable because it
@@ -648,47 +637,60 @@ class JsonDeserializer {
DeserializationError _error; DeserializationError _error;
}; };
//
// deserializeJson(JsonDocument&, const std::string&, ...) // deserializeJson(JsonDocument&, const std::string&, ...)
template <typename TInput> //
// ... = NestingLimit
template <typename TString>
DeserializationError deserializeJson( DeserializationError deserializeJson(
JsonDocument &doc, const TInput &input, JsonDocument &doc, const TString &input,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, return deserialize<JsonDeserializer>(doc, input, nestingLimit,
AllowAllFilter()); AllowAllFilter());
} }
template <typename TInput> // ... = Filter, NestingLimit
template <typename TString>
DeserializationError deserializeJson( DeserializationError deserializeJson(
JsonDocument &doc, const TInput &input, Filter filter, JsonDocument &doc, const TString &input, Filter filter,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
} }
template <typename TInput> // ... = NestingLimit, Filter
DeserializationError deserializeJson(JsonDocument &doc, const TInput &input, template <typename TString>
DeserializationError deserializeJson(JsonDocument &doc, const TString &input,
NestingLimit nestingLimit, Filter filter) { NestingLimit nestingLimit, Filter filter) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
} }
// deserializeJson(JsonDocument&, const std::istream&, ...) //
template <typename TInput> // deserializeJson(JsonDocument&, std::istream&, ...)
//
// ... = NestingLimit
template <typename TStream>
DeserializationError deserializeJson( DeserializationError deserializeJson(
JsonDocument &doc, TInput &input, JsonDocument &doc, TStream &input,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, return deserialize<JsonDeserializer>(doc, input, nestingLimit,
AllowAllFilter()); AllowAllFilter());
} }
template <typename TInput> // ... = Filter, NestingLimit
template <typename TStream>
DeserializationError deserializeJson( DeserializationError deserializeJson(
JsonDocument &doc, TInput &input, Filter filter, JsonDocument &doc, TStream &input, Filter filter,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
} }
template <typename TInput> // ... = NestingLimit, Filter
DeserializationError deserializeJson(JsonDocument &doc, TInput &input, template <typename TStream>
DeserializationError deserializeJson(JsonDocument &doc, TStream &input,
NestingLimit nestingLimit, Filter filter) { NestingLimit nestingLimit, Filter filter) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
} }
//
// deserializeJson(JsonDocument&, char*, ...) // deserializeJson(JsonDocument&, char*, ...)
//
// ... = NestingLimit
template <typename TChar> template <typename TChar>
DeserializationError deserializeJson( DeserializationError deserializeJson(
JsonDocument &doc, TChar *input, JsonDocument &doc, TChar *input,
@@ -696,19 +698,24 @@ DeserializationError deserializeJson(
return deserialize<JsonDeserializer>(doc, input, nestingLimit, return deserialize<JsonDeserializer>(doc, input, nestingLimit,
AllowAllFilter()); AllowAllFilter());
} }
// ... = Filter, NestingLimit
template <typename TChar> template <typename TChar>
DeserializationError deserializeJson( DeserializationError deserializeJson(
JsonDocument &doc, TChar *input, Filter filter, JsonDocument &doc, TChar *input, Filter filter,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
} }
// ... = NestingLimit, Filter
template <typename TChar> template <typename TChar>
DeserializationError deserializeJson(JsonDocument &doc, TChar *input, DeserializationError deserializeJson(JsonDocument &doc, TChar *input,
NestingLimit nestingLimit, Filter filter) { NestingLimit nestingLimit, Filter filter) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
} }
//
// deserializeJson(JsonDocument&, char*, size_t, ...) // deserializeJson(JsonDocument&, char*, size_t, ...)
//
// ... = NestingLimit
template <typename TChar> template <typename TChar>
DeserializationError deserializeJson( DeserializationError deserializeJson(
JsonDocument &doc, TChar *input, size_t inputSize, JsonDocument &doc, TChar *input, size_t inputSize,
@@ -716,6 +723,7 @@ DeserializationError deserializeJson(
return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit, return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit,
AllowAllFilter()); AllowAllFilter());
} }
// ... = Filter, NestingLimit
template <typename TChar> template <typename TChar>
DeserializationError deserializeJson( DeserializationError deserializeJson(
JsonDocument &doc, TChar *input, size_t inputSize, Filter filter, JsonDocument &doc, TChar *input, size_t inputSize, Filter filter,
@@ -723,6 +731,7 @@ DeserializationError deserializeJson(
return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit, return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit,
filter); filter);
} }
// ... = NestingLimit, Filter
template <typename TChar> template <typename TChar>
DeserializationError deserializeJson(JsonDocument &doc, TChar *input, DeserializationError deserializeJson(JsonDocument &doc, TChar *input,
size_t inputSize, size_t inputSize,

View File

@@ -12,11 +12,11 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename TWriter> template <typename TWriter>
class JsonSerializer { class JsonSerializer : public Visitor<size_t> {
public: public:
JsonSerializer(TWriter writer) : _formatter(writer) {} JsonSerializer(TWriter writer) : _formatter(writer) {}
FORCE_INLINE void visitArray(const CollectionData &array) { FORCE_INLINE size_t visitArray(const CollectionData &array) {
write('['); write('[');
VariantSlot *slot = array.head(); VariantSlot *slot = array.head();
@@ -32,9 +32,10 @@ class JsonSerializer {
} }
write(']'); write(']');
return bytesWritten();
} }
void visitObject(const CollectionData &object) { size_t visitObject(const CollectionData &object) {
write('{'); write('{');
VariantSlot *slot = object.head(); VariantSlot *slot = object.head();
@@ -52,41 +53,49 @@ class JsonSerializer {
} }
write('}'); write('}');
return bytesWritten();
} }
void visitFloat(Float value) { size_t visitFloat(Float value) {
_formatter.writeFloat(value); _formatter.writeFloat(value);
return bytesWritten();
} }
void visitString(const char *value) { size_t visitString(const char *value) {
_formatter.writeString(value); _formatter.writeString(value);
return bytesWritten();
} }
void visitRawJson(const char *data, size_t n) { size_t visitRawJson(const char *data, size_t n) {
_formatter.writeRaw(data, n); _formatter.writeRaw(data, n);
return bytesWritten();
} }
void visitNegativeInteger(UInt value) { size_t visitNegativeInteger(UInt value) {
_formatter.writeNegativeInteger(value); _formatter.writeNegativeInteger(value);
return bytesWritten();
} }
void visitPositiveInteger(UInt value) { size_t visitPositiveInteger(UInt value) {
_formatter.writePositiveInteger(value); _formatter.writePositiveInteger(value);
return bytesWritten();
} }
void visitBoolean(bool value) { size_t visitBoolean(bool value) {
_formatter.writeBoolean(value); _formatter.writeBoolean(value);
return bytesWritten();
} }
void visitNull() { size_t visitNull() {
_formatter.writeRaw("null"); _formatter.writeRaw("null");
return bytesWritten();
} }
protected:
size_t bytesWritten() const { size_t bytesWritten() const {
return _formatter.bytesWritten(); return _formatter.bytesWritten();
} }
protected:
void write(char c) { void write(char c) {
_formatter.writeRaw(c); _formatter.writeRaw(c);
} }

View File

@@ -18,11 +18,9 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
public: public:
PrettyJsonSerializer(TWriter &writer) : base(writer), _nesting(0) {} PrettyJsonSerializer(TWriter &writer) : base(writer), _nesting(0) {}
void visitArray(const CollectionData &array) { size_t visitArray(const CollectionData &array) {
VariantSlot *slot = array.head(); VariantSlot *slot = array.head();
if (!slot) if (slot) {
return base::write("[]");
base::write("[\r\n"); base::write("[\r\n");
_nesting++; _nesting++;
while (slot != 0) { while (slot != 0) {
@@ -35,13 +33,15 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
_nesting--; _nesting--;
indent(); indent();
base::write("]"); base::write("]");
} else {
base::write("[]");
}
return this->bytesWritten();
} }
void visitObject(const CollectionData &object) { size_t visitObject(const CollectionData &object) {
VariantSlot *slot = object.head(); VariantSlot *slot = object.head();
if (!slot) if (slot) {
return base::write("{}");
base::write("{\r\n"); base::write("{\r\n");
_nesting++; _nesting++;
while (slot != 0) { while (slot != 0) {
@@ -56,6 +56,10 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
_nesting--; _nesting--;
indent(); indent();
base::write("}"); base::write("}");
} else {
base::write("{}");
}
return this->bytesWritten();
} }
private: private:

View File

@@ -12,17 +12,18 @@
#include <ArduinoJson/Numbers/Integer.hpp> #include <ArduinoJson/Numbers/Integer.hpp>
#include <ArduinoJson/Polyfills/assert.hpp> #include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/attributes.hpp> #include <ArduinoJson/Polyfills/attributes.hpp>
#include <ArduinoJson/Serialization/CountingDecorator.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename TWriter> template <typename TWriter>
class TextFormatter { class TextFormatter {
public: public:
explicit TextFormatter(TWriter writer) : _writer(writer), _length(0) {} explicit TextFormatter(TWriter writer) : _writer(writer) {}
// Returns the number of bytes sent to the TWriter implementation. // Returns the number of bytes sent to the TWriter implementation.
size_t bytesWritten() const { size_t bytesWritten() const {
return _length; return _writer.count();
} }
void writeBoolean(bool value) { void writeBoolean(bool value) {
@@ -128,28 +129,28 @@ class TextFormatter {
} }
void writeRaw(const char *s) { void writeRaw(const char *s) {
_length += _writer.write(reinterpret_cast<const uint8_t *>(s), strlen(s)); _writer.write(reinterpret_cast<const uint8_t *>(s), strlen(s));
} }
void writeRaw(const char *s, size_t n) { void writeRaw(const char *s, size_t n) {
_length += _writer.write(reinterpret_cast<const uint8_t *>(s), n); _writer.write(reinterpret_cast<const uint8_t *>(s), n);
} }
void writeRaw(const char *begin, const char *end) { void writeRaw(const char *begin, const char *end) {
_length += _writer.write(reinterpret_cast<const uint8_t *>(begin), _writer.write(reinterpret_cast<const uint8_t *>(begin),
static_cast<size_t>(end - begin)); static_cast<size_t>(end - begin));
} }
template <size_t N> template <size_t N>
void writeRaw(const char (&s)[N]) { void writeRaw(const char (&s)[N]) {
_length += _writer.write(reinterpret_cast<const uint8_t *>(s), N - 1); _writer.write(reinterpret_cast<const uint8_t *>(s), N - 1);
} }
void writeRaw(char c) { void writeRaw(char c) {
_length += _writer.write(static_cast<uint8_t>(c)); _writer.write(static_cast<uint8_t>(c));
} }
protected: protected:
TWriter _writer; CountingDecorator<TWriter> _writer;
size_t _length; size_t _length;
private: private:

View File

@@ -5,13 +5,14 @@
#pragma once #pragma once
#include <ArduinoJson/Memory/Alignment.hpp> #include <ArduinoJson/Memory/Alignment.hpp>
#include <ArduinoJson/Memory/StringSlot.hpp>
#include <ArduinoJson/Polyfills/assert.hpp> #include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/mpl/max.hpp> #include <ArduinoJson/Polyfills/mpl/max.hpp>
#include <ArduinoJson/Variant/VariantSlot.hpp> #include <ArduinoJson/Variant/VariantSlot.hpp>
#include <string.h> // memmove #include <string.h> // memmove
#define JSON_STRING_SIZE(SIZE) (SIZE + 1)
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
// _begin _end // _begin _end
@@ -28,7 +29,8 @@ class MemoryPool {
: _begin(buf), : _begin(buf),
_left(buf), _left(buf),
_right(buf ? buf + capa : 0), _right(buf ? buf + capa : 0),
_end(buf ? buf + capa : 0) { _end(buf ? buf + capa : 0),
_overflowed(false) {
ARDUINOJSON_ASSERT(isAligned(_begin)); ARDUINOJSON_ASSERT(isAligned(_begin));
ARDUINOJSON_ASSERT(isAligned(_right)); ARDUINOJSON_ASSERT(isAligned(_right));
ARDUINOJSON_ASSERT(isAligned(_end)); ARDUINOJSON_ASSERT(isAligned(_end));
@@ -47,6 +49,10 @@ class MemoryPool {
return size_t(_left - _begin + _end - _right); return size_t(_left - _begin + _end - _right);
} }
bool overflowed() const {
return _overflowed;
}
VariantSlot* allocVariant() { VariantSlot* allocVariant() {
return allocRight<VariantSlot>(); return allocRight<VariantSlot>();
} }
@@ -90,9 +96,14 @@ class MemoryPool {
return str; return str;
} }
void markAsOverflowed() {
_overflowed = true;
}
void clear() { void clear() {
_left = _begin; _left = _begin;
_right = _end; _right = _end;
_overflowed = false;
} }
bool canAlloc(size_t bytes) const { bool canAlloc(size_t bytes) const {
@@ -143,10 +154,6 @@ class MemoryPool {
} }
private: private:
StringSlot* allocStringSlot() {
return allocRight<StringSlot>();
}
void checkInvariants() { void checkInvariants() {
ARDUINOJSON_ASSERT(_begin <= _left); ARDUINOJSON_ASSERT(_begin <= _left);
ARDUINOJSON_ASSERT(_left <= _right); ARDUINOJSON_ASSERT(_left <= _right);
@@ -174,8 +181,10 @@ class MemoryPool {
#endif #endif
char* allocString(size_t n) { char* allocString(size_t n) {
if (!canAlloc(n)) if (!canAlloc(n)) {
_overflowed = true;
return 0; return 0;
}
char* s = _left; char* s = _left;
_left += n; _left += n;
checkInvariants(); checkInvariants();
@@ -188,13 +197,16 @@ class MemoryPool {
} }
void* allocRight(size_t bytes) { void* allocRight(size_t bytes) {
if (!canAlloc(bytes)) if (!canAlloc(bytes)) {
_overflowed = true;
return 0; return 0;
}
_right -= bytes; _right -= bytes;
return _right; return _right;
} }
char *_begin, *_left, *_right, *_end; char *_begin, *_left, *_right, *_end;
bool _overflowed;
}; };
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -1,19 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2020
// MIT License
#pragma once
#include <stddef.h> // for size_t
#include <ArduinoJson/Namespace.hpp>
#define JSON_STRING_SIZE(SIZE) (SIZE + 1)
namespace ARDUINOJSON_NAMESPACE {
struct StringSlot {
char *value;
size_t size;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -8,6 +8,11 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename TResult>
struct Visitor {
typedef TResult result_type;
};
struct Visitable { struct Visitable {
// template<Visitor> // template<Visitor>
// void accept(Visitor&) const; // void accept(Visitor&) const;

View File

@@ -21,121 +21,244 @@ class MsgPackDeserializer {
: _pool(&pool), : _pool(&pool),
_reader(reader), _reader(reader),
_stringStorage(stringStorage), _stringStorage(stringStorage),
_error(DeserializationError::Ok) {} _error(DeserializationError::Ok),
_foundSomething(false) {}
DeserializationError parse(VariantData &variant, AllowAllFilter, template <typename TFilter>
DeserializationError parse(VariantData &variant, TFilter filter,
NestingLimit nestingLimit) { NestingLimit nestingLimit) {
parseVariant(variant, nestingLimit); parseVariant(variant, filter, nestingLimit);
return _error; return _foundSomething ? _error : DeserializationError::EmptyInput;
} }
private: private:
bool parseVariant(VariantData &variant, NestingLimit nestingLimit) { // Prevent VS warning "assignment operator could not be generated"
uint8_t code; MsgPackDeserializer &operator=(const MsgPackDeserializer &);
if (!readByte(code)) {
_error = DeserializationError::IncompleteInput; bool invalidInput() {
_error = DeserializationError::InvalidInput;
return false; return false;
} }
if ((code & 0x80) == 0) { bool notSupported() {
variant.setUnsignedInteger(code); _error = DeserializationError::NotSupported;
return true; return false;
} }
if ((code & 0xe0) == 0xe0) { template <typename TFilter>
variant.setSignedInteger(static_cast<int8_t>(code)); bool parseVariant(VariantData &variant, TFilter filter,
return true; NestingLimit nestingLimit) {
} uint8_t code = 0;
if (!readByte(code))
return false;
if ((code & 0xe0) == 0xa0) { _foundSomething = true;
return readString(variant, code & 0x1f);
}
if ((code & 0xf0) == 0x90) { bool allowValue = filter.allowValue();
return readArray(variant.toArray(), code & 0x0F, nestingLimit);
}
if ((code & 0xf0) == 0x80) {
return readObject(variant.toObject(), code & 0x0F, nestingLimit);
}
switch (code) { switch (code) {
case 0xc0: case 0xc0:
// already null // already null
return true; return true;
case 0xc1:
return invalidInput();
case 0xc2: case 0xc2:
if (allowValue)
variant.setBoolean(false); variant.setBoolean(false);
return true; return true;
case 0xc3: case 0xc3:
if (allowValue)
variant.setBoolean(true); variant.setBoolean(true);
return true; return true;
case 0xcc: case 0xc4: // bin 8
return readInteger<uint8_t>(variant); if (allowValue)
return notSupported();
else
return skipString<uint8_t>();
case 0xcd: case 0xc5: // bin 16
return readInteger<uint16_t>(variant); if (allowValue)
return notSupported();
else
return skipString<uint16_t>();
case 0xce: case 0xc6: // bin 32
return readInteger<uint32_t>(variant); if (allowValue)
return notSupported();
else
return skipString<uint32_t>();
#if ARDUINOJSON_USE_LONG_LONG case 0xc7: // ext 8
case 0xcf: if (allowValue)
return readInteger<uint64_t>(variant); return notSupported();
#endif else
return skipExt<uint8_t>();
case 0xd0: case 0xc8: // ext 16
return readInteger<int8_t>(variant); if (allowValue)
return notSupported();
else
return skipExt<uint16_t>();
case 0xd1: case 0xc9: // ext 32
return readInteger<int16_t>(variant); if (allowValue)
return notSupported();
case 0xd2: else
return readInteger<int32_t>(variant); return skipExt<uint32_t>();
#if ARDUINOJSON_USE_LONG_LONG
case 0xd3:
return readInteger<int64_t>(variant);
#endif
case 0xca: case 0xca:
if (allowValue)
return readFloat<float>(variant); return readFloat<float>(variant);
else
return skipBytes(4);
case 0xcb: case 0xcb:
if (allowValue)
return readDouble<double>(variant); return readDouble<double>(variant);
else
return skipBytes(8);
case 0xcc:
if (allowValue)
return readInteger<uint8_t>(variant);
else
return skipBytes(1);
case 0xcd:
if (allowValue)
return readInteger<uint16_t>(variant);
else
return skipBytes(2);
case 0xce:
if (allowValue)
return readInteger<uint32_t>(variant);
else
return skipBytes(4);
case 0xcf:
if (allowValue)
#if ARDUINOJSON_USE_LONG_LONG
return readInteger<uint64_t>(variant);
#else
return notSupported();
#endif
else
return skipBytes(8);
case 0xd0:
if (allowValue)
return readInteger<int8_t>(variant);
else
return skipBytes(1);
case 0xd1:
if (allowValue)
return readInteger<int16_t>(variant);
else
return skipBytes(2);
case 0xd2:
if (allowValue)
return readInteger<int32_t>(variant);
else
return skipBytes(4);
case 0xd3:
if (allowValue)
#if ARDUINOJSON_USE_LONG_LONG
return readInteger<int64_t>(variant);
#else
return notSupported();
#endif
else
return skipBytes(8);
case 0xd4: // fixext 1
if (allowValue)
return notSupported();
else
return skipBytes(2);
case 0xd5: // fixext 2
if (allowValue)
return notSupported();
else
return skipBytes(3);
case 0xd6: // fixext 4
if (allowValue)
return notSupported();
else
return skipBytes(5);
case 0xd7: // fixext 8
if (allowValue)
return notSupported();
else
return skipBytes(9);
case 0xd8: // fixext 16
if (allowValue)
return notSupported();
else
return skipBytes(17);
case 0xd9: case 0xd9:
if (allowValue)
return readString<uint8_t>(variant); return readString<uint8_t>(variant);
else
return skipString<uint8_t>();
case 0xda: case 0xda:
if (allowValue)
return readString<uint16_t>(variant); return readString<uint16_t>(variant);
else
return skipString<uint16_t>();
case 0xdb: case 0xdb:
if (allowValue)
return readString<uint32_t>(variant); return readString<uint32_t>(variant);
else
return skipString<uint32_t>();
case 0xdc: case 0xdc:
return readArray<uint16_t>(variant.toArray(), nestingLimit); return readArray<uint16_t>(variant, filter, nestingLimit);
case 0xdd: case 0xdd:
return readArray<uint32_t>(variant.toArray(), nestingLimit); return readArray<uint32_t>(variant, filter, nestingLimit);
case 0xde: case 0xde:
return readObject<uint16_t>(variant.toObject(), nestingLimit); return readObject<uint16_t>(variant, filter, nestingLimit);
case 0xdf: case 0xdf:
return readObject<uint32_t>(variant.toObject(), nestingLimit); return readObject<uint32_t>(variant, filter, nestingLimit);
default:
_error = DeserializationError::NotSupported;
return false;
}
} }
private: switch (code & 0xf0) {
// Prevent VS warning "assignment operator could not be generated" case 0x80:
MsgPackDeserializer &operator=(const MsgPackDeserializer &); return readObject(variant, code & 0x0F, filter, nestingLimit);
case 0x90:
return readArray(variant, code & 0x0F, filter, nestingLimit);
}
if ((code & 0xe0) == 0xa0) {
if (allowValue)
return readString(variant, code & 0x1f);
else
return skipBytes(code & 0x1f);
}
if (allowValue)
variant.setInteger(static_cast<int8_t>(code));
return true;
}
bool readByte(uint8_t &value) { bool readByte(uint8_t &value) {
int c = _reader.read(); int c = _reader.read();
@@ -159,6 +282,16 @@ class MsgPackDeserializer {
return readBytes(reinterpret_cast<uint8_t *>(&value), sizeof(value)); return readBytes(reinterpret_cast<uint8_t *>(&value), sizeof(value));
} }
bool skipBytes(size_t n) {
for (; n; --n) {
if (_reader.read() < 0) {
_error = DeserializationError::IncompleteInput;
return false;
}
}
return true;
}
template <typename T> template <typename T>
bool readInteger(T &value) { bool readInteger(T &value) {
if (!readBytes(value)) if (!readBytes(value))
@@ -221,24 +354,31 @@ class MsgPackDeserializer {
} }
template <typename T> template <typename T>
bool readString(const char *&str) { bool readString() {
T size; T size;
if (!readInteger(size)) if (!readInteger(size))
return false; return false;
return readString(str, size); return readString(size);
}
template <typename T>
bool skipString() {
T size;
if (!readInteger(size))
return false;
return skipBytes(size);
} }
bool readString(VariantData &variant, size_t n) { bool readString(VariantData &variant, size_t n) {
const char *s = 0; // <- mute "maybe-uninitialized" (+4 bytes on AVR) if (!readString(n))
if (!readString(s, n))
return false; return false;
variant.setString(make_not_null(s), variant.setStringPointer(_stringStorage.save(),
typename TStringStorage::storage_policy()); typename TStringStorage::storage_policy());
return true; return true;
} }
bool readString(const char *&result, size_t n) { bool readString(size_t n) {
_stringStorage.startString(_pool); _stringStorage.startString();
for (; n; --n) { for (; n; --n) {
uint8_t c; uint8_t c;
if (!readBytes(c)) if (!readBytes(c))
@@ -251,131 +391,247 @@ class MsgPackDeserializer {
return false; return false;
} }
result = _stringStorage.save(_pool);
return true; return true;
} }
template <typename TSize> template <typename TSize, typename TFilter>
bool readArray(CollectionData &array, NestingLimit nestingLimit) { bool readArray(VariantData &variant, TFilter filter,
NestingLimit nestingLimit) {
TSize size; TSize size;
if (!readInteger(size)) if (!readInteger(size))
return false; return false;
return readArray(array, size, nestingLimit); return readArray(variant, size, filter, nestingLimit);
} }
bool readArray(CollectionData &array, size_t n, NestingLimit nestingLimit) { template <typename TFilter>
bool readArray(VariantData &variant, size_t n, TFilter filter,
NestingLimit nestingLimit) {
if (nestingLimit.reached()) { if (nestingLimit.reached()) {
_error = DeserializationError::TooDeep; _error = DeserializationError::TooDeep;
return false; return false;
} }
bool allowArray = filter.allowArray();
CollectionData *array = allowArray ? &variant.toArray() : 0;
TFilter memberFilter = filter[0U];
for (; n; --n) { for (; n; --n) {
VariantData *value = array.addElement(_pool); VariantData *value;
if (memberFilter.allow()) {
value = array->addElement(_pool);
if (!value) { if (!value) {
_error = DeserializationError::NoMemory; _error = DeserializationError::NoMemory;
return false; return false;
} }
} else {
value = 0;
}
if (!parseVariant(*value, nestingLimit.decrement())) if (!parseVariant(*value, memberFilter, nestingLimit.decrement()))
return false; return false;
} }
return true; return true;
} }
template <typename TSize> template <typename TSize, typename TFilter>
bool readObject(CollectionData &object, NestingLimit nestingLimit) { bool readObject(VariantData &variant, TFilter filter,
NestingLimit nestingLimit) {
TSize size; TSize size;
if (!readInteger(size)) if (!readInteger(size))
return false; return false;
return readObject(object, size, nestingLimit); return readObject(variant, size, filter, nestingLimit);
} }
bool readObject(CollectionData &object, size_t n, NestingLimit nestingLimit) { template <typename TFilter>
bool readObject(VariantData &variant, size_t n, TFilter filter,
NestingLimit nestingLimit) {
if (nestingLimit.reached()) { if (nestingLimit.reached()) {
_error = DeserializationError::TooDeep; _error = DeserializationError::TooDeep;
return false; return false;
} }
CollectionData *object = filter.allowObject() ? &variant.toObject() : 0;
for (; n; --n) { for (; n; --n) {
VariantSlot *slot = object.addSlot(_pool); if (!readKey())
return false;
const char *key = _stringStorage.c_str();
TFilter memberFilter = filter[key];
VariantData *member;
if (memberFilter.allow()) {
// Save key in memory pool.
// This MUST be done before adding the slot.
key = _stringStorage.save();
VariantSlot *slot = object->addSlot(_pool);
if (!slot) { if (!slot) {
_error = DeserializationError::NoMemory; _error = DeserializationError::NoMemory;
return false; return false;
} }
const char *key = 0; // <- mute "maybe-uninitialized" (+4 bytes on AVR)
if (!parseKey(key))
return false;
slot->setKey(key, typename TStringStorage::storage_policy()); slot->setKey(key, typename TStringStorage::storage_policy());
if (!parseVariant(*slot->data(), nestingLimit.decrement())) member = slot->data();
} else {
member = 0;
}
if (!parseVariant(*member, memberFilter, nestingLimit.decrement()))
return false; return false;
} }
return true; return true;
} }
bool parseKey(const char *&key) { bool readKey() {
uint8_t code; uint8_t code;
if (!readByte(code)) if (!readByte(code))
return false; return false;
if ((code & 0xe0) == 0xa0) if ((code & 0xe0) == 0xa0)
return readString(key, code & 0x1f); return readString(code & 0x1f);
switch (code) { switch (code) {
case 0xd9: case 0xd9:
return readString<uint8_t>(key); return readString<uint8_t>();
case 0xda: case 0xda:
return readString<uint16_t>(key); return readString<uint16_t>();
case 0xdb: case 0xdb:
return readString<uint32_t>(key); return readString<uint32_t>();
default: default:
_error = DeserializationError::NotSupported; return notSupported();
return false;
} }
} }
template <typename T>
bool skipExt() {
T size;
if (!readInteger(size))
return false;
return skipBytes(size + 1);
}
MemoryPool *_pool; MemoryPool *_pool;
TReader _reader; TReader _reader;
TStringStorage _stringStorage; TStringStorage _stringStorage;
DeserializationError _error; DeserializationError _error;
bool _foundSomething;
}; };
template <typename TInput> //
// deserializeMsgPack(JsonDocument&, const std::string&, ...)
//
// ... = NestingLimit
template <typename TString>
DeserializationError deserializeMsgPack( DeserializationError deserializeMsgPack(
JsonDocument &doc, const TInput &input, JsonDocument &doc, const TString &input,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, return deserialize<MsgPackDeserializer>(doc, input, nestingLimit,
AllowAllFilter()); AllowAllFilter());
} }
// ... = Filter, NestingLimit
template <typename TInput> template <typename TString>
DeserializationError deserializeMsgPack( DeserializationError deserializeMsgPack(
JsonDocument &doc, TInput *input, JsonDocument &doc, const TString &input, Filter filter,
NestingLimit nestingLimit = NestingLimit()) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
}
// ... = NestingLimit, Filter
template <typename TString>
DeserializationError deserializeMsgPack(JsonDocument &doc, const TString &input,
NestingLimit nestingLimit,
Filter filter) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
}
//
// deserializeMsgPack(JsonDocument&, std::istream&, ...)
//
// ... = NestingLimit
template <typename TStream>
DeserializationError deserializeMsgPack(
JsonDocument &doc, TStream &input,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, return deserialize<MsgPackDeserializer>(doc, input, nestingLimit,
AllowAllFilter()); AllowAllFilter());
} }
// ... = Filter, NestingLimit
template <typename TInput> template <typename TStream>
DeserializationError deserializeMsgPack( DeserializationError deserializeMsgPack(
JsonDocument &doc, TInput *input, size_t inputSize, JsonDocument &doc, TStream &input, Filter filter,
NestingLimit nestingLimit = NestingLimit()) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
}
// ... = NestingLimit, Filter
template <typename TStream>
DeserializationError deserializeMsgPack(JsonDocument &doc, TStream &input,
NestingLimit nestingLimit,
Filter filter) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
}
//
// deserializeMsgPack(JsonDocument&, char*, ...)
//
// ... = NestingLimit
template <typename TChar>
DeserializationError deserializeMsgPack(
JsonDocument &doc, TChar *input,
NestingLimit nestingLimit = NestingLimit()) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit,
AllowAllFilter());
}
// ... = Filter, NestingLimit
template <typename TChar>
DeserializationError deserializeMsgPack(
JsonDocument &doc, TChar *input, Filter filter,
NestingLimit nestingLimit = NestingLimit()) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
}
// ... = NestingLimit, Filter
template <typename TChar>
DeserializationError deserializeMsgPack(JsonDocument &doc, TChar *input,
NestingLimit nestingLimit,
Filter filter) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
}
//
// deserializeMsgPack(JsonDocument&, char*, size_t, ...)
//
// ... = NestingLimit
template <typename TChar>
DeserializationError deserializeMsgPack(
JsonDocument &doc, TChar *input, size_t inputSize,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit, return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit,
AllowAllFilter()); AllowAllFilter());
} }
// ... = Filter, NestingLimit
template <typename TInput> template <typename TChar>
DeserializationError deserializeMsgPack( DeserializationError deserializeMsgPack(
JsonDocument &doc, TInput &input, JsonDocument &doc, TChar *input, size_t inputSize, Filter filter,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit,
AllowAllFilter()); filter);
} }
// ... = NestingLimit, Filter
template <typename TChar>
DeserializationError deserializeMsgPack(JsonDocument &doc, TChar *input,
size_t inputSize,
NestingLimit nestingLimit,
Filter filter) {
return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit,
filter);
}
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -7,6 +7,7 @@
#include <ArduinoJson/MsgPack/endianess.hpp> #include <ArduinoJson/MsgPack/endianess.hpp>
#include <ArduinoJson/Polyfills/assert.hpp> #include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Serialization/CountingDecorator.hpp>
#include <ArduinoJson/Serialization/measure.hpp> #include <ArduinoJson/Serialization/measure.hpp>
#include <ArduinoJson/Serialization/serialize.hpp> #include <ArduinoJson/Serialization/serialize.hpp>
#include <ArduinoJson/Variant/VariantData.hpp> #include <ArduinoJson/Variant/VariantData.hpp>
@@ -14,19 +15,20 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename TWriter> template <typename TWriter>
class MsgPackSerializer { class MsgPackSerializer : public Visitor<size_t> {
public: public:
MsgPackSerializer(TWriter writer) : _writer(writer), _bytesWritten(0) {} MsgPackSerializer(TWriter writer) : _writer(writer) {}
template <typename T> template <typename T>
typename enable_if<sizeof(T) == 4>::type visitFloat(T value32) { typename enable_if<sizeof(T) == 4, size_t>::type visitFloat(T value32) {
writeByte(0xCA); writeByte(0xCA);
writeInteger(value32); writeInteger(value32);
return bytesWritten();
} }
template <typename T> template <typename T>
ARDUINOJSON_NO_SANITIZE("float-cast-overflow") ARDUINOJSON_NO_SANITIZE("float-cast-overflow")
typename enable_if<sizeof(T) == 8>::type visitFloat(T value64) { typename enable_if<sizeof(T) == 8, size_t>::type visitFloat(T value64) {
float value32 = float(value64); float value32 = float(value64);
if (value32 == value64) { if (value32 == value64) {
writeByte(0xCA); writeByte(0xCA);
@@ -35,9 +37,10 @@ class MsgPackSerializer {
writeByte(0xCB); writeByte(0xCB);
writeInteger(value64); writeInteger(value64);
} }
return bytesWritten();
} }
void visitArray(const CollectionData& array) { size_t visitArray(const CollectionData& array) {
size_t n = array.size(); size_t n = array.size();
if (n < 0x10) { if (n < 0x10) {
writeByte(uint8_t(0x90 + array.size())); writeByte(uint8_t(0x90 + array.size()));
@@ -51,9 +54,10 @@ class MsgPackSerializer {
for (VariantSlot* slot = array.head(); slot; slot = slot->next()) { for (VariantSlot* slot = array.head(); slot; slot = slot->next()) {
slot->data()->accept(*this); slot->data()->accept(*this);
} }
return bytesWritten();
} }
void visitObject(const CollectionData& object) { size_t visitObject(const CollectionData& object) {
size_t n = object.size(); size_t n = object.size();
if (n < 0x10) { if (n < 0x10) {
writeByte(uint8_t(0x80 + n)); writeByte(uint8_t(0x80 + n));
@@ -68,9 +72,10 @@ class MsgPackSerializer {
visitString(slot->key()); visitString(slot->key());
slot->data()->accept(*this); slot->data()->accept(*this);
} }
return bytesWritten();
} }
void visitString(const char* value) { size_t visitString(const char* value) {
ARDUINOJSON_ASSERT(value != NULL); ARDUINOJSON_ASSERT(value != NULL);
size_t n = strlen(value); size_t n = strlen(value);
@@ -88,13 +93,15 @@ class MsgPackSerializer {
writeInteger(uint32_t(n)); writeInteger(uint32_t(n));
} }
writeBytes(reinterpret_cast<const uint8_t*>(value), n); writeBytes(reinterpret_cast<const uint8_t*>(value), n);
return bytesWritten();
} }
void visitRawJson(const char* data, size_t size) { size_t visitRawJson(const char* data, size_t size) {
writeBytes(reinterpret_cast<const uint8_t*>(data), size); writeBytes(reinterpret_cast<const uint8_t*>(data), size);
return bytesWritten();
} }
void visitNegativeInteger(UInt value) { size_t visitNegativeInteger(UInt value) {
UInt negated = UInt(~value + 1); UInt negated = UInt(~value + 1);
if (value <= 0x20) { if (value <= 0x20) {
writeInteger(int8_t(negated)); writeInteger(int8_t(negated));
@@ -114,9 +121,10 @@ class MsgPackSerializer {
writeInteger(int64_t(negated)); writeInteger(int64_t(negated));
} }
#endif #endif
return bytesWritten();
} }
void visitPositiveInteger(UInt value) { size_t visitPositiveInteger(UInt value) {
if (value <= 0x7F) { if (value <= 0x7F) {
writeInteger(uint8_t(value)); writeInteger(uint8_t(value));
} else if (value <= 0xFF) { } else if (value <= 0xFF) {
@@ -141,27 +149,30 @@ class MsgPackSerializer {
writeInteger(uint64_t(value)); writeInteger(uint64_t(value));
} }
#endif #endif
return bytesWritten();
} }
void visitBoolean(bool value) { size_t visitBoolean(bool value) {
writeByte(value ? 0xC3 : 0xC2); writeByte(value ? 0xC3 : 0xC2);
return bytesWritten();
} }
void visitNull() { size_t visitNull() {
writeByte(0xC0); writeByte(0xC0);
} return bytesWritten();
size_t bytesWritten() const {
return _bytesWritten;
} }
private: private:
size_t bytesWritten() const {
return _writer.count();
}
void writeByte(uint8_t c) { void writeByte(uint8_t c) {
_bytesWritten += _writer.write(c); _writer.write(c);
} }
void writeBytes(const uint8_t* p, size_t n) { void writeBytes(const uint8_t* p, size_t n) {
_bytesWritten += _writer.write(p, n); _writer.write(p, n);
} }
template <typename T> template <typename T>
@@ -170,8 +181,7 @@ class MsgPackSerializer {
writeBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value)); writeBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
} }
TWriter _writer; CountingDecorator<TWriter> _writer;
size_t _bytesWritten;
}; };
template <typename TSource, typename TDestination> template <typename TSource, typename TDestination>

View File

@@ -5,42 +5,19 @@
#pragma once #pragma once
#include <ArduinoJson/Configuration.hpp> #include <ArduinoJson/Configuration.hpp>
#include <ArduinoJson/Polyfills/preprocessor.hpp>
#include <ArduinoJson/version.hpp> #include <ArduinoJson/version.hpp>
#ifndef ARDUINOJSON_NAMESPACE #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 \ #define ARDUINOJSON_NAMESPACE \
ARDUINOJSON_CONCAT4( \ ARDUINOJSON_CONCAT4( \
ARDUINOJSON_CONCAT4(ArduinoJson, ARDUINOJSON_VERSION_MAJOR, \ ARDUINOJSON_CONCAT4(ArduinoJson, ARDUINOJSON_VERSION_MAJOR, \
ARDUINOJSON_VERSION_MINOR, \ ARDUINOJSON_VERSION_MINOR, \
ARDUINOJSON_VERSION_REVISION), \ ARDUINOJSON_VERSION_REVISION), \
_, \ _, \
ARDUINOJSON_HEX_DIGIT(0, ARDUINOJSON_USE_LONG_LONG, \ ARDUINOJSON_HEX_DIGIT(ARDUINOJSON_ENABLE_PROGMEM, \
ARDUINOJSON_USE_DOUBLE, \ ARDUINOJSON_USE_LONG_LONG, ARDUINOJSON_USE_DOUBLE, \
ARDUINOJSON_ENABLE_STRING_DEDUPLICATION), \ ARDUINOJSON_ENABLE_STRING_DEDUPLICATION), \
ARDUINOJSON_HEX_DIGIT( \ ARDUINOJSON_HEX_DIGIT( \
ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY, \ ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY, \

View File

@@ -10,6 +10,8 @@
#include <ArduinoJson/Configuration.hpp> #include <ArduinoJson/Configuration.hpp>
#include <ArduinoJson/Polyfills/alias_cast.hpp> #include <ArduinoJson/Polyfills/alias_cast.hpp>
#include <ArduinoJson/Polyfills/math.hpp> #include <ArduinoJson/Polyfills/math.hpp>
#include <ArduinoJson/Polyfills/preprocessor.hpp>
#include <ArduinoJson/Polyfills/static_array.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
@@ -46,48 +48,60 @@ struct FloatTraits<T, 8 /*64bits*/> {
} }
static T positiveBinaryPowerOfTen(int index) { static T positiveBinaryPowerOfTen(int index) {
static T factors[] = { ARDUINOJSON_DEFINE_STATIC_ARRAY( //
1e1, uint32_t, factors,
1e2, ARDUINOJSON_EXPAND18({
1e4, 0x40240000, 0x00000000, // 1e1
1e8, 0x40590000, 0x00000000, // 1e2
1e16, 0x40C38800, 0x00000000, // 1e4
forge(0x4693B8B5, 0xB5056E17), // 1e32 0x4197D784, 0x00000000, // 1e8
forge(0x4D384F03, 0xE93FF9F5), // 1e64 0x4341C379, 0x37E08000, // 1e16
forge(0x5A827748, 0xF9301D32), // 1e128 0x4693B8B5, 0xB5056E17, // 1e32
forge(0x75154FDD, 0x7F73BF3C) // 1e256 0x4D384F03, 0xE93FF9F5, // 1e64
}; 0x5A827748, 0xF9301D32, // 1e128
return factors[index]; 0x75154FDD, 0x7F73BF3C // 1e256
}));
return forge(
ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index),
ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1));
} }
static T negativeBinaryPowerOfTen(int index) { static T negativeBinaryPowerOfTen(int index) {
static T factors[] = { ARDUINOJSON_DEFINE_STATIC_ARRAY( //
forge(0x3FB99999, 0x9999999A), // 1e-1 uint32_t, factors,
forge(0x3F847AE1, 0x47AE147B), // 1e-2 ARDUINOJSON_EXPAND18({
forge(0x3F1A36E2, 0xEB1C432D), // 1e-4 0x3FB99999, 0x9999999A, // 1e-1
forge(0x3E45798E, 0xE2308C3A), // 1e-8 0x3F847AE1, 0x47AE147B, // 1e-2
forge(0x3C9CD2B2, 0x97D889BC), // 1e-16 0x3F1A36E2, 0xEB1C432D, // 1e-4
forge(0x3949F623, 0xD5A8A733), // 1e-32 0x3E45798E, 0xE2308C3A, // 1e-8
forge(0x32A50FFD, 0x44F4A73D), // 1e-64 0x3C9CD2B2, 0x97D889BC, // 1e-16
forge(0x255BBA08, 0xCF8C979D), // 1e-128 0x3949F623, 0xD5A8A733, // 1e-32
forge(0x0AC80628, 0x64AC6F43) // 1e-256 0x32A50FFD, 0x44F4A73D, // 1e-64
}; 0x255BBA08, 0xCF8C979D, // 1e-128
return factors[index]; 0x0AC80628, 0x64AC6F43 // 1e-256
}));
return forge(
ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index),
ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1));
} }
static T negativeBinaryPowerOfTenPlusOne(int index) { static T negativeBinaryPowerOfTenPlusOne(int index) {
static T factors[] = { ARDUINOJSON_DEFINE_STATIC_ARRAY( //
1e0, uint32_t, factors,
forge(0x3FB99999, 0x9999999A), // 1e-1 ARDUINOJSON_EXPAND18({
forge(0x3F50624D, 0xD2F1A9FC), // 1e-3 0x3FF00000, 0x00000000, // 1e0
forge(0x3E7AD7F2, 0x9ABCAF48), // 1e-7 0x3FB99999, 0x9999999A, // 1e-1
forge(0x3CD203AF, 0x9EE75616), // 1e-15 0x3F50624D, 0xD2F1A9FC, // 1e-3
forge(0x398039D6, 0x65896880), // 1e-31 0x3E7AD7F2, 0x9ABCAF48, // 1e-7
forge(0x32DA53FC, 0x9631D10D), // 1e-63 0x3CD203AF, 0x9EE75616, // 1e-15
forge(0x25915445, 0x81B7DEC2), // 1e-127 0x398039D6, 0x65896880, // 1e-31
forge(0x0AFE07B2, 0x7DD78B14) // 1e-255 0x32DA53FC, 0x9631D10D, // 1e-63
}; 0x25915445, 0x81B7DEC2, // 1e-127
return factors[index]; 0x0AFE07B2, 0x7DD78B14 // 1e-255
}));
return forge(
ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index),
ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1));
} }
static T nan() { static T nan() {
@@ -144,18 +158,24 @@ struct FloatTraits<T, 4 /*32bits*/> {
} }
static T positiveBinaryPowerOfTen(int index) { static T positiveBinaryPowerOfTen(int index) {
static T factors[] = {1e1f, 1e2f, 1e4f, 1e8f, 1e16f, 1e32f}; ARDUINOJSON_DEFINE_STATIC_ARRAY(
return factors[index]; T, factors,
ARDUINOJSON_EXPAND6({1e1f, 1e2f, 1e4f, 1e8f, 1e16f, 1e32f}));
return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index);
} }
static T negativeBinaryPowerOfTen(int index) { static T negativeBinaryPowerOfTen(int index) {
static T factors[] = {1e-1f, 1e-2f, 1e-4f, 1e-8f, 1e-16f, 1e-32f}; ARDUINOJSON_DEFINE_STATIC_ARRAY(
return factors[index]; T, factors,
ARDUINOJSON_EXPAND6({1e-1f, 1e-2f, 1e-4f, 1e-8f, 1e-16f, 1e-32f}));
return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index);
} }
static T negativeBinaryPowerOfTenPlusOne(int index) { static T negativeBinaryPowerOfTenPlusOne(int index) {
static T factors[] = {1e0f, 1e-1f, 1e-3f, 1e-7f, 1e-15f, 1e-31f}; ARDUINOJSON_DEFINE_STATIC_ARRAY(
return factors[index]; T, factors,
ARDUINOJSON_EXPAND6({1e0f, 1e-1f, 1e-3f, 1e-7f, 1e-15f, 1e-31f}));
return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index);
} }
static T forge(uint32_t bits) { static T forge(uint32_t bits) {

View File

@@ -1,20 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2020
// MIT License
#pragma once
#include <ArduinoJson/Numbers/convertNumber.hpp>
#include <ArduinoJson/Numbers/parseNumber.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename T>
inline T parseFloat(const char* s) {
// try to reuse the same parameters as JsonDeserializer
typedef typename choose_largest<Float, T>::type TFloat;
ParsedNumber<TFloat, UInt> value;
parseNumber(s, value);
return value.template as<T>();
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -1,21 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2020
// MIT License
#pragma once
#include <ArduinoJson/Numbers/convertNumber.hpp>
#include <ArduinoJson/Numbers/parseNumber.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename T>
T parseInteger(const char *s) {
// try to reuse the same parameters as JsonDeserializer
typedef typename choose_largest<UInt, typename make_unsigned<T>::type>::type
TUInt;
ParsedNumber<Float, TUInt> value;
parseNumber(s, value);
return value.template as<T>();
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -10,59 +10,18 @@
#include <ArduinoJson/Polyfills/ctype.hpp> #include <ArduinoJson/Polyfills/ctype.hpp>
#include <ArduinoJson/Polyfills/math.hpp> #include <ArduinoJson/Polyfills/math.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Variant/VariantContent.hpp> #include <ArduinoJson/Variant/VariantAs.hpp>
#include <ArduinoJson/Variant/VariantData.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename TFloat, typename TUInt>
struct ParsedNumber {
ParsedNumber() : _type(VALUE_IS_NULL) {}
void setInteger(TUInt value, bool is_negative) {
uintValue = value;
_type = uint8_t(is_negative ? VALUE_IS_NEGATIVE_INTEGER
: VALUE_IS_POSITIVE_INTEGER);
}
void setFloat(TFloat value) {
floatValue = value;
_type = VALUE_IS_FLOAT;
}
template <typename T>
T as() const {
switch (_type) {
case VALUE_IS_NEGATIVE_INTEGER:
return convertNegativeInteger<T>(uintValue);
case VALUE_IS_POSITIVE_INTEGER:
return convertPositiveInteger<T>(uintValue);
case VALUE_IS_FLOAT:
return convertFloat<T>(floatValue);
default:
return 0;
}
}
uint8_t type() const {
return _type;
}
union {
TUInt uintValue;
TFloat floatValue;
};
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> inline bool parseNumber(const char* s, VariantData& result) {
inline void parseNumber(const char* s, ParsedNumber<TFloat, TUInt>& result) { typedef FloatTraits<Float> traits;
typedef FloatTraits<TFloat> traits; typedef choose_largest<traits::mantissa_type, UInt>::type mantissa_t;
typedef typename choose_largest<typename traits::mantissa_type, TUInt>::type typedef traits::exponent_type exponent_t;
mantissa_t;
typedef typename traits::exponent_type exponent_t;
ARDUINOJSON_ASSERT(s != 0); ARDUINOJSON_ASSERT(s != 0);
@@ -80,24 +39,23 @@ inline void parseNumber(const char* s, ParsedNumber<TFloat, TUInt>& result) {
#if ARDUINOJSON_ENABLE_NAN #if ARDUINOJSON_ENABLE_NAN
if (*s == 'n' || *s == 'N') { if (*s == 'n' || *s == 'N') {
result.setFloat(traits::nan()); result.setFloat(traits::nan());
return; return true;
} }
#endif #endif
#if ARDUINOJSON_ENABLE_INFINITY #if ARDUINOJSON_ENABLE_INFINITY
if (*s == 'i' || *s == 'I') { if (*s == 'i' || *s == 'I') {
result.setFloat(is_negative ? -traits::inf() : traits::inf()); result.setFloat(is_negative ? -traits::inf() : traits::inf());
return; return true;
} }
#endif #endif
if (!isdigit(*s) && *s != '.') if (!isdigit(*s) && *s != '.')
return; return false;
mantissa_t mantissa = 0; mantissa_t mantissa = 0;
exponent_t exponent_offset = 0; exponent_t exponent_offset = 0;
const mantissa_t maxUint = TUInt(-1); const mantissa_t maxUint = UInt(-1);
while (isdigit(*s)) { while (isdigit(*s)) {
uint8_t digit = uint8_t(*s - '0'); uint8_t digit = uint8_t(*s - '0');
@@ -111,8 +69,11 @@ inline void parseNumber(const char* s, ParsedNumber<TFloat, TUInt>& result) {
} }
if (*s == '\0') { if (*s == '\0') {
result.setInteger(TUInt(mantissa), is_negative); if (is_negative)
return; result.setNegativeInteger(UInt(mantissa));
else
result.setPositiveInteger(UInt(mantissa));
return true;
} }
// avoid mantissa overflow // avoid mantissa overflow
@@ -156,7 +117,7 @@ inline void parseNumber(const char* s, ParsedNumber<TFloat, TUInt>& result) {
result.setFloat(is_negative ? -0.0f : 0.0f); result.setFloat(is_negative ? -0.0f : 0.0f);
else else
result.setFloat(is_negative ? -traits::inf() : traits::inf()); result.setFloat(is_negative ? -traits::inf() : traits::inf());
return; return true;
} }
s++; s++;
} }
@@ -167,11 +128,20 @@ inline void parseNumber(const char* s, ParsedNumber<TFloat, TUInt>& result) {
// 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 false;
TFloat final_result = Float final_result =
traits::make_float(static_cast<TFloat>(mantissa), exponent); traits::make_float(static_cast<Float>(mantissa), exponent);
result.setFloat(is_negative ? -final_result : final_result); result.setFloat(is_negative ? -final_result : final_result);
return true;
}
template <typename T>
inline T parseNumber(const char* s) {
VariantData value;
value.init(); // VariantData is a POD, so it has no constructor
parseNumber(s, value);
return variantAs<T>(&value);
} }
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -120,8 +120,8 @@ class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >,
return getOrAddUpstreamMember().set(value); return getOrAddUpstreamMember().set(value);
} }
template <typename Visitor> template <typename TVisitor>
void accept(Visitor &visitor) const { typename TVisitor::result_type accept(TVisitor &visitor) const {
return getUpstreamMember().accept(visitor); return getUpstreamMember().accept(visitor);
} }

View File

@@ -8,12 +8,13 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename Visitor> template <typename TVisitor>
void objectAccept(const CollectionData *obj, Visitor &visitor) { typename TVisitor::result_type objectAccept(const CollectionData *obj,
TVisitor &visitor) {
if (obj) if (obj)
visitor.visitObject(*obj); return visitor.visitObject(*obj);
else else
visitor.visitNull(); return visitor.visitNull();
} }
inline bool objectEquals(const CollectionData *lhs, const CollectionData *rhs) { inline bool objectEquals(const CollectionData *lhs, const CollectionData *rhs) {

View File

@@ -22,9 +22,9 @@ class ObjectRefBase {
return VariantConstRef(reinterpret_cast<const VariantData*>(data)); return VariantConstRef(reinterpret_cast<const VariantData*>(data));
} }
template <typename Visitor> template <typename TVisitor>
FORCE_INLINE void accept(Visitor& visitor) const { typename TVisitor::result_type accept(TVisitor& visitor) const {
objectAccept(_data, visitor); return objectAccept(_data, visitor);
} }
FORCE_INLINE bool isNull() const { FORCE_INLINE bool isNull() const {

View File

@@ -1,34 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2020
// MIT License
#pragma once
#include <ArduinoJson/Namespace.hpp>
#include <ArduinoJson/Polyfills/assert.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename T>
class not_null {
public:
explicit not_null(T ptr) : _ptr(ptr) {
ARDUINOJSON_ASSERT(ptr != NULL);
}
T get() const {
ARDUINOJSON_ASSERT(_ptr != NULL);
return _ptr;
}
private:
T _ptr;
};
template <typename T>
not_null<T> make_not_null(T ptr) {
ARDUINOJSON_ASSERT(ptr != NULL);
return not_null<T>(ptr);
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -4,6 +4,7 @@
#pragma once #pragma once
#include <ArduinoJson/Configuration.hpp>
#include <ArduinoJson/Namespace.hpp> #include <ArduinoJson/Namespace.hpp>
#include <ArduinoJson/Polyfills/assert.hpp> #include <ArduinoJson/Polyfills/assert.hpp>

View File

@@ -0,0 +1,32 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2020
// MIT License
#pragma once
#include <ArduinoJson/Namespace.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename T>
typename enable_if<is_pointer<T>::value, T>::type pgm_read(const void* p) {
return reinterpret_cast<T>(pgm_read_ptr(p));
}
template <typename T>
typename enable_if<is_floating_point<T>::value &&
sizeof(T) == sizeof(float), // on AVR sizeof(double) ==
// sizeof(float)
T>::type
pgm_read(const void* p) {
return pgm_read_float(p);
}
template <typename T>
typename enable_if<is_same<T, uint32_t>::value, T>::type pgm_read(
const void* p) {
return pgm_read_dword(p);
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -0,0 +1,36 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2020
// MIT License
#pragma once
#define ARDUINOJSON_EXPAND6(a, b, c, d, e, f) a, b, c, d, e, f
#define ARDUINOJSON_EXPAND7(a, b, c, d, e, f, g) a, b, c, d, e, f, g
#define ARDUINOJSON_EXPAND9(a, b, c, d, e, f, g, h, i) a, b, c, d, e, f, g, h, i
#define ARDUINOJSON_EXPAND18(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, \
q, r) \
a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r
#define ARDUINOJSON_CONCAT_(A, B) A##B
#define ARDUINOJSON_CONCAT2(A, B) ARDUINOJSON_CONCAT_(A, B)
#define ARDUINOJSON_CONCAT4(A, B, C, D) \
ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT2(A, B), ARDUINOJSON_CONCAT2(C, D))
#define ARDUINOJSON_HEX_DIGIT_0000() 0
#define ARDUINOJSON_HEX_DIGIT_0001() 1
#define ARDUINOJSON_HEX_DIGIT_0010() 2
#define ARDUINOJSON_HEX_DIGIT_0011() 3
#define ARDUINOJSON_HEX_DIGIT_0100() 4
#define ARDUINOJSON_HEX_DIGIT_0101() 5
#define ARDUINOJSON_HEX_DIGIT_0110() 6
#define ARDUINOJSON_HEX_DIGIT_0111() 7
#define ARDUINOJSON_HEX_DIGIT_1000() 8
#define ARDUINOJSON_HEX_DIGIT_1001() 9
#define ARDUINOJSON_HEX_DIGIT_1010() A
#define ARDUINOJSON_HEX_DIGIT_1011() B
#define ARDUINOJSON_HEX_DIGIT_1100() C
#define ARDUINOJSON_HEX_DIGIT_1101() D
#define ARDUINOJSON_HEX_DIGIT_1110() E
#define ARDUINOJSON_HEX_DIGIT_1111() F
#define ARDUINOJSON_HEX_DIGIT_(A, B, C, D) ARDUINOJSON_HEX_DIGIT_##A##B##C##D()
#define ARDUINOJSON_HEX_DIGIT(A, B, C, D) ARDUINOJSON_HEX_DIGIT_(A, B, C, D)

View File

@@ -0,0 +1,34 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2020
// MIT License
#pragma once
#include <ArduinoJson/Configuration.hpp>
#if ARDUINOJSON_ENABLE_PROGMEM
#include <ArduinoJson/Polyfills/pgmspace_generic.hpp>
#ifndef ARDUINOJSON_DEFINE_STATIC_ARRAY
#define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) \
static type const name[] PROGMEM = value;
#endif
#ifndef ARDUINOJSON_READ_STATIC_ARRAY
#define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) \
pgm_read<type>(name + index)
#endif
#else // i.e. ARDUINOJSON_ENABLE_PROGMEM == 0
#ifndef ARDUINOJSON_DEFINE_STATIC_ARRAY
#define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) \
static type const name[] = value;
#endif
#ifndef ARDUINOJSON_READ_STATIC_ARRAY
#define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) name[index]
#endif
#endif

View File

@@ -15,6 +15,7 @@
#include "type_traits/is_enum.hpp" #include "type_traits/is_enum.hpp"
#include "type_traits/is_floating_point.hpp" #include "type_traits/is_floating_point.hpp"
#include "type_traits/is_integral.hpp" #include "type_traits/is_integral.hpp"
#include "type_traits/is_pointer.hpp"
#include "type_traits/is_same.hpp" #include "type_traits/is_same.hpp"
#include "type_traits/is_signed.hpp" #include "type_traits/is_signed.hpp"
#include "type_traits/is_unsigned.hpp" #include "type_traits/is_unsigned.hpp"

View File

@@ -0,0 +1,16 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2020
// MIT License
#pragma once
#include "integral_constant.hpp"
namespace ARDUINOJSON_NAMESPACE {
template <typename T>
struct is_pointer : false_type {};
template <typename T>
struct is_pointer<T*> : true_type {};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -0,0 +1,33 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2020
// MIT License
#pragma once
#include <ArduinoJson/Namespace.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename TWriter>
class CountingDecorator {
public:
explicit CountingDecorator(TWriter& writer) : _writer(writer), _count(0) {}
void write(uint8_t c) {
_count += _writer.write(c);
}
void write(const uint8_t* s, size_t n) {
_count += _writer.write(s, n);
}
size_t count() const {
return _count;
}
private:
TWriter _writer;
size_t _count;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -4,7 +4,7 @@
#pragma once #pragma once
#include <WString.h> #include <Arduino.h>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {

View File

@@ -12,8 +12,7 @@ template <template <typename> class TSerializer, typename TSource>
size_t measure(const TSource &source) { size_t measure(const TSource &source) {
DummyWriter dp; DummyWriter dp;
TSerializer<DummyWriter> serializer(dp); TSerializer<DummyWriter> serializer(dp);
source.accept(serializer); return source.accept(serializer);
return serializer.bytesWritten();
} }
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -12,8 +12,7 @@ template <template <typename> class TSerializer, typename TSource,
typename TWriter> typename TWriter>
size_t doSerialize(const TSource &source, TWriter writer) { size_t doSerialize(const TSource &source, TWriter writer) {
TSerializer<TWriter> serializer(writer); TSerializer<TWriter> serializer(writer);
source.accept(serializer); return source.accept(serializer);
return serializer.bytesWritten();
} }
template <template <typename> class TSerializer, typename TSource, template <template <typename> class TSerializer, typename TSource,

View File

@@ -10,14 +10,16 @@ namespace ARDUINOJSON_NAMESPACE {
class StringCopier { class StringCopier {
public: public:
void startString(MemoryPool* pool) { StringCopier(MemoryPool& pool) : _pool(&pool) {}
pool->getFreeZone(&_ptr, &_capacity);
void startString() {
_pool->getFreeZone(&_ptr, &_capacity);
_size = 0; _size = 0;
} }
const char* save(MemoryPool* pool) { const char* save() {
ARDUINOJSON_ASSERT(_ptr); ARDUINOJSON_ASSERT(_ptr);
return pool->saveStringFromFreeZone(_size); return _pool->saveStringFromFreeZone(_size);
} }
void append(const char* s) { void append(const char* s) {
@@ -34,6 +36,7 @@ class StringCopier {
if (_size >= _capacity) { if (_size >= _capacity) {
_ptr = 0; _ptr = 0;
_pool->markAsOverflowed();
return; return;
} }
@@ -51,6 +54,7 @@ class StringCopier {
typedef storage_policies::store_by_copy storage_policy; typedef storage_policies::store_by_copy storage_policy;
private: private:
MemoryPool* _pool;
char* _ptr; char* _ptr;
size_t _size; size_t _size;
size_t _capacity; size_t _capacity;

View File

@@ -13,11 +13,11 @@ class StringMover {
public: public:
StringMover(char* ptr) : _writePtr(ptr) {} StringMover(char* ptr) : _writePtr(ptr) {}
void startString(MemoryPool*) { void startString() {
_startPtr = _writePtr; _startPtr = _writePtr;
} }
const char* save(MemoryPool*) const { const char* save() const {
return _startPtr; return _startPtr;
} }

View File

@@ -9,32 +9,15 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename TInput, typename Enable = void>
struct StringStorage {
typedef StringCopier type;
static type create(TInput&) {
return type();
}
};
template <typename TChar>
struct StringStorage<TChar*,
typename enable_if<!is_const<TChar>::value>::type> {
typedef StringMover type;
static type create(TChar* input) {
return type(reinterpret_cast<char*>(input));
}
};
template <typename TInput> template <typename TInput>
typename StringStorage<TInput>::type makeStringStorage(TInput& input) { StringCopier makeStringStorage(TInput&, MemoryPool& pool) {
return StringStorage<TInput>::create(input); return StringCopier(pool);
} }
template <typename TChar> template <typename TChar>
typename StringStorage<TChar*>::type makeStringStorage(TChar* input) { StringMover makeStringStorage(
return StringStorage<TChar*>::create(input); TChar* input, MemoryPool&,
typename enable_if<!is_const<TChar>::value>::type* = 0) {
return StringMover(reinterpret_cast<char*>(input));
} }
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -4,7 +4,7 @@
#pragma once #pragma once
#include <WString.h> #include <Arduino.h>
#include <ArduinoJson/Polyfills/safe_strcmp.hpp> #include <ArduinoJson/Polyfills/safe_strcmp.hpp>
#include <ArduinoJson/Strings/IsString.hpp> #include <ArduinoJson/Strings/IsString.hpp>

View File

@@ -8,7 +8,7 @@
#include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp>
#if ARDUINOJSON_ENABLE_ARDUINO_STRING #if ARDUINOJSON_ENABLE_ARDUINO_STRING
#include <WString.h> #include <Arduino.h>
#endif #endif
#if ARDUINOJSON_ENABLE_STD_STRING #if ARDUINOJSON_ENABLE_STD_STRING

View File

@@ -13,9 +13,9 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename TString> template <typename TString>
class StlStringAdapter { class StdStringAdapter {
public: public:
StlStringAdapter(const TString& str) : _str(&str) {} StdStringAdapter(const TString& str) : _str(&str) {}
void copyTo(char* p, size_t n) const { void copyTo(char* p, size_t n) const {
memcpy(p, _str->c_str(), n); memcpy(p, _str->c_str(), n);
@@ -56,9 +56,9 @@ struct IsString<std::basic_string<char, TCharTraits, TAllocator> > : true_type {
}; };
template <typename TCharTraits, typename TAllocator> template <typename TCharTraits, typename TAllocator>
inline StlStringAdapter<std::basic_string<char, TCharTraits, TAllocator> > inline StdStringAdapter<std::basic_string<char, TCharTraits, TAllocator> >
adaptString(const std::basic_string<char, TCharTraits, TAllocator>& str) { adaptString(const std::basic_string<char, TCharTraits, TAllocator>& str) {
return StlStringAdapter<std::basic_string<char, TCharTraits, TAllocator> >( return StdStringAdapter<std::basic_string<char, TCharTraits, TAllocator> >(
str); str);
} }

View File

@@ -9,7 +9,7 @@
#include <ArduinoJson/Strings/SizedRamStringAdapter.hpp> #include <ArduinoJson/Strings/SizedRamStringAdapter.hpp>
#if ARDUINOJSON_ENABLE_STD_STRING #if ARDUINOJSON_ENABLE_STD_STRING
#include <ArduinoJson/Strings/StlStringAdapter.hpp> #include <ArduinoJson/Strings/StdStringAdapter.hpp>
#endif #endif
#if ARDUINOJSON_ENABLE_ARDUINO_STRING #if ARDUINOJSON_ENABLE_ARDUINO_STRING

View File

@@ -14,20 +14,34 @@ namespace ARDUINOJSON_NAMESPACE {
class CollectionData; class CollectionData;
struct ComparerBase { struct ComparerBase : Visitor<CompareResult> {
CompareResult result; CompareResult visitArray(const CollectionData &) {
return COMPARE_RESULT_DIFFER;
ComparerBase() : result(COMPARE_RESULT_DIFFER) {} }
CompareResult visitBoolean(bool) {
void visitArray(const CollectionData &) {} return COMPARE_RESULT_DIFFER;
void visitBoolean(bool) {} }
void visitFloat(Float) {} CompareResult visitFloat(Float) {
void visitNegativeInteger(UInt) {} return COMPARE_RESULT_DIFFER;
void visitNull() {} }
void visitObject(const CollectionData &) {} CompareResult visitNegativeInteger(UInt) {
void visitPositiveInteger(UInt) {} return COMPARE_RESULT_DIFFER;
void visitRawJson(const char *, size_t) {} }
void visitString(const char *) {} CompareResult visitNull() {
return COMPARE_RESULT_DIFFER;
}
CompareResult visitObject(const CollectionData &) {
return COMPARE_RESULT_DIFFER;
}
CompareResult visitPositiveInteger(UInt) {
return COMPARE_RESULT_DIFFER;
}
CompareResult visitRawJson(const char *, size_t) {
return COMPARE_RESULT_DIFFER;
}
CompareResult visitString(const char *) {
return COMPARE_RESULT_DIFFER;
}
}; };
template <typename T, typename Enable = void> template <typename T, typename Enable = void>
@@ -40,19 +54,21 @@ struct Comparer<T, typename enable_if<IsString<T>::value>::type>
explicit Comparer(T value) : rhs(value) {} explicit Comparer(T value) : rhs(value) {}
void visitString(const char *lhs) { CompareResult visitString(const char *lhs) {
int i = adaptString(rhs).compare(lhs); int i = adaptString(rhs).compare(lhs);
if (i < 0) if (i < 0)
result = COMPARE_RESULT_GREATER; return COMPARE_RESULT_GREATER;
else if (i > 0) else if (i > 0)
result = COMPARE_RESULT_LESS; return COMPARE_RESULT_LESS;
else else
result = COMPARE_RESULT_EQUAL; return COMPARE_RESULT_EQUAL;
} }
void visitNull() { CompareResult visitNull() {
if (adaptString(rhs).isNull()) if (adaptString(rhs).isNull())
result = COMPARE_RESULT_EQUAL; return COMPARE_RESULT_EQUAL;
else
return COMPARE_RESULT_DIFFER;
} }
}; };
@@ -64,26 +80,26 @@ struct Comparer<T, typename enable_if<is_integral<T>::value ||
explicit Comparer(T value) : rhs(value) {} explicit Comparer(T value) : rhs(value) {}
void visitFloat(Float lhs) { CompareResult visitFloat(Float lhs) {
result = arithmeticCompare(lhs, rhs); return arithmeticCompare(lhs, rhs);
} }
void visitNegativeInteger(UInt lhs) { CompareResult visitNegativeInteger(UInt lhs) {
result = arithmeticCompareNegateLeft(lhs, rhs); return arithmeticCompareNegateLeft(lhs, rhs);
} }
void visitPositiveInteger(UInt lhs) { CompareResult visitPositiveInteger(UInt lhs) {
result = arithmeticCompare(lhs, rhs); return arithmeticCompare(lhs, rhs);
} }
void visitBoolean(bool lhs) { CompareResult visitBoolean(bool lhs) {
visitPositiveInteger(static_cast<UInt>(lhs)); return visitPositiveInteger(static_cast<UInt>(lhs));
} }
}; };
struct NullComparer : ComparerBase { struct NullComparer : ComparerBase {
void visitNull() { CompareResult visitNull() {
result = COMPARE_RESULT_EQUAL; return COMPARE_RESULT_EQUAL;
} }
}; };
@@ -99,9 +115,11 @@ struct ArrayComparer : ComparerBase {
explicit ArrayComparer(const CollectionData &rhs) : _rhs(&rhs) {} explicit ArrayComparer(const CollectionData &rhs) : _rhs(&rhs) {}
void visitArray(const CollectionData &lhs) { CompareResult visitArray(const CollectionData &lhs) {
if (lhs.equalsArray(*_rhs)) if (lhs.equalsArray(*_rhs))
result = COMPARE_RESULT_EQUAL; return COMPARE_RESULT_EQUAL;
else
return COMPARE_RESULT_DIFFER;
} }
}; };
@@ -110,20 +128,20 @@ struct NegativeIntegerComparer : ComparerBase {
explicit NegativeIntegerComparer(UInt rhs) : _rhs(rhs) {} explicit NegativeIntegerComparer(UInt rhs) : _rhs(rhs) {}
void visitFloat(Float lhs) { CompareResult visitFloat(Float lhs) {
result = arithmeticCompareNegateRight(lhs, _rhs); return arithmeticCompareNegateRight(lhs, _rhs);
} }
void visitNegativeInteger(UInt lhs) { CompareResult visitNegativeInteger(UInt lhs) {
result = arithmeticCompare(_rhs, lhs); return arithmeticCompare(_rhs, lhs);
} }
void visitPositiveInteger(UInt) { CompareResult visitPositiveInteger(UInt) {
result = COMPARE_RESULT_GREATER; return COMPARE_RESULT_GREATER;
} }
void visitBoolean(bool) { CompareResult visitBoolean(bool) {
result = COMPARE_RESULT_GREATER; return COMPARE_RESULT_GREATER;
} }
}; };
@@ -132,9 +150,11 @@ struct ObjectComparer : ComparerBase {
explicit ObjectComparer(const CollectionData &rhs) : _rhs(&rhs) {} explicit ObjectComparer(const CollectionData &rhs) : _rhs(&rhs) {}
void visitObject(const CollectionData &lhs) { CompareResult visitObject(const CollectionData &lhs) {
if (lhs.equalsObject(*_rhs)) if (lhs.equalsObject(*_rhs))
result = COMPARE_RESULT_EQUAL; return COMPARE_RESULT_EQUAL;
else
return COMPARE_RESULT_DIFFER;
} }
}; };
@@ -145,15 +165,15 @@ struct RawComparer : ComparerBase {
explicit RawComparer(const char *rhsData, size_t rhsSize) explicit RawComparer(const char *rhsData, size_t rhsSize)
: _rhsData(rhsData), _rhsSize(rhsSize) {} : _rhsData(rhsData), _rhsSize(rhsSize) {}
void visitRawJson(const char *lhsData, size_t lhsSize) { CompareResult visitRawJson(const char *lhsData, size_t lhsSize) {
size_t size = _rhsSize < lhsSize ? _rhsSize : lhsSize; size_t size = _rhsSize < lhsSize ? _rhsSize : lhsSize;
int n = memcmp(lhsData, _rhsData, size); int n = memcmp(lhsData, _rhsData, size);
if (n < 0) if (n < 0)
result = COMPARE_RESULT_LESS; return COMPARE_RESULT_LESS;
else if (n > 0) else if (n > 0)
result = COMPARE_RESULT_GREATER; return COMPARE_RESULT_GREATER;
else else
result = COMPARE_RESULT_EQUAL; return COMPARE_RESULT_EQUAL;
} }
}; };
@@ -164,65 +184,62 @@ struct Comparer<T, typename enable_if<IsVisitable<T>::value>::type>
explicit Comparer(T value) : rhs(value) {} explicit Comparer(T value) : rhs(value) {}
void visitArray(const CollectionData &lhs) { CompareResult visitArray(const CollectionData &lhs) {
ArrayComparer comparer(lhs); ArrayComparer comparer(lhs);
accept(comparer); return accept(comparer);
} }
void visitObject(const CollectionData &lhs) { CompareResult visitObject(const CollectionData &lhs) {
ObjectComparer comparer(lhs); ObjectComparer comparer(lhs);
accept(comparer); return accept(comparer);
} }
void visitFloat(Float lhs) { CompareResult visitFloat(Float lhs) {
Comparer<Float> comparer(lhs); Comparer<Float> comparer(lhs);
accept(comparer); return accept(comparer);
} }
void visitString(const char *lhs) { CompareResult visitString(const char *lhs) {
Comparer<const char *> comparer(lhs); Comparer<const char *> comparer(lhs);
accept(comparer); return accept(comparer);
} }
void visitRawJson(const char *lhsData, size_t lhsSize) { CompareResult visitRawJson(const char *lhsData, size_t lhsSize) {
RawComparer comparer(lhsData, lhsSize); RawComparer comparer(lhsData, lhsSize);
accept(comparer); return accept(comparer);
} }
void visitNegativeInteger(UInt lhs) { CompareResult visitNegativeInteger(UInt lhs) {
NegativeIntegerComparer comparer(lhs); NegativeIntegerComparer comparer(lhs);
accept(comparer); return accept(comparer);
} }
void visitPositiveInteger(UInt lhs) { CompareResult visitPositiveInteger(UInt lhs) {
Comparer<UInt> comparer(lhs); Comparer<UInt> comparer(lhs);
accept(comparer); return accept(comparer);
} }
void visitBoolean(bool lhs) { CompareResult visitBoolean(bool lhs) {
Comparer<bool> comparer(lhs); Comparer<bool> comparer(lhs);
accept(comparer); return accept(comparer);
} }
void visitNull() { CompareResult visitNull() {
NullComparer comparer; NullComparer comparer;
accept(comparer); return accept(comparer);
} }
private: private:
template <typename TComparer> template <typename TComparer>
void accept(TComparer &comparer) { CompareResult accept(TComparer &comparer) {
rhs.accept(comparer); CompareResult reversedResult = rhs.accept(comparer);
switch (comparer.result) { switch (reversedResult) {
case COMPARE_RESULT_GREATER: case COMPARE_RESULT_GREATER:
result = COMPARE_RESULT_LESS; return COMPARE_RESULT_LESS;
break;
case COMPARE_RESULT_LESS: case COMPARE_RESULT_LESS:
result = COMPARE_RESULT_GREATER; return COMPARE_RESULT_GREATER;
break;
default: default:
result = comparer.result; return reversedResult;
break;
} }
} }
}; };
@@ -230,8 +247,7 @@ struct Comparer<T, typename enable_if<IsVisitable<T>::value>::type>
template <typename T1, typename T2> template <typename T1, typename T2>
CompareResult compare(const T1 &lhs, const T2 &rhs) { CompareResult compare(const T1 &lhs, const T2 &rhs) {
Comparer<T2> comparer(rhs); Comparer<T2> comparer(rhs);
lhs.accept(comparer); return lhs.accept(comparer);
return comparer.result;
} }
inline int variantCompare(const VariantData *a, const VariantData *b) { inline int variantCompare(const VariantData *a, const VariantData *b) {

View File

@@ -7,7 +7,6 @@
#include <ArduinoJson/Memory/MemoryPool.hpp> #include <ArduinoJson/Memory/MemoryPool.hpp>
#include <ArduinoJson/Misc/SerializedValue.hpp> #include <ArduinoJson/Misc/SerializedValue.hpp>
#include <ArduinoJson/Numbers/convertNumber.hpp> #include <ArduinoJson/Numbers/convertNumber.hpp>
#include <ArduinoJson/Polyfills/gsl/not_null.hpp>
#include <ArduinoJson/Strings/RamStringAdapter.hpp> #include <ArduinoJson/Strings/RamStringAdapter.hpp>
#include <ArduinoJson/Variant/VariantContent.hpp> #include <ArduinoJson/Variant/VariantContent.hpp>
@@ -33,9 +32,12 @@ class VariantData {
// - no destructor // - no destructor
// - no virtual // - no virtual
// - no inheritance // - no inheritance
void init() {
_flags = 0;
}
template <typename Visitor> template <typename TVisitor>
void accept(Visitor &visitor) const { typename TVisitor::result_type accept(TVisitor &visitor) const {
switch (type()) { switch (type()) {
case VALUE_IS_FLOAT: case VALUE_IS_FLOAT:
return visitor.visitFloat(_content.asFloat); return visitor.visitFloat(_content.asFloat);
@@ -242,25 +244,14 @@ class VariantData {
setType(VALUE_IS_NULL); setType(VALUE_IS_NULL);
} }
void setString(not_null<const char *> s, storage_policies::store_by_copy) { void setStringPointer(const char *s, storage_policies::store_by_copy) {
setType(VALUE_IS_OWNED_STRING); setType(VALUE_IS_OWNED_STRING);
_content.asString = s.get(); _content.asString = s;
} }
void setString(not_null<const char *> s, storage_policies::store_by_address) { void setStringPointer(const char *s, storage_policies::store_by_address) {
setType(VALUE_IS_LINKED_STRING); setType(VALUE_IS_LINKED_STRING);
_content.asString = s.get(); _content.asString = s;
}
template <typename TStoragePolicy>
bool setString(const char *s, TStoragePolicy storage_policy) {
if (s) {
setString(make_not_null(s), storage_policy);
return true;
} else {
setType(VALUE_IS_NULL);
return false;
}
} }
template <typename TAdaptedString> template <typename TAdaptedString>
@@ -280,14 +271,27 @@ class VariantData {
template <typename TAdaptedString> template <typename TAdaptedString>
inline bool setString(TAdaptedString value, MemoryPool *, inline bool setString(TAdaptedString value, MemoryPool *,
storage_policies::store_by_address) { storage_policies::store_by_address) {
return setString(value.data(), storage_policies::store_by_address()); if (value.isNull())
setNull();
else
setStringPointer(value.data(), storage_policies::store_by_address());
return true;
} }
template <typename TAdaptedString> template <typename TAdaptedString>
inline bool setString(TAdaptedString value, MemoryPool *pool, inline bool setString(TAdaptedString value, MemoryPool *pool,
storage_policies::store_by_copy) { storage_policies::store_by_copy) {
return setString(pool->saveString(value), if (value.isNull()) {
storage_policies::store_by_copy()); setNull();
return true;
}
const char *copy = pool->saveString(value);
if (!copy) {
setNull();
return false;
}
setStringPointer(copy, storage_policies::store_by_copy());
return true;
} }
CollectionData &toArray() { CollectionData &toArray() {
@@ -365,11 +369,11 @@ class VariantData {
_content.asCollection.movePointers(stringDistance, variantDistance); _content.asCollection.movePointers(stringDistance, variantDistance);
} }
private:
uint8_t type() const { uint8_t type() const {
return _flags & VALUE_MASK; return _flags & VALUE_MASK;
} }
private:
void setType(uint8_t t) { void setType(uint8_t t) {
_flags &= KEY_IS_OWNED; _flags &= KEY_IS_OWNED;
_flags |= t; _flags |= t;

View File

@@ -9,12 +9,13 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename Visitor> template <typename TVisitor>
inline void variantAccept(const VariantData *var, Visitor &visitor) { inline typename TVisitor::result_type variantAccept(const VariantData *var,
TVisitor &visitor) {
if (var != 0) if (var != 0)
var->accept(visitor); return var->accept(visitor);
else else
visitor.visitNull(); return visitor.visitNull();
} }
inline const CollectionData *variantAsArray(const VariantData *var) { inline const CollectionData *variantAsArray(const VariantData *var) {

View File

@@ -4,10 +4,11 @@
#pragma once #pragma once
#include <ArduinoJson/Array/ArrayRef.hpp>
#include <ArduinoJson/Configuration.hpp> #include <ArduinoJson/Configuration.hpp>
#include <ArduinoJson/Numbers/convertNumber.hpp> #include <ArduinoJson/Numbers/convertNumber.hpp>
#include <ArduinoJson/Numbers/parseFloat.hpp> #include <ArduinoJson/Numbers/parseNumber.hpp>
#include <ArduinoJson/Numbers/parseInteger.hpp> #include <ArduinoJson/Object/ObjectRef.hpp>
#include <ArduinoJson/Variant/VariantRef.hpp> #include <ArduinoJson/Variant/VariantRef.hpp>
#include <string.h> // for strcmp #include <string.h> // for strcmp
@@ -24,7 +25,7 @@ inline T VariantData::asIntegral() const {
return convertNegativeInteger<T>(_content.asInteger); return convertNegativeInteger<T>(_content.asInteger);
case VALUE_IS_LINKED_STRING: case VALUE_IS_LINKED_STRING:
case VALUE_IS_OWNED_STRING: case VALUE_IS_OWNED_STRING:
return parseInteger<T>(_content.asString); return parseNumber<T>(_content.asString);
case VALUE_IS_FLOAT: case VALUE_IS_FLOAT:
return convertFloat<T>(_content.asFloat); return convertFloat<T>(_content.asFloat);
default: default:
@@ -58,7 +59,7 @@ inline T VariantData::asFloat() const {
return -static_cast<T>(_content.asInteger); return -static_cast<T>(_content.asInteger);
case VALUE_IS_LINKED_STRING: case VALUE_IS_LINKED_STRING:
case VALUE_IS_OWNED_STRING: case VALUE_IS_OWNED_STRING:
return parseFloat<T>(_content.asString); return parseNumber<T>(_content.asString);
case VALUE_IS_FLOAT: case VALUE_IS_FLOAT:
return static_cast<T>(_content.asFloat); return static_cast<T>(_content.asFloat);
default: default:
@@ -138,4 +139,9 @@ template <typename TString>
inline VariantRef VariantRef::getOrAddMember(const TString &key) const { inline VariantRef VariantRef::getOrAddMember(const TString &key) const {
return VariantRef(_pool, variantGetOrAddMember(_data, key, _pool)); return VariantRef(_pool, variantGetOrAddMember(_data, key, _pool));
} }
inline VariantConstRef operator|(VariantConstRef preferedValue,
VariantConstRef defaultValue) {
return preferedValue ? preferedValue : defaultValue;
}
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -19,7 +19,8 @@ template <typename TVariant>
struct VariantOperators { struct VariantOperators {
// Returns the default value if the VariantRef is undefined of incompatible // Returns the default value if the VariantRef is undefined of incompatible
template <typename T> template <typename T>
friend T operator|(const TVariant &variant, const T &defaultValue) { friend typename enable_if<!IsVisitable<T>::value, T>::type operator|(
const TVariant &variant, const T &defaultValue) {
if (variant.template is<T>()) if (variant.template is<T>())
return variant.template as<T>(); return variant.template as<T>();
else else
@@ -28,8 +29,9 @@ struct VariantOperators {
// Returns the default value if the VariantRef is undefined of incompatible // Returns the default value if the VariantRef is undefined of incompatible
// Special case for string: null is treated as undefined // Special case for string: null is treated as undefined
friend const char *operator|(const TVariant &variant, template <typename T>
const char *defaultValue) { friend typename enable_if<is_same<T, const char *>::value, T>::type operator|(
const TVariant &variant, T defaultValue) {
const char *value = variant.template as<const char *>(); const char *value = variant.template as<const char *>();
return value ? value : defaultValue; return value ? value : defaultValue;
} }

View File

@@ -261,9 +261,9 @@ class VariantRef : public VariantRefBase<VariantData>,
return variantAs<T>(_data, _pool); return variantAs<T>(_data, _pool);
} }
template <typename Visitor> template <typename TVisitor>
void accept(Visitor &visitor) const { typename TVisitor::result_type accept(TVisitor &visitor) const {
variantAccept(_data, visitor); return variantAccept(_data, visitor);
} }
// Change the type of the variant // Change the type of the variant
@@ -347,9 +347,9 @@ class VariantConstRef : public VariantRefBase<const VariantData>,
VariantConstRef(const VariantData *data) : base_type(data) {} VariantConstRef(const VariantData *data) : base_type(data) {}
VariantConstRef(VariantRef var) : base_type(var._data) {} VariantConstRef(VariantRef var) : base_type(var._data) {}
template <typename Visitor> template <typename TVisitor>
void accept(Visitor &visitor) const { typename TVisitor::result_type accept(TVisitor &visitor) const {
variantAccept(_data, visitor); return variantAccept(_data, visitor);
} }
template <typename T> template <typename T>

View File

@@ -6,7 +6,6 @@
#include <stdint.h> // int8_t, int16_t #include <stdint.h> // int8_t, int16_t
#include <ArduinoJson/Polyfills/gsl/not_null.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp> #include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Variant/VariantContent.hpp> #include <ArduinoJson/Variant/VariantContent.hpp>

View File

@@ -4,7 +4,7 @@
#pragma once #pragma once
#define ARDUINOJSON_VERSION "6.16.1" #define ARDUINOJSON_VERSION "6.17.0"
#define ARDUINOJSON_VERSION_MAJOR 6 #define ARDUINOJSON_VERSION_MAJOR 6
#define ARDUINOJSON_VERSION_MINOR 16 #define ARDUINOJSON_VERSION_MINOR 17
#define ARDUINOJSON_VERSION_REVISION 1 #define ARDUINOJSON_VERSION_REVISION 0

View File

@@ -59,7 +59,6 @@ int digitalRead(uint8_t pin);
&__c[0]; \ &__c[0]; \
})) }))
class __FlashStringHelper; class __FlashStringHelper;
#define FPSTR(string_literal) (reinterpret_cast<const __FlashStringHelper *>(string_literal)) #define FPSTR(string_literal) (reinterpret_cast<const __FlashStringHelper *>(string_literal))
#define F(string_literal) (FPSTR(PSTR(string_literal))) #define F(string_literal) (FPSTR(PSTR(string_literal)))
@@ -67,7 +66,13 @@ class __FlashStringHelper;
int snprintf_P(char * str, size_t size, const char * format, ...); int snprintf_P(char * str, size_t size, const char * format, ...);
int vsnprintf_P(char * str, size_t size, const char * format, va_list ap); int vsnprintf_P(char * str, size_t size, const char * format, va_list ap);
#define pgm_read_byte(addr) (*reinterpret_cast<const char *>(addr)) // #define pgm_read_byte(addr) (*reinterpret_cast<const char *>(addr))
// #define pgm_read_ptr(p) (reinterpret_cast<const void *>(p))
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#define pgm_read_word(addr) (*(const unsigned short *)(addr))
#define pgm_read_dword(addr) (*(const unsigned long *)(addr))
#define pgm_read_float(addr) (*(const float *)(addr))
#define pgm_read_ptr(addr) (*(const void **)(addr))
class Print; class Print;