dolphin/Source/Core/Common/FileSearch.cpp
JosJuice 382356627a FileSearch: Check isDirectory in the non-Windows code
c5fa470 made the extension check discard directories, but
only in the new code that currently only is used on Windows.
Let's add an equivalent check in the old code so that the
behavior is consistent across platforms.
2017-06-26 11:44:23 +02:00

128 lines
4.1 KiB
C++

// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <algorithm>
#include <functional>
#include "Common/CommonPaths.h"
#include "Common/FileSearch.h"
#ifdef _MSC_VER
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#define HAS_STD_FILESYSTEM
#else
#include "Common/FileUtil.h"
#endif
namespace Common
{
#ifndef HAS_STD_FILESYSTEM
static std::vector<std::string>
FileSearchWithTest(const std::vector<std::string>& directories, bool recursive,
std::function<bool(const File::FSTEntry&)> callback)
{
std::vector<std::string> result;
for (const std::string& directory : directories)
{
File::FSTEntry top = File::ScanDirectoryTree(directory, recursive);
std::function<void(File::FSTEntry&)> DoEntry;
DoEntry = [&](File::FSTEntry& entry) {
if (callback(entry))
result.push_back(entry.physicalName);
for (auto& child : entry.children)
DoEntry(child);
};
for (auto& child : top.children)
DoEntry(child);
}
// remove duplicates
std::sort(result.begin(), result.end());
result.erase(std::unique(result.begin(), result.end()), result.end());
return result;
}
std::vector<std::string> DoFileSearch(const std::vector<std::string>& directories,
const std::vector<std::string>& exts, bool recursive)
{
bool accept_all = exts.empty();
return FileSearchWithTest(directories, recursive, [&](const File::FSTEntry& entry) {
if (accept_all)
return true;
if (entry.isDirectory)
return false;
std::string name = entry.virtualName;
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
return std::any_of(exts.begin(), exts.end(), [&](const std::string& ext) {
return name.length() >= ext.length() &&
name.compare(name.length() - ext.length(), ext.length(), ext) == 0;
});
});
}
#else
std::vector<std::string> DoFileSearch(const std::vector<std::string>& directories,
const std::vector<std::string>& exts, bool recursive)
{
bool accept_all = exts.empty();
std::vector<fs::path> native_exts;
for (const auto& ext : exts)
native_exts.push_back(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
return native_path.length() >= ext.native().length() &&
_wcsicmp(&native_path.c_str()[native_path.length() - ext.native().length()],
ext.c_str()) == 0;
});
};
std::vector<std::string> 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(path.u8string());
};
for (const auto& directory : directories)
{
if (recursive)
{
// TODO use fs::directory_options::follow_directory_symlink ?
for (auto& entry : fs::recursive_directory_iterator(fs::path(directory.c_str())))
add_filtered(entry);
}
else
{
for (auto& entry : fs::directory_iterator(fs::path(directory.c_str())))
add_filtered(entry);
}
}
// Remove duplicates (occurring because caller gave e.g. duplicate or overlapping directories -
// not because std::filesystem returns duplicates). Also note that this pathname-based uniqueness
// isn't as thorough as std::filesystem::equivalent.
std::sort(result.begin(), result.end());
result.erase(std::unique(result.begin(), result.end()), result.end());
// Dolphin expects to be able to use "/" (DIR_SEP) everywhere. std::filesystem uses the OS
// separator.
if (fs::path::preferred_separator != DIR_SEP_CHR)
for (auto& path : result)
std::replace(path.begin(), path.end(), '\\', DIR_SEP_CHR);
return result;
}
#endif
} // namespace Common