diff --git a/rpcs3/Crypto/unpkg.h b/rpcs3/Crypto/unpkg.h index 3ac43758d1..5dbe1203f5 100644 --- a/rpcs3/Crypto/unpkg.h +++ b/rpcs3/Crypto/unpkg.h @@ -305,6 +305,7 @@ public: package_reader(const std::string& path); ~package_reader(); + bool is_valid() const { return m_is_valid; } package_error check_target_app_version(); bool extract_data(atomic_t& sync); psf::registry get_psf() const { return m_psf; } diff --git a/rpcs3/main.cpp b/rpcs3/main.cpp index eb940f8689..f850a39be3 100644 --- a/rpcs3/main.cpp +++ b/rpcs3/main.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "rpcs3qt/gui_application.h" #include "rpcs3qt/fatal_error_dialog.h" @@ -207,6 +208,7 @@ constexpr auto arg_q_debug = "qDebug"; constexpr auto arg_error = "error"; constexpr auto arg_updating = "updating"; constexpr auto arg_installfw = "installfw"; +constexpr auto arg_installpkg = "installpkg"; constexpr auto arg_commit_db = "get-commit-db"; int find_arg(std::string arg, int& argc, char* argv[]) @@ -511,6 +513,8 @@ int main(int argc, char** argv) parser.addOption(config_option); const QCommandLineOption installfw_option(arg_installfw, "Forces the emulator to install this firmware file.", "path", ""); parser.addOption(installfw_option); + const QCommandLineOption installpkg_option(arg_installpkg, "Forces the emulator to install this pkg file.", "path", ""); + parser.addOption(installpkg_option); parser.addOption(QCommandLineOption(arg_q_debug, "Log qDebug to RPCS3.log.")); parser.addOption(QCommandLineOption(arg_error, "For internal usage.")); parser.addOption(QCommandLineOption(arg_updating, "For internal usage.")); @@ -769,32 +773,41 @@ int main(int argc, char** argv) Emu.SetConfigOverride(config_override_path); } - std::string firmware_path; - - // Force install firmware first if specified through command-line - if (parser.isSet(arg_installfw)) + // Force install firmware or pkg first if specified through command-line + if (parser.isSet(arg_installfw) || parser.isSet(arg_installpkg)) { if (auto gui_app = qobject_cast(app.data())) { if (s_no_gui) { - report_fatal_error("Cannot install firmware in no-gui mode!"); + report_fatal_error("Cannot perform installation in no-gui mode!"); return 1; } if (gui_app->m_main_window) { - gui_app->m_main_window->HandlePupInstallation(parser.value(installfw_option)); + if (parser.isSet(arg_installfw) && parser.isSet(arg_installpkg)) + { + QMessageBox::warning(gui_app->m_main_window, QObject::tr("Invalid command-line arguments!"), QObject::tr("Cannot perform multiple installations at the same time!")); + } + else if (parser.isSet(arg_installfw)) + { + gui_app->m_main_window->InstallPup(parser.value(installfw_option)); + } + else + { + gui_app->m_main_window->InstallPackages({parser.value(installpkg_option)}); + } } else { - report_fatal_error("Cannot install firmware. No main window found!"); + report_fatal_error("Cannot perform installation. No main window found!"); return 1; } } else { - report_fatal_error("Cannot install firmware in headless mode!"); + report_fatal_error("Cannot perform installation in headless mode!"); return 1; } } @@ -804,7 +817,7 @@ int main(int argc, char** argv) sys_log.notice("Option passed via command line: %s %s", opt.toStdString(), parser.value(opt).toStdString()); } - if (const QStringList args = parser.positionalArguments(); !args.isEmpty() && !is_updating && !parser.isSet(arg_installfw)) + if (const QStringList args = parser.positionalArguments(); !args.isEmpty() && !is_updating && !parser.isSet(arg_installfw) && !parser.isSet(arg_installpkg)) { sys_log.notice("Booting application from command line: %s", args.at(0).toStdString()); diff --git a/rpcs3/rpcs3qt/game_compatibility.cpp b/rpcs3/rpcs3qt/game_compatibility.cpp index 2fa98c7dfb..2860132047 100644 --- a/rpcs3/rpcs3qt/game_compatibility.cpp +++ b/rpcs3/rpcs3qt/game_compatibility.cpp @@ -247,14 +247,21 @@ compat::status game_compatibility::GetStatusData(const QString& status) compat::package_info game_compatibility::GetPkgInfo(const QString& pkg_path, game_compatibility* compat) { + compat::package_info info; + package_reader reader(pkg_path.toStdString()); + if (!reader.is_valid()) + { + info.is_valid = false; + return info; + } + psf::registry psf = reader.get_psf(); // TODO: localization of title and changelog std::string title_key = "TITLE"; std::string changelog_key = "paramhip"; - compat::package_info info; info.path = pkg_path; info.title = qstr(std::string(psf::get_string(psf, title_key))); // Let's read this from the psf first info.title_id = qstr(std::string(psf::get_string(psf, "TITLE_ID"))); diff --git a/rpcs3/rpcs3qt/game_compatibility.h b/rpcs3/rpcs3qt/game_compatibility.h index 802702c55d..9d73521b34 100644 --- a/rpcs3/rpcs3qt/game_compatibility.h +++ b/rpcs3/rpcs3qt/game_compatibility.h @@ -100,6 +100,8 @@ namespace compat /** Concicely represents a specific pkg's localized information for use in the GUI */ struct package_info { + bool is_valid = true; + QString path; // File path QString title_id; // TEST12345 QString title; // Localized diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 921cc004e2..25e5915276 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -557,12 +557,18 @@ void main_window::InstallPackages(QStringList file_paths) } else if (file_paths.count() == 1) { - // This can currently only happen by drag and drop. + // This can currently only happen by drag and drop and cli arg. const QString file_path = file_paths.front(); const QFileInfo file_info(file_path); compat::package_info info = game_compatibility::GetPkgInfo(file_path, m_game_list_frame ? m_game_list_frame->GetGameCompatibility() : nullptr); + if (!info.is_valid) + { + QMessageBox::warning(this, QObject::tr("Invalid package!"), QObject::tr("The selected package is invalid!\n\nPath:\n%0").arg(file_path)); + return; + } + if (info.type != compat::package_type::other) { if (info.type == compat::package_type::dlc) @@ -634,6 +640,11 @@ void main_window::InstallPackages(QStringList file_paths) void main_window::HandlePackageInstallation(QStringList file_paths) { + if (file_paths.empty()) + { + return; + } + std::vector packages; game_compatibility* compat = m_game_list_frame ? m_game_list_frame->GetGameCompatibility() : nullptr; diff --git a/rpcs3/rpcs3qt/main_window.h b/rpcs3/rpcs3qt/main_window.h index 676a52079f..9ca075898d 100644 --- a/rpcs3/rpcs3qt/main_window.h +++ b/rpcs3/rpcs3qt/main_window.h @@ -85,7 +85,8 @@ public: bool Init(); QIcon GetAppIcon(); bool OnMissingFw(); - void HandlePupInstallation(QString file_path, QString dir_path = ""); + void InstallPackages(QStringList file_paths = QStringList()); + void InstallPup(QString filePath = ""); Q_SIGNALS: void RequestLanguageChange(const QString& language); @@ -141,10 +142,9 @@ private: static bool InstallRapFile(const QString& path, const std::string& filename); - void InstallPackages(QStringList file_paths = QStringList()); void HandlePackageInstallation(QStringList file_paths); - void InstallPup(QString filePath = ""); + void HandlePupInstallation(QString file_path, QString dir_path = ""); void ExtractPup(); void ExtractTar(); diff --git a/rpcs3/rpcs3qt/pkg_install_dialog.cpp b/rpcs3/rpcs3qt/pkg_install_dialog.cpp index a4694af316..8ca5d6e782 100644 --- a/rpcs3/rpcs3qt/pkg_install_dialog.cpp +++ b/rpcs3/rpcs3qt/pkg_install_dialog.cpp @@ -28,6 +28,11 @@ pkg_install_dialog::pkg_install_dialog(const QStringList& paths, game_compatibil for (const QString& path : paths) { const compat::package_info info = game_compatibility::GetPkgInfo(path, compat); + if (!info.is_valid) + { + continue; + } + const QFileInfo file_info(path); // We have to build our complicated localized string in some annoying manner