diff options
-rw-r--r-- | src/core/CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/core/crypto/key_manager.cpp | 1 | ||||
-rw-r--r-- | src/core/file_sys/registered_cache.cpp | 53 | ||||
-rw-r--r-- | src/core/file_sys/system_archive/ng_word.cpp | 42 | ||||
-rw-r--r-- | src/core/file_sys/system_archive/ng_word.h | 13 | ||||
-rw-r--r-- | src/core/file_sys/system_archive/system_archive.cpp | 91 | ||||
-rw-r--r-- | src/core/file_sys/system_archive/system_archive.h | 14 | ||||
-rw-r--r-- | src/core/file_sys/vfs_vector.cpp | 1 | ||||
-rw-r--r-- | src/core/file_sys/vfs_vector.h | 53 | ||||
-rw-r--r-- | src/core/hle/kernel/svc.cpp | 48 | ||||
-rw-r--r-- | src/core/hle/kernel/svc_wrap.h | 13 | ||||
-rw-r--r-- | src/core/hle/service/filesystem/fsp_srv.cpp | 10 | ||||
-rw-r--r-- | src/yuzu/game_list_worker.cpp | 105 |
13 files changed, 357 insertions, 91 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 73aec8ab0..882c9ab59 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -63,6 +63,10 @@ add_library(core STATIC file_sys/sdmc_factory.h file_sys/submission_package.cpp file_sys/submission_package.h + file_sys/system_archive/ng_word.cpp + file_sys/system_archive/ng_word.h + file_sys/system_archive/system_archive.cpp + file_sys/system_archive/system_archive.h file_sys/vfs.cpp file_sys/vfs.h file_sys/vfs_concat.cpp diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index ed231927b..ca12fb4ab 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -246,7 +246,6 @@ std::vector<TicketRaw> GetTicketblob(const FileUtil::IOFile& ticket_save) { } std::vector<TicketRaw> out; - u32 magic{}; for (std::size_t offset = 0; offset + 0x4 < buffer.size(); ++offset) { if (buffer[offset] == 0x4 && buffer[offset + 1] == 0x0 && buffer[offset + 2] == 0x1 && buffer[offset + 3] == 0x0) { diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index 07c3af64a..128199063 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp @@ -107,42 +107,41 @@ static ContentRecordType GetCRTypeFromNCAType(NCAContentType type) { VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const { const auto file = dir->GetFileRelative(path); - if (file != nullptr) + if (file != nullptr) { return file; + } const auto nca_dir = dir->GetDirectoryRelative(path); - if (nca_dir != nullptr) { - const auto nca_dir = dir->GetDirectoryRelative(path); - VirtualFile file = nullptr; + if (nca_dir == nullptr) { + return nullptr; + } - const auto files = nca_dir->GetFiles(); - if (files.size() == 1 && files[0]->GetName() == "00") { - file = files[0]; + const auto files = nca_dir->GetFiles(); + if (files.size() == 1 && files[0]->GetName() == "00") { + return files[0]; + } + + std::vector<VirtualFile> concat; + // Since the files are a two-digit hex number, max is FF. + for (std::size_t i = 0; i < 0x100; ++i) { + auto next = nca_dir->GetFile(fmt::format("{:02X}", i)); + if (next != nullptr) { + concat.push_back(std::move(next)); } else { - std::vector<VirtualFile> concat; - // Since the files are a two-digit hex number, max is FF. - for (std::size_t i = 0; i < 0x100; ++i) { - auto next = nca_dir->GetFile(fmt::format("{:02X}", i)); - if (next != nullptr) { - concat.push_back(std::move(next)); - } else { - next = nca_dir->GetFile(fmt::format("{:02x}", i)); - if (next != nullptr) - concat.push_back(std::move(next)); - else - break; - } + next = nca_dir->GetFile(fmt::format("{:02x}", i)); + if (next != nullptr) { + concat.push_back(std::move(next)); + } else { + break; } - - if (concat.empty()) - return nullptr; - - file = ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName()); } + } - return file; + if (concat.empty()) { + return nullptr; } - return nullptr; + + return ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName()); } VirtualFile RegisteredCache::GetFileAtID(NcaID id) const { diff --git a/src/core/file_sys/system_archive/ng_word.cpp b/src/core/file_sys/system_archive/ng_word.cpp new file mode 100644 index 000000000..d0acdbd49 --- /dev/null +++ b/src/core/file_sys/system_archive/ng_word.cpp @@ -0,0 +1,42 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <fmt/format.h> +#include "common/common_types.h" +#include "core/file_sys/system_archive/ng_word.h" +#include "core/file_sys/vfs_vector.h" + +namespace FileSys::SystemArchive { + +namespace NgWord1Data { + +constexpr std::size_t NUMBER_WORD_TXT_FILES = 0x10; + +// Should this archive replacement mysteriously not work on a future game, consider updating. +constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x19}; // 5.1.0 System Version + +constexpr std::array<u8, 30> WORD_TXT{ + 0xFE, 0xFF, 0x00, 0x5E, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x79, 0x00, 0x62, 0x00, + 0x61, 0x00, 0x64, 0x00, 0x77, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x64, 0x00, 0x24, 0x00, 0x0A, +}; // "^verybadword$" in UTF-16 + +} // namespace NgWord1Data + +VirtualDir NgWord1() { + std::vector<VirtualFile> files(NgWord1Data::NUMBER_WORD_TXT_FILES); + + for (std::size_t i = 0; i < NgWord1Data::NUMBER_WORD_TXT_FILES; ++i) { + files[i] = std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>( + NgWord1Data::WORD_TXT, fmt::format("{}.txt", i)); + } + + files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>( + NgWord1Data::WORD_TXT, "common.txt")); + files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::VERSION_DAT.size()>>( + NgWord1Data::VERSION_DAT, "version.dat")); + + return std::make_shared<VectorVfsDirectory>(files, std::vector<VirtualDir>{}, "data"); +} + +} // namespace FileSys::SystemArchive diff --git a/src/core/file_sys/system_archive/ng_word.h b/src/core/file_sys/system_archive/ng_word.h new file mode 100644 index 000000000..f4bc67344 --- /dev/null +++ b/src/core/file_sys/system_archive/ng_word.h @@ -0,0 +1,13 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/file_sys/vfs_types.h" + +namespace FileSys::SystemArchive { + +VirtualDir NgWord1(); + +} // namespace FileSys::SystemArchive diff --git a/src/core/file_sys/system_archive/system_archive.cpp b/src/core/file_sys/system_archive/system_archive.cpp new file mode 100644 index 000000000..c9c40a07d --- /dev/null +++ b/src/core/file_sys/system_archive/system_archive.cpp @@ -0,0 +1,91 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <functional> +#include "common/logging/log.h" +#include "core/file_sys/romfs.h" +#include "core/file_sys/system_archive/ng_word.h" +#include "core/file_sys/system_archive/system_archive.h" + +namespace FileSys::SystemArchive { + +constexpr u64 SYSTEM_ARCHIVE_BASE_TITLE_ID = 0x0100000000000800; +constexpr std::size_t SYSTEM_ARCHIVE_COUNT = 0x28; + +using SystemArchiveSupplier = std::function<VirtualDir()>; + +struct SystemArchiveDescriptor { + u64 title_id; + const char* name; + SystemArchiveSupplier supplier; +}; + +const std::array<SystemArchiveDescriptor, SYSTEM_ARCHIVE_COUNT> SYSTEM_ARCHIVES = {{ + {0x0100000000000800, "CertStore", nullptr}, + {0x0100000000000801, "ErrorMessage", nullptr}, + {0x0100000000000802, "MiiModel", nullptr}, + {0x0100000000000803, "BrowserDll", nullptr}, + {0x0100000000000804, "Help", nullptr}, + {0x0100000000000805, "SharedFont", nullptr}, + {0x0100000000000806, "NgWord", &NgWord1}, + {0x0100000000000807, "SsidList", nullptr}, + {0x0100000000000808, "Dictionary", nullptr}, + {0x0100000000000809, "SystemVersion", nullptr}, + {0x010000000000080A, "AvatarImage", nullptr}, + {0x010000000000080B, "LocalNews", nullptr}, + {0x010000000000080C, "Eula", nullptr}, + {0x010000000000080D, "UrlBlackList", nullptr}, + {0x010000000000080E, "TimeZoneBinary", nullptr}, + {0x010000000000080F, "CertStoreCruiser", nullptr}, + {0x0100000000000810, "FontNintendoExtension", nullptr}, + {0x0100000000000811, "FontStandard", nullptr}, + {0x0100000000000812, "FontKorean", nullptr}, + {0x0100000000000813, "FontChineseTraditional", nullptr}, + {0x0100000000000814, "FontChineseSimple", nullptr}, + {0x0100000000000815, "FontBfcpx", nullptr}, + {0x0100000000000816, "SystemUpdate", nullptr}, + {0x0100000000000817, "0100000000000817", nullptr}, + {0x0100000000000818, "FirmwareDebugSettings", nullptr}, + {0x0100000000000819, "BootImagePackage", nullptr}, + {0x010000000000081A, "BootImagePackageSafe", nullptr}, + {0x010000000000081B, "BootImagePackageExFat", nullptr}, + {0x010000000000081C, "BootImagePackageExFatSafe", nullptr}, + {0x010000000000081D, "FatalMessage", nullptr}, + {0x010000000000081E, "ControllerIcon", nullptr}, + {0x010000000000081F, "PlatformConfigIcosa", nullptr}, + {0x0100000000000820, "PlatformConfigCopper", nullptr}, + {0x0100000000000821, "PlatformConfigHoag", nullptr}, + {0x0100000000000822, "ControllerFirmware", nullptr}, + {0x0100000000000823, "NgWord2", nullptr}, + {0x0100000000000824, "PlatformConfigIcosaMariko", nullptr}, + {0x0100000000000825, "ApplicationBlackList", nullptr}, + {0x0100000000000826, "RebootlessSystemUpdateVersion", nullptr}, + {0x0100000000000827, "ContentActionTable", nullptr}, +}}; + +VirtualFile SynthesizeSystemArchive(const u64 title_id) { + if (title_id < SYSTEM_ARCHIVES.front().title_id || title_id > SYSTEM_ARCHIVES.back().title_id) + return nullptr; + + const auto& desc = SYSTEM_ARCHIVES[title_id - SYSTEM_ARCHIVE_BASE_TITLE_ID]; + + LOG_INFO(Service_FS, "Synthesizing system archive '{}' (0x{:016X}).", desc.name, desc.title_id); + + if (desc.supplier == nullptr) + return nullptr; + + const auto dir = desc.supplier(); + + if (dir == nullptr) + return nullptr; + + const auto romfs = CreateRomFS(dir); + + if (romfs == nullptr) + return nullptr; + + LOG_INFO(Service_FS, " - System archive generation successful!"); + return romfs; +} +} // namespace FileSys::SystemArchive diff --git a/src/core/file_sys/system_archive/system_archive.h b/src/core/file_sys/system_archive/system_archive.h new file mode 100644 index 000000000..724a8eb17 --- /dev/null +++ b/src/core/file_sys/system_archive/system_archive.h @@ -0,0 +1,14 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" +#include "core/file_sys/vfs_types.h" + +namespace FileSys::SystemArchive { + +VirtualFile SynthesizeSystemArchive(u64 title_id); + +} // namespace FileSys::SystemArchive diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp index 808f31e81..515626658 100644 --- a/src/core/file_sys/vfs_vector.cpp +++ b/src/core/file_sys/vfs_vector.cpp @@ -3,7 +3,6 @@ // Refer to the license.txt file included. #include <algorithm> -#include <cstring> #include <utility> #include "core/file_sys/vfs_vector.h" diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h index 3e3f790c3..ac36cb2ee 100644 --- a/src/core/file_sys/vfs_vector.h +++ b/src/core/file_sys/vfs_vector.h @@ -4,10 +4,63 @@ #pragma once +#include <cstring> #include "core/file_sys/vfs.h" namespace FileSys { +// An implementation of VfsFile that is backed by a statically-sized array +template <std::size_t size> +class ArrayVfsFile : public VfsFile { +public: + ArrayVfsFile(std::array<u8, size> data, std::string name = "", VirtualDir parent = nullptr) + : data(data), name(std::move(name)), parent(std::move(parent)) {} + + std::string GetName() const override { + return name; + } + + std::size_t GetSize() const override { + return size; + } + + bool Resize(std::size_t new_size) override { + return false; + } + + std::shared_ptr<VfsDirectory> GetContainingDirectory() const override { + return parent; + } + + bool IsWritable() const override { + return false; + } + + bool IsReadable() const override { + return true; + } + + std::size_t Read(u8* data_, std::size_t length, std::size_t offset) const override { + const auto read = std::min(length, size - offset); + std::memcpy(data_, data.data() + offset, read); + return read; + } + + std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override { + return 0; + } + + bool Rename(std::string_view name) override { + this->name = name; + return true; + } + +private: + std::array<u8, size> data; + std::string name; + VirtualDir parent; +}; + // An implementation of VfsFile that is backed by a vector optionally supplied upon construction class VectorVfsFile : public VfsFile { public: diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 812b32005..e6c77f9db 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -35,7 +35,6 @@ #include "core/hle/lock.h" #include "core/hle/result.h" #include "core/hle/service/service.h" -#include "core/settings.h" namespace Kernel { namespace { @@ -1598,6 +1597,34 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss return RESULT_SUCCESS; } +static ResultCode CreateEvent(Handle* write_handle, Handle* read_handle) { + LOG_DEBUG(Kernel_SVC, "called"); + + auto& kernel = Core::System::GetInstance().Kernel(); + const auto [readable_event, writable_event] = + WritableEvent::CreateEventPair(kernel, ResetType::Sticky, "CreateEvent"); + + HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); + + const auto write_create_result = handle_table.Create(writable_event); + if (write_create_result.Failed()) { + return write_create_result.Code(); + } + *write_handle = *write_create_result; + + const auto read_create_result = handle_table.Create(readable_event); + if (read_create_result.Failed()) { + handle_table.Close(*write_create_result); + return read_create_result.Code(); + } + *read_handle = *read_create_result; + + LOG_DEBUG(Kernel_SVC, + "successful. Writable event handle=0x{:08X}, Readable event handle=0x{:08X}", + *write_create_result, *read_create_result); + return RESULT_SUCCESS; +} + static ResultCode ClearEvent(Handle handle) { LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle); @@ -1619,6 +1646,21 @@ static ResultCode ClearEvent(Handle handle) { return ERR_INVALID_HANDLE; } +static ResultCode SignalEvent(Handle handle) { + LOG_DEBUG(Kernel_SVC, "called. Handle=0x{:08X}", handle); + + HandleTable& handle_table = Core::CurrentProcess()->GetHandleTable(); + auto writable_event = handle_table.Get<WritableEvent>(handle); + + if (!writable_event) { + LOG_ERROR(Kernel_SVC, "Non-existent writable event handle used (0x{:08X})", handle); + return ERR_INVALID_HANDLE; + } + + writable_event->Signal(); + return RESULT_SUCCESS; +} + static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) { LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, type); @@ -1754,7 +1796,7 @@ static const FunctionDef SVC_Table[] = { {0x0E, SvcWrap<GetThreadCoreMask>, "GetThreadCoreMask"}, {0x0F, SvcWrap<SetThreadCoreMask>, "SetThreadCoreMask"}, {0x10, SvcWrap<GetCurrentProcessorNumber>, "GetCurrentProcessorNumber"}, - {0x11, nullptr, "SignalEvent"}, + {0x11, SvcWrap<SignalEvent>, "SignalEvent"}, {0x12, SvcWrap<ClearEvent>, "ClearEvent"}, {0x13, SvcWrap<MapSharedMemory>, "MapSharedMemory"}, {0x14, SvcWrap<UnmapSharedMemory>, "UnmapSharedMemory"}, @@ -1806,7 +1848,7 @@ static const FunctionDef SVC_Table[] = { {0x42, nullptr, "ReplyAndReceiveLight"}, {0x43, nullptr, "ReplyAndReceive"}, {0x44, nullptr, "ReplyAndReceiveWithUserBuffer"}, - {0x45, nullptr, "CreateEvent"}, + {0x45, SvcWrap<CreateEvent>, "CreateEvent"}, {0x46, nullptr, "Unknown"}, {0x47, nullptr, "Unknown"}, {0x48, nullptr, "MapPhysicalMemoryUnsafe"}, diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index fa1116624..24aef46c9 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -59,6 +59,19 @@ void SvcWrap() { FuncReturn(retval); } +template <ResultCode func(u32*, u32*)> +void SvcWrap() { + u32 param_1 = 0; + u32 param_2 = 0; + const u32 retval = func(¶m_1, ¶m_2).raw; + + auto& arm_interface = Core::CurrentArmInterface(); + arm_interface.SetReg(1, param_1); + arm_interface.SetReg(2, param_2); + + FuncReturn(retval); +} + template <ResultCode func(u32*, u64)> void SvcWrap() { u32 param_1 = 0; diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 694ec40ec..d2ffd5776 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -20,6 +20,7 @@ #include "core/file_sys/nca_metadata.h" #include "core/file_sys/patch_manager.h" #include "core/file_sys/savedata_factory.h" +#include "core/file_sys/system_archive/system_archive.h" #include "core/file_sys/vfs.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/process.h" @@ -831,6 +832,15 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) { auto data = OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data); if (data.Failed()) { + const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id); + + if (archive != nullptr) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface(std::make_shared<IStorage>(archive)); + return; + } + // TODO(DarkLordZach): Find the right error code to use here LOG_ERROR(Service_FS, "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id, diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp index 1edc60df7..9fd074223 100644 --- a/src/yuzu/game_list_worker.cpp +++ b/src/yuzu/game_list_worker.cpp @@ -86,6 +86,35 @@ QString FormatPatchNameVersions(const FileSys::PatchManager& patch_manager, out.chop(1); return out; } + +QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::string& name, + const std::vector<u8>& icon, Loader::AppLoader& loader, + u64 program_id, const CompatibilityList& compatibility_list, + const FileSys::PatchManager& patch) { + const auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); + + // The game list uses this as compatibility number for untested games + QString compatibility{"99"}; + if (it != compatibility_list.end()) { + compatibility = it->second.first; + } + + QList<QStandardItem*> list{ + new GameListItemPath( + FormatGameName(path), icon, QString::fromStdString(name), + QString::fromStdString(Loader::GetFileTypeString(loader.GetFileType())), program_id), + new GameListItemCompat(compatibility), + new GameListItem(QString::fromStdString(Loader::GetFileTypeString(loader.GetFileType()))), + new GameListItemSize(FileUtil::GetSize(path)), + }; + + if (UISettings::values.show_add_ons) { + list.insert( + 2, new GameListItem(FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable()))); + } + + return list; +} } // Anonymous namespace GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs, QString dir_path, bool deep_scan, @@ -116,29 +145,8 @@ void GameListWorker::AddInstalledTitlesToGameList() { if (control != nullptr) GetMetadataFromControlNCA(patch, *control, icon, name); - auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); - - // The game list uses this as compatibility number for untested games - QString compatibility("99"); - if (it != compatibility_list.end()) - compatibility = it->second.first; - - QList<QStandardItem*> list{ - new GameListItemPath( - FormatGameName(file->GetFullPath()), icon, QString::fromStdString(name), - QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())), - program_id), - new GameListItemCompat(compatibility), - new GameListItem( - QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))), - new GameListItemSize(file->GetSize()), - }; - - if (UISettings::values.show_add_ons) { - list.insert(2, new GameListItem(FormatPatchNameVersions(patch, *loader))); - } - - emit EntryReady(list); + emit EntryReady(MakeGameListEntry(file->GetFullPath(), name, icon, *loader, program_id, + compatibility_list, patch)); } const auto control_data = cache.ListEntriesFilter(FileSys::TitleType::Application, @@ -155,14 +163,14 @@ void GameListWorker::AddInstalledTitlesToGameList() { void GameListWorker::FillControlMap(const std::string& dir_path) { const auto nca_control_callback = [this](u64* num_entries_out, const std::string& directory, const std::string& virtual_name) -> bool { - std::string physical_name = directory + DIR_SEP + virtual_name; - - if (stop_processing) - return false; // Breaks the callback loop. + if (stop_processing) { + // Breaks the callback loop + return false; + } - bool is_dir = FileUtil::IsDirectory(physical_name); - QFileInfo file_info(physical_name.c_str()); - if (!is_dir && file_info.suffix().toStdString() == "nca") { + const std::string physical_name = directory + DIR_SEP + virtual_name; + const QFileInfo file_info(QString::fromStdString(physical_name)); + if (!file_info.isDir() && file_info.suffix() == QStringLiteral("nca")) { auto nca = std::make_unique<FileSys::NCA>(vfs->OpenFile(physical_name, FileSys::Mode::Read)); if (nca->GetType() == FileSys::NCAContentType::Control) { @@ -179,12 +187,13 @@ void GameListWorker::FillControlMap(const std::string& dir_path) { void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) { const auto callback = [this, recursion](u64* num_entries_out, const std::string& directory, const std::string& virtual_name) -> bool { - std::string physical_name = directory + DIR_SEP + virtual_name; - - if (stop_processing) - return false; // Breaks the callback loop. + if (stop_processing) { + // Breaks the callback loop. + return false; + } - bool is_dir = FileUtil::IsDirectory(physical_name); + const std::string physical_name = directory + DIR_SEP + virtual_name; + const bool is_dir = FileUtil::IsDirectory(physical_name); if (!is_dir && (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { std::unique_ptr<Loader::AppLoader> loader = @@ -214,30 +223,8 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign } } - auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); - - // The game list uses this as compatibility number for untested games - QString compatibility("99"); - if (it != compatibility_list.end()) - compatibility = it->second.first; - - QList<QStandardItem*> list{ - new GameListItemPath( - FormatGameName(physical_name), icon, QString::fromStdString(name), - QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())), - program_id), - new GameListItemCompat(compatibility), - new GameListItem( - QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))), - new GameListItemSize(FileUtil::GetSize(physical_name)), - }; - - if (UISettings::values.show_add_ons) { - list.insert(2, new GameListItem(FormatPatchNameVersions( - patch, *loader, loader->IsRomFSUpdatable()))); - } - - emit EntryReady(std::move(list)); + emit EntryReady(MakeGameListEntry(physical_name, name, icon, *loader, program_id, + compatibility_list, patch)); } else if (is_dir && recursion > 0) { watch_list.append(QString::fromStdString(physical_name)); AddFstEntriesToGameList(physical_name, recursion - 1); |