s32 sys_spu_image_open(vm::ptr<sys_spu_image_t> img, vm::cptr<char> path) { sys_spu.warning("sys_spu_image_open(img=*0x%x, path=*0x%x)", img, path); const fs::file f(vfs::get(path.get_ptr())); if (!f) { sys_spu.error("sys_spu_image_open() error: '%s' not found!", path.get_ptr()); return CELL_ENOENT; } SceHeader hdr; hdr.Load(f); if (hdr.CheckMagic()) { throw fmt::exception("sys_spu_image_open() error: '%s' is encrypted! Try to decrypt it manually and try again.", path.get_ptr()); } f.seek(0); u32 entry; u32 offset = LoadSpuImage(f, entry); img->type = SYS_SPU_IMAGE_TYPE_USER; img->entry_point = entry; img->segs.set(offset); // TODO: writing actual segment info img->nsegs = 1; // wrong value return CELL_OK; }
extern bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key) { if (!self) return false; self.seek(0); if (self.size() >= 4 && self.read<u32>() == "SCE\0"_u32) { // Check the ELF file class (32 or 64 bit). bool isElf32 = IsSelfElf32(self); // Start the decrypter on this SELF file. SELFDecrypter self_dec(self); // Load the SELF file headers. if (!self_dec.LoadHeaders(isElf32)) { LOG_ERROR(LOADER, "SELF: Failed to load SELF file headers!"); return false; } // Load and decrypt the SELF file metadata. if (!self_dec.LoadMetadata(klic_key)) { LOG_ERROR(LOADER, "SELF: Failed to load SELF file metadata!"); return false; } } return true; }
s32 cellUserInfoGetStat(u32 id, vm::ptr<CellUserInfoUserStat> stat) { cellUserInfo.warning("cellUserInfoGetStat(id=%d, stat=*0x%x)", id, stat); if (id > CELL_SYSUTIL_USERID_MAX) return CELL_USERINFO_ERROR_NOUSER; if (id == CELL_SYSUTIL_USERID_CURRENT) { // TODO: Return current user/profile when that is implemented id = 1; } const std::string& path = vfs::get(fmt::format("/dev_hdd0/home/%08d/", id)); if (!fs::is_dir(path)) return CELL_USERINFO_ERROR_NOUSER; const fs::file f(path + "localusername"); if (!f) return CELL_USERINFO_ERROR_INTERNAL; stat->id = id; strcpy_trunc(stat->name, f.to_string()); return CELL_OK; }
s32 sys_raw_spu_load(s32 id, vm::cptr<char> path, vm::ptr<u32> entry) { sysPrxForUser.warning("sys_raw_spu_load(id=%d, path=*0x%x, entry=*0x%x)", id, path, entry); sysPrxForUser.warning("*** path = '%s'", path.get_ptr()); const fs::file f(vfs::get(path.get_ptr())); if (!f) { sysPrxForUser.error("sys_raw_spu_load() error: '%s' not found!", path.get_ptr()); return CELL_ENOENT; } SceHeader hdr; hdr.Load(f); if (hdr.CheckMagic()) { throw fmt::exception("sys_raw_spu_load() error: '%s' is encrypted! Try to decrypt it manually and try again.", path.get_ptr()); } f.seek(0); u32 _entry; LoadSpuImage(f, _entry, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id); *entry = _entry | 1; return CELL_OK; }
void save_gui_cfg() { YAML::Emitter out; out.SetSeqFormat(YAML::Flow); out << g_gui_cfg; // Save to file s_gui_cfg.seek(0); s_gui_cfg.trunc(0); s_gui_cfg.write(out.c_str(), out.size()); }
error_code sys_tty_write(s32 ch, vm::cptr<char> buf, u32 len, vm::ptr<u32> pwritelen) { sys_tty.notice("sys_tty_write(ch=%d, buf=*0x%x, len=%d, pwritelen=*0x%x)", ch, buf, len, pwritelen); if (ch > 15) { return CELL_EINVAL; } if (static_cast<s32>(len) <= 0) { *pwritelen = 0; return CELL_OK; } if (g_tty) { g_tty.write(buf.get_ptr(), len); } *pwritelen = len; return CELL_OK; }
error_code sys_tty_write(s32 ch, vm::cptr<char> buf, u32 len, vm::ptr<u32> pwritelen) { sys_tty.notice("sys_tty_write(ch=%d, buf=*0x%x, len=%d, pwritelen=*0x%x)", ch, buf, len, pwritelen); if (ch > 15) { return CELL_EINVAL; } const u32 written_len = static_cast<s32>(len) > 0 ? len : 0; if (written_len > 0 && g_tty) { // Lock size by making it negative g_tty_size -= (1ll << 48); g_tty.write(buf.get_ptr(), len); g_tty_size += (1ll << 48) + len; } if (!pwritelen) { return CELL_EFAULT; } *pwritelen = written_len; return CELL_OK; }
extern fs::file decrypt_self(fs::file elf_or_self, u8* klic_key) { if (!elf_or_self) { return fs::file{}; } elf_or_self.seek(0); // Check SELF header first. Check for a debug SELF. if (elf_or_self.size() >= 4 && elf_or_self.read<u32>() == "SCE\0"_u32 && !CheckDebugSelf(elf_or_self)) { // Check the ELF file class (32 or 64 bit). bool isElf32 = IsSelfElf32(elf_or_self); // Start the decrypter on this SELF file. SELFDecrypter self_dec(elf_or_self); // Load the SELF file headers. if (!self_dec.LoadHeaders(isElf32)) { LOG_ERROR(LOADER, "SELF: Failed to load SELF file headers!"); return fs::file{}; } // Load and decrypt the SELF file metadata. if (!self_dec.LoadMetadata(klic_key)) { LOG_ERROR(LOADER, "SELF: Failed to load SELF file metadata!"); return fs::file{}; } // Decrypt the SELF file data. if (!self_dec.DecryptData()) { LOG_ERROR(LOADER, "SELF: Failed to decrypt SELF file data!"); return fs::file{}; } // Make a new ELF file from this SELF. return self_dec.MakeElf(isElf32); } return elf_or_self; }
void ControlInfo::Load(const fs::file& f) { type = Read32(f); size = Read32(f); next = Read64(f); if (type == 1) { control_flags.ctrl_flag1 = Read32(f); control_flags.unknown1 = Read32(f); control_flags.unknown2 = Read32(f); control_flags.unknown3 = Read32(f); control_flags.unknown4 = Read32(f); control_flags.unknown5 = Read32(f); control_flags.unknown6 = Read32(f); control_flags.unknown7 = Read32(f); } else if (type == 2) { if (size == 0x30) { f.read(file_digest_30.digest, 20); file_digest_30.unknown = Read64(f); } else if (size == 0x40) { f.read(file_digest_40.digest1, 20); f.read(file_digest_40.digest2, 20); file_digest_40.unknown = Read64(f); } } else if (type == 3) { npdrm.magic = Read32(f); npdrm.unknown1 = Read32(f); npdrm.license = Read32(f); npdrm.type = Read32(f); f.read(npdrm.content_id, 48); f.read(npdrm.digest, 16); f.read(npdrm.invdigest, 16); f.read(npdrm.xordigest, 16); npdrm.unknown2 = Read64(f); npdrm.unknown3 = Read64(f); } }
error_code sys_console_write(vm::ps3::cptr<char> buf, u32 len) { if (g_tty) { g_tty.write(buf.get_ptr(), len); } return CELL_OK; }
static bool IsSelfElf32(const fs::file& f) { if (!f) return false; f.seek(0); SceHeader hdr; SelfHeader sh; hdr.Load(f); sh.Load(f); // Locate the class byte and check it. u8 elf_class[0x8]; f.seek(sh.se_elfoff); f.read(elf_class, 0x8); return (elf_class[4] == 1); }
s32 _sys_printf(ppu_thread& ppu, vm::cptr<char> fmt, ppu_va_args_t va_args) { sysPrxForUser.warning("_sys_printf(fmt=%s, ...)", fmt); if (g_tty) { g_tty.write(ps3_fmt(ppu, fmt, va_args.count)); } return CELL_OK; }
s32 console_write(vm::ptr<char> data, u32 len) { sysPrxForUser.warning("console_write(data=*0x%x, len=%d)", data, len); if (g_tty) { g_tty.write(data.get_ptr(), len); } return CELL_OK; }
static bool CheckDebugSelf(fs::file& s) { if (s.size() < 0x18) { return false; } // Get the key version. s.seek(0x08); const u16 key_version = s.read<le_t<u16>>(); // Check for DEBUG version. if (key_version == 0x80 || key_version == 0xc0) { LOG_WARNING(LOADER, "Debug SELF detected! Removing fake header..."); // Get the real elf offset. s.seek(0x10); // Start at the real elf offset. s.seek(key_version == 0x80 ? +s.read<be_t<u64>>() : +s.read<le_t<u64>>()); // Write the real ELF file back. fs::file e = fs::make_stream<std::vector<u8>>(); // Copy the data. char buf[2048]; while (u64 size = s.read(buf, 2048)) { e.write(buf, size); } s = std::move(e); return true; } // Leave the file untouched. return false; }
error_code cellUserInfoGetStat(u32 id, vm::ptr<CellUserInfoUserStat> stat) { cellUserInfo.warning("cellUserInfoGetStat(id=%d, stat=*0x%x)", id, stat); if (id > CELL_SYSUTIL_USERID_MAX) { return CELL_USERINFO_ERROR_NOUSER; } if (id == CELL_SYSUTIL_USERID_CURRENT) { // TODO: Return current user/profile when that is implemented id = 1; } if (!stat) return CELL_USERINFO_ERROR_PARAM; const std::string& path = vfs::get(fmt::format("/dev_hdd0/home/%08d/", id)); if (!fs::is_dir(path)) { cellUserInfo.error("cellUserInfoGetStat(): CELL_USERINFO_ERROR_NOUSER. User %d doesn't exist. Did you delete the user folder?", id); return CELL_USERINFO_ERROR_NOUSER; } const fs::file f(path + "localusername"); if (!f) { cellUserInfo.error("cellUserInfoGetStat(): CELL_USERINFO_ERROR_INTERNAL. Username for user %d doesn't exist. Did you delete the username file?", id); return CELL_USERINFO_ERROR_INTERNAL; } stat->id = id; strcpy_trunc(stat->name, f.to_string()); return CELL_OK; }
void Emulator::Init() { if (!g_tty) { g_tty.open(fs::get_config_dir() + "TTY.log", fs::rewrite + fs::append); } idm::init(); fxm::init(); // Reset defaults, cache them cfg::root.from_default(); g_cfg_defaults = cfg::root.to_string(); // Reload global configuration cfg::root.from_string(fs::file(fs::get_config_dir() + "/config.yml", fs::read + fs::create).to_string()); }
void Emulator::Init() { if (!g_tty) { g_tty.open(fs::get_config_dir() + "TTY.log", fs::rewrite + fs::append); } idm::init(); fxm::init(); // Reset defaults, cache them g_cfg.from_default(); g_cfg_defaults = g_cfg.to_string(); // Reload global configuration g_cfg.from_string(fs::file(fs::get_config_dir() + "/config.yml", fs::read + fs::create).to_string()); // Create directories 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 dev_hdd0 = fmt::replace_all(g_cfg.vfs.dev_hdd0, "$(EmulatorDir)", emu_dir); const std::string dev_hdd1 = fmt::replace_all(g_cfg.vfs.dev_hdd1, "$(EmulatorDir)", emu_dir); const std::string dev_usb = fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir); fs::create_path(dev_hdd0); fs::create_dir(dev_hdd0 + "game/"); fs::create_dir(dev_hdd0 + "game/TEST12345/"); fs::create_dir(dev_hdd0 + "game/TEST12345/USRDIR/"); fs::create_dir(dev_hdd0 + "home/"); fs::create_dir(dev_hdd0 + "home/00000001/"); fs::create_dir(dev_hdd0 + "home/00000001/exdata/"); fs::create_dir(dev_hdd0 + "home/00000001/savedata/"); fs::create_dir(dev_hdd0 + "home/00000001/trophy/"); fs::write_file(dev_hdd0 + "home/00000001/localusername", fs::create + fs::excl + fs::write, "User"s); fs::create_dir(dev_hdd0 + "disc/"); fs::create_dir(dev_hdd1 + "cache/"); fs::create_dir(dev_hdd1 + "game/"); fs::create_path(dev_hdd1); fs::create_path(dev_usb); #ifdef WITH_GDB_DEBUGGER fxm::make<GDBDebugServer>(); #endif // Initialize patch engine fxm::make_always<patch_engine>()->append(fs::get_config_dir() + "/patch.yml"); }
void log(const LogMessage &msg) override { std::string text = msg.mText; if (mPrependChannelName) { text.insert(0, gTypeNameTable[static_cast<u32>(msg.mType)].mName); if (msg.mType == Log::TTY) { text = fmt::escape(text); if (text[text.length() - 1] != '\n') { text += '\n'; } } } mFile.write(text.c_str(), text.size()); }
inline void Write16LE(const fs::file& f, const u16 data) { f.write(&data, sizeof(data)); }
void Elf32_Phdr::LoadLE(const fs::file& f) { f.read(this, sizeof(*this)); }
inline u64 Read64LE(const fs::file& f) { u64 ret; f.read(&ret, sizeof(ret)); return ret; }
SettingsDialog::SettingsDialog(wxWindow* parent) : wxDialog(parent, wxID_ANY, "Settings", wxDefaultPosition) { // Load default config loaded = YAML::Load(g_cfg_defaults); // Incrementally load config.yml const fs::file config(fs::get_config_dir() + "/config.yml", fs::read + fs::write + fs::create); loaded += YAML::Load(config.to_string()); std::vector<std::unique_ptr<cfg_adapter>> pads; static const u32 width = 458; static const u32 height = 400; // Settings panels wxNotebook* nb_config = new wxNotebook(this, wxID_ANY, wxPoint(6, 6), wxSize(width, height)); wxPanel* p_system = new wxPanel(nb_config, wxID_ANY); wxPanel* p_core = new wxPanel(nb_config, wxID_ANY); wxPanel* p_graphics = new wxPanel(nb_config, wxID_ANY); wxPanel* p_audio = new wxPanel(nb_config, wxID_ANY); wxPanel* p_io = new wxPanel(nb_config, wxID_ANY); wxPanel* p_misc = new wxPanel(nb_config, wxID_ANY); wxPanel* p_networking = new wxPanel(nb_config, wxID_ANY); nb_config->AddPage(p_core, "Core"); nb_config->AddPage(p_graphics, "Graphics"); nb_config->AddPage(p_audio, "Audio"); nb_config->AddPage(p_io, "Input / Output"); nb_config->AddPage(p_misc, "Misc"); nb_config->AddPage(p_networking, "Networking"); nb_config->AddPage(p_system, "System"); wxBoxSizer* s_subpanel_core = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* s_subpanel_core1 = new wxBoxSizer(wxVERTICAL); wxBoxSizer* s_subpanel_core2 = new wxBoxSizer(wxVERTICAL); wxBoxSizer* s_subpanel_graphics = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* s_subpanel_graphics1 = new wxBoxSizer(wxVERTICAL); wxBoxSizer* s_subpanel_graphics2 = new wxBoxSizer(wxVERTICAL); wxBoxSizer* s_subpanel_audio = new wxBoxSizer(wxVERTICAL); wxBoxSizer* s_subpanel_io = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* s_subpanel_io1 = new wxBoxSizer(wxVERTICAL); wxBoxSizer* s_subpanel_io2 = new wxBoxSizer(wxVERTICAL); wxBoxSizer* s_subpanel_system = new wxBoxSizer(wxVERTICAL); wxBoxSizer* s_subpanel_misc = new wxBoxSizer(wxVERTICAL); wxBoxSizer* s_subpanel_networking = new wxBoxSizer(wxVERTICAL); // Core wxStaticBoxSizer* s_round_core_lle = new wxStaticBoxSizer(wxVERTICAL, p_core, "Load libraries"); chbox_list_core_lle = new wxCheckListBox(p_core, wxID_ANY, wxDefaultPosition, wxDefaultSize, {}, wxLB_EXTENDED); chbox_list_core_lle->Bind(wxEVT_CHECKLISTBOX, &SettingsDialog::OnModuleListItemToggled, this); wxTextCtrl* s_module_search_box = new wxTextCtrl(p_core, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, {}); s_module_search_box->Bind(wxEVT_TEXT, &SettingsDialog::OnSearchBoxTextChanged, this); // Graphics wxStaticBoxSizer* s_round_gs_render = new wxStaticBoxSizer(wxVERTICAL, p_graphics, "Rendering API"); wxStaticBoxSizer* s_round_gs_d3d_adapter = new wxStaticBoxSizer(wxVERTICAL, p_graphics, "D3D Adapter"); wxStaticBoxSizer* s_round_gs_res = new wxStaticBoxSizer(wxVERTICAL, p_graphics, "Resolution"); wxStaticBoxSizer* s_round_gs_aspect = new wxStaticBoxSizer(wxVERTICAL, p_graphics, "Aspect ratio"); wxStaticBoxSizer* s_round_gs_frame_limit = new wxStaticBoxSizer(wxVERTICAL, p_graphics, "Frame limit"); // Input / Output wxStaticBoxSizer* s_round_io_pad_handler = new wxStaticBoxSizer(wxVERTICAL, p_io, "Controller handler"); wxStaticBoxSizer* s_round_io_keyboard_handler = new wxStaticBoxSizer(wxVERTICAL, p_io, "Keyboard handler"); wxStaticBoxSizer* s_round_io_mouse_handler = new wxStaticBoxSizer(wxVERTICAL, p_io, "Mouse handler"); wxStaticBoxSizer* s_round_io_camera = new wxStaticBoxSizer(wxVERTICAL, p_io, "Camera"); wxStaticBoxSizer* s_round_io_camera_type = new wxStaticBoxSizer(wxVERTICAL, p_io, "Camera type"); // Audio wxStaticBoxSizer* s_round_audio_out = new wxStaticBoxSizer(wxVERTICAL, p_audio, "Audio out"); // Networking wxStaticBoxSizer* s_round_net_status = new wxStaticBoxSizer(wxVERTICAL, p_networking, "Connection status"); // System wxStaticBoxSizer* s_round_sys_lang = new wxStaticBoxSizer(wxVERTICAL, p_system, "Language"); wxRadioBox* rbox_ppu_decoder; wxRadioBox* rbox_spu_decoder; wxComboBox* cbox_gs_render = new wxComboBox(p_graphics, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(150, -1), 0, NULL, wxCB_READONLY); wxComboBox* cbox_gs_d3d_adapter = new wxComboBox(p_graphics, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(150, -1), 0, NULL, wxCB_READONLY); wxComboBox* cbox_gs_resolution = new wxComboBox(p_graphics, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(150, -1), 0, NULL, wxCB_READONLY); wxComboBox* cbox_gs_aspect = new wxComboBox(p_graphics, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(150, -1), 0, NULL, wxCB_READONLY); wxComboBox* cbox_gs_frame_limit = new wxComboBox(p_graphics, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(150, -1), 0, NULL, wxCB_READONLY); wxComboBox* cbox_pad_handler = new wxComboBox(p_io, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(150, -1), 0, NULL, wxCB_READONLY);; wxComboBox* cbox_keyboard_handler = new wxComboBox(p_io, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(150, -1), 0, NULL, wxCB_READONLY); wxComboBox* cbox_mouse_handler = new wxComboBox(p_io, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(150, -1), 0, NULL, wxCB_READONLY); wxComboBox* cbox_camera = new wxComboBox(p_io, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(150, -1), 0, NULL, wxCB_READONLY); wxComboBox* cbox_camera_type = new wxComboBox(p_io, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(150, -1), 0, NULL, wxCB_READONLY); wxComboBox* cbox_audio_out = new wxComboBox(p_audio, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(150, -1), 0, NULL, wxCB_READONLY); wxComboBox* cbox_net_status = new wxComboBox(p_networking, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY); wxComboBox* cbox_sys_lang = new wxComboBox(p_system, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY); wxCheckBox* chbox_core_hook_stfunc = new wxCheckBox(p_core, wxID_ANY, "Hook static functions"); wxCheckBox* chbox_core_load_liblv2 = new wxCheckBox(p_core, wxID_ANY, "Load liblv2.sprx"); wxCheckBox* chbox_vfs_enable_host_root = new wxCheckBox(p_system, wxID_ANY, "Enable /host_root/"); wxCheckBox* chbox_gs_log_prog = new wxCheckBox(p_graphics, wxID_ANY, "Log shader programs"); wxCheckBox* chbox_gs_dump_depth = new wxCheckBox(p_graphics, wxID_ANY, "Write depth buffer"); wxCheckBox* chbox_gs_dump_color = new wxCheckBox(p_graphics, wxID_ANY, "Write color buffers"); wxCheckBox* chbox_gs_read_color = new wxCheckBox(p_graphics, wxID_ANY, "Read color buffers"); wxCheckBox* chbox_gs_read_depth = new wxCheckBox(p_graphics, wxID_ANY, "Read depth buffer"); wxCheckBox* chbox_gs_vsync = new wxCheckBox(p_graphics, wxID_ANY, "VSync"); wxCheckBox* chbox_gs_debug_output = new wxCheckBox(p_graphics, wxID_ANY, "Debug output"); wxCheckBox* chbox_gs_overlay = new wxCheckBox(p_graphics, wxID_ANY, "Debug overlay"); wxCheckBox* chbox_gs_gl_legacy_buffers = new wxCheckBox(p_graphics, wxID_ANY, "Use legacy OpenGL buffers"); wxCheckBox* chbox_audio_dump = new wxCheckBox(p_audio, wxID_ANY, "Dump to file"); wxCheckBox* chbox_audio_conv = new wxCheckBox(p_audio, wxID_ANY, "Convert to 16-bit"); wxCheckBox* chbox_hle_exitonstop = new wxCheckBox(p_misc, wxID_ANY, "Exit RPCS3 when process finishes"); wxCheckBox* chbox_hle_always_start = new wxCheckBox(p_misc, wxID_ANY, "Always start after boot"); wxCheckBox* chbox_dbg_ap_systemcall = new wxCheckBox(p_misc, wxID_ANY, "Automatically pause at system call"); wxCheckBox* chbox_dbg_ap_functioncall = new wxCheckBox(p_misc, wxID_ANY, "Automatically pause at function call"); { // Sort string vector alphabetically static const auto sort_string_vector = [](std::vector<std::string>& vec) { std::sort(vec.begin(), vec.end(), [](const std::string &str1, const std::string &str2) { return str1 < str2; }); }; auto&& data = loaded["Core"]["Load libraries"].as<std::vector<std::string>, std::initializer_list<std::string>>({}); sort_string_vector(data); // List selected modules first for (const auto& unk : data) { lle_module_list.insert(lle_module_list.end(), std::pair<std::string, bool>(unk, true)); chbox_list_core_lle->Check(chbox_list_core_lle->Append(unk)); } const std::string& lle_dir = Emu.GetLibDir(); // TODO std::unordered_set<std::string> set(data.begin(), data.end()); std::vector<std::string> lle_module_list_unselected; for (const auto& prxf : fs::dir(lle_dir)) { // List found unselected modules if (!prxf.is_directory && ppu_prx_object(fs::file(lle_dir + prxf.name)) == elf_error::ok && !set.count(prxf.name)) { lle_module_list_unselected.push_back(prxf.name); } } sort_string_vector(lle_module_list_unselected); for (const auto& prxf : lle_module_list_unselected) { lle_module_list.insert(lle_module_list.end(), std::pair<std::string, bool>(prxf, false)); chbox_list_core_lle->Check(chbox_list_core_lle->Append(prxf), false); } lle_module_list_unselected.clear(); } radiobox_pad_helper ppu_decoder_modes({ "Core", "PPU decoder" }); rbox_ppu_decoder = new wxRadioBox(p_core, wxID_ANY, "PPU decoder", wxDefaultPosition, wxSize(-1, -1), ppu_decoder_modes, 1); pads.emplace_back(std::make_unique<radiobox_pad>(std::move(ppu_decoder_modes), rbox_ppu_decoder)); radiobox_pad_helper spu_decoder_modes({ "Core", "SPU decoder" }); rbox_spu_decoder = new wxRadioBox(p_core, wxID_ANY, "SPU decoder", wxDefaultPosition, wxSize(-1, -1), spu_decoder_modes, 1); pads.emplace_back(std::make_unique<radiobox_pad>(std::move(spu_decoder_modes), rbox_spu_decoder)); rbox_spu_decoder->Enable(3, false); // TODO pads.emplace_back(std::make_unique<checkbox_pad>(cfg_location{ "Core", "Hook static functions" }, chbox_core_hook_stfunc)); pads.emplace_back(std::make_unique<checkbox_pad>(cfg_location{ "Core", "Load liblv2.sprx only" }, chbox_core_load_liblv2)); pads.emplace_back(std::make_unique<checkbox_pad>(cfg_location{ "VFS", "Enable /host_root/" }, chbox_vfs_enable_host_root)); pads.emplace_back(std::make_unique<combobox_pad>(cfg_location{ "Video", "Rendering API" }, cbox_gs_render)); pads.emplace_back(std::make_unique<combobox_pad>(cfg_location{ "Video", "Resolution" }, cbox_gs_resolution)); pads.emplace_back(std::make_unique<combobox_pad>(cfg_location{ "Video", "Aspect ratio" }, cbox_gs_aspect)); pads.emplace_back(std::make_unique<combobox_pad>(cfg_location{ "Video", "Frame limit" }, cbox_gs_frame_limit)); pads.emplace_back(std::make_unique<checkbox_pad>(cfg_location{ "Video", "Log shader programs" }, chbox_gs_log_prog)); pads.emplace_back(std::make_unique<checkbox_pad>(cfg_location{ "Video", "Write depth buffer" }, chbox_gs_dump_depth)); pads.emplace_back(std::make_unique<checkbox_pad>(cfg_location{ "Video", "Write color buffers" }, chbox_gs_dump_color)); pads.emplace_back(std::make_unique<checkbox_pad>(cfg_location{ "Video", "Read color buffers" }, chbox_gs_read_color)); pads.emplace_back(std::make_unique<checkbox_pad>(cfg_location{ "Video", "Read depth buffer" }, chbox_gs_read_depth)); pads.emplace_back(std::make_unique<checkbox_pad>(cfg_location{ "Video", "VSync" }, chbox_gs_vsync)); pads.emplace_back(std::make_unique<checkbox_pad>(cfg_location{ "Video", "Debug output" }, chbox_gs_debug_output)); pads.emplace_back(std::make_unique<checkbox_pad>(cfg_location{ "Video", "Debug overlay" }, chbox_gs_overlay)); pads.emplace_back(std::make_unique<checkbox_pad>(cfg_location{ "Video", "Use legacy OpenGL buffers (Debug)" }, chbox_gs_gl_legacy_buffers)); pads.emplace_back(std::make_unique<combobox_pad>(cfg_location{ "Audio", "Renderer" }, cbox_audio_out)); pads.emplace_back(std::make_unique<checkbox_pad>(cfg_location{ "Audio", "Dump to file" }, chbox_audio_dump)); pads.emplace_back(std::make_unique<checkbox_pad>(cfg_location{ "Audio", "Convert to 16-bit" }, chbox_audio_conv)); pads.emplace_back(std::make_unique<combobox_pad>(cfg_location{ "Input/Output", "Controller" }, cbox_pad_handler)); pads.emplace_back(std::make_unique<combobox_pad>(cfg_location{ "Input/Output", "Keyboard" }, cbox_keyboard_handler)); pads.emplace_back(std::make_unique<combobox_pad>(cfg_location{ "Input/Output", "Mouse" }, cbox_mouse_handler)); pads.emplace_back(std::make_unique<combobox_pad>(cfg_location{ "Input/Output", "Camera" }, cbox_camera)); pads.emplace_back(std::make_unique<combobox_pad>(cfg_location{ "Input/Output", "Camera type" }, cbox_camera_type)); pads.emplace_back(std::make_unique<combobox_pad>(cfg_location{ "Net", "Connection status" }, cbox_net_status)); pads.emplace_back(std::make_unique<combobox_pad>(cfg_location{ "System", "Language" }, cbox_sys_lang)); pads.emplace_back(std::make_unique<checkbox_pad>(cfg_location{ "Miscellaneous", "Exit RPCS3 when process finishes" }, chbox_hle_exitonstop)); pads.emplace_back(std::make_unique<checkbox_pad>(cfg_location{ "Miscellaneous", "Always start after boot" }, chbox_hle_always_start)); pads.emplace_back(std::make_unique<checkbox_pad>(cfg_location{ "Miscellaneous", "Automatically pause at system call" }, chbox_dbg_ap_systemcall)); pads.emplace_back(std::make_unique<checkbox_pad>(cfg_location{ "Miscellaneous", "Automatically pause at function call" }, chbox_dbg_ap_functioncall)); #ifdef _MSC_VER Microsoft::WRL::ComPtr<IDXGIFactory4> dxgi_factory; if (SUCCEEDED(CreateDXGIFactory(IID_PPV_ARGS(&dxgi_factory)))) { Microsoft::WRL::ComPtr<IDXGIAdapter> adapter; for (UINT id = 0; dxgi_factory->EnumAdapters(id, adapter.ReleaseAndGetAddressOf()) != DXGI_ERROR_NOT_FOUND; id++) { DXGI_ADAPTER_DESC desc; adapter->GetDesc(&desc); cbox_gs_d3d_adapter->Append(desc.Description); } pads.emplace_back(std::make_unique<combobox_pad>(cfg_location{ "Video", "D3D12", "Adapter" }, cbox_gs_d3d_adapter)); } else #endif { cbox_gs_d3d_adapter->Enable(false); } // Core s_round_core_lle->Add(chbox_list_core_lle, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_core_lle->Add(s_module_search_box, wxSizerFlags().Border(wxALL, 5).Expand()); // Rendering s_round_gs_render->Add(cbox_gs_render, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_gs_d3d_adapter->Add(cbox_gs_d3d_adapter, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_gs_res->Add(cbox_gs_resolution, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_gs_aspect->Add(cbox_gs_aspect, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_gs_frame_limit->Add(cbox_gs_frame_limit, wxSizerFlags().Border(wxALL, 5).Expand()); // Input/Output s_round_io_pad_handler->Add(cbox_pad_handler, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_io_keyboard_handler->Add(cbox_keyboard_handler, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_io_mouse_handler->Add(cbox_mouse_handler, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_io_camera->Add(cbox_camera, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_io_camera_type->Add(cbox_camera_type, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_audio_out->Add(cbox_audio_out, wxSizerFlags().Border(wxALL, 5).Expand()); // Networking s_round_net_status->Add(cbox_net_status, wxSizerFlags().Border(wxALL, 5).Expand()); // System s_round_sys_lang->Add(cbox_sys_lang, wxSizerFlags().Border(wxALL, 5).Expand()); // Core s_subpanel_core1->Add(rbox_ppu_decoder, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_core1->Add(rbox_spu_decoder, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_core1->Add(chbox_core_hook_stfunc, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_core1->Add(chbox_core_load_liblv2, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_core2->Add(s_round_core_lle, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_core->Add(s_subpanel_core1); s_subpanel_core->Add(s_subpanel_core2); // Graphics s_subpanel_graphics1->Add(s_round_gs_render, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics1->Add(s_round_gs_res, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics1->Add(s_round_gs_d3d_adapter, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics1->Add(chbox_gs_dump_color, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics1->Add(chbox_gs_read_color, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics1->Add(chbox_gs_dump_depth, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics1->Add(chbox_gs_read_depth, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics1->Add(chbox_gs_gl_legacy_buffers, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics2->Add(s_round_gs_aspect, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics2->Add(s_round_gs_frame_limit, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics2->AddSpacer(68); s_subpanel_graphics2->Add(chbox_gs_debug_output, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics2->Add(chbox_gs_overlay, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics2->Add(chbox_gs_log_prog, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics2->Add(chbox_gs_vsync, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(s_subpanel_graphics1); s_subpanel_graphics->Add(s_subpanel_graphics2); // Input - Output s_subpanel_io1->Add(s_round_io_pad_handler, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_io1->Add(s_round_io_keyboard_handler, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_io1->Add(s_round_io_mouse_handler, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_io2->Add(s_round_io_camera, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_io2->Add(s_round_io_camera_type, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_io->Add(s_subpanel_io1); s_subpanel_io->Add(s_subpanel_io2); // Audio s_subpanel_audio->Add(s_round_audio_out, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_audio->Add(chbox_audio_dump, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_audio->Add(chbox_audio_conv, wxSizerFlags().Border(wxALL, 5).Expand()); // Miscellaneous s_subpanel_misc->Add(chbox_hle_exitonstop, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_misc->Add(chbox_hle_always_start, wxSizerFlags().Border(wxALL, 5).Expand()); // Auto Pause s_subpanel_misc->Add(chbox_dbg_ap_systemcall, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_misc->Add(chbox_dbg_ap_functioncall, wxSizerFlags().Border(wxALL, 5).Expand()); // Networking s_subpanel_networking->Add(s_round_net_status, wxSizerFlags().Border(wxALL, 5).Expand()); // System s_subpanel_system->Add(chbox_vfs_enable_host_root, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_system->Add(s_round_sys_lang, wxSizerFlags().Border(wxALL, 5).Expand()); // Buttons wxBoxSizer* s_b_panel(new wxBoxSizer(wxHORIZONTAL)); s_b_panel->Add(new wxButton(this, wxID_OK), wxSizerFlags().Border(wxALL, 5).Bottom()); s_b_panel->Add(new wxButton(this, wxID_CANCEL), wxSizerFlags().Border(wxALL, 5).Bottom()); // Resize panels SetSizerAndFit(s_subpanel_core, false); SetSizerAndFit(s_subpanel_graphics, false); SetSizerAndFit(s_subpanel_io, false); SetSizerAndFit(s_subpanel_audio, false); SetSizerAndFit(s_subpanel_misc, false); SetSizerAndFit(s_subpanel_networking, false); SetSizerAndFit(s_subpanel_system, false); SetSizerAndFit(s_b_panel, false); SetSize(width + 26, height + 80); if (ShowModal() == wxID_OK) { std::set<std::string> lle_selected; for (auto& i : lle_module_list) { if (i.second) // selected { lle_selected.emplace(i.first); } } saved.reset(); saved["Core"]["Load libraries"] = std::vector<std::string>(lle_selected.begin(), lle_selected.end()); for (auto& pad : pads) { pad->save(); } loaded += saved; YAML::Emitter out; emit(out, loaded); // Save config config.seek(0); config.trunc(0); config.write(out.c_str(), out.size()); } }
inline void Write8(const fs::file& f, const u8 data) { f.write(&data, sizeof(data)); }
bool Rpcs3App::OnInit() { static const wxCmdLineEntryDesc desc[] { { wxCMD_LINE_SWITCH, "h", "help", "Command line options:\nh (help): Help and commands\nt (test): For directly executing a (S)ELF", wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP }, { wxCMD_LINE_SWITCH, "t", "test", "Run in test mode on (S)ELF", wxCMD_LINE_VAL_NONE }, { wxCMD_LINE_PARAM, NULL, NULL, "(S)ELF", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, { wxCMD_LINE_NONE } }; parser.SetDesc(desc); parser.SetCmdLine(argc, argv); if (parser.Parse()) { // help was given, terminating this->Exit(); } s_gui_cfg.open(fs::get_config_dir() + "/config_gui.yml", fs::read + fs::write + fs::create); g_gui_cfg = YAML::Load(s_gui_cfg.to_string()); EmuCallbacks callbacks; callbacks.call_after = [](std::function<void()> func) { wxGetApp().CallAfter(std::move(func)); }; callbacks.process_events = [this]() { m_MainFrame->Update(); wxGetApp().ProcessPendingEvents(); }; callbacks.exit = [this]() { wxGetApp().Exit(); }; callbacks.send_dbg_command = [](DbgCommand id, cpu_thread* t) { wxGetApp().SendDbgCommand(id, t); }; callbacks.get_kb_handler = PURE_EXPR(g_cfg_kb_handler.get()()); callbacks.get_mouse_handler = PURE_EXPR(g_cfg_mouse_handler.get()()); callbacks.get_pad_handler = PURE_EXPR(g_cfg_pad_handler.get()()); callbacks.get_gs_frame = [](frame_type type, int w, int h) -> std::unique_ptr<GSFrameBase> { switch (type) { case frame_type::OpenGL: return std::make_unique<GLGSFrame>(w, h); case frame_type::DX12: return std::make_unique<GSFrame>("DirectX 12", w, h); case frame_type::Null: return std::make_unique<GSFrame>("Null", w, h); case frame_type::Vulkan: return std::make_unique<GSFrame>("Vulkan", w, h); } throw EXCEPTION("Invalid Frame Type (0x%x)", type); }; callbacks.get_gs_render = PURE_EXPR(g_cfg_gs_render.get()()); callbacks.get_audio = PURE_EXPR(g_cfg_audio_render.get()()); callbacks.get_msg_dialog = []() -> std::shared_ptr<MsgDialogBase> { return std::make_shared<MsgDialogFrame>(); }; callbacks.get_save_dialog = []() -> std::unique_ptr<SaveDialogBase> { return std::make_unique<SaveDialogFrame>(); }; Emu.SetCallbacks(std::move(callbacks)); TheApp = this; SetAppName("RPCS3"); wxInitAllImageHandlers(); Emu.Init(); m_MainFrame = new MainFrame(); SetTopWindow(m_MainFrame); m_MainFrame->Show(); m_MainFrame->DoSettings(true); OnArguments(parser); return true; }
inline void Write32LE(const fs::file& f, const u32 data) { f.write(&data, sizeof(data)); }
inline void Write16(const fs::file& f, const be_t<u16> data) { f.write(&data, sizeof(data)); }
__forceinline void Write64LE(const fs::file& f, const u64 data) { f.write(&data, sizeof(data)); }
bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>& sync, const std::string& pkg_filepath) { const std::size_t BUF_SIZE = 8192 * 1024; // 8 MB std::vector<fs::file> filelist; u32 cur_file=0; fs::file original_file(pkg_filepath); original_file.seek(pkg_f.pos()); filelist.push_back(std::move(original_file)); // Save current file offset (probably zero) const u64 start_offset = pkg_f.pos(); u64 cur_offset = start_offset; u64 cur_file_offset = start_offset; // Get basic PKG information PKGHeader header; auto archive_seek = [&](const s64 new_offset, const fs::seek_mode damode = fs::seek_set) { if(damode == fs::seek_set) cur_offset = new_offset; else if (damode == fs::seek_cur) cur_offset += new_offset; u64 _offset = 0; for (u32 i = 0; i < filelist.size(); i++) { if (cur_offset < (_offset + filelist[i].size())) { cur_file = i; cur_file_offset = cur_offset - _offset; filelist[i].seek(cur_file_offset); break; } _offset += filelist[i].size(); } }; auto archive_read = [&](const void *data_ptr, const u64 num_bytes) { u64 num_bytes_left = filelist[cur_file].size() - cur_file_offset; //check if it continues in another file if (num_bytes > num_bytes_left) { filelist[cur_file].read((u8 *)data_ptr, num_bytes_left); if ((cur_file + 1) < filelist.size()) cur_file++; else { cur_offset += num_bytes_left; cur_file_offset = filelist[cur_file].size(); return num_bytes_left; } u64 num_read = filelist[cur_file].read((u8 *)data_ptr + num_bytes_left, num_bytes - num_bytes_left); cur_offset += (num_read + num_bytes_left); cur_file_offset = num_read; return (num_read+num_bytes_left); } u64 num_read = filelist[cur_file].read((u8 *)data_ptr, num_bytes); cur_offset += num_read; cur_file_offset += num_read; return num_read; }; if (archive_read(&header, sizeof(header)) != sizeof(header)) { LOG_ERROR(LOADER, "PKG file is too short!"); return false; } if (header.pkg_magic != "\x7FPKG"_u32) { LOG_ERROR(LOADER, "Not a PKG file!"); return false; } switch (const u16 type = header.pkg_type) { case PKG_RELEASE_TYPE_DEBUG: break; case PKG_RELEASE_TYPE_RELEASE: break; default: { LOG_ERROR(LOADER, "Unknown PKG type (0x%x)", type); return false; } } switch (const u16 platform = header.pkg_platform) { case PKG_PLATFORM_TYPE_PS3: break; case PKG_PLATFORM_TYPE_PSP: break; default: { LOG_ERROR(LOADER, "Unknown PKG platform (0x%x)", platform); return false; } } if (header.pkg_size > pkg_f.size()) { //Check if multi-files pkg if (pkg_filepath.length() < 7 || pkg_filepath.substr(pkg_filepath.length() - 7).compare("_00.pkg") != 0) { LOG_ERROR(LOADER, "PKG file size mismatch (pkg_size=0x%llx)", header.pkg_size); return false; } std::string name_wo_number = pkg_filepath.substr(0, pkg_filepath.length() - 7); u64 cursize = pkg_f.size(); while (cursize != header.pkg_size) { std::string archive_filename = fmt::format("%s_%2d.pkg", name_wo_number, filelist.size()); fs::file archive_file(archive_filename); if (!archive_file) { LOG_ERROR(LOADER, "Missing part of the multi-files pkg: %s", archive_filename); return false; } cursize += archive_file.size(); filelist.push_back(std::move(archive_file)); } } if (header.data_size + header.data_offset > header.pkg_size) { LOG_ERROR(LOADER, "PKG data size mismatch (data_size=0x%llx, data_offset=0x%llx, file_size=0x%llx)", header.data_size, header.data_offset, header.pkg_size); return false; } be_t<u32> drm_type{0}; be_t<u32> content_type{0}; archive_seek(header.pkg_info_off); for (u32 i = 0; i < header.pkg_info_num; i++) { struct packet_T { be_t<u32> id; be_t<u32> size; } packet; archive_read(&packet, sizeof(packet)); // TODO switch (+packet.id) { case 0x1: { if (packet.size == sizeof(drm_type)) { archive_read(&drm_type, sizeof(drm_type)); continue; } break; } case 0x2: { if (packet.size == sizeof(content_type)) { archive_read(&content_type, sizeof(content_type)); continue; } break; } } archive_seek(packet.size, fs::seek_cur); } // Allocate buffer with BUF_SIZE size or more if required const std::unique_ptr<u128[]> buf(new u128[std::max<u64>(BUF_SIZE, sizeof(PKGEntry) * header.file_count) / sizeof(u128)]); // Define decryption subfunction (`psp` arg selects the key for specific block) auto decrypt = [&](u64 offset, u64 size, const uchar* key) -> u64 { archive_seek(start_offset + header.data_offset + offset); // Read the data and set available size const u64 read = archive_read(buf.get(), size); // Get block count const u64 blocks = (read + 15) / 16; if (header.pkg_type == PKG_RELEASE_TYPE_DEBUG) { // Debug key be_t<u64> input[8] = { header.qa_digest[0], header.qa_digest[0], header.qa_digest[1], header.qa_digest[1], }; for (u64 i = 0; i < blocks; i++) { // Initialize stream cipher for current position input[7] = offset / 16 + i; union sha1_hash { u8 data[20]; u128 _v128; } hash; sha1(reinterpret_cast<const u8*>(input), sizeof(input), hash.data); buf[i] ^= hash._v128; } } if (header.pkg_type == PKG_RELEASE_TYPE_RELEASE) { aes_context ctx; // Set encryption key for stream cipher aes_setkey_enc(&ctx, key, 128); // Initialize stream cipher for start position be_t<u128> input = header.klicensee.value() + offset / 16; // Increment stream position for every block for (u64 i = 0; i < blocks; i++, input++) { u128 key; aes_crypt_ecb(&ctx, AES_ENCRYPT, reinterpret_cast<const u8*>(&input), reinterpret_cast<u8*>(&key)); buf[i] ^= key; } } // Return the amount of data written in buf return read; }; std::array<uchar, 16> dec_key; if (header.pkg_platform == PKG_PLATFORM_TYPE_PSP && content_type >= 0x15 && content_type <= 0x17) { const uchar psp2t1[] = {0xE3, 0x1A, 0x70, 0xC9, 0xCE, 0x1D, 0xD7, 0x2B, 0xF3, 0xC0, 0x62, 0x29, 0x63, 0xF2, 0xEC, 0xCB}; const uchar psp2t2[] = {0x42, 0x3A, 0xCA, 0x3A, 0x2B, 0xD5, 0x64, 0x9F, 0x96, 0x86, 0xAB, 0xAD, 0x6F, 0xD8, 0x80, 0x1F}; const uchar psp2t3[] = {0xAF, 0x07, 0xFD, 0x59, 0x65, 0x25, 0x27, 0xBA, 0xF1, 0x33, 0x89, 0x66, 0x8B, 0x17, 0xD9, 0xEA}; aes_context ctx; aes_setkey_enc(&ctx, content_type == 0x15 ? psp2t1 : content_type == 0x16 ? psp2t2 : psp2t3, 128); aes_crypt_ecb(&ctx, AES_ENCRYPT, reinterpret_cast<const uchar*>(&header.klicensee), dec_key.data()); decrypt(0, header.file_count * sizeof(PKGEntry), dec_key.data()); } else { std::memcpy(dec_key.data(), PKG_AES_KEY, dec_key.size()); decrypt(0, header.file_count * sizeof(PKGEntry), header.pkg_platform == PKG_PLATFORM_TYPE_PSP ? PKG_AES_KEY2 : dec_key.data()); } std::vector<PKGEntry> entries(header.file_count); std::memcpy(entries.data(), buf.get(), entries.size() * sizeof(PKGEntry)); for (const auto& entry : entries) { const bool is_psp = (entry.type & PKG_FILE_ENTRY_PSP) != 0; if (entry.name_size > 256) { LOG_ERROR(LOADER, "PKG name size is too big (0x%x)", entry.name_size); continue; } decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : dec_key.data()); const std::string name(reinterpret_cast<char*>(buf.get()), entry.name_size); LOG_NOTICE(LOADER, "Entry 0x%08x: %s", entry.type, name); switch (entry.type & 0xff) { case PKG_FILE_ENTRY_NPDRM: case PKG_FILE_ENTRY_NPDRMEDAT: case PKG_FILE_ENTRY_SDAT: case PKG_FILE_ENTRY_REGULAR: case PKG_FILE_ENTRY_UNK1: case 0xe: case 0x10: case 0x11: case 0x13: case 0x15: case 0x16: { const std::string path = dir + name; const bool did_overwrite = fs::is_file(path); if (did_overwrite && (entry.type&PKG_FILE_ENTRY_OVERWRITE) == 0) { LOG_NOTICE(LOADER, "Didn't overwrite %s", name); break; } if (fs::file out{ path, fs::rewrite }) { for (u64 pos = 0; pos < entry.file_size; pos += BUF_SIZE) { const u64 block_size = std::min<u64>(BUF_SIZE, entry.file_size - pos); if (decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : dec_key.data()) != block_size) { LOG_ERROR(LOADER, "Failed to extract file %s", path); break; } if (out.write(buf.get(), block_size) != block_size) { LOG_ERROR(LOADER, "Failed to write file %s", path); break; } if (sync.fetch_add((block_size + 0.0) / header.data_size) < 0.) { LOG_ERROR(LOADER, "Package installation cancelled: %s", dir); return false; } } if (did_overwrite) { LOG_WARNING(LOADER, "Overwritten file %s", name); } else { LOG_NOTICE(LOADER, "Created file %s", name); } } else { LOG_ERROR(LOADER, "Failed to create file %s", path); } break; } case PKG_FILE_ENTRY_FOLDER: case 0x12: { const std::string path = dir + name; if (fs::create_dir(path)) { LOG_NOTICE(LOADER, "Created directory %s", name); } else if (fs::is_dir(path)) { LOG_WARNING(LOADER, "Reused existing directory %s", name); } else { LOG_ERROR(LOADER, "Failed to create directory %s", path); } break; } default: { LOG_ERROR(LOADER, "Unknown PKG entry type (0x%x) %s", entry.type, name); } } } LOG_SUCCESS(LOADER, "Package successfully installed to %s", dir); return true; }
inline void Write64(const fs::file& f, const be_t<u64> data) { f.write(&data, sizeof(data)); }
inline void Write32(const fs::file& f, const be_t<u32> data) { f.write(&data, sizeof(data)); }