From 9228010625f6a83a9e1aa43b1befe74e36508cea Mon Sep 17 00:00:00 2001 From: Georg Hagen Date: Thu, 10 Oct 2024 14:54:36 +0200 Subject: [PATCH] Add ToValidFileName function --- openVulkanoCpp/IO/FsUtils.cpp | 59 +++++++++++++++++++++++++++++++++++ openVulkanoCpp/IO/FsUtils.hpp | 2 ++ 2 files changed, 61 insertions(+) diff --git a/openVulkanoCpp/IO/FsUtils.cpp b/openVulkanoCpp/IO/FsUtils.cpp index 3a3595a..ae38496 100644 --- a/openVulkanoCpp/IO/FsUtils.cpp +++ b/openVulkanoCpp/IO/FsUtils.cpp @@ -5,6 +5,8 @@ */ #include "FsUtils.hpp" +#include +#include namespace fs = std::filesystem; @@ -88,4 +90,61 @@ namespace OpenVulkano return size; } + + std::string FsUtils::ToValidFileName(std::string str) + { + // Map of characters to replace with similar looking ones + static const std::unordered_map replacements = { + {'<', "<"}, // Use full-width less than + {'>', ">"}, // Use full-width greater than + {':', "꞉"}, // Use modifier letter colon + {'"', """}, // Use full-width quotation mark + {'/', "⁄"}, // Use fraction slash + {'\\', "⧹"}, // Use big reverse solidus + {'|', "|"}, // Use full-width vertical line + {'?', "?"}, // Use full-width question mark + {'*', "∗"}, // Use asterisk operator + }; + + // Characters to remove (control characters and others that might cause issues) + static const std::regex remove_pattern("[\\x00-\\x1F\\x7F~`!@#$%^&(){}\\[\\]=+,;]"); + + // Maximum length for many filesystems + static const size_t MAX_LENGTH = 255; + + // Replace problematic characters with similar looking ones + for (const auto& [key, value] : replacements) { + size_t pos = 0; + while ((pos = str.find(key, pos)) != std::string::npos) { + str.replace(pos, 1, value); + pos += value.length(); + } + } + + // Remove other invalid characters + str = std::regex_replace(str, remove_pattern, ""); + + // Trim leading/trailing spaces and periods + str = std::regex_replace(str, std::regex("^[\\.\\s]+"), ""); + str = std::regex_replace(str, std::regex("[\\.\\s]+$"), ""); + + // Replace multiple spaces with a single space + str = std::regex_replace(str, std::regex("\\s+"), " "); + + // Ensure the string isn't empty after sanitization + if (str.empty()) { + str = "unnamed_file"; + } + + // Truncate if too long, being careful not to cut in the middle of a UTF-8 character + if (str.length() > MAX_LENGTH) { + size_t len = MAX_LENGTH; + while (len > 0 && (str[len] & 0xC0) == 0x80) { + --len; + } + str = str.substr(0, len); + } + + return str; + } } diff --git a/openVulkanoCpp/IO/FsUtils.hpp b/openVulkanoCpp/IO/FsUtils.hpp index 4dc397c..e37d2f6 100644 --- a/openVulkanoCpp/IO/FsUtils.hpp +++ b/openVulkanoCpp/IO/FsUtils.hpp @@ -20,5 +20,7 @@ namespace OpenVulkano static bool IsTreeEmpty(const std::filesystem::path& dir); static ByteSize GetDirSize(const std::filesystem::path& dir); + + static std::string ToValidFileName(std::string filename); }; }