V2.1
This commit is contained in:
@ -1,9 +0,0 @@
|
|||||||
name=Adafruit BusIO
|
|
||||||
version=1.15.0
|
|
||||||
author=Adafruit
|
|
||||||
maintainer=Adafruit <info@adafruit.com>
|
|
||||||
sentence=This is a library for abstracting away I2C and SPI interfacing
|
|
||||||
paragraph=This is a library for abstracting away I2C and SPI interfacing
|
|
||||||
category=Signal Input/Output
|
|
||||||
url=https://github.com/adafruit/Adafruit_BusIO
|
|
||||||
architectures=*
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
name=Adafruit MLX90614 Library
|
|
||||||
version=2.1.5
|
|
||||||
author=Adafruit
|
|
||||||
maintainer=Adafruit <info@adafruit.com>
|
|
||||||
sentence=Arduino library for the MLX90614 sensors in the Adafruit shop
|
|
||||||
paragraph=Arduino library for the MLX90614 sensors in the Adafruit shop
|
|
||||||
category=Sensors
|
|
||||||
url=https://github.com/adafruit/Adafruit-MLX90614-Library
|
|
||||||
architectures=*
|
|
||||||
depends=Adafruit BusIO
|
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
# See: https://github.com/codespell-project/codespell#using-a-config-file
|
||||||
|
[codespell]
|
||||||
|
# In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here:
|
||||||
|
ignore-words-list = ,
|
||||||
|
check-filenames =
|
||||||
|
check-hidden =
|
||||||
|
skip = ./.git,./src/utility/URLParser
|
||||||
12
.pio/libdeps/esp32-s3-devkitc-1/ArduinoHttpClient/.github/dependabot.yml
vendored
Normal file
12
.pio/libdeps/esp32-s3-devkitc-1/ArduinoHttpClient/.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# See: https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#about-the-dependabotyml-file
|
||||||
|
version: 2
|
||||||
|
|
||||||
|
updates:
|
||||||
|
# Configure check for outdated GitHub Actions actions in workflows.
|
||||||
|
# See: https://docs.github.com/en/github/administering-a-repository/keeping-your-actions-up-to-date-with-dependabot
|
||||||
|
- package-ecosystem: github-actions
|
||||||
|
directory: / # Check the repository's workflows under /.github/workflows/
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
labels:
|
||||||
|
- "topic: infrastructure"
|
||||||
28
.pio/libdeps/esp32-s3-devkitc-1/ArduinoHttpClient/.github/workflows/check-arduino.yml
vendored
Normal file
28
.pio/libdeps/esp32-s3-devkitc-1/ArduinoHttpClient/.github/workflows/check-arduino.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
name: Check Arduino
|
||||||
|
|
||||||
|
# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
schedule:
|
||||||
|
# Run every Tuesday at 8 AM UTC to catch breakage caused by new rules added to Arduino Lint.
|
||||||
|
- cron: "0 8 * * TUE"
|
||||||
|
workflow_dispatch:
|
||||||
|
repository_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Arduino Lint
|
||||||
|
uses: arduino/arduino-lint-action@v1
|
||||||
|
with:
|
||||||
|
compliance: specification
|
||||||
|
library-manager: update
|
||||||
|
# Always use this setting for official repositories. Remove for 3rd party projects.
|
||||||
|
official: true
|
||||||
|
project-type: library
|
||||||
63
.pio/libdeps/esp32-s3-devkitc-1/ArduinoHttpClient/.github/workflows/compile-examples.yml
vendored
Normal file
63
.pio/libdeps/esp32-s3-devkitc-1/ArduinoHttpClient/.github/workflows/compile-examples.yml
vendored
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
name: Compile Examples
|
||||||
|
|
||||||
|
# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/compile-examples.yml"
|
||||||
|
- "examples/**"
|
||||||
|
- "src/**"
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/compile-examples.yml"
|
||||||
|
- "examples/**"
|
||||||
|
- "src/**"
|
||||||
|
schedule:
|
||||||
|
# Run every Tuesday at 8 AM UTC to catch breakage caused by changes to external resources (libraries, platforms).
|
||||||
|
- cron: "0 8 * * TUE"
|
||||||
|
workflow_dispatch:
|
||||||
|
repository_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: ${{ matrix.board.fqbn }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
env:
|
||||||
|
SKETCHES_REPORTS_PATH: sketches-reports
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
board:
|
||||||
|
- fqbn: arduino:samd:mkr1000
|
||||||
|
platforms: |
|
||||||
|
- name: arduino:samd
|
||||||
|
artifact-name-suffix: arduino-samd-mkr1000
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Compile examples
|
||||||
|
uses: arduino/compile-sketches@v1
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
fqbn: ${{ matrix.board.fqbn }}
|
||||||
|
platforms: ${{ matrix.board.platforms }}
|
||||||
|
libraries: |
|
||||||
|
# Install the library from the local path.
|
||||||
|
- source-path: ./
|
||||||
|
- name: WiFi101
|
||||||
|
sketch-paths: |
|
||||||
|
- examples
|
||||||
|
enable-deltas-report: true
|
||||||
|
sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }}
|
||||||
|
|
||||||
|
- name: Save sketches report as workflow artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
if-no-files-found: error
|
||||||
|
path: ${{ env.SKETCHES_REPORTS_PATH }}
|
||||||
|
name: sketches-report-${{ matrix.board.artifact-name-suffix }}
|
||||||
24
.pio/libdeps/esp32-s3-devkitc-1/ArduinoHttpClient/.github/workflows/report-size-deltas.yml
vendored
Normal file
24
.pio/libdeps/esp32-s3-devkitc-1/ArduinoHttpClient/.github/workflows/report-size-deltas.yml
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
name: Report Size Deltas
|
||||||
|
|
||||||
|
# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/report-size-deltas.yml"
|
||||||
|
schedule:
|
||||||
|
# Run at the minimum interval allowed by GitHub Actions.
|
||||||
|
# Note: GitHub Actions periodically has outages which result in workflow failures.
|
||||||
|
# In this event, the workflows will start passing again once the service recovers.
|
||||||
|
- cron: "*/5 * * * *"
|
||||||
|
workflow_dispatch:
|
||||||
|
repository_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
report:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Comment size deltas reports to PRs
|
||||||
|
uses: arduino/report-size-deltas@v1
|
||||||
|
with:
|
||||||
|
# Regex matching the names of the workflow artifacts created by the "Compile Examples" workflow
|
||||||
|
sketches-reports-source: ^sketches-report-.+
|
||||||
22
.pio/libdeps/esp32-s3-devkitc-1/ArduinoHttpClient/.github/workflows/spell-check.yml
vendored
Normal file
22
.pio/libdeps/esp32-s3-devkitc-1/ArduinoHttpClient/.github/workflows/spell-check.yml
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
name: Spell Check
|
||||||
|
|
||||||
|
# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
schedule:
|
||||||
|
# Run every Tuesday at 8 AM UTC to catch new misspelling detections resulting from dictionary updates.
|
||||||
|
- cron: "0 8 * * TUE"
|
||||||
|
workflow_dispatch:
|
||||||
|
repository_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
spellcheck:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Spell check
|
||||||
|
uses: codespell-project/actions-codespell@master
|
||||||
138
.pio/libdeps/esp32-s3-devkitc-1/ArduinoHttpClient/.github/workflows/sync-labels.yml
vendored
Normal file
138
.pio/libdeps/esp32-s3-devkitc-1/ArduinoHttpClient/.github/workflows/sync-labels.yml
vendored
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/sync-labels.md
|
||||||
|
name: Sync Labels
|
||||||
|
|
||||||
|
# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/sync-labels.ya?ml"
|
||||||
|
- ".github/label-configuration-files/*.ya?ml"
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/sync-labels.ya?ml"
|
||||||
|
- ".github/label-configuration-files/*.ya?ml"
|
||||||
|
schedule:
|
||||||
|
# Run daily at 8 AM UTC to sync with changes to shared label configurations.
|
||||||
|
- cron: "0 8 * * *"
|
||||||
|
workflow_dispatch:
|
||||||
|
repository_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
CONFIGURATIONS_FOLDER: .github/label-configuration-files
|
||||||
|
CONFIGURATIONS_ARTIFACT: label-configuration-files
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Download JSON schema for labels configuration file
|
||||||
|
id: download-schema
|
||||||
|
uses: carlosperate/download-file-action@v2
|
||||||
|
with:
|
||||||
|
file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/arduino-tooling-gh-label-configuration-schema.json
|
||||||
|
location: ${{ runner.temp }}/label-configuration-schema
|
||||||
|
|
||||||
|
- name: Install JSON schema validator
|
||||||
|
run: |
|
||||||
|
sudo npm install \
|
||||||
|
--global \
|
||||||
|
ajv-cli \
|
||||||
|
ajv-formats
|
||||||
|
|
||||||
|
- name: Validate local labels configuration
|
||||||
|
run: |
|
||||||
|
# See: https://github.com/ajv-validator/ajv-cli#readme
|
||||||
|
ajv validate \
|
||||||
|
--all-errors \
|
||||||
|
-c ajv-formats \
|
||||||
|
-s "${{ steps.download-schema.outputs.file-path }}" \
|
||||||
|
-d "${{ env.CONFIGURATIONS_FOLDER }}/*.{yml,yaml}"
|
||||||
|
|
||||||
|
download:
|
||||||
|
needs: check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
filename:
|
||||||
|
# Filenames of the shared configurations to apply to the repository in addition to the local configuration.
|
||||||
|
# https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/sync-labels
|
||||||
|
- universal.yml
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Download
|
||||||
|
uses: carlosperate/download-file-action@v2
|
||||||
|
with:
|
||||||
|
file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/${{ matrix.filename }}
|
||||||
|
|
||||||
|
- name: Pass configuration files to next job via workflow artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
*.yaml
|
||||||
|
*.yml
|
||||||
|
if-no-files-found: error
|
||||||
|
name: ${{ env.CONFIGURATIONS_ARTIFACT }}
|
||||||
|
|
||||||
|
sync:
|
||||||
|
needs: download
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Set environment variables
|
||||||
|
run: |
|
||||||
|
# See: https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable
|
||||||
|
echo "MERGED_CONFIGURATION_PATH=${{ runner.temp }}/labels.yml" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Determine whether to dry run
|
||||||
|
id: dry-run
|
||||||
|
if: >
|
||||||
|
github.event_name == 'pull_request' ||
|
||||||
|
(
|
||||||
|
(
|
||||||
|
github.event_name == 'push' ||
|
||||||
|
github.event_name == 'workflow_dispatch'
|
||||||
|
) &&
|
||||||
|
github.ref != format('refs/heads/{0}', github.event.repository.default_branch)
|
||||||
|
)
|
||||||
|
run: |
|
||||||
|
# Use of this flag in the github-label-sync command will cause it to only check the validity of the
|
||||||
|
# configuration.
|
||||||
|
echo "::set-output name=flag::--dry-run"
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Download configuration files artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ env.CONFIGURATIONS_ARTIFACT }}
|
||||||
|
path: ${{ env.CONFIGURATIONS_FOLDER }}
|
||||||
|
|
||||||
|
- name: Remove unneeded artifact
|
||||||
|
uses: geekyeggo/delete-artifact@v5
|
||||||
|
with:
|
||||||
|
name: ${{ env.CONFIGURATIONS_ARTIFACT }}
|
||||||
|
|
||||||
|
- name: Merge label configuration files
|
||||||
|
run: |
|
||||||
|
# Merge all configuration files
|
||||||
|
shopt -s extglob
|
||||||
|
cat "${{ env.CONFIGURATIONS_FOLDER }}"/*.@(yml|yaml) > "${{ env.MERGED_CONFIGURATION_PATH }}"
|
||||||
|
|
||||||
|
- name: Install github-label-sync
|
||||||
|
run: sudo npm install --global github-label-sync
|
||||||
|
|
||||||
|
- name: Sync labels
|
||||||
|
env:
|
||||||
|
GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
# See: https://github.com/Financial-Times/github-label-sync
|
||||||
|
github-label-sync \
|
||||||
|
--labels "${{ env.MERGED_CONFIGURATION_PATH }}" \
|
||||||
|
${{ steps.dry-run.outputs.flag }} \
|
||||||
|
${{ github.repository }}
|
||||||
@ -3,3 +3,4 @@ examples/node_test_server/node_modules/
|
|||||||
*.DS_Store
|
*.DS_Store
|
||||||
*/.DS_Store
|
*/.DS_Store
|
||||||
examples/.DS_Store
|
examples/.DS_Store
|
||||||
|
.idea/
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
{"type": "library", "name": "ArduinoHttpClient", "version": "0.4.0", "spec": {"owner": "arduino-libraries", "id": 798, "name": "ArduinoHttpClient", "requirements": null, "uri": null}}
|
{"type": "library", "name": "ArduinoHttpClient", "version": "0.6.1", "spec": {"owner": "arduino-libraries", "id": 798, "name": "ArduinoHttpClient", "requirements": null, "uri": null}}
|
||||||
@ -9,7 +9,7 @@
|
|||||||
## ArduinoHttpClient 0.3.1 - 2017.09.25
|
## ArduinoHttpClient 0.3.1 - 2017.09.25
|
||||||
|
|
||||||
* Changed examples to support Arduino Create secret tabs
|
* Changed examples to support Arduino Create secret tabs
|
||||||
* Increase WebSocket secrect-key length to 24 characters
|
* Increase WebSocket secret-key length to 24 characters
|
||||||
|
|
||||||
## ArduinoHttpClient 0.3.0 - 2017.04.20
|
## ArduinoHttpClient 0.3.0 - 2017.04.20
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
# ArduinoHttpClient
|
# ArduinoHttpClient
|
||||||
|
|
||||||
|
[](https://github.com/arduino-libraries/ArduinoHttpClient/actions/workflows/check-arduino.yml)
|
||||||
|
[](https://github.com/arduino-libraries/ArduinoHttpClient/actions/workflows/compile-examples.yml)
|
||||||
|
[](https://github.com/arduino-libraries/ArduinoHttpClient/actions/workflows/spell-check.yml)
|
||||||
|
|
||||||
ArduinoHttpClient is a library to make it easier to interact with web servers from Arduino.
|
ArduinoHttpClient is a library to make it easier to interact with web servers from Arduino.
|
||||||
|
|
||||||
Derived from [Adrian McEwen's HttpClient library](https://github.com/amcewen/HttpClient)
|
Derived from [Adrian McEwen's HttpClient library](https://github.com/amcewen/HttpClient)
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
#include <WiFi101.h>
|
#include <WiFi101.h>
|
||||||
#include "arduino_secrets.h"
|
#include "arduino_secrets.h"
|
||||||
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
||||||
/////// Wifi Settings ///////
|
/////// WiFi Settings ///////
|
||||||
char ssid[] = SECRET_SSID;
|
char ssid[] = SECRET_SSID;
|
||||||
char pass[] = SECRET_PASS;
|
char pass[] = SECRET_PASS;
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
#include "arduino_secrets.h"
|
#include "arduino_secrets.h"
|
||||||
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
||||||
/////// Wifi Settings ///////
|
/////// WiFi Settings ///////
|
||||||
char ssid[] = SECRET_SSID;
|
char ssid[] = SECRET_SSID;
|
||||||
char pass[] = SECRET_PASS;
|
char pass[] = SECRET_PASS;
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
#include "arduino_secrets.h"
|
#include "arduino_secrets.h"
|
||||||
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
||||||
/////// Wifi Settings ///////
|
/////// WiFi Settings ///////
|
||||||
char ssid[] = SECRET_SSID;
|
char ssid[] = SECRET_SSID;
|
||||||
char pass[] = SECRET_PASS;
|
char pass[] = SECRET_PASS;
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#include "arduino_secrets.h"
|
#include "arduino_secrets.h"
|
||||||
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
||||||
/////// Wifi Settings ///////
|
/////// WiFi Settings ///////
|
||||||
char ssid[] = SECRET_SSID;
|
char ssid[] = SECRET_SSID;
|
||||||
char pass[] = SECRET_PASS;
|
char pass[] = SECRET_PASS;
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
The body of the PUT request looks like this:
|
The body of the PUT request looks like this:
|
||||||
{"on": true} or {"on":false}
|
{"on": true} or {"on":false}
|
||||||
|
|
||||||
This example shows how to concatenate Strings to assemble the
|
This example shows how to concatenate Strings to assemble the
|
||||||
PUT request and the body of the request.
|
PUT request and the body of the request.
|
||||||
|
|
||||||
modified 15 Feb 2016
|
modified 15 Feb 2016
|
||||||
@ -23,16 +23,16 @@
|
|||||||
#include "arduino_secrets.h"
|
#include "arduino_secrets.h"
|
||||||
|
|
||||||
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
||||||
/////// Wifi Settings ///////
|
/////// WiFi Settings ///////
|
||||||
char ssid[] = SECRET_SSID;
|
char ssid[] = SECRET_SSID;
|
||||||
char pass[] = SECRET_PASS;
|
char pass[] = SECRET_PASS;
|
||||||
|
|
||||||
int status = WL_IDLE_STATUS; // the Wifi radio's status
|
int status = WL_IDLE_STATUS; // the WiFi radio's status
|
||||||
|
|
||||||
char hueHubIP[] = "192.168.0.3"; // IP address of the HUE bridge
|
char hueHubIP[] = "192.168.0.3"; // IP address of the HUE bridge
|
||||||
String hueUserName = "huebridgeusername"; // hue bridge username
|
String hueUserName = "huebridgeusername"; // hue bridge username
|
||||||
|
|
||||||
// make a wifi instance and a HttpClient instance:
|
// make a WiFiClient instance and a HttpClient instance:
|
||||||
WiFiClient wifi;
|
WiFiClient wifi;
|
||||||
HttpClient httpClient = HttpClient(wifi, hueHubIP);
|
HttpClient httpClient = HttpClient(wifi, hueHubIP);
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ void setup() {
|
|||||||
Serial.begin(9600);
|
Serial.begin(9600);
|
||||||
while (!Serial); // wait for serial port to connect.
|
while (!Serial); // wait for serial port to connect.
|
||||||
|
|
||||||
// attempt to connect to Wifi network:
|
// attempt to connect to WiFi network:
|
||||||
while ( status != WL_CONNECTED) {
|
while ( status != WL_CONNECTED) {
|
||||||
Serial.print("Attempting to connect to WPA SSID: ");
|
Serial.print("Attempting to connect to WPA SSID: ");
|
||||||
Serial.println(ssid);
|
Serial.println(ssid);
|
||||||
@ -95,4 +95,4 @@ void sendRequest(int light, String cmd, String value) {
|
|||||||
Serial.print("Server response: ");
|
Serial.print("Server response: ");
|
||||||
Serial.println(response);
|
Serial.println(response);
|
||||||
Serial.println();
|
Serial.println();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,29 @@
|
|||||||
|
#include "URLParser.h"
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
while(!Serial);
|
||||||
|
|
||||||
|
Serial.println("starting");
|
||||||
|
|
||||||
|
ParsedUrl url(
|
||||||
|
"https://www.google.com/search?q=arduino"
|
||||||
|
);
|
||||||
|
|
||||||
|
Serial.print("parsed URL schema: \"");
|
||||||
|
Serial.print(url.schema());
|
||||||
|
Serial.print("\"\nparsed URL host: \"");
|
||||||
|
Serial.print(url.host());
|
||||||
|
Serial.print("\"\nparsed URL path: \"");
|
||||||
|
Serial.print(url.path());
|
||||||
|
Serial.print("\"\nparsed URL query: \"");
|
||||||
|
Serial.print(url.query());
|
||||||
|
Serial.print("\"\nparsed URL userinfo: \"");
|
||||||
|
Serial.print(url.userinfo());
|
||||||
|
Serial.println("\"");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() { }
|
||||||
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
POST with headers client for ArduinoHttpClient library
|
POST with headers client for ArduinoHttpClient library
|
||||||
Connects to server once every five seconds, sends a POST request
|
Connects to server once every five seconds, sends a POST request
|
||||||
with custome headers and a request body
|
with custom headers and a request body
|
||||||
|
|
||||||
created 14 Feb 2016
|
created 14 Feb 2016
|
||||||
by Tom Igoe
|
by Tom Igoe
|
||||||
@ -18,7 +18,7 @@
|
|||||||
#include "arduino_secrets.h"
|
#include "arduino_secrets.h"
|
||||||
|
|
||||||
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
||||||
/////// Wifi Settings ///////
|
/////// WiFi Settings ///////
|
||||||
char ssid[] = SECRET_SSID;
|
char ssid[] = SECRET_SSID;
|
||||||
char pass[] = SECRET_PASS;
|
char pass[] = SECRET_PASS;
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
#include "arduino_secrets.h"
|
#include "arduino_secrets.h"
|
||||||
|
|
||||||
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
||||||
/////// Wifi Settings ///////
|
/////// WiFi Settings ///////
|
||||||
char ssid[] = SECRET_SSID;
|
char ssid[] = SECRET_SSID;
|
||||||
char pass[] = SECRET_PASS;
|
char pass[] = SECRET_PASS;
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
#include "arduino_secrets.h"
|
#include "arduino_secrets.h"
|
||||||
|
|
||||||
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
||||||
/////// Wifi Settings ///////
|
/////// WiFi Settings ///////
|
||||||
char ssid[] = SECRET_SSID;
|
char ssid[] = SECRET_SSID;
|
||||||
char pass[] = SECRET_PASS;
|
char pass[] = SECRET_PASS;
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// Released under Apache License, version 2.0
|
// Released under Apache License, version 2.0
|
||||||
//
|
//
|
||||||
// Simple example to show how to use the HttpClient library
|
// Simple example to show how to use the HttpClient library
|
||||||
// Get's the web page given at http://<kHostname><kPath> and
|
// Gets the web page given at http://<kHostname><kPath> and
|
||||||
// outputs the content to the serial port
|
// outputs the content to the serial port
|
||||||
|
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
@ -14,7 +14,7 @@
|
|||||||
#include "arduino_secrets.h"
|
#include "arduino_secrets.h"
|
||||||
|
|
||||||
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
||||||
/////// Wifi Settings ///////
|
/////// WiFi Settings ///////
|
||||||
char ssid[] = SECRET_SSID;
|
char ssid[] = SECRET_SSID;
|
||||||
char pass[] = SECRET_PASS;
|
char pass[] = SECRET_PASS;
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ void setup()
|
|||||||
; // wait for serial port to connect. Needed for native USB port only
|
; // wait for serial port to connect. Needed for native USB port only
|
||||||
}
|
}
|
||||||
|
|
||||||
// attempt to connect to Wifi network:
|
// attempt to connect to WiFi network:
|
||||||
Serial.print("Attempting to connect to WPA SSID: ");
|
Serial.print("Attempting to connect to WPA SSID: ");
|
||||||
Serial.println(ssid);
|
Serial.println(ssid);
|
||||||
while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
|
while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
|
||||||
@ -129,5 +129,3 @@ void loop()
|
|||||||
// And just stop, now that we've tried a download
|
// And just stop, now that we've tried a download
|
||||||
while(1);
|
while(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
#include "arduino_secrets.h"
|
#include "arduino_secrets.h"
|
||||||
|
|
||||||
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
||||||
/////// Wifi Settings ///////
|
/////// WiFi Settings ///////
|
||||||
char ssid[] = SECRET_SSID;
|
char ssid[] = SECRET_SSID;
|
||||||
char pass[] = SECRET_PASS;
|
char pass[] = SECRET_PASS;
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
#include "arduino_secrets.h"
|
#include "arduino_secrets.h"
|
||||||
|
|
||||||
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
||||||
/////// Wifi Settings ///////
|
/////// WiFi Settings ///////
|
||||||
char ssid[] = SECRET_SSID;
|
char ssid[] = SECRET_SSID;
|
||||||
char pass[] = SECRET_PASS;
|
char pass[] = SECRET_PASS;
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
#include "arduino_secrets.h"
|
#include "arduino_secrets.h"
|
||||||
|
|
||||||
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
|
||||||
/////// Wifi Settings ///////
|
/////// WiFi Settings ///////
|
||||||
char ssid[] = SECRET_SSID;
|
char ssid[] = SECRET_SSID;
|
||||||
char pass[] = SECRET_PASS;
|
char pass[] = SECRET_PASS;
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#######################################
|
#######################################
|
||||||
# Syntax Coloring Map For HttpClient
|
# Syntax Coloring Map For ArduinoHttpClient
|
||||||
#######################################
|
#######################################
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "ArduinoHttpClient",
|
|
||||||
"keywords": "http, web, client, ethernet, wifi, GSM",
|
|
||||||
"description": "Easily interact with web servers from Arduino, using HTTP and WebSocket's.",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/arduino-libraries/ArduinoHttpClient.git"
|
|
||||||
},
|
|
||||||
"frameworks": "arduino",
|
|
||||||
"platforms": "*",
|
|
||||||
"version": "0.4.0"
|
|
||||||
}
|
|
||||||
@ -1,8 +1,8 @@
|
|||||||
name=ArduinoHttpClient
|
name=ArduinoHttpClient
|
||||||
version=0.4.0
|
version=0.6.1
|
||||||
author=Arduino
|
author=Arduino
|
||||||
maintainer=Arduino <info@arduino.cc>
|
maintainer=Arduino <info@arduino.cc>
|
||||||
sentence=[EXPERIMENTAL] Easily interact with web servers from Arduino, using HTTP and WebSocket's.
|
sentence=[EXPERIMENTAL] Easily interact with web servers from Arduino, using HTTP and WebSockets.
|
||||||
paragraph=This library can be used for HTTP (GET, POST, PUT, DELETE) requests to a web server. It also supports exchanging messages with WebSocket servers. Based on Adrian McEwen's HttpClient library.
|
paragraph=This library can be used for HTTP (GET, POST, PUT, DELETE) requests to a web server. It also supports exchanging messages with WebSocket servers. Based on Adrian McEwen's HttpClient library.
|
||||||
category=Communication
|
category=Communication
|
||||||
url=https://github.com/arduino-libraries/ArduinoHttpClient
|
url=https://github.com/arduino-libraries/ArduinoHttpClient
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "HttpClient.h"
|
#include "HttpClient.h"
|
||||||
#include "b64.h"
|
#include "b64.h"
|
||||||
|
|
||||||
// Initialize constants
|
// Initialize constants
|
||||||
const char* HttpClient::kUserAgent = "Arduino/2.2.0";
|
const char* HttpClient::kUserAgent = "Arduino/2.2.0";
|
||||||
const char* HttpClient::kContentLengthPrefix = HTTP_HEADER_CONTENT_LENGTH ": ";
|
const char* HttpClient::kContentLengthPrefix = HTTP_HEADER_CONTENT_LENGTH ": ";
|
||||||
@ -39,6 +40,7 @@ void HttpClient::resetState()
|
|||||||
iIsChunked = false;
|
iIsChunked = false;
|
||||||
iChunkLength = 0;
|
iChunkLength = 0;
|
||||||
iHttpResponseTimeout = kHttpResponseTimeout;
|
iHttpResponseTimeout = kHttpResponseTimeout;
|
||||||
|
iHttpWaitForDataDelay = kHttpWaitForDataDelay;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpClient::stop()
|
void HttpClient::stop()
|
||||||
@ -83,7 +85,7 @@ int HttpClient::startRequest(const char* aURLPath, const char* aHttpMethod,
|
|||||||
{
|
{
|
||||||
if (iServerName)
|
if (iServerName)
|
||||||
{
|
{
|
||||||
if (!iClient->connect(iServerName, iServerPort) > 0)
|
if (!(iClient->connect(iServerName, iServerPort) > 0))
|
||||||
{
|
{
|
||||||
#ifdef LOGGING
|
#ifdef LOGGING
|
||||||
Serial.println("Connection failed");
|
Serial.println("Connection failed");
|
||||||
@ -93,7 +95,7 @@ int HttpClient::startRequest(const char* aURLPath, const char* aHttpMethod,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!iClient->connect(iServerAddress, iServerPort) > 0)
|
if (!(iClient->connect(iServerAddress, iServerPort) > 0))
|
||||||
{
|
{
|
||||||
#ifdef LOGGING
|
#ifdef LOGGING
|
||||||
Serial.println("Connection failed");
|
Serial.println("Connection failed");
|
||||||
@ -160,7 +162,7 @@ int HttpClient::sendInitialHeaders(const char* aURLPath, const char* aHttpMethod
|
|||||||
{
|
{
|
||||||
iClient->print("Host: ");
|
iClient->print("Host: ");
|
||||||
iClient->print(iServerName);
|
iClient->print(iServerName);
|
||||||
if (iServerPort != kHttpPort)
|
if (iServerPort != kHttpPort && iServerPort != kHttpsPort)
|
||||||
{
|
{
|
||||||
iClient->print(":");
|
iClient->print(":");
|
||||||
iClient->print(iServerPort);
|
iClient->print(iServerPort);
|
||||||
@ -420,7 +422,7 @@ int HttpClient::responseStatusCode()
|
|||||||
{
|
{
|
||||||
if (available())
|
if (available())
|
||||||
{
|
{
|
||||||
c = read();
|
c = HttpClient::read();
|
||||||
if (c != -1)
|
if (c != -1)
|
||||||
{
|
{
|
||||||
switch(iState)
|
switch(iState)
|
||||||
@ -472,7 +474,7 @@ int HttpClient::responseStatusCode()
|
|||||||
{
|
{
|
||||||
// We haven't got any data, so let's pause to allow some to
|
// We haven't got any data, so let's pause to allow some to
|
||||||
// arrive
|
// arrive
|
||||||
delay(kHttpWaitForDataDelay);
|
delay(iHttpWaitForDataDelay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( (c == '\n') && (iStatusCode < 200 && iStatusCode != 101) )
|
if ( (c == '\n') && (iStatusCode < 200 && iStatusCode != 101) )
|
||||||
@ -521,7 +523,7 @@ int HttpClient::skipResponseHeaders()
|
|||||||
{
|
{
|
||||||
// We haven't got any data, so let's pause to allow some to
|
// We haven't got any data, so let's pause to allow some to
|
||||||
// arrive
|
// arrive
|
||||||
delay(kHttpWaitForDataDelay);
|
delay(iHttpWaitForDataDelay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (endOfHeadersReached())
|
if (endOfHeadersReached())
|
||||||
@ -541,7 +543,7 @@ bool HttpClient::endOfHeadersReached()
|
|||||||
return (iState == eReadingBody || iState == eReadingChunkLength || iState == eReadingBodyChunk);
|
return (iState == eReadingBody || iState == eReadingChunkLength || iState == eReadingBodyChunk);
|
||||||
};
|
};
|
||||||
|
|
||||||
int HttpClient::contentLength()
|
long HttpClient::contentLength()
|
||||||
{
|
{
|
||||||
// skip the response headers, if they haven't been read already
|
// skip the response headers, if they haven't been read already
|
||||||
if (!endOfHeadersReached())
|
if (!endOfHeadersReached())
|
||||||
@ -586,7 +588,7 @@ String HttpClient::responseBody()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bodyLength > 0 && (unsigned int)bodyLength != response.length()) {
|
if (bodyLength > 0 && (unsigned int)bodyLength != response.length()) {
|
||||||
// failure, we did not read in reponse content length bytes
|
// failure, we did not read in response content length bytes
|
||||||
return String((const char*)NULL);
|
return String((const char*)NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -684,12 +686,12 @@ int HttpClient::read()
|
|||||||
|
|
||||||
bool HttpClient::headerAvailable()
|
bool HttpClient::headerAvailable()
|
||||||
{
|
{
|
||||||
// clear the currently store header line
|
// clear the currently stored header line
|
||||||
iHeaderLine = "";
|
iHeaderLine = "";
|
||||||
|
|
||||||
while (!endOfHeadersReached())
|
while (!endOfHeadersReached())
|
||||||
{
|
{
|
||||||
uint64_t i =0;
|
// read a byte from the header
|
||||||
|
|
||||||
int c = readHeader();
|
int c = readHeader();
|
||||||
|
|
||||||
if (c == '\r' || c == '\n')
|
if (c == '\r' || c == '\n')
|
||||||
@ -705,13 +707,7 @@ bool HttpClient::headerAvailable()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i++;
|
|
||||||
|
|
||||||
if(i > 1024*2)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// append byte to header line
|
// append byte to header line
|
||||||
iHeaderLine += (char)c;
|
iHeaderLine += (char)c;
|
||||||
}
|
}
|
||||||
@ -767,7 +763,7 @@ int HttpClient::read(uint8_t *buf, size_t size)
|
|||||||
|
|
||||||
int HttpClient::readHeader()
|
int HttpClient::readHeader()
|
||||||
{
|
{
|
||||||
char c = read();
|
char c = HttpClient::read();
|
||||||
|
|
||||||
if (endOfHeadersReached())
|
if (endOfHeadersReached())
|
||||||
{
|
{
|
||||||
@ -823,7 +819,11 @@ int HttpClient::readHeader()
|
|||||||
case eReadingContentLength:
|
case eReadingContentLength:
|
||||||
if (isdigit(c))
|
if (isdigit(c))
|
||||||
{
|
{
|
||||||
iContentLength = iContentLength*10 + (c - '0');
|
long _iContentLength = iContentLength*10 + (c - '0');
|
||||||
|
// Only apply if the value didn't wrap around
|
||||||
|
if (_iContentLength > iContentLength) {
|
||||||
|
iContentLength = _iContentLength;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@ -43,6 +43,7 @@ class HttpClient : public Client
|
|||||||
public:
|
public:
|
||||||
static const int kNoContentLengthHeader =-1;
|
static const int kNoContentLengthHeader =-1;
|
||||||
static const int kHttpPort =80;
|
static const int kHttpPort =80;
|
||||||
|
static const int kHttpsPort =443;
|
||||||
static const char* kUserAgent;
|
static const char* kUserAgent;
|
||||||
|
|
||||||
// FIXME Write longer API request, using port and user-agent, example
|
// FIXME Write longer API request, using port and user-agent, example
|
||||||
@ -228,7 +229,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
String readHeaderName();
|
String readHeaderName();
|
||||||
|
|
||||||
/** Read the vallue of the current response header.
|
/** Read the value of the current response header.
|
||||||
Returns empty string if a header is not available.
|
Returns empty string if a header is not available.
|
||||||
*/
|
*/
|
||||||
String readHeaderValue();
|
String readHeaderValue();
|
||||||
@ -272,7 +273,7 @@ public:
|
|||||||
@return Length of the body, in bytes, or kNoContentLengthHeader if no
|
@return Length of the body, in bytes, or kNoContentLengthHeader if no
|
||||||
Content-Length header was returned by the server
|
Content-Length header was returned by the server
|
||||||
*/
|
*/
|
||||||
int contentLength();
|
long contentLength();
|
||||||
|
|
||||||
/** Returns if the response body is chunked
|
/** Returns if the response body is chunked
|
||||||
@return true if response body is chunked, false otherwise
|
@return true if response body is chunked, false otherwise
|
||||||
@ -317,6 +318,8 @@ public:
|
|||||||
virtual operator bool() { return bool(iClient); };
|
virtual operator bool() { return bool(iClient); };
|
||||||
virtual uint32_t httpResponseTimeout() { return iHttpResponseTimeout; };
|
virtual uint32_t httpResponseTimeout() { return iHttpResponseTimeout; };
|
||||||
virtual void setHttpResponseTimeout(uint32_t timeout) { iHttpResponseTimeout = timeout; };
|
virtual void setHttpResponseTimeout(uint32_t timeout) { iHttpResponseTimeout = timeout; };
|
||||||
|
virtual uint32_t httpWaitForDataDelay() { return iHttpWaitForDataDelay; };
|
||||||
|
virtual void setHttpWaitForDataDelay(uint32_t delay) { iHttpWaitForDataDelay = delay; };
|
||||||
protected:
|
protected:
|
||||||
/** Reset internal state data back to the "just initialised" state
|
/** Reset internal state data back to the "just initialised" state
|
||||||
*/
|
*/
|
||||||
@ -340,8 +343,8 @@ protected:
|
|||||||
|
|
||||||
// Number of milliseconds that we wait each time there isn't any data
|
// Number of milliseconds that we wait each time there isn't any data
|
||||||
// available to be read (during status code and header processing)
|
// available to be read (during status code and header processing)
|
||||||
static const int kHttpWaitForDataDelay = 1000;
|
static const int kHttpWaitForDataDelay = 100;
|
||||||
// Number of milliseconds that we'll wait in total without receiveing any
|
// Number of milliseconds that we'll wait in total without receiving any
|
||||||
// data before returning HTTP_ERROR_TIMED_OUT (during status code and header
|
// data before returning HTTP_ERROR_TIMED_OUT (during status code and header
|
||||||
// processing)
|
// processing)
|
||||||
static const int kHttpResponseTimeout = 30*1000;
|
static const int kHttpResponseTimeout = 30*1000;
|
||||||
@ -372,7 +375,7 @@ protected:
|
|||||||
// Stores the status code for the response, once known
|
// Stores the status code for the response, once known
|
||||||
int iStatusCode;
|
int iStatusCode;
|
||||||
// Stores the value of the Content-Length header, if present
|
// Stores the value of the Content-Length header, if present
|
||||||
int iContentLength;
|
long iContentLength;
|
||||||
// How many bytes of the response body have been read by the user
|
// How many bytes of the response body have been read by the user
|
||||||
int iBodyLengthConsumed;
|
int iBodyLengthConsumed;
|
||||||
// How far through a Content-Length header prefix we are
|
// How far through a Content-Length header prefix we are
|
||||||
@ -384,6 +387,7 @@ protected:
|
|||||||
// Stores the value of the current chunk length, if present
|
// Stores the value of the current chunk length, if present
|
||||||
int iChunkLength;
|
int iChunkLength;
|
||||||
uint32_t iHttpResponseTimeout;
|
uint32_t iHttpResponseTimeout;
|
||||||
|
uint32_t iHttpWaitForDataDelay;
|
||||||
bool iConnectionClose;
|
bool iConnectionClose;
|
||||||
bool iSendDefaultRequestHeaders;
|
bool iSendDefaultRequestHeaders;
|
||||||
String iHeaderLine;
|
String iHeaderLine;
|
||||||
|
|||||||
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* PackageLicenseDeclared: Apache-2.0
|
||||||
|
* Copyright (c) 2017 ARM Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following class is defined in mbed libraries, in case of STM32H7 include the original library
|
||||||
|
*/
|
||||||
|
#if defined __has_include
|
||||||
|
# if __has_include(<utility/http_parsed_url.h>)
|
||||||
|
# include <utility/http_parsed_url.h>
|
||||||
|
# else
|
||||||
|
# define NO_HTTP_PARSED
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef NO_HTTP_PARSED
|
||||||
|
#ifndef _MBED_HTTP_PARSED_URL_H_
|
||||||
|
#define _MBED_HTTP_PARSED_URL_H_
|
||||||
|
|
||||||
|
#include "utility/URLParser/http_parser.h"
|
||||||
|
|
||||||
|
class ParsedUrl {
|
||||||
|
public:
|
||||||
|
ParsedUrl(const char* url) {
|
||||||
|
struct http_parser_url parsed_url;
|
||||||
|
http_parser_parse_url(url, strlen(url), false, &parsed_url);
|
||||||
|
|
||||||
|
for (size_t ix = 0; ix < UF_MAX; ix++) {
|
||||||
|
char* value;
|
||||||
|
if (parsed_url.field_set & (1 << ix)) {
|
||||||
|
value = (char*)calloc(parsed_url.field_data[ix].len + 1, 1);
|
||||||
|
memcpy(value, url + parsed_url.field_data[ix].off,
|
||||||
|
parsed_url.field_data[ix].len);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
value = (char*)calloc(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ((http_parser_url_fields)ix) {
|
||||||
|
case UF_SCHEMA: _schema = value; break;
|
||||||
|
case UF_HOST: _host = value; break;
|
||||||
|
case UF_PATH: _path = value; break;
|
||||||
|
case UF_QUERY: _query = value; break;
|
||||||
|
case UF_USERINFO: _userinfo = value; break;
|
||||||
|
default:
|
||||||
|
// PORT is already parsed, FRAGMENT is not relevant for HTTP requests
|
||||||
|
free(value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_port = parsed_url.port;
|
||||||
|
if (!_port) {
|
||||||
|
if (strcmp(_schema, "https") == 0 || strcmp(_schema, "wss") == 0) {
|
||||||
|
_port = 443;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_port = 80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(_path, "") == 0) {
|
||||||
|
free(_path);
|
||||||
|
_path = (char*)calloc(2, 1);
|
||||||
|
_path[0] = '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~ParsedUrl() {
|
||||||
|
if (_schema) free(_schema);
|
||||||
|
if (_host) free(_host);
|
||||||
|
if (_path) free(_path);
|
||||||
|
if (_query) free(_query);
|
||||||
|
if (_userinfo) free(_userinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t port() const { return _port; }
|
||||||
|
char* schema() const { return _schema; }
|
||||||
|
char* host() const { return _host; }
|
||||||
|
char* path() const { return _path; }
|
||||||
|
char* query() const { return _query; }
|
||||||
|
char* userinfo() const { return _userinfo; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint16_t _port;
|
||||||
|
char* _schema;
|
||||||
|
char* _host;
|
||||||
|
char* _path;
|
||||||
|
char* _query;
|
||||||
|
char* _userinfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _MBED_HTTP_PARSED_URL_H_
|
||||||
|
#endif // NO_HTTP_PARSED
|
||||||
|
#undef NO_HTTP_PARSED
|
||||||
@ -8,6 +8,10 @@
|
|||||||
|
|
||||||
#include "HttpClient.h"
|
#include "HttpClient.h"
|
||||||
|
|
||||||
|
#ifndef WS_TX_BUFFER_SIZE
|
||||||
|
#define WS_TX_BUFFER_SIZE 128
|
||||||
|
#endif
|
||||||
|
|
||||||
static const int TYPE_CONTINUATION = 0x0;
|
static const int TYPE_CONTINUATION = 0x0;
|
||||||
static const int TYPE_TEXT = 0x1;
|
static const int TYPE_TEXT = 0x1;
|
||||||
static const int TYPE_BINARY = 0x2;
|
static const int TYPE_BINARY = 0x2;
|
||||||
@ -86,7 +90,7 @@ private:
|
|||||||
private:
|
private:
|
||||||
bool iTxStarted;
|
bool iTxStarted;
|
||||||
uint8_t iTxMessageType;
|
uint8_t iTxMessageType;
|
||||||
uint8_t iTxBuffer[128];
|
uint8_t iTxBuffer[WS_TX_BUFFER_SIZE];
|
||||||
uint64_t iTxSize;
|
uint64_t iTxSize;
|
||||||
|
|
||||||
uint8_t iRxOpCode;
|
uint8_t iRxOpCode;
|
||||||
|
|||||||
@ -0,0 +1,23 @@
|
|||||||
|
http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright
|
||||||
|
Igor Sysoev.
|
||||||
|
|
||||||
|
Additional changes are licensed under the same terms as NGINX and
|
||||||
|
copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||||
|
|
||||||
|
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.
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
# http_parser library
|
||||||
|
|
||||||
|
This code is imported from: https://github.com/arduino/ArduinoCore-mbed/tree/4.1.1/libraries/SocketWrapper/src/utility/http_parser
|
||||||
|
|
||||||
|
The code is shrinked in size by deleting all the unrelated code to url parse.
|
||||||
@ -0,0 +1,591 @@
|
|||||||
|
#if defined __has_include
|
||||||
|
# if ! __has_include(<utility/http_parser/http_parser.h>) && ! __has_include(<http_parser.h>)
|
||||||
|
# define NO_HTTP_PARSER
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef NO_HTTP_PARSER
|
||||||
|
/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev
|
||||||
|
*
|
||||||
|
* Additional changes are licensed under the same terms as NGINX and
|
||||||
|
* copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#include "http_parser.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#ifndef BIT_AT
|
||||||
|
# define BIT_AT(a, i) \
|
||||||
|
(!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \
|
||||||
|
(1 << ((unsigned int) (i) & 7))))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SET_ERRNO(e) \
|
||||||
|
do { \
|
||||||
|
parser->http_errno = (e); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#if HTTP_PARSER_STRICT
|
||||||
|
# define T(v) 0
|
||||||
|
#else
|
||||||
|
# define T(v) v
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static const uint8_t normal_url_char[32] = {
|
||||||
|
/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
|
||||||
|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
|
||||||
|
/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
|
||||||
|
0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0,
|
||||||
|
/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
|
||||||
|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
|
||||||
|
/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
|
||||||
|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
|
||||||
|
/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
|
||||||
|
0 | 2 | 4 | 0 | 16 | 32 | 64 | 128,
|
||||||
|
/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
|
||||||
|
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||||
|
/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
|
||||||
|
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||||
|
/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
|
||||||
|
1 | 2 | 4 | 8 | 16 | 32 | 64 | 0,
|
||||||
|
/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
|
||||||
|
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||||
|
/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
|
||||||
|
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||||
|
/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
|
||||||
|
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||||
|
/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
|
||||||
|
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||||
|
/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
|
||||||
|
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||||
|
/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
|
||||||
|
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||||
|
/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
|
||||||
|
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||||
|
/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
|
||||||
|
1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, };
|
||||||
|
|
||||||
|
#undef T
|
||||||
|
|
||||||
|
enum state
|
||||||
|
{ s_dead = 1 /* important that this is > 0 */
|
||||||
|
|
||||||
|
, s_start_req
|
||||||
|
|
||||||
|
, s_req_spaces_before_url
|
||||||
|
, s_req_schema
|
||||||
|
, s_req_schema_slash
|
||||||
|
, s_req_schema_slash_slash
|
||||||
|
, s_req_server_start
|
||||||
|
, s_req_server
|
||||||
|
, s_req_server_with_at
|
||||||
|
, s_req_path
|
||||||
|
, s_req_query_string_start
|
||||||
|
, s_req_query_string
|
||||||
|
, s_req_fragment_start
|
||||||
|
, s_req_fragment
|
||||||
|
, s_headers_done
|
||||||
|
};
|
||||||
|
|
||||||
|
enum http_host_state
|
||||||
|
{
|
||||||
|
s_http_host_dead = 1
|
||||||
|
, s_http_userinfo_start
|
||||||
|
, s_http_userinfo
|
||||||
|
, s_http_host_start
|
||||||
|
, s_http_host_v6_start
|
||||||
|
, s_http_host
|
||||||
|
, s_http_host_v6
|
||||||
|
, s_http_host_v6_end
|
||||||
|
, s_http_host_v6_zone_start
|
||||||
|
, s_http_host_v6_zone
|
||||||
|
, s_http_host_port_start
|
||||||
|
, s_http_host_port
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Macros for character classes; depends on strict-mode */
|
||||||
|
#define LOWER(c) (unsigned char)(c | 0x20)
|
||||||
|
#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z')
|
||||||
|
#define IS_NUM(c) ((c) >= '0' && (c) <= '9')
|
||||||
|
#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
|
||||||
|
#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f'))
|
||||||
|
#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \
|
||||||
|
(c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \
|
||||||
|
(c) == ')')
|
||||||
|
#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \
|
||||||
|
(c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \
|
||||||
|
(c) == '$' || (c) == ',')
|
||||||
|
|
||||||
|
#if HTTP_PARSER_STRICT
|
||||||
|
#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c))
|
||||||
|
#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
|
||||||
|
#else
|
||||||
|
#define IS_URL_CHAR(c) \
|
||||||
|
(BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80))
|
||||||
|
#define IS_HOST_CHAR(c) \
|
||||||
|
(IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Our URL parser.
|
||||||
|
*
|
||||||
|
* This is designed to be shared by http_parser_execute() for URL validation,
|
||||||
|
* hence it has a state transition + byte-for-byte interface. In addition, it
|
||||||
|
* is meant to be embedded in http_parser_parse_url(), which does the dirty
|
||||||
|
* work of turning state transitions URL components for its API.
|
||||||
|
*
|
||||||
|
* This function should only be invoked with non-space characters. It is
|
||||||
|
* assumed that the caller cares about (and can detect) the transition between
|
||||||
|
* URL and non-URL states by looking for these.
|
||||||
|
*/
|
||||||
|
static enum state
|
||||||
|
parse_url_char(enum state s, const char ch)
|
||||||
|
{
|
||||||
|
if (ch == ' ' || ch == '\r' || ch == '\n') {
|
||||||
|
return s_dead;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HTTP_PARSER_STRICT
|
||||||
|
if (ch == '\t' || ch == '\f') {
|
||||||
|
return s_dead;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (s) {
|
||||||
|
case s_req_spaces_before_url:
|
||||||
|
/* Proxied requests are followed by scheme of an absolute URI (alpha).
|
||||||
|
* All methods except CONNECT are followed by '/' or '*'.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (ch == '/' || ch == '*') {
|
||||||
|
return s_req_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_ALPHA(ch)) {
|
||||||
|
return s_req_schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_req_schema:
|
||||||
|
if (IS_ALPHA(ch)) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch == ':') {
|
||||||
|
return s_req_schema_slash;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_req_schema_slash:
|
||||||
|
if (ch == '/') {
|
||||||
|
return s_req_schema_slash_slash;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_req_schema_slash_slash:
|
||||||
|
if (ch == '/') {
|
||||||
|
return s_req_server_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_req_server_with_at:
|
||||||
|
if (ch == '@') {
|
||||||
|
return s_dead;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case s_req_server_start:
|
||||||
|
case s_req_server:
|
||||||
|
if (ch == '/') {
|
||||||
|
return s_req_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch == '?') {
|
||||||
|
return s_req_query_string_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch == '@') {
|
||||||
|
return s_req_server_with_at;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') {
|
||||||
|
return s_req_server;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_req_path:
|
||||||
|
if (IS_URL_CHAR(ch)) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ch) {
|
||||||
|
case '?':
|
||||||
|
return s_req_query_string_start;
|
||||||
|
|
||||||
|
case '#':
|
||||||
|
return s_req_fragment_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_req_query_string_start:
|
||||||
|
case s_req_query_string:
|
||||||
|
if (IS_URL_CHAR(ch)) {
|
||||||
|
return s_req_query_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ch) {
|
||||||
|
case '?':
|
||||||
|
/* allow extra '?' in query string */
|
||||||
|
return s_req_query_string;
|
||||||
|
|
||||||
|
case '#':
|
||||||
|
return s_req_fragment_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_req_fragment_start:
|
||||||
|
if (IS_URL_CHAR(ch)) {
|
||||||
|
return s_req_fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ch) {
|
||||||
|
case '?':
|
||||||
|
return s_req_fragment;
|
||||||
|
|
||||||
|
case '#':
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_req_fragment:
|
||||||
|
if (IS_URL_CHAR(ch)) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ch) {
|
||||||
|
case '?':
|
||||||
|
case '#':
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We should never fall out of the switch above unless there's an error */
|
||||||
|
return s_dead;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum http_host_state
|
||||||
|
http_parse_host_char(enum http_host_state s, const char ch) {
|
||||||
|
switch(s) {
|
||||||
|
case s_http_userinfo:
|
||||||
|
case s_http_userinfo_start:
|
||||||
|
if (ch == '@') {
|
||||||
|
return s_http_host_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_USERINFO_CHAR(ch)) {
|
||||||
|
return s_http_userinfo;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_http_host_start:
|
||||||
|
if (ch == '[') {
|
||||||
|
return s_http_host_v6_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_HOST_CHAR(ch)) {
|
||||||
|
return s_http_host;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_http_host:
|
||||||
|
if (IS_HOST_CHAR(ch)) {
|
||||||
|
return s_http_host;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case s_http_host_v6_end:
|
||||||
|
if (ch == ':') {
|
||||||
|
return s_http_host_port_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_http_host_v6:
|
||||||
|
if (ch == ']') {
|
||||||
|
return s_http_host_v6_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case s_http_host_v6_start:
|
||||||
|
if (IS_HEX(ch) || ch == ':' || ch == '.') {
|
||||||
|
return s_http_host_v6;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s == s_http_host_v6 && ch == '%') {
|
||||||
|
return s_http_host_v6_zone_start;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_http_host_v6_zone:
|
||||||
|
if (ch == ']') {
|
||||||
|
return s_http_host_v6_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case s_http_host_v6_zone_start:
|
||||||
|
/* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */
|
||||||
|
if (IS_ALPHANUM(ch) || ch == '%' || ch == '.' || ch == '-' || ch == '_' ||
|
||||||
|
ch == '~') {
|
||||||
|
return s_http_host_v6_zone;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_http_host_port:
|
||||||
|
case s_http_host_port_start:
|
||||||
|
if (IS_NUM(ch)) {
|
||||||
|
return s_http_host_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return s_http_host_dead;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
http_parse_host(const char * buf, struct http_parser_url *u, int found_at) {
|
||||||
|
enum http_host_state s;
|
||||||
|
|
||||||
|
const char *p;
|
||||||
|
uint32_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len;
|
||||||
|
|
||||||
|
assert(u->field_set & (1 << UF_HOST));
|
||||||
|
|
||||||
|
u->field_data[UF_HOST].len = 0;
|
||||||
|
|
||||||
|
s = found_at ? s_http_userinfo_start : s_http_host_start;
|
||||||
|
|
||||||
|
for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) {
|
||||||
|
enum http_host_state new_s = http_parse_host_char(s, *p);
|
||||||
|
|
||||||
|
if (new_s == s_http_host_dead) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(new_s) {
|
||||||
|
case s_http_host:
|
||||||
|
if (s != s_http_host) {
|
||||||
|
u->field_data[UF_HOST].off = p - buf;
|
||||||
|
}
|
||||||
|
u->field_data[UF_HOST].len++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_http_host_v6:
|
||||||
|
if (s != s_http_host_v6) {
|
||||||
|
u->field_data[UF_HOST].off = p - buf;
|
||||||
|
}
|
||||||
|
u->field_data[UF_HOST].len++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_http_host_v6_zone_start:
|
||||||
|
case s_http_host_v6_zone:
|
||||||
|
u->field_data[UF_HOST].len++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_http_host_port:
|
||||||
|
if (s != s_http_host_port) {
|
||||||
|
u->field_data[UF_PORT].off = p - buf;
|
||||||
|
u->field_data[UF_PORT].len = 0;
|
||||||
|
u->field_set |= (1 << UF_PORT);
|
||||||
|
}
|
||||||
|
u->field_data[UF_PORT].len++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_http_userinfo:
|
||||||
|
if (s != s_http_userinfo) {
|
||||||
|
u->field_data[UF_USERINFO].off = p - buf ;
|
||||||
|
u->field_data[UF_USERINFO].len = 0;
|
||||||
|
u->field_set |= (1 << UF_USERINFO);
|
||||||
|
}
|
||||||
|
u->field_data[UF_USERINFO].len++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
s = new_s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure we don't end somewhere unexpected */
|
||||||
|
switch (s) {
|
||||||
|
case s_http_host_start:
|
||||||
|
case s_http_host_v6_start:
|
||||||
|
case s_http_host_v6:
|
||||||
|
case s_http_host_v6_zone_start:
|
||||||
|
case s_http_host_v6_zone:
|
||||||
|
case s_http_host_port_start:
|
||||||
|
case s_http_userinfo:
|
||||||
|
case s_http_userinfo_start:
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
http_parser_url_init(struct http_parser_url *u) {
|
||||||
|
memset(u, 0, sizeof(*u));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
http_parser_parse_url(const char *buf, uint32_t buflen, int is_connect,
|
||||||
|
struct http_parser_url *u)
|
||||||
|
{
|
||||||
|
enum state s;
|
||||||
|
const char *p;
|
||||||
|
enum http_parser_url_fields uf, old_uf;
|
||||||
|
int found_at = 0;
|
||||||
|
|
||||||
|
u->port = u->field_set = 0;
|
||||||
|
s = is_connect ? s_req_server_start : s_req_spaces_before_url;
|
||||||
|
old_uf = UF_MAX;
|
||||||
|
|
||||||
|
for (p = buf; p < buf + buflen; p++) {
|
||||||
|
s = parse_url_char(s, *p);
|
||||||
|
|
||||||
|
/* Figure out the next field that we're operating on */
|
||||||
|
switch (s) {
|
||||||
|
case s_dead:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Skip delimeters */
|
||||||
|
case s_req_schema_slash:
|
||||||
|
case s_req_schema_slash_slash:
|
||||||
|
case s_req_server_start:
|
||||||
|
case s_req_query_string_start:
|
||||||
|
case s_req_fragment_start:
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case s_req_schema:
|
||||||
|
uf = UF_SCHEMA;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_req_server_with_at:
|
||||||
|
found_at = 1;
|
||||||
|
|
||||||
|
/* FALLTROUGH */
|
||||||
|
case s_req_server:
|
||||||
|
uf = UF_HOST;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_req_path:
|
||||||
|
uf = UF_PATH;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_req_query_string:
|
||||||
|
uf = UF_QUERY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case s_req_fragment:
|
||||||
|
uf = UF_FRAGMENT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(!"Unexpected state");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nothing's changed; soldier on */
|
||||||
|
if (uf == old_uf) {
|
||||||
|
u->field_data[uf].len++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
u->field_data[uf].off = p - buf;
|
||||||
|
u->field_data[uf].len = 1;
|
||||||
|
|
||||||
|
u->field_set |= (1 << uf);
|
||||||
|
old_uf = uf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* host must be present if there is a schema */
|
||||||
|
/* parsing http:///toto will fail */
|
||||||
|
if ((u->field_set & (1 << UF_SCHEMA)) &&
|
||||||
|
(u->field_set & (1 << UF_HOST)) == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (u->field_set & (1 << UF_HOST)) {
|
||||||
|
if (http_parse_host(buf, u, found_at) != 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CONNECT requests can only contain "hostname:port" */
|
||||||
|
if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (u->field_set & (1 << UF_PORT)) {
|
||||||
|
/* Don't bother with endp; we've already validated the string */
|
||||||
|
unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10);
|
||||||
|
|
||||||
|
/* Ports have a max value of 2^16 */
|
||||||
|
if (v > 0xffff) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
u->port = (uint16_t) v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long
|
||||||
|
http_parser_version(void) {
|
||||||
|
return HTTP_PARSER_VERSION_MAJOR * 0x10000 |
|
||||||
|
HTTP_PARSER_VERSION_MINOR * 0x00100 |
|
||||||
|
HTTP_PARSER_VERSION_PATCH * 0x00001;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // NO_HTTP_PARSER
|
||||||
@ -0,0 +1,96 @@
|
|||||||
|
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#ifndef http_parser_h
|
||||||
|
#define http_parser_h
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Also update SONAME in the Makefile whenever you change these. */
|
||||||
|
#define HTTP_PARSER_VERSION_MAJOR 2
|
||||||
|
#define HTTP_PARSER_VERSION_MINOR 7
|
||||||
|
#define HTTP_PARSER_VERSION_PATCH 1
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
|
||||||
|
* faster
|
||||||
|
*/
|
||||||
|
#ifndef HTTP_PARSER_STRICT
|
||||||
|
# define HTTP_PARSER_STRICT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
enum http_parser_url_fields
|
||||||
|
{ UF_SCHEMA = 0
|
||||||
|
, UF_HOST = 1
|
||||||
|
, UF_PORT = 2
|
||||||
|
, UF_PATH = 3
|
||||||
|
, UF_QUERY = 4
|
||||||
|
, UF_FRAGMENT = 5
|
||||||
|
, UF_USERINFO = 6
|
||||||
|
, UF_MAX = 7
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Result structure for http_parser_parse_url().
|
||||||
|
*
|
||||||
|
* Callers should index into field_data[] with UF_* values iff field_set
|
||||||
|
* has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
|
||||||
|
* because we probably have padding left over), we convert any port to
|
||||||
|
* a uint16_t.
|
||||||
|
*/
|
||||||
|
struct http_parser_url {
|
||||||
|
uint16_t field_set; /* Bitmask of (1 << UF_*) values */
|
||||||
|
uint16_t port; /* Converted UF_PORT string */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint16_t off; /* Offset into buffer in which field starts */
|
||||||
|
uint16_t len; /* Length of run in buffer */
|
||||||
|
} field_data[UF_MAX];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Returns the library version. Bits 16-23 contain the major version number,
|
||||||
|
* bits 8-15 the minor version number and bits 0-7 the patch level.
|
||||||
|
* Usage example:
|
||||||
|
*
|
||||||
|
* unsigned long version = http_parser_version();
|
||||||
|
* unsigned major = (version >> 16) & 255;
|
||||||
|
* unsigned minor = (version >> 8) & 255;
|
||||||
|
* unsigned patch = version & 255;
|
||||||
|
* printf("http_parser v%u.%u.%u\n", major, minor, patch);
|
||||||
|
*/
|
||||||
|
unsigned long http_parser_version(void);
|
||||||
|
|
||||||
|
/* Initialize all http_parser_url members to 0 */
|
||||||
|
void http_parser_url_init(struct http_parser_url *u);
|
||||||
|
|
||||||
|
/* Parse a URL; return nonzero on failure */
|
||||||
|
int http_parser_parse_url(const char *buf, uint32_t buflen,
|
||||||
|
int is_connect,
|
||||||
|
struct http_parser_url *u);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
@ -1 +1 @@
|
|||||||
{"type": "library", "name": "ArduinoJson", "version": "6.21.5", "spec": {"owner": "bblanchon", "id": 64, "name": "ArduinoJson", "requirements": null, "uri": null}}
|
{"type": "library", "name": "ArduinoJson", "version": "7.4.2", "spec": {"owner": "bblanchon", "id": 64, "name": "ArduinoJson", "requirements": null, "uri": null}}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#include "src/ArduinoJson.h"
|
#include "src/ArduinoJson.h"
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
Copyright © 2014-2023, Benoit BLANCHON
|
Copyright © 2014-2025, 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:
|
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:
|
||||||
|
|
||||||
|
|||||||
@ -4,13 +4,10 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A6.x)
|
[](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A7.x)
|
||||||
[](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x)
|
[](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/7.x)
|
||||||
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
|
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
|
||||||
[](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x)
|
[](https://coveralls.io/github/bblanchon/ArduinoJson?branch=7.x)
|
||||||
[](https://www.ardu-badge.com/ArduinoJson/6.21.5)
|
|
||||||
[](https://registry.platformio.org/packages/libraries/bblanchon/ArduinoJson?version=6.21.5)
|
|
||||||
[](https://components.espressif.com/components/bblanchon/arduinojson)
|
|
||||||
[](https://github.com/bblanchon/ArduinoJson/stargazers)
|
[](https://github.com/bblanchon/ArduinoJson/stargazers)
|
||||||
[](https://github.com/sponsors/bblanchon)
|
[](https://github.com/sponsors/bblanchon)
|
||||||
|
|
||||||
@ -18,31 +15,28 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* [JSON deserialization](https://arduinojson.org/v6/api/json/deserializejson/)
|
* [JSON deserialization](https://arduinojson.org/v7/api/json/deserializejson/)
|
||||||
* [Optionally decodes UTF-16 escape sequences to UTF-8](https://arduinojson.org/v6/api/config/decode_unicode/)
|
* [Optionally decodes UTF-16 escape sequences to UTF-8](https://arduinojson.org/v7/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/v7/api/config/enable_comments/)
|
||||||
* [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/v7/api/json/deserializejson/#filtering)
|
||||||
* [Optionally filters the input to keep only desired values](https://arduinojson.org/v6/api/json/deserializejson/#filtering)
|
|
||||||
* Supports single quotes as a string delimiter
|
* Supports single quotes as a string delimiter
|
||||||
* Compatible with [NDJSON](http://ndjson.org/) and [JSON Lines](https://jsonlines.org/)
|
* Compatible with [NDJSON](http://ndjson.org/) and [JSON Lines](https://jsonlines.org/)
|
||||||
* [JSON serialization](https://arduinojson.org/v6/api/json/serializejson/)
|
* [JSON serialization](https://arduinojson.org/v7/api/json/serializejson/)
|
||||||
* [Can write to a buffer or a stream](https://arduinojson.org/v6/api/json/serializejson/)
|
* [Can write to a buffer or a stream](https://arduinojson.org/v7/api/json/serializejson/)
|
||||||
* [Optionally indents the document (prettified JSON)](https://arduinojson.org/v6/api/json/serializejsonpretty/)
|
* [Optionally indents the document (prettified JSON)](https://arduinojson.org/v7/api/json/serializejsonpretty/)
|
||||||
* [MessagePack serialization](https://arduinojson.org/v6/api/msgpack/serializemsgpack/)
|
* [MessagePack serialization](https://arduinojson.org/v7/api/msgpack/serializemsgpack/)
|
||||||
* [MessagePack deserialization](https://arduinojson.org/v6/api/msgpack/deserializemsgpack/)
|
* [MessagePack deserialization](https://arduinojson.org/v7/api/msgpack/deserializemsgpack/)
|
||||||
* Efficient
|
* Efficient
|
||||||
* [Twice smaller than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
|
* [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/)
|
* [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/)
|
* [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/)
|
* [Deduplicates strings](https://arduinojson.org/news/2020/08/01/version-6-16-0/)
|
||||||
* Versatile
|
* Versatile
|
||||||
* Supports [custom allocators (to use external RAM chip, for example)](https://arduinojson.org/v6/how-to/use-external-ram-on-esp32/)
|
* Supports [custom allocators (to use external RAM chip, for example)](https://arduinojson.org/v7/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 [`String`](https://arduinojson.org/v7/api/config/enable_arduino_string/), [`std::string`](https://arduinojson.org/v7/api/config/enable_std_string/), and [`std::string_view`](https://arduinojson.org/v7/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 [`Stream`](https://arduinojson.org/v7/api/config/enable_arduino_stream/) and [`std::istream`/`std::ostream`](https://arduinojson.org/v7/api/config/enable_std_stream/)
|
||||||
* Supports [Flash strings](https://arduinojson.org/v6/api/config/enable_progmem/)
|
* Supports [Flash strings](https://arduinojson.org/v7/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 readers](https://arduinojson.org/v7/api/json/deserializejson/#custom-reader) and [custom writers](https://arduinojson.org/v7/api/json/serializejson/#custom-writer)
|
||||||
* Supports [custom converters](https://arduinojson.org/news/2021/05/04/version-6-18-0/)
|
* Supports [custom converters](https://arduinojson.org/news/2021/05/04/version-6-18-0/)
|
||||||
* Portable
|
* Portable
|
||||||
* Usable on any C++ project (not limited to Arduino)
|
* Usable on any C++ project (not limited to Arduino)
|
||||||
@ -72,29 +66,29 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
|
|||||||
* [Visual Micro](http://www.visualmicro.com/)
|
* [Visual Micro](http://www.visualmicro.com/)
|
||||||
* [Visual Studio](https://www.visualstudio.com/)
|
* [Visual Studio](https://www.visualstudio.com/)
|
||||||
* [Even works with online compilers like wandbox.org](https://wandbox.org/permlink/RlZSKy17DjJ6HcdN)
|
* [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/)
|
* [CMake friendly](https://arduinojson.org/v7/how-to/use-arduinojson-with-cmake/)
|
||||||
* Well designed
|
* Well designed
|
||||||
* [Elegant API](http://arduinojson.org/v6/example/)
|
* [Elegant API](http://arduinojson.org/v7/example/)
|
||||||
* [Thread-safe](https://en.wikipedia.org/wiki/Thread_safety)
|
* [Thread-safe](https://en.wikipedia.org/wiki/Thread_safety)
|
||||||
* Self-contained (no external dependency)
|
* Self-contained (no external dependency)
|
||||||
* `const` friendly
|
* `const` friendly
|
||||||
* [`for` friendly](https://arduinojson.org/v6/api/jsonobject/begin_end/)
|
* [`for` friendly](https://arduinojson.org/v7/api/jsonobject/begin_end/)
|
||||||
* [TMP friendly](https://en.wikipedia.org/wiki/Template_metaprogramming)
|
* [TMP friendly](https://en.wikipedia.org/wiki/Template_metaprogramming)
|
||||||
* Handles [integer overflows](https://arduinojson.org/v6/api/jsonvariant/as/#integer-overflows)
|
* Handles [integer overflows](https://arduinojson.org/v7/api/jsonvariant/as/#integer-overflows)
|
||||||
* Well tested
|
* Well tested
|
||||||
* [Unit test coverage close to 100%](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x)
|
* [Unit test coverage close to 100%](https://coveralls.io/github/bblanchon/ArduinoJson?branch=7.x)
|
||||||
* Continuously tested on
|
* Continuously tested on
|
||||||
* [Visual Studio 2017, 2019, 2022](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x)
|
* [Visual Studio 2017, 2019, 2022](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/7.x)
|
||||||
* [GCC 5, 6, 7, 8, 9, 10, 11](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
|
* [GCC 4.8, 5, 6, 7, 8, 9, 10, 11, 12](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)
|
* [Clang 7 to 19](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)
|
* [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/)
|
* Passes all default checks of [clang-tidy](https://releases.llvm.org/10.0.0/tools/clang/tools/extra/docs/clang-tidy/)
|
||||||
* Well documented
|
* Well documented
|
||||||
* [Tutorials](https://arduinojson.org/v6/doc/deserialization/)
|
* [Tutorials](https://arduinojson.org/v7/doc/deserialization/)
|
||||||
* [Examples](https://arduinojson.org/v6/example/)
|
* [Examples](https://arduinojson.org/v7/example/)
|
||||||
* [How-tos](https://arduinojson.org/v6/example/)
|
* [How-tos](https://arduinojson.org/v7/example/)
|
||||||
* [FAQ](https://arduinojson.org/v6/faq/)
|
* [FAQ](https://arduinojson.org/v7/faq/)
|
||||||
* [Troubleshooter](https://arduinojson.org/v6/troubleshooter/)
|
* [Troubleshooter](https://arduinojson.org/v7/troubleshooter/)
|
||||||
* [Book](https://arduinojson.org/book/)
|
* [Book](https://arduinojson.org/book/)
|
||||||
* [Changelog](CHANGELOG.md)
|
* [Changelog](CHANGELOG.md)
|
||||||
* Vibrant user community
|
* Vibrant user community
|
||||||
@ -109,9 +103,9 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
|
|||||||
Here is a program that parses a JSON document with ArduinoJson.
|
Here is a program that parses a JSON document with ArduinoJson.
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
|
const char* json = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
|
||||||
|
|
||||||
DynamicJsonDocument doc(1024);
|
JsonDocument doc;
|
||||||
deserializeJson(doc, json);
|
deserializeJson(doc, json);
|
||||||
|
|
||||||
const char* sensor = doc["sensor"];
|
const char* sensor = doc["sensor"];
|
||||||
@ -120,14 +114,14 @@ double latitude = doc["data"][0];
|
|||||||
double longitude = doc["data"][1];
|
double longitude = doc["data"][1];
|
||||||
```
|
```
|
||||||
|
|
||||||
See the [tutorial on arduinojson.org](https://arduinojson.org/v6/doc/deserialization/)
|
See the [tutorial on arduinojson.org](https://arduinojson.org/v7/doc/deserialization/)
|
||||||
|
|
||||||
### Serialization
|
### Serialization
|
||||||
|
|
||||||
Here is a program that generates a JSON document with ArduinoJson:
|
Here is a program that generates a JSON document with ArduinoJson:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
DynamicJsonDocument doc(1024);
|
JsonDocument doc;
|
||||||
|
|
||||||
doc["sensor"] = "gps";
|
doc["sensor"] = "gps";
|
||||||
doc["time"] = 1351824120;
|
doc["time"] = 1351824120;
|
||||||
@ -139,21 +133,19 @@ serializeJson(doc, Serial);
|
|||||||
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
|
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
|
||||||
```
|
```
|
||||||
|
|
||||||
See the [tutorial on arduinojson.org](https://arduinojson.org/v6/doc/serialization/)
|
See the [tutorial on arduinojson.org](https://arduinojson.org/v7/doc/serialization/)
|
||||||
|
|
||||||
## Sponsors
|
## Sponsors
|
||||||
|
|
||||||
ArduinoJson is thankful to its sponsors. Please give them a visit; they deserve it!
|
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>
|
<p>
|
||||||
<a href="https://github.com/1technophile" rel="sponsored">
|
<a href="https://github.com/1technophile" rel="sponsored">
|
||||||
<img alt="1technophile" src="https://avatars.githubusercontent.com/u/12672732?s=40&v=4">
|
<img alt="1technophile" src="https://avatars.githubusercontent.com/u/12672732?s=40&v=4">
|
||||||
</a>
|
</a>
|
||||||
|
<a href="https://github.com/LArkema" rel="sponsored">
|
||||||
|
<img alt="LArkema" src="https://avatars.githubusercontent.com/u/38381313?s=40&v=4">
|
||||||
|
</a>
|
||||||
</p>
|
</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 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.
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
//
|
//
|
||||||
// This example shows how to store your project configuration in a file.
|
// This example shows how to store your project configuration in a file.
|
||||||
@ -17,35 +17,28 @@
|
|||||||
// * CLK <-> pin 13
|
// * CLK <-> pin 13
|
||||||
// * CS <-> pin 4
|
// * CS <-> pin 4
|
||||||
//
|
//
|
||||||
// https://arduinojson.org/v6/example/config/
|
// https://arduinojson.org/v7/example/config/
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <SD.h>
|
#include <SD.h>
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
|
|
||||||
// Our configuration structure.
|
// 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 {
|
struct Config {
|
||||||
char hostname[64];
|
char hostname[64];
|
||||||
int port;
|
int port;
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *filename = "/config.txt"; // <- SD library uses 8.3 filenames
|
const char* filename = "/config.txt"; // <- SD library uses 8.3 filenames
|
||||||
Config config; // <- global configuration object
|
Config config; // <- global configuration object
|
||||||
|
|
||||||
// Loads the configuration from a file
|
// Loads the configuration from a file
|
||||||
void loadConfiguration(const char *filename, Config &config) {
|
void loadConfiguration(const char* filename, Config& config) {
|
||||||
// Open file for reading
|
// Open file for reading
|
||||||
File file = SD.open(filename);
|
File file = SD.open(filename);
|
||||||
|
|
||||||
// Allocate a temporary JsonDocument
|
// Allocate a temporary JsonDocument
|
||||||
// Don't forget to change the capacity to match your requirements.
|
JsonDocument doc;
|
||||||
// Use https://arduinojson.org/v6/assistant to compute the capacity.
|
|
||||||
StaticJsonDocument<512> doc;
|
|
||||||
|
|
||||||
// Deserialize the JSON document
|
// Deserialize the JSON document
|
||||||
DeserializationError error = deserializeJson(doc, file);
|
DeserializationError error = deserializeJson(doc, file);
|
||||||
@ -63,7 +56,7 @@ void loadConfiguration(const char *filename, Config &config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Saves the configuration to a file
|
// Saves the configuration to a file
|
||||||
void saveConfiguration(const char *filename, const Config &config) {
|
void saveConfiguration(const char* filename, const Config& config) {
|
||||||
// Delete existing file, otherwise the configuration is appended to the file
|
// Delete existing file, otherwise the configuration is appended to the file
|
||||||
SD.remove(filename);
|
SD.remove(filename);
|
||||||
|
|
||||||
@ -75,9 +68,7 @@ void saveConfiguration(const char *filename, const Config &config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allocate a temporary JsonDocument
|
// Allocate a temporary JsonDocument
|
||||||
// Don't forget to change the capacity to match your requirements.
|
JsonDocument doc;
|
||||||
// Use https://arduinojson.org/assistant to compute the capacity.
|
|
||||||
StaticJsonDocument<256> doc;
|
|
||||||
|
|
||||||
// Set the values in the document
|
// Set the values in the document
|
||||||
doc["hostname"] = config.hostname;
|
doc["hostname"] = config.hostname;
|
||||||
@ -93,7 +84,7 @@ void saveConfiguration(const char *filename, const Config &config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Prints the content of a file to the Serial
|
// Prints the content of a file to the Serial
|
||||||
void printFile(const char *filename) {
|
void printFile(const char* filename) {
|
||||||
// Open file for reading
|
// Open file for reading
|
||||||
File file = SD.open(filename);
|
File file = SD.open(filename);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
@ -114,7 +105,8 @@ void printFile(const char *filename) {
|
|||||||
void setup() {
|
void setup() {
|
||||||
// Initialize serial port
|
// Initialize serial port
|
||||||
Serial.begin(9600);
|
Serial.begin(9600);
|
||||||
while (!Serial) continue;
|
while (!Serial)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Initialize SD library
|
// Initialize SD library
|
||||||
const int chipSelect = 4;
|
const int chipSelect = 4;
|
||||||
@ -144,7 +136,7 @@ void loop() {
|
|||||||
// ------------------
|
// ------------------
|
||||||
//
|
//
|
||||||
// File is an unbuffered stream, which is not optimal for ArduinoJson.
|
// File is an unbuffered stream, which is not optimal for ArduinoJson.
|
||||||
// See: https://arduinojson.org/v6/how-to/improve-speed/
|
// See: https://arduinojson.org/v7/how-to/improve-speed/
|
||||||
|
|
||||||
// See also
|
// See also
|
||||||
// --------
|
// --------
|
||||||
|
|||||||
@ -1,17 +1,18 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
//
|
//
|
||||||
// This example shows how to use DeserializationOption::Filter
|
// This example shows how to use DeserializationOption::Filter
|
||||||
//
|
//
|
||||||
// https://arduinojson.org/v6/example/filter/
|
// https://arduinojson.org/v7/example/filter/
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
// Initialize serial port
|
// Initialize serial port
|
||||||
Serial.begin(9600);
|
Serial.begin(9600);
|
||||||
while (!Serial) continue;
|
while (!Serial)
|
||||||
|
continue;
|
||||||
|
|
||||||
// The huge input: an extract from OpenWeatherMap response
|
// The huge input: an extract from OpenWeatherMap response
|
||||||
auto input_json = F(
|
auto input_json = F(
|
||||||
@ -33,12 +34,12 @@ void setup() {
|
|||||||
"1000000,\"timezone\":0,\"sunrise\":1581492085,\"sunset\":1581527294}}");
|
"1000000,\"timezone\":0,\"sunrise\":1581492085,\"sunset\":1581527294}}");
|
||||||
|
|
||||||
// The filter: it contains "true" for each value we want to keep
|
// The filter: it contains "true" for each value we want to keep
|
||||||
StaticJsonDocument<200> filter;
|
JsonDocument filter;
|
||||||
filter["list"][0]["dt"] = true;
|
filter["list"][0]["dt"] = true;
|
||||||
filter["list"][0]["main"]["temp"] = true;
|
filter["list"][0]["main"]["temp"] = true;
|
||||||
|
|
||||||
// Deserialize the document
|
// Deserialize the document
|
||||||
StaticJsonDocument<400> doc;
|
JsonDocument doc;
|
||||||
deserializeJson(doc, input_json, DeserializationOption::Filter(filter));
|
deserializeJson(doc, input_json, DeserializationOption::Filter(filter));
|
||||||
|
|
||||||
// Print the result
|
// Print the result
|
||||||
|
|||||||
@ -1,43 +1,32 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
//
|
//
|
||||||
// This example shows how to generate a JSON document with ArduinoJson.
|
// This example shows how to generate a JSON document with ArduinoJson.
|
||||||
//
|
//
|
||||||
// https://arduinojson.org/v6/example/generator/
|
// https://arduinojson.org/v7/example/generator/
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
// Initialize Serial port
|
// Initialize Serial port
|
||||||
Serial.begin(9600);
|
Serial.begin(9600);
|
||||||
while (!Serial) continue;
|
while (!Serial)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Allocate the JSON document
|
// Allocate the JSON document
|
||||||
//
|
JsonDocument doc;
|
||||||
// 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
|
// Add values in the document
|
||||||
//
|
|
||||||
doc["sensor"] = "gps";
|
doc["sensor"] = "gps";
|
||||||
doc["time"] = 1351824120;
|
doc["time"] = 1351824120;
|
||||||
|
|
||||||
// Add an array.
|
// Add an array
|
||||||
//
|
JsonArray data = doc["data"].to<JsonArray>();
|
||||||
JsonArray data = doc.createNestedArray("data");
|
|
||||||
data.add(48.756080);
|
data.add(48.756080);
|
||||||
data.add(2.302038);
|
data.add(2.302038);
|
||||||
|
|
||||||
// Generate the minified JSON and send it to the Serial port.
|
// Generate the minified JSON and send it to the Serial port
|
||||||
//
|
|
||||||
serializeJson(doc, Serial);
|
serializeJson(doc, Serial);
|
||||||
// The above line prints:
|
// The above line prints:
|
||||||
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
|
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
|
||||||
@ -45,8 +34,7 @@ void setup() {
|
|||||||
// Start a new line
|
// Start a new line
|
||||||
Serial.println();
|
Serial.println();
|
||||||
|
|
||||||
// Generate the prettified JSON and send it to the Serial port.
|
// Generate the prettified JSON and send it to the Serial port
|
||||||
//
|
|
||||||
serializeJsonPretty(doc, Serial);
|
serializeJsonPretty(doc, Serial);
|
||||||
// The above line prints:
|
// The above line prints:
|
||||||
// {
|
// {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
//
|
//
|
||||||
// This example shows how to parse a JSON document in an HTTP response.
|
// This example shows how to parse a JSON document in an HTTP response.
|
||||||
@ -16,7 +16,7 @@
|
|||||||
// ]
|
// ]
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// https://arduinojson.org/v6/example/http-client/
|
// https://arduinojson.org/v7/example/http-client/
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <Ethernet.h>
|
#include <Ethernet.h>
|
||||||
@ -25,7 +25,8 @@
|
|||||||
void setup() {
|
void setup() {
|
||||||
// Initialize Serial port
|
// Initialize Serial port
|
||||||
Serial.begin(9600);
|
Serial.begin(9600);
|
||||||
while (!Serial) continue;
|
while (!Serial)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Initialize Ethernet library
|
// Initialize Ethernet library
|
||||||
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
|
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
|
||||||
@ -77,9 +78,7 @@ void setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allocate the JSON document
|
// Allocate the JSON document
|
||||||
// Use https://arduinojson.org/v6/assistant to compute the capacity.
|
JsonDocument doc;
|
||||||
const size_t capacity = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 60;
|
|
||||||
DynamicJsonDocument doc(capacity);
|
|
||||||
|
|
||||||
// Parse JSON object
|
// Parse JSON object
|
||||||
DeserializationError error = deserializeJson(doc, client);
|
DeserializationError error = deserializeJson(doc, client);
|
||||||
@ -109,7 +108,7 @@ void loop() {
|
|||||||
// ------------------
|
// ------------------
|
||||||
//
|
//
|
||||||
// EthernetClient is an unbuffered stream, which is not optimal for ArduinoJson.
|
// EthernetClient is an unbuffered stream, which is not optimal for ArduinoJson.
|
||||||
// See: https://arduinojson.org/v6/how-to/improve-speed/
|
// See: https://arduinojson.org/v7/how-to/improve-speed/
|
||||||
|
|
||||||
// See also
|
// See also
|
||||||
// --------
|
// --------
|
||||||
|
|||||||
@ -1,52 +1,37 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
//
|
//
|
||||||
// This example shows how to deserialize a JSON document with ArduinoJson.
|
// This example shows how to deserialize a JSON document with ArduinoJson.
|
||||||
//
|
//
|
||||||
// https://arduinojson.org/v6/example/parser/
|
// https://arduinojson.org/v7/example/parser/
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
// Initialize serial port
|
// Initialize serial port
|
||||||
Serial.begin(9600);
|
Serial.begin(9600);
|
||||||
while (!Serial) continue;
|
while (!Serial)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Allocate the JSON document
|
// Allocate the JSON document
|
||||||
//
|
JsonDocument doc;
|
||||||
// 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.
|
// JSON input string.
|
||||||
//
|
const char* json =
|
||||||
// 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]}";
|
"{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
|
||||||
|
|
||||||
// Deserialize the JSON document
|
// Deserialize the JSON document
|
||||||
DeserializationError error = deserializeJson(doc, json);
|
DeserializationError error = deserializeJson(doc, json);
|
||||||
|
|
||||||
// Test if parsing succeeds.
|
// Test if parsing succeeds
|
||||||
if (error) {
|
if (error) {
|
||||||
Serial.print(F("deserializeJson() failed: "));
|
Serial.print(F("deserializeJson() failed: "));
|
||||||
Serial.println(error.f_str());
|
Serial.println(error.f_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch values.
|
// Fetch the values
|
||||||
//
|
//
|
||||||
// Most of the time, you can rely on the implicit casts.
|
// Most of the time, you can rely on the implicit casts.
|
||||||
// In other case, you can do doc["time"].as<long>();
|
// In other case, you can do doc["time"].as<long>();
|
||||||
@ -55,7 +40,7 @@ void setup() {
|
|||||||
double latitude = doc["data"][0];
|
double latitude = doc["data"][0];
|
||||||
double longitude = doc["data"][1];
|
double longitude = doc["data"][1];
|
||||||
|
|
||||||
// Print values.
|
// Print the values
|
||||||
Serial.println(sensor);
|
Serial.println(sensor);
|
||||||
Serial.println(time);
|
Serial.println(time);
|
||||||
Serial.println(latitude, 6);
|
Serial.println(latitude, 6);
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
//
|
//
|
||||||
// This example shows how to implement an HTTP server that sends a JSON document
|
// This example shows how to implement an HTTP server that sends a JSON document
|
||||||
@ -13,7 +13,7 @@
|
|||||||
// "digital": [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0]
|
// "digital": [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0]
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// https://arduinojson.org/v6/example/http-server/
|
// https://arduinojson.org/v7/example/http-server/
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <Ethernet.h>
|
#include <Ethernet.h>
|
||||||
@ -25,7 +25,8 @@ EthernetServer server(80);
|
|||||||
void setup() {
|
void setup() {
|
||||||
// Initialize serial port
|
// Initialize serial port
|
||||||
Serial.begin(9600);
|
Serial.begin(9600);
|
||||||
while (!Serial) continue;
|
while (!Serial)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Initialize Ethernet libary
|
// Initialize Ethernet libary
|
||||||
if (!Ethernet.begin(mac)) {
|
if (!Ethernet.begin(mac)) {
|
||||||
@ -52,14 +53,14 @@ void loop() {
|
|||||||
Serial.println(F("New client"));
|
Serial.println(F("New client"));
|
||||||
|
|
||||||
// Read the request (we ignore the content in this example)
|
// Read the request (we ignore the content in this example)
|
||||||
while (client.available()) client.read();
|
while (client.available())
|
||||||
|
client.read();
|
||||||
|
|
||||||
// Allocate a temporary JsonDocument
|
// Allocate a temporary JsonDocument
|
||||||
// Use https://arduinojson.org/v6/assistant to compute the capacity.
|
JsonDocument doc;
|
||||||
StaticJsonDocument<500> doc;
|
|
||||||
|
|
||||||
// Create the "analog" array
|
// Create the "analog" array
|
||||||
JsonArray analogValues = doc.createNestedArray("analog");
|
JsonArray analogValues = doc["analog"].to<JsonArray>();
|
||||||
for (int pin = 0; pin < 6; pin++) {
|
for (int pin = 0; pin < 6; pin++) {
|
||||||
// Read the analog input
|
// Read the analog input
|
||||||
int value = analogRead(pin);
|
int value = analogRead(pin);
|
||||||
@ -69,7 +70,7 @@ void loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the "digital" array
|
// Create the "digital" array
|
||||||
JsonArray digitalValues = doc.createNestedArray("digital");
|
JsonArray digitalValues = doc["digital"].to<JsonArray>();
|
||||||
for (int pin = 0; pin < 14; pin++) {
|
for (int pin = 0; pin < 14; pin++) {
|
||||||
// Read the digital input
|
// Read the digital input
|
||||||
int value = digitalRead(pin);
|
int value = digitalRead(pin);
|
||||||
@ -101,7 +102,7 @@ void loop() {
|
|||||||
// ------------------
|
// ------------------
|
||||||
//
|
//
|
||||||
// EthernetClient is an unbuffered stream, which is not optimal for ArduinoJson.
|
// EthernetClient is an unbuffered stream, which is not optimal for ArduinoJson.
|
||||||
// See: https://arduinojson.org/v6/how-to/improve-speed/
|
// See: https://arduinojson.org/v7/how-to/improve-speed/
|
||||||
|
|
||||||
// See also
|
// See also
|
||||||
// --------
|
// --------
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
//
|
//
|
||||||
// This example shows how to send a JSON document to a UDP socket.
|
// This example shows how to send a JSON document to a UDP socket.
|
||||||
@ -17,7 +17,7 @@
|
|||||||
// $ ncat -ulp 8888
|
// $ ncat -ulp 8888
|
||||||
// See https://nmap.org/ncat/
|
// See https://nmap.org/ncat/
|
||||||
//
|
//
|
||||||
// https://arduinojson.org/v6/example/udp-beacon/
|
// https://arduinojson.org/v7/example/udp-beacon/
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <Ethernet.h>
|
#include <Ethernet.h>
|
||||||
@ -32,7 +32,8 @@ EthernetUDP udp;
|
|||||||
void setup() {
|
void setup() {
|
||||||
// Initialize serial port
|
// Initialize serial port
|
||||||
Serial.begin(9600);
|
Serial.begin(9600);
|
||||||
while (!Serial) continue;
|
while (!Serial)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Initialize Ethernet libary
|
// Initialize Ethernet libary
|
||||||
if (!Ethernet.begin(mac)) {
|
if (!Ethernet.begin(mac)) {
|
||||||
@ -46,11 +47,10 @@ void setup() {
|
|||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
// Allocate a temporary JsonDocument
|
// Allocate a temporary JsonDocument
|
||||||
// Use https://arduinojson.org/v6/assistant to compute the capacity.
|
JsonDocument doc;
|
||||||
StaticJsonDocument<500> doc;
|
|
||||||
|
|
||||||
// Create the "analog" array
|
// Create the "analog" array
|
||||||
JsonArray analogValues = doc.createNestedArray("analog");
|
JsonArray analogValues = doc["analog"].to<JsonArray>();
|
||||||
for (int pin = 0; pin < 6; pin++) {
|
for (int pin = 0; pin < 6; pin++) {
|
||||||
// Read the analog input
|
// Read the analog input
|
||||||
int value = analogRead(pin);
|
int value = analogRead(pin);
|
||||||
@ -60,7 +60,7 @@ void loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the "digital" array
|
// Create the "digital" array
|
||||||
JsonArray digitalValues = doc.createNestedArray("digital");
|
JsonArray digitalValues = doc["digital"].to<JsonArray>();
|
||||||
for (int pin = 0; pin < 14; pin++) {
|
for (int pin = 0; pin < 14; pin++) {
|
||||||
// Read the digital input
|
// Read the digital input
|
||||||
int value = digitalRead(pin);
|
int value = digitalRead(pin);
|
||||||
@ -90,7 +90,7 @@ void loop() {
|
|||||||
// ------------------
|
// ------------------
|
||||||
//
|
//
|
||||||
// EthernetUDP is an unbuffered stream, which is not optimal for ArduinoJson.
|
// EthernetUDP is an unbuffered stream, which is not optimal for ArduinoJson.
|
||||||
// See: https://arduinojson.org/v6/how-to/improve-speed/
|
// See: https://arduinojson.org/v7/how-to/improve-speed/
|
||||||
|
|
||||||
// See also
|
// See also
|
||||||
// --------
|
// --------
|
||||||
|
|||||||
@ -1,39 +1,24 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
//
|
//
|
||||||
// This example shows how to deserialize a MessagePack document with
|
// This example shows how to deserialize a MessagePack document with
|
||||||
// ArduinoJson.
|
// ArduinoJson.
|
||||||
//
|
//
|
||||||
// https://arduinojson.org/v6/example/msgpack-parser/
|
// https://arduinojson.org/v7/example/msgpack-parser/
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
// Initialize serial port
|
// Initialize serial port
|
||||||
Serial.begin(9600);
|
Serial.begin(9600);
|
||||||
while (!Serial) continue;
|
while (!Serial)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Allocate the JSON document
|
// Allocate the JSON document
|
||||||
//
|
JsonDocument doc;
|
||||||
// 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
|
// The MessagePack input string
|
||||||
// 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,
|
uint8_t input[] = {131, 166, 115, 101, 110, 115, 111, 114, 163, 103, 112, 115,
|
||||||
164, 116, 105, 109, 101, 206, 80, 147, 50, 248, 164, 100,
|
164, 116, 105, 109, 101, 206, 80, 147, 50, 248, 164, 100,
|
||||||
97, 116, 97, 146, 203, 64, 72, 96, 199, 58, 188, 148,
|
97, 116, 97, 146, 203, 64, 72, 96, 199, 58, 188, 148,
|
||||||
@ -45,16 +30,17 @@ void setup() {
|
|||||||
// "data": [48.75608, 2.302038]
|
// "data": [48.75608, 2.302038]
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// Parse the input
|
||||||
DeserializationError error = deserializeMsgPack(doc, input);
|
DeserializationError error = deserializeMsgPack(doc, input);
|
||||||
|
|
||||||
// Test if parsing succeeded.
|
// Test if parsing succeeded
|
||||||
if (error) {
|
if (error) {
|
||||||
Serial.print("deserializeMsgPack() failed: ");
|
Serial.print("deserializeMsgPack() failed: ");
|
||||||
Serial.println(error.f_str());
|
Serial.println(error.f_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch values.
|
// Fetch the values
|
||||||
//
|
//
|
||||||
// Most of the time, you can rely on the implicit casts.
|
// Most of the time, you can rely on the implicit casts.
|
||||||
// In other case, you can do doc["time"].as<long>();
|
// In other case, you can do doc["time"].as<long>();
|
||||||
@ -63,7 +49,7 @@ void setup() {
|
|||||||
double latitude = doc["data"][0];
|
double latitude = doc["data"][0];
|
||||||
double longitude = doc["data"][1];
|
double longitude = doc["data"][1];
|
||||||
|
|
||||||
// Print values.
|
// Print the values
|
||||||
Serial.println(sensor);
|
Serial.println(sensor);
|
||||||
Serial.println(time);
|
Serial.println(time);
|
||||||
Serial.println(latitude, 6);
|
Serial.println(latitude, 6);
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
//
|
//
|
||||||
// This example shows the different ways you can use Flash strings with
|
// This example shows the different ways you can use Flash strings with
|
||||||
@ -9,12 +9,12 @@
|
|||||||
// JsonDocument. Prefer plain old char*, as they are more efficient in term of
|
// JsonDocument. Prefer plain old char*, as they are more efficient in term of
|
||||||
// code size, speed, and memory usage.
|
// code size, speed, and memory usage.
|
||||||
//
|
//
|
||||||
// https://arduinojson.org/v6/example/progmem/
|
// https://arduinojson.org/v7/example/progmem/
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
DynamicJsonDocument doc(1024);
|
JsonDocument doc;
|
||||||
|
|
||||||
// You can use a Flash String as your JSON input.
|
// You can use a Flash String as your JSON input.
|
||||||
// WARNING: the strings in the input will be duplicated in the JsonDocument.
|
// WARNING: the strings in the input will be duplicated in the JsonDocument.
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
//
|
//
|
||||||
// This example shows the different ways you can use String with ArduinoJson.
|
// This example shows the different ways you can use String with ArduinoJson.
|
||||||
@ -8,12 +8,12 @@
|
|||||||
// JsonDocument. Prefer plain old char[], as they are more efficient in term of
|
// JsonDocument. Prefer plain old char[], as they are more efficient in term of
|
||||||
// code size, speed, and memory usage.
|
// code size, speed, and memory usage.
|
||||||
//
|
//
|
||||||
// https://arduinojson.org/v6/example/string/
|
// https://arduinojson.org/v7/example/string/
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
DynamicJsonDocument doc(1024);
|
JsonDocument doc;
|
||||||
|
|
||||||
// You can use a String as your JSON input.
|
// You can use a String as your JSON input.
|
||||||
// WARNING: the string in the input will be duplicated in the JsonDocument.
|
// WARNING: the string in the input will be duplicated in the JsonDocument.
|
||||||
@ -55,7 +55,6 @@ void setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Lastly, you can print the resulting JSON to a String
|
// Lastly, you can print the resulting JSON to a String
|
||||||
// WARNING: it doesn't replace the content but appends to it
|
|
||||||
String output;
|
String output;
|
||||||
serializeJson(doc, output);
|
serializeJson(doc, output);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "ArduinoJson",
|
"name": "ArduinoJson",
|
||||||
"keywords": "json, rest, http, web",
|
"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.",
|
"description": "A simple and efficient JSON library for embedded C++. ⭐ 6953 stars on GitHub! Supports serialization, deserialization, MessagePack, streams, filtering, and more. Fully tested and documented.",
|
||||||
"homepage": "https://arduinojson.org/?utm_source=meta&utm_medium=library.json",
|
"homepage": "https://arduinojson.org/?utm_source=meta&utm_medium=library.json",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/bblanchon/ArduinoJson.git"
|
"url": "https://github.com/bblanchon/ArduinoJson.git"
|
||||||
},
|
},
|
||||||
"version": "6.21.5",
|
"version": "7.4.2",
|
||||||
"authors": {
|
"authors": {
|
||||||
"name": "Benoit Blanchon",
|
"name": "Benoit Blanchon",
|
||||||
"url": "https://blog.benoitblanchon.fr"
|
"url": "https://blog.benoitblanchon.fr"
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
name=ArduinoJson
|
name=ArduinoJson
|
||||||
version=6.21.5
|
version=7.4.2
|
||||||
author=Benoit Blanchon <blog.benoitblanchon.fr>
|
author=Benoit Blanchon <blog.benoitblanchon.fr>
|
||||||
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
|
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
|
||||||
sentence=A simple and efficient JSON library for embedded C++.
|
sentence=A simple and efficient JSON library for embedded C++.
|
||||||
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.
|
paragraph=⭐ 6953 stars on GitHub! Supports serialization, deserialization, MessagePack, streams, filtering, and more. Fully tested and documented.
|
||||||
category=Data Processing
|
category=Data Processing
|
||||||
url=https://arduinojson.org/?utm_source=meta&utm_medium=library.properties
|
url=https://arduinojson.org/?utm_source=meta&utm_medium=library.properties
|
||||||
architectures=*
|
architectures=*
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -26,27 +26,40 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Remove true and false macros defined by some cores, such as Arduino Due's
|
||||||
|
// See issues #2181 and arduino/ArduinoCore-sam#50
|
||||||
|
#ifdef true
|
||||||
|
# undef true
|
||||||
|
#endif
|
||||||
|
#ifdef false
|
||||||
|
# undef false
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "ArduinoJson/Array/JsonArray.hpp"
|
#include "ArduinoJson/Array/JsonArray.hpp"
|
||||||
#include "ArduinoJson/Object/JsonObject.hpp"
|
#include "ArduinoJson/Object/JsonObject.hpp"
|
||||||
#include "ArduinoJson/Variant/JsonVariantConst.hpp"
|
#include "ArduinoJson/Variant/JsonVariantConst.hpp"
|
||||||
|
|
||||||
#include "ArduinoJson/Document/DynamicJsonDocument.hpp"
|
#include "ArduinoJson/Document/JsonDocument.hpp"
|
||||||
#include "ArduinoJson/Document/StaticJsonDocument.hpp"
|
|
||||||
|
|
||||||
|
#include "ArduinoJson/Array/ArrayImpl.hpp"
|
||||||
#include "ArduinoJson/Array/ElementProxy.hpp"
|
#include "ArduinoJson/Array/ElementProxy.hpp"
|
||||||
#include "ArduinoJson/Array/JsonArrayImpl.hpp"
|
|
||||||
#include "ArduinoJson/Array/Utilities.hpp"
|
#include "ArduinoJson/Array/Utilities.hpp"
|
||||||
#include "ArduinoJson/Collection/CollectionImpl.hpp"
|
#include "ArduinoJson/Collection/CollectionImpl.hpp"
|
||||||
#include "ArduinoJson/Object/JsonObjectImpl.hpp"
|
#include "ArduinoJson/Memory/ResourceManagerImpl.hpp"
|
||||||
#include "ArduinoJson/Object/MemberProxy.hpp"
|
#include "ArduinoJson/Object/MemberProxy.hpp"
|
||||||
|
#include "ArduinoJson/Object/ObjectImpl.hpp"
|
||||||
#include "ArduinoJson/Variant/ConverterImpl.hpp"
|
#include "ArduinoJson/Variant/ConverterImpl.hpp"
|
||||||
|
#include "ArduinoJson/Variant/JsonVariantCopier.hpp"
|
||||||
#include "ArduinoJson/Variant/VariantCompare.hpp"
|
#include "ArduinoJson/Variant/VariantCompare.hpp"
|
||||||
#include "ArduinoJson/Variant/VariantImpl.hpp"
|
#include "ArduinoJson/Variant/VariantImpl.hpp"
|
||||||
|
#include "ArduinoJson/Variant/VariantRefBaseImpl.hpp"
|
||||||
|
|
||||||
#include "ArduinoJson/Json/JsonDeserializer.hpp"
|
#include "ArduinoJson/Json/JsonDeserializer.hpp"
|
||||||
#include "ArduinoJson/Json/JsonSerializer.hpp"
|
#include "ArduinoJson/Json/JsonSerializer.hpp"
|
||||||
#include "ArduinoJson/Json/PrettyJsonSerializer.hpp"
|
#include "ArduinoJson/Json/PrettyJsonSerializer.hpp"
|
||||||
|
#include "ArduinoJson/MsgPack/MsgPackBinary.hpp"
|
||||||
#include "ArduinoJson/MsgPack/MsgPackDeserializer.hpp"
|
#include "ArduinoJson/MsgPack/MsgPackDeserializer.hpp"
|
||||||
|
#include "ArduinoJson/MsgPack/MsgPackExtension.hpp"
|
||||||
#include "ArduinoJson/MsgPack/MsgPackSerializer.hpp"
|
#include "ArduinoJson/MsgPack/MsgPackSerializer.hpp"
|
||||||
|
|
||||||
#include "ArduinoJson/compatibility.hpp"
|
#include "ArduinoJson/compatibility.hpp"
|
||||||
|
|||||||
@ -0,0 +1,66 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Collection/CollectionData.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
class ArrayData : public CollectionData {
|
||||||
|
public:
|
||||||
|
VariantData* addElement(ResourceManager* resources);
|
||||||
|
|
||||||
|
static VariantData* addElement(ArrayData* array, ResourceManager* resources) {
|
||||||
|
if (!array)
|
||||||
|
return nullptr;
|
||||||
|
return array->addElement(resources);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool addValue(const T& value, ResourceManager* resources);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static bool addValue(ArrayData* array, const T& value,
|
||||||
|
ResourceManager* resources) {
|
||||||
|
if (!array)
|
||||||
|
return false;
|
||||||
|
return array->addValue(value, resources);
|
||||||
|
}
|
||||||
|
|
||||||
|
VariantData* getOrAddElement(size_t index, ResourceManager* resources);
|
||||||
|
|
||||||
|
VariantData* getElement(size_t index, const ResourceManager* resources) const;
|
||||||
|
|
||||||
|
static VariantData* getElement(const ArrayData* array, size_t index,
|
||||||
|
const ResourceManager* resources) {
|
||||||
|
if (!array)
|
||||||
|
return nullptr;
|
||||||
|
return array->getElement(index, resources);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeElement(size_t index, ResourceManager* resources);
|
||||||
|
|
||||||
|
static void removeElement(ArrayData* array, size_t index,
|
||||||
|
ResourceManager* resources) {
|
||||||
|
if (!array)
|
||||||
|
return;
|
||||||
|
array->removeElement(index, resources);
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(iterator it, ResourceManager* resources) {
|
||||||
|
CollectionData::removeOne(it, resources);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remove(ArrayData* array, iterator it,
|
||||||
|
ResourceManager* resources) {
|
||||||
|
if (array)
|
||||||
|
return array->remove(it, resources);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
iterator at(size_t index, const ResourceManager* resources) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
@ -0,0 +1,79 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Array/ArrayData.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantCompare.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
inline ArrayData::iterator ArrayData::at(
|
||||||
|
size_t index, const ResourceManager* resources) const {
|
||||||
|
auto it = createIterator(resources);
|
||||||
|
while (!it.done() && index) {
|
||||||
|
it.next(resources);
|
||||||
|
--index;
|
||||||
|
}
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VariantData* ArrayData::addElement(ResourceManager* resources) {
|
||||||
|
auto slot = resources->allocVariant();
|
||||||
|
if (!slot)
|
||||||
|
return nullptr;
|
||||||
|
CollectionData::appendOne(slot, resources);
|
||||||
|
return slot.ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VariantData* ArrayData::getOrAddElement(size_t index,
|
||||||
|
ResourceManager* resources) {
|
||||||
|
auto it = createIterator(resources);
|
||||||
|
while (!it.done() && index > 0) {
|
||||||
|
it.next(resources);
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
if (it.done())
|
||||||
|
index++;
|
||||||
|
VariantData* element = it.data();
|
||||||
|
while (index > 0) {
|
||||||
|
element = addElement(resources);
|
||||||
|
if (!element)
|
||||||
|
return nullptr;
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VariantData* ArrayData::getElement(
|
||||||
|
size_t index, const ResourceManager* resources) const {
|
||||||
|
return at(index, resources).data();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ArrayData::removeElement(size_t index, ResourceManager* resources) {
|
||||||
|
remove(at(index, resources), resources);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline bool ArrayData::addValue(const T& value, ResourceManager* resources) {
|
||||||
|
ARDUINOJSON_ASSERT(resources != nullptr);
|
||||||
|
auto slot = resources->allocVariant();
|
||||||
|
if (!slot)
|
||||||
|
return false;
|
||||||
|
JsonVariant variant(slot.ptr(), resources);
|
||||||
|
if (!variant.set(value)) {
|
||||||
|
resources->freeVariant(slot);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CollectionData::appendOne(slot, resources);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the size (in bytes) of an array with n elements.
|
||||||
|
constexpr size_t sizeofArray(size_t n) {
|
||||||
|
return n * ResourceManager::slotSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -9,48 +9,63 @@
|
|||||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
// A proxy class to get or set an element of an array.
|
// A proxy class to get or set an element of an array.
|
||||||
// https://arduinojson.org/v6/api/jsonarray/subscript/
|
// https://arduinojson.org/v7/api/jsonarray/subscript/
|
||||||
template <typename TUpstream>
|
template <typename TUpstream>
|
||||||
class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>,
|
class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>,
|
||||||
public VariantOperators<ElementProxy<TUpstream>> {
|
public VariantOperators<ElementProxy<TUpstream>> {
|
||||||
friend class VariantAttorney;
|
friend class VariantAttorney;
|
||||||
|
|
||||||
|
friend class VariantRefBase<ElementProxy<TUpstream>>;
|
||||||
|
|
||||||
|
template <typename, typename>
|
||||||
|
friend class MemberProxy;
|
||||||
|
|
||||||
|
template <typename>
|
||||||
|
friend class ElementProxy;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ElementProxy(TUpstream upstream, size_t index)
|
ElementProxy(TUpstream upstream, size_t index)
|
||||||
: upstream_(upstream), index_(index) {}
|
: upstream_(upstream), index_(index) {}
|
||||||
|
|
||||||
ElementProxy(const ElementProxy& src)
|
ElementProxy& operator=(const ElementProxy& src) {
|
||||||
: upstream_(src.upstream_), index_(src.index_) {}
|
|
||||||
|
|
||||||
FORCE_INLINE ElementProxy& operator=(const ElementProxy& src) {
|
|
||||||
this->set(src);
|
this->set(src);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
FORCE_INLINE ElementProxy& operator=(const T& src) {
|
ElementProxy& operator=(const T& src) {
|
||||||
this->set(src);
|
this->set(src);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
FORCE_INLINE ElementProxy& operator=(T* src) {
|
ElementProxy& operator=(T* src) {
|
||||||
this->set(src);
|
this->set(src);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FORCE_INLINE MemoryPool* getPool() const {
|
// clang-format off
|
||||||
return VariantAttorney::getPool(upstream_);
|
ElementProxy(const ElementProxy& src) // Error here? See https://arduinojson.org/v7/proxy-non-copyable/
|
||||||
|
: upstream_(src.upstream_), index_(src.index_) {}
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
ResourceManager* getResourceManager() const {
|
||||||
|
return VariantAttorney::getResourceManager(upstream_);
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE VariantData* getData() const {
|
FORCE_INLINE VariantData* getData() const {
|
||||||
return variantGetElement(VariantAttorney::getData(upstream_), index_);
|
return VariantData::getElement(
|
||||||
|
VariantAttorney::getData(upstream_), index_,
|
||||||
|
VariantAttorney::getResourceManager(upstream_));
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE VariantData* getOrCreateData() const {
|
VariantData* getOrCreateData() const {
|
||||||
return variantGetOrAddElement(VariantAttorney::getOrCreateData(upstream_),
|
auto data = VariantAttorney::getOrCreateData(upstream_);
|
||||||
index_, VariantAttorney::getPool(upstream_));
|
if (!data)
|
||||||
|
return nullptr;
|
||||||
|
return data->getOrAddElement(
|
||||||
|
index_, VariantAttorney::getResourceManager(upstream_));
|
||||||
}
|
}
|
||||||
|
|
||||||
TUpstream upstream_;
|
TUpstream upstream_;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -12,163 +12,196 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
|||||||
class JsonObject;
|
class JsonObject;
|
||||||
|
|
||||||
// A reference to an array in a JsonDocument
|
// A reference to an array in a JsonDocument
|
||||||
// https://arduinojson.org/v6/api/jsonarray/
|
// https://arduinojson.org/v7/api/jsonarray/
|
||||||
class JsonArray : public detail::VariantOperators<JsonArray> {
|
class JsonArray : public detail::VariantOperators<JsonArray> {
|
||||||
friend class detail::VariantAttorney;
|
friend class detail::VariantAttorney;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef JsonArrayIterator iterator;
|
using iterator = JsonArrayIterator;
|
||||||
|
|
||||||
// Constructs an unbound reference.
|
// Constructs an unbound reference.
|
||||||
FORCE_INLINE JsonArray() : data_(0), pool_(0) {}
|
JsonArray() : data_(0), resources_(0) {}
|
||||||
|
|
||||||
// INTERNAL USE ONLY
|
// INTERNAL USE ONLY
|
||||||
FORCE_INLINE JsonArray(detail::MemoryPool* pool, detail::CollectionData* data)
|
JsonArray(detail::ArrayData* data, detail::ResourceManager* resources)
|
||||||
: data_(data), pool_(pool) {}
|
: data_(data), resources_(resources) {}
|
||||||
|
|
||||||
// Returns a JsonVariant pointing to the array.
|
// Returns a JsonVariant pointing to the array.
|
||||||
// https://arduinojson.org/v6/api/jsonvariant/
|
// https://arduinojson.org/v7/api/jsonvariant/
|
||||||
operator JsonVariant() {
|
operator JsonVariant() {
|
||||||
void* data = data_; // prevent warning cast-align
|
void* data = data_; // prevent warning cast-align
|
||||||
return JsonVariant(pool_, reinterpret_cast<detail::VariantData*>(data));
|
return JsonVariant(reinterpret_cast<detail::VariantData*>(data),
|
||||||
|
resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a read-only reference to the array.
|
// Returns a read-only reference to the array.
|
||||||
// https://arduinojson.org/v6/api/jsonarrayconst/
|
// https://arduinojson.org/v7/api/jsonarrayconst/
|
||||||
operator JsonArrayConst() const {
|
operator JsonArrayConst() const {
|
||||||
return JsonArrayConst(data_);
|
return JsonArrayConst(data_, resources_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Appends a new (empty) element to the array.
|
||||||
|
// Returns a reference to the new element.
|
||||||
|
// https://arduinojson.org/v7/api/jsonarray/add/
|
||||||
|
template <typename T, detail::enable_if_t<
|
||||||
|
!detail::is_same<T, JsonVariant>::value, int> = 0>
|
||||||
|
T add() const {
|
||||||
|
return add<JsonVariant>().to<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Appends a new (null) element to the array.
|
// Appends a new (null) element to the array.
|
||||||
// Returns a reference to the new element.
|
// Returns a reference to the new element.
|
||||||
// https://arduinojson.org/v6/api/jsonarray/add/
|
// https://arduinojson.org/v7/api/jsonarray/add/
|
||||||
|
template <typename T, detail::enable_if_t<
|
||||||
|
detail::is_same<T, JsonVariant>::value, int> = 0>
|
||||||
JsonVariant add() const {
|
JsonVariant add() const {
|
||||||
if (!data_)
|
return JsonVariant(detail::ArrayData::addElement(data_, resources_),
|
||||||
return JsonVariant();
|
resources_);
|
||||||
return JsonVariant(pool_, data_->addElement(pool_));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Appends a value to the array.
|
// Appends a value to the array.
|
||||||
// https://arduinojson.org/v6/api/jsonarray/add/
|
// https://arduinojson.org/v7/api/jsonarray/add/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
FORCE_INLINE bool add(const T& value) const {
|
bool add(const T& value) const {
|
||||||
return add().set(value);
|
return detail::ArrayData::addValue(data_, value, resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Appends a value to the array.
|
// Appends a value to the array.
|
||||||
// https://arduinojson.org/v6/api/jsonarray/add/
|
// https://arduinojson.org/v7/api/jsonarray/add/
|
||||||
template <typename T>
|
template <typename T,
|
||||||
FORCE_INLINE bool add(T* value) const {
|
detail::enable_if_t<!detail::is_const<T>::value, int> = 0>
|
||||||
return add().set(value);
|
bool add(T* value) const {
|
||||||
|
return detail::ArrayData::addValue(data_, value, resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns an iterator to the first element of the array.
|
// Returns an iterator to the first element of the array.
|
||||||
// https://arduinojson.org/v6/api/jsonarray/begin/
|
// https://arduinojson.org/v7/api/jsonarray/begin/
|
||||||
FORCE_INLINE iterator begin() const {
|
iterator begin() const {
|
||||||
if (!data_)
|
if (!data_)
|
||||||
return iterator();
|
return iterator();
|
||||||
return iterator(pool_, data_->head());
|
return iterator(data_->createIterator(resources_), resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns an iterator following the last element of the array.
|
// Returns an iterator following the last element of the array.
|
||||||
// https://arduinojson.org/v6/api/jsonarray/end/
|
// https://arduinojson.org/v7/api/jsonarray/end/
|
||||||
FORCE_INLINE iterator end() const {
|
iterator end() const {
|
||||||
return iterator();
|
return iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copies an array.
|
// Copies an array.
|
||||||
// https://arduinojson.org/v6/api/jsonarray/set/
|
// https://arduinojson.org/v7/api/jsonarray/set/
|
||||||
FORCE_INLINE bool set(JsonArrayConst src) const {
|
bool set(JsonArrayConst src) const {
|
||||||
if (!data_ || !src.data_)
|
if (!data_)
|
||||||
return false;
|
return false;
|
||||||
return data_->copyFrom(*src.data_, pool_);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compares the content of two arrays.
|
clear();
|
||||||
FORCE_INLINE bool operator==(JsonArray rhs) const {
|
for (auto element : src) {
|
||||||
return JsonArrayConst(data_) == JsonArrayConst(rhs.data_);
|
if (!add(element))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes the element at the specified iterator.
|
// Removes the element at the specified iterator.
|
||||||
// ⚠️ Doesn't release the memory associated with the removed element.
|
// https://arduinojson.org/v7/api/jsonarray/remove/
|
||||||
// https://arduinojson.org/v6/api/jsonarray/remove/
|
void remove(iterator it) const {
|
||||||
FORCE_INLINE void remove(iterator it) const {
|
detail::ArrayData::remove(data_, it.iterator_, resources_);
|
||||||
if (!data_)
|
|
||||||
return;
|
|
||||||
data_->removeSlot(it.slot_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes the element at the specified index.
|
// Removes the element at the specified index.
|
||||||
// ⚠️ Doesn't release the memory associated with the removed element.
|
// https://arduinojson.org/v7/api/jsonarray/remove/
|
||||||
// https://arduinojson.org/v6/api/jsonarray/remove/
|
void remove(size_t index) const {
|
||||||
FORCE_INLINE void remove(size_t index) const {
|
detail::ArrayData::removeElement(data_, index, resources_);
|
||||||
if (!data_)
|
}
|
||||||
return;
|
|
||||||
data_->removeElement(index);
|
// Removes the element at the specified index.
|
||||||
|
// https://arduinojson.org/v7/api/jsonarray/remove/
|
||||||
|
template <typename TVariant,
|
||||||
|
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||||
|
void remove(const TVariant& variant) const {
|
||||||
|
if (variant.template is<size_t>())
|
||||||
|
remove(variant.template as<size_t>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes all the elements of the array.
|
// Removes all the elements of the array.
|
||||||
// ⚠️ Doesn't release the memory associated with the removed elements.
|
// https://arduinojson.org/v7/api/jsonarray/clear/
|
||||||
// https://arduinojson.org/v6/api/jsonarray/clear/
|
|
||||||
void clear() const {
|
void clear() const {
|
||||||
if (!data_)
|
detail::ArrayData::clear(data_, resources_);
|
||||||
return;
|
|
||||||
data_->clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets or sets the element at the specified index.
|
// Gets or sets the element at the specified index.
|
||||||
// https://arduinojson.org/v6/api/jsonarray/subscript/
|
// https://arduinojson.org/v7/api/jsonarray/subscript/
|
||||||
FORCE_INLINE detail::ElementProxy<JsonArray> operator[](size_t index) const {
|
template <typename T,
|
||||||
return {*this, index};
|
detail::enable_if_t<detail::is_integral<T>::value, int> = 0>
|
||||||
|
detail::ElementProxy<JsonArray> operator[](T index) const {
|
||||||
|
return {*this, size_t(index)};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates an object and appends it to the array.
|
// Gets or sets the element at the specified index.
|
||||||
// https://arduinojson.org/v6/api/jsonarray/createnestedobject/
|
// https://arduinojson.org/v7/api/jsonarray/subscript/
|
||||||
FORCE_INLINE JsonObject createNestedObject() const;
|
template <typename TVariant,
|
||||||
|
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||||
// Creates an array and appends it to the array.
|
detail::ElementProxy<JsonArray> operator[](const TVariant& variant) const {
|
||||||
// https://arduinojson.org/v6/api/jsonarray/createnestedarray/
|
if (variant.template is<size_t>())
|
||||||
FORCE_INLINE JsonArray createNestedArray() const {
|
return {*this, variant.template as<size_t>()};
|
||||||
return add().to<JsonArray>();
|
else
|
||||||
|
return {*this, size_t(-1)};
|
||||||
}
|
}
|
||||||
|
|
||||||
operator JsonVariantConst() const {
|
operator JsonVariantConst() const {
|
||||||
return JsonVariantConst(collectionToVariant(data_));
|
return JsonVariantConst(collectionToVariant(data_), resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the reference is unbound.
|
// Returns true if the reference is unbound.
|
||||||
// https://arduinojson.org/v6/api/jsonarray/isnull/
|
// https://arduinojson.org/v7/api/jsonarray/isnull/
|
||||||
FORCE_INLINE bool isNull() const {
|
bool isNull() const {
|
||||||
return data_ == 0;
|
return data_ == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the reference is bound.
|
// Returns true if the reference is bound.
|
||||||
// https://arduinojson.org/v6/api/jsonarray/isnull/
|
// https://arduinojson.org/v7/api/jsonarray/isnull/
|
||||||
FORCE_INLINE operator bool() const {
|
operator bool() const {
|
||||||
return data_ != 0;
|
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.
|
// Returns the depth (nesting level) of the array.
|
||||||
// https://arduinojson.org/v6/api/jsonarray/nesting/
|
// https://arduinojson.org/v7/api/jsonarray/nesting/
|
||||||
FORCE_INLINE size_t nesting() const {
|
size_t nesting() const {
|
||||||
return variantNesting(collectionToVariant(data_));
|
return detail::VariantData::nesting(collectionToVariant(data_), resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the number of elements in the array.
|
// Returns the number of elements in the array.
|
||||||
// https://arduinojson.org/v6/api/jsonarray/size/
|
// https://arduinojson.org/v7/api/jsonarray/size/
|
||||||
FORCE_INLINE size_t size() const {
|
size_t size() const {
|
||||||
return data_ ? data_->size() : 0;
|
return data_ ? data_->size(resources_) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED: use add<JsonVariant>() instead
|
||||||
|
ARDUINOJSON_DEPRECATED("use add<JsonVariant>() instead")
|
||||||
|
JsonVariant add() const {
|
||||||
|
return add<JsonVariant>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED: use add<JsonArray>() instead
|
||||||
|
ARDUINOJSON_DEPRECATED("use add<JsonArray>() instead")
|
||||||
|
JsonArray createNestedArray() const {
|
||||||
|
return add<JsonArray>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED: use add<JsonObject>() instead
|
||||||
|
ARDUINOJSON_DEPRECATED("use add<JsonObject>() instead")
|
||||||
|
JsonObject createNestedObject() const;
|
||||||
|
|
||||||
|
// DEPRECATED: always returns zero
|
||||||
|
ARDUINOJSON_DEPRECATED("always returns zero")
|
||||||
|
size_t memoryUsage() const {
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
detail::MemoryPool* getPool() const {
|
detail::ResourceManager* getResourceManager() const {
|
||||||
return pool_;
|
return resources_;
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::VariantData* getData() const {
|
detail::VariantData* getData() const {
|
||||||
@ -179,33 +212,8 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
|
|||||||
return collectionToVariant(data_);
|
return collectionToVariant(data_);
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::CollectionData* data_;
|
detail::ArrayData* data_;
|
||||||
detail::MemoryPool* pool_;
|
detail::ResourceManager* resources_;
|
||||||
};
|
|
||||||
|
|
||||||
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
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -13,98 +13,89 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
|||||||
class JsonObject;
|
class JsonObject;
|
||||||
|
|
||||||
// A read-only reference to an array in a JsonDocument
|
// A read-only reference to an array in a JsonDocument
|
||||||
// https://arduinojson.org/v6/api/jsonarrayconst/
|
// https://arduinojson.org/v7/api/jsonarrayconst/
|
||||||
class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
|
class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
|
||||||
friend class JsonArray;
|
friend class JsonArray;
|
||||||
friend class detail::VariantAttorney;
|
friend class detail::VariantAttorney;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef JsonArrayConstIterator iterator;
|
using iterator = JsonArrayConstIterator;
|
||||||
|
|
||||||
// Returns an iterator to the first element of the array.
|
// Returns an iterator to the first element of the array.
|
||||||
// https://arduinojson.org/v6/api/jsonarrayconst/begin/
|
// https://arduinojson.org/v7/api/jsonarrayconst/begin/
|
||||||
FORCE_INLINE iterator begin() const {
|
iterator begin() const {
|
||||||
if (!data_)
|
if (!data_)
|
||||||
return iterator();
|
return iterator();
|
||||||
return iterator(data_->head());
|
return iterator(data_->createIterator(resources_), resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns an iterator to the element following the last element of the array.
|
// Returns an iterator to the element following the last element of the array.
|
||||||
// https://arduinojson.org/v6/api/jsonarrayconst/end/
|
// https://arduinojson.org/v7/api/jsonarrayconst/end/
|
||||||
FORCE_INLINE iterator end() const {
|
iterator end() const {
|
||||||
return iterator();
|
return iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates an unbound reference.
|
// Creates an unbound reference.
|
||||||
FORCE_INLINE JsonArrayConst() : data_(0) {}
|
JsonArrayConst() : data_(0), resources_(0) {}
|
||||||
|
|
||||||
// INTERNAL USE ONLY
|
// INTERNAL USE ONLY
|
||||||
FORCE_INLINE JsonArrayConst(const detail::CollectionData* data)
|
JsonArrayConst(const detail::ArrayData* data,
|
||||||
: data_(data) {}
|
const detail::ResourceManager* resources)
|
||||||
|
: data_(data), resources_(resources) {}
|
||||||
|
|
||||||
// Compares the content of two arrays.
|
// Returns the element at the specified index.
|
||||||
// Returns true if the two arrays are equal.
|
// https://arduinojson.org/v7/api/jsonarrayconst/subscript/
|
||||||
FORCE_INLINE bool operator==(JsonArrayConst rhs) const {
|
template <typename T,
|
||||||
if (data_ == rhs.data_)
|
detail::enable_if_t<detail::is_integral<T>::value, int> = 0>
|
||||||
return true;
|
JsonVariantConst operator[](T index) const {
|
||||||
if (!data_ || !rhs.data_)
|
return JsonVariantConst(
|
||||||
return false;
|
detail::ArrayData::getElement(data_, size_t(index), resources_),
|
||||||
|
resources_);
|
||||||
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.
|
// Returns the element at the specified index.
|
||||||
// https://arduinojson.org/v6/api/jsonarrayconst/subscript/
|
// https://arduinojson.org/v7/api/jsonarrayconst/subscript/
|
||||||
FORCE_INLINE JsonVariantConst operator[](size_t index) const {
|
template <typename TVariant,
|
||||||
return JsonVariantConst(data_ ? data_->getElement(index) : 0);
|
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||||
|
JsonVariantConst operator[](const TVariant& variant) const {
|
||||||
|
if (variant.template is<size_t>())
|
||||||
|
return operator[](variant.template as<size_t>());
|
||||||
|
else
|
||||||
|
return JsonVariantConst();
|
||||||
}
|
}
|
||||||
|
|
||||||
operator JsonVariantConst() const {
|
operator JsonVariantConst() const {
|
||||||
return JsonVariantConst(collectionToVariant(data_));
|
return JsonVariantConst(getData(), resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the reference is unbound.
|
// Returns true if the reference is unbound.
|
||||||
// https://arduinojson.org/v6/api/jsonarrayconst/isnull/
|
// https://arduinojson.org/v7/api/jsonarrayconst/isnull/
|
||||||
FORCE_INLINE bool isNull() const {
|
bool isNull() const {
|
||||||
return data_ == 0;
|
return data_ == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the reference is bound.
|
// Returns true if the reference is bound.
|
||||||
// https://arduinojson.org/v6/api/jsonarrayconst/isnull/
|
// https://arduinojson.org/v7/api/jsonarrayconst/isnull/
|
||||||
FORCE_INLINE operator bool() const {
|
operator bool() const {
|
||||||
return data_ != 0;
|
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.
|
// Returns the depth (nesting level) of the array.
|
||||||
// https://arduinojson.org/v6/api/jsonarrayconst/nesting/
|
// https://arduinojson.org/v7/api/jsonarrayconst/nesting/
|
||||||
FORCE_INLINE size_t nesting() const {
|
size_t nesting() const {
|
||||||
return variantNesting(collectionToVariant(data_));
|
return detail::VariantData::nesting(getData(), resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the number of elements in the array.
|
// Returns the number of elements in the array.
|
||||||
// https://arduinojson.org/v6/api/jsonarrayconst/size/
|
// https://arduinojson.org/v7/api/jsonarrayconst/size/
|
||||||
FORCE_INLINE size_t size() const {
|
size_t size() const {
|
||||||
return data_ ? data_->size() : 0;
|
return data_ ? data_->size(resources_) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED: always returns zero
|
||||||
|
ARDUINOJSON_DEPRECATED("always returns zero")
|
||||||
|
size_t memoryUsage() const {
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -112,24 +103,31 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
|
|||||||
return collectionToVariant(data_);
|
return collectionToVariant(data_);
|
||||||
}
|
}
|
||||||
|
|
||||||
const detail::CollectionData* data_;
|
const detail::ArrayData* data_;
|
||||||
|
const detail::ResourceManager* resources_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
// Compares the content of two arrays.
|
||||||
struct Converter<JsonArrayConst> : private detail::VariantAttorney {
|
// Returns true if the two arrays are equal.
|
||||||
static void toJson(JsonVariantConst src, JsonVariant dst) {
|
inline bool operator==(JsonArrayConst lhs, JsonArrayConst rhs) {
|
||||||
variantCopyFrom(getData(dst), getData(src), getPool(dst));
|
if (!lhs && !rhs)
|
||||||
}
|
return true;
|
||||||
|
if (!lhs || !rhs)
|
||||||
|
return false;
|
||||||
|
|
||||||
static JsonArrayConst fromJson(JsonVariantConst src) {
|
auto a = lhs.begin();
|
||||||
auto data = getData(src);
|
auto b = rhs.begin();
|
||||||
return data ? data->asArray() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool checkJson(JsonVariantConst src) {
|
for (;;) {
|
||||||
auto data = getData(src);
|
if (a == b) // same pointer or both null
|
||||||
return data && data->isArray();
|
return true;
|
||||||
|
if (a == lhs.end() || b == rhs.end())
|
||||||
|
return false;
|
||||||
|
if (*a != *b)
|
||||||
|
return false;
|
||||||
|
++a;
|
||||||
|
++b;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||||
|
|||||||
@ -1,36 +0,0 @@
|
|||||||
// 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
|
|
||||||
@ -1,121 +1,96 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ArduinoJson/Variant/JsonVariant.hpp>
|
#include <ArduinoJson/Variant/JsonVariant.hpp>
|
||||||
#include <ArduinoJson/Variant/SlotFunctions.hpp>
|
|
||||||
|
|
||||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
class VariantPtr {
|
template <typename T>
|
||||||
|
class Ptr {
|
||||||
public:
|
public:
|
||||||
VariantPtr(detail::MemoryPool* pool, detail::VariantData* data)
|
Ptr(T value) : value_(value) {}
|
||||||
: variant_(pool, data) {}
|
|
||||||
|
|
||||||
JsonVariant* operator->() {
|
T* operator->() {
|
||||||
return &variant_;
|
return &value_;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonVariant& operator*() {
|
T& operator*() {
|
||||||
return variant_;
|
return value_;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JsonVariant variant_;
|
T value_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class JsonArrayIterator {
|
class JsonArrayIterator {
|
||||||
friend class JsonArray;
|
friend class JsonArray;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
JsonArrayIterator() : slot_(0) {}
|
JsonArrayIterator() {}
|
||||||
explicit JsonArrayIterator(detail::MemoryPool* pool,
|
explicit JsonArrayIterator(detail::ArrayData::iterator iterator,
|
||||||
detail::VariantSlot* slot)
|
detail::ResourceManager* resources)
|
||||||
: pool_(pool), slot_(slot) {}
|
: iterator_(iterator), resources_(resources) {}
|
||||||
|
|
||||||
JsonVariant operator*() const {
|
JsonVariant operator*() {
|
||||||
return JsonVariant(pool_, slot_->data());
|
return JsonVariant(iterator_.data(), resources_);
|
||||||
}
|
}
|
||||||
VariantPtr operator->() {
|
Ptr<JsonVariant> operator->() {
|
||||||
return VariantPtr(pool_, slot_->data());
|
return operator*();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const JsonArrayIterator& other) const {
|
bool operator==(const JsonArrayIterator& other) const {
|
||||||
return slot_ == other.slot_;
|
return iterator_ == other.iterator_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const JsonArrayIterator& other) const {
|
bool operator!=(const JsonArrayIterator& other) const {
|
||||||
return slot_ != other.slot_;
|
return iterator_ != other.iterator_;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonArrayIterator& operator++() {
|
JsonArrayIterator& operator++() {
|
||||||
slot_ = slot_->next();
|
iterator_.next(resources_);
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonArrayIterator& operator+=(size_t distance) {
|
|
||||||
slot_ = slot_->next(distance);
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
detail::MemoryPool* pool_;
|
detail::ArrayData::iterator iterator_;
|
||||||
detail::VariantSlot* slot_;
|
detail::ResourceManager* resources_;
|
||||||
};
|
|
||||||
|
|
||||||
class VariantConstPtr {
|
|
||||||
public:
|
|
||||||
VariantConstPtr(const detail::VariantData* data) : variant_(data) {}
|
|
||||||
|
|
||||||
JsonVariantConst* operator->() {
|
|
||||||
return &variant_;
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonVariantConst& operator*() {
|
|
||||||
return variant_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
JsonVariantConst variant_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class JsonArrayConstIterator {
|
class JsonArrayConstIterator {
|
||||||
friend class JsonArray;
|
friend class JsonArray;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
JsonArrayConstIterator() : slot_(0) {}
|
JsonArrayConstIterator() {}
|
||||||
explicit JsonArrayConstIterator(const detail::VariantSlot* slot)
|
explicit JsonArrayConstIterator(detail::ArrayData::iterator iterator,
|
||||||
: slot_(slot) {}
|
const detail::ResourceManager* resources)
|
||||||
|
: iterator_(iterator), resources_(resources) {}
|
||||||
|
|
||||||
JsonVariantConst operator*() const {
|
JsonVariantConst operator*() const {
|
||||||
return JsonVariantConst(slot_->data());
|
return JsonVariantConst(iterator_.data(), resources_);
|
||||||
}
|
}
|
||||||
VariantConstPtr operator->() {
|
Ptr<JsonVariantConst> operator->() {
|
||||||
return VariantConstPtr(slot_->data());
|
return operator*();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const JsonArrayConstIterator& other) const {
|
bool operator==(const JsonArrayConstIterator& other) const {
|
||||||
return slot_ == other.slot_;
|
return iterator_ == other.iterator_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const JsonArrayConstIterator& other) const {
|
bool operator!=(const JsonArrayConstIterator& other) const {
|
||||||
return slot_ != other.slot_;
|
return iterator_ != other.iterator_;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonArrayConstIterator& operator++() {
|
JsonArrayConstIterator& operator++() {
|
||||||
slot_ = slot_->next();
|
iterator_.next(resources_);
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonArrayConstIterator& operator+=(size_t distance) {
|
|
||||||
slot_ = slot_->next(distance);
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const detail::VariantSlot* slot_;
|
detail::ArrayData::iterator iterator_;
|
||||||
|
const detail::ResourceManager* resources_;
|
||||||
};
|
};
|
||||||
|
|
||||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -11,30 +11,29 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
|||||||
|
|
||||||
// Copies a value to a JsonVariant.
|
// Copies a value to a JsonVariant.
|
||||||
// This is a degenerated form of copyArray() to stop the recursion.
|
// This is a degenerated form of copyArray() to stop the recursion.
|
||||||
template <typename T>
|
template <typename T, detail::enable_if_t<!detail::is_array<T>::value, int> = 0>
|
||||||
inline typename detail::enable_if<!detail::is_array<T>::value, bool>::type
|
inline bool copyArray(const T& src, JsonVariant dst) {
|
||||||
copyArray(const T& src, JsonVariant dst) {
|
|
||||||
return dst.set(src);
|
return dst.set(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copies values from an array to a JsonArray or a JsonVariant.
|
// Copies values from an array to a JsonArray or a JsonVariant.
|
||||||
// https://arduinojson.org/v6/api/misc/copyarray/
|
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||||
template <typename T, size_t N, typename TDestination>
|
template <typename T, size_t N, typename TDestination,
|
||||||
inline typename detail::enable_if<
|
detail::enable_if_t<
|
||||||
!detail::is_base_of<JsonDocument, TDestination>::value, bool>::type
|
!detail::is_base_of<JsonDocument, TDestination>::value, int> = 0>
|
||||||
copyArray(T (&src)[N], const TDestination& dst) {
|
inline bool copyArray(T (&src)[N], const TDestination& dst) {
|
||||||
return copyArray(src, N, dst);
|
return copyArray(src, N, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copies values from an array to a JsonArray or a JsonVariant.
|
// Copies values from an array to a JsonArray or a JsonVariant.
|
||||||
// https://arduinojson.org/v6/api/misc/copyarray/
|
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||||
template <typename T, typename TDestination>
|
template <typename T, typename TDestination,
|
||||||
inline typename detail::enable_if<
|
detail::enable_if_t<
|
||||||
!detail::is_base_of<JsonDocument, TDestination>::value, bool>::type
|
!detail::is_base_of<JsonDocument, TDestination>::value, int> = 0>
|
||||||
copyArray(const T* src, size_t len, const TDestination& dst) {
|
inline bool copyArray(const T* src, size_t len, const TDestination& dst) {
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
ok &= copyArray(src[i], dst.add());
|
ok &= copyArray(src[i], dst.template add<JsonVariant>());
|
||||||
}
|
}
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
@ -47,14 +46,14 @@ inline bool copyArray(const char* src, size_t, const TDestination& dst) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copies values from an array to a JsonDocument.
|
// Copies values from an array to a JsonDocument.
|
||||||
// https://arduinojson.org/v6/api/misc/copyarray/
|
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline bool copyArray(const T& src, JsonDocument& dst) {
|
inline bool copyArray(const T& src, JsonDocument& dst) {
|
||||||
return copyArray(src, dst.to<JsonArray>());
|
return copyArray(src, dst.to<JsonArray>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copies an array to a JsonDocument.
|
// Copies an array to a JsonDocument.
|
||||||
// https://arduinojson.org/v6/api/misc/copyarray/
|
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline bool copyArray(const T* src, size_t len, JsonDocument& dst) {
|
inline bool copyArray(const T* src, size_t len, JsonDocument& dst) {
|
||||||
return copyArray(src, len, dst.to<JsonArray>());
|
return copyArray(src, len, dst.to<JsonArray>());
|
||||||
@ -62,22 +61,21 @@ inline bool copyArray(const T* src, size_t len, JsonDocument& dst) {
|
|||||||
|
|
||||||
// Copies a value from a JsonVariant.
|
// Copies a value from a JsonVariant.
|
||||||
// This is a degenerated form of copyArray() to stop the recursion.
|
// This is a degenerated form of copyArray() to stop the recursion.
|
||||||
template <typename T>
|
template <typename T, detail::enable_if_t<!detail::is_array<T>::value, int> = 0>
|
||||||
inline typename detail::enable_if<!detail::is_array<T>::value, size_t>::type
|
inline size_t copyArray(JsonVariantConst src, T& dst) {
|
||||||
copyArray(JsonVariantConst src, T& dst) {
|
|
||||||
dst = src.as<T>();
|
dst = src.as<T>();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copies values from a JsonArray or JsonVariant to an array.
|
// Copies values from a JsonArray or JsonVariant to an array.
|
||||||
// https://arduinojson.org/v6/api/misc/copyarray/
|
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||||
template <typename T, size_t N>
|
template <typename T, size_t N>
|
||||||
inline size_t copyArray(JsonArrayConst src, T (&dst)[N]) {
|
inline size_t copyArray(JsonArrayConst src, T (&dst)[N]) {
|
||||||
return copyArray(src, dst, N);
|
return copyArray(src, dst, N);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copies values from a JsonArray or JsonVariant to an array.
|
// Copies values from a JsonArray or JsonVariant to an array.
|
||||||
// https://arduinojson.org/v6/api/misc/copyarray/
|
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline size_t copyArray(JsonArrayConst src, T* dst, size_t len) {
|
inline size_t copyArray(JsonArrayConst src, T* dst, size_t len) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
@ -101,13 +99,13 @@ inline size_t copyArray(JsonVariantConst src, char (&dst)[N]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copies values from a JsonDocument to an array.
|
// Copies values from a JsonDocument to an array.
|
||||||
// https://arduinojson.org/v6/api/misc/copyarray/
|
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||||
template <typename TSource, typename T>
|
template <
|
||||||
inline typename detail::enable_if<
|
typename TSource, typename T,
|
||||||
detail::is_array<T>::value &&
|
detail::enable_if_t<detail::is_array<T>::value &&
|
||||||
detail::is_base_of<JsonDocument, TSource>::value,
|
detail::is_base_of<JsonDocument, TSource>::value,
|
||||||
size_t>::type
|
int> = 0>
|
||||||
copyArray(const TSource& src, T& dst) {
|
inline size_t copyArray(const TSource& src, T& dst) {
|
||||||
return copyArray(src.template as<JsonArrayConst>(), dst);
|
return copyArray(src.template as<JsonArrayConst>(), dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Memory/MemoryPool.hpp>
|
||||||
#include <ArduinoJson/Namespace.hpp>
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||||
|
|
||||||
@ -11,74 +12,100 @@
|
|||||||
|
|
||||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
class MemoryPool;
|
|
||||||
class VariantData;
|
class VariantData;
|
||||||
class VariantSlot;
|
class ResourceManager;
|
||||||
|
|
||||||
class CollectionData {
|
class CollectionIterator {
|
||||||
VariantSlot* head_;
|
friend class CollectionData;
|
||||||
VariantSlot* tail_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Must be a POD!
|
CollectionIterator() : slot_(nullptr), currentId_(NULL_SLOT) {}
|
||||||
// - no constructor
|
|
||||||
// - no destructor
|
|
||||||
// - no virtual
|
|
||||||
// - no inheritance
|
|
||||||
|
|
||||||
// Array only
|
void next(const ResourceManager* resources);
|
||||||
|
|
||||||
VariantData* addElement(MemoryPool* pool);
|
bool done() const {
|
||||||
|
return slot_ == nullptr;
|
||||||
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 operator==(const CollectionIterator& other) const {
|
||||||
bool containsKey(const TAdaptedString& key) const;
|
return slot_ == other.slot_;
|
||||||
|
}
|
||||||
|
|
||||||
// Generic
|
bool operator!=(const CollectionIterator& other) const {
|
||||||
|
return slot_ != other.slot_;
|
||||||
|
}
|
||||||
|
|
||||||
void clear();
|
VariantData* operator->() {
|
||||||
size_t memoryUsage() const;
|
ARDUINOJSON_ASSERT(slot_ != nullptr);
|
||||||
size_t size() const;
|
return data();
|
||||||
|
}
|
||||||
|
|
||||||
VariantSlot* addSlot(MemoryPool*);
|
VariantData& operator*() {
|
||||||
void removeSlot(VariantSlot* slot);
|
ARDUINOJSON_ASSERT(slot_ != nullptr);
|
||||||
|
return *data();
|
||||||
|
}
|
||||||
|
|
||||||
bool copyFrom(const CollectionData& src, MemoryPool* pool);
|
const VariantData& operator*() const {
|
||||||
|
ARDUINOJSON_ASSERT(slot_ != nullptr);
|
||||||
|
return *data();
|
||||||
|
}
|
||||||
|
|
||||||
VariantSlot* head() const {
|
VariantData* data() {
|
||||||
|
return reinterpret_cast<VariantData*>(slot_);
|
||||||
|
}
|
||||||
|
|
||||||
|
const VariantData* data() const {
|
||||||
|
return reinterpret_cast<const VariantData*>(slot_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CollectionIterator(VariantData* slot, SlotId slotId);
|
||||||
|
|
||||||
|
VariantData* slot_;
|
||||||
|
SlotId currentId_, nextId_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CollectionData {
|
||||||
|
SlotId head_ = NULL_SLOT;
|
||||||
|
SlotId tail_ = NULL_SLOT;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Placement new
|
||||||
|
static void* operator new(size_t, void* p) noexcept {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void operator delete(void*, void*) noexcept {}
|
||||||
|
|
||||||
|
using iterator = CollectionIterator;
|
||||||
|
|
||||||
|
iterator createIterator(const ResourceManager* resources) const;
|
||||||
|
|
||||||
|
size_t size(const ResourceManager*) const;
|
||||||
|
size_t nesting(const ResourceManager*) const;
|
||||||
|
|
||||||
|
void clear(ResourceManager* resources);
|
||||||
|
|
||||||
|
static void clear(CollectionData* collection, ResourceManager* resources) {
|
||||||
|
if (!collection)
|
||||||
|
return;
|
||||||
|
collection->clear(resources);
|
||||||
|
}
|
||||||
|
|
||||||
|
SlotId head() const {
|
||||||
return head_;
|
return head_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance);
|
protected:
|
||||||
|
void appendOne(Slot<VariantData> slot, const ResourceManager* resources);
|
||||||
|
void appendPair(Slot<VariantData> key, Slot<VariantData> value,
|
||||||
|
const ResourceManager* resources);
|
||||||
|
|
||||||
|
void removeOne(iterator it, ResourceManager* resources);
|
||||||
|
void removePair(iterator it, ResourceManager* resources);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VariantSlot* getSlot(size_t index) const;
|
Slot<VariantData> getPreviousSlot(VariantData*, const ResourceManager*) const;
|
||||||
|
|
||||||
template <typename TAdaptedString>
|
|
||||||
VariantSlot* getSlot(TAdaptedString key) const;
|
|
||||||
|
|
||||||
VariantSlot* getPreviousSlot(VariantSlot*) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const VariantData* collectionToVariant(
|
inline const VariantData* collectionToVariant(
|
||||||
|
|||||||
@ -1,197 +1,137 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ArduinoJson/Collection/CollectionData.hpp>
|
#include <ArduinoJson/Collection/CollectionData.hpp>
|
||||||
#include <ArduinoJson/Strings/StoragePolicy.hpp>
|
#include <ArduinoJson/Memory/Alignment.hpp>
|
||||||
#include <ArduinoJson/Strings/StringAdapters.hpp>
|
#include <ArduinoJson/Strings/StringAdapters.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantCompare.hpp>
|
||||||
#include <ArduinoJson/Variant/VariantData.hpp>
|
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||||
|
|
||||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) {
|
inline CollectionIterator::CollectionIterator(VariantData* slot, SlotId slotId)
|
||||||
VariantSlot* slot = pool->allocVariant();
|
: slot_(slot), currentId_(slotId) {
|
||||||
if (!slot)
|
nextId_ = slot_ ? slot_->next() : NULL_SLOT;
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
if (tail_) {
|
inline void CollectionIterator::next(const ResourceManager* resources) {
|
||||||
ARDUINOJSON_ASSERT(pool->owns(tail_)); // Can't alter a linked array/object
|
ARDUINOJSON_ASSERT(currentId_ != NULL_SLOT);
|
||||||
tail_->setNextNotNull(slot);
|
slot_ = resources->getVariant(nextId_);
|
||||||
tail_ = slot;
|
currentId_ = nextId_;
|
||||||
|
if (slot_)
|
||||||
|
nextId_ = slot_->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CollectionData::iterator CollectionData::createIterator(
|
||||||
|
const ResourceManager* resources) const {
|
||||||
|
return iterator(resources->getVariant(head_), head_);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void CollectionData::appendOne(Slot<VariantData> slot,
|
||||||
|
const ResourceManager* resources) {
|
||||||
|
if (tail_ != NULL_SLOT) {
|
||||||
|
auto tail = resources->getVariant(tail_);
|
||||||
|
tail->setNext(slot.id());
|
||||||
|
tail_ = slot.id();
|
||||||
} else {
|
} else {
|
||||||
head_ = slot;
|
head_ = slot.id();
|
||||||
tail_ = slot;
|
tail_ = slot.id();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void CollectionData::appendPair(Slot<VariantData> key,
|
||||||
|
Slot<VariantData> value,
|
||||||
|
const ResourceManager* resources) {
|
||||||
|
key->setNext(value.id());
|
||||||
|
|
||||||
|
if (tail_ != NULL_SLOT) {
|
||||||
|
auto tail = resources->getVariant(tail_);
|
||||||
|
tail->setNext(key.id());
|
||||||
|
tail_ = value.id();
|
||||||
|
} else {
|
||||||
|
head_ = key.id();
|
||||||
|
tail_ = value.id();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void CollectionData::clear(ResourceManager* resources) {
|
||||||
|
auto next = head_;
|
||||||
|
while (next != NULL_SLOT) {
|
||||||
|
auto currId = next;
|
||||||
|
auto slot = resources->getVariant(next);
|
||||||
|
next = slot->next();
|
||||||
|
resources->freeVariant({slot, currId});
|
||||||
}
|
}
|
||||||
|
|
||||||
slot->clear();
|
head_ = NULL_SLOT;
|
||||||
return slot;
|
tail_ = NULL_SLOT;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline VariantData* CollectionData::addElement(MemoryPool* pool) {
|
inline Slot<VariantData> CollectionData::getPreviousSlot(
|
||||||
return slotData(addSlot(pool));
|
VariantData* target, const ResourceManager* resources) const {
|
||||||
}
|
auto prev = Slot<VariantData>();
|
||||||
|
auto currentId = head_;
|
||||||
template <typename TAdaptedString>
|
while (currentId != NULL_SLOT) {
|
||||||
inline VariantData* CollectionData::addMember(TAdaptedString key,
|
auto currentSlot = resources->getVariant(currentId);
|
||||||
MemoryPool* pool) {
|
if (currentSlot == target)
|
||||||
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;
|
break;
|
||||||
slot = slot->next();
|
prev = Slot<VariantData>(currentSlot, currentId);
|
||||||
|
currentId = currentSlot->next();
|
||||||
}
|
}
|
||||||
return slot;
|
return prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline VariantSlot* CollectionData::getSlot(size_t index) const {
|
inline void CollectionData::removeOne(iterator it, ResourceManager* resources) {
|
||||||
if (!head_)
|
if (it.done())
|
||||||
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;
|
return;
|
||||||
VariantSlot* prev = getPreviousSlot(slot);
|
auto curr = it.slot_;
|
||||||
VariantSlot* next = slot->next();
|
auto prev = getPreviousSlot(curr, resources);
|
||||||
|
auto next = curr->next();
|
||||||
if (prev)
|
if (prev)
|
||||||
prev->setNext(next);
|
prev->setNext(next);
|
||||||
else
|
else
|
||||||
head_ = next;
|
head_ = next;
|
||||||
if (!next)
|
if (next == NULL_SLOT)
|
||||||
tail_ = prev;
|
tail_ = prev.id();
|
||||||
|
resources->freeVariant({it.slot_, it.currentId_});
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void CollectionData::removeElement(size_t index) {
|
inline void CollectionData::removePair(ObjectData::iterator it,
|
||||||
removeSlot(getSlot(index));
|
ResourceManager* resources) {
|
||||||
}
|
if (it.done())
|
||||||
|
|
||||||
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;
|
return;
|
||||||
p = reinterpret_cast<T*>(
|
|
||||||
reinterpret_cast<void*>(reinterpret_cast<char*>(p) + offset));
|
auto keySlot = it.slot_;
|
||||||
ARDUINOJSON_ASSERT(isAligned(p));
|
|
||||||
|
auto valueId = it.nextId_;
|
||||||
|
auto valueSlot = resources->getVariant(valueId);
|
||||||
|
|
||||||
|
// remove value slot
|
||||||
|
keySlot->setNext(valueSlot->next());
|
||||||
|
resources->freeVariant({valueSlot, valueId});
|
||||||
|
|
||||||
|
// remove key slot
|
||||||
|
removeOne(it, resources);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void CollectionData::movePointers(ptrdiff_t stringDistance,
|
inline size_t CollectionData::nesting(const ResourceManager* resources) const {
|
||||||
ptrdiff_t variantDistance) {
|
size_t maxChildNesting = 0;
|
||||||
movePointer(head_, variantDistance);
|
for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
|
||||||
movePointer(tail_, variantDistance);
|
size_t childNesting = it->nesting(resources);
|
||||||
for (VariantSlot* slot = head_; slot; slot = slot->next())
|
if (childNesting > maxChildNesting)
|
||||||
slot->movePointers(stringDistance, variantDistance);
|
maxChildNesting = childNesting;
|
||||||
|
}
|
||||||
|
return maxChildNesting + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t CollectionData::size(const ResourceManager* resources) const {
|
||||||
|
size_t count = 0;
|
||||||
|
for (auto it = createIterator(resources); !it.done(); it.next(resources))
|
||||||
|
count++;
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Support std::istream and std::ostream
|
// Support std::istream and std::ostream
|
||||||
|
// https://arduinojson.org/v7/config/enable_std_stream/
|
||||||
#ifndef ARDUINOJSON_ENABLE_STD_STREAM
|
#ifndef ARDUINOJSON_ENABLE_STD_STREAM
|
||||||
# ifdef __has_include
|
# ifdef __has_include
|
||||||
# if __has_include(<istream>) && \
|
# if __has_include(<istream>) && \
|
||||||
@ -25,6 +26,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Support std::string
|
// Support std::string
|
||||||
|
// https://arduinojson.org/v7/config/enable_std_string/
|
||||||
#ifndef ARDUINOJSON_ENABLE_STD_STRING
|
#ifndef ARDUINOJSON_ENABLE_STD_STRING
|
||||||
# ifdef __has_include
|
# ifdef __has_include
|
||||||
# if __has_include(<string>) && !defined(min) && !defined(max)
|
# if __has_include(<string>) && !defined(min) && !defined(max)
|
||||||
@ -54,51 +56,105 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Pointer size: a heuristic to set sensible defaults
|
||||||
|
#ifndef ARDUINOJSON_SIZEOF_POINTER
|
||||||
|
# if defined(__SIZEOF_POINTER__)
|
||||||
|
# define ARDUINOJSON_SIZEOF_POINTER __SIZEOF_POINTER__
|
||||||
|
# elif defined(_WIN64) && _WIN64
|
||||||
|
# define ARDUINOJSON_SIZEOF_POINTER 8 // 64 bits
|
||||||
|
# else
|
||||||
|
# define ARDUINOJSON_SIZEOF_POINTER 4 // assume 32 bits otherwise
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
// Store floating-point values with float (0) or double (1)
|
// Store floating-point values with float (0) or double (1)
|
||||||
|
// https://arduinojson.org/v7/config/use_double/
|
||||||
#ifndef ARDUINOJSON_USE_DOUBLE
|
#ifndef ARDUINOJSON_USE_DOUBLE
|
||||||
# define ARDUINOJSON_USE_DOUBLE 1
|
# if ARDUINOJSON_SIZEOF_POINTER >= 4 // 32 & 64 bits systems
|
||||||
|
# define ARDUINOJSON_USE_DOUBLE 1
|
||||||
|
# else
|
||||||
|
# define ARDUINOJSON_USE_DOUBLE 0
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Store integral values with long (0) or long long (1)
|
// Store integral values with long (0) or long long (1)
|
||||||
|
// https://arduinojson.org/v7/config/use_long_long/
|
||||||
#ifndef ARDUINOJSON_USE_LONG_LONG
|
#ifndef ARDUINOJSON_USE_LONG_LONG
|
||||||
# if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ >= 4 || \
|
# if ARDUINOJSON_SIZEOF_POINTER >= 4 // 32 & 64 bits systems
|
||||||
defined(_MSC_VER)
|
|
||||||
# define ARDUINOJSON_USE_LONG_LONG 1
|
# define ARDUINOJSON_USE_LONG_LONG 1
|
||||||
|
# else
|
||||||
|
# define ARDUINOJSON_USE_LONG_LONG 0
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
#ifndef ARDUINOJSON_USE_LONG_LONG
|
|
||||||
# define ARDUINOJSON_USE_LONG_LONG 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Limit nesting as the stack is likely to be small
|
// Limit nesting as the stack is likely to be small
|
||||||
|
// https://arduinojson.org/v7/config/default_nesting_limit/
|
||||||
#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT
|
#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT
|
||||||
# define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10
|
# define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Number of bits to store the pointer to next node
|
// Number of bytes to store a slot id
|
||||||
// (saves RAM but limits the number of values in a document)
|
// https://arduinojson.org/v7/config/slot_id_size/
|
||||||
#ifndef ARDUINOJSON_SLOT_OFFSET_SIZE
|
#ifndef ARDUINOJSON_SLOT_ID_SIZE
|
||||||
# if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ <= 2
|
# if ARDUINOJSON_SIZEOF_POINTER <= 2
|
||||||
// Address space == 16-bit => max 127 values
|
// 8-bit and 16-bit archs => up to 255 slots
|
||||||
# define ARDUINOJSON_SLOT_OFFSET_SIZE 1
|
# define ARDUINOJSON_SLOT_ID_SIZE 1
|
||||||
# elif defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ >= 8 || \
|
# elif ARDUINOJSON_SIZEOF_POINTER == 4
|
||||||
defined(_WIN64) && _WIN64
|
// 32-bit arch => up to 65535 slots
|
||||||
// Address space == 64-bit => max 2147483647 values
|
# define ARDUINOJSON_SLOT_ID_SIZE 2
|
||||||
# define ARDUINOJSON_SLOT_OFFSET_SIZE 4
|
|
||||||
# else
|
# else
|
||||||
// Address space == 32-bit => max 32767 values
|
// 64-bit arch => up to 4294967295 slots
|
||||||
# define ARDUINOJSON_SLOT_OFFSET_SIZE 2
|
# define ARDUINOJSON_SLOT_ID_SIZE 4
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Capacity of each variant pool (in slots)
|
||||||
|
#ifndef ARDUINOJSON_POOL_CAPACITY
|
||||||
|
# if ARDUINOJSON_SLOT_ID_SIZE == 1
|
||||||
|
# define ARDUINOJSON_POOL_CAPACITY 16 // 96 bytes
|
||||||
|
# elif ARDUINOJSON_SLOT_ID_SIZE == 2
|
||||||
|
# define ARDUINOJSON_POOL_CAPACITY 128 // 1024 bytes
|
||||||
|
# else
|
||||||
|
# define ARDUINOJSON_POOL_CAPACITY 256 // 4096 bytes
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Initial capacity of the pool list
|
||||||
|
#ifndef ARDUINOJSON_INITIAL_POOL_COUNT
|
||||||
|
# define ARDUINOJSON_INITIAL_POOL_COUNT 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Automatically call shrinkToFit() from deserializeXxx()
|
||||||
|
// Disabled by default on 8-bit platforms because it's not worth the increase in
|
||||||
|
// code size
|
||||||
|
#ifndef ARDUINOJSON_AUTO_SHRINK
|
||||||
|
# if ARDUINOJSON_SIZEOF_POINTER <= 2
|
||||||
|
# define ARDUINOJSON_AUTO_SHRINK 0
|
||||||
|
# else
|
||||||
|
# define ARDUINOJSON_AUTO_SHRINK 1
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Number of bytes to store the length of a string
|
||||||
|
// https://arduinojson.org/v7/config/string_length_size/
|
||||||
|
#ifndef ARDUINOJSON_STRING_LENGTH_SIZE
|
||||||
|
# if ARDUINOJSON_SIZEOF_POINTER <= 2
|
||||||
|
# define ARDUINOJSON_STRING_LENGTH_SIZE 1 // up to 255 characters
|
||||||
|
# else
|
||||||
|
# define ARDUINOJSON_STRING_LENGTH_SIZE 2 // up to 65535 characters
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ARDUINO
|
#ifdef ARDUINO
|
||||||
|
|
||||||
// Enable support for Arduino's String class
|
// Enable support for Arduino's String class
|
||||||
|
// https://arduinojson.org/v7/config/enable_arduino_string/
|
||||||
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
|
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
|
||||||
# define ARDUINOJSON_ENABLE_ARDUINO_STRING 1
|
# define ARDUINOJSON_ENABLE_ARDUINO_STRING 1
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
// Enable support for Arduino's Stream class
|
// Enable support for Arduino's Stream class
|
||||||
|
// https://arduinojson.org/v7/config/enable_arduino_stream/
|
||||||
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
|
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
|
||||||
# define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1
|
# define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1
|
||||||
# endif
|
# endif
|
||||||
@ -109,6 +165,7 @@
|
|||||||
# endif
|
# endif
|
||||||
|
|
||||||
// Enable support for PROGMEM
|
// Enable support for PROGMEM
|
||||||
|
// https://arduinojson.org/v7/config/enable_progmem/
|
||||||
# ifndef ARDUINOJSON_ENABLE_PROGMEM
|
# ifndef ARDUINOJSON_ENABLE_PROGMEM
|
||||||
# define ARDUINOJSON_ENABLE_PROGMEM 1
|
# define ARDUINOJSON_ENABLE_PROGMEM 1
|
||||||
# endif
|
# endif
|
||||||
@ -116,11 +173,13 @@
|
|||||||
#else // ARDUINO
|
#else // ARDUINO
|
||||||
|
|
||||||
// Disable support for Arduino's String class
|
// Disable support for Arduino's String class
|
||||||
|
// https://arduinojson.org/v7/config/enable_arduino_string/
|
||||||
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
|
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
|
||||||
# define ARDUINOJSON_ENABLE_ARDUINO_STRING 0
|
# define ARDUINOJSON_ENABLE_ARDUINO_STRING 0
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
// Disable support for Arduino's Stream class
|
// Disable support for Arduino's Stream class
|
||||||
|
// https://arduinojson.org/v7/config/enable_arduino_stream/
|
||||||
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
|
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
|
||||||
# define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0
|
# define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0
|
||||||
# endif
|
# endif
|
||||||
@ -131,6 +190,7 @@
|
|||||||
# endif
|
# endif
|
||||||
|
|
||||||
// Enable PROGMEM support on AVR only
|
// Enable PROGMEM support on AVR only
|
||||||
|
// https://arduinojson.org/v7/config/enable_progmem/
|
||||||
# ifndef ARDUINOJSON_ENABLE_PROGMEM
|
# ifndef ARDUINOJSON_ENABLE_PROGMEM
|
||||||
# ifdef __AVR__
|
# ifdef __AVR__
|
||||||
# define ARDUINOJSON_ENABLE_PROGMEM 1
|
# define ARDUINOJSON_ENABLE_PROGMEM 1
|
||||||
@ -142,32 +202,38 @@
|
|||||||
#endif // ARDUINO
|
#endif // ARDUINO
|
||||||
|
|
||||||
// Convert unicode escape sequence (\u0123) to UTF-8
|
// Convert unicode escape sequence (\u0123) to UTF-8
|
||||||
|
// https://arduinojson.org/v7/config/decode_unicode/
|
||||||
#ifndef ARDUINOJSON_DECODE_UNICODE
|
#ifndef ARDUINOJSON_DECODE_UNICODE
|
||||||
# define ARDUINOJSON_DECODE_UNICODE 1
|
# define ARDUINOJSON_DECODE_UNICODE 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Ignore comments in input
|
// Ignore comments in input
|
||||||
|
// https://arduinojson.org/v7/config/enable_comments/
|
||||||
#ifndef ARDUINOJSON_ENABLE_COMMENTS
|
#ifndef ARDUINOJSON_ENABLE_COMMENTS
|
||||||
# define ARDUINOJSON_ENABLE_COMMENTS 0
|
# define ARDUINOJSON_ENABLE_COMMENTS 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Support NaN in JSON
|
// Support NaN in JSON
|
||||||
|
// https://arduinojson.org/v7/config/enable_nan/
|
||||||
#ifndef ARDUINOJSON_ENABLE_NAN
|
#ifndef ARDUINOJSON_ENABLE_NAN
|
||||||
# define ARDUINOJSON_ENABLE_NAN 0
|
# define ARDUINOJSON_ENABLE_NAN 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Support Infinity in JSON
|
// Support Infinity in JSON
|
||||||
|
// https://arduinojson.org/v7/config/enable_infinity/
|
||||||
#ifndef ARDUINOJSON_ENABLE_INFINITY
|
#ifndef ARDUINOJSON_ENABLE_INFINITY
|
||||||
# define ARDUINOJSON_ENABLE_INFINITY 0
|
# define ARDUINOJSON_ENABLE_INFINITY 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Control the exponentiation threshold for big numbers
|
// Control the exponentiation threshold for big numbers
|
||||||
// CAUTION: cannot be more that 1e9 !!!!
|
// CAUTION: cannot be more that 1e9 !!!!
|
||||||
|
// https://arduinojson.org/v7/config/positive_exponentiation_threshold/
|
||||||
#ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD
|
#ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD
|
||||||
# define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e7
|
# define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e7
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Control the exponentiation threshold for small numbers
|
// Control the exponentiation threshold for small numbers
|
||||||
|
// https://arduinojson.org/v7/config/negative_exponentiation_threshold/
|
||||||
#ifndef ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD
|
#ifndef ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD
|
||||||
# define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5
|
# define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5
|
||||||
#endif
|
#endif
|
||||||
@ -195,10 +261,6 @@
|
|||||||
# define ARDUINOJSON_TAB " "
|
# define ARDUINOJSON_TAB " "
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
|
|
||||||
# define ARDUINOJSON_ENABLE_STRING_DEDUPLICATION 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ARDUINOJSON_STRING_BUFFER_SIZE
|
#ifndef ARDUINOJSON_STRING_BUFFER_SIZE
|
||||||
# define ARDUINOJSON_STRING_BUFFER_SIZE 32
|
# define ARDUINOJSON_STRING_BUFFER_SIZE 32
|
||||||
#endif
|
#endif
|
||||||
@ -211,6 +273,12 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_DOUBLE
|
||||||
|
# define ARDUINOJSON_USE_EXTENSIONS 1
|
||||||
|
#else
|
||||||
|
# define ARDUINOJSON_USE_EXTENSIONS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(nullptr)
|
#if defined(nullptr)
|
||||||
# error nullptr is defined as a macro. Remove the faulty #define or #undef nullptr
|
# error nullptr is defined as a macro. Remove the faulty #define or #undef nullptr
|
||||||
// See https://github.com/bblanchon/ArduinoJson/issues/1355
|
// See https://github.com/bblanchon/ArduinoJson/issues/1355
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|||||||
@ -1,17 +1,24 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ArduinoJson/Namespace.hpp>
|
#include <ArduinoJson/Variant/JsonVariant.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantAttorney.hpp>
|
||||||
|
|
||||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
namespace DeserializationOption {
|
namespace DeserializationOption {
|
||||||
class Filter {
|
class Filter {
|
||||||
public:
|
public:
|
||||||
explicit Filter(JsonVariantConst v) : variant_(v) {}
|
#if ARDUINOJSON_AUTO_SHRINK
|
||||||
|
explicit Filter(JsonDocument& doc) : variant_(doc) {
|
||||||
|
doc.shrinkToFit();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
explicit Filter(JsonVariantConst variant) : variant_(variant) {}
|
||||||
|
|
||||||
bool allow() const {
|
bool allow() const {
|
||||||
return variant_;
|
return variant_;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
// The default reader is a simple wrapper for Readers that are not copiable
|
// The default reader is a simple wrapper for Readers that are not copyable
|
||||||
template <typename TSource, typename Enable = void>
|
template <typename TSource, typename Enable = void>
|
||||||
struct Reader {
|
struct Reader {
|
||||||
public:
|
public:
|
||||||
@ -19,7 +19,7 @@ struct Reader {
|
|||||||
|
|
||||||
int read() {
|
int read() {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
return source_->read(); // Error here? See https://arduinojson.org/v6/invalid-input/
|
return source_->read(); // Error here? See https://arduinojson.org/v7/invalid-input/
|
||||||
// clang-format on
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,9 +62,8 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE
|
|||||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
template <typename TInput>
|
template <typename TInput>
|
||||||
Reader<typename remove_reference<TInput>::type> makeReader(TInput&& input) {
|
Reader<remove_reference_t<TInput>> makeReader(TInput&& input) {
|
||||||
return Reader<typename remove_reference<TInput>::type>{
|
return Reader<remove_reference_t<TInput>>{detail::forward<TInput>(input)};
|
||||||
detail::forward<TInput>(input)};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TChar>
|
template <typename TChar>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -9,13 +9,12 @@
|
|||||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
template <typename TSource>
|
template <typename TSource>
|
||||||
struct Reader<TSource,
|
struct Reader<TSource, enable_if_t<is_base_of<Stream, TSource>::value>> {
|
||||||
typename enable_if<is_base_of<Stream, TSource>::value>::type> {
|
|
||||||
public:
|
public:
|
||||||
explicit Reader(Stream& stream) : stream_(&stream) {}
|
explicit Reader(Stream& stream) : stream_(&stream) {}
|
||||||
|
|
||||||
int read() {
|
int read() {
|
||||||
// don't use stream_.read() as it ignores the timeout
|
// don't use stream_->read() as it ignores the timeout
|
||||||
char c;
|
char c;
|
||||||
return stream_->readBytes(&c, 1) ? static_cast<unsigned char>(c) : -1;
|
return stream_->readBytes(&c, 1) ? static_cast<unsigned char>(c) : -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -9,8 +9,7 @@
|
|||||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
template <typename TSource>
|
template <typename TSource>
|
||||||
struct Reader<TSource,
|
struct Reader<TSource, enable_if_t<is_base_of<::String, TSource>::value>>
|
||||||
typename enable_if<is_base_of<::String, TSource>::value>::type>
|
|
||||||
: BoundedReader<const char*> {
|
: BoundedReader<const char*> {
|
||||||
explicit Reader(const ::String& s)
|
explicit Reader(const ::String& s)
|
||||||
: BoundedReader<const char*>(s.c_str(), s.length()) {}
|
: BoundedReader<const char*>(s.c_str(), s.length()) {}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||||
|
|
||||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
template <typename TIterator>
|
template <typename TIterator>
|
||||||
@ -29,13 +31,8 @@ class IteratorReader {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct void_ {
|
|
||||||
typedef void type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename TSource>
|
template <typename TSource>
|
||||||
struct Reader<TSource, typename void_<typename TSource::const_iterator>::type>
|
struct Reader<TSource, void_t<typename TSource::const_iterator>>
|
||||||
: IteratorReader<typename TSource::const_iterator> {
|
: IteratorReader<typename TSource::const_iterator> {
|
||||||
explicit Reader(const TSource& source)
|
explicit Reader(const TSource& source)
|
||||||
: IteratorReader<typename TSource::const_iterator>(source.begin(),
|
: IteratorReader<typename TSource::const_iterator>(source.begin(),
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -19,8 +19,7 @@ template <typename T>
|
|||||||
struct IsCharOrVoid<const T> : IsCharOrVoid<T> {};
|
struct IsCharOrVoid<const T> : IsCharOrVoid<T> {};
|
||||||
|
|
||||||
template <typename TSource>
|
template <typename TSource>
|
||||||
struct Reader<TSource*,
|
struct Reader<TSource*, enable_if_t<IsCharOrVoid<TSource>::value>> {
|
||||||
typename enable_if<IsCharOrVoid<TSource>::value>::type> {
|
|
||||||
const char* ptr_;
|
const char* ptr_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -39,8 +38,7 @@ struct Reader<TSource*,
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename TSource>
|
template <typename TSource>
|
||||||
struct BoundedReader<TSource*,
|
struct BoundedReader<TSource*, enable_if_t<IsCharOrVoid<TSource>::value>>
|
||||||
typename enable_if<IsCharOrVoid<TSource>::value>::type>
|
|
||||||
: public IteratorReader<const char*> {
|
: public IteratorReader<const char*> {
|
||||||
public:
|
public:
|
||||||
explicit BoundedReader(const void* ptr, size_t len)
|
explicit BoundedReader(const void* ptr, size_t len)
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -9,8 +9,7 @@
|
|||||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
template <typename TSource>
|
template <typename TSource>
|
||||||
struct Reader<TSource, typename enable_if<
|
struct Reader<TSource, enable_if_t<is_base_of<std::istream, TSource>::value>> {
|
||||||
is_base_of<std::istream, TSource>::value>::type> {
|
|
||||||
public:
|
public:
|
||||||
explicit Reader(std::istream& stream) : stream_(&stream) {}
|
explicit Reader(std::istream& stream) : stream_(&stream) {}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -10,7 +10,7 @@
|
|||||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
template <typename TVariant>
|
template <typename TVariant>
|
||||||
struct Reader<TVariant, typename enable_if<IsVariant<TVariant>::value>::type>
|
struct Reader<TVariant, enable_if_t<IsVariant<TVariant>::value>>
|
||||||
: Reader<char*, void> {
|
: Reader<char*, void> {
|
||||||
explicit Reader(const TVariant& x)
|
explicit Reader(const TVariant& x)
|
||||||
: Reader<char*, void>(x.template as<const char*>()) {}
|
: Reader<char*, void>(x.template as<const char*>()) {}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -8,7 +8,6 @@
|
|||||||
#include <ArduinoJson/Deserialization/DeserializationOptions.hpp>
|
#include <ArduinoJson/Deserialization/DeserializationOptions.hpp>
|
||||||
#include <ArduinoJson/Deserialization/Reader.hpp>
|
#include <ArduinoJson/Deserialization/Reader.hpp>
|
||||||
#include <ArduinoJson/Polyfills/utility.hpp>
|
#include <ArduinoJson/Polyfills/utility.hpp>
|
||||||
#include <ArduinoJson/StringStorage/StringStorage.hpp>
|
|
||||||
|
|
||||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
@ -23,44 +22,58 @@ struct first_or_void<T, Rest...> {
|
|||||||
using type = T;
|
using type = T;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <template <typename, typename> class TDeserializer, typename TReader,
|
// A meta-function that returns true if T is a valid destination type for
|
||||||
typename TWriter>
|
// deserialize()
|
||||||
TDeserializer<TReader, TWriter> makeDeserializer(MemoryPool* pool,
|
template <class T>
|
||||||
TReader reader,
|
using is_deserialize_destination =
|
||||||
TWriter writer) {
|
bool_constant<is_base_of<JsonDocument, remove_cv_t<T>>::value ||
|
||||||
ARDUINOJSON_ASSERT(pool != 0);
|
IsVariant<T>::value>;
|
||||||
return TDeserializer<TReader, TWriter>(pool, reader, writer);
|
|
||||||
|
template <typename TDestination>
|
||||||
|
inline void shrinkJsonDocument(TDestination&) {
|
||||||
|
// no-op by default
|
||||||
}
|
}
|
||||||
|
|
||||||
template <template <typename, typename> class TDeserializer, typename TStream,
|
#if ARDUINOJSON_AUTO_SHRINK
|
||||||
typename... Args,
|
inline void shrinkJsonDocument(JsonDocument& doc) {
|
||||||
typename = typename enable_if< // issue #1897
|
doc.shrinkToFit();
|
||||||
!is_integral<typename first_or_void<Args...>::type>::value>::type>
|
}
|
||||||
DeserializationError deserialize(JsonDocument& doc, TStream&& input,
|
#endif
|
||||||
|
|
||||||
|
template <template <typename> class TDeserializer, typename TDestination,
|
||||||
|
typename TReader, typename TOptions>
|
||||||
|
DeserializationError doDeserialize(TDestination&& dst, TReader reader,
|
||||||
|
TOptions options) {
|
||||||
|
auto data = VariantAttorney::getOrCreateData(dst);
|
||||||
|
if (!data)
|
||||||
|
return DeserializationError::NoMemory;
|
||||||
|
auto resources = VariantAttorney::getResourceManager(dst);
|
||||||
|
dst.clear();
|
||||||
|
auto err = TDeserializer<TReader>(resources, reader)
|
||||||
|
.parse(*data, options.filter, options.nestingLimit);
|
||||||
|
shrinkJsonDocument(dst);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
template <typename> class TDeserializer, typename TDestination,
|
||||||
|
typename TStream, typename... Args,
|
||||||
|
enable_if_t< // issue #1897
|
||||||
|
!is_integral<typename first_or_void<Args...>::type>::value, int> = 0>
|
||||||
|
DeserializationError deserialize(TDestination&& dst, TStream&& input,
|
||||||
Args... args) {
|
Args... args) {
|
||||||
auto reader = makeReader(detail::forward<TStream>(input));
|
return doDeserialize<TDeserializer>(
|
||||||
auto data = VariantAttorney::getData(doc);
|
dst, makeReader(detail::forward<TStream>(input)),
|
||||||
auto pool = VariantAttorney::getPool(doc);
|
makeDeserializationOptions(args...));
|
||||||
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,
|
template <template <typename> class TDeserializer, typename TDestination,
|
||||||
typename Size, typename... Args,
|
typename TChar, typename Size, typename... Args,
|
||||||
typename = typename enable_if<is_integral<Size>::value>::type>
|
enable_if_t<is_integral<Size>::value, int> = 0>
|
||||||
DeserializationError deserialize(JsonDocument& doc, TChar* input,
|
DeserializationError deserialize(TDestination&& dst, TChar* input,
|
||||||
Size inputSize, Args... args) {
|
Size inputSize, Args... args) {
|
||||||
auto reader = makeReader(input, size_t(inputSize));
|
return doDeserialize<TDeserializer>(dst, makeReader(input, size_t(inputSize)),
|
||||||
auto data = VariantAttorney::getData(doc);
|
makeDeserializationOptions(args...));
|
||||||
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
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
|
|||||||
@ -1,168 +0,0 @@
|
|||||||
// 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
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
// 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
|
|
||||||
@ -1,308 +1,406 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ArduinoJson/Array/ElementProxy.hpp>
|
#include <ArduinoJson/Array/ElementProxy.hpp>
|
||||||
#include <ArduinoJson/Memory/MemoryPool.hpp>
|
#include <ArduinoJson/Memory/Allocator.hpp>
|
||||||
|
#include <ArduinoJson/Memory/ResourceManager.hpp>
|
||||||
#include <ArduinoJson/Object/JsonObject.hpp>
|
#include <ArduinoJson/Object/JsonObject.hpp>
|
||||||
#include <ArduinoJson/Object/MemberProxy.hpp>
|
#include <ArduinoJson/Object/MemberProxy.hpp>
|
||||||
#include <ArduinoJson/Strings/StoragePolicy.hpp>
|
#include <ArduinoJson/Polyfills/utility.hpp>
|
||||||
#include <ArduinoJson/Variant/JsonVariantConst.hpp>
|
#include <ArduinoJson/Variant/JsonVariantConst.hpp>
|
||||||
#include <ArduinoJson/Variant/VariantTo.hpp>
|
#include <ArduinoJson/Variant/VariantTo.hpp>
|
||||||
|
|
||||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
// A JSON document.
|
// A JSON document.
|
||||||
// https://arduinojson.org/v6/api/jsondocument/
|
// https://arduinojson.org/v7/api/jsondocument/
|
||||||
class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||||
friend class detail::VariantAttorney;
|
friend class detail::VariantAttorney;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
JsonDocument(const JsonDocument&) = delete;
|
explicit JsonDocument(Allocator* alloc = detail::DefaultAllocator::instance())
|
||||||
JsonDocument& operator=(const JsonDocument&) = delete;
|
: resources_(alloc) {}
|
||||||
|
|
||||||
|
// Copy-constructor
|
||||||
|
JsonDocument(const JsonDocument& src) : JsonDocument(src.allocator()) {
|
||||||
|
set(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move-constructor
|
||||||
|
JsonDocument(JsonDocument&& src)
|
||||||
|
: JsonDocument(detail::DefaultAllocator::instance()) {
|
||||||
|
swap(*this, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct from variant, array, or object
|
||||||
|
template <typename T,
|
||||||
|
detail::enable_if_t<detail::IsVariant<T>::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,
|
||||||
|
int> = 0>
|
||||||
|
JsonDocument(const T& src,
|
||||||
|
Allocator* alloc = detail::DefaultAllocator::instance())
|
||||||
|
: JsonDocument(alloc) {
|
||||||
|
set(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonDocument& operator=(JsonDocument src) {
|
||||||
|
swap(*this, src);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
JsonDocument& operator=(const T& src) {
|
||||||
|
set(src);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Allocator* allocator() const {
|
||||||
|
return resources_.allocator();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduces the capacity of the memory pool to match the current usage.
|
||||||
|
// https://arduinojson.org/v7/api/jsondocument/shrinktofit/
|
||||||
|
void shrinkToFit() {
|
||||||
|
resources_.shrinkToFit();
|
||||||
|
}
|
||||||
|
|
||||||
// Casts the root to the specified type.
|
// Casts the root to the specified type.
|
||||||
// https://arduinojson.org/v6/api/jsondocument/as/
|
// https://arduinojson.org/v7/api/jsondocument/as/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T as() {
|
T as() {
|
||||||
return getVariant().template as<T>();
|
return getVariant().template as<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Casts the root to the specified type.
|
// Casts the root to the specified type.
|
||||||
// https://arduinojson.org/v6/api/jsondocument/as/
|
// https://arduinojson.org/v7/api/jsondocument/as/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T as() const {
|
T as() const {
|
||||||
return getVariant().template as<T>();
|
return getVariant().template as<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empties the document and resets the memory pool
|
// Empties the document and resets the memory pool
|
||||||
// https://arduinojson.org/v6/api/jsondocument/clear/
|
// https://arduinojson.org/v7/api/jsondocument/clear/
|
||||||
void clear() {
|
void clear() {
|
||||||
pool_.clear();
|
resources_.clear();
|
||||||
data_.setNull();
|
data_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the root is of the specified type.
|
// Returns true if the root is of the specified type.
|
||||||
// https://arduinojson.org/v6/api/jsondocument/is/
|
// https://arduinojson.org/v7/api/jsondocument/is/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool is() {
|
bool is() {
|
||||||
return getVariant().template is<T>();
|
return getVariant().template is<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the root is of the specified type.
|
// Returns true if the root is of the specified type.
|
||||||
// https://arduinojson.org/v6/api/jsondocument/is/
|
// https://arduinojson.org/v7/api/jsondocument/is/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool is() const {
|
bool is() const {
|
||||||
return getVariant().template is<T>();
|
return getVariant().template is<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the root is null.
|
// Returns true if the root is null.
|
||||||
// https://arduinojson.org/v6/api/jsondocument/isnull/
|
// https://arduinojson.org/v7/api/jsondocument/isnull/
|
||||||
bool isNull() const {
|
bool isNull() const {
|
||||||
return getVariant().isNull();
|
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.
|
// Returns trues if the memory pool was too small.
|
||||||
// https://arduinojson.org/v6/api/jsondocument/overflowed/
|
// https://arduinojson.org/v7/api/jsondocument/overflowed/
|
||||||
bool overflowed() const {
|
bool overflowed() const {
|
||||||
return pool_.overflowed();
|
return resources_.overflowed();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the depth (nesting level) of the array.
|
// Returns the depth (nesting level) of the array.
|
||||||
// https://arduinojson.org/v6/api/jsondocument/nesting/
|
// https://arduinojson.org/v7/api/jsondocument/nesting/
|
||||||
size_t nesting() const {
|
size_t nesting() const {
|
||||||
return variantNesting(&data_);
|
return data_.nesting(&resources_);
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
// Returns the number of elements in the root array or object.
|
||||||
// https://arduinojson.org/v6/api/jsondocument/size/
|
// https://arduinojson.org/v7/api/jsondocument/size/
|
||||||
size_t size() const {
|
size_t size() const {
|
||||||
return data_.size();
|
return data_.size(&resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copies the specified document.
|
// Copies the specified document.
|
||||||
// https://arduinojson.org/v6/api/jsondocument/set/
|
// https://arduinojson.org/v7/api/jsondocument/set/
|
||||||
bool set(const JsonDocument& src) {
|
bool set(const JsonDocument& src) {
|
||||||
return to<JsonVariant>().set(src.as<JsonVariantConst>());
|
return to<JsonVariant>().set(src.as<JsonVariantConst>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replaces the root with the specified value.
|
// Replaces the root with the specified value.
|
||||||
// https://arduinojson.org/v6/api/jsondocument/set/
|
// https://arduinojson.org/v7/api/jsondocument/set/
|
||||||
template <typename T>
|
template <
|
||||||
typename detail::enable_if<!detail::is_base_of<JsonDocument, T>::value,
|
typename T,
|
||||||
bool>::type
|
detail::enable_if_t<!detail::is_base_of<JsonDocument, T>::value, int> = 0>
|
||||||
set(const T& src) {
|
bool set(const T& src) {
|
||||||
|
return to<JsonVariant>().set(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replaces the root with the specified value.
|
||||||
|
// https://arduinojson.org/v7/api/jsondocument/set/
|
||||||
|
template <typename TChar,
|
||||||
|
detail::enable_if_t<!detail::is_const<TChar>::value, int> = 0>
|
||||||
|
bool set(TChar* src) {
|
||||||
return to<JsonVariant>().set(src);
|
return to<JsonVariant>().set(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clears the document and converts it to the specified type.
|
// Clears the document and converts it to the specified type.
|
||||||
// https://arduinojson.org/v6/api/jsondocument/to/
|
// https://arduinojson.org/v7/api/jsondocument/to/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename detail::VariantTo<T>::type to() {
|
typename detail::VariantTo<T>::type to() {
|
||||||
clear();
|
clear();
|
||||||
return getVariant().template to<T>();
|
return getVariant().template to<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates an array and appends it to the root array.
|
// DEPRECATED: use obj["key"].is<T>() instead
|
||||||
// https://arduinojson.org/v6/api/jsondocument/createnestedarray/
|
// https://arduinojson.org/v7/api/jsondocument/containskey/
|
||||||
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>
|
template <typename TChar>
|
||||||
|
ARDUINOJSON_DEPRECATED("use doc[\"key\"].is<T>() instead")
|
||||||
bool containsKey(TChar* key) const {
|
bool containsKey(TChar* key) const {
|
||||||
return data_.getMember(detail::adaptString(key)) != 0;
|
return data_.getMember(detail::adaptString(key), &resources_) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the root object contains the specified key.
|
// DEPRECATED: use obj[key].is<T>() instead
|
||||||
// https://arduinojson.org/v6/api/jsondocument/containskey/
|
// https://arduinojson.org/v7/api/jsondocument/containskey/
|
||||||
template <typename TString>
|
template <typename TString,
|
||||||
|
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||||
|
ARDUINOJSON_DEPRECATED("use doc[key].is<T>() instead")
|
||||||
bool containsKey(const TString& key) const {
|
bool containsKey(const TString& key) const {
|
||||||
return data_.getMember(detail::adaptString(key)) != 0;
|
return data_.getMember(detail::adaptString(key), &resources_) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED: use obj[key].is<T>() instead
|
||||||
|
// https://arduinojson.org/v7/api/jsondocument/containskey/
|
||||||
|
template <typename TVariant,
|
||||||
|
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||||
|
ARDUINOJSON_DEPRECATED("use doc[key].is<T>() instead")
|
||||||
|
bool containsKey(const TVariant& key) const {
|
||||||
|
return containsKey(key.template as<const char*>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets or sets a root object's member.
|
// Gets or sets a root object's member.
|
||||||
// https://arduinojson.org/v6/api/jsondocument/subscript/
|
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||||
template <typename TString>
|
template <typename TString,
|
||||||
FORCE_INLINE typename detail::enable_if<
|
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||||
detail::IsString<TString>::value,
|
detail::MemberProxy<JsonDocument&, detail::AdaptedString<TString>> operator[](
|
||||||
detail::MemberProxy<JsonDocument&, TString>>::type
|
const TString& key) {
|
||||||
operator[](const TString& key) {
|
return {*this, detail::adaptString(key)};
|
||||||
return {*this, key};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets or sets a root object's member.
|
// Gets or sets a root object's member.
|
||||||
// https://arduinojson.org/v6/api/jsondocument/subscript/
|
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||||
template <typename TChar>
|
template <typename TChar,
|
||||||
FORCE_INLINE typename detail::enable_if<
|
detail::enable_if_t<detail::IsString<TChar*>::value &&
|
||||||
detail::IsString<TChar*>::value,
|
!detail::is_const<TChar>::value,
|
||||||
detail::MemberProxy<JsonDocument&, TChar*>>::type
|
int> = 0>
|
||||||
operator[](TChar* key) {
|
detail::MemberProxy<JsonDocument&, detail::AdaptedString<TChar*>> operator[](
|
||||||
return {*this, key};
|
TChar* key) {
|
||||||
|
return {*this, detail::adaptString(key)};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets a root object's member.
|
// Gets a root object's member.
|
||||||
// https://arduinojson.org/v6/api/jsondocument/subscript/
|
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||||
template <typename TString>
|
template <typename TString,
|
||||||
FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value,
|
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||||
JsonVariantConst>::type
|
JsonVariantConst operator[](const TString& key) const {
|
||||||
operator[](const TString& key) const {
|
return JsonVariantConst(
|
||||||
return JsonVariantConst(data_.getMember(detail::adaptString(key)));
|
data_.getMember(detail::adaptString(key), &resources_), &resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets a root object's member.
|
// Gets a root object's member.
|
||||||
// https://arduinojson.org/v6/api/jsondocument/subscript/
|
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||||
template <typename TChar>
|
template <typename TChar,
|
||||||
FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value,
|
detail::enable_if_t<detail::IsString<TChar*>::value &&
|
||||||
JsonVariantConst>::type
|
!detail::is_const<TChar>::value,
|
||||||
operator[](TChar* key) const {
|
int> = 0>
|
||||||
return JsonVariantConst(data_.getMember(detail::adaptString(key)));
|
JsonVariantConst operator[](TChar* key) const {
|
||||||
|
return JsonVariantConst(
|
||||||
|
data_.getMember(detail::adaptString(key), &resources_), &resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets or sets a root array's element.
|
// Gets or sets a root array's element.
|
||||||
// https://arduinojson.org/v6/api/jsondocument/subscript/
|
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||||
FORCE_INLINE detail::ElementProxy<JsonDocument&> operator[](size_t index) {
|
template <typename T,
|
||||||
return {*this, index};
|
detail::enable_if_t<detail::is_integral<T>::value, int> = 0>
|
||||||
|
detail::ElementProxy<JsonDocument&> operator[](T index) {
|
||||||
|
return {*this, size_t(index)};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets a root array's member.
|
// Gets a root array's member.
|
||||||
// https://arduinojson.org/v6/api/jsondocument/subscript/
|
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||||
FORCE_INLINE JsonVariantConst operator[](size_t index) const {
|
JsonVariantConst operator[](size_t index) const {
|
||||||
return JsonVariantConst(data_.getElement(index));
|
return JsonVariantConst(data_.getElement(index, &resources_), &resources_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets or sets a root object's member.
|
||||||
|
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||||
|
template <typename TVariant,
|
||||||
|
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||||
|
JsonVariantConst operator[](const TVariant& key) const {
|
||||||
|
if (key.template is<JsonString>())
|
||||||
|
return operator[](key.template as<JsonString>());
|
||||||
|
if (key.template is<size_t>())
|
||||||
|
return operator[](key.template as<size_t>());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Appends a new (empty) element to the root array.
|
||||||
|
// Returns a reference to the new element.
|
||||||
|
// https://arduinojson.org/v7/api/jsondocument/add/
|
||||||
|
template <typename T, detail::enable_if_t<
|
||||||
|
!detail::is_same<T, JsonVariant>::value, int> = 0>
|
||||||
|
T add() {
|
||||||
|
return add<JsonVariant>().to<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Appends a new (null) element to the root array.
|
// Appends a new (null) element to the root array.
|
||||||
// Returns a reference to the new element.
|
// Returns a reference to the new element.
|
||||||
// https://arduinojson.org/v6/api/jsondocument/add/
|
// https://arduinojson.org/v7/api/jsondocument/add/
|
||||||
FORCE_INLINE JsonVariant add() {
|
template <typename T, detail::enable_if_t<
|
||||||
return JsonVariant(&pool_, data_.addElement(&pool_));
|
detail::is_same<T, JsonVariant>::value, int> = 0>
|
||||||
|
JsonVariant add() {
|
||||||
|
return JsonVariant(data_.addElement(&resources_), &resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Appends a value to the root array.
|
// Appends a value to the root array.
|
||||||
// https://arduinojson.org/v6/api/jsondocument/add/
|
// https://arduinojson.org/v7/api/jsondocument/add/
|
||||||
template <typename TValue>
|
template <typename TValue>
|
||||||
FORCE_INLINE bool add(const TValue& value) {
|
bool add(const TValue& value) {
|
||||||
return add().set(value);
|
return data_.addValue(value, &resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Appends a value to the root array.
|
// Appends a value to the root array.
|
||||||
// https://arduinojson.org/v6/api/jsondocument/add/
|
// https://arduinojson.org/v7/api/jsondocument/add/
|
||||||
template <typename TChar>
|
template <typename TChar,
|
||||||
FORCE_INLINE bool add(TChar* value) {
|
detail::enable_if_t<!detail::is_const<TChar>::value, int> = 0>
|
||||||
return add().set(value);
|
bool add(TChar* value) {
|
||||||
|
return data_.addValue(value, &resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes an element of the root array.
|
// Removes an element of the root array.
|
||||||
// ⚠️ Doesn't release the memory associated with the removed element.
|
// https://arduinojson.org/v7/api/jsondocument/remove/
|
||||||
// https://arduinojson.org/v6/api/jsondocument/remove/
|
template <typename T,
|
||||||
FORCE_INLINE void remove(size_t index) {
|
detail::enable_if_t<detail::is_integral<T>::value, int> = 0>
|
||||||
data_.remove(index);
|
void remove(T index) {
|
||||||
|
detail::VariantData::removeElement(getData(), size_t(index),
|
||||||
|
getResourceManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes a member of the root object.
|
// Removes a member of the root object.
|
||||||
// ⚠️ Doesn't release the memory associated with the removed element.
|
// https://arduinojson.org/v7/api/jsondocument/remove/
|
||||||
// https://arduinojson.org/v6/api/jsondocument/remove/
|
template <typename TChar,
|
||||||
|
detail::enable_if_t<detail::IsString<TChar*>::value &&
|
||||||
|
!detail::is_const<TChar>::value,
|
||||||
|
int> = 0>
|
||||||
|
void remove(TChar* key) {
|
||||||
|
detail::VariantData::removeMember(getData(), detail::adaptString(key),
|
||||||
|
getResourceManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes a member of the root object.
|
||||||
|
// https://arduinojson.org/v7/api/jsondocument/remove/
|
||||||
|
template <typename TString,
|
||||||
|
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||||
|
void remove(const TString& key) {
|
||||||
|
detail::VariantData::removeMember(getData(), detail::adaptString(key),
|
||||||
|
getResourceManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes a member of the root object or an element of the root array.
|
||||||
|
// https://arduinojson.org/v7/api/jsondocument/remove/
|
||||||
|
template <typename TVariant,
|
||||||
|
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||||
|
void remove(const TVariant& key) {
|
||||||
|
if (key.template is<const char*>())
|
||||||
|
remove(key.template as<const char*>());
|
||||||
|
if (key.template is<size_t>())
|
||||||
|
remove(key.template as<size_t>());
|
||||||
|
}
|
||||||
|
|
||||||
|
operator JsonVariant() {
|
||||||
|
return getVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
operator JsonVariantConst() const {
|
||||||
|
return getVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
friend void swap(JsonDocument& a, JsonDocument& b) {
|
||||||
|
swap(a.resources_, b.resources_);
|
||||||
|
swap_(a.data_, b.data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED: use add<JsonVariant>() instead
|
||||||
|
ARDUINOJSON_DEPRECATED("use add<JsonVariant>() instead")
|
||||||
|
JsonVariant add() {
|
||||||
|
return add<JsonVariant>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED: use add<JsonArray>() instead
|
||||||
|
ARDUINOJSON_DEPRECATED("use add<JsonArray>() instead")
|
||||||
|
JsonArray createNestedArray() {
|
||||||
|
return add<JsonArray>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED: use doc[key].to<JsonArray>() instead
|
||||||
template <typename TChar>
|
template <typename TChar>
|
||||||
FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value>::type
|
ARDUINOJSON_DEPRECATED("use doc[key].to<JsonArray>() instead")
|
||||||
remove(TChar* key) {
|
JsonArray createNestedArray(TChar* key) {
|
||||||
data_.remove(detail::adaptString(key));
|
return operator[](key).template to<JsonArray>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes a member of the root object.
|
// DEPRECATED: use doc[key].to<JsonArray>() instead
|
||||||
// ⚠️ Doesn't release the memory associated with the removed element.
|
|
||||||
// https://arduinojson.org/v6/api/jsondocument/remove/
|
|
||||||
template <typename TString>
|
template <typename TString>
|
||||||
FORCE_INLINE
|
ARDUINOJSON_DEPRECATED("use doc[key].to<JsonArray>() instead")
|
||||||
typename detail::enable_if<detail::IsString<TString>::value>::type
|
JsonArray createNestedArray(const TString& key) {
|
||||||
remove(const TString& key) {
|
return operator[](key).template to<JsonArray>();
|
||||||
data_.remove(detail::adaptString(key));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE operator JsonVariant() {
|
// DEPRECATED: use add<JsonObject>() instead
|
||||||
return getVariant();
|
ARDUINOJSON_DEPRECATED("use add<JsonObject>() instead")
|
||||||
|
JsonObject createNestedObject() {
|
||||||
|
return add<JsonObject>();
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE operator JsonVariantConst() const {
|
// DEPRECATED: use doc[key].to<JsonObject>() instead
|
||||||
return getVariant();
|
template <typename TChar>
|
||||||
|
ARDUINOJSON_DEPRECATED("use doc[key].to<JsonObject>() instead")
|
||||||
|
JsonObject createNestedObject(TChar* key) {
|
||||||
|
return operator[](key).template to<JsonObject>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
// DEPRECATED: use doc[key].to<JsonObject>() instead
|
||||||
JsonDocument() : pool_(0, 0) {}
|
template <typename TString>
|
||||||
|
ARDUINOJSON_DEPRECATED("use doc[key].to<JsonObject>() instead")
|
||||||
JsonDocument(detail::MemoryPool pool) : pool_(pool) {}
|
JsonObject createNestedObject(const TString& key) {
|
||||||
|
return operator[](key).template to<JsonObject>();
|
||||||
JsonDocument(char* buf, size_t capa) : pool_(buf, capa) {}
|
|
||||||
|
|
||||||
~JsonDocument() {}
|
|
||||||
|
|
||||||
void replacePool(detail::MemoryPool pool) {
|
|
||||||
pool_ = pool;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEPRECATED: always returns zero
|
||||||
|
ARDUINOJSON_DEPRECATED("always returns zero")
|
||||||
|
size_t memoryUsage() const {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
JsonVariant getVariant() {
|
JsonVariant getVariant() {
|
||||||
return JsonVariant(&pool_, &data_);
|
return JsonVariant(&data_, &resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonVariantConst getVariant() const {
|
JsonVariantConst getVariant() const {
|
||||||
return JsonVariantConst(&data_);
|
return JsonVariantConst(&data_, &resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::MemoryPool pool_;
|
detail::ResourceManager* getResourceManager() {
|
||||||
detail::VariantData data_;
|
return &resources_;
|
||||||
|
|
||||||
protected:
|
|
||||||
detail::MemoryPool* getPool() {
|
|
||||||
return &pool_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::VariantData* getData() {
|
detail::VariantData* getData() {
|
||||||
@ -316,6 +414,9 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
|||||||
detail::VariantData* getOrCreateData() {
|
detail::VariantData* getOrCreateData() {
|
||||||
return &data_;
|
return &data_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detail::ResourceManager resources_;
|
||||||
|
detail::VariantData data_;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void convertToJson(const JsonDocument& src, JsonVariant dst) {
|
inline void convertToJson(const JsonDocument& src, JsonVariant dst) {
|
||||||
|
|||||||
@ -1,61 +0,0 @@
|
|||||||
// 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
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -32,8 +32,8 @@ class EscapeSequence {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const char* escapeTable(bool excludeSolidus) {
|
static const char* escapeTable(bool isSerializing) {
|
||||||
return &"//\"\"\\\\b\bf\fn\nr\rt\t"[excludeSolidus ? 2 : 0];
|
return &"//''\"\"\\\\b\bf\fn\nr\rt\t"[isSerializing ? 4 : 0];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -9,7 +9,7 @@
|
|||||||
#include <ArduinoJson/Json/Latch.hpp>
|
#include <ArduinoJson/Json/Latch.hpp>
|
||||||
#include <ArduinoJson/Json/Utf16.hpp>
|
#include <ArduinoJson/Json/Utf16.hpp>
|
||||||
#include <ArduinoJson/Json/Utf8.hpp>
|
#include <ArduinoJson/Json/Utf8.hpp>
|
||||||
#include <ArduinoJson/Memory/MemoryPool.hpp>
|
#include <ArduinoJson/Memory/ResourceManager.hpp>
|
||||||
#include <ArduinoJson/Numbers/parseNumber.hpp>
|
#include <ArduinoJson/Numbers/parseNumber.hpp>
|
||||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||||
@ -18,15 +18,14 @@
|
|||||||
|
|
||||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
template <typename TReader, typename TStringStorage>
|
template <typename TReader>
|
||||||
class JsonDeserializer {
|
class JsonDeserializer {
|
||||||
public:
|
public:
|
||||||
JsonDeserializer(MemoryPool* pool, TReader reader,
|
JsonDeserializer(ResourceManager* resources, TReader reader)
|
||||||
TStringStorage stringStorage)
|
: stringBuilder_(resources),
|
||||||
: stringStorage_(stringStorage),
|
|
||||||
foundSomething_(false),
|
foundSomething_(false),
|
||||||
latch_(reader),
|
latch_(reader),
|
||||||
pool_(pool) {}
|
resources_(resources) {}
|
||||||
|
|
||||||
template <typename TFilter>
|
template <typename TFilter>
|
||||||
DeserializationError parse(VariantData& variant, TFilter filter,
|
DeserializationError parse(VariantData& variant, TFilter filter,
|
||||||
@ -35,7 +34,7 @@ class JsonDeserializer {
|
|||||||
|
|
||||||
err = parseVariant(variant, filter, nestingLimit);
|
err = parseVariant(variant, filter, nestingLimit);
|
||||||
|
|
||||||
if (!err && latch_.last() != 0 && !variant.isEnclosed()) {
|
if (!err && latch_.last() != 0 && variant.isFloat()) {
|
||||||
// We don't detect trailing characters earlier, so we need to check now
|
// We don't detect trailing characters earlier, so we need to check now
|
||||||
return DeserializationError::InvalidInput;
|
return DeserializationError::InvalidInput;
|
||||||
}
|
}
|
||||||
@ -147,7 +146,7 @@ class JsonDeserializer {
|
|||||||
|
|
||||||
template <typename TFilter>
|
template <typename TFilter>
|
||||||
DeserializationError::Code parseArray(
|
DeserializationError::Code parseArray(
|
||||||
CollectionData& array, TFilter filter,
|
ArrayData& array, TFilter filter,
|
||||||
DeserializationOption::NestingLimit nestingLimit) {
|
DeserializationOption::NestingLimit nestingLimit) {
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
|
|
||||||
@ -167,18 +166,18 @@ class JsonDeserializer {
|
|||||||
if (eat(']'))
|
if (eat(']'))
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
|
|
||||||
TFilter memberFilter = filter[0UL];
|
TFilter elementFilter = filter[0UL];
|
||||||
|
|
||||||
// Read each value
|
// Read each value
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (memberFilter.allow()) {
|
if (elementFilter.allow()) {
|
||||||
// Allocate slot in array
|
// Allocate slot in array
|
||||||
VariantData* value = array.addElement(pool_);
|
VariantData* value = array.addElement(resources_);
|
||||||
if (!value)
|
if (!value)
|
||||||
return DeserializationError::NoMemory;
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
// 1 - Parse value
|
// 1 - Parse value
|
||||||
err = parseVariant(*value, memberFilter, nestingLimit.decrement());
|
err = parseVariant(*value, elementFilter, nestingLimit.decrement());
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
} else {
|
} else {
|
||||||
@ -233,7 +232,7 @@ class JsonDeserializer {
|
|||||||
|
|
||||||
template <typename TFilter>
|
template <typename TFilter>
|
||||||
DeserializationError::Code parseObject(
|
DeserializationError::Code parseObject(
|
||||||
CollectionData& object, TFilter filter,
|
ObjectData& object, TFilter filter,
|
||||||
DeserializationOption::NestingLimit nestingLimit) {
|
DeserializationOption::NestingLimit nestingLimit) {
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
|
|
||||||
@ -269,29 +268,24 @@ class JsonDeserializer {
|
|||||||
if (!eat(':'))
|
if (!eat(':'))
|
||||||
return DeserializationError::InvalidInput;
|
return DeserializationError::InvalidInput;
|
||||||
|
|
||||||
JsonString key = stringStorage_.str();
|
JsonString key = stringBuilder_.str();
|
||||||
|
|
||||||
TFilter memberFilter = filter[key.c_str()];
|
TFilter memberFilter = filter[key];
|
||||||
|
|
||||||
if (memberFilter.allow()) {
|
if (memberFilter.allow()) {
|
||||||
VariantData* variant = object.getMember(adaptString(key.c_str()));
|
auto member = object.getMember(adaptString(key), resources_);
|
||||||
if (!variant) {
|
if (!member) {
|
||||||
// Save key in memory pool.
|
auto keyVariant = object.addPair(&member, resources_);
|
||||||
// This MUST be done before adding the slot.
|
if (!keyVariant)
|
||||||
key = stringStorage_.save();
|
|
||||||
|
|
||||||
// Allocate slot in object
|
|
||||||
VariantSlot* slot = object.addSlot(pool_);
|
|
||||||
if (!slot)
|
|
||||||
return DeserializationError::NoMemory;
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
slot->setKey(key);
|
stringBuilder_.save(keyVariant);
|
||||||
|
} else {
|
||||||
variant = slot->data();
|
member->clear(resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse value
|
// Parse value
|
||||||
err = parseVariant(*variant, memberFilter, nestingLimit.decrement());
|
err = parseVariant(*member, memberFilter, nestingLimit.decrement());
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
} else {
|
} else {
|
||||||
@ -377,7 +371,7 @@ class JsonDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError::Code parseKey() {
|
DeserializationError::Code parseKey() {
|
||||||
stringStorage_.startString();
|
stringBuilder_.startString();
|
||||||
if (isQuote(current())) {
|
if (isQuote(current())) {
|
||||||
return parseQuotedString();
|
return parseQuotedString();
|
||||||
} else {
|
} else {
|
||||||
@ -388,13 +382,13 @@ class JsonDeserializer {
|
|||||||
DeserializationError::Code parseStringValue(VariantData& variant) {
|
DeserializationError::Code parseStringValue(VariantData& variant) {
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
|
|
||||||
stringStorage_.startString();
|
stringBuilder_.startString();
|
||||||
|
|
||||||
err = parseQuotedString();
|
err = parseQuotedString();
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
variant.setString(stringStorage_.save());
|
stringBuilder_.save(&variant);
|
||||||
|
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
@ -430,9 +424,9 @@ class JsonDeserializer {
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
if (codepoint.append(codeunit))
|
if (codepoint.append(codeunit))
|
||||||
Utf8::encodeCodepoint(codepoint.value(), stringStorage_);
|
Utf8::encodeCodepoint(codepoint.value(), stringBuilder_);
|
||||||
#else
|
#else
|
||||||
stringStorage_.append('\\');
|
stringBuilder_.append('\\');
|
||||||
#endif
|
#endif
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -444,10 +438,10 @@ class JsonDeserializer {
|
|||||||
move();
|
move();
|
||||||
}
|
}
|
||||||
|
|
||||||
stringStorage_.append(c);
|
stringBuilder_.append(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stringStorage_.isValid())
|
if (!stringBuilder_.isValid())
|
||||||
return DeserializationError::NoMemory;
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
@ -460,14 +454,14 @@ class JsonDeserializer {
|
|||||||
if (canBeInNonQuotedString(c)) { // no quotes
|
if (canBeInNonQuotedString(c)) { // no quotes
|
||||||
do {
|
do {
|
||||||
move();
|
move();
|
||||||
stringStorage_.append(c);
|
stringBuilder_.append(c);
|
||||||
c = current();
|
c = current();
|
||||||
} while (canBeInNonQuotedString(c));
|
} while (canBeInNonQuotedString(c));
|
||||||
} else {
|
} else {
|
||||||
return DeserializationError::InvalidInput;
|
return DeserializationError::InvalidInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stringStorage_.isValid())
|
if (!stringBuilder_.isValid())
|
||||||
return DeserializationError::NoMemory;
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
@ -521,10 +515,37 @@ class JsonDeserializer {
|
|||||||
}
|
}
|
||||||
buffer_[n] = 0;
|
buffer_[n] = 0;
|
||||||
|
|
||||||
if (!parseNumber(buffer_, result))
|
auto number = parseNumber(buffer_);
|
||||||
return DeserializationError::InvalidInput;
|
switch (number.type()) {
|
||||||
|
case NumberType::UnsignedInteger:
|
||||||
|
if (result.setInteger(number.asUnsignedInteger(), resources_))
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
else
|
||||||
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
return DeserializationError::Ok;
|
case NumberType::SignedInteger:
|
||||||
|
if (result.setInteger(number.asSignedInteger(), resources_))
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
else
|
||||||
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
|
case NumberType::Float:
|
||||||
|
if (result.setFloat(number.asFloat(), resources_))
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
else
|
||||||
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
|
#if ARDUINOJSON_USE_DOUBLE
|
||||||
|
case NumberType::Double:
|
||||||
|
if (result.setFloat(number.asDouble(), resources_))
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
else
|
||||||
|
return DeserializationError::NoMemory;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError::Code skipNumericValue() {
|
DeserializationError::Code skipNumericValue() {
|
||||||
@ -659,10 +680,10 @@ class JsonDeserializer {
|
|||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
TStringStorage stringStorage_;
|
StringBuilder stringBuilder_;
|
||||||
bool foundSomething_;
|
bool foundSomething_;
|
||||||
Latch<TReader> latch_;
|
Latch<TReader> latch_;
|
||||||
MemoryPool* pool_;
|
ResourceManager* resources_;
|
||||||
char buffer_[64]; // using a member instead of a local variable because it
|
char buffer_[64]; // using a member instead of a local variable because it
|
||||||
// ended in the recursive path after compiler inlined the
|
// ended in the recursive path after compiler inlined the
|
||||||
// code
|
// code
|
||||||
@ -673,21 +694,27 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE
|
|||||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
// Parses a JSON input, filters, and puts the result in a JsonDocument.
|
// Parses a JSON input, filters, and puts the result in a JsonDocument.
|
||||||
// https://arduinojson.org/v6/api/json/deserializejson/
|
// https://arduinojson.org/v7/api/json/deserializejson/
|
||||||
template <typename... Args>
|
template <typename TDestination, typename... Args,
|
||||||
DeserializationError deserializeJson(JsonDocument& doc, Args&&... args) {
|
detail::enable_if_t<
|
||||||
|
detail::is_deserialize_destination<TDestination>::value, int> = 0>
|
||||||
|
inline DeserializationError deserializeJson(TDestination&& dst,
|
||||||
|
Args&&... args) {
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
return deserialize<JsonDeserializer>(doc, detail::forward<Args>(args)...);
|
return deserialize<JsonDeserializer>(detail::forward<TDestination>(dst),
|
||||||
}
|
|
||||||
|
|
||||||
// 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)...);
|
detail::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parses a JSON input, filters, and puts the result in a JsonDocument.
|
||||||
|
// https://arduinojson.org/v7/api/json/deserializejson/
|
||||||
|
template <typename TDestination, typename TChar, typename... Args,
|
||||||
|
detail::enable_if_t<
|
||||||
|
detail::is_deserialize_destination<TDestination>::value, int> = 0>
|
||||||
|
inline DeserializationError deserializeJson(TDestination&& dst, TChar* input,
|
||||||
|
Args&&... args) {
|
||||||
|
using namespace detail;
|
||||||
|
return deserialize<JsonDeserializer>(detail::forward<TDestination>(dst),
|
||||||
|
input, detail::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -7,93 +7,98 @@
|
|||||||
#include <ArduinoJson/Json/TextFormatter.hpp>
|
#include <ArduinoJson/Json/TextFormatter.hpp>
|
||||||
#include <ArduinoJson/Serialization/measure.hpp>
|
#include <ArduinoJson/Serialization/measure.hpp>
|
||||||
#include <ArduinoJson/Serialization/serialize.hpp>
|
#include <ArduinoJson/Serialization/serialize.hpp>
|
||||||
#include <ArduinoJson/Variant/Visitor.hpp>
|
#include <ArduinoJson/Variant/VariantDataVisitor.hpp>
|
||||||
|
|
||||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
template <typename TWriter>
|
template <typename TWriter>
|
||||||
class JsonSerializer : public Visitor<size_t> {
|
class JsonSerializer : public VariantDataVisitor<size_t> {
|
||||||
public:
|
public:
|
||||||
static const bool producesText = true;
|
static const bool producesText = true;
|
||||||
|
|
||||||
JsonSerializer(TWriter writer) : formatter_(writer) {}
|
JsonSerializer(TWriter writer, const ResourceManager* resources)
|
||||||
|
: formatter_(writer), resources_(resources) {}
|
||||||
|
|
||||||
FORCE_INLINE size_t visitArray(const CollectionData& array) {
|
size_t visit(const ArrayData& array) {
|
||||||
write('[');
|
write('[');
|
||||||
|
|
||||||
const VariantSlot* slot = array.head();
|
auto slotId = array.head();
|
||||||
|
|
||||||
while (slot != 0) {
|
while (slotId != NULL_SLOT) {
|
||||||
slot->data()->accept(*this);
|
auto slot = resources_->getVariant(slotId);
|
||||||
|
|
||||||
slot = slot->next();
|
slot->accept(*this, resources_);
|
||||||
if (slot == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
write(',');
|
slotId = slot->next();
|
||||||
|
|
||||||
|
if (slotId != NULL_SLOT)
|
||||||
|
write(',');
|
||||||
}
|
}
|
||||||
|
|
||||||
write(']');
|
write(']');
|
||||||
return bytesWritten();
|
return bytesWritten();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t visitObject(const CollectionData& object) {
|
size_t visit(const ObjectData& object) {
|
||||||
write('{');
|
write('{');
|
||||||
|
|
||||||
const VariantSlot* slot = object.head();
|
auto slotId = object.head();
|
||||||
|
|
||||||
while (slot != 0) {
|
bool isKey = true;
|
||||||
formatter_.writeString(slot->key());
|
|
||||||
write(':');
|
|
||||||
slot->data()->accept(*this);
|
|
||||||
|
|
||||||
slot = slot->next();
|
while (slotId != NULL_SLOT) {
|
||||||
if (slot == 0)
|
auto slot = resources_->getVariant(slotId);
|
||||||
break;
|
slot->accept(*this, resources_);
|
||||||
|
|
||||||
write(',');
|
slotId = slot->next();
|
||||||
|
|
||||||
|
if (slotId != NULL_SLOT)
|
||||||
|
write(isKey ? ':' : ',');
|
||||||
|
|
||||||
|
isKey = !isKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
write('}');
|
write('}');
|
||||||
return bytesWritten();
|
return bytesWritten();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t visitFloat(JsonFloat value) {
|
template <typename T>
|
||||||
|
enable_if_t<is_floating_point<T>::value, size_t> visit(T value) {
|
||||||
formatter_.writeFloat(value);
|
formatter_.writeFloat(value);
|
||||||
return bytesWritten();
|
return bytesWritten();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t visitString(const char* value) {
|
size_t visit(const char* value) {
|
||||||
formatter_.writeString(value);
|
formatter_.writeString(value);
|
||||||
return bytesWritten();
|
return bytesWritten();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t visitString(const char* value, size_t n) {
|
size_t visit(JsonString value) {
|
||||||
formatter_.writeString(value, n);
|
formatter_.writeString(value.c_str(), value.size());
|
||||||
return bytesWritten();
|
return bytesWritten();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t visitRawJson(const char* data, size_t n) {
|
size_t visit(RawString value) {
|
||||||
formatter_.writeRaw(data, n);
|
formatter_.writeRaw(value.data(), value.size());
|
||||||
return bytesWritten();
|
return bytesWritten();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t visitSignedInteger(JsonInteger value) {
|
size_t visit(JsonInteger value) {
|
||||||
formatter_.writeInteger(value);
|
formatter_.writeInteger(value);
|
||||||
return bytesWritten();
|
return bytesWritten();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t visitUnsignedInteger(JsonUInt value) {
|
size_t visit(JsonUInt value) {
|
||||||
formatter_.writeInteger(value);
|
formatter_.writeInteger(value);
|
||||||
return bytesWritten();
|
return bytesWritten();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t visitBoolean(bool value) {
|
size_t visit(bool value) {
|
||||||
formatter_.writeBoolean(value);
|
formatter_.writeBoolean(value);
|
||||||
return bytesWritten();
|
return bytesWritten();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t visitNull() {
|
size_t visit(nullptr_t) {
|
||||||
formatter_.writeRaw("null");
|
formatter_.writeRaw("null");
|
||||||
return bytesWritten();
|
return bytesWritten();
|
||||||
}
|
}
|
||||||
@ -113,6 +118,9 @@ class JsonSerializer : public Visitor<size_t> {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
TextFormatter<TWriter> formatter_;
|
TextFormatter<TWriter> formatter_;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const ResourceManager* resources_;
|
||||||
};
|
};
|
||||||
|
|
||||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
@ -120,15 +128,17 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE
|
|||||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
// Produces a minified JSON document.
|
// Produces a minified JSON document.
|
||||||
// https://arduinojson.org/v6/api/json/serializejson/
|
// https://arduinojson.org/v7/api/json/serializejson/
|
||||||
template <typename TDestination>
|
template <
|
||||||
|
typename TDestination,
|
||||||
|
detail::enable_if_t<!detail::is_pointer<TDestination>::value, int> = 0>
|
||||||
size_t serializeJson(JsonVariantConst source, TDestination& destination) {
|
size_t serializeJson(JsonVariantConst source, TDestination& destination) {
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
return serialize<JsonSerializer>(source, destination);
|
return serialize<JsonSerializer>(source, destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Produces a minified JSON document.
|
// Produces a minified JSON document.
|
||||||
// https://arduinojson.org/v6/api/json/serializejson/
|
// https://arduinojson.org/v7/api/json/serializejson/
|
||||||
inline size_t serializeJson(JsonVariantConst source, void* buffer,
|
inline size_t serializeJson(JsonVariantConst source, void* buffer,
|
||||||
size_t bufferSize) {
|
size_t bufferSize) {
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
@ -136,17 +146,17 @@ inline size_t serializeJson(JsonVariantConst source, void* buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Computes the length of the document that serializeJson() produces.
|
// Computes the length of the document that serializeJson() produces.
|
||||||
// https://arduinojson.org/v6/api/json/measurejson/
|
// https://arduinojson.org/v7/api/json/measurejson/
|
||||||
inline size_t measureJson(JsonVariantConst source) {
|
inline size_t measureJson(JsonVariantConst source) {
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
return measure<JsonSerializer>(source);
|
return measure<JsonSerializer>(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ARDUINOJSON_ENABLE_STD_STREAM
|
#if ARDUINOJSON_ENABLE_STD_STREAM
|
||||||
template <typename T>
|
template <typename T,
|
||||||
inline typename detail::enable_if<
|
detail::enable_if_t<
|
||||||
detail::is_convertible<T, JsonVariantConst>::value, std::ostream&>::type
|
detail::is_convertible<T, JsonVariantConst>::value, int> = 0>
|
||||||
operator<<(std::ostream& os, const T& source) {
|
inline std::ostream& operator<<(std::ostream& os, const T& source) {
|
||||||
serializeJson(source, os);
|
serializeJson(source, os);
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -13,22 +13,23 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
|||||||
|
|
||||||
template <typename TWriter>
|
template <typename TWriter>
|
||||||
class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
||||||
typedef JsonSerializer<TWriter> base;
|
using base = JsonSerializer<TWriter>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PrettyJsonSerializer(TWriter writer) : base(writer), nesting_(0) {}
|
PrettyJsonSerializer(TWriter writer, const ResourceManager* resources)
|
||||||
|
: base(writer, resources), nesting_(0) {}
|
||||||
|
|
||||||
size_t visitArray(const CollectionData& array) {
|
size_t visit(const ArrayData& array) {
|
||||||
const VariantSlot* slot = array.head();
|
auto it = array.createIterator(base::resources_);
|
||||||
if (slot) {
|
if (!it.done()) {
|
||||||
base::write("[\r\n");
|
base::write("[\r\n");
|
||||||
nesting_++;
|
nesting_++;
|
||||||
while (slot != 0) {
|
while (!it.done()) {
|
||||||
indent();
|
indent();
|
||||||
slot->data()->accept(*this);
|
it->accept(*this, base::resources_);
|
||||||
|
|
||||||
slot = slot->next();
|
it.next(base::resources_);
|
||||||
base::write(slot ? ",\r\n" : "\r\n");
|
base::write(it.done() ? "\r\n" : ",\r\n");
|
||||||
}
|
}
|
||||||
nesting_--;
|
nesting_--;
|
||||||
indent();
|
indent();
|
||||||
@ -39,19 +40,22 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
|||||||
return this->bytesWritten();
|
return this->bytesWritten();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t visitObject(const CollectionData& object) {
|
size_t visit(const ObjectData& object) {
|
||||||
const VariantSlot* slot = object.head();
|
auto it = object.createIterator(base::resources_);
|
||||||
if (slot) {
|
if (!it.done()) {
|
||||||
base::write("{\r\n");
|
base::write("{\r\n");
|
||||||
nesting_++;
|
nesting_++;
|
||||||
while (slot != 0) {
|
bool isKey = true;
|
||||||
indent();
|
while (!it.done()) {
|
||||||
base::visitString(slot->key());
|
if (isKey)
|
||||||
base::write(": ");
|
indent();
|
||||||
slot->data()->accept(*this);
|
it->accept(*this, base::resources_);
|
||||||
|
it.next(base::resources_);
|
||||||
slot = slot->next();
|
if (isKey)
|
||||||
base::write(slot ? ",\r\n" : "\r\n");
|
base::write(": ");
|
||||||
|
else
|
||||||
|
base::write(it.done() ? "\r\n" : ",\r\n");
|
||||||
|
isKey = !isKey;
|
||||||
}
|
}
|
||||||
nesting_--;
|
nesting_--;
|
||||||
indent();
|
indent();
|
||||||
@ -62,6 +66,8 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
|||||||
return this->bytesWritten();
|
return this->bytesWritten();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using base::visit;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void indent() {
|
void indent() {
|
||||||
for (uint8_t i = 0; i < nesting_; i++)
|
for (uint8_t i = 0; i < nesting_; i++)
|
||||||
@ -76,15 +82,18 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE
|
|||||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
// Produces JsonDocument to create a prettified JSON document.
|
// Produces JsonDocument to create a prettified JSON document.
|
||||||
// https://arduinojson.org/v6/api/json/serializejsonpretty/
|
// https://arduinojson.org/v7/api/json/serializejsonpretty/
|
||||||
template <typename TDestination>
|
template <
|
||||||
size_t serializeJsonPretty(JsonVariantConst source, TDestination& destination) {
|
typename TDestination,
|
||||||
|
detail::enable_if_t<!detail::is_pointer<TDestination>::value, int> = 0>
|
||||||
|
inline size_t serializeJsonPretty(JsonVariantConst source,
|
||||||
|
TDestination& destination) {
|
||||||
using namespace ArduinoJson::detail;
|
using namespace ArduinoJson::detail;
|
||||||
return serialize<PrettyJsonSerializer>(source, destination);
|
return serialize<PrettyJsonSerializer>(source, destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Produces JsonDocument to create a prettified JSON document.
|
// Produces JsonDocument to create a prettified JSON document.
|
||||||
// https://arduinojson.org/v6/api/json/serializejsonpretty/
|
// https://arduinojson.org/v7/api/json/serializejsonpretty/
|
||||||
inline size_t serializeJsonPretty(JsonVariantConst source, void* buffer,
|
inline size_t serializeJsonPretty(JsonVariantConst source, void* buffer,
|
||||||
size_t bufferSize) {
|
size_t bufferSize) {
|
||||||
using namespace ArduinoJson::detail;
|
using namespace ArduinoJson::detail;
|
||||||
@ -92,7 +101,7 @@ inline size_t serializeJsonPretty(JsonVariantConst source, void* buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Computes the length of the document that serializeJsonPretty() produces.
|
// Computes the length of the document that serializeJsonPretty() produces.
|
||||||
// https://arduinojson.org/v6/api/json/measurejsonpretty/
|
// https://arduinojson.org/v7/api/json/measurejsonpretty/
|
||||||
inline size_t measureJsonPretty(JsonVariantConst source) {
|
inline size_t measureJsonPretty(JsonVariantConst source) {
|
||||||
using namespace ArduinoJson::detail;
|
using namespace ArduinoJson::detail;
|
||||||
return measure<PrettyJsonSerializer>(source);
|
return measure<PrettyJsonSerializer>(source);
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -66,6 +66,10 @@ class TextFormatter {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void writeFloat(T value) {
|
void writeFloat(T value) {
|
||||||
|
writeFloat(JsonFloat(value), sizeof(T) >= 8 ? 9 : 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeFloat(JsonFloat value, int8_t decimalPlaces) {
|
||||||
if (isnan(value))
|
if (isnan(value))
|
||||||
return writeRaw(ARDUINOJSON_ENABLE_NAN ? "NaN" : "null");
|
return writeRaw(ARDUINOJSON_ENABLE_NAN ? "NaN" : "null");
|
||||||
|
|
||||||
@ -87,7 +91,7 @@ class TextFormatter {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FloatParts<T> parts(value);
|
auto parts = decomposeFloat(value, decimalPlaces);
|
||||||
|
|
||||||
writeInteger(parts.integral);
|
writeInteger(parts.integral);
|
||||||
if (parts.decimalPlaces)
|
if (parts.decimalPlaces)
|
||||||
@ -100,8 +104,8 @@ class TextFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename enable_if<is_signed<T>::value>::type writeInteger(T value) {
|
enable_if_t<is_signed<T>::value> writeInteger(T value) {
|
||||||
typedef typename make_unsigned<T>::type unsigned_type;
|
using unsigned_type = make_unsigned_t<T>;
|
||||||
unsigned_type unsigned_value;
|
unsigned_type unsigned_value;
|
||||||
if (value < 0) {
|
if (value < 0) {
|
||||||
writeRaw('-');
|
writeRaw('-');
|
||||||
@ -113,7 +117,7 @@ class TextFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename enable_if<is_unsigned<T>::value>::type writeInteger(T value) {
|
enable_if_t<is_unsigned<T>::value> writeInteger(T value) {
|
||||||
char buffer[22];
|
char buffer[22];
|
||||||
char* end = buffer + sizeof(buffer);
|
char* end = buffer + sizeof(buffer);
|
||||||
char* begin = end;
|
char* begin = end;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|||||||
@ -0,0 +1,49 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
|
||||||
|
#include <stdlib.h> // malloc, free
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||||
|
|
||||||
|
class Allocator {
|
||||||
|
public:
|
||||||
|
virtual void* allocate(size_t size) = 0;
|
||||||
|
virtual void deallocate(void* ptr) = 0;
|
||||||
|
virtual void* reallocate(void* ptr, size_t new_size) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~Allocator() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
class DefaultAllocator : public Allocator {
|
||||||
|
public:
|
||||||
|
void* allocate(size_t size) override {
|
||||||
|
return malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(void* ptr) override {
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* reallocate(void* ptr, size_t new_size) override {
|
||||||
|
return realloc(ptr, new_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Allocator* instance() {
|
||||||
|
static DefaultAllocator allocator;
|
||||||
|
return &allocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
DefaultAllocator() = default;
|
||||||
|
~DefaultAllocator() = default;
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||||
@ -1,253 +1,110 @@
|
|||||||
// ArduinoJson - https://arduinojson.org
|
// ArduinoJson - https://arduinojson.org
|
||||||
// Copyright © 2014-2023, Benoit BLANCHON
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
// MIT License
|
// MIT License
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ArduinoJson/Memory/Alignment.hpp>
|
#include <ArduinoJson/Memory/Allocator.hpp>
|
||||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||||
#include <ArduinoJson/Polyfills/mpl/max.hpp>
|
#include <ArduinoJson/Polyfills/integer.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
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
// begin_ end_
|
using SlotId = uint_t<ARDUINOJSON_SLOT_ID_SIZE * 8>;
|
||||||
// v v
|
using SlotCount = SlotId;
|
||||||
// +-------------+--------------+--------------+
|
const SlotId NULL_SLOT = SlotId(-1);
|
||||||
// | strings... | (free) | ...variants |
|
|
||||||
// +-------------+--------------+--------------+
|
|
||||||
// ^ ^
|
|
||||||
// left_ right_
|
|
||||||
|
|
||||||
class MemoryPool {
|
template <typename T>
|
||||||
|
class Slot {
|
||||||
public:
|
public:
|
||||||
MemoryPool(char* buf, size_t capa)
|
Slot() : ptr_(nullptr), id_(NULL_SLOT) {}
|
||||||
: begin_(buf),
|
Slot(T* p, SlotId id) : ptr_(p), id_(id) {
|
||||||
left_(buf),
|
ARDUINOJSON_ASSERT((p == nullptr) == (id == NULL_SLOT));
|
||||||
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() {
|
explicit operator bool() const {
|
||||||
return begin_; // NOLINT(clang-analyzer-unix.Malloc)
|
return ptr_ != nullptr;
|
||||||
// movePointers() alters this pointer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the capacity of the memoryPool in bytes
|
SlotId id() const {
|
||||||
size_t capacity() const {
|
return id_;
|
||||||
return size_t(end_ - begin_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size() const {
|
T* ptr() const {
|
||||||
return size_t(left_ - begin_ + end_ - right_);
|
return ptr_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool overflowed() const {
|
T* operator->() const {
|
||||||
return overflowed_;
|
ARDUINOJSON_ASSERT(ptr_ != nullptr);
|
||||||
}
|
return ptr_;
|
||||||
|
|
||||||
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:
|
private:
|
||||||
void checkInvariants() {
|
T* ptr_;
|
||||||
ARDUINOJSON_ASSERT(begin_ <= left_);
|
SlotId id_;
|
||||||
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>
|
template <typename T>
|
||||||
bool storeString(MemoryPool* pool, TAdaptedString str,
|
class MemoryPool {
|
||||||
StringStoragePolicy::Copy, TCallback callback) {
|
public:
|
||||||
const char* copy = pool->saveString(str);
|
void create(SlotCount cap, Allocator* allocator) {
|
||||||
JsonString storedString(copy, str.size(), JsonString::Copied);
|
ARDUINOJSON_ASSERT(cap > 0);
|
||||||
callback(storedString);
|
slots_ = reinterpret_cast<T*>(allocator->allocate(slotsToBytes(cap)));
|
||||||
return copy != 0;
|
capacity_ = slots_ ? cap : 0;
|
||||||
}
|
usage_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename TAdaptedString, typename TCallback>
|
void destroy(Allocator* allocator) {
|
||||||
bool storeString(MemoryPool*, TAdaptedString str, StringStoragePolicy::Link,
|
if (slots_)
|
||||||
TCallback callback) {
|
allocator->deallocate(slots_);
|
||||||
JsonString storedString(str.data(), str.size(), JsonString::Linked);
|
slots_ = nullptr;
|
||||||
callback(storedString);
|
capacity_ = 0;
|
||||||
return !str.isNull();
|
usage_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TAdaptedString, typename TCallback>
|
Slot<T> allocSlot() {
|
||||||
bool storeString(MemoryPool* pool, TAdaptedString str,
|
if (!slots_)
|
||||||
StringStoragePolicy::LinkOrCopy policy, TCallback callback) {
|
return {};
|
||||||
if (policy.link)
|
if (usage_ >= capacity_)
|
||||||
return storeString(pool, str, StringStoragePolicy::Link(), callback);
|
return {};
|
||||||
else
|
auto index = usage_++;
|
||||||
return storeString(pool, str, StringStoragePolicy::Copy(), callback);
|
return {slots_ + index, SlotId(index)};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TAdaptedString, typename TCallback>
|
T* getSlot(SlotId id) const {
|
||||||
bool storeString(MemoryPool* pool, TAdaptedString str, TCallback callback) {
|
ARDUINOJSON_ASSERT(id < usage_);
|
||||||
return storeString(pool, str, str.storagePolicy(), callback);
|
return slots_ + id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
usage_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void shrinkToFit(Allocator* allocator) {
|
||||||
|
auto newSlots = reinterpret_cast<T*>(
|
||||||
|
allocator->reallocate(slots_, slotsToBytes(usage_)));
|
||||||
|
if (newSlots) {
|
||||||
|
slots_ = newSlots;
|
||||||
|
capacity_ = usage_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SlotCount usage() const {
|
||||||
|
return usage_;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SlotCount bytesToSlots(size_t n) {
|
||||||
|
return static_cast<SlotCount>(n / sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t slotsToBytes(SlotCount n) {
|
||||||
|
return n * sizeof(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SlotCount capacity_;
|
||||||
|
SlotCount usage_;
|
||||||
|
T* slots_;
|
||||||
|
};
|
||||||
|
|
||||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
|
|||||||
@ -0,0 +1,214 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Memory/MemoryPool.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/utility.hpp>
|
||||||
|
|
||||||
|
#include <string.h> // memcpy
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
using PoolCount = SlotId;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class MemoryPoolList {
|
||||||
|
struct FreeSlot {
|
||||||
|
SlotId next;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(FreeSlot) <= sizeof(T), "T is too small");
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Pool = MemoryPool<T>;
|
||||||
|
|
||||||
|
MemoryPoolList() = default;
|
||||||
|
|
||||||
|
~MemoryPoolList() {
|
||||||
|
ARDUINOJSON_ASSERT(count_ == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend void swap(MemoryPoolList& a, MemoryPoolList& b) {
|
||||||
|
bool aUsedPreallocated = a.pools_ == a.preallocatedPools_;
|
||||||
|
bool bUsedPreallocated = b.pools_ == b.preallocatedPools_;
|
||||||
|
|
||||||
|
// Who is using preallocated pools?
|
||||||
|
if (aUsedPreallocated && bUsedPreallocated) {
|
||||||
|
// both of us => swap preallocated pools
|
||||||
|
for (PoolCount i = 0; i < ARDUINOJSON_INITIAL_POOL_COUNT; i++)
|
||||||
|
swap_(a.preallocatedPools_[i], b.preallocatedPools_[i]);
|
||||||
|
} else if (bUsedPreallocated) {
|
||||||
|
// only b => copy b's preallocated pools and give him a's pointer
|
||||||
|
for (PoolCount i = 0; i < b.count_; i++)
|
||||||
|
a.preallocatedPools_[i] = b.preallocatedPools_[i];
|
||||||
|
b.pools_ = a.pools_;
|
||||||
|
a.pools_ = a.preallocatedPools_;
|
||||||
|
} else if (aUsedPreallocated) {
|
||||||
|
// only a => copy a's preallocated pools and give him b's pointer
|
||||||
|
for (PoolCount i = 0; i < a.count_; i++)
|
||||||
|
b.preallocatedPools_[i] = a.preallocatedPools_[i];
|
||||||
|
a.pools_ = b.pools_;
|
||||||
|
b.pools_ = b.preallocatedPools_;
|
||||||
|
} else {
|
||||||
|
// neither => swap pointers
|
||||||
|
swap_(a.pools_, b.pools_);
|
||||||
|
}
|
||||||
|
|
||||||
|
swap_(a.count_, b.count_);
|
||||||
|
swap_(a.capacity_, b.capacity_);
|
||||||
|
swap_(a.freeList_, b.freeList_);
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryPoolList& operator=(MemoryPoolList&& src) {
|
||||||
|
ARDUINOJSON_ASSERT(count_ == 0);
|
||||||
|
if (src.pools_ == src.preallocatedPools_) {
|
||||||
|
memcpy(preallocatedPools_, src.preallocatedPools_,
|
||||||
|
sizeof(preallocatedPools_));
|
||||||
|
pools_ = preallocatedPools_;
|
||||||
|
} else {
|
||||||
|
pools_ = src.pools_;
|
||||||
|
src.pools_ = nullptr;
|
||||||
|
}
|
||||||
|
count_ = src.count_;
|
||||||
|
capacity_ = src.capacity_;
|
||||||
|
src.count_ = 0;
|
||||||
|
src.capacity_ = 0;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Slot<T> allocSlot(Allocator* allocator) {
|
||||||
|
// try to allocate from free list
|
||||||
|
if (freeList_ != NULL_SLOT) {
|
||||||
|
return allocFromFreeList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to allocate from last pool (other pools are full)
|
||||||
|
if (count_) {
|
||||||
|
auto slot = allocFromLastPool();
|
||||||
|
if (slot)
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new pool and try again
|
||||||
|
auto pool = addPool(allocator);
|
||||||
|
if (!pool)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return allocFromLastPool();
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeSlot(Slot<T> slot) {
|
||||||
|
reinterpret_cast<FreeSlot*>(slot.ptr())->next = freeList_;
|
||||||
|
freeList_ = slot.id();
|
||||||
|
}
|
||||||
|
|
||||||
|
T* getSlot(SlotId id) const {
|
||||||
|
if (id == NULL_SLOT)
|
||||||
|
return nullptr;
|
||||||
|
auto poolIndex = SlotId(id / ARDUINOJSON_POOL_CAPACITY);
|
||||||
|
auto indexInPool = SlotId(id % ARDUINOJSON_POOL_CAPACITY);
|
||||||
|
ARDUINOJSON_ASSERT(poolIndex < count_);
|
||||||
|
return pools_[poolIndex].getSlot(indexInPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear(Allocator* allocator) {
|
||||||
|
for (PoolCount i = 0; i < count_; i++)
|
||||||
|
pools_[i].destroy(allocator);
|
||||||
|
count_ = 0;
|
||||||
|
freeList_ = NULL_SLOT;
|
||||||
|
if (pools_ != preallocatedPools_) {
|
||||||
|
allocator->deallocate(pools_);
|
||||||
|
pools_ = preallocatedPools_;
|
||||||
|
capacity_ = ARDUINOJSON_INITIAL_POOL_COUNT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SlotCount usage() const {
|
||||||
|
SlotCount total = 0;
|
||||||
|
for (PoolCount i = 0; i < count_; i++)
|
||||||
|
total = SlotCount(total + pools_[i].usage());
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const {
|
||||||
|
return Pool::slotsToBytes(usage());
|
||||||
|
}
|
||||||
|
|
||||||
|
void shrinkToFit(Allocator* allocator) {
|
||||||
|
if (count_ > 0)
|
||||||
|
pools_[count_ - 1].shrinkToFit(allocator);
|
||||||
|
if (pools_ != preallocatedPools_ && count_ != capacity_) {
|
||||||
|
pools_ = static_cast<Pool*>(
|
||||||
|
allocator->reallocate(pools_, count_ * sizeof(Pool)));
|
||||||
|
ARDUINOJSON_ASSERT(pools_ != nullptr); // realloc to smaller can't fail
|
||||||
|
capacity_ = count_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Slot<T> allocFromFreeList() {
|
||||||
|
ARDUINOJSON_ASSERT(freeList_ != NULL_SLOT);
|
||||||
|
auto id = freeList_;
|
||||||
|
auto slot = getSlot(freeList_);
|
||||||
|
freeList_ = reinterpret_cast<FreeSlot*>(slot)->next;
|
||||||
|
return {slot, id};
|
||||||
|
}
|
||||||
|
|
||||||
|
Slot<T> allocFromLastPool() {
|
||||||
|
ARDUINOJSON_ASSERT(count_ > 0);
|
||||||
|
auto poolIndex = SlotId(count_ - 1);
|
||||||
|
auto slot = pools_[poolIndex].allocSlot();
|
||||||
|
if (!slot)
|
||||||
|
return {};
|
||||||
|
return {slot.ptr(),
|
||||||
|
SlotId(poolIndex * ARDUINOJSON_POOL_CAPACITY + slot.id())};
|
||||||
|
}
|
||||||
|
|
||||||
|
Pool* addPool(Allocator* allocator) {
|
||||||
|
if (count_ == capacity_ && !increaseCapacity(allocator))
|
||||||
|
return nullptr;
|
||||||
|
auto pool = &pools_[count_++];
|
||||||
|
SlotCount poolCapacity = ARDUINOJSON_POOL_CAPACITY;
|
||||||
|
if (count_ == maxPools) // last pool is smaller because of NULL_SLOT
|
||||||
|
poolCapacity--;
|
||||||
|
pool->create(poolCapacity, allocator);
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool increaseCapacity(Allocator* allocator) {
|
||||||
|
if (capacity_ == maxPools)
|
||||||
|
return false;
|
||||||
|
void* newPools;
|
||||||
|
auto newCapacity = PoolCount(capacity_ * 2);
|
||||||
|
|
||||||
|
if (pools_ == preallocatedPools_) {
|
||||||
|
newPools = allocator->allocate(newCapacity * sizeof(Pool));
|
||||||
|
if (!newPools)
|
||||||
|
return false;
|
||||||
|
memcpy(newPools, preallocatedPools_, sizeof(preallocatedPools_));
|
||||||
|
} else {
|
||||||
|
newPools = allocator->reallocate(pools_, newCapacity * sizeof(Pool));
|
||||||
|
if (!newPools)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pools_ = static_cast<Pool*>(newPools);
|
||||||
|
capacity_ = newCapacity;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pool preallocatedPools_[ARDUINOJSON_INITIAL_POOL_COUNT];
|
||||||
|
Pool* pools_ = preallocatedPools_;
|
||||||
|
PoolCount count_ = 0;
|
||||||
|
PoolCount capacity_ = ARDUINOJSON_INITIAL_POOL_COUNT;
|
||||||
|
SlotId freeList_ = NULL_SLOT;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const PoolCount maxPools =
|
||||||
|
PoolCount(NULL_SLOT / ARDUINOJSON_POOL_CAPACITY + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
@ -0,0 +1,131 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Memory/Allocator.hpp>
|
||||||
|
#include <ArduinoJson/Memory/MemoryPoolList.hpp>
|
||||||
|
#include <ArduinoJson/Memory/StringPool.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/utility.hpp>
|
||||||
|
#include <ArduinoJson/Strings/StringAdapters.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
class VariantData;
|
||||||
|
class VariantWithId;
|
||||||
|
|
||||||
|
class ResourceManager {
|
||||||
|
union SlotData {
|
||||||
|
VariantData variant;
|
||||||
|
#if ARDUINOJSON_USE_EXTENSIONS
|
||||||
|
VariantExtension extension;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
constexpr static size_t slotSize = sizeof(SlotData);
|
||||||
|
|
||||||
|
ResourceManager(Allocator* allocator = DefaultAllocator::instance())
|
||||||
|
: allocator_(allocator), overflowed_(false) {}
|
||||||
|
|
||||||
|
~ResourceManager() {
|
||||||
|
stringPool_.clear(allocator_);
|
||||||
|
variantPools_.clear(allocator_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceManager(const ResourceManager&) = delete;
|
||||||
|
ResourceManager& operator=(const ResourceManager& src) = delete;
|
||||||
|
|
||||||
|
friend void swap(ResourceManager& a, ResourceManager& b) {
|
||||||
|
swap(a.stringPool_, b.stringPool_);
|
||||||
|
swap(a.variantPools_, b.variantPools_);
|
||||||
|
swap_(a.allocator_, b.allocator_);
|
||||||
|
swap_(a.overflowed_, b.overflowed_);
|
||||||
|
}
|
||||||
|
|
||||||
|
Allocator* allocator() const {
|
||||||
|
return allocator_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const {
|
||||||
|
return variantPools_.size() + stringPool_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool overflowed() const {
|
||||||
|
return overflowed_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Slot<VariantData> allocVariant();
|
||||||
|
void freeVariant(Slot<VariantData> slot);
|
||||||
|
VariantData* getVariant(SlotId id) const;
|
||||||
|
|
||||||
|
#if ARDUINOJSON_USE_EXTENSIONS
|
||||||
|
Slot<VariantExtension> allocExtension();
|
||||||
|
void freeExtension(SlotId slot);
|
||||||
|
VariantExtension* getExtension(SlotId id) const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename TAdaptedString>
|
||||||
|
StringNode* saveString(TAdaptedString str) {
|
||||||
|
if (str.isNull())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
auto node = stringPool_.add(str, allocator_);
|
||||||
|
if (!node)
|
||||||
|
overflowed_ = true;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveString(StringNode* node) {
|
||||||
|
stringPool_.add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TAdaptedString>
|
||||||
|
StringNode* getString(const TAdaptedString& str) const {
|
||||||
|
return stringPool_.get(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringNode* createString(size_t length) {
|
||||||
|
auto node = StringNode::create(length, allocator_);
|
||||||
|
if (!node)
|
||||||
|
overflowed_ = true;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringNode* resizeString(StringNode* node, size_t length) {
|
||||||
|
node = StringNode::resize(node, length, allocator_);
|
||||||
|
if (!node)
|
||||||
|
overflowed_ = true;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroyString(StringNode* node) {
|
||||||
|
StringNode::destroy(node, allocator_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dereferenceString(const char* s) {
|
||||||
|
stringPool_.dereference(s, allocator_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
variantPools_.clear(allocator_);
|
||||||
|
overflowed_ = false;
|
||||||
|
stringPool_.clear(allocator_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shrinkToFit() {
|
||||||
|
variantPools_.shrinkToFit(allocator_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Allocator* allocator_;
|
||||||
|
bool overflowed_;
|
||||||
|
StringPool stringPool_;
|
||||||
|
MemoryPoolList<SlotData> variantPools_;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Collection/CollectionData.hpp>
|
||||||
|
#include <ArduinoJson/Memory/ResourceManager.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/alias_cast.hpp>
|
||||||
|
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
inline Slot<VariantData> ResourceManager::allocVariant() {
|
||||||
|
auto p = variantPools_.allocSlot(allocator_);
|
||||||
|
if (!p) {
|
||||||
|
overflowed_ = true;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return {new (&p->variant) VariantData, p.id()};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ResourceManager::freeVariant(Slot<VariantData> variant) {
|
||||||
|
variant->clear(this);
|
||||||
|
variantPools_.freeSlot({alias_cast<SlotData*>(variant.ptr()), variant.id()});
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VariantData* ResourceManager::getVariant(SlotId id) const {
|
||||||
|
return reinterpret_cast<VariantData*>(variantPools_.getSlot(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ARDUINOJSON_USE_EXTENSIONS
|
||||||
|
inline Slot<VariantExtension> ResourceManager::allocExtension() {
|
||||||
|
auto p = variantPools_.allocSlot(allocator_);
|
||||||
|
if (!p) {
|
||||||
|
overflowed_ = true;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return {&p->extension, p.id()};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ResourceManager::freeExtension(SlotId id) {
|
||||||
|
auto p = getExtension(id);
|
||||||
|
variantPools_.freeSlot({reinterpret_cast<SlotData*>(p), id});
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VariantExtension* ResourceManager::getExtension(SlotId id) const {
|
||||||
|
return &variantPools_.getSlot(id)->extension;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
@ -0,0 +1,79 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Memory/ResourceManager.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
class StringBuffer {
|
||||||
|
public:
|
||||||
|
StringBuffer(ResourceManager* resources) : resources_(resources) {}
|
||||||
|
|
||||||
|
~StringBuffer() {
|
||||||
|
if (node_)
|
||||||
|
resources_->destroyString(node_);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* reserve(size_t capacity) {
|
||||||
|
if (node_ && capacity > node_->length) {
|
||||||
|
// existing buffer is too small, we need to reallocate
|
||||||
|
resources_->destroyString(node_);
|
||||||
|
node_ = nullptr;
|
||||||
|
}
|
||||||
|
if (!node_)
|
||||||
|
node_ = resources_->createString(capacity);
|
||||||
|
if (!node_)
|
||||||
|
return nullptr;
|
||||||
|
size_ = capacity;
|
||||||
|
node_->data[capacity] = 0; // null-terminate the string
|
||||||
|
return node_->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonString str() const {
|
||||||
|
ARDUINOJSON_ASSERT(node_ != nullptr);
|
||||||
|
return JsonString(node_->data, node_->length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void save(VariantData* data) {
|
||||||
|
ARDUINOJSON_ASSERT(node_ != nullptr);
|
||||||
|
const char* s = node_->data;
|
||||||
|
if (isTinyString(s, size_))
|
||||||
|
data->setTinyString(adaptString(s, size_));
|
||||||
|
else
|
||||||
|
data->setOwnedString(commitStringNode());
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveRaw(VariantData* data) {
|
||||||
|
data->setRawString(commitStringNode());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
StringNode* commitStringNode() {
|
||||||
|
ARDUINOJSON_ASSERT(node_ != nullptr);
|
||||||
|
node_->data[size_] = 0;
|
||||||
|
auto node = resources_->getString(adaptString(node_->data, size_));
|
||||||
|
if (node) {
|
||||||
|
node->references++;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node_->length != size_) {
|
||||||
|
node = resources_->resizeString(node_, size_);
|
||||||
|
ARDUINOJSON_ASSERT(node != nullptr); // realloc to smaller can't fail
|
||||||
|
} else {
|
||||||
|
node = node_;
|
||||||
|
}
|
||||||
|
node_ = nullptr;
|
||||||
|
resources_->saveString(node);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceManager* resources_;
|
||||||
|
StringNode* node_ = nullptr;
|
||||||
|
size_t size_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
@ -0,0 +1,88 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Memory/ResourceManager.hpp>
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
class StringBuilder {
|
||||||
|
public:
|
||||||
|
static const size_t initialCapacity = 31;
|
||||||
|
|
||||||
|
StringBuilder(ResourceManager* resources) : resources_(resources) {}
|
||||||
|
|
||||||
|
~StringBuilder() {
|
||||||
|
if (node_)
|
||||||
|
resources_->destroyString(node_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void startString() {
|
||||||
|
size_ = 0;
|
||||||
|
if (!node_)
|
||||||
|
node_ = resources_->createString(initialCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void save(VariantData* variant) {
|
||||||
|
ARDUINOJSON_ASSERT(variant != nullptr);
|
||||||
|
ARDUINOJSON_ASSERT(node_ != nullptr);
|
||||||
|
|
||||||
|
char* p = node_->data;
|
||||||
|
if (isTinyString(p, size_)) {
|
||||||
|
variant->setTinyString(adaptString(p, size_));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
p[size_] = 0;
|
||||||
|
StringNode* node = resources_->getString(adaptString(p, size_));
|
||||||
|
if (!node) {
|
||||||
|
node = resources_->resizeString(node_, size_);
|
||||||
|
ARDUINOJSON_ASSERT(node != nullptr); // realloc to smaller can't fail
|
||||||
|
resources_->saveString(node);
|
||||||
|
node_ = nullptr; // next time we need a new string
|
||||||
|
} else {
|
||||||
|
node->references++;
|
||||||
|
}
|
||||||
|
variant->setOwnedString(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(const char* s) {
|
||||||
|
while (*s)
|
||||||
|
append(*s++);
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(const char* s, size_t n) {
|
||||||
|
while (n-- > 0) // TODO: memcpy
|
||||||
|
append(*s++);
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(char c) {
|
||||||
|
if (node_ && size_ == node_->length)
|
||||||
|
node_ = resources_->resizeString(node_, size_ * 2U + 1);
|
||||||
|
if (node_)
|
||||||
|
node_->data[size_++] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid() const {
|
||||||
|
return node_ != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const {
|
||||||
|
return size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonString str() const {
|
||||||
|
ARDUINOJSON_ASSERT(node_ != nullptr);
|
||||||
|
node_->data[size_] = 0;
|
||||||
|
return JsonString(node_->data, size_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ResourceManager* resources_;
|
||||||
|
StringNode* node_ = nullptr;
|
||||||
|
size_t size_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright © 2014-2025, Benoit BLANCHON
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Memory/Allocator.hpp>
|
||||||
|
#include <ArduinoJson/Namespace.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/integer.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/limits.hpp>
|
||||||
|
|
||||||
|
#include <stddef.h> // offsetof
|
||||||
|
|
||||||
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
struct StringNode {
|
||||||
|
// Use the same type as SlotId to store the reference count
|
||||||
|
// (there can never be more references than slots)
|
||||||
|
using references_type = uint_t<ARDUINOJSON_SLOT_ID_SIZE * 8>;
|
||||||
|
|
||||||
|
using length_type = uint_t<ARDUINOJSON_STRING_LENGTH_SIZE * 8>;
|
||||||
|
|
||||||
|
struct StringNode* next;
|
||||||
|
references_type references;
|
||||||
|
length_type length;
|
||||||
|
char data[1];
|
||||||
|
|
||||||
|
static constexpr size_t maxLength = numeric_limits<length_type>::highest();
|
||||||
|
|
||||||
|
static constexpr size_t sizeForLength(size_t n) {
|
||||||
|
return n + 1 + offsetof(StringNode, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static StringNode* create(size_t length, Allocator* allocator) {
|
||||||
|
if (length > maxLength)
|
||||||
|
return nullptr;
|
||||||
|
auto size = sizeForLength(length);
|
||||||
|
if (size < length) // integer overflow
|
||||||
|
return nullptr; // (not testable on 64-bit)
|
||||||
|
auto node = reinterpret_cast<StringNode*>(allocator->allocate(size));
|
||||||
|
if (node) {
|
||||||
|
node->length = length_type(length);
|
||||||
|
node->references = 1;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static StringNode* resize(StringNode* node, size_t length,
|
||||||
|
Allocator* allocator) {
|
||||||
|
ARDUINOJSON_ASSERT(node != nullptr);
|
||||||
|
StringNode* newNode;
|
||||||
|
if (length <= maxLength)
|
||||||
|
newNode = reinterpret_cast<StringNode*>(
|
||||||
|
allocator->reallocate(node, sizeForLength(length)));
|
||||||
|
else
|
||||||
|
newNode = nullptr;
|
||||||
|
if (newNode)
|
||||||
|
newNode->length = length_type(length);
|
||||||
|
else
|
||||||
|
allocator->deallocate(node);
|
||||||
|
return newNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy(StringNode* node, Allocator* allocator) {
|
||||||
|
allocator->deallocate(node);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns the size (in bytes) of an string with n characters.
|
||||||
|
constexpr size_t sizeofString(size_t n) {
|
||||||
|
return StringNode::sizeForLength(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user