mirror of
https://github.com/nlohmann/json.git
synced 2026-09-27 02:10:28 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c637e73bea |
@@ -25,15 +25,10 @@ and `ensure_ascii` parameters.
|
|||||||
result consists of ASCII characters only.
|
result consists of ASCII characters only.
|
||||||
|
|
||||||
`error_handler` (in)
|
`error_handler` (in)
|
||||||
: how to react on decoding errors; there are four possible values (see [`error_handler_t`](error_handler_t.md)):
|
: how to react on decoding errors; there are three possible values (see [`error_handler_t`](error_handler_t.md):
|
||||||
|
`strict` (throws an exception in case a decoding error occurs; default), `replace` (replace invalid UTF-8 sequences
|
||||||
- `strict`: throw a [`type_error`](../../home/exceptions.md#type-errors) exception in case a decoding error occurs
|
with U+FFFD), and `ignore` (ignore invalid UTF-8 sequences during serialization; all valid bytes are copied to the
|
||||||
(default),
|
output unchanged, and invalid bytes are dropped)).
|
||||||
- `replace`: replace invalid UTF-8 sequences with U+FFFD (� REPLACEMENT CHARACTER),
|
|
||||||
- `ignore`: ignore invalid UTF-8 sequences during serialization; all valid bytes are copied to the output unchanged,
|
|
||||||
and invalid bytes are dropped, and
|
|
||||||
- `keep`: keep invalid UTF-8 sequences during serialization; all bytes are copied to the output unchanged, so the
|
|
||||||
result is not valid UTF-8.
|
|
||||||
|
|
||||||
## Return value
|
## Return value
|
||||||
|
|
||||||
@@ -99,4 +94,3 @@ Binary values are serialized as an object containing two keys:
|
|||||||
- Indentation character `indent_char`, option `ensure_ascii` and exceptions added in version 3.0.0.
|
- Indentation character `indent_char`, option `ensure_ascii` and exceptions added in version 3.0.0.
|
||||||
- Error handlers added in version 3.4.0.
|
- Error handlers added in version 3.4.0.
|
||||||
- Serialization of binary values added in version 3.8.0.
|
- Serialization of binary values added in version 3.8.0.
|
||||||
- Error handler value `keep` added in version 3.13.0.
|
|
||||||
|
|||||||
@@ -4,13 +4,12 @@
|
|||||||
enum class error_handler_t {
|
enum class error_handler_t {
|
||||||
strict,
|
strict,
|
||||||
replace,
|
replace,
|
||||||
ignore,
|
ignore
|
||||||
keep
|
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
This enumeration is used in the [`dump`](dump.md) function to choose how to treat decoding errors while serializing a
|
This enumeration is used in the [`dump`](dump.md) function to choose how to treat decoding errors while serializing a
|
||||||
`basic_json` value. Four values are differentiated:
|
`basic_json` value. Three values are differentiated:
|
||||||
|
|
||||||
strict
|
strict
|
||||||
: throw a `type_error` exception in case of invalid UTF-8
|
: throw a `type_error` exception in case of invalid UTF-8
|
||||||
@@ -21,12 +20,6 @@ replace
|
|||||||
ignore
|
ignore
|
||||||
: ignore invalid UTF-8 sequences; all valid bytes are copied to the output unchanged, and invalid bytes are dropped
|
: ignore invalid UTF-8 sequences; all valid bytes are copied to the output unchanged, and invalid bytes are dropped
|
||||||
|
|
||||||
keep
|
|
||||||
: keep invalid UTF-8 sequences; all bytes are copied to the output unchanged. Valid characters are still escaped as
|
|
||||||
usual (e.g., `"`, `\\`, and control characters), so the result has valid JSON syntax, but it is not valid UTF-8.
|
|
||||||
In particular, [`parse`](parse.md) rejects it, and with `ensure_ascii` set to `true`, the invalid bytes are the
|
|
||||||
only non-ASCII bytes of the output.
|
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
??? example
|
??? example
|
||||||
@@ -47,4 +40,3 @@ keep
|
|||||||
## Version history
|
## Version history
|
||||||
|
|
||||||
- Added in version 3.4.0.
|
- Added in version 3.4.0.
|
||||||
- Added value `keep` in version 3.13.0.
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
#include <iomanip>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
@@ -22,12 +21,4 @@ int main()
|
|||||||
<< "\nstring with ignored invalid characters: "
|
<< "\nstring with ignored invalid characters: "
|
||||||
<< j_invalid.dump(-1, ' ', false, json::error_handler_t::ignore)
|
<< j_invalid.dump(-1, ' ', false, json::error_handler_t::ignore)
|
||||||
<< '\n';
|
<< '\n';
|
||||||
|
|
||||||
// the invalid byte is kept; print the result byte-wise to make it visible
|
|
||||||
std::cout << "string with kept invalid characters:";
|
|
||||||
for (const unsigned char c : j_invalid.dump(-1, ' ', false, json::error_handler_t::keep))
|
|
||||||
{
|
|
||||||
std::cout << ' ' << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(c);
|
|
||||||
}
|
|
||||||
std::cout << '\n';
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
[json.exception.type_error.316] invalid UTF-8 byte at index 2: 0xA9
|
[json.exception.type_error.316] invalid UTF-8 byte at index 2: 0xA9
|
||||||
string with replaced invalid characters: "ä�ü"
|
string with replaced invalid characters: "ä�ü"
|
||||||
string with ignored invalid characters: "äü"
|
string with ignored invalid characters: "äü"
|
||||||
string with kept invalid characters: 22 c3 a4 a9 c3 bc 22
|
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ serialization fails by default. The fourth argument of `dump` selects an
|
|||||||
- `strict` (default) — throw a [`type_error.316`](../home/exceptions.md#jsonexceptiontype_error316) exception.
|
- `strict` (default) — throw a [`type_error.316`](../home/exceptions.md#jsonexceptiontype_error316) exception.
|
||||||
- `replace` — replace invalid bytes with the Unicode replacement character U+FFFD (`�`).
|
- `replace` — replace invalid bytes with the Unicode replacement character U+FFFD (`�`).
|
||||||
- `ignore` — silently drop invalid bytes.
|
- `ignore` — silently drop invalid bytes.
|
||||||
- `keep` — copy invalid bytes to the output unchanged; the result is not valid UTF-8.
|
|
||||||
|
|
||||||
??? example
|
??? example
|
||||||
|
|
||||||
|
|||||||
@@ -755,7 +755,6 @@ The `dump()` function only works with UTF-8 encoded strings; that is, if you ass
|
|||||||
- Pass an error handler as last parameter to the `dump()` function to avoid this exception:
|
- Pass an error handler as last parameter to the `dump()` function to avoid this exception:
|
||||||
- `json::error_handler_t::replace` will replace invalid bytes sequences with `U+FFFD`
|
- `json::error_handler_t::replace` will replace invalid bytes sequences with `U+FFFD`
|
||||||
- `json::error_handler_t::ignore` will silently ignore invalid byte sequences
|
- `json::error_handler_t::ignore` will silently ignore invalid byte sequences
|
||||||
- `json::error_handler_t::keep` will copy invalid byte sequences to the output unchanged
|
|
||||||
|
|
||||||
### json.exception.type_error.317
|
### json.exception.type_error.317
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ The library supports **Unicode input** as follows:
|
|||||||
- The library will not replace [Unicode noncharacters](http://www.unicode.org/faq/private_use.html#nonchar1).
|
- The library will not replace [Unicode noncharacters](http://www.unicode.org/faq/private_use.html#nonchar1).
|
||||||
- Invalid surrogates (e.g., incomplete pairs such as `\uDEAD`) will yield parse errors.
|
- Invalid surrogates (e.g., incomplete pairs such as `\uDEAD`) will yield parse errors.
|
||||||
- The strings stored in the library are UTF-8 encoded. When using the default string type (`std::string`), note that its length/size functions return the number of stored bytes rather than the number of characters or glyphs.
|
- The strings stored in the library are UTF-8 encoded. When using the default string type (`std::string`), note that its length/size functions return the number of stored bytes rather than the number of characters or glyphs.
|
||||||
- When you store strings with different encodings in the library, calling [`dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a50ec80b02d0f3f51130d4abb5d1cfdc5.html#a50ec80b02d0f3f51130d4abb5d1cfdc5) may throw an exception unless `json::error_handler_t::replace`, `json::error_handler_t::ignore`, or `json::error_handler_t::keep` are used as error handlers.
|
- When you store strings with different encodings in the library, calling [`dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a50ec80b02d0f3f51130d4abb5d1cfdc5.html#a50ec80b02d0f3f51130d4abb5d1cfdc5) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers.
|
||||||
|
|
||||||
In most cases, the parser is right to complain, because the input is not UTF-8 encoded. This is especially true for Microsoft Windows, where Latin-1 or ISO 8859-1 is often the standard encoding.
|
In most cases, the parser is right to complain, because the input is not UTF-8 encoded. This is especially true for Microsoft Windows, where Latin-1 or ISO 8859-1 is often the standard encoding.
|
||||||
|
|
||||||
|
|||||||
@@ -168,92 +168,20 @@ class binary_writer
|
|||||||
if (j.m_data.m_value.number_integer >= 0)
|
if (j.m_data.m_value.number_integer >= 0)
|
||||||
{
|
{
|
||||||
// CBOR does not differentiate between positive signed
|
// CBOR does not differentiate between positive signed
|
||||||
// integers and unsigned integers. Therefore, we used the
|
// integers and unsigned integers
|
||||||
// code from the value_t::number_unsigned case here.
|
write_cbor_head(0x00, static_cast<std::uint64_t>(j.m_data.m_value.number_integer));
|
||||||
if (j.m_data.m_value.number_integer <= 0x17)
|
|
||||||
{
|
|
||||||
write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
|
|
||||||
}
|
|
||||||
else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x18));
|
|
||||||
write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
|
|
||||||
}
|
|
||||||
else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x19));
|
|
||||||
write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer));
|
|
||||||
}
|
|
||||||
else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x1A));
|
|
||||||
write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x1B));
|
|
||||||
write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The conversions below encode the sign in the first
|
// a negative integer n is encoded as -1 - n
|
||||||
// byte, and the value is converted to a positive number.
|
write_cbor_head(0x20, static_cast<std::uint64_t>(-1 - j.m_data.m_value.number_integer));
|
||||||
const auto positive_number = -1 - j.m_data.m_value.number_integer;
|
|
||||||
if (j.m_data.m_value.number_integer >= -24)
|
|
||||||
{
|
|
||||||
write_number(static_cast<std::uint8_t>(0x20 + positive_number));
|
|
||||||
}
|
|
||||||
else if (positive_number <= (std::numeric_limits<std::uint8_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x38));
|
|
||||||
write_number(static_cast<std::uint8_t>(positive_number));
|
|
||||||
}
|
|
||||||
else if (positive_number <= (std::numeric_limits<std::uint16_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x39));
|
|
||||||
write_number(static_cast<std::uint16_t>(positive_number));
|
|
||||||
}
|
|
||||||
else if (positive_number <= (std::numeric_limits<std::uint32_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x3A));
|
|
||||||
write_number(static_cast<std::uint32_t>(positive_number));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x3B));
|
|
||||||
write_number(static_cast<std::uint64_t>(positive_number));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case value_t::number_unsigned:
|
case value_t::number_unsigned:
|
||||||
{
|
{
|
||||||
if (j.m_data.m_value.number_unsigned <= 0x17)
|
write_cbor_head(0x00, j.m_data.m_value.number_unsigned);
|
||||||
{
|
|
||||||
write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_unsigned));
|
|
||||||
}
|
|
||||||
else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x18));
|
|
||||||
write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_unsigned));
|
|
||||||
}
|
|
||||||
else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x19));
|
|
||||||
write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_unsigned));
|
|
||||||
}
|
|
||||||
else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x1A));
|
|
||||||
write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_unsigned));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x1B));
|
|
||||||
write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_unsigned));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,33 +211,7 @@ class binary_writer
|
|||||||
case value_t::string:
|
case value_t::string:
|
||||||
{
|
{
|
||||||
// step 1: write control byte and the string length
|
// step 1: write control byte and the string length
|
||||||
const auto N = j.m_data.m_value.string->size();
|
write_cbor_head(0x60, j.m_data.m_value.string->size());
|
||||||
if (N <= 0x17)
|
|
||||||
{
|
|
||||||
write_number(static_cast<std::uint8_t>(0x60 + N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint8_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x78));
|
|
||||||
write_number(static_cast<std::uint8_t>(N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint16_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x79));
|
|
||||||
write_number(static_cast<std::uint16_t>(N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint32_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x7A));
|
|
||||||
write_number(static_cast<std::uint32_t>(N));
|
|
||||||
}
|
|
||||||
// LCOV_EXCL_START
|
|
||||||
else if (N <= (std::numeric_limits<std::uint64_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x7B));
|
|
||||||
write_number(static_cast<std::uint64_t>(N));
|
|
||||||
}
|
|
||||||
// LCOV_EXCL_STOP
|
|
||||||
|
|
||||||
// step 2: write the string
|
// step 2: write the string
|
||||||
oa.write_characters(
|
oa.write_characters(
|
||||||
@@ -321,33 +223,7 @@ class binary_writer
|
|||||||
case value_t::array:
|
case value_t::array:
|
||||||
{
|
{
|
||||||
// step 1: write control byte and the array size
|
// step 1: write control byte and the array size
|
||||||
const auto N = j.m_data.m_value.array->size();
|
write_cbor_head(0x80, j.m_data.m_value.array->size());
|
||||||
if (N <= 0x17)
|
|
||||||
{
|
|
||||||
write_number(static_cast<std::uint8_t>(0x80 + N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint8_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x98));
|
|
||||||
write_number(static_cast<std::uint8_t>(N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint16_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x99));
|
|
||||||
write_number(static_cast<std::uint16_t>(N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint32_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x9A));
|
|
||||||
write_number(static_cast<std::uint32_t>(N));
|
|
||||||
}
|
|
||||||
// LCOV_EXCL_START
|
|
||||||
else if (N <= (std::numeric_limits<std::uint64_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x9B));
|
|
||||||
write_number(static_cast<std::uint64_t>(N));
|
|
||||||
}
|
|
||||||
// LCOV_EXCL_STOP
|
|
||||||
|
|
||||||
// step 2: write each element
|
// step 2: write each element
|
||||||
for (const auto& el : *j.m_data.m_value.array)
|
for (const auto& el : *j.m_data.m_value.array)
|
||||||
@@ -376,7 +252,7 @@ class binary_writer
|
|||||||
write_number(static_cast<std::uint8_t>(0xda));
|
write_number(static_cast<std::uint8_t>(0xda));
|
||||||
write_number(static_cast<std::uint32_t>(j.m_data.m_value.binary->subtype()));
|
write_number(static_cast<std::uint32_t>(j.m_data.m_value.binary->subtype()));
|
||||||
}
|
}
|
||||||
else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint64_t>::max)())
|
else
|
||||||
{
|
{
|
||||||
write_number(static_cast<std::uint8_t>(0xdb));
|
write_number(static_cast<std::uint8_t>(0xdb));
|
||||||
write_number(static_cast<std::uint64_t>(j.m_data.m_value.binary->subtype()));
|
write_number(static_cast<std::uint64_t>(j.m_data.m_value.binary->subtype()));
|
||||||
@@ -385,32 +261,7 @@ class binary_writer
|
|||||||
|
|
||||||
// step 1: write control byte and the binary array size
|
// step 1: write control byte and the binary array size
|
||||||
const auto N = j.m_data.m_value.binary->size();
|
const auto N = j.m_data.m_value.binary->size();
|
||||||
if (N <= 0x17)
|
write_cbor_head(0x40, N);
|
||||||
{
|
|
||||||
write_number(static_cast<std::uint8_t>(0x40 + N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint8_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x58));
|
|
||||||
write_number(static_cast<std::uint8_t>(N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint16_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x59));
|
|
||||||
write_number(static_cast<std::uint16_t>(N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint32_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x5A));
|
|
||||||
write_number(static_cast<std::uint32_t>(N));
|
|
||||||
}
|
|
||||||
// LCOV_EXCL_START
|
|
||||||
else if (N <= (std::numeric_limits<std::uint64_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x5B));
|
|
||||||
write_number(static_cast<std::uint64_t>(N));
|
|
||||||
}
|
|
||||||
// LCOV_EXCL_STOP
|
|
||||||
|
|
||||||
// step 2: write each element
|
// step 2: write each element
|
||||||
oa.write_characters(
|
oa.write_characters(
|
||||||
@@ -423,33 +274,7 @@ class binary_writer
|
|||||||
case value_t::object:
|
case value_t::object:
|
||||||
{
|
{
|
||||||
// step 1: write control byte and the object size
|
// step 1: write control byte and the object size
|
||||||
const auto N = j.m_data.m_value.object->size();
|
write_cbor_head(0xA0, j.m_data.m_value.object->size());
|
||||||
if (N <= 0x17)
|
|
||||||
{
|
|
||||||
write_number(static_cast<std::uint8_t>(0xA0 + N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint8_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0xB8));
|
|
||||||
write_number(static_cast<std::uint8_t>(N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint16_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0xB9));
|
|
||||||
write_number(static_cast<std::uint16_t>(N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint32_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0xBA));
|
|
||||||
write_number(static_cast<std::uint32_t>(N));
|
|
||||||
}
|
|
||||||
// LCOV_EXCL_START
|
|
||||||
else if (N <= (std::numeric_limits<std::uint64_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0xBB));
|
|
||||||
write_number(static_cast<std::uint64_t>(N));
|
|
||||||
}
|
|
||||||
// LCOV_EXCL_STOP
|
|
||||||
|
|
||||||
// step 2: write each element
|
// step 2: write each element
|
||||||
for (const auto& el : *j.m_data.m_value.object)
|
for (const auto& el : *j.m_data.m_value.object)
|
||||||
@@ -517,7 +342,7 @@ class binary_writer
|
|||||||
oa.write_character(to_char_type(0xCE));
|
oa.write_character(to_char_type(0xCE));
|
||||||
write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
|
write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
|
||||||
}
|
}
|
||||||
else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
|
else
|
||||||
{
|
{
|
||||||
// uint 64
|
// uint 64
|
||||||
oa.write_character(to_char_type(0xCF));
|
oa.write_character(to_char_type(0xCF));
|
||||||
@@ -552,8 +377,7 @@ class binary_writer
|
|||||||
oa.write_character(to_char_type(0xD2));
|
oa.write_character(to_char_type(0xD2));
|
||||||
write_number(static_cast<std::int32_t>(j.m_data.m_value.number_integer));
|
write_number(static_cast<std::int32_t>(j.m_data.m_value.number_integer));
|
||||||
}
|
}
|
||||||
else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() &&
|
else
|
||||||
j.m_data.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
|
|
||||||
{
|
{
|
||||||
// int 64
|
// int 64
|
||||||
oa.write_character(to_char_type(0xD3));
|
oa.write_character(to_char_type(0xD3));
|
||||||
@@ -588,7 +412,7 @@ class binary_writer
|
|||||||
oa.write_character(to_char_type(0xCE));
|
oa.write_character(to_char_type(0xCE));
|
||||||
write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
|
write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
|
||||||
}
|
}
|
||||||
else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
|
else
|
||||||
{
|
{
|
||||||
// uint 64
|
// uint 64
|
||||||
oa.write_character(to_char_type(0xCF));
|
oa.write_character(to_char_type(0xCF));
|
||||||
@@ -1526,6 +1350,46 @@ class binary_writer
|
|||||||
// CBOR //
|
// CBOR //
|
||||||
//////////
|
//////////
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief write the head of a CBOR data item
|
||||||
|
|
||||||
|
The head is the major type in the upper three bits of the first byte and
|
||||||
|
an argument - an unsigned integer, the length of a string, the number of
|
||||||
|
elements of a container - in the shortest of its encodings: in the lower
|
||||||
|
five bits of the first byte itself if it is at most 23, otherwise in the
|
||||||
|
1, 2, 4, or 8 bytes that follow (RFC 8949, section 3).
|
||||||
|
|
||||||
|
@param[in] major_type the major type, shifted into the upper three bits
|
||||||
|
@param[in] argument the argument of the data item
|
||||||
|
*/
|
||||||
|
void write_cbor_head(const std::uint8_t major_type, const std::uint64_t argument)
|
||||||
|
{
|
||||||
|
if (argument <= 0x17)
|
||||||
|
{
|
||||||
|
write_number(static_cast<std::uint8_t>(major_type + argument));
|
||||||
|
}
|
||||||
|
else if (argument <= (std::numeric_limits<std::uint8_t>::max)())
|
||||||
|
{
|
||||||
|
oa.write_character(to_char_type(static_cast<std::uint8_t>(major_type + 0x18)));
|
||||||
|
write_number(static_cast<std::uint8_t>(argument));
|
||||||
|
}
|
||||||
|
else if (argument <= (std::numeric_limits<std::uint16_t>::max)())
|
||||||
|
{
|
||||||
|
oa.write_character(to_char_type(static_cast<std::uint8_t>(major_type + 0x19)));
|
||||||
|
write_number(static_cast<std::uint16_t>(argument));
|
||||||
|
}
|
||||||
|
else if (argument <= (std::numeric_limits<std::uint32_t>::max)())
|
||||||
|
{
|
||||||
|
oa.write_character(to_char_type(static_cast<std::uint8_t>(major_type + 0x1A)));
|
||||||
|
write_number(static_cast<std::uint32_t>(argument));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
oa.write_character(to_char_type(static_cast<std::uint8_t>(major_type + 0x1B)));
|
||||||
|
write_number(argument);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr CharType get_cbor_float_prefix(float /*unused*/)
|
static constexpr CharType get_cbor_float_prefix(float /*unused*/)
|
||||||
{
|
{
|
||||||
return to_char_type(0xFA); // Single-Precision Float
|
return to_char_type(0xFA); // Single-Precision Float
|
||||||
@@ -1631,7 +1495,7 @@ class binary_writer
|
|||||||
}
|
}
|
||||||
write_number(static_cast<std::int64_t>(n), use_bjdata);
|
write_number(static_cast<std::int64_t>(n), use_bjdata);
|
||||||
}
|
}
|
||||||
else if (use_bjdata && n <= (std::numeric_limits<uint64_t>::max)())
|
else if (use_bjdata)
|
||||||
{
|
{
|
||||||
if (add_prefix)
|
if (add_prefix)
|
||||||
{
|
{
|
||||||
@@ -1711,30 +1575,59 @@ class binary_writer
|
|||||||
}
|
}
|
||||||
write_number(static_cast<uint32_t>(n), use_bjdata);
|
write_number(static_cast<uint32_t>(n), use_bjdata);
|
||||||
}
|
}
|
||||||
else if ((std::numeric_limits<std::int64_t>::min)() <= n && n <= (std::numeric_limits<std::int64_t>::max)())
|
|
||||||
{
|
|
||||||
if (add_prefix)
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type('L')); // int64
|
|
||||||
}
|
|
||||||
write_number(static_cast<std::int64_t>(n), use_bjdata);
|
|
||||||
}
|
|
||||||
// LCOV_EXCL_START
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (add_prefix)
|
// every value of an integer type of at most 64 bits fits into an
|
||||||
{
|
// int64; only a wider type needs a range check
|
||||||
oa.write_character(to_char_type('H')); // high-precision number
|
write_ubjson_int64_or_high_precision(n, add_prefix, use_bjdata,
|
||||||
}
|
std::integral_constant < bool, std::numeric_limits<NumberType>::digits <= std::numeric_limits<std::int64_t>::digits > {});
|
||||||
|
|
||||||
const auto number = BasicJsonType(n).dump();
|
|
||||||
write_number_with_ubjson_prefix(number.size(), true, use_bjdata);
|
|
||||||
for (std::size_t i = 0; i < number.size(); ++i)
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// LCOV_EXCL_STOP
|
}
|
||||||
|
|
||||||
|
template<typename NumberType>
|
||||||
|
void write_ubjson_int64_or_high_precision(const NumberType n, const bool add_prefix, const bool use_bjdata, std::true_type /*fits_int64*/)
|
||||||
|
{
|
||||||
|
if (add_prefix)
|
||||||
|
{
|
||||||
|
oa.write_character(to_char_type('L')); // int64
|
||||||
|
}
|
||||||
|
write_number(static_cast<std::int64_t>(n), use_bjdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename NumberType>
|
||||||
|
void write_ubjson_int64_or_high_precision(const NumberType n, const bool add_prefix, const bool use_bjdata, std::false_type /*fits_int64*/)
|
||||||
|
{
|
||||||
|
if ((std::numeric_limits<std::int64_t>::min)() <= n && n <= (std::numeric_limits<std::int64_t>::max)())
|
||||||
|
{
|
||||||
|
write_ubjson_int64_or_high_precision(n, add_prefix, use_bjdata, std::true_type {});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (add_prefix)
|
||||||
|
{
|
||||||
|
oa.write_character(to_char_type('H')); // high-precision number
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto number = BasicJsonType(n).dump();
|
||||||
|
write_number_with_ubjson_prefix(number.size(), true, use_bjdata);
|
||||||
|
for (std::size_t i = 0; i < number.size(); ++i)
|
||||||
|
{
|
||||||
|
oa.write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename NumberType>
|
||||||
|
static constexpr CharType ubjson_int64_or_high_precision_prefix(const NumberType /*n*/, std::true_type /*fits_int64*/) noexcept
|
||||||
|
{
|
||||||
|
return 'L';
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename NumberType>
|
||||||
|
static CharType ubjson_int64_or_high_precision_prefix(const NumberType n, std::false_type /*fits_int64*/) noexcept
|
||||||
|
{
|
||||||
|
// anything outside of the range of an int64 is treated as a
|
||||||
|
// high-precision number
|
||||||
|
return ((std::numeric_limits<std::int64_t>::min)() <= n && n <= (std::numeric_limits<std::int64_t>::max)()) ? 'L' : 'H';
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -1776,12 +1669,10 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
return 'm';
|
return 'm';
|
||||||
}
|
}
|
||||||
if ((std::numeric_limits<std::int64_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
|
// every value of an integer type of at most 64 bits fits into
|
||||||
{
|
// an int64; only a wider type needs a range check
|
||||||
return 'L';
|
return ubjson_int64_or_high_precision_prefix(j.m_data.m_value.number_integer,
|
||||||
}
|
std::integral_constant < bool, std::numeric_limits<typename BasicJsonType::number_integer_t>::digits <= std::numeric_limits<std::int64_t>::digits > {});
|
||||||
// anything else is treated as a high-precision number
|
|
||||||
return 'H'; // LCOV_EXCL_LINE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case value_t::number_unsigned:
|
case value_t::number_unsigned:
|
||||||
@@ -1814,12 +1705,12 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
return 'L';
|
return 'L';
|
||||||
}
|
}
|
||||||
if (use_bjdata && j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
|
if (use_bjdata)
|
||||||
{
|
{
|
||||||
return 'M';
|
return 'M';
|
||||||
}
|
}
|
||||||
// anything else is treated as a high-precision number
|
// anything else is treated as a high-precision number
|
||||||
return 'H'; // LCOV_EXCL_LINE
|
return 'H';
|
||||||
}
|
}
|
||||||
|
|
||||||
case value_t::number_float:
|
case value_t::number_float:
|
||||||
|
|||||||
@@ -48,8 +48,7 @@ enum class error_handler_t
|
|||||||
{
|
{
|
||||||
strict, ///< throw a type_error exception in case of invalid UTF-8
|
strict, ///< throw a type_error exception in case of invalid UTF-8
|
||||||
replace, ///< replace invalid UTF-8 sequences with U+FFFD
|
replace, ///< replace invalid UTF-8 sequences with U+FFFD
|
||||||
ignore, ///< ignore invalid UTF-8 sequences
|
ignore ///< ignore invalid UTF-8 sequences
|
||||||
keep ///< keep invalid UTF-8 sequences; their bytes are copied unchanged
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
@@ -1020,47 +1019,6 @@ class serializer
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case error_handler_t::keep:
|
|
||||||
{
|
|
||||||
// drop whatever the incomplete sequence left in
|
|
||||||
// the buffer (only copied if !EnsureAscii) and copy
|
|
||||||
// the ill-formed bytes from the input instead
|
|
||||||
bytes = bytes_after_last_accept;
|
|
||||||
|
|
||||||
if (undumped_chars > 0)
|
|
||||||
{
|
|
||||||
// the pending bytes of the incomplete sequence
|
|
||||||
// are ill-formed; the current byte may be OK for
|
|
||||||
// itself, so we would like to read it again
|
|
||||||
for (std::size_t j = i - undumped_chars; j < i; ++j)
|
|
||||||
{
|
|
||||||
string_buffer[bytes++] = s[j];
|
|
||||||
}
|
|
||||||
--i;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// the current byte cannot start any sequence
|
|
||||||
string_buffer[bytes++] = s[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// write buffer and reset index; there must be 13 bytes
|
|
||||||
// left, as this is the maximal number of bytes to be
|
|
||||||
// written ("\uxxxx\uxxxx\0") for one code point
|
|
||||||
if (string_buffer.size() - bytes < 13)
|
|
||||||
{
|
|
||||||
put_buffer(string_buffer, bytes);
|
|
||||||
bytes = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes_after_last_accept = bytes;
|
|
||||||
undumped_chars = 0;
|
|
||||||
|
|
||||||
// continue processing the string
|
|
||||||
state = UTF8_ACCEPT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default: // LCOV_EXCL_LINE
|
default: // LCOV_EXCL_LINE
|
||||||
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
|
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
@@ -1106,15 +1064,6 @@ class serializer
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case error_handler_t::keep:
|
|
||||||
{
|
|
||||||
// write all accepted bytes
|
|
||||||
put_buffer(string_buffer, bytes_after_last_accept);
|
|
||||||
// copy the bytes of the incomplete sequence unchanged
|
|
||||||
put_string(s, s.size() - undumped_chars, s.size());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case error_handler_t::replace:
|
case error_handler_t::replace:
|
||||||
{
|
{
|
||||||
// write all accepted bytes
|
// write all accepted bytes
|
||||||
|
|||||||
@@ -2157,17 +2157,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// value access //
|
// value access //
|
||||||
//////////////////
|
//////////////////
|
||||||
|
|
||||||
/// get a boolean (explicit)
|
|
||||||
boolean_t get_impl(boolean_t* /*unused*/) const
|
|
||||||
{
|
|
||||||
if (JSON_HEDLEY_LIKELY(is_boolean()))
|
|
||||||
{
|
|
||||||
return m_data.m_value.boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSON_THROW(type_error::create(302, detail::concat("type must be boolean, but is ", type_name()), this));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// get a pointer to the value (object)
|
/// get a pointer to the value (object)
|
||||||
object_t* get_impl_ptr(object_t* /*unused*/) noexcept
|
object_t* get_impl_ptr(object_t* /*unused*/) noexcept
|
||||||
{
|
{
|
||||||
|
|||||||
+111
-282
@@ -19633,92 +19633,20 @@ class binary_writer
|
|||||||
if (j.m_data.m_value.number_integer >= 0)
|
if (j.m_data.m_value.number_integer >= 0)
|
||||||
{
|
{
|
||||||
// CBOR does not differentiate between positive signed
|
// CBOR does not differentiate between positive signed
|
||||||
// integers and unsigned integers. Therefore, we used the
|
// integers and unsigned integers
|
||||||
// code from the value_t::number_unsigned case here.
|
write_cbor_head(0x00, static_cast<std::uint64_t>(j.m_data.m_value.number_integer));
|
||||||
if (j.m_data.m_value.number_integer <= 0x17)
|
|
||||||
{
|
|
||||||
write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
|
|
||||||
}
|
|
||||||
else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x18));
|
|
||||||
write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
|
|
||||||
}
|
|
||||||
else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x19));
|
|
||||||
write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer));
|
|
||||||
}
|
|
||||||
else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x1A));
|
|
||||||
write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x1B));
|
|
||||||
write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The conversions below encode the sign in the first
|
// a negative integer n is encoded as -1 - n
|
||||||
// byte, and the value is converted to a positive number.
|
write_cbor_head(0x20, static_cast<std::uint64_t>(-1 - j.m_data.m_value.number_integer));
|
||||||
const auto positive_number = -1 - j.m_data.m_value.number_integer;
|
|
||||||
if (j.m_data.m_value.number_integer >= -24)
|
|
||||||
{
|
|
||||||
write_number(static_cast<std::uint8_t>(0x20 + positive_number));
|
|
||||||
}
|
|
||||||
else if (positive_number <= (std::numeric_limits<std::uint8_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x38));
|
|
||||||
write_number(static_cast<std::uint8_t>(positive_number));
|
|
||||||
}
|
|
||||||
else if (positive_number <= (std::numeric_limits<std::uint16_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x39));
|
|
||||||
write_number(static_cast<std::uint16_t>(positive_number));
|
|
||||||
}
|
|
||||||
else if (positive_number <= (std::numeric_limits<std::uint32_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x3A));
|
|
||||||
write_number(static_cast<std::uint32_t>(positive_number));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x3B));
|
|
||||||
write_number(static_cast<std::uint64_t>(positive_number));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case value_t::number_unsigned:
|
case value_t::number_unsigned:
|
||||||
{
|
{
|
||||||
if (j.m_data.m_value.number_unsigned <= 0x17)
|
write_cbor_head(0x00, j.m_data.m_value.number_unsigned);
|
||||||
{
|
|
||||||
write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_unsigned));
|
|
||||||
}
|
|
||||||
else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x18));
|
|
||||||
write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_unsigned));
|
|
||||||
}
|
|
||||||
else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x19));
|
|
||||||
write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_unsigned));
|
|
||||||
}
|
|
||||||
else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x1A));
|
|
||||||
write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_unsigned));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x1B));
|
|
||||||
write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_unsigned));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19748,33 +19676,7 @@ class binary_writer
|
|||||||
case value_t::string:
|
case value_t::string:
|
||||||
{
|
{
|
||||||
// step 1: write control byte and the string length
|
// step 1: write control byte and the string length
|
||||||
const auto N = j.m_data.m_value.string->size();
|
write_cbor_head(0x60, j.m_data.m_value.string->size());
|
||||||
if (N <= 0x17)
|
|
||||||
{
|
|
||||||
write_number(static_cast<std::uint8_t>(0x60 + N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint8_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x78));
|
|
||||||
write_number(static_cast<std::uint8_t>(N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint16_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x79));
|
|
||||||
write_number(static_cast<std::uint16_t>(N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint32_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x7A));
|
|
||||||
write_number(static_cast<std::uint32_t>(N));
|
|
||||||
}
|
|
||||||
// LCOV_EXCL_START
|
|
||||||
else if (N <= (std::numeric_limits<std::uint64_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x7B));
|
|
||||||
write_number(static_cast<std::uint64_t>(N));
|
|
||||||
}
|
|
||||||
// LCOV_EXCL_STOP
|
|
||||||
|
|
||||||
// step 2: write the string
|
// step 2: write the string
|
||||||
oa.write_characters(
|
oa.write_characters(
|
||||||
@@ -19786,33 +19688,7 @@ class binary_writer
|
|||||||
case value_t::array:
|
case value_t::array:
|
||||||
{
|
{
|
||||||
// step 1: write control byte and the array size
|
// step 1: write control byte and the array size
|
||||||
const auto N = j.m_data.m_value.array->size();
|
write_cbor_head(0x80, j.m_data.m_value.array->size());
|
||||||
if (N <= 0x17)
|
|
||||||
{
|
|
||||||
write_number(static_cast<std::uint8_t>(0x80 + N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint8_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x98));
|
|
||||||
write_number(static_cast<std::uint8_t>(N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint16_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x99));
|
|
||||||
write_number(static_cast<std::uint16_t>(N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint32_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x9A));
|
|
||||||
write_number(static_cast<std::uint32_t>(N));
|
|
||||||
}
|
|
||||||
// LCOV_EXCL_START
|
|
||||||
else if (N <= (std::numeric_limits<std::uint64_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x9B));
|
|
||||||
write_number(static_cast<std::uint64_t>(N));
|
|
||||||
}
|
|
||||||
// LCOV_EXCL_STOP
|
|
||||||
|
|
||||||
// step 2: write each element
|
// step 2: write each element
|
||||||
for (const auto& el : *j.m_data.m_value.array)
|
for (const auto& el : *j.m_data.m_value.array)
|
||||||
@@ -19841,7 +19717,7 @@ class binary_writer
|
|||||||
write_number(static_cast<std::uint8_t>(0xda));
|
write_number(static_cast<std::uint8_t>(0xda));
|
||||||
write_number(static_cast<std::uint32_t>(j.m_data.m_value.binary->subtype()));
|
write_number(static_cast<std::uint32_t>(j.m_data.m_value.binary->subtype()));
|
||||||
}
|
}
|
||||||
else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint64_t>::max)())
|
else
|
||||||
{
|
{
|
||||||
write_number(static_cast<std::uint8_t>(0xdb));
|
write_number(static_cast<std::uint8_t>(0xdb));
|
||||||
write_number(static_cast<std::uint64_t>(j.m_data.m_value.binary->subtype()));
|
write_number(static_cast<std::uint64_t>(j.m_data.m_value.binary->subtype()));
|
||||||
@@ -19850,32 +19726,7 @@ class binary_writer
|
|||||||
|
|
||||||
// step 1: write control byte and the binary array size
|
// step 1: write control byte and the binary array size
|
||||||
const auto N = j.m_data.m_value.binary->size();
|
const auto N = j.m_data.m_value.binary->size();
|
||||||
if (N <= 0x17)
|
write_cbor_head(0x40, N);
|
||||||
{
|
|
||||||
write_number(static_cast<std::uint8_t>(0x40 + N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint8_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x58));
|
|
||||||
write_number(static_cast<std::uint8_t>(N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint16_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x59));
|
|
||||||
write_number(static_cast<std::uint16_t>(N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint32_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x5A));
|
|
||||||
write_number(static_cast<std::uint32_t>(N));
|
|
||||||
}
|
|
||||||
// LCOV_EXCL_START
|
|
||||||
else if (N <= (std::numeric_limits<std::uint64_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0x5B));
|
|
||||||
write_number(static_cast<std::uint64_t>(N));
|
|
||||||
}
|
|
||||||
// LCOV_EXCL_STOP
|
|
||||||
|
|
||||||
// step 2: write each element
|
// step 2: write each element
|
||||||
oa.write_characters(
|
oa.write_characters(
|
||||||
@@ -19888,33 +19739,7 @@ class binary_writer
|
|||||||
case value_t::object:
|
case value_t::object:
|
||||||
{
|
{
|
||||||
// step 1: write control byte and the object size
|
// step 1: write control byte and the object size
|
||||||
const auto N = j.m_data.m_value.object->size();
|
write_cbor_head(0xA0, j.m_data.m_value.object->size());
|
||||||
if (N <= 0x17)
|
|
||||||
{
|
|
||||||
write_number(static_cast<std::uint8_t>(0xA0 + N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint8_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0xB8));
|
|
||||||
write_number(static_cast<std::uint8_t>(N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint16_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0xB9));
|
|
||||||
write_number(static_cast<std::uint16_t>(N));
|
|
||||||
}
|
|
||||||
else if (N <= (std::numeric_limits<std::uint32_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0xBA));
|
|
||||||
write_number(static_cast<std::uint32_t>(N));
|
|
||||||
}
|
|
||||||
// LCOV_EXCL_START
|
|
||||||
else if (N <= (std::numeric_limits<std::uint64_t>::max)())
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(0xBB));
|
|
||||||
write_number(static_cast<std::uint64_t>(N));
|
|
||||||
}
|
|
||||||
// LCOV_EXCL_STOP
|
|
||||||
|
|
||||||
// step 2: write each element
|
// step 2: write each element
|
||||||
for (const auto& el : *j.m_data.m_value.object)
|
for (const auto& el : *j.m_data.m_value.object)
|
||||||
@@ -19982,7 +19807,7 @@ class binary_writer
|
|||||||
oa.write_character(to_char_type(0xCE));
|
oa.write_character(to_char_type(0xCE));
|
||||||
write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
|
write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
|
||||||
}
|
}
|
||||||
else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
|
else
|
||||||
{
|
{
|
||||||
// uint 64
|
// uint 64
|
||||||
oa.write_character(to_char_type(0xCF));
|
oa.write_character(to_char_type(0xCF));
|
||||||
@@ -20017,8 +19842,7 @@ class binary_writer
|
|||||||
oa.write_character(to_char_type(0xD2));
|
oa.write_character(to_char_type(0xD2));
|
||||||
write_number(static_cast<std::int32_t>(j.m_data.m_value.number_integer));
|
write_number(static_cast<std::int32_t>(j.m_data.m_value.number_integer));
|
||||||
}
|
}
|
||||||
else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() &&
|
else
|
||||||
j.m_data.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
|
|
||||||
{
|
{
|
||||||
// int 64
|
// int 64
|
||||||
oa.write_character(to_char_type(0xD3));
|
oa.write_character(to_char_type(0xD3));
|
||||||
@@ -20053,7 +19877,7 @@ class binary_writer
|
|||||||
oa.write_character(to_char_type(0xCE));
|
oa.write_character(to_char_type(0xCE));
|
||||||
write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
|
write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
|
||||||
}
|
}
|
||||||
else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
|
else
|
||||||
{
|
{
|
||||||
// uint 64
|
// uint 64
|
||||||
oa.write_character(to_char_type(0xCF));
|
oa.write_character(to_char_type(0xCF));
|
||||||
@@ -20991,6 +20815,46 @@ class binary_writer
|
|||||||
// CBOR //
|
// CBOR //
|
||||||
//////////
|
//////////
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief write the head of a CBOR data item
|
||||||
|
|
||||||
|
The head is the major type in the upper three bits of the first byte and
|
||||||
|
an argument - an unsigned integer, the length of a string, the number of
|
||||||
|
elements of a container - in the shortest of its encodings: in the lower
|
||||||
|
five bits of the first byte itself if it is at most 23, otherwise in the
|
||||||
|
1, 2, 4, or 8 bytes that follow (RFC 8949, section 3).
|
||||||
|
|
||||||
|
@param[in] major_type the major type, shifted into the upper three bits
|
||||||
|
@param[in] argument the argument of the data item
|
||||||
|
*/
|
||||||
|
void write_cbor_head(const std::uint8_t major_type, const std::uint64_t argument)
|
||||||
|
{
|
||||||
|
if (argument <= 0x17)
|
||||||
|
{
|
||||||
|
write_number(static_cast<std::uint8_t>(major_type + argument));
|
||||||
|
}
|
||||||
|
else if (argument <= (std::numeric_limits<std::uint8_t>::max)())
|
||||||
|
{
|
||||||
|
oa.write_character(to_char_type(static_cast<std::uint8_t>(major_type + 0x18)));
|
||||||
|
write_number(static_cast<std::uint8_t>(argument));
|
||||||
|
}
|
||||||
|
else if (argument <= (std::numeric_limits<std::uint16_t>::max)())
|
||||||
|
{
|
||||||
|
oa.write_character(to_char_type(static_cast<std::uint8_t>(major_type + 0x19)));
|
||||||
|
write_number(static_cast<std::uint16_t>(argument));
|
||||||
|
}
|
||||||
|
else if (argument <= (std::numeric_limits<std::uint32_t>::max)())
|
||||||
|
{
|
||||||
|
oa.write_character(to_char_type(static_cast<std::uint8_t>(major_type + 0x1A)));
|
||||||
|
write_number(static_cast<std::uint32_t>(argument));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
oa.write_character(to_char_type(static_cast<std::uint8_t>(major_type + 0x1B)));
|
||||||
|
write_number(argument);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr CharType get_cbor_float_prefix(float /*unused*/)
|
static constexpr CharType get_cbor_float_prefix(float /*unused*/)
|
||||||
{
|
{
|
||||||
return to_char_type(0xFA); // Single-Precision Float
|
return to_char_type(0xFA); // Single-Precision Float
|
||||||
@@ -21096,7 +20960,7 @@ class binary_writer
|
|||||||
}
|
}
|
||||||
write_number(static_cast<std::int64_t>(n), use_bjdata);
|
write_number(static_cast<std::int64_t>(n), use_bjdata);
|
||||||
}
|
}
|
||||||
else if (use_bjdata && n <= (std::numeric_limits<uint64_t>::max)())
|
else if (use_bjdata)
|
||||||
{
|
{
|
||||||
if (add_prefix)
|
if (add_prefix)
|
||||||
{
|
{
|
||||||
@@ -21176,30 +21040,59 @@ class binary_writer
|
|||||||
}
|
}
|
||||||
write_number(static_cast<uint32_t>(n), use_bjdata);
|
write_number(static_cast<uint32_t>(n), use_bjdata);
|
||||||
}
|
}
|
||||||
else if ((std::numeric_limits<std::int64_t>::min)() <= n && n <= (std::numeric_limits<std::int64_t>::max)())
|
|
||||||
{
|
|
||||||
if (add_prefix)
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type('L')); // int64
|
|
||||||
}
|
|
||||||
write_number(static_cast<std::int64_t>(n), use_bjdata);
|
|
||||||
}
|
|
||||||
// LCOV_EXCL_START
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (add_prefix)
|
// every value of an integer type of at most 64 bits fits into an
|
||||||
{
|
// int64; only a wider type needs a range check
|
||||||
oa.write_character(to_char_type('H')); // high-precision number
|
write_ubjson_int64_or_high_precision(n, add_prefix, use_bjdata,
|
||||||
}
|
std::integral_constant < bool, std::numeric_limits<NumberType>::digits <= std::numeric_limits<std::int64_t>::digits > {});
|
||||||
|
|
||||||
const auto number = BasicJsonType(n).dump();
|
|
||||||
write_number_with_ubjson_prefix(number.size(), true, use_bjdata);
|
|
||||||
for (std::size_t i = 0; i < number.size(); ++i)
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// LCOV_EXCL_STOP
|
}
|
||||||
|
|
||||||
|
template<typename NumberType>
|
||||||
|
void write_ubjson_int64_or_high_precision(const NumberType n, const bool add_prefix, const bool use_bjdata, std::true_type /*fits_int64*/)
|
||||||
|
{
|
||||||
|
if (add_prefix)
|
||||||
|
{
|
||||||
|
oa.write_character(to_char_type('L')); // int64
|
||||||
|
}
|
||||||
|
write_number(static_cast<std::int64_t>(n), use_bjdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename NumberType>
|
||||||
|
void write_ubjson_int64_or_high_precision(const NumberType n, const bool add_prefix, const bool use_bjdata, std::false_type /*fits_int64*/)
|
||||||
|
{
|
||||||
|
if ((std::numeric_limits<std::int64_t>::min)() <= n && n <= (std::numeric_limits<std::int64_t>::max)())
|
||||||
|
{
|
||||||
|
write_ubjson_int64_or_high_precision(n, add_prefix, use_bjdata, std::true_type {});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (add_prefix)
|
||||||
|
{
|
||||||
|
oa.write_character(to_char_type('H')); // high-precision number
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto number = BasicJsonType(n).dump();
|
||||||
|
write_number_with_ubjson_prefix(number.size(), true, use_bjdata);
|
||||||
|
for (std::size_t i = 0; i < number.size(); ++i)
|
||||||
|
{
|
||||||
|
oa.write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename NumberType>
|
||||||
|
static constexpr CharType ubjson_int64_or_high_precision_prefix(const NumberType /*n*/, std::true_type /*fits_int64*/) noexcept
|
||||||
|
{
|
||||||
|
return 'L';
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename NumberType>
|
||||||
|
static CharType ubjson_int64_or_high_precision_prefix(const NumberType n, std::false_type /*fits_int64*/) noexcept
|
||||||
|
{
|
||||||
|
// anything outside of the range of an int64 is treated as a
|
||||||
|
// high-precision number
|
||||||
|
return ((std::numeric_limits<std::int64_t>::min)() <= n && n <= (std::numeric_limits<std::int64_t>::max)()) ? 'L' : 'H';
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -21241,12 +21134,10 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
return 'm';
|
return 'm';
|
||||||
}
|
}
|
||||||
if ((std::numeric_limits<std::int64_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
|
// every value of an integer type of at most 64 bits fits into
|
||||||
{
|
// an int64; only a wider type needs a range check
|
||||||
return 'L';
|
return ubjson_int64_or_high_precision_prefix(j.m_data.m_value.number_integer,
|
||||||
}
|
std::integral_constant < bool, std::numeric_limits<typename BasicJsonType::number_integer_t>::digits <= std::numeric_limits<std::int64_t>::digits > {});
|
||||||
// anything else is treated as a high-precision number
|
|
||||||
return 'H'; // LCOV_EXCL_LINE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case value_t::number_unsigned:
|
case value_t::number_unsigned:
|
||||||
@@ -21279,12 +21170,12 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
return 'L';
|
return 'L';
|
||||||
}
|
}
|
||||||
if (use_bjdata && j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
|
if (use_bjdata)
|
||||||
{
|
{
|
||||||
return 'M';
|
return 'M';
|
||||||
}
|
}
|
||||||
// anything else is treated as a high-precision number
|
// anything else is treated as a high-precision number
|
||||||
return 'H'; // LCOV_EXCL_LINE
|
return 'H';
|
||||||
}
|
}
|
||||||
|
|
||||||
case value_t::number_float:
|
case value_t::number_float:
|
||||||
@@ -23006,8 +22897,7 @@ enum class error_handler_t
|
|||||||
{
|
{
|
||||||
strict, ///< throw a type_error exception in case of invalid UTF-8
|
strict, ///< throw a type_error exception in case of invalid UTF-8
|
||||||
replace, ///< replace invalid UTF-8 sequences with U+FFFD
|
replace, ///< replace invalid UTF-8 sequences with U+FFFD
|
||||||
ignore, ///< ignore invalid UTF-8 sequences
|
ignore ///< ignore invalid UTF-8 sequences
|
||||||
keep ///< keep invalid UTF-8 sequences; their bytes are copied unchanged
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
@@ -23978,47 +23868,6 @@ class serializer
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case error_handler_t::keep:
|
|
||||||
{
|
|
||||||
// drop whatever the incomplete sequence left in
|
|
||||||
// the buffer (only copied if !EnsureAscii) and copy
|
|
||||||
// the ill-formed bytes from the input instead
|
|
||||||
bytes = bytes_after_last_accept;
|
|
||||||
|
|
||||||
if (undumped_chars > 0)
|
|
||||||
{
|
|
||||||
// the pending bytes of the incomplete sequence
|
|
||||||
// are ill-formed; the current byte may be OK for
|
|
||||||
// itself, so we would like to read it again
|
|
||||||
for (std::size_t j = i - undumped_chars; j < i; ++j)
|
|
||||||
{
|
|
||||||
string_buffer[bytes++] = s[j];
|
|
||||||
}
|
|
||||||
--i;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// the current byte cannot start any sequence
|
|
||||||
string_buffer[bytes++] = s[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// write buffer and reset index; there must be 13 bytes
|
|
||||||
// left, as this is the maximal number of bytes to be
|
|
||||||
// written ("\uxxxx\uxxxx\0") for one code point
|
|
||||||
if (string_buffer.size() - bytes < 13)
|
|
||||||
{
|
|
||||||
put_buffer(string_buffer, bytes);
|
|
||||||
bytes = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes_after_last_accept = bytes;
|
|
||||||
undumped_chars = 0;
|
|
||||||
|
|
||||||
// continue processing the string
|
|
||||||
state = UTF8_ACCEPT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default: // LCOV_EXCL_LINE
|
default: // LCOV_EXCL_LINE
|
||||||
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
|
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
@@ -24064,15 +23913,6 @@ class serializer
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case error_handler_t::keep:
|
|
||||||
{
|
|
||||||
// write all accepted bytes
|
|
||||||
put_buffer(string_buffer, bytes_after_last_accept);
|
|
||||||
// copy the bytes of the incomplete sequence unchanged
|
|
||||||
put_string(s, s.size() - undumped_chars, s.size());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case error_handler_t::replace:
|
case error_handler_t::replace:
|
||||||
{
|
{
|
||||||
// write all accepted bytes
|
// write all accepted bytes
|
||||||
@@ -27166,17 +27006,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// value access //
|
// value access //
|
||||||
//////////////////
|
//////////////////
|
||||||
|
|
||||||
/// get a boolean (explicit)
|
|
||||||
boolean_t get_impl(boolean_t* /*unused*/) const
|
|
||||||
{
|
|
||||||
if (JSON_HEDLEY_LIKELY(is_boolean()))
|
|
||||||
{
|
|
||||||
return m_data.m_value.boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSON_THROW(type_error::create(302, detail::concat("type must be boolean, but is ", type_name()), this));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// get a pointer to the value (object)
|
/// get a pointer to the value (object)
|
||||||
object_t* get_impl_ptr(object_t* /*unused*/) noexcept
|
object_t* get_impl_ptr(object_t* /*unused*/) noexcept
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -765,15 +765,6 @@ TEST_CASE("regression tests 2")
|
|||||||
CHECK(j == k);
|
CHECK(j == k);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("issue #4552 - UTF-8 invalid characters are not always ignored when dumping with error_handler_t::ignore")
|
|
||||||
{
|
|
||||||
json node;
|
|
||||||
node["test"] = "test\334\005";
|
|
||||||
CHECK(node.dump(-1, ' ', false, json::error_handler_t::ignore) == "{\"test\":\"test\\u0005\"}");
|
|
||||||
CHECK(node.dump(-1, ' ', false, json::error_handler_t::keep) == "{\"test\":\"test\334\\u0005\"}");
|
|
||||||
CHECK(node.dump(-1, ' ', true, json::error_handler_t::keep) == "{\"test\":\"test\334\\u0005\"}");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("regression test - parser callback must not lose a duplicate key's prior value")
|
TEST_CASE("regression test - parser callback must not lose a duplicate key's prior value")
|
||||||
|
|||||||
@@ -92,8 +92,6 @@ TEST_CASE("serialization")
|
|||||||
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\"");
|
||||||
CHECK(j.dump(-1, ' ', false, json::error_handler_t::keep) == "\"ä\xA9ü\"");
|
|
||||||
CHECK(j.dump(-1, ' ', true, json::error_handler_t::keep) == "\"\\u00e4\xA9\\u00fc\"");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("invalid character (regression guard for shared UTF-8 decoder, see #5529)")
|
SECTION("invalid character (regression guard for shared UTF-8 decoder, see #5529)")
|
||||||
@@ -116,8 +114,6 @@ TEST_CASE("serialization")
|
|||||||
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\"");
|
||||||
CHECK(j.dump(-1, ' ', false, json::error_handler_t::keep) == "\"123\xC2\"");
|
|
||||||
CHECK(j.dump(-1, ' ', true, json::error_handler_t::keep) == "\"123\xC2\"");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("unexpected character")
|
SECTION("unexpected character")
|
||||||
@@ -130,39 +126,6 @@ TEST_CASE("serialization")
|
|||||||
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\"");
|
||||||
CHECK(j.dump(-1, ' ', false, json::error_handler_t::keep) == "\"123\xF1\xB0\x34\x35\x36\"");
|
|
||||||
CHECK(j.dump(-1, ' ', true, json::error_handler_t::keep) == "\"123\xF1\xB0\x34\x35\x36\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("keep: valid characters are still escaped")
|
|
||||||
{
|
|
||||||
// an invalid byte followed by characters that must be escaped
|
|
||||||
const json j = "\xC2\"\\\n\xFF\x05";
|
|
||||||
CHECK(j.dump(-1, ' ', false, json::error_handler_t::keep) == "\"\xC2\\\"\\\\\\n\xFF\\u0005\"");
|
|
||||||
CHECK(j.dump(-1, ' ', true, json::error_handler_t::keep) == "\"\xC2\\\"\\\\\\n\xFF\\u0005\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("keep: truncated multibyte sequences")
|
|
||||||
{
|
|
||||||
CHECK(json("\xF0\x9F\x98").dump(-1, ' ', false, json::error_handler_t::keep) == "\"\xF0\x9F\x98\"");
|
|
||||||
CHECK(json("\xF0\x9F\x98").dump(-1, ' ', true, json::error_handler_t::keep) == "\"\xF0\x9F\x98\"");
|
|
||||||
CHECK(json("\xF0\x9F\x98" "a").dump(-1, ' ', false, json::error_handler_t::keep) == "\"\xF0\x9F\x98" "a\"");
|
|
||||||
CHECK(json("\xF0\x9F\x98" "a").dump(-1, ' ', true, json::error_handler_t::keep) == "\"\xF0\x9F\x98" "a\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("keep: long string with many invalid bytes")
|
|
||||||
{
|
|
||||||
// exceeds the internal string buffer several times
|
|
||||||
std::string input;
|
|
||||||
std::string expected = "\"";
|
|
||||||
for (int i = 0; i < 2000; ++i)
|
|
||||||
{
|
|
||||||
input += "\xFF\xE2\x82\n\xC3\xA4";
|
|
||||||
expected += "\xFF\xE2\x82\\n\xC3\xA4";
|
|
||||||
}
|
|
||||||
expected += "\"";
|
|
||||||
const json j = input;
|
|
||||||
CHECK(j.dump(-1, ' ', false, json::error_handler_t::keep) == expected);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("U+FFFD Substitution of Maximal Subparts")
|
SECTION("U+FFFD Substitution of Maximal Subparts")
|
||||||
|
|||||||
@@ -2981,3 +2981,18 @@ TEST_CASE("UBJSON roundtrips" * doctest::skip())
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("UBJSON optimized array of unsigned integers beyond int64")
|
||||||
|
{
|
||||||
|
// UBJSON has no unsigned 64-bit type, so such values are written as
|
||||||
|
// high-precision numbers - also as the type of an optimized container
|
||||||
|
const json j = {18446744073709551615ULL, 9223372036854775808ULL};
|
||||||
|
const std::vector<std::uint8_t> expected =
|
||||||
|
{
|
||||||
|
'[', '$', 'H', '#', 'i', 2,
|
||||||
|
'i', 20, '1', '8', '4', '4', '6', '7', '4', '4', '0', '7', '3', '7', '0', '9', '5', '5', '1', '6', '1', '5',
|
||||||
|
'i', 19, '9', '2', '2', '3', '3', '7', '2', '0', '3', '6', '8', '5', '4', '7', '7', '5', '8', '0', '8'
|
||||||
|
};
|
||||||
|
CHECK(json::to_ubjson(j, true, true) == expected);
|
||||||
|
CHECK(json::from_ubjson(expected) == j);
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
using nlohmann::json;
|
using nlohmann::json;
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -76,11 +75,8 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
|||||||
static std::string s_replaced2;
|
static std::string s_replaced2;
|
||||||
static std::string s_replaced_ascii;
|
static std::string s_replaced_ascii;
|
||||||
static std::string s_replaced2_ascii;
|
static std::string s_replaced2_ascii;
|
||||||
static std::string s_kept;
|
|
||||||
static std::string s_kept2;
|
|
||||||
static std::string s_kept_ascii;
|
|
||||||
|
|
||||||
// dumping with ignore/replace/keep must not throw in any case
|
// dumping with ignore/replace must not throw in any case
|
||||||
s_ignored = j.dump(-1, ' ', false, json::error_handler_t::ignore);
|
s_ignored = j.dump(-1, ' ', false, json::error_handler_t::ignore);
|
||||||
s_ignored2 = j2.dump(-1, ' ', false, json::error_handler_t::ignore);
|
s_ignored2 = j2.dump(-1, ' ', false, json::error_handler_t::ignore);
|
||||||
s_ignored_ascii = j.dump(-1, ' ', true, json::error_handler_t::ignore);
|
s_ignored_ascii = j.dump(-1, ' ', true, json::error_handler_t::ignore);
|
||||||
@@ -89,9 +85,6 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
|||||||
s_replaced2 = j2.dump(-1, ' ', false, json::error_handler_t::replace);
|
s_replaced2 = j2.dump(-1, ' ', false, json::error_handler_t::replace);
|
||||||
s_replaced_ascii = j.dump(-1, ' ', true, json::error_handler_t::replace);
|
s_replaced_ascii = j.dump(-1, ' ', true, json::error_handler_t::replace);
|
||||||
s_replaced2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::replace);
|
s_replaced2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::replace);
|
||||||
s_kept = j.dump(-1, ' ', false, json::error_handler_t::keep);
|
|
||||||
s_kept2 = j2.dump(-1, ' ', false, json::error_handler_t::keep);
|
|
||||||
s_kept_ascii = j.dump(-1, ' ', true, json::error_handler_t::keep);
|
|
||||||
|
|
||||||
if (success_expected)
|
if (success_expected)
|
||||||
{
|
{
|
||||||
@@ -101,7 +94,6 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
|||||||
// all dumps should agree on the string
|
// all dumps should agree on the string
|
||||||
CHECK(s_strict == s_ignored);
|
CHECK(s_strict == s_ignored);
|
||||||
CHECK(s_strict == s_replaced);
|
CHECK(s_strict == s_replaced);
|
||||||
CHECK(s_strict == s_kept);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -113,20 +105,6 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
|||||||
|
|
||||||
// check that replace string contains a replacement character
|
// check that replace string contains a replacement character
|
||||||
CHECK(s_replaced.find("\xEF\xBF\xBD") != std::string::npos);
|
CHECK(s_replaced.find("\xEF\xBF\xBD") != std::string::npos);
|
||||||
|
|
||||||
// ignore drops the invalid bytes, keep copies them
|
|
||||||
CHECK(s_ignored != s_kept);
|
|
||||||
CHECK(s_ignored_ascii != s_kept_ascii);
|
|
||||||
|
|
||||||
// unless a byte needs escaping, keep copies the input unchanged
|
|
||||||
const bool needs_escaping = std::any_of(json_string.begin(), json_string.end(), [](char c)
|
|
||||||
{
|
|
||||||
return static_cast<unsigned char>(c) < 0x20 || c == '"' || c == '\\';
|
|
||||||
});
|
|
||||||
if (!needs_escaping)
|
|
||||||
{
|
|
||||||
CHECK(s_kept == "\"" + json_string + "\"");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check that prefix and suffix are preserved
|
// check that prefix and suffix are preserved
|
||||||
@@ -138,8 +116,6 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
|||||||
CHECK(s_replaced2.substr(s_replaced2.size() - 4, 3) == "xyz");
|
CHECK(s_replaced2.substr(s_replaced2.size() - 4, 3) == "xyz");
|
||||||
CHECK(s_replaced2_ascii.substr(1, 3) == "abc");
|
CHECK(s_replaced2_ascii.substr(1, 3) == "abc");
|
||||||
CHECK(s_replaced2_ascii.substr(s_replaced2_ascii.size() - 4, 3) == "xyz");
|
CHECK(s_replaced2_ascii.substr(s_replaced2_ascii.size() - 4, 3) == "xyz");
|
||||||
CHECK(s_kept2.substr(1, 3) == "abc");
|
|
||||||
CHECK(s_kept2.substr(s_kept2.size() - 4, 3) == "xyz");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_utf8string(bool success_expected, int byte1, int byte2, int byte3, int byte4);
|
void check_utf8string(bool success_expected, int byte1, int byte2, int byte3, int byte4);
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
using nlohmann::json;
|
using nlohmann::json;
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -76,11 +75,8 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
|||||||
static std::string s_replaced2;
|
static std::string s_replaced2;
|
||||||
static std::string s_replaced_ascii;
|
static std::string s_replaced_ascii;
|
||||||
static std::string s_replaced2_ascii;
|
static std::string s_replaced2_ascii;
|
||||||
static std::string s_kept;
|
|
||||||
static std::string s_kept2;
|
|
||||||
static std::string s_kept_ascii;
|
|
||||||
|
|
||||||
// dumping with ignore/replace/keep must not throw in any case
|
// dumping with ignore/replace must not throw in any case
|
||||||
s_ignored = j.dump(-1, ' ', false, json::error_handler_t::ignore);
|
s_ignored = j.dump(-1, ' ', false, json::error_handler_t::ignore);
|
||||||
s_ignored2 = j2.dump(-1, ' ', false, json::error_handler_t::ignore);
|
s_ignored2 = j2.dump(-1, ' ', false, json::error_handler_t::ignore);
|
||||||
s_ignored_ascii = j.dump(-1, ' ', true, json::error_handler_t::ignore);
|
s_ignored_ascii = j.dump(-1, ' ', true, json::error_handler_t::ignore);
|
||||||
@@ -89,9 +85,6 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
|||||||
s_replaced2 = j2.dump(-1, ' ', false, json::error_handler_t::replace);
|
s_replaced2 = j2.dump(-1, ' ', false, json::error_handler_t::replace);
|
||||||
s_replaced_ascii = j.dump(-1, ' ', true, json::error_handler_t::replace);
|
s_replaced_ascii = j.dump(-1, ' ', true, json::error_handler_t::replace);
|
||||||
s_replaced2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::replace);
|
s_replaced2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::replace);
|
||||||
s_kept = j.dump(-1, ' ', false, json::error_handler_t::keep);
|
|
||||||
s_kept2 = j2.dump(-1, ' ', false, json::error_handler_t::keep);
|
|
||||||
s_kept_ascii = j.dump(-1, ' ', true, json::error_handler_t::keep);
|
|
||||||
|
|
||||||
if (success_expected)
|
if (success_expected)
|
||||||
{
|
{
|
||||||
@@ -101,7 +94,6 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
|||||||
// all dumps should agree on the string
|
// all dumps should agree on the string
|
||||||
CHECK(s_strict == s_ignored);
|
CHECK(s_strict == s_ignored);
|
||||||
CHECK(s_strict == s_replaced);
|
CHECK(s_strict == s_replaced);
|
||||||
CHECK(s_strict == s_kept);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -113,20 +105,6 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
|||||||
|
|
||||||
// check that replace string contains a replacement character
|
// check that replace string contains a replacement character
|
||||||
CHECK(s_replaced.find("\xEF\xBF\xBD") != std::string::npos);
|
CHECK(s_replaced.find("\xEF\xBF\xBD") != std::string::npos);
|
||||||
|
|
||||||
// ignore drops the invalid bytes, keep copies them
|
|
||||||
CHECK(s_ignored != s_kept);
|
|
||||||
CHECK(s_ignored_ascii != s_kept_ascii);
|
|
||||||
|
|
||||||
// unless a byte needs escaping, keep copies the input unchanged
|
|
||||||
const bool needs_escaping = std::any_of(json_string.begin(), json_string.end(), [](char c)
|
|
||||||
{
|
|
||||||
return static_cast<unsigned char>(c) < 0x20 || c == '"' || c == '\\';
|
|
||||||
});
|
|
||||||
if (!needs_escaping)
|
|
||||||
{
|
|
||||||
CHECK(s_kept == "\"" + json_string + "\"");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check that prefix and suffix are preserved
|
// check that prefix and suffix are preserved
|
||||||
@@ -138,8 +116,6 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
|||||||
CHECK(s_replaced2.substr(s_replaced2.size() - 4, 3) == "xyz");
|
CHECK(s_replaced2.substr(s_replaced2.size() - 4, 3) == "xyz");
|
||||||
CHECK(s_replaced2_ascii.substr(1, 3) == "abc");
|
CHECK(s_replaced2_ascii.substr(1, 3) == "abc");
|
||||||
CHECK(s_replaced2_ascii.substr(s_replaced2_ascii.size() - 4, 3) == "xyz");
|
CHECK(s_replaced2_ascii.substr(s_replaced2_ascii.size() - 4, 3) == "xyz");
|
||||||
CHECK(s_kept2.substr(1, 3) == "abc");
|
|
||||||
CHECK(s_kept2.substr(s_kept2.size() - 4, 3) == "xyz");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_utf8string(bool success_expected, int byte1, int byte2, int byte3, int byte4);
|
void check_utf8string(bool success_expected, int byte1, int byte2, int byte3, int byte4);
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
using nlohmann::json;
|
using nlohmann::json;
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -76,11 +75,8 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
|||||||
static std::string s_replaced2;
|
static std::string s_replaced2;
|
||||||
static std::string s_replaced_ascii;
|
static std::string s_replaced_ascii;
|
||||||
static std::string s_replaced2_ascii;
|
static std::string s_replaced2_ascii;
|
||||||
static std::string s_kept;
|
|
||||||
static std::string s_kept2;
|
|
||||||
static std::string s_kept_ascii;
|
|
||||||
|
|
||||||
// dumping with ignore/replace/keep must not throw in any case
|
// dumping with ignore/replace must not throw in any case
|
||||||
s_ignored = j.dump(-1, ' ', false, json::error_handler_t::ignore);
|
s_ignored = j.dump(-1, ' ', false, json::error_handler_t::ignore);
|
||||||
s_ignored2 = j2.dump(-1, ' ', false, json::error_handler_t::ignore);
|
s_ignored2 = j2.dump(-1, ' ', false, json::error_handler_t::ignore);
|
||||||
s_ignored_ascii = j.dump(-1, ' ', true, json::error_handler_t::ignore);
|
s_ignored_ascii = j.dump(-1, ' ', true, json::error_handler_t::ignore);
|
||||||
@@ -89,9 +85,6 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
|||||||
s_replaced2 = j2.dump(-1, ' ', false, json::error_handler_t::replace);
|
s_replaced2 = j2.dump(-1, ' ', false, json::error_handler_t::replace);
|
||||||
s_replaced_ascii = j.dump(-1, ' ', true, json::error_handler_t::replace);
|
s_replaced_ascii = j.dump(-1, ' ', true, json::error_handler_t::replace);
|
||||||
s_replaced2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::replace);
|
s_replaced2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::replace);
|
||||||
s_kept = j.dump(-1, ' ', false, json::error_handler_t::keep);
|
|
||||||
s_kept2 = j2.dump(-1, ' ', false, json::error_handler_t::keep);
|
|
||||||
s_kept_ascii = j.dump(-1, ' ', true, json::error_handler_t::keep);
|
|
||||||
|
|
||||||
if (success_expected)
|
if (success_expected)
|
||||||
{
|
{
|
||||||
@@ -101,7 +94,6 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
|||||||
// all dumps should agree on the string
|
// all dumps should agree on the string
|
||||||
CHECK(s_strict == s_ignored);
|
CHECK(s_strict == s_ignored);
|
||||||
CHECK(s_strict == s_replaced);
|
CHECK(s_strict == s_replaced);
|
||||||
CHECK(s_strict == s_kept);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -113,20 +105,6 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
|||||||
|
|
||||||
// check that replace string contains a replacement character
|
// check that replace string contains a replacement character
|
||||||
CHECK(s_replaced.find("\xEF\xBF\xBD") != std::string::npos);
|
CHECK(s_replaced.find("\xEF\xBF\xBD") != std::string::npos);
|
||||||
|
|
||||||
// ignore drops the invalid bytes, keep copies them
|
|
||||||
CHECK(s_ignored != s_kept);
|
|
||||||
CHECK(s_ignored_ascii != s_kept_ascii);
|
|
||||||
|
|
||||||
// unless a byte needs escaping, keep copies the input unchanged
|
|
||||||
const bool needs_escaping = std::any_of(json_string.begin(), json_string.end(), [](char c)
|
|
||||||
{
|
|
||||||
return static_cast<unsigned char>(c) < 0x20 || c == '"' || c == '\\';
|
|
||||||
});
|
|
||||||
if (!needs_escaping)
|
|
||||||
{
|
|
||||||
CHECK(s_kept == "\"" + json_string + "\"");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check that prefix and suffix are preserved
|
// check that prefix and suffix are preserved
|
||||||
@@ -138,8 +116,6 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
|||||||
CHECK(s_replaced2.substr(s_replaced2.size() - 4, 3) == "xyz");
|
CHECK(s_replaced2.substr(s_replaced2.size() - 4, 3) == "xyz");
|
||||||
CHECK(s_replaced2_ascii.substr(1, 3) == "abc");
|
CHECK(s_replaced2_ascii.substr(1, 3) == "abc");
|
||||||
CHECK(s_replaced2_ascii.substr(s_replaced2_ascii.size() - 4, 3) == "xyz");
|
CHECK(s_replaced2_ascii.substr(s_replaced2_ascii.size() - 4, 3) == "xyz");
|
||||||
CHECK(s_kept2.substr(1, 3) == "abc");
|
|
||||||
CHECK(s_kept2.substr(s_kept2.size() - 4, 3) == "xyz");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_utf8string(bool success_expected, int byte1, int byte2, int byte3, int byte4);
|
void check_utf8string(bool success_expected, int byte1, int byte2, int byte3, int byte4);
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
using nlohmann::json;
|
using nlohmann::json;
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -76,11 +75,8 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
|||||||
static std::string s_replaced2;
|
static std::string s_replaced2;
|
||||||
static std::string s_replaced_ascii;
|
static std::string s_replaced_ascii;
|
||||||
static std::string s_replaced2_ascii;
|
static std::string s_replaced2_ascii;
|
||||||
static std::string s_kept;
|
|
||||||
static std::string s_kept2;
|
|
||||||
static std::string s_kept_ascii;
|
|
||||||
|
|
||||||
// dumping with ignore/replace/keep must not throw in any case
|
// dumping with ignore/replace must not throw in any case
|
||||||
s_ignored = j.dump(-1, ' ', false, json::error_handler_t::ignore);
|
s_ignored = j.dump(-1, ' ', false, json::error_handler_t::ignore);
|
||||||
s_ignored2 = j2.dump(-1, ' ', false, json::error_handler_t::ignore);
|
s_ignored2 = j2.dump(-1, ' ', false, json::error_handler_t::ignore);
|
||||||
s_ignored_ascii = j.dump(-1, ' ', true, json::error_handler_t::ignore);
|
s_ignored_ascii = j.dump(-1, ' ', true, json::error_handler_t::ignore);
|
||||||
@@ -89,9 +85,6 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
|||||||
s_replaced2 = j2.dump(-1, ' ', false, json::error_handler_t::replace);
|
s_replaced2 = j2.dump(-1, ' ', false, json::error_handler_t::replace);
|
||||||
s_replaced_ascii = j.dump(-1, ' ', true, json::error_handler_t::replace);
|
s_replaced_ascii = j.dump(-1, ' ', true, json::error_handler_t::replace);
|
||||||
s_replaced2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::replace);
|
s_replaced2_ascii = j2.dump(-1, ' ', true, json::error_handler_t::replace);
|
||||||
s_kept = j.dump(-1, ' ', false, json::error_handler_t::keep);
|
|
||||||
s_kept2 = j2.dump(-1, ' ', false, json::error_handler_t::keep);
|
|
||||||
s_kept_ascii = j.dump(-1, ' ', true, json::error_handler_t::keep);
|
|
||||||
|
|
||||||
if (success_expected)
|
if (success_expected)
|
||||||
{
|
{
|
||||||
@@ -101,7 +94,6 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
|||||||
// all dumps should agree on the string
|
// all dumps should agree on the string
|
||||||
CHECK(s_strict == s_ignored);
|
CHECK(s_strict == s_ignored);
|
||||||
CHECK(s_strict == s_replaced);
|
CHECK(s_strict == s_replaced);
|
||||||
CHECK(s_strict == s_kept);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -113,20 +105,6 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
|||||||
|
|
||||||
// check that replace string contains a replacement character
|
// check that replace string contains a replacement character
|
||||||
CHECK(s_replaced.find("\xEF\xBF\xBD") != std::string::npos);
|
CHECK(s_replaced.find("\xEF\xBF\xBD") != std::string::npos);
|
||||||
|
|
||||||
// ignore drops the invalid bytes, keep copies them
|
|
||||||
CHECK(s_ignored != s_kept);
|
|
||||||
CHECK(s_ignored_ascii != s_kept_ascii);
|
|
||||||
|
|
||||||
// unless a byte needs escaping, keep copies the input unchanged
|
|
||||||
const bool needs_escaping = std::any_of(json_string.begin(), json_string.end(), [](char c)
|
|
||||||
{
|
|
||||||
return static_cast<unsigned char>(c) < 0x20 || c == '"' || c == '\\';
|
|
||||||
});
|
|
||||||
if (!needs_escaping)
|
|
||||||
{
|
|
||||||
CHECK(s_kept == "\"" + json_string + "\"");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check that prefix and suffix are preserved
|
// check that prefix and suffix are preserved
|
||||||
@@ -138,8 +116,6 @@ void check_utf8dump(bool success_expected, int byte1, int byte2 = -1, int byte3
|
|||||||
CHECK(s_replaced2.substr(s_replaced2.size() - 4, 3) == "xyz");
|
CHECK(s_replaced2.substr(s_replaced2.size() - 4, 3) == "xyz");
|
||||||
CHECK(s_replaced2_ascii.substr(1, 3) == "abc");
|
CHECK(s_replaced2_ascii.substr(1, 3) == "abc");
|
||||||
CHECK(s_replaced2_ascii.substr(s_replaced2_ascii.size() - 4, 3) == "xyz");
|
CHECK(s_replaced2_ascii.substr(s_replaced2_ascii.size() - 4, 3) == "xyz");
|
||||||
CHECK(s_kept2.substr(1, 3) == "abc");
|
|
||||||
CHECK(s_kept2.substr(s_kept2.size() - 4, 3) == "xyz");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_utf8string(bool success_expected, int byte1, int byte2, int byte3, int byte4);
|
void check_utf8string(bool success_expected, int byte1, int byte2, int byte3, int byte4);
|
||||||
|
|||||||
Reference in New Issue
Block a user