From 163ca54a90ded07164e7fbfbc414ac39bdf771fc Mon Sep 17 00:00:00 2001 From: black-sliver <59490463+black-sliver@users.noreply.github.com> Date: Sun, 4 Aug 2024 17:26:27 +0200 Subject: [PATCH] Ignore unicode for auto-save path and special symbols for default filename Also refactor and add tests. --- src/core/statemanager.cpp | 11 +---------- src/core/util.h | 28 +++++++++++++++++++++----- test/core/test_util.cpp | 41 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 15 deletions(-) create mode 100644 test/core/test_util.cpp diff --git a/src/core/statemanager.cpp b/src/core/statemanager.cpp index 1ce61af9..9afcb113 100644 --- a/src/core/statemanager.cpp +++ b/src/core/statemanager.cpp @@ -1,22 +1,13 @@ #include "statemanager.h" #include "jsonutil.h" #include "fileutil.h" +#include "util.h" #include using nlohmann::json; std::map StateManager::_states; std::string StateManager::_dir; -static std::string sanitize_dir(std::string s) -{ - if (s.empty()) return "_"; - if ((size_t)std::count(s.begin(), s.end(), '.') == s.length()) return "_"; - std::replace(s.begin(), s.end(), '/', '_'); - std::replace(s.begin(), s.end(), '\\', '_'); - std::replace(s.begin(), s.end(), ':', '_'); - return s; -} - void StateManager::setDir(const std::string& dir) { _dir = dir; diff --git a/src/core/util.h b/src/core/util.h index ecd03661..c371078e 100644 --- a/src/core/util.h +++ b/src/core/util.h @@ -1,7 +1,10 @@ #ifndef _CORE_UTIL_H #define _CORE_UTIL_H -#include +#include +#include +#include + template< class Type, ptrdiff_t n > static ptrdiff_t countOf( Type (&)[n] ) { return n; } @@ -12,10 +15,25 @@ static std::string sanitize_print(const std::string& s) { return res; } -static std::string sanitize_filename(const std::string& s) { - std::string res = s; - for (auto& c: res) if (c<0x20 || c=='/' || c=='\\' || c==':') c = '_'; - return res; +/// Replaces reserved/non-portable symbols by '_'. +static std::string sanitize_filename(std::string s) { + auto exclude = "<>:\"/\\|?*$'`"; + auto sanitize = [&](char c) { return strchr(exclude, c) || c == 0; }; + std::replace_if(s.begin(), s.end(), sanitize, '_'); + return s; +} + +/// Replaces non-ASCII and reserved/non-portable symbols by '_'. Returns "_" for empty and resrved folder names. +static std::string sanitize_dir(std::string s) +{ + if (s.empty()) + return "_"; + if ((size_t)std::count(s.begin(), s.end(), '.') == s.length()) + return "_"; + auto exclude = "<>:\"/\\|?*$'`"; + auto sanitize = [&](char c) { return c<0x20 || strchr(exclude, c); }; + std::replace_if(s.begin(), s.end(), sanitize, '_'); + return s; } template diff --git a/test/core/test_util.cpp b/test/core/test_util.cpp new file mode 100644 index 00000000..af884e2b --- /dev/null +++ b/test/core/test_util.cpp @@ -0,0 +1,41 @@ +#include +#include "../../src/core/util.h" + + +TEST(SanitizeFilenameTest, InvalidSymbol) { + EXPECT_EQ(sanitize_filename({"a\x00z", 3}), "a_z"); + EXPECT_EQ(sanitize_filename("ä"), "ä"); + EXPECT_EQ(sanitize_filename("a*b"), "a_b"); + EXPECT_EQ(sanitize_filename("a/b"), "a_b"); + EXPECT_EQ(sanitize_filename("a\\b"), "a_b"); +} + +TEST(SanitizeFilenameTest, Empty) { + // allow empty filename + EXPECT_EQ(sanitize_filename(""), ""); +} + +TEST(SanitizeDirTest, InvalidSymbol) { + EXPECT_EQ(sanitize_dir({"a\x00z", 3}), "a_z"); + EXPECT_EQ(sanitize_dir("a\x01z"), "a_z"); + EXPECT_EQ(sanitize_dir("a\x80z"), "a_z"); + EXPECT_EQ(sanitize_dir("a*b"), "a_b"); + EXPECT_EQ(sanitize_dir("a/b"), "a_b"); + EXPECT_EQ(sanitize_dir("a\\b"), "a_b"); +} + +TEST(SanitizeDirTest, Empty) { + // can't have an empty dirname + EXPECT_EQ(sanitize_dir(""), "_"); +} + +TEST(SanitizeDirTest, NoCWD) { + EXPECT_EQ(sanitize_dir("."), "_"); + EXPECT_EQ(sanitize_dir("./"), "._"); +} + +TEST(SanitizeDirTest, NoParent) { + EXPECT_EQ(sanitize_dir(".."), "_"); + EXPECT_EQ(sanitize_dir("../"), ".._"); + EXPECT_EQ(sanitize_dir("..\\"), ".._"); +}