[App] Fix game scanning
This commit is contained in:
parent
3459ee11d4
commit
fb3a52983a
|
@ -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, ¤t_file);
|
filesystem::GetInfo(current_path, ¤t_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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue