mirror of
https://github.com/nlohmann/json.git
synced 2026-10-28 16:55:41 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a17a07f0e | ||
|
|
402af742c0 |
No files matched your search
@@ -26,7 +26,6 @@
|
|||||||
#include <nlohmann/detail/view/lookup.hpp>
|
#include <nlohmann/detail/view/lookup.hpp>
|
||||||
#include <nlohmann/detail/view/macro_scope.hpp>
|
#include <nlohmann/detail/view/macro_scope.hpp>
|
||||||
#include <nlohmann/detail/view/node.hpp>
|
#include <nlohmann/detail/view/node.hpp>
|
||||||
#include <nlohmann/detail/view/scan.hpp>
|
|
||||||
#include <nlohmann/detail/view/view_mode.hpp>
|
#include <nlohmann/detail/view/view_mode.hpp>
|
||||||
|
|
||||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
@@ -47,9 +46,10 @@ struct first_true<false, Conditions...> : std::integral_constant < int, 1 + firs
|
|||||||
/// (type_error.316 with the same message), so that an editable document
|
/// (type_error.316 with the same message), so that an editable document
|
||||||
/// only holds valid UTF-8: the error is at the first byte that no
|
/// only holds valid UTF-8: the error is at the first byte that no
|
||||||
/// well-formed sequence can continue with (Unicode, Table 3-7).
|
/// well-formed sequence can continue with (Unicode, Table 3-7).
|
||||||
NLOHMANN_VIEW_ALWAYS_INLINE void check_utf8_bytewise(const unsigned char* p, std::size_t n, std::size_t i)
|
inline void check_utf8(const char* s, std::size_t n)
|
||||||
{
|
{
|
||||||
for (; i < n;)
|
const auto* const p = reinterpret_cast<const unsigned char*>(s); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||||
|
for (std::size_t i = 0; i < n;)
|
||||||
{
|
{
|
||||||
const unsigned char c = p[i];
|
const unsigned char c = p[i];
|
||||||
if (c < 0x80)
|
if (c < 0x80)
|
||||||
@@ -79,43 +79,6 @@ NLOHMANN_VIEW_ALWAYS_INLINE void check_utf8_bytewise(const unsigned char* p, std
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The long-string path of check_utf8(): skips well-formed runs with the
|
|
||||||
/// parser's string scan (which stops at a quote, a backslash, or a control
|
|
||||||
/// character, all legal here, and at ill-formed UTF-8); the byte-wise check
|
|
||||||
/// runs only from where the scan found ill-formed UTF-8, to report it.
|
|
||||||
NLOHMANN_VIEW_NOINLINE inline void check_utf8_scan(const unsigned char* p, std::size_t n)
|
|
||||||
{
|
|
||||||
const unsigned char* const e = p + n;
|
|
||||||
const unsigned char* q = p;
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
q = scan_string_run<true>(q, e);
|
|
||||||
if (q == e)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (*q >= 0x80)
|
|
||||||
{
|
|
||||||
check_utf8_bytewise(p, n, static_cast<std::size_t>(q - p));
|
|
||||||
return; // not reached: the scan stopped at ill-formed UTF-8
|
|
||||||
}
|
|
||||||
++q; // a quote, backslash, or control character
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void check_utf8(const char* s, std::size_t n)
|
|
||||||
{
|
|
||||||
const auto* const p = reinterpret_cast<const unsigned char*>(s); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
|
||||||
if (NLOHMANN_VIEW_UNLIKELY(n >= 32))
|
|
||||||
{
|
|
||||||
check_utf8_scan(p, n);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// short strings: the vector scan costs more than it saves; (the loop is
|
|
||||||
// inlined with a constant start, so this path is the plain byte-wise check)
|
|
||||||
check_utf8_bytewise(p, n, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief the edits of an editable basic_json_document
|
@brief the edits of an editable basic_json_document
|
||||||
|
|
||||||
|
|||||||
Generated
+3
-41
@@ -3740,8 +3740,6 @@ NLOHMANN_JSON_NAMESPACE_END
|
|||||||
|
|
||||||
// #include <nlohmann/detail/view/node.hpp>
|
// #include <nlohmann/detail/view/node.hpp>
|
||||||
|
|
||||||
// #include <nlohmann/detail/view/scan.hpp>
|
|
||||||
|
|
||||||
// #include <nlohmann/detail/view/view_mode.hpp>
|
// #include <nlohmann/detail/view/view_mode.hpp>
|
||||||
// __ _____ _____ _____
|
// __ _____ _____ _____
|
||||||
// __| | __| | | | JSON for Modern C++
|
// __| | __| | | | JSON for Modern C++
|
||||||
@@ -3815,9 +3813,10 @@ struct first_true<false, Conditions...> : std::integral_constant < int, 1 + firs
|
|||||||
/// (type_error.316 with the same message), so that an editable document
|
/// (type_error.316 with the same message), so that an editable document
|
||||||
/// only holds valid UTF-8: the error is at the first byte that no
|
/// only holds valid UTF-8: the error is at the first byte that no
|
||||||
/// well-formed sequence can continue with (Unicode, Table 3-7).
|
/// well-formed sequence can continue with (Unicode, Table 3-7).
|
||||||
NLOHMANN_VIEW_ALWAYS_INLINE void check_utf8_bytewise(const unsigned char* p, std::size_t n, std::size_t i)
|
inline void check_utf8(const char* s, std::size_t n)
|
||||||
{
|
{
|
||||||
for (; i < n;)
|
const auto* const p = reinterpret_cast<const unsigned char*>(s); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||||
|
for (std::size_t i = 0; i < n;)
|
||||||
{
|
{
|
||||||
const unsigned char c = p[i];
|
const unsigned char c = p[i];
|
||||||
if (c < 0x80)
|
if (c < 0x80)
|
||||||
@@ -3847,43 +3846,6 @@ NLOHMANN_VIEW_ALWAYS_INLINE void check_utf8_bytewise(const unsigned char* p, std
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The long-string path of check_utf8(): skips well-formed runs with the
|
|
||||||
/// parser's string scan (which stops at a quote, a backslash, or a control
|
|
||||||
/// character, all legal here, and at ill-formed UTF-8); the byte-wise check
|
|
||||||
/// runs only from where the scan found ill-formed UTF-8, to report it.
|
|
||||||
NLOHMANN_VIEW_NOINLINE inline void check_utf8_scan(const unsigned char* p, std::size_t n)
|
|
||||||
{
|
|
||||||
const unsigned char* const e = p + n;
|
|
||||||
const unsigned char* q = p;
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
q = scan_string_run<true>(q, e);
|
|
||||||
if (q == e)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (*q >= 0x80)
|
|
||||||
{
|
|
||||||
check_utf8_bytewise(p, n, static_cast<std::size_t>(q - p));
|
|
||||||
return; // not reached: the scan stopped at ill-formed UTF-8
|
|
||||||
}
|
|
||||||
++q; // a quote, backslash, or control character
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void check_utf8(const char* s, std::size_t n)
|
|
||||||
{
|
|
||||||
const auto* const p = reinterpret_cast<const unsigned char*>(s); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
|
||||||
if (NLOHMANN_VIEW_UNLIKELY(n >= 32))
|
|
||||||
{
|
|
||||||
check_utf8_scan(p, n);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// short strings: the vector scan costs more than it saves; (the loop is
|
|
||||||
// inlined with a constant start, so this path is the plain byte-wise check)
|
|
||||||
check_utf8_bytewise(p, n, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief the edits of an editable basic_json_document
|
@brief the edits of an editable basic_json_document
|
||||||
|
|
||||||
|
|||||||
@@ -941,123 +941,3 @@ TEST_CASE("json_view edits: duplicate keys")
|
|||||||
CHECK(d.root()["o"]["d"].get<int>() == 0);
|
CHECK(d.root()["o"]["d"].get<int>() == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(JSON_NOEXCEPTION)
|
|
||||||
TEST_CASE("json_view edits: check_utf8 agrees with the byte-wise check")
|
|
||||||
{
|
|
||||||
namespace dv = nlohmann::detail::view;
|
|
||||||
|
|
||||||
// "ok" or the exception message
|
|
||||||
const auto run = [](bool fast, const std::string & s) -> std::string
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (fast)
|
|
||||||
{
|
|
||||||
dv::check_utf8(s.data(), s.size());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dv::check_utf8_bytewise(reinterpret_cast<const unsigned char*>(s.data()), s.size(), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (const json::type_error& e)
|
|
||||||
{
|
|
||||||
return {e.what()};
|
|
||||||
}
|
|
||||||
return {"ok"};
|
|
||||||
};
|
|
||||||
std::size_t errors = 0;
|
|
||||||
const auto same = [&](const std::string & s)
|
|
||||||
{
|
|
||||||
const std::string a = run(true, s);
|
|
||||||
const std::string b = run(false, s);
|
|
||||||
if (a != b)
|
|
||||||
{
|
|
||||||
INFO("fast: " << a << ", byte-wise: " << b << ", length " << s.size());
|
|
||||||
CHECK(a == b);
|
|
||||||
}
|
|
||||||
errors += b != "ok" ? 1u : 0u;
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::vector<std::string> pieces =
|
|
||||||
{
|
|
||||||
"a", "Z", " ", "\"", "\\", "\n", "\x01", "\x7f", "\xc3\xa4", "\xe4\xb8\xad", "\xf0\x9f\x98\x80",
|
|
||||||
"\x80", "\xbf", "\xc0\x80", "\xc1\xbf", "\xc2", "\xe0\x80\x80", "\xe0\x9f\xbf", "\xed\xa0\x80", "\xed\xbf\xbf",
|
|
||||||
"\xf0\x80\x80\x80", "\xf0\x8f\xbf\xbf", "\xf4\x90\x80\x80", "\xf4\x8f\xbf\xbf", "\xf5", "\xf8", "\xff", "\xfe",
|
|
||||||
"\xe4\xb8", "\xf0\x9f\x98", "\xf0\x9f", "\xf0"
|
|
||||||
};
|
|
||||||
|
|
||||||
// every piece behind prefixes of every length, and followed by more bytes
|
|
||||||
for (std::size_t prefix = 0; prefix <= 64; ++prefix)
|
|
||||||
{
|
|
||||||
for (const auto& piece : pieces)
|
|
||||||
{
|
|
||||||
same(std::string(prefix, 'x') + piece);
|
|
||||||
same(std::string(prefix, 'x') + piece + "yz");
|
|
||||||
same(std::string(prefix, '"') + piece);
|
|
||||||
same(std::string(prefix, '\xc3') + piece);
|
|
||||||
same(std::string(prefix / 2, '\xc3').append(prefix / 2, '\xa4') + piece);
|
|
||||||
same(std::string(prefix, 'x') + "\xe4\xb8\xad" + piece);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// an invalid byte at every position of valid strings of every length
|
|
||||||
for (std::size_t len = 0; len <= 64; ++len)
|
|
||||||
{
|
|
||||||
const std::string ascii(len, 'a');
|
|
||||||
std::string mixed;
|
|
||||||
while (mixed.size() < len)
|
|
||||||
{
|
|
||||||
if (mixed.size() % 7 == 0)
|
|
||||||
{
|
|
||||||
mixed += "\xc3\xa4";
|
|
||||||
}
|
|
||||||
else if (mixed.size() % 11 == 0)
|
|
||||||
{
|
|
||||||
mixed += "\xf0\x9f\x98\x80";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mixed += "a";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
same(ascii);
|
|
||||||
same(mixed);
|
|
||||||
for (std::size_t pos = 0; pos < len; ++pos)
|
|
||||||
{
|
|
||||||
for (const char bad :
|
|
||||||
{'\x80', '\xc0', '\xc2', '\xe0', '\xf4', '\xff', '"', '\\', '\x1f'
|
|
||||||
})
|
|
||||||
{
|
|
||||||
std::string s = ascii;
|
|
||||||
s[pos] = bad;
|
|
||||||
same(s);
|
|
||||||
s = mixed;
|
|
||||||
s[pos] = bad;
|
|
||||||
same(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// random bytes, biased to the interesting ones
|
|
||||||
std::mt19937 gen(5869); // NOLINT(cert-msc32-c,cert-msc51-cpp,bugprone-random-generator-seed): reproducible
|
|
||||||
static const std::array<unsigned char, 23> interesting = {{0x00, 0x1f, 0x22, 0x5c, 0x7f, 0x80, 0x8f, 0x90, 0x9f, 0xa0, 0xbf, 0xc0, 0xc2, 0xdf, 0xe0, 0xe1, 0xed, 0xef, 0xf0, 0xf1, 0xf4, 0xf5, 0xff}};
|
|
||||||
for (int i = 0; i < 100000; ++i)
|
|
||||||
{
|
|
||||||
std::string s(gen() % 80, 'a');
|
|
||||||
for (auto& c : s)
|
|
||||||
{
|
|
||||||
const unsigned r = gen() % 8;
|
|
||||||
if (r == 0)
|
|
||||||
{
|
|
||||||
c = static_cast<char>(gen() & 0xff);
|
|
||||||
}
|
|
||||||
else if (r == 1)
|
|
||||||
{
|
|
||||||
c = static_cast<char>(interesting[gen() % interesting.size()]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
same(s);
|
|
||||||
}
|
|
||||||
CHECK(errors > 1000);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -54,14 +54,18 @@ int accepts_any(nlohmann::basic_json_view<BasicJsonType, Mode> /*unused*/)
|
|||||||
return Mode == nlohmann::view_mode::editable ? 3 : 4;
|
return Mode == nlohmann::view_mode::editable ? 3 : 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename View>
|
// overloads that differ only in the mode; deduction ignores the conversion from
|
||||||
auto overload(View v) -> decltype(accepts_editable(v))
|
// read-only to editable views, so each view picks the overload of its own mode
|
||||||
|
// (two templates that differ only in a decltype return type are a redefinition
|
||||||
|
// for MSVC 2015)
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
int overload(nlohmann::basic_json_view<BasicJsonType, nlohmann::view_mode::editable> v)
|
||||||
{
|
{
|
||||||
return accepts_editable(v);
|
return accepts_editable(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename View>
|
template<typename BasicJsonType>
|
||||||
auto overload(View v) -> decltype(accepts_read_only(v))
|
int overload(nlohmann::basic_json_view<BasicJsonType, nlohmann::view_mode::read_only> v)
|
||||||
{
|
{
|
||||||
return accepts_read_only(v);
|
return accepts_read_only(v);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user