forked from blastrock/pkgj
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstall.cpp
More file actions
312 lines (259 loc) · 10.2 KB
/
Copy pathinstall.cpp
File metadata and controls
312 lines (259 loc) · 10.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
#include "install.hpp"
#include "psx.hpp"
#include "extractzip.hpp"
#include "file.hpp"
#include "log.hpp"
#include "sfo.hpp"
#include "sqlite.hpp"
#include "psx.hpp"
#include <boost/scope_exit.hpp>
#include <psp2/io/fcntl.h>
#include <psp2/promoterutil.h>
std::vector<std::string> pkgi_get_installed_games()
{
return pkgi_list_dir_contents("ux0:app");
}
std::vector<std::string> pkgi_get_installed_themes()
{
return pkgi_list_dir_contents("ux0:theme");
}
namespace
{
std::string pkgi_extract_package_version(const std::string& package)
{
const auto sfo = pkgi_load(fmt::format("{}/sce_sys/param.sfo", package));
return pkgi_sfo_get_string(sfo.data(), sfo.size(), "APP_VER");
}
}
std::string pkgi_get_game_version(const std::string& titleid)
{
const auto patch_dir = fmt::format("ux0:patch/{}", titleid);
if (pkgi_file_exists(patch_dir.c_str()))
return pkgi_extract_package_version(patch_dir);
const auto game_dir = fmt::format("ux0:app/{}", titleid);
if (pkgi_file_exists(game_dir.c_str()))
return pkgi_extract_package_version(game_dir);
return "";
}
bool pkgi_dlc_is_installed(const char* content)
{
return pkgi_file_exists(
fmt::format("ux0:addcont/{:.9}/{:.16}", content + 7, content + 20)
.c_str());
}
bool pkgi_psm_is_installed(const char* titleid)
{
return pkgi_file_exists(fmt::format("ux0:psm/{}", titleid).c_str());
}
bool pkgi_psp_is_installed(const char* psppartition, const char* content)
{
return pkgi_file_exists(
fmt::format(
"{}pspemu/ISO/{:.9}.iso", psppartition, content + 7)
.c_str()) ||
pkgi_file_exists(fmt::format(
"{}pspemu/PSP/GAME/{:.9}/EBOOT.PBP",
psppartition,
content + 7)
.c_str());
}
bool pkgi_psx_is_installed(const char* psppartition, const char* content)
{
bool game_exist = pkgi_file_exists(
fmt::format("{}pspemu/PSP/GAME/{:.9}", psppartition, content + 7)
.c_str());
if(!game_exist) {
game_exist = pkgi_is_psx_game_installed_titleid(std::string(content + 7, 9));
}
return game_exist;
}
void pkgi_install(const char* contentid)
{
char path[128];
snprintf(path, sizeof(path), "ux0:pkgj/%s", contentid);
LOG("Installing package from: %s", path);
const auto res = scePromoterUtilityPromotePkgWithRif(path, 1);
if (res < 0)
throw formatEx<std::runtime_error>(
"scePromoterUtilityPromotePkgWithRif failed: {:#08x}\n{}",
static_cast<uint32_t>(res),
static_cast<uint32_t>(res) == 0x80870004
? "Please check your NoNpDrm installation"
: "");
}
void pkgi_install_update(const std::string& titleid)
{
pkgi_mkdirs("ux0:patch");
const auto src = fmt::format("ux0:pkgj/{}", titleid);
LOGF("Installing patch from: {}", src);
const auto res = scePromoterUtilityPromotePkgWithRif(src.c_str(), 1);
if (res < 0)
throw formatEx<std::runtime_error>(
"scePromoterUtilityPromotePkgWithRif failed: {:#08x}",
static_cast<uint32_t>(res));
}
void pkgi_install_comppack(
const std::string& titleid, bool patch, const std::string& version)
{
const auto src = fmt::format("ux0:pkgj/{}-comp.ppk", titleid);
const auto dest = fmt::format("ux0:rePatch/{}", titleid);
if (!patch)
pkgi_rm((dest + "/patch_comppack_version").c_str());
pkgi_mkdirs(dest.c_str());
LOGF("Installing comppack: src={} dst={}", src, dest);
pkgi_extract_zip(src, dest);
pkgi_save(
fmt::format(
"{}/{}_comppack_version", dest, patch ? "patch" : "base"),
version.data(),
version.size());
}
CompPackVersion pkgi_get_comppack_versions(const std::string& titleid)
{
const std::string dir = fmt::format("ux0:rePatch/{}", titleid);
const bool present = pkgi_file_exists(dir.c_str());
const auto base = [&]
{
try
{
const auto data = pkgi_load(dir + "/base_comppack_version");
return std::string(data.begin(), data.end());
}
catch (const std::exception& e)
{
LOGFW("Base comppack version not found: {}", e.what());
// return empty string if not found
return std::string{};
}
}();
const auto patch = [&]
{
try
{
const auto data = pkgi_load(dir + "/patch_comppack_version");
return std::string(data.begin(), data.end());
}
catch (const std::exception& e)
{
LOGFW("Patch comppack version not found: {}", e.what());
// return empty string if not found
return std::string{};
}
}();
return {present, base, patch};
}
void pkgi_install_psmgame(const char* contentid)
{
const std::string base = "ux0:temp/game";
pkgi_mkdirs(base.c_str());
const auto titleid = fmt::format("{:.9}", contentid + 7);
const auto src = fmt::format("ux0:pkgj/{}", contentid);
const auto dest = fmt::format("{}/{}", base, titleid);
LOGF("Moving PSM game: {} -> {}", src, dest);
int res = sceIoRename(src.c_str(), dest.c_str());
if (res < 0)
throw formatEx<std::runtime_error>(
"failed to rename: {:#08x}", static_cast<uint32_t>(res));
LOGF("Promoting PSM game at: {}", dest);
ScePromoterUtilityImportParams promote_args;
memset(&promote_args, 0, sizeof(promote_args));
strncpy(promote_args.path, base.c_str(), sizeof(promote_args.path) - 1);
strncpy(promote_args.titleid,
titleid.c_str(),
sizeof(promote_args.titleid) - 1);
promote_args.type = SCE_PKG_TYPE_PSM;
promote_args.attribute = 0x1;
res = scePromoterUtilityPromoteImport(&promote_args);
if (res < 0)
throw formatEx<std::runtime_error>(
"scePromoterUtilityPromoteImport failed: {:#08x}",
static_cast<uint32_t>(res));
}
void pkgi_install_pspgame(const char* partition, const char* contentid)
{
LOG("Installing PSP/PSX game");
const auto path = fmt::format("{}pkgj/{}", partition, contentid);
const auto eboot_path = fmt::format("{}/EBOOT.PBP", path);
const auto sce_sys_path = fmt::format("{}/sce_sys", path);
// determine disc id from the pbp file
std::string title_id = std::string(contentid + 7, 9);
std::string disc_id = pkgi_pbp_read_disc_id(eboot_path);
if(disc_id.length() < 9)
disc_id = title_id;
const auto dest = fmt::format("{}pspemu/PSP/GAME/{:.9}", partition, disc_id);
pkgi_mkdirs(fmt::format("{}pspemu/PSP/GAME", partition).c_str());
// sce_sys folder from pkg not included on psx and psp game
pkgi_delete_dir(sce_sys_path);
LOG("Installing PSX game: src=%s dst=%s", path.c_str(), dest.c_str());
int res = sceIoRename(path.c_str(), dest.c_str());
if (res < 0)
throw std::runtime_error(fmt::format(
"failed to rename: {:#08x}", static_cast<uint32_t>(res)));
// add game to installed psx games list so it comes up as installed.
pkgi_psx_add_installed_game(title_id, disc_id);
}
static void pkgi_move_merge(const std::string& from, const std::string& to)
{
LOGF("Merging PSX disc: {} into {}", from, to);
const auto fromType = pkgi_get_inode_type(from);
const auto toType = pkgi_get_inode_type(to);
if (toType == InodeType::NotExist ||
(fromType == InodeType::File && toType == InodeType::File))
pkgi_rename(from, to);
else if (fromType == InodeType::File && toType == InodeType::Directory)
throw formatEx("cannot replace directory {} by file {}", to, from);
else if (fromType == InodeType::Directory && toType == InodeType::File)
throw formatEx("cannot replace directory {} by file {}", from, to);
else if (fromType == InodeType::Directory && toType == InodeType::Directory)
{
const auto fromContents = pkgi_list_dir_contents(from);
for (const auto& fromContent : fromContents)
pkgi_move_merge(
fmt::format("{}/{}", from, fromContent),
fmt::format("{}/{}", to, fromContent));
}
else
throw formatEx(
"cannot merge {} ({}) and {} ({})",
from,
(int)fromType,
to,
(int)toType);
}
void pkgi_install_pspgame_as_iso(const char* partition, const char* contentid)
{
const auto path = fmt::format("{}pkgj/{}", partition, contentid);
const auto dest =
fmt::format("{}pspemu/PSP/GAME/{:.9}", partition, contentid + 7);
// this is actually a misnamed ISO file
const auto eboot = fmt::format("{}/EBOOT.PBP", path);
const auto content = fmt::format("{}/CONTENT.DAT", path);
const auto pspkey = fmt::format("{}/PSP-KEY.EDAT", path);
const auto isodest =
fmt::format("{}pspemu/ISO/{:.9}.iso", partition, contentid + 7);
pkgi_mkdirs(fmt::format("{}pspemu/ISO", partition).c_str());
LOG("Installing PSP game as ISO: src=%s dst=%s", path.c_str(), dest.c_str());
pkgi_rename(eboot.c_str(), isodest.c_str());
const auto content_exists = pkgi_file_exists(content.c_str());
const auto pspkey_exists = pkgi_file_exists(pspkey.c_str());
if (content_exists || pspkey_exists)
pkgi_mkdirs(dest.c_str());
if (content_exists)
pkgi_rename(
content.c_str(), fmt::format("{}/CONTENT.DAT", dest).c_str());
if (pspkey_exists)
pkgi_rename(
pspkey.c_str(), fmt::format("{}/PSP-KEY.EDAT", dest).c_str());
pkgi_delete_dir(path);
}
void pkgi_install_pspdlc(const char* partition, const char* contentid)
{
LOG("Installing PSP DLC");
const auto path = fmt::format("{}pkgj/{}", partition, contentid);
const auto dest =
fmt::format("{}pspemu/PSP/GAME/{:.9}", partition, contentid + 7);
pkgi_mkdirs(fmt::format("{}pspemu/PSP/GAME", partition).c_str());
LOG("Installing PSP DLC: src=%s dst=%s", path.c_str(), dest.c_str());
pkgi_move_merge(path, dest);
pkgi_delete_dir(path);
}