mirror of
https://github.com/nlohmann/json.git
synced 2026-08-08 10:13:20 +00:00
Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21af527e75 | ||
|
|
23518f54fe | ||
|
|
1c136a66c4 | ||
|
|
c1c19a7bcd | ||
|
|
bacdabd176 | ||
|
|
d5647e6a3b | ||
|
|
9a091d2b82 | ||
|
|
b890b4cba3 | ||
|
|
dca9d49a33 | ||
|
|
acd87e2336 |
@@ -38,14 +38,14 @@ jobs:
|
|||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
|
uses: github/codeql-action/init@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4
|
||||||
with:
|
with:
|
||||||
languages: c-cpp
|
languages: c-cpp
|
||||||
|
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
|
uses: github/codeql-action/autobuild@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
|
uses: github/codeql-action/analyze@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4
|
||||||
|
|||||||
@@ -43,6 +43,6 @@ jobs:
|
|||||||
output: 'flawfinder_results.sarif'
|
output: 'flawfinder_results.sarif'
|
||||||
|
|
||||||
- name: Upload analysis results to GitHub Security tab
|
- name: Upload analysis results to GitHub Security tab
|
||||||
uses: github/codeql-action/upload-sarif@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
|
uses: github/codeql-action/upload-sarif@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4
|
||||||
with:
|
with:
|
||||||
sarif_file: ${{github.workspace}}/flawfinder_results.sarif
|
sarif_file: ${{github.workspace}}/flawfinder_results.sarif
|
||||||
|
|||||||
@@ -76,6 +76,6 @@ jobs:
|
|||||||
|
|
||||||
# Upload the results to GitHub's code scanning dashboard.
|
# Upload the results to GitHub's code scanning dashboard.
|
||||||
- name: "Upload to code-scanning"
|
- name: "Upload to code-scanning"
|
||||||
uses: github/codeql-action/upload-sarif@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
|
uses: github/codeql-action/upload-sarif@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ jobs:
|
|||||||
|
|
||||||
# Upload SARIF file generated in previous step
|
# Upload SARIF file generated in previous step
|
||||||
- name: Upload SARIF file
|
- name: Upload SARIF file
|
||||||
uses: github/codeql-action/upload-sarif@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
|
uses: github/codeql-action/upload-sarif@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4
|
||||||
with:
|
with:
|
||||||
sarif_file: semgrep.sarif
|
sarif_file: semgrep.sarif
|
||||||
if: always()
|
if: always()
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Get latest CMake and ninja
|
- name: Get latest CMake and ninja
|
||||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1
|
||||||
- name: Run CMake
|
- name: Run CMake
|
||||||
run: cmake -S . -B build -DJSON_CI=On
|
run: cmake -S . -B build -DJSON_CI=On
|
||||||
- name: Build
|
- name: Build
|
||||||
@@ -47,7 +47,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Get latest CMake and ninja
|
- name: Get latest CMake and ninja
|
||||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1
|
||||||
- name: Run CMake
|
- name: Run CMake
|
||||||
run: cmake -S . -B build -DJSON_CI=On
|
run: cmake -S . -B build -DJSON_CI=On
|
||||||
- name: Build
|
- name: Build
|
||||||
@@ -70,7 +70,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Get latest CMake and ninja
|
- name: Get latest CMake and ninja
|
||||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1
|
||||||
- name: Run CMake
|
- name: Run CMake
|
||||||
run: cmake -S . -B build -DJSON_CI=On
|
run: cmake -S . -B build -DJSON_CI=On
|
||||||
- name: Build
|
- name: Build
|
||||||
@@ -89,7 +89,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Get latest CMake and ninja
|
- name: Get latest CMake and ninja
|
||||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1
|
||||||
- name: Run CMake
|
- name: Run CMake
|
||||||
run: cmake -S . -B build -DJSON_CI=On
|
run: cmake -S . -B build -DJSON_CI=On
|
||||||
- name: Build
|
- name: Build
|
||||||
@@ -108,7 +108,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Get latest CMake and ninja
|
- name: Get latest CMake and ninja
|
||||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1
|
||||||
- name: Run CMake
|
- name: Run CMake
|
||||||
run: cmake -S . -B build -DJSON_CI=On
|
run: cmake -S . -B build -DJSON_CI=On
|
||||||
- name: Build
|
- name: Build
|
||||||
@@ -184,7 +184,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Get latest CMake and ninja
|
- name: Get latest CMake and ninja
|
||||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1
|
||||||
- name: Run CMake
|
- name: Run CMake
|
||||||
run: CXX=g++-${{ matrix.compiler }} cmake -S . -B build -DJSON_CI=On
|
run: CXX=g++-${{ matrix.compiler }} cmake -S . -B build -DJSON_CI=On
|
||||||
- name: Build
|
- name: Build
|
||||||
@@ -202,7 +202,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Get latest CMake and ninja
|
- name: Get latest CMake and ninja
|
||||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1
|
||||||
- name: Run CMake
|
- name: Run CMake
|
||||||
run: cmake -S . -B build -DJSON_CI=On
|
run: cmake -S . -B build -DJSON_CI=On
|
||||||
- name: Build
|
- name: Build
|
||||||
@@ -212,14 +212,14 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
compiler: ['3.4', '3.5', '3.6', '3.7', '3.8', '3.9', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15-bullseye', '16', '17', '18', '19', '20', 'latest']
|
compiler: ['3.4', '3.5', '3.6', '3.7', '3.8', '3.9', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15-bullseye', '16', '17', '18', '19', '20', '21', '22', 'latest']
|
||||||
container: silkeh/clang:${{ matrix.compiler }}
|
container: silkeh/clang:${{ matrix.compiler }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Get latest CMake and ninja
|
- name: Get latest CMake and ninja
|
||||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1
|
||||||
- name: Set env FORCE_STDCPPFS_FLAG for clang 7 / 8 / 9 / 10
|
- name: Set env FORCE_STDCPPFS_FLAG for clang 7 / 8 / 9 / 10
|
||||||
run: echo "JSON_FORCED_GLOBAL_COMPILE_OPTIONS=-DJSON_HAS_FILESYSTEM=0;-DJSON_HAS_EXPERIMENTAL_FILESYSTEM=0" >> "$GITHUB_ENV"
|
run: echo "JSON_FORCED_GLOBAL_COMPILE_OPTIONS=-DJSON_HAS_FILESYSTEM=0;-DJSON_HAS_EXPERIMENTAL_FILESYSTEM=0" >> "$GITHUB_ENV"
|
||||||
if: ${{ matrix.compiler == '7' || matrix.compiler == '8' || matrix.compiler == '9' || matrix.compiler == '10' }}
|
if: ${{ matrix.compiler == '7' || matrix.compiler == '8' || matrix.compiler == '9' || matrix.compiler == '10' }}
|
||||||
@@ -239,7 +239,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Get latest CMake and ninja
|
- name: Get latest CMake and ninja
|
||||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1
|
||||||
- name: Run CMake
|
- name: Run CMake
|
||||||
run: cmake -S . -B build -DJSON_CI=On
|
run: cmake -S . -B build -DJSON_CI=On
|
||||||
- name: Build
|
- name: Build
|
||||||
@@ -259,7 +259,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Get latest CMake and ninja
|
- name: Get latest CMake and ninja
|
||||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1
|
||||||
- name: Run CMake
|
- name: Run CMake
|
||||||
run: cmake -S . -B build -DJSON_CI=On
|
run: cmake -S . -B build -DJSON_CI=On
|
||||||
- name: Build with libc++
|
- name: Build with libc++
|
||||||
@@ -286,7 +286,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Get latest CMake and ninja
|
- name: Get latest CMake and ninja
|
||||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1
|
||||||
- name: Run CMake
|
- name: Run CMake
|
||||||
run: cmake -S . -B build -DJSON_CI=On
|
run: cmake -S . -B build -DJSON_CI=On
|
||||||
- name: Build
|
- name: Build
|
||||||
@@ -306,7 +306,7 @@ jobs:
|
|||||||
# import-std support. Its opt-in token is CMake-version-specific, so pin
|
# import-std support. Its opt-in token is CMake-version-specific, so pin
|
||||||
# CMake to the version whose token is set in tests/module_cpp20/CMakeLists.txt.
|
# CMake to the version whose token is set in tests/module_cpp20/CMakeLists.txt.
|
||||||
- name: Get pinned CMake and ninja
|
- name: Get pinned CMake and ninja
|
||||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1
|
||||||
with:
|
with:
|
||||||
cmakeVersion: 4.3.4
|
cmakeVersion: 4.3.4
|
||||||
# Clang: the std library module is provided by libc++ (the image's libstdc++
|
# Clang: the std library module is provided by libc++ (the image's libstdc++
|
||||||
@@ -332,7 +332,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Get latest CMake and ninja
|
- name: Get latest CMake and ninja
|
||||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1
|
||||||
- name: Run CMake
|
- name: Run CMake
|
||||||
run: cmake -S . -B build -DJSON_CI=On
|
run: cmake -S . -B build -DJSON_CI=On
|
||||||
- name: Build
|
- name: Build
|
||||||
@@ -347,7 +347,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
- name: Get latest CMake and ninja
|
- name: Get latest CMake and ninja
|
||||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1
|
||||||
- name: Run CMake
|
- name: Run CMake
|
||||||
run: cmake -S . -B build -DJSON_CI=On
|
run: cmake -S . -B build -DJSON_CI=On
|
||||||
- name: Build
|
- name: Build
|
||||||
@@ -359,7 +359,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
- name: Get latest CMake and ninja
|
- name: Get latest CMake and ninja
|
||||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1
|
||||||
- name: Run CMake
|
- name: Run CMake
|
||||||
run: cmake -S . -B build -DJSON_CI=On
|
run: cmake -S . -B build -DJSON_CI=On
|
||||||
- name: Build
|
- name: Build
|
||||||
@@ -379,7 +379,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Get latest CMake and ninja
|
- name: Get latest CMake and ninja
|
||||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1
|
||||||
- name: Run CMake
|
- name: Run CMake
|
||||||
run: cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -GNinja
|
run: cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -GNinja
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
- name: Get latest CMake and ninja
|
- name: Get latest CMake and ninja
|
||||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1
|
||||||
- name: Set extra CXX_FLAGS for latest std_version
|
- name: Set extra CXX_FLAGS for latest std_version
|
||||||
# /wd5285 silences C5285 emitted by the bundled third-party doctest.h, which
|
# /wd5285 silences C5285 emitted by the bundled third-party doctest.h, which
|
||||||
# specializes std::tuple (newly diagnosed by the VS2026 v145 toolset)
|
# specializes std::tuple (newly diagnosed by the VS2026 v145 toolset)
|
||||||
@@ -153,10 +153,16 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
platform: x64
|
platform: x64
|
||||||
version: 12.2.0 # https://github.com/egor-tensin/setup-mingw/issues/14
|
version: 12.2.0 # https://github.com/egor-tensin/setup-mingw/issues/14
|
||||||
|
# CMAKE_CXX_FLAGS_DEBUG is overridden to drop the default -g: linking
|
||||||
|
# test-regression2_cpp20 intermittently fails with "relocation truncated
|
||||||
|
# to fit: IMAGE_REL_AMD64_SECREL against `.debug_line'" because the
|
||||||
|
# MinGW linker cannot relocate the debug sections this test produces.
|
||||||
|
# The tests are only built and run here, so the debug info is not used.
|
||||||
- name: Run CMake
|
- name: Run CMake
|
||||||
run: cmake -S . -B build ^
|
run: cmake -S . -B build ^
|
||||||
-DCMAKE_CXX_COMPILER="C:/Program Files/LLVM/bin/clang++.exe" ^
|
-DCMAKE_CXX_COMPILER="C:/Program Files/LLVM/bin/clang++.exe" ^
|
||||||
-DCMAKE_CXX_FLAGS="--target=x86_64-w64-mingw32 -stdlib=libstdc++ -pthread" ^
|
-DCMAKE_CXX_FLAGS="--target=x86_64-w64-mingw32 -stdlib=libstdc++ -pthread" ^
|
||||||
|
-DCMAKE_CXX_FLAGS_DEBUG="-g0" ^
|
||||||
-DCMAKE_EXE_LINKER_FLAGS="-lwinpthread" ^
|
-DCMAKE_EXE_LINKER_FLAGS="-lwinpthread" ^
|
||||||
-G"MinGW Makefiles" ^
|
-G"MinGW Makefiles" ^
|
||||||
-DCMAKE_BUILD_TYPE=Debug ^
|
-DCMAKE_BUILD_TYPE=Debug ^
|
||||||
@@ -193,7 +199,7 @@ jobs:
|
|||||||
# import-std support. Its opt-in token is CMake-version-specific, so pin
|
# import-std support. Its opt-in token is CMake-version-specific, so pin
|
||||||
# CMake to the version whose token is set in tests/module_cpp20/CMakeLists.txt.
|
# CMake to the version whose token is set in tests/module_cpp20/CMakeLists.txt.
|
||||||
- name: Get pinned CMake and ninja
|
- name: Get pinned CMake and ninja
|
||||||
uses: lukka/get-cmake@e6906078ebd1ccb8ce51ab4626ac46a1b5a517e3 # v4.4.0
|
uses: lukka/get-cmake@4a7d025fc60f00db0c7b44ebf783d19b52444830 # v4.4.1
|
||||||
with:
|
with:
|
||||||
cmakeVersion: 4.3.4
|
cmakeVersion: 4.3.4
|
||||||
- name: Run CMake (Debug)
|
- name: Run CMake (Debug)
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
- [Specializing enum conversion](#specializing-enum-conversion)
|
- [Specializing enum conversion](#specializing-enum-conversion)
|
||||||
- [Binary formats (BSON, CBOR, MessagePack, UBJSON, and BJData)](#binary-formats-bson-cbor-messagepack-ubjson-and-bjdata)
|
- [Binary formats (BSON, CBOR, MessagePack, UBJSON, and BJData)](#binary-formats-bson-cbor-messagepack-ubjson-and-bjdata)
|
||||||
- [Customers](#customers)
|
- [Customers](#customers)
|
||||||
|
- [Ecosystem](#ecosystem)
|
||||||
- [Supported compilers](#supported-compilers)
|
- [Supported compilers](#supported-compilers)
|
||||||
- [Integration](#integration)
|
- [Integration](#integration)
|
||||||
- [CMake](#cmake)
|
- [CMake](#cmake)
|
||||||
@@ -1186,6 +1187,11 @@ The library is used in multiple projects, applications, operating systems, etc.
|
|||||||
|
|
||||||
[](https://json.nlohmann.me/home/customers/)
|
[](https://json.nlohmann.me/home/customers/)
|
||||||
|
|
||||||
|
## Ecosystem
|
||||||
|
|
||||||
|
Beyond projects that use the library, there are third-party projects that build on top of it - schema validators,
|
||||||
|
language bindings, format converters, and the like. See the curated [Ecosystem](https://json.nlohmann.me/community/ecosystem/) page.
|
||||||
|
|
||||||
## Supported compilers
|
## Supported compilers
|
||||||
|
|
||||||
Though it's 2026 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work:
|
Though it's 2026 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work:
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# Ecosystem
|
||||||
|
|
||||||
|
The projects below build on top of `nlohmann::json` rather than merely using it - schema validators, language
|
||||||
|
bindings, format converters, and similar building blocks. The list is not exhaustive, and is curated rather than
|
||||||
|
automatically generated. If you maintain or know of a project that belongs here,
|
||||||
|
[please let me know](mailto:mail@nlohmann.me).
|
||||||
|
|
||||||
|
For products, applications, and organizations that use the library, see [Customers](../home/customers.md) instead.
|
||||||
|
|
||||||
|
## Schema validation
|
||||||
|
|
||||||
|
- [**json-schema-validator**](https://github.com/pboettch/json-schema-validator), a JSON Schema (draft 7) validator
|
||||||
|
with human-readable error messages
|
||||||
|
|
||||||
|
## Serialization and reflection
|
||||||
|
|
||||||
|
- [**nlohmann_json_reflect**](https://github.com/1261385937/nlohmann_json_reflect), a reflection extension for
|
||||||
|
(de)serializing nested containers-in-structs-in-containers
|
||||||
|
|
||||||
|
## Encodings
|
||||||
|
|
||||||
|
- [**base-encode-decode**](https://github.com/saxonnicholls/base-encode-decode), a header-only Base64/32/16/8/4/2
|
||||||
|
(and DNA/RNA) encoding library, with an adapter that serializes binary data through `nlohmann::json`
|
||||||
|
|
||||||
|
## Language bindings and interop
|
||||||
|
|
||||||
|
- [**pybind11_json**](https://github.com/pybind/pybind11_json), a bidirectional type caster between
|
||||||
|
`nlohmann::json` and Python objects for [pybind11](https://github.com/pybind/pybind11) bindings
|
||||||
|
- [**nanobind_json**](https://github.com/ianhbell/nanobind_json), the same idea for
|
||||||
|
[nanobind](https://github.com/wjakob/nanobind) bindings
|
||||||
|
- [**nlohmann_json_qt**](https://github.com/dpurgin/nlohmann_json_qt), deserialization helpers for Qt types
|
||||||
|
(`QString`, `QUrl`, `QDateTime`, `QVector`, ...) from `nlohmann::json`
|
||||||
|
- [**vulkan2json**](https://github.com/Fadis/vulkan2json), serialization and deserialization of Vulkan API structs
|
||||||
|
|
||||||
|
## Format converters
|
||||||
|
|
||||||
|
- [**tojson**](https://github.com/mircodz/tojson), a header-only converter between YAML/XML documents and
|
||||||
|
`nlohmann::json`
|
||||||
|
- [**json2xml**](https://github.com/testillano/json2xml), a header-only converter from `nlohmann::json` to XML for
|
||||||
|
simple configuration documents
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
# Community
|
# Community
|
||||||
|
|
||||||
|
- [Ecosystem](ecosystem.md) - third-party projects built on top of this library
|
||||||
- [Code of Conduct](code_of_conduct.md) - the rules and norms of this project
|
- [Code of Conduct](code_of_conduct.md) - the rules and norms of this project
|
||||||
- [Contribution Guidelines](contribution_guidelines.md) - guidelines how to contribute to this project
|
- [Contribution Guidelines](contribution_guidelines.md) - guidelines how to contribute to this project
|
||||||
- [Governance](governance.md) - the governance model of this project
|
- [Governance](governance.md) - the governance model of this project
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ Note: Some modern features (like C++20 ranges or filesystem support) may be disa
|
|||||||
| Clang 20.1.1 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
|
| Clang 20.1.1 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
|
||||||
| Clang 20.1.8 with GNU-like command-line | x86_64 | Windows Server 2022 (Build 20348) | GitHub |
|
| Clang 20.1.8 with GNU-like command-line | x86_64 | Windows Server 2022 (Build 20348) | GitHub |
|
||||||
| Clang 21.1.8 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
|
| Clang 21.1.8 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
|
||||||
|
| Clang 22.1.8 | x86_64 | Ubuntu 22.04.1 LTS | GitHub |
|
||||||
| CUDA 11.8.0 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub |
|
| CUDA 11.8.0 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub |
|
||||||
| CUDA 12.1.1 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub |
|
| CUDA 12.1.1 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub |
|
||||||
| CUDA 12.6.3 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub |
|
| CUDA 12.6.3 (nvcc) | x86_64 | Ubuntu 22.04 LTS | GitHub |
|
||||||
|
|||||||
@@ -116,9 +116,19 @@ The library uses the following mapping from JSON values types to BJData types ac
|
|||||||
```
|
```
|
||||||
|
|
||||||
Likewise, when a JSON object in the above form is serialized using
|
Likewise, when a JSON object in the above form is serialized using
|
||||||
[`to_bjdata`](../../api/basic_json/to_bjdata.md), it is automatically converted into a compact BJData ND-array. The
|
[`to_bjdata`](../../api/basic_json/to_bjdata.md), it is automatically converted into a compact BJData ND-array. When
|
||||||
only exception is, that when the 1-dimensional vector stored in `"_ArraySize_"` contains a single integer or two
|
the 1-dimensional vector stored in `"_ArraySize_"` contains a single integer or two integers with one being 1, a
|
||||||
integers with one being 1, a regular 1-D optimized array is generated.
|
regular 1-D optimized array is generated instead.
|
||||||
|
|
||||||
|
An object is only converted if the annotation actually describes a packed array; otherwise it is serialized as a
|
||||||
|
regular JSON object. This requires all of the following:
|
||||||
|
|
||||||
|
- `"_ArrayType_"` is one of `uint8`, `int8`, `uint16`, `int16`, `uint32`, `int32`, `uint64`, `int64`, `single`,
|
||||||
|
`double`, `char`, or `byte`,
|
||||||
|
- every entry of `"_ArraySize_"` is a non-negative integer, and their product is representable as a `std::size_t`,
|
||||||
|
- `"_ArrayData_"` holds exactly that many elements, and
|
||||||
|
- every element of `"_ArrayData_"` is a number of the kind named by `"_ArrayType_"` (a floating-point number for
|
||||||
|
`single` and `double`, an integer otherwise).
|
||||||
|
|
||||||
The current version of this library does not yet support automatic detection of and conversion from a nested JSON
|
The current version of this library does not yet support automatic detection of and conversion from a nested JSON
|
||||||
array input to a BJData ND-array.
|
array input to a BJData ND-array.
|
||||||
|
|||||||
@@ -308,6 +308,7 @@ nav:
|
|||||||
- 'NLOHMANN_JSON_VERSION_MAJOR, NLOHMANN_JSON_VERSION_MINOR, NLOHMANN_JSON_VERSION_PATCH': api/macros/nlohmann_json_version_major.md
|
- 'NLOHMANN_JSON_VERSION_MAJOR, NLOHMANN_JSON_VERSION_MINOR, NLOHMANN_JSON_VERSION_PATCH': api/macros/nlohmann_json_version_major.md
|
||||||
- Community:
|
- Community:
|
||||||
- community/index.md
|
- community/index.md
|
||||||
|
- community/ecosystem.md
|
||||||
- "Code of Conduct": community/code_of_conduct.md
|
- "Code of Conduct": community/code_of_conduct.md
|
||||||
- community/contribution_guidelines.md
|
- community/contribution_guidelines.md
|
||||||
- community/quality_assurance.md
|
- community/quality_assurance.md
|
||||||
|
|||||||
@@ -465,15 +465,6 @@ class binary_reader
|
|||||||
// CBOR //
|
// CBOR //
|
||||||
//////////
|
//////////
|
||||||
|
|
||||||
/*!
|
|
||||||
@param[in] get_char whether a new character should be retrieved from the
|
|
||||||
input (true) or whether the last read character should
|
|
||||||
be considered instead (false)
|
|
||||||
@param[in] tag_handler how CBOR tags should be treated
|
|
||||||
|
|
||||||
@return whether a valid CBOR value was passed to the SAX parser
|
|
||||||
*/
|
|
||||||
|
|
||||||
template<typename NumberType>
|
template<typename NumberType>
|
||||||
bool get_cbor_negative_integer()
|
bool get_cbor_negative_integer()
|
||||||
{
|
{
|
||||||
@@ -492,6 +483,14 @@ class binary_reader
|
|||||||
return sax->number_integer(static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(number));
|
return sax->number_integer(static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(number));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@param[in] get_char whether a new character should be retrieved from the
|
||||||
|
input (true) or whether the last read character should
|
||||||
|
be considered instead (false)
|
||||||
|
@param[in] tag_handler how CBOR tags should be treated
|
||||||
|
|
||||||
|
@return whether a valid CBOR value was passed to the SAX parser
|
||||||
|
*/
|
||||||
bool parse_cbor_internal(const bool get_char,
|
bool parse_cbor_internal(const bool get_char,
|
||||||
const cbor_tag_handler_t tag_handler)
|
const cbor_tag_handler_t tag_handler)
|
||||||
{
|
{
|
||||||
@@ -1988,7 +1987,11 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
if (get_char)
|
if (get_char)
|
||||||
{
|
{
|
||||||
get(); // TODO(niels): may we ignore N here?
|
// no get_ignore_noop() here: the byte read next must be a string
|
||||||
|
// length type specification, and a no-op ('N') is not valid in
|
||||||
|
// that position. No-ops at positions where a value may appear are
|
||||||
|
// already consumed by the callers via get_ignore_noop().
|
||||||
|
get();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value")))
|
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value")))
|
||||||
|
|||||||
@@ -345,8 +345,12 @@ struct wide_string_input_helper<BaseInputAdapter, 4>
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// unknown character
|
// A code point above U+10FFFF has no UTF-8 encoding. Passing the
|
||||||
utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
|
// unit through would narrow it to int, where 0xFFFFFFFF becomes
|
||||||
|
// char_traits<char>::eof() and would end the input silently, so
|
||||||
|
// emit a byte that is never valid UTF-8 and let the decoder
|
||||||
|
// reject it.
|
||||||
|
utf8_bytes[0] = 0xFF;
|
||||||
utf8_bytes_filled = 1;
|
utf8_bytes_filled = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -370,8 +370,10 @@ class json_sax_dom_parser
|
|||||||
|
|
||||||
case value_t::string:
|
case value_t::string:
|
||||||
{
|
{
|
||||||
// include the length of the quotes, which is 2
|
// escape sequences make the token longer than the value it
|
||||||
v.start_position = v.end_position - v.m_data.m_value.string->size() - 2;
|
// parses to, so the start position cannot be derived from
|
||||||
|
// the value; use the offset the lexer recorded instead
|
||||||
|
v.start_position = m_lexer_ref->get_token_start_position();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -769,8 +771,10 @@ class json_sax_dom_callback_parser
|
|||||||
|
|
||||||
case value_t::string:
|
case value_t::string:
|
||||||
{
|
{
|
||||||
// include the length of the quotes, which is 2
|
// escape sequences make the token longer than the value it
|
||||||
v.start_position = v.end_position - v.m_data.m_value.string->size() - 2;
|
// parses to, so the start position cannot be derived from
|
||||||
|
// the value; use the offset the lexer recorded instead
|
||||||
|
v.start_position = m_lexer_ref->get_token_start_position();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1357,6 +1357,11 @@ scan_number_done:
|
|||||||
token_buffer.clear();
|
token_buffer.clear();
|
||||||
decimal_point_position = std::string::npos;
|
decimal_point_position = std::string::npos;
|
||||||
|
|
||||||
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
|
// the first character of the token has already been read, hence the -1
|
||||||
|
token_start_position = position.chars_read_total - 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
note_token_start(std::integral_constant<bool, lazy_token_string> {});
|
note_token_start(std::integral_constant<bool, lazy_token_string> {});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1519,6 +1524,15 @@ scan_number_done:
|
|||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
|
/// return the offset of the first character of the last read token; unlike
|
||||||
|
/// the token's parsed value, this accounts for escape sequences
|
||||||
|
constexpr std::size_t get_token_start_position() const noexcept
|
||||||
|
{
|
||||||
|
return token_start_position;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/// seekable adapter: rebuild the last read token from the input on demand
|
/// seekable adapter: rebuild the last read token from the input on demand
|
||||||
const std::vector<char_type>& collect_token_chars(std::vector<char_type>& out, std::true_type /*lazy*/) const
|
const std::vector<char_type>& collect_token_chars(std::vector<char_type>& out, std::true_type /*lazy*/) const
|
||||||
{
|
{
|
||||||
@@ -1719,6 +1733,12 @@ scan_number_done:
|
|||||||
/// the last read token on error for seekable adapters (see collect_token_chars)
|
/// the last read token on error for seekable adapters (see collect_token_chars)
|
||||||
std::size_t token_string_start = 0;
|
std::size_t token_string_start = 0;
|
||||||
|
|
||||||
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
|
/// start offset of the current token within the input, used to report
|
||||||
|
/// diagnostic positions (see reset())
|
||||||
|
std::size_t token_start_position = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
/// buffer for variable-length tokens (numbers, strings)
|
/// buffer for variable-length tokens (numbers, strings)
|
||||||
string_t token_buffer {};
|
string_t token_buffer {};
|
||||||
|
|
||||||
|
|||||||
@@ -1670,7 +1670,23 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
len *= static_cast<std::size_t>(el.template get<std::uint64_t>());
|
|
||||||
|
// a dimension that does not fit into std::size_t, or a product that
|
||||||
|
// overflows it, would wrap around and could match the size of
|
||||||
|
// _ArrayData_ by accident; the resulting header announces an
|
||||||
|
// element count that no reader can honor (the binary reader rejects
|
||||||
|
// it with out_of_range.408), so encode as a plain object instead
|
||||||
|
const auto dim = el.template get<std::uint64_t>();
|
||||||
|
if (!value_in_range_of<std::size_t>(dim))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const auto dim_size = static_cast<std::size_t>(dim);
|
||||||
|
if (dim_size != 0 && len > (std::numeric_limits<std::size_t>::max)() / dim_size)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
len *= dim_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
key = "_ArrayData_";
|
key = "_ArrayData_";
|
||||||
|
|||||||
@@ -7348,8 +7348,12 @@ struct wide_string_input_helper<BaseInputAdapter, 4>
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// unknown character
|
// A code point above U+10FFFF has no UTF-8 encoding. Passing the
|
||||||
utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
|
// unit through would narrow it to int, where 0xFFFFFFFF becomes
|
||||||
|
// char_traits<char>::eof() and would end the input silently, so
|
||||||
|
// emit a byte that is never valid UTF-8 and let the decoder
|
||||||
|
// reject it.
|
||||||
|
utf8_bytes[0] = 0xFF;
|
||||||
utf8_bytes_filled = 1;
|
utf8_bytes_filled = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9071,6 +9075,11 @@ scan_number_done:
|
|||||||
token_buffer.clear();
|
token_buffer.clear();
|
||||||
decimal_point_position = std::string::npos;
|
decimal_point_position = std::string::npos;
|
||||||
|
|
||||||
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
|
// the first character of the token has already been read, hence the -1
|
||||||
|
token_start_position = position.chars_read_total - 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
note_token_start(std::integral_constant<bool, lazy_token_string> {});
|
note_token_start(std::integral_constant<bool, lazy_token_string> {});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9233,6 +9242,15 @@ scan_number_done:
|
|||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
|
/// return the offset of the first character of the last read token; unlike
|
||||||
|
/// the token's parsed value, this accounts for escape sequences
|
||||||
|
constexpr std::size_t get_token_start_position() const noexcept
|
||||||
|
{
|
||||||
|
return token_start_position;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/// seekable adapter: rebuild the last read token from the input on demand
|
/// seekable adapter: rebuild the last read token from the input on demand
|
||||||
const std::vector<char_type>& collect_token_chars(std::vector<char_type>& out, std::true_type /*lazy*/) const
|
const std::vector<char_type>& collect_token_chars(std::vector<char_type>& out, std::true_type /*lazy*/) const
|
||||||
{
|
{
|
||||||
@@ -9433,6 +9451,12 @@ scan_number_done:
|
|||||||
/// the last read token on error for seekable adapters (see collect_token_chars)
|
/// the last read token on error for seekable adapters (see collect_token_chars)
|
||||||
std::size_t token_string_start = 0;
|
std::size_t token_string_start = 0;
|
||||||
|
|
||||||
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
|
/// start offset of the current token within the input, used to report
|
||||||
|
/// diagnostic positions (see reset())
|
||||||
|
std::size_t token_start_position = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
/// buffer for variable-length tokens (numbers, strings)
|
/// buffer for variable-length tokens (numbers, strings)
|
||||||
string_t token_buffer {};
|
string_t token_buffer {};
|
||||||
|
|
||||||
@@ -9809,8 +9833,10 @@ class json_sax_dom_parser
|
|||||||
|
|
||||||
case value_t::string:
|
case value_t::string:
|
||||||
{
|
{
|
||||||
// include the length of the quotes, which is 2
|
// escape sequences make the token longer than the value it
|
||||||
v.start_position = v.end_position - v.m_data.m_value.string->size() - 2;
|
// parses to, so the start position cannot be derived from
|
||||||
|
// the value; use the offset the lexer recorded instead
|
||||||
|
v.start_position = m_lexer_ref->get_token_start_position();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10208,8 +10234,10 @@ class json_sax_dom_callback_parser
|
|||||||
|
|
||||||
case value_t::string:
|
case value_t::string:
|
||||||
{
|
{
|
||||||
// include the length of the quotes, which is 2
|
// escape sequences make the token longer than the value it
|
||||||
v.start_position = v.end_position - v.m_data.m_value.string->size() - 2;
|
// parses to, so the start position cannot be derived from
|
||||||
|
// the value; use the offset the lexer recorded instead
|
||||||
|
v.start_position = m_lexer_ref->get_token_start_position();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11059,15 +11087,6 @@ class binary_reader
|
|||||||
// CBOR //
|
// CBOR //
|
||||||
//////////
|
//////////
|
||||||
|
|
||||||
/*!
|
|
||||||
@param[in] get_char whether a new character should be retrieved from the
|
|
||||||
input (true) or whether the last read character should
|
|
||||||
be considered instead (false)
|
|
||||||
@param[in] tag_handler how CBOR tags should be treated
|
|
||||||
|
|
||||||
@return whether a valid CBOR value was passed to the SAX parser
|
|
||||||
*/
|
|
||||||
|
|
||||||
template<typename NumberType>
|
template<typename NumberType>
|
||||||
bool get_cbor_negative_integer()
|
bool get_cbor_negative_integer()
|
||||||
{
|
{
|
||||||
@@ -11086,6 +11105,14 @@ class binary_reader
|
|||||||
return sax->number_integer(static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(number));
|
return sax->number_integer(static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(number));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@param[in] get_char whether a new character should be retrieved from the
|
||||||
|
input (true) or whether the last read character should
|
||||||
|
be considered instead (false)
|
||||||
|
@param[in] tag_handler how CBOR tags should be treated
|
||||||
|
|
||||||
|
@return whether a valid CBOR value was passed to the SAX parser
|
||||||
|
*/
|
||||||
bool parse_cbor_internal(const bool get_char,
|
bool parse_cbor_internal(const bool get_char,
|
||||||
const cbor_tag_handler_t tag_handler)
|
const cbor_tag_handler_t tag_handler)
|
||||||
{
|
{
|
||||||
@@ -12582,7 +12609,11 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
if (get_char)
|
if (get_char)
|
||||||
{
|
{
|
||||||
get(); // TODO(niels): may we ignore N here?
|
// no get_ignore_noop() here: the byte read next must be a string
|
||||||
|
// length type specification, and a no-op ('N') is not valid in
|
||||||
|
// that position. No-ops at positions where a value may appear are
|
||||||
|
// already consumed by the callers via get_ignore_noop().
|
||||||
|
get();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value")))
|
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value")))
|
||||||
@@ -18573,7 +18604,23 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
len *= static_cast<std::size_t>(el.template get<std::uint64_t>());
|
|
||||||
|
// a dimension that does not fit into std::size_t, or a product that
|
||||||
|
// overflows it, would wrap around and could match the size of
|
||||||
|
// _ArrayData_ by accident; the resulting header announces an
|
||||||
|
// element count that no reader can honor (the binary reader rejects
|
||||||
|
// it with out_of_range.408), so encode as a plain object instead
|
||||||
|
const auto dim = el.template get<std::uint64_t>();
|
||||||
|
if (!value_in_range_of<std::size_t>(dim))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const auto dim_size = static_cast<std::size_t>(dim);
|
||||||
|
if (dim_size != 0 && len > (std::numeric_limits<std::size_t>::max)() / dim_size)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
len *= dim_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
key = "_ArrayData_";
|
key = "_ArrayData_";
|
||||||
|
|||||||
@@ -2730,6 +2730,27 @@ TEST_CASE("BJData")
|
|||||||
CHECK(json::from_bjdata(json::to_bjdata(j_type), true, true) == j_type);
|
CHECK(json::from_bjdata(json::to_bjdata(j_type), true, true) == j_type);
|
||||||
CHECK(json::from_bjdata(json::to_bjdata(j_size), true, true) == j_size);
|
CHECK(json::from_bjdata(json::to_bjdata(j_size), true, true) == j_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("ndarray whose dimensions overflow stays as object")
|
||||||
|
{
|
||||||
|
// the product of the dimensions wraps around std::size_t to 0
|
||||||
|
// and so matches the size of the empty _ArrayData_; writing this
|
||||||
|
// as an ndarray would announce an element count no reader can
|
||||||
|
// honor, so it has to stay a plain object
|
||||||
|
json j_overflow = json({{"_ArrayData_", json::array()}, {"_ArraySize_", {9223372036854775808ull, 2}}, {"_ArrayType_", "uint8"}});
|
||||||
|
CHECK(json::from_bjdata(json::to_bjdata(j_overflow), true, true) == j_overflow);
|
||||||
|
|
||||||
|
// a single dimension that does not fit into std::size_t is
|
||||||
|
// rejected for the same reason (only observable where
|
||||||
|
// std::size_t is narrower than 64 bit)
|
||||||
|
json j_huge = json({{"_ArrayData_", json::array()}, {"_ArraySize_", {18446744073709551615ull}}, {"_ArrayType_", "uint8"}});
|
||||||
|
CHECK(json::from_bjdata(json::to_bjdata(j_huge), true, true) == j_huge);
|
||||||
|
|
||||||
|
// a well-formed ndarray is still encoded as one
|
||||||
|
json j_ok = json({{"_ArrayData_", {1, 2, 3, 4, 5, 6}}, {"_ArraySize_", {2, 3}}, {"_ArrayType_", "uint8"}});
|
||||||
|
CHECK(json::to_bjdata(j_ok) == std::vector<uint8_t>({'[', '$', 'U', '#', '[', 'i', 2, 'i', 3, ']', 1, 2, 3, 4, 5, 6}));
|
||||||
|
CHECK(json::from_bjdata(json::to_bjdata(j_ok), true, true) == j_ok);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,36 @@ TEST_CASE("Better diagnostics with positions")
|
|||||||
"[json.exception.type_error.302] type must be number, but is string", json::type_error);
|
"[json.exception.type_error.302] type must be number, but is string", json::type_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("positions of strings containing escape sequences")
|
||||||
|
{
|
||||||
|
// escape sequences make the token longer than the string it parses to,
|
||||||
|
// so the positions must not be derived from the parsed value's length
|
||||||
|
const auto check = [](const std::string & text, const std::string & token)
|
||||||
|
{
|
||||||
|
CAPTURE(text)
|
||||||
|
CAPTURE(token)
|
||||||
|
const json j = json::parse(text);
|
||||||
|
const json& v = j.at("a");
|
||||||
|
CHECK(text.substr(v.start_pos(), v.end_pos() - v.start_pos()) == token);
|
||||||
|
};
|
||||||
|
|
||||||
|
check(R"({"a":"plain"})", R"("plain")");
|
||||||
|
check(R"({"a":"tab\there"})", R"("tab\there")");
|
||||||
|
check(R"({"a":"\n\n\n\n\n\n"})", R"("\n\n\n\n\n\n")");
|
||||||
|
check(R"({"a":"\""})", R"("\"")");
|
||||||
|
check(R"({"a":"\\"})", R"("\\")");
|
||||||
|
check(R"({"a":"é"})", R"("é")");
|
||||||
|
check(R"({"a":"🌞"})", R"("🌞")");
|
||||||
|
check("{\"a\":\"\xc3\xa9\"}", "\"\xc3\xa9\""); // multi-byte UTF-8, no escapes
|
||||||
|
|
||||||
|
// a string at the root, where an escape would otherwise push the
|
||||||
|
// reported start position past the opening quote
|
||||||
|
const std::string root = R"("a\tb")";
|
||||||
|
const json j = json::parse(root);
|
||||||
|
CHECK(j.start_pos() == 0);
|
||||||
|
CHECK(j.end_pos() == root.size());
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("JSON patch add to primitive parent (#4292)")
|
SECTION("JSON patch add to primitive parent (#4292)")
|
||||||
{
|
{
|
||||||
// the JSON Patch "add" target /foo/bar/baz has a string parent
|
// the JSON Patch "add" target /foo/bar/baz has a string parent
|
||||||
|
|||||||
@@ -1713,6 +1713,44 @@ TEST_CASE("UBJSON")
|
|||||||
CHECK(json::to_ubjson(json::from_ubjson(s_L)) == s_i);
|
CHECK(json::to_ubjson(json::from_ubjson(s_L)) == s_i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("no-op markers")
|
||||||
|
{
|
||||||
|
// A no-op ('N') is valid wherever a value may start; it is consumed
|
||||||
|
// by get_ignore_noop() before the value is read. It is not valid
|
||||||
|
// where a string length type specification is expected.
|
||||||
|
|
||||||
|
SECTION("accepted where a value may start")
|
||||||
|
{
|
||||||
|
// at top level, also repeated
|
||||||
|
CHECK(json::from_ubjson(std::vector<uint8_t>({'N', 'i', 1})) == json(1));
|
||||||
|
CHECK(json::from_ubjson(std::vector<uint8_t>({'N', 'N', 'N', 'i', 1})) == json(1));
|
||||||
|
|
||||||
|
// inside an array of unknown size, before and after an element
|
||||||
|
CHECK(json::from_ubjson(std::vector<uint8_t>({'[', 'N', 'i', 1, ']'})) == json({1}));
|
||||||
|
CHECK(json::from_ubjson(std::vector<uint8_t>({'[', 'i', 1, 'N', ']'})) == json({1}));
|
||||||
|
|
||||||
|
// inside an object of unknown size: before a key, between key
|
||||||
|
// and value, and before the closing '}'
|
||||||
|
CHECK(json::from_ubjson(std::vector<uint8_t>({'{', 'N', 'U', 1, 'a', 'i', 1, '}'})) == json({{"a", 1}}));
|
||||||
|
CHECK(json::from_ubjson(std::vector<uint8_t>({'{', 'U', 1, 'a', 'N', 'i', 1, '}'})) == json({{"a", 1}}));
|
||||||
|
CHECK(json::from_ubjson(std::vector<uint8_t>({'{', 'U', 1, 'a', 'i', 1, 'N', '}'})) == json({{"a", 1}}));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("rejected where a length type specification is expected")
|
||||||
|
{
|
||||||
|
json _;
|
||||||
|
|
||||||
|
// after the 'S' marker of a string value
|
||||||
|
std::vector<uint8_t> const v_S = {'S', 'N', 'U', 1, 'a'};
|
||||||
|
CHECK_THROWS_WITH_AS(_ = json::from_ubjson(v_S), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing UBJSON string: expected length type specification (U, i, I, l, L); last byte: 0x4E", json::parse_error&);
|
||||||
|
|
||||||
|
// as the key length of an object with a known size, where
|
||||||
|
// no-ops are not permitted in the first place
|
||||||
|
std::vector<uint8_t> const v_key = {'{', '#', 'i', 1, 'N', 'U', 1, 'a', 'i', 1};
|
||||||
|
CHECK_THROWS_WITH_AS(_ = json::from_ubjson(v_key), "[json.exception.parse_error.113] parse error at byte 5: syntax error while parsing UBJSON string: expected length type specification (U, i, I, l, L); last byte: 0x4E", json::parse_error&);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("number")
|
SECTION("number")
|
||||||
{
|
{
|
||||||
SECTION("float")
|
SECTION("float")
|
||||||
|
|||||||
@@ -125,6 +125,16 @@ TEST_CASE("wide strings")
|
|||||||
std::u32string const w = U"\"\x110000";
|
std::u32string const w = U"\"\x110000";
|
||||||
json _;
|
json _;
|
||||||
CHECK_THROWS_AS(_ = json::parse(w), json::parse_error&);
|
CHECK_THROWS_AS(_ = json::parse(w), json::parse_error&);
|
||||||
|
|
||||||
|
// a code unit above U+10FFFF must not be narrowed onto the EOF
|
||||||
|
// sentinel: 0xFFFFFFFF would otherwise end the document silently and
|
||||||
|
// let everything following it pass the strict end-of-input check
|
||||||
|
std::u32string const trailing{U'[', U'1', U']', static_cast<char32_t>(0xFFFFFFFF), U'x'};
|
||||||
|
CHECK_THROWS_WITH_AS(_ = json::parse(trailing), "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: '1]\xFF'; expected end of input", json::parse_error&);
|
||||||
|
CHECK(!json::accept(trailing));
|
||||||
|
|
||||||
|
// the same unit inside a string is reported as an ill-formed byte
|
||||||
|
CHECK_THROWS_WITH_AS(_ = json::parse(std::u32string{U'"', static_cast<char32_t>(0xFFFFFFFF), U'"'}), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: ill-formed UTF-8 byte; last read: '\"\xFF'", json::parse_error&);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user