From 0368b44d2fb96247e8abbc75488d7ac6e0da695a Mon Sep 17 00:00:00 2001 From: bucanero <dparrino@gmail.com> Date: Sun, 17 Mar 2024 20:08:55 -0300 Subject: [PATCH] Add ps2 VME support show ps1 / ps2 save icons --- include/mcio.h | 4 +- include/ps2icon.h | 75 +++++++++++ include/saves.h | 7 +- source/draw.c | 5 +- source/exec_cmd.c | 69 ++++------ source/main.c | 2 +- source/mcio.c | 156 +++++++++++++++++----- source/menu_cheats.c | 2 +- source/menu_main.c | 36 +++-- source/ps1card.c | 2 +- source/ps2classic.c | 21 --- source/ps2icon.c | 139 ++++++++++++++++++++ source/saves.c | 307 +++++++++++++++++++------------------------ 13 files changed, 533 insertions(+), 292 deletions(-) create mode 100644 include/ps2icon.h create mode 100644 source/ps2icon.c diff --git a/include/mcio.h b/include/mcio.h index 00edfd6..52b041f 100644 --- a/include/mcio.h +++ b/include/mcio.h @@ -63,6 +63,8 @@ struct io_dirent { } __attribute__((packed)); int mcio_vmcInit(const char* vmc); +int mcio_vmcExportImage(const char *dst, int ecc); +int mcio_vmcImportImage(const char *src); void mcio_vmcFinish(void); int mcio_mcDetect(void); int mcio_mcGetInfo(int *pagesize, int *blocksize, int *cardsize, int *cardflags); @@ -77,7 +79,7 @@ int mcio_mcDopen(const char *dirname); int mcio_mcDclose(int fd); int mcio_mcDread(int fd, struct io_dirent *dirent); int mcio_mcMkDir(const char *dirname); -int mcio_mcReadPage(int pagenum, void *buf); +int mcio_mcReadPage(int pagenum, void *buf, void *ecc); int mcio_mcUnformat(void); int mcio_mcFormat(void); int mcio_mcRemove(const char *filename); diff --git a/include/ps2icon.h b/include/ps2icon.h new file mode 100644 index 0000000..167ba27 --- /dev/null +++ b/include/ps2icon.h @@ -0,0 +1,75 @@ +/* +* +* Copyright (c) 2008 Andreas Weis (http://www.ghulbus-inc.de/) +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +//================================================================================================ +// Typedefs and Defines +//================================================================================================ + +/** File header + */ +typedef struct Icon_Header_t { + unsigned int file_id; ///< reserved; should be: 0x010000 (but does not have to ;) ) + unsigned int animation_shapes; ///< number of animation shapes per vertex + unsigned int texture_type; ///< texture type - 0x07: uncompressed, 0x06: uncompresses, 0x0f: RLE compression + unsigned int reserved; ///< reserved; should be: 0x3F800000 (but does not have to ;) ) + unsigned int n_vertices; ///< number of vertices; must be a multiple of 3 +} Icon_Header; +/** Set of vertex coordinates + * @note The f16_* fields indicate float16 data; divide by 4096.0f to convert to float32; + */ +typedef struct Vertex_Coord_t { + short f16_x; ///< vertex x coordinate in float16 + short f16_y; ///< vertex y coordinate in float16 + short f16_z; ///< vertex z coordinate in float16 + short f16_unknown; ///< unknown; seems to influence lightning? +} Vertex_Coord; +/** Set of texture coordinates + * @note The f16_* fields indicate float16 data; divide by 4096.0f to convert to float32; + */ +typedef struct Texture_Data_t { + short f16_u; ///< vertex u texture coordinate in float16 + short f16_v; ///< vertex v texture coordinate in float16 + unsigned int color; ///< vertex color (32 bit RGBA) +} Texture_Data; +/** Animation header + */ +typedef struct Animation_Header_t { + unsigned int id_tag; ///< ??? + unsigned int frame_length; ///< ??? + float anim_speed; ///< ??? + unsigned int play_offset; ///< ??? + unsigned int n_frames; ///< number of frames in the animation +} Animation_Header; +/** Per-frame animation data + */ +typedef struct Frame_Data_t { + unsigned int shape_id; ///< shape used for this frame + unsigned int n_keys; ///< number of keys corresponding to this frame +} Frame_Data; +/** Per-key animation data + */ +typedef struct Frame_Key_t { + float time; ///< ??? + float value; ///< ??? +} Frame_Key; diff --git a/include/saves.h b/include/saves.h index 448fae4..9fd1e95 100644 --- a/include/saves.h +++ b/include/saves.h @@ -91,8 +91,6 @@ enum cmd_code_enum CMD_VIEW_DETAILS, CMD_VIEW_RAW_PATCH, CMD_RESIGN_PSV, - CMD_DECRYPT_PS2_VME, - CMD_ENCRYPT_PS2_VMC, CMD_CONVERT_TO_PSV, CMD_COPY_DUMMY_PSV, CMD_IMPORT_DATA_FILE, @@ -117,6 +115,7 @@ enum cmd_code_enum CMD_EXP_LICS_RAPS, CMD_EXP_FLASH2_USB, CMD_EXP_PS2_BINENC, + CMD_EXP_PS2_VM2, CMD_EXP_PSV_MCS, CMD_EXP_PSV_PSU, CMD_EXP_VM2_RAW, @@ -126,6 +125,7 @@ enum cmd_code_enum // Import commands CMD_IMP_EXDATA_USB, + CMD_IMP_PS2_VM2, CMD_IMP_PS2_ISO, CMD_IMP_PS2_CONFIG, CMD_IMP_PS2VMC_USB, @@ -262,6 +262,7 @@ typedef struct } save_list_t; list_t * ReadUserList(const char* userPath); +list_t * ReadUsbList(const char* userPath); list_t * ReadOnlineList(const char* urlPath); list_t * ReadBackupList(const char* userPath); list_t * ReadTrophyList(const char* userPath); @@ -318,7 +319,6 @@ void ps2_encrypt_image(uint8_t cfg_file, const char* image_name, const char* dat void ps2_decrypt_image(uint8_t dex_mode, const char* image_name, const char* data_file); void ps2_crypt_vmc(uint8_t dex_mode, const char* vmc_path, const char* vmc_out, int crypt_mode); int ps2_add_vmc_ecc(const char* src, const char* dst); -int ps2_remove_vmc_ecc(const char* src, const char* dst); int psv_resign(const char *src_psv); int vmp_resign(const char *src_vmp); @@ -337,3 +337,4 @@ int vmc_import_psv(const char *input); int vmc_import_psu(const char *input); char* sjis2utf8(char* input); +uint8_t* getIconPS2(const char* folder, const char* iconfile); diff --git a/source/draw.c b/source/draw.c index f30a53c..fb101e8 100644 --- a/source/draw.c +++ b/source/draw.c @@ -121,8 +121,9 @@ static void _drawListBackground(int off, int icon) if (menu_textures[icon_png_file_index].size) { - DrawTexture(&menu_textures[help_png_index], 624, help_png_y + 4, 0, 168, 98, 0xFFFFFF00 | 0xFF); - DrawTexture(&menu_textures[icon_png_file_index], 628, help_png_y + 8, 0, 160, 88, 0xFFFFFF00 | 0xFF); + int adj = (menu_textures[icon_png_file_index].texture.width == 16) ? 6 : 1; // resize PS1 icons + DrawTexture(&menu_textures[help_png_index], 624, help_png_y + 4, 0, (menu_textures[icon_png_file_index].texture.width / 2 * adj) + 8, (menu_textures[icon_png_file_index].texture.height / 2 * adj) + 10, 0xFFFFFF00 | 0xFF); + DrawTexture(&menu_textures[icon_png_file_index], 628, help_png_y + 8, 0, menu_textures[icon_png_file_index].texture.width / 2 * adj, menu_textures[icon_png_file_index].texture.height / 2 * adj, 0xFFFFFF00 | 0xFF); } break; diff --git a/source/exec_cmd.c b/source/exec_cmd.c index 54a8256..c4fbce7 100644 --- a/source/exec_cmd.c +++ b/source/exec_cmd.c @@ -12,6 +12,7 @@ #include "pfd.h" #include "sfo.h" #include "ps1card.h" +#include "mcio.h" static char host_buf[256]; @@ -875,45 +876,21 @@ static void convertSavePSV(const save_entry_t* save, int dst) show_message("File successfully saved to:\n%s", out_path); } -static void decryptVMEfile(const char* vme_path, const char* vme_file, uint8_t dst) +static void importVM2file(const char* vme_file, const char* src_name) { - char vmefile[256]; - char outfile[256]; - char path[256]; - - _set_dest_path(path, dst, VMC_PS2_PATH_USB); - if (dst == STORAGE_HDD) - snprintf(path, sizeof(path), VMC_PS2_PATH_HDD); - - if (mkdirs(path) != SUCCESS) - { - show_message("Error! Export folder is not available:\n%s", path); - return; - } - - snprintf(vmefile, sizeof(vmefile), "%s%s", vme_path, vme_file); - snprintf(outfile, sizeof(outfile), "%sAPOLLO%c.VM2", path, vme_file[6]); - - init_loading_screen("Decrypting VME card..."); - ps2_crypt_vmc(0, vmefile, outfile, 0); - stop_loading_screen(); - - show_message("File successfully saved to:\n%s", outfile); -} - -static void encryptVM2file(const char* vme_path, const char* vme_file, const char* src_name) -{ - char vmefile[256]; + int ret; char srcfile[256]; - snprintf(vmefile, sizeof(vmefile), "%s%s", vme_path, vme_file); snprintf(srcfile, sizeof(srcfile), "%s%s", VMC_PS2_PATH_HDD, src_name); - init_loading_screen("Encrypting VM2 card..."); - ps2_crypt_vmc(0, srcfile, vmefile, 1); + init_loading_screen("Importing VM2 card..."); + ret = mcio_vmcImportImage(srcfile); stop_loading_screen(); - show_message("File successfully saved to:\n%s", vmefile); + if (ret == sceMcResSucceed) + show_message("File successfully imported to:\n%s", vme_file); + else + show_message("Error! Failed to import PS2 memory card"); } static void importPS2VMC(const char* vmc_path, const char* vmc_file) @@ -932,9 +909,9 @@ static void importPS2VMC(const char* vmc_path, const char* vmc_file) show_message("File successfully saved to:\n%s", vm2file); } -static void exportVM2raw(const char* vm2_path, const char* vm2_file, int dst) +static void exportVM2raw(const char* vm2_file, int dst, int ecc) { - char vm2file[256]; + int ret; char dstfile[256]; char dst_path[256]; @@ -945,15 +922,17 @@ static void exportVM2raw(const char* vm2_path, const char* vm2_file, int dst) return; } - snprintf(vm2file, sizeof(vm2file), "%s%s", vm2_path, vm2_file); - snprintf(dstfile, sizeof(dstfile), "%s%s.vmc", dst_path, vm2_file); + snprintf(dstfile, sizeof(dstfile), "%s%s.%s", dst_path, vm2_file, ecc ? "VM2" : "vmc"); - init_loading_screen("Exporting PS2 .VM2 memory card..."); - ps2_remove_vmc_ecc(vm2file, dstfile); + init_loading_screen("Exporting PS2 memory card..."); + ret = mcio_vmcExportImage(dstfile, ecc); file_chmod(dstfile); stop_loading_screen(); - show_message("File successfully saved to:\n%s", dstfile); + if (ret == sceMcResSucceed) + show_message("File successfully saved to:\n%s", dstfile); + else + show_message("Error! Failed to export PS2 memory card"); } static void importPS2classicsCfg(const char* cfg_path, const char* cfg_file) @@ -1762,13 +1741,8 @@ void execCodeCommand(code_entry_t* code, const char* codecmd) code->activated = 0; break; - case CMD_DECRYPT_PS2_VME: - decryptVMEfile(selected_entry->path, code->file, codecmd[1]); - code->activated = 0; - break; - - case CMD_ENCRYPT_PS2_VMC: - encryptVM2file(selected_entry->path, code->file, code->options[0].name[code->options[0].sel]); + case CMD_IMP_PS2_VM2: + importVM2file(selected_entry->path, code->options[0].name[code->options[0].sel]); code->activated = 0; break; @@ -1807,8 +1781,9 @@ void execCodeCommand(code_entry_t* code, const char* codecmd) code->activated = 0; break; + case CMD_EXP_PS2_VM2: case CMD_EXP_VM2_RAW: - exportVM2raw(selected_entry->path, code->file, codecmd[1]); + exportVM2raw(code->file, codecmd[1], codecmd[0] == CMD_EXP_PS2_VM2); code->activated = 0; break; diff --git a/source/main.c b/source/main.c index 05aeff2..25d06a7 100644 --- a/source/main.c +++ b/source/main.c @@ -121,7 +121,7 @@ save_list_t usb_saves = { .title = "USB Saves", .list = NULL, .path = "", - .ReadList = &ReadUserList, + .ReadList = &ReadUsbList, .ReadCodes = &ReadCodes, .UpdatePath = &update_usb_path, }; diff --git a/source/mcio.c b/source/mcio.c index 7da3677..10f5fbf 100644 --- a/source/mcio.c +++ b/source/mcio.c @@ -23,6 +23,7 @@ #include "mcio.h" #include "util.h" #include "ps2mc.h" +#include "common.h" #include <stdio.h> #include <time.h> @@ -46,6 +47,7 @@ static const char SUPERBLOCK_MAGIC[] = "Sony PS2 Memory Card Format "; static const char SUPERBLOCK_VERSION[] = "1.2.0.0\0\0\0\0"; static FILE *vmc_fp = NULL; +static char vmcpath[256]; struct MCDevInfo { /* size = 384 */ uint8_t magic[28]; /* Superblock magic, on PS2 MC : "Sony PS2 Memory Card Format " */ @@ -126,40 +128,7 @@ static uint8_t mcio_eccdata[512]; /* size for 32 ecc */ static int32_t mcio_badblock = 0; static int32_t mcio_replacementcluster[16]; -static const uint8_t mcio_xortable[256] = { - 0x00, 0x87, 0x96, 0x11, 0xA5, 0x22, 0x33, 0xB4, - 0xB4, 0x33, 0x22, 0xA5, 0x11, 0x96, 0x87, 0x00, - 0xC3, 0x44, 0x55, 0xD2, 0x66, 0xE1, 0xF0, 0x77, - 0x77, 0xF0, 0xE1, 0x66, 0xD2, 0x55, 0x44, 0xC3, - 0xD2, 0x55, 0x44, 0xC3, 0x77, 0xF0, 0xE1, 0x66, - 0x66, 0xE1, 0xF0, 0x77, 0xC3, 0x44, 0x55, 0xD2, - 0x11, 0x96, 0x87, 0x00, 0xB4, 0x33, 0x22, 0xA5, - 0xA5, 0x22, 0x33, 0xB4, 0x00, 0x87, 0x96, 0x11, - 0xE1, 0x66, 0x77, 0xF0, 0x44, 0xC3, 0xD2, 0x55, - 0x55, 0xD2, 0xC3, 0x44, 0xF0, 0x77, 0x66, 0xE1, - 0x22, 0xA5, 0xB4, 0x33, 0x87, 0x00, 0x11, 0x96, - 0x96, 0x11, 0x00, 0x87, 0x33, 0xB4, 0xA5, 0x22, - 0x33, 0xB4, 0xA5, 0x22, 0x96, 0x11, 0x00, 0x87, - 0x87, 0x00, 0x11, 0x96, 0x22, 0xA5, 0xB4, 0x33, - 0xF0, 0x77, 0x66, 0xE1, 0x55, 0xD2, 0xC3, 0x44, - 0x44, 0xC3, 0xD2, 0x55, 0xE1, 0x66, 0x77, 0xF0, - 0xF0, 0x77, 0x66, 0xE1, 0x55, 0xD2, 0xC3, 0x44, - 0x44, 0xC3, 0xD2, 0x55, 0xE1, 0x66, 0x77, 0xF0, - 0x33, 0xB4, 0xA5, 0x22, 0x96, 0x11, 0x00, 0x87, - 0x87, 0x00, 0x11, 0x96, 0x22, 0xA5, 0xB4, 0x33, - 0x22, 0xA5, 0xB4, 0x33, 0x87, 0x00, 0x11, 0x96, - 0x96, 0x11, 0x00, 0x87, 0x33, 0xB4, 0xA5, 0x22, - 0xE1, 0x66, 0x77, 0xF0, 0x44, 0xC3, 0xD2, 0x55, - 0x55, 0xD2, 0xC3, 0x44, 0xF0, 0x77, 0x66, 0xE1, - 0x11, 0x96, 0x87, 0x00, 0xB4, 0x33, 0x22, 0xA5, - 0xA5, 0x22, 0x33, 0xB4, 0x00, 0x87, 0x96, 0x11, - 0xD2, 0x55, 0x44, 0xC3, 0x77, 0xF0, 0xE1, 0x66, - 0x66, 0xE1, 0xF0, 0x77, 0xC3, 0x44, 0x55, 0xD2, - 0xC3, 0x44, 0x55, 0xD2, 0x66, 0xE1, 0xF0, 0x77, - 0x77, 0xF0, 0xE1, 0x66, 0xD2, 0x55, 0x44, 0xC3, - 0x00, 0x87, 0x96, 0x11, 0xA5, 0x22, 0x33, 0xB4, - 0xB4, 0x33, 0x22, 0xA5, 0x11, 0x96, 0x87, 0x00 -}; +extern const uint8_t ECC_Table[]; struct MCFHandle { /* size = 48 */ @@ -185,6 +154,7 @@ struct MCFHandle { /* size = 48 */ struct MCFHandle mcio_fdhandles[MAX_FDHANDLES]; static int Card_FileClose(int fd); +void ps2_crypt_vmc(uint8_t dex_mode, const char* vmc_path, const char* vmc_out, int crypt_mode); static void long_multiply(uint32_t v1, uint32_t v2, uint32_t *HI, uint32_t *LO) @@ -211,6 +181,7 @@ static void Card_DataChecksum(uint8_t *pagebuf, uint8_t *ecc) { uint8_t *p, *p_ecc; int32_t i, a2, a3, v, t0; + const uint8_t *mcio_xortable = ECC_Table; p = pagebuf; a2 = 0; @@ -3009,10 +2980,19 @@ static int Card_FileWrite(int fd, void *buffer, int nbyte) int mcio_vmcInit(const char* vmc) { int r; + vmcpath[0] = 0; if (vmc_fp) fclose(vmc_fp); + // decrypt ps2classic format + if (strcmp(".VME", strrchr(vmc, '.')) == 0) + { + snprintf(vmcpath, sizeof(vmcpath), "%s%s", vmc, ".out"); + ps2_crypt_vmc(0, vmc, vmcpath, 0); + vmc = vmcpath; + } + vmc_fp = fopen(vmc, "r+b"); if (!vmc_fp) return sceMcResFailIO; @@ -3031,6 +3011,17 @@ void mcio_vmcFinish(void) if (vmc_fp) fclose(vmc_fp); + // encrypt ps2classic format + if (vmcpath[0]) + { + char vme[256]; + + strncpy(vme, vmcpath, sizeof(vme)); + *strrchr(vme, '.') = 0; + ps2_crypt_vmc(0, vmcpath, vme, 1); + unlink_secure(vmcpath); + } + vmc_fp = NULL; } @@ -3498,9 +3489,24 @@ int mcio_mcGetAvailableSpace(int *cardfree) return 0; } -int mcio_mcReadPage(int pagenum, void *buf) +int mcio_mcReadPage(int pagenum, void *buf, void *ecc) { - return Card_ReadPage((int32_t)pagenum, (uint8_t *)buf); + int r; + + r = Card_ReadPage((int32_t)pagenum, (uint8_t *)buf); + + if (ecc) + { + struct MCDevInfo *mcdi = (struct MCDevInfo *)&mcio_devinfo; + uint16_t pagesize = read_le_uint16((uint8_t *)&mcdi->pagesize); + uint8_t* p_ecc = ecc; + + memset(ecc, 0, pagesize >> 5); + for (int i = 0; i < pagesize; i += 128, p_ecc += 3) + Card_DataChecksum(buf + i, p_ecc); + } + + return r; } int mcio_mcUnformat(void) @@ -3566,3 +3572,81 @@ int mcio_mcRmDir(const char *dirname) return r; } + +int mcio_vmcExportImage(const char *output, int add_ecc) +{ + int r; + int pagesize, blocksize, cardsize, cardflags; + + r = mcio_mcGetInfo(&pagesize, &blocksize, &cardsize, &cardflags); + if (r < 0) + return -1; + + FILE *fh = fopen(output, "wb"); + if (fh == NULL) + return -2; + + void *ecc = malloc(pagesize >> 5); + void *buf = malloc(pagesize); + if (buf == NULL || ecc == NULL) { + fclose(fh); + return -3; + } + + for (int i = 0; i < (cardsize / pagesize); i++) { + mcio_mcReadPage(i, buf, ecc); + r = fwrite(buf, 1, pagesize, fh); + if (r != pagesize) { + free(buf); + fclose(fh); + return -4; + } + + if (!add_ecc) + continue; + + r = fwrite(ecc, 1, pagesize >> 5, fh); + if (r != pagesize >> 5) { + free(buf); + fclose(fh); + return -4; + } + } + + fclose(fh); + free(buf); + free(ecc); + + return sceMcResSucceed; +} + +int mcio_vmcImportImage(const char *input) +{ + off_t size; + size_t r, w; + char tmpbuf[0x8000]; + + if (!vmc_fp) + return -1; + + FILE *fh = fopen(input, "rb"); + if (fh == NULL) + return -2; + + fseek(fh, 0, SEEK_END); + size = ftell(fh); + + fseek(fh, 0, SEEK_SET); + fseek(vmc_fp, 0, SEEK_SET); + + do { + r = fread(tmpbuf, 1, sizeof(tmpbuf), fh); + w = fwrite(tmpbuf, 1, r, vmc_fp); + } + while ((r == w) && (r == sizeof(tmpbuf))); + + ftruncate(fileno(vmc_fp), size); + fclose(fh); + + return sceMcResSucceed; +} diff --git a/source/menu_cheats.c b/source/menu_cheats.c index e8f849b..e521e61 100644 --- a/source/menu_cheats.c +++ b/source/menu_cheats.c @@ -378,7 +378,7 @@ void DrawGameList(int selIndex, list_t * games, u8 alpha) tmp[1] = (item->flags & SAVE_FLAG_OWNER) ? CHAR_TAG_OWNER : ' '; tmp[2] = (item->flags & SAVE_FLAG_LOCKED) ? CHAR_TAG_LOCKED : ' '; if (item->flags & SAVE_FLAG_PSV) tmp[1] = CHAR_TAG_PSV; - if (item->type == FILE_TYPE_VMC) tmp[2] = CHAR_TAG_VMC; + if (item->type == FILE_TYPE_VMC) tmp[1] = CHAR_TAG_VMC; DrawString(800 - (MENU_ICON_OFF * 1), game_y, tmp); node = list_next(node); diff --git a/source/menu_main.c b/source/menu_main.c index 3e3f9a9..e67d76f 100644 --- a/source/menu_main.c +++ b/source/menu_main.c @@ -60,16 +60,25 @@ void initMenuOptions(void) *menu_options[OWNER_SETTING].value = menu_options_maxsel[OWNER_SETTING] - 1; } -static void LoadFileTexture(const char* fname, int idx) +static void LoadFileTexture(const char* fname) { - if (!menu_textures[idx].buffer) - menu_textures[idx].buffer = free_mem; + pngLoadFromFile(fname, &menu_textures[icon_png_file_index].texture); + copyTexture(icon_png_file_index); - pngLoadFromFile(fname, &menu_textures[idx].texture); - copyTexture(idx); + menu_textures[icon_png_file_index].size = 1; + free_mem = (u32*) menu_textures[icon_png_file_index].buffer; +} - menu_textures[idx].size = 1; - free_mem = (u32*) menu_textures[idx].buffer; +static void LoadVmcTexture(int width, int height, uint8_t* icon) +{ + menu_textures[icon_png_file_index].texture.width = width; + menu_textures[icon_png_file_index].texture.height = height; + menu_textures[icon_png_file_index].texture.pitch = (width*4); + menu_textures[icon_png_file_index].texture.bmp_out = icon; + copyTexture(icon_png_file_index); + + menu_textures[icon_png_file_index].size = 1; + free_mem = (u32*) menu_textures[icon_png_file_index].buffer; } static int ReloadUserSaves(save_list_t* save_list) @@ -159,10 +168,12 @@ static code_entry_t* LoadSaveDetails(void) asprintf(¢ry->codes, "%s\n\n" "Title: %s\n" "Sub-Title: %s\n" + "Folder: %s\n" "Lock: %s\n\n" "User ID: %08d\n" "Account ID: %.16s (%s)\n" "PSID: %016lX %016lX\n", selected_entry->path, selected_entry->name, subtitle, + selected_entry->dir_name, (selected_entry->flags & SAVE_FLAG_LOCKED ? "Copying Prohibited" : "Unlocked"), param_ids->user_id, param_ids->account_id, (selected_entry->flags & SAVE_FLAG_OWNER ? "Owner" : "Not Owner"), @@ -307,6 +318,7 @@ static void SetMenu(int id) menu_old_sel[MENU_PATCHES] = 0; char iconfile[256]; + menu_textures[icon_png_file_index].size = 0; snprintf(iconfile, sizeof(iconfile), "%s" "ICON0.PNG", selected_entry->path); if (selected_entry->flags & SAVE_FLAG_ONLINE) @@ -317,10 +329,14 @@ static void SetMenu(int id) http_download(selected_entry->path, "ICON0.PNG", iconfile, 1); } + if (selected_entry->flags & SAVE_FLAG_VMC && selected_entry->type == FILE_TYPE_PS1) + LoadVmcTexture(16, 16, getIconRGBA(selected_entry->path[strlen(selected_entry->path)+1], 0)); + + if (selected_entry->flags & SAVE_FLAG_VMC && selected_entry->type == FILE_TYPE_PS2) + LoadVmcTexture(128, 128, getIconPS2(selected_entry->dir_name, strrchr(selected_entry->path, '\n')+1)); + if (file_exists(iconfile) == SUCCESS) - LoadFileTexture(iconfile, icon_png_file_index); - else - menu_textures[icon_png_file_index].size = 0; + LoadFileTexture(iconfile); if (apollo_config.doAni && menu_id != MENU_PATCH_VIEW && menu_id != MENU_CODE_OPTIONS) Draw_CheatsMenu_Selection_Ani(); diff --git a/source/ps1card.c b/source/ps1card.c index 403aa35..0b14bb0 100644 --- a/source/ps1card.c +++ b/source/ps1card.c @@ -301,7 +301,7 @@ static void loadPalette(void) if ((redChannel | greenChannel | blueChannel | blackFlag) == 0) ps1saves[slotNumber].iconPalette[colorCounter] = 0x00000000; else - ps1saves[slotNumber].iconPalette[colorCounter] = redChannel | (greenChannel << 8) | (blueChannel << 16) | 0xFF000000; + ps1saves[slotNumber].iconPalette[colorCounter] = blueChannel | (greenChannel << 8) | (redChannel << 16) | 0xFF000000; colorCounter++; } diff --git a/source/ps2classic.c b/source/ps2classic.c index 30154a1..8cf3623 100644 --- a/source/ps2classic.c +++ b/source/ps2classic.c @@ -269,27 +269,6 @@ int ps2_add_vmc_ecc(const char* src, const char* dst) return 1; } -int ps2_remove_vmc_ecc(const char* src, const char* dst) -{ - ps2_block_t block; - - FILE *in = fopen(src, "rb"); - FILE *fo = fopen(dst, "wb"); - - if (!in || !fo) - return 0; - - while(fread(&block, 1, sizeof(ps2_block_t), in) > 0) - { - fwrite(&block, PS2_VMC_DATASIZE, 1, fo); - } - - fclose(in); - fclose(fo); - - return 1; -} - /* * ps2_iso9660_sig */ diff --git a/source/ps2icon.c b/source/ps2icon.c new file mode 100644 index 0000000..2c02f5d --- /dev/null +++ b/source/ps2icon.c @@ -0,0 +1,139 @@ +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <string.h> + +#include "ps2icon.h" +#include "mcio.h" + + +static uint32_t TIM2RGBA(const uint8_t *buf) +{ + uint8_t ARGB[4]; + uint16_t lRGB = (int16_t) (buf[1] << 8) | buf[0]; + + ARGB[0] = 0xFF; + ARGB[1] = 8 * (lRGB & 0x1F); + ARGB[2] = 8 * ((lRGB >> 5) & 0x1F); + ARGB[3] = 8 * (lRGB >> 10); + + return *((uint32_t *) &ARGB); +} + +static void* ps2IconTexture(const uint8_t* iData) +{ + int i; + uint16_t j; + Icon_Header header; + Animation_Header anim_header; + Frame_Data animation; + uint32_t *lTexturePtr, *lRGBA; + + lTexturePtr = (uint32_t *) calloc(128 * 128, sizeof(uint32_t)); + + //read header: + memcpy(&header, iData, sizeof(Icon_Header)); + iData += sizeof(Icon_Header); + + //convert to big endian + header.n_vertices = __builtin_bswap32(header.n_vertices); + header.texture_type = __builtin_bswap32(header.texture_type); + header.animation_shapes = __builtin_bswap32(header.animation_shapes); + + //n_vertices has to be divisible by three, that's for sure: + if(header.file_id != 0x0100 || header.n_vertices % 3 != 0) + return lTexturePtr; + + //read icon data from file: https://ghulbus-inc.de/projects/ps2iconsys/ + ///Vertex data + // each vertex consists of animation_shapes tuples for vertex coordinates, + // followed by one vertex coordinate tuple for normal coordinates + // followed by one texture data tuple for texture coordinates and color + for(i=0; i<header.n_vertices; i++) { + iData += sizeof(Vertex_Coord) * header.animation_shapes; + iData += sizeof(Vertex_Coord); + iData += sizeof(Texture_Data); + } + + //animation data + // preceeded by an animation header, there is a frame data/key set for every frame: + memcpy(&anim_header, iData, sizeof(Animation_Header)); + anim_header.n_frames = __builtin_bswap32(anim_header.n_frames); + iData += sizeof(Animation_Header); + + //read animation data: + for(i=0; i<anim_header.n_frames; i++) { + memcpy(&animation, iData, sizeof(Frame_Data)); + animation.n_keys = __builtin_bswap32(animation.n_keys); + iData += sizeof(Frame_Data); + + if(animation.n_keys > 0) + iData += sizeof(Frame_Key) * animation.n_keys; + } + + lRGBA = lTexturePtr; + + if (header.texture_type <= 7) + { // Uncompressed texture + for (i = 0; i < (128 * 128); i++) + { + *lRGBA = TIM2RGBA(iData); + lRGBA++; + iData += 2; + } + } + else + { //Compressed texture + iData += 4; + do + { + j = (int16_t) (iData[1] << 8) | iData[0]; + if (0xFF00 == (j & 0xFF00)) + { + for (j = (0x0000 - j) & 0xFFFF; j > 0; j--) + { + iData += 2; + *lRGBA = TIM2RGBA(iData); + lRGBA++; + } + } + else + { + iData += 2; + for (; j > 0; j--) + { + *lRGBA = TIM2RGBA(iData); + lRGBA++; + } + } + iData += 2; + } while ((lRGBA - lTexturePtr) < 0x4000); + } + + return (lTexturePtr); +} + +//Get icon data as bytes +uint8_t* getIconPS2(const char* folder, const char* iconfile) +{ + int fd; + uint8_t *buf, *out; + char filePath[256]; + struct io_dirent st; + + snprintf(filePath, sizeof(filePath), "%s/%s", folder, iconfile); + mcio_mcStat(filePath, &st); + + fd = mcio_mcOpen(filePath, sceMcFileAttrReadable | sceMcFileAttrFile); + if (fd < 0) + return calloc(128 * 128, sizeof(uint32_t)); + + buf = malloc(st.stat.size); + mcio_mcRead(fd, buf, st.stat.size); + mcio_mcClose(fd); + + out = ps2IconTexture(buf); + free(buf); + + return out; +} diff --git a/source/saves.c b/source/saves.c index d709aef..9750900 100644 --- a/source/saves.c +++ b/source/saves.c @@ -387,51 +387,6 @@ static int set_psv_codes(save_entry_t* item) return list_count(item->codes); } -static int set_ps2_codes(save_entry_t* item) -{ - code_entry_t* cmd; - item->codes = list_alloc(); - - cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_USER " View Save Details", CMD_VIEW_DETAILS); - list_append(item->codes, cmd); - - cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Decrypt SCEVMC0.VME", CMD_CODE_NULL); - cmd->file = strdup("SCEVMC0.VME"); - cmd->options_count = 1; - cmd->options = _createOptions(3, "Decrypt SCEVMC0.VME to USB", CMD_DECRYPT_PS2_VME); - asprintf(&cmd->options->name[2], "Decrypt SCEVMC0.VME to HDD"); - asprintf(&cmd->options->value[2], "%c%c", CMD_DECRYPT_PS2_VME, STORAGE_HDD); - list_append(item->codes, cmd); - - cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Decrypt SCEVMC1.VME", CMD_CODE_NULL); - cmd->file = strdup("SCEVMC1.VME"); - cmd->options_count = 1; - cmd->options = _createOptions(3, "Decrypt SCEVMC1.VME to USB", CMD_DECRYPT_PS2_VME); - asprintf(&cmd->options->name[2], "Decrypt SCEVMC1.VME to HDD"); - asprintf(&cmd->options->value[2], "%c%c", CMD_DECRYPT_PS2_VME, STORAGE_HDD); - list_append(item->codes, cmd); - - cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Import a .VM2 to SCEVMC0.VME", CMD_CODE_NULL); - cmd->file = strdup("SCEVMC0.VME"); - cmd->options_count = 1; - cmd->options = _getFileOptions(VMC_PS2_PATH_HDD, "*.VM2", CMD_ENCRYPT_PS2_VMC); - list_append(item->codes, cmd); - - cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Import a .VM2 to SCEVMC1.VME", CMD_CODE_NULL); - cmd->file = strdup("SCEVMC1.VME"); - cmd->options_count = 1; - cmd->options = _getFileOptions(VMC_PS2_PATH_HDD, "*.VM2", CMD_ENCRYPT_PS2_VMC); - list_append(item->codes, cmd); - - cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Copy dummy .PSV Save", CMD_CODE_NULL); - cmd->file = strdup("APOLLO-99PS2.PSV"); - cmd->options_count = 1; - cmd->options = _createOptions(2, "Copy APOLLO-99PS2.PSV to USB", CMD_COPY_DUMMY_PSV); - list_append(item->codes, cmd); - - return list_count(item->codes); -} - static void add_vmp_commands(save_entry_t* save) { char path[256]; @@ -483,9 +438,6 @@ int ReadCodes(save_entry_t * save) if (save->flags & SAVE_FLAG_PSV) return set_psv_codes(save); - if (save->flags & SAVE_FLAG_PS2) - return set_ps2_codes(save); - if (save->flags & SAVE_FLAG_PSP) return set_psp_codes(save); @@ -1096,12 +1048,6 @@ list_t * ReadBackupList(const char* userPath) list_append(item->codes, cmd); list_append(list, item); - item = _createSaveEntry(SAVE_FLAG_PS2, CHAR_ICON_COPY " Export PS2 .VM2 memory cards to USB"); - item->path = strdup(VMC_PS2_PATH_HDD); - item->title_id = strdup("HDD"); - item->type = FILE_TYPE_VM2; - list_append(list, item); - item = _createSaveEntry(0, CHAR_ICON_ZIP " Extract Archives (RAR, Zip, 7z)"); item->path = strdup(PS3_TMP_PATH); item->title_id = strdup("HDD"); @@ -1196,46 +1142,6 @@ static int get_binenc_files(save_entry_t * item) return list_count(item->codes); } -static int get_vm2_files(save_entry_t * item) -{ - code_entry_t* cmd; - DIR *d; - struct dirent *dir; - char name[256]; - item->codes = list_alloc(); - - d = opendir(item->path); - - if (d) - { - while ((dir = readdir(d)) != NULL) - { - if (dir->d_type == DT_REG && endsWith(dir->d_name, ".VM2")) - { - snprintf(name, sizeof(name), "Export \"%s\" to .VMC", dir->d_name); - - cmd = _createCmdCode(PATCH_COMMAND, name, CMD_CODE_NULL); - cmd->file = strdup(dir->d_name); - cmd->options_count = 1; - cmd->options = _createOptions(2, "Save .VMC to USB", CMD_EXP_VM2_RAW); - list_append(item->codes, cmd); - - LOG("Adding File '%s'", cmd->file); - } - } - closedir(d); - } - - if (!list_count(item->codes)) - { - list_free(item->codes); - item->codes = NULL; - return 0; - } - - return list_count(item->codes); -} - static int get_ps2_raw_files(save_entry_t * item) { code_entry_t* cmd; @@ -1326,9 +1232,6 @@ int ReadBackupCodes(save_entry_t * bup) case FILE_TYPE_BINENC: return get_binenc_files(bup); - case FILE_TYPE_VM2: - return get_vm2_files(bup); - case FILE_TYPE_PS2RAW: return get_ps2_raw_files(bup); @@ -1560,14 +1463,15 @@ int sortSaveList_Compare_TitleID(const void* a, const void* b) return strcasecmp(ta, tb); } -static void read_savegames(const char* userPath, list_t *list, uint32_t flag) +static void read_savegames(const char* userPath, const char* folder, list_t *list, uint32_t flag) { DIR *d; struct dirent *dir; save_entry_t *item; char sfoPath[256]; - d = opendir(userPath); + snprintf(sfoPath, sizeof(sfoPath), "%s%s", userPath, folder); + d = opendir(sfoPath); if (!d) return; @@ -1577,7 +1481,7 @@ static void read_savegames(const char* userPath, list_t *list, uint32_t flag) if (dir->d_type != DT_DIR || strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) continue; - snprintf(sfoPath, sizeof(sfoPath), "%s%s/PARAM.SFO", userPath, dir->d_name); + snprintf(sfoPath, sizeof(sfoPath), "%s%s%s/PARAM.SFO", userPath, folder, dir->d_name); if (file_exists(sfoPath) == SUCCESS) { LOG("Reading %s...", sfoPath); @@ -1590,9 +1494,38 @@ static void read_savegames(const char* userPath, list_t *list, uint32_t flag) } char *sfo_data = (char*) sfo_get_param_value(sfo, "TITLE"); - item = _createSaveEntry(flag, sfo_data); - asprintf(&item->path, "%s%s/", userPath, dir->d_name); + if (flag & SAVE_FLAG_PS2) + { + snprintf(sfoPath, sizeof(sfoPath), "%s%s%s/SCEVMC0.VME", userPath, folder, dir->d_name); + if (file_exists(sfoPath) != SUCCESS) + { + sfo_free(sfo); + continue; + } + + snprintf(sfoPath, sizeof(sfoPath), "%s (MemCard)", sfo_data); + item = _createSaveEntry(flag | SAVE_FLAG_VMC | SAVE_FLAG_LOCKED, sfoPath); + item->type = FILE_TYPE_VMC; + asprintf(&item->path, "%s%s%s/SCEVMC0.VME", userPath, folder, dir->d_name); + item->title_id = strdup("VME 0"); + item->dir_name = strdup(userPath); + list_append(list, item); + + item = _createSaveEntry(flag | SAVE_FLAG_VMC | SAVE_FLAG_LOCKED, sfoPath); + item->type = FILE_TYPE_VMC; + asprintf(&item->path, "%s%s%s/SCEVMC1.VME", userPath, folder, dir->d_name); + item->title_id = strdup("VME 1"); + item->dir_name = strdup(userPath); + list_append(list, item); + + sfo_free(sfo); + LOG("[%s] F(%X) name '%s'", item->title_id, item->flags, item->name); + continue; + } + + item = _createSaveEntry(flag, sfo_data); + asprintf(&item->path, "%s%s%s/", userPath, folder, dir->d_name); asprintf(&item->title_id, "%.9s", dir->d_name); item->dir_name = strdup(dir->d_name); @@ -1654,7 +1587,7 @@ static void read_vmc2_files(const char* userPath, list_t *list) closedir(d); } -static void read_psv_savegames(const char* userPath, list_t *list) +static void read_psv_savegames(const char* userPath, const char* folder, list_t *list) { DIR *d; struct dirent *dir; @@ -1662,7 +1595,8 @@ static void read_psv_savegames(const char* userPath, list_t *list) char psvPath[256]; char data[0x100]; - d = opendir(userPath); + snprintf(psvPath, sizeof(psvPath), "%s%s", userPath, folder); + d = opendir(psvPath); if (!d) return; @@ -1672,7 +1606,7 @@ static void read_psv_savegames(const char* userPath, list_t *list) if (dir->d_type != DT_REG || !endsWith(dir->d_name, ".PSV")) continue; - snprintf(psvPath, sizeof(psvPath), "%s%s", userPath, dir->d_name); + snprintf(psvPath, sizeof(psvPath), "%s%s%s", userPath, folder, dir->d_name); LOG("Reading %s...", psvPath); FILE *psvf = fopen(psvPath, "rb"); @@ -1700,8 +1634,8 @@ static void read_psv_savegames(const char* userPath, list_t *list) memset(item, 0, sizeof(save_entry_t)); item->flags = SAVE_FLAG_PSV | (type == 1 ? SAVE_FLAG_PS1 : SAVE_FLAG_PS2); - asprintf(&item->path, "%s%s", userPath, dir->d_name); - asprintf(&item->title_id, "%.12s", dir->d_name); + asprintf(&item->path, "%s%s%s", userPath, folder, dir->d_name); + asprintf(&item->title_id, "%.10s", dir->d_name + 2); //PS2 Title offset 0xC0 //PS1 Title offset 0x04 @@ -1714,7 +1648,7 @@ static void read_psv_savegames(const char* userPath, list_t *list) closedir(d); } -static void read_psx_savegames(const char* userPath, list_t *list) +static void read_psx_savegames(const char* userPath, const char* folder, list_t *list) { DIR *d; struct dirent *dir; @@ -1723,7 +1657,8 @@ static void read_psx_savegames(const char* userPath, list_t *list) char data[64]; int type, toff; - d = opendir(userPath); + snprintf(psvPath, sizeof(psvPath), "%s%s", userPath, folder); + d = opendir(psvPath); if (!d) return; @@ -1760,13 +1695,13 @@ static void read_psx_savegames(const char* userPath, list_t *list) } else if (endsWith(dir->d_name, ".XPS") || endsWith(dir->d_name, ".SPS")) { - toff = 0x04; + toff = 0x02; type = FILE_TYPE_XPS; } else continue; - snprintf(psvPath, sizeof(psvPath), "%s%s", userPath, dir->d_name); + snprintf(psvPath, sizeof(psvPath), "%s%s%s", userPath, folder, dir->d_name); LOG("Reading %s...", psvPath); FILE *fp = fopen(psvPath, "rb"); @@ -1786,8 +1721,8 @@ static void read_psx_savegames(const char* userPath, list_t *list) item->flags = SAVE_FLAG_PS1; item->type = type; - asprintf(&item->path, "%s%s", userPath, dir->d_name); - asprintf(&item->title_id, "%.12s", data); + asprintf(&item->path, "%s%s%s", userPath, folder, dir->d_name); + asprintf(&item->title_id, "%.10s", data + 2); LOG("[%s] F(%X) name '%s'", item->title_id, item->flags, item->name); list_append(list, item); @@ -1810,8 +1745,6 @@ list_t * ReadUserList(const char* userPath) save_entry_t *item; code_entry_t *cmd; list_t *list; - char savePath[256]; - char * save_paths[3]; if (dir_exists(userPath) != SUCCESS) return NULL; @@ -1821,6 +1754,7 @@ list_t * ReadUserList(const char* userPath) item = _createSaveEntry(SAVE_FLAG_PS3, CHAR_ICON_COPY " Bulk Save Management"); item->type = FILE_TYPE_MENU; item->codes = list_alloc(); + asprintf(&item->path, "%s%s", userPath, PS3_SAVES_PATH_HDD); //bulk management hack item->dir_name = malloc(sizeof(void**)); ((void**)item->dir_name)[0] = list; @@ -1831,77 +1765,82 @@ list_t * ReadUserList(const char* userPath) cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_SIGN " Resign & Unlock selected Saves", CMD_RESIGN_SAVES); list_append(item->codes, cmd); - if (strncmp(userPath, USER_PATH_HDD, 15) == 0) - { - asprintf(&item->path, SAVES_PATH_HDD, apollo_config.user_id); + cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Copy all Saves to USB", CMD_CODE_NULL); + cmd->options_count = 1; + cmd->options = _createOptions(2, "Copy Saves to USB", CMD_COPY_ALL_SAVES_USB); + list_append(item->codes, cmd); - cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Copy all Saves to USB", CMD_CODE_NULL); - cmd->options_count = 1; - cmd->options = _createOptions(2, "Copy Saves to USB", CMD_COPY_ALL_SAVES_USB); - list_append(item->codes, cmd); + cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Copy selected Saves to USB", CMD_CODE_NULL); + cmd->options_count = 1; + cmd->options = _createOptions(2, "Copy Saves to USB", CMD_COPY_SAVES_USB); + list_append(item->codes, cmd); - cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Copy selected Saves to USB", CMD_CODE_NULL); - cmd->options_count = 1; - cmd->options = _createOptions(2, "Copy Saves to USB", CMD_COPY_SAVES_USB); - list_append(item->codes, cmd); + cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_NET " Start local Web Server", CMD_SAVE_WEB_SERVER); + list_append(item->codes, cmd); + list_append(list, item); - save_paths[0] = PS3_SAVES_PATH_HDD; - save_paths[1] = PS2_SAVES_PATH_HDD; - save_paths[2] = PSP_SAVES_PATH_HDD; - } - else - { - asprintf(&item->path, "%s" PS3_SAVES_PATH_USB, userPath); + read_savegames(userPath, PS3_SAVES_PATH_HDD, list, SAVE_FLAG_PS3); + read_savegames(userPath, PS2_SAVES_PATH_HDD, list, SAVE_FLAG_PS2); + read_savegames(userPath, PSP_SAVES_PATH_HDD, list, SAVE_FLAG_PSP); - cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Copy all Saves to HDD", CMD_COPY_ALL_SAVES_HDD); - list_append(item->codes, cmd); + read_vmc1_files(VMC_PS2_PATH_HDD, list); + read_vmc2_files(VMC_PS2_PATH_HDD, list); - cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Copy selected Saves to HDD", CMD_COPY_SAVES_HDD); - list_append(item->codes, cmd); + return list; +} - save_paths[0] = PS3_SAVES_PATH_USB; - save_paths[1] = PS2_SAVES_PATH_USB; - save_paths[2] = PSP_SAVES_PATH_USB; - } +list_t * ReadUsbList(const char* userPath) +{ + save_entry_t *item; + code_entry_t *cmd; + list_t *list; + char savePath[256]; - cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_NET " Start local Web Server", CMD_SAVE_WEB_SERVER); + if (dir_exists(userPath) != SUCCESS) + return NULL; + + list = list_alloc(); + + item = _createSaveEntry(SAVE_FLAG_PS3, CHAR_ICON_COPY " Bulk Save Management"); + item->type = FILE_TYPE_MENU; + item->codes = list_alloc(); + asprintf(&item->path, "%s%s", userPath, PS3_SAVES_PATH_USB); + //bulk management hack + item->dir_name = malloc(sizeof(void**)); + ((void**)item->dir_name)[0] = list; + + cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_SIGN " Resign & Unlock all Saves", CMD_RESIGN_ALL_SAVES); list_append(item->codes, cmd); - list_append(list, item); - snprintf(savePath, sizeof(savePath), "%s%s", userPath, save_paths[0]); - read_savegames(savePath, list, SAVE_FLAG_PS3); + cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_SIGN " Resign & Unlock selected Saves", CMD_RESIGN_SAVES); + list_append(item->codes, cmd); - snprintf(savePath, sizeof(savePath), "%s%s", userPath, save_paths[1]); - read_savegames(savePath, list, SAVE_FLAG_PS2); + cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Copy all Saves to HDD", CMD_COPY_ALL_SAVES_HDD); + list_append(item->codes, cmd); - snprintf(savePath, sizeof(savePath), "%s%s", userPath, save_paths[2]); - read_savegames(savePath, list, SAVE_FLAG_PSP); + cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Copy selected Saves to HDD", CMD_COPY_SAVES_HDD); + list_append(item->codes, cmd); - if (strncmp(userPath, USB_PATH, 8) == 0) - { - snprintf(savePath, sizeof(savePath), "%s%s", userPath, PSV_SAVES_PATH_USB); - read_psv_savegames(savePath, list); + cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_NET " Start local Web Server", CMD_SAVE_WEB_SERVER); + list_append(item->codes, cmd); + list_append(list, item); - snprintf(savePath, sizeof(savePath), "%s%s", userPath, PS2_IMP_PATH_USB); - read_psx_savegames(savePath, list); + read_savegames(userPath, PS3_SAVES_PATH_USB, list, SAVE_FLAG_PS3); + read_savegames(userPath, PS2_SAVES_PATH_USB, list, SAVE_FLAG_PS2); + read_savegames(userPath, PSP_SAVES_PATH_USB, list, SAVE_FLAG_PSP); - snprintf(savePath, sizeof(savePath), "%s%s", userPath, PS1_IMP_PATH_USB); - read_psx_savegames(savePath, list); + read_psv_savegames(userPath, PSV_SAVES_PATH_USB, list); + read_psx_savegames(userPath, PS2_IMP_PATH_USB, list); + read_psx_savegames(userPath, PS1_IMP_PATH_USB, list); - snprintf(savePath, sizeof(savePath), "%s%s", userPath, VMC_PS1_PATH_USB); - read_vmc1_files(savePath, list); + snprintf(savePath, sizeof(savePath), "%s%s", userPath, VMC_PS1_PATH_USB); + read_vmc1_files(savePath, list); - snprintf(savePath, sizeof(savePath), "%s%s", userPath, VMC_PS2_PATH_USB); - read_vmc2_files(savePath, list); + snprintf(savePath, sizeof(savePath), "%s%s", userPath, VMC_PS2_PATH_USB); + read_vmc2_files(savePath, list); - snprintf(savePath, sizeof(savePath), "%s%s", userPath, "VMC/"); - read_vmc2_files(savePath, list); - } - else - { - read_vmc1_files(VMC_PS2_PATH_HDD, list); - read_vmc2_files(VMC_PS2_PATH_HDD, list); - } + snprintf(savePath, sizeof(savePath), "%s%s", userPath, "VMC/"); + read_vmc2_files(savePath, list); return list; } @@ -2104,6 +2043,7 @@ list_t * ReadVmc2List(const char* userPath) item = _createSaveEntry(SAVE_FLAG_PS2, CHAR_ICON_VMC " Memory Card Management"); item->type = FILE_TYPE_MENU; item->path = strdup(userPath); + item->title_id = strdup("VMC"); item->codes = list_alloc(); //bulk management hack item->dir_name = malloc(sizeof(void**)); @@ -2119,6 +2059,35 @@ list_t * ReadVmc2List(const char* userPath) list_append(item->codes, cmd); list_append(list, item); + cmd = _createCmdCode(PATCH_NULL, "----- " UTF8_CHAR_STAR " Virtual Memory Card " UTF8_CHAR_STAR " -----", CMD_CODE_NULL); + list_append(item->codes, cmd); + + if (!endsWith(userPath, ".VM2")) + { + cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Export Memory Card to .VM2 format", CMD_CODE_NULL); + cmd->file = strdup(strrchr(userPath, '/')+1); + cmd->options_count = 1; + cmd->options = _createOptions(3, "Save .VM2 Memory Card to USB", CMD_EXP_PS2_VM2); + asprintf(&cmd->options->name[2], "Save .VM2 Memory Card to HDD"); + asprintf(&cmd->options->value[2], "%c%c", CMD_EXP_PS2_VM2, STORAGE_HDD); + list_append(item->codes, cmd); + } + + cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Export Memory Card to .VMC format (No ECC)", CMD_CODE_NULL); + cmd->file = strdup(strrchr(userPath, '/')+1); + cmd->options_count = 1; + cmd->options = _createOptions(2, "Save .VMC Memory Card to USB", CMD_EXP_VM2_RAW); + list_append(item->codes, cmd); + + if (!endsWith(userPath, ".VMC")) + { + cmd = _createCmdCode(PATCH_COMMAND, CHAR_ICON_COPY " Import a .VM2 file to Memory Card", CMD_CODE_NULL); + cmd->file = strdup(strrchr(userPath, '/')+1); + cmd->options_count = 1; + cmd->options = _getFileOptions(VMC_PS2_PATH_HDD, "*.VM2", CMD_IMP_PS2_VM2); + list_append(item->codes, cmd); + } + item = _createSaveEntry(SAVE_FLAG_PS2, CHAR_ICON_COPY " Import Saves to Virtual Card"); if (strncmp(userPath, USB_PATH, 8) == 0) {