diff --git a/src/json.hpp b/src/json.hpp index 9a2011532..fad9d87ab 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -8826,8 +8826,10 @@ class basic_json { // clear stream flags is.clear(); - // set stream after last processed char - is.seekg(start_position + static_cast(processed_chars - 1)); + // We initially read a lot of characters into the buffer, and we + // may not have processed all of them. Therefore, we need to + // "rewind" the stream after the last processed char. + is.seekg(start_position + static_cast(processed_chars)); } int get_character() override @@ -8840,20 +8842,19 @@ class basic_json // store number of bytes in the buffer fill_size = static_cast(is.gcount()); + // the buffer is ready + buffer_pos = 0; + // remember that filling did not yield new input if (fill_size == 0) { eof = true; + return std::char_traits::eof(); } - - // the buffer is ready - buffer_pos = 0; } ++processed_chars; - return eof - ? std::char_traits::eof() - : buffer[buffer_pos++] & 0xFF; + return buffer[buffer_pos++] & 0xFF;; } std::string read(size_t offset, size_t length) override diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 1ff8f987e..db281ac45 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -599,6 +599,118 @@ TEST_CASE("regression tests") "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input"); } + SECTION("issue #367 - behavior of operator>> should more closely resemble that of built-in overloads") + { + SECTION("(empty)") + { + std::stringstream ss; + json j; + CHECK_THROWS_AS(ss >> j, json::parse_error); + CHECK_THROWS_WITH(ss >> j, + "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input"); + } + + SECTION("(whitespace)") + { + std::stringstream ss; + ss << " "; + json j; + CHECK_THROWS_AS(ss >> j, json::parse_error); + CHECK_THROWS_WITH(ss >> j, + "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input"); + } + + SECTION("one value") + { + std::stringstream ss; + ss << "111"; + json j; + CHECK_NOTHROW(ss >> j); + CHECK(j == 111); + + CHECK_THROWS_AS(ss >> j, json::parse_error); + CHECK_THROWS_WITH(ss >> j, + "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input"); + } + + SECTION("one value + whitespace") + { + std::stringstream ss; + ss << "222 \t\n"; + json j; + CHECK_NOTHROW(ss >> j); + CHECK(j == 222); + + CHECK_THROWS_AS(ss >> j, json::parse_error); + CHECK_THROWS_WITH(ss >> j, + "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input"); + } + + SECTION("whitespace + one value") + { + std::stringstream ss; + ss << "\n\t 333"; + json j; + CHECK_NOTHROW(ss >> j); + CHECK(j == 333); + + CHECK_THROWS_AS(ss >> j, json::parse_error); + CHECK_THROWS_WITH(ss >> j, + "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input"); + } + + SECTION("three values") + { + std::stringstream ss; + ss << " 111 \n222\n \n 333"; + json j; + CHECK_NOTHROW(ss >> j); + CHECK(j == 111); + CHECK_NOTHROW(ss >> j); + CHECK(j == 222); + CHECK_NOTHROW(ss >> j); + CHECK(j == 333); + + CHECK_THROWS_AS(ss >> j, json::parse_error); + CHECK_THROWS_WITH(ss >> j, + "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input"); + } + + SECTION("literals without whitespace") + { + std::stringstream ss; + ss << "truefalsenull\"\""; + json j; + CHECK_NOTHROW(ss >> j); + CHECK(j == true); + CHECK_NOTHROW(ss >> j); + CHECK(j == false); + CHECK_NOTHROW(ss >> j); + CHECK(j == nullptr); + CHECK_NOTHROW(ss >> j); + CHECK(j == ""); + + CHECK_THROWS_AS(ss >> j, json::parse_error); + CHECK_THROWS_WITH(ss >> j, + "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input"); + } + + SECTION("example from #529") + { + std::stringstream ss; + ss << "{\n \"one\" : 1,\n \"two\" : 2\n}\n{\n \"three\" : 3\n}"; + json j; + CHECK_NOTHROW(ss >> j); + CHECK(j == json({{"one", 1}, {"two", 2}})); + CHECK_NOTHROW(ss >> j); + CHECK(j == json({{"three", 3}})); + + CHECK_THROWS_AS(ss >> j, json::parse_error); + CHECK_THROWS_WITH(ss >> j, + "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input"); + } + } + SECTION("issue #389 - Integer-overflow (OSS-Fuzz issue 267)") { // original test case