Example #1
0
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;
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #4
0
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;
}
Example #5
0
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());
}
Example #6
0
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;
}
Example #7
0
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;
}
Example #8
0
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;
}
Example #9
0
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);
	}
}
Example #10
0
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;
}
Example #11
0
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);
}
Example #12
0
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;
}
Example #13
0
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;
}
Example #14
0
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;
}
Example #15
0
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;
}
Example #16
0
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());
}
Example #17
0
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");
}
Example #18
0
	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());
	}
Example #19
0
inline void Write16LE(const fs::file& f, const u16 data)
{
	f.write(&data, sizeof(data));
}
Example #20
0
void Elf32_Phdr::LoadLE(const fs::file& f)
{
	f.read(this, sizeof(*this));
}
Example #21
0
inline u64 Read64LE(const fs::file& f)
{
	u64 ret;
	f.read(&ret, sizeof(ret));
	return ret;
}
Example #22
0
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());
	}
}
Example #23
0
inline void Write8(const fs::file& f, const u8 data)
{
	f.write(&data, sizeof(data));
}
Example #24
0
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;
}
Example #25
0
inline void Write32LE(const fs::file& f, const u32 data)
{
	f.write(&data, sizeof(data));
}
Example #26
0
inline void Write16(const fs::file& f, const be_t<u16> data)
{
	f.write(&data, sizeof(data));
}
Example #27
0
__forceinline void Write64LE(const fs::file& f, const u64 data)
{
	f.write(&data, sizeof(data));
}
Example #28
0
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;
}
Example #29
0
inline void Write64(const fs::file& f, const be_t<u64> data)
{
	f.write(&data, sizeof(data));
}
Example #30
0
inline void Write32(const fs::file& f, const be_t<u32> data)
{
	f.write(&data, sizeof(data));
}