public
This commit is contained in:
commit
5f1b6cd8f0
4
001-homekit_hub/.gitignore
vendored
Executable file
4
001-homekit_hub/.gitignore
vendored
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
.pio
|
||||||
|
.vscode
|
||||||
|
src/passwords.h
|
||||||
|
src/passwords_ftp.h
|
3
001-homekit_hub/CMakeLists.txt
Executable file
3
001-homekit_hub/CMakeLists.txt
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.16.0)
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(hub)
|
7
001-homekit_hub/README.md
Normal file
7
001-homekit_hub/README.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# 001-HomeKit_hub
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
This is HomeKit hub for remote sensors.
|
||||||
|
Based on https://github.com/HomeSpan/HomeSpan
|
2
001-homekit_hub/changelog.txt
Executable file
2
001-homekit_hub/changelog.txt
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
2024-07-20:
|
||||||
|
- 2.3.4a - pushed clean version to public
|
11
001-homekit_hub/extra_scripts/erase_before_upload.py
Executable file
11
001-homekit_hub/extra_scripts/erase_before_upload.py
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
Import("env")
|
||||||
|
|
||||||
|
old_uploaderflags = env["UPLOADERFLAGS"]
|
||||||
|
#print("Old uploaderflags: " + str(old_uploaderflags))
|
||||||
|
|
||||||
|
index_write_flash = old_uploaderflags.index("write_flash")
|
||||||
|
if index_write_flash != -1:
|
||||||
|
new_uploaderflags = old_uploaderflags[::]
|
||||||
|
new_uploaderflags.insert(index_write_flash + 1, "--erase-all")
|
||||||
|
#print("Replaced with: " + str(new_uploaderflags))
|
||||||
|
env.Replace(UPLOADERFLAGS=new_uploaderflags)
|
138
001-homekit_hub/extra_scripts/output_bins.py
Executable file
138
001-homekit_hub/extra_scripts/output_bins.py
Executable file
@ -0,0 +1,138 @@
|
|||||||
|
Import('env')
|
||||||
|
use_ftp = 'y'
|
||||||
|
|
||||||
|
# Troubleshooting python modules ================================
|
||||||
|
# https://docs.platformio.org/en/stable/scripting/examples/extra_python_packages.html
|
||||||
|
# List installed packages
|
||||||
|
# env.Execute("$PYTHONEXE -m pip list")
|
||||||
|
|
||||||
|
# Install custom packages from the PyPi registry
|
||||||
|
# env.Execute("$PYTHONEXE -m pip install python-dotenv")
|
||||||
|
|
||||||
|
# Install missed package
|
||||||
|
# try:
|
||||||
|
# import dotenv
|
||||||
|
# except ImportError:
|
||||||
|
# env.Execute("$PYTHONEXE -m pip install python-dotenv")
|
||||||
|
# Troubleshooting python modules END =============================
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import ftplib
|
||||||
|
# for passwords
|
||||||
|
from dotenv import dotenv_values
|
||||||
|
from dotenv import set_key
|
||||||
|
from dotenv import get_key
|
||||||
|
|
||||||
|
OUTPUT_DIR = "/Volumes/scripts/scripts/001-esp-firmware/esp/02-homekit/001-fv{}".format(os.path.sep)
|
||||||
|
|
||||||
|
config = env.GetProjectConfig()
|
||||||
|
version = config.get("program_customisation", "version")
|
||||||
|
client = config.get("program_customisation", "client")
|
||||||
|
|
||||||
|
def _get_cpp_define_value(env, define):
|
||||||
|
define_list = [item[-1] for item in env["CPPDEFINES"] if item[0] == define]
|
||||||
|
|
||||||
|
if define_list:
|
||||||
|
return define_list[0]
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _create_dirs(dirs=["firmware"]):
|
||||||
|
# check if output directories exist and create if necessary
|
||||||
|
if not os.path.isdir(OUTPUT_DIR):
|
||||||
|
os.mkdir(OUTPUT_DIR)
|
||||||
|
|
||||||
|
for d in dirs:
|
||||||
|
if not os.path.isdir("{}{}".format(OUTPUT_DIR, d)):
|
||||||
|
os.mkdir("{}{}".format(OUTPUT_DIR, d))
|
||||||
|
|
||||||
|
def bin_rename_copy(source, target, env):
|
||||||
|
print()
|
||||||
|
print("============== bin_rename_copy =================================")
|
||||||
|
_create_dirs()
|
||||||
|
variant = env["PIOENV"]
|
||||||
|
bin_file = "{}firmware{}{}.bin".format(OUTPUT_DIR, os.path.sep, variant)
|
||||||
|
fw_file = "{}.bin".format(variant)
|
||||||
|
ver_file = "{}.bin.version".format(variant)
|
||||||
|
print("firmware file:",fw_file)
|
||||||
|
print("version file:",ver_file)
|
||||||
|
print("version:",version)
|
||||||
|
print("client:",client)
|
||||||
|
shutil.copy(str(target[0]), bin_file)
|
||||||
|
|
||||||
|
# version file
|
||||||
|
version_file = "{}firmware{}{}.bin.version".format(OUTPUT_DIR, os.path.sep, variant)
|
||||||
|
config = env.GetProjectConfig()
|
||||||
|
ver = config.get("program_customisation", "version")
|
||||||
|
ver = ver.replace('"', '')
|
||||||
|
print("version compiled (inside version file):",ver)
|
||||||
|
file = open(version_file,"w")
|
||||||
|
file.write(ver)
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ftp transfer
|
||||||
|
# get credentials:
|
||||||
|
if (use_ftp != 'y'):
|
||||||
|
print("============== FTP ===========================================")
|
||||||
|
print("NOT sending firmware to ftp server")
|
||||||
|
print("============== FTP END =======================================")
|
||||||
|
print()
|
||||||
|
else:
|
||||||
|
print()
|
||||||
|
print("============== FTP DETAILS =================================")
|
||||||
|
print("Uploading firmware to ftp server...")
|
||||||
|
password_file=(os.getcwd()) + "/src/passwords_ftp.h"
|
||||||
|
# print("password_file: ",password_file)
|
||||||
|
config = dotenv_values(password_file)
|
||||||
|
FTP_HOST=config['FTP_HOST']
|
||||||
|
# print("host=",FTP_HOST)
|
||||||
|
FTP_USER=config['FTP_USER']
|
||||||
|
# print("user=",FTP_USER)
|
||||||
|
FTP_PASSWORD=config['FTP_PASSWORD']
|
||||||
|
# print("password=",FTP_PASSWORD)
|
||||||
|
FTP_DEST_DIR=config['FTP_DEST_DIR']
|
||||||
|
print("destination folder: ftp://",FTP_HOST,"/",FTP_DEST_DIR,sep='')
|
||||||
|
print()
|
||||||
|
print("============== TRANSFER FIRMWARE FILE ==========================")
|
||||||
|
ftp = ftplib.FTP_TLS(FTP_HOST)
|
||||||
|
ftp.login(FTP_USER, FTP_PASSWORD)
|
||||||
|
ftp.prot_p()
|
||||||
|
# print("landing dir: ",ftp.pwd())
|
||||||
|
# print("content:")
|
||||||
|
# ftp.dir()
|
||||||
|
ftp.cwd(FTP_DEST_DIR)
|
||||||
|
# print("dest dir: ",ftp.pwd())
|
||||||
|
# print("content:")
|
||||||
|
# ftp.dir()
|
||||||
|
|
||||||
|
# bin_file
|
||||||
|
print("Firmware file to store: ",bin_file)
|
||||||
|
file = open(bin_file,"rb")
|
||||||
|
command = "STOR " + fw_file
|
||||||
|
ftp.storbinary(command, file)
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
print()
|
||||||
|
print("============== TRANSFER VERSION FILE ===========================")
|
||||||
|
# version_file
|
||||||
|
print("Version file to store: ",version_file)
|
||||||
|
file = open(version_file,"rb")
|
||||||
|
command = "STOR " + ver_file
|
||||||
|
ftp.storbinary(command, file)
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
print()
|
||||||
|
print("============== FTP RESULTS: ====================================")
|
||||||
|
print("destination folder: ",ftp.pwd())
|
||||||
|
print("content after transfer:")
|
||||||
|
ftp.dir()
|
||||||
|
ftp.close()
|
||||||
|
print("============== FTP END ========================================")
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [bin_rename_copy])
|
39
001-homekit_hub/include/README
Executable file
39
001-homekit_hub/include/README
Executable file
@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
This directory is intended for project header files.
|
||||||
|
|
||||||
|
A header file is a file containing C declarations and macro definitions
|
||||||
|
to be shared between several project source files. You request the use of a
|
||||||
|
header file in your project source file (C, C++, etc) located in `src` folder
|
||||||
|
by including it, with the C preprocessing directive `#include'.
|
||||||
|
|
||||||
|
```src/main.c
|
||||||
|
|
||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Including a header file produces the same results as copying the header file
|
||||||
|
into each source file that needs it. Such copying would be time-consuming
|
||||||
|
and error-prone. With a header file, the related declarations appear
|
||||||
|
in only one place. If they need to be changed, they can be changed in one
|
||||||
|
place, and programs that include the header file will automatically use the
|
||||||
|
new version when next recompiled. The header file eliminates the labor of
|
||||||
|
finding and changing all the copies as well as the risk that a failure to
|
||||||
|
find one copy will result in inconsistencies within a program.
|
||||||
|
|
||||||
|
In C, the usual convention is to give header files names that end with `.h'.
|
||||||
|
It is most portable to use only letters, digits, dashes, and underscores in
|
||||||
|
header file names, and at most one dot.
|
||||||
|
|
||||||
|
Read more about using header files in official GCC documentation:
|
||||||
|
|
||||||
|
* Include Syntax
|
||||||
|
* Include Operation
|
||||||
|
* Once-Only Headers
|
||||||
|
* Computed Includes
|
||||||
|
|
||||||
|
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
1
001-homekit_hub/lib/ArduinoJson/.piopm
Normal file
1
001-homekit_hub/lib/ArduinoJson/.piopm
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"type": "library", "name": "ArduinoJson", "version": "6.21.5", "spec": {"owner": "bblanchon", "id": 64, "name": "ArduinoJson", "requirements": null, "uri": null}}
|
5
001-homekit_hub/lib/ArduinoJson/ArduinoJson.h
Normal file
5
001-homekit_hub/lib/ArduinoJson/ArduinoJson.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#include "src/ArduinoJson.h"
|
10
001-homekit_hub/lib/ArduinoJson/LICENSE.txt
Normal file
10
001-homekit_hub/lib/ArduinoJson/LICENSE.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
161
001-homekit_hub/lib/ArduinoJson/README.md
Normal file
161
001-homekit_hub/lib/ArduinoJson/README.md
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
<p align="center">
|
||||||
|
<a href="https://arduinojson.org/"><img alt="ArduinoJson" src="https://arduinojson.org/images/logo.svg" width="200" /></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/bblanchon/ArduinoJson/ci.yml?branch=6.x&logo=github)](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A6.x)
|
||||||
|
[![Continuous Integration](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/6.x?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x)
|
||||||
|
[![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)
|
||||||
|
[![Coveralls branch](https://img.shields.io/coveralls/github/bblanchon/ArduinoJson/6.x?logo=coveralls)](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x)
|
||||||
|
[![Arduino Library Manager](https://img.shields.io/static/v1?label=Arduino&message=v6.21.5&logo=arduino&logoColor=white&color=blue)](https://www.ardu-badge.com/ArduinoJson/6.21.5)
|
||||||
|
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/bblanchon/library/ArduinoJson.svg?version=6.21.5)](https://registry.platformio.org/packages/libraries/bblanchon/ArduinoJson?version=6.21.5)
|
||||||
|
[![ESP IDF](https://img.shields.io/static/v1?label=ESP+IDF&message=v6.21.5&logo=cpu&logoColor=white&color=blue)](https://components.espressif.com/components/bblanchon/arduinojson)
|
||||||
|
[![GitHub stars](https://img.shields.io/github/stars/bblanchon/ArduinoJson?style=flat&logo=github&color=orange)](https://github.com/bblanchon/ArduinoJson/stargazers)
|
||||||
|
[![GitHub Sponsors](https://img.shields.io/github/sponsors/bblanchon?logo=github&color=orange)](https://github.com/sponsors/bblanchon)
|
||||||
|
|
||||||
|
ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
* [JSON deserialization](https://arduinojson.org/v6/api/json/deserializejson/)
|
||||||
|
* [Optionally decodes UTF-16 escape sequences to UTF-8](https://arduinojson.org/v6/api/config/decode_unicode/)
|
||||||
|
* [Optionally stores links to the input buffer (zero-copy)](https://arduinojson.org/v6/api/json/deserializejson/)
|
||||||
|
* [Optionally supports comments in the input](https://arduinojson.org/v6/api/config/enable_comments/)
|
||||||
|
* [Optionally filters the input to keep only desired values](https://arduinojson.org/v6/api/json/deserializejson/#filtering)
|
||||||
|
* Supports single quotes as a string delimiter
|
||||||
|
* Compatible with [NDJSON](http://ndjson.org/) and [JSON Lines](https://jsonlines.org/)
|
||||||
|
* [JSON serialization](https://arduinojson.org/v6/api/json/serializejson/)
|
||||||
|
* [Can write to a buffer or a stream](https://arduinojson.org/v6/api/json/serializejson/)
|
||||||
|
* [Optionally indents the document (prettified JSON)](https://arduinojson.org/v6/api/json/serializejsonpretty/)
|
||||||
|
* [MessagePack serialization](https://arduinojson.org/v6/api/msgpack/serializemsgpack/)
|
||||||
|
* [MessagePack deserialization](https://arduinojson.org/v6/api/msgpack/deserializemsgpack/)
|
||||||
|
* Efficient
|
||||||
|
* [Twice smaller than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
|
||||||
|
* [Almost 10% faster than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
|
||||||
|
* [Consumes roughly 10% less RAM than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
|
||||||
|
* [Fixed memory allocation, no heap fragmentation](https://arduinojson.org/v6/api/jsondocument/)
|
||||||
|
* [Optionally works without heap memory (zero malloc)](https://arduinojson.org/v6/api/staticjsondocument/)
|
||||||
|
* [Deduplicates strings](https://arduinojson.org/news/2020/08/01/version-6-16-0/)
|
||||||
|
* Versatile
|
||||||
|
* Supports [custom allocators (to use external RAM chip, for example)](https://arduinojson.org/v6/how-to/use-external-ram-on-esp32/)
|
||||||
|
* Supports [`String`](https://arduinojson.org/v6/api/config/enable_arduino_string/), [`std::string`](https://arduinojson.org/v6/api/config/enable_std_string/), and [`std::string_view`](https://arduinojson.org/v6/api/config/enable_string_view/)
|
||||||
|
* Supports [`Stream`](https://arduinojson.org/v6/api/config/enable_arduino_stream/) and [`std::istream`/`std::ostream`](https://arduinojson.org/v6/api/config/enable_std_stream/)
|
||||||
|
* Supports [Flash strings](https://arduinojson.org/v6/api/config/enable_progmem/)
|
||||||
|
* Supports [custom readers](https://arduinojson.org/v6/api/json/deserializejson/#custom-reader) and [custom writers](https://arduinojson.org/v6/api/json/serializejson/#custom-writer)
|
||||||
|
* Supports [custom converters](https://arduinojson.org/news/2021/05/04/version-6-18-0/)
|
||||||
|
* Portable
|
||||||
|
* Usable on any C++ project (not limited to Arduino)
|
||||||
|
* Compatible with C++11, C++14 and C++17
|
||||||
|
* Support for C++98/C++03 available on [ArduinoJson 6.20.x](https://github.com/bblanchon/ArduinoJson/tree/6.20.x)
|
||||||
|
* Zero warnings with `-Wall -Wextra -pedantic` and `/W4`
|
||||||
|
* [Header-only library](https://en.wikipedia.org/wiki/Header-only)
|
||||||
|
* Works with virtually any board
|
||||||
|
* Arduino boards: [Uno](https://amzn.to/38aL2ik), [Due](https://amzn.to/36YkWi2), [Micro](https://amzn.to/35WkdwG), [Nano](https://amzn.to/2QTvwRX), [Mega](https://amzn.to/36XWhuf), [Yun](https://amzn.to/30odURc), [Leonardo](https://amzn.to/36XWjlR)...
|
||||||
|
* Espressif chips: [ESP8266](https://amzn.to/36YluV8), [ESP32](https://amzn.to/2G4pRCB)
|
||||||
|
* Lolin (WeMos) boards: [D1 mini](https://amzn.to/2QUpz7q), [D1 Mini Pro](https://amzn.to/36UsGSs)...
|
||||||
|
* Teensy boards: [4.0](https://amzn.to/30ljXGq), [3.2](https://amzn.to/2FT0EuC), [2.0](https://amzn.to/2QXUMXj)
|
||||||
|
* Particle boards: [Argon](https://amzn.to/2FQHa9X), [Boron](https://amzn.to/36WgLUd), [Electron](https://amzn.to/30vEc4k), [Photon](https://amzn.to/387F9Cd)...
|
||||||
|
* Texas Instruments boards: [MSP430](https://amzn.to/30nJWgg)...
|
||||||
|
* Soft cores: [Nios II](https://en.wikipedia.org/wiki/Nios_II)...
|
||||||
|
* Tested on all major development environments
|
||||||
|
* [Arduino IDE](https://www.arduino.cc/en/Main/Software)
|
||||||
|
* [Atmel Studio](http://www.atmel.com/microsite/atmel-studio/)
|
||||||
|
* [Atollic TrueSTUDIO](https://atollic.com/truestudio/)
|
||||||
|
* [Energia](http://energia.nu/)
|
||||||
|
* [IAR Embedded Workbench](https://www.iar.com/iar-embedded-workbench/)
|
||||||
|
* [Keil uVision](http://www.keil.com/)
|
||||||
|
* [MPLAB X IDE](http://www.microchip.com/mplab/mplab-x-ide)
|
||||||
|
* [Particle](https://www.particle.io/)
|
||||||
|
* [PlatformIO](http://platformio.org/)
|
||||||
|
* [Sloeber plugin for Eclipse](https://eclipse.baeyens.it/)
|
||||||
|
* [Visual Micro](http://www.visualmicro.com/)
|
||||||
|
* [Visual Studio](https://www.visualstudio.com/)
|
||||||
|
* [Even works with online compilers like wandbox.org](https://wandbox.org/permlink/RlZSKy17DjJ6HcdN)
|
||||||
|
* [CMake friendly](https://arduinojson.org/v6/how-to/use-arduinojson-with-cmake/)
|
||||||
|
* Well designed
|
||||||
|
* [Elegant API](http://arduinojson.org/v6/example/)
|
||||||
|
* [Thread-safe](https://en.wikipedia.org/wiki/Thread_safety)
|
||||||
|
* Self-contained (no external dependency)
|
||||||
|
* `const` friendly
|
||||||
|
* [`for` friendly](https://arduinojson.org/v6/api/jsonobject/begin_end/)
|
||||||
|
* [TMP friendly](https://en.wikipedia.org/wiki/Template_metaprogramming)
|
||||||
|
* Handles [integer overflows](https://arduinojson.org/v6/api/jsonvariant/as/#integer-overflows)
|
||||||
|
* Well tested
|
||||||
|
* [Unit test coverage close to 100%](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x)
|
||||||
|
* Continuously tested on
|
||||||
|
* [Visual Studio 2017, 2019, 2022](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x)
|
||||||
|
* [GCC 5, 6, 7, 8, 9, 10, 11](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
|
||||||
|
* [Clang 3.8, 3.9, 4.0, 5.0, 6.0, 7, 8, 9, 10](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
|
||||||
|
* [Continuously fuzzed with Google OSS Fuzz](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
|
||||||
|
* Passes all default checks of [clang-tidy](https://releases.llvm.org/10.0.0/tools/clang/tools/extra/docs/clang-tidy/)
|
||||||
|
* Well documented
|
||||||
|
* [Tutorials](https://arduinojson.org/v6/doc/deserialization/)
|
||||||
|
* [Examples](https://arduinojson.org/v6/example/)
|
||||||
|
* [How-tos](https://arduinojson.org/v6/example/)
|
||||||
|
* [FAQ](https://arduinojson.org/v6/faq/)
|
||||||
|
* [Troubleshooter](https://arduinojson.org/v6/troubleshooter/)
|
||||||
|
* [Book](https://arduinojson.org/book/)
|
||||||
|
* [Changelog](CHANGELOG.md)
|
||||||
|
* Vibrant user community
|
||||||
|
* Most popular of all Arduino libraries on [GitHub](https://github.com/search?o=desc&q=arduino+library&s=stars&type=Repositories)
|
||||||
|
* [Used in hundreds of projects](https://www.hackster.io/search?i=projects&q=arduinojson)
|
||||||
|
* [Responsive support](https://github.com/bblanchon/ArduinoJson/issues?q=is%3Aissue+is%3Aclosed)
|
||||||
|
|
||||||
|
## Quickstart
|
||||||
|
|
||||||
|
### Deserialization
|
||||||
|
|
||||||
|
Here is a program that parses a JSON document with ArduinoJson.
|
||||||
|
|
||||||
|
```c++
|
||||||
|
char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
|
||||||
|
|
||||||
|
DynamicJsonDocument doc(1024);
|
||||||
|
deserializeJson(doc, json);
|
||||||
|
|
||||||
|
const char* sensor = doc["sensor"];
|
||||||
|
long time = doc["time"];
|
||||||
|
double latitude = doc["data"][0];
|
||||||
|
double longitude = doc["data"][1];
|
||||||
|
```
|
||||||
|
|
||||||
|
See the [tutorial on arduinojson.org](https://arduinojson.org/v6/doc/deserialization/)
|
||||||
|
|
||||||
|
### Serialization
|
||||||
|
|
||||||
|
Here is a program that generates a JSON document with ArduinoJson:
|
||||||
|
|
||||||
|
```c++
|
||||||
|
DynamicJsonDocument doc(1024);
|
||||||
|
|
||||||
|
doc["sensor"] = "gps";
|
||||||
|
doc["time"] = 1351824120;
|
||||||
|
doc["data"][0] = 48.756080;
|
||||||
|
doc["data"][1] = 2.302038;
|
||||||
|
|
||||||
|
serializeJson(doc, Serial);
|
||||||
|
// This prints:
|
||||||
|
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
|
||||||
|
```
|
||||||
|
|
||||||
|
See the [tutorial on arduinojson.org](https://arduinojson.org/v6/doc/serialization/)
|
||||||
|
|
||||||
|
## Sponsors
|
||||||
|
|
||||||
|
ArduinoJson is thankful to its sponsors. Please give them a visit; they deserve it!
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a href="https://www.programmingelectronics.com/" rel="sponsored">
|
||||||
|
<img src="https://arduinojson.org/images/2021/10/programmingeleactronicsacademy.png" alt="Programming Electronics Academy" width="200">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a href="https://github.com/1technophile" rel="sponsored">
|
||||||
|
<img alt="1technophile" src="https://avatars.githubusercontent.com/u/12672732?s=40&v=4">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
If you run a commercial project that embeds ArduinoJson, think about [sponsoring the library's development](https://github.com/sponsors/bblanchon): it ensures the code that your products rely on stays actively maintained. It can also give your project some exposure to the makers' community.
|
||||||
|
|
||||||
|
If you are an individual user and want to support the development (or give a sign of appreciation), consider purchasing the book [Mastering ArduinoJson](https://arduinojson.org/book/) ❤, or simply [cast a star](https://github.com/bblanchon/ArduinoJson/stargazers) ⭐.
|
@ -0,0 +1,160 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// 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 https://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 https://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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Performance issue?
|
||||||
|
// ------------------
|
||||||
|
//
|
||||||
|
// File is an unbuffered stream, which is not optimal for ArduinoJson.
|
||||||
|
// See: https://arduinojson.org/v6/how-to/improve-speed/
|
||||||
|
|
||||||
|
// See also
|
||||||
|
// --------
|
||||||
|
//
|
||||||
|
// https://arduinojson.org/ contains the documentation for all the functions
|
||||||
|
// used above. It also includes an FAQ that will help you solve any
|
||||||
|
// serialization or deserialization problem.
|
||||||
|
//
|
||||||
|
// The book "Mastering ArduinoJson" contains a case study of a project that has
|
||||||
|
// a complex configuration with nested members.
|
||||||
|
// Contrary to this example, the project in the book uses the SPIFFS filesystem.
|
||||||
|
// Learn more at https://arduinojson.org/book/
|
||||||
|
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤
|
@ -0,0 +1,63 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// This example shows how to use DeserializationOption::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
|
||||||
|
auto 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 ❤❤❤❤❤
|
@ -0,0 +1,77 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// 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 https://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 ❤❤❤❤❤
|
@ -0,0 +1,126 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// 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 https://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"));
|
||||||
|
client.stop();
|
||||||
|
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);
|
||||||
|
client.stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip HTTP headers
|
||||||
|
char endOfHeaders[] = "\r\n\r\n";
|
||||||
|
if (!client.find(endOfHeaders)) {
|
||||||
|
Serial.println(F("Invalid response"));
|
||||||
|
client.stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate the JSON document
|
||||||
|
// Use https://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.f_str());
|
||||||
|
client.stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract values
|
||||||
|
Serial.println(F("Response:"));
|
||||||
|
Serial.println(doc["sensor"].as<const 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Performance issue?
|
||||||
|
// ------------------
|
||||||
|
//
|
||||||
|
// EthernetClient is an unbuffered stream, which is not optimal for ArduinoJson.
|
||||||
|
// See: https://arduinojson.org/v6/how-to/improve-speed/
|
||||||
|
|
||||||
|
// 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 ❤❤❤❤❤
|
@ -0,0 +1,80 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// 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 https://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.f_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 ❤❤❤❤❤
|
@ -0,0 +1,117 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// 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 https://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();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Performance issue?
|
||||||
|
// ------------------
|
||||||
|
//
|
||||||
|
// EthernetClient is an unbuffered stream, which is not optimal for ArduinoJson.
|
||||||
|
// See: https://arduinojson.org/v6/how-to/improve-speed/
|
||||||
|
|
||||||
|
// 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 ❤❤❤❤❤
|
@ -0,0 +1,106 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// 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 https://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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Performance issue?
|
||||||
|
// ------------------
|
||||||
|
//
|
||||||
|
// EthernetUDP is an unbuffered stream, which is not optimal for ArduinoJson.
|
||||||
|
// See: https://arduinojson.org/v6/how-to/improve-speed/
|
||||||
|
|
||||||
|
// 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 ❤❤❤❤❤
|
@ -0,0 +1,75 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// 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 https://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.f_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
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// 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() {
|
||||||
|
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]}"));
|
||||||
|
|
||||||
|
// You can use a Flash String as a key to get a member from JsonDocument
|
||||||
|
// No duplication is done.
|
||||||
|
long time = doc[F("time")];
|
||||||
|
|
||||||
|
// You can use a Flash String as a key to set a member of a JsonDocument
|
||||||
|
// WARNING: the content of the Flash String will be duplicated in the
|
||||||
|
// JsonDocument.
|
||||||
|
doc[F("time")] = time;
|
||||||
|
|
||||||
|
// You can set a Flash String as the content of a JsonVariant
|
||||||
|
// WARNING: the content of the Flash String will be duplicated in the
|
||||||
|
// JsonDocument.
|
||||||
|
doc["sensor"] = F("gps");
|
||||||
|
|
||||||
|
// It works with serialized() too:
|
||||||
|
doc["sensor"] = serialized(F("\"gps\""));
|
||||||
|
doc["sensor"] = serialized(F("\xA3gps"), 3);
|
||||||
|
|
||||||
|
// You can compare the content of a JsonVariant to a Flash String
|
||||||
|
if (doc["sensor"] == F("gps")) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ❤❤❤❤❤
|
@ -0,0 +1,77 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// You can use a String as a key to get a member from JsonDocument
|
||||||
|
// No duplication is done.
|
||||||
|
long time = doc[String("time")];
|
||||||
|
|
||||||
|
// You can use a String as a key to set a member of a JsonDocument
|
||||||
|
// WARNING: the content of the String will be duplicated in the JsonDocument.
|
||||||
|
doc[String("time")] = time;
|
||||||
|
|
||||||
|
// You can get the content of a JsonVariant as a String
|
||||||
|
// No duplication is done, at least not in the JsonDocument.
|
||||||
|
String sensor = doc["sensor"];
|
||||||
|
|
||||||
|
// Unfortunately, the following doesn't work (issue #118):
|
||||||
|
// sensor = doc["sensor"]; // <- error "ambiguous overload for 'operator='"
|
||||||
|
// As a workaround, you need to replace by:
|
||||||
|
sensor = doc["sensor"].as<String>();
|
||||||
|
|
||||||
|
// You can set a String as the content of a JsonVariant
|
||||||
|
// WARNING: the content of the String will be duplicated in the JsonDocument.
|
||||||
|
doc["sensor"] = sensor;
|
||||||
|
|
||||||
|
// It works with serialized() too:
|
||||||
|
doc["sensor"] = serialized(sensor);
|
||||||
|
|
||||||
|
// You can also concatenate strings
|
||||||
|
// WARNING: the content of the String will be duplicated in the JsonDocument.
|
||||||
|
doc[String("sen") + "sor"] = String("gp") + "s";
|
||||||
|
|
||||||
|
// You can compare the content of a JsonObject with a String
|
||||||
|
if (doc["sensor"] == sensor) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lastly, you can print the resulting JSON to a String
|
||||||
|
// WARNING: it doesn't replace the content but appends to it
|
||||||
|
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 ❤❤❤❤❤
|
23
001-homekit_hub/lib/ArduinoJson/library.json
Normal file
23
001-homekit_hub/lib/ArduinoJson/library.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"name": "ArduinoJson",
|
||||||
|
"keywords": "json, rest, http, web",
|
||||||
|
"description": "A simple and efficient JSON library for embedded C++. 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.",
|
||||||
|
"homepage": "https://arduinojson.org/?utm_source=meta&utm_medium=library.json",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/bblanchon/ArduinoJson.git"
|
||||||
|
},
|
||||||
|
"version": "6.21.5",
|
||||||
|
"authors": {
|
||||||
|
"name": "Benoit Blanchon",
|
||||||
|
"url": "https://blog.benoitblanchon.fr"
|
||||||
|
},
|
||||||
|
"export": {
|
||||||
|
"include": ["src", "examples", "LICENSE.txt", "ArduinoJson.h"]
|
||||||
|
},
|
||||||
|
"frameworks": "*",
|
||||||
|
"platforms": "*",
|
||||||
|
"build": {
|
||||||
|
"libArchive": false
|
||||||
|
}
|
||||||
|
}
|
11
001-homekit_hub/lib/ArduinoJson/library.properties
Normal file
11
001-homekit_hub/lib/ArduinoJson/library.properties
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
name=ArduinoJson
|
||||||
|
version=6.21.5
|
||||||
|
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
|
17
001-homekit_hub/lib/ArduinoJson/src/ArduinoJson.h
Normal file
17
001-homekit_hub/lib/ArduinoJson/src/ArduinoJson.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
# include "ArduinoJson.hpp"
|
||||||
|
|
||||||
|
using namespace ArduinoJson;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#error ArduinoJson requires a C++ compiler, please change file extension to .cc or .cpp
|
||||||
|
|
||||||
|
#endif
|
52
001-homekit_hub/lib/ArduinoJson/src/ArduinoJson.hpp
Normal file
52
001-homekit_hub/lib/ArduinoJson/src/ArduinoJson.hpp
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if __cplusplus < 201103L && (!defined(_MSC_VER) || _MSC_VER < 1910)
|
||||||
|
# error ArduinoJson requires C++11 or newer. Configure your compiler for C++11 or downgrade ArduinoJson to 6.20.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ArduinoJson/Configuration.hpp"
|
||||||
|
|
||||||
|
// Include Arduino.h before stdlib.h to avoid conflict with atexit()
|
||||||
|
// https://github.com/bblanchon/ArduinoJson/pull/1693#issuecomment-1001060240
|
||||||
|
#if ARDUINOJSON_ENABLE_ARDUINO_STRING || ARDUINOJSON_ENABLE_ARDUINO_STREAM || \
|
||||||
|
ARDUINOJSON_ENABLE_ARDUINO_PRINT || \
|
||||||
|
(ARDUINOJSON_ENABLE_PROGMEM && defined(ARDUINO))
|
||||||
|
# include <Arduino.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !ARDUINOJSON_DEBUG
|
||||||
|
# ifdef __clang__
|
||||||
|
# pragma clang system_header
|
||||||
|
# elif defined __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ArduinoJson/Array/JsonArray.hpp"
|
||||||
|
#include "ArduinoJson/Object/JsonObject.hpp"
|
||||||
|
#include "ArduinoJson/Variant/JsonVariantConst.hpp"
|
||||||
|
|
||||||
|
#include "ArduinoJson/Document/DynamicJsonDocument.hpp"
|
||||||
|
#include "ArduinoJson/Document/StaticJsonDocument.hpp"
|
||||||
|
|
||||||
|
#include "ArduinoJson/Array/ElementProxy.hpp"
|
||||||
|
#include "ArduinoJson/Array/JsonArrayImpl.hpp"
|
||||||
|
#include "ArduinoJson/Array/Utilities.hpp"
|
||||||
|
#include "ArduinoJson/Collection/CollectionImpl.hpp"
|
||||||
|
#include "ArduinoJson/Object/JsonObjectImpl.hpp"
|
||||||
|
#include "ArduinoJson/Object/MemberProxy.hpp"
|
||||||
|
#include "ArduinoJson/Variant/ConverterImpl.hpp"
|
||||||
|
#include "ArduinoJson/Variant/VariantCompare.hpp"
|
||||||
|
#include "ArduinoJson/Variant/VariantImpl.hpp"
|
||||||
|
|
||||||
|
#include "ArduinoJson/Json/JsonDeserializer.hpp"
|
||||||
|
#include "ArduinoJson/Json/JsonSerializer.hpp"
|
||||||
|
#include "ArduinoJson/Json/PrettyJsonSerializer.hpp"
|
||||||
|
#include "ArduinoJson/MsgPack/MsgPackDeserializer.hpp"
|
||||||
|
#include "ArduinoJson/MsgPack/MsgPackSerializer.hpp"
|
||||||
|
|
||||||
|
#include "ArduinoJson/compatibility.hpp"
|
@ -0,0 +1,60 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Variant/VariantRefBase.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
// A proxy class to get or set an element of an array.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarray/subscript/
|
||||||
|
template <typename TUpstream>
|
||||||
|
class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>,
|
||||||
|
public VariantOperators<ElementProxy<TUpstream>> {
|
||||||
|
friend class VariantAttorney;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ElementProxy(TUpstream upstream, size_t index)
|
||||||
|
: upstream_(upstream), index_(index) {}
|
||||||
|
|
||||||
|
ElementProxy(const ElementProxy& src)
|
||||||
|
: upstream_(src.upstream_), index_(src.index_) {}
|
||||||
|
|
||||||
|
FORCE_INLINE ElementProxy& operator=(const ElementProxy& src) {
|
||||||
|
this->set(src);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
FORCE_INLINE ElementProxy& operator=(const T& src) {
|
||||||
|
this->set(src);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
FORCE_INLINE ElementProxy& operator=(T* src) {
|
||||||
|
this->set(src);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FORCE_INLINE MemoryPool* getPool() const {
|
||||||
|
return VariantAttorney::getPool(upstream_);
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE VariantData* getData() const {
|
||||||
|
return variantGetElement(VariantAttorney::getData(upstream_), index_);
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE VariantData* getOrCreateData() const {
|
||||||
|
return variantGetOrAddElement(VariantAttorney::getOrCreateData(upstream_),
|
||||||
|
index_, VariantAttorney::getPool(upstream_));
|
||||||
|
}
|
||||||
|
|
||||||
|
TUpstream upstream_;
|
||||||
|
size_t index_;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,211 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Array/ElementProxy.hpp>
|
||||||
|
#include <ArduinoJson/Array/JsonArrayConst.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
class JsonObject;
|
||||||
|
|
||||||
|
// A reference to an array in a JsonDocument
|
||||||
|
// https://arduinojson.org/v6/api/jsonarray/
|
||||||
|
class JsonArray : public detail::VariantOperators<JsonArray> {
|
||||||
|
friend class detail::VariantAttorney;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef JsonArrayIterator iterator;
|
||||||
|
|
||||||
|
// Constructs an unbound reference.
|
||||||
|
FORCE_INLINE JsonArray() : data_(0), pool_(0) {}
|
||||||
|
|
||||||
|
// INTERNAL USE ONLY
|
||||||
|
FORCE_INLINE JsonArray(detail::MemoryPool* pool, detail::CollectionData* data)
|
||||||
|
: data_(data), pool_(pool) {}
|
||||||
|
|
||||||
|
// Returns a JsonVariant pointing to the array.
|
||||||
|
// https://arduinojson.org/v6/api/jsonvariant/
|
||||||
|
operator JsonVariant() {
|
||||||
|
void* data = data_; // prevent warning cast-align
|
||||||
|
return JsonVariant(pool_, reinterpret_cast<detail::VariantData*>(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a read-only reference to the array.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarrayconst/
|
||||||
|
operator JsonArrayConst() const {
|
||||||
|
return JsonArrayConst(data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Appends a new (null) element to the array.
|
||||||
|
// Returns a reference to the new element.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarray/add/
|
||||||
|
JsonVariant add() const {
|
||||||
|
if (!data_)
|
||||||
|
return JsonVariant();
|
||||||
|
return JsonVariant(pool_, data_->addElement(pool_));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Appends a value to the array.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarray/add/
|
||||||
|
template <typename T>
|
||||||
|
FORCE_INLINE bool add(const T& value) const {
|
||||||
|
return add().set(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Appends a value to the array.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarray/add/
|
||||||
|
template <typename T>
|
||||||
|
FORCE_INLINE bool add(T* value) const {
|
||||||
|
return add().set(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns an iterator to the first element of the array.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarray/begin/
|
||||||
|
FORCE_INLINE iterator begin() const {
|
||||||
|
if (!data_)
|
||||||
|
return iterator();
|
||||||
|
return iterator(pool_, data_->head());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns an iterator following the last element of the array.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarray/end/
|
||||||
|
FORCE_INLINE iterator end() const {
|
||||||
|
return iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copies an array.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarray/set/
|
||||||
|
FORCE_INLINE bool set(JsonArrayConst src) const {
|
||||||
|
if (!data_ || !src.data_)
|
||||||
|
return false;
|
||||||
|
return data_->copyFrom(*src.data_, pool_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compares the content of two arrays.
|
||||||
|
FORCE_INLINE bool operator==(JsonArray rhs) const {
|
||||||
|
return JsonArrayConst(data_) == JsonArrayConst(rhs.data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes the element at the specified iterator.
|
||||||
|
// ⚠️ Doesn't release the memory associated with the removed element.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarray/remove/
|
||||||
|
FORCE_INLINE void remove(iterator it) const {
|
||||||
|
if (!data_)
|
||||||
|
return;
|
||||||
|
data_->removeSlot(it.slot_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes the element at the specified index.
|
||||||
|
// ⚠️ Doesn't release the memory associated with the removed element.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarray/remove/
|
||||||
|
FORCE_INLINE void remove(size_t index) const {
|
||||||
|
if (!data_)
|
||||||
|
return;
|
||||||
|
data_->removeElement(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes all the elements of the array.
|
||||||
|
// ⚠️ Doesn't release the memory associated with the removed elements.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarray/clear/
|
||||||
|
void clear() const {
|
||||||
|
if (!data_)
|
||||||
|
return;
|
||||||
|
data_->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets or sets the element at the specified index.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarray/subscript/
|
||||||
|
FORCE_INLINE detail::ElementProxy<JsonArray> operator[](size_t index) const {
|
||||||
|
return {*this, index};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an object and appends it to the array.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarray/createnestedobject/
|
||||||
|
FORCE_INLINE JsonObject createNestedObject() const;
|
||||||
|
|
||||||
|
// Creates an array and appends it to the array.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarray/createnestedarray/
|
||||||
|
FORCE_INLINE JsonArray createNestedArray() const {
|
||||||
|
return add().to<JsonArray>();
|
||||||
|
}
|
||||||
|
|
||||||
|
operator JsonVariantConst() const {
|
||||||
|
return JsonVariantConst(collectionToVariant(data_));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the reference is unbound.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarray/isnull/
|
||||||
|
FORCE_INLINE bool isNull() const {
|
||||||
|
return data_ == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the reference is bound.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarray/isnull/
|
||||||
|
FORCE_INLINE operator bool() const {
|
||||||
|
return data_ != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the number of bytes occupied by the array.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarray/memoryusage/
|
||||||
|
FORCE_INLINE size_t memoryUsage() const {
|
||||||
|
return data_ ? data_->memoryUsage() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the depth (nesting level) of the array.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarray/nesting/
|
||||||
|
FORCE_INLINE size_t nesting() const {
|
||||||
|
return variantNesting(collectionToVariant(data_));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the number of elements in the array.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarray/size/
|
||||||
|
FORCE_INLINE size_t size() const {
|
||||||
|
return data_ ? data_->size() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
detail::MemoryPool* getPool() const {
|
||||||
|
return pool_;
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::VariantData* getData() const {
|
||||||
|
return collectionToVariant(data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::VariantData* getOrCreateData() const {
|
||||||
|
return collectionToVariant(data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::CollectionData* data_;
|
||||||
|
detail::MemoryPool* pool_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct Converter<JsonArray> : private detail::VariantAttorney {
|
||||||
|
static void toJson(JsonVariantConst src, JsonVariant dst) {
|
||||||
|
variantCopyFrom(getData(dst), getData(src), getPool(dst));
|
||||||
|
}
|
||||||
|
|
||||||
|
static JsonArray fromJson(JsonVariant src) {
|
||||||
|
auto data = getData(src);
|
||||||
|
auto pool = getPool(src);
|
||||||
|
return JsonArray(pool, data != 0 ? data->asArray() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static detail::InvalidConversion<JsonVariantConst, JsonArray> fromJson(
|
||||||
|
JsonVariantConst);
|
||||||
|
|
||||||
|
static bool checkJson(JsonVariantConst) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool checkJson(JsonVariant src) {
|
||||||
|
auto data = getData(src);
|
||||||
|
return data && data->isArray();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,135 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Array/JsonArrayIterator.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantAttorney.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
class JsonObject;
|
||||||
|
|
||||||
|
// A read-only reference to an array in a JsonDocument
|
||||||
|
// https://arduinojson.org/v6/api/jsonarrayconst/
|
||||||
|
class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
|
||||||
|
friend class JsonArray;
|
||||||
|
friend class detail::VariantAttorney;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef JsonArrayConstIterator iterator;
|
||||||
|
|
||||||
|
// Returns an iterator to the first element of the array.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarrayconst/begin/
|
||||||
|
FORCE_INLINE iterator begin() const {
|
||||||
|
if (!data_)
|
||||||
|
return iterator();
|
||||||
|
return iterator(data_->head());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns an iterator to the element following the last element of the array.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarrayconst/end/
|
||||||
|
FORCE_INLINE iterator end() const {
|
||||||
|
return iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an unbound reference.
|
||||||
|
FORCE_INLINE JsonArrayConst() : data_(0) {}
|
||||||
|
|
||||||
|
// INTERNAL USE ONLY
|
||||||
|
FORCE_INLINE JsonArrayConst(const detail::CollectionData* data)
|
||||||
|
: data_(data) {}
|
||||||
|
|
||||||
|
// Compares the content of two arrays.
|
||||||
|
// Returns true if the two arrays are equal.
|
||||||
|
FORCE_INLINE bool operator==(JsonArrayConst rhs) const {
|
||||||
|
if (data_ == rhs.data_)
|
||||||
|
return true;
|
||||||
|
if (!data_ || !rhs.data_)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
iterator it1 = begin();
|
||||||
|
iterator it2 = rhs.begin();
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
bool end1 = it1 == end();
|
||||||
|
bool end2 = it2 == rhs.end();
|
||||||
|
if (end1 && end2)
|
||||||
|
return true;
|
||||||
|
if (end1 || end2)
|
||||||
|
return false;
|
||||||
|
if (*it1 != *it2)
|
||||||
|
return false;
|
||||||
|
++it1;
|
||||||
|
++it2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the element at the specified index.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarrayconst/subscript/
|
||||||
|
FORCE_INLINE JsonVariantConst operator[](size_t index) const {
|
||||||
|
return JsonVariantConst(data_ ? data_->getElement(index) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
operator JsonVariantConst() const {
|
||||||
|
return JsonVariantConst(collectionToVariant(data_));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the reference is unbound.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarrayconst/isnull/
|
||||||
|
FORCE_INLINE bool isNull() const {
|
||||||
|
return data_ == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the reference is bound.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarrayconst/isnull/
|
||||||
|
FORCE_INLINE operator bool() const {
|
||||||
|
return data_ != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the number of bytes occupied by the array.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarrayconst/memoryusage/
|
||||||
|
FORCE_INLINE size_t memoryUsage() const {
|
||||||
|
return data_ ? data_->memoryUsage() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the depth (nesting level) of the array.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarrayconst/nesting/
|
||||||
|
FORCE_INLINE size_t nesting() const {
|
||||||
|
return variantNesting(collectionToVariant(data_));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the number of elements in the array.
|
||||||
|
// https://arduinojson.org/v6/api/jsonarrayconst/size/
|
||||||
|
FORCE_INLINE size_t size() const {
|
||||||
|
return data_ ? data_->size() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const detail::VariantData* getData() const {
|
||||||
|
return collectionToVariant(data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
const detail::CollectionData* data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct Converter<JsonArrayConst> : private detail::VariantAttorney {
|
||||||
|
static void toJson(JsonVariantConst src, JsonVariant dst) {
|
||||||
|
variantCopyFrom(getData(dst), getData(src), getPool(dst));
|
||||||
|
}
|
||||||
|
|
||||||
|
static JsonArrayConst fromJson(JsonVariantConst src) {
|
||||||
|
auto data = getData(src);
|
||||||
|
return data ? data->asArray() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool checkJson(JsonVariantConst src) {
|
||||||
|
auto data = getData(src);
|
||||||
|
return data && data->isArray();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,36 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Array/JsonArray.hpp>
|
||||||
|
#include <ArduinoJson/Object/JsonObject.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
inline JsonObject JsonArray::createNestedObject() const {
|
||||||
|
return add().to<JsonObject>();
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename TDerived>
|
||||||
|
inline JsonArray VariantRefBase<TDerived>::createNestedArray() const {
|
||||||
|
return add().template to<JsonArray>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TDerived>
|
||||||
|
inline JsonObject VariantRefBase<TDerived>::createNestedObject() const {
|
||||||
|
return add().template to<JsonObject>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TDerived>
|
||||||
|
inline ElementProxy<TDerived> VariantRefBase<TDerived>::operator[](
|
||||||
|
size_t index) const {
|
||||||
|
return ElementProxy<TDerived>(derived(), index);
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,121 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Variant/JsonVariant.hpp>
|
||||||
|
#include <ArduinoJson/Variant/SlotFunctions.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
class VariantPtr {
|
||||||
|
public:
|
||||||
|
VariantPtr(detail::MemoryPool* pool, detail::VariantData* data)
|
||||||
|
: variant_(pool, data) {}
|
||||||
|
|
||||||
|
JsonVariant* operator->() {
|
||||||
|
return &variant_;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonVariant& operator*() {
|
||||||
|
return variant_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
JsonVariant variant_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class JsonArrayIterator {
|
||||||
|
friend class JsonArray;
|
||||||
|
|
||||||
|
public:
|
||||||
|
JsonArrayIterator() : slot_(0) {}
|
||||||
|
explicit JsonArrayIterator(detail::MemoryPool* pool,
|
||||||
|
detail::VariantSlot* slot)
|
||||||
|
: pool_(pool), slot_(slot) {}
|
||||||
|
|
||||||
|
JsonVariant operator*() const {
|
||||||
|
return JsonVariant(pool_, slot_->data());
|
||||||
|
}
|
||||||
|
VariantPtr operator->() {
|
||||||
|
return VariantPtr(pool_, slot_->data());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const JsonArrayIterator& other) const {
|
||||||
|
return slot_ == other.slot_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const JsonArrayIterator& other) const {
|
||||||
|
return slot_ != other.slot_;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonArrayIterator& operator++() {
|
||||||
|
slot_ = slot_->next();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonArrayIterator& operator+=(size_t distance) {
|
||||||
|
slot_ = slot_->next(distance);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
detail::MemoryPool* pool_;
|
||||||
|
detail::VariantSlot* slot_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VariantConstPtr {
|
||||||
|
public:
|
||||||
|
VariantConstPtr(const detail::VariantData* data) : variant_(data) {}
|
||||||
|
|
||||||
|
JsonVariantConst* operator->() {
|
||||||
|
return &variant_;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonVariantConst& operator*() {
|
||||||
|
return variant_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
JsonVariantConst variant_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class JsonArrayConstIterator {
|
||||||
|
friend class JsonArray;
|
||||||
|
|
||||||
|
public:
|
||||||
|
JsonArrayConstIterator() : slot_(0) {}
|
||||||
|
explicit JsonArrayConstIterator(const detail::VariantSlot* slot)
|
||||||
|
: slot_(slot) {}
|
||||||
|
|
||||||
|
JsonVariantConst operator*() const {
|
||||||
|
return JsonVariantConst(slot_->data());
|
||||||
|
}
|
||||||
|
VariantConstPtr operator->() {
|
||||||
|
return VariantConstPtr(slot_->data());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const JsonArrayConstIterator& other) const {
|
||||||
|
return slot_ == other.slot_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const JsonArrayConstIterator& other) const {
|
||||||
|
return slot_ != other.slot_;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonArrayConstIterator& operator++() {
|
||||||
|
slot_ = slot_->next();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonArrayConstIterator& operator+=(size_t distance) {
|
||||||
|
slot_ = slot_->next(distance);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const detail::VariantSlot* slot_;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,114 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Array/JsonArray.hpp>
|
||||||
|
#include <ArduinoJson/Document/JsonDocument.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
// Copies a value to a JsonVariant.
|
||||||
|
// This is a degenerated form of copyArray() to stop the recursion.
|
||||||
|
template <typename T>
|
||||||
|
inline typename detail::enable_if<!detail::is_array<T>::value, bool>::type
|
||||||
|
copyArray(const T& src, JsonVariant dst) {
|
||||||
|
return dst.set(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copies values from an array to a JsonArray or a JsonVariant.
|
||||||
|
// https://arduinojson.org/v6/api/misc/copyarray/
|
||||||
|
template <typename T, size_t N, typename TDestination>
|
||||||
|
inline typename detail::enable_if<
|
||||||
|
!detail::is_base_of<JsonDocument, TDestination>::value, bool>::type
|
||||||
|
copyArray(T (&src)[N], const TDestination& dst) {
|
||||||
|
return copyArray(src, N, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copies values from an array to a JsonArray or a JsonVariant.
|
||||||
|
// https://arduinojson.org/v6/api/misc/copyarray/
|
||||||
|
template <typename T, typename TDestination>
|
||||||
|
inline typename detail::enable_if<
|
||||||
|
!detail::is_base_of<JsonDocument, TDestination>::value, bool>::type
|
||||||
|
copyArray(const T* src, size_t len, const TDestination& dst) {
|
||||||
|
bool ok = true;
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
ok &= copyArray(src[i], dst.add());
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copies a string to a JsonVariant.
|
||||||
|
// This is a degenerated form of copyArray() to handle strings.
|
||||||
|
template <typename TDestination>
|
||||||
|
inline bool copyArray(const char* src, size_t, const TDestination& dst) {
|
||||||
|
return dst.set(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copies values from an array to a JsonDocument.
|
||||||
|
// https://arduinojson.org/v6/api/misc/copyarray/
|
||||||
|
template <typename T>
|
||||||
|
inline bool copyArray(const T& src, JsonDocument& dst) {
|
||||||
|
return copyArray(src, dst.to<JsonArray>());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copies an array to a JsonDocument.
|
||||||
|
// https://arduinojson.org/v6/api/misc/copyarray/
|
||||||
|
template <typename T>
|
||||||
|
inline bool copyArray(const T* src, size_t len, JsonDocument& dst) {
|
||||||
|
return copyArray(src, len, dst.to<JsonArray>());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copies a value from a JsonVariant.
|
||||||
|
// This is a degenerated form of copyArray() to stop the recursion.
|
||||||
|
template <typename T>
|
||||||
|
inline typename detail::enable_if<!detail::is_array<T>::value, size_t>::type
|
||||||
|
copyArray(JsonVariantConst src, T& dst) {
|
||||||
|
dst = src.as<T>();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copies values from a JsonArray or JsonVariant to an array.
|
||||||
|
// https://arduinojson.org/v6/api/misc/copyarray/
|
||||||
|
template <typename T, size_t N>
|
||||||
|
inline size_t copyArray(JsonArrayConst src, T (&dst)[N]) {
|
||||||
|
return copyArray(src, dst, N);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copies values from a JsonArray or JsonVariant to an array.
|
||||||
|
// https://arduinojson.org/v6/api/misc/copyarray/
|
||||||
|
template <typename T>
|
||||||
|
inline size_t copyArray(JsonArrayConst src, T* dst, size_t len) {
|
||||||
|
size_t i = 0;
|
||||||
|
for (JsonArrayConst::iterator it = src.begin(); it != src.end() && i < len;
|
||||||
|
++it)
|
||||||
|
copyArray(*it, dst[i++]);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copies a string from a JsonVariant.
|
||||||
|
// This is a degenerated form of copyArray() to handle strings.
|
||||||
|
template <size_t N>
|
||||||
|
inline size_t copyArray(JsonVariantConst src, char (&dst)[N]) {
|
||||||
|
JsonString s = src;
|
||||||
|
size_t len = N - 1;
|
||||||
|
if (len > s.size())
|
||||||
|
len = s.size();
|
||||||
|
memcpy(dst, s.c_str(), len);
|
||||||
|
dst[len] = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copies values from a JsonDocument to an array.
|
||||||
|
// https://arduinojson.org/v6/api/misc/copyarray/
|
||||||
|
template <typename TSource, typename T>
|
||||||
|
inline typename detail::enable_if<
|
||||||
|
detail::is_array<T>::value &&
|
||||||
|
detail::is_base_of<JsonDocument, TSource>::value,
|
||||||
|
size_t>::type
|
||||||
|
copyArray(const TSource& src, T& dst) {
|
||||||
|
return copyArray(src.template as<JsonArrayConst>(), dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,95 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||||
|
|
||||||
|
#include <stddef.h> // size_t
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
class MemoryPool;
|
||||||
|
class VariantData;
|
||||||
|
class VariantSlot;
|
||||||
|
|
||||||
|
class CollectionData {
|
||||||
|
VariantSlot* head_;
|
||||||
|
VariantSlot* tail_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Must be a POD!
|
||||||
|
// - no constructor
|
||||||
|
// - no destructor
|
||||||
|
// - no virtual
|
||||||
|
// - no inheritance
|
||||||
|
|
||||||
|
// Array only
|
||||||
|
|
||||||
|
VariantData* addElement(MemoryPool* pool);
|
||||||
|
|
||||||
|
VariantData* getElement(size_t index) const;
|
||||||
|
|
||||||
|
VariantData* getOrAddElement(size_t index, MemoryPool* pool);
|
||||||
|
|
||||||
|
void removeElement(size_t index);
|
||||||
|
|
||||||
|
// Object only
|
||||||
|
|
||||||
|
template <typename TAdaptedString>
|
||||||
|
VariantData* addMember(TAdaptedString key, MemoryPool* pool);
|
||||||
|
|
||||||
|
template <typename TAdaptedString>
|
||||||
|
VariantData* getMember(TAdaptedString key) const;
|
||||||
|
|
||||||
|
template <typename TAdaptedString>
|
||||||
|
VariantData* getOrAddMember(TAdaptedString key, MemoryPool* pool);
|
||||||
|
|
||||||
|
template <typename TAdaptedString>
|
||||||
|
void removeMember(TAdaptedString key) {
|
||||||
|
removeSlot(getSlot(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TAdaptedString>
|
||||||
|
bool containsKey(const TAdaptedString& key) const;
|
||||||
|
|
||||||
|
// Generic
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
size_t memoryUsage() const;
|
||||||
|
size_t size() const;
|
||||||
|
|
||||||
|
VariantSlot* addSlot(MemoryPool*);
|
||||||
|
void removeSlot(VariantSlot* slot);
|
||||||
|
|
||||||
|
bool copyFrom(const CollectionData& src, MemoryPool* pool);
|
||||||
|
|
||||||
|
VariantSlot* head() const {
|
||||||
|
return head_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance);
|
||||||
|
|
||||||
|
private:
|
||||||
|
VariantSlot* getSlot(size_t index) const;
|
||||||
|
|
||||||
|
template <typename TAdaptedString>
|
||||||
|
VariantSlot* getSlot(TAdaptedString key) const;
|
||||||
|
|
||||||
|
VariantSlot* getPreviousSlot(VariantSlot*) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const VariantData* collectionToVariant(
|
||||||
|
const CollectionData* collection) {
|
||||||
|
const void* data = collection; // prevent warning cast-align
|
||||||
|
return reinterpret_cast<const VariantData*>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VariantData* collectionToVariant(CollectionData* collection) {
|
||||||
|
void* data = collection; // prevent warning cast-align
|
||||||
|
return reinterpret_cast<VariantData*>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,197 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Collection/CollectionData.hpp>
|
||||||
|
#include <ArduinoJson/Strings/StoragePolicy.hpp>
|
||||||
|
#include <ArduinoJson/Strings/StringAdapters.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) {
|
||||||
|
VariantSlot* slot = pool->allocVariant();
|
||||||
|
if (!slot)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (tail_) {
|
||||||
|
ARDUINOJSON_ASSERT(pool->owns(tail_)); // Can't alter a linked array/object
|
||||||
|
tail_->setNextNotNull(slot);
|
||||||
|
tail_ = slot;
|
||||||
|
} else {
|
||||||
|
head_ = slot;
|
||||||
|
tail_ = slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
slot->clear();
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VariantData* CollectionData::addElement(MemoryPool* pool) {
|
||||||
|
return slotData(addSlot(pool));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TAdaptedString>
|
||||||
|
inline VariantData* CollectionData::addMember(TAdaptedString key,
|
||||||
|
MemoryPool* pool) {
|
||||||
|
VariantSlot* slot = addSlot(pool);
|
||||||
|
if (!slotSetKey(slot, key, pool)) {
|
||||||
|
removeSlot(slot);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return slot->data();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void CollectionData::clear() {
|
||||||
|
head_ = 0;
|
||||||
|
tail_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TAdaptedString>
|
||||||
|
inline bool CollectionData::containsKey(const TAdaptedString& key) const {
|
||||||
|
return getSlot(key) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool CollectionData::copyFrom(const CollectionData& src,
|
||||||
|
MemoryPool* pool) {
|
||||||
|
clear();
|
||||||
|
for (VariantSlot* s = src.head_; s; s = s->next()) {
|
||||||
|
VariantData* var;
|
||||||
|
if (s->key() != 0) {
|
||||||
|
JsonString key(s->key(),
|
||||||
|
s->ownsKey() ? JsonString::Copied : JsonString::Linked);
|
||||||
|
var = addMember(adaptString(key), pool);
|
||||||
|
} else {
|
||||||
|
var = addElement(pool);
|
||||||
|
}
|
||||||
|
if (!var)
|
||||||
|
return false;
|
||||||
|
if (!var->copyFrom(*s->data(), pool))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TAdaptedString>
|
||||||
|
inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const {
|
||||||
|
if (key.isNull())
|
||||||
|
return 0;
|
||||||
|
VariantSlot* slot = head_;
|
||||||
|
while (slot) {
|
||||||
|
if (stringEquals(key, adaptString(slot->key())))
|
||||||
|
break;
|
||||||
|
slot = slot->next();
|
||||||
|
}
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VariantSlot* CollectionData::getSlot(size_t index) const {
|
||||||
|
if (!head_)
|
||||||
|
return 0;
|
||||||
|
return head_->next(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VariantSlot* CollectionData::getPreviousSlot(VariantSlot* target) const {
|
||||||
|
VariantSlot* current = head_;
|
||||||
|
while (current) {
|
||||||
|
VariantSlot* next = current->next();
|
||||||
|
if (next == target)
|
||||||
|
return current;
|
||||||
|
current = next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TAdaptedString>
|
||||||
|
inline VariantData* CollectionData::getMember(TAdaptedString key) const {
|
||||||
|
VariantSlot* slot = getSlot(key);
|
||||||
|
return slot ? slot->data() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TAdaptedString>
|
||||||
|
inline VariantData* CollectionData::getOrAddMember(TAdaptedString key,
|
||||||
|
MemoryPool* pool) {
|
||||||
|
// ignore null key
|
||||||
|
if (key.isNull())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// search a matching key
|
||||||
|
VariantSlot* slot = getSlot(key);
|
||||||
|
if (slot)
|
||||||
|
return slot->data();
|
||||||
|
|
||||||
|
return addMember(key, pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VariantData* CollectionData::getElement(size_t index) const {
|
||||||
|
VariantSlot* slot = getSlot(index);
|
||||||
|
return slot ? slot->data() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VariantData* CollectionData::getOrAddElement(size_t index,
|
||||||
|
MemoryPool* pool) {
|
||||||
|
VariantSlot* slot = head_;
|
||||||
|
while (slot && index > 0) {
|
||||||
|
slot = slot->next();
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
if (!slot)
|
||||||
|
index++;
|
||||||
|
while (index > 0) {
|
||||||
|
slot = addSlot(pool);
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
return slotData(slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void CollectionData::removeSlot(VariantSlot* slot) {
|
||||||
|
if (!slot)
|
||||||
|
return;
|
||||||
|
VariantSlot* prev = getPreviousSlot(slot);
|
||||||
|
VariantSlot* next = slot->next();
|
||||||
|
if (prev)
|
||||||
|
prev->setNext(next);
|
||||||
|
else
|
||||||
|
head_ = next;
|
||||||
|
if (!next)
|
||||||
|
tail_ = prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void CollectionData::removeElement(size_t index) {
|
||||||
|
removeSlot(getSlot(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t CollectionData::memoryUsage() const {
|
||||||
|
size_t total = 0;
|
||||||
|
for (VariantSlot* s = head_; s; s = s->next()) {
|
||||||
|
total += sizeof(VariantSlot) + s->data()->memoryUsage();
|
||||||
|
if (s->ownsKey())
|
||||||
|
total += strlen(s->key()) + 1;
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t CollectionData::size() const {
|
||||||
|
return slotSize(head_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline void movePointer(T*& p, ptrdiff_t offset) {
|
||||||
|
if (!p)
|
||||||
|
return;
|
||||||
|
p = reinterpret_cast<T*>(
|
||||||
|
reinterpret_cast<void*>(reinterpret_cast<char*>(p) + offset));
|
||||||
|
ARDUINOJSON_ASSERT(isAligned(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void CollectionData::movePointers(ptrdiff_t stringDistance,
|
||||||
|
ptrdiff_t variantDistance) {
|
||||||
|
movePointer(head_, variantDistance);
|
||||||
|
movePointer(tail_, variantDistance);
|
||||||
|
for (VariantSlot* slot = head_; slot; slot = slot->next())
|
||||||
|
slot->movePointers(stringDistance, variantDistance);
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,217 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Support std::istream and std::ostream
|
||||||
|
#ifndef ARDUINOJSON_ENABLE_STD_STREAM
|
||||||
|
# ifdef __has_include
|
||||||
|
# if __has_include(<istream>) && \
|
||||||
|
__has_include(<ostream>) && \
|
||||||
|
!defined(min) && \
|
||||||
|
!defined(max)
|
||||||
|
# define ARDUINOJSON_ENABLE_STD_STREAM 1
|
||||||
|
# else
|
||||||
|
# define ARDUINOJSON_ENABLE_STD_STREAM 0
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# ifdef ARDUINO
|
||||||
|
# define ARDUINOJSON_ENABLE_STD_STREAM 0
|
||||||
|
# else
|
||||||
|
# define ARDUINOJSON_ENABLE_STD_STREAM 1
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Support std::string
|
||||||
|
#ifndef ARDUINOJSON_ENABLE_STD_STRING
|
||||||
|
# ifdef __has_include
|
||||||
|
# if __has_include(<string>) && !defined(min) && !defined(max)
|
||||||
|
# define ARDUINOJSON_ENABLE_STD_STRING 1
|
||||||
|
# else
|
||||||
|
# define ARDUINOJSON_ENABLE_STD_STRING 0
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# ifdef ARDUINO
|
||||||
|
# define ARDUINOJSON_ENABLE_STD_STRING 0
|
||||||
|
# else
|
||||||
|
# define ARDUINOJSON_ENABLE_STD_STRING 1
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Support for std::string_view
|
||||||
|
#ifndef ARDUINOJSON_ENABLE_STRING_VIEW
|
||||||
|
# ifdef __has_include
|
||||||
|
# if __has_include(<string_view>) && __cplusplus >= 201703L
|
||||||
|
# define ARDUINOJSON_ENABLE_STRING_VIEW 1
|
||||||
|
# else
|
||||||
|
# define ARDUINOJSON_ENABLE_STRING_VIEW 0
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# define ARDUINOJSON_ENABLE_STRING_VIEW 0
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Store floating-point values with float (0) or double (1)
|
||||||
|
#ifndef ARDUINOJSON_USE_DOUBLE
|
||||||
|
# define ARDUINOJSON_USE_DOUBLE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Store integral values with long (0) or long long (1)
|
||||||
|
#ifndef ARDUINOJSON_USE_LONG_LONG
|
||||||
|
# if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ >= 4 || \
|
||||||
|
defined(_MSC_VER)
|
||||||
|
# define ARDUINOJSON_USE_LONG_LONG 1
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#ifndef ARDUINOJSON_USE_LONG_LONG
|
||||||
|
# define ARDUINOJSON_USE_LONG_LONG 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Limit nesting as the stack is likely to be small
|
||||||
|
#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT
|
||||||
|
# define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Number of bits to store the pointer to next node
|
||||||
|
// (saves RAM but limits the number of values in a document)
|
||||||
|
#ifndef ARDUINOJSON_SLOT_OFFSET_SIZE
|
||||||
|
# if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ <= 2
|
||||||
|
// Address space == 16-bit => max 127 values
|
||||||
|
# define ARDUINOJSON_SLOT_OFFSET_SIZE 1
|
||||||
|
# elif defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ >= 8 || \
|
||||||
|
defined(_WIN64) && _WIN64
|
||||||
|
// Address space == 64-bit => max 2147483647 values
|
||||||
|
# define ARDUINOJSON_SLOT_OFFSET_SIZE 4
|
||||||
|
# else
|
||||||
|
// Address space == 32-bit => max 32767 values
|
||||||
|
# define ARDUINOJSON_SLOT_OFFSET_SIZE 2
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ARDUINO
|
||||||
|
|
||||||
|
// Enable support for Arduino's String class
|
||||||
|
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
|
||||||
|
# define ARDUINOJSON_ENABLE_ARDUINO_STRING 1
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// Enable support for Arduino's Stream class
|
||||||
|
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
|
||||||
|
# define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// Enable support for Arduino's Print class
|
||||||
|
# ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT
|
||||||
|
# define ARDUINOJSON_ENABLE_ARDUINO_PRINT 1
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// Enable support for PROGMEM
|
||||||
|
# ifndef ARDUINOJSON_ENABLE_PROGMEM
|
||||||
|
# define ARDUINOJSON_ENABLE_PROGMEM 1
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#else // ARDUINO
|
||||||
|
|
||||||
|
// Disable support for Arduino's String class
|
||||||
|
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
|
||||||
|
# define ARDUINOJSON_ENABLE_ARDUINO_STRING 0
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// Disable support for Arduino's Stream class
|
||||||
|
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
|
||||||
|
# define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// Disable support for Arduino's Print class
|
||||||
|
# ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT
|
||||||
|
# define ARDUINOJSON_ENABLE_ARDUINO_PRINT 0
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// Enable PROGMEM support on AVR only
|
||||||
|
# ifndef ARDUINOJSON_ENABLE_PROGMEM
|
||||||
|
# ifdef __AVR__
|
||||||
|
# define ARDUINOJSON_ENABLE_PROGMEM 1
|
||||||
|
# else
|
||||||
|
# define ARDUINOJSON_ENABLE_PROGMEM 0
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif // ARDUINO
|
||||||
|
|
||||||
|
// Convert unicode escape sequence (\u0123) to UTF-8
|
||||||
|
#ifndef ARDUINOJSON_DECODE_UNICODE
|
||||||
|
# define ARDUINOJSON_DECODE_UNICODE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Ignore comments in input
|
||||||
|
#ifndef ARDUINOJSON_ENABLE_COMMENTS
|
||||||
|
# define ARDUINOJSON_ENABLE_COMMENTS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Support NaN in JSON
|
||||||
|
#ifndef ARDUINOJSON_ENABLE_NAN
|
||||||
|
# define ARDUINOJSON_ENABLE_NAN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Support Infinity in JSON
|
||||||
|
#ifndef ARDUINOJSON_ENABLE_INFINITY
|
||||||
|
# define ARDUINOJSON_ENABLE_INFINITY 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Control the exponentiation threshold for big numbers
|
||||||
|
// CAUTION: cannot be more that 1e9 !!!!
|
||||||
|
#ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD
|
||||||
|
# define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e7
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Control the exponentiation threshold for small numbers
|
||||||
|
#ifndef ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD
|
||||||
|
# define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ARDUINOJSON_LITTLE_ENDIAN
|
||||||
|
# if defined(_MSC_VER) || \
|
||||||
|
(defined(__BYTE_ORDER__) && \
|
||||||
|
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \
|
||||||
|
defined(__LITTLE_ENDIAN__) || defined(__i386) || defined(__x86_64)
|
||||||
|
# define ARDUINOJSON_LITTLE_ENDIAN 1
|
||||||
|
# else
|
||||||
|
# define ARDUINOJSON_LITTLE_ENDIAN 0
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ARDUINOJSON_ENABLE_ALIGNMENT
|
||||||
|
# if defined(__AVR)
|
||||||
|
# define ARDUINOJSON_ENABLE_ALIGNMENT 0
|
||||||
|
# else
|
||||||
|
# define ARDUINOJSON_ENABLE_ALIGNMENT 1
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ARDUINOJSON_TAB
|
||||||
|
# define ARDUINOJSON_TAB " "
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
|
||||||
|
# define ARDUINOJSON_ENABLE_STRING_DEDUPLICATION 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ARDUINOJSON_STRING_BUFFER_SIZE
|
||||||
|
# define ARDUINOJSON_STRING_BUFFER_SIZE 32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ARDUINOJSON_DEBUG
|
||||||
|
# ifdef __PLATFORMIO_BUILD_DEBUG__
|
||||||
|
# define ARDUINOJSON_DEBUG 1
|
||||||
|
# else
|
||||||
|
# define ARDUINOJSON_DEBUG 0
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 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
|
@ -0,0 +1,106 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/pgmspace_generic.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/preprocessor.hpp>
|
||||||
|
|
||||||
|
#if ARDUINOJSON_ENABLE_STD_STREAM
|
||||||
|
# include <ostream>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
class DeserializationError {
|
||||||
|
public:
|
||||||
|
enum Code {
|
||||||
|
Ok,
|
||||||
|
EmptyInput,
|
||||||
|
IncompleteInput,
|
||||||
|
InvalidInput,
|
||||||
|
NoMemory,
|
||||||
|
TooDeep
|
||||||
|
};
|
||||||
|
|
||||||
|
DeserializationError() {}
|
||||||
|
DeserializationError(Code c) : code_(c) {}
|
||||||
|
|
||||||
|
// Compare with DeserializationError
|
||||||
|
friend bool operator==(const DeserializationError& lhs,
|
||||||
|
const DeserializationError& rhs) {
|
||||||
|
return lhs.code_ == rhs.code_;
|
||||||
|
}
|
||||||
|
friend bool operator!=(const DeserializationError& lhs,
|
||||||
|
const DeserializationError& rhs) {
|
||||||
|
return lhs.code_ != rhs.code_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare with Code
|
||||||
|
friend bool operator==(const DeserializationError& lhs, Code rhs) {
|
||||||
|
return lhs.code_ == rhs;
|
||||||
|
}
|
||||||
|
friend bool operator==(Code lhs, const DeserializationError& rhs) {
|
||||||
|
return lhs == rhs.code_;
|
||||||
|
}
|
||||||
|
friend bool operator!=(const DeserializationError& lhs, Code rhs) {
|
||||||
|
return lhs.code_ != rhs;
|
||||||
|
}
|
||||||
|
friend bool operator!=(Code lhs, const DeserializationError& rhs) {
|
||||||
|
return lhs != rhs.code_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if there is an error
|
||||||
|
explicit operator bool() const {
|
||||||
|
return code_ != Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns internal enum, useful for switch statement
|
||||||
|
Code code() const {
|
||||||
|
return code_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* c_str() const {
|
||||||
|
static const char* messages[] = {
|
||||||
|
"Ok", "EmptyInput", "IncompleteInput",
|
||||||
|
"InvalidInput", "NoMemory", "TooDeep"};
|
||||||
|
ARDUINOJSON_ASSERT(static_cast<size_t>(code_) <
|
||||||
|
sizeof(messages) / sizeof(messages[0]));
|
||||||
|
return messages[code_];
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ARDUINOJSON_ENABLE_PROGMEM
|
||||||
|
const __FlashStringHelper* f_str() const {
|
||||||
|
ARDUINOJSON_DEFINE_PROGMEM_ARRAY(char, s0, "Ok");
|
||||||
|
ARDUINOJSON_DEFINE_PROGMEM_ARRAY(char, s1, "EmptyInput");
|
||||||
|
ARDUINOJSON_DEFINE_PROGMEM_ARRAY(char, s2, "IncompleteInput");
|
||||||
|
ARDUINOJSON_DEFINE_PROGMEM_ARRAY(char, s3, "InvalidInput");
|
||||||
|
ARDUINOJSON_DEFINE_PROGMEM_ARRAY(char, s4, "NoMemory");
|
||||||
|
ARDUINOJSON_DEFINE_PROGMEM_ARRAY(char, s5, "TooDeep");
|
||||||
|
ARDUINOJSON_DEFINE_PROGMEM_ARRAY(const char*, messages,
|
||||||
|
{s0, s1, s2, s3, s4, s5});
|
||||||
|
return reinterpret_cast<const __FlashStringHelper*>(
|
||||||
|
detail::pgm_read(messages + code_));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
Code code_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if ARDUINOJSON_ENABLE_STD_STREAM
|
||||||
|
inline std::ostream& operator<<(std::ostream& s,
|
||||||
|
const DeserializationError& e) {
|
||||||
|
s << e.c_str();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& s, DeserializationError::Code c) {
|
||||||
|
s << DeserializationError(c).c_str();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,35 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Deserialization/Filter.hpp>
|
||||||
|
#include <ArduinoJson/Deserialization/NestingLimit.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename TFilter>
|
||||||
|
struct DeserializationOptions {
|
||||||
|
TFilter filter;
|
||||||
|
DeserializationOption::NestingLimit nestingLimit;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TFilter>
|
||||||
|
inline DeserializationOptions<TFilter> makeDeserializationOptions(
|
||||||
|
TFilter filter, DeserializationOption::NestingLimit nestingLimit = {}) {
|
||||||
|
return {filter, nestingLimit};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TFilter>
|
||||||
|
inline DeserializationOptions<TFilter> makeDeserializationOptions(
|
||||||
|
DeserializationOption::NestingLimit nestingLimit, TFilter filter) {
|
||||||
|
return {filter, nestingLimit};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DeserializationOptions<AllowAllFilter> makeDeserializationOptions(
|
||||||
|
DeserializationOption::NestingLimit nestingLimit = {}) {
|
||||||
|
return {{}, nestingLimit};
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,70 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
namespace DeserializationOption {
|
||||||
|
class Filter {
|
||||||
|
public:
|
||||||
|
explicit Filter(JsonVariantConst v) : variant_(v) {}
|
||||||
|
|
||||||
|
bool allow() const {
|
||||||
|
return variant_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool allowArray() const {
|
||||||
|
return variant_ == true || variant_.is<JsonArrayConst>();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool allowObject() const {
|
||||||
|
return variant_ == true || variant_.is<JsonObjectConst>();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool allowValue() const {
|
||||||
|
return variant_ == true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TKey>
|
||||||
|
Filter operator[](const TKey& key) const {
|
||||||
|
if (variant_ == true) // "true" means "allow recursively"
|
||||||
|
return *this;
|
||||||
|
JsonVariantConst member = variant_[key];
|
||||||
|
return Filter(member.isNull() ? variant_["*"] : member);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
JsonVariantConst variant_;
|
||||||
|
};
|
||||||
|
} // namespace DeserializationOption
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
struct AllowAllFilter {
|
||||||
|
bool allow() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool allowArray() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool allowObject() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool allowValue() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TKey>
|
||||||
|
AllowAllFilter operator[](const TKey&) const {
|
||||||
|
return AllowAllFilter();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,32 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
namespace DeserializationOption {
|
||||||
|
class NestingLimit {
|
||||||
|
public:
|
||||||
|
NestingLimit() : value_(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {}
|
||||||
|
explicit NestingLimit(uint8_t n) : value_(n) {}
|
||||||
|
|
||||||
|
NestingLimit decrement() const {
|
||||||
|
ARDUINOJSON_ASSERT(value_ > 0);
|
||||||
|
return NestingLimit(static_cast<uint8_t>(value_ - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool reached() const {
|
||||||
|
return value_ == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t value_;
|
||||||
|
};
|
||||||
|
} // namespace DeserializationOption
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,75 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/utility.hpp>
|
||||||
|
|
||||||
|
#include <stdlib.h> // for size_t
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
// The default reader is a simple wrapper for Readers that are not copiable
|
||||||
|
template <typename TSource, typename Enable = void>
|
||||||
|
struct Reader {
|
||||||
|
public:
|
||||||
|
Reader(TSource& source) : source_(&source) {}
|
||||||
|
|
||||||
|
int read() {
|
||||||
|
// clang-format off
|
||||||
|
return source_->read(); // Error here? See https://arduinojson.org/v6/invalid-input/
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t readBytes(char* buffer, size_t length) {
|
||||||
|
return source_->readBytes(buffer, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TSource* source_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TSource, typename Enable = void>
|
||||||
|
struct BoundedReader {
|
||||||
|
// no default implementation because we need to pass the size to the
|
||||||
|
// constructor
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
#include <ArduinoJson/Deserialization/Readers/IteratorReader.hpp>
|
||||||
|
#include <ArduinoJson/Deserialization/Readers/RamReader.hpp>
|
||||||
|
#include <ArduinoJson/Deserialization/Readers/VariantReader.hpp>
|
||||||
|
|
||||||
|
#if ARDUINOJSON_ENABLE_ARDUINO_STREAM
|
||||||
|
# include <ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
|
||||||
|
# include <ArduinoJson/Deserialization/Readers/ArduinoStringReader.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ARDUINOJSON_ENABLE_PROGMEM
|
||||||
|
# include <ArduinoJson/Deserialization/Readers/FlashReader.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ARDUINOJSON_ENABLE_STD_STREAM
|
||||||
|
# include <ArduinoJson/Deserialization/Readers/StdStreamReader.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename TInput>
|
||||||
|
Reader<typename remove_reference<TInput>::type> makeReader(TInput&& input) {
|
||||||
|
return Reader<typename remove_reference<TInput>::type>{
|
||||||
|
detail::forward<TInput>(input)};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TChar>
|
||||||
|
BoundedReader<TChar*> makeReader(TChar* input, size_t inputSize) {
|
||||||
|
return BoundedReader<TChar*>{input, inputSize};
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,31 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename TSource>
|
||||||
|
struct Reader<TSource,
|
||||||
|
typename enable_if<is_base_of<Stream, TSource>::value>::type> {
|
||||||
|
public:
|
||||||
|
explicit Reader(Stream& stream) : stream_(&stream) {}
|
||||||
|
|
||||||
|
int read() {
|
||||||
|
// don't use stream_.read() as it ignores the timeout
|
||||||
|
char c;
|
||||||
|
return stream_->readBytes(&c, 1) ? static_cast<unsigned char>(c) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t readBytes(char* buffer, size_t length) {
|
||||||
|
return stream_->readBytes(buffer, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Stream* stream_;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,19 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename TSource>
|
||||||
|
struct Reader<TSource,
|
||||||
|
typename enable_if<is_base_of<::String, TSource>::value>::type>
|
||||||
|
: BoundedReader<const char*> {
|
||||||
|
explicit Reader(const ::String& s)
|
||||||
|
: BoundedReader<const char*>(s.c_str(), s.length()) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,56 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Polyfills/pgmspace.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct Reader<const __FlashStringHelper*, void> {
|
||||||
|
const char* ptr_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Reader(const __FlashStringHelper* ptr)
|
||||||
|
: ptr_(reinterpret_cast<const char*>(ptr)) {}
|
||||||
|
|
||||||
|
int read() {
|
||||||
|
return pgm_read_byte(ptr_++);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t readBytes(char* buffer, size_t length) {
|
||||||
|
memcpy_P(buffer, ptr_, length);
|
||||||
|
ptr_ += length;
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct BoundedReader<const __FlashStringHelper*, void> {
|
||||||
|
const char* ptr_;
|
||||||
|
const char* end_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit BoundedReader(const __FlashStringHelper* ptr, size_t size)
|
||||||
|
: ptr_(reinterpret_cast<const char*>(ptr)), end_(ptr_ + size) {}
|
||||||
|
|
||||||
|
int read() {
|
||||||
|
if (ptr_ < end_)
|
||||||
|
return pgm_read_byte(ptr_++);
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t readBytes(char* buffer, size_t length) {
|
||||||
|
size_t available = static_cast<size_t>(end_ - ptr_);
|
||||||
|
if (available < length)
|
||||||
|
length = available;
|
||||||
|
memcpy_P(buffer, ptr_, length);
|
||||||
|
ptr_ += length;
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,45 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename TIterator>
|
||||||
|
class IteratorReader {
|
||||||
|
TIterator ptr_, end_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit IteratorReader(TIterator begin, TIterator end)
|
||||||
|
: ptr_(begin), end_(end) {}
|
||||||
|
|
||||||
|
int read() {
|
||||||
|
if (ptr_ < end_)
|
||||||
|
return static_cast<unsigned char>(*ptr_++);
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t readBytes(char* buffer, size_t length) {
|
||||||
|
size_t i = 0;
|
||||||
|
while (i < length && ptr_ < end_)
|
||||||
|
buffer[i++] = *ptr_++;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct void_ {
|
||||||
|
typedef void type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TSource>
|
||||||
|
struct Reader<TSource, typename void_<typename TSource::const_iterator>::type>
|
||||||
|
: IteratorReader<typename TSource::const_iterator> {
|
||||||
|
explicit Reader(const TSource& source)
|
||||||
|
: IteratorReader<typename TSource::const_iterator>(source.begin(),
|
||||||
|
source.end()) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,51 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct IsCharOrVoid {
|
||||||
|
static const bool value =
|
||||||
|
is_same<T, void>::value || is_same<T, char>::value ||
|
||||||
|
is_same<T, unsigned char>::value || is_same<T, signed char>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct IsCharOrVoid<const T> : IsCharOrVoid<T> {};
|
||||||
|
|
||||||
|
template <typename TSource>
|
||||||
|
struct Reader<TSource*,
|
||||||
|
typename enable_if<IsCharOrVoid<TSource>::value>::type> {
|
||||||
|
const char* ptr_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Reader(const void* ptr)
|
||||||
|
: ptr_(ptr ? reinterpret_cast<const char*>(ptr) : "") {}
|
||||||
|
|
||||||
|
int read() {
|
||||||
|
return static_cast<unsigned char>(*ptr_++);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t readBytes(char* buffer, size_t length) {
|
||||||
|
for (size_t i = 0; i < length; i++)
|
||||||
|
buffer[i] = *ptr_++;
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TSource>
|
||||||
|
struct BoundedReader<TSource*,
|
||||||
|
typename enable_if<IsCharOrVoid<TSource>::value>::type>
|
||||||
|
: public IteratorReader<const char*> {
|
||||||
|
public:
|
||||||
|
explicit BoundedReader(const void* ptr, size_t len)
|
||||||
|
: IteratorReader<const char*>(reinterpret_cast<const char*>(ptr),
|
||||||
|
reinterpret_cast<const char*>(ptr) + len) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,30 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <istream>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename TSource>
|
||||||
|
struct Reader<TSource, typename enable_if<
|
||||||
|
is_base_of<std::istream, TSource>::value>::type> {
|
||||||
|
public:
|
||||||
|
explicit Reader(std::istream& stream) : stream_(&stream) {}
|
||||||
|
|
||||||
|
int read() {
|
||||||
|
return stream_->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t readBytes(char* buffer, size_t length) {
|
||||||
|
stream_->read(buffer, static_cast<std::streamsize>(length));
|
||||||
|
return static_cast<size_t>(stream_->gcount());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::istream* stream_;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,19 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Object/MemberProxy.hpp>
|
||||||
|
#include <ArduinoJson/Variant/JsonVariantConst.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename TVariant>
|
||||||
|
struct Reader<TVariant, typename enable_if<IsVariant<TVariant>::value>::type>
|
||||||
|
: Reader<char*, void> {
|
||||||
|
explicit Reader(const TVariant& x)
|
||||||
|
: Reader<char*, void>(x.template as<const char*>()) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,66 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Deserialization/DeserializationError.hpp>
|
||||||
|
#include <ArduinoJson/Deserialization/DeserializationOptions.hpp>
|
||||||
|
#include <ArduinoJson/Deserialization/Reader.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/utility.hpp>
|
||||||
|
#include <ArduinoJson/StringStorage/StringStorage.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
// A meta-function that returns the first type of the parameter pack
|
||||||
|
// or void if empty
|
||||||
|
template <typename...>
|
||||||
|
struct first_or_void {
|
||||||
|
using type = void;
|
||||||
|
};
|
||||||
|
template <typename T, typename... Rest>
|
||||||
|
struct first_or_void<T, Rest...> {
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <template <typename, typename> class TDeserializer, typename TReader,
|
||||||
|
typename TWriter>
|
||||||
|
TDeserializer<TReader, TWriter> makeDeserializer(MemoryPool* pool,
|
||||||
|
TReader reader,
|
||||||
|
TWriter writer) {
|
||||||
|
ARDUINOJSON_ASSERT(pool != 0);
|
||||||
|
return TDeserializer<TReader, TWriter>(pool, reader, writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <template <typename, typename> class TDeserializer, typename TStream,
|
||||||
|
typename... Args,
|
||||||
|
typename = typename enable_if< // issue #1897
|
||||||
|
!is_integral<typename first_or_void<Args...>::type>::value>::type>
|
||||||
|
DeserializationError deserialize(JsonDocument& doc, TStream&& input,
|
||||||
|
Args... args) {
|
||||||
|
auto reader = makeReader(detail::forward<TStream>(input));
|
||||||
|
auto data = VariantAttorney::getData(doc);
|
||||||
|
auto pool = VariantAttorney::getPool(doc);
|
||||||
|
auto options = makeDeserializationOptions(args...);
|
||||||
|
doc.clear();
|
||||||
|
return makeDeserializer<TDeserializer>(pool, reader,
|
||||||
|
makeStringStorage(input, pool))
|
||||||
|
.parse(*data, options.filter, options.nestingLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <template <typename, typename> class TDeserializer, typename TChar,
|
||||||
|
typename Size, typename... Args,
|
||||||
|
typename = typename enable_if<is_integral<Size>::value>::type>
|
||||||
|
DeserializationError deserialize(JsonDocument& doc, TChar* input,
|
||||||
|
Size inputSize, Args... args) {
|
||||||
|
auto reader = makeReader(input, size_t(inputSize));
|
||||||
|
auto data = VariantAttorney::getData(doc);
|
||||||
|
auto pool = VariantAttorney::getPool(doc);
|
||||||
|
auto options = makeDeserializationOptions(args...);
|
||||||
|
doc.clear();
|
||||||
|
return makeDeserializer<TDeserializer>(pool, reader,
|
||||||
|
makeStringStorage(input, pool))
|
||||||
|
.parse(*data, options.filter, options.nestingLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,168 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Document/JsonDocument.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
// Helper to implement the "base-from-member" idiom
|
||||||
|
// (we need to store the allocator before constructing JsonDocument)
|
||||||
|
template <typename TAllocator>
|
||||||
|
class AllocatorOwner {
|
||||||
|
public:
|
||||||
|
AllocatorOwner() {}
|
||||||
|
AllocatorOwner(TAllocator a) : allocator_(a) {}
|
||||||
|
|
||||||
|
void* allocate(size_t size) {
|
||||||
|
return allocator_.allocate(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(void* ptr) {
|
||||||
|
if (ptr)
|
||||||
|
allocator_.deallocate(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* reallocate(void* ptr, size_t new_size) {
|
||||||
|
return allocator_.reallocate(ptr, new_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
TAllocator& allocator() {
|
||||||
|
return allocator_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TAllocator allocator_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A JsonDocument that uses the provided allocator to allocate its memory pool.
|
||||||
|
// https://arduinojson.org/v6/api/basicjsondocument/
|
||||||
|
template <typename TAllocator>
|
||||||
|
class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument {
|
||||||
|
public:
|
||||||
|
explicit BasicJsonDocument(size_t capa, TAllocator alloc = TAllocator())
|
||||||
|
: AllocatorOwner<TAllocator>(alloc), JsonDocument(allocPool(capa)) {}
|
||||||
|
|
||||||
|
// Copy-constructor
|
||||||
|
BasicJsonDocument(const BasicJsonDocument& src)
|
||||||
|
: AllocatorOwner<TAllocator>(src), JsonDocument() {
|
||||||
|
copyAssignFrom(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move-constructor
|
||||||
|
BasicJsonDocument(BasicJsonDocument&& src) : AllocatorOwner<TAllocator>(src) {
|
||||||
|
moveAssignFrom(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicJsonDocument(const JsonDocument& src) {
|
||||||
|
copyAssignFrom(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct from variant, array, or object
|
||||||
|
template <typename T>
|
||||||
|
BasicJsonDocument(const T& src,
|
||||||
|
typename detail::enable_if<
|
||||||
|
detail::is_same<T, JsonVariant>::value ||
|
||||||
|
detail::is_same<T, JsonVariantConst>::value ||
|
||||||
|
detail::is_same<T, JsonArray>::value ||
|
||||||
|
detail::is_same<T, JsonArrayConst>::value ||
|
||||||
|
detail::is_same<T, JsonObject>::value ||
|
||||||
|
detail::is_same<T, JsonObjectConst>::value>::type* = 0)
|
||||||
|
: JsonDocument(allocPool(src.memoryUsage())) {
|
||||||
|
set(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
// disambiguate
|
||||||
|
BasicJsonDocument(JsonVariant src)
|
||||||
|
: JsonDocument(allocPool(src.memoryUsage())) {
|
||||||
|
set(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
~BasicJsonDocument() {
|
||||||
|
freePool();
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicJsonDocument& operator=(const BasicJsonDocument& src) {
|
||||||
|
copyAssignFrom(src);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicJsonDocument& operator=(BasicJsonDocument&& src) {
|
||||||
|
moveAssignFrom(src);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
BasicJsonDocument& operator=(const T& src) {
|
||||||
|
size_t requiredSize = src.memoryUsage();
|
||||||
|
if (requiredSize > capacity())
|
||||||
|
reallocPool(requiredSize);
|
||||||
|
set(src);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduces the capacity of the memory pool to match the current usage.
|
||||||
|
// https://arduinojson.org/v6/api/basicjsondocument/shrinktofit/
|
||||||
|
void shrinkToFit() {
|
||||||
|
ptrdiff_t bytes_reclaimed = pool_.squash();
|
||||||
|
if (bytes_reclaimed == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
void* old_ptr = pool_.buffer();
|
||||||
|
void* new_ptr = this->reallocate(old_ptr, pool_.capacity());
|
||||||
|
|
||||||
|
ptrdiff_t ptr_offset =
|
||||||
|
static_cast<char*>(new_ptr) - static_cast<char*>(old_ptr);
|
||||||
|
|
||||||
|
pool_.movePointers(ptr_offset);
|
||||||
|
data_.movePointers(ptr_offset, ptr_offset - bytes_reclaimed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reclaims the memory leaked when removing and replacing values.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/garbagecollect/
|
||||||
|
bool garbageCollect() {
|
||||||
|
// make a temporary clone and move assign
|
||||||
|
BasicJsonDocument tmp(*this);
|
||||||
|
if (!tmp.capacity())
|
||||||
|
return false;
|
||||||
|
moveAssignFrom(tmp);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
using AllocatorOwner<TAllocator>::allocator;
|
||||||
|
|
||||||
|
private:
|
||||||
|
detail::MemoryPool allocPool(size_t requiredSize) {
|
||||||
|
size_t capa = detail::addPadding(requiredSize);
|
||||||
|
return {reinterpret_cast<char*>(this->allocate(capa)), capa};
|
||||||
|
}
|
||||||
|
|
||||||
|
void reallocPool(size_t requiredSize) {
|
||||||
|
size_t capa = detail::addPadding(requiredSize);
|
||||||
|
if (capa == pool_.capacity())
|
||||||
|
return;
|
||||||
|
freePool();
|
||||||
|
replacePool(allocPool(detail::addPadding(requiredSize)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void freePool() {
|
||||||
|
this->deallocate(getPool()->buffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
void copyAssignFrom(const JsonDocument& src) {
|
||||||
|
reallocPool(src.capacity());
|
||||||
|
set(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
void moveAssignFrom(BasicJsonDocument& src) {
|
||||||
|
freePool();
|
||||||
|
data_ = src.data_;
|
||||||
|
pool_ = src.pool_;
|
||||||
|
src.data_.setNull();
|
||||||
|
src.pool_ = {0, 0};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,32 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Document/BasicJsonDocument.hpp>
|
||||||
|
|
||||||
|
#include <stdlib.h> // malloc, free
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
// The allocator of DynamicJsonDocument.
|
||||||
|
struct DefaultAllocator {
|
||||||
|
void* allocate(size_t size) {
|
||||||
|
return malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(void* ptr) {
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* reallocate(void* ptr, size_t new_size) {
|
||||||
|
return realloc(ptr, new_size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// A JsonDocument with a memory pool in the heap.
|
||||||
|
// https://arduinojson.org/v6/api/dynamicjsondocument/
|
||||||
|
typedef BasicJsonDocument<DefaultAllocator> DynamicJsonDocument;
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,325 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Array/ElementProxy.hpp>
|
||||||
|
#include <ArduinoJson/Memory/MemoryPool.hpp>
|
||||||
|
#include <ArduinoJson/Object/JsonObject.hpp>
|
||||||
|
#include <ArduinoJson/Object/MemberProxy.hpp>
|
||||||
|
#include <ArduinoJson/Strings/StoragePolicy.hpp>
|
||||||
|
#include <ArduinoJson/Variant/JsonVariantConst.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantTo.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
// A JSON document.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/
|
||||||
|
class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||||
|
friend class detail::VariantAttorney;
|
||||||
|
|
||||||
|
public:
|
||||||
|
JsonDocument(const JsonDocument&) = delete;
|
||||||
|
JsonDocument& operator=(const JsonDocument&) = delete;
|
||||||
|
|
||||||
|
// Casts the root to the specified type.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/as/
|
||||||
|
template <typename T>
|
||||||
|
T as() {
|
||||||
|
return getVariant().template as<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Casts the root to the specified type.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/as/
|
||||||
|
template <typename T>
|
||||||
|
T as() const {
|
||||||
|
return getVariant().template as<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empties the document and resets the memory pool
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/clear/
|
||||||
|
void clear() {
|
||||||
|
pool_.clear();
|
||||||
|
data_.setNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the root is of the specified type.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/is/
|
||||||
|
template <typename T>
|
||||||
|
bool is() {
|
||||||
|
return getVariant().template is<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the root is of the specified type.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/is/
|
||||||
|
template <typename T>
|
||||||
|
bool is() const {
|
||||||
|
return getVariant().template is<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the root is null.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/isnull/
|
||||||
|
bool isNull() const {
|
||||||
|
return getVariant().isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the number of used bytes in the memory pool.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/memoryusage/
|
||||||
|
size_t memoryUsage() const {
|
||||||
|
return pool_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns trues if the memory pool was too small.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/overflowed/
|
||||||
|
bool overflowed() const {
|
||||||
|
return pool_.overflowed();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the depth (nesting level) of the array.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/nesting/
|
||||||
|
size_t nesting() const {
|
||||||
|
return variantNesting(&data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the capacity of the memory pool.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/capacity/
|
||||||
|
size_t capacity() const {
|
||||||
|
return pool_.capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the number of elements in the root array or object.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/size/
|
||||||
|
size_t size() const {
|
||||||
|
return data_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copies the specified document.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/set/
|
||||||
|
bool set(const JsonDocument& src) {
|
||||||
|
return to<JsonVariant>().set(src.as<JsonVariantConst>());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replaces the root with the specified value.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/set/
|
||||||
|
template <typename T>
|
||||||
|
typename detail::enable_if<!detail::is_base_of<JsonDocument, T>::value,
|
||||||
|
bool>::type
|
||||||
|
set(const T& src) {
|
||||||
|
return to<JsonVariant>().set(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clears the document and converts it to the specified type.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/to/
|
||||||
|
template <typename T>
|
||||||
|
typename detail::VariantTo<T>::type to() {
|
||||||
|
clear();
|
||||||
|
return getVariant().template to<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an array and appends it to the root array.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/createnestedarray/
|
||||||
|
JsonArray createNestedArray() {
|
||||||
|
return add().to<JsonArray>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an array and adds it to the root object.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/createnestedarray/
|
||||||
|
template <typename TChar>
|
||||||
|
JsonArray createNestedArray(TChar* key) {
|
||||||
|
return operator[](key).template to<JsonArray>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an array and adds it to the root object.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/createnestedarray/
|
||||||
|
template <typename TString>
|
||||||
|
JsonArray createNestedArray(const TString& key) {
|
||||||
|
return operator[](key).template to<JsonArray>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an object and appends it to the root array.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/createnestedobject/
|
||||||
|
JsonObject createNestedObject() {
|
||||||
|
return add().to<JsonObject>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an object and adds it to the root object.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/createnestedobject/
|
||||||
|
template <typename TChar>
|
||||||
|
JsonObject createNestedObject(TChar* key) {
|
||||||
|
return operator[](key).template to<JsonObject>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an object and adds it to the root object.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/createnestedobject/
|
||||||
|
template <typename TString>
|
||||||
|
JsonObject createNestedObject(const TString& key) {
|
||||||
|
return operator[](key).template to<JsonObject>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the root object contains the specified key.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/containskey/
|
||||||
|
template <typename TChar>
|
||||||
|
bool containsKey(TChar* key) const {
|
||||||
|
return data_.getMember(detail::adaptString(key)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the root object contains the specified key.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/containskey/
|
||||||
|
template <typename TString>
|
||||||
|
bool containsKey(const TString& key) const {
|
||||||
|
return data_.getMember(detail::adaptString(key)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets or sets a root object's member.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/subscript/
|
||||||
|
template <typename TString>
|
||||||
|
FORCE_INLINE typename detail::enable_if<
|
||||||
|
detail::IsString<TString>::value,
|
||||||
|
detail::MemberProxy<JsonDocument&, TString>>::type
|
||||||
|
operator[](const TString& key) {
|
||||||
|
return {*this, key};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets or sets a root object's member.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/subscript/
|
||||||
|
template <typename TChar>
|
||||||
|
FORCE_INLINE typename detail::enable_if<
|
||||||
|
detail::IsString<TChar*>::value,
|
||||||
|
detail::MemberProxy<JsonDocument&, TChar*>>::type
|
||||||
|
operator[](TChar* key) {
|
||||||
|
return {*this, key};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets a root object's member.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/subscript/
|
||||||
|
template <typename TString>
|
||||||
|
FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value,
|
||||||
|
JsonVariantConst>::type
|
||||||
|
operator[](const TString& key) const {
|
||||||
|
return JsonVariantConst(data_.getMember(detail::adaptString(key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets a root object's member.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/subscript/
|
||||||
|
template <typename TChar>
|
||||||
|
FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value,
|
||||||
|
JsonVariantConst>::type
|
||||||
|
operator[](TChar* key) const {
|
||||||
|
return JsonVariantConst(data_.getMember(detail::adaptString(key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets or sets a root array's element.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/subscript/
|
||||||
|
FORCE_INLINE detail::ElementProxy<JsonDocument&> operator[](size_t index) {
|
||||||
|
return {*this, index};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets a root array's member.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/subscript/
|
||||||
|
FORCE_INLINE JsonVariantConst operator[](size_t index) const {
|
||||||
|
return JsonVariantConst(data_.getElement(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Appends a new (null) element to the root array.
|
||||||
|
// Returns a reference to the new element.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/add/
|
||||||
|
FORCE_INLINE JsonVariant add() {
|
||||||
|
return JsonVariant(&pool_, data_.addElement(&pool_));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Appends a value to the root array.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/add/
|
||||||
|
template <typename TValue>
|
||||||
|
FORCE_INLINE bool add(const TValue& value) {
|
||||||
|
return add().set(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Appends a value to the root array.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/add/
|
||||||
|
template <typename TChar>
|
||||||
|
FORCE_INLINE bool add(TChar* value) {
|
||||||
|
return add().set(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes an element of the root array.
|
||||||
|
// ⚠️ Doesn't release the memory associated with the removed element.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/remove/
|
||||||
|
FORCE_INLINE void remove(size_t index) {
|
||||||
|
data_.remove(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes a member of the root object.
|
||||||
|
// ⚠️ Doesn't release the memory associated with the removed element.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/remove/
|
||||||
|
template <typename TChar>
|
||||||
|
FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value>::type
|
||||||
|
remove(TChar* key) {
|
||||||
|
data_.remove(detail::adaptString(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes a member of the root object.
|
||||||
|
// ⚠️ Doesn't release the memory associated with the removed element.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/remove/
|
||||||
|
template <typename TString>
|
||||||
|
FORCE_INLINE
|
||||||
|
typename detail::enable_if<detail::IsString<TString>::value>::type
|
||||||
|
remove(const TString& key) {
|
||||||
|
data_.remove(detail::adaptString(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE operator JsonVariant() {
|
||||||
|
return getVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE operator JsonVariantConst() const {
|
||||||
|
return getVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
JsonDocument() : pool_(0, 0) {}
|
||||||
|
|
||||||
|
JsonDocument(detail::MemoryPool pool) : pool_(pool) {}
|
||||||
|
|
||||||
|
JsonDocument(char* buf, size_t capa) : pool_(buf, capa) {}
|
||||||
|
|
||||||
|
~JsonDocument() {}
|
||||||
|
|
||||||
|
void replacePool(detail::MemoryPool pool) {
|
||||||
|
pool_ = pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonVariant getVariant() {
|
||||||
|
return JsonVariant(&pool_, &data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonVariantConst getVariant() const {
|
||||||
|
return JsonVariantConst(&data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::MemoryPool pool_;
|
||||||
|
detail::VariantData data_;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
detail::MemoryPool* getPool() {
|
||||||
|
return &pool_;
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::VariantData* getData() {
|
||||||
|
return &data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const detail::VariantData* getData() const {
|
||||||
|
return &data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::VariantData* getOrCreateData() {
|
||||||
|
return &data_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void convertToJson(const JsonDocument& src, JsonVariant dst) {
|
||||||
|
dst.set(src.as<JsonVariantConst>());
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,61 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Document/JsonDocument.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
// A JsonDocument with a memory pool on the stack.
|
||||||
|
template <size_t desiredCapacity>
|
||||||
|
class StaticJsonDocument : public JsonDocument {
|
||||||
|
static const size_t capacity_ =
|
||||||
|
detail::AddPadding<detail::Max<1, desiredCapacity>::value>::value;
|
||||||
|
|
||||||
|
public:
|
||||||
|
StaticJsonDocument() : JsonDocument(buffer_, capacity_) {}
|
||||||
|
|
||||||
|
StaticJsonDocument(const StaticJsonDocument& src)
|
||||||
|
: JsonDocument(buffer_, capacity_) {
|
||||||
|
set(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
StaticJsonDocument(
|
||||||
|
const T& src,
|
||||||
|
typename detail::enable_if<
|
||||||
|
detail::is_convertible<T, JsonVariantConst>::value>::type* = 0)
|
||||||
|
: JsonDocument(buffer_, capacity_) {
|
||||||
|
set(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
// disambiguate
|
||||||
|
StaticJsonDocument(JsonVariant src) : JsonDocument(buffer_, capacity_) {
|
||||||
|
set(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
StaticJsonDocument& operator=(const StaticJsonDocument& src) {
|
||||||
|
set(src);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
StaticJsonDocument& operator=(const T& src) {
|
||||||
|
set(src);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reclaims the memory leaked when removing and replacing values.
|
||||||
|
// https://arduinojson.org/v6/api/jsondocument/garbagecollect/
|
||||||
|
void garbageCollect() {
|
||||||
|
StaticJsonDocument tmp(*this);
|
||||||
|
set(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
char buffer_[capacity_];
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,40 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
class EscapeSequence {
|
||||||
|
public:
|
||||||
|
// Optimized for code size on a 8-bit AVR
|
||||||
|
static char escapeChar(char c) {
|
||||||
|
const char* p = escapeTable(true);
|
||||||
|
while (p[0] && p[1] != c) {
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
return p[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optimized for code size on a 8-bit AVR
|
||||||
|
static char unescapeChar(char c) {
|
||||||
|
const char* p = escapeTable(false);
|
||||||
|
for (;;) {
|
||||||
|
if (p[0] == '\0')
|
||||||
|
return 0;
|
||||||
|
if (p[0] == c)
|
||||||
|
return p[1];
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const char* escapeTable(bool excludeSolidus) {
|
||||||
|
return &"//\"\"\\\\b\bf\fn\nr\rt\t"[excludeSolidus ? 2 : 0];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,693 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Deserialization/deserialize.hpp>
|
||||||
|
#include <ArduinoJson/Json/EscapeSequence.hpp>
|
||||||
|
#include <ArduinoJson/Json/Latch.hpp>
|
||||||
|
#include <ArduinoJson/Json/Utf16.hpp>
|
||||||
|
#include <ArduinoJson/Json/Utf8.hpp>
|
||||||
|
#include <ArduinoJson/Memory/MemoryPool.hpp>
|
||||||
|
#include <ArduinoJson/Numbers/parseNumber.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/utility.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename TReader, typename TStringStorage>
|
||||||
|
class JsonDeserializer {
|
||||||
|
public:
|
||||||
|
JsonDeserializer(MemoryPool* pool, TReader reader,
|
||||||
|
TStringStorage stringStorage)
|
||||||
|
: stringStorage_(stringStorage),
|
||||||
|
foundSomething_(false),
|
||||||
|
latch_(reader),
|
||||||
|
pool_(pool) {}
|
||||||
|
|
||||||
|
template <typename TFilter>
|
||||||
|
DeserializationError parse(VariantData& variant, TFilter filter,
|
||||||
|
DeserializationOption::NestingLimit nestingLimit) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
|
||||||
|
err = parseVariant(variant, filter, nestingLimit);
|
||||||
|
|
||||||
|
if (!err && latch_.last() != 0 && !variant.isEnclosed()) {
|
||||||
|
// We don't detect trailing characters earlier, so we need to check now
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
char current() {
|
||||||
|
return latch_.current();
|
||||||
|
}
|
||||||
|
|
||||||
|
void move() {
|
||||||
|
latch_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool eat(char charToSkip) {
|
||||||
|
if (current() != charToSkip)
|
||||||
|
return false;
|
||||||
|
move();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TFilter>
|
||||||
|
DeserializationError::Code parseVariant(
|
||||||
|
VariantData& variant, TFilter filter,
|
||||||
|
DeserializationOption::NestingLimit nestingLimit) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
|
||||||
|
err = skipSpacesAndComments();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
switch (current()) {
|
||||||
|
case '[':
|
||||||
|
if (filter.allowArray())
|
||||||
|
return parseArray(variant.toArray(), filter, nestingLimit);
|
||||||
|
else
|
||||||
|
return skipArray(nestingLimit);
|
||||||
|
|
||||||
|
case '{':
|
||||||
|
if (filter.allowObject())
|
||||||
|
return parseObject(variant.toObject(), filter, nestingLimit);
|
||||||
|
else
|
||||||
|
return skipObject(nestingLimit);
|
||||||
|
|
||||||
|
case '\"':
|
||||||
|
case '\'':
|
||||||
|
if (filter.allowValue())
|
||||||
|
return parseStringValue(variant);
|
||||||
|
else
|
||||||
|
return skipQuotedString();
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
if (filter.allowValue())
|
||||||
|
variant.setBoolean(true);
|
||||||
|
return skipKeyword("true");
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
if (filter.allowValue())
|
||||||
|
variant.setBoolean(false);
|
||||||
|
return skipKeyword("false");
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
// the variant should already by null, except if the same object key was
|
||||||
|
// used twice, as in {"a":1,"a":null}
|
||||||
|
return skipKeyword("null");
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (filter.allowValue())
|
||||||
|
return parseNumericValue(variant);
|
||||||
|
else
|
||||||
|
return skipNumericValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeserializationError::Code skipVariant(
|
||||||
|
DeserializationOption::NestingLimit nestingLimit) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
|
||||||
|
err = skipSpacesAndComments();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
switch (current()) {
|
||||||
|
case '[':
|
||||||
|
return skipArray(nestingLimit);
|
||||||
|
|
||||||
|
case '{':
|
||||||
|
return skipObject(nestingLimit);
|
||||||
|
|
||||||
|
case '\"':
|
||||||
|
case '\'':
|
||||||
|
return skipQuotedString();
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
return skipKeyword("true");
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
return skipKeyword("false");
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
return skipKeyword("null");
|
||||||
|
|
||||||
|
default:
|
||||||
|
return skipNumericValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TFilter>
|
||||||
|
DeserializationError::Code parseArray(
|
||||||
|
CollectionData& array, TFilter filter,
|
||||||
|
DeserializationOption::NestingLimit nestingLimit) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
|
||||||
|
if (nestingLimit.reached())
|
||||||
|
return DeserializationError::TooDeep;
|
||||||
|
|
||||||
|
// Skip opening braket
|
||||||
|
ARDUINOJSON_ASSERT(current() == '[');
|
||||||
|
move();
|
||||||
|
|
||||||
|
// Skip spaces
|
||||||
|
err = skipSpacesAndComments();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
// Empty array?
|
||||||
|
if (eat(']'))
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
|
||||||
|
TFilter memberFilter = filter[0UL];
|
||||||
|
|
||||||
|
// Read each value
|
||||||
|
for (;;) {
|
||||||
|
if (memberFilter.allow()) {
|
||||||
|
// Allocate slot in array
|
||||||
|
VariantData* value = array.addElement(pool_);
|
||||||
|
if (!value)
|
||||||
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
|
// 1 - Parse value
|
||||||
|
err = parseVariant(*value, memberFilter, nestingLimit.decrement());
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
} else {
|
||||||
|
err = skipVariant(nestingLimit.decrement());
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2 - Skip spaces
|
||||||
|
err = skipSpacesAndComments();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
// 3 - More values?
|
||||||
|
if (eat(']'))
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
if (!eat(','))
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeserializationError::Code skipArray(
|
||||||
|
DeserializationOption::NestingLimit nestingLimit) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
|
||||||
|
if (nestingLimit.reached())
|
||||||
|
return DeserializationError::TooDeep;
|
||||||
|
|
||||||
|
// Skip opening braket
|
||||||
|
ARDUINOJSON_ASSERT(current() == '[');
|
||||||
|
move();
|
||||||
|
|
||||||
|
// Read each value
|
||||||
|
for (;;) {
|
||||||
|
// 1 - Skip value
|
||||||
|
err = skipVariant(nestingLimit.decrement());
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
// 2 - Skip spaces
|
||||||
|
err = skipSpacesAndComments();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
// 3 - More values?
|
||||||
|
if (eat(']'))
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
if (!eat(','))
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TFilter>
|
||||||
|
DeserializationError::Code parseObject(
|
||||||
|
CollectionData& object, TFilter filter,
|
||||||
|
DeserializationOption::NestingLimit nestingLimit) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
|
||||||
|
if (nestingLimit.reached())
|
||||||
|
return DeserializationError::TooDeep;
|
||||||
|
|
||||||
|
// Skip opening brace
|
||||||
|
ARDUINOJSON_ASSERT(current() == '{');
|
||||||
|
move();
|
||||||
|
|
||||||
|
// Skip spaces
|
||||||
|
err = skipSpacesAndComments();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
// Empty object?
|
||||||
|
if (eat('}'))
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
|
||||||
|
// Read each key value pair
|
||||||
|
for (;;) {
|
||||||
|
// Parse key
|
||||||
|
err = parseKey();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
// Skip spaces
|
||||||
|
err = skipSpacesAndComments();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
// Colon
|
||||||
|
if (!eat(':'))
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
|
|
||||||
|
JsonString key = stringStorage_.str();
|
||||||
|
|
||||||
|
TFilter memberFilter = filter[key.c_str()];
|
||||||
|
|
||||||
|
if (memberFilter.allow()) {
|
||||||
|
VariantData* variant = object.getMember(adaptString(key.c_str()));
|
||||||
|
if (!variant) {
|
||||||
|
// Save key in memory pool.
|
||||||
|
// This MUST be done before adding the slot.
|
||||||
|
key = stringStorage_.save();
|
||||||
|
|
||||||
|
// Allocate slot in object
|
||||||
|
VariantSlot* slot = object.addSlot(pool_);
|
||||||
|
if (!slot)
|
||||||
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
|
slot->setKey(key);
|
||||||
|
|
||||||
|
variant = slot->data();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse value
|
||||||
|
err = parseVariant(*variant, memberFilter, nestingLimit.decrement());
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
} else {
|
||||||
|
err = skipVariant(nestingLimit.decrement());
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip spaces
|
||||||
|
err = skipSpacesAndComments();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
// More keys/values?
|
||||||
|
if (eat('}'))
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
if (!eat(','))
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
|
|
||||||
|
// Skip spaces
|
||||||
|
err = skipSpacesAndComments();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeserializationError::Code skipObject(
|
||||||
|
DeserializationOption::NestingLimit nestingLimit) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
|
||||||
|
if (nestingLimit.reached())
|
||||||
|
return DeserializationError::TooDeep;
|
||||||
|
|
||||||
|
// Skip opening brace
|
||||||
|
ARDUINOJSON_ASSERT(current() == '{');
|
||||||
|
move();
|
||||||
|
|
||||||
|
// Skip spaces
|
||||||
|
err = skipSpacesAndComments();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
// Empty object?
|
||||||
|
if (eat('}'))
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
|
||||||
|
// Read each key value pair
|
||||||
|
for (;;) {
|
||||||
|
// Skip key
|
||||||
|
err = skipKey();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
// Skip spaces
|
||||||
|
err = skipSpacesAndComments();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
// Colon
|
||||||
|
if (!eat(':'))
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
|
|
||||||
|
// Skip value
|
||||||
|
err = skipVariant(nestingLimit.decrement());
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
// Skip spaces
|
||||||
|
err = skipSpacesAndComments();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
// More keys/values?
|
||||||
|
if (eat('}'))
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
if (!eat(','))
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
|
|
||||||
|
err = skipSpacesAndComments();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeserializationError::Code parseKey() {
|
||||||
|
stringStorage_.startString();
|
||||||
|
if (isQuote(current())) {
|
||||||
|
return parseQuotedString();
|
||||||
|
} else {
|
||||||
|
return parseNonQuotedString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeserializationError::Code parseStringValue(VariantData& variant) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
|
||||||
|
stringStorage_.startString();
|
||||||
|
|
||||||
|
err = parseQuotedString();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
variant.setString(stringStorage_.save());
|
||||||
|
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeserializationError::Code parseQuotedString() {
|
||||||
|
#if ARDUINOJSON_DECODE_UNICODE
|
||||||
|
Utf16::Codepoint codepoint;
|
||||||
|
DeserializationError::Code err;
|
||||||
|
#endif
|
||||||
|
const char stopChar = current();
|
||||||
|
|
||||||
|
move();
|
||||||
|
for (;;) {
|
||||||
|
char c = current();
|
||||||
|
move();
|
||||||
|
if (c == stopChar)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (c == '\0')
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
|
|
||||||
|
if (c == '\\') {
|
||||||
|
c = current();
|
||||||
|
|
||||||
|
if (c == '\0')
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
|
|
||||||
|
if (c == 'u') {
|
||||||
|
#if ARDUINOJSON_DECODE_UNICODE
|
||||||
|
move();
|
||||||
|
uint16_t codeunit;
|
||||||
|
err = parseHex4(codeunit);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
if (codepoint.append(codeunit))
|
||||||
|
Utf8::encodeCodepoint(codepoint.value(), stringStorage_);
|
||||||
|
#else
|
||||||
|
stringStorage_.append('\\');
|
||||||
|
#endif
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace char
|
||||||
|
c = EscapeSequence::unescapeChar(c);
|
||||||
|
if (c == '\0')
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
|
move();
|
||||||
|
}
|
||||||
|
|
||||||
|
stringStorage_.append(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stringStorage_.isValid())
|
||||||
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeserializationError::Code parseNonQuotedString() {
|
||||||
|
char c = current();
|
||||||
|
ARDUINOJSON_ASSERT(c);
|
||||||
|
|
||||||
|
if (canBeInNonQuotedString(c)) { // no quotes
|
||||||
|
do {
|
||||||
|
move();
|
||||||
|
stringStorage_.append(c);
|
||||||
|
c = current();
|
||||||
|
} while (canBeInNonQuotedString(c));
|
||||||
|
} else {
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stringStorage_.isValid())
|
||||||
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeserializationError::Code skipKey() {
|
||||||
|
if (isQuote(current())) {
|
||||||
|
return skipQuotedString();
|
||||||
|
} else {
|
||||||
|
return skipNonQuotedString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeserializationError::Code skipQuotedString() {
|
||||||
|
const char stopChar = current();
|
||||||
|
|
||||||
|
move();
|
||||||
|
for (;;) {
|
||||||
|
char c = current();
|
||||||
|
move();
|
||||||
|
if (c == stopChar)
|
||||||
|
break;
|
||||||
|
if (c == '\0')
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
|
if (c == '\\') {
|
||||||
|
if (current() != '\0')
|
||||||
|
move();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeserializationError::Code skipNonQuotedString() {
|
||||||
|
char c = current();
|
||||||
|
while (canBeInNonQuotedString(c)) {
|
||||||
|
move();
|
||||||
|
c = current();
|
||||||
|
}
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeserializationError::Code parseNumericValue(VariantData& result) {
|
||||||
|
uint8_t n = 0;
|
||||||
|
|
||||||
|
char c = current();
|
||||||
|
while (canBeInNumber(c) && n < 63) {
|
||||||
|
move();
|
||||||
|
buffer_[n++] = c;
|
||||||
|
c = current();
|
||||||
|
}
|
||||||
|
buffer_[n] = 0;
|
||||||
|
|
||||||
|
if (!parseNumber(buffer_, result))
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
|
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeserializationError::Code skipNumericValue() {
|
||||||
|
char c = current();
|
||||||
|
while (canBeInNumber(c)) {
|
||||||
|
move();
|
||||||
|
c = current();
|
||||||
|
}
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeserializationError::Code parseHex4(uint16_t& result) {
|
||||||
|
result = 0;
|
||||||
|
for (uint8_t i = 0; i < 4; ++i) {
|
||||||
|
char digit = current();
|
||||||
|
if (!digit)
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
|
uint8_t value = decodeHex(digit);
|
||||||
|
if (value > 0x0F)
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
|
result = uint16_t((result << 4) | value);
|
||||||
|
move();
|
||||||
|
}
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isBetween(char c, char min, char max) {
|
||||||
|
return min <= c && c <= max;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool canBeInNumber(char c) {
|
||||||
|
return isBetween(c, '0', '9') || c == '+' || c == '-' || c == '.' ||
|
||||||
|
#if ARDUINOJSON_ENABLE_NAN || ARDUINOJSON_ENABLE_INFINITY
|
||||||
|
isBetween(c, 'A', 'Z') || isBetween(c, 'a', 'z');
|
||||||
|
#else
|
||||||
|
c == 'e' || c == 'E';
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool canBeInNonQuotedString(char c) {
|
||||||
|
return isBetween(c, '0', '9') || isBetween(c, '_', 'z') ||
|
||||||
|
isBetween(c, 'A', 'Z');
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isQuote(char c) {
|
||||||
|
return c == '\'' || c == '\"';
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t decodeHex(char c) {
|
||||||
|
if (c < 'A')
|
||||||
|
return uint8_t(c - '0');
|
||||||
|
c = char(c & ~0x20); // uppercase
|
||||||
|
return uint8_t(c - 'A' + 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeserializationError::Code skipSpacesAndComments() {
|
||||||
|
for (;;) {
|
||||||
|
switch (current()) {
|
||||||
|
// end of string
|
||||||
|
case '\0':
|
||||||
|
return foundSomething_ ? DeserializationError::IncompleteInput
|
||||||
|
: DeserializationError::EmptyInput;
|
||||||
|
|
||||||
|
// spaces
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
move();
|
||||||
|
continue;
|
||||||
|
|
||||||
|
#if ARDUINOJSON_ENABLE_COMMENTS
|
||||||
|
// comments
|
||||||
|
case '/':
|
||||||
|
move(); // skip '/'
|
||||||
|
switch (current()) {
|
||||||
|
// block comment
|
||||||
|
case '*': {
|
||||||
|
move(); // skip '*'
|
||||||
|
bool wasStar = false;
|
||||||
|
for (;;) {
|
||||||
|
char c = current();
|
||||||
|
if (c == '\0')
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
|
if (c == '/' && wasStar) {
|
||||||
|
move();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
wasStar = c == '*';
|
||||||
|
move();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// trailing comment
|
||||||
|
case '/':
|
||||||
|
// no need to skip "//"
|
||||||
|
for (;;) {
|
||||||
|
move();
|
||||||
|
char c = current();
|
||||||
|
if (c == '\0')
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
|
if (c == '\n')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// not a comment, just a '/'
|
||||||
|
default:
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
foundSomething_ = true;
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeserializationError::Code skipKeyword(const char* s) {
|
||||||
|
while (*s) {
|
||||||
|
char c = current();
|
||||||
|
if (c == '\0')
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
|
if (*s != c)
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
|
++s;
|
||||||
|
move();
|
||||||
|
}
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
TStringStorage stringStorage_;
|
||||||
|
bool foundSomething_;
|
||||||
|
Latch<TReader> latch_;
|
||||||
|
MemoryPool* pool_;
|
||||||
|
char buffer_[64]; // using a member instead of a local variable because it
|
||||||
|
// ended in the recursive path after compiler inlined the
|
||||||
|
// code
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
// Parses a JSON input, filters, and puts the result in a JsonDocument.
|
||||||
|
// https://arduinojson.org/v6/api/json/deserializejson/
|
||||||
|
template <typename... Args>
|
||||||
|
DeserializationError deserializeJson(JsonDocument& doc, Args&&... args) {
|
||||||
|
using namespace detail;
|
||||||
|
return deserialize<JsonDeserializer>(doc, detail::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parses a JSON input, filters, and puts the result in a JsonDocument.
|
||||||
|
// https://arduinojson.org/v6/api/json/deserializejson/
|
||||||
|
template <typename TChar, typename... Args>
|
||||||
|
DeserializationError deserializeJson(JsonDocument& doc, TChar* input,
|
||||||
|
Args&&... args) {
|
||||||
|
using namespace detail;
|
||||||
|
return deserialize<JsonDeserializer>(doc, input,
|
||||||
|
detail::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,155 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Json/TextFormatter.hpp>
|
||||||
|
#include <ArduinoJson/Serialization/measure.hpp>
|
||||||
|
#include <ArduinoJson/Serialization/serialize.hpp>
|
||||||
|
#include <ArduinoJson/Variant/Visitor.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename TWriter>
|
||||||
|
class JsonSerializer : public Visitor<size_t> {
|
||||||
|
public:
|
||||||
|
static const bool producesText = true;
|
||||||
|
|
||||||
|
JsonSerializer(TWriter writer) : formatter_(writer) {}
|
||||||
|
|
||||||
|
FORCE_INLINE size_t visitArray(const CollectionData& array) {
|
||||||
|
write('[');
|
||||||
|
|
||||||
|
const VariantSlot* slot = array.head();
|
||||||
|
|
||||||
|
while (slot != 0) {
|
||||||
|
slot->data()->accept(*this);
|
||||||
|
|
||||||
|
slot = slot->next();
|
||||||
|
if (slot == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
write(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
write(']');
|
||||||
|
return bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t visitObject(const CollectionData& object) {
|
||||||
|
write('{');
|
||||||
|
|
||||||
|
const VariantSlot* slot = object.head();
|
||||||
|
|
||||||
|
while (slot != 0) {
|
||||||
|
formatter_.writeString(slot->key());
|
||||||
|
write(':');
|
||||||
|
slot->data()->accept(*this);
|
||||||
|
|
||||||
|
slot = slot->next();
|
||||||
|
if (slot == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
write(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
write('}');
|
||||||
|
return bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t visitFloat(JsonFloat value) {
|
||||||
|
formatter_.writeFloat(value);
|
||||||
|
return bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t visitString(const char* value) {
|
||||||
|
formatter_.writeString(value);
|
||||||
|
return bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t visitString(const char* value, size_t n) {
|
||||||
|
formatter_.writeString(value, n);
|
||||||
|
return bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t visitRawJson(const char* data, size_t n) {
|
||||||
|
formatter_.writeRaw(data, n);
|
||||||
|
return bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t visitSignedInteger(JsonInteger value) {
|
||||||
|
formatter_.writeInteger(value);
|
||||||
|
return bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t visitUnsignedInteger(JsonUInt value) {
|
||||||
|
formatter_.writeInteger(value);
|
||||||
|
return bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t visitBoolean(bool value) {
|
||||||
|
formatter_.writeBoolean(value);
|
||||||
|
return bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t visitNull() {
|
||||||
|
formatter_.writeRaw("null");
|
||||||
|
return bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
size_t bytesWritten() const {
|
||||||
|
return formatter_.bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
void write(char c) {
|
||||||
|
formatter_.writeRaw(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void write(const char* s) {
|
||||||
|
formatter_.writeRaw(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TextFormatter<TWriter> formatter_;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
// Produces a minified JSON document.
|
||||||
|
// https://arduinojson.org/v6/api/json/serializejson/
|
||||||
|
template <typename TDestination>
|
||||||
|
size_t serializeJson(JsonVariantConst source, TDestination& destination) {
|
||||||
|
using namespace detail;
|
||||||
|
return serialize<JsonSerializer>(source, destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Produces a minified JSON document.
|
||||||
|
// https://arduinojson.org/v6/api/json/serializejson/
|
||||||
|
inline size_t serializeJson(JsonVariantConst source, void* buffer,
|
||||||
|
size_t bufferSize) {
|
||||||
|
using namespace detail;
|
||||||
|
return serialize<JsonSerializer>(source, buffer, bufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Computes the length of the document that serializeJson() produces.
|
||||||
|
// https://arduinojson.org/v6/api/json/measurejson/
|
||||||
|
inline size_t measureJson(JsonVariantConst source) {
|
||||||
|
using namespace detail;
|
||||||
|
return measure<JsonSerializer>(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ARDUINOJSON_ENABLE_STD_STREAM
|
||||||
|
template <typename T>
|
||||||
|
inline typename detail::enable_if<
|
||||||
|
detail::is_convertible<T, JsonVariantConst>::value, std::ostream&>::type
|
||||||
|
operator<<(std::ostream& os, const T& source) {
|
||||||
|
serializeJson(source, os);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,56 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename TReader>
|
||||||
|
class Latch {
|
||||||
|
public:
|
||||||
|
Latch(TReader reader) : reader_(reader), loaded_(false) {
|
||||||
|
#if ARDUINOJSON_DEBUG
|
||||||
|
ended_ = false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
loaded_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int last() const {
|
||||||
|
return current_;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE char current() {
|
||||||
|
if (!loaded_) {
|
||||||
|
load();
|
||||||
|
}
|
||||||
|
return current_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void load() {
|
||||||
|
ARDUINOJSON_ASSERT(!ended_);
|
||||||
|
int c = reader_.read();
|
||||||
|
#if ARDUINOJSON_DEBUG
|
||||||
|
if (c <= 0)
|
||||||
|
ended_ = true;
|
||||||
|
#endif
|
||||||
|
current_ = static_cast<char>(c > 0 ? c : 0);
|
||||||
|
loaded_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TReader reader_;
|
||||||
|
char current_; // NOLINT(clang-analyzer-optin.cplusplus.UninitializedObject)
|
||||||
|
// Not initialized in constructor (+10 bytes on AVR)
|
||||||
|
bool loaded_;
|
||||||
|
#if ARDUINOJSON_DEBUG
|
||||||
|
bool ended_;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,101 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Configuration.hpp>
|
||||||
|
#include <ArduinoJson/Json/JsonSerializer.hpp>
|
||||||
|
#include <ArduinoJson/Serialization/measure.hpp>
|
||||||
|
#include <ArduinoJson/Serialization/serialize.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename TWriter>
|
||||||
|
class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
||||||
|
typedef JsonSerializer<TWriter> base;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PrettyJsonSerializer(TWriter writer) : base(writer), nesting_(0) {}
|
||||||
|
|
||||||
|
size_t visitArray(const CollectionData& array) {
|
||||||
|
const VariantSlot* slot = array.head();
|
||||||
|
if (slot) {
|
||||||
|
base::write("[\r\n");
|
||||||
|
nesting_++;
|
||||||
|
while (slot != 0) {
|
||||||
|
indent();
|
||||||
|
slot->data()->accept(*this);
|
||||||
|
|
||||||
|
slot = slot->next();
|
||||||
|
base::write(slot ? ",\r\n" : "\r\n");
|
||||||
|
}
|
||||||
|
nesting_--;
|
||||||
|
indent();
|
||||||
|
base::write("]");
|
||||||
|
} else {
|
||||||
|
base::write("[]");
|
||||||
|
}
|
||||||
|
return this->bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t visitObject(const CollectionData& object) {
|
||||||
|
const VariantSlot* slot = object.head();
|
||||||
|
if (slot) {
|
||||||
|
base::write("{\r\n");
|
||||||
|
nesting_++;
|
||||||
|
while (slot != 0) {
|
||||||
|
indent();
|
||||||
|
base::visitString(slot->key());
|
||||||
|
base::write(": ");
|
||||||
|
slot->data()->accept(*this);
|
||||||
|
|
||||||
|
slot = slot->next();
|
||||||
|
base::write(slot ? ",\r\n" : "\r\n");
|
||||||
|
}
|
||||||
|
nesting_--;
|
||||||
|
indent();
|
||||||
|
base::write("}");
|
||||||
|
} else {
|
||||||
|
base::write("{}");
|
||||||
|
}
|
||||||
|
return this->bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void indent() {
|
||||||
|
for (uint8_t i = 0; i < nesting_; i++)
|
||||||
|
base::write(ARDUINOJSON_TAB);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t nesting_;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
// Produces JsonDocument to create a prettified JSON document.
|
||||||
|
// https://arduinojson.org/v6/api/json/serializejsonpretty/
|
||||||
|
template <typename TDestination>
|
||||||
|
size_t serializeJsonPretty(JsonVariantConst source, TDestination& destination) {
|
||||||
|
using namespace ArduinoJson::detail;
|
||||||
|
return serialize<PrettyJsonSerializer>(source, destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Produces JsonDocument to create a prettified JSON document.
|
||||||
|
// https://arduinojson.org/v6/api/json/serializejsonpretty/
|
||||||
|
inline size_t serializeJsonPretty(JsonVariantConst source, void* buffer,
|
||||||
|
size_t bufferSize) {
|
||||||
|
using namespace ArduinoJson::detail;
|
||||||
|
return serialize<PrettyJsonSerializer>(source, buffer, bufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Computes the length of the document that serializeJsonPretty() produces.
|
||||||
|
// https://arduinojson.org/v6/api/json/measurejsonpretty/
|
||||||
|
inline size_t measureJsonPretty(JsonVariantConst source) {
|
||||||
|
using namespace ArduinoJson::detail;
|
||||||
|
return measure<PrettyJsonSerializer>(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,173 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h> // for strlen
|
||||||
|
|
||||||
|
#include <ArduinoJson/Json/EscapeSequence.hpp>
|
||||||
|
#include <ArduinoJson/Numbers/FloatParts.hpp>
|
||||||
|
#include <ArduinoJson/Numbers/JsonInteger.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/attributes.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||||
|
#include <ArduinoJson/Serialization/CountingDecorator.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename TWriter>
|
||||||
|
class TextFormatter {
|
||||||
|
public:
|
||||||
|
explicit TextFormatter(TWriter writer) : writer_(writer) {}
|
||||||
|
|
||||||
|
TextFormatter& operator=(const TextFormatter&) = delete;
|
||||||
|
|
||||||
|
// Returns the number of bytes sent to the TWriter implementation.
|
||||||
|
size_t bytesWritten() const {
|
||||||
|
return writer_.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeBoolean(bool value) {
|
||||||
|
if (value)
|
||||||
|
writeRaw("true");
|
||||||
|
else
|
||||||
|
writeRaw("false");
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeString(const char* value) {
|
||||||
|
ARDUINOJSON_ASSERT(value != NULL);
|
||||||
|
writeRaw('\"');
|
||||||
|
while (*value)
|
||||||
|
writeChar(*value++);
|
||||||
|
writeRaw('\"');
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeString(const char* value, size_t n) {
|
||||||
|
ARDUINOJSON_ASSERT(value != NULL);
|
||||||
|
writeRaw('\"');
|
||||||
|
while (n--)
|
||||||
|
writeChar(*value++);
|
||||||
|
writeRaw('\"');
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeChar(char c) {
|
||||||
|
char specialChar = EscapeSequence::escapeChar(c);
|
||||||
|
if (specialChar) {
|
||||||
|
writeRaw('\\');
|
||||||
|
writeRaw(specialChar);
|
||||||
|
} else if (c) {
|
||||||
|
writeRaw(c);
|
||||||
|
} else {
|
||||||
|
writeRaw("\\u0000");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void writeFloat(T value) {
|
||||||
|
if (isnan(value))
|
||||||
|
return writeRaw(ARDUINOJSON_ENABLE_NAN ? "NaN" : "null");
|
||||||
|
|
||||||
|
#if ARDUINOJSON_ENABLE_INFINITY
|
||||||
|
if (value < 0.0) {
|
||||||
|
writeRaw('-');
|
||||||
|
value = -value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isinf(value))
|
||||||
|
return writeRaw("Infinity");
|
||||||
|
#else
|
||||||
|
if (isinf(value))
|
||||||
|
return writeRaw("null");
|
||||||
|
|
||||||
|
if (value < 0.0) {
|
||||||
|
writeRaw('-');
|
||||||
|
value = -value;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FloatParts<T> parts(value);
|
||||||
|
|
||||||
|
writeInteger(parts.integral);
|
||||||
|
if (parts.decimalPlaces)
|
||||||
|
writeDecimals(parts.decimal, parts.decimalPlaces);
|
||||||
|
|
||||||
|
if (parts.exponent) {
|
||||||
|
writeRaw('e');
|
||||||
|
writeInteger(parts.exponent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
typename enable_if<is_signed<T>::value>::type writeInteger(T value) {
|
||||||
|
typedef typename make_unsigned<T>::type unsigned_type;
|
||||||
|
unsigned_type unsigned_value;
|
||||||
|
if (value < 0) {
|
||||||
|
writeRaw('-');
|
||||||
|
unsigned_value = unsigned_type(unsigned_type(~value) + 1);
|
||||||
|
} else {
|
||||||
|
unsigned_value = unsigned_type(value);
|
||||||
|
}
|
||||||
|
writeInteger(unsigned_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
typename enable_if<is_unsigned<T>::value>::type writeInteger(T value) {
|
||||||
|
char buffer[22];
|
||||||
|
char* end = buffer + sizeof(buffer);
|
||||||
|
char* begin = end;
|
||||||
|
|
||||||
|
// write the string in reverse order
|
||||||
|
do {
|
||||||
|
*--begin = char(value % 10 + '0');
|
||||||
|
value = T(value / 10);
|
||||||
|
} while (value);
|
||||||
|
|
||||||
|
// and dump it in the right order
|
||||||
|
writeRaw(begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeDecimals(uint32_t value, int8_t width) {
|
||||||
|
// buffer should be big enough for all digits and the dot
|
||||||
|
char buffer[16];
|
||||||
|
char* end = buffer + sizeof(buffer);
|
||||||
|
char* begin = end;
|
||||||
|
|
||||||
|
// write the string in reverse order
|
||||||
|
while (width--) {
|
||||||
|
*--begin = char(value % 10 + '0');
|
||||||
|
value /= 10;
|
||||||
|
}
|
||||||
|
*--begin = '.';
|
||||||
|
|
||||||
|
// and dump it in the right order
|
||||||
|
writeRaw(begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeRaw(const char* s) {
|
||||||
|
writer_.write(reinterpret_cast<const uint8_t*>(s), strlen(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeRaw(const char* s, size_t n) {
|
||||||
|
writer_.write(reinterpret_cast<const uint8_t*>(s), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeRaw(const char* begin, const char* end) {
|
||||||
|
writer_.write(reinterpret_cast<const uint8_t*>(begin),
|
||||||
|
static_cast<size_t>(end - begin));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
|
void writeRaw(const char (&s)[N]) {
|
||||||
|
writer_.write(reinterpret_cast<const uint8_t*>(s), N - 1);
|
||||||
|
}
|
||||||
|
void writeRaw(char c) {
|
||||||
|
writer_.write(static_cast<uint8_t>(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
CountingDecorator<TWriter> writer_;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,67 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
#include <stdint.h> // uint16_t, uint32_t
|
||||||
|
|
||||||
|
// The high surrogate may be uninitialized if the pair is invalid,
|
||||||
|
// we choose to ignore the problem to reduce the size of the code
|
||||||
|
// Garbage in => Garbage out
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
# if __GNUC__ >= 7
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
namespace Utf16 {
|
||||||
|
inline bool isHighSurrogate(uint16_t codeunit) {
|
||||||
|
return codeunit >= 0xD800 && codeunit < 0xDC00;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isLowSurrogate(uint16_t codeunit) {
|
||||||
|
return codeunit >= 0xDC00 && codeunit < 0xE000;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Codepoint {
|
||||||
|
public:
|
||||||
|
Codepoint() : highSurrogate_(0), codepoint_(0) {}
|
||||||
|
|
||||||
|
bool append(uint16_t codeunit) {
|
||||||
|
if (isHighSurrogate(codeunit)) {
|
||||||
|
highSurrogate_ = codeunit & 0x3FF;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLowSurrogate(codeunit)) {
|
||||||
|
codepoint_ =
|
||||||
|
uint32_t(0x10000 + ((highSurrogate_ << 10) | (codeunit & 0x3FF)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
codepoint_ = codeunit;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t value() const {
|
||||||
|
return codepoint_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint16_t highSurrogate_;
|
||||||
|
uint32_t codepoint_;
|
||||||
|
};
|
||||||
|
} // namespace Utf16
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
# if __GNUC__ >= 8
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
# endif
|
||||||
|
#endif
|
@ -0,0 +1,46 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
namespace Utf8 {
|
||||||
|
template <typename TStringBuilder>
|
||||||
|
inline void encodeCodepoint(uint32_t codepoint32, TStringBuilder& str) {
|
||||||
|
// this function was optimize for code size on AVR
|
||||||
|
|
||||||
|
if (codepoint32 < 0x80) {
|
||||||
|
str.append(char(codepoint32));
|
||||||
|
} else {
|
||||||
|
// a buffer to store the string in reverse
|
||||||
|
char buf[5];
|
||||||
|
char* p = buf;
|
||||||
|
|
||||||
|
*(p++) = 0;
|
||||||
|
*(p++) = char((codepoint32 | 0x80) & 0xBF);
|
||||||
|
uint16_t codepoint16 = uint16_t(codepoint32 >> 6);
|
||||||
|
if (codepoint16 < 0x20) { // 0x800
|
||||||
|
*(p++) = char(codepoint16 | 0xC0);
|
||||||
|
} else {
|
||||||
|
*(p++) = char((codepoint16 | 0x80) & 0xBF);
|
||||||
|
codepoint16 = uint16_t(codepoint16 >> 6);
|
||||||
|
if (codepoint16 < 0x10) { // 0x10000
|
||||||
|
*(p++) = char(codepoint16 | 0xE0);
|
||||||
|
} else {
|
||||||
|
*(p++) = char((codepoint16 | 0x80) & 0xBF);
|
||||||
|
codepoint16 = uint16_t(codepoint16 >> 6);
|
||||||
|
*(p++) = char(codepoint16 | 0xF0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*(--p)) {
|
||||||
|
str.append(*p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace Utf8
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,60 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
#include <stddef.h> // size_t
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
#if ARDUINOJSON_ENABLE_ALIGNMENT
|
||||||
|
|
||||||
|
inline bool isAligned(size_t value) {
|
||||||
|
const size_t mask = sizeof(void*) - 1;
|
||||||
|
size_t addr = value;
|
||||||
|
return (addr & mask) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t addPadding(size_t bytes) {
|
||||||
|
const size_t mask = sizeof(void*) - 1;
|
||||||
|
return (bytes + mask) & ~mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t bytes>
|
||||||
|
struct AddPadding {
|
||||||
|
static const size_t mask = sizeof(void*) - 1;
|
||||||
|
static const size_t value = (bytes + mask) & ~mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
inline bool isAligned(size_t) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t addPadding(size_t bytes) {
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t bytes>
|
||||||
|
struct AddPadding {
|
||||||
|
static const size_t value = bytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline bool isAligned(T* ptr) {
|
||||||
|
return isAligned(reinterpret_cast<size_t>(ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T* addPadding(T* p) {
|
||||||
|
size_t address = addPadding(reinterpret_cast<size_t>(p));
|
||||||
|
return reinterpret_cast<T*>(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,253 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Memory/Alignment.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/mpl/max.hpp>
|
||||||
|
#include <ArduinoJson/Strings/StringAdapters.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantSlot.hpp>
|
||||||
|
|
||||||
|
#include <string.h> // memmove
|
||||||
|
|
||||||
|
#define JSON_STRING_SIZE(SIZE) (SIZE + 1)
|
||||||
|
|
||||||
|
// Computes the size required to store an array in a JsonDocument.
|
||||||
|
// https://arduinojson.org/v6/how-to/determine-the-capacity-of-the-jsondocument/
|
||||||
|
#define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \
|
||||||
|
((NUMBER_OF_ELEMENTS) * sizeof(ArduinoJson::detail::VariantSlot))
|
||||||
|
|
||||||
|
// Returns the size (in bytes) of an object with n elements.
|
||||||
|
// Can be very handy to determine the size of a StaticMemoryPool.
|
||||||
|
#define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \
|
||||||
|
((NUMBER_OF_ELEMENTS) * sizeof(ArduinoJson::detail::VariantSlot))
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
// begin_ end_
|
||||||
|
// v v
|
||||||
|
// +-------------+--------------+--------------+
|
||||||
|
// | strings... | (free) | ...variants |
|
||||||
|
// +-------------+--------------+--------------+
|
||||||
|
// ^ ^
|
||||||
|
// left_ right_
|
||||||
|
|
||||||
|
class MemoryPool {
|
||||||
|
public:
|
||||||
|
MemoryPool(char* buf, size_t capa)
|
||||||
|
: begin_(buf),
|
||||||
|
left_(buf),
|
||||||
|
right_(buf ? buf + capa : 0),
|
||||||
|
end_(buf ? buf + capa : 0),
|
||||||
|
overflowed_(false) {
|
||||||
|
ARDUINOJSON_ASSERT(isAligned(begin_));
|
||||||
|
ARDUINOJSON_ASSERT(isAligned(right_));
|
||||||
|
ARDUINOJSON_ASSERT(isAligned(end_));
|
||||||
|
}
|
||||||
|
|
||||||
|
void* buffer() {
|
||||||
|
return begin_; // NOLINT(clang-analyzer-unix.Malloc)
|
||||||
|
// movePointers() alters this pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the capacity of the memoryPool in bytes
|
||||||
|
size_t capacity() const {
|
||||||
|
return size_t(end_ - begin_);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const {
|
||||||
|
return size_t(left_ - begin_ + end_ - right_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool overflowed() const {
|
||||||
|
return overflowed_;
|
||||||
|
}
|
||||||
|
|
||||||
|
VariantSlot* allocVariant() {
|
||||||
|
return allocRight<VariantSlot>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TAdaptedString>
|
||||||
|
const char* saveString(TAdaptedString str) {
|
||||||
|
if (str.isNull())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
|
||||||
|
const char* existingCopy = findString(str);
|
||||||
|
if (existingCopy)
|
||||||
|
return existingCopy;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t n = str.size();
|
||||||
|
|
||||||
|
char* newCopy = allocString(n + 1);
|
||||||
|
if (newCopy) {
|
||||||
|
stringGetChars(str, newCopy, n);
|
||||||
|
newCopy[n] = 0; // force null-terminator
|
||||||
|
}
|
||||||
|
return newCopy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void getFreeZone(char** zoneStart, size_t* zoneSize) const {
|
||||||
|
*zoneStart = left_;
|
||||||
|
*zoneSize = size_t(right_ - left_);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* saveStringFromFreeZone(size_t len) {
|
||||||
|
#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
|
||||||
|
const char* dup = findString(adaptString(left_, len));
|
||||||
|
if (dup)
|
||||||
|
return dup;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char* str = left_;
|
||||||
|
left_ += len;
|
||||||
|
*left_++ = 0;
|
||||||
|
checkInvariants();
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
void markAsOverflowed() {
|
||||||
|
overflowed_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
left_ = begin_;
|
||||||
|
right_ = end_;
|
||||||
|
overflowed_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canAlloc(size_t bytes) const {
|
||||||
|
return left_ + bytes <= right_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool owns(void* p) const {
|
||||||
|
return begin_ <= p && p < end_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Workaround for missing placement new
|
||||||
|
void* operator new(size_t, void* p) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Squash the free space between strings and variants
|
||||||
|
//
|
||||||
|
// begin_ end_
|
||||||
|
// v v
|
||||||
|
// +-------------+--------------+
|
||||||
|
// | strings... | ...variants |
|
||||||
|
// +-------------+--------------+
|
||||||
|
// ^
|
||||||
|
// left_ right_
|
||||||
|
//
|
||||||
|
// This funcion is called before a realloc.
|
||||||
|
ptrdiff_t squash() {
|
||||||
|
char* new_right = addPadding(left_);
|
||||||
|
if (new_right >= right_)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
size_t right_size = static_cast<size_t>(end_ - right_);
|
||||||
|
memmove(new_right, right_, right_size);
|
||||||
|
|
||||||
|
ptrdiff_t bytes_reclaimed = right_ - new_right;
|
||||||
|
right_ = new_right;
|
||||||
|
end_ = new_right + right_size;
|
||||||
|
return bytes_reclaimed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move all pointers together
|
||||||
|
// This funcion is called after a realloc.
|
||||||
|
void movePointers(ptrdiff_t offset) {
|
||||||
|
begin_ += offset;
|
||||||
|
left_ += offset;
|
||||||
|
right_ += offset;
|
||||||
|
end_ += offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void checkInvariants() {
|
||||||
|
ARDUINOJSON_ASSERT(begin_ <= left_);
|
||||||
|
ARDUINOJSON_ASSERT(left_ <= right_);
|
||||||
|
ARDUINOJSON_ASSERT(right_ <= end_);
|
||||||
|
ARDUINOJSON_ASSERT(isAligned(right_));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
|
||||||
|
template <typename TAdaptedString>
|
||||||
|
const char* findString(const TAdaptedString& str) const {
|
||||||
|
size_t n = str.size();
|
||||||
|
for (char* next = begin_; next + n < left_; ++next) {
|
||||||
|
if (next[n] == '\0' && stringEquals(str, adaptString(next, n)))
|
||||||
|
return next;
|
||||||
|
|
||||||
|
// jump to next terminator
|
||||||
|
while (*next)
|
||||||
|
++next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char* allocString(size_t n) {
|
||||||
|
if (!canAlloc(n)) {
|
||||||
|
overflowed_ = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
char* s = left_;
|
||||||
|
left_ += n;
|
||||||
|
checkInvariants();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T* allocRight() {
|
||||||
|
return reinterpret_cast<T*>(allocRight(sizeof(T)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void* allocRight(size_t bytes) {
|
||||||
|
if (!canAlloc(bytes)) {
|
||||||
|
overflowed_ = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
right_ -= bytes;
|
||||||
|
return right_;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *begin_, *left_, *right_, *end_;
|
||||||
|
bool overflowed_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TAdaptedString, typename TCallback>
|
||||||
|
bool storeString(MemoryPool* pool, TAdaptedString str,
|
||||||
|
StringStoragePolicy::Copy, TCallback callback) {
|
||||||
|
const char* copy = pool->saveString(str);
|
||||||
|
JsonString storedString(copy, str.size(), JsonString::Copied);
|
||||||
|
callback(storedString);
|
||||||
|
return copy != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TAdaptedString, typename TCallback>
|
||||||
|
bool storeString(MemoryPool*, TAdaptedString str, StringStoragePolicy::Link,
|
||||||
|
TCallback callback) {
|
||||||
|
JsonString storedString(str.data(), str.size(), JsonString::Linked);
|
||||||
|
callback(storedString);
|
||||||
|
return !str.isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TAdaptedString, typename TCallback>
|
||||||
|
bool storeString(MemoryPool* pool, TAdaptedString str,
|
||||||
|
StringStoragePolicy::LinkOrCopy policy, TCallback callback) {
|
||||||
|
if (policy.link)
|
||||||
|
return storeString(pool, str, StringStoragePolicy::Link(), callback);
|
||||||
|
else
|
||||||
|
return storeString(pool, str, StringStoragePolicy::Copy(), callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TAdaptedString, typename TCallback>
|
||||||
|
bool storeString(MemoryPool* pool, TAdaptedString str, TCallback callback) {
|
||||||
|
return storeString(pool, str, str.storagePolicy(), callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,69 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Strings/StringAdapters.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
// A special type of data that can be used to insert pregenerated JSON portions.
|
||||||
|
template <typename T>
|
||||||
|
class SerializedValue {
|
||||||
|
public:
|
||||||
|
explicit SerializedValue(T str) : str_(str) {}
|
||||||
|
operator T() const {
|
||||||
|
return str_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* data() const {
|
||||||
|
return str_.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const {
|
||||||
|
// CAUTION: the old Arduino String doesn't have size()
|
||||||
|
return str_.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T str_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TChar>
|
||||||
|
class SerializedValue<TChar*> {
|
||||||
|
public:
|
||||||
|
explicit SerializedValue(TChar* p, size_t n) : data_(p), size_(n) {}
|
||||||
|
operator TChar*() const {
|
||||||
|
return data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
TChar* data() const {
|
||||||
|
return data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const {
|
||||||
|
return size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TChar* data_;
|
||||||
|
size_t size_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline SerializedValue<T> serialized(T str) {
|
||||||
|
return SerializedValue<T>(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TChar>
|
||||||
|
inline SerializedValue<TChar*> serialized(TChar* p) {
|
||||||
|
return SerializedValue<TChar*>(p, detail::adaptString(p).size());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TChar>
|
||||||
|
inline SerializedValue<TChar*> serialized(TChar* p, size_t n) {
|
||||||
|
return SerializedValue<TChar*>(p, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,585 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Deserialization/deserialize.hpp>
|
||||||
|
#include <ArduinoJson/Memory/MemoryPool.hpp>
|
||||||
|
#include <ArduinoJson/MsgPack/endianess.hpp>
|
||||||
|
#include <ArduinoJson/MsgPack/ieee754.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename TReader, typename TStringStorage>
|
||||||
|
class MsgPackDeserializer {
|
||||||
|
public:
|
||||||
|
MsgPackDeserializer(MemoryPool* pool, TReader reader,
|
||||||
|
TStringStorage stringStorage)
|
||||||
|
: pool_(pool),
|
||||||
|
reader_(reader),
|
||||||
|
stringStorage_(stringStorage),
|
||||||
|
foundSomething_(false) {}
|
||||||
|
|
||||||
|
template <typename TFilter>
|
||||||
|
DeserializationError parse(VariantData& variant, TFilter filter,
|
||||||
|
DeserializationOption::NestingLimit nestingLimit) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
err = parseVariant(&variant, filter, nestingLimit);
|
||||||
|
return foundSomething_ ? err : DeserializationError::EmptyInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename TFilter>
|
||||||
|
DeserializationError::Code parseVariant(
|
||||||
|
VariantData* variant, TFilter filter,
|
||||||
|
DeserializationOption::NestingLimit nestingLimit) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
|
||||||
|
uint8_t code = 0; // TODO: why do we need to initialize this variable?
|
||||||
|
err = readByte(code);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
foundSomething_ = true;
|
||||||
|
|
||||||
|
bool allowValue = filter.allowValue();
|
||||||
|
|
||||||
|
if (allowValue) {
|
||||||
|
// callers pass a null pointer only when value must be ignored
|
||||||
|
ARDUINOJSON_ASSERT(variant != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (code) {
|
||||||
|
case 0xc0:
|
||||||
|
// already null
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
|
||||||
|
case 0xc1:
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
|
|
||||||
|
case 0xc2:
|
||||||
|
if (allowValue)
|
||||||
|
variant->setBoolean(false);
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
|
||||||
|
case 0xc3:
|
||||||
|
if (allowValue)
|
||||||
|
variant->setBoolean(true);
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
|
||||||
|
case 0xc4: // bin 8 (not supported)
|
||||||
|
return skipString<uint8_t>();
|
||||||
|
|
||||||
|
case 0xc5: // bin 16 (not supported)
|
||||||
|
return skipString<uint16_t>();
|
||||||
|
|
||||||
|
case 0xc6: // bin 32 (not supported)
|
||||||
|
return skipString<uint32_t>();
|
||||||
|
|
||||||
|
case 0xc7: // ext 8 (not supported)
|
||||||
|
return skipExt<uint8_t>();
|
||||||
|
|
||||||
|
case 0xc8: // ext 16 (not supported)
|
||||||
|
return skipExt<uint16_t>();
|
||||||
|
|
||||||
|
case 0xc9: // ext 32 (not supported)
|
||||||
|
return skipExt<uint32_t>();
|
||||||
|
|
||||||
|
case 0xca:
|
||||||
|
if (allowValue)
|
||||||
|
return readFloat<float>(variant);
|
||||||
|
else
|
||||||
|
return skipBytes(4);
|
||||||
|
|
||||||
|
case 0xcb:
|
||||||
|
if (allowValue)
|
||||||
|
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 ARDUINOJSON_USE_LONG_LONG
|
||||||
|
if (allowValue)
|
||||||
|
return readInteger<uint64_t>(variant);
|
||||||
|
else
|
||||||
|
return skipBytes(8);
|
||||||
|
#else
|
||||||
|
return skipBytes(8); // not supported
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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 ARDUINOJSON_USE_LONG_LONG
|
||||||
|
if (allowValue)
|
||||||
|
return readInteger<int64_t>(variant);
|
||||||
|
else
|
||||||
|
return skipBytes(8); // not supported
|
||||||
|
#else
|
||||||
|
return skipBytes(8);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case 0xd4: // fixext 1 (not supported)
|
||||||
|
return skipBytes(2);
|
||||||
|
|
||||||
|
case 0xd5: // fixext 2 (not supported)
|
||||||
|
return skipBytes(3);
|
||||||
|
|
||||||
|
case 0xd6: // fixext 4 (not supported)
|
||||||
|
return skipBytes(5);
|
||||||
|
|
||||||
|
case 0xd7: // fixext 8 (not supported)
|
||||||
|
return skipBytes(9);
|
||||||
|
|
||||||
|
case 0xd8: // fixext 16 (not supported)
|
||||||
|
return skipBytes(17);
|
||||||
|
|
||||||
|
case 0xd9:
|
||||||
|
if (allowValue)
|
||||||
|
return readString<uint8_t>(variant);
|
||||||
|
else
|
||||||
|
return skipString<uint8_t>();
|
||||||
|
|
||||||
|
case 0xda:
|
||||||
|
if (allowValue)
|
||||||
|
return readString<uint16_t>(variant);
|
||||||
|
else
|
||||||
|
return skipString<uint16_t>();
|
||||||
|
|
||||||
|
case 0xdb:
|
||||||
|
if (allowValue)
|
||||||
|
return readString<uint32_t>(variant);
|
||||||
|
else
|
||||||
|
return skipString<uint32_t>();
|
||||||
|
|
||||||
|
case 0xdc:
|
||||||
|
return readArray<uint16_t>(variant, filter, nestingLimit);
|
||||||
|
|
||||||
|
case 0xdd:
|
||||||
|
return readArray<uint32_t>(variant, filter, nestingLimit);
|
||||||
|
|
||||||
|
case 0xde:
|
||||||
|
return readObject<uint16_t>(variant, filter, nestingLimit);
|
||||||
|
|
||||||
|
case 0xdf:
|
||||||
|
return readObject<uint32_t>(variant, filter, nestingLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (code & 0xf0) {
|
||||||
|
case 0x80:
|
||||||
|
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 DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeserializationError::Code readByte(uint8_t& value) {
|
||||||
|
int c = reader_.read();
|
||||||
|
if (c < 0)
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
|
value = static_cast<uint8_t>(c);
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeserializationError::Code readBytes(uint8_t* p, size_t n) {
|
||||||
|
if (reader_.readBytes(reinterpret_cast<char*>(p), n) == n)
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
DeserializationError::Code readBytes(T& value) {
|
||||||
|
return readBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
DeserializationError::Code skipBytes(size_t n) {
|
||||||
|
for (; n; --n) {
|
||||||
|
if (reader_.read() < 0)
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
|
}
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
DeserializationError::Code readInteger(T& value) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
|
||||||
|
err = readBytes(value);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
fixEndianess(value);
|
||||||
|
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
DeserializationError::Code readInteger(VariantData* variant) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
T value;
|
||||||
|
|
||||||
|
err = readInteger(value);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
variant->setInteger(value);
|
||||||
|
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
typename enable_if<sizeof(T) == 4, DeserializationError::Code>::type
|
||||||
|
readFloat(VariantData* variant) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
T value;
|
||||||
|
|
||||||
|
err = readBytes(value);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
fixEndianess(value);
|
||||||
|
variant->setFloat(value);
|
||||||
|
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
typename enable_if<sizeof(T) == 8, DeserializationError::Code>::type
|
||||||
|
readDouble(VariantData* variant) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
T value;
|
||||||
|
|
||||||
|
err = readBytes(value);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
fixEndianess(value);
|
||||||
|
variant->setFloat(value);
|
||||||
|
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
typename enable_if<sizeof(T) == 4, DeserializationError::Code>::type
|
||||||
|
readDouble(VariantData* variant) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
uint8_t i[8]; // input is 8 bytes
|
||||||
|
T value; // output is 4 bytes
|
||||||
|
uint8_t* o = reinterpret_cast<uint8_t*>(&value);
|
||||||
|
|
||||||
|
err = readBytes(i, 8);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
doubleToFloat(i, o);
|
||||||
|
fixEndianess(value);
|
||||||
|
variant->setFloat(value);
|
||||||
|
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
DeserializationError::Code readString(VariantData* variant) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
T size;
|
||||||
|
|
||||||
|
err = readInteger(size);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return readString(variant, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
DeserializationError::Code readString() {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
T size;
|
||||||
|
|
||||||
|
err = readInteger(size);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return readString(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
DeserializationError::Code skipString() {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
T size;
|
||||||
|
|
||||||
|
err = readInteger(size);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return skipBytes(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeserializationError::Code readString(VariantData* variant, size_t n) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
|
||||||
|
err = readString(n);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
variant->setString(stringStorage_.save());
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeserializationError::Code readString(size_t n) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
|
||||||
|
stringStorage_.startString();
|
||||||
|
for (; n; --n) {
|
||||||
|
uint8_t c;
|
||||||
|
|
||||||
|
err = readBytes(c);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
stringStorage_.append(static_cast<char>(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stringStorage_.isValid())
|
||||||
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSize, typename TFilter>
|
||||||
|
DeserializationError::Code readArray(
|
||||||
|
VariantData* variant, TFilter filter,
|
||||||
|
DeserializationOption::NestingLimit nestingLimit) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
TSize size;
|
||||||
|
|
||||||
|
err = readInteger(size);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return readArray(variant, size, filter, nestingLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TFilter>
|
||||||
|
DeserializationError::Code readArray(
|
||||||
|
VariantData* variant, size_t n, TFilter filter,
|
||||||
|
DeserializationOption::NestingLimit nestingLimit) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
|
||||||
|
if (nestingLimit.reached())
|
||||||
|
return DeserializationError::TooDeep;
|
||||||
|
|
||||||
|
bool allowArray = filter.allowArray();
|
||||||
|
|
||||||
|
CollectionData* array;
|
||||||
|
if (allowArray) {
|
||||||
|
ARDUINOJSON_ASSERT(variant != 0);
|
||||||
|
array = &variant->toArray();
|
||||||
|
} else {
|
||||||
|
array = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TFilter memberFilter = filter[0U];
|
||||||
|
|
||||||
|
for (; n; --n) {
|
||||||
|
VariantData* value;
|
||||||
|
|
||||||
|
if (memberFilter.allow()) {
|
||||||
|
ARDUINOJSON_ASSERT(array != 0);
|
||||||
|
value = array->addElement(pool_);
|
||||||
|
if (!value)
|
||||||
|
return DeserializationError::NoMemory;
|
||||||
|
} else {
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = parseVariant(value, memberFilter, nestingLimit.decrement());
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TSize, typename TFilter>
|
||||||
|
DeserializationError::Code readObject(
|
||||||
|
VariantData* variant, TFilter filter,
|
||||||
|
DeserializationOption::NestingLimit nestingLimit) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
TSize size;
|
||||||
|
|
||||||
|
err = readInteger(size);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return readObject(variant, size, filter, nestingLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TFilter>
|
||||||
|
DeserializationError::Code readObject(
|
||||||
|
VariantData* variant, size_t n, TFilter filter,
|
||||||
|
DeserializationOption::NestingLimit nestingLimit) {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
|
||||||
|
if (nestingLimit.reached())
|
||||||
|
return DeserializationError::TooDeep;
|
||||||
|
|
||||||
|
CollectionData* object;
|
||||||
|
if (filter.allowObject()) {
|
||||||
|
ARDUINOJSON_ASSERT(variant != 0);
|
||||||
|
object = &variant->toObject();
|
||||||
|
} else {
|
||||||
|
object = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; n; --n) {
|
||||||
|
err = readKey();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
JsonString key = stringStorage_.str();
|
||||||
|
TFilter memberFilter = filter[key.c_str()];
|
||||||
|
VariantData* member;
|
||||||
|
|
||||||
|
if (memberFilter.allow()) {
|
||||||
|
ARDUINOJSON_ASSERT(object != 0);
|
||||||
|
|
||||||
|
// Save key in memory pool.
|
||||||
|
// This MUST be done before adding the slot.
|
||||||
|
key = stringStorage_.save();
|
||||||
|
|
||||||
|
VariantSlot* slot = object->addSlot(pool_);
|
||||||
|
if (!slot)
|
||||||
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
|
slot->setKey(key);
|
||||||
|
|
||||||
|
member = slot->data();
|
||||||
|
} else {
|
||||||
|
member = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = parseVariant(member, memberFilter, nestingLimit.decrement());
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeserializationError::Code readKey() {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
uint8_t code;
|
||||||
|
|
||||||
|
err = readByte(code);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if ((code & 0xe0) == 0xa0)
|
||||||
|
return readString(code & 0x1f);
|
||||||
|
|
||||||
|
switch (code) {
|
||||||
|
case 0xd9:
|
||||||
|
return readString<uint8_t>();
|
||||||
|
|
||||||
|
case 0xda:
|
||||||
|
return readString<uint16_t>();
|
||||||
|
|
||||||
|
case 0xdb:
|
||||||
|
return readString<uint32_t>();
|
||||||
|
|
||||||
|
default:
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
DeserializationError::Code skipExt() {
|
||||||
|
DeserializationError::Code err;
|
||||||
|
T size;
|
||||||
|
|
||||||
|
err = readInteger(size);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return skipBytes(size + 1U);
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryPool* pool_;
|
||||||
|
TReader reader_;
|
||||||
|
TStringStorage stringStorage_;
|
||||||
|
bool foundSomething_;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
// Parses a MessagePack input and puts the result in a JsonDocument.
|
||||||
|
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
|
||||||
|
template <typename... Args>
|
||||||
|
DeserializationError deserializeMsgPack(JsonDocument& doc, Args&&... args) {
|
||||||
|
using namespace detail;
|
||||||
|
return deserialize<MsgPackDeserializer>(doc, detail::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parses a MessagePack input and puts the result in a JsonDocument.
|
||||||
|
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
|
||||||
|
template <typename TChar, typename... Args>
|
||||||
|
DeserializationError deserializeMsgPack(JsonDocument& doc, TChar* input,
|
||||||
|
Args&&... args) {
|
||||||
|
using namespace detail;
|
||||||
|
return deserialize<MsgPackDeserializer>(doc, input,
|
||||||
|
detail::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,227 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/MsgPack/endianess.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||||
|
#include <ArduinoJson/Serialization/CountingDecorator.hpp>
|
||||||
|
#include <ArduinoJson/Serialization/measure.hpp>
|
||||||
|
#include <ArduinoJson/Serialization/serialize.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename TWriter>
|
||||||
|
class MsgPackSerializer : public Visitor<size_t> {
|
||||||
|
public:
|
||||||
|
static const bool producesText = false;
|
||||||
|
|
||||||
|
MsgPackSerializer(TWriter writer) : writer_(writer) {}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
typename enable_if<sizeof(T) == 4, size_t>::type visitFloat(T value32) {
|
||||||
|
if (canConvertNumber<JsonInteger>(value32)) {
|
||||||
|
JsonInteger truncatedValue = JsonInteger(value32);
|
||||||
|
if (value32 == T(truncatedValue))
|
||||||
|
return visitSignedInteger(truncatedValue);
|
||||||
|
}
|
||||||
|
writeByte(0xCA);
|
||||||
|
writeInteger(value32);
|
||||||
|
return bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
ARDUINOJSON_NO_SANITIZE("float-cast-overflow")
|
||||||
|
typename enable_if<sizeof(T) == 8, size_t>::type visitFloat(T value64) {
|
||||||
|
float value32 = float(value64);
|
||||||
|
if (value32 == value64)
|
||||||
|
return visitFloat(value32);
|
||||||
|
writeByte(0xCB);
|
||||||
|
writeInteger(value64);
|
||||||
|
return bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t visitArray(const CollectionData& array) {
|
||||||
|
size_t n = array.size();
|
||||||
|
if (n < 0x10) {
|
||||||
|
writeByte(uint8_t(0x90 + n));
|
||||||
|
} else if (n < 0x10000) {
|
||||||
|
writeByte(0xDC);
|
||||||
|
writeInteger(uint16_t(n));
|
||||||
|
} else {
|
||||||
|
writeByte(0xDD);
|
||||||
|
writeInteger(uint32_t(n));
|
||||||
|
}
|
||||||
|
for (const VariantSlot* slot = array.head(); slot; slot = slot->next()) {
|
||||||
|
slot->data()->accept(*this);
|
||||||
|
}
|
||||||
|
return bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t visitObject(const CollectionData& object) {
|
||||||
|
size_t n = object.size();
|
||||||
|
if (n < 0x10) {
|
||||||
|
writeByte(uint8_t(0x80 + n));
|
||||||
|
} else if (n < 0x10000) {
|
||||||
|
writeByte(0xDE);
|
||||||
|
writeInteger(uint16_t(n));
|
||||||
|
} else {
|
||||||
|
writeByte(0xDF);
|
||||||
|
writeInteger(uint32_t(n));
|
||||||
|
}
|
||||||
|
for (const VariantSlot* slot = object.head(); slot; slot = slot->next()) {
|
||||||
|
visitString(slot->key());
|
||||||
|
slot->data()->accept(*this);
|
||||||
|
}
|
||||||
|
return bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t visitString(const char* value) {
|
||||||
|
return visitString(value, strlen(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t visitString(const char* value, size_t n) {
|
||||||
|
ARDUINOJSON_ASSERT(value != NULL);
|
||||||
|
|
||||||
|
if (n < 0x20) {
|
||||||
|
writeByte(uint8_t(0xA0 + n));
|
||||||
|
} else if (n < 0x100) {
|
||||||
|
writeByte(0xD9);
|
||||||
|
writeInteger(uint8_t(n));
|
||||||
|
} else if (n < 0x10000) {
|
||||||
|
writeByte(0xDA);
|
||||||
|
writeInteger(uint16_t(n));
|
||||||
|
} else {
|
||||||
|
writeByte(0xDB);
|
||||||
|
writeInteger(uint32_t(n));
|
||||||
|
}
|
||||||
|
writeBytes(reinterpret_cast<const uint8_t*>(value), n);
|
||||||
|
return bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t visitRawJson(const char* data, size_t size) {
|
||||||
|
writeBytes(reinterpret_cast<const uint8_t*>(data), size);
|
||||||
|
return bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t visitSignedInteger(JsonInteger value) {
|
||||||
|
if (value > 0) {
|
||||||
|
visitUnsignedInteger(static_cast<JsonUInt>(value));
|
||||||
|
} else if (value >= -0x20) {
|
||||||
|
writeInteger(int8_t(value));
|
||||||
|
} else if (value >= -0x80) {
|
||||||
|
writeByte(0xD0);
|
||||||
|
writeInteger(int8_t(value));
|
||||||
|
} else if (value >= -0x8000) {
|
||||||
|
writeByte(0xD1);
|
||||||
|
writeInteger(int16_t(value));
|
||||||
|
}
|
||||||
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
|
else if (value >= -0x80000000LL)
|
||||||
|
#else
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
writeByte(0xD2);
|
||||||
|
writeInteger(int32_t(value));
|
||||||
|
}
|
||||||
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
|
else {
|
||||||
|
writeByte(0xD3);
|
||||||
|
writeInteger(int64_t(value));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t visitUnsignedInteger(JsonUInt value) {
|
||||||
|
if (value <= 0x7F) {
|
||||||
|
writeInteger(uint8_t(value));
|
||||||
|
} else if (value <= 0xFF) {
|
||||||
|
writeByte(0xCC);
|
||||||
|
writeInteger(uint8_t(value));
|
||||||
|
} else if (value <= 0xFFFF) {
|
||||||
|
writeByte(0xCD);
|
||||||
|
writeInteger(uint16_t(value));
|
||||||
|
}
|
||||||
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
|
else if (value <= 0xFFFFFFFF)
|
||||||
|
#else
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
writeByte(0xCE);
|
||||||
|
writeInteger(uint32_t(value));
|
||||||
|
}
|
||||||
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
|
else {
|
||||||
|
writeByte(0xCF);
|
||||||
|
writeInteger(uint64_t(value));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t visitBoolean(bool value) {
|
||||||
|
writeByte(value ? 0xC3 : 0xC2);
|
||||||
|
return bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t visitNull() {
|
||||||
|
writeByte(0xC0);
|
||||||
|
return bytesWritten();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t bytesWritten() const {
|
||||||
|
return writer_.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeByte(uint8_t c) {
|
||||||
|
writer_.write(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeBytes(const uint8_t* p, size_t n) {
|
||||||
|
writer_.write(p, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void writeInteger(T value) {
|
||||||
|
fixEndianess(value);
|
||||||
|
writeBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
CountingDecorator<TWriter> writer_;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
// Produces a MessagePack document.
|
||||||
|
// https://arduinojson.org/v6/api/msgpack/serializemsgpack/
|
||||||
|
template <typename TDestination>
|
||||||
|
inline size_t serializeMsgPack(JsonVariantConst source, TDestination& output) {
|
||||||
|
using namespace ArduinoJson::detail;
|
||||||
|
return serialize<MsgPackSerializer>(source, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Produces a MessagePack document.
|
||||||
|
// https://arduinojson.org/v6/api/msgpack/serializemsgpack/
|
||||||
|
inline size_t serializeMsgPack(JsonVariantConst source, void* output,
|
||||||
|
size_t size) {
|
||||||
|
using namespace ArduinoJson::detail;
|
||||||
|
return serialize<MsgPackSerializer>(source, output, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Computes the length of the document that serializeMsgPack() produces.
|
||||||
|
// https://arduinojson.org/v6/api/msgpack/measuremsgpack/
|
||||||
|
inline size_t measureMsgPack(JsonVariantConst source) {
|
||||||
|
using namespace ArduinoJson::detail;
|
||||||
|
return measure<MsgPackSerializer>(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,46 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
#if ARDUINOJSON_LITTLE_ENDIAN
|
||||||
|
inline void swapBytes(uint8_t& a, uint8_t& b) {
|
||||||
|
uint8_t t(a);
|
||||||
|
a = b;
|
||||||
|
b = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void fixEndianess(uint8_t* p, integral_constant<size_t, 8>) {
|
||||||
|
swapBytes(p[0], p[7]);
|
||||||
|
swapBytes(p[1], p[6]);
|
||||||
|
swapBytes(p[2], p[5]);
|
||||||
|
swapBytes(p[3], p[4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void fixEndianess(uint8_t* p, integral_constant<size_t, 4>) {
|
||||||
|
swapBytes(p[0], p[3]);
|
||||||
|
swapBytes(p[1], p[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void fixEndianess(uint8_t* p, integral_constant<size_t, 2>) {
|
||||||
|
swapBytes(p[0], p[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void fixEndianess(uint8_t*, integral_constant<size_t, 1>) {}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline void fixEndianess(T& value) {
|
||||||
|
fixEndianess(reinterpret_cast<uint8_t*>(&value),
|
||||||
|
integral_constant<size_t, sizeof(T)>());
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
template <typename T>
|
||||||
|
inline void fixEndianess(T&) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,18 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
inline void doubleToFloat(const uint8_t d[8], uint8_t f[4]) {
|
||||||
|
f[0] = uint8_t((d[0] & 0xC0) | (d[0] << 3 & 0x3f) | (d[1] >> 5));
|
||||||
|
f[1] = uint8_t((d[1] << 3) | (d[2] >> 5));
|
||||||
|
f[2] = uint8_t((d[2] << 3) | (d[3] >> 5));
|
||||||
|
f[3] = uint8_t((d[3] << 3) | (d[4] >> 5));
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,42 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Configuration.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/preprocessor.hpp>
|
||||||
|
#include <ArduinoJson/version.hpp>
|
||||||
|
|
||||||
|
#ifndef ARDUINOJSON_VERSION_NAMESPACE
|
||||||
|
|
||||||
|
# define ARDUINOJSON_VERSION_NAMESPACE \
|
||||||
|
ARDUINOJSON_CONCAT4( \
|
||||||
|
ARDUINOJSON_VERSION_MACRO, \
|
||||||
|
ARDUINOJSON_BIN2ALPHA( \
|
||||||
|
ARDUINOJSON_ENABLE_PROGMEM, ARDUINOJSON_USE_LONG_LONG, \
|
||||||
|
ARDUINOJSON_USE_DOUBLE, ARDUINOJSON_ENABLE_STRING_DEDUPLICATION), \
|
||||||
|
ARDUINOJSON_BIN2ALPHA( \
|
||||||
|
ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY, \
|
||||||
|
ARDUINOJSON_ENABLE_COMMENTS, ARDUINOJSON_DECODE_UNICODE), \
|
||||||
|
ARDUINOJSON_SLOT_OFFSET_SIZE)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE \
|
||||||
|
namespace ArduinoJson { \
|
||||||
|
inline namespace ARDUINOJSON_VERSION_NAMESPACE {
|
||||||
|
|
||||||
|
#define ARDUINOJSON_END_PUBLIC_NAMESPACE \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE \
|
||||||
|
namespace ArduinoJson { \
|
||||||
|
inline namespace ARDUINOJSON_VERSION_NAMESPACE { \
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
#define ARDUINOJSON_END_PRIVATE_NAMESPACE \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Configuration.hpp>
|
||||||
|
#include <ArduinoJson/Numbers/FloatTraits.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/math.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename TFloat>
|
||||||
|
struct FloatParts {
|
||||||
|
uint32_t integral;
|
||||||
|
uint32_t decimal;
|
||||||
|
int16_t exponent;
|
||||||
|
int8_t decimalPlaces;
|
||||||
|
|
||||||
|
FloatParts(TFloat value) {
|
||||||
|
uint32_t maxDecimalPart = sizeof(TFloat) >= 8 ? 1000000000 : 1000000;
|
||||||
|
decimalPlaces = sizeof(TFloat) >= 8 ? 9 : 6;
|
||||||
|
|
||||||
|
exponent = normalize(value);
|
||||||
|
|
||||||
|
integral = uint32_t(value);
|
||||||
|
// reduce number of decimal places by the number of integral places
|
||||||
|
for (uint32_t tmp = integral; tmp >= 10; tmp /= 10) {
|
||||||
|
maxDecimalPart /= 10;
|
||||||
|
decimalPlaces--;
|
||||||
|
}
|
||||||
|
|
||||||
|
TFloat remainder = (value - TFloat(integral)) * TFloat(maxDecimalPart);
|
||||||
|
|
||||||
|
decimal = uint32_t(remainder);
|
||||||
|
remainder = remainder - TFloat(decimal);
|
||||||
|
|
||||||
|
// rounding:
|
||||||
|
// increment by 1 if remainder >= 0.5
|
||||||
|
decimal += uint32_t(remainder * 2);
|
||||||
|
if (decimal >= maxDecimalPart) {
|
||||||
|
decimal = 0;
|
||||||
|
integral++;
|
||||||
|
if (exponent && integral >= 10) {
|
||||||
|
exponent++;
|
||||||
|
integral = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove trailing zeros
|
||||||
|
while (decimal % 10 == 0 && decimalPlaces > 0) {
|
||||||
|
decimal /= 10;
|
||||||
|
decimalPlaces--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int16_t normalize(TFloat& value) {
|
||||||
|
typedef FloatTraits<TFloat> traits;
|
||||||
|
int16_t powersOf10 = 0;
|
||||||
|
|
||||||
|
int8_t index = sizeof(TFloat) == 8 ? 8 : 5;
|
||||||
|
int bit = 1 << index;
|
||||||
|
|
||||||
|
if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) {
|
||||||
|
for (; index >= 0; index--) {
|
||||||
|
if (value >= traits::positiveBinaryPowersOfTen()[index]) {
|
||||||
|
value *= traits::negativeBinaryPowersOfTen()[index];
|
||||||
|
powersOf10 = int16_t(powersOf10 + bit);
|
||||||
|
}
|
||||||
|
bit >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) {
|
||||||
|
for (; index >= 0; index--) {
|
||||||
|
if (value < traits::negativeBinaryPowersOfTen()[index] * 10) {
|
||||||
|
value *= traits::positiveBinaryPowersOfTen()[index];
|
||||||
|
powersOf10 = int16_t(powersOf10 - bit);
|
||||||
|
}
|
||||||
|
bit >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return powersOf10;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,212 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h> // for size_t
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <ArduinoJson/Configuration.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/alias_cast.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/math.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/pgmspace_generic.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/preprocessor.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename T, size_t = sizeof(T)>
|
||||||
|
struct FloatTraits {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct FloatTraits<T, 8 /*64bits*/> {
|
||||||
|
typedef uint64_t mantissa_type;
|
||||||
|
static const short mantissa_bits = 52;
|
||||||
|
static const mantissa_type mantissa_max =
|
||||||
|
(mantissa_type(1) << mantissa_bits) - 1;
|
||||||
|
|
||||||
|
typedef int16_t exponent_type;
|
||||||
|
static const exponent_type exponent_max = 308;
|
||||||
|
|
||||||
|
static pgm_ptr<T> positiveBinaryPowersOfTen() {
|
||||||
|
ARDUINOJSON_DEFINE_PROGMEM_ARRAY( //
|
||||||
|
uint64_t, factors,
|
||||||
|
{
|
||||||
|
0x4024000000000000, // 1e1
|
||||||
|
0x4059000000000000, // 1e2
|
||||||
|
0x40C3880000000000, // 1e4
|
||||||
|
0x4197D78400000000, // 1e8
|
||||||
|
0x4341C37937E08000, // 1e16
|
||||||
|
0x4693B8B5B5056E17, // 1e32
|
||||||
|
0x4D384F03E93FF9F5, // 1e64
|
||||||
|
0x5A827748F9301D32, // 1e128
|
||||||
|
0x75154FDD7F73BF3C, // 1e256
|
||||||
|
});
|
||||||
|
return pgm_ptr<T>(reinterpret_cast<const T*>(factors));
|
||||||
|
}
|
||||||
|
|
||||||
|
static pgm_ptr<T> negativeBinaryPowersOfTen() {
|
||||||
|
ARDUINOJSON_DEFINE_PROGMEM_ARRAY( //
|
||||||
|
uint64_t, factors,
|
||||||
|
{
|
||||||
|
0x3FB999999999999A, // 1e-1
|
||||||
|
0x3F847AE147AE147B, // 1e-2
|
||||||
|
0x3F1A36E2EB1C432D, // 1e-4
|
||||||
|
0x3E45798EE2308C3A, // 1e-8
|
||||||
|
0x3C9CD2B297D889BC, // 1e-16
|
||||||
|
0x3949F623D5A8A733, // 1e-32
|
||||||
|
0x32A50FFD44F4A73D, // 1e-64
|
||||||
|
0x255BBA08CF8C979D, // 1e-128
|
||||||
|
0x0AC8062864AC6F43 // 1e-256
|
||||||
|
});
|
||||||
|
return pgm_ptr<T>(reinterpret_cast<const T*>(factors));
|
||||||
|
}
|
||||||
|
|
||||||
|
static T nan() {
|
||||||
|
return forge(0x7ff8000000000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
static T inf() {
|
||||||
|
return forge(0x7ff0000000000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
static T highest() {
|
||||||
|
return forge(0x7FEFFFFFFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TOut> // int64_t
|
||||||
|
static T highest_for(
|
||||||
|
typename enable_if<is_integral<TOut>::value && is_signed<TOut>::value &&
|
||||||
|
sizeof(TOut) == 8,
|
||||||
|
signed>::type* = 0) {
|
||||||
|
return forge(0x43DFFFFFFFFFFFFF); // 9.2233720368547748e+18
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TOut> // uint64_t
|
||||||
|
static T highest_for(
|
||||||
|
typename enable_if<is_integral<TOut>::value && is_unsigned<TOut>::value &&
|
||||||
|
sizeof(TOut) == 8,
|
||||||
|
unsigned>::type* = 0) {
|
||||||
|
return forge(0x43EFFFFFFFFFFFFF); // 1.8446744073709549568e+19
|
||||||
|
}
|
||||||
|
|
||||||
|
static T lowest() {
|
||||||
|
return forge(0xFFEFFFFFFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// constructs a double floating point values from its binary representation
|
||||||
|
// we use this function to workaround platforms with single precision literals
|
||||||
|
// (for example, when -fsingle-precision-constant is passed to GCC)
|
||||||
|
static T forge(uint64_t bits) {
|
||||||
|
return alias_cast<T>(bits);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct FloatTraits<T, 4 /*32bits*/> {
|
||||||
|
typedef uint32_t mantissa_type;
|
||||||
|
static const short mantissa_bits = 23;
|
||||||
|
static const mantissa_type mantissa_max =
|
||||||
|
(mantissa_type(1) << mantissa_bits) - 1;
|
||||||
|
|
||||||
|
typedef int8_t exponent_type;
|
||||||
|
static const exponent_type exponent_max = 38;
|
||||||
|
|
||||||
|
static pgm_ptr<T> positiveBinaryPowersOfTen() {
|
||||||
|
ARDUINOJSON_DEFINE_PROGMEM_ARRAY(uint32_t, factors,
|
||||||
|
{
|
||||||
|
0x41200000, // 1e1f
|
||||||
|
0x42c80000, // 1e2f
|
||||||
|
0x461c4000, // 1e4f
|
||||||
|
0x4cbebc20, // 1e8f
|
||||||
|
0x5a0e1bca, // 1e16f
|
||||||
|
0x749dc5ae // 1e32f
|
||||||
|
});
|
||||||
|
return pgm_ptr<T>(reinterpret_cast<const T*>(factors));
|
||||||
|
}
|
||||||
|
|
||||||
|
static pgm_ptr<T> negativeBinaryPowersOfTen() {
|
||||||
|
ARDUINOJSON_DEFINE_PROGMEM_ARRAY(uint32_t, factors,
|
||||||
|
{
|
||||||
|
0x3dcccccd, // 1e-1f
|
||||||
|
0x3c23d70a, // 1e-2f
|
||||||
|
0x38d1b717, // 1e-4f
|
||||||
|
0x322bcc77, // 1e-8f
|
||||||
|
0x24e69595, // 1e-16f
|
||||||
|
0x0a4fb11f // 1e-32f
|
||||||
|
});
|
||||||
|
return pgm_ptr<T>(reinterpret_cast<const T*>(factors));
|
||||||
|
}
|
||||||
|
|
||||||
|
static T forge(uint32_t bits) {
|
||||||
|
return alias_cast<T>(bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
static T nan() {
|
||||||
|
return forge(0x7fc00000);
|
||||||
|
}
|
||||||
|
|
||||||
|
static T inf() {
|
||||||
|
return forge(0x7f800000);
|
||||||
|
}
|
||||||
|
|
||||||
|
static T highest() {
|
||||||
|
return forge(0x7f7fffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TOut> // int32_t
|
||||||
|
static T highest_for(
|
||||||
|
typename enable_if<is_integral<TOut>::value && is_signed<TOut>::value &&
|
||||||
|
sizeof(TOut) == 4,
|
||||||
|
signed>::type* = 0) {
|
||||||
|
return forge(0x4EFFFFFF); // 2.14748352E9
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TOut> // uint32_t
|
||||||
|
static T highest_for(
|
||||||
|
typename enable_if<is_integral<TOut>::value && is_unsigned<TOut>::value &&
|
||||||
|
sizeof(TOut) == 4,
|
||||||
|
unsigned>::type* = 0) {
|
||||||
|
return forge(0x4F7FFFFF); // 4.29496704E9
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TOut> // int64_t
|
||||||
|
static T highest_for(
|
||||||
|
typename enable_if<is_integral<TOut>::value && is_signed<TOut>::value &&
|
||||||
|
sizeof(TOut) == 8,
|
||||||
|
signed>::type* = 0) {
|
||||||
|
return forge(0x5EFFFFFF); // 9.22337148709896192E18
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TOut> // uint64_t
|
||||||
|
static T highest_for(
|
||||||
|
typename enable_if<is_integral<TOut>::value && is_unsigned<TOut>::value &&
|
||||||
|
sizeof(TOut) == 8,
|
||||||
|
unsigned>::type* = 0) {
|
||||||
|
return forge(0x5F7FFFFF); // 1.844674297419792384E19
|
||||||
|
}
|
||||||
|
|
||||||
|
static T lowest() {
|
||||||
|
return forge(0xFf7fffff);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TFloat, typename TExponent>
|
||||||
|
inline TFloat make_float(TFloat m, TExponent e) {
|
||||||
|
using traits = FloatTraits<TFloat>;
|
||||||
|
|
||||||
|
auto powersOfTen = e > 0 ? traits::positiveBinaryPowersOfTen()
|
||||||
|
: traits::negativeBinaryPowersOfTen();
|
||||||
|
if (e <= 0)
|
||||||
|
e = TExponent(-e);
|
||||||
|
|
||||||
|
for (uint8_t index = 0; e != 0; index++) {
|
||||||
|
if (e & 1)
|
||||||
|
m *= powersOfTen[index];
|
||||||
|
e >>= 1;
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,18 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Configuration.hpp>
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
#if ARDUINOJSON_USE_DOUBLE
|
||||||
|
typedef double JsonFloat;
|
||||||
|
#else
|
||||||
|
typedef float JsonFloat;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,28 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Configuration.hpp>
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
#include <stdint.h> // int64_t
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
|
typedef int64_t JsonInteger;
|
||||||
|
typedef uint64_t JsonUInt;
|
||||||
|
#else
|
||||||
|
typedef long JsonInteger;
|
||||||
|
typedef unsigned long JsonUInt;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
#define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) \
|
||||||
|
static_assert(sizeof(T) <= sizeof(ArduinoJson::JsonInteger), \
|
||||||
|
"To use 64-bit integers with ArduinoJson, you must set " \
|
||||||
|
"ARDUINOJSON_USE_LONG_LONG to 1. See " \
|
||||||
|
"https://arduinojson.org/v6/api/config/use_long_long/");
|
@ -0,0 +1,120 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Numbers/JsonInteger.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
enum CompareResult {
|
||||||
|
COMPARE_RESULT_DIFFER = 0,
|
||||||
|
COMPARE_RESULT_EQUAL = 1,
|
||||||
|
COMPARE_RESULT_GREATER = 2,
|
||||||
|
COMPARE_RESULT_LESS = 4,
|
||||||
|
|
||||||
|
COMPARE_RESULT_GREATER_OR_EQUAL = 3,
|
||||||
|
COMPARE_RESULT_LESS_OR_EQUAL = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
CompareResult arithmeticCompare(const T& lhs, const T& rhs) {
|
||||||
|
if (lhs < rhs)
|
||||||
|
return COMPARE_RESULT_LESS;
|
||||||
|
else if (lhs > rhs)
|
||||||
|
return COMPARE_RESULT_GREATER;
|
||||||
|
else
|
||||||
|
return COMPARE_RESULT_EQUAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
CompareResult arithmeticCompare(
|
||||||
|
const T1& lhs, const T2& rhs,
|
||||||
|
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||||
|
sizeof(T1) < sizeof(T2)>::type* = 0) {
|
||||||
|
return arithmeticCompare<T2>(static_cast<T2>(lhs), rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
CompareResult arithmeticCompare(
|
||||||
|
const T1& lhs, const T2& rhs,
|
||||||
|
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||||
|
sizeof(T2) < sizeof(T1)>::type* = 0) {
|
||||||
|
return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
CompareResult arithmeticCompare(
|
||||||
|
const T1& lhs, const T2& rhs,
|
||||||
|
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||||
|
is_signed<T1>::value == is_signed<T2>::value &&
|
||||||
|
sizeof(T2) == sizeof(T1)>::type* = 0) {
|
||||||
|
return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
CompareResult arithmeticCompare(
|
||||||
|
const T1& lhs, const T2& rhs,
|
||||||
|
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||||
|
is_unsigned<T1>::value && is_signed<T2>::value &&
|
||||||
|
sizeof(T2) == sizeof(T1)>::type* = 0) {
|
||||||
|
if (rhs < 0)
|
||||||
|
return COMPARE_RESULT_GREATER;
|
||||||
|
return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
CompareResult arithmeticCompare(
|
||||||
|
const T1& lhs, const T2& rhs,
|
||||||
|
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||||
|
is_signed<T1>::value && is_unsigned<T2>::value &&
|
||||||
|
sizeof(T2) == sizeof(T1)>::type* = 0) {
|
||||||
|
if (lhs < 0)
|
||||||
|
return COMPARE_RESULT_LESS;
|
||||||
|
return arithmeticCompare<T2>(static_cast<T2>(lhs), rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
CompareResult arithmeticCompare(
|
||||||
|
const T1& lhs, const T2& rhs,
|
||||||
|
typename enable_if<is_floating_point<T1>::value ||
|
||||||
|
is_floating_point<T2>::value>::type* = 0) {
|
||||||
|
return arithmeticCompare<double>(static_cast<double>(lhs),
|
||||||
|
static_cast<double>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T2>
|
||||||
|
CompareResult arithmeticCompareNegateLeft(
|
||||||
|
JsonUInt, const T2&,
|
||||||
|
typename enable_if<is_unsigned<T2>::value>::type* = 0) {
|
||||||
|
return COMPARE_RESULT_LESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T2>
|
||||||
|
CompareResult arithmeticCompareNegateLeft(
|
||||||
|
JsonUInt lhs, const T2& rhs,
|
||||||
|
typename enable_if<is_signed<T2>::value>::type* = 0) {
|
||||||
|
if (rhs > 0)
|
||||||
|
return COMPARE_RESULT_LESS;
|
||||||
|
return arithmeticCompare(-rhs, static_cast<T2>(lhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1>
|
||||||
|
CompareResult arithmeticCompareNegateRight(
|
||||||
|
const T1&, JsonUInt,
|
||||||
|
typename enable_if<is_unsigned<T1>::value>::type* = 0) {
|
||||||
|
return COMPARE_RESULT_GREATER;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1>
|
||||||
|
CompareResult arithmeticCompareNegateRight(
|
||||||
|
const T1& lhs, JsonUInt rhs,
|
||||||
|
typename enable_if<is_signed<T1>::value>::type* = 0) {
|
||||||
|
if (lhs > 0)
|
||||||
|
return COMPARE_RESULT_GREATER;
|
||||||
|
return arithmeticCompare(static_cast<T1>(rhs), -lhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,135 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
# pragma clang diagnostic push
|
||||||
|
# pragma clang diagnostic ignored "-Wconversion"
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wconversion"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <ArduinoJson/Numbers/FloatTraits.hpp>
|
||||||
|
#include <ArduinoJson/Numbers/JsonFloat.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/limits.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
// uint32 -> int32
|
||||||
|
// uint64 -> int32
|
||||||
|
template <typename TOut, typename TIn>
|
||||||
|
typename enable_if<is_integral<TIn>::value && is_unsigned<TIn>::value &&
|
||||||
|
is_integral<TOut>::value && sizeof(TOut) <= sizeof(TIn),
|
||||||
|
bool>::type
|
||||||
|
canConvertNumber(TIn value) {
|
||||||
|
return value <= TIn(numeric_limits<TOut>::highest());
|
||||||
|
}
|
||||||
|
|
||||||
|
// uint32 -> int64
|
||||||
|
template <typename TOut, typename TIn>
|
||||||
|
typename enable_if<is_integral<TIn>::value && is_unsigned<TIn>::value &&
|
||||||
|
is_integral<TOut>::value && sizeof(TIn) < sizeof(TOut),
|
||||||
|
bool>::type
|
||||||
|
canConvertNumber(TIn) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// uint32 -> float
|
||||||
|
// int32 -> float
|
||||||
|
template <typename TOut, typename TIn>
|
||||||
|
typename enable_if<is_integral<TIn>::value && is_floating_point<TOut>::value,
|
||||||
|
bool>::type
|
||||||
|
canConvertNumber(TIn) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// int64 -> int32
|
||||||
|
template <typename TOut, typename TIn>
|
||||||
|
typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value &&
|
||||||
|
is_integral<TOut>::value && is_signed<TOut>::value &&
|
||||||
|
sizeof(TOut) < sizeof(TIn),
|
||||||
|
bool>::type
|
||||||
|
canConvertNumber(TIn value) {
|
||||||
|
return value >= TIn(numeric_limits<TOut>::lowest()) &&
|
||||||
|
value <= TIn(numeric_limits<TOut>::highest());
|
||||||
|
}
|
||||||
|
|
||||||
|
// int32 -> int32
|
||||||
|
// int32 -> int64
|
||||||
|
template <typename TOut, typename TIn>
|
||||||
|
typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value &&
|
||||||
|
is_integral<TOut>::value && is_signed<TOut>::value &&
|
||||||
|
sizeof(TIn) <= sizeof(TOut),
|
||||||
|
bool>::type
|
||||||
|
canConvertNumber(TIn) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// int32 -> uint32
|
||||||
|
// int32 -> uint64
|
||||||
|
template <typename TOut, typename TIn>
|
||||||
|
typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value &&
|
||||||
|
is_integral<TOut>::value && is_unsigned<TOut>::value &&
|
||||||
|
sizeof(TOut) >= sizeof(TIn),
|
||||||
|
bool>::type
|
||||||
|
canConvertNumber(TIn value) {
|
||||||
|
if (value < 0)
|
||||||
|
return false;
|
||||||
|
return TOut(value) <= numeric_limits<TOut>::highest();
|
||||||
|
}
|
||||||
|
|
||||||
|
// int32 -> uint16
|
||||||
|
template <typename TOut, typename TIn>
|
||||||
|
typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value &&
|
||||||
|
is_integral<TOut>::value && is_unsigned<TOut>::value &&
|
||||||
|
sizeof(TOut) < sizeof(TIn),
|
||||||
|
bool>::type
|
||||||
|
canConvertNumber(TIn value) {
|
||||||
|
if (value < 0)
|
||||||
|
return false;
|
||||||
|
return value <= TIn(numeric_limits<TOut>::highest());
|
||||||
|
}
|
||||||
|
|
||||||
|
// float32 -> int16
|
||||||
|
// float64 -> int32
|
||||||
|
template <typename TOut, typename TIn>
|
||||||
|
typename enable_if<is_floating_point<TIn>::value && is_integral<TOut>::value &&
|
||||||
|
sizeof(TOut) < sizeof(TIn),
|
||||||
|
bool>::type
|
||||||
|
canConvertNumber(TIn value) {
|
||||||
|
return value >= numeric_limits<TOut>::lowest() &&
|
||||||
|
value <= numeric_limits<TOut>::highest();
|
||||||
|
}
|
||||||
|
|
||||||
|
// float32 -> int32
|
||||||
|
// float32 -> uint32
|
||||||
|
// float32 -> int64
|
||||||
|
// float32 -> uint64
|
||||||
|
// float64 -> int64
|
||||||
|
// float64 -> uint64
|
||||||
|
template <typename TOut, typename TIn>
|
||||||
|
typename enable_if<is_floating_point<TIn>::value && is_integral<TOut>::value &&
|
||||||
|
sizeof(TOut) >= sizeof(TIn),
|
||||||
|
bool>::type
|
||||||
|
canConvertNumber(TIn value) {
|
||||||
|
// Avoid error "9.22337e+18 is outside the range of representable values of
|
||||||
|
// type 'long'"
|
||||||
|
return value >= numeric_limits<TOut>::lowest() &&
|
||||||
|
value <= FloatTraits<TIn>::template highest_for<TOut>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TOut, typename TIn>
|
||||||
|
TOut convertNumber(TIn value) {
|
||||||
|
return canConvertNumber<TOut>(value) ? TOut(value) : 0;
|
||||||
|
}
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
# pragma clang diagnostic pop
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#endif
|
@ -0,0 +1,152 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Numbers/FloatTraits.hpp>
|
||||||
|
#include <ArduinoJson/Numbers/convertNumber.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/ctype.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/math.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||||
|
#include <ArduinoJson/Variant/Converter.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename A, typename B>
|
||||||
|
struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> {};
|
||||||
|
|
||||||
|
inline bool parseNumber(const char* s, VariantData& result) {
|
||||||
|
typedef FloatTraits<JsonFloat> traits;
|
||||||
|
typedef choose_largest<traits::mantissa_type, JsonUInt>::type mantissa_t;
|
||||||
|
typedef traits::exponent_type exponent_t;
|
||||||
|
|
||||||
|
ARDUINOJSON_ASSERT(s != 0);
|
||||||
|
|
||||||
|
bool is_negative = false;
|
||||||
|
switch (*s) {
|
||||||
|
case '-':
|
||||||
|
is_negative = true;
|
||||||
|
s++;
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
s++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ARDUINOJSON_ENABLE_NAN
|
||||||
|
if (*s == 'n' || *s == 'N') {
|
||||||
|
result.setFloat(traits::nan());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ARDUINOJSON_ENABLE_INFINITY
|
||||||
|
if (*s == 'i' || *s == 'I') {
|
||||||
|
result.setFloat(is_negative ? -traits::inf() : traits::inf());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!isdigit(*s) && *s != '.')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
mantissa_t mantissa = 0;
|
||||||
|
exponent_t exponent_offset = 0;
|
||||||
|
const mantissa_t maxUint = JsonUInt(-1);
|
||||||
|
|
||||||
|
while (isdigit(*s)) {
|
||||||
|
uint8_t digit = uint8_t(*s - '0');
|
||||||
|
if (mantissa > maxUint / 10)
|
||||||
|
break;
|
||||||
|
mantissa *= 10;
|
||||||
|
if (mantissa > maxUint - digit)
|
||||||
|
break;
|
||||||
|
mantissa += digit;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*s == '\0') {
|
||||||
|
if (is_negative) {
|
||||||
|
const mantissa_t sintMantissaMax = mantissa_t(1)
|
||||||
|
<< (sizeof(JsonInteger) * 8 - 1);
|
||||||
|
if (mantissa <= sintMantissaMax) {
|
||||||
|
result.setInteger(JsonInteger(~mantissa + 1));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.setInteger(JsonUInt(mantissa));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// avoid mantissa overflow
|
||||||
|
while (mantissa > traits::mantissa_max) {
|
||||||
|
mantissa /= 10;
|
||||||
|
exponent_offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remaing digits can't fit in the mantissa
|
||||||
|
while (isdigit(*s)) {
|
||||||
|
exponent_offset++;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*s == '.') {
|
||||||
|
s++;
|
||||||
|
while (isdigit(*s)) {
|
||||||
|
if (mantissa < traits::mantissa_max / 10) {
|
||||||
|
mantissa = mantissa * 10 + uint8_t(*s - '0');
|
||||||
|
exponent_offset--;
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int exponent = 0;
|
||||||
|
if (*s == 'e' || *s == 'E') {
|
||||||
|
s++;
|
||||||
|
bool negative_exponent = false;
|
||||||
|
if (*s == '-') {
|
||||||
|
negative_exponent = true;
|
||||||
|
s++;
|
||||||
|
} else if (*s == '+') {
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (isdigit(*s)) {
|
||||||
|
exponent = exponent * 10 + (*s - '0');
|
||||||
|
if (exponent + exponent_offset > traits::exponent_max) {
|
||||||
|
if (negative_exponent)
|
||||||
|
result.setFloat(is_negative ? -0.0f : 0.0f);
|
||||||
|
else
|
||||||
|
result.setFloat(is_negative ? -traits::inf() : traits::inf());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
if (negative_exponent)
|
||||||
|
exponent = -exponent;
|
||||||
|
}
|
||||||
|
exponent += exponent_offset;
|
||||||
|
|
||||||
|
// we should be at the end of the string, otherwise it's an error
|
||||||
|
if (*s != '\0')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
JsonFloat final_result =
|
||||||
|
make_float(static_cast<JsonFloat>(mantissa), exponent);
|
||||||
|
|
||||||
|
result.setFloat(is_negative ? -final_result : final_result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T parseNumber(const char* s) {
|
||||||
|
VariantData value;
|
||||||
|
parseNumber(s, value);
|
||||||
|
return Converter<T>::fromJson(JsonVariantConst(&value));
|
||||||
|
}
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,251 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Object/JsonObjectConst.hpp>
|
||||||
|
#include <ArduinoJson/Object/MemberProxy.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
class JsonArray;
|
||||||
|
|
||||||
|
// A reference to an object in a JsonDocument.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/
|
||||||
|
class JsonObject : public detail::VariantOperators<JsonObject> {
|
||||||
|
friend class detail::VariantAttorney;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef JsonObjectIterator iterator;
|
||||||
|
|
||||||
|
// Creates an unbound reference.
|
||||||
|
FORCE_INLINE JsonObject() : data_(0), pool_(0) {}
|
||||||
|
|
||||||
|
// INTERNAL USE ONLY
|
||||||
|
FORCE_INLINE JsonObject(detail::MemoryPool* buf, detail::CollectionData* data)
|
||||||
|
: data_(data), pool_(buf) {}
|
||||||
|
|
||||||
|
operator JsonVariant() const {
|
||||||
|
void* data = data_; // prevent warning cast-align
|
||||||
|
return JsonVariant(pool_, reinterpret_cast<detail::VariantData*>(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
operator JsonObjectConst() const {
|
||||||
|
return JsonObjectConst(data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
operator JsonVariantConst() const {
|
||||||
|
return JsonVariantConst(collectionToVariant(data_));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the reference is unbound.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/isnull/
|
||||||
|
FORCE_INLINE bool isNull() const {
|
||||||
|
return data_ == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the reference is bound.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/isnull/
|
||||||
|
FORCE_INLINE operator bool() const {
|
||||||
|
return data_ != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the number of bytes occupied by the object.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/memoryusage/
|
||||||
|
FORCE_INLINE size_t memoryUsage() const {
|
||||||
|
return data_ ? data_->memoryUsage() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the depth (nesting level) of the object.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/nesting/
|
||||||
|
FORCE_INLINE size_t nesting() const {
|
||||||
|
return variantNesting(collectionToVariant(data_));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the number of members in the object.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/size/
|
||||||
|
FORCE_INLINE size_t size() const {
|
||||||
|
return data_ ? data_->size() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns an iterator to the first key-value pair of the object.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/begin/
|
||||||
|
FORCE_INLINE iterator begin() const {
|
||||||
|
if (!data_)
|
||||||
|
return iterator();
|
||||||
|
return iterator(pool_, data_->head());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns an iterator following the last key-value pair of the object.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/end/
|
||||||
|
FORCE_INLINE iterator end() const {
|
||||||
|
return iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes all the members of the object.
|
||||||
|
// ⚠️ Doesn't release the memory associated with the removed members.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/clear/
|
||||||
|
void clear() const {
|
||||||
|
if (!data_)
|
||||||
|
return;
|
||||||
|
data_->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copies an object.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/set/
|
||||||
|
FORCE_INLINE bool set(JsonObjectConst src) {
|
||||||
|
if (!data_ || !src.data_)
|
||||||
|
return false;
|
||||||
|
return data_->copyFrom(*src.data_, pool_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compares the content of two objects.
|
||||||
|
FORCE_INLINE bool operator==(JsonObject rhs) const {
|
||||||
|
return JsonObjectConst(data_) == JsonObjectConst(rhs.data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets or sets the member with specified key.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/subscript/
|
||||||
|
template <typename TString>
|
||||||
|
FORCE_INLINE
|
||||||
|
typename detail::enable_if<detail::IsString<TString>::value,
|
||||||
|
detail::MemberProxy<JsonObject, TString>>::type
|
||||||
|
operator[](const TString& key) const {
|
||||||
|
return {*this, key};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets or sets the member with specified key.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/subscript/
|
||||||
|
template <typename TChar>
|
||||||
|
FORCE_INLINE
|
||||||
|
typename detail::enable_if<detail::IsString<TChar*>::value,
|
||||||
|
detail::MemberProxy<JsonObject, TChar*>>::type
|
||||||
|
operator[](TChar* key) const {
|
||||||
|
return {*this, key};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes the member at the specified iterator.
|
||||||
|
// ⚠️ Doesn't release the memory associated with the removed member.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/remove/
|
||||||
|
FORCE_INLINE void remove(iterator it) const {
|
||||||
|
if (!data_)
|
||||||
|
return;
|
||||||
|
data_->removeSlot(it.slot_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes the member with the specified key.
|
||||||
|
// ⚠️ Doesn't release the memory associated with the removed member.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/remove/
|
||||||
|
template <typename TString>
|
||||||
|
FORCE_INLINE void remove(const TString& key) const {
|
||||||
|
removeMember(detail::adaptString(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes the member with the specified key.
|
||||||
|
// ⚠️ Doesn't release the memory associated with the removed member.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/remove/
|
||||||
|
template <typename TChar>
|
||||||
|
FORCE_INLINE void remove(TChar* key) const {
|
||||||
|
removeMember(detail::adaptString(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the object contains the specified key.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/containskey/
|
||||||
|
template <typename TString>
|
||||||
|
FORCE_INLINE
|
||||||
|
typename detail::enable_if<detail::IsString<TString>::value, bool>::type
|
||||||
|
containsKey(const TString& key) const {
|
||||||
|
return getMember(detail::adaptString(key)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the object contains the specified key.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/containskey/
|
||||||
|
template <typename TChar>
|
||||||
|
FORCE_INLINE
|
||||||
|
typename detail::enable_if<detail::IsString<TChar*>::value, bool>::type
|
||||||
|
containsKey(TChar* key) const {
|
||||||
|
return getMember(detail::adaptString(key)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an array and adds it to the object.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/createnestedarray/
|
||||||
|
template <typename TString>
|
||||||
|
FORCE_INLINE JsonArray createNestedArray(const TString& key) const;
|
||||||
|
|
||||||
|
// Creates an array and adds it to the object.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/createnestedarray/
|
||||||
|
template <typename TChar>
|
||||||
|
FORCE_INLINE JsonArray createNestedArray(TChar* key) const;
|
||||||
|
|
||||||
|
// Creates an object and adds it to the object.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/createnestedobject/
|
||||||
|
template <typename TString>
|
||||||
|
JsonObject createNestedObject(const TString& key) const {
|
||||||
|
return operator[](key).template to<JsonObject>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an object and adds it to the object.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/createnestedobject/
|
||||||
|
template <typename TChar>
|
||||||
|
JsonObject createNestedObject(TChar* key) const {
|
||||||
|
return operator[](key).template to<JsonObject>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
detail::MemoryPool* getPool() const {
|
||||||
|
return pool_;
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::VariantData* getData() const {
|
||||||
|
return detail::collectionToVariant(data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::VariantData* getOrCreateData() const {
|
||||||
|
return detail::collectionToVariant(data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TAdaptedString>
|
||||||
|
inline detail::VariantData* getMember(TAdaptedString key) const {
|
||||||
|
if (!data_)
|
||||||
|
return 0;
|
||||||
|
return data_->getMember(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TAdaptedString>
|
||||||
|
void removeMember(TAdaptedString key) const {
|
||||||
|
if (!data_)
|
||||||
|
return;
|
||||||
|
data_->removeMember(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::CollectionData* data_;
|
||||||
|
detail::MemoryPool* pool_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct Converter<JsonObject> : private detail::VariantAttorney {
|
||||||
|
static void toJson(JsonVariantConst src, JsonVariant dst) {
|
||||||
|
variantCopyFrom(getData(dst), getData(src), getPool(dst));
|
||||||
|
}
|
||||||
|
|
||||||
|
static JsonObject fromJson(JsonVariant src) {
|
||||||
|
auto data = getData(src);
|
||||||
|
auto pool = getPool(src);
|
||||||
|
return JsonObject(pool, data != 0 ? data->asObject() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static detail::InvalidConversion<JsonVariantConst, JsonObject> fromJson(
|
||||||
|
JsonVariantConst);
|
||||||
|
|
||||||
|
static bool checkJson(JsonVariantConst) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool checkJson(JsonVariant src) {
|
||||||
|
auto data = getData(src);
|
||||||
|
return data && data->isObject();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,156 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Object/JsonObjectIterator.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantOperators.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
// A read-only reference to an object in a JsonDocument.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobjectconst/
|
||||||
|
class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
|
||||||
|
friend class JsonObject;
|
||||||
|
friend class detail::VariantAttorney;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef JsonObjectConstIterator iterator;
|
||||||
|
|
||||||
|
// Creates an unbound reference.
|
||||||
|
JsonObjectConst() : data_(0) {}
|
||||||
|
|
||||||
|
// INTERNAL USE ONLY
|
||||||
|
JsonObjectConst(const detail::CollectionData* data) : data_(data) {}
|
||||||
|
|
||||||
|
operator JsonVariantConst() const {
|
||||||
|
return JsonVariantConst(collectionToVariant(data_));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the reference is unbound.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobjectconst/isnull/
|
||||||
|
FORCE_INLINE bool isNull() const {
|
||||||
|
return data_ == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the reference is bound.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobjectconst/isnull/
|
||||||
|
FORCE_INLINE operator bool() const {
|
||||||
|
return data_ != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the number of bytes occupied by the object.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobjectconst/memoryusage/
|
||||||
|
FORCE_INLINE size_t memoryUsage() const {
|
||||||
|
return data_ ? data_->memoryUsage() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the depth (nesting level) of the object.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobjectconst/nesting/
|
||||||
|
FORCE_INLINE size_t nesting() const {
|
||||||
|
return variantNesting(collectionToVariant(data_));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the number of members in the object.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobjectconst/size/
|
||||||
|
FORCE_INLINE size_t size() const {
|
||||||
|
return data_ ? data_->size() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns an iterator to the first key-value pair of the object.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobjectconst/begin/
|
||||||
|
FORCE_INLINE iterator begin() const {
|
||||||
|
if (!data_)
|
||||||
|
return iterator();
|
||||||
|
return iterator(data_->head());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns an iterator following the last key-value pair of the object.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobjectconst/end/
|
||||||
|
FORCE_INLINE iterator end() const {
|
||||||
|
return iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the object contains the specified key.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobjectconst/containskey/
|
||||||
|
template <typename TString>
|
||||||
|
FORCE_INLINE bool containsKey(const TString& key) const {
|
||||||
|
return getMember(detail::adaptString(key)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the object contains the specified key.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobjectconst/containskey/
|
||||||
|
template <typename TChar>
|
||||||
|
FORCE_INLINE bool containsKey(TChar* key) const {
|
||||||
|
return getMember(detail::adaptString(key)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the member with specified key.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobjectconst/subscript/
|
||||||
|
template <typename TString>
|
||||||
|
FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value,
|
||||||
|
JsonVariantConst>::type
|
||||||
|
operator[](const TString& key) const {
|
||||||
|
return JsonVariantConst(getMember(detail::adaptString(key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the member with specified key.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobjectconst/subscript/
|
||||||
|
template <typename TChar>
|
||||||
|
FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value,
|
||||||
|
JsonVariantConst>::type
|
||||||
|
operator[](TChar* key) const {
|
||||||
|
return JsonVariantConst(getMember(detail::adaptString(key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compares objects.
|
||||||
|
FORCE_INLINE bool operator==(JsonObjectConst rhs) const {
|
||||||
|
if (data_ == rhs.data_)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!data_ || !rhs.data_)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
size_t count = 0;
|
||||||
|
for (iterator it = begin(); it != end(); ++it) {
|
||||||
|
if (it->value() != rhs[it->key()])
|
||||||
|
return false;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count == rhs.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const detail::VariantData* getData() const {
|
||||||
|
return collectionToVariant(data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TAdaptedString>
|
||||||
|
const detail::VariantData* getMember(TAdaptedString key) const {
|
||||||
|
if (!data_)
|
||||||
|
return 0;
|
||||||
|
return data_->getMember(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
const detail::CollectionData* data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct Converter<JsonObjectConst> : private detail::VariantAttorney {
|
||||||
|
static void toJson(JsonVariantConst src, JsonVariant dst) {
|
||||||
|
variantCopyFrom(getData(dst), getData(src), getPool(dst));
|
||||||
|
}
|
||||||
|
|
||||||
|
static JsonObjectConst fromJson(JsonVariantConst src) {
|
||||||
|
auto data = getData(src);
|
||||||
|
return data != 0 ? data->asObject() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool checkJson(JsonVariantConst src) {
|
||||||
|
auto data = getData(src);
|
||||||
|
return data && data->isObject();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,85 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Array/JsonArray.hpp>
|
||||||
|
#include <ArduinoJson/Object/JsonObject.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
template <typename TString>
|
||||||
|
inline JsonArray JsonObject::createNestedArray(const TString& key) const {
|
||||||
|
return operator[](key).template to<JsonArray>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TChar>
|
||||||
|
inline JsonArray JsonObject::createNestedArray(TChar* key) const {
|
||||||
|
return operator[](key).template to<JsonArray>();
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename TDerived>
|
||||||
|
template <typename TString>
|
||||||
|
inline JsonArray VariantRefBase<TDerived>::createNestedArray(
|
||||||
|
const TString& key) const {
|
||||||
|
return operator[](key).template to<JsonArray>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TDerived>
|
||||||
|
template <typename TChar>
|
||||||
|
inline JsonArray VariantRefBase<TDerived>::createNestedArray(TChar* key) const {
|
||||||
|
return operator[](key).template to<JsonArray>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TDerived>
|
||||||
|
template <typename TString>
|
||||||
|
inline JsonObject VariantRefBase<TDerived>::createNestedObject(
|
||||||
|
const TString& key) const {
|
||||||
|
return operator[](key).template to<JsonObject>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TDerived>
|
||||||
|
template <typename TChar>
|
||||||
|
inline JsonObject VariantRefBase<TDerived>::createNestedObject(
|
||||||
|
TChar* key) const {
|
||||||
|
return operator[](key).template to<JsonObject>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TDerived>
|
||||||
|
template <typename TString>
|
||||||
|
inline typename enable_if<IsString<TString>::value, bool>::type
|
||||||
|
VariantRefBase<TDerived>::containsKey(const TString& key) const {
|
||||||
|
return variantGetMember(VariantAttorney::getData(derived()),
|
||||||
|
adaptString(key)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TDerived>
|
||||||
|
template <typename TChar>
|
||||||
|
inline typename enable_if<IsString<TChar*>::value, bool>::type
|
||||||
|
VariantRefBase<TDerived>::containsKey(TChar* key) const {
|
||||||
|
return variantGetMember(VariantAttorney::getData(derived()),
|
||||||
|
adaptString(key)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TDerived>
|
||||||
|
template <typename TString>
|
||||||
|
inline typename enable_if<IsString<TString*>::value,
|
||||||
|
MemberProxy<TDerived, TString*>>::type
|
||||||
|
VariantRefBase<TDerived>::operator[](TString* key) const {
|
||||||
|
return MemberProxy<TDerived, TString*>(derived(), key);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TDerived>
|
||||||
|
template <typename TString>
|
||||||
|
inline typename enable_if<IsString<TString>::value,
|
||||||
|
MemberProxy<TDerived, TString>>::type
|
||||||
|
VariantRefBase<TDerived>::operator[](const TString& key) const {
|
||||||
|
return MemberProxy<TDerived, TString>(derived(), key);
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,123 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Object/JsonPair.hpp>
|
||||||
|
#include <ArduinoJson/Variant/SlotFunctions.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
class JsonPairPtr {
|
||||||
|
public:
|
||||||
|
JsonPairPtr(detail::MemoryPool* pool, detail::VariantSlot* slot)
|
||||||
|
: pair_(pool, slot) {}
|
||||||
|
|
||||||
|
const JsonPair* operator->() const {
|
||||||
|
return &pair_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const JsonPair& operator*() const {
|
||||||
|
return pair_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
JsonPair pair_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class JsonObjectIterator {
|
||||||
|
friend class JsonObject;
|
||||||
|
|
||||||
|
public:
|
||||||
|
JsonObjectIterator() : slot_(0) {}
|
||||||
|
|
||||||
|
explicit JsonObjectIterator(detail::MemoryPool* pool,
|
||||||
|
detail::VariantSlot* slot)
|
||||||
|
: pool_(pool), slot_(slot) {}
|
||||||
|
|
||||||
|
JsonPair operator*() const {
|
||||||
|
return JsonPair(pool_, slot_);
|
||||||
|
}
|
||||||
|
JsonPairPtr operator->() {
|
||||||
|
return JsonPairPtr(pool_, slot_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const JsonObjectIterator& other) const {
|
||||||
|
return slot_ == other.slot_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const JsonObjectIterator& other) const {
|
||||||
|
return slot_ != other.slot_;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObjectIterator& operator++() {
|
||||||
|
slot_ = slot_->next();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObjectIterator& operator+=(size_t distance) {
|
||||||
|
slot_ = slot_->next(distance);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
detail::MemoryPool* pool_;
|
||||||
|
detail::VariantSlot* slot_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class JsonPairConstPtr {
|
||||||
|
public:
|
||||||
|
JsonPairConstPtr(const detail::VariantSlot* slot) : pair_(slot) {}
|
||||||
|
|
||||||
|
const JsonPairConst* operator->() const {
|
||||||
|
return &pair_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const JsonPairConst& operator*() const {
|
||||||
|
return pair_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
JsonPairConst pair_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class JsonObjectConstIterator {
|
||||||
|
friend class JsonObject;
|
||||||
|
|
||||||
|
public:
|
||||||
|
JsonObjectConstIterator() : slot_(0) {}
|
||||||
|
|
||||||
|
explicit JsonObjectConstIterator(const detail::VariantSlot* slot)
|
||||||
|
: slot_(slot) {}
|
||||||
|
|
||||||
|
JsonPairConst operator*() const {
|
||||||
|
return JsonPairConst(slot_);
|
||||||
|
}
|
||||||
|
JsonPairConstPtr operator->() {
|
||||||
|
return JsonPairConstPtr(slot_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const JsonObjectConstIterator& other) const {
|
||||||
|
return slot_ == other.slot_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const JsonObjectConstIterator& other) const {
|
||||||
|
return slot_ != other.slot_;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObjectConstIterator& operator++() {
|
||||||
|
slot_ = slot_->next();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObjectConstIterator& operator+=(size_t distance) {
|
||||||
|
slot_ = slot_->next(distance);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const detail::VariantSlot* slot_;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,68 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Strings/JsonString.hpp>
|
||||||
|
#include <ArduinoJson/Variant/JsonVariant.hpp>
|
||||||
|
#include <ArduinoJson/Variant/JsonVariantConst.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
// A key-value pair.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/begin_end/
|
||||||
|
class JsonPair {
|
||||||
|
public:
|
||||||
|
// INTERNAL USE ONLY
|
||||||
|
JsonPair(detail::MemoryPool* pool, detail::VariantSlot* slot) {
|
||||||
|
if (slot) {
|
||||||
|
key_ = JsonString(slot->key(), slot->ownsKey() ? JsonString::Copied
|
||||||
|
: JsonString::Linked);
|
||||||
|
value_ = JsonVariant(pool, slot->data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the key.
|
||||||
|
JsonString key() const {
|
||||||
|
return key_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the value.
|
||||||
|
JsonVariant value() const {
|
||||||
|
return value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
JsonString key_;
|
||||||
|
JsonVariant value_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A read-only key-value pair.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobjectconst/begin_end/
|
||||||
|
class JsonPairConst {
|
||||||
|
public:
|
||||||
|
JsonPairConst(const detail::VariantSlot* slot) {
|
||||||
|
if (slot) {
|
||||||
|
key_ = JsonString(slot->key(), slot->ownsKey() ? JsonString::Copied
|
||||||
|
: JsonString::Linked);
|
||||||
|
value_ = JsonVariantConst(slot->data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the key.
|
||||||
|
JsonString key() const {
|
||||||
|
return key_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the value.
|
||||||
|
JsonVariantConst value() const {
|
||||||
|
return value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
JsonString key_;
|
||||||
|
JsonVariantConst value_;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
@ -0,0 +1,64 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Variant/VariantRefBase.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
// A proxy class to get or set a member of an object.
|
||||||
|
// https://arduinojson.org/v6/api/jsonobject/subscript/
|
||||||
|
template <typename TUpstream, typename TStringRef>
|
||||||
|
class MemberProxy
|
||||||
|
: public VariantRefBase<MemberProxy<TUpstream, TStringRef>>,
|
||||||
|
public VariantOperators<MemberProxy<TUpstream, TStringRef>> {
|
||||||
|
friend class VariantAttorney;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FORCE_INLINE MemberProxy(TUpstream upstream, TStringRef key)
|
||||||
|
: upstream_(upstream), key_(key) {}
|
||||||
|
|
||||||
|
MemberProxy(const MemberProxy& src)
|
||||||
|
: upstream_(src.upstream_), key_(src.key_) {}
|
||||||
|
|
||||||
|
FORCE_INLINE MemberProxy& operator=(const MemberProxy& src) {
|
||||||
|
this->set(src);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
FORCE_INLINE MemberProxy& operator=(const T& src) {
|
||||||
|
this->set(src);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
FORCE_INLINE MemberProxy& operator=(T* src) {
|
||||||
|
this->set(src);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FORCE_INLINE MemoryPool* getPool() const {
|
||||||
|
return VariantAttorney::getPool(upstream_);
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE VariantData* getData() const {
|
||||||
|
return variantGetMember(VariantAttorney::getData(upstream_),
|
||||||
|
adaptString(key_));
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE VariantData* getOrCreateData() const {
|
||||||
|
return variantGetOrAddMember(VariantAttorney::getOrCreateData(upstream_),
|
||||||
|
adaptString(key_),
|
||||||
|
VariantAttorney::getPool(upstream_));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TUpstream upstream_;
|
||||||
|
TStringRef key_;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,30 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h> // for size_t
|
||||||
|
|
||||||
|
#include <ArduinoJson/Configuration.hpp>
|
||||||
|
#include "math.hpp"
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename T, typename F>
|
||||||
|
struct alias_cast_t {
|
||||||
|
union {
|
||||||
|
F raw;
|
||||||
|
T data;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename F>
|
||||||
|
T alias_cast(F raw_data) {
|
||||||
|
alias_cast_t<T, F> ac;
|
||||||
|
ac.raw = raw_data;
|
||||||
|
return ac.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,14 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Configuration.hpp>
|
||||||
|
|
||||||
|
#if ARDUINOJSON_DEBUG
|
||||||
|
# include <assert.h>
|
||||||
|
# define ARDUINOJSON_ASSERT(X) assert(X)
|
||||||
|
#else
|
||||||
|
# define ARDUINOJSON_ASSERT(X) ((void)0)
|
||||||
|
#endif
|
@ -0,0 +1,32 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef _MSC_VER // Visual Studio
|
||||||
|
|
||||||
|
# define FORCE_INLINE // __forceinline causes C4714 when returning std::string
|
||||||
|
# define NO_INLINE __declspec(noinline)
|
||||||
|
|
||||||
|
#elif defined(__GNUC__) // GCC or Clang
|
||||||
|
|
||||||
|
# define FORCE_INLINE __attribute__((always_inline))
|
||||||
|
# define NO_INLINE __attribute__((noinline))
|
||||||
|
|
||||||
|
#else // Other compilers
|
||||||
|
|
||||||
|
# define FORCE_INLINE
|
||||||
|
# define NO_INLINE
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__has_attribute)
|
||||||
|
# if __has_attribute(no_sanitize)
|
||||||
|
# define ARDUINOJSON_NO_SANITIZE(check) __attribute__((no_sanitize(check)))
|
||||||
|
# else
|
||||||
|
# define ARDUINOJSON_NO_SANITIZE(check)
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define ARDUINOJSON_NO_SANITIZE(check)
|
||||||
|
#endif
|
@ -0,0 +1,21 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
#ifndef isdigit
|
||||||
|
inline bool isdigit(char c) {
|
||||||
|
return '0' <= c && c <= '9';
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline bool issign(char c) {
|
||||||
|
return '-' == c || c == '+';
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,31 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h> // int8_t, int16_t
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <int Bits>
|
||||||
|
struct int_t;
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct int_t<8> {
|
||||||
|
typedef int8_t type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct int_t<16> {
|
||||||
|
typedef int16_t type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct int_t<32> {
|
||||||
|
typedef int32_t type;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,45 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "type_traits.hpp"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning(push)
|
||||||
|
# pragma warning(disable : 4310)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
// Differs from standard because we can't use the symbols "min" and "max"
|
||||||
|
template <typename T, typename Enable = void>
|
||||||
|
struct numeric_limits;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct numeric_limits<T, typename enable_if<is_unsigned<T>::value>::type> {
|
||||||
|
static T lowest() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static T highest() {
|
||||||
|
return T(-1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct numeric_limits<
|
||||||
|
T, typename enable_if<is_integral<T>::value && is_signed<T>::value>::type> {
|
||||||
|
static T lowest() {
|
||||||
|
return T(T(1) << (sizeof(T) * 8 - 1));
|
||||||
|
}
|
||||||
|
static T highest() {
|
||||||
|
return T(~lowest());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning(pop)
|
||||||
|
#endif
|
@ -0,0 +1,27 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
// Some libraries #define isnan() and isinf() so we need to check before
|
||||||
|
// using this name
|
||||||
|
|
||||||
|
#ifndef isnan
|
||||||
|
template <typename T>
|
||||||
|
bool isnan(T x) {
|
||||||
|
return x != x;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef isinf
|
||||||
|
template <typename T>
|
||||||
|
bool isinf(T x) {
|
||||||
|
return x != 0.0 && x * 2 == x;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,27 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
#include <stddef.h> // for size_t
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
// A meta-function that returns the highest value
|
||||||
|
template <size_t X, size_t Y, bool MaxIsX = (X > Y)>
|
||||||
|
struct Max {};
|
||||||
|
|
||||||
|
template <size_t X, size_t Y>
|
||||||
|
struct Max<X, Y, true> {
|
||||||
|
static const size_t value = X;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <size_t X, size_t Y>
|
||||||
|
struct Max<X, Y, false> {
|
||||||
|
static const size_t value = Y;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,144 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef ARDUINO
|
||||||
|
# include <Arduino.h>
|
||||||
|
#else
|
||||||
|
// Allow using PROGMEM outside of Arduino (issue #1903)
|
||||||
|
class __FlashStringHelper;
|
||||||
|
# include <avr/pgmspace.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <ArduinoJson/Configuration.hpp>
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
// Wraps a const char* so that the our functions are picked only if the
|
||||||
|
// originals are missing
|
||||||
|
struct pgm_p {
|
||||||
|
pgm_p(const void* p) : address(reinterpret_cast<const char*>(p)) {}
|
||||||
|
const char* address;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
#ifndef strlen_P
|
||||||
|
inline size_t strlen_P(ArduinoJson::detail::pgm_p s) {
|
||||||
|
const char* p = s.address;
|
||||||
|
ARDUINOJSON_ASSERT(p != NULL);
|
||||||
|
while (pgm_read_byte(p))
|
||||||
|
p++;
|
||||||
|
return size_t(p - s.address);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef strncmp_P
|
||||||
|
inline int strncmp_P(const char* a, ArduinoJson::detail::pgm_p b, size_t n) {
|
||||||
|
const char* s1 = a;
|
||||||
|
const char* s2 = b.address;
|
||||||
|
ARDUINOJSON_ASSERT(s1 != NULL);
|
||||||
|
ARDUINOJSON_ASSERT(s2 != NULL);
|
||||||
|
while (n-- > 0) {
|
||||||
|
char c1 = *s1++;
|
||||||
|
char c2 = static_cast<char>(pgm_read_byte(s2++));
|
||||||
|
if (c1 < c2)
|
||||||
|
return -1;
|
||||||
|
if (c1 > c2)
|
||||||
|
return 1;
|
||||||
|
if (c1 == 0 /* and c2 as well */)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef strcmp_P
|
||||||
|
inline int strcmp_P(const char* a, ArduinoJson::detail::pgm_p b) {
|
||||||
|
const char* s1 = a;
|
||||||
|
const char* s2 = b.address;
|
||||||
|
ARDUINOJSON_ASSERT(s1 != NULL);
|
||||||
|
ARDUINOJSON_ASSERT(s2 != NULL);
|
||||||
|
for (;;) {
|
||||||
|
char c1 = *s1++;
|
||||||
|
char c2 = static_cast<char>(pgm_read_byte(s2++));
|
||||||
|
if (c1 < c2)
|
||||||
|
return -1;
|
||||||
|
if (c1 > c2)
|
||||||
|
return 1;
|
||||||
|
if (c1 == 0 /* and c2 as well */)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef memcmp_P
|
||||||
|
inline int memcmp_P(const void* a, ArduinoJson::detail::pgm_p b, size_t n) {
|
||||||
|
const uint8_t* p1 = reinterpret_cast<const uint8_t*>(a);
|
||||||
|
const char* p2 = b.address;
|
||||||
|
ARDUINOJSON_ASSERT(p1 != NULL);
|
||||||
|
ARDUINOJSON_ASSERT(p2 != NULL);
|
||||||
|
while (n-- > 0) {
|
||||||
|
uint8_t v1 = *p1++;
|
||||||
|
uint8_t v2 = pgm_read_byte(p2++);
|
||||||
|
if (v1 != v2)
|
||||||
|
return v1 - v2;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef memcpy_P
|
||||||
|
inline void* memcpy_P(void* dst, ArduinoJson::detail::pgm_p src, size_t n) {
|
||||||
|
uint8_t* d = reinterpret_cast<uint8_t*>(dst);
|
||||||
|
const char* s = src.address;
|
||||||
|
ARDUINOJSON_ASSERT(d != NULL);
|
||||||
|
ARDUINOJSON_ASSERT(s != NULL);
|
||||||
|
while (n-- > 0) {
|
||||||
|
*d++ = pgm_read_byte(s++);
|
||||||
|
}
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef pgm_read_dword
|
||||||
|
inline uint32_t pgm_read_dword(ArduinoJson::detail::pgm_p p) {
|
||||||
|
uint32_t result;
|
||||||
|
memcpy_P(&result, p.address, 4);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef pgm_read_float
|
||||||
|
inline float pgm_read_float(ArduinoJson::detail::pgm_p p) {
|
||||||
|
float result;
|
||||||
|
memcpy_P(&result, p.address, sizeof(float));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef pgm_read_double
|
||||||
|
# if defined(__SIZEOF_DOUBLE__) && defined(__SIZEOF_FLOAT__) && \
|
||||||
|
__SIZEOF_DOUBLE__ == __SIZEOF_FLOAT__
|
||||||
|
inline double pgm_read_double(ArduinoJson::detail::pgm_p p) {
|
||||||
|
return pgm_read_float(p.address);
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
inline double pgm_read_double(ArduinoJson::detail::pgm_p p) {
|
||||||
|
double result;
|
||||||
|
memcpy_P(&result, p.address, sizeof(double));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef pgm_read_ptr
|
||||||
|
inline void* pgm_read_ptr(ArduinoJson::detail::pgm_p p) {
|
||||||
|
void* result;
|
||||||
|
memcpy_P(&result, p.address, sizeof(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,67 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
#if ARDUINOJSON_ENABLE_PROGMEM
|
||||||
|
# include <ArduinoJson/Polyfills/pgmspace.hpp>
|
||||||
|
# include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
#if ARDUINOJSON_ENABLE_PROGMEM
|
||||||
|
|
||||||
|
# ifndef ARDUINOJSON_DEFINE_PROGMEM_ARRAY
|
||||||
|
# define ARDUINOJSON_DEFINE_PROGMEM_ARRAY(type, name, ...) \
|
||||||
|
static type const name[] PROGMEM = __VA_ARGS__;
|
||||||
|
# endif
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline const T* pgm_read(const T* const* p) {
|
||||||
|
return reinterpret_cast<const T*>(pgm_read_ptr(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t pgm_read(const uint32_t* p) {
|
||||||
|
return pgm_read_dword(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double pgm_read(const double* p) {
|
||||||
|
return pgm_read_double(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float pgm_read(const float* p) {
|
||||||
|
return pgm_read_float(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
# ifndef ARDUINOJSON_DEFINE_PROGMEM_ARRAY
|
||||||
|
# define ARDUINOJSON_DEFINE_PROGMEM_ARRAY(type, name, ...) \
|
||||||
|
static type const name[] = __VA_ARGS__;
|
||||||
|
# endif
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T pgm_read(const T* p) {
|
||||||
|
return *p;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class pgm_ptr {
|
||||||
|
public:
|
||||||
|
explicit pgm_ptr(const T* ptr) : ptr_(ptr) {}
|
||||||
|
|
||||||
|
T operator[](intptr_t index) const {
|
||||||
|
return pgm_read(ptr_ + index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const T* ptr_;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,29 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#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_BIN2ALPHA_0000() A
|
||||||
|
#define ARDUINOJSON_BIN2ALPHA_0001() B
|
||||||
|
#define ARDUINOJSON_BIN2ALPHA_0010() C
|
||||||
|
#define ARDUINOJSON_BIN2ALPHA_0011() D
|
||||||
|
#define ARDUINOJSON_BIN2ALPHA_0100() E
|
||||||
|
#define ARDUINOJSON_BIN2ALPHA_0101() F
|
||||||
|
#define ARDUINOJSON_BIN2ALPHA_0110() G
|
||||||
|
#define ARDUINOJSON_BIN2ALPHA_0111() H
|
||||||
|
#define ARDUINOJSON_BIN2ALPHA_1000() I
|
||||||
|
#define ARDUINOJSON_BIN2ALPHA_1001() J
|
||||||
|
#define ARDUINOJSON_BIN2ALPHA_1010() K
|
||||||
|
#define ARDUINOJSON_BIN2ALPHA_1011() L
|
||||||
|
#define ARDUINOJSON_BIN2ALPHA_1100() M
|
||||||
|
#define ARDUINOJSON_BIN2ALPHA_1101() N
|
||||||
|
#define ARDUINOJSON_BIN2ALPHA_1110() O
|
||||||
|
#define ARDUINOJSON_BIN2ALPHA_1111() P
|
||||||
|
#define ARDUINOJSON_BIN2ALPHA_(A, B, C, D) ARDUINOJSON_BIN2ALPHA_##A##B##C##D()
|
||||||
|
#define ARDUINOJSON_BIN2ALPHA(A, B, C, D) ARDUINOJSON_BIN2ALPHA_(A, B, C, D)
|
@ -0,0 +1,25 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "type_traits/conditional.hpp"
|
||||||
|
#include "type_traits/enable_if.hpp"
|
||||||
|
#include "type_traits/integral_constant.hpp"
|
||||||
|
#include "type_traits/is_array.hpp"
|
||||||
|
#include "type_traits/is_base_of.hpp"
|
||||||
|
#include "type_traits/is_class.hpp"
|
||||||
|
#include "type_traits/is_const.hpp"
|
||||||
|
#include "type_traits/is_convertible.hpp"
|
||||||
|
#include "type_traits/is_enum.hpp"
|
||||||
|
#include "type_traits/is_floating_point.hpp"
|
||||||
|
#include "type_traits/is_integral.hpp"
|
||||||
|
#include "type_traits/is_pointer.hpp"
|
||||||
|
#include "type_traits/is_same.hpp"
|
||||||
|
#include "type_traits/is_signed.hpp"
|
||||||
|
#include "type_traits/is_unsigned.hpp"
|
||||||
|
#include "type_traits/make_unsigned.hpp"
|
||||||
|
#include "type_traits/make_void.hpp"
|
||||||
|
#include "type_traits/remove_const.hpp"
|
||||||
|
#include "type_traits/remove_reference.hpp"
|
@ -0,0 +1,21 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <bool Condition, class TrueType, class FalseType>
|
||||||
|
struct conditional {
|
||||||
|
typedef TrueType type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class TrueType, class FalseType>
|
||||||
|
struct conditional<false, TrueType, FalseType> {
|
||||||
|
typedef FalseType type;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,14 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T&& declval();
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,20 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
// A meta-function that return the type T if Condition is true.
|
||||||
|
template <bool Condition, typename T = void>
|
||||||
|
struct enable_if {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct enable_if<true, T> {
|
||||||
|
typedef T type;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,19 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename T, T v>
|
||||||
|
struct integral_constant {
|
||||||
|
static const T value = v;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef integral_constant<bool, true> true_type;
|
||||||
|
typedef integral_constant<bool, false> false_type;
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,22 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
#include <stddef.h> // size_t
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_array : false_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_array<T[]> : true_type {};
|
||||||
|
|
||||||
|
template <typename T, size_t N>
|
||||||
|
struct is_array<T[N]> : true_type {};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,27 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
#include "remove_reference.hpp"
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
// A meta-function that returns true if Derived inherits from TBase is an
|
||||||
|
// integral type.
|
||||||
|
template <typename TBase, typename TDerived>
|
||||||
|
class is_base_of {
|
||||||
|
protected: // <- to avoid GCC's "all member functions in class are private"
|
||||||
|
static int probe(const TBase*);
|
||||||
|
static char probe(...);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const bool value =
|
||||||
|
sizeof(probe(reinterpret_cast<typename remove_reference<TDerived>::type*>(
|
||||||
|
0))) == sizeof(int);
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,23 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "declval.hpp"
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_class {
|
||||||
|
protected: // <- to avoid GCC's "all member functions in class are private"
|
||||||
|
template <typename U>
|
||||||
|
static int probe(void (U::*)(void));
|
||||||
|
template <typename>
|
||||||
|
static char probe(...);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const bool value = sizeof(probe<T>(0)) == sizeof(int);
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -0,0 +1,18 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2023, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "integral_constant.hpp"
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
// A meta-function that return the type T without the const modifier
|
||||||
|
template <typename T>
|
||||||
|
struct is_const : false_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_const<const T> : true_type {};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user