int main(int argc, char **argv) { int ret = EXIT_SUCCESS; int opt; kga_init(); set_signal_handler(SIGHUP, interrupted); set_signal_handler(SIGINT, interrupted); set_signal_handler(SIGTERM, interrupted); try_scope { while ((opt = getopt(argc, argv, "r:d:ti")) != -1) { switch(opt) { case 'i': pkg_confirm = common_confirm; break; case 'r': root = optarg; break; case 'd': db_path = optarg; break; default: throw(pkg_main_incorrect_cmd, 1, "unknown option", NULL); break; }; }; int real_argc = argc - optind; char **real_argv = &argv[optind]; if (!real_argc) { throw(pkg_main_incorrect_cmd, 1, "no subcommand", NULL); } else if (!strcmp(real_argv[0], "install")) { if (real_argc != 2) { throw(pkg_main_incorrect_cmd, 1, "incorrect subcommand", NULL); }; pkg_install(real_argv[1], root, db_path, 0, stderr); } else if (!strcmp(real_argv[0], "upgrade")) { if (real_argc != 2) { throw(pkg_main_incorrect_cmd, 1, "incorrect subcommand", NULL); }; pkg_install(real_argv[1], root, db_path, PKG_UPGRADE, stderr); } else if (!strcmp(real_argv[0], "drop")) { if (real_argc < 2 || real_argc > 3) { throw(pkg_main_incorrect_cmd, 1, "incorrect subcommand", NULL); }; char *slash; if ((slash = strchr(real_argv[1], '/'))) { *slash = '\0'; pkg_drop(root, db_path, real_argv[1], &slash[1], stderr); } else { pkg_drop(root, db_path, real_argv[1], real_argc == 2 ? NULL : real_argv[2], stderr); } } else { throw(pkg_main_incorrect_cmd, 1, "unknown subcommand", NULL); }; }; catch { if (exception()->type == &pkg_main_incorrect_cmd) {
void MainFrame::InstallPkg(wxCommandEvent& WXUNUSED(event)) { const bool paused = Emu.Pause(); wxFileDialog ctrl(this, L"Select PKG", wxEmptyString, wxEmptyString, "PKG files (*.pkg)|*.pkg|All files (*.*)|*.*", wxFD_OPEN | wxFD_FILE_MUST_EXIST); if (ctrl.ShowModal() == wxID_CANCEL) { if (paused) Emu.Resume(); return; } Emu.Stop(); // Open PKG file fs::file pkg_f(ctrl.GetPath().ToStdString()); if (!pkg_f || pkg_f.size() < 64) { LOG_ERROR(LOADER, "PKG: Failed to open %s", ctrl.GetPath().ToStdString()); return; } // Get title ID std::vector<char> title_id(9); pkg_f.seek(55); pkg_f.read(title_id); pkg_f.seek(0); // Get full path const auto& local_path = Emu.GetGameDir() + std::string(std::begin(title_id), std::end(title_id)); if (!fs::create_dir(local_path)) { if (fs::is_dir(local_path)) { if (wxMessageDialog(this, "Another installation found. Do you want to overwrite it?", "PKG Decrypter / Installer", wxYES_NO | wxCENTRE).ShowModal() != wxID_YES) { LOG_ERROR(LOADER, "PKG: Cancelled installation to existing directory %s", local_path); return; } } else { LOG_ERROR(LOADER, "PKG: Could not create the installation directory %s", local_path); return; } } wxProgressDialog pdlg("PKG Installer", "Please wait, unpacking...", 1000, this, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT); // Synchronization variable atomic_t<double> progress(0.); { // Run PKG unpacking asynchronously scope_thread worker("PKG Installer", [&] { if (pkg_install(pkg_f, local_path + '/', progress)) { progress = 1.; return_; } // TODO: Ask user to delete files on cancellation/failure? progress = -1.; }); // Wait for the completion while (std::this_thread::sleep_for(5ms), std::abs(progress) < 1.) { // Update progress window if (!pdlg.Update(static_cast<int>(progress * pdlg.GetRange()))) { // Installation cancelled (signal with negative value) progress -= 1.; break; } } if (progress > 0.) { pdlg.Update(pdlg.GetRange()); std::this_thread::sleep_for(100ms); } } pdlg.Close(); if (progress >= 1.) { // Refresh game list m_game_viewer->Refresh(); } }
void MainFrame::InstallPkg(wxCommandEvent& WXUNUSED(event)) { const bool was_running = Emu.Pause(); wxFileDialog ctrl(this, L"Select PKG", wxEmptyString, wxEmptyString, "PKG files (*.pkg)|*.pkg|All files (*.*)|*.*", wxFD_OPEN | wxFD_FILE_MUST_EXIST); if (ctrl.ShowModal() == wxID_CANCEL) { if (was_running) Emu.Resume(); return; } Emu.Stop(); Emu.GetVFS().Init("/"); std::string local_path; Emu.GetVFS().GetDevice("/dev_hdd0/game/", local_path); // Open PKG file fs::file pkg_f(ctrl.GetPath().ToStdString()); // Open file mapping (test) fs::file_ptr pkg_ptr(pkg_f); if (!pkg_f || !pkg_ptr) { LOG_ERROR(LOADER, "PKG: Failed to open %s", ctrl.GetPath().ToStdString()); return; } // Append title ID to the path local_path += '/'; local_path += { pkg_ptr + 55, 9 }; if (!fs::create_dir(local_path)) { if (fs::is_dir(local_path)) { if (wxMessageDialog(this, "Another installation found. Do you want to overwrite it?", "PKG Decrypter / Installer", wxYES_NO | wxCENTRE).ShowModal() != wxID_YES) { LOG_ERROR(LOADER, "PKG: Cancelled installation to existing directory %s", local_path); return; } } else { LOG_ERROR(LOADER, "PKG: Could not create the installation directory %s", local_path); return; } } wxProgressDialog pdlg("PKG Decrypter / Installer", "Please wait, unpacking...", 1000, this, wxPD_AUTO_HIDE | wxPD_APP_MODAL); volatile f64 progress = 0.0; // Run PKG unpacking asynchronously auto result = std::async(std::launch::async, WRAP_EXPR(pkg_install(pkg_f, local_path + "/", progress))); // Wait for the completion while (result.wait_for(15ms) != std::future_status::ready) { // Update progress window pdlg.Update(progress * pdlg.GetRange()); // Update main frame Update(); wxGetApp().ProcessPendingEvents(); } pdlg.Close(); if (result.get()) { LOG_SUCCESS(LOADER, "PKG: Package successfully installed in %s", local_path); // Refresh game list m_game_viewer->Refresh(); } }