Files
LightningMods 36ca31d21b ItemzCore version: 1.4-V-2024-01-23T18:42:41
- Fixed dumping DLCs and AC w/p data
- Added an Install all PKGs option for folders with more than 1 PKG
- Installing a PKG will no longer boot you back to settings
- Carried over some improvements from the PS5 version of IF
- Replaced reg. vectors for ThreadSafeVectors
- Added the Chinese lang files
- Fixed a bug that would cause the Utility thread to deadlock
- Fixed a Bug that caused the daemon not to give a backtrace on 9.00
2024-01-23 18:56:00 -05:00

669 lines
30 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "utils.h"
#include "defines.h"
#include <sqlite3.h>
#include <iosfwd>
#include <string>
#include <fstream>
#include <map>
#include "game_saves.h"
#ifdef __ORBIS__
#include "installpkg.h"
#endif
#include "feature_classes.hpp"
char *err_msg = 0;
sqlite3 *db = NULL;
int count = 0;
// Function to sanitize a string for use in SQL
std::string sanitizeString(const std::string& str)
{
std::string results;
for ( std::string::const_iterator current = str.begin();
current != str.end();
++ current ) {
if ( *current == '\'' ) {
results.push_back( '\'');
}
results.push_back( *current );
}
return results;
}
sqlite3 *SQLiteOpenDb(char *path)
{
int ret;
struct stat sb;
// check if our sqlite db is already present in our path
ret = sceKernelStat(path, &sb);
if (ret != 0)
{
log_error("[ERROR][SQLLDR][%s][%d] sceKernelStat(%s) failed: 0x%08X", __FUNCTION__, __LINE__, path, ret);
goto sqlite_error_out;
}
ret = sqlite3_open_v2(path, &db, SQLITE_OPEN_READWRITE, NULL);
sqlite_error_out:
// return error is something went wrong errmsg on klogs
if (ret != SQLITE_OK)
{
log_error("[ERROR][SQLLDR][%s][%d] ERROR 0x%08X: %s", __FUNCTION__, __LINE__, ret, sqlite3_errmsg(db));
return NULL;
}
else
return db;
}
int callback(void *, int, char **, char **);
bool SQL_Load_DB(const char *dir)
{
if(db){
sqlite3_close(db), db = NULL;
}
db = SQLiteOpenDb((char *)dir);
if (db == NULL)
{
log_error("[SQLLDR] Cannot open database: %s", sqlite3_errmsg(db));
return false;
}
return true;
}
bool SQL_Exec(const char *smt, int (*cb)(void *, int, char **, char **))
{
log_info("Executing SQL Statement: %s", smt);
if (sqlite3_exec(db, smt, cb, 0, &err_msg) != SQLITE_OK)
{
log_info("Failed to select data");
log_info("SQL error: %s", err_msg);
sqlite3_free(err_msg);
return false;
}
else
return true;
}
int int_cb(void *in, int idc, char **argv, char **idc_2)
{
if (argv[0] != NULL) { // Check if argv[0] is not NULL
int *numb = (int *)in;
*numb = atoi(argv[0]);
}
else{
log_error("SQL CB argv[0] is NULL");
}
return 0;
}
/*
* Arguments:
*
* unused - Ignored in this case, see the documentation for sqlite3_exec
* count - The number of columns in the result set
* data - The row's data
* columns - The column names
static int token_cb(void *in, int count, char **data, char **columns)
{
char **result_str = (char **)in;
*result_str = sqlite3_mprintf("%q", data[0]);
return 0;
}
*/
/*
appdb = open_sqlite_db("/system_data/priv/mms/app.db");
read_hdd_savegames(userPath, list, appdb);
sqlite3_close(appdb);
typedef struct save_entry
{
char* name;
char* title_id;
char* path;
char* dir_name;
char* main_title;
char* sub_title;
char* detail;
char* mtime;
int numb_of_saves;
uint32_t userid;
uint32_t blocks;
uint16_t flags;
uint16_t type;
} save_entry_t;
*/
//SELECT COUNT(*) FROM savedata WHERE title_id = 'CUSA00744'
bool GameSave_Info(save_entry_t *item, int off)
{
std::string tmp;
int err = 0;
sqlite3_stmt *stmt;
if(title_id.get().empty()){
log_error("title_id is empty");
return false;
}
item->title_id = title_id.get();
if ((err = sceUserServiceGetForegroundUser(&item->userid)) != ITEMZCORE_SUCCESS)
{
log_error("[ERROR] sceUserServiceGetForegroundUser ERROR: %x", err);
return false;
}
tmp = fmt::format("/system_data/savedata/{0:x}/db/user/savedata.db", item->userid);
if (!SQL_Load_DB(tmp.c_str()))
return false;
item->numb_of_saves = 0;
tmp = fmt::format("SELECT COUNT(*) FROM savedata WHERE title_id = '{}'", item->title_id);
err = sqlite3_prepare_v2(db, tmp.c_str(), -1, &stmt, 0);
if(err){
log_error("Selecting data from DB Failed");
return false;
}
if (sqlite3_step(stmt) == SQLITE_ERROR) {
log_debug("Error when counting rows for item->numb_of_saves %s",sqlite3_errmsg(db));
return false;
}
else
item->numb_of_saves = sqlite3_column_int(stmt, 0);
log_debug("item->numb_of_saves: %d",item->numb_of_saves);
if(item->numb_of_saves == 0)
return false;
sqlite3_finalize(stmt);
tmp = fmt::format("SELECT * FROM savedata WHERE title_id = '{0:}' LIMIT 1 OFFSET {1:d}", item->title_id, off);
err = sqlite3_prepare_v2(db ,tmp.c_str(), -1, &stmt, 0);
if(err){
log_error("Selecting data from DB Failed");
return false;
}
while(1)
{
// fetch a rows status
err = sqlite3_step(stmt);
if(err == SQLITE_ROW)
{
item->dir_name = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2)));
item->main_title = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)));
item->sub_title = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4)));
item->detail = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 5)));
item->mtime = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 12)));
item->size = sqlite3_column_int(stmt,11);
item->blocks = sqlite3_column_int(stmt,9);
log_debug("item->detail: %s",item->detail.c_str());
}
else if(err == SQLITE_DONE){
// All rows finished
log_debug("All rows fetched");
break;
}
else if (err == SQLITE_ERROR){
return false;
}
}
sqlite3_finalize(stmt);
sqlite3_close(db);
return true;
}
bool If_Save_Exists(const char *userPath, save_entry_t *item)
{
std::string tmp;
int id = -1;
if (!SQL_Load_DB(userPath))
return false;
tmp = fmt::format("SELECT id FROM savedata WHERE dir_name = '{}' LIMIT 1", item->dir_name);
if (sqlite3_exec(db, tmp.c_str(), int_cb, &id, &err_msg) != SQLITE_OK || id == -1)
{
if (id == -1 && !err_msg)
log_error("[SAVE] No Game Saves Found for %s", item->title_id.c_str());
else
log_error("[SAVE] Failed to fetch data: %s", sqlite3_errmsg(db));
sqlite3_close(db);
return false;
}
fmt::print("[SAVE] ID Found: %i", id);
sqlite3_close(db);
return true;
}
bool AppDBVisiable(std::string tid, APP_DB_VIS opt, int write_value)
{
std::string tmp;
u32 userId = -1;
int ret, vis = -1;
log_info("[SQL] tid %s write_value %i", tid.c_str(), write_value);
if (!SQL_Load_DB(APP_DB))
return false;
if ((ret = sceUserServiceGetForegroundUser(&userId)) != ITEMZCORE_SUCCESS)
{
log_error("[ERROR] sceUserServiceGetForegroundUser ERROR: %x", ret);
goto error;
}
if (opt == VIS_READ)
tmp = fmt::format("SELECT visible FROM tbl_appbrowse_0{0:d} WHERE titleId = '{1:}'", userId, tid);
else
tmp = fmt::format("UPDATE tbl_appbrowse_0{0:d} SET visible = {1:d} WHERE titleId = '{2:}'", userId, write_value, tid);
if (sqlite3_exec(db, tmp.c_str(), int_cb, &vis, &err_msg) != SQLITE_OK)
{
log_error("[APPDB] Failed to fetch data: %s", sqlite3_errmsg(db));
if(err_msg)
sqlite3_free(err_msg);
goto error;
}
sqlite3_close(db);
if (opt == VIS_WRTIE)
{
fmt::print("[APPDB] Changed to {}", write_value);
return true;
}
return vis == 1;
error:
sqlite3_close(db);
return false;
}
bool Reactivate_external_content(bool is_addcont_open = true) {
OrbisUserServiceRegisteredUserIdList userIdList;
std::string query;
int ret = -1;
char name[20];
if (!is_addcont_open && !SQL_Load_DB("/system_data/priv/mms/addcont.db")) {
log_error("Failed to open db");
return false;
}
if (sqlite3_exec(db, "UPDATE addcont SET status = 0", NULL, NULL, & err_msg) != SQLITE_OK || err_msg) {
log_error("[Addcont] Failed: %s | UPDATE addcont SET status = 0", sqlite3_errmsg(db));
sqlite3_free(err_msg);
}
sqlite3_close(db), db = NULL;
memset(&userIdList, 0, sizeof(userIdList));
if (!SQL_Load_DB(APP_DB)) {
log_error("Failed to open app.db");
return false;
}
for (int i = 0; i < ORBIS_USER_SERVICE_MAX_REGISTER_USERS; i++) {
if (userIdList.userId[i] != 0xFF) {
memset(name, 0, sizeof(name));
if ((ret = sceUserServiceGetUserName(userIdList.userId[i], name, sizeof(name))) != ITEMZCORE_SUCCESS) {
log_error("[ERROR] sceUserServiceGetUserName ERROR: 0x%X for %d 0x%x", ret, i, userIdList.userId[i]);
continue;
}
//do the following sql commands below
//UPDATE tbl_appinfo SET val = 0 WHERE key = "_external_hdd_app_status";
//UPDATE tbl_appbrowse_#### SET externalHddAppStatus = 0;
query = fmt::format("UPDATE tbl_appbrowse_0{0:d} SET externalHddAppStatus = 0", userIdList.userId[i]);
if (sqlite3_exec(db, query.c_str(), NULL, NULL, & err_msg) != SQLITE_OK || err_msg) {
log_error("[AppDB] Failed: %s | %s", sqlite3_errmsg(db), query.c_str());
sqlite3_free(err_msg);
return false;
}
}
}
if (sqlite3_exec(db, "UPDATE tbl_appinfo SET val = 0 WHERE key = \"_external_hdd_app_status\"", NULL, NULL, & err_msg) != SQLITE_OK || err_msg) {
log_error("[AppDB] Failed: %s | UPDATE tbl_appinfo SET val = 0 WHERE key = \"_external_hdd_app_status\"", sqlite3_errmsg(db));
sqlite3_free(err_msg);
return false;
}
sqlite3_close(db), db = NULL;
return true;
}
bool change_game_name(std::string new_title, std::string tid, std::string sfo_path)
{
std::string tmp;
std::string tmp2;
int ret =0;
u32 userId = -1;
std::string ini_content = fmt::format("[APP_NAME]\nCUSTOM_NAME={0:}", new_title);
if (!SQL_Load_DB(APP_DB))
return false;
if ((ret = sceUserServiceGetForegroundUser(&userId)) != ITEMZCORE_SUCCESS)
{
log_error("[ERROR] sceUserServiceGetForegroundUser ERROR: 0x%X", ret);
sqlite3_close(db);
return false;
}
tmp = fmt::format("UPDATE tbl_appbrowse_0{0:d} SET titleName='{1:}' WHERE titleId='{2:}'", userId, new_title, tid);
if (sqlite3_exec(db, tmp.c_str(), NULL, NULL, &err_msg) != SQLITE_OK || err_msg)
{
log_error("[TID] Failed to fetch data: %s", sqlite3_errmsg(db));
sqlite3_free(err_msg);
sqlite3_close(db);
return false;
}
sqlite3_close(db);
fmt::print("[TID] Saving Title Name: {}", new_title);
std::ofstream out(fmt::format("/user/app/ITEM00001/custom_app_names/{}.ini", tid));
if(out.bad()){
log_error("Failed to create custom_name ini file");
return false;
}
out << ini_content;
out.close();
return true;
}
/* stolen from Buc at the request of a user*/
/* https://github.com/bucanero/apollo-ps4/commit/c7bbd262f9b243878372ae7134f581e016467c9c */
bool addcont_dlc_rebuild(const char* db_path, bool ext_hdd)
{
char path[256];
DIR *dp, *dp2;
int ret = 0;
struct dirent *dirp, *dirp2;
std::string query;
DLC_PKG_DETAILS dlc_details;
OrbisUserServiceRegisteredUserIdList userIdList;
dp = opendir(ext_hdd ? "/mnt/ext0/user/addcont" : "/user/addcont");
if (!dp)
{
log_error("Failed to open %s", ext_hdd ? "/mnt/ext0/user/addcont" : "/user/addcont");
return false;
}
if (!SQL_Load_DB(db_path)){
log_error("Failed to open %s", db_path);
return false;
}
if ((ret = sceUserServiceGetRegisteredUserIdList(&userIdList) != ITEMZCORE_SUCCESS)) {
log_error("[ERROR] sceUserServiceGetForegroundUser ERROR: 0x%X", ret);
sqlite3_close(db), db = NULL;
return false;
}
while ((dirp = readdir(dp)) != NULL)
{
if (dirp->d_type != DT_DIR || dirp->d_namlen != 9)
continue;
snprintf(path, sizeof(path), "%s/%s", ext_hdd ? "/mnt/ext0/user/addcont" : "/user/addcont", dirp->d_name);
dp2 = opendir(path);
if (!dp2)
continue;
while ((dirp2 = readdir(dp2)) != NULL)
{
if (dirp2->d_type != DT_DIR || dirp2->d_namlen != 16)
continue;
snprintf(path, sizeof(path), "%s/%s/%s/ac.pkg", ext_hdd ? "/mnt/ext0/user/addcont" : "/user/addcont", dirp->d_name, dirp2->d_name);
if(!dlc_pkg_details(path, dlc_details)){
log_error("Failed to get dlc details for %s", path);
continue;
}
log_info("Adding %s to addcont...", dirp2->d_name);
//TODO "IRO_TAG"
query = fmt::format("INSERT OR IGNORE INTO addcont(title_id, dir_name, content_id, title, version, attribute, status, titles_JAPANESE, titles_ENGLISH_US, titles_FRENCH, titles_SPANISH, titles_GERMAN, titles_ITALIAN, titles_DUTCH, titles_PORTUGUESE_PT, titles_RUSSIAN, titles_KOREAN, titles_CHINESE_T, titles_CHINESE_S, titles_FINNISH, titles_SWEDISH, titles_DANISH, titles_NORWEGIAN, titles_POLISH, titles_PORTUGUESE_BR, titles_ENGLISH_GB, titles_TURKISH, titles_SPANISH_LA, titles_ARABIC, titles_FRENCH_CA, titles_CZECH, titles_HUNGARIAN, titles_GREEK, titles_ROMANIAN, titles_THAI, titles_VIETNAMESE, titles_INDONESIAN) VALUES('{0:}', \"{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:}')",dirp->d_name, dirp2->d_name, dlc_details.contentid, dlc_details.name, ext_hdd ? "1610612736" : "536870912", dlc_details.version.c_str(), dlc_details.esd["IRO_TAG"].empty() ? "0" : dlc_details.esd["IRO_TAG"].c_str(), dlc_details.esd["TITLE_00"].c_str(), dlc_details.esd["TITLE_01"].c_str(), dlc_details.esd["TITLE_02"].c_str(), dlc_details.esd["TITLE_03"].c_str(), dlc_details.esd["TITLE_04"].c_str(), dlc_details.esd["TITLE_05"].c_str(), dlc_details.esd["TITLE_06"].c_str(), dlc_details.esd["TITLE_07"].c_str(), dlc_details.esd["TITLE_08"].c_str(), dlc_details.esd["TITLE_09"].c_str(), dlc_details.esd["TITLE_10"].c_str(), dlc_details.esd["TITLE_11"].c_str(), dlc_details.esd["TITLE_12"].c_str(), dlc_details.esd["TITLE_13"].c_str(), dlc_details.esd["TITLE_14"].c_str(), dlc_details.esd["TITLE_15"].c_str(), dlc_details.esd["TITLE_16"].c_str(), dlc_details.esd["TITLE_17"].c_str(), dlc_details.esd["TITLE_18"].c_str(), dlc_details.esd["TITLE_19"].c_str(), dlc_details.esd["TITLE_20"].c_str(), dlc_details.esd["TITLE_21"].c_str(), dlc_details.esd["TITLE_22"].c_str(), dlc_details.esd["TITLE_23"].c_str(), dlc_details.esd["TITLE_24"].c_str(), dlc_details.esd["TITLE_25"].c_str(), dlc_details.esd["TITLE_26"].c_str(), dlc_details.esd["TITLE_27"].c_str(), dlc_details.esd["TITLE_28"].c_str(), dlc_details.esd["TITLE_29"].c_str());
if (sqlite3_exec(db, query.c_str(), NULL, NULL, NULL) != SQLITE_OK){
log_info("[PASS1] addcont insert failed: %s", sqlite3_errmsg(db));
std::replace_if(dlc_details.name.begin(), dlc_details.name.end(), [](auto ch) { return ::ispunct(ch); }, ' ');
query = fmt::format("INSERT OR IGNORE INTO addcont(title_id, dir_name, content_id, title, version, attribute, status, titles_JAPANESE, titles_ENGLISH_US, titles_FRENCH, titles_SPANISH, titles_GERMAN, titles_ITALIAN, titles_DUTCH, titles_PORTUGUESE_PT, titles_RUSSIAN, titles_KOREAN, titles_CHINESE_T, titles_CHINESE_S, titles_FINNISH, titles_SWEDISH, titles_DANISH, titles_NORWEGIAN, titles_POLISH, titles_PORTUGUESE_BR, titles_ENGLISH_GB, titles_TURKISH, titles_SPANISH_LA, titles_ARABIC, titles_FRENCH_CA, titles_CZECH, titles_HUNGARIAN, titles_GREEK, titles_ROMANIAN, titles_THAI, titles_VIETNAMESE, titles_INDONESIAN) VALUES('{0:}', \"{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:}')", dirp->d_name, dirp2->d_name, dlc_details.contentid, dlc_details.name, ext_hdd ? "1610612736" : "536870912", dlc_details.version.c_str(), dlc_details.esd["IRO_TAG"].empty() ? "0" : dlc_details.esd["IRO_TAG"].c_str(), dlc_details.esd["TITLE_00"].c_str(), dlc_details.esd["TITLE_01"].c_str(), dlc_details.esd["TITLE_02"].c_str(), dlc_details.esd["TITLE_03"].c_str(), dlc_details.esd["TITLE_04"].c_str(), dlc_details.esd["TITLE_05"].c_str(), dlc_details.esd["TITLE_06"].c_str(), dlc_details.esd["TITLE_07"].c_str(), dlc_details.esd["TITLE_08"].c_str(), dlc_details.esd["TITLE_09"].c_str(), dlc_details.esd["TITLE_10"].c_str(), dlc_details.esd["TITLE_11"].c_str(), dlc_details.esd["TITLE_12"].c_str(), dlc_details.esd["TITLE_13"].c_str(), dlc_details.esd["TITLE_14"].c_str(), dlc_details.esd["TITLE_15"].c_str(), dlc_details.esd["TITLE_16"].c_str(), dlc_details.esd["TITLE_17"].c_str(), dlc_details.esd["TITLE_18"].c_str(), dlc_details.esd["TITLE_19"].c_str(), dlc_details.esd["TITLE_20"].c_str(), dlc_details.esd["TITLE_21"].c_str(), dlc_details.esd["TITLE_22"].c_str(), dlc_details.esd["TITLE_23"].c_str(), dlc_details.esd["TITLE_24"].c_str(), dlc_details.esd["TITLE_25"].c_str(), dlc_details.esd["TITLE_26"].c_str(), dlc_details.esd["TITLE_27"].c_str(), dlc_details.esd["TITLE_28"].c_str(), dlc_details.esd["TITLE_29"].c_str());
if (sqlite3_exec(db, query.c_str(), NULL, NULL, NULL) != SQLITE_OK){
log_info("[PASS2] addcont insert failed: %s", sqlite3_errmsg(db));
//log_info("addcont insert failed for %s", query.c_str());
}
}
// log_info("addcont insert success %s", query.c_str());
dlc_details.esd.clear();
dlc_details.name.clear();
dlc_details.version.clear();
dlc_details.contentid.clear();
}
closedir(dp2);
}
closedir(dp);
Reactivate_external_content();
return true;
}
bool insert_app_info(std::string titleId, std::string key, std::string value = std::string(), bool is_string = true){
std::string tmp;
long numb = 0;
if(!value.empty() && !is_string){
numb = std::stol(value);
}
if(is_string){
tmp = fmt::format("INSERT OR IGNORE INTO tbl_appinfo(titleId, key, val) VALUES('{0:}', '{1:}', \"{2:}\")", titleId, key, value);
}
else
tmp = fmt::format("INSERT OR IGNORE INTO tbl_appinfo(titleId, key, val) VALUES('{0:}', '{1:}', {2:d})", titleId, key, numb);
if (sqlite3_exec(db, tmp.c_str(), NULL, NULL, &err_msg) != SQLITE_OK || err_msg)
{
log_error("[AppDB] Failed: %s | %s", sqlite3_errmsg(db), tmp.c_str());
sqlite3_free(err_msg);
return false;
}
//log_info("AppDB insert success %s", tmp.c_str());
return true;
}
bool Fix_Game_In_DB(ThreadSafeVector<item_t> &app_info, int index, bool is_ext_hdd) {
std::string tmp;
std::string tmp2;
int ret = -1;
u32 userId = -1;
OrbisUserServiceRegisteredUserIdList userIdList;
char name[20];
if (app_info.empty() || index > app_info.size())
return false;
auto item = app_info.at(index);
memset(&userIdList, 0, sizeof(userIdList));
if (!SQL_Load_DB(APP_DB))
return false;
if ((ret = sceUserServiceGetRegisteredUserIdList(&userIdList) != ITEMZCORE_SUCCESS)) {
log_error("[ERROR] sceUserServiceGetRegisteredUserIdList ERROR: 0x%X", ret);
sqlite3_close(db), db = NULL;
return false;
}
for (int i = 0; i < ORBIS_USER_SERVICE_MAX_REGISTER_USERS; i++) {
if (userIdList.userId[i] != 0xFF) {
userId = userIdList.userId[i];
memset(name, 0, sizeof(name));
if ((ret = sceUserServiceGetUserName(userIdList.userId[i], name, sizeof(name))) != ITEMZCORE_SUCCESS){
log_error("[ERROR] sceUserServiceGetUserName ERROR: 0x%X for %d 0x%x", ret, i, userId);
continue;
}
log_error("Running for User ID: 0x%x | %d name: %s", userId, i, name);
int ver = (ps4_fw_version() >> 16);
tmp = fmt::format("INSERT OR IGNORE INTO tbl_appbrowse_0{0:d}(titleId, contentId, titleName, metaDataPath, lastAccessTime, contentStatus, onDisc, parentalLevel, visible, sortPriority, pathInfo, lastAccessIndex, dispLocation, canRemove, category, contentType, pathInfo2, presentBoxStatus, entitlement, thumbnailUrl, lastUpdateTime, playableDate, contentSize, installDate, platform, uiCategory, skuId, disableLiveDetail, linkType, linkUri, serviceIdAddCont1, serviceIdAddCont2, serviceIdAddCont3, serviceIdAddCont4, serviceIdAddCont5, serviceIdAddCont6, serviceIdAddCont7, folderType, folderInfo, parentFolderId, positionInFolder, activeDate, entitlementTitleName, hddLocation, externalHddAppStatus, entitlementIdKamaji, mTime {1:}) VALUES('{2:}', \"{3:}\", '{4:}', '{5:}', '2022-02-06 14:03:08.359', 0, 0, '{6:}', 1, 100, 0, 0, 5, 1, '{7:}', 0, 0, 0, 0, NULL, NULL, NULL, '{8:d}', '2018-07-27 15:06:46.802', 0, '{9:}', NULL, 0, 0, NULL, '{10:}', '{11:}', '{12:}','{13:}', '{14:}', '{15:}', '{16:}', 0, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, '2022-05-06 18:02:21.702'{17:})", userId, (ver > 0x555) ? ",freePsPlusContent, entitlementActiveFlag, sizeOtherHdd, entitlementHidden, preorderPlaceholderFlag, gatingEntitlementJson" : "", item.info.id, item.extra_data.extra_sfo_data["CONTENT_ID"], item.info.name, item.flags.is_ext_hdd ? "/user/appmeta/external/" + item.info.id : "/user/appmeta/" + item.info.id, item.extra_data.extra_sfo_data["PARENTAL_LEVEL"], item.extra_data.extra_sfo_data["CATEGORY"], file_size(item.info.package.c_str()), (item.extra_data.extra_sfo_data["CATEGORY"] == "gde") ? "app" : "game", item.extra_data.extra_sfo_data["SERVICE_ID_ADDCONT_ADD_1"], item.extra_data.extra_sfo_data["SERVICE_ID_ADDCONT_ADD_2"], item.extra_data.extra_sfo_data["SERVICE_ID_ADDCONT_ADD_3"], item.extra_data.extra_sfo_data["SERVICE_ID_ADDCONT_ADD_4"], item.extra_data.extra_sfo_data["SERVICE_ID_ADDCONT_ADD_5"], item.extra_data.extra_sfo_data["SERVICE_ID_ADDCONT_ADD_6"], item.extra_data.extra_sfo_data["SERVICE_ID_ADDCONT_ADD_7"], (ver > 0x555) ? ", 0,0, 0, 0, 0, NULL" : "");
if (sqlite3_exec(db, tmp.c_str(), NULL, NULL, & err_msg) != SQLITE_OK || err_msg) {
log_error("[AppDB][PASS1] Failed: %s", sqlite3_errmsg(db));
sqlite3_free(err_msg);
log_info("[AppDB] Trying without special Chars ...");
//remove spec char
// std::replace_if(item.name.begin(), item.name.end(), [](auto ch) {
//return ::ispunct(ch);
//}, ' ');
tmp = fmt::format("INSERT OR IGNORE INTO tbl_appbrowse_0{0:d}(titleId, contentId, titleName, metaDataPath, lastAccessTime, contentStatus, onDisc, parentalLevel, visible, sortPriority, pathInfo, lastAccessIndex, dispLocation, canRemove, category, contentType, pathInfo2, presentBoxStatus, entitlement, thumbnailUrl, lastUpdateTime, playableDate, contentSize, installDate, platform, uiCategory, skuId, disableLiveDetail, linkType, linkUri, serviceIdAddCont1, serviceIdAddCont2, serviceIdAddCont3, serviceIdAddCont4, serviceIdAddCont5, serviceIdAddCont6, serviceIdAddCont7, folderType, folderInfo, parentFolderId, positionInFolder, activeDate, entitlementTitleName, hddLocation, externalHddAppStatus, entitlementIdKamaji, mTime {1:}) VALUES('{2:}', \"{3:}\", '{4:}', '{5:}', '2022-02-06 14:03:08.359', 0, 0, '{6:}', 1, 100, 0, 0, 5, 1, '{7:}', 0, 0, 0, 0, NULL, NULL, NULL, '{8:d}', '2018-07-27 15:06:46.802', 0, '{9:}', NULL, 0, 0, NULL, '{10:}', '{11:}', '{12:}','{13:}', '{14:}', '{15:}', '{16:}', 0, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, '2022-05-06 18:02:21.702'{17:})", userId, (ver > 0x555) ? ",freePsPlusContent, entitlementActiveFlag, sizeOtherHdd, entitlementHidden, preorderPlaceholderFlag, gatingEntitlementJson" : "", item.info.id, item.extra_data.extra_sfo_data["CONTENT_ID"], sanitizeString(item.info.name), item.flags.is_ext_hdd ? "/user/appmeta/external/" + item.info.id : "/user/appmeta/" + item.info.id, item.extra_data.extra_sfo_data["PARENTAL_LEVEL"], item.extra_data.extra_sfo_data["CATEGORY"], file_size(item.info.package.c_str()), (item.extra_data.extra_sfo_data["CATEGORY"] == "gde") ? "app" : "game", item.extra_data.extra_sfo_data["SERVICE_ID_ADDCONT_ADD_1"], item.extra_data.extra_sfo_data["SERVICE_ID_ADDCONT_ADD_2"], item.extra_data.extra_sfo_data["SERVICE_ID_ADDCONT_ADD_3"], item.extra_data.extra_sfo_data["SERVICE_ID_ADDCONT_ADD_4"], item.extra_data.extra_sfo_data["SERVICE_ID_ADDCONT_ADD_5"], item.extra_data.extra_sfo_data["SERVICE_ID_ADDCONT_ADD_6"], item.extra_data.extra_sfo_data["SERVICE_ID_ADDCONT_ADD_7"], (ver > 0x555) ? ", 0,0, 0, 0, 0, NULL" : "");
if (sqlite3_exec(db, tmp.c_str(), NULL, NULL, & err_msg) != SQLITE_OK || err_msg) {
log_error("[AppDB][PASS2][FATAL] Failed: %s", sqlite3_errmsg(db));
sqlite3_free(err_msg);
sqlite3_close(db);
return false;
}
}
for (int z = 1; z <= 7; z++) {
// Construct the UPDATE statement as a string
std::string sql = fmt::format("UPDATE tbl_appbrowse_0{0:d} SET serviceIdAddCont{1:d} = NULL WHERE serviceIdAddCont{2:d} = ''", userId, z, z);
// Execute the UPDATE statement
char * error_message = 0;
ret = sqlite3_exec(db, sql.c_str(), 0, 0, & error_message);
if (ret) {
sqlite3_free(error_message);
log_error("[AppDB][SASS][FATAL] Failed: %s | %s", sqlite3_errmsg(db), tmp.c_str());
}
}
}
}
//print out extra sfo data
if (!insert_app_info(item.info.id, "TITLE", item.info.name)) {
insert_app_info(item.info.id, "TITLE", sanitizeString(item.info.name));
}
insert_app_info(item.info.id, "TITLE_ID", item.info.id);
insert_app_info(item.info.id, "_metadata_path", item.flags.is_ext_hdd ? "/user/appmeta/external/" + item.info.id : "/user/appmeta/" + item.info.id);
insert_app_info(item.info.id, "_org_path", item.flags.is_ext_hdd ? "/mnt/ext0/user/app/" + item.info.id : "/user/app/" + item.info.id);
insert_app_info(item.info.id, "APP_VER", item.info.version);
insert_app_info(item.info.id, "ATTRIBUTE", item.extra_data.extra_sfo_data["ATTRIBUTE"], false);
insert_app_info(item.info.id, "CATEGORY", item.extra_data.extra_sfo_data["CATEGORY"]);
insert_app_info(item.info.id, "CONTENT_ID", item.extra_data.extra_sfo_data["CONTENT_ID"]);
insert_app_info(item.info.id, "VERSION", item.extra_data.extra_sfo_data["VERSION"]);
insert_app_info(item.info.id, "#_access_index", "1", false);
insert_app_info(item.info.id, "#_last_access_time", "2022-01-21 15:04:39.822");
insert_app_info(item.info.id, "#_contents_status", "0", false);
insert_app_info(item.info.id, "#_mtime", "2022-01-21 15:04:39.822");
insert_app_info(item.info.id, "_contents_location", "0", false);
insert_app_info(item.info.id, "#_update_index", "0", false);
insert_app_info(item.info.id, "#exit_type", "0", false);
insert_app_info(item.info.id, "DISP_LOCATION_1", "0", false);
insert_app_info(item.info.id, "DISP_LOCATION_2", "0", false);
insert_app_info(item.info.id, "DOWNLOAD_DATA_SIZE", item.extra_data.extra_sfo_data["DOWNLOAD_DATA_SIZE"], false);
insert_app_info(item.info.id, "FORMAT", "obs");
insert_app_info(item.info.id, "PARENTAL_LEVEL", item.extra_data.extra_sfo_data["PARENTAL_LEVEL"], false);
insert_app_info(item.info.id, "SYSTEM_VER", item.extra_data.extra_sfo_data["SYSTEM_VER"], false);
if (!item.extra_data.extra_sfo_data["INSTALL_DIR_SAVEDATA"].empty())
insert_app_info(item.info.id, "INSTALL_DIR_SAVEDATA", item.extra_data.extra_sfo_data["INSTALL_DIR_SAVEDATA"]);
for (int i = 1; i <= 4; i++) {
insert_app_info(item.info.id, fmt::format("USER_DEFINED_PARAM_{0:d}", i), item.extra_data.extra_sfo_data[fmt::format("USER_DEFINED_PARAM_{0:d}", i)], false);
}
for (int i = 1; i <= 7; i++) {
std::string SERV_ID = fmt::format("SERVICE_ID_ADDCONT_APPINFO_ADD_{0:d}", i);
std::string SERV_ID2 = fmt::format("SERVICE_ID_ADDCONT_ADD_{0:d}", i);
if (!item.extra_data.extra_sfo_data[SERV_ID].empty())
insert_app_info(item.info.id, SERV_ID2, item.extra_data.extra_sfo_data[SERV_ID]);
else
insert_app_info(item.info.id, SERV_ID2, "0", false);
}
for (int i = 0; i < 30; i++) {
std::string title = fmt::format("TITLE_{0:}{1:d}", (i < 10) ? "0" : "", i);
if (!item.extra_data.extra_sfo_data[title].empty()) {
if (!insert_app_info(item.info.id, title, item.extra_data.extra_sfo_data[title])) {
//std::replace_if(item.extra_data.extra_sfo_data[title].begin(), item.extra_data.extra_sfo_data[title].end(), [](auto ch) {
// return ::ispunct(ch);
//}, ' ');
insert_app_info(item.info.id, title, sanitizeString(item.extra_data.extra_sfo_data[title]));
}
}
}
insert_app_info(item.info.id, "_contents_ext_type", "0", false);
insert_app_info(item.info.id, "_current_slot", "0", false);
insert_app_info(item.info.id, "_disable_live_detail", "0", false);
insert_app_info(item.info.id, "_external_hdd_app_status", "0", false);
insert_app_info(item.info.id, "_hdd_location", "0", false);
insert_app_info(item.info.id, "_path_info", "0", false);
insert_app_info(item.info.id, "_path_info_2", "0", false);
insert_app_info(item.info.id, "_size_other_hdd", "0", false);
insert_app_info(item.info.id, "_sort_priority", "100", false);
insert_app_info(item.info.id, "_uninstallable", "1", false);
insert_app_info(item.info.id, "_view_category", "0", false);
insert_app_info(item.info.id, "_working_status", "0", false);
insert_app_info(item.info.id, "ATTRIBUTE2", item.extra_data.extra_sfo_data["ATTRIBUTE2"], false);
insert_app_info(item.info.id, "ATTRIBUTE_INTERNAL", item.extra_data.extra_sfo_data["ATTRIBUTE_INTERNAL"], false);
insert_app_info(item.info.id, "PT_PARAM", item.extra_data.extra_sfo_data["PT_PARAM"], false);
insert_app_info(item.info.id, "APP_TYPE", item.extra_data.extra_sfo_data["APP_TYPE"], false);
insert_app_info(item.info.id, "REMOTE_PLAY_KEY_ASSIGN", item.extra_data.extra_sfo_data["REMOTE_PLAY_KEY_ASSIGN"], false);
insert_app_info(item.info.id, "#_promote_time", "2022-01-21 15:04:39.822");
insert_app_info(item.info.id, "#_booted", "1", false);
insert_app_info(item.info.id, "#_size", std::to_string(file_size(item.info.package.c_str())), false);
sqlite3_close(db), db = NULL;
return true;
}