diff --git a/Makefile b/Makefile index 28a323d..6434aec 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,8 @@ RESOURCES_PNG = resources/folder_icon.png resources/file_icon.png resources/arch resources/battery_bar_charge.png resources/headphone.png resources/audio_previous.png resources/audio_pause.png \ resources/audio_play.png resources/audio_next.png RESOURCES_TXT = resources/theme.txt resources/colors.txt resources/english_us.txt -OBJS += $(RESOURCES_PNG:.png=.o) $(RESOURCES_TXT:.txt=.o) +RESOURCES_BIN = resources/updater_eboot.bin resources/updater_param.bin +OBJS += $(RESOURCES_PNG:.png=.o) $(RESOURCES_TXT:.txt=.o) $(RESOURCES_BIN:.bin=.o) LIBS = -lftpvita -lvita2d -lpng -ljpeg -lz -lm -lc \ -lSceAppMgr_stub -lSceAppUtil_stub -lSceCommonDialog_stub \ @@ -59,6 +60,8 @@ $(TARGET).elf: $(OBJS) $(PREFIX)-ld -r -b binary -o $@ $^ %.o: %.txt $(PREFIX)-ld -r -b binary -o $@ $^ +%.o: %.bin + $(PREFIX)-ld -r -b binary -o $@ $^ clean: @rm -rf $(TARGET).vpk $(TARGET).velf $(TARGET).elf $(OBJS) \ diff --git a/VitaShellUpdater/main.c b/VitaShellUpdater/main.c deleted file mode 100644 index e69de29..0000000 diff --git a/file.c b/file.c index 6d55625..e5b3baa 100644 --- a/file.c +++ b/file.c @@ -356,14 +356,16 @@ typedef struct { static ExtensionType extension_types[] = { { ".BMP", FILE_TYPE_BMP }, + { ".INI", FILE_TYPE_INI }, { ".JPG", FILE_TYPE_JPEG }, { ".JPEG", FILE_TYPE_JPEG }, - { ".PNG", FILE_TYPE_PNG }, { ".MP3", FILE_TYPE_MP3 }, + { ".PNG", FILE_TYPE_PNG }, { ".SFO", FILE_TYPE_SFO }, - { ".VPK", FILE_TYPE_VPK }, - { ".ZIP", FILE_TYPE_ZIP }, { ".TXT", FILE_TYPE_TXT }, + { ".VPK", FILE_TYPE_VPK }, + { ".XML", FILE_TYPE_XML }, + { ".ZIP", FILE_TYPE_ZIP }, }; int getFileType(char *file) { diff --git a/file.h b/file.h index 8e64930..70b861b 100644 --- a/file.h +++ b/file.h @@ -32,13 +32,15 @@ enum FileTypes { FILE_TYPE_UNKNOWN, FILE_TYPE_BMP, + FILE_TYPE_INI, FILE_TYPE_JPEG, - FILE_TYPE_PNG, FILE_TYPE_MP3, + FILE_TYPE_PNG, FILE_TYPE_SFO, - FILE_TYPE_VPK, - FILE_TYPE_ZIP, FILE_TYPE_TXT, + FILE_TYPE_VPK, + FILE_TYPE_XML, + FILE_TYPE_ZIP, }; enum SortFlags { diff --git a/language.c b/language.c index 265d263..5242e3c 100644 --- a/language.c +++ b/language.c @@ -85,6 +85,7 @@ void loadLanguage(int id) { LANGUAGE_ENTRY(DELETING), LANGUAGE_ENTRY(INSTALLING), LANGUAGE_ENTRY(DOWNLOADING), + LANGUAGE_ENTRY(EXTRACTING), LANGUAGE_ENTRY(DELETE_FILE_QUESTION), LANGUAGE_ENTRY(DELETE_FOLDER_QUESTION), LANGUAGE_ENTRY(DELETE_FILES_FOLDERS_QUESTION), diff --git a/language.h b/language.h index f2c8df7..f4e3610 100644 --- a/language.h +++ b/language.h @@ -43,6 +43,7 @@ enum LanguageContainer { DELETING, INSTALLING, DOWNLOADING, + EXTRACTING, DELETE_FILE_QUESTION, DELETE_FOLDER_QUESTION, DELETE_FILES_FOLDERS_QUESTION, diff --git a/main.c b/main.c index 0ec9115..8d2d481 100644 --- a/main.c +++ b/main.c @@ -259,7 +259,9 @@ int handleFile(char *file, FileListEntry *entry) { } switch (type) { + case FILE_TYPE_INI: case FILE_TYPE_TXT: + case FILE_TYPE_XML: case FILE_TYPE_UNKNOWN: res = textViewer(file); break; @@ -758,7 +760,6 @@ int dialogSteps() { case DIALOG_STEP_COPIED: case DIALOG_STEP_DELETED: case DIALOG_STEP_INSTALLED: - case DIALOG_STEP_DOWNLOADED: if (msg_result == MESSAGE_DIALOG_RESULT_NONE || msg_result == MESSAGE_DIALOG_RESULT_FINISHED) { refresh = 1; dialog_step = DIALOG_STEP_NONE; @@ -835,47 +836,6 @@ int dialogSteps() { break; - case DIALOG_STEP_INSTALL_QUESTION: - if (msg_result == MESSAGE_DIALOG_RESULT_YES) { - initMessageDialog(MESSAGE_DIALOG_PROGRESS_BAR, language_container[INSTALLING]); - dialog_step = DIALOG_STEP_INSTALL_CONFIRMED; - } else if (msg_result == MESSAGE_DIALOG_RESULT_NO) { - dialog_step = DIALOG_STEP_NONE; - } - - break; - - case DIALOG_STEP_INSTALL_CONFIRMED: - if (msg_result == MESSAGE_DIALOG_RESULT_RUNNING) { - InstallArguments args; - args.file = cur_file; - - SceUID thid = sceKernelCreateThread("install_thread", (SceKernelThreadEntry)install_thread, 0x40, 0x10000, 0, 0, NULL); - if (thid >= 0) - sceKernelStartThread(thid, sizeof(InstallArguments), &args); - - dialog_step = DIALOG_STEP_INSTALLING; - } - - break; - - case DIALOG_STEP_INSTALL_WARNING: - if (msg_result == MESSAGE_DIALOG_RESULT_YES) { - dialog_step = DIALOG_STEP_INSTALL_WARNING_AGREED; - } else if (msg_result == MESSAGE_DIALOG_RESULT_NO) { - dialog_step = DIALOG_STEP_CANCELLED; - } - - break; - - case DIALOG_STEP_UPDATE_QUESTION: - if (msg_result == MESSAGE_DIALOG_RESULT_YES) { - initMessageDialog(MESSAGE_DIALOG_PROGRESS_BAR, language_container[DOWNLOADING]); - dialog_step = DIALOG_STEP_UPDATE_CONFIRMED; - } else if (msg_result == MESSAGE_DIALOG_RESULT_NO) { - dialog_step = DIALOG_STEP_NONE; - } - case DIALOG_STEP_RENAME: if (ime_result == IME_DIALOG_RESULT_FINISHED) { char *name = (char *)getImeDialogInputTextUTF8(); @@ -934,6 +894,65 @@ int dialogSteps() { } break; + + case DIALOG_STEP_INSTALL_QUESTION: + if (msg_result == MESSAGE_DIALOG_RESULT_YES) { + initMessageDialog(MESSAGE_DIALOG_PROGRESS_BAR, language_container[INSTALLING]); + dialog_step = DIALOG_STEP_INSTALL_CONFIRMED; + } else if (msg_result == MESSAGE_DIALOG_RESULT_NO) { + dialog_step = DIALOG_STEP_NONE; + } + + break; + + case DIALOG_STEP_INSTALL_CONFIRMED: + if (msg_result == MESSAGE_DIALOG_RESULT_RUNNING) { + InstallArguments args; + args.file = cur_file; + + SceUID thid = sceKernelCreateThread("install_thread", (SceKernelThreadEntry)install_thread, 0x40, 0x10000, 0, 0, NULL); + if (thid >= 0) + sceKernelStartThread(thid, sizeof(InstallArguments), &args); + + dialog_step = DIALOG_STEP_INSTALLING; + } + + break; + + case DIALOG_STEP_INSTALL_WARNING: + if (msg_result == MESSAGE_DIALOG_RESULT_YES) { + dialog_step = DIALOG_STEP_INSTALL_WARNING_AGREED; + } else if (msg_result == MESSAGE_DIALOG_RESULT_NO) { + dialog_step = DIALOG_STEP_CANCELLED; + } + + break; + + case DIALOG_STEP_UPDATE_QUESTION: + if (msg_result == MESSAGE_DIALOG_RESULT_YES) { + initMessageDialog(MESSAGE_DIALOG_PROGRESS_BAR, language_container[DOWNLOADING]); + dialog_step = DIALOG_STEP_DOWNLOADING; + } else if (msg_result == MESSAGE_DIALOG_RESULT_NO) { + dialog_step = DIALOG_STEP_NONE; + } + + case DIALOG_STEP_DOWNLOADED: + if (msg_result == MESSAGE_DIALOG_RESULT_FINISHED) { + initMessageDialog(MESSAGE_DIALOG_PROGRESS_BAR, language_container[INSTALLING]); + + SceUID thid = sceKernelCreateThread("update_extract_thread", (SceKernelThreadEntry)update_extract_thread, 0x40, 0x10000, 0, 0, NULL); + if (thid >= 0) + sceKernelStartThread(thid, 0, NULL); + + dialog_step = DIALOG_STEP_EXTRACTING; + } + + break; + + case DIALOG_STEP_EXTRACTED: + launchAppByUriExit("VSUPDATER"); + dialog_step = DIALOG_STEP_NONE; + break; } return refresh; @@ -1166,7 +1185,7 @@ int shellMain() { } else if (file_entry->type == FILE_TYPE_SFO) { // SFO // note: specific color to be determined vita2d_draw_texture(sfo_icon, SHELL_MARGIN_X, y + 3.0f); - } else if (file_entry->type == FILE_TYPE_TXT) { // TXT + } else if (file_entry->type == FILE_TYPE_INI || file_entry->type == FILE_TYPE_TXT || file_entry->type == FILE_TYPE_XML) { // TXT // note: specific color to be determined vita2d_draw_texture(text_icon, SHELL_MARGIN_X, y + 3.0f); } else { // Other files diff --git a/main.h b/main.h index 207ba40..77fa9dd 100644 --- a/main.h +++ b/main.h @@ -175,8 +175,10 @@ enum DialogSteps { DIALOG_STEP_RENAME, DIALOG_STEP_UPDATE_QUESTION, - DIALOG_STEP_UPDATE_CONFIRMED, + DIALOG_STEP_DOWNLOADING, DIALOG_STEP_DOWNLOADED, + DIALOG_STEP_EXTRACTING, + DIALOG_STEP_EXTRACTED, }; extern vita2d_pgf *font; diff --git a/network_update.c b/network_update.c index 1d3d715..28e4c00 100644 --- a/network_update.c +++ b/network_update.c @@ -19,11 +19,21 @@ #include "main.h" #include "io_process.h" #include "network_update.h" +#include "package_installer.h" +#include "archive.h" #include "file.h" #include "message_dialog.h" #include "language.h" #include "utils.h" +#define BASE_ADDRESS "https://github.com/TheOfficialFloW/VitaShell/releases/download" +#define VITASHELL_UPDATE_FILE "ux0:VitaShell/VitaShell.vpk" + +extern unsigned char _binary_resources_updater_eboot_bin_start; +extern unsigned char _binary_resources_updater_eboot_bin_size; +extern unsigned char _binary_resources_updater_param_bin_start; +extern unsigned char _binary_resources_updater_param_bin_size; + int getDownloadFileSize(char *src, uint64_t *size) { int tpl = sceHttpCreateTemplate("VitaShell/1.00 libhttp/1.1", SCE_HTTP_VERSION_1_1, 1); if (tpl < 0) @@ -117,7 +127,7 @@ int downloadProcess(char *version_string) { // Download url char url[128]; - sprintf(url, "https://github.com/TheOfficialFloW/VitaShell/releases/download/%s/VitaShell.vpk", version_string); + sprintf(url, BASE_ADDRESS "/%s/VitaShell.vpk", version_string); // File size uint64_t size = 0; @@ -128,7 +138,7 @@ int downloadProcess(char *version_string) { // Download uint64_t value = 0; - int res = downloadFile(url, "ux0:VitaShell/Vitashell.vpk", &value, size, SetProgress, cancelHandler); + int res = downloadFile(url, VITASHELL_UPDATE_FILE, &value, size, SetProgress, cancelHandler); if (res <= 0) { closeWaitDialog(); dialog_step = DIALOG_STEP_CANCELLED; @@ -158,7 +168,7 @@ EXIT: int network_update_thread(SceSize args, void *argp) { sceHttpsDisableOption(SCE_HTTPS_FLAG_SERVER_VERIFY); - if (downloadFile("http://github.com/TheOfficialFloW/VitaShell/releases/download/0.0/version.bin", "ux0:VitaShell/version.bin", NULL, 0, NULL, NULL) > 0) { + if (downloadFile(BASE_ADDRESS "/0.0/version.bin", "ux0:VitaShell/version.bin", NULL, 0, NULL, NULL) > 0) { uint32_t version = 0; ReadFile("ux0:VitaShell/version.bin", &version, sizeof(uint32_t)); sceIoRemove("ux0:VitaShell/version.bin"); @@ -195,5 +205,101 @@ int network_update_thread(SceSize args, void *argp) { } } + return sceKernelExitDeleteThread(0); +} + +int installUpdater() { + // Recursively clean up package_temp directory + removePath(PACKAGE_PARENT, NULL, 0, NULL, NULL); + sceIoMkdir(PACKAGE_PARENT, 0777); + + sceIoMkdir("ux0:ptmp", 0777); + sceIoMkdir("ux0:ptmp/pkg", 0777); + sceIoMkdir("ux0:ptmp/pkg/sce_sys", 0777); + + WriteFile("ux0:ptmp/pkg/eboot.bin", (void *)&_binary_resources_updater_eboot_bin_start, (int)&_binary_resources_updater_eboot_bin_size); + WriteFile("ux0:ptmp/pkg/sce_sys/param.sfo", (void *)&_binary_resources_updater_param_bin_start, (int)&_binary_resources_updater_param_bin_size); + + // Make head.bin + makeHeadBin(); + + // Promote + promote(PACKAGE_DIR); +} + +int update_extract_thread(SceSize args, void *argp) { + SceUID thid = -1; + + // Lock power timers + powerLock(); + + // Set progress to 0% + sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 0); + sceKernelDelayThread(DIALOG_WAIT); // Needed to see the percentage + + // Install updater + installUpdater(); + + // Recursively clean up package_temp directory + removePath(PACKAGE_PARENT, NULL, 0, NULL, NULL); + sceIoMkdir(PACKAGE_PARENT, 0777); + + // Open archive + int res = archiveOpen(VITASHELL_UPDATE_FILE); + if (res < 0) { + closeWaitDialog(); + errorDialog(res); + goto EXIT; + } + + // Src path + char *src_path = VITASHELL_UPDATE_FILE "/"; + + // Get archive path info + uint64_t size = 0; + uint32_t folders = 0, files = 0; + getArchivePathInfo(src_path, &size, &folders, &files); + + // Update thread + thid = createStartUpdateThread(size + folders); + + // Extract process + uint64_t value = 0; + + res = extractArchivePath(src_path, PACKAGE_DIR "/", &value, size + folders, SetProgress, cancelHandler); + if (res <= 0) { + closeWaitDialog(); + dialog_step = DIALOG_STEP_CANCELLED; + errorDialog(res); + goto EXIT; + } + + // Remove update file + sceIoRemove(VITASHELL_UPDATE_FILE); + + // Make head.bin + res = makeHeadBin(); + if (res < 0) { + closeWaitDialog(); + errorDialog(res); + goto EXIT; + } + + // Set progress to 100% + sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 100); + sceKernelDelayThread(COUNTUP_WAIT); + + // Close + sceMsgDialogClose(); + + dialog_step = DIALOG_STEP_EXTRACTED; + +EXIT: + if (thid >= 0) + sceKernelWaitThreadEnd(thid, NULL, NULL); + + // Unlock power timers + powerUnlock(); + return sceKernelExitDeleteThread(0); } \ No newline at end of file diff --git a/network_update.h b/network_update.h index 7611f27..fef701c 100644 --- a/network_update.h +++ b/network_update.h @@ -20,5 +20,6 @@ #define __NETWORK_UPDATE_H__ int network_update_thread(SceSize args, void *argp); +int update_extract_thread(SceSize args, void *argp); #endif \ No newline at end of file diff --git a/package_installer.c b/package_installer.c index 58623ce..3afe032 100644 --- a/package_installer.c +++ b/package_installer.c @@ -31,12 +31,6 @@ #include "resources/base_head_bin.h" -#define ntohl __builtin_bswap32 - -#define PACKAGE_PARENT "ux0:ptmp" -#define PACKAGE_DIR PACKAGE_PARENT "/pkg" -#define HEAD_BIN PACKAGE_DIR "/sce_sys/package/head.bin" - void loadScePaf() { uint32_t ptr[0x100] = { 0 }; ptr[0] = 0; @@ -68,7 +62,7 @@ int promote(char *path) { if (res < 0) return res; - sceKernelDelayThread(300 * 1000); + sceKernelDelayThread(100 * 1000); } while (state); int result = 0; diff --git a/package_installer.h b/package_installer.h index fe6a6a5..b45c296 100644 --- a/package_installer.h +++ b/package_installer.h @@ -19,10 +19,19 @@ #ifndef __PACKAGE_INSTALLER_H__ #define __PACKAGE_INSTALLER_H__ +#define ntohl __builtin_bswap32 + +#define PACKAGE_PARENT "ux0:ptmp" +#define PACKAGE_DIR PACKAGE_PARENT "/pkg" +#define HEAD_BIN PACKAGE_DIR "/sce_sys/package/head.bin" + typedef struct { char *file; } InstallArguments; +int promote(char *path); +int makeHeadBin(); + int install_thread(SceSize args_size, InstallArguments *args); #endif \ No newline at end of file diff --git a/resources/english_us.txt b/resources/english_us.txt index 6e9fe21..3a0d2db 100644 --- a/resources/english_us.txt +++ b/resources/english_us.txt @@ -23,6 +23,7 @@ COPYING = "Copying..." DELETING = "Deleting..." INSTALLING = "Installing..." DOWNLOADING = "Downloading..." +EXTRACTING = "Extracting..." DELETE_FILE_QUESTION = "Are you sure you want to delete this file?" DELETE_FOLDER_QUESTION = "Are you sure you want to delete this folder?" DELETE_FILES_FOLDERS_QUESTION = "Are you sure you want to delete these files/folders?" diff --git a/resources/updater_eboot.bin b/resources/updater_eboot.bin new file mode 100644 index 0000000..568cda7 Binary files /dev/null and b/resources/updater_eboot.bin differ diff --git a/resources/updater_param.bin b/resources/updater_param.bin new file mode 100644 index 0000000..4dc8bc8 Binary files /dev/null and b/resources/updater_param.bin differ diff --git a/VitaShellUpdater/Makefile b/updater/Makefile similarity index 62% rename from VitaShellUpdater/Makefile rename to updater/Makefile index de47c87..f9c7982 100644 --- a/VitaShellUpdater/Makefile +++ b/updater/Makefile @@ -1,24 +1,25 @@ TITLE_ID = VSUPDATER -TARGET = VitaShellUpdater +TARGET = updater OBJS = main.o -LIBS = -PREFIX = arm-vita-eabi -CC = $(PREFIX)-gcc -CFLAGS = -Wl,-q -Wall -O3 -marm -ASFLAGS = $(CFLAGS) +LIBS = -lSceAppMgr_stub ../libpromoter/libScePromoterUtil_stub.a -lSceSysmodule_stub + +PREFIX = arm-vita-eabi +CC = $(PREFIX)-gcc +CFLAGS = -Wl,-q -Wall -O3 -marm +ASFLAGS = $(CFLAGS) all: $(TARGET).vpk %.vpk: eboot.bin - vita-mksfoex -s TITLE_ID=$(TITLE_ID) "$(TARGET)" param.sfo + vita-mksfoex -s TITLE_ID=$(TITLE_ID) "VitaShell Updater" param.sfo vita-pack-vpk -s param.sfo -b eboot.bin $@ eboot.bin: $(TARGET).velf vita-make-fself $< $@ %.velf: %.elf - vita-elf-create $< $@ + vita-elf-create $< $@ ../libpromoter/promoterutil.json $(TARGET).elf: $(OBJS) $(CC) $(CFLAGS) $^ $(LIBS) -o $@ diff --git a/updater/main.c b/updater/main.c new file mode 100644 index 0000000..4c4013a --- /dev/null +++ b/updater/main.c @@ -0,0 +1,199 @@ +/* + VitaShell + Copyright (C) 2015-2016, TheFloW + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include +#include + +#include +#include +#include + +#include "../sysmodule_internal.h" +#include "../libpromoter/promoterutil.h" + +#define TRANSFER_SIZE 64 * 1024 + +#define PACKAGE_PARENT "ux0:ptmp" +#define PACKAGE_DIR PACKAGE_PARENT "/pkg" +#define HEAD_BIN PACKAGE_DIR "/sce_sys/package/head.bin" + +typedef struct SfoHeader { + uint32_t magic; + uint32_t version; + uint32_t keyofs; + uint32_t valofs; + uint32_t count; +} __attribute__((packed)) SfoHeader; + +typedef struct SfoEntry { + uint16_t nameofs; + uint8_t alignment; + uint8_t type; + uint32_t valsize; + uint32_t totalsize; + uint32_t dataofs; +} __attribute__((packed)) SfoEntry; + +int launchAppByUriExit(char *titleid) { + char uri[32]; + sprintf(uri, "psgm:play?titleid=%s", titleid); + + sceKernelDelayThread(10000); + sceAppMgrLaunchAppByUri(0xFFFFF, uri); + sceKernelDelayThread(10000); + sceAppMgrLaunchAppByUri(0xFFFFF, uri); + + sceKernelExitProcess(0); + + return 0; +} + +int copyFile(char *src_path, char *dst_path) { + SceUID fdsrc = sceIoOpen(src_path, SCE_O_RDONLY, 0); + if (fdsrc < 0) + return fdsrc; + + SceUID fddst = sceIoOpen(dst_path, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777); + if (fddst < 0) { + sceIoClose(fdsrc); + return fddst; + } + + void *buf = malloc(TRANSFER_SIZE); + + int read; + while ((read = sceIoRead(fdsrc, buf, TRANSFER_SIZE)) > 0) { + sceIoWrite(fddst, buf, read); + } + + free(buf); + + sceIoClose(fddst); + sceIoClose(fdsrc); + + return 0; +} + +void loadScePaf() { + uint32_t ptr[0x100] = { 0 }; + ptr[0] = 0; + ptr[1] = (uint32_t)&ptr[0]; + uint32_t scepaf_argp[] = { 0x400000, 0xEA60, 0x40000, 0, 0 }; + sceSysmoduleLoadModuleInternalWithArg(0x80000008, sizeof(scepaf_argp), scepaf_argp, ptr); +} + +int promote(char *path) { + int res; + + loadScePaf(); + + res = sceSysmoduleLoadModuleInternal(SCE_SYSMODULE_PROMOTER_UTIL); + if (res < 0) + return res; + + res = scePromoterUtilityInit(); + if (res < 0) + return res; + + res = scePromoterUtilityPromotePkg(path, 0); + if (res < 0) + return res; + + int state = 0; + do { + res = scePromoterUtilityGetState(&state); + if (res < 0) + return res; + + sceKernelDelayThread(100 * 1000); + } while (state); + + int result = 0; + res = scePromoterUtilityGetResult(&result); + if (res < 0) + return res; + + res = scePromoterUtilityExit(); + if (res < 0) + return res; + + res = sceSysmoduleUnloadModuleInternal(SCE_SYSMODULE_PROMOTER_UTIL); + if (res < 0) + return res; + + return result; +} + +char *get_title_id(const char *filename) { + char *res = NULL; + long size = 0; + FILE *fin = NULL; + char *buf = NULL; + int i; + + SfoHeader *header; + SfoEntry *entry; + + fin = fopen(filename, "rb"); + if (!fin) + goto cleanup; + if (fseek(fin, 0, SEEK_END) != 0) + goto cleanup; + if ((size = ftell(fin)) == -1) + goto cleanup; + if (fseek(fin, 0, SEEK_SET) != 0) + goto cleanup; + buf = calloc(1, size + 1); + if (!buf) + goto cleanup; + if (fread(buf, size, 1, fin) != 1) + goto cleanup; + + header = (SfoHeader*)buf; + entry = (SfoEntry*)(buf + sizeof(SfoHeader)); + for (i = 0; i < header->count; ++i, ++entry) { + const char *name = buf + header->keyofs + entry->nameofs; + const char *value = buf + header->valofs + entry->dataofs; + if (name >= buf + size || value >= buf + size) + break; + if (strcmp(name, "TITLE_ID") == 0) + res = strdup(value); + } + +cleanup: + if (buf) + free(buf); + if (fin) + fclose(fin); + + return res; +} + +int main(int argc, const char *argv[]) { + char *titleid = get_title_id(PACKAGE_DIR "/sce_sys/param.sfo"); + if (strcmp(titleid, "VITASHELL") == 0) { + copyFile(PACKAGE_DIR "/eboot.bin", "ux0:app/MLCL00001/eboot.bin"); + + if (promote(PACKAGE_DIR) >= 0) + launchAppByUriExit("VITASHELL"); + } + + return sceKernelExitProcess(0); +} \ No newline at end of file diff --git a/utils.c b/utils.c index f4a7c75..6a76714 100644 --- a/utils.c +++ b/utils.c @@ -299,5 +299,19 @@ int debugPrintf(char *text, ...) { #endif #endif + return 0; +} + +int launchAppByUriExit(char *titleid) { + char uri[32]; + sprintf(uri, "psgm:play?titleid=%s", titleid); + + sceKernelDelayThread(10000); + sceAppMgrLaunchAppByUri(0xFFFFF, uri); + sceKernelDelayThread(10000); + sceAppMgrLaunchAppByUri(0xFFFFF, uri); + + sceKernelExitProcess(0); + return 0; } \ No newline at end of file diff --git a/utils.h b/utils.h index dc6fc54..f96fb11 100644 --- a/utils.h +++ b/utils.h @@ -71,4 +71,6 @@ int randomNumber(int low, int high); int debugPrintf(char *text, ...); +int launchAppByUriExit(char *titleid); + #endif