diff options
| author | Zephyron <zephyron@citron-emu.org> | 2025-01-06 14:41:06 +1000 | 
|---|---|---|
| committer | Zephyron <zephyron@citron-emu.org> | 2025-01-06 14:41:06 +1000 | 
| commit | 60cb826e937f4fa6a7b262e95dea4f2b87dcf2cf (patch) | |
| tree | 818a0d4c659b47ca291a6c77a574241340692c4e | |
| parent | 3100d13fc08cf04f831cd8167e98394c22389f59 (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.
| -rw-r--r-- | src/citron/game_list_worker.cpp | 188 | ||||
| -rw-r--r-- | src/citron/game_list_worker.h | 3 | 
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;  | 
