diff --git a/include/json/reader.h b/include/json/reader.h index 917546608..285c66eac 100644 --- a/include/json/reader.h +++ b/include/json/reader.h @@ -392,6 +392,12 @@ bool JSON_API parseFromStream(CharReader::Factory const&, IStream&, Value* root, */ JSON_API IStream& operator>>(IStream&, Value&); +/** Get the line and column of a character within a string. + */ +void JSON_API getLocationLineAndColumn(char const* beginDoc, char const* endDoc, + ptrdiff_t location, int& line, + int& column); + } // namespace Json #pragma pack(pop) diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index a34017d99..7de72aade 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -761,24 +761,9 @@ Reader::Char Reader::getNextChar() { void Reader::getLocationLineAndColumn(Location location, int& line, int& column) const { - Location current = begin_; - Location lastLineStart = current; - line = 0; - while (current < location && current != end_) { - Char c = *current++; - if (c == '\r') { - if (*current == '\n') - ++current; - lastLineStart = current; - ++line; - } else if (c == '\n') { - lastLineStart = current; - ++line; - } - } - // column & line start at 1 - column = int(location - lastLineStart) + 1; - ++line; + Json::getLocationLineAndColumn(document_.data(), + document_.data() + document_.length(), + location - document_.data(), line, column); } String Reader::getLocationLineAndColumn(Location location) const { @@ -1990,4 +1975,26 @@ IStream& operator>>(IStream& sin, Value& root) { return sin; } +void getLocationLineAndColumn(char const* beginDoc, char const* endDoc, + ptrdiff_t location, int& line, int& column) { + char const* current = beginDoc; + char const* lastLineStart = current; + line = 0; + while (current < beginDoc + location && current < endDoc) { + char c = *current++; + if (c == '\r') { + if (*current == '\n') + ++current; + lastLineStart = current; + ++line; + } else if (c == '\n') { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(beginDoc + location - lastLineStart) + 1; + ++line; +} + } // namespace Json diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index d0f5364ac..12e5c2940 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -3903,6 +3903,28 @@ JSONTEST_FIXTURE_LOCAL(FuzzTest, fuzzDoesntCrash) { example.size())); } +struct GetLocationLineAndColumnTest : JsonTest::TestCase { + void testLineAndColumn(const std::string& doc, ptrdiff_t location, int row, + int column) { + int actualRow; + int actualColumn; + Json::getLocationLineAndColumn(doc.data(), doc.data() + doc.length(), + location, actualRow, actualColumn); + JSONTEST_ASSERT_EQUAL(row, actualRow); + JSONTEST_ASSERT_EQUAL(column, actualColumn); + } +}; + +JSONTEST_FIXTURE_LOCAL(GetLocationLineAndColumnTest, test) { + const std::string example = "line 1\nline 2\r\nline 3\rline 4"; + testLineAndColumn(example, 0, 1, 1); + testLineAndColumn(example, 6, 1, 7); + testLineAndColumn(example, 8, 2, 2); + testLineAndColumn(example, 14, 3, 0); + testLineAndColumn(example, 15, 3, 1); + testLineAndColumn(example, 25, 4, 4); +} + int main(int argc, const char* argv[]) { JsonTest::Runner runner;