diff --git a/include/nlohmann/detail/view/builder.hpp b/include/nlohmann/detail/view/builder.hpp index 90d435ae6..6a68f9d35 100644 --- a/include/nlohmann/detail/view/builder.hpp +++ b/include/nlohmann/detail/view/builder.hpp @@ -16,7 +16,6 @@ #include // memcmp, memcpy #include // numeric_limits #include // string -#include // false_type, integral_constant, true_type #include // vector #include @@ -309,31 +308,25 @@ class builder --p; return failed(error_code::string_escape, p); } + if (p != end && *p == '\\') + { + continue; // (escapes in a row: no run of text between them) + } p = scan_string_run(p, end); // the text up to the next backslash, quote, control character, or ill-formed UTF-8 } } - /// the string from p, decoded into the arena, or only checked (Store == false) - decoded decode_string(const unsigned char* s, const unsigned char* p) - { - return decode_string(s, p, std::integral_constant()); - } - - decoded decode_string(const unsigned char* s, const unsigned char* p, std::true_type /*unused*/) - { - return slow_string(s, p); - } - - decoded decode_string(const unsigned char* /*unused*/, const unsigned char* p, std::false_type /*unused*/) - { - return check_string(p); - } - /// s points to the start of the string, p to a backslash, a control /// character, an ill-formed UTF-8 byte, or the end: decode the string into /// the arena NLOHMANN_VIEW_NOINLINE decoded slow_string(const unsigned char* s, const unsigned char* p) { + if (!enabled(Store)) + { + // (accept(): the string is checked, not decoded) + static_cast(s); + return check_string(p); + } // single-character escapes; 0: invalid (and 'u', handled separately) static const std::array simple_escape = { @@ -1271,7 +1264,7 @@ indent_done: ++p; return true; } - const decoded r = cold.decode_string(s, p); + const decoded r = cold.slow_string(s, p); if (r.p == nullptr) { return false; diff --git a/single_include/nlohmann/json_view.hpp b/single_include/nlohmann/json_view.hpp index e410ef3a5..ec18242ea 100644 --- a/single_include/nlohmann/json_view.hpp +++ b/single_include/nlohmann/json_view.hpp @@ -88,7 +88,6 @@ #include // memcmp, memcpy #include // numeric_limits #include // string -#include // false_type, integral_constant, true_type #include // vector // #include @@ -1551,31 +1550,25 @@ class builder --p; return failed(error_code::string_escape, p); } + if (p != end && *p == '\\') + { + continue; // (escapes in a row: no run of text between them) + } p = scan_string_run(p, end); // the text up to the next backslash, quote, control character, or ill-formed UTF-8 } } - /// the string from p, decoded into the arena, or only checked (Store == false) - decoded decode_string(const unsigned char* s, const unsigned char* p) - { - return decode_string(s, p, std::integral_constant()); - } - - decoded decode_string(const unsigned char* s, const unsigned char* p, std::true_type /*unused*/) - { - return slow_string(s, p); - } - - decoded decode_string(const unsigned char* /*unused*/, const unsigned char* p, std::false_type /*unused*/) - { - return check_string(p); - } - /// s points to the start of the string, p to a backslash, a control /// character, an ill-formed UTF-8 byte, or the end: decode the string into /// the arena NLOHMANN_VIEW_NOINLINE decoded slow_string(const unsigned char* s, const unsigned char* p) { + if (!enabled(Store)) + { + // (accept(): the string is checked, not decoded) + static_cast(s); + return check_string(p); + } // single-character escapes; 0: invalid (and 'u', handled separately) static const std::array simple_escape = { @@ -2513,7 +2506,7 @@ indent_done: ++p; return true; } - const decoded r = cold.decode_string(s, p); + const decoded r = cold.slow_string(s, p); if (r.p == nullptr) { return false; diff --git a/tests/src/unit-json_view_builder.cpp b/tests/src/unit-json_view_builder.cpp index 88d3c9434..85c9124ce 100644 --- a/tests/src/unit-json_view_builder.cpp +++ b/tests/src/unit-json_view_builder.cpp @@ -553,6 +553,20 @@ TEST_CASE("json_view builder") } } + SECTION("escapes in a row") + { + for (const char* content : + { + "\\n", "\\n\\t\\\\", "\\u00e9\\u00e9\\u4e2d", "\\u00e9\\u00e", "\\u00e9\\", "\\n\\q", "\\n\\ud83d\\ude00\\n", + "\\ud83d\\ude00\\ud83d", "\\n\\n\\n abc \\n\\n", "\\n\x01", "\\n\xC3\x28", "\\n\\" + }) + { + check_accept(std::string("[\"") + content + "\"]"); + check_accept(std::string("[\"") + content); + check_accept(std::string("{\"") + content + "\":1}"); + } + } + SECTION("test files") { for (const char* name :