From cfa9c83d33ab24c39df3bd74459176354849c4e1 Mon Sep 17 00:00:00 2001 From: asrelo <47759736+asrelo@users.noreply.github.com> Date: Sun, 11 Aug 2024 21:19:14 +0300 Subject: [PATCH] Improve fs::PathStartsWith to handle empty strings (#14877) `""` does not refer to a proper path, and `fs::PathStartsWith(path, "")` should just return `false`. This is also the case in libraries in other languages where I looked, seems to be common. The new behavior: * check early, if `prefix` is empty - return if path is empty or not, * no special processing for when `path` is empty, the function meets characters in `prefix` and returns false anyway. --- src/filesys.cpp | 11 +++++++++++ src/unittest/test_filesys.cpp | 23 ++++++++++++----------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/filesys.cpp b/src/filesys.cpp index 733a3b203..4287c8b05 100644 --- a/src/filesys.cpp +++ b/src/filesys.cpp @@ -697,32 +697,43 @@ bool MoveDir(const std::string &source, const std::string &target) bool PathStartsWith(const std::string &path, const std::string &prefix) { + if (prefix.empty()) + return path.empty(); size_t pathsize = path.size(); size_t pathpos = 0; size_t prefixsize = prefix.size(); size_t prefixpos = 0; for(;;){ + // Test if current characters at path and prefix are delimiter OR EOS bool delim1 = pathpos == pathsize || IsDirDelimiter(path[pathpos]); bool delim2 = prefixpos == prefixsize || IsDirDelimiter(prefix[prefixpos]); + // Return false if it's delimiter/EOS in one path but not in the other if(delim1 != delim2) return false; if(delim1){ + // Skip consequent delimiters in path, in prefix while(pathpos < pathsize && IsDirDelimiter(path[pathpos])) ++pathpos; while(prefixpos < prefixsize && IsDirDelimiter(prefix[prefixpos])) ++prefixpos; + // Return true if prefix has ended (at delimiter/EOS) if(prefixpos == prefixsize) return true; + // Return false if path has ended (at delimiter/EOS) + // while prefix did not. if(pathpos == pathsize) return false; } else{ + // Skip pairwise-equal characters in path and prefix until + // delimiter/EOS in path or prefix. + // Return false if differing characters are met. size_t len = 0; do{ char pathchar = path[pathpos+len]; diff --git a/src/unittest/test_filesys.cpp b/src/unittest/test_filesys.cpp index 8fc9db3d8..fd25d2de9 100644 --- a/src/unittest/test_filesys.cpp +++ b/src/unittest/test_filesys.cpp @@ -113,6 +113,7 @@ void TestFileSys::testPathStartsWith() }; /* expected fs::PathStartsWith results + (row for every path, column for every prefix) 0 = returns false 1 = returns true 2 = returns false on windows, true elsewhere @@ -122,17 +123,17 @@ void TestFileSys::testPathStartsWith() */ int expected_results[numpaths][numpaths] = { {1,2,0,0,0,0,0,0,0,0,0,0}, - {1,1,0,0,0,0,0,0,0,0,0,0}, - {1,1,1,0,0,0,0,0,0,0,0,0}, - {1,1,1,1,0,0,0,0,0,0,0,0}, - {1,1,0,0,1,0,0,0,0,0,0,0}, - {1,1,0,0,0,1,0,0,1,1,0,0}, - {1,1,0,0,0,0,1,4,1,0,0,0}, - {1,1,0,0,0,0,4,1,4,0,0,0}, - {1,1,0,0,0,0,0,0,1,0,0,0}, - {1,1,0,0,0,0,0,0,1,1,0,0}, - {1,1,0,0,0,0,0,0,0,0,1,0}, - {1,1,0,0,0,0,0,0,0,0,0,1}, + {0,1,0,0,0,0,0,0,0,0,0,0}, + {0,1,1,0,0,0,0,0,0,0,0,0}, + {0,1,1,1,0,0,0,0,0,0,0,0}, + {0,1,0,0,1,0,0,0,0,0,0,0}, + {0,1,0,0,0,1,0,0,1,1,0,0}, + {0,1,0,0,0,0,1,4,1,0,0,0}, + {0,1,0,0,0,0,4,1,4,0,0,0}, + {0,1,0,0,0,0,0,0,1,0,0,0}, + {0,1,0,0,0,0,0,0,1,1,0,0}, + {0,1,0,0,0,0,0,0,0,0,1,0}, + {0,1,0,0,0,0,0,0,0,0,0,1}, }; for (int i = 0; i < numpaths; i++)