mirror of
https://github.com/ApfelTeeSaft/Itemzflow.git
synced 2026-08-26 19:23:39 +00:00
- 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
2331 lines
73 KiB
C++
2331 lines
73 KiB
C++
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <md5.h>
|
|
#include <errno.h>
|
|
#include <sys/time.h>
|
|
#include <stdlib.h>
|
|
#include <pthread.h>
|
|
#include "utils.h"
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <iosfwd>
|
|
extern "C"{
|
|
#include "mp3/dr_mp3.h"
|
|
#include <orbisAudio.h>
|
|
#include "ini.h"
|
|
#include "log.h"
|
|
#include "net.h"
|
|
#include "defines.h"
|
|
#include "dialog.h"
|
|
#include "zip/zip.h"
|
|
}
|
|
#include <ipc_client.hpp>
|
|
#include "installpkg.h"
|
|
#include <sys/sysctl.h>
|
|
#include <sys/param.h>
|
|
#include <sys/mount.h>
|
|
#include <signal.h>
|
|
#include <atomic>
|
|
#include <thread>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <fstream>
|
|
|
|
|
|
|
|
|
|
/*================== MISC GOLBAL VAR ============*/
|
|
static uint32_t sdkVersion = -1;
|
|
static std::string checkedsize;
|
|
static const char* sizes[] = { "EiB", "PiB", "TiB", "GiB", "MiB", "KiB", "B" };
|
|
static const uint64_t exbibytes = 1024ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL;
|
|
|
|
void* __stack_chk_guard = (void*)0xdeadbeef;
|
|
size_t _orbisFile_lastopenFile_size;
|
|
/* =========================================== */
|
|
|
|
/* ================== IF GLOBAL VARS========== */
|
|
ItemzSettings set,
|
|
* get;
|
|
|
|
extern std::string ipc_msg;
|
|
extern std::atomic_int inserted_disc;
|
|
extern std::atomic_bool is_disc_inserted;
|
|
extern struct retry_t* cf_tex;
|
|
extern int total_pages;
|
|
extern ThreadSafeVector<item_t> all_apps; // Installed_Apps
|
|
bool sceAppInst_done = false;
|
|
|
|
using namespace multi_select_options;
|
|
|
|
bool (*sceStoreApiLaunchStore)(const char* query) = NULL;
|
|
update_ret (*sceStoreApiCheckUpdate)(const char* tid) = NULL;
|
|
/* =========================================== */
|
|
|
|
/* ================== MP3 VARS =====================-*/
|
|
#include <libtag/taglib.h>
|
|
#include <libtag/fileref.h>
|
|
#include <libtag/tag.h>
|
|
ThreadSafeVector<item_t> mp3_playlist;
|
|
current_song_t current_song;
|
|
|
|
static uint64_t off2 = 0;
|
|
//drmp3_uint8 pData[DRMP3_DATA_CHUNK_SIZE]; // reading buffer from opened file, 16k
|
|
static drmp3 mp3; // the main dr_mp3 object
|
|
static drmp3_config Config; // and its config
|
|
static std::atomic_int dataSize = 0;
|
|
static std::vector<uint8_t> mp3data;
|
|
|
|
extern int g_idx;
|
|
static std::atomic_int main_ch = 0;
|
|
static std::atomic_int fill = 0;
|
|
static std::atomic_bool m_bPlaying = false;
|
|
static int numframe = 1;
|
|
int retry_mp3_count = 0;
|
|
|
|
static short play_buf[(1024 * 2) * 4], // small fixed buffer to append decoded pcm s16le samples
|
|
snd[1152 * 2]; // small fixed buffer to store a single audio frame of decoded samples
|
|
|
|
|
|
|
|
#define MP3_BUFFER_SIZE (1152) // max decoded s16le sample, for a single channel
|
|
/*===============================================*/
|
|
|
|
/*============= USB VARS ========================*/
|
|
std::mutex usb_lock;
|
|
std::atomic_int usb_number = ATOMIC_VAR_INIT(false);
|
|
/*=============================================*/
|
|
|
|
/*-===================== THEME =========================*/
|
|
typedef struct {
|
|
std::string name, version, date, author;
|
|
bool is_image, has_font, using_sb;
|
|
} theme;
|
|
|
|
const char *required_theme_files[] = {
|
|
"theme/btn_o.png", "theme/btn_sq.png",
|
|
"theme/btn_tri.png", "theme/btn_x.png",
|
|
"theme/btn_up.png", "theme/btn_down.png",
|
|
"theme/btn_left.png", "theme/btn_right.png",
|
|
"theme/btn_l1.png", "theme/btn_l2.png",
|
|
"theme/btn_r1.png"
|
|
};
|
|
|
|
const char *if_d_zip[] = {
|
|
"ONLY WORKS IN ITEMZFLOW"
|
|
};
|
|
bool reboot_app = false;
|
|
#include "shaders.h"
|
|
|
|
|
|
double CalcFreeGigs(const char* path) {
|
|
struct statfs st;
|
|
if (statfs(path, &st) != 0) {
|
|
return 0;
|
|
}
|
|
return (double)st.f_bfree * st.f_bsize / (1024 * 1024 * 1024);
|
|
}
|
|
|
|
#if __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
int64_t sys_dynlib_load_prx(char* prxPath, int* moduleID)
|
|
{
|
|
return (int64_t)syscall4(594, prxPath, 0, moduleID, 0);
|
|
}
|
|
|
|
int64_t sys_dynlib_unload_prx(int64_t prxID)
|
|
{
|
|
return (int64_t)syscall1(595, (void*)prxID);
|
|
}
|
|
|
|
|
|
int64_t sys_dynlib_dlsym(int64_t moduleHandle, const char* functionName, void* destFuncOffset)
|
|
{
|
|
return (int64_t)syscall3(591, (void*)moduleHandle, (void*)functionName, destFuncOffset);
|
|
}
|
|
|
|
unsigned char* orbisFileGetFileContent(const char* filename)
|
|
{
|
|
_orbisFile_lastopenFile_size = -1;
|
|
|
|
FILE* file = fopen(filename, "rb");
|
|
if (!file)
|
|
{
|
|
log_error("Unable to open file \"%s\".", filename); return NULL;
|
|
}
|
|
|
|
fseek(file, 0, SEEK_END);
|
|
size_t size = ftell(file);
|
|
fseek(file, 0, SEEK_SET);
|
|
|
|
unsigned char* buffer = (unsigned char*)malloc((size + 1) * sizeof(char));
|
|
fread(buffer, sizeof(char), size, file);
|
|
buffer[size] = 0;
|
|
_orbisFile_lastopenFile_size = size;
|
|
fclose(file);
|
|
|
|
return buffer;
|
|
}
|
|
|
|
int sceSystemServiceKillApp(uint32_t appid, int opt,int method, int reason);
|
|
int sceShellUIUtilInitialize();
|
|
int sceShellUIUtilLaunchByUri(const char* uri, SceShellUIUtilLaunchByUriParam *Param);
|
|
int sceAppInstUtilAppUnInstallAddcont(const char* title_id, const char* content_id);
|
|
int sceAppInstUtilAppUnInstallPat(const char* tid);
|
|
int malloc_stats_fast(LibcMallocManagedSize *ManagedSize);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
/*=====================================================*/
|
|
/*
|
|
* Creates all the directories in the provided path. (can include a filename)
|
|
* (directory must end with '/')
|
|
*/
|
|
|
|
void* prx_func_loader(std::string prx_path, std::string symbol) {
|
|
|
|
void* addrp = NULL;
|
|
log_info("Loading %s", prx_path.c_str());
|
|
|
|
int libcmi = sceKernelLoadStartModule(prx_path.c_str(), 0, nullptr, 0, 0, 0);
|
|
if(libcmi < 0){
|
|
log_error("Error loading prx: 0x%X", libcmi);
|
|
return addrp;
|
|
}
|
|
else
|
|
log_debug("%s loaded successfully", prx_path.c_str());
|
|
|
|
if(sceKernelDlsym(libcmi, symbol.c_str(), &addrp) < 0){
|
|
log_error("Symbol %s NOT Found", symbol.c_str());
|
|
}
|
|
else
|
|
log_debug("Function %s | addr %p loaded successfully", symbol.c_str(), addrp);
|
|
|
|
return addrp;
|
|
}
|
|
|
|
// folder that sees if a path is a folder
|
|
bool is_folder(const char* path)
|
|
{
|
|
struct stat st;
|
|
if (stat(path, &st) == 0)
|
|
return S_ISDIR(st.st_mode);
|
|
return false;
|
|
}
|
|
|
|
static int theme_info(void* user, const char* section, const char* name,
|
|
const char* value, int unused)
|
|
{
|
|
static char prev_section[50] = "";
|
|
|
|
if (strcmp("THEME", prev_section)) {
|
|
log_debug("%s [%s]", (prev_section[0] ? "" : ""), section);
|
|
strncpy(prev_section, section, sizeof(prev_section));
|
|
prev_section[sizeof(prev_section) - 1] = '\0';
|
|
}
|
|
|
|
theme* set = (theme*)user;
|
|
|
|
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
|
|
|
|
if (MATCH("THEME", "Author")) {
|
|
set->author = value;
|
|
|
|
}
|
|
if (MATCH("THEME", "Date")) {
|
|
set->date = value;
|
|
}
|
|
if (MATCH("THEME", "Name")) {
|
|
set->name = value;
|
|
}
|
|
if (MATCH("THEME", "Version")) {
|
|
set->version = value;
|
|
}
|
|
if (MATCH("THEME", "Image")) {
|
|
set->is_image = atol(value);
|
|
}
|
|
if (MATCH("THEME", "Font")) {
|
|
set->has_font = atol(value);
|
|
}
|
|
if (MATCH("THEME", "Shader") && !set->is_image) {
|
|
set->using_sb = atol(value);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void __stack_chk_fail(void)
|
|
{
|
|
log_info("Stack smashing detected.");
|
|
msgok(MSG_DIALOG::FATAL, "Stack Smashing has been Detected");
|
|
}
|
|
|
|
bool IS_ERROR(uint32_t ret)
|
|
{
|
|
return ret & 0x80000000;
|
|
}
|
|
|
|
std::string calculateSize(uint64_t size)
|
|
{
|
|
std::string result;
|
|
uint64_t multiplier = exbibytes;
|
|
int i;
|
|
|
|
for (i = 0; i < DIM(sizes); i++, multiplier /= 1024)
|
|
{
|
|
if (size < multiplier)
|
|
continue;
|
|
if (size % multiplier == 0)
|
|
result = fmt::format("{0:} {1:}", size / multiplier, sizes[i]);
|
|
else
|
|
result = fmt::format("{0:.1f} {1:}", (float)(size / multiplier), sizes[i]);
|
|
|
|
return result;
|
|
}
|
|
result = "0";
|
|
return result;
|
|
}
|
|
|
|
size_t CalcAppsize(const char* filename) {
|
|
struct stat st;
|
|
if(stat(filename, &st) != 0) {
|
|
return 0;
|
|
}
|
|
return st.st_size;
|
|
}
|
|
|
|
int ItemzLocalKillApp(uint32_t appid) {
|
|
|
|
log_info("ItemzLocalKillApp(%x, -1, 0, 0)", appid);
|
|
if ((appid & ~0xFFFFFF) == 0x60000000)
|
|
return sceSystemServiceKillApp(appid, -1, 0, 0);
|
|
else
|
|
return ITEMZCORE_EINVAL;
|
|
}
|
|
|
|
|
|
int ItemzLaunchByUri(const char* uri) {
|
|
int libcmi = -1;
|
|
|
|
if (!uri)
|
|
return ITEMZCORE_EINVAL;
|
|
|
|
if (sys_dynlib_load_prx((char*)"/system/common/lib/libSceShellUIUtil.sprx", &libcmi) < 0 || libcmi < 0)
|
|
return ITEMZCORE_PRX_RESOLVE_ERROR;
|
|
|
|
SceShellUIUtilLaunchByUriParam Param;
|
|
Param.size = sizeof(SceShellUIUtilLaunchByUriParam);
|
|
sceUserServiceGetForegroundUser(&Param.userId); // DONT CARE
|
|
log_info("ItemzLaunchByUri(%s)", uri);
|
|
log_info("sceShellUIUtilInitialize returned %x", sceShellUIUtilInitialize());
|
|
|
|
return sceShellUIUtilLaunchByUri(uri, &Param);
|
|
}
|
|
|
|
|
|
bool copyFile(std::string source, std::string dest, bool show_progress)
|
|
{
|
|
std::string buf;
|
|
int src = sceKernelOpen(source.c_str(), 0x0000, 0);
|
|
if (src > 0)
|
|
{
|
|
|
|
int out = sceKernelOpen(dest.c_str(), 0x0001 | 0x0200 | 0x0400, 0777);
|
|
if (out > 0)
|
|
{
|
|
if(show_progress)
|
|
progstart("Starting...");
|
|
|
|
size_t bytes ,total = 0;
|
|
size_t len = CalcAppsize(source.c_str());
|
|
std::string size = calculateSize(len);
|
|
|
|
std::vector<char> buffer(MB(10));
|
|
if (buffer.size() > 0)
|
|
{
|
|
while (0 < (bytes = sceKernelRead(src, &buffer[0], MB(10)))){
|
|
sceKernelWrite(out, &buffer[0], bytes);
|
|
total += bytes;
|
|
if(show_progress){
|
|
uint32_t g_progress = (uint32_t)(((float)total / len) * 100.f);
|
|
int status = sceMsgDialogUpdateStatus();
|
|
if (ORBIS_COMMON_DIALOG_STATUS_RUNNING == status) {
|
|
buf = fmt::format("{0:}...\n Size: {1:}", getLangSTR(LANG_STR::COPYING_FILE), size);
|
|
sceMsgDialogProgressBarSetValue(0, g_progress);
|
|
sceMsgDialogProgressBarSetMsg(0, buf.c_str());
|
|
}
|
|
}
|
|
}
|
|
buffer.clear();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fmt::print("Could copy file: {} Reason: {x}", src, out);
|
|
sceKernelClose(src);
|
|
if(show_progress)
|
|
sceMsgDialogTerminate();
|
|
return false;
|
|
}
|
|
|
|
sceKernelClose(src);
|
|
sceKernelClose(out);
|
|
sceMsgDialogTerminate();
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
fmt::print("Could copy file: {} Reason: {x}", dest, src);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void ProgSetMessagewText(int prog, const char* fmt, ...)
|
|
{
|
|
|
|
char buff[300];
|
|
memset(&buff[0], 0, sizeof(buff));
|
|
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
vsnprintf(&buff[0], 299, fmt, args);
|
|
va_end(args);
|
|
|
|
sceMsgDialogProgressBarSetValue(0, prog);
|
|
sceMsgDialogProgressBarSetMsg(0, buff);
|
|
}
|
|
/// timing
|
|
float get_time_ms(std::chrono::time_point<std::chrono::system_clock> &last_time)
|
|
{
|
|
auto now = std::chrono::system_clock::now();
|
|
auto duration = now - last_time;
|
|
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
|
|
last_time = now;
|
|
|
|
return (float)(millis / 1000.f);
|
|
}
|
|
|
|
bool touch_file(const char* destfile)
|
|
{
|
|
int fd = open(destfile, O_WRONLY | O_CREAT | O_TRUNC, 0777);
|
|
if (fd > 0) {
|
|
unlink(destfile);
|
|
close(fd);
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
#define SCE_KERNEL_EVF_WAITMODE_OR 0x02
|
|
unsigned char _bittest64(uint64_t *Base, uint64_t Offset)
|
|
{
|
|
int old = 0;
|
|
__asm__ __volatile__("btq %2,%1\n\tsbbl %0,%0 "
|
|
:"=r" (old),"=m" ((*(volatile long long *) Base))
|
|
:"Ir" (Offset));
|
|
return (old != 0);
|
|
}
|
|
// both real and _func functions are the same
|
|
unsigned int sceShellCoreUtilIsUsbMassStorageMounted(unsigned int usb_index);
|
|
//interchangable
|
|
unsigned int sceShellCoreUtilIsUsbMassStorageMounted_func(unsigned int usb_index)
|
|
{
|
|
uint64_t res;
|
|
void* ef;
|
|
|
|
if ( (unsigned int)sceKernelOpenEventFlag(&ef, "SceAutoMountUsbMass") )
|
|
return 0;
|
|
sceKernelPollEventFlag(ef, 0xFFFFFFF, SCE_KERNEL_EVF_WAITMODE_OR, &res);
|
|
sceKernelCloseEventFlag(ef);
|
|
|
|
return _bittest64(&res, usb_index);
|
|
}
|
|
|
|
unsigned int usbpath()
|
|
{
|
|
// std::lock_guard<std::mutex> lock(disc_lock);
|
|
unsigned int usb_index = -1;
|
|
for (int i = 0; i < 8; i++){
|
|
if (sceShellCoreUtilIsUsbMassStorageMounted_func((unsigned int)i)){
|
|
usb_index = i;
|
|
//log_info("[UTIL] USB %i is mounted, SceAutoMountUsbMass: %i", i, usb_number);
|
|
break;
|
|
}
|
|
}
|
|
return usb_index;
|
|
}
|
|
|
|
bool MD5_file_compare(const char* file1, const char* file2)
|
|
{
|
|
unsigned char c[MD5_HASH_LENGTH];
|
|
unsigned char c2[MD5_HASH_LENGTH];
|
|
int i;
|
|
FILE* f1 = fopen(file1, "rb");
|
|
FILE* f2 = fopen(file2, "rb");
|
|
if(!f1)
|
|
{
|
|
log_error("Could not open both files");
|
|
return false;
|
|
}
|
|
if(!f2)
|
|
{
|
|
fclose(f1);
|
|
log_error("Could not open both files");
|
|
return false;
|
|
}
|
|
MD5_CTX mdContext;
|
|
|
|
MD5_CTX mdContext2;
|
|
int bytes2 = 0;
|
|
unsigned char data2[1024];
|
|
|
|
int bytes = 0;
|
|
unsigned char data[1024];
|
|
|
|
MD5_Init(&mdContext);
|
|
while ((bytes = fread(data, 1, 1024, f1)) != 0)
|
|
MD5_Update(&mdContext, data, bytes);
|
|
MD5_Final(c, &mdContext);
|
|
|
|
MD5_Init(&mdContext2);
|
|
while ((bytes2 = fread(data2, 1, 1024, f2)) != 0)
|
|
MD5_Update(&mdContext2, data2, bytes2);
|
|
MD5_Final(c2, &mdContext2);
|
|
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
if (c[i] != c2[i]){
|
|
log_error("MD5 compare failed: %s != %s HASH %s | %s", file1, file2, c, c2);
|
|
fclose(f1);
|
|
fclose(f2);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
fclose(f1);
|
|
fclose(f2);
|
|
|
|
log_info("MD5s match for %s and %s", file1, file2);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool MD5_hash_compare(const char* file1, const char* hash)
|
|
{
|
|
unsigned char c[MD5_HASH_LENGTH];
|
|
FILE* f1 = fopen(file1, "rb");
|
|
if(!f1) return false;
|
|
MD5_CTX mdContext;
|
|
|
|
int bytes = 0;
|
|
unsigned char data[1024];
|
|
|
|
MD5_Init(&mdContext);
|
|
while ((bytes = fread(data, 1, 1024, f1)) != 0)
|
|
MD5_Update(&mdContext, data, bytes);
|
|
MD5_Final(c, &mdContext);
|
|
|
|
char md5_string[33] = {0};
|
|
|
|
for(int i = 0; i < 16; ++i) {
|
|
snprintf(&md5_string[i*2], 32, "%02x", (unsigned int)c[i]);
|
|
}
|
|
log_info( "[MD5] FILE HASH: %s", md5_string);
|
|
md5_string[32] = 0;
|
|
|
|
if (strcmp(md5_string, hash) != 0) {
|
|
fclose(f1);
|
|
return DIFFERENT_HASH;
|
|
}
|
|
|
|
log_info( "[MD5] Input HASH: %s", hash);
|
|
fclose(f1);
|
|
|
|
return SAME_HASH;
|
|
}
|
|
|
|
|
|
bool is_apputil_init()
|
|
{
|
|
int ret = sceAppInstUtilInitialize();
|
|
if (ret) {
|
|
log_error( " sceAppInstUtilInitialize failed: 0x%08X", ret);
|
|
return false;
|
|
}
|
|
else
|
|
sceAppInst_done = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool app_inst_util_uninstall_patch(const char* title_id, int* error) {
|
|
int ret;
|
|
|
|
*error = 0;
|
|
if(!sceAppInst_done)
|
|
{
|
|
bool res = is_apputil_init();
|
|
if (!res)
|
|
{ *error = 0xDEADBEEF;
|
|
return false;
|
|
}
|
|
}
|
|
if (!title_id) {
|
|
ret = 0x80020016;
|
|
if (error) {
|
|
*error = ret;
|
|
}
|
|
goto err;
|
|
}
|
|
|
|
ret = sceAppInstUtilAppUnInstallPat(title_id);
|
|
if (ret)
|
|
{
|
|
if (error) {
|
|
*error = ret;
|
|
}
|
|
log_error( " sceAppInstUtilAppUnInstallPat failed: 0x%08X", ret);
|
|
goto err;
|
|
}
|
|
|
|
return true;
|
|
|
|
err:
|
|
log_error("app_inst_util_uninstall_patch: 0x%X", error);
|
|
return false;
|
|
}
|
|
|
|
bool app_inst_util_uninstall_game(const char *title_id, int *error)
|
|
{
|
|
int ret;
|
|
*error = 0;
|
|
|
|
if (strlen(title_id) != 9)
|
|
{
|
|
*error = 0xBADBAD;
|
|
return false;
|
|
}
|
|
if(!sceAppInst_done)
|
|
{
|
|
bool res = is_apputil_init();
|
|
if (!res)
|
|
{ *error = 0xDEADBEEF;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!title_id)
|
|
{
|
|
ret = 0x80020016;
|
|
if (error)
|
|
{
|
|
*error = ret;
|
|
}
|
|
goto err;
|
|
}
|
|
|
|
|
|
ret = sceAppInstUtilAppUnInstall(title_id);
|
|
if (ret)
|
|
{
|
|
if (error)
|
|
{
|
|
*error = ret;
|
|
}
|
|
log_error( " sceAppInstUtilAppUnInstall failed: 0x%08X", ret);
|
|
goto err;
|
|
}
|
|
|
|
return true;
|
|
|
|
err:
|
|
log_error("app_inst_util_uninstall_game: 0x%X", error);
|
|
return false;
|
|
}
|
|
|
|
bool app_inst_util_uninstall_ac(const char* content_id, const char* title_id, int* error) {
|
|
|
|
*error = 0;
|
|
|
|
if (!sceAppInst_done)
|
|
{
|
|
bool res = is_apputil_init();
|
|
if (!res)
|
|
{
|
|
*error = 0xDEADBEEF;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
int ret = sceAppInstUtilAppUnInstallAddcont(title_id, content_id);
|
|
if (ret) {
|
|
if (error) {
|
|
*error = ret;
|
|
}
|
|
log_error("sceAppInstUtilAppUnInstallAddcont failed: 0x%08X", ret);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
int app_inst_util_get_size(const char* title_id) {
|
|
uint64_t size = 0;
|
|
|
|
if (!sceAppInst_done) {
|
|
log_debug(" Starting app_inst_util_init..");
|
|
if (!app_inst_util_init()) {
|
|
log_error("app_inst_util_init has failed...");
|
|
return ITEMZCORE_GENERAL_ERROR;
|
|
}
|
|
}
|
|
|
|
int ret = sceAppInstUtilAppGetSize(title_id, &size);
|
|
if (ret) {
|
|
log_error("sceAppInstUtilAppGetSize failed: 0x%08X", ret);
|
|
return ret;
|
|
}
|
|
else
|
|
log_info("Size: %s", calculateSize(size).c_str());
|
|
|
|
return B2GB(size);
|
|
}
|
|
|
|
bool Fnt_setting_enabled = false;
|
|
|
|
static int print_ini_info(void* user, const char* section, const char* name,
|
|
const char* value, int unused)
|
|
{
|
|
static char prev_section[50] = "";
|
|
|
|
if (strcmp(section, prev_section)) {
|
|
log_debug("%s[%s]", (prev_section[0] ? "" : ""), section);
|
|
strncpy(prev_section, section, sizeof(prev_section));
|
|
prev_section[sizeof(prev_section) - 1] = '\0';
|
|
}
|
|
|
|
ItemzSettings* set = (ItemzSettings*)user;
|
|
|
|
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
|
|
|
|
//log_info("Settings: %s = %s", name, value);
|
|
|
|
if (MATCH("Settings", "Daemon_on_start")) {
|
|
set->setting_bools[Daemon_on_start] = atoi(value);
|
|
}
|
|
else if (MATCH("Settings", "TTF_Font")) {
|
|
set->setting_strings[FNT_PATH] = value;
|
|
if (set->setting_strings[FNT_PATH].find("SCE-PS3-RD-R-LATIN.TTF") == std::string::npos){
|
|
log_debug("Font is not default, enabling font settings");
|
|
Fnt_setting_enabled = true;
|
|
}
|
|
}
|
|
else if (MATCH("Settings", "HomeMenu_Redirection")) {
|
|
set->setting_bools[HomeMenu_Redirection] = atoi(value);
|
|
}
|
|
else if (MATCH("Settings", "Show_install_prog")) {
|
|
set->setting_bools[Show_install_prog] = atoi(value);
|
|
}
|
|
else if (MATCH("Settings", "Dumper_option")) {
|
|
set->Dump_opt = (Dump_Multi_Sels)atoi(value);
|
|
}
|
|
else if (MATCH("Settings", "Sort_By")) {
|
|
set->sort_by = (Sort_Multi_Sel)atoi(value);
|
|
}
|
|
else if (MATCH("Settings", "Sort_Cat")) {
|
|
set->sort_cat = (Sort_Category)atoi(value);
|
|
}
|
|
else if (MATCH("Settings", "cover_message")) {
|
|
set->setting_bools[cover_message] = atoi(value);
|
|
}
|
|
else if (MATCH("Settings", "Dumper_Path")) {
|
|
set->setting_strings[DUMPER_PATH] = value;
|
|
}
|
|
else if (MATCH("Settings", "MP3_Path")) {
|
|
set->setting_strings[MP3_PATH] = value;
|
|
}
|
|
else if (MATCH("Settings", "Show_Buttons")) {
|
|
set->setting_bools[Show_Buttons] = atoi(value);
|
|
}
|
|
else if (MATCH("Settings", "Enable_Theme")) {
|
|
set->setting_bools[using_theme] = atoi(value);
|
|
log_debug("Enable_Theme: %d : %d", set->setting_bools[using_theme], atoi(value));
|
|
}
|
|
else if (MATCH("Settings", "Image_path")) {
|
|
set->setting_strings[IMAGE_PATH] = value;//nReflections
|
|
}
|
|
else if (MATCH("Settings", "Reflections")) {
|
|
use_reflection = atoi(value);
|
|
}
|
|
else if (MATCH("Settings", "Fuse_IP")) {
|
|
set->setting_strings[FUSE_PC_NFS_IP] = value;
|
|
}
|
|
else if(MATCH("Settings", "Internal_update")){
|
|
set->setting_bools[INTERNAL_UPDATE] = atoi(value);
|
|
}
|
|
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
bool LoadOptions(ItemzSettings *set)
|
|
{
|
|
bool no_error = true;
|
|
int error = 1;
|
|
theme t;
|
|
unsigned int usb_num = usbpath();
|
|
|
|
set->setting_bools.reserve(NUMB_OF_BOOLS);
|
|
set->setting_strings.reserve(NUMB_OF_STRINGS);
|
|
|
|
//"http://IFUpdate.pkg-zone.com"
|
|
dump = SEL_RESET;
|
|
set->setting_bools[Daemon_on_start] = true;
|
|
set->Dump_opt = SEL_DUMP_ALL;
|
|
set->sort_cat = NO_CATEGORY_FILTER;
|
|
set->sort_by = multi_select_options::NA_SORT;
|
|
set->setting_bools[using_sb] = true;
|
|
set->setting_bools[INTERNAL_UPDATE] = false;
|
|
set->setting_bools[Show_install_prog] = true;
|
|
set->setting_bools[Show_Buttons] = true;
|
|
set->setting_bools[HomeMenu_Redirection] = false;
|
|
set->setting_bools[cover_message] = true;
|
|
set->setting_strings[THEME_NAME] = "Default Theme";
|
|
set->setting_strings[THEME_AUTHOR] = "LM & MZ";
|
|
set->setting_strings[THEME_VERSION] = "1.00";
|
|
set->ItemzCore_AppId = sceSystemServiceGetAppIdOfMiniApp();
|
|
set->ItemzDaemon_AppId = -1;
|
|
if(usb_num != -1)
|
|
set->setting_strings[DUMPER_PATH] = fmt::format("/mnt/usb{}/", usb_num);
|
|
else
|
|
set->setting_strings[DUMPER_PATH] = "/mnt/usb0";
|
|
|
|
|
|
set->setting_strings[FNT_PATH] = "/system_ex/app/NPXS20113/bdjstack/lib/fonts/SCE-PS3-RD-R-LATIN.TTF";
|
|
/* Initialize INI structure */
|
|
if (usb_num != -1)
|
|
{
|
|
set->setting_strings[INI_PATH] = fmt::format("{}/settings.ini", set->setting_strings[DUMPER_PATH]);
|
|
if (!if_exists(set->setting_strings[INI_PATH].c_str()))
|
|
{
|
|
log_warn("No INI on USB");
|
|
if (if_exists("/user/app/ITEM00001/settings.ini")){
|
|
set->setting_strings[INI_PATH] = "/user/app/ITEM00001/settings.ini";
|
|
error = ini_parse("/user/app/ITEM00001/settings.ini", print_ini_info, set);
|
|
if (error < 0) log_error("Bad config file (first error on line %d)!", error);
|
|
}
|
|
} else {
|
|
error = ini_parse(set->setting_strings[INI_PATH].c_str(), print_ini_info, set);
|
|
if (error < 0) log_error("Bad config file (first error on line %d)!", error);
|
|
log_info( " Loading ini from USB");
|
|
}
|
|
}
|
|
else if (!if_exists("/user/app/ITEM00001/settings.ini"))
|
|
{
|
|
log_error("CANT FIND INI"); no_error = false;
|
|
} else {
|
|
error = ini_parse("/user/app/ITEM00001/settings.ini", print_ini_info, set);
|
|
if (error < 0) log_error("Bad config file (first error on line %d)!", error);
|
|
log_info( " Loading ini from APP DIR");
|
|
set->setting_strings[INI_PATH] = "/user/app/ITEM00001/settings.ini";
|
|
}
|
|
|
|
if(set->setting_bools[using_theme] && (set->setting_bools[using_theme] = if_exists(APP_PATH("theme/theme.ini")))){
|
|
log_debug("[THEME] Using Theme detected");
|
|
log_debug("[THEME] Getting Theme Info");
|
|
|
|
t.is_image = false;
|
|
t.using_sb = false;
|
|
t.has_font = false;
|
|
if(ini_parse(APP_PATH("theme/theme.ini"), theme_info, &t) < 0){
|
|
log_error("[THEME] Failed to get Theme Info");
|
|
set->setting_bools[using_theme] = false;
|
|
goto no_theme;
|
|
}
|
|
|
|
log_debug("[THEME] ======== Theme Info =======");
|
|
|
|
fmt::print("[THEME] Name: {}", t.name);
|
|
fmt::print("[THEME] Version: {}", t.version);
|
|
fmt::print("[THEME] Author: {}", t.author);
|
|
fmt::print("[THEME] Date: {}", t.date);
|
|
|
|
set->setting_strings[THEME_NAME] = t.name;
|
|
set->setting_strings[THEME_VERSION] = t.version;
|
|
set->setting_strings[THEME_AUTHOR] = t.author;
|
|
|
|
log_debug("[THEME] Image: %s", t.is_image ? "Yes" : "No");
|
|
log_debug("[THEME] Font: %s", t.has_font ? "Yes" : "No");
|
|
log_debug("[THEME] Shader: %s", t.using_sb ? "Yes" : "No");
|
|
log_debug("[THEME] ======== End of Theme Info =======");
|
|
log_debug("[THEME] Setting ItemzCore settings ...");
|
|
|
|
if(t.has_font){
|
|
//THEME FONT CHECK
|
|
set->setting_strings[FNT_PATH] = fmt::format("{}/font.ttf", APP_PATH("theme"));
|
|
if(!if_exists(set->setting_strings[FNT_PATH].c_str())){
|
|
log_error("[THEME] Font not found");
|
|
t.has_font = false;
|
|
}
|
|
else{
|
|
log_debug("[THEME] Font found");
|
|
Fnt_setting_enabled = true;
|
|
}
|
|
}
|
|
else
|
|
log_debug("[THEME] No Font being used");
|
|
|
|
if(t.is_image){
|
|
set->setting_strings[IMAGE_PATH] = fmt::format("{}/background.png", APP_PATH("theme"));
|
|
if(!if_exists( set->setting_strings[IMAGE_PATH].c_str())){
|
|
fmt::print("[THEME] Image not found, looked @ {}", set->setting_strings[IMAGE_PATH]);
|
|
set->setting_bools[has_image] = t.is_image = false;
|
|
}
|
|
else{
|
|
fmt::print("[THEME] Image found @ {}", set->setting_strings[IMAGE_PATH]);
|
|
set->setting_bools[has_image] = true;
|
|
set->setting_bools[using_sb] = false;
|
|
}
|
|
}
|
|
else {
|
|
log_debug("[THEME] No Image being used");
|
|
set->setting_strings[SB_PATH] = fmt::format("{}/shader.bin", APP_PATH("theme"));
|
|
if(!if_exists(set->setting_strings[SB_PATH].c_str())){
|
|
log_error("[THEME] Shader not found");
|
|
set->setting_bools[using_sb] = t.using_sb = false;
|
|
}
|
|
else{
|
|
log_debug("[THEME] Shader found");
|
|
set->setting_bools[using_sb] = true;
|
|
set->setting_bools[has_image] = false;
|
|
}
|
|
}
|
|
|
|
log_debug("[THEME] Freeing Theme ...");
|
|
}
|
|
no_theme:
|
|
if(!set->setting_strings[IMAGE_PATH].empty()
|
|
&& !set->setting_bools[has_image]){
|
|
set->setting_bools[has_image] = true;
|
|
set->setting_bools[using_sb] = false;
|
|
}
|
|
log_debug("Starting Lang.");
|
|
uint32_t lang = PS4GetLang();
|
|
if (error < 0)
|
|
log_error("ERROR reading INI setting default vals");
|
|
|
|
#if TEST_INI_LANGS
|
|
for (int i = 0; i < 29; i++)
|
|
{
|
|
if (!LoadLangs(i))
|
|
log_debug("Failed to Load %s", Language_GetName(i));
|
|
else
|
|
log_debug("Successfully Loaded %s", Language_GetName(i));
|
|
|
|
}
|
|
#endif
|
|
//fallback lang
|
|
#ifdef OVERRIDE_LANG
|
|
lang = OVERRIDE_LANG;
|
|
#else
|
|
set->lang = lang;
|
|
#endif
|
|
|
|
if (!LoadLangs(lang)) {
|
|
set->lang = 0x01; /// fallback english
|
|
if (!LoadLangs(set->lang)) {
|
|
log_debug(" This PKG has no lang files... trying embedded");
|
|
|
|
if(!load_embdded_eng())
|
|
msgok(MSG_DIALOG::FATAL, "Failed to load Backup Lang...\nThe App is unable to continue");
|
|
else
|
|
log_debug(" Loaded embdded ini lang file");
|
|
}
|
|
else
|
|
log_debug(" Loaded the backup, %s failed to load", Language_GetName(lang).c_str());
|
|
}
|
|
|
|
if (!Fnt_setting_enabled) {
|
|
|
|
switch (lang) {
|
|
case 0: //jAPN IS GREAT
|
|
set->setting_strings[FNT_PATH] = asset_path("fonts/NotoSansJP-Regular.ttf");
|
|
break;
|
|
case 9:///THIS IS FOR JOON, IF HE COMES BACK
|
|
set->setting_strings[FNT_PATH] = asset_path("fonts/NotoSansKR-Regular.ttf");
|
|
break;
|
|
case 21:
|
|
case 23:
|
|
case 24:
|
|
case 25:
|
|
case 26:
|
|
set->setting_strings[FNT_PATH] = asset_path("fonts/HelveticaWorld-Multi.ttf");
|
|
break;
|
|
//NO USERS HAS TRANSLATED THE FOLLOWING LANGS, SO I DELETED THEM OUT THE PKG TO SAVE SPACE
|
|
/*
|
|
case 10:
|
|
strcpy(set->opt[FNT_PATH],"/mnt/sandbox/pfsmnt/ITEM00001-app0/assets/fonts/NotoSansTC-Regular.ttf");
|
|
break;
|
|
case 11:
|
|
strcpy(set->opt[FNT_PATH],"/mnt/sandbox/pfsmnt/ITEM00001-app0/assets/fonts/NotoSansSC-Regular.ttf");
|
|
break;
|
|
case 27:
|
|
strcpy(set->opt[FNT_PATH],"/mnt/sandbox/pfsmnt/ITEM00001-app0/assets/fonts/NotoSansThai-Regular.ttf");
|
|
break;*/
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
//
|
|
|
|
fmt::print("set->ini_path: {}", set->setting_strings[INI_PATH]);
|
|
fmt::print("set->dumper_path: {}", set->setting_strings[DUMPER_PATH]);
|
|
fmt::print("get->fnt_path: {}", set->setting_strings[FNT_PATH]);
|
|
fmt::print("set->fuse_ip: {}", set->setting_strings[FUSE_PC_NFS_IP]);
|
|
fmt::print("set->RESTRICTED: {}", set->setting_bools[INTERNAL_UPDATE]);
|
|
|
|
log_info( "set->Daemon_... : %s", set->setting_bools[Daemon_on_start] ? "ON" : "OFF");
|
|
log_info( "set->HomeMen... : %s", set->setting_bools[HomeMenu_Redirection] ? "ItemzFlow (ON)" : "Orbis (OFF)");
|
|
log_info( "set->sort_by : %i", set->sort_by);
|
|
log_info( "set->Cover_message : %i", set->setting_bools[Cover_message]);
|
|
log_info( "set->using_theme : %i", set->setting_bools[using_theme]);
|
|
log_info( "set->Dump_opt : %i", set->Dump_opt);
|
|
log_info( "set->Install_prog.: %s", set->setting_bools[Show_install_prog] ? "ON" : "OFF");
|
|
log_info( "set->Lang : %s : %i", Language_GetName(lang).c_str(), set->lang);
|
|
|
|
return no_error;
|
|
}
|
|
|
|
|
|
bool SaveOptions(ItemzSettings *set)
|
|
{
|
|
std::string ini_content = fmt::format("[Settings]\nSort_By={0:d}\nSort_Cat={1:d}\nSecure_Boot=1\nTTF_Font={2:}\nShow_install_prog={3:d}\nHomeMenu_Redirection={4:d}\nDaemon_on_start={5:d}\ncover_message={6:d}\nDumper_Path={7:}\nMP3_Path={8:}\nShow_Buttons={9:d}\nEnable_Theme={10:d}\nImage_path={11:}\nReflections={12:d}\nFuse_IP={13:}\n{14:}={15:d}", (int)set->sort_by, (int)set->sort_cat, set->setting_strings[FNT_PATH], set->setting_bools[Show_install_prog], set->setting_bools[HomeMenu_Redirection], set->setting_bools[Daemon_on_start], set->setting_bools[cover_message], set->setting_strings[DUMPER_PATH], set->setting_strings[MP3_PATH], set->setting_bools[Show_Buttons], set->setting_bools[using_theme], set->setting_strings[IMAGE_PATH], use_reflection, set->setting_strings[FUSE_PC_NFS_IP], set->setting_bools[INTERNAL_UPDATE] ? "Internal_update" : "RESTRICTED" , set->setting_bools[INTERNAL_UPDATE]);
|
|
|
|
std::ofstream out(set->setting_strings[INI_PATH]);
|
|
if(out.bad()){
|
|
log_error("Failed to create ini file");
|
|
return false;
|
|
}
|
|
|
|
out << ini_content;
|
|
out.close();
|
|
|
|
log_info("============ Saving the following settings ============");
|
|
fmt::print("set->ini_path: {}", set->setting_strings[INI_PATH]);
|
|
fmt::print("set->dumper_path: {}", set->setting_strings[DUMPER_PATH]);
|
|
fmt::print("get->fnt_path: {}", set->setting_strings[FNT_PATH]);
|
|
fmt::print("set->mp3_path: {}", set->setting_strings[MP3_PATH]);
|
|
fmt::print("set->fuse_ip: {}", set->setting_strings[FUSE_PC_NFS_IP]);
|
|
|
|
log_info("set->Daemon_... : %s", set->setting_bools[Daemon_on_start] ? "ON" : "OFF");
|
|
log_info("set->HomeMen... : %s", set->setting_bools[HomeMenu_Redirection] ? "ItemzFlow (ON)" : "Orbis (OFF)");
|
|
log_info("set->sort_by : %i", set->sort_by);
|
|
log_info("set->Show_Buttons : %i", set->setting_bools[Show_Buttons]);
|
|
log_info("set->cover_message : %i", set->setting_bools[cover_message]);
|
|
log_info("set->Dump_opt : %i", set->Dump_opt);
|
|
log_info("set->using_theme : %i", set->setting_bools[using_theme]);
|
|
log_info("set->RESTIRCTED : %i", set->setting_bools[INTERNAL_UPDATE]);
|
|
log_info("set->Install_prog.: %s", set->setting_bools[Show_install_prog] ? "ON" : "OFF");
|
|
log_info("set->Lang : %s : %i", Language_GetName(set->lang).c_str(), set->lang);
|
|
log_info("==========================================================");
|
|
|
|
/* Load values */
|
|
chmod(set->setting_strings[INI_PATH].c_str(), 0777);
|
|
|
|
return true;
|
|
}
|
|
|
|
uint32_t ps4_fw_version(void)
|
|
{
|
|
//cache the FW Version
|
|
if (0 < sdkVersion) {
|
|
size_t len = 4;
|
|
// sysKernelGetLowerLimitUpdVersion == machdep.lower_limit_upd_version
|
|
// rewrite of sysKernelGetLowerLimitUpdVersion
|
|
sysctlbyname("machdep.lower_limit_upd_version", &sdkVersion, &len, NULL, 0);
|
|
}
|
|
|
|
// FW Returned is in HEX
|
|
return sdkVersion;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////
|
|
|
|
bool Keyboard(const char* Title, const char* initialTextBuffer, char* out_buffer, bool keypad)
|
|
{
|
|
sceSysmoduleLoadModule(ORBIS_SYSMODULE_IME_DIALOG);
|
|
|
|
wchar_t title[100];
|
|
wchar_t inputTextBuffer[255];
|
|
char titl[100];
|
|
|
|
if (initialTextBuffer
|
|
&& strlen(initialTextBuffer) > 1023) return "Too Long";
|
|
|
|
memset(&inputTextBuffer[0], 0, 255);
|
|
memset(out_buffer, 0, 255);
|
|
|
|
if (initialTextBuffer)
|
|
snprintf(out_buffer, 254, "%s", initialTextBuffer);
|
|
//converts the multibyte string src to a wide-character string starting at dest.
|
|
mbstowcs(&inputTextBuffer[0], out_buffer, strlen(out_buffer) + 1);
|
|
// use custom title
|
|
snprintf(&titl[0], 99, "%s", Title ? Title : "Itemzflow");
|
|
//converts the multibyte string src to a wide-character string starting at dest.
|
|
mbstowcs(title, titl, strlen(titl) + 1);
|
|
|
|
OrbisImeDialogParam param;
|
|
memset(¶m, 0, sizeof(OrbisImeDialogParam));
|
|
|
|
param.maxTextLength = 1023;
|
|
param.inputTextBuffer = inputTextBuffer;
|
|
param.title = title;
|
|
param.userId = 0xFE;
|
|
param.type = ORBIS_IME_TYPE_BASIC_LATIN;
|
|
if (keypad)
|
|
param.type = ORBIS_IME_TYPE_NUMBER;
|
|
param.enterLabel = ORBIS_IME_ENTER_LABEL_DEFAULT;
|
|
|
|
sceImeDialogInit(¶m, NULL);
|
|
|
|
int status;
|
|
while (1)
|
|
{
|
|
status = sceImeDialogGetStatus();
|
|
|
|
if (status == ORBIS_IME_DIALOG_STATUS_FINISHED)
|
|
{
|
|
OrbisImeDialogResult result;
|
|
memset(&result, 0, sizeof(OrbisImeDialogResult));
|
|
sceImeDialogGetResult(&result);
|
|
log_info("status %i, endstatus %i ", status, result.endstatus);
|
|
|
|
if (result.endstatus == ORBIS_IME_DIALOG_END_STATUS_USER_CANCELED){
|
|
log_info("User Cancelled this Keyboard Session");
|
|
ani_notify(NOTIFI::WARNING, getLangSTR(LANG_STR::OP_CANNED), getLangSTR(LANG_STR::OP_CANNED_1));
|
|
}
|
|
else if (result.endstatus == ORBIS_IME_DIALOG_END_STATUS_OK)
|
|
{
|
|
log_info("User Entered text.. Entering into buffer");
|
|
wcstombs(out_buffer, &inputTextBuffer[0], 254);
|
|
sceImeDialogTerm();
|
|
return true;
|
|
}
|
|
goto Finished;
|
|
}
|
|
else if (status == ORBIS_IME_DIALOG_STATUS_NONE) goto Finished;
|
|
}
|
|
|
|
Finished:
|
|
sceImeDialogTerm();
|
|
return false;
|
|
}
|
|
|
|
|
|
bool rmtree(const char path[]) {
|
|
|
|
struct dirent* de;
|
|
char fname[300];
|
|
DIR* dr = opendir(path);
|
|
if (dr == NULL)
|
|
{
|
|
log_debug("No file or directory found: %s", path);
|
|
return false;
|
|
}
|
|
while ((de = readdir(dr)) != NULL)
|
|
{
|
|
int ret = -1;
|
|
struct stat statbuf;
|
|
snprintf(fname, 299, "%s/%s", path, de->d_name);
|
|
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
|
|
continue;
|
|
if (!stat(fname, &statbuf))
|
|
{
|
|
if (S_ISDIR(statbuf.st_mode))
|
|
{
|
|
log_debug("removing dir: %s Err: %d", fname, ret = unlinkat(dirfd(dr), fname, AT_REMOVEDIR));
|
|
if (ret != 0)
|
|
{
|
|
rmtree(fname);
|
|
log_debug("Err: %d", ret = unlinkat(dirfd(dr), fname, AT_REMOVEDIR));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
log_debug("Removing file: %s, Err: %d", fname, unlink(fname));
|
|
}
|
|
}
|
|
}
|
|
closedir(dr);
|
|
|
|
return true;
|
|
}
|
|
|
|
void print_memory()
|
|
{
|
|
size_t sz = 0;
|
|
LibcMallocManagedSize ManagedSize;
|
|
SCE_LIBC_INIT_MALLOC_MANAGED_SIZE(ManagedSize);
|
|
malloc_stats_fast(&ManagedSize);
|
|
sceKernelAvailableFlexibleMemorySize(&sz);
|
|
double dfp_fmem = (1. - (double)sz / (double)0x8000000) * 100.;
|
|
|
|
log_info("[MEM] CurrentSystemSize: %s, CurrentInUseSize: %s", calculateSize(ManagedSize.currentSystemSize).c_str(), calculateSize(ManagedSize.currentInuseSize).c_str());
|
|
log_info("[MEM] MaxSystemSize: %s, MaxInUseSize: %s", calculateSize(ManagedSize.maxSystemSize).c_str(), calculateSize(ManagedSize.maxInuseSize).c_str());
|
|
log_info("[VRAM] VRAM_Available: %s, AmountUsed: %.2f%%",calculateSize(sz).c_str(), dfp_fmem);
|
|
}
|
|
|
|
void Kill_BigApp(std::atomic<GameStatus> &status){
|
|
int ret = -1;
|
|
|
|
int BigAppid = sceSystemServiceGetAppIdOfBigApp();
|
|
if(status == NO_APP_OPENED || status == APP_NA_STATUS)
|
|
{
|
|
log_info("[CLOSE] No App is opened");
|
|
return;
|
|
}
|
|
log_info("[CLOSE] BigApp ID: 0x%X", BigAppid);
|
|
if ((ret = ItemzLocalKillApp(BigAppid)) == ITEMZCORE_SUCCESS)
|
|
{
|
|
ani_notify(NOTIFI::INFO, getLangSTR(LANG_STR::APP_CLOSED), "");
|
|
log_info("[CLOSE] App Closed");
|
|
}
|
|
else
|
|
{
|
|
ani_notify(NOTIFI::WARNING, getLangSTR(LANG_STR::FAILED_TO_CLOSE), fmt::format( "{0:}: {1:#x}", getLangSTR(LANG_STR::ERROR_CODE), ret));
|
|
log_error("[CLOSE] Failed to close APP: 0x%X", ret);
|
|
}
|
|
|
|
status = NO_APP_OPENED;
|
|
}
|
|
|
|
int progstart(const char* format, ...)
|
|
{
|
|
|
|
|
|
int ret = 0;
|
|
|
|
char buff[1024];
|
|
|
|
memset(buff, 0, 1024);
|
|
|
|
va_list args;
|
|
va_start(args, format);
|
|
vsprintf(&buff[0], format, args);
|
|
va_end(args);
|
|
|
|
sceSysmoduleLoadModule(ORBIS_SYSMODULE_MESSAGE_DIALOG);
|
|
sceMsgDialogInitialize();
|
|
|
|
OrbisMsgDialogParam dialogParam;
|
|
OrbisMsgDialogParamInitialize(&dialogParam);
|
|
dialogParam.mode = ORBIS_MSG_DIALOG_MODE_PROGRESS_BAR;
|
|
|
|
OrbisMsgDialogProgressBarParam progBarParam;
|
|
memset(&progBarParam, 0, sizeof(OrbisMsgDialogProgressBarParam));
|
|
|
|
dialogParam.progBarParam = &progBarParam;
|
|
dialogParam.progBarParam->barType = ORBIS_MSG_DIALOG_PROGRESSBAR_TYPE_PERCENTAGE;
|
|
dialogParam.progBarParam->msg = &buff[0];
|
|
|
|
sceMsgDialogOpen(&dialogParam);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int Confirmation_Msg(std::string msg)
|
|
{
|
|
|
|
sceMsgDialogTerminate();
|
|
//ds
|
|
|
|
sceMsgDialogInitialize();
|
|
OrbisMsgDialogParam param;
|
|
OrbisMsgDialogParamInitialize(¶m);
|
|
param.mode = ORBIS_MSG_DIALOG_MODE_USER_MSG;
|
|
|
|
OrbisMsgDialogUserMessageParam userMsgParam;
|
|
memset(&userMsgParam, 0, sizeof(userMsgParam));
|
|
userMsgParam.msg = msg.c_str();
|
|
userMsgParam.buttonType = ORBIS_MSG_DIALOG_BUTTON_TYPE_YESNO;
|
|
param.userMsgParam = &userMsgParam;
|
|
// cv
|
|
if (0 < sceMsgDialogOpen(¶m))
|
|
return NO;
|
|
|
|
OrbisCommonDialogStatus stat;
|
|
//
|
|
while (1) {
|
|
stat = sceMsgDialogUpdateStatus();
|
|
if (stat == ORBIS_COMMON_DIALOG_STATUS_FINISHED) {
|
|
|
|
OrbisMsgDialogResult result;
|
|
memset(&result, 0, sizeof(result));
|
|
|
|
sceMsgDialogGetResult(&result);
|
|
|
|
return result.buttonId;
|
|
}
|
|
}
|
|
//c
|
|
return NO;
|
|
}
|
|
// now read frames and decode to s16le samples, from callback
|
|
static int dr_mp3_decode(void)
|
|
{
|
|
if (mp3.pData == NULL) return -1;
|
|
|
|
if (mp3.streamCursor <= dataSize.load())
|
|
{
|
|
int count = drmp3_read_pcm_frames_s16(&mp3, MP3_BUFFER_SIZE, &snd[0] /* &snd */);
|
|
if (count < 0) {
|
|
log_info("[MP3] Failed to read from file");
|
|
return 0;
|
|
}
|
|
else if (count == 0) {
|
|
memset(&snd, 0, MP3_BUFFER_SIZE * 2 * sizeof(short));
|
|
return -1;
|
|
}
|
|
off2 += count;
|
|
|
|
/* play audio sample after being decoded */
|
|
if (!(mp3.streamCursor % 1000)) {
|
|
log_info( "[MP3] audioout play %4d pFrames: %p, %zub %zu %zu %lu %.3f%%",
|
|
count, &snd[0], MP3_BUFFER_SIZE * 2 * sizeof(short),
|
|
off2, dataSize.load(), mp3.streamCursor,
|
|
(float)((float)mp3.streamCursor / (float)dataSize.load()) * 100.f);
|
|
}
|
|
}
|
|
return off2;
|
|
}
|
|
static void audio_PlayCallback(OrbisAudioSample* _buf2, unsigned int length, void* pdata)
|
|
{
|
|
const short* _buf = (short*)_buf2;
|
|
const int play_size = length * 2 * sizeof(short);
|
|
int handle = orbisAudioGetHandle(main_ch.load());
|
|
|
|
if (m_bPlaying.load())
|
|
{
|
|
static int decoded;
|
|
while (fill.load() < (1024 * 2)){
|
|
|
|
decoded = dr_mp3_decode();
|
|
if (decoded < 1) {
|
|
if (!(numframe % 500))
|
|
log_info("[MP3] Playing, but no audio samples decoded yet...");
|
|
|
|
memset(&snd[0], 0, sizeof(snd)); // fill with silence
|
|
log_info("[MP3] ended");
|
|
m_bPlaying = false; // break main loop
|
|
mp3data.clear();
|
|
break;
|
|
}
|
|
else {
|
|
memcpy(&play_buf[fill.load()], &snd[0], 4608); // we are doing in two step, sort of waste
|
|
fill += 1152 /* decoded samples */ * 2 /* channels */;
|
|
}
|
|
}
|
|
if (!(numframe % 500))
|
|
log_info("[MP3] play_buf samples: %d", fill.load());
|
|
|
|
if (!m_bPlaying.load()) {
|
|
orbisAudioSetCallback(main_ch.load(), 0, 0);
|
|
return;
|
|
}
|
|
|
|
/* write to audio device buffers */
|
|
memcpy((void*)_buf, &play_buf[0], play_size); // 1024 samples per channel, = 4096b
|
|
/* move remaining samples to head of buffer */
|
|
memcpy(&play_buf[0], &play_buf[1024 * 2], sizeof(play_buf) - play_size);
|
|
fill -= 1024 * 2;
|
|
|
|
if (fill.load() < 0){
|
|
|
|
fill = 0;
|
|
if (!(numframe % 500))
|
|
log_info("[MP3] no audio frames to play, fill: %d", fill.load());
|
|
|
|
log_info("[MP3] fill.load() < 0");
|
|
m_bPlaying = false;
|
|
mp3data.clear();
|
|
}
|
|
}
|
|
else // Not Playing, so clear buffer
|
|
{
|
|
if (!(numframe % 60))
|
|
log_info("[MP3] Inside audio_PlayCallback, not playing m_bPlaying: %d", m_bPlaying.load());
|
|
|
|
/* write silence to audio device buffers */
|
|
memset((void*)_buf, 0, play_size);
|
|
usleep(1000);
|
|
}
|
|
numframe++;
|
|
sceAudioOutOutput(handle, NULL);
|
|
}
|
|
|
|
/*================================== THEME SHIT BELOW =====================================*/
|
|
|
|
int on_extract_entry(const char *filename, void *arg)
|
|
{
|
|
log_debug("[ZIP] Extracted: %s", filename);
|
|
return 0;
|
|
}
|
|
|
|
bool extract_zip(const char* zip_file, const char* dest_path)
|
|
{
|
|
uint64_t progress[2];
|
|
|
|
struct zip_t *archive = zip_open(zip_file, ZIP_DEFAULT_COMPRESSION_LEVEL, 'r');
|
|
if (!archive){
|
|
log_error("[ZIP] Failed to open archive: %s", zip_file);
|
|
return false;
|
|
}
|
|
|
|
progress[0] = 0;
|
|
progress[1] = zip_entries_total(archive);
|
|
zip_close(archive);
|
|
|
|
log_debug("[ZIP] Extracting ZIP (%lu files) to %s...", progress[1], dest_path);
|
|
|
|
if(zip_extract(zip_file, dest_path, on_extract_entry, progress) == 0) return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/*============================================================================================*/
|
|
bool power_settings(Power_control_sel sel)
|
|
{
|
|
|
|
if(Confirmation_Msg(fmt::format("{}?", power_menu_get_str(sel))) == YES){
|
|
#define SYSCORE_PID 1
|
|
int num = -1;
|
|
switch(sel){
|
|
case POWER_OFF_OPT:
|
|
num = 31;
|
|
break;
|
|
case RESTART_OPT:
|
|
num = 30;
|
|
break;
|
|
case SUSPEND_OPT:
|
|
num = 1;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
if (syscall(37, SYSCORE_PID, num) != ITEMZCORE_SUCCESS) return false;
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
void* timer_thr(void* args){
|
|
sleep(5);
|
|
log_debug("[TIMER] Rebooting App");
|
|
raise(SIGQUIT);
|
|
return NULL;
|
|
}
|
|
|
|
void relaunch_timer_thread()
|
|
{
|
|
pthread_t id;
|
|
reboot_app = true;
|
|
pthread_create(&id, NULL, timer_thr, NULL);
|
|
}
|
|
|
|
/*==================================== UPDATE SHIT ===========================================*/
|
|
update_ret check_update_from_url(const char* tid = ITEMZFLOW_TID)
|
|
{
|
|
if(get->setting_bools[INTERNAL_UPDATE])
|
|
return IF_NO_UPDATE;
|
|
|
|
sceStoreApiCheckUpdate = (update_ret(*)(const char*))prx_func_loader(asset_path("../Media/store_api.prx"), "sceStoreApiCheckUpdate");
|
|
if(sceStoreApiCheckUpdate)
|
|
{
|
|
return sceStoreApiCheckUpdate(tid);
|
|
}
|
|
else
|
|
{
|
|
log_error("Failed to load store_api.prx");
|
|
return IF_UPDATE_ERROR;
|
|
}
|
|
}
|
|
|
|
void* CheckForUpdateThread(void*)
|
|
{
|
|
while (1) {
|
|
update_ret ret = check_update_from_url(ITEMZFLOW_TID);
|
|
if (ret == IF_UPDATE_FOUND){
|
|
log_info(" Update is available, the server reported a different Hash");
|
|
ani_notify(NOTIFI::INFO, getLangSTR(LANG_STR::OPT_UPDATE), "");
|
|
sleep(5 * 60);
|
|
}
|
|
else if(ret == IF_NO_UPDATE) {
|
|
sleep(5 * 60); // no update, check again in 5 minutes
|
|
}
|
|
else if(ret == IF_UPDATE_ERROR) {
|
|
log_info("Update Server is connectionn error, retrying in 60 secs");
|
|
sleep(60);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void launch_update_thread()
|
|
{
|
|
pthread_t id;
|
|
pthread_create(&id, NULL, CheckForUpdateThread, NULL);// pthread_create(&id, NULL, timer_thr, NULL);
|
|
}
|
|
|
|
|
|
bool Launch_Store_URI()
|
|
{
|
|
sceStoreApiLaunchStore = (bool (*)(const char*))prx_func_loader(asset_path("../Media/store_api.prx"), "sceStoreApiLaunchStore");
|
|
if(sceStoreApiLaunchStore)
|
|
{
|
|
return sceStoreApiLaunchStore("Itemzflow");
|
|
}
|
|
else
|
|
{
|
|
log_error("Failed to load store_api.prx");
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void ProgressUpdate(uint32_t prog, std::string fmt)
|
|
{
|
|
|
|
int status = sceMsgDialogUpdateStatus();
|
|
if (ORBIS_COMMON_DIALOG_STATUS_RUNNING == status) {
|
|
sceMsgDialogProgressBarSetValue(0, prog);
|
|
sceMsgDialogProgressBarSetMsg(0, fmt.c_str());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
mp3_status_t MP3_Player(std::string path) {
|
|
|
|
TagLib::FileRef songf;
|
|
std::ifstream file;
|
|
|
|
if(path.empty() || path.size() < 3 || !if_exists(path.c_str()))
|
|
return MP3_STATUS_ERROR;
|
|
|
|
|
|
if (m_bPlaying.load() || retry_mp3_count >= 2) // ALREADY PLAYING
|
|
return MP3_STATUS_PLAYING;
|
|
|
|
current_song.song_title.clear();
|
|
current_song.song_artist.clear();
|
|
current_song.is_playing = false;
|
|
dataSize = 0;
|
|
if (path.substr(path.size() - 3, 3) != "mp3" && mp3_playlist.empty()) {
|
|
if(!is_folder(path.c_str()))
|
|
{
|
|
log_error("Not a folder: %s", path.c_str());
|
|
goto err;
|
|
}
|
|
FS_FILTER filter = fs_ret.filter;
|
|
fs_ret.filter = FS_MP3_ONLY;
|
|
index_items_from_dir_v2(path, mp3_playlist);
|
|
fs_ret.filter = filter;
|
|
//skip reserved index
|
|
if (mp3_playlist.size() <= 1) {
|
|
log_error("No MP3s in: %s", path.c_str());
|
|
mp3_playlist.clear();
|
|
goto err;
|
|
}
|
|
else {
|
|
log_info("Found %d MP3 files in %s", mp3_playlist.size()-1, path.c_str());
|
|
current_song.total_files = mp3_playlist.size()-1;
|
|
current_song.current_file = 1;
|
|
}
|
|
}
|
|
|
|
if (path.substr(path.size() - 3, 3) != "mp3" && mp3_playlist.size() > 1) {
|
|
if (current_song.current_file >= mp3_playlist.size()) {
|
|
log_info("Reached end of playlist, resetting index");
|
|
current_song.current_file = 1;
|
|
}
|
|
path = path + "/" + mp3_playlist[current_song.current_file].info.id;
|
|
if (path.substr(path.size() - 3, 3) != "mp3") {
|
|
log_error("Not a valid MP3 file: %s", path.c_str());
|
|
goto err;
|
|
}
|
|
}
|
|
else if (path.substr(path.size() - 3, 3) == "mp3") {
|
|
current_song.total_files = 1;
|
|
current_song.current_file = 0;
|
|
}
|
|
|
|
log_info("[MP3] Trying to play: %s", path.c_str());
|
|
songf = TagLib::FileRef(path.c_str());
|
|
if(songf.isNull() || !songf.tag())
|
|
{
|
|
log_error("Unknown File: %s", path.c_str());
|
|
goto err;
|
|
}
|
|
|
|
if (path.substr(path.size() - 3, 3) == "mp3") {
|
|
current_song.song_title = songf.tag()->title().isEmpty() ? path : songf.tag()->title().toCString(true);
|
|
current_song.song_artist = songf.tag()->artist().isEmpty() ? "Unknown Artist" : songf.tag()->artist().toCString(true);
|
|
}
|
|
else
|
|
{
|
|
current_song.song_title = songf.tag()->title().isEmpty() ? mp3_playlist[current_song.current_file].info.id : songf.tag()->title().toCString(true);
|
|
current_song.song_artist = songf.tag()->artist().isEmpty() ? "Unknown Artist" : songf.tag()->artist().toCString(true);
|
|
}
|
|
|
|
Config.outputSampleRate = 48000;
|
|
//load mp3 data for the drmp3 mp3 decoder
|
|
file.open(path.c_str(), std::ios::binary);
|
|
if(!file.is_open())
|
|
{
|
|
log_error("Failed to open file: %s", path.c_str());
|
|
goto err;
|
|
}
|
|
file.seekg(0, std::ios::end);
|
|
dataSize = file.tellg();
|
|
file.seekg(0, std::ios::beg);
|
|
//get the file size
|
|
if(dataSize == 0 || dataSize > MB(20))
|
|
{
|
|
log_error("MP3 Too big or is truncated: %s", path.c_str());
|
|
file.close();
|
|
goto err;
|
|
}
|
|
mp3data = std::vector<uint8_t>(std::istreambuf_iterator<char>(file), {});
|
|
file.close();
|
|
|
|
if (!drmp3_init_memory(&mp3, mp3data.data(), mp3data.size(), &Config)) {
|
|
mp3data.clear();
|
|
log_error("[MP3] drmp3_init_memory failed: %s", path.c_str());
|
|
goto err;
|
|
}
|
|
// attach audio callback
|
|
off2 = 0, fill = 0;
|
|
orbisAudioSetCallback(main_ch.load(), audio_PlayCallback, 0);
|
|
// start audio callback, and play
|
|
fmt::print("Playing: {0:} - {1:} ({2:})", current_song.song_title, current_song.song_artist, dataSize, (get->lang == 1 || get->lang == 2));
|
|
current_song.is_playing = m_bPlaying = true, orbisAudioResume(0);
|
|
current_song.current_file++;
|
|
GLES2_refresh_sysinfo();
|
|
|
|
return MP3_STATUS_STARTED;
|
|
|
|
err:
|
|
if (2 >= retry_mp3_count) {
|
|
ani_notify(NOTIFI::WARNING, getLangSTR(LANG_STR::FAILED_MP3), fmt::format("({0:d}/2)", retry_mp3_count+1));
|
|
retry_mp3_count++;
|
|
}
|
|
dataSize = 0;
|
|
mp3data.clear();
|
|
|
|
return MP3_STATUS_ERROR;
|
|
}
|
|
|
|
void Stop_Music(){
|
|
|
|
if(!m_bPlaying)
|
|
return;
|
|
|
|
log_info("Stopping MP3 Playback ...");
|
|
// set playing to false
|
|
current_song.is_playing = m_bPlaying = false;
|
|
//Stop audio callback
|
|
orbisAudioPause(0);
|
|
orbisAudioSetCallback(main_ch.load(), NULL, 0);
|
|
//Clear mp3 data
|
|
mp3data.clear();
|
|
mp3_playlist.clear();
|
|
get->setting_strings[MP3_PATH].clear();
|
|
//Clear mp3 decoder
|
|
drmp3_uninit(&mp3);
|
|
//Clear mp3 tags AND audio channel handle
|
|
current_song.song_artist = current_song.song_title = "";
|
|
retry_mp3_count = current_song.current_file = main_ch = current_song.total_files = 0;
|
|
|
|
}
|
|
bool do_update(std::string url) {
|
|
IPC_Client& ipc = IPC_Client::getInstance();
|
|
|
|
log_debug("[UPDATE] Starting Update...");
|
|
log_debug("[UPDATE] Updating...");
|
|
|
|
if (get->setting_bools[INTERNAL_UPDATE] && !is_connected_app) {
|
|
log_debug("[UPDATE] Daemon Not connected to app, exiting update mode ... ");
|
|
return false;
|
|
}
|
|
|
|
if (get->setting_bools[INTERNAL_UPDATE]) {
|
|
std::string tmp;
|
|
long ret = -1;
|
|
tmp = fmt::format("{}/update/if_update.pkg", url.c_str());
|
|
if ((ret = dl_from_url(tmp.c_str(), APP_PATH("../if_update.pkg"))) < 0 && if_exists(APP_PATH("../if_update.pkg"))) {
|
|
log_error("[UPDATE] Failed to download if_update.pkg ret: %i", ret);
|
|
return false;
|
|
}
|
|
|
|
ipc_msg = std::to_string(getpid());
|
|
|
|
IPC_Ret error = ipc.IPCSendCommand(IPC_Commands::INSTALL_IF_UPDATE, ipc_msg);
|
|
if (error != IPC_Ret::NO_ERROR) {
|
|
sceMsgDialogTerminate();
|
|
log_error("[UPDATE] IPC INSTALL UPDATE ERROR: %i", error);
|
|
return false;
|
|
}
|
|
|
|
log_debug("[UPDATE] Copied, Removing Temp Files");
|
|
log_debug("[UPDATE] Complete...");
|
|
|
|
raise(SIGQUIT);
|
|
} else {
|
|
if (!Launch_Store_URI()) {
|
|
log_error("[UPDATE] Failed to launch store uri");
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void check_for_update_file() {
|
|
IPC_Client& ipc = IPC_Client::getInstance();
|
|
|
|
loadmsg(getLangSTR(LANG_STR::CHECH_UPDATE_IN_PROGRESS));
|
|
|
|
bool found = false;
|
|
log_debug("[STARTUP][UPDATE] Checking for update file ...");
|
|
if (if_exists("/user/update_tmp")) {
|
|
log_debug("[IF_UPDATE] Found Update temp folder, moving files back.."); //if updated via store
|
|
copy_dir("/user/update_tmp/covers", "/user/app/ITEM00001/covers");
|
|
copy_dir("/user/update_tmp/custom_app_names", "/user/app/ITEM00001/custom_app_names");
|
|
copyFile("/user/update_tmp/settings.ini", "/user/app/ITEM00001/settings.ini", false);
|
|
rmtree("/user/update_tmp");
|
|
unlink("/user/update_tmp");
|
|
log_debug("[IF_UPDATE] Moved files back, removing temp folder..");
|
|
} else {
|
|
log_info("No Update temp folder found");
|
|
}
|
|
|
|
if (!is_connected_app) {
|
|
log_debug("[STARTUP][UPDATE] Daemon Not connected to app, exiting update mode ... ");
|
|
sceMsgDialogTerminate();
|
|
return;
|
|
}
|
|
|
|
if (if_exists(APP_PATH("../if_update.pkg"))) {
|
|
log_debug("[STARTUP][UPDATE][HDD] if_update.pkg exists, starting update ...");
|
|
found = true;
|
|
} else if (usbpath() != -1 && if_exists(fmt::format("/mnt/usb{}/if_update.pkg", usbpath()).c_str())) {
|
|
log_debug("[STARTUP][UPDATE][USB] if_update.pkg exists, starting update ...");
|
|
copyFile(fmt::format("/mnt/usb{}/if_update.pkg", usbpath()), APP_PATH("../if_update.pkg"), false);
|
|
found = true;
|
|
} else {
|
|
log_debug("[STARTUP][UPDATE] if_update.pkg does not exist, exiting update mode ...");
|
|
sceMsgDialogTerminate();
|
|
return;
|
|
}
|
|
|
|
if (found) {
|
|
log_debug("[STARTUP][UPDATE] Update Found, Sending IPC Command for Update Installing ...");
|
|
ipc_msg = std::to_string(getpid());
|
|
log_info("[STARTUP] Sending PID: %s", ipc_msg.c_str());
|
|
IPC_Ret error = ipc.IPCSendCommand(IPC_Commands::INSTALL_IF_UPDATE, ipc_msg);
|
|
if (error != IPC_Ret::NO_ERROR) {
|
|
log_error("[STARTUP][UPDATE] IPC INSTALL UPDATE ERROR: %i", error);
|
|
sceMsgDialogTerminate();
|
|
return;
|
|
}
|
|
} else {
|
|
log_debug("[STARTUP][UPDATE] if_update.pkg does not exist, exiting update mode ...");
|
|
sceMsgDialogTerminate();
|
|
return;
|
|
}
|
|
|
|
raise(SIGQUIT);
|
|
}
|
|
/*============================================================================================*/
|
|
|
|
void notify(const char* message)
|
|
{
|
|
|
|
log_info(message);
|
|
sceKernelLoadStartModule("/system/common/lib/libSceSysUtil.sprx", 0, NULL, 0, 0, 0);
|
|
sceSysUtilSendSystemNotificationWithText(222, message);
|
|
}
|
|
|
|
// https://github.com/OSM-Made/PS4-Notify/blob/c6d259bc5bd4aa519f5b0ce4f5e27ef7cb01ffdd/Notify.cpp
|
|
void notifywithicon(const char* IconURI, const char* MessageFMT, ...)
|
|
{
|
|
NotifyBuffer Buffer;
|
|
|
|
va_list args;
|
|
va_start(args, MessageFMT);
|
|
vsprintf(Buffer.Message, MessageFMT, args);
|
|
va_end(args);
|
|
|
|
Buffer.Type = NotifyType::NotificationRequest;
|
|
Buffer.unk3 = 0;
|
|
Buffer.UseIconImageUri = 1;
|
|
Buffer.TargetId = -1;
|
|
strcpy(Buffer.Uri, IconURI);
|
|
sceKernelSendNotificationRequest(0, (char*)&Buffer, sizeof(Buffer), 0);
|
|
}
|
|
|
|
bool get_ip_address(std::string &ip)
|
|
{
|
|
int ret;
|
|
SceNetCtlInfo info;
|
|
|
|
ret = sceNetCtlGetInfo(14, &info);
|
|
if (ret < 0)
|
|
return false;
|
|
|
|
ip = info.ip_address;
|
|
|
|
return true;
|
|
}
|
|
|
|
void msgok(MSG_DIALOG::MSG_DIALOG_TYPE level, std::string in)
|
|
{
|
|
sceMsgDialogTerminate();
|
|
std::string out;
|
|
|
|
switch (level)
|
|
{
|
|
case MSG_DIALOG::NORMAL:
|
|
out = in;
|
|
break;
|
|
case MSG_DIALOG::FATAL:
|
|
|
|
log_fatal(in.c_str());
|
|
out = fmt::format("{0:} {1:}\n\n {2:}", getLangSTR(LANG_STR::FATAL_ERROR), in, getLangSTR(LANG_STR::PRESS_OK_CLOSE));
|
|
break;
|
|
case MSG_DIALOG::WARNING:
|
|
log_warn( in.c_str());
|
|
out = fmt::format("{0:} {1:}", getLangSTR(LANG_STR::WARNING2), in);
|
|
break;
|
|
}
|
|
|
|
sceMsgDialogInitialize();
|
|
OrbisMsgDialogParam param;
|
|
OrbisMsgDialogParamInitialize(¶m);
|
|
param.mode = ORBIS_MSG_DIALOG_MODE_USER_MSG;
|
|
|
|
OrbisMsgDialogUserMessageParam userMsgParam;
|
|
memset(&userMsgParam, 0, sizeof(userMsgParam));
|
|
userMsgParam.msg = out.c_str();
|
|
userMsgParam.buttonType = ORBIS_MSG_DIALOG_BUTTON_TYPE_OK;
|
|
param.userMsgParam = &userMsgParam;
|
|
|
|
if (sceMsgDialogOpen(¶m) < 0) log_fatal( "MsgD failed");
|
|
|
|
OrbisCommonDialogStatus stat;
|
|
|
|
while (1) {
|
|
stat = sceMsgDialogUpdateStatus();
|
|
if (stat == ORBIS_COMMON_DIALOG_STATUS_FINISHED)
|
|
{
|
|
OrbisMsgDialogResult result;
|
|
memset(&result, 0, sizeof(result));
|
|
|
|
if (0 > sceMsgDialogGetResult(&result)) log_fatal( "MsgD failed");
|
|
|
|
sceMsgDialogTerminate();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (level == MSG_DIALOG::FATAL) {
|
|
log_fatal(in.c_str());
|
|
raise(SIGQUIT);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void loadmsg(std::string in)
|
|
{
|
|
|
|
OrbisMsgDialogButtonsParam buttonsParam;
|
|
OrbisMsgDialogUserMessageParam messageParam;
|
|
OrbisMsgDialogParam dialogParam;
|
|
|
|
sceMsgDialogInitialize();
|
|
OrbisMsgDialogParamInitialize(&dialogParam);
|
|
|
|
memset(&buttonsParam, 0x00, sizeof(buttonsParam));
|
|
memset(&messageParam, 0x00, sizeof(messageParam));
|
|
|
|
dialogParam.userMsgParam = &messageParam;
|
|
dialogParam.mode = ORBIS_MSG_DIALOG_MODE_USER_MSG;
|
|
|
|
messageParam.buttonType = ORBIS_MSG_DIALOG_BUTTON_TYPE_WAIT;
|
|
messageParam.msg = in.c_str();
|
|
|
|
sceMsgDialogOpen(&dialogParam);
|
|
|
|
return;
|
|
}
|
|
|
|
void scan_for_disc() {
|
|
//check if theres a disc
|
|
//std::lock_guard < std::mutex > lock(disc_lock);
|
|
char stack_tid[16];
|
|
int ret = -1;
|
|
|
|
memset( & stack_tid[0], 0, 16);
|
|
if ((ret = sceAppInstUtilAppGetInsertedDiscTitleId( & stack_tid[0])) >= 0 && !is_disc_inserted.load()) {
|
|
if (!all_apps.empty() && all_apps.size() > 1) {
|
|
for (int i = 0; i < all_apps[0].count.token_c + 1; i++) {
|
|
// skip if its an FPKG
|
|
if (all_apps[i].flags.is_fpkg)
|
|
continue;
|
|
|
|
// log_info("Disc inserted: %s : %i %s", stack_tid, i , all_apps[i].id.c_str());
|
|
if (all_apps[i].info.id.find( & stack_tid[0]) != std::string::npos) {
|
|
//Store the texture ID of the inserted disc
|
|
inserted_disc = i;
|
|
//inserted_disc: 1 CUSA00900 1 18
|
|
log_info("[UTIL] inserted_disc: %i %s %i %s %i", inserted_disc.load(), stack_tid, i, all_apps[i].info.id.c_str(), all_apps.size());
|
|
is_disc_inserted = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else if (ret == SCE_APP_INSTALLER_ERROR_DISC_NOT_INSERTED) {
|
|
// log_info("[UTIL] disc not inserted %x", ret);
|
|
inserted_disc = -999;
|
|
is_disc_inserted = false;
|
|
}
|
|
}
|
|
|
|
bool install_IF_Theme(std::string theme_path){
|
|
|
|
theme t;
|
|
int ret = -9;
|
|
int h, w;
|
|
std::string tmp;
|
|
fmt::print("[THEME][START] Installing Theme: {}", theme_path);
|
|
|
|
if(!if_exists(APP_PATH("theme"))){
|
|
log_error("[THEME] No Theme already exists, Making folder");
|
|
mkdir(APP_PATH("theme"), 0777);
|
|
}
|
|
else{
|
|
log_debug("[THEME] Theme already exists, Removing");
|
|
rmtree(APP_PATH("theme"));
|
|
log_debug("[THEME] Theme Removed");
|
|
}
|
|
log_debug("[THEME] Extracting Theme ...");
|
|
if(!extract_zip(theme_path.c_str(), APP_PATH("theme"))){
|
|
log_error("[THEME] Failed to extract Theme");
|
|
goto err;
|
|
}
|
|
log_debug("[THEME] Extracting Theme Done");
|
|
log_debug("[THEME] Getting Theme Info");
|
|
|
|
t.is_image = false;
|
|
t.using_sb = false;
|
|
get->setting_strings[FNT_PATH] = "/system_ex/app/NPXS20113/bdjstack/lib/fonts/SCE-PS3-RD-R-LATIN.TTF";
|
|
|
|
if(!if_exists(APP_PATH("theme/theme.ini")) || (ret = ini_parse(APP_PATH("theme/theme.ini"), theme_info, &t)) < 0){
|
|
log_error("[THEME][ERROR] Failed to Fetch Theme Info, ERROR %i", ret);
|
|
goto err;
|
|
}
|
|
/*============================ QA Theme CHECKS ================================================*/
|
|
if(t.version.empty() || t.name.empty() || t.author.empty() || t.date.empty()){
|
|
log_error("[THEME][ERROR] Theme Info is missing");
|
|
goto err;
|
|
}
|
|
if(t.is_image && (!if_exists(APP_PATH("theme/background.png")) || !is_png_vaild(APP_PATH("theme/background.png"), &h, &w))){
|
|
log_error("[THEME][ERROR] No vaild Theme Image but the INI reports its using one");
|
|
goto err;
|
|
}
|
|
if(t.has_font && !if_exists(APP_PATH("theme/font.ttf")) ){
|
|
log_error("[THEME][ERROR] No vaild FONT but the INI reports its using one");
|
|
goto err;
|
|
}
|
|
for(int i = 0; i < sizeof required_theme_files / sizeof required_theme_files[0]; i++){
|
|
|
|
tmp = fmt::format("{}{}", APP_PATH(""), required_theme_files[i]);
|
|
|
|
if(!if_exists(tmp.c_str()) || !is_png_vaild(tmp.c_str(), &h, &w)){
|
|
log_error("[THEME][ERROR] Error Loading file %s which is required for themes, maybe its invaild/corrupt?", &tmp[0]);
|
|
goto err;
|
|
}
|
|
}
|
|
if(t.using_sb && !if_exists(APP_PATH("theme/shader.bin"))){
|
|
log_error("[THEME][ERROR] No Shader Binary but the INI reports its using one");
|
|
goto err;
|
|
}
|
|
else if(t.using_sb){
|
|
int programID = -1;
|
|
const char* data = (const char*)orbisFileGetFileContent(APP_PATH("theme/shader.bin"));
|
|
if(data == NULL){
|
|
log_debug("[THEME][ERROR] can't load shader.bin");
|
|
goto err;
|
|
}
|
|
else{
|
|
programID = BuildProgram(p_vs1, data, p_vs1_length, _orbisFile_lastopenFile_size);
|
|
if(programID == -1){
|
|
log_debug("[THEME][ERROR] Shader Testing Failed!!!");
|
|
free((void*)data);
|
|
goto err;
|
|
}
|
|
else
|
|
log_debug("[THEME][INFO] Shader Built... programID: %i", programID);
|
|
// NO leaks pls
|
|
glDeleteProgram(programID);
|
|
free((void*)data);
|
|
|
|
}
|
|
}
|
|
|
|
log_debug("[THEME] ======== Theme Info =======");
|
|
|
|
fmt::print("[THEME] Name: {}", t.name);
|
|
fmt::print("[THEME] Version: {}", t.version);
|
|
fmt::print("[THEME] Date: {}", t.date);
|
|
fmt::print("[THEME] Author: {}", t.author);
|
|
|
|
log_debug("[THEME] Image: %s", t.is_image ? "Yes" : "No");
|
|
log_debug("[THEME] Font: %s", t.has_font ? "Yes" : "No");
|
|
log_debug("[THEME] Shader: %s", t.using_sb ? "Yes" : "No");
|
|
log_debug("[THEME] ======== End of Theme Info =======");
|
|
log_debug("[THEME] Freeing Theme Info ...");
|
|
|
|
get->setting_bools[has_image] = t.is_image;
|
|
get->setting_bools[using_sb] = t.using_sb;
|
|
get->setting_bools[using_theme] = true;
|
|
|
|
if(!SaveOptions(get)){
|
|
log_error("[THEME] Failed to save Theme Options");
|
|
goto err;
|
|
}
|
|
|
|
zip_create(APP_PATH("Reset Theme to Default.zip"), &if_d_zip[0], 200);
|
|
|
|
if(usbpath() != -1){
|
|
log_debug("[THEME] USB Path is set, updating USB Theme");
|
|
tmp = fmt::format("/mnt/usb{}/Reset Theme to Default.zip", usbpath());
|
|
zip_create(tmp.c_str(), &if_d_zip[0], 200);
|
|
|
|
}
|
|
|
|
fmt::print("[THEME] Theme Installed: {}", t.name);
|
|
sceMsgDialogTerminate();
|
|
|
|
return true;
|
|
|
|
err:
|
|
log_error("[THEME][ERROR] Freeing Theme Info ...");
|
|
log_error("[THEME][ERROR] Deleting Theme Dir ...");
|
|
rmtree(APP_PATH("theme"));
|
|
log_error("[THEME][ERROR] Theme Dir Deleted");
|
|
log_error("[THEME][ERROR] Resetting IF Settings ...");
|
|
get->setting_strings[FNT_PATH] = "/system_ex/app/NPXS20113/bdjstack/lib/fonts/SCE-PS3-RD-R-LATIN.TTF";
|
|
get->setting_bools[using_theme] = false;
|
|
if(!SaveOptions(get))
|
|
log_error("[THEME][ERROR] Failed to save Theme Options");
|
|
|
|
log_error("[THEME][ERROR] Complete.. returning....");
|
|
sceMsgDialogTerminate();
|
|
return false;
|
|
}
|
|
|
|
uint32_t Launch_App(std::string TITLE_ID, bool silent, int index) {
|
|
|
|
uint32_t sys_res = -1;
|
|
u32 userId = -1;
|
|
|
|
int libcmi = sceKernelLoadStartModule("/system/common/lib/libSceSystemService.sprx", 0, NULL, 0, 0, 0);
|
|
if (libcmi > 0)
|
|
{
|
|
fmt::print("Starting action Launch_App({0:}, {1:d})", TITLE_ID, silent);
|
|
fmt::print("sceUserServiceGetForegroundUser {0:#x}", sceUserServiceGetForegroundUser(&userId));
|
|
fmt::print("Launching App for User: {0:#x}", userId);
|
|
|
|
LncAppParam param;
|
|
param.sz = sizeof(LncAppParam);
|
|
param.user_id = userId;
|
|
param.app_opt = 0;
|
|
param.crash_report = 0;
|
|
param.check_flag = SkipSystemUpdateCheck;
|
|
|
|
sys_res = sceLncUtilLaunchApp(TITLE_ID.c_str(), NULL, ¶m);
|
|
if (IS_ERROR(sys_res))
|
|
{
|
|
if (!silent) {
|
|
fmt::print("[ERROR] Switch {0:#x}", sys_res);
|
|
switch (sys_res) {
|
|
case SCE_LNC_ERROR_APP_NOT_FOUND: {
|
|
//msgok(MSG_DIALOG::WARNING, getLangSTR(LANG_STR::APP_NOT_FOUND));
|
|
if(Confirmation_Msg(fmt::format("{0:}\n\n{1:}\n{2:}", getLangSTR(LANG_STR::IF_LAUNCH_TROUBLESHOOTER), getLangSTR(LANG_STR::LAUNCH_FAILED_BC_NOT_FOUND), getLangSTR(LANG_STR::CONFIRMATION_2))) == YES){
|
|
if(Fix_Game_In_DB(all_apps, index, all_apps[index].flags.is_fpkg))
|
|
ani_notify(NOTIFI::GAME, getLangSTR(LANG_STR::GAME_INSERT_SUCCESSFUL), getLangSTR(LANG_STR::REPAIR_ATTEMPTED1));
|
|
else
|
|
msgok(MSG_DIALOG::WARNING, getLangSTR(LANG_STR::GAME_INSERT_FAILED));
|
|
}
|
|
break;
|
|
}
|
|
case SCE_LNC_UTIL_ERROR_ALREADY_RUNNING: {
|
|
msgok(MSG_DIALOG::WARNING, getLangSTR(LANG_STR::APP_OPENED));
|
|
break;
|
|
}
|
|
case SCE_LNC_UTIL_ERROR_APPHOME_EBOOTBIN_NOT_FOUND: {
|
|
msgok(MSG_DIALOG::WARNING, getLangSTR(LANG_STR::MISSING_EBOOT));
|
|
break;
|
|
}
|
|
case SCE_LNC_UTIL_ERROR_APPHOME_PARAMSFO_NOT_FOUND: {
|
|
msgok(MSG_DIALOG::WARNING, getLangSTR(LANG_STR::MISSING_SFO));
|
|
break;
|
|
}
|
|
case SCE_LNC_UTIL_ERROR_NO_SFOKEY_IN_APP_INFO: {
|
|
//msgok(MSG_DIALOG::WARNING, getLangSTR(LANG_STR::CORRUPT_SFO));
|
|
if(Confirmation_Msg(fmt::format("{0:}\n\n{1:}\n{2:}", getLangSTR(LANG_STR::IF_LAUNCH_TROUBLESHOOTER), getLangSTR(LANG_STR::FIX_BROKEN_SFO_DB), getLangSTR(LANG_STR::CONFIRMATION_3))) == YES){
|
|
if(Fix_Game_In_DB(all_apps, index, all_apps[index].flags.is_fpkg))
|
|
ani_notify(NOTIFI::GAME, getLangSTR(LANG_STR::REPAIR_ATTEMPTED), getLangSTR(LANG_STR::REPAIR_ATTEMPTED1));
|
|
else
|
|
msgok(MSG_DIALOG::WARNING, getLangSTR(LANG_STR::GAME_INSERT_FAILED));
|
|
}
|
|
break;
|
|
}
|
|
case SCE_LNC_UTIL_ERROR_ALREADY_RUNNING_KILL_NEEDED: {
|
|
log_debug("ALREADY RUNNING KILL NEEDED");
|
|
break;
|
|
}
|
|
case SCE_LNC_UTIL_ERROR_ALREADY_RUNNING_SUSPEND_NEEDED: {
|
|
log_debug("ALREADY RUNNING SUSPEND NEEDED");
|
|
break;
|
|
}
|
|
case SCE_LNC_UTIL_ERROR_SETUP_FS_SANDBOX: {
|
|
msgok(MSG_DIALOG::WARNING, getLangSTR(LANG_STR::APP_UNL));
|
|
break;
|
|
}
|
|
case SCE_LNC_UTIL_ERROR_INVALID_TITLE_ID: {
|
|
msgok(MSG_DIALOG::WARNING, getLangSTR(LANG_STR::ID_NOT_VAILD));
|
|
break;
|
|
}
|
|
case PROCCESS_STARTER_OP_NOT_SUPPORTED: {
|
|
|
|
if(TITLE_ID == APP_HOME_HOST_TID)
|
|
msgok(MSG_DIALOG::WARNING, getLangSTR(LANG_STR::LNC_TOO_MANY_ROOT_FILES));
|
|
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
msgok(MSG_DIALOG::WARNING, fmt::format("{0:}: {1:#x}", getLangSTR(LANG_STR::LAUNCH_ERROR),sys_res));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fmt::print("launch ret {0:#x}", sys_res);
|
|
}
|
|
else {
|
|
if(!silent)
|
|
msgok(MSG_DIALOG::WARNING, fmt::format("{0:}: {1:#x}", getLangSTR(LANG_STR::LAUNCH_ERROR),libcmi));
|
|
}
|
|
|
|
return sys_res;
|
|
}
|
|
|
|
bool is_sfo(const char* input_file_name) {
|
|
FILE* file = fopen(input_file_name, "rb");
|
|
if (file == NULL) return false;
|
|
|
|
// Get SFO header offset
|
|
uint32_t magic;
|
|
fread(&magic, 4, 1, file);
|
|
if (magic == 1179865088) { // Param.sfo file
|
|
rewind(file);
|
|
}
|
|
else
|
|
{
|
|
log_error("[SFO] Not a param.sfo file. %s", input_file_name);
|
|
fclose(file);
|
|
return false;
|
|
}
|
|
fclose(file);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool is_fpkg(std::string pkg_path) {
|
|
|
|
PKG_HDR hdr;
|
|
// Open path
|
|
int pkg = open(pkg_path.c_str(), 0, 0);
|
|
if (pkg < 0){
|
|
fmt::print("[ERROR] Error opening file: {}", pkg_path);
|
|
return false;
|
|
}
|
|
|
|
lseek(pkg, 0, SEEK_SET);
|
|
//first byte
|
|
read(pkg, &hdr, sizeof(PKG_HDR));
|
|
close(pkg);
|
|
|
|
//fmt::print("pkg_path: {0:} | hdr.magic: {1:x}", pkg_path, hdr.magic);
|
|
|
|
return (hdr.flags & FPKG) == 0;
|
|
}
|
|
|
|
bool dlc_pkg_details(const char* src_dest, DLC_PKG_DETAILS &details) {
|
|
|
|
// Read PKG header
|
|
struct pkg_header hdr;
|
|
//char title[256];
|
|
static const uint8_t pkg_magic[] = { '\x7F', 'C', 'N', 'T' };
|
|
// Open path
|
|
int pkg = sceKernelOpen(src_dest, O_RDONLY, 0);
|
|
if (pkg < 0){
|
|
log_error("Error opening file: %s, err: %s", src_dest, strerror(errno));
|
|
return false;
|
|
}
|
|
|
|
sceKernelLseek(pkg, 0, SEEK_SET);
|
|
sceKernelRead(pkg, &hdr, sizeof(struct pkg_header));
|
|
|
|
if (memcmp(hdr.magic, pkg_magic, sizeof(pkg_magic)) != 0) {
|
|
log_error("PKG Format is wrong");
|
|
sceKernelClose(pkg);
|
|
return false;
|
|
}
|
|
|
|
sceKernelClose(pkg);
|
|
details.contentid = std::string(hdr.content_id);
|
|
if(!extract_sfo_from_pkg(src_dest, "/user/app/ITEM00001/tmp_param.sfo")){
|
|
log_error("Could not extract param.sfo");
|
|
return false;
|
|
}
|
|
//TODO make more effecient
|
|
std::vector<uint8_t> sfo_data = readFile("/user/app/ITEM00001/tmp_param.sfo");
|
|
if(sfo_data.empty()){
|
|
log_error("Could not read param.sfo");
|
|
return false;
|
|
}
|
|
|
|
SfoReader sfo(sfo_data);
|
|
|
|
details.name = sanitizeString(sfo.GetValueFor<std::string>("TITLE"));
|
|
details.version = sfo.GetValueFor<std::string>("VERSION");
|
|
details.esd.insert(std::pair<std::string, std::string>("IRO_TAG", sfo.GetValueFor<std::string>("IRO_TAG")));
|
|
|
|
for (int i = 0; i <= 30; i++) {
|
|
std::string key = fmt::format("TITLE_{0:}{1:d}", (i < 10) ? "0" : "", i);
|
|
details.esd.insert(std::pair<std::string, std::string>(key, sanitizeString(sfo.GetValueFor<std::string>(key))));
|
|
}
|
|
//log_info("[DLC] Content ID: %s", details.contentid.c_str());
|
|
//log_info("[DLC] Version: %s", details.version.c_str());
|
|
log_info("[DLC] Title: %s", details.name.c_str());
|
|
|
|
return true;
|
|
}
|
|
|
|
void rebuild_db(){
|
|
|
|
if (get->sort_cat == NO_CATEGORY_FILTER ||
|
|
(get->sort_cat != NO_CATEGORY_FILTER && Confirmation_Msg(getLangSTR(LANG_STR::CAT_REBUILD_WARNING)) == YES))
|
|
{
|
|
|
|
progstart((char *)getLangSTR(LANG_STR::REBUILDING_FOR_FPKG).c_str());
|
|
int failures = 0;
|
|
for (int i = 1; i <= all_apps[0].count.HDD_count; i++)
|
|
{
|
|
bool is_if = ((all_apps[i].info.id == "ITEM00001") || (all_apps[i].info.id == "ITEM99999"));
|
|
if (!all_apps[i].flags.is_fpkg || is_if)
|
|
{ // if its not an fpkg or Itemzflow, skip
|
|
fmt::print("Skipping {}: {}", is_if ? "IF" : "Retail Game", all_apps[i].info.name);
|
|
continue;
|
|
}
|
|
|
|
if (i > all_apps[0].count.HDD_count){
|
|
log_info("Skipping external HDD app: %s ???", all_apps[i].info.name.c_str());
|
|
continue;
|
|
}
|
|
|
|
int prog = (uint32_t)(((float)i / all_apps[0].count.HDD_count) * 100.f);
|
|
ProgSetMessagewText(prog, fmt::format("{0:}\n{1:}\n{2:}\n\n {3:} {4:d}\n{5:} {6:d}", getLangSTR(LANG_STR::REBUILDING_FOR_FPKG), all_apps[i].info.name, all_apps[i].info.id, getLangSTR(LANG_STR::CURRENT_APP), i, getLangSTR(LANG_STR::TOTAL_NUM_OF_APPS), all_apps[0].count.HDD_count).c_str());
|
|
log_info("App Info: %s | %i", all_apps[i].info.name.c_str(), i);
|
|
// function also replaces special chars for SQL smt
|
|
if (Fix_Game_In_DB(all_apps, i, all_apps[i].flags.is_ext_hdd))
|
|
log_info("Game Fixed: %s", all_apps[i].info.name.c_str());
|
|
else
|
|
{
|
|
log_error("Game NOT Fixed: %s", all_apps[i].info.name.c_str());
|
|
failures++;
|
|
}
|
|
}
|
|
sceMsgDialogTerminate();
|
|
loadmsg((char *)getLangSTR(LANG_STR::REBUILDING_ADDCONT).c_str());
|
|
addcont_dlc_rebuild("/system_data/priv/mms/addcont.db", false);
|
|
//addcont_dlc_rebuild("/system_data/priv/mms/addcont.db", true);
|
|
msgok(MSG_DIALOG::NORMAL, fmt::format("{0:}: {1:d}\n{2:}: {3:d}", getLangSTR(LANG_STR::NUMB_OF_FIXED_APPS), all_apps[0].count.HDD_count-failures, getLangSTR(LANG_STR::NOT_FIXED), failures));
|
|
}
|
|
}
|
|
|
|
void rebuild_dlc_db(){
|
|
loadmsg((char *)getLangSTR(LANG_STR::REBUILDING_ADDCONT).c_str());
|
|
addcont_dlc_rebuild("/system_data/priv/mms/addcont.db", true);
|
|
if(addcont_dlc_rebuild("/system_data/priv/mms/addcont.db", false))
|
|
ani_notify(NOTIFI::SUCCESS, getLangSTR(LANG_STR::ADDCONT_REBUILT), "");
|
|
else
|
|
ani_notify(NOTIFI::WARNING, getLangSTR(LANG_STR::ADDCONT_FAILED), "");
|
|
|
|
sceMsgDialogTerminate();
|
|
|
|
}
|
|
|
|
void print_Apps_Array(ThreadSafeVector<item_t> &b)
|
|
{
|
|
for (int i = 0; i <= b.at(0).count.token_c; i++)
|
|
{
|
|
fmt::print("b[{0:d}].token_d[0].off ptr: {1:}", i, b.at(i).info.id);
|
|
fmt::print("b[{0:d}].token_d[1].off ptr: {1:}", i, b.at(i).info.name);
|
|
}
|
|
}
|
|
void delete_apps_array(ThreadSafeVector<item_t> &apps_arr)
|
|
{
|
|
if(apps_arr.empty())
|
|
return;
|
|
|
|
for (int i = 1; i <= apps_arr.at(0).count.token_c; i++)
|
|
{
|
|
GLuint text = apps_arr.at(i).icon.texture.load();
|
|
if (text > GL_NULL){
|
|
glDeleteTextures(1, &text);
|
|
apps_arr.at(i).icon.texture = GL_NULL;
|
|
}
|
|
}
|
|
|
|
apps_arr.clear();
|
|
}
|
|
|
|
std::ifstream::pos_type file_size(const char* filename)
|
|
{
|
|
std::ifstream in(filename, std::ifstream::ate | std::ifstream::binary);
|
|
return in.tellg();
|
|
}
|
|
|
|
std::string NormalizeFWVersion(int version) {
|
|
std::string versionString = fmt::format("{:x}", version);
|
|
versionString.insert(1, ".");
|
|
std::string::size_type pos;
|
|
while ((pos = versionString.find("0000")) != std::string::npos) {
|
|
versionString.erase(pos, 4); // 4 is the length of "0000"
|
|
}
|
|
|
|
return versionString;
|
|
} |