Compare commits

..
Author SHA1 Message Date
Niels Lohmann b826fbf9d7 Reject a nested BJData ndarray dimension vector where it is read
get_ubjson_size_type() takes an inside_ndarray parameter saying whether it is
being called for an ndarray's dimension vector, where another ndarray is not
allowed. It then seeded the flag it passes down to get_ubjson_size_value()
with `false` rather than with that parameter, and only consulted
inside_ndarray afterwards, on the '$' branch.

So on the '#' branch nothing stopped the descent: every "#[" pair of an input
like "[" followed by "#[#[#[..." opened another dimension vector, several
native stack frames deeper each time, and the recursion was only reported on
the way back out. 100,000 pairs crash the process. This is #5104 again, in a
path that has nothing to do with containers.

Seed the flag with inside_ndarray, which is what get_ubjson_size_value()
documents it wants: "for input, `true` means already inside an ndarray vector
or ndarray dimension is not allowed". The nested '[' is then refused where it
is read, so the length of the chain no longer matters.

Both post-checks gain `&& !inside_ndarray`, because an ndarray was found
*here* only if the flag flipped -- get_ubjson_size_value() only ever returns
`true` when its initial value was `false`, as its documentation says. With
that, the "ndarray can not be recursive" branch is unreachable: a recursive
ndarray is now caught one level earlier, and reported as "ndarray dimensional
vector is not allowed" like every other nested dimension vector.

Three existing expectations move accordingly (vR2, vR4, vR6). All three now
fail earlier, and all three now report the same error that vR1, vR5 and vH
already reported for the same shape, which is the more consistent outcome.
Everything else is unchanged: valid 1D and 2D ndarrays, optimized containers
and plain arrays produce identical results, and unit-ubjson is untouched.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-08 13:12:59 +02:00
Niels Lohmann 271a0139ea Stop CBOR indefinite-length strings from recursing per chunk
get_cbor_string() and get_cbor_binary() handled the indefinite-length forms
(0x7F and 0x5F) by calling themselves once per chunk. Each chunk therefore
cost a native stack frame, and since a chunk may itself be an indefinite-
length string, an input of repeated 0x7F bytes reached one frame per input
byte: 200,000 of them crash the process with SIGSEGV before a single byte is
rejected. This is the same defect as #5104, in a path the container-level
work does not touch.

Count the open levels instead of recursing through them. That is enough here
because every chunk is appended to the same result -- get_bytes() writes at
result.size() -- so there is no per-level state to keep. The temporary chunk
string and its copy into the result go away with the recursion.

The definite-length cases move to get_cbor_string_chunk() and
get_cbor_binary_chunk() unchanged, including their error messages, which
still name 0x7F and 0x5F because those are handled one level up.

Behaviour is unchanged. Comparing against develop over the interesting byte
sequences -- empty, single-chunk, nested, over-closed and truncated forms,
both strings and byte arrays, and an indefinite-length map key -- produces
identical values, error codes, messages and byte offsets. The 200,000-level
input now reports parse_error.110 at byte 200001 instead of crashing.

Note that nesting these is not valid CBOR: RFC 8949, Section 3.2.3 forbids
it. This does not change that either way -- it has always been accepted, and
rejecting it is a separate decision (#5317, #5325). Should it be rejected
later, that is now one condition on the level counter rather than a change to
the control flow.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-08 13:12:59 +02:00
Niels Lohmann ea02fda1de Return the parsed value by move from from_cbor() and friends
The binary entry points end with

    return res ? result : basic_json(value_t::discarded);

The condition operator's second operand is an lvalue, so this is not a case
where the return value can be elided or implicitly moved from: every
successful from_cbor(), from_msgpack(), from_ubjson(), from_bjdata() and
from_bson() call deep-copies the value it just parsed, and then destroys the
original.

The copy is not cheap, and it is not incidental: basic_json's copy
constructor walks the whole value. Parsing a 2 MB CBOR document with 60,000
objects, median of 25 runs, clang 17 -O3:

    from_cbor      26.99 ms  ->  14.65 ms
    from_msgpack   26.82 ms  ->  14.82 ms

Moving instead of copying is the entire change; the parsed value is not used
again after the return expression is evaluated.

There is a second reason to prefer the move. The copy constructor recurses
once per nesting level, so the copy is also a stack-overflow path on the
return side, on a value the reader has already accepted. That is currently
masked because the readers themselves recurse and overflow first (#5104), but
it has to be fixed for making them iterative to have any effect.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-08 13:12:59 +02:00
dependabot[bot] 7b2d73cf2e Bump step-security/harden-runner from 2.21.0 to 2.21.1 (#5513)
Bumps [step-security/harden-runner](https://github.com/step-security/harden-runner) from 2.21.0 to 2.21.1.
- [Release notes](https://github.com/step-security/harden-runner/releases)
- [Commits](https://github.com/step-security/harden-runner/compare/05e31511f85b41b11d1cf0ef85d0992719546e2c...e14015d583714f6e62063499dc959a02595150a1)

---
updated-dependencies:
- dependency-name: step-security/harden-runner
  dependency-version: 2.21.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-07 21:37:08 +02:00
28 changed files with 544 additions and 311 deletions
+2 -2
View File
@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with: with:
egress-policy: audit egress-policy: audit
@@ -34,7 +34,7 @@ jobs:
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with: with:
egress-policy: audit egress-policy: audit
+1 -1
View File
@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with: with:
egress-policy: audit egress-policy: audit
+1 -1
View File
@@ -27,7 +27,7 @@ jobs:
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with: with:
egress-policy: audit egress-policy: audit
@@ -19,7 +19,7 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with: with:
egress-policy: audit egress-policy: audit
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with: with:
egress-policy: audit egress-policy: audit
+1 -1
View File
@@ -27,7 +27,7 @@ jobs:
security-events: write security-events: write
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with: with:
egress-policy: audit egress-policy: audit
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with: with:
egress-policy: audit egress-policy: audit
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with: with:
egress-policy: audit egress-policy: audit
+1 -1
View File
@@ -36,7 +36,7 @@ jobs:
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with: with:
egress-policy: audit egress-policy: audit
+1 -1
View File
@@ -32,7 +32,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with: with:
egress-policy: audit egress-policy: audit
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with: with:
egress-policy: audit egress-policy: audit
+5 -5
View File
@@ -35,7 +35,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with: with:
egress-policy: audit egress-policy: audit
@@ -60,7 +60,7 @@ jobs:
target: [ci_test_amalgamation, ci_test_single_header, ci_cppcheck, ci_cpplint, ci_reproducible_tests, ci_non_git_tests, ci_offline_testdata, ci_reuse_compliance, ci_test_valgrind] target: [ci_test_amalgamation, ci_test_single_header, ci_cppcheck, ci_cpplint, ci_reproducible_tests, ci_non_git_tests, ci_offline_testdata, ci_reuse_compliance, ci_test_valgrind]
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with: with:
egress-policy: audit egress-policy: audit
@@ -118,7 +118,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with: with:
egress-policy: audit egress-policy: audit
@@ -369,7 +369,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with: with:
egress-policy: audit egress-policy: audit
@@ -392,7 +392,7 @@ jobs:
target: [ci_test_examples, ci_test_build_documentation] target: [ci_test_examples, ci_test_build_documentation]
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with: with:
egress-policy: audit egress-policy: audit
+148 -59
View File
@@ -996,23 +996,21 @@ class binary_reader
} }
/*! /*!
@brief reads a CBOR string @brief reads a definite-length CBOR string
This function first reads starting bytes to determine the expected Reads everything @ref get_cbor_string accepts except the indefinite-length
string length and then copies this number of bytes into a string. form, which that function handles itself. The bytes are appended to @a
Additionally, CBOR's strings with indefinite lengths are supported. result, so consecutive chunks of an indefinite-length string can be read
into the same string.
@param[out] result created string @param[out] result string the bytes are appended to
@return whether string creation completed @return whether string creation completed
*/
bool get_cbor_string(string_t& result)
{
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string")))
{
return false;
}
@pre @a current is not EOF
*/
bool get_cbor_string_chunk(string_t& result)
{
switch (current) switch (current)
{ {
// UTF-8 string (0x00..0x17 bytes follow) // UTF-8 string (0x00..0x17 bytes follow)
@@ -1068,20 +1066,6 @@ class binary_reader
return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
} }
case 0x7F: // UTF-8 string (indefinite length)
{
while (get() != 0xFF)
{
string_t chunk;
if (!get_cbor_string(chunk))
{
return false;
}
result.append(chunk);
}
return true;
}
default: default:
{ {
auto last_token = get_token_string(); auto last_token = get_token_string();
@@ -1092,23 +1076,82 @@ class binary_reader
} }
/*! /*!
@brief reads a CBOR byte array @brief reads a CBOR string
This function first reads starting bytes to determine the expected This function first reads starting bytes to determine the expected
byte array length and then copies this number of bytes into the byte array. string length and then copies this number of bytes into a string.
Additionally, CBOR's byte arrays with indefinite lengths are supported. Additionally, CBOR's strings with indefinite lengths are supported.
@param[out] result created byte array @param[out] result created string
@return whether string creation completed
*/
bool get_cbor_string(string_t& result)
{
// number of indefinite-length strings that have been opened and not
// closed yet. RFC 8949, Section 3.2.3 does not permit nesting them,
// but this reader has always accepted it, so the open levels are
// counted instead of recursed through, which overflowed the stack for
// an input of repeated 0x7F bytes (see #5104). Every chunk is appended
// to the same result, so no per-level state is needed.
std::size_t open = 0;
while (true)
{
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string")))
{
return false;
}
if (current == 0x7F) // UTF-8 string (indefinite length)
{
++open;
get();
continue;
}
// a break marker closes the innermost indefinite-length string;
// outside of one it is not a string and falls through to the error
if (open != 0 && current == 0xFF)
{
if (--open == 0)
{
return true;
}
get();
continue;
}
if (JSON_HEDLEY_UNLIKELY(!get_cbor_string_chunk(result)))
{
return false;
}
if (open == 0)
{
return true;
}
get();
}
}
/*!
@brief reads a definite-length CBOR byte array
Reads everything @ref get_cbor_binary accepts except the indefinite-length
form, which that function handles itself. The bytes are appended to @a
result, so consecutive chunks of an indefinite-length byte array can be
read into the same byte array.
@param[out] result byte array the bytes are appended to
@return whether byte array creation completed @return whether byte array creation completed
*/
bool get_cbor_binary(binary_t& result)
{
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary")))
{
return false;
}
@pre @a current is not EOF
*/
bool get_cbor_binary_chunk(binary_t& result)
{
switch (current) switch (current)
{ {
// Binary data (0x00..0x17 bytes follow) // Binary data (0x00..0x17 bytes follow)
@@ -1168,20 +1211,6 @@ class binary_reader
get_binary(input_format_t::cbor, len, result); get_binary(input_format_t::cbor, len, result);
} }
case 0x5F: // Binary data (indefinite length)
{
while (get() != 0xFF)
{
binary_t chunk;
if (!get_cbor_binary(chunk))
{
return false;
}
result.insert(result.end(), chunk.begin(), chunk.end());
}
return true;
}
default: default:
{ {
auto last_token = get_token_string(); auto last_token = get_token_string();
@@ -1191,6 +1220,63 @@ class binary_reader
} }
} }
/*!
@brief reads a CBOR byte array
This function first reads starting bytes to determine the expected
byte array length and then copies this number of bytes into the byte array.
Additionally, CBOR's byte arrays with indefinite lengths are supported.
@param[out] result created byte array
@return whether byte array creation completed
*/
bool get_cbor_binary(binary_t& result)
{
// the open indefinite-length byte arrays are counted rather than
// recursed through, for the reason given in @ref get_cbor_string
std::size_t open = 0;
while (true)
{
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary")))
{
return false;
}
if (current == 0x5F) // Binary data (indefinite length)
{
++open;
get();
continue;
}
// a break marker closes the innermost indefinite-length byte
// array; outside of one it falls through to the error below
if (open != 0 && current == 0xFF)
{
if (--open == 0)
{
return true;
}
get();
continue;
}
if (JSON_HEDLEY_UNLIKELY(!get_cbor_binary_chunk(result)))
{
return false;
}
if (open == 0)
{
return true;
}
get();
}
}
/*! /*!
@brief narrow a definite CBOR array/map length to std::size_t @brief narrow a definite CBOR array/map length to std::size_t
@@ -2391,7 +2477,12 @@ class binary_reader
{ {
result.first = npos; // size result.first = npos; // size
result.second = 0; // type result.second = 0; // type
bool is_ndarray = false; // seed the flag with the caller's context: inside an ndarray dimension
// vector another ndarray is not allowed, and get_ubjson_size_value()
// rejects it up front instead of reading it and reporting afterwards.
// Seeding it with `false` made every '#' of a "[#[#[..." chain descend
// another level, which overflowed the stack (see #5104).
bool is_ndarray = inside_ndarray;
get_ignore_noop(); get_ignore_noop();
@@ -2424,13 +2515,11 @@ class binary_reader
} }
const bool is_error = get_ubjson_size_value(result.first, is_ndarray); const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
if (input_format == input_format_t::bjdata && is_ndarray) // an ndarray was read here only if the flag flipped; when it was
// seeded true, get_ubjson_size_value() already rejected the nested
// dimension vector
if (input_format == input_format_t::bjdata && is_ndarray && !inside_ndarray)
{ {
if (inside_ndarray)
{
return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
exception_message(input_format, "ndarray can not be recursive", "size"), nullptr));
}
result.second |= (1 << 8); // use bit 8 to indicate ndarray, all UBJSON and BJData markers should be ASCII letters result.second |= (1 << 8); // use bit 8 to indicate ndarray, all UBJSON and BJData markers should be ASCII letters
} }
return is_error; return is_error;
@@ -2439,7 +2528,7 @@ class binary_reader
if (current == '#') if (current == '#')
{ {
const bool is_error = get_ubjson_size_value(result.first, is_ndarray); const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
if (input_format == input_format_t::bjdata && is_ndarray) if (input_format == input_format_t::bjdata && is_ndarray && !inside_ndarray)
{ {
return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read, return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
exception_message(input_format, "ndarray requires both type and size", "size"), nullptr)); exception_message(input_format, "ndarray requires both type and size", "size"), nullptr));
+70 -55
View File
@@ -1335,7 +1335,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief serialization /// @brief serialization
/// @sa https://json.nlohmann.me/api/basic_json/dump/ /// @sa https://json.nlohmann.me/api/basic_json/dump/
JSON_HEDLEY_WARN_UNUSED_RESULT
string_t dump(const int indent = -1, string_t dump(const int indent = -1,
const char indent_char = ' ', const char indent_char = ' ',
const bool ensure_ascii = false, const bool ensure_ascii = false,
@@ -1358,7 +1357,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return the type of the JSON value (explicit) /// @brief return the type of the JSON value (explicit)
/// @sa https://json.nlohmann.me/api/basic_json/type/ /// @sa https://json.nlohmann.me/api/basic_json/type/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr value_t type() const noexcept constexpr value_t type() const noexcept
{ {
return m_data.m_type; return m_data.m_type;
@@ -1366,7 +1364,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether type is primitive /// @brief return whether type is primitive
/// @sa https://json.nlohmann.me/api/basic_json/is_primitive/ /// @sa https://json.nlohmann.me/api/basic_json/is_primitive/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_primitive() const noexcept constexpr bool is_primitive() const noexcept
{ {
return is_null() || is_string() || is_boolean() || is_number() || is_binary(); return is_null() || is_string() || is_boolean() || is_number() || is_binary();
@@ -1374,7 +1371,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether type is structured /// @brief return whether type is structured
/// @sa https://json.nlohmann.me/api/basic_json/is_structured/ /// @sa https://json.nlohmann.me/api/basic_json/is_structured/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_structured() const noexcept constexpr bool is_structured() const noexcept
{ {
return is_array() || is_object(); return is_array() || is_object();
@@ -1382,7 +1378,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is null /// @brief return whether value is null
/// @sa https://json.nlohmann.me/api/basic_json/is_null/ /// @sa https://json.nlohmann.me/api/basic_json/is_null/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_null() const noexcept constexpr bool is_null() const noexcept
{ {
return m_data.m_type == value_t::null; return m_data.m_type == value_t::null;
@@ -1390,7 +1385,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is a boolean /// @brief return whether value is a boolean
/// @sa https://json.nlohmann.me/api/basic_json/is_boolean/ /// @sa https://json.nlohmann.me/api/basic_json/is_boolean/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_boolean() const noexcept constexpr bool is_boolean() const noexcept
{ {
return m_data.m_type == value_t::boolean; return m_data.m_type == value_t::boolean;
@@ -1398,7 +1392,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is a number /// @brief return whether value is a number
/// @sa https://json.nlohmann.me/api/basic_json/is_number/ /// @sa https://json.nlohmann.me/api/basic_json/is_number/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_number() const noexcept constexpr bool is_number() const noexcept
{ {
return is_number_integer() || is_number_float(); return is_number_integer() || is_number_float();
@@ -1406,7 +1399,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is an integer number /// @brief return whether value is an integer number
/// @sa https://json.nlohmann.me/api/basic_json/is_number_integer/ /// @sa https://json.nlohmann.me/api/basic_json/is_number_integer/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_number_integer() const noexcept constexpr bool is_number_integer() const noexcept
{ {
return m_data.m_type == value_t::number_integer || m_data.m_type == value_t::number_unsigned; return m_data.m_type == value_t::number_integer || m_data.m_type == value_t::number_unsigned;
@@ -1414,7 +1406,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is an unsigned integer number /// @brief return whether value is an unsigned integer number
/// @sa https://json.nlohmann.me/api/basic_json/is_number_unsigned/ /// @sa https://json.nlohmann.me/api/basic_json/is_number_unsigned/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_number_unsigned() const noexcept constexpr bool is_number_unsigned() const noexcept
{ {
return m_data.m_type == value_t::number_unsigned; return m_data.m_type == value_t::number_unsigned;
@@ -1422,7 +1413,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is a floating-point number /// @brief return whether value is a floating-point number
/// @sa https://json.nlohmann.me/api/basic_json/is_number_float/ /// @sa https://json.nlohmann.me/api/basic_json/is_number_float/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_number_float() const noexcept constexpr bool is_number_float() const noexcept
{ {
return m_data.m_type == value_t::number_float; return m_data.m_type == value_t::number_float;
@@ -1430,7 +1420,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is an object /// @brief return whether value is an object
/// @sa https://json.nlohmann.me/api/basic_json/is_object/ /// @sa https://json.nlohmann.me/api/basic_json/is_object/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_object() const noexcept constexpr bool is_object() const noexcept
{ {
return m_data.m_type == value_t::object; return m_data.m_type == value_t::object;
@@ -1438,7 +1427,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is an array /// @brief return whether value is an array
/// @sa https://json.nlohmann.me/api/basic_json/is_array/ /// @sa https://json.nlohmann.me/api/basic_json/is_array/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_array() const noexcept constexpr bool is_array() const noexcept
{ {
return m_data.m_type == value_t::array; return m_data.m_type == value_t::array;
@@ -1446,7 +1434,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is a string /// @brief return whether value is a string
/// @sa https://json.nlohmann.me/api/basic_json/is_string/ /// @sa https://json.nlohmann.me/api/basic_json/is_string/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_string() const noexcept constexpr bool is_string() const noexcept
{ {
return m_data.m_type == value_t::string; return m_data.m_type == value_t::string;
@@ -1454,7 +1441,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is a binary array /// @brief return whether value is a binary array
/// @sa https://json.nlohmann.me/api/basic_json/is_binary/ /// @sa https://json.nlohmann.me/api/basic_json/is_binary/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_binary() const noexcept constexpr bool is_binary() const noexcept
{ {
return m_data.m_type == value_t::binary; return m_data.m_type == value_t::binary;
@@ -1462,7 +1448,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is discarded /// @brief return whether value is discarded
/// @sa https://json.nlohmann.me/api/basic_json/is_discarded/ /// @sa https://json.nlohmann.me/api/basic_json/is_discarded/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_discarded() const noexcept constexpr bool is_discarded() const noexcept
{ {
return m_data.m_type == value_t::discarded; return m_data.m_type == value_t::discarded;
@@ -2794,7 +2779,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief returns the number of occurrences of a key in a JSON object /// @brief returns the number of occurrences of a key in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/count/ /// @sa https://json.nlohmann.me/api/basic_json/count/
JSON_HEDLEY_WARN_UNUSED_RESULT
size_type count(const typename object_t::key_type& key) const size_type count(const typename object_t::key_type& key) const
{ {
// return 0 for all nonobject types // return 0 for all nonobject types
@@ -2805,7 +2789,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/count/ /// @sa https://json.nlohmann.me/api/basic_json/count/
template<class KeyType, detail::enable_if_t< template<class KeyType, detail::enable_if_t<
detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0> detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
JSON_HEDLEY_WARN_UNUSED_RESULT
size_type count(KeyType && key) const size_type count(KeyType && key) const
{ {
// return 0 for all nonobject types // return 0 for all nonobject types
@@ -2814,7 +2797,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief check the existence of an element in a JSON object /// @brief check the existence of an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/contains/ /// @sa https://json.nlohmann.me/api/basic_json/contains/
JSON_HEDLEY_WARN_UNUSED_RESULT
bool contains(const typename object_t::key_type& key) const bool contains(const typename object_t::key_type& key) const
{ {
return is_object() && m_data.m_value.object->find(key) != m_data.m_value.object->end(); return is_object() && m_data.m_value.object->find(key) != m_data.m_value.object->end();
@@ -2824,7 +2806,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/contains/ /// @sa https://json.nlohmann.me/api/basic_json/contains/
template<class KeyType, detail::enable_if_t< template<class KeyType, detail::enable_if_t<
detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0> detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
JSON_HEDLEY_WARN_UNUSED_RESULT
bool contains(KeyType && key) const bool contains(KeyType && key) const
{ {
return is_object() && m_data.m_value.object->find(std::forward<KeyType>(key)) != m_data.m_value.object->end(); return is_object() && m_data.m_value.object->find(std::forward<KeyType>(key)) != m_data.m_value.object->end();
@@ -2832,14 +2813,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief check the existence of an element in a JSON object given a JSON pointer /// @brief check the existence of an element in a JSON object given a JSON pointer
/// @sa https://json.nlohmann.me/api/basic_json/contains/ /// @sa https://json.nlohmann.me/api/basic_json/contains/
JSON_HEDLEY_WARN_UNUSED_RESULT
bool contains(const json_pointer& ptr) const bool contains(const json_pointer& ptr) const
{ {
return ptr.contains(this); return ptr.contains(this);
} }
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const
{ {
@@ -2995,7 +2974,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief checks whether the container is empty. /// @brief checks whether the container is empty.
/// @sa https://json.nlohmann.me/api/basic_json/empty/ /// @sa https://json.nlohmann.me/api/basic_json/empty/
JSON_HEDLEY_WARN_UNUSED_RESULT
bool empty() const noexcept bool empty() const noexcept
{ {
switch (m_data.m_type) switch (m_data.m_type)
@@ -3035,7 +3013,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief returns the number of elements /// @brief returns the number of elements
/// @sa https://json.nlohmann.me/api/basic_json/size/ /// @sa https://json.nlohmann.me/api/basic_json/size/
JSON_HEDLEY_WARN_UNUSED_RESULT
size_type size() const noexcept size_type size() const noexcept
{ {
switch (m_data.m_type) switch (m_data.m_type)
@@ -3075,7 +3052,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief returns the maximum possible number of elements /// @brief returns the maximum possible number of elements
/// @sa https://json.nlohmann.me/api/basic_json/max_size/ /// @sa https://json.nlohmann.me/api/basic_json/max_size/
JSON_HEDLEY_WARN_UNUSED_RESULT
size_type max_size() const noexcept size_type max_size() const noexcept
{ {
switch (m_data.m_type) switch (m_data.m_type)
@@ -4153,7 +4129,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief check if the input is valid JSON /// @brief check if the input is valid JSON
/// @sa https://json.nlohmann.me/api/basic_json/accept/ /// @sa https://json.nlohmann.me/api/basic_json/accept/
template<typename InputType> template<typename InputType>
JSON_HEDLEY_WARN_UNUSED_RESULT
static bool accept(InputType&& i, static bool accept(InputType&& i,
const bool ignore_comments = false, const bool ignore_comments = false,
const bool ignore_trailing_commas = false) const bool ignore_trailing_commas = false)
@@ -4165,7 +4140,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/accept/ /// @sa https://json.nlohmann.me/api/basic_json/accept/
template<typename IteratorType, typename SentinelType = IteratorType, template<typename IteratorType, typename SentinelType = IteratorType,
detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0> detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0>
JSON_HEDLEY_WARN_UNUSED_RESULT
static bool accept(IteratorType first, SentinelType last, static bool accept(IteratorType first, SentinelType last,
const bool ignore_comments = false, const bool ignore_comments = false,
const bool ignore_trailing_commas = false) const bool ignore_trailing_commas = false)
@@ -4265,7 +4239,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return the type as string /// @brief return the type as string
/// @sa https://json.nlohmann.me/api/basic_json/type_name/ /// @sa https://json.nlohmann.me/api/basic_json/type_name/
JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_RETURNS_NON_NULL JSON_HEDLEY_RETURNS_NON_NULL
const char* type_name() const noexcept const char* type_name() const noexcept
{ {
@@ -4500,8 +4473,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
basic_json result; basic_json result;
auto ia = detail::input_adapter(std::forward<InputType>(i)); auto ia = detail::input_adapter(std::forward<InputType>(i));
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
/// @brief create a JSON value from an input in CBOR format (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief create a JSON value from an input in CBOR format (iterator pair, or iterator+sentinel pair for C++20 ranges support)
@@ -4517,8 +4493,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
basic_json result; basic_json result;
auto ia = detail::input_adapter(std::move(first), std::move(last)); auto ia = detail::input_adapter(std::move(first), std::move(last));
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
template<typename T> template<typename T>
@@ -4543,8 +4522,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
auto ia = i.get(); auto ia = i.get();
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
/// @brief create a JSON value from an input in MessagePack format /// @brief create a JSON value from an input in MessagePack format
@@ -4558,8 +4540,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
basic_json result; basic_json result;
auto ia = detail::input_adapter(std::forward<InputType>(i)); auto ia = detail::input_adapter(std::forward<InputType>(i));
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
/// @brief create a JSON value from an input in MessagePack format (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief create a JSON value from an input in MessagePack format (iterator pair, or iterator+sentinel pair for C++20 ranges support)
@@ -4574,8 +4559,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
basic_json result; basic_json result;
auto ia = detail::input_adapter(std::move(first), std::move(last)); auto ia = detail::input_adapter(std::move(first), std::move(last));
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
template<typename T> template<typename T>
@@ -4598,8 +4586,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
auto ia = i.get(); auto ia = i.get();
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
/// @brief create a JSON value from an input in UBJSON format /// @brief create a JSON value from an input in UBJSON format
@@ -4613,8 +4604,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
basic_json result; basic_json result;
auto ia = detail::input_adapter(std::forward<InputType>(i)); auto ia = detail::input_adapter(std::forward<InputType>(i));
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
/// @brief create a JSON value from an input in UBJSON format (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief create a JSON value from an input in UBJSON format (iterator pair, or iterator+sentinel pair for C++20 ranges support)
@@ -4629,8 +4623,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
basic_json result; basic_json result;
auto ia = detail::input_adapter(std::move(first), std::move(last)); auto ia = detail::input_adapter(std::move(first), std::move(last));
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
template<typename T> template<typename T>
@@ -4653,8 +4650,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
auto ia = i.get(); auto ia = i.get();
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
/// @brief create a JSON value from an input in BJData format /// @brief create a JSON value from an input in BJData format
@@ -4668,8 +4668,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
basic_json result; basic_json result;
auto ia = detail::input_adapter(std::forward<InputType>(i)); auto ia = detail::input_adapter(std::forward<InputType>(i));
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
/// @brief create a JSON value from an input in BJData format (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief create a JSON value from an input in BJData format (iterator pair, or iterator+sentinel pair for C++20 ranges support)
@@ -4684,8 +4687,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
basic_json result; basic_json result;
auto ia = detail::input_adapter(std::move(first), std::move(last)); auto ia = detail::input_adapter(std::move(first), std::move(last));
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
/// @brief create a JSON value from an input in BSON format /// @brief create a JSON value from an input in BSON format
@@ -4699,8 +4705,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
basic_json result; basic_json result;
auto ia = detail::input_adapter(std::forward<InputType>(i)); auto ia = detail::input_adapter(std::forward<InputType>(i));
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
/// @brief create a JSON value from an input in BSON format (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief create a JSON value from an input in BSON format (iterator pair, or iterator+sentinel pair for C++20 ranges support)
@@ -4715,8 +4724,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
basic_json result; basic_json result;
auto ia = detail::input_adapter(std::move(first), std::move(last)); auto ia = detail::input_adapter(std::move(first), std::move(last));
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
template<typename T> template<typename T>
@@ -4739,8 +4751,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
auto ia = i.get(); auto ia = i.get();
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
/// @} /// @}
+218 -114
View File
@@ -11683,23 +11683,21 @@ class binary_reader
} }
/*! /*!
@brief reads a CBOR string @brief reads a definite-length CBOR string
This function first reads starting bytes to determine the expected Reads everything @ref get_cbor_string accepts except the indefinite-length
string length and then copies this number of bytes into a string. form, which that function handles itself. The bytes are appended to @a
Additionally, CBOR's strings with indefinite lengths are supported. result, so consecutive chunks of an indefinite-length string can be read
into the same string.
@param[out] result created string @param[out] result string the bytes are appended to
@return whether string creation completed @return whether string creation completed
*/
bool get_cbor_string(string_t& result)
{
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string")))
{
return false;
}
@pre @a current is not EOF
*/
bool get_cbor_string_chunk(string_t& result)
{
switch (current) switch (current)
{ {
// UTF-8 string (0x00..0x17 bytes follow) // UTF-8 string (0x00..0x17 bytes follow)
@@ -11755,20 +11753,6 @@ class binary_reader
return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
} }
case 0x7F: // UTF-8 string (indefinite length)
{
while (get() != 0xFF)
{
string_t chunk;
if (!get_cbor_string(chunk))
{
return false;
}
result.append(chunk);
}
return true;
}
default: default:
{ {
auto last_token = get_token_string(); auto last_token = get_token_string();
@@ -11779,23 +11763,82 @@ class binary_reader
} }
/*! /*!
@brief reads a CBOR byte array @brief reads a CBOR string
This function first reads starting bytes to determine the expected This function first reads starting bytes to determine the expected
byte array length and then copies this number of bytes into the byte array. string length and then copies this number of bytes into a string.
Additionally, CBOR's byte arrays with indefinite lengths are supported. Additionally, CBOR's strings with indefinite lengths are supported.
@param[out] result created byte array @param[out] result created string
@return whether string creation completed
*/
bool get_cbor_string(string_t& result)
{
// number of indefinite-length strings that have been opened and not
// closed yet. RFC 8949, Section 3.2.3 does not permit nesting them,
// but this reader has always accepted it, so the open levels are
// counted instead of recursed through, which overflowed the stack for
// an input of repeated 0x7F bytes (see #5104). Every chunk is appended
// to the same result, so no per-level state is needed.
std::size_t open = 0;
while (true)
{
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string")))
{
return false;
}
if (current == 0x7F) // UTF-8 string (indefinite length)
{
++open;
get();
continue;
}
// a break marker closes the innermost indefinite-length string;
// outside of one it is not a string and falls through to the error
if (open != 0 && current == 0xFF)
{
if (--open == 0)
{
return true;
}
get();
continue;
}
if (JSON_HEDLEY_UNLIKELY(!get_cbor_string_chunk(result)))
{
return false;
}
if (open == 0)
{
return true;
}
get();
}
}
/*!
@brief reads a definite-length CBOR byte array
Reads everything @ref get_cbor_binary accepts except the indefinite-length
form, which that function handles itself. The bytes are appended to @a
result, so consecutive chunks of an indefinite-length byte array can be
read into the same byte array.
@param[out] result byte array the bytes are appended to
@return whether byte array creation completed @return whether byte array creation completed
*/
bool get_cbor_binary(binary_t& result)
{
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary")))
{
return false;
}
@pre @a current is not EOF
*/
bool get_cbor_binary_chunk(binary_t& result)
{
switch (current) switch (current)
{ {
// Binary data (0x00..0x17 bytes follow) // Binary data (0x00..0x17 bytes follow)
@@ -11855,20 +11898,6 @@ class binary_reader
get_binary(input_format_t::cbor, len, result); get_binary(input_format_t::cbor, len, result);
} }
case 0x5F: // Binary data (indefinite length)
{
while (get() != 0xFF)
{
binary_t chunk;
if (!get_cbor_binary(chunk))
{
return false;
}
result.insert(result.end(), chunk.begin(), chunk.end());
}
return true;
}
default: default:
{ {
auto last_token = get_token_string(); auto last_token = get_token_string();
@@ -11878,6 +11907,63 @@ class binary_reader
} }
} }
/*!
@brief reads a CBOR byte array
This function first reads starting bytes to determine the expected
byte array length and then copies this number of bytes into the byte array.
Additionally, CBOR's byte arrays with indefinite lengths are supported.
@param[out] result created byte array
@return whether byte array creation completed
*/
bool get_cbor_binary(binary_t& result)
{
// the open indefinite-length byte arrays are counted rather than
// recursed through, for the reason given in @ref get_cbor_string
std::size_t open = 0;
while (true)
{
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary")))
{
return false;
}
if (current == 0x5F) // Binary data (indefinite length)
{
++open;
get();
continue;
}
// a break marker closes the innermost indefinite-length byte
// array; outside of one it falls through to the error below
if (open != 0 && current == 0xFF)
{
if (--open == 0)
{
return true;
}
get();
continue;
}
if (JSON_HEDLEY_UNLIKELY(!get_cbor_binary_chunk(result)))
{
return false;
}
if (open == 0)
{
return true;
}
get();
}
}
/*! /*!
@brief narrow a definite CBOR array/map length to std::size_t @brief narrow a definite CBOR array/map length to std::size_t
@@ -13078,7 +13164,12 @@ class binary_reader
{ {
result.first = npos; // size result.first = npos; // size
result.second = 0; // type result.second = 0; // type
bool is_ndarray = false; // seed the flag with the caller's context: inside an ndarray dimension
// vector another ndarray is not allowed, and get_ubjson_size_value()
// rejects it up front instead of reading it and reporting afterwards.
// Seeding it with `false` made every '#' of a "[#[#[..." chain descend
// another level, which overflowed the stack (see #5104).
bool is_ndarray = inside_ndarray;
get_ignore_noop(); get_ignore_noop();
@@ -13111,13 +13202,11 @@ class binary_reader
} }
const bool is_error = get_ubjson_size_value(result.first, is_ndarray); const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
if (input_format == input_format_t::bjdata && is_ndarray) // an ndarray was read here only if the flag flipped; when it was
// seeded true, get_ubjson_size_value() already rejected the nested
// dimension vector
if (input_format == input_format_t::bjdata && is_ndarray && !inside_ndarray)
{ {
if (inside_ndarray)
{
return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
exception_message(input_format, "ndarray can not be recursive", "size"), nullptr));
}
result.second |= (1 << 8); // use bit 8 to indicate ndarray, all UBJSON and BJData markers should be ASCII letters result.second |= (1 << 8); // use bit 8 to indicate ndarray, all UBJSON and BJData markers should be ASCII letters
} }
return is_error; return is_error;
@@ -13126,7 +13215,7 @@ class binary_reader
if (current == '#') if (current == '#')
{ {
const bool is_error = get_ubjson_size_value(result.first, is_ndarray); const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
if (input_format == input_format_t::bjdata && is_ndarray) if (input_format == input_format_t::bjdata && is_ndarray && !inside_ndarray)
{ {
return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read, return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
exception_message(input_format, "ndarray requires both type and size", "size"), nullptr)); exception_message(input_format, "ndarray requires both type and size", "size"), nullptr));
@@ -22763,7 +22852,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief serialization /// @brief serialization
/// @sa https://json.nlohmann.me/api/basic_json/dump/ /// @sa https://json.nlohmann.me/api/basic_json/dump/
JSON_HEDLEY_WARN_UNUSED_RESULT
string_t dump(const int indent = -1, string_t dump(const int indent = -1,
const char indent_char = ' ', const char indent_char = ' ',
const bool ensure_ascii = false, const bool ensure_ascii = false,
@@ -22786,7 +22874,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return the type of the JSON value (explicit) /// @brief return the type of the JSON value (explicit)
/// @sa https://json.nlohmann.me/api/basic_json/type/ /// @sa https://json.nlohmann.me/api/basic_json/type/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr value_t type() const noexcept constexpr value_t type() const noexcept
{ {
return m_data.m_type; return m_data.m_type;
@@ -22794,7 +22881,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether type is primitive /// @brief return whether type is primitive
/// @sa https://json.nlohmann.me/api/basic_json/is_primitive/ /// @sa https://json.nlohmann.me/api/basic_json/is_primitive/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_primitive() const noexcept constexpr bool is_primitive() const noexcept
{ {
return is_null() || is_string() || is_boolean() || is_number() || is_binary(); return is_null() || is_string() || is_boolean() || is_number() || is_binary();
@@ -22802,7 +22888,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether type is structured /// @brief return whether type is structured
/// @sa https://json.nlohmann.me/api/basic_json/is_structured/ /// @sa https://json.nlohmann.me/api/basic_json/is_structured/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_structured() const noexcept constexpr bool is_structured() const noexcept
{ {
return is_array() || is_object(); return is_array() || is_object();
@@ -22810,7 +22895,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is null /// @brief return whether value is null
/// @sa https://json.nlohmann.me/api/basic_json/is_null/ /// @sa https://json.nlohmann.me/api/basic_json/is_null/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_null() const noexcept constexpr bool is_null() const noexcept
{ {
return m_data.m_type == value_t::null; return m_data.m_type == value_t::null;
@@ -22818,7 +22902,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is a boolean /// @brief return whether value is a boolean
/// @sa https://json.nlohmann.me/api/basic_json/is_boolean/ /// @sa https://json.nlohmann.me/api/basic_json/is_boolean/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_boolean() const noexcept constexpr bool is_boolean() const noexcept
{ {
return m_data.m_type == value_t::boolean; return m_data.m_type == value_t::boolean;
@@ -22826,7 +22909,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is a number /// @brief return whether value is a number
/// @sa https://json.nlohmann.me/api/basic_json/is_number/ /// @sa https://json.nlohmann.me/api/basic_json/is_number/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_number() const noexcept constexpr bool is_number() const noexcept
{ {
return is_number_integer() || is_number_float(); return is_number_integer() || is_number_float();
@@ -22834,7 +22916,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is an integer number /// @brief return whether value is an integer number
/// @sa https://json.nlohmann.me/api/basic_json/is_number_integer/ /// @sa https://json.nlohmann.me/api/basic_json/is_number_integer/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_number_integer() const noexcept constexpr bool is_number_integer() const noexcept
{ {
return m_data.m_type == value_t::number_integer || m_data.m_type == value_t::number_unsigned; return m_data.m_type == value_t::number_integer || m_data.m_type == value_t::number_unsigned;
@@ -22842,7 +22923,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is an unsigned integer number /// @brief return whether value is an unsigned integer number
/// @sa https://json.nlohmann.me/api/basic_json/is_number_unsigned/ /// @sa https://json.nlohmann.me/api/basic_json/is_number_unsigned/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_number_unsigned() const noexcept constexpr bool is_number_unsigned() const noexcept
{ {
return m_data.m_type == value_t::number_unsigned; return m_data.m_type == value_t::number_unsigned;
@@ -22850,7 +22930,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is a floating-point number /// @brief return whether value is a floating-point number
/// @sa https://json.nlohmann.me/api/basic_json/is_number_float/ /// @sa https://json.nlohmann.me/api/basic_json/is_number_float/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_number_float() const noexcept constexpr bool is_number_float() const noexcept
{ {
return m_data.m_type == value_t::number_float; return m_data.m_type == value_t::number_float;
@@ -22858,7 +22937,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is an object /// @brief return whether value is an object
/// @sa https://json.nlohmann.me/api/basic_json/is_object/ /// @sa https://json.nlohmann.me/api/basic_json/is_object/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_object() const noexcept constexpr bool is_object() const noexcept
{ {
return m_data.m_type == value_t::object; return m_data.m_type == value_t::object;
@@ -22866,7 +22944,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is an array /// @brief return whether value is an array
/// @sa https://json.nlohmann.me/api/basic_json/is_array/ /// @sa https://json.nlohmann.me/api/basic_json/is_array/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_array() const noexcept constexpr bool is_array() const noexcept
{ {
return m_data.m_type == value_t::array; return m_data.m_type == value_t::array;
@@ -22874,7 +22951,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is a string /// @brief return whether value is a string
/// @sa https://json.nlohmann.me/api/basic_json/is_string/ /// @sa https://json.nlohmann.me/api/basic_json/is_string/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_string() const noexcept constexpr bool is_string() const noexcept
{ {
return m_data.m_type == value_t::string; return m_data.m_type == value_t::string;
@@ -22882,7 +22958,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is a binary array /// @brief return whether value is a binary array
/// @sa https://json.nlohmann.me/api/basic_json/is_binary/ /// @sa https://json.nlohmann.me/api/basic_json/is_binary/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_binary() const noexcept constexpr bool is_binary() const noexcept
{ {
return m_data.m_type == value_t::binary; return m_data.m_type == value_t::binary;
@@ -22890,7 +22965,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return whether value is discarded /// @brief return whether value is discarded
/// @sa https://json.nlohmann.me/api/basic_json/is_discarded/ /// @sa https://json.nlohmann.me/api/basic_json/is_discarded/
JSON_HEDLEY_WARN_UNUSED_RESULT
constexpr bool is_discarded() const noexcept constexpr bool is_discarded() const noexcept
{ {
return m_data.m_type == value_t::discarded; return m_data.m_type == value_t::discarded;
@@ -24222,7 +24296,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief returns the number of occurrences of a key in a JSON object /// @brief returns the number of occurrences of a key in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/count/ /// @sa https://json.nlohmann.me/api/basic_json/count/
JSON_HEDLEY_WARN_UNUSED_RESULT
size_type count(const typename object_t::key_type& key) const size_type count(const typename object_t::key_type& key) const
{ {
// return 0 for all nonobject types // return 0 for all nonobject types
@@ -24233,7 +24306,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/count/ /// @sa https://json.nlohmann.me/api/basic_json/count/
template<class KeyType, detail::enable_if_t< template<class KeyType, detail::enable_if_t<
detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0> detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
JSON_HEDLEY_WARN_UNUSED_RESULT
size_type count(KeyType && key) const size_type count(KeyType && key) const
{ {
// return 0 for all nonobject types // return 0 for all nonobject types
@@ -24242,7 +24314,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief check the existence of an element in a JSON object /// @brief check the existence of an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/contains/ /// @sa https://json.nlohmann.me/api/basic_json/contains/
JSON_HEDLEY_WARN_UNUSED_RESULT
bool contains(const typename object_t::key_type& key) const bool contains(const typename object_t::key_type& key) const
{ {
return is_object() && m_data.m_value.object->find(key) != m_data.m_value.object->end(); return is_object() && m_data.m_value.object->find(key) != m_data.m_value.object->end();
@@ -24252,7 +24323,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/contains/ /// @sa https://json.nlohmann.me/api/basic_json/contains/
template<class KeyType, detail::enable_if_t< template<class KeyType, detail::enable_if_t<
detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0> detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
JSON_HEDLEY_WARN_UNUSED_RESULT
bool contains(KeyType && key) const bool contains(KeyType && key) const
{ {
return is_object() && m_data.m_value.object->find(std::forward<KeyType>(key)) != m_data.m_value.object->end(); return is_object() && m_data.m_value.object->find(std::forward<KeyType>(key)) != m_data.m_value.object->end();
@@ -24260,14 +24330,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief check the existence of an element in a JSON object given a JSON pointer /// @brief check the existence of an element in a JSON object given a JSON pointer
/// @sa https://json.nlohmann.me/api/basic_json/contains/ /// @sa https://json.nlohmann.me/api/basic_json/contains/
JSON_HEDLEY_WARN_UNUSED_RESULT
bool contains(const json_pointer& ptr) const bool contains(const json_pointer& ptr) const
{ {
return ptr.contains(this); return ptr.contains(this);
} }
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const
{ {
@@ -24423,7 +24491,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief checks whether the container is empty. /// @brief checks whether the container is empty.
/// @sa https://json.nlohmann.me/api/basic_json/empty/ /// @sa https://json.nlohmann.me/api/basic_json/empty/
JSON_HEDLEY_WARN_UNUSED_RESULT
bool empty() const noexcept bool empty() const noexcept
{ {
switch (m_data.m_type) switch (m_data.m_type)
@@ -24463,7 +24530,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief returns the number of elements /// @brief returns the number of elements
/// @sa https://json.nlohmann.me/api/basic_json/size/ /// @sa https://json.nlohmann.me/api/basic_json/size/
JSON_HEDLEY_WARN_UNUSED_RESULT
size_type size() const noexcept size_type size() const noexcept
{ {
switch (m_data.m_type) switch (m_data.m_type)
@@ -24503,7 +24569,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief returns the maximum possible number of elements /// @brief returns the maximum possible number of elements
/// @sa https://json.nlohmann.me/api/basic_json/max_size/ /// @sa https://json.nlohmann.me/api/basic_json/max_size/
JSON_HEDLEY_WARN_UNUSED_RESULT
size_type max_size() const noexcept size_type max_size() const noexcept
{ {
switch (m_data.m_type) switch (m_data.m_type)
@@ -25581,7 +25646,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief check if the input is valid JSON /// @brief check if the input is valid JSON
/// @sa https://json.nlohmann.me/api/basic_json/accept/ /// @sa https://json.nlohmann.me/api/basic_json/accept/
template<typename InputType> template<typename InputType>
JSON_HEDLEY_WARN_UNUSED_RESULT
static bool accept(InputType&& i, static bool accept(InputType&& i,
const bool ignore_comments = false, const bool ignore_comments = false,
const bool ignore_trailing_commas = false) const bool ignore_trailing_commas = false)
@@ -25593,7 +25657,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/accept/ /// @sa https://json.nlohmann.me/api/basic_json/accept/
template<typename IteratorType, typename SentinelType = IteratorType, template<typename IteratorType, typename SentinelType = IteratorType,
detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0> detail::enable_if_t<detail::can_compare_ne<IteratorType, SentinelType>::value, int> = 0>
JSON_HEDLEY_WARN_UNUSED_RESULT
static bool accept(IteratorType first, SentinelType last, static bool accept(IteratorType first, SentinelType last,
const bool ignore_comments = false, const bool ignore_comments = false,
const bool ignore_trailing_commas = false) const bool ignore_trailing_commas = false)
@@ -25693,7 +25756,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @brief return the type as string /// @brief return the type as string
/// @sa https://json.nlohmann.me/api/basic_json/type_name/ /// @sa https://json.nlohmann.me/api/basic_json/type_name/
JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_RETURNS_NON_NULL JSON_HEDLEY_RETURNS_NON_NULL
const char* type_name() const noexcept const char* type_name() const noexcept
{ {
@@ -25928,8 +25990,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
basic_json result; basic_json result;
auto ia = detail::input_adapter(std::forward<InputType>(i)); auto ia = detail::input_adapter(std::forward<InputType>(i));
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
/// @brief create a JSON value from an input in CBOR format (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief create a JSON value from an input in CBOR format (iterator pair, or iterator+sentinel pair for C++20 ranges support)
@@ -25945,8 +26010,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
basic_json result; basic_json result;
auto ia = detail::input_adapter(std::move(first), std::move(last)); auto ia = detail::input_adapter(std::move(first), std::move(last));
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
template<typename T> template<typename T>
@@ -25971,8 +26039,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
auto ia = i.get(); auto ia = i.get();
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
/// @brief create a JSON value from an input in MessagePack format /// @brief create a JSON value from an input in MessagePack format
@@ -25986,8 +26057,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
basic_json result; basic_json result;
auto ia = detail::input_adapter(std::forward<InputType>(i)); auto ia = detail::input_adapter(std::forward<InputType>(i));
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
/// @brief create a JSON value from an input in MessagePack format (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief create a JSON value from an input in MessagePack format (iterator pair, or iterator+sentinel pair for C++20 ranges support)
@@ -26002,8 +26076,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
basic_json result; basic_json result;
auto ia = detail::input_adapter(std::move(first), std::move(last)); auto ia = detail::input_adapter(std::move(first), std::move(last));
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
template<typename T> template<typename T>
@@ -26026,8 +26103,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
auto ia = i.get(); auto ia = i.get();
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
/// @brief create a JSON value from an input in UBJSON format /// @brief create a JSON value from an input in UBJSON format
@@ -26041,8 +26121,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
basic_json result; basic_json result;
auto ia = detail::input_adapter(std::forward<InputType>(i)); auto ia = detail::input_adapter(std::forward<InputType>(i));
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
/// @brief create a JSON value from an input in UBJSON format (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief create a JSON value from an input in UBJSON format (iterator pair, or iterator+sentinel pair for C++20 ranges support)
@@ -26057,8 +26140,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
basic_json result; basic_json result;
auto ia = detail::input_adapter(std::move(first), std::move(last)); auto ia = detail::input_adapter(std::move(first), std::move(last));
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
template<typename T> template<typename T>
@@ -26081,8 +26167,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
auto ia = i.get(); auto ia = i.get();
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
/// @brief create a JSON value from an input in BJData format /// @brief create a JSON value from an input in BJData format
@@ -26096,8 +26185,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
basic_json result; basic_json result;
auto ia = detail::input_adapter(std::forward<InputType>(i)); auto ia = detail::input_adapter(std::forward<InputType>(i));
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
/// @brief create a JSON value from an input in BJData format (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief create a JSON value from an input in BJData format (iterator pair, or iterator+sentinel pair for C++20 ranges support)
@@ -26112,8 +26204,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
basic_json result; basic_json result;
auto ia = detail::input_adapter(std::move(first), std::move(last)); auto ia = detail::input_adapter(std::move(first), std::move(last));
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
/// @brief create a JSON value from an input in BSON format /// @brief create a JSON value from an input in BSON format
@@ -26127,8 +26222,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
basic_json result; basic_json result;
auto ia = detail::input_adapter(std::forward<InputType>(i)); auto ia = detail::input_adapter(std::forward<InputType>(i));
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
/// @brief create a JSON value from an input in BSON format (iterator pair, or iterator+sentinel pair for C++20 ranges support) /// @brief create a JSON value from an input in BSON format (iterator pair, or iterator+sentinel pair for C++20 ranges support)
@@ -26143,8 +26241,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
basic_json result; basic_json result;
auto ia = detail::input_adapter(std::move(first), std::move(last)); auto ia = detail::input_adapter(std::move(first), std::move(last));
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
template<typename T> template<typename T>
@@ -26167,8 +26268,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
auto ia = i.get(); auto ia = i.get();
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions); detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved] if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict)) // cppcheck-suppress[accessMoved]
return res ? result : basic_json(value_t::discarded); {
result = value_t::discarded;
}
return result;
} }
/// @} /// @}
-9
View File
@@ -15,15 +15,6 @@
namespace utils namespace utils
{ {
// Some tests intentionally discard the [[nodiscard]]/JSON_HEDLEY_WARN_UNUSED_RESULT
// return value of a call they only make to exercise its side effects (e.g. checking
// that it does not throw). A plain (void) cast on the call expression does not
// suppress GCC's warning for functions using the GNU __attribute__((warn_unused_result))
// form (as opposed to the C++17 [[nodiscard]] attribute) -- passing the value into an
// ordinary function call does.
template<typename T>
inline void ignore_return_value(T&& /*unused*/) noexcept {}
inline std::vector<std::uint8_t> read_binary_file(const std::string& filename) inline std::vector<std::uint8_t> read_binary_file(const std::string& filename)
{ {
std::ifstream file(filename, std::ios::binary); std::ifstream file(filename, std::ios::binary);
+18 -3
View File
@@ -3288,8 +3288,10 @@ TEST_CASE("BJData")
CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR1), "[json.exception.parse_error.113] parse error at byte 6: syntax error while parsing BJData size: ndarray dimensional vector is not allowed", json::parse_error&); CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR1), "[json.exception.parse_error.113] parse error at byte 6: syntax error while parsing BJData size: ndarray dimensional vector is not allowed", json::parse_error&);
CHECK(json::from_bjdata(vR1, true, false).is_discarded()); CHECK(json::from_bjdata(vR1, true, false).is_discarded());
// a dimension vector that opens another one is rejected where the
// nested '[' is read, rather than after it has been descended into
std::vector<uint8_t> const vR2 = {'[', '$', 'i', '#', '[', '#', '[', 'i', 1, ']', ']', 1}; std::vector<uint8_t> const vR2 = {'[', '$', 'i', '#', '[', '#', '[', 'i', 1, ']', ']', 1};
CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR2), "[json.exception.parse_error.113] parse error at byte 11: syntax error while parsing BJData size: expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x5D", json::parse_error&); CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR2), "[json.exception.parse_error.113] parse error at byte 7: syntax error while parsing BJData size: ndarray dimensional vector is not allowed", json::parse_error&);
CHECK(json::from_bjdata(vR2, true, false).is_discarded()); CHECK(json::from_bjdata(vR2, true, false).is_discarded());
std::vector<uint8_t> const vR3 = {'[', '#', '[', 'i', '2', 'i', 2, ']'}; std::vector<uint8_t> const vR3 = {'[', '#', '[', 'i', '2', 'i', 2, ']'};
@@ -3297,7 +3299,7 @@ TEST_CASE("BJData")
CHECK(json::from_bjdata(vR3, true, false).is_discarded()); CHECK(json::from_bjdata(vR3, true, false).is_discarded());
std::vector<uint8_t> const vR4 = {'[', '$', 'i', '#', '[', '$', 'i', '#', '[', 'i', 1, ']', 1}; std::vector<uint8_t> const vR4 = {'[', '$', 'i', '#', '[', '$', 'i', '#', '[', 'i', 1, ']', 1};
CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR4), "[json.exception.parse_error.110] parse error at byte 14: syntax error while parsing BJData number: unexpected end of input", json::parse_error&); CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR4), "[json.exception.parse_error.113] parse error at byte 9: syntax error while parsing BJData size: ndarray dimensional vector is not allowed", json::parse_error&);
CHECK(json::from_bjdata(vR4, true, false).is_discarded()); CHECK(json::from_bjdata(vR4, true, false).is_discarded());
std::vector<uint8_t> const vR5 = {'[', '$', 'i', '#', '[', '[', '[', ']', ']', ']'}; std::vector<uint8_t> const vR5 = {'[', '$', 'i', '#', '[', '[', '[', ']', ']', ']'};
@@ -3305,12 +3307,25 @@ TEST_CASE("BJData")
CHECK(json::from_bjdata(vR5, true, false).is_discarded()); CHECK(json::from_bjdata(vR5, true, false).is_discarded());
std::vector<uint8_t> const vR6 = {'[', '$', 'i', '#', '[', '$', 'i', '#', '[', 'i', '2', 'i', 2, ']'}; std::vector<uint8_t> const vR6 = {'[', '$', 'i', '#', '[', '$', 'i', '#', '[', 'i', '2', 'i', 2, ']'};
CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR6), "[json.exception.parse_error.112] parse error at byte 14: syntax error while parsing BJData size: ndarray can not be recursive", json::parse_error&); CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vR6), "[json.exception.parse_error.113] parse error at byte 9: syntax error while parsing BJData size: ndarray dimensional vector is not allowed", json::parse_error&);
CHECK(json::from_bjdata(vR6, true, false).is_discarded()); CHECK(json::from_bjdata(vR6, true, false).is_discarded());
std::vector<uint8_t> const vH = {'[', 'H', '[', '#', '[', '$', 'i', '#', '[', 'i', '2', 'i', 2, ']'}; std::vector<uint8_t> const vH = {'[', 'H', '[', '#', '[', '$', 'i', '#', '[', 'i', '2', 'i', 2, ']'};
CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vH), "[json.exception.parse_error.113] parse error at byte 3: syntax error while parsing BJData size: ndarray dimensional vector is not allowed", json::parse_error&); CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vH), "[json.exception.parse_error.113] parse error at byte 3: syntax error while parsing BJData size: ndarray dimensional vector is not allowed", json::parse_error&);
CHECK(json::from_bjdata(vH, true, false).is_discarded()); CHECK(json::from_bjdata(vH, true, false).is_discarded());
// Every "#[" of this chain used to open another dimension vector
// and cost several stack frames before anything was rejected, so a
// long enough chain crashed the process (see #5104). The nested
// vector is refused where it is read, so the length is irrelevant.
std::vector<uint8_t> vRdeep = {'['};
for (std::size_t i = 0; i < 100000; ++i)
{
vRdeep.push_back('#');
vRdeep.push_back('[');
}
CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vRdeep), "[json.exception.parse_error.113] parse error at byte 5: syntax error while parsing BJData size: ndarray dimensional vector is not allowed", json::parse_error&);
CHECK(json::from_bjdata(vRdeep, true, false).is_discarded());
} }
SECTION("objects") SECTION("objects")
+52
View File
@@ -2035,6 +2035,58 @@ TEST_CASE("CBOR definite length equal to the indefinite-length sentinel")
} }
} }
TEST_CASE("CBOR indefinite-length strings do not recurse per chunk")
{
// Reading an indefinite-length string or byte array used to call itself
// once per chunk, so a payload of repeated 0x7F (or 0x5F) bytes exhausted
// the call stack before any of the input was rejected. The open levels are
// counted now, and the levels below prove the reader still reads the same
// values and reports the same errors at the same byte offsets.
json _;
SECTION("many open levels are reported, not crashed on")
{
const std::vector<uint8_t> input(200000, 0x7F);
CHECK_THROWS_WITH_AS(_ = json::from_cbor(input), "[json.exception.parse_error.110] parse error at byte 200001: syntax error while parsing CBOR string: unexpected end of input", json::parse_error&);
CHECK(json::from_cbor(input, true, false).is_discarded());
}
SECTION("many open levels are reported, not crashed on (binary)")
{
const std::vector<uint8_t> input(200000, 0x5F);
CHECK_THROWS_WITH_AS(_ = json::from_cbor(input), "[json.exception.parse_error.110] parse error at byte 200001: syntax error while parsing CBOR binary: unexpected end of input", json::parse_error&);
CHECK(json::from_cbor(input, true, false).is_discarded());
}
SECTION("chunks are still concatenated")
{
CHECK(json::from_cbor(std::vector<uint8_t>({0x7F, 0xFF})) == json(""));
CHECK(json::from_cbor(std::vector<uint8_t>({0x7F, 0x61, 0x61, 0xFF})) == json("a"));
// nested indefinite-length strings are concatenated across levels
CHECK(json::from_cbor(std::vector<uint8_t>({0x7F, 0x7F, 0x61, 0x61, 0xFF, 0x61, 0x62, 0xFF})) == json("ab"));
CHECK(json::from_cbor(std::vector<uint8_t>({0x7F, 0x7F, 0x7F, 0x61, 0x7A, 0xFF, 0xFF, 0xFF})) == json("z"));
CHECK(json::from_cbor(std::vector<uint8_t>({0xA1, 0x7F, 0x61, 0x61, 0xFF, 0x01})) == json({{"a", 1}}));
}
SECTION("chunks are still concatenated (binary)")
{
CHECK(json::from_cbor(std::vector<uint8_t>({0x5F, 0x41, 0x61, 0xFF})) == json::binary({0x61}));
CHECK(json::from_cbor(std::vector<uint8_t>({0x5F, 0x5F, 0x41, 0x61, 0xFF, 0x41, 0x62, 0xFF})) == json::binary({0x61, 0x62}));
}
SECTION("a chunk that is not a string is still rejected")
{
CHECK_THROWS_WITH_AS(_ = json::from_cbor(std::vector<uint8_t>({0x7F, 0x7F, 0x00})), "[json.exception.parse_error.113] parse error at byte 3: syntax error while parsing CBOR string: expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x00", json::parse_error&);
CHECK_THROWS_WITH_AS(_ = json::from_cbor(std::vector<uint8_t>({0x5F, 0x5F, 0x00})), "[json.exception.parse_error.113] parse error at byte 3: syntax error while parsing CBOR binary: expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x00", json::parse_error&);
}
SECTION("a break marker outside an indefinite-length string is not a string")
{
// 0xFF only closes a string that was opened; on its own it is not one
CHECK_THROWS_WITH_AS(_ = json::from_cbor(std::vector<uint8_t>({0xA1, 0xFF, 0x01})), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing CBOR string: expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0xFF", json::parse_error&);
}
}
TEST_CASE("CBOR roundtrips" * doctest::skip()) TEST_CASE("CBOR roundtrips" * doctest::skip())
{ {
SECTION("input from flynn") SECTION("input from flynn")
+1 -4
View File
@@ -23,8 +23,6 @@ using nlohmann::json;
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "test_utils.hpp"
namespace namespace
{ {
class SaxEventLogger class SaxEventLogger
@@ -626,8 +624,7 @@ TEST_CASE("parser class")
SECTION("overflow") SECTION("overflow")
{ {
// overflows during parsing yield an exception // overflows during parsing yield an exception
// empty() is nodiscard; the exception is thrown by parser_helper() itself, before empty() would run CHECK_THROWS_WITH_AS(parser_helper("1.18973e+4932").empty(), "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'", json::out_of_range&);
CHECK_THROWS_WITH_AS(utils::ignore_return_value(parser_helper("1.18973e+4932").empty()), "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'", json::out_of_range&);
} }
SECTION("invalid numbers") SECTION("invalid numbers")
@@ -22,8 +22,6 @@ using nlohmann::json;
#include <valarray> #include <valarray>
#include "test_utils.hpp"
namespace namespace
{ {
class SaxEventLogger class SaxEventLogger
@@ -631,8 +629,7 @@ TEST_CASE("parser class")
SECTION("overflow") SECTION("overflow")
{ {
// overflows during parsing yield an exception // overflows during parsing yield an exception
// empty() is nodiscard; the exception is thrown by parser_helper() itself, before empty() would run CHECK_THROWS_WITH_AS(parser_helper("1.18973e+4932").empty(), "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'", json::out_of_range&);
CHECK_THROWS_WITH_AS(utils::ignore_return_value(parser_helper("1.18973e+4932").empty()), "[json.exception.out_of_range.406] number overflow parsing '1.18973e+4932'", json::out_of_range&);
} }
SECTION("invalid numbers") SECTION("invalid numbers")
+1 -3
View File
@@ -29,7 +29,6 @@ using nlohmann::json;
#include <limits> #include <limits>
#include <cstdio> #include <cstdio>
#include "make_test_data_available.hpp" #include "make_test_data_available.hpp"
#include "test_utils.hpp"
#ifdef JSON_HAS_CPP_17 #ifdef JSON_HAS_CPP_17
#include <variant> #include <variant>
@@ -1374,8 +1373,7 @@ TEST_CASE("regression tests 1")
std::array<uint8_t, 28> key1 = {{ 103, 92, 117, 48, 48, 48, 55, 92, 114, 215, 126, 214, 95, 92, 34, 174, 40, 71, 38, 174, 40, 71, 38, 223, 134, 247, 127, 0 }}; std::array<uint8_t, 28> key1 = {{ 103, 92, 117, 48, 48, 48, 55, 92, 114, 215, 126, 214, 95, 92, 34, 174, 40, 71, 38, 174, 40, 71, 38, 223, 134, 247, 127, 0 }};
std::string const key1_str(reinterpret_cast<char*>(key1.data())); std::string const key1_str(reinterpret_cast<char*>(key1.data()));
json const j = key1_str; json const j = key1_str;
// dump() is nodiscard; the exception is thrown by dump() itself before it would return CHECK_THROWS_WITH_AS(j.dump(), "[json.exception.type_error.316] invalid UTF-8 byte at index 10: 0x7E", json::type_error&);
CHECK_THROWS_WITH_AS(utils::ignore_return_value(j.dump()), "[json.exception.type_error.316] invalid UTF-8 byte at index 10: 0x7E", json::type_error&);
} }
#if JSON_USE_IMPLICIT_CONVERSIONS #if JSON_USE_IMPLICIT_CONVERSIONS
+6 -15
View File
@@ -31,8 +31,6 @@ using ordered_json = nlohmann::ordered_json;
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include "test_utils.hpp"
#ifdef JSON_HAS_CPP_17 #ifdef JSON_HAS_CPP_17
#include <any> #include <any>
#include <variant> #include <variant>
@@ -641,12 +639,7 @@ TEST_CASE("regression tests 2")
s += static_cast<char>(i); s += static_cast<char>(i);
} }
dump_test["1"] = s; dump_test["1"] = s;
// dump() is nodiscard; this only checks that dumping does not throw/crash. dump_test.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace);
// A (void) cast on the call itself does not suppress GCC's warning for the
// GNU warn_unused_result attribute (unlike a real C++17 [[nodiscard]]), so
// capture the result in a variable and discard that instead.
auto dump_result = dump_test.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace);
(void)dump_result;
} }
} }
@@ -738,14 +731,12 @@ TEST_CASE("regression tests 2")
{ {
const std::array<unsigned char, 23> data = {{0x81, 0xA4, 0x64, 0x61, 0x74, 0x61, 0xC4, 0x0F, 0x33, 0x30, 0x30, 0x32, 0x33, 0x34, 0x30, 0x31, 0x30, 0x37, 0x30, 0x35, 0x30, 0x31, 0x30}}; const std::array<unsigned char, 23> data = {{0x81, 0xA4, 0x64, 0x61, 0x74, 0x61, 0xC4, 0x0F, 0x33, 0x30, 0x30, 0x32, 0x33, 0x34, 0x30, 0x31, 0x30, 0x37, 0x30, 0x35, 0x30, 0x31, 0x30}};
const json j = json::from_msgpack(data.data(), data.size()); const json j = json::from_msgpack(data.data(), data.size());
// dump() is nodiscard; this only checks that dumping does not throw
CHECK_NOTHROW( CHECK_NOTHROW(
utils::ignore_return_value( j.dump(4, // Indent
j.dump(4, // Indent ' ', // Indent char
' ', // Indent char false, // Ensure ascii
false, // Ensure ascii json::error_handler_t::strict // Error
json::error_handler_t::strict // Error ));
)));
} }
SECTION("PR #2181 - regression bug with lvalue") SECTION("PR #2181 - regression bug with lvalue")
+6 -11
View File
@@ -15,8 +15,6 @@ using nlohmann::json;
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include "test_utils.hpp"
TEST_CASE("serialization") TEST_CASE("serialization")
{ {
SECTION("operator<<") SECTION("operator<<")
@@ -86,9 +84,8 @@ TEST_CASE("serialization")
{ {
const json j = "ä\xA9ü"; const json j = "ä\xA9ü";
// dump() is nodiscard; the exception is thrown by dump() itself before it would return CHECK_THROWS_WITH_AS(j.dump(), "[json.exception.type_error.316] invalid UTF-8 byte at index 2: 0xA9", json::type_error&);
CHECK_THROWS_WITH_AS(utils::ignore_return_value(j.dump()), "[json.exception.type_error.316] invalid UTF-8 byte at index 2: 0xA9", json::type_error&); CHECK_THROWS_WITH_AS(j.dump(1, ' ', false, json::error_handler_t::strict), "[json.exception.type_error.316] invalid UTF-8 byte at index 2: 0xA9", json::type_error&);
CHECK_THROWS_WITH_AS(utils::ignore_return_value(j.dump(1, ' ', false, json::error_handler_t::strict)), "[json.exception.type_error.316] invalid UTF-8 byte at index 2: 0xA9", json::type_error&);
CHECK(j.dump(-1, ' ', false, json::error_handler_t::ignore) == "\"äü\""); CHECK(j.dump(-1, ' ', false, json::error_handler_t::ignore) == "\"äü\"");
CHECK(j.dump(-1, ' ', false, json::error_handler_t::replace) == "\"ä\xEF\xBF\xBDü\""); CHECK(j.dump(-1, ' ', false, json::error_handler_t::replace) == "\"ä\xEF\xBF\xBDü\"");
CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"\\u00e4\\ufffd\\u00fc\""); CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"\\u00e4\\ufffd\\u00fc\"");
@@ -98,9 +95,8 @@ TEST_CASE("serialization")
{ {
const json j = "123\xC2"; const json j = "123\xC2";
// dump() is nodiscard; the exception is thrown by dump() itself before it would return CHECK_THROWS_WITH_AS(j.dump(), "[json.exception.type_error.316] incomplete UTF-8 string; last byte: 0xC2", json::type_error&);
CHECK_THROWS_WITH_AS(utils::ignore_return_value(j.dump()), "[json.exception.type_error.316] incomplete UTF-8 string; last byte: 0xC2", json::type_error&); CHECK_THROWS_AS(j.dump(1, ' ', false, json::error_handler_t::strict), json::type_error&);
CHECK_THROWS_AS(utils::ignore_return_value(j.dump(1, ' ', false, json::error_handler_t::strict)), json::type_error&);
CHECK(j.dump(-1, ' ', false, json::error_handler_t::ignore) == "\"123\""); CHECK(j.dump(-1, ' ', false, json::error_handler_t::ignore) == "\"123\"");
CHECK(j.dump(-1, ' ', false, json::error_handler_t::replace) == "\"123\xEF\xBF\xBD\""); CHECK(j.dump(-1, ' ', false, json::error_handler_t::replace) == "\"123\xEF\xBF\xBD\"");
CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"123\\ufffd\""); CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"123\\ufffd\"");
@@ -110,9 +106,8 @@ TEST_CASE("serialization")
{ {
const json j = "123\xF1\xB0\x34\x35\x36"; const json j = "123\xF1\xB0\x34\x35\x36";
// dump() is nodiscard; the exception is thrown by dump() itself before it would return CHECK_THROWS_WITH_AS(j.dump(), "[json.exception.type_error.316] invalid UTF-8 byte at index 5: 0x34", json::type_error&);
CHECK_THROWS_WITH_AS(utils::ignore_return_value(j.dump()), "[json.exception.type_error.316] invalid UTF-8 byte at index 5: 0x34", json::type_error&); CHECK_THROWS_AS(j.dump(1, ' ', false, json::error_handler_t::strict), json::type_error&);
CHECK_THROWS_AS(utils::ignore_return_value(j.dump(1, ' ', false, json::error_handler_t::strict)), json::type_error&);
CHECK(j.dump(-1, ' ', false, json::error_handler_t::ignore) == "\"123456\""); CHECK(j.dump(-1, ' ', false, json::error_handler_t::ignore) == "\"123456\"");
CHECK(j.dump(-1, ' ', false, json::error_handler_t::replace) == "\"123\xEF\xBF\xBD\x34\x35\x36\""); CHECK(j.dump(-1, ' ', false, json::error_handler_t::replace) == "\"123\xEF\xBF\xBD\x34\x35\x36\"");
CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"123\\ufffd456\""); CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"123\\ufffd456\"");
+2 -5
View File
@@ -17,7 +17,6 @@ using nlohmann::json;
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include "make_test_data_available.hpp" #include "make_test_data_available.hpp"
#include "test_utils.hpp"
TEST_CASE("Unicode (1/5)" * doctest::skip()) TEST_CASE("Unicode (1/5)" * doctest::skip())
{ {
@@ -241,8 +240,7 @@ void roundtrip(bool success_expected, const std::string& s)
if (success_expected) if (success_expected)
{ {
// serialization succeeds // serialization succeeds
// dump() is nodiscard; this only checks that dumping does not throw CHECK_NOTHROW(j.dump());
CHECK_NOTHROW(utils::ignore_return_value(j.dump()));
// exclude parse test for U+0000 // exclude parse test for U+0000
if (s[0] != '\0') if (s[0] != '\0')
@@ -261,8 +259,7 @@ void roundtrip(bool success_expected, const std::string& s)
else else
{ {
// serialization fails // serialization fails
// dump() is nodiscard; the exception is thrown by dump() itself before it would return CHECK_THROWS_AS(j.dump(), json::type_error&);
CHECK_THROWS_AS(utils::ignore_return_value(j.dump()), json::type_error&);
// parsing JSON text fails // parsing JSON text fails
CHECK_THROWS_AS(_ = json::parse(ps), json::parse_error&); CHECK_THROWS_AS(_ = json::parse(ps), json::parse_error&);
+1 -3
View File
@@ -19,7 +19,6 @@ using nlohmann::json;
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include "make_test_data_available.hpp" #include "make_test_data_available.hpp"
#include "test_utils.hpp"
// this test suite uses static variables with non-trivial destructors // this test suite uses static variables with non-trivial destructors
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
@@ -98,8 +97,7 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
else else
{ {
// strict mode must throw if success is not expected // strict mode must throw if success is not expected
// dump() is nodiscard; the exception is thrown by dump() itself before it would return CHECK_THROWS_AS(j.dump(), json::type_error&);
CHECK_THROWS_AS(utils::ignore_return_value(j.dump()), json::type_error&);
// ignore and replace must create different dumps // ignore and replace must create different dumps
CHECK(s_ignored != s_replaced); CHECK(s_ignored != s_replaced);
+1 -3
View File
@@ -19,7 +19,6 @@ using nlohmann::json;
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include "make_test_data_available.hpp" #include "make_test_data_available.hpp"
#include "test_utils.hpp"
// this test suite uses static variables with non-trivial destructors // this test suite uses static variables with non-trivial destructors
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
@@ -98,8 +97,7 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
else else
{ {
// strict mode must throw if success is not expected // strict mode must throw if success is not expected
// dump() is nodiscard; the exception is thrown by dump() itself before it would return CHECK_THROWS_AS(j.dump(), json::type_error&);
CHECK_THROWS_AS(utils::ignore_return_value(j.dump()), json::type_error&);
// ignore and replace must create different dumps // ignore and replace must create different dumps
CHECK(s_ignored != s_replaced); CHECK(s_ignored != s_replaced);
+1 -3
View File
@@ -19,7 +19,6 @@ using nlohmann::json;
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include "make_test_data_available.hpp" #include "make_test_data_available.hpp"
#include "test_utils.hpp"
// this test suite uses static variables with non-trivial destructors // this test suite uses static variables with non-trivial destructors
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
@@ -98,8 +97,7 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
else else
{ {
// strict mode must throw if success is not expected // strict mode must throw if success is not expected
// dump() is nodiscard; the exception is thrown by dump() itself before it would return CHECK_THROWS_AS(j.dump(), json::type_error&);
CHECK_THROWS_AS(utils::ignore_return_value(j.dump()), json::type_error&);
// ignore and replace must create different dumps // ignore and replace must create different dumps
CHECK(s_ignored != s_replaced); CHECK(s_ignored != s_replaced);
+1 -3
View File
@@ -19,7 +19,6 @@ using nlohmann::json;
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include "make_test_data_available.hpp" #include "make_test_data_available.hpp"
#include "test_utils.hpp"
// this test suite uses static variables with non-trivial destructors // this test suite uses static variables with non-trivial destructors
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
@@ -98,8 +97,7 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
else else
{ {
// strict mode must throw if success is not expected // strict mode must throw if success is not expected
// dump() is nodiscard; the exception is thrown by dump() itself before it would return CHECK_THROWS_AS(j.dump(), json::type_error&);
CHECK_THROWS_AS(utils::ignore_return_value(j.dump()), json::type_error&);
// ignore and replace must create different dumps // ignore and replace must create different dumps
CHECK(s_ignored != s_replaced); CHECK(s_ignored != s_replaced);