mirror of
https://git.citron-emu.org/Citron/Citron.git
synced 2025-01-22 08:36:32 +01:00
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.
This commit is contained in:
parent
3100d13fc0
commit
60cb826e93
2 changed files with 99 additions and 96 deletions
|
@ -336,46 +336,83 @@ 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 {
|
||||
// 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) {
|
||||
// Breaks the callback loop.
|
||||
return false;
|
||||
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))) {
|
||||
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;
|
||||
}
|
||||
|
||||
const auto physical_name = entry.path().string();
|
||||
const bool is_dir = entry.is_directory();
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
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 true;
|
||||
return;
|
||||
}
|
||||
|
||||
auto loader = Loader::GetLoader(system, file);
|
||||
if (!loader) {
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto file_type = loader->GetFileType();
|
||||
if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) {
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
u64 program_id = 0;
|
||||
const auto res2 = loader->ReadProgramId(program_id);
|
||||
if (loader->ReadProgramId(program_id) != Loader::ResultStatus::Success) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (target == ScanTarget::FillManualContentProvider) {
|
||||
if (res2 == Loader::ResultStatus::Success && file_type == Loader::FileType::NCA) {
|
||||
if (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)) {
|
||||
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)
|
||||
: FileSys::XCI{file}.GetSecurePartitionNSP();
|
||||
: 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,
|
||||
|
@ -384,64 +421,27 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa
|
|||
}
|
||||
}
|
||||
} 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);
|
||||
|
||||
std::string name;
|
||||
const FileSys::PatchManager patch{program_id, system.GetFileSystemController(),
|
||||
system.GetContentProvider()};
|
||||
|
||||
auto entry = MakeGameListEntry(
|
||||
physical_name, name, Common::FS::GetSize(physical_name), icon, *loader,
|
||||
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 (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(
|
||||
[=](GameList* game_list) { game_list->AddEntry(entry, parent_dir); });
|
||||
RecordEvent([entry, parent_dir](GameList* game_list) {
|
||||
game_list->AddEntry(entry, parent_dir);
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (is_dir) {
|
||||
watch_list.append(QString::fromStdString(physical_name));
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
if (deep_scan) {
|
||||
Common::FS::IterateDirEntriesRecursively(dir_path, callback,
|
||||
Common::FS::DirEntryFilter::All);
|
||||
} else {
|
||||
Common::FS::IterateDirEntries(dir_path, callback, Common::FS::DirEntryFilter::File);
|
||||
}
|
||||
}
|
||||
|
||||
void GameListWorker::run() {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue