[App] Fix game scanning

This commit is contained in:
Jonathan Goyvaerts 2020-08-23 16:00:40 +02:00 committed by Satori
parent 3459ee11d4
commit fb3a52983a
4 changed files with 32 additions and 25 deletions

View File

@ -11,18 +11,19 @@ namespace app {
using filesystem::FileInfo; using filesystem::FileInfo;
using AsyncCallback = XGameScanner::AsyncCallback; using AsyncCallback = XGameScanner::AsyncCallback;
std::vector<wstring> XGameScanner::FindGamesInPath(const wstring& path) { std::vector<std::filesystem::path> XGameScanner::FindGamesInPath(
const std::filesystem::path& path) {
// Path is a directory, scan recursively // Path is a directory, scan recursively
// TODO: Warn about recursively scanning paths with large hierarchies // TODO: Warn about recursively scanning paths with large hierarchies
std::deque<wstring> queue; std::deque<std::filesystem::path> queue;
queue.push_front(path); queue.push_front(path);
std::vector<wstring> paths; std::vector<std::filesystem::path> paths;
int game_count = 0; int game_count = 0;
while (!queue.empty()) { while (!queue.empty()) {
wstring current_path = queue.front(); std::filesystem::path current_path = queue.front();
FileInfo current_file; FileInfo current_file;
filesystem::GetInfo(current_path, &current_file); filesystem::GetInfo(current_path, &current_file);
@ -34,10 +35,10 @@ std::vector<wstring> XGameScanner::FindGamesInPath(const wstring& path) {
for (FileInfo file : directory_files) { for (FileInfo file : directory_files) {
if (CompareCaseInsensitive(file.name, L"$SystemUpdate")) continue; if (CompareCaseInsensitive(file.name, L"$SystemUpdate")) continue;
auto next_path = (current_path, file.name); auto next_path = current_path / file.name;
// Skip searching directories with an extracted default.xex file // Skip searching directories with an extracted default.xex file
if (std::filesystem::exists(next_path / L"default.xex")) { if (std::filesystem::exists(next_path / "default.xex")) {
queue.push_front(next_path / L"default.xex"); queue.push_front(next_path / "default.xex");
continue; continue;
} }
queue.push_front(next_path); queue.push_front(next_path);
@ -45,7 +46,7 @@ std::vector<wstring> XGameScanner::FindGamesInPath(const wstring& path) {
} else { } else {
// Exclusively scan iso, xex, or files without an extension. // Exclusively scan iso, xex, or files without an extension.
auto extension = GetFileExtension(current_path); auto extension = GetFileExtension(current_path);
if (!extension.empty() && extension != L"xex" && extension != L"iso") { if (!extension.empty() && extension != ".xex" && extension != ".iso") {
continue; continue;
} }
@ -63,7 +64,8 @@ std::vector<wstring> XGameScanner::FindGamesInPath(const wstring& path) {
return paths; return paths;
} }
std::vector<XGameEntry> XGameScanner::ScanPath(const wstring& path) { std::vector<XGameEntry> XGameScanner::ScanPath(
const std::filesystem::path& path) {
std::vector<XGameEntry> games; std::vector<XGameEntry> games;
// Check if the given path exists // Check if the given path exists
@ -80,8 +82,9 @@ std::vector<XGameEntry> XGameScanner::ScanPath(const wstring& path) {
games.emplace_back(std::move(game_entry)); games.emplace_back(std::move(game_entry));
} }
} else { } else {
const std::vector<wstring>& game_paths = FindGamesInPath(path); const std::vector<std::filesystem::path>& game_paths =
for (const wstring& game_path : game_paths) { FindGamesInPath(path);
for (const std::filesystem::path& game_path : game_paths) {
XGameEntry game_entry; XGameEntry game_entry;
if (XFAILED(ScanGame(game_path, &game_entry))) { if (XFAILED(ScanGame(game_path, &game_entry))) {
continue; continue;
@ -94,20 +97,23 @@ std::vector<XGameEntry> XGameScanner::ScanPath(const wstring& path) {
return games; return games;
} }
int XGameScanner::ScanPathAsync(const wstring& path, const AsyncCallback& cb) { int XGameScanner::ScanPathAsync(const std::filesystem::path& path,
std::vector<wstring> paths = {path}; const AsyncCallback& cb) {
std::vector<std::filesystem::path> paths = {path};
return ScanPathsAsync(paths, cb); return ScanPathsAsync(paths, cb);
} }
int XGameScanner::ScanPathsAsync(const std::vector<wstring>& paths, int XGameScanner::ScanPathsAsync(
const std::vector<std::filesystem::path>& paths,
const AsyncCallback& cb) { const AsyncCallback& cb) {
// start scanning in a new thread // start scanning in a new thread
// TODO: switch to xe::threading::Thread instead of std::thread? // TODO: switch to xe::threading::Thread instead of std::thread?
std::thread scan_thread = std::thread( std::thread scan_thread = std::thread(
[](std::vector<wstring> paths, AsyncCallback cb) { [](std::vector<std::filesystem::path> paths, AsyncCallback cb) {
std::atomic<int> scanned = 0; std::atomic<int> scanned = 0;
auto scan_func = [&](const std::vector<wstring>& paths, size_t start, auto scan_func = [&](const std::vector<std::filesystem::path>& paths,
size_t start,
size_t size) { size_t size) {
for (auto it = paths.begin() + start; for (auto it = paths.begin() + start;
it != paths.begin() + start + size; ++it) { it != paths.begin() + start + size; ++it) {

View File

@ -18,22 +18,23 @@ class XGameScanner {
using AsyncCallback = std::function<void(const XGameEntry&, int)>; using AsyncCallback = std::function<void(const XGameEntry&, int)>;
// Returns a vector of all supported games in provided path. // Returns a vector of all supported games in provided path.
static std::vector<wstring> FindGamesInPath(const wstring& path); static std::vector<std::filesystem::path> FindGamesInPath(
const std::filesystem::path& path);
// Scans a provided path and recursively parses the games. // Scans a provided path and recursively parses the games.
// Returns a vector of parsed game entries. // Returns a vector of parsed game entries.
static std::vector<XGameEntry> ScanPath(const wstring& path); static std::vector<XGameEntry> ScanPath(const std::filesystem::path& path);
// Scans a provided path and recursively parses the games asynchronously. // Scans a provided path and recursively parses the games asynchronously.
// The callback provided is called on each successfully parsed game. // The callback provided is called on each successfully parsed game.
// Returns the number of games found in the path. // Returns the number of games found in the path.
static int ScanPathAsync(const wstring& path, static int ScanPathAsync(const std::filesystem::path& path,
const AsyncCallback& cb = nullptr); const AsyncCallback& cb = nullptr);
// Scans a list of provided paths and recursively parses the games // Scans a list of provided paths and recursively parses the games
// asynchronously. The callback provided is called on each successfully parsed // asynchronously. The callback provided is called on each successfully parsed
// game. Returns the number of games found in all paths provided. // game. Returns the number of games found in all paths provided.
static int ScanPathsAsync(const std::vector<wstring>& paths, static int ScanPathsAsync(const std::vector<std::filesystem::path>& paths,
const AsyncCallback& cb = nullptr); const AsyncCallback& cb = nullptr);
// Scans a path for a single game, populating the provided output game entry // Scans a path for a single game, populating the provided output game entry

View File

@ -113,7 +113,7 @@ inline const bool CompareCaseInsensitive(const wstring& left,
inline const std::filesystem::path GetFileExtension( inline const std::filesystem::path GetFileExtension(
const std::filesystem::path& path) { const std::filesystem::path& path) {
return path.extension(); return xe::utf8::lower_ascii(xe::path_to_utf8(path.extension()));
} }
inline const std::filesystem::path GetFileName(const std::filesystem::path& path) { inline const std::filesystem::path GetFileName(const std::filesystem::path& path) {
@ -157,8 +157,8 @@ inline void ReadStfsMagic(const std::filesystem::path& path, char out[4]) {
inline const XGameFormat ResolveFormat(const std::filesystem::path& path) { inline const XGameFormat ResolveFormat(const std::filesystem::path& path) {
const std::wstring& extension = GetFileExtension(path); const std::wstring& extension = GetFileExtension(path);
if (CompareCaseInsensitive(extension, L"iso")) return XGameFormat::kIso; if (CompareCaseInsensitive(extension, L".iso")) return XGameFormat::kIso;
if (CompareCaseInsensitive(extension, L"xex")) return XGameFormat::kXex; if (CompareCaseInsensitive(extension, L".xex")) return XGameFormat::kXex;
// STFS Container // STFS Container
char magic[4]; char magic[4];

View File

@ -491,8 +491,8 @@ X_STATUS ReadXexResources(File* file, XexInfo* info) {
auto resource = &resources[i]; auto resource = &resources[i];
uint32_t title_id = info->execution_info.title_id; uint32_t title_id = info->execution_info.title_id;
uint32_t name = uint32_t name = xe::string_util::from_string<uint32_t>(
xe::string_util::from_string<uint32_t>(resource->name, true); std::string(reinterpret_cast<char*>(resource->name), 8), true);
XELOGI("Found resource: %X", name); XELOGI("Found resource: %X", name);
// Game resources are listed as the TitleID // Game resources are listed as the TitleID