diff --git a/src/core/importer.cpp b/src/core/importer.cpp index db124f9..087c7ce 100644 --- a/src/core/importer.cpp +++ b/src/core/importer.cpp @@ -142,8 +142,6 @@ bool SDMCImporter::ImportContentImpl(const ContentSpecifier& specifier, } else { return ImportNandExtdata(specifier.id, callback); } - case ContentType::SystemArchive: - return ImportSystemArchive(specifier.id, callback); case ContentType::Sysdata: return ImportSysdata(specifier.id, callback); case ContentType::SystemTitle: @@ -299,30 +297,6 @@ bool SDMCImporter::ImportNandExtdata(u64 id, "data/00000000000000000000000000000000/" + path); } -bool SDMCImporter::ImportSystemArchive(u64 id, - [[maybe_unused]] const Common::ProgressCallback& callback) { - const auto path = fmt::format("{}{:08x}/{:08x}.app", config.system_archives_path, (id >> 32), - (id & 0xFFFFFFFF)); - FileUtil::IOFile file(path, "rb"); - std::vector data = file.GetData(); - if (data.empty()) { - LOG_ERROR(Core, "Failed to read from {}", path); - return false; - } - - const auto& romfs = LoadSharedRomFS(data); - - const auto target_path = fmt::format( - "{}00000000000000000000000000000000/title/{:08x}/{:08x}/content/00000000.app.romfs", - FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), (id >> 32), (id & 0xFFFFFFFF)); - if (!FileUtil::CreateFullPath(target_path)) { - LOG_ERROR(Core, "Could not create path {}", target_path); - return false; - } - - return FileUtil::WriteBytesToFile(target_path, romfs.data(), romfs.size()); -} - bool SDMCImporter::ImportSysdata(u64 id, [[maybe_unused]] const Common::ProgressCallback& callback) { switch (id) { @@ -334,36 +308,6 @@ bool SDMCImporter::ImportSysdata(u64 id, } return FileUtil::Copy(config.bootrom_path, target_path); } - case 1: { // safe mode firm - // Our GM9 script dumps to different folders for different version (new/old) - std::string real_path; - bool is_new_3ds = false; - if (FileUtil::Exists(config.safe_mode_firm_path + "new/")) { - real_path = config.safe_mode_firm_path + "new/"; - is_new_3ds = true; - } else { - real_path = config.safe_mode_firm_path + "old/"; - } - return FileUtil::ForeachDirectoryEntry( - nullptr, real_path, - [is_new_3ds](u64* /*num_entries_out*/, const std::string& directory, - const std::string& virtual_name) { - if (FileUtil::IsDirectory(directory + virtual_name)) { - return true; - } - - const auto target_path = - fmt::format("{}00000000000000000000000000000000/title/00040138/{}/content/{}", - FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), - (is_new_3ds ? "20000003" : "00000003"), virtual_name); - - if (!FileUtil::CreateFullPath(target_path)) { - return false; - } - - return FileUtil::Copy(directory + virtual_name, target_path); - }); - } case 2: { // seed db const auto target_path = FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir) + SEED_DB; LOG_INFO(Core, "Dumping SeedDB from {} to {}", SEED_DB, config.seed_db_path, target_path); @@ -453,7 +397,6 @@ std::vector SDMCImporter::ListContent() const { ListNandTitle(content_list); ListNandSavegame(content_list); ListExtdata(content_list); - ListSystemArchive(content_list); ListSysdata(content_list); return content_list; } @@ -558,11 +501,24 @@ std::shared_ptr SDMCImporter::OpenContent(const ContentSpecifi using TitleData = std::tuple>; static TitleData LoadTitleData(NCCHContainer& ncch) { - std::string codeset_name; - ncch.ReadCodesetName(codeset_name); + static const std::unordered_map NamedTitles{{ + {0x0004009b'00010202, "Mii Data"}, + {0x0004009b'00010402, "Region Manifest"}, + {0x0004009b'00014002, "Shared Font (JPN/EUR/USA)"}, + {0x0004009b'00014102, "Shared Font (CHN)"}, + {0x0004009b'00014202, "Shared Font (KOR)"}, + {0x0004009b'00014302, "Shared Font (TWN)"}, + {0x000400db'00010302, "Bad word list"}, + }}; u64 program_id{}; ncch.ReadProgramId(program_id); + if (NamedTitles.count(program_id)) { + return TitleData{NamedTitles.at(program_id), 0, {}}; + } + + std::string codeset_name; + ncch.ReadCodesetName(codeset_name); std::string title_name_from_codeset; if (!codeset_name.empty()) { @@ -983,8 +939,10 @@ void SDMCImporter::ListNandTitle(std::vector& out) const { ProcessDirectory(0x00040010); ProcessDirectory(0x0004001b); ProcessDirectory(0x00040030); + ProcessDirectory(0x0004009b); ProcessDirectory(0x000400db); ProcessDirectory(0x00040130); + ProcessDirectory(0x00040138); } void SDMCImporter::ListNandSavegame(std::vector& out) const { @@ -1059,30 +1017,6 @@ void SDMCImporter::ListExtdata(std::vector& out) const { "data/00000000000000000000000000000000/extdata/00048000/{}"); } -void SDMCImporter::ListSystemArchive(std::vector& out) const { - constexpr std::array, 8> SystemArchives{{ - {0x0004009b'00010202, "Mii Data"}, - {0x0004009b'00010402, "Region Manifest"}, - {0x0004009b'00014002, "Shared Font (JPN/EUR/USA)"}, - {0x0004009b'00014102, "Shared Font (CHN)"}, - {0x0004009b'00014202, "Shared Font (KOR)"}, - {0x0004009b'00014302, "Shared Font (TWN)"}, - {0x000400db'00010302, "Bad word list"}, - }}; - - for (const auto& [id, name] : SystemArchives) { - const auto path = fmt::format("{}{:08x}/{:08x}.app", config.system_archives_path, - (id >> 32), (id & 0xFFFFFFFF)); - if (FileUtil::Exists(path)) { - const auto target_path = fmt::format( - "{}00000000000000000000000000000000/title/{:08x}/{:08x}/content/", - FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), (id >> 32), (id & 0xFFFFFFFF)); - out.push_back({ContentType::SystemArchive, id, FileUtil::Exists(target_path), - FileUtil::GetSize(path), name}); - } - } -} - void SDMCImporter::ListSysdata(std::vector& out) const { const auto CheckContent = [&out](u64 id, const std::string& var_path, const std::string& citra_path, @@ -1111,30 +1045,6 @@ void SDMCImporter::ListSysdata(std::vector& out) const { "Config savegame"); } - do { - if (config.safe_mode_firm_path.empty()) { - break; - } - - bool is_new = false; - if (FileUtil::Exists(config.safe_mode_firm_path + "new/")) { - is_new = true; - } - if (!is_new && !FileUtil::Exists(config.safe_mode_firm_path + "old/")) { - LOG_ERROR(Core, "Safe mode firm path specified but not found"); - break; - } - - const auto citra_path = fmt::format( - "{}00000000000000000000000000000000/title/00040138/{}/content/", - FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), (is_new ? "20000003" : "00000003")); - if (!config.safe_mode_firm_path.empty()) { - out.push_back({ContentType::Sysdata, 1, FileUtil::Exists(citra_path), - FileUtil::GetDirectoryTreeSize(config.safe_mode_firm_path), - "Safe mode firm"}); - } - } while (0); - // Check for seeddb if (config.seed_db_path.empty()) { return; @@ -1174,8 +1084,6 @@ void SDMCImporter::DeleteContent(const ContentSpecifier& specifier) const { return DeleteSavegame(specifier.id); case ContentType::Extdata: return DeleteExtdata(specifier.id); - case ContentType::SystemArchive: - return DeleteSystemArchive(specifier.id); case ContentType::Sysdata: return DeleteSysdata(specifier.id); case ContentType::SystemTitle: @@ -1228,25 +1136,11 @@ void SDMCImporter::DeleteExtdata(u64 id) const { } } -void SDMCImporter::DeleteSystemArchive(u64 id) const { - FileUtil::DeleteDirRecursively(fmt::format( - "{}00000000000000000000000000000000/title/{:08x}/{:08x}/content/", - FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), (id >> 32), (id & 0xFFFFFFFF))); -} - void SDMCImporter::DeleteSysdata(u64 id) const { switch (id) { case 0: { // boot9.bin FileUtil::Delete(FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir) + BOOTROM9); } - case 1: { // safe mode firm - const bool is_new_3ds = FileUtil::Exists(config.safe_mode_firm_path + "new/"); - const auto target_path = - fmt::format("{}00000000000000000000000000000000/title/00040138/{}/", - FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), - (is_new_3ds ? "20000003" : "00000003")); - FileUtil::DeleteDirRecursively(target_path); - } case 2: { // seed db FileUtil::Delete(FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir) + SEED_DB); } @@ -1291,11 +1185,9 @@ std::vector LoadPresetConfig(std::string mount_point) { LOAD_DATA(certs_db_path, CERTS_DB); LOAD_DATA(nand_title_db_path, TITLE_DB); LOAD_DATA(ticket_db_path, TICKET_DB); - LOAD_DATA(safe_mode_firm_path, "firm/"); LOAD_DATA(seed_db_path, SEED_DB); LOAD_DATA(secret_sector_path, SECRET_SECTOR); LOAD_DATA(config_savegame_path, "config.sav"); - LOAD_DATA(system_archives_path, "sysarchives/"); LOAD_DATA(system_titles_path, "title/"); LOAD_DATA(nand_data_path, "data/"); #undef LOAD_DATA diff --git a/src/core/importer.h b/src/core/importer.h index 7dcc1fc..dc3bee1 100644 --- a/src/core/importer.h +++ b/src/core/importer.h @@ -31,7 +31,6 @@ enum class ContentType { DLC, Savegame, Extdata, - SystemArchive, Sysdata, SystemTitle, SystemApplet, // This should belong to System Title, but they cause problems so a new category. @@ -75,20 +74,18 @@ struct Config { // Optional, used while building CIA, but usually missing these files won't hinder CIA building. std::string nand_title_db_path; ///< Path to NAND title.db. Entirely optional. std::string ticket_db_path; ///< Path to ticket.db. Entirely optional. - std::string enc_title_keys_bin_path; ///< Path to encTitleKeys.bin. Entireley optional. + std::string enc_title_keys_bin_path; ///< Path to encTitleKeys.bin. Entirely optional. // The following system files are optional for importing and are only copied so that Citra // will be able to decrypt imported encrypted ROMs. - std::string safe_mode_firm_path; ///< Path to safe mode firm (A folder) (Sysdata 1) - std::string seed_db_path; ///< Path to seeddb.bin (Sysdata 2) - std::string secret_sector_path; ///< Path to secret sector (New3DS only) (Sysdata 3) + std::string seed_db_path; ///< Path to seeddb.bin (Sysdata 2) + std::string secret_sector_path; ///< Path to secret sector (New3DS only) (Sysdata 3) // Note: Sysdata 4 is aes_keys.txt (slot0x25KeyX) std::string config_savegame_path; ///< Path to config savegame (Sysdata 5) - std::string system_archives_path; ///< Path to system archives. - std::string system_titles_path; ///< Path to system titles. - std::string nand_data_path; ///< Path to NAND data. (Extdata and savedata) + std::string system_titles_path; ///< Path to system titles. + std::string nand_data_path; ///< Path to NAND data. (Extdata and savedata) int version = 0; ///< Version of the dumper used. }; @@ -201,14 +198,12 @@ private: bool ImportNandSavegame(u64 id, const Common::ProgressCallback& callback); bool ImportExtdata(u64 id, const Common::ProgressCallback& callback); bool ImportNandExtdata(u64 id, const Common::ProgressCallback& callback); - bool ImportSystemArchive(u64 id, const Common::ProgressCallback& callback); bool ImportSysdata(u64 id, const Common::ProgressCallback& callback); void ListTitle(std::vector& out) const; void ListNandTitle(std::vector& out) const; void ListNandSavegame(std::vector& out) const; void ListExtdata(std::vector& out) const; - void ListSystemArchive(std::vector& out) const; void ListSysdata(std::vector& out) const; void DeleteContent(const ContentSpecifier& specifier) const; @@ -216,7 +211,6 @@ private: void DeleteNandTitle(u64 id) const; void DeleteSavegame(u64 id) const; void DeleteExtdata(u64 id) const; - void DeleteSystemArchive(u64 id) const; void DeleteSysdata(u64 id) const; bool is_good{}; diff --git a/src/frontend/import_dialog.cpp b/src/frontend/import_dialog.cpp index 0182365..79c5c9c 100644 --- a/src/frontend/import_dialog.cpp +++ b/src/frontend/import_dialog.cpp @@ -36,7 +36,6 @@ static constexpr std::array SpecialContentTypeList{{ - Core::ContentType::SystemArchive, +constexpr std::array SpecialContentTypeList{{ Core::ContentType::Sysdata, Core::ContentType::SystemTitle, Core::ContentType::SystemApplet, @@ -255,9 +253,8 @@ void ImportDialog::InsertSecondLevelItem(std::size_t row, const Core::ContentSpe content.type != Core::ContentType::SystemApplet) { icon = GetContentTypeIcon(content.type); } else { - // When not in title view, System Data and System Archive groups use category icons. - const bool use_category_icon = content.type == Core::ContentType::Sysdata || - content.type == Core::ContentType::SystemArchive; + // When not in title view, System Data groups use category icons. + const bool use_category_icon = content.type == Core::ContentType::Sysdata; icon = GetContentIcon(content, use_category_icon); } } else { @@ -296,8 +293,7 @@ void ImportDialog::OnItemChanged(QTreeWidgetItem* item, int column) { total_selected_size += specifier.maximum_size; } else { if (!system_warning_shown && !specifier.already_exists && - (specifier.type == Core::ContentType::SystemArchive || - specifier.type == Core::ContentType::Sysdata || + (specifier.type == Core::ContentType::Sysdata || specifier.type == Core::ContentType::SystemTitle)) { QMessageBox::warning(this, tr("Warning"), diff --git a/src/frontend/main.cpp b/src/frontend/main.cpp index 1f74aac..36c0566 100644 --- a/src/frontend/main.cpp +++ b/src/frontend/main.cpp @@ -36,6 +36,13 @@ bool IsConfigGood(const Core::Config& config) { !config.movable_sed_path.empty() && !config.bootrom_path.empty(); } +bool IsConfigComplete(const Core::Config& config) { + return IsConfigGood(config) && !config.certs_db_path.empty() && + !config.nand_title_db_path.empty() && !config.ticket_db_path.empty() && + !config.config_savegame_path.empty() && !config.system_titles_path.empty() && + !config.nand_data_path.empty(); +} + MainDialog::MainDialog(QWidget* parent) : DPIAwareDialog(parent, 640, 256), ui(std::make_unique()) { @@ -145,10 +152,7 @@ void MainDialog::LoadPresetConfig() { status = tr("No Configuration Found"); } else if (list[i].version != Core::CurrentDumperVersion) { status = tr("Version Dismatch"); - } else if (list[i].safe_mode_firm_path.empty() || - list[i].config_savegame_path.empty() || - list[i].system_archives_path.empty()) { - + } else if (!IsConfigComplete(list[i])) { status = tr("Missing System Files"); } else if (list[i].seed_db_path.empty()) { status = tr("Good, Missing Seeds"); @@ -217,8 +221,7 @@ void MainDialog::LaunchImportDialog() { return; } - if (config.safe_mode_firm_path.empty() || config.config_savegame_path.empty() || - config.system_archives_path.empty()) { + if (!IsConfigComplete(config)) { QMessageBox::warning( this, tr("Warning"), tr("Certain system files are missing from your configuration.
Some contents "