summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorZephyron <zephyron@citron-emu.org>2025-01-06 14:41:06 +1000
committerZephyron <zephyron@citron-emu.org>2025-01-06 14:41:06 +1000
commit60cb826e937f4fa6a7b262e95dea4f2b87dcf2cf (patch)
tree818a0d4c659b47ca291a6c77a574241340692c4e /src
parent3100d13fc08cf04f831cd8167e98394c22389f59 (diff)
refactor: Improve game list scanning with std::filesystem
Refactors the game list scanning code to use std::filesystem instead of custom directory iteration functions. Main changes include: - Replace Common::FS directory iteration with std::filesystem iterators - Split game file processing logic into separate ProcessGameFile method - Improve error handling with try-catch for filesystem operations - Simplify control NCA metadata extraction - Use more modern C++ features and cleaner code organization This change should improve maintainability and reliability of the game scanning system while potentially offering better performance through native filesystem APIs.
Diffstat (limited to 'src')
-rw-r--r--src/citron/game_list_worker.cpp188
-rw-r--r--src/citron/game_list_worker.h3
2 files changed, 97 insertions, 94 deletions
diff --git a/src/citron/game_list_worker.cpp b/src/citron/game_list_worker.cpp
index 9d6a47074..5703e4e21 100644
--- a/src/citron/game_list_worker.cpp
+++ b/src/citron/game_list_worker.cpp
@@ -335,112 +335,112 @@ void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) {
}
void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_path, bool deep_scan,
- GameListDir* parent_dir) {
- const auto callback = [this, target, parent_dir](const std::filesystem::path& path) -> bool {
- if (stop_requested) {
- // Breaks the callback loop.
- return false;
- }
+ GameListDir* parent_dir) {
+ // Use std::filesystem for native directory iteration
+ const std::filesystem::path root_path(dir_path);
+
+ try {
+ if (deep_scan) {
+ // Use recursive directory iterator for deep scanning
+ for (const auto& entry : std::filesystem::recursive_directory_iterator(root_path)) {
+ if (stop_requested) {
+ return;
+ }
- const auto physical_name = Common::FS::PathToUTF8String(path);
- const auto is_dir = Common::FS::IsDir(path);
+ const auto physical_name = entry.path().string();
+ const bool is_dir = entry.is_directory();
- if (!is_dir &&
- (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) {
- const auto file = vfs->OpenFile(physical_name, FileSys::OpenMode::Read);
- if (!file) {
- return true;
+ if (!is_dir && (HasSupportedFileExtension(physical_name) ||
+ IsExtractedNCAMain(physical_name))) {
+ ProcessGameFile(physical_name, target, parent_dir);
+ } else if (is_dir) {
+ watch_list.append(QString::fromStdString(physical_name));
+ }
}
+ } else {
+ // Use regular directory iterator for shallow scanning
+ for (const auto& entry : std::filesystem::directory_iterator(root_path)) {
+ if (stop_requested) {
+ return;
+ }
- auto loader = Loader::GetLoader(system, file);
- if (!loader) {
- return true;
- }
+ const auto physical_name = entry.path().string();
+ const bool is_dir = entry.is_directory();
- const auto file_type = loader->GetFileType();
- if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) {
- return true;
+ if (!is_dir && (HasSupportedFileExtension(physical_name) ||
+ IsExtractedNCAMain(physical_name))) {
+ ProcessGameFile(physical_name, target, parent_dir);
+ } else if (is_dir) {
+ watch_list.append(QString::fromStdString(physical_name));
+ }
}
+ }
+ } catch (const std::filesystem::filesystem_error& e) {
+ LOG_ERROR(Frontend, "Error scanning directory {}: {}", dir_path, e.what());
+ }
+}
- u64 program_id = 0;
- const auto res2 = loader->ReadProgramId(program_id);
-
- if (target == ScanTarget::FillManualContentProvider) {
- if (res2 == Loader::ResultStatus::Success && file_type == Loader::FileType::NCA) {
- provider->AddEntry(FileSys::TitleType::Application,
- FileSys::GetCRTypeFromNCAType(FileSys::NCA{file}.GetType()),
- program_id, file);
- } else if (res2 == Loader::ResultStatus::Success &&
- (file_type == Loader::FileType::XCI ||
- file_type == Loader::FileType::NSP)) {
- const auto nsp = file_type == Loader::FileType::NSP
- ? std::make_shared<FileSys::NSP>(file)
- : FileSys::XCI{file}.GetSecurePartitionNSP();
- for (const auto& title : nsp->GetNCAs()) {
- for (const auto& entry : title.second) {
- provider->AddEntry(entry.first.first, entry.first.second, title.first,
- entry.second->GetBaseFile());
- }
- }
- }
- } else {
- std::vector<u64> program_ids;
- loader->ReadProgramIds(program_ids);
-
- if (res2 == Loader::ResultStatus::Success && program_ids.size() > 1 &&
- (file_type == Loader::FileType::XCI || file_type == Loader::FileType::NSP)) {
- for (const auto id : program_ids) {
- loader = Loader::GetLoader(system, file, id);
- if (!loader) {
- continue;
- }
-
- std::vector<u8> icon;
- [[maybe_unused]] const auto res1 = loader->ReadIcon(icon);
-
- std::string name = " ";
- [[maybe_unused]] const auto res3 = loader->ReadTitle(name);
-
- const FileSys::PatchManager patch{id, system.GetFileSystemController(),
- system.GetContentProvider()};
-
- auto entry = MakeGameListEntry(
- physical_name, name, Common::FS::GetSize(physical_name), icon, *loader,
- id, compatibility_list, play_time_manager, patch);
-
- RecordEvent(
- [=](GameList* game_list) { game_list->AddEntry(entry, parent_dir); });
- }
- } else {
- std::vector<u8> icon;
- [[maybe_unused]] const auto res1 = loader->ReadIcon(icon);
-
- std::string name = " ";
- [[maybe_unused]] const auto res3 = loader->ReadTitle(name);
-
- const FileSys::PatchManager patch{program_id, system.GetFileSystemController(),
- system.GetContentProvider()};
-
- auto entry = MakeGameListEntry(
- physical_name, name, Common::FS::GetSize(physical_name), icon, *loader,
- program_id, compatibility_list, play_time_manager, patch);
-
- RecordEvent(
- [=](GameList* game_list) { game_list->AddEntry(entry, parent_dir); });
+void GameListWorker::ProcessGameFile(const std::string& physical_name, ScanTarget target,
+ GameListDir* parent_dir) {
+ const auto file = vfs->OpenFile(physical_name, FileSys::OpenMode::Read);
+ if (!file) {
+ return;
+ }
+
+ auto loader = Loader::GetLoader(system, file);
+ if (!loader) {
+ return;
+ }
+
+ const auto file_type = loader->GetFileType();
+ if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) {
+ return;
+ }
+
+ u64 program_id = 0;
+ if (loader->ReadProgramId(program_id) != Loader::ResultStatus::Success) {
+ return;
+ }
+
+ if (target == ScanTarget::FillManualContentProvider) {
+ if (file_type == Loader::FileType::NCA) {
+ provider->AddEntry(FileSys::TitleType::Application,
+ FileSys::GetCRTypeFromNCAType(FileSys::NCAContentType::Program),
+ program_id,
+ std::static_pointer_cast<FileSys::VfsFile>(file));
+ } else if (file_type == Loader::FileType::NSP || file_type == Loader::FileType::XCI) {
+ const auto nsp = file_type == Loader::FileType::NSP
+ ? std::make_shared<FileSys::NSP>(file)
+ : std::make_shared<FileSys::XCI>(file)
+ ->GetSecurePartitionNSP();
+ for (const auto& title : nsp->GetNCAs()) {
+ for (const auto& entry : title.second) {
+ provider->AddEntry(entry.first.first, entry.first.second, title.first,
+ entry.second->GetBaseFile());
}
}
- } else if (is_dir) {
- watch_list.append(QString::fromStdString(physical_name));
}
+ } else {
+ std::vector<u8> icon;
+ std::string name;
+ const FileSys::PatchManager patch{program_id, system.GetFileSystemController(),
+ system.GetContentProvider()};
- return true;
- };
+ const auto control = system.GetContentProvider().GetEntry(program_id, FileSys::ContentRecordType::Control);
+ if (control != nullptr) {
+ GetMetadataFromControlNCA(patch, *control, icon, name);
+ } else {
+ std::tie(icon, name) = std::make_pair(std::vector<u8>{}, "");
+ }
- if (deep_scan) {
- Common::FS::IterateDirEntriesRecursively(dir_path, callback,
- Common::FS::DirEntryFilter::All);
- } else {
- Common::FS::IterateDirEntries(dir_path, callback, Common::FS::DirEntryFilter::File);
+ if (loader->ReadProgramId(program_id) == Loader::ResultStatus::Success) {
+ auto entry = MakeGameListEntry(physical_name, name, file->GetSize(), icon, *loader,
+ program_id, compatibility_list, play_time_manager, patch);
+
+ RecordEvent([entry, parent_dir](GameList* game_list) {
+ game_list->AddEntry(entry, parent_dir);
+ });
+ }
}
}
diff --git a/src/citron/game_list_worker.h b/src/citron/game_list_worker.h
index 80e6b384a..083bf8262 100644
--- a/src/citron/game_list_worker.h
+++ b/src/citron/game_list_worker.h
@@ -76,6 +76,9 @@ private:
void ScanFileSystem(ScanTarget target, const std::string& dir_path, bool deep_scan,
GameListDir* parent_dir);
+ void ProcessGameFile(const std::string& physical_name, ScanTarget target,
+ GameListDir* parent_dir);
+
std::shared_ptr<FileSys::VfsFilesystem> vfs;
FileSys::ManualContentProvider* provider;
QVector<UISettings::GameDir>& game_dirs;