diff --git a/Source/Core/Common/FileSearch.cpp b/Source/Core/Common/FileSearch.cpp index 0da6c4fc13..d022414efc 100644 --- a/Source/Core/Common/FileSearch.cpp +++ b/Source/Core/Common/FileSearch.cpp @@ -4,17 +4,17 @@ #include "Common/FileSearch.h" #include +#include #include #include +#include #include "Common/CommonPaths.h" +#include "Common/Logging/Log.h" #include "Common/StringUtil.h" #ifdef _MSC_VER #include -#include -namespace fs = std::filesystem; -#define HAS_STD_FILESYSTEM #else #ifdef ANDROID #include "jni/AndroidCommon/AndroidCommon.h" @@ -25,52 +25,45 @@ namespace fs = std::filesystem; #include "Common/FileUtil.h" #endif +namespace fs = std::filesystem; + namespace Common { -#ifndef HAS_STD_FILESYSTEM - -static void FileSearchWithTest(const std::string& directory, bool recursive, - std::vector* result_out, - std::function callback) -{ - File::FSTEntry top = File::ScanDirectoryTree(directory, recursive); - - const std::function DoEntry = [&](File::FSTEntry& entry) { - if (callback(entry)) - result_out->push_back(entry.physicalName); - for (auto& child : entry.children) - DoEntry(child); - }; - - for (auto& child : top.children) - DoEntry(child); -} - std::vector DoFileSearch(const std::vector& directories, const std::vector& exts, bool recursive) { - std::vector result; + const bool accept_all = exts.empty(); - bool accept_all = exts.empty(); - const auto callback = [&exts, accept_all](const File::FSTEntry& entry) { - if (accept_all) - return true; - if (entry.isDirectory) - return false; - return std::any_of(exts.begin(), exts.end(), [&](const std::string& ext) { - const std::string& name = entry.virtualName; - return name.length() >= ext.length() && - strcasecmp(name.c_str() + name.length() - ext.length(), ext.c_str()) == 0; + std::vector native_exts; + for (const auto& ext : exts) + native_exts.push_back(StringToPath(ext)); + + // N.B. This avoids doing any copies + auto ext_matches = [&native_exts](const fs::path& path) { + const std::basic_string_view native_path = path.native(); + return std::any_of(native_exts.cbegin(), native_exts.cend(), [&native_path](const auto& ext) { + const auto compare_len = ext.native().length(); + if (native_path.length() < compare_len) + return false; + const auto substr_to_compare = native_path.substr(native_path.length() - compare_len); +#ifdef _WIN32 + return CompareStringOrdinal(substr_to_compare.data(), static_cast(compare_len), + ext.c_str(), static_cast(compare_len), TRUE) == CSTR_EQUAL; +#else + return strncasecmp(substr_to_compare.data(), ext.c_str(), compare_len) == 0; +#endif }); }; - for (const std::string& directory : directories) + std::vector result; + auto add_filtered = [&](const fs::directory_entry& entry) { + auto& path = entry.path(); + if (accept_all || (!entry.is_directory() && ext_matches(path))) + result.emplace_back(PathToString(path)); + }; + for (const auto& directory : directories) { #ifdef ANDROID - // While File::ScanDirectoryTree (which is called in FileSearchWithTest) does handle Android - // content correctly, having a specialized implementation of DoFileSearch for Android content - // provides a much needed performance boost. Also, this specialized implementation will be - // required if we in the future replace the use of File::ScanDirectoryTree with std::filesystem. if (IsPathAndroidContent(directory)) { const std::vector partial_result = @@ -82,62 +75,22 @@ std::vector DoFileSearch(const std::vector& directorie else #endif { - FileSearchWithTest(directory, recursive, &result, callback); - } - } - - // remove duplicates - std::sort(result.begin(), result.end()); - result.erase(std::unique(result.begin(), result.end()), result.end()); - return result; -} - -#else - -std::vector DoFileSearch(const std::vector& directories, - const std::vector& exts, bool recursive) -{ - bool accept_all = exts.empty(); - - std::vector native_exts; - for (const auto& ext : exts) - native_exts.push_back(StringToPath(ext)); - - // N.B. This avoids doing any copies - auto ext_matches = [&native_exts](const fs::path& path) { - const auto& native_path = path.native(); - return std::any_of(native_exts.cbegin(), native_exts.cend(), [&native_path](const auto& ext) { - // TODO provide cross-platform compat for the comparison function, once more platforms - // support std::filesystem - int compare_len = static_cast(ext.native().length()); - return native_path.length() >= compare_len && - CompareStringOrdinal(&native_path.c_str()[native_path.length() - compare_len], - compare_len, ext.c_str(), compare_len, TRUE) == CSTR_EQUAL; - }); - }; - - std::vector result; - auto add_filtered = [&](const fs::directory_entry& entry) { - auto& path = entry.path(); - if (accept_all || (ext_matches(path) && !fs::is_directory(path))) - result.emplace_back(PathToString(path)); - }; - for (const auto& directory : directories) - { - fs::path directory_path = StringToPath(directory); - if (fs::is_directory(directory_path)) // Can't create iterators for non-existant directories - { + fs::path directory_path = StringToPath(directory); + std::error_code error; if (recursive) { - // TODO use fs::directory_options::follow_directory_symlink ? - for (auto& entry : fs::recursive_directory_iterator(std::move(directory_path))) - add_filtered(entry); + for (auto it = fs::recursive_directory_iterator(std::move(directory_path), error); + it != fs::recursive_directory_iterator(); it.increment(error)) + add_filtered(*it); } else { - for (auto& entry : fs::directory_iterator(std::move(directory_path))) - add_filtered(entry); + for (auto it = fs::directory_iterator(std::move(directory_path), error); + it != fs::directory_iterator(); it.increment(error)) + add_filtered(*it); } + if (error) + ERROR_LOG_FMT(COMMON, "{} error on {}: {}", __func__, directory, error.message()); } } @@ -160,6 +113,4 @@ std::vector DoFileSearch(const std::vector& directorie return result; } -#endif - } // namespace Common diff --git a/Source/Core/Common/FileUtil.cpp b/Source/Core/Common/FileUtil.cpp index 1dbadafe86..983e7d21a0 100644 --- a/Source/Core/Common/FileUtil.cpp +++ b/Source/Core/Common/FileUtil.cpp @@ -54,7 +54,6 @@ #endif #ifdef ANDROID -#include "Common/StringUtil.h" #include "jni/AndroidCommon/AndroidCommon.h" #endif diff --git a/Source/Core/Common/StringUtil.cpp b/Source/Core/Common/StringUtil.cpp index 849e83815c..c8d862e424 100644 --- a/Source/Core/Common/StringUtil.cpp +++ b/Source/Core/Common/StringUtil.cpp @@ -645,7 +645,6 @@ std::u16string UTF8ToUTF16(std::string_view input) return converter.from_bytes(input.data(), input.data() + input.size()); } -#ifdef HAS_STD_FILESYSTEM // This is a replacement for path::u8path, which is deprecated starting with C++20. std::filesystem::path StringToPath(std::string_view path) { @@ -666,7 +665,6 @@ std::string PathToString(const std::filesystem::path& path) return path.native(); #endif } -#endif #ifdef _WIN32 std::vector CommandLineToUtf8Argv(const wchar_t* command_line) diff --git a/Source/Core/Common/StringUtil.h b/Source/Core/Common/StringUtil.h index 7cd8b691bc..620d437f35 100644 --- a/Source/Core/Common/StringUtil.h +++ b/Source/Core/Common/StringUtil.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -16,11 +17,6 @@ #include "Common/CommonTypes.h" -#ifdef _MSC_VER -#include -#define HAS_STD_FILESYSTEM -#endif - std::string StringFromFormatV(const char* format, va_list args); std::string StringFromFormat(const char* format, ...) @@ -214,10 +210,8 @@ inline std::string UTF8ToTStr(std::string_view str) #endif -#ifdef HAS_STD_FILESYSTEM std::filesystem::path StringToPath(std::string_view path); std::string PathToString(const std::filesystem::path& path); -#endif // Thousand separator. Turns 12345678 into 12,345,678 template diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 60fb7d98fa..ea7f9b3673 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -3,12 +3,6 @@ #include "Core/Boot/Boot.h" -#ifdef _MSC_VER -#include -namespace fs = std::filesystem; -#define HAS_STD_FILESYSTEM -#endif - #include #include #include @@ -67,10 +61,6 @@ namespace fs = std::filesystem; static std::vector ReadM3UFile(const std::string& m3u_path, const std::string& folder_path) { -#ifndef HAS_STD_FILESYSTEM - ASSERT(folder_path.back() == '/'); -#endif - std::vector result; std::vector nonexistent; @@ -91,12 +81,7 @@ static std::vector ReadM3UFile(const std::string& m3u_path, if (!line.empty() && line.front() != '#') // Comments start with # { -#ifdef HAS_STD_FILESYSTEM const std::string path_to_add = PathToString(StringToPath(folder_path) / StringToPath(line)); -#else - const std::string path_to_add = line.front() != '/' ? folder_path + line : line; -#endif - (File::Exists(path_to_add) ? result : nonexistent).push_back(path_to_add); } } diff --git a/Source/Core/DiscIO/GameModDescriptor.cpp b/Source/Core/DiscIO/GameModDescriptor.cpp index 5ed11dec3a..1a2fea422f 100644 --- a/Source/Core/DiscIO/GameModDescriptor.cpp +++ b/Source/Core/DiscIO/GameModDescriptor.cpp @@ -18,13 +18,7 @@ namespace DiscIO { static std::string MakeAbsolute(const std::string& directory, const std::string& path) { -#ifdef _WIN32 return PathToString(StringToPath(directory) / StringToPath(path)); -#else - if (StringBeginsWith(path, "/")) - return path; - return directory + "/" + path; -#endif } std::optional ParseGameModDescriptorFile(const std::string& filename)