From 07cf36cbb0de7a2774d7fa017c0f4ddf86c274d9 Mon Sep 17 00:00:00 2001 From: Yuantao Feng Date: Tue, 29 Jul 2025 17:04:55 +0800 Subject: [PATCH] Merge pull request #27587 from fengyuentau:4x/core/filestorage_json_support_backslash core: support parsing back slash \ in parseKey in FileStorage (JSON) #27587 Fixes #27585 ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [ ] The feature is well documented and sample code can be built with the project CMake --- modules/core/src/persistence_json.cpp | 17 +++++++++++++---- modules/core/test/test_io.cpp | 23 +++++++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/modules/core/src/persistence_json.cpp b/modules/core/src/persistence_json.cpp index 9d05650814..c63acb8c10 100644 --- a/modules/core/src/persistence_json.cpp +++ b/modules/core/src/persistence_json.cpp @@ -419,10 +419,19 @@ public: CV_PARSE_ERROR_CPP( "Key must start with \'\"\'" ); char * beg = ptr + 1; - + std::string key_name; do { - ++ptr; - CV_PERSISTENCE_CHECK_END_OF_BUFFER_BUG_CPP(); + if (*ptr == '\\') { // skip the next character if current is back slash + ++ptr; + CV_PERSISTENCE_CHECK_END_OF_BUFFER_BUG_CPP(); + key_name += *ptr; + ++ptr; + CV_PERSISTENCE_CHECK_END_OF_BUFFER_BUG_CPP(); + } else { + ++ptr; + CV_PERSISTENCE_CHECK_END_OF_BUFFER_BUG_CPP(); + if (*ptr != '\\' && *ptr != '"') key_name += *ptr; + } } while( cv_isprint(*ptr) && *ptr != '"' ); if( *ptr != '"' ) @@ -430,7 +439,7 @@ public: if( ptr == beg ) CV_PARSE_ERROR_CPP( "Key is empty" ); - value_placeholder = fs->addNode(collection, std::string(beg, (size_t)(ptr - beg)), FileNode::NONE); + value_placeholder = fs->addNode(collection, key_name, FileNode::NONE); ptr++; ptr = skipSpaces( ptr ); diff --git a/modules/core/test/test_io.cpp b/modules/core/test/test_io.cpp index 67b0ab5803..7e2a9d52d4 100644 --- a/modules/core/test/test_io.cpp +++ b/modules/core/test/test_io.cpp @@ -1569,6 +1569,29 @@ TEST(Core_InputOutput, FileStorage_json_null_object) fs.release(); } +TEST(Core_InputOutput, FileStorage_json_key_backslash) +{ + // equivalent to json text {"\"":1,"\\":59,"Ġ\"":366,"\\\\":6852} + std::string test = R"({"\"":1,"\\":59,"Ġ\"":366,"\\\\":6852})"; + FileStorage fs(test, FileStorage::READ | FileStorage::MEMORY); + + ASSERT_TRUE(fs[R"(")"].isNamed()); // = "\"" + ASSERT_TRUE(fs[R"(\)"].isNamed()); // = "\\" + ASSERT_TRUE(fs[R"(Ġ")"].isNamed()); // = "Ġ\"" + ASSERT_TRUE(fs[R"(\\)"].isNamed()); // = "\\\\" + + ASSERT_EQ(fs[R"(")"].name(), R"(")"); + ASSERT_EQ(fs[R"(\)"].name(), R"(\)"); + ASSERT_EQ(fs[R"(Ġ")"].name(), R"(Ġ")"); + ASSERT_EQ(fs[R"(\\)"].name(), R"(\\)"); + + ASSERT_EQ((int)fs[R"(")"], 1); + ASSERT_EQ((int)fs[R"(\)"], 59); + ASSERT_EQ((int)fs[R"(Ġ")"], 366); + ASSERT_EQ((int)fs[R"(\\)"], 6852); + fs.release(); +} + TEST(Core_InputOutput, FileStorage_json_named_nodes) { std::string test =