Пример #1
0
void GameList::UninstallWAD()
{
  const auto game = GetSelectedGame();
  if (!game)
    return;

  ModalMessageBox warning_dialog(this);

  warning_dialog.setIcon(QMessageBox::Information);
  warning_dialog.setWindowTitle(tr("Confirm"));
  warning_dialog.setText(tr("Uninstalling the WAD will remove the currently installed version of "
                            "this title from the NAND without deleting its save data. Continue?"));
  warning_dialog.setStandardButtons(QMessageBox::No | QMessageBox::Yes);

  if (warning_dialog.exec() == QMessageBox::No)
    return;

  ModalMessageBox result_dialog(this);

  const bool success = WiiUtils::UninstallTitle(game->GetTitleID());

  result_dialog.setIcon(success ? QMessageBox::Information : QMessageBox::Critical);
  result_dialog.setWindowTitle(success ? tr("Success") : tr("Failure"));
  result_dialog.setText(success ? tr("Successfully removed this title from the NAND.") :
                                  tr("Failed to remove this title from the NAND."));
  result_dialog.exec();
}
Пример #2
0
std::vector<u32> VolumeWAD::GetBanner(int* width, int* height) const
{
  *width = 0;
  *height = 0;

  const std::optional<u64> title_id = GetTitleID();
  if (!title_id)
    return std::vector<u32>();

  return GetWiiBanner(width, height, *title_id);
}
Пример #3
0
std::vector<u32> CVolumeWiiCrypted::GetBanner(int* width, int* height) const
{
  *width = 0;
  *height = 0;

  u64 title_id;
  if (!GetTitleID(&title_id))
    return std::vector<u32>();

  return GetWiiBanner(width, height, title_id);
}
Пример #4
0
void Emulator::Load()
{
	Stop();

	try
	{
		Init();

		if (!fs::is_file(m_path))
		{
			LOG_ERROR(LOADER, "File not found: %s", m_path);
			return;
		}

		const std::string& elf_dir = fs::get_parent_dir(m_path);

		if (IsSelf(m_path))
		{
			const std::size_t elf_ext_pos = m_path.find_last_of('.');
			const std::string& elf_ext = fmt::to_upper(m_path.substr(elf_ext_pos != -1 ? elf_ext_pos : m_path.size()));
			const std::string& elf_name = m_path.substr(elf_dir.size());

			if (elf_name.compare(elf_name.find_last_of("/\\", -1, 2) + 1, 9, "EBOOT.BIN", 9) == 0)
			{
				m_path.erase(m_path.size() - 9, 1); // change EBOOT.BIN to BOOT.BIN
			}
			else if (elf_ext == ".SELF" || elf_ext == ".SPRX")
			{
				m_path.erase(m_path.size() - 4, 1); // change *.self to *.elf, *.sprx to *.prx
			}
			else
			{
				m_path += ".decrypted.elf";
			}

			if (!DecryptSelf(m_path, elf_dir + elf_name))
			{
				LOG_ERROR(LOADER, "Failed to decrypt %s", elf_dir + elf_name);
				return;
			}
		}

		SetCPUThreadStop(0);

		LOG_NOTICE(LOADER, "Path: %s", m_path);

		// Load custom config
		if (fs::file cfg_file{ m_path + ".yml" })
		{
			LOG_NOTICE(LOADER, "Custom config: %s.yml", m_path);
			cfg::root.from_string(cfg_file.to_string());
		}

		const fs::file elf_file(m_path);
		ppu_exec_object ppu_exec;
		ppu_prx_object ppu_prx;
		spu_exec_object spu_exec;
		arm_exec_object arm_exec;

		if (!elf_file)
		{
			LOG_ERROR(LOADER, "Failed to open %s", m_path);
			return;
		}
		else if (ppu_exec.open(elf_file) == elf_error::ok)
		{
			// PS3 executable
			m_status = Ready;
			vm::ps3::init();

			if (m_elf_path.empty())
			{
				m_elf_path = "/host_root/" + m_path;
				LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path);
			}

			// Load PARAM.SFO
			const auto _psf = psf::load_object(fs::file(elf_dir + "/../PARAM.SFO"));
			m_title = psf::get_string(_psf, "TITLE", m_path);
			m_title_id = psf::get_string(_psf, "TITLE_ID");
			fs::get_data_dir(m_title_id, m_path);

			LOG_NOTICE(LOADER, "Title: %s", GetTitle());
			LOG_NOTICE(LOADER, "Serial: %s", GetTitleID());

			// Mount all devices
			const std::string& emu_dir_ = g_cfg_vfs_emulator_dir;
			const std::string& emu_dir = emu_dir_.empty() ? fs::get_executable_dir() : emu_dir_;
			const std::string& bdvd_dir = g_cfg_vfs_dev_bdvd;
			const std::string& home_dir = g_cfg_vfs_app_home;

			vfs::mount("dev_hdd0", fmt::replace_all(g_cfg_vfs_dev_hdd0, "$(EmulatorDir)", emu_dir));
			vfs::mount("dev_hdd1", fmt::replace_all(g_cfg_vfs_dev_hdd1, "$(EmulatorDir)", emu_dir));
			vfs::mount("dev_flash", fmt::replace_all(g_cfg_vfs_dev_flash, "$(EmulatorDir)", emu_dir));
			vfs::mount("dev_usb", fmt::replace_all(g_cfg_vfs_dev_usb000, "$(EmulatorDir)", emu_dir));
			vfs::mount("dev_usb000", fmt::replace_all(g_cfg_vfs_dev_usb000, "$(EmulatorDir)", emu_dir));
			vfs::mount("app_home", home_dir.empty() ? elf_dir + '/' : fmt::replace_all(home_dir, "$(EmulatorDir)", emu_dir));

			// Mount /dev_bdvd/ if necessary
			if (bdvd_dir.empty() && fs::is_file(elf_dir + "/../../PS3_DISC.SFB"))
			{
				const auto dir_list = fmt::split(elf_dir, { "/", "\\" });

				// Check latest two directories
				if (dir_list.size() >= 2 && dir_list.back() == "USRDIR" && *(dir_list.end() - 2) == "PS3_GAME")
				{
					vfs::mount("dev_bdvd", elf_dir.substr(0, elf_dir.length() - 15));
				}
				else
				{
					vfs::mount("dev_bdvd", elf_dir + "/../../");
				}

				LOG_NOTICE(LOADER, "Disc: %s", vfs::get("/dev_bdvd"));
			}
			else if (bdvd_dir.size())
			{
				vfs::mount("dev_bdvd", fmt::replace_all(bdvd_dir, "$(EmulatorDir)", emu_dir));
			}

			// Mount /host_root/ if necessary
			if (g_cfg_vfs_allow_host_root)
			{
				vfs::mount("host_root", {});
			}

			LOG_NOTICE(LOADER, "Used configuration:\n%s\n", cfg::root.to_string());

			ppu_load_exec(ppu_exec);

			fxm::import<GSRender>(PURE_EXPR(Emu.GetCallbacks().get_gs_render())); // TODO: must be created in appropriate sys_rsx syscall
		}
		else if (ppu_prx.open(elf_file) == elf_error::ok)
		{
			// PPU PRX (experimental)
			m_status = Ready;
			vm::ps3::init();
			ppu_load_prx(ppu_prx);
		}
		else if (spu_exec.open(elf_file) == elf_error::ok)
		{
			// SPU executable (experimental)
			m_status = Ready;
			vm::ps3::init();
			spu_load_exec(spu_exec);
		}
		else if (arm_exec.open(elf_file) == elf_error::ok)
		{
			// ARMv7 executable
			m_status = Ready;
			vm::psv::init();
			arm_load_exec(arm_exec);
		}
		else
		{
			LOG_ERROR(LOADER, "Invalid or unsupported file format: %s", m_path);

			LOG_WARNING(LOADER, "** ppu_exec -> %s", ppu_exec.get_error());
			LOG_WARNING(LOADER, "** ppu_prx  -> %s", ppu_prx.get_error());
			LOG_WARNING(LOADER, "** spu_exec -> %s", spu_exec.get_error());
			LOG_WARNING(LOADER, "** arm_exec -> %s", arm_exec.get_error());
			return;
		}

		debug::autopause::reload();
		SendDbgCommand(DID_READY_EMU);
		if (g_cfg_autostart) Run();
	}
	catch (const std::exception& e)
	{
		LOG_FATAL(LOADER, "%s thrown: %s", typeid(e).name(), e.what());
		Stop();
	}
}
Пример #5
0
void Emulator::Load(bool add_only)
{
	Stop();

	try
	{
		Init();

		// Load game list (maps ABCD12345 IDs to /dev_bdvd/ locations) 
		YAML::Node games = YAML::Load(fs::file{fs::get_config_dir() + "/games.yml", fs::read + fs::create}.to_string());

		if (!games.IsMap())
		{
			games.reset();
		}

		LOG_NOTICE(LOADER, "Path: %s", m_path);

		const std::string elf_dir = fs::get_parent_dir(m_path);

		// Load PARAM.SFO (TODO)
		const auto _psf = psf::load_object([&]
		{
			if (fs::file sfov{elf_dir + "/sce_sys/param.sfo"})
			{
				return sfov;
			}
			else
			{
				return fs::file(elf_dir + "/../PARAM.SFO");
			}
		}());
		m_title = psf::get_string(_psf, "TITLE", m_path);
		m_title_id = psf::get_string(_psf, "TITLE_ID");
		const auto _cat = psf::get_string(_psf, "CATEGORY");

		LOG_NOTICE(LOADER, "Title: %s", GetTitle());
		LOG_NOTICE(LOADER, "Serial: %s", GetTitleID());

		// Initialize data/cache directory
		m_cache_path = fs::get_data_dir(m_title_id, m_path);
		LOG_NOTICE(LOADER, "Cache: %s", GetCachePath());

		// Load custom config-0
		if (fs::file cfg_file{m_cache_path + "/config.yml"})
		{
			LOG_NOTICE(LOADER, "Applying custom config: %s/config.yml", m_cache_path);
			g_cfg.from_string(cfg_file.to_string());
		}

		// Load custom config-1
		if (fs::file cfg_file{fs::get_config_dir() + "data/" + m_title_id + "/config.yml"})
		{
			LOG_NOTICE(LOADER, "Applying custom config: data/%s/config.yml", m_title_id);
			g_cfg.from_string(cfg_file.to_string());
		}

		// Load custom config-2
		if (fs::file cfg_file{m_path + ".yml"})
		{
			LOG_NOTICE(LOADER, "Applying custom config: %s.yml", m_path);
			g_cfg.from_string(cfg_file.to_string());
		}

		LOG_NOTICE(LOADER, "Used configuration:\n%s\n", g_cfg.to_string());

		// Load patches from different locations
		fxm::check_unlocked<patch_engine>()->append(fs::get_config_dir() + "data/" + m_title_id + "/patch.yml");
		fxm::check_unlocked<patch_engine>()->append(m_cache_path + "/patch.yml");

		// Mount all devices
		const std::string emu_dir_ = g_cfg.vfs.emulator_dir;
		const std::string emu_dir = emu_dir_.empty() ? fs::get_config_dir() : emu_dir_;
		const std::string home_dir = g_cfg.vfs.app_home;
		std::string bdvd_dir = g_cfg.vfs.dev_bdvd;

		vfs::mount("dev_hdd0", fmt::replace_all(g_cfg.vfs.dev_hdd0, "$(EmulatorDir)", emu_dir));
		vfs::mount("dev_hdd1", fmt::replace_all(g_cfg.vfs.dev_hdd1, "$(EmulatorDir)", emu_dir));
		vfs::mount("dev_flash", fmt::replace_all(g_cfg.vfs.dev_flash, "$(EmulatorDir)", emu_dir));
		vfs::mount("dev_usb", fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir));
		vfs::mount("dev_usb000", fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir));
		vfs::mount("app_home", home_dir.empty() ? elf_dir + '/' : fmt::replace_all(home_dir, "$(EmulatorDir)", emu_dir));

		// Detect boot location
		const std::string hdd0_game = vfs::get("/dev_hdd0/game/");
		const std::string hdd0_disc = vfs::get("/dev_hdd0/disc/");

		if (_cat == "DG" && m_path.find(hdd0_game + m_title_id + '/') != -1)
		{
			// Booting disc game from wrong location
			LOG_ERROR(LOADER, "Disc game found at invalid location: /dev_hdd0/game/%s/", m_title_id);

			// Move and retry from correct location
			if (fs::rename(hdd0_game + m_title_id, hdd0_disc + m_title_id))
			{
				LOG_SUCCESS(LOADER, "Disc game moved to special location: /dev_hdd0/disc/%s/", m_title_id);
				return SetPath(hdd0_disc + m_path.substr(hdd0_game.size())), Load();
			}
			else
			{
				LOG_ERROR(LOADER, "Failed to move disc game to /dev_hdd0/disc/%s/ (%s)", m_title_id, fs::g_tls_error);
				return;
			}
		}

		// Booting disc game
		if (_cat == "DG" && bdvd_dir.empty())
		{
			// Mount /dev_bdvd/ if necessary
			if (auto pos = elf_dir.rfind("/PS3_GAME") + 1)
			{
				bdvd_dir = elf_dir.substr(0, pos);
			}
		}

		// Booting patch data
		if (_cat == "GD" && bdvd_dir.empty())
		{
			// Load /dev_bdvd/ from game list if available
			if (auto node = games[m_title_id])
			{
				bdvd_dir = node.Scalar();
			}
			else
			{
				LOG_FATAL(LOADER, "Disc directory not found. Try to run the game from the actual game disc directory.");
			}
		}

		// Check /dev_bdvd/
		if (!bdvd_dir.empty() && fs::is_dir(bdvd_dir))
		{
			fs::file sfb_file;

			vfs::mount("dev_bdvd", bdvd_dir);
			LOG_NOTICE(LOADER, "Disc: %s", vfs::get("/dev_bdvd"));

			if (!sfb_file.open(vfs::get("/dev_bdvd/PS3_DISC.SFB")) || sfb_file.size() < 4 || sfb_file.read<u32>() != ".SFB"_u32)
			{
				LOG_ERROR(LOADER, "Invalid disc directory for the disc game %s", m_title_id);
				return;
			}

			const std::string bdvd_title_id = psf::get_string(psf::load_object(fs::file{vfs::get("/dev_bdvd/PS3_GAME/PARAM.SFO")}), "TITLE_ID");

			if (bdvd_title_id != m_title_id)
			{
				LOG_ERROR(LOADER, "Unexpected disc directory for the disc game %s (found %s)", m_title_id, bdvd_title_id);
				return;
			}

			// Store /dev_bdvd/ location
			games[m_title_id] = bdvd_dir;
			YAML::Emitter out;
			out << games;
			fs::file(fs::get_config_dir() + "/games.yml", fs::rewrite).write(out.c_str(), out.size());
		}
		else if (_cat == "DG" || _cat == "GD")
		{
			LOG_ERROR(LOADER, "Failed to mount disc directory for the disc game %s", m_title_id);
			return;
		}

		if (add_only)
		{
			LOG_NOTICE(LOADER, "Finished to add data to games.yml by boot for: %s", m_path);
			return;
		}

		// Check game updates
		const std::string hdd0_boot = hdd0_game + m_title_id + "/USRDIR/EBOOT.BIN";

		if (_cat == "DG" && fs::is_file(hdd0_boot))
		{
			// Booting game update
			LOG_SUCCESS(LOADER, "Updates found at /dev_hdd0/game/%s/!", m_title_id);
			return SetPath(hdd0_boot), Load();
		}

		// Mount /host_root/ if necessary
		if (g_cfg.vfs.host_root)
		{
			vfs::mount("host_root", {});
		}

		// Open SELF or ELF
		fs::file elf_file(m_path);

		if (!elf_file)
		{
			LOG_ERROR(LOADER, "Failed to open executable: %s", m_path);
			return;
		}

		// Check SELF header
		if (elf_file.size() >= 4 && elf_file.read<u32>() == "SCE\0"_u32)
		{
			const std::string decrypted_path = m_cache_path + "boot.elf";

			fs::stat_t encrypted_stat = elf_file.stat();
			fs::stat_t decrypted_stat;

			// Check modification time and try to load decrypted ELF
			if (fs::stat(decrypted_path, decrypted_stat) && decrypted_stat.mtime == encrypted_stat.mtime)
			{
				elf_file.open(decrypted_path);
			}
			else
			{
				// Decrypt SELF
				elf_file = decrypt_self(std::move(elf_file));

				if (fs::file elf_out{decrypted_path, fs::rewrite})
				{
					elf_out.write(elf_file.to_vector<u8>());
					elf_out.close();
					fs::utime(decrypted_path, encrypted_stat.atime, encrypted_stat.mtime);
				}
				else
				{
					LOG_ERROR(LOADER, "Failed to create boot.elf");
				}
			}
		}

		ppu_exec_object ppu_exec;
		ppu_prx_object ppu_prx;
		spu_exec_object spu_exec;
		arm_exec_object arm_exec;

		if (!elf_file)
		{
			LOG_ERROR(LOADER, "Failed to decrypt SELF: %s", m_path);
			return;
		}
		else if (ppu_exec.open(elf_file) == elf_error::ok)
		{
			// PS3 executable
			g_system = system_type::ps3;
			m_state = system_state::ready;
			GetCallbacks().on_ready();

			vm::ps3::init();

			if (m_elf_path.empty())
			{
				if (m_path.find(hdd0_game) != -1)
				{
					m_elf_path = "/dev_hdd0/game/" + m_path.substr(hdd0_game.size());
				}
				else if (!bdvd_dir.empty() && fs::is_dir(bdvd_dir))
				{
					//Disc games are on /dev_bdvd/
					size_t pos = m_path.rfind("PS3_GAME");
					m_elf_path = "/dev_bdvd/" + m_path.substr(pos);
				}
				else
				{
					//For homebrew
					m_elf_path = "/host_root/" + m_path;
				}

				LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path);
			}

			ppu_load_exec(ppu_exec);

			fxm::import<GSRender>(Emu.GetCallbacks().get_gs_render); // TODO: must be created in appropriate sys_rsx syscall
		}
		else if (ppu_prx.open(elf_file) == elf_error::ok)
		{
			// PPU PRX (experimental)
			g_system = system_type::ps3;
			m_state = system_state::ready;
			GetCallbacks().on_ready();
			vm::ps3::init();
			ppu_load_prx(ppu_prx, m_path);
		}
		else if (spu_exec.open(elf_file) == elf_error::ok)
		{
			// SPU executable (experimental)
			g_system = system_type::ps3;
			m_state = system_state::ready;
			GetCallbacks().on_ready();
			vm::ps3::init();
			spu_load_exec(spu_exec);
		}
		else if (arm_exec.open(elf_file) == elf_error::ok)
		{
			// ARMv7 executable
			g_system = system_type::psv;
			m_state = system_state::ready;
			GetCallbacks().on_ready();
			vm::psv::init();

			if (m_elf_path.empty())
			{
				m_elf_path = "host_root:" + m_path;
				LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path);
			}

			arm_load_exec(arm_exec);
		}
		else
		{
			LOG_ERROR(LOADER, "Invalid or unsupported file format: %s", m_path);

			LOG_WARNING(LOADER, "** ppu_exec -> %s", ppu_exec.get_error());
			LOG_WARNING(LOADER, "** ppu_prx  -> %s", ppu_prx.get_error());
			LOG_WARNING(LOADER, "** spu_exec -> %s", spu_exec.get_error());
			LOG_WARNING(LOADER, "** arm_exec -> %s", arm_exec.get_error());
			return;
		}

		if (g_cfg.misc.autostart && IsReady())
		{
			Run();
		}
		else if (IsPaused())
		{
			m_state = system_state::ready;
			GetCallbacks().on_ready();
		}
	}
	catch (const std::exception& e)
	{
		LOG_FATAL(LOADER, "%s thrown: %s", typeid(e).name(), e.what());
		Stop();
	}
}
Пример #6
0
void Emulator::Load()
{
	Stop();

	try
	{
		Init();

		// Open SELF or ELF
		fs::file elf_file(m_path);

		if (!elf_file)
		{
			LOG_ERROR(LOADER, "Failed to open file: %s", m_path);
			return;
		}

		LOG_NOTICE(LOADER, "Path: %s", m_path);

		const std::string elf_dir = fs::get_parent_dir(m_path);
		const fs::file sfov(elf_dir + "/sce_sys/param.sfo");
		const fs::file sfo1(elf_dir + "/../PARAM.SFO");

		// Load PARAM.SFO (TODO)
		const auto _psf = psf::load_object(sfov ? sfov : sfo1);
		m_title = psf::get_string(_psf, "TITLE", m_path);
		m_title_id = psf::get_string(_psf, "TITLE_ID");

		LOG_NOTICE(LOADER, "Title: %s", GetTitle());
		LOG_NOTICE(LOADER, "Serial: %s", GetTitleID());

		// Initialize data/cache directory
		m_cache_path = fs::get_data_dir(m_title_id, m_path);
		LOG_NOTICE(LOADER, "Cache: %s", GetCachePath());

		// Load custom config-0
		if (fs::file cfg_file{m_cache_path + "/config.yml"})
		{
			LOG_NOTICE(LOADER, "Applying custom config: %s/config.yml", m_cache_path);
			g_cfg.from_string(cfg_file.to_string());
		}

		// Load custom config-1
		if (fs::file cfg_file{fs::get_config_dir() + "data/" + m_title_id + "/config.yml"})
		{
			LOG_NOTICE(LOADER, "Applying custom config: data/%s/config.yml", m_title_id);
			g_cfg.from_string(cfg_file.to_string());
		}

		// Load custom config-2
		if (fs::file cfg_file{m_path + ".yml"})
		{
			LOG_NOTICE(LOADER, "Applying custom config: %s.yml", m_path);
			g_cfg.from_string(cfg_file.to_string());
		}

		LOG_NOTICE(LOADER, "Used configuration:\n%s\n", g_cfg.to_string());

		// Load patches from different locations
		fxm::check_unlocked<patch_engine>()->append(fs::get_config_dir() + "data/" + m_title_id + "/patch.yml");
		fxm::check_unlocked<patch_engine>()->append(m_cache_path + "/patch.yml");

		// Mount all devices
		const std::string emu_dir_ = g_cfg.vfs.emulator_dir;
		const std::string emu_dir = emu_dir_.empty() ? fs::get_config_dir() : emu_dir_;
		const std::string home_dir = g_cfg.vfs.app_home;
		std::string bdvd_dir = g_cfg.vfs.dev_bdvd;

		vfs::mount("dev_hdd0", fmt::replace_all(g_cfg.vfs.dev_hdd0, "$(EmulatorDir)", emu_dir));
		vfs::mount("dev_hdd1", fmt::replace_all(g_cfg.vfs.dev_hdd1, "$(EmulatorDir)", emu_dir));
		vfs::mount("dev_flash", fmt::replace_all(g_cfg.vfs.dev_flash, "$(EmulatorDir)", emu_dir));
		vfs::mount("dev_usb", fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir));
		vfs::mount("dev_usb000", fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir));
		vfs::mount("app_home", home_dir.empty() ? elf_dir + '/' : fmt::replace_all(home_dir, "$(EmulatorDir)", emu_dir));

		// Mount /dev_bdvd/ if necessary
		if (bdvd_dir.empty()) 
		{
			size_t pos = elf_dir.rfind("PS3_GAME");
			std::string temp = elf_dir.substr(0, pos);
			if ((pos != std::string::npos) && fs::is_file(temp + "/PS3_DISC.SFB")) {
				bdvd_dir = temp;
			}
		}
		if (!bdvd_dir.empty() && fs::is_dir(bdvd_dir))
		{
			vfs::mount("dev_bdvd", fmt::replace_all(bdvd_dir, "$(EmulatorDir)", emu_dir));
			LOG_NOTICE(LOADER, "Disc: %s", vfs::get("/dev_bdvd"));
		}

		// Mount /host_root/ if necessary
		if (g_cfg.vfs.host_root)
		{
			vfs::mount("host_root", {});
		}

		// Check SELF header
		if (elf_file.size() >= 4 && elf_file.read<u32>() == "SCE\0"_u32)
		{
			const std::string decrypted_path = m_cache_path + "boot.elf";

			fs::stat_t encrypted_stat = elf_file.stat();
			fs::stat_t decrypted_stat;

			// Check modification time and try to load decrypted ELF
			if (fs::stat(decrypted_path, decrypted_stat) && decrypted_stat.mtime == encrypted_stat.mtime)
			{
				elf_file.open(decrypted_path);
			}
			else
			{
				// Decrypt SELF
				elf_file = decrypt_self(std::move(elf_file));

				if (fs::file elf_out{decrypted_path, fs::rewrite})
				{
					elf_out.write(elf_file.to_vector<u8>());
					elf_out.close();
					fs::utime(decrypted_path, encrypted_stat.atime, encrypted_stat.mtime);
				}
				else
				{
					LOG_ERROR(LOADER, "Failed to create boot.elf");
				}
			}
		}

		ppu_exec_object ppu_exec;
		ppu_prx_object ppu_prx;
		spu_exec_object spu_exec;
		arm_exec_object arm_exec;

		if (!elf_file)
		{
			LOG_ERROR(LOADER, "Failed to decrypt SELF: %s", m_path);
			return;
		}
		else if (ppu_exec.open(elf_file) == elf_error::ok)
		{
			// PS3 executable
			g_system = system_type::ps3;
			m_state = system_state::ready;
			GetCallbacks().on_ready();

			vm::ps3::init();

			if (m_elf_path.empty())
			{
				if (!bdvd_dir.empty() && fs::is_dir(bdvd_dir))
				{
					//Disc games are on /dev_bdvd/
					size_t pos = m_path.rfind("PS3_GAME");
					m_elf_path = "/dev_bdvd/" + m_path.substr(pos);
				}
				else if (m_path.find(vfs::get("/dev_hdd0/game/")) != -1)
				{
					m_elf_path = "/dev_hdd0/game/" + m_path.substr(vfs::get("/dev_hdd0/game/").size());
				}
				else
				{
					//For homebrew
					m_elf_path = "/host_root/" + m_path;
				}

				LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path);
			}

			ppu_load_exec(ppu_exec);

			fxm::import<GSRender>(Emu.GetCallbacks().get_gs_render); // TODO: must be created in appropriate sys_rsx syscall
		}
		else if (ppu_prx.open(elf_file) == elf_error::ok)
		{
			// PPU PRX (experimental)
			g_system = system_type::ps3;
			m_state = system_state::ready;
			GetCallbacks().on_ready();
			vm::ps3::init();
			ppu_load_prx(ppu_prx, "");
		}
		else if (spu_exec.open(elf_file) == elf_error::ok)
		{
			// SPU executable (experimental)
			g_system = system_type::ps3;
			m_state = system_state::ready;
			GetCallbacks().on_ready();
			vm::ps3::init();
			spu_load_exec(spu_exec);
		}
		else if (arm_exec.open(elf_file) == elf_error::ok)
		{
			// ARMv7 executable
			g_system = system_type::psv;
			m_state = system_state::ready;
			GetCallbacks().on_ready();
			vm::psv::init();

			if (m_elf_path.empty())
			{
				m_elf_path = "host_root:" + m_path;
				LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path);
			}

			arm_load_exec(arm_exec);
		}
		else
		{
			LOG_ERROR(LOADER, "Invalid or unsupported file format: %s", m_path);

			LOG_WARNING(LOADER, "** ppu_exec -> %s", ppu_exec.get_error());
			LOG_WARNING(LOADER, "** ppu_prx  -> %s", ppu_prx.get_error());
			LOG_WARNING(LOADER, "** spu_exec -> %s", spu_exec.get_error());
			LOG_WARNING(LOADER, "** arm_exec -> %s", arm_exec.get_error());
			return;
		}

		if (g_cfg.misc.autostart && IsReady())
		{
			Run();
		}
		else if (IsPaused())
		{
			m_state = system_state::ready;
			GetCallbacks().on_ready();
		}
	}
	catch (const std::exception& e)
	{
		LOG_FATAL(LOADER, "%s thrown: %s", typeid(e).name(), e.what());
		Stop();
	}
}
Пример #7
0
void GameList::ShowContextMenu(const QPoint&)
{
  if (!GetSelectedGame())
    return;

  QMenu* menu = new QMenu(this);

  if (HasMultipleSelected())
  {
    bool wii_saves = true;
    bool compress = false;
    bool decompress = false;

    for (const auto& game : GetSelectedGames())
    {
      DiscIO::Platform platform = game->GetPlatform();

      if (platform == DiscIO::Platform::GameCubeDisc || platform == DiscIO::Platform::WiiDisc)
      {
        const auto blob_type = game->GetBlobType();
        if (blob_type == DiscIO::BlobType::GCZ)
          decompress = true;
        else if (blob_type == DiscIO::BlobType::PLAIN)
          compress = true;
      }

      if (platform != DiscIO::Platform::WiiWAD && platform != DiscIO::Platform::WiiDisc)
        wii_saves = false;
    }

    if (compress)
      menu->addAction(tr("Compress Selected ISOs..."), this, [this] { CompressISO(false); });
    if (decompress)
      menu->addAction(tr("Decompress Selected ISOs..."), this, [this] { CompressISO(true); });
    if (compress || decompress)
      menu->addSeparator();

    if (wii_saves)
    {
      menu->addAction(tr("Export Wii Saves (Experimental)"), this, &GameList::ExportWiiSave);
      menu->addSeparator();
    }

    menu->addAction(tr("Delete Selected Files..."), this, &GameList::DeleteFile);
  }
  else
  {
    const auto game = GetSelectedGame();
    DiscIO::Platform platform = game->GetPlatform();

    if (platform != DiscIO::Platform::ELFOrDOL)
    {
      menu->addAction(tr("&Properties"), this, &GameList::OpenProperties);
      menu->addAction(tr("&Wiki"), this, &GameList::OpenWiki);

      menu->addSeparator();
    }

    if (platform == DiscIO::Platform::GameCubeDisc || platform == DiscIO::Platform::WiiDisc)
    {
      menu->addAction(tr("Set as &Default ISO"), this, &GameList::SetDefaultISO);
      const auto blob_type = game->GetBlobType();

      if (blob_type == DiscIO::BlobType::GCZ)
        menu->addAction(tr("Decompress ISO..."), this, [this] { CompressISO(true); });
      else if (blob_type == DiscIO::BlobType::PLAIN)
        menu->addAction(tr("Compress ISO..."), this, [this] { CompressISO(false); });

      QAction* change_disc = menu->addAction(tr("Change &Disc"), this, &GameList::ChangeDisc);

      connect(&Settings::Instance(), &Settings::EmulationStateChanged, change_disc,
              [change_disc] { change_disc->setEnabled(Core::IsRunning()); });
      change_disc->setEnabled(Core::IsRunning());

      menu->addSeparator();
    }

    if (platform == DiscIO::Platform::WiiDisc)
    {
      auto* perform_disc_update = menu->addAction(tr("Perform System Update"), this,
                                                  [this, file_path = game->GetFilePath()] {
                                                    WiiUpdate::PerformDiscUpdate(file_path, this);
                                                  });
      perform_disc_update->setEnabled(!Core::IsRunning() || !SConfig::GetInstance().bWii);
    }

    if (platform == DiscIO::Platform::WiiWAD)
    {
      QAction* wad_install_action = new QAction(tr("Install to the NAND"), menu);
      QAction* wad_uninstall_action = new QAction(tr("Uninstall from the NAND"), menu);

      connect(wad_install_action, &QAction::triggered, this, &GameList::InstallWAD);
      connect(wad_uninstall_action, &QAction::triggered, this, &GameList::UninstallWAD);

      for (QAction* a : {wad_install_action, wad_uninstall_action})
      {
        a->setEnabled(!Core::IsRunning());
        menu->addAction(a);
      }
      if (!Core::IsRunning())
        wad_uninstall_action->setEnabled(WiiUtils::IsTitleInstalled(game->GetTitleID()));

      connect(&Settings::Instance(), &Settings::EmulationStateChanged, menu,
              [=](Core::State state) {
                wad_install_action->setEnabled(state == Core::State::Uninitialized);
                wad_uninstall_action->setEnabled(state == Core::State::Uninitialized &&
                                                 WiiUtils::IsTitleInstalled(game->GetTitleID()));
              });

      menu->addSeparator();
    }

    if (platform == DiscIO::Platform::WiiWAD || platform == DiscIO::Platform::WiiDisc)
    {
      menu->addAction(tr("Open Wii &Save Folder"), this, &GameList::OpenWiiSaveFolder);
      menu->addAction(tr("Export Wii Save (Experimental)"), this, &GameList::ExportWiiSave);
      menu->addSeparator();
    }

    if (platform == DiscIO::Platform::GameCubeDisc)
    {
      menu->addAction(tr("Open GameCube &Save Folder"), this, &GameList::OpenGCSaveFolder);
      menu->addSeparator();
    }

    menu->addAction(tr("Open &Containing Folder"), this, &GameList::OpenContainingFolder);
    menu->addAction(tr("Delete File..."), this, &GameList::DeleteFile);

    menu->addSeparator();

    auto* model = Settings::Instance().GetGameListModel();

    auto* tags_menu = menu->addMenu(tr("Tags"));

    auto path = game->GetFilePath();
    auto game_tags = model->GetGameTags(path);

    for (const auto& tag : model->GetAllTags())
    {
      auto* tag_action = tags_menu->addAction(tag);

      tag_action->setCheckable(true);
      tag_action->setChecked(game_tags.contains(tag));

      connect(tag_action, &QAction::toggled, [path, tag, model](bool checked) {
        if (!checked)
          model->RemoveGameTag(path, tag);
        else
          model->AddGameTag(path, tag);
      });
    }

    menu->addAction(tr("New Tag..."), this, &GameList::NewTag);
    menu->addAction(tr("Remove Tag..."), this, &GameList::DeleteTag);

    menu->addSeparator();

    QAction* netplay_host = new QAction(tr("Host with NetPlay"), menu);

    connect(netplay_host, &QAction::triggered, [this, game] {
      emit NetPlayHost(QString::fromStdString(game->GetUniqueIdentifier()));
    });

    connect(&Settings::Instance(), &Settings::EmulationStateChanged, menu, [=](Core::State state) {
      netplay_host->setEnabled(state == Core::State::Uninitialized);
    });
    netplay_host->setEnabled(!Core::IsRunning());

    menu->addAction(netplay_host);
  }

  menu->exec(QCursor::pos());
}
Пример #8
0
void Emulator::Load()
{
	Stop();

	try
	{
		Init();

		if (!fs::is_file(m_path))
		{
			LOG_ERROR(LOADER, "File not found: %s", m_path);
			return;
		}

		const std::string& elf_dir = fs::get_parent_dir(m_path);

		if (IsSelf(m_path))
		{
			const std::size_t elf_ext_pos = m_path.find_last_of('.');
			const std::string& elf_ext = fmt::to_upper(m_path.substr(elf_ext_pos != -1 ? elf_ext_pos : m_path.size()));
			const std::string& elf_name = m_path.substr(elf_dir.size());

			if (elf_name.compare(elf_name.find_last_of("/\\", -1, 2) + 1, 9, "EBOOT.BIN", 9) == 0)
			{
				m_path.erase(m_path.size() - 9, 1); // change EBOOT.BIN to BOOT.BIN
			}
			else if (elf_ext == ".SELF" || elf_ext == ".SPRX")
			{
				m_path.erase(m_path.size() - 4, 1); // change *.self to *.elf, *.sprx to *.prx
			}
			else
			{
				m_path += ".decrypted.elf";
			}

			if (!DecryptSelf(m_path, elf_dir + elf_name))
			{
				LOG_ERROR(LOADER, "Failed to decrypt %s", elf_dir + elf_name);
				return;
			}
		}

		ResetInfo();

		LOG_NOTICE(LOADER, "Path: %s", m_path);

		// Load custom config
		if (fs::file cfg_file{ m_path + ".yml" })
		{
			LOG_NOTICE(LOADER, "Custom config: %s.yml", m_path);
			cfg::root.from_string(cfg_file.to_string());
		}

		const fs::file elf_file(m_path);
		ppu_exec_loader ppu_exec;
		ppu_prx_loader ppu_prx;
		spu_exec_loader spu_exec;
		arm_exec_loader arm_exec;

		if (!elf_file)
		{
			LOG_ERROR(LOADER, "Failed to open %s", m_path);
			return;
		}
		else if (ppu_exec.open(elf_file) == elf_error::ok)
		{
			// PS3 executable
			m_status = Ready;
			vm::ps3::init();

			if (m_elf_path.empty())
			{
				m_elf_path = "/host_root/" + m_path;
				LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path);
			}

			// Load PARAM.SFO
			m_psf = psf::load_object(fs::file(elf_dir + "/../PARAM.SFO"));
			m_title = psf::get_string(m_psf, "TITLE", m_path);
			m_title_id = psf::get_string(m_psf, "TITLE_ID");
			LOG_NOTICE(LOADER, "Title: %s", GetTitle());
			LOG_NOTICE(LOADER, "Serial: %s", GetTitleID());
			LOG_NOTICE(LOADER, "");

			LOG_NOTICE(LOADER, "Used configuration:\n%s\n", cfg::root.to_string());

			// Mount /dev_bdvd/
			if (g_cfg_vfs_dev_bdvd.size() == 0 && fs::is_file(elf_dir + "/../../PS3_DISC.SFB"))
			{
				const auto dir_list = fmt::split(elf_dir, { "/", "\\" });

				// Check latest two directories
				if (dir_list.size() >= 2 && dir_list.back() == "USRDIR" && *(dir_list.end() - 2) == "PS3_GAME")
				{
					g_cfg_vfs_dev_bdvd = elf_dir.substr(0, elf_dir.length() - 15);
				}
				else
				{
					g_cfg_vfs_dev_bdvd = elf_dir + "/../../";
				}
			}

			// Mount /app_home/
			if (g_cfg_vfs_app_home.size() == 0)
			{
				g_cfg_vfs_app_home = elf_dir + '/';
			}

			vfs::dump();

			ppu_exec.load();

			Emu.GetCallbackManager().Init();
			fxm::import<GSRender>(PURE_EXPR(Emu.GetCallbacks().get_gs_render())); // TODO: must be created in appropriate sys_rsx syscall
		}
		else if (ppu_prx.open(elf_file) == elf_error::ok)
		{
			// PPU PRX (experimental)
			m_status = Ready;
			vm::ps3::init();
			ppu_prx.load();
			GetCallbackManager().Init();
		}
		else if (spu_exec.open(elf_file) == elf_error::ok)
		{
			// SPU executable (experimental)
			m_status = Ready;
			vm::ps3::init();
			spu_exec.load();
		}
		else if (arm_exec.open(elf_file) == elf_error::ok)
		{
			// ARMv7 executable
			m_status = Ready;
			vm::psv::init();
			arm_exec.load();
		}
		else
		{
			LOG_ERROR(LOADER, "Invalid or unsupported file format: %s", m_path);

			LOG_WARNING(LOADER, "** ppu_exec_loader -> %s", bijective_find<elf_error>(ppu_exec, "???"));
			LOG_WARNING(LOADER, "** ppu_prx_loader -> %s", bijective_find<elf_error>(ppu_prx, "???"));
			LOG_WARNING(LOADER, "** spu_exec_loader -> %s", bijective_find<elf_error>(spu_exec, "???"));
			LOG_WARNING(LOADER, "** arm_exec_loader -> %s", bijective_find<elf_error>(arm_exec, "???"));
			return;
		}

		debug::autopause::reload();
		SendDbgCommand(DID_READY_EMU);
		if (g_cfg_autostart) Run();
	}
	catch (const std::exception& e)
	{
		LOG_FATAL(LOADER, "%s thrown: %s", typeid(e).name(), e.what());
		Stop();
	}
}
Пример #9
0
// called from ---GUI--- thread
bool NetPlayServer::SyncSaveData()
{
  m_save_data_synced_players = 0;

  u8 save_count = 0;

  constexpr size_t exi_device_count = 2;
  for (size_t i = 0; i < exi_device_count; i++)
  {
    if (m_settings.m_EXIDevice[i] == ExpansionInterface::EXIDEVICE_MEMORYCARD ||
        SConfig::GetInstance().m_EXIDevice[i] == ExpansionInterface::EXIDEVICE_MEMORYCARDFOLDER)
    {
      save_count++;
    }
  }

  const auto game = m_dialog->FindGameFile(m_selected_game);
  if (game == nullptr)
  {
    PanicAlertT("Selected game doesn't exist in game list!");
    return false;
  }

  bool wii_save = false;
  if (m_settings.m_CopyWiiSave && (game->GetPlatform() == DiscIO::Platform::WiiDisc ||
                                   game->GetPlatform() == DiscIO::Platform::WiiWAD))
  {
    wii_save = true;
    save_count++;
  }

  {
    sf::Packet pac;
    pac << static_cast<MessageId>(NP_MSG_SYNC_SAVE_DATA);
    pac << static_cast<MessageId>(SYNC_SAVE_DATA_NOTIFY);
    pac << save_count;

    SendAsyncToClients(std::move(pac));
  }

  if (save_count == 0)
    return true;

  const std::string region =
      SConfig::GetDirectoryForRegion(SConfig::ToGameCubeRegion(game->GetRegion()));

  for (size_t i = 0; i < exi_device_count; i++)
  {
    const bool is_slot_a = i == 0;

    if (m_settings.m_EXIDevice[i] == ExpansionInterface::EXIDEVICE_MEMORYCARD)
    {
      std::string path = is_slot_a ? Config::Get(Config::MAIN_MEMCARD_A_PATH) :
                                     Config::Get(Config::MAIN_MEMCARD_B_PATH);

      MemoryCard::CheckPath(path, region, is_slot_a);

      bool mc251;
      IniFile gameIni = SConfig::LoadGameIni(game->GetGameID(), game->GetRevision());
      gameIni.GetOrCreateSection("Core")->Get("MemoryCard251", &mc251, false);

      if (mc251)
        path.insert(path.find_last_of('.'), ".251");

      sf::Packet pac;
      pac << static_cast<MessageId>(NP_MSG_SYNC_SAVE_DATA);
      pac << static_cast<MessageId>(SYNC_SAVE_DATA_RAW);
      pac << is_slot_a << region << mc251;

      if (File::Exists(path))
      {
        if (!CompressFileIntoPacket(path, pac))
          return false;
      }
      else
      {
        // No file, so we'll say the size is 0
        pac << sf::Uint64{0};
      }

      SendAsyncToClients(std::move(pac));
    }
    else if (SConfig::GetInstance().m_EXIDevice[i] ==
             ExpansionInterface::EXIDEVICE_MEMORYCARDFOLDER)
    {
      const std::string path = File::GetUserPath(D_GCUSER_IDX) + region + DIR_SEP +
                               StringFromFormat("Card %c", is_slot_a ? 'A' : 'B');

      sf::Packet pac;
      pac << static_cast<MessageId>(NP_MSG_SYNC_SAVE_DATA);
      pac << static_cast<MessageId>(SYNC_SAVE_DATA_GCI);
      pac << is_slot_a;

      if (File::IsDirectory(path))
      {
        std::vector<std::string> files =
            GCMemcardDirectory::GetFileNamesForGameID(path + DIR_SEP, game->GetGameID());

        pac << static_cast<u8>(files.size());

        for (const std::string& file : files)
        {
          pac << file.substr(file.find_last_of('/') + 1);
          if (!CompressFileIntoPacket(file, pac))
            return false;
        }
      }
      else
      {
        pac << static_cast<u8>(0);
      }

      SendAsyncToClients(std::move(pac));
    }
  }

  if (wii_save)
  {
    const auto configured_fs = IOS::HLE::FS::MakeFileSystem(IOS::HLE::FS::Location::Configured);
    const auto save = WiiSave::MakeNandStorage(configured_fs.get(), game->GetTitleID());

    sf::Packet pac;
    pac << static_cast<MessageId>(NP_MSG_SYNC_SAVE_DATA);
    pac << static_cast<MessageId>(SYNC_SAVE_DATA_WII);

    if (save->SaveExists())
    {
      const std::optional<WiiSave::Header> header = save->ReadHeader();
      const std::optional<WiiSave::BkHeader> bk_header = save->ReadBkHeader();
      const std::optional<std::vector<WiiSave::Storage::SaveFile>> files = save->ReadFiles();
      if (!header || !bk_header || !files)
        return false;

      pac << true;  // save exists

      // Header
      pac << sf::Uint64{header->tid};
      pac << header->banner_size << header->permissions << header->unk1;
      for (size_t i = 0; i < header->md5.size(); i++)
        pac << header->md5[i];
      pac << header->unk2;
      for (size_t i = 0; i < header->banner_size; i++)
        pac << header->banner[i];

      // BkHeader
      pac << bk_header->size << bk_header->magic << bk_header->ngid << bk_header->number_of_files
          << bk_header->size_of_files << bk_header->unk1 << bk_header->unk2
          << bk_header->total_size;
      for (size_t i = 0; i < bk_header->unk3.size(); i++)
        pac << bk_header->unk3[i];
      pac << sf::Uint64{bk_header->tid};
      for (size_t i = 0; i < bk_header->mac_address.size(); i++)
        pac << bk_header->mac_address[i];

      // Files
      for (const WiiSave::Storage::SaveFile& file : *files)
      {
        pac << file.mode << file.attributes << static_cast<u8>(file.type) << file.path;

        if (file.type == WiiSave::Storage::SaveFile::Type::File)
        {
          const std::optional<std::vector<u8>>& data = *file.data;
          if (!data || !CompressBufferIntoPacket(*data, pac))
            return false;
        }
      }
    }
    else
    {
      pac << false;  // save does not exist
    }

    SendAsyncToClients(std::move(pac));
  }

  return true;
}