diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f1a7805 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/category_lite.elf +/category_lite.prx +/category_lite_lang.h diff --git a/Makefile b/Makefile index 37debcb..e3f48a3 100644 --- a/Makefile +++ b/Makefile @@ -1,47 +1,47 @@ -TARGET = category_lite -STUBS = imports.o scePaf.o func_stubs.o -CATEGORY_MODES = multims.o context.o vshitem.o mode.o selection.o -HELPER = clearcache.o logger.o utils.o config.o filter.o -OBJS = main.o category.o gcread.o gcpatches.o sysconf.o language.o -OBJS += $(CATEGORY_MODES) $(HELPER) $(STUBS) -LIBS = -lpsprtc -lpspreg - -EXTRA_TARGETS = category_lang -EXTRA_CLEAN = category_lite_??.h - -ifeq (x$(CONFIG_LANG), x) -CONFIG_LANG = en -endif - -# use a psp-filer with VSH support or the plugin won't load on PRO firmware -# edit: 6.20 Pro won't work with this. Bugs, bugs everywhere.... -all: category_lang -# -psp-packer category_lite.prx - -category_lang: - bin2c lang/category_lite_$(CONFIG_LANG).txt category_lite_lang.h category_lite_lang - -EXTRA_WARNS= -Wextra -Wfloat-equal -Wundef -Wshadow -Wpointer-arith -Wwrite-strings -Wunreachable-code -CFLAGS =-O2 -Wall -G0 -std=c99 -fshort-wchar $(EXTRA_WARNS) - -ifeq ($(DEBUG), 1) -CFLAGS+=-DDEBUG -endif - -ifeq ($(BENCHMARK), 1) -CFLAGS+=-DBENCHMARK -endif - -ASFLAGS = $(CFLAGS) -LDFLAGS = -mno-crt0 -nostartfiles - -BUILD_PRX = 1 -PRX_EXPORTS = exports.exp - -USE_USER_LIBS = 1 -USE_USER_LIBC = 1 - -PSP_FW_VERSION=620 - -PSPSDK=$(shell psp-config --pspsdk-path) -include $(PSPSDK)/lib/build.mak +TARGET = category_lite +STUBS = imports.o scePaf.o func_stubs.o +CATEGORY_MODES = multims.o context.o vshitem.o mode.o selection.o +HELPER = clearcache.o logger.o utils.o config.o filter.o +OBJS = main.o category.o gcread.o gcpatches.o sysconf.o language.o +OBJS += $(CATEGORY_MODES) $(HELPER) $(STUBS) +LIBS = -lpsprtc -lpspreg + +EXTRA_TARGETS = category_lang +EXTRA_CLEAN = category_lite_??.h + +ifeq (x$(CONFIG_LANG), x) +CONFIG_LANG = en +endif + +# use a psp-filer with VSH support or the plugin won't load on PRO firmware +# edit: 6.20 Pro won't work with this. Bugs, bugs everywhere.... +all: category_lang +# -psp-packer category_lite.prx + +category_lang: + bin2c lang/category_lite_$(CONFIG_LANG).txt category_lite_lang.h category_lite_lang + +EXTRA_WARNS= -Wextra -Wfloat-equal -Wundef -Wshadow -Wpointer-arith -Wwrite-strings -Wunreachable-code +CFLAGS =-O2 -Wall -G0 -std=c99 -fshort-wchar $(EXTRA_WARNS) + +ifeq ($(DEBUG), 1) +CFLAGS+=-DDEBUG +endif + +ifeq ($(BENCHMARK), 1) +CFLAGS+=-DBENCHMARK +endif + +ASFLAGS = $(CFLAGS) +LDFLAGS = -nostartfiles + +BUILD_PRX = 1 +PRX_EXPORTS = exports.exp + +USE_USER_LIBS = 1 +USE_USER_LIBC = 1 + +PSP_FW_VERSION=620 + +PSPSDK=$(shell psp-config --pspsdk-path) +include $(PSPSDK)/lib/build.mak diff --git a/categories_lite.h b/categories_lite.h index 7620725..e099477 100644 --- a/categories_lite.h +++ b/categories_lite.h @@ -1,228 +1,228 @@ -/* - * this file is part of Game Categories Lite - * - * Copyright (C) 2011 Bubbletune - * Copyright (C) 2011 Codestation - * - * 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 . - */ - -#ifndef CATEGORY_LITE_ -#define CATEGORY_LITE_ - -#include -#include "gcpatches.h" - -int sceKernelGetCompiledSdkVersion(); - -#define MAKE_CALL(a, f) _sw(0x0C000000 | (((u32)(f) >> 2) & 0x03ffffff), a); -#define MAKE_JUMP(a, f) _sw(0x08000000 | (((u32)(f) & 0x0ffffffc) >> 2), a); -#define MAKE_STUB(a, f) {u32 addr = a; _sw(0x08000000 | (((u32)(f) & 0x0ffffffc) >> 2), addr); _sw(0, addr+4); } -#define U_EXTRACT_CALL(x) ((((u32)_lw((u32)x)) & ~0x0C000000) << 2) -#define ClearCachesForUser sceKernelGetCompiledSdkVersion -#define NOP_OPCODE 0 -#define ISSET(v, m) (((v) & (m)) == (m)) - -// useful to know who is the caller -#define GET_RA(x) __asm__("move %0,$ra" : "=r"((x))) - -#define UNUSED __attribute__((unused)) - -#define ITEMSOF(arr) (sizeof(arr) / sizeof(0[arr])) - -// uncomment this once the oldplugin of Pro is gone -//#define DEVICE_MEMORY_STICK "ms0:" -//#define DEVICE_INTERNAL_STORAGE "ef0:" - -/* Avoid that "Old Plugin Support (PSP-Go only)" screw us */ -#define XOR_KEY 0xDEADC0DE -#define XORED_MEMORY_STICK 0xE49DB3B3 -#define XORED_INTERNAL_STORAGE 0xE49DA6BB - -#define PSPGO_MULTIMS_SENTINEL 1000 -#define PSPMS_MULTIMS_SENTINEL 100 - -#define PSPGO_UNCAT_SENTINEL 2000 -#define PSPMS_UNCAT_SENTINEL 200 - -#define PSPGO_CONTEXT_SENTINEL 0x90000 -#define PSPMS_CONTEXT_SENTINEL 0x70000 - -typedef struct -{ - void *next; - int location; - u64 mtime; - char letter; - char name; -} Category; - -typedef struct -{ - void *unk; // 0 - int id; // 4 - const char *regkey; // 8 - const char *text; // 12 - const char *subtitle; // 16 - const char *page; // 20 -} SceSysconfItem; // 24 - -typedef struct -{ - char text[48]; - int play_sound; - int action; - int action_arg; -} SceContextItem; // 60 - -typedef struct -{ - int id; // 0 - int relocate; // 4 - int action; // 8 - int action_arg; // 12 - SceContextItem *context; // 16 - char *subtitle; // 20 - int unk; // 24 - char play_sound; // 28 - char memstick; // 29 - char umd_icon; // 30 - char image[4]; // 31 - char image_shadow[4]; // 35 - char image_glow[4]; // 39 - char text[37]; // 43 -} SceVshItem; // 80 - -typedef struct { - char *name; - void *callback; - u32 unknown; -} SceCallbackItem; - -typedef struct -{ - u8 id; //00 - u8 type; //01 - u16 unk1; //02 - u32 label; //04 - u32 param; //08 - u32 first_child; //0c - int child_count; //10 - u32 next_entry; // 14 - u32 prev_entry; //18 - u32 parent; //1c - u32 unknown[2]; //20 -} SceRcoEntry; - -typedef struct -{ - void *unknown; - int option; - const char *text; -} SceGameContext; - -typedef struct { - u8 unk0[0xF0]; - char gametitle[0x80]; - u32 unk1; - char gamecode[0xA]; - u8 unk2[0x5E]; - char firmware[0x5]; - u8 unk3[0x3]; - char category[0x3]; - u8 unk4; -} SfoInfo620; - -typedef struct { - u8 unk0[0x68]; - char gametitle[0x80]; - u32 unk1; - char gamecode[0xA]; - u8 unk2[0x5E]; - char firmware[0x5]; - u8 unk3[0x3]; - char category[0x3]; - u8 unk4; -} SfoInfo630; - -typedef union _sfo { - SfoInfo620 sfo620; - SfoInfo630 sfo630; -} SfoInfo; - -enum CategoryLocation { - MEMORY_STICK, - INTERNAL_STORAGE, - INVALID = -1, -}; - -enum GameCategoriesModes { - MODE_MULTI_MS, - MODE_CONTEXT_MENU, - MODE_FOLDER, -}; - -typedef union _dpath { - u32 *device; - const char *path; -} dpath; - -#define SET_DEVICENAME(p, l) { \ - dpath __d; \ - __d.path = (p); \ - *__d.device = XOR_KEY; \ - *__d.device ^= (l) == MEMORY_STICK ? XORED_MEMORY_STICK : XORED_INTERNAL_STORAGE; \ -} - -// Functions in: multims.c -void PatchVshmain(u32 text_addr); -void PatchGameText(u32 text_addr); - -// Functions in: vshitem.c -void PatchPaf(u32 text_addr); -void PatchVshCommonGui(u32 text_addr); - -// Functions in: sysconf.c -void PatchSysconf(u32 text_addr); -void PatchVshmainForSysconf(u32 text_addr); -void PatchPafForSysconf(u32 text_addr); -void PatchExecuteActionForSysconf(int action, int action_arg); - -// Functions in: context.c -void PatchVshmainForContext(u32 text_addr); - -// Functions in: gcread.c -void PatchGamePluginForGCread(u32 text_addr); - -// Functions in: selection.c -void PatchSelection(u32 text_addr); - -// Functions in: category.c -int CountCategories(Category *head[], int location); -void ClearCategories(Category *head[], int location); -int AddCategory(Category *head[], const char *category, u64 mtime, int location); -Category *GetNextCategory(Category *head[], Category *prev, int location); -Category *FindCategory(Category *head[], const char *category, int location); -void IndexCategories(Category *head[], const char *path, int location); -int is_game_folder(const char *base, const char *path); -int has_directories(const char *base, const char *path); - -// Functions in: gcpatches.c -void ResolveNIDs(); -GCPatches *GetPatches(int fw_group); - -// Functions in: clearcache.S -void ClearCaches(); - -#endif /* CATEGORY_LITE_ */ +/* + * this file is part of Game Categories Lite + * + * Copyright (C) 2011 Bubbletune + * Copyright (C) 2011 Codestation + * + * 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 . + */ + +#ifndef CATEGORY_LITE_ +#define CATEGORY_LITE_ + +#include +#include "gcpatches.h" + +int sceKernelGetCompiledSdkVersion(); + +#define MAKE_CALL(a, f) _sw(0x0C000000 | (((u32)(f) >> 2) & 0x03ffffff), a); +#define MAKE_JUMP(a, f) _sw(0x08000000 | (((u32)(f) & 0x0ffffffc) >> 2), a); +#define MAKE_STUB(a, f) {u32 addr = a; _sw(0x08000000 | (((u32)(f) & 0x0ffffffc) >> 2), addr); _sw(0, addr+4); } +#define U_EXTRACT_CALL(x) ((((u32)_lw((u32)x)) & ~0x0C000000) << 2) +#define ClearCachesForUser sceKernelGetCompiledSdkVersion +#define NOP_OPCODE 0 +#define ISSET(v, m) (((v) & (m)) == (m)) + +// useful to know who is the caller +#define GET_RA(x) __asm__("move %0,$ra" : "=r"((x))) + +#define UNUSED __attribute__((unused)) + +#define ITEMSOF(arr) (sizeof(arr) / sizeof(0[arr])) + +// uncomment this once the oldplugin of Pro is gone +//#define DEVICE_MEMORY_STICK "ms0:" +//#define DEVICE_INTERNAL_STORAGE "ef0:" + +/* Avoid that "Old Plugin Support (PSP-Go only)" screw us */ +#define XOR_KEY 0xDEADC0DE +#define XORED_MEMORY_STICK 0xE49DB3B3 +#define XORED_INTERNAL_STORAGE 0xE49DA6BB + +#define PSPGO_MULTIMS_SENTINEL 1000 +#define PSPMS_MULTIMS_SENTINEL 100 + +#define PSPGO_UNCAT_SENTINEL 2000 +#define PSPMS_UNCAT_SENTINEL 200 + +#define PSPGO_CONTEXT_SENTINEL 0x90000 +#define PSPMS_CONTEXT_SENTINEL 0x70000 + +typedef struct +{ + void *next; + int location; + u64 mtime; + char letter; + char name; +} Category; + +typedef struct +{ + void *unk; // 0 + int id; // 4 + const char *regkey; // 8 + const char *text; // 12 + const char *subtitle; // 16 + const char *page; // 20 +} SceSysconfItem; // 24 + +typedef struct +{ + char text[48]; + int play_sound; + int action; + int action_arg; +} SceContextItem; // 60 + +typedef struct +{ + int id; // 0 + int relocate; // 4 + int action; // 8 + int action_arg; // 12 + SceContextItem *context; // 16 + char *subtitle; // 20 + int unk; // 24 + char play_sound; // 28 + char memstick; // 29 + char umd_icon; // 30 + char image[4]; // 31 + char image_shadow[4]; // 35 + char image_glow[4]; // 39 + char text[37]; // 43 +} SceVshItem; // 80 + +typedef struct { + char *name; + void *callback; + u32 unknown; +} SceCallbackItem; + +typedef struct +{ + u8 id; //00 + u8 type; //01 + u16 unk1; //02 + u32 label; //04 + u32 param; //08 + u32 first_child; //0c + int child_count; //10 + u32 next_entry; // 14 + u32 prev_entry; //18 + u32 parent; //1c + u32 unknown[2]; //20 +} SceRcoEntry; + +typedef struct +{ + void *unknown; + int option; + const char *text; +} SceGameContext; + +typedef struct { + u8 unk0[0xF0]; + char gametitle[0x80]; + u32 unk1; + char gamecode[0xA]; + u8 unk2[0x5E]; + char firmware[0x5]; + u8 unk3[0x3]; + char category[0x3]; + u8 unk4; +} SfoInfo620; + +typedef struct { + u8 unk0[0x68]; + char gametitle[0x80]; + u32 unk1; + char gamecode[0xA]; + u8 unk2[0x5E]; + char firmware[0x5]; + u8 unk3[0x3]; + char category[0x3]; + u8 unk4; +} SfoInfo630; + +typedef union _sfo { + SfoInfo620 sfo620; + SfoInfo630 sfo630; +} SfoInfo; + +enum CategoryLocation { + MEMORY_STICK, + INTERNAL_STORAGE, + INVALID = -1, +}; + +enum GameCategoriesModes { + MODE_MULTI_MS, + MODE_CONTEXT_MENU, + MODE_FOLDER, +}; + +typedef union _dpath { + u32 *device; + const char *path; +} dpath; + +#define SET_DEVICENAME(p, l) { \ + dpath __d; \ + __d.path = (p); \ + *__d.device = XOR_KEY; \ + *__d.device ^= (l) == MEMORY_STICK ? XORED_MEMORY_STICK : XORED_INTERNAL_STORAGE; \ +} + +// Functions in: multims.c +void PatchVshmain(u32 text_addr); +void PatchGameText(u32 text_addr); + +// Functions in: vshitem.c +void PatchPaf(u32 text_addr); +void PatchVshCommonGui(u32 text_addr); + +// Functions in: sysconf.c +void PatchSysconf(u32 text_addr); +void PatchVshmainForSysconf(u32 text_addr); +void PatchPafForSysconf(u32 text_addr); +void PatchExecuteActionForSysconf(int action, int action_arg); + +// Functions in: context.c +void PatchVshmainForContext(u32 text_addr); + +// Functions in: gcread.c +void PatchGamePluginForGCread(u32 text_addr); + +// Functions in: selection.c +void PatchSelection(u32 text_addr); + +// Functions in: category.c +int CountCategories(Category *head[], int location); +void ClearCategories(Category *head[], int location); +int AddCategory(Category *head[], const char *category, u64 mtime, int location); +Category *GetNextCategory(Category *head[], Category *prev, int location); +Category *FindCategory(Category *head[], const char *category, int location); +void IndexCategories(Category *head[], const char *path, int location); +int is_game_folder(const char *base, const char *path); +int has_directories(const char *base, const char *path); + +// Functions in: gcpatches.c +void ResolveNIDs(); +GCPatches *GetPatches(int fw_group); + +// Functions in: clearcache.S +void ClearCaches(); + +#endif /* CATEGORY_LITE_ */ diff --git a/category.c b/category.c index 8607a02..10738ed 100644 --- a/category.c +++ b/category.c @@ -28,25 +28,39 @@ static const char *eboot_types[] = { "EBOOT.PBP", "PARAM.PBP", "PBOOT.PBP" }; Category *GetNextCategory(Category *head[], Category *prev, int location) { - u64 time = 0, last; - Category *newest = NULL; - if (prev) { - last = prev->mtime; - } else { - last = (u64) -1; - } + Category *newest = NULL; Category *p = (Category *) head[location]; - while (p) { - if (p->mtime < last) { - if (p->mtime > time) { - time = p->mtime; - newest = p; + if(config.catsort) { + char *name = NULL; + char *last = prev ? &prev->name : NULL; + + while (p) { + if (!last || sce_paf_private_strcmp(&p->name, last) > 0) { + if(!name || sce_paf_private_strcmp(&p->name, name) < 0) { + name = &p->name; + newest = p; + } } + + p = p->next; } - p = p->next; + } else { + u64 time = 0; + u64 last = prev ? prev->mtime : (u64)-1; + + while (p) { + if (p->mtime < last) { + if (p->mtime > time) { + time = p->mtime; + newest = p; + } + } + + p = p->next; + } } return newest; diff --git a/config.c b/config.c index 4b9c9d9..b7ddef3 100644 --- a/config.c +++ b/config.c @@ -23,7 +23,7 @@ #include "logger.h" CategoryConfig config; -static CategoryConfig prev_conf = {-1, -1, -1, -1}; +static CategoryConfig prev_conf = {-1, -1, -1, -1, -1}; extern int model; @@ -57,7 +57,7 @@ int save_config() { char device[12]; if(sce_paf_private_memcmp(&config, &prev_conf, sizeof(CategoryConfig)) != 0) { - if(prev_conf.mode != config.mode || prev_conf.prefix != config.prefix || prev_conf.uncategorized != config.uncategorized) { + if(prev_conf.mode != config.mode || prev_conf.prefix != config.prefix || prev_conf.uncategorized != config.uncategorized || prev_conf.catsort != config.catsort) { reset = 1; } else { reset = 0; diff --git a/config.h b/config.h index 623fcb7..ffa1549 100644 --- a/config.h +++ b/config.h @@ -27,6 +27,7 @@ typedef struct { u32 prefix; u32 uncategorized; u32 selection; + u32 catsort; } CategoryConfig; enum uncat { diff --git a/exports.exp b/exports.exp index 30896f6..43b7f97 100644 --- a/exports.exp +++ b/exports.exp @@ -1,8 +1,8 @@ -PSP_BEGIN_EXPORTS - -PSP_EXPORT_START(syslib, 0, 0x8000) -PSP_EXPORT_FUNC_HASH(module_start) -PSP_EXPORT_VAR_HASH(module_info) +PSP_BEGIN_EXPORTS + +PSP_EXPORT_START(syslib, 0, 0x8000) +PSP_EXPORT_FUNC_HASH(module_start) +PSP_EXPORT_VAR_HASH(module_info) PSP_EXPORT_END - -PSP_END_EXPORTS + +PSP_END_EXPORTS diff --git a/gcpatches.c b/gcpatches.c index 17bbbd2..4b210bb 100644 --- a/gcpatches.c +++ b/gcpatches.c @@ -1,180 +1,180 @@ -/* - * this file is part of Game Categories Lite - * - * Copyright (C) 2011 Bubbletune - * Copyright (C) 2011 Codestation - * - * 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 "gcpatches.h" -#include "categories_lite.h" - -extern SceModuleInfo module_info; - -typedef struct { - u32 nid620; - u32 nid630; - u32 nid660; -} nid; - -static nid nids[] = -{ - { 0xE5A74996, 0x8F95CC01, 0x726DFBA9 }, // sce_paf_private_strcpy - { 0x4F487FBC, 0xD38E62C6, 0x706ABBFF }, // sce_paf_private_strncpy - { 0x5E7610DF, 0x726776D7, 0x7B7133D5 }, // sce_paf_private_snprintf - { 0x4900119B, 0x1B952318, 0x4CF09BA2 }, // sce_paf_private_strcmp - { 0xE00E38F8, 0x9DF5623C, 0xE0B32AE8 }, // sce_paf_private_strncmp - { 0x16789955, 0x861C4627, 0xB05D9677 }, // sce_paf_private_memcmp - { 0x23C8DAB5, 0xE281261E, 0xF7C46E37 }, // sce_paf_private_memmove - { 0xF0D98BD1, 0x9E9FFBFB, 0x5E909060 }, // sce_paf_private_malloc - { 0xE0E8820F, 0xB0363C2E, 0xDB1612F1 }, // sce_paf_private_free - { 0x58189108, 0x49A72E5D, 0xD7DCB972 }, // sce_paf_private_strlen - { 0x0C962B6E, 0x5612DE15, 0xA4B8A4E3 }, // sce_paf_private_strtoul - { 0xF200AF8E, 0xE1C930B5, 0x02119936 }, // scePafSetSelectedItem -// { 0xE8473E80, 0x4C386F3C, 0xA138A376 }, // sce_paf_private_sprintf - -// { 0x03A0E8C2, 0xDE69A6CD, 0xAF067FA2 }, // sce_paf_private_wcslen -// { 0xF7A832C8, 0xDCE3B13E, 0xB4652CFE }, // sce_paf_private_memcpy -// { 0xBF48C1FC, 0x5870455C, 0xD9E2D6E1 }, // sce_paf_private_memset -// { 0x3029535C, 0xFD6C776F, 0xC3B2D310 }, // sce_paf_private_strchr -// { 0x42D04DD2, 0xCFC81D9F, 0x22420CC7 }, // sce_paf_private_strrchr -// { 0x2C433251, 0x4853DF6E, 0x4CE9C8D7 }, // sce_paf_private_strpbrk - -// { 0x39E9B515, 0xBF2046E2, 0xC907E7CF }, // scePafGetPageChild -// { 0x62D2266B, 0x9CFBB2D9, 0x4918DB1A }, // scePafGetPageString -// { 0xCB608DE5, 0x70082F6F, 0x3874A5F8 }, // scePafGetText -// { 0x511991AE, 0xE03A5C26, 0x50DCB767 }, // PAF_Resource_GetPageNodeByID -// { 0xC8C59436, 0xFDAFC9E9, 0x64A31513 }, // PAF_Resource_ResolveRefWString - -// { 0xE73C355B, 0x3A370539, 0x6C582683 }, // vshGetRegistryValue -// { 0x2375A440, 0xCD3AF2EC, 0x858291A3 }, // vshSetRegistryValue -}; - -GCPatches patches = -{ - /** main.c (sceSystemMemoryManager) */ - { 0x88009B28, 0x88009A08, 0x880098CC }, // get_compiled_sdk_version - - /** gcread.c (game_plugin_module) */ - { 0x28930, 0x2A5F0, 0x2A894 }, // io_dopen_stub - { 0x28940, 0x2A600, 0x2A8A4 }, // io_dread_stub - { 0x28948, 0x2A608, 0x2A8AC }, // io_dclose_stub - - { 0x28958, 0x2A618, 0x2A8BC }, // io_open_stub - { 0x28928, 0x2A5E8, 0x2A88C }, // io_getstat_stub - { 0x28938, 0x2A5F8, 0x2A89C }, // io_chstat_stub - { 0x28950, 0x2A610, 0x2A8B4 }, // io_remove_stub - { 0x28960, 0x2A620, 0x2A8C4 }, // io_rmdir_stub - - { 0x1FB4C, 0x21310, 0x215B4 }, // base_path - { 0x1FB50, 0x21314, 0x215B8 }, // base_path_arg - - { { 0x1CD24, 0x1CD18 }, { 0x1E42C, 0x1E420 }, {0x1E6A8, 0x1E69C} }, // snprintf_call_arg_1 - { { 0x1F8F0, 0x1F8B4 }, { 0x2109C, 0x21060 }, {0x21340, 0x21304} }, // snprintf_call_arg_2 - - //{ { 0x10EFC, 0x11C68 }, { 0x1176C, 0x123A4 } }, // sce_paf_get_text_call - - /** vshitem.c (vshmain) */ - - // { 0x1F3BC, 0x1FB70 }, // RegisterCallbacks - { 0x2348C, 0x23C7C, 0x23CE8 }, // AddVshItem - { 0x21D68, 0x22558, 0x22598 }, // GetBackupVshItem - //{ { 0x1631C, 0x2FF8C }, { 0x16984, 0x30828 } }, // ExecuteAction - //{ 0x16514, 0x16B7C// UnloadModule - - { 0x21E18, 0x22608, 0x22648 }, // AddVshItemOffset - { 0x16340, 0x169A8, 0x16A70 }, // ExecuteActionOffset - { 0x16734, 0x16D9C, 0x16E64 }, // UnloadModuleOffset - - //{ 0x23BE0, 0x243D0 }, // sce_paf_get_text_call - - /** sysconf.c (sysconf_plugin_module) */ - { 0x1C4A8, 0x1CD18, 0x1D150 }, // AddSysconfItem - { 0x02934, 0x02A28, 0x02A28 }, // GetSysconfItem - - /** sysconf.c (scePaf) */ - { 0x6750C, 0x674D4, 0x676F4 }, // GetPageNodeByIDOffset - { 0x677EC, 0x677B4, 0x679D4 }, // ResolveRefWStringOffset - - /** sysconf.c (vshmain) */ - { 0x03908, 0x03998, 0x03998 }, // vshGetRegistryValueOffset - { 0x03A38, 0x03AC8, 0x03AC8 }, // vshSetRegistryValueOffset - - /** vshitem.c (scePaf) */ - { 0x3C404, 0x3C3CC, 0x3C5EC }, // scePafGetTextOffset - /** vshitem.c (commonGui) */ - { 0x03C54, 0x03C54, 0x03C54 }, // CommonGuiDisplayContextOffset - - /** context.c (vshmain) */ - { 0x16284, 0x168EC, 0x169B4 }, // OnXmbPush - { 0x15D38, 0x163A0, 0x16468 }, // OnXmbContextMenu - //{ 0x0DEAD, 0x0DEAD, 0x1643C }, // OnMenuListScrollIn - - //{0xDEAD, 0xDEAD, 0x66E48}, // scePafGetPageChildOffset - - // folder categories patches (game_plugin_module) - { 0x2C8A8, 0x2E61C, 0x2E94C }, // current_mode - { 0x19B5C, 0x1ABF4, 0x1AE10 }, // categorize_game - //{ 0x28BF0, 0x2A800, 0x2AC04 }, // play_sound - { 0x119A4, 0x12300, 0x124E0 }, // play_sound_call - { (52/4), (56/4), (56/4) }, // array_index - { { 0x10680, 0x11750 }, { 0x11348, 0x11FD0 }, {0x114D8, 0x12178} }, // add_game_context_call - { 0x26B38, 0x28560, 0x28804 }, // add_game_context - { { 0xC704, 0xC708 }, { 0x8B8C, 0x8B90 }, {0x8C94, 0x8C90 } }, // setmode_call_arg_1 - { { 0xC638, 0xC630 }, { 0, 0 }, { 0, 0 } }, // setmode_call_arg_2 - { 0x02203821, 0x02003821, 0x02003821 }, // setmode_arg_opcode - { 0xC458, 0xCE44, 0xCFC8 }, // setmode - { 0x2C290, 0x2DFB0, 0x2E2E4 }, // on_push_folder_options_call - { 0x117DC, 0x120B4, 0x12294 }, // on_push_folder_options - { 0x2C218, 0x2DF44, 0x2E278 }, // on_push_options_call - { 0x1070C, 0x1142C, 0x115F4 }, // on_push_options - { 0x1B0F0, 0x1C5D0, 0x1C84C }, // get_selection - { 0x2CFCC, 0x2ED8C, 0x2F0BC }, // get_selection_arg - { {0, 0}, { 0x113B8, 0x12040 }, {0x11548, 0x121E8 } }, // set_selection_call - { 2, 3, 3 }, // OPTION_BY_CATEGORY - { 1, 2, 2 }, // MODE_BY_EXPIRE_DATE - {0x2D1D4, 0x2EF84, 0x2F2B4 }, // struct_addr - {1, 0, 0 }, // index -}; - -void ResolveNIDs(int fw_ver) { - u32 stub_top = (u32) module_info.stub_top; - u32 stub_end = (u32) module_info.stub_end; - - while (stub_top < stub_end) { - SceLibraryStubTable *stub = (SceLibraryStubTable *) stub_top; - if (strcmp(stub->libname, "scePaf") == 0) { - for (u32 i = 0; i < stub->stubcount; i++) { - for (u32 x = 0; x < ITEMSOF(nids); x++) { - if (stub->nidtable[i] == nids[x].nid630) { - if(fw_ver == FW_620) { - stub->nidtable[i] = nids[x].nid620; - } else if (fw_ver == FW_630) { - stub->nidtable[i] = nids[x].nid630; - } else if (fw_ver == FW_660) { - stub->nidtable[i] = nids[x].nid660; - } - } - } - } - } - stub_top += (u32)(stub->len * 4); - } -} +/* + * this file is part of Game Categories Lite + * + * Copyright (C) 2011 Bubbletune + * Copyright (C) 2011 Codestation + * + * 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 "gcpatches.h" +#include "categories_lite.h" + +extern SceModuleInfo module_info; + +typedef struct { + u32 nid620; + u32 nid630; + u32 nid660; +} nid; + +static nid nids[] = +{ + { 0xE5A74996, 0x8F95CC01, 0x726DFBA9 }, // sce_paf_private_strcpy + { 0x4F487FBC, 0xD38E62C6, 0x706ABBFF }, // sce_paf_private_strncpy + { 0x5E7610DF, 0x726776D7, 0x7B7133D5 }, // sce_paf_private_snprintf + { 0x4900119B, 0x1B952318, 0x4CF09BA2 }, // sce_paf_private_strcmp + { 0xE00E38F8, 0x9DF5623C, 0xE0B32AE8 }, // sce_paf_private_strncmp + { 0x16789955, 0x861C4627, 0xB05D9677 }, // sce_paf_private_memcmp + { 0x23C8DAB5, 0xE281261E, 0xF7C46E37 }, // sce_paf_private_memmove + { 0xF0D98BD1, 0x9E9FFBFB, 0x5E909060 }, // sce_paf_private_malloc + { 0xE0E8820F, 0xB0363C2E, 0xDB1612F1 }, // sce_paf_private_free + { 0x58189108, 0x49A72E5D, 0xD7DCB972 }, // sce_paf_private_strlen + { 0x0C962B6E, 0x5612DE15, 0xA4B8A4E3 }, // sce_paf_private_strtoul + { 0xF200AF8E, 0xE1C930B5, 0x02119936 }, // scePafSetSelectedItem +// { 0xE8473E80, 0x4C386F3C, 0xA138A376 }, // sce_paf_private_sprintf + +// { 0x03A0E8C2, 0xDE69A6CD, 0xAF067FA2 }, // sce_paf_private_wcslen +// { 0xF7A832C8, 0xDCE3B13E, 0xB4652CFE }, // sce_paf_private_memcpy +// { 0xBF48C1FC, 0x5870455C, 0xD9E2D6E1 }, // sce_paf_private_memset +// { 0x3029535C, 0xFD6C776F, 0xC3B2D310 }, // sce_paf_private_strchr +// { 0x42D04DD2, 0xCFC81D9F, 0x22420CC7 }, // sce_paf_private_strrchr +// { 0x2C433251, 0x4853DF6E, 0x4CE9C8D7 }, // sce_paf_private_strpbrk + +// { 0x39E9B515, 0xBF2046E2, 0xC907E7CF }, // scePafGetPageChild +// { 0x62D2266B, 0x9CFBB2D9, 0x4918DB1A }, // scePafGetPageString +// { 0xCB608DE5, 0x70082F6F, 0x3874A5F8 }, // scePafGetText +// { 0x511991AE, 0xE03A5C26, 0x50DCB767 }, // PAF_Resource_GetPageNodeByID +// { 0xC8C59436, 0xFDAFC9E9, 0x64A31513 }, // PAF_Resource_ResolveRefWString + +// { 0xE73C355B, 0x3A370539, 0x6C582683 }, // vshGetRegistryValue +// { 0x2375A440, 0xCD3AF2EC, 0x858291A3 }, // vshSetRegistryValue +}; + +GCPatches patches = +{ + /** main.c (sceSystemMemoryManager) */ + { 0x88009B28, 0x88009A08, 0x880098CC }, // get_compiled_sdk_version + + /** gcread.c (game_plugin_module) */ + { 0x28930, 0x2A5F0, 0x2A894 }, // io_dopen_stub + { 0x28940, 0x2A600, 0x2A8A4 }, // io_dread_stub + { 0x28948, 0x2A608, 0x2A8AC }, // io_dclose_stub + + { 0x28958, 0x2A618, 0x2A8BC }, // io_open_stub + { 0x28928, 0x2A5E8, 0x2A88C }, // io_getstat_stub + { 0x28938, 0x2A5F8, 0x2A89C }, // io_chstat_stub + { 0x28950, 0x2A610, 0x2A8B4 }, // io_remove_stub + { 0x28960, 0x2A620, 0x2A8C4 }, // io_rmdir_stub + + { 0x1FB4C, 0x21310, 0x215B4 }, // base_path + { 0x1FB50, 0x21314, 0x215B8 }, // base_path_arg + + { { 0x1CD24, 0x1CD18 }, { 0x1E42C, 0x1E420 }, {0x1E6A8, 0x1E69C} }, // snprintf_call_arg_1 + { { 0x1F8F0, 0x1F8B4 }, { 0x2109C, 0x21060 }, {0x21340, 0x21304} }, // snprintf_call_arg_2 + + //{ { 0x10EFC, 0x11C68 }, { 0x1176C, 0x123A4 } }, // sce_paf_get_text_call + + /** vshitem.c (vshmain) */ + + // { 0x1F3BC, 0x1FB70 }, // RegisterCallbacks + { 0x2348C, 0x23C7C, 0x23CE8 }, // AddVshItem + { 0x21D68, 0x22558, 0x22598 }, // GetBackupVshItem + //{ { 0x1631C, 0x2FF8C }, { 0x16984, 0x30828 } }, // ExecuteAction + //{ 0x16514, 0x16B7C// UnloadModule + + { 0x21E18, 0x22608, 0x22648 }, // AddVshItemOffset + { 0x16340, 0x169A8, 0x16A70 }, // ExecuteActionOffset + { 0x16734, 0x16D9C, 0x16E64 }, // UnloadModuleOffset + + //{ 0x23BE0, 0x243D0 }, // sce_paf_get_text_call + + /** sysconf.c (sysconf_plugin_module) */ + { 0x1C4A8, 0x1CD18, 0x1D150 }, // AddSysconfItem + { 0x02934, 0x02A28, 0x02A28 }, // GetSysconfItem + + /** sysconf.c (scePaf) */ + { 0x6750C, 0x674D4, 0x676F4 }, // GetPageNodeByIDOffset + { 0x677EC, 0x677B4, 0x679D4 }, // ResolveRefWStringOffset + + /** sysconf.c (vshmain) */ + { 0x03908, 0x03998, 0x03998 }, // vshGetRegistryValueOffset + { 0x03A38, 0x03AC8, 0x03AC8 }, // vshSetRegistryValueOffset + + /** vshitem.c (scePaf) */ + { 0x3C404, 0x3C3CC, 0x3C5EC }, // scePafGetTextOffset + /** vshitem.c (commonGui) */ + { 0x03C54, 0x03C54, 0x03C54 }, // CommonGuiDisplayContextOffset + + /** context.c (vshmain) */ + { 0x16284, 0x168EC, 0x169B4 }, // OnXmbPush + { 0x15D38, 0x163A0, 0x16468 }, // OnXmbContextMenu + //{ 0x0DEAD, 0x0DEAD, 0x1643C }, // OnMenuListScrollIn + + //{0xDEAD, 0xDEAD, 0x66E48}, // scePafGetPageChildOffset + + // folder categories patches (game_plugin_module) + { 0x2C8A8, 0x2E61C, 0x2E94C }, // current_mode + { 0x19B5C, 0x1ABF4, 0x1AE10 }, // categorize_game + //{ 0x28BF0, 0x2A800, 0x2AC04 }, // play_sound + { 0x119A4, 0x12300, 0x124E0 }, // play_sound_call + { (52/4), (56/4), (56/4) }, // array_index + { { 0x10680, 0x11750 }, { 0x11348, 0x11FD0 }, {0x114D8, 0x12178} }, // add_game_context_call + { 0x26B38, 0x28560, 0x28804 }, // add_game_context + { { 0xC704, 0xC708 }, { 0x8B8C, 0x8B90 }, {0x8C94, 0x8C90 } }, // setmode_call_arg_1 + { { 0xC638, 0xC630 }, { 0, 0 }, { 0, 0 } }, // setmode_call_arg_2 + { 0x02203821, 0x02003821, 0x02003821 }, // setmode_arg_opcode + { 0xC458, 0xCE44, 0xCFC8 }, // setmode + { 0x2C290, 0x2DFB0, 0x2E2E4 }, // on_push_folder_options_call + { 0x117DC, 0x120B4, 0x12294 }, // on_push_folder_options + { 0x2C218, 0x2DF44, 0x2E278 }, // on_push_options_call + { 0x1070C, 0x1142C, 0x115F4 }, // on_push_options + { 0x1B0F0, 0x1C5D0, 0x1C84C }, // get_selection + { 0x2CFCC, 0x2ED8C, 0x2F0BC }, // get_selection_arg + { {0, 0}, { 0x113B8, 0x12040 }, {0x11548, 0x121E8 } }, // set_selection_call + { 2, 3, 3 }, // OPTION_BY_CATEGORY + { 1, 2, 2 }, // MODE_BY_EXPIRE_DATE + {0x2D1D4, 0x2EF84, 0x2F2B4 }, // struct_addr + {1, 0, 0 }, // index +}; + +void ResolveNIDs(int fw_ver) { + u32 stub_top = (u32) module_info.stub_top; + u32 stub_end = (u32) module_info.stub_end; + + while (stub_top < stub_end) { + SceLibraryStubTable *stub = (SceLibraryStubTable *) stub_top; + if (strcmp(stub->libname, "scePaf") == 0) { + for (u32 i = 0; i < stub->stubcount; i++) { + for (u32 x = 0; x < ITEMSOF(nids); x++) { + if (stub->nidtable[i] == nids[x].nid630) { + if(fw_ver == FW_620) { + stub->nidtable[i] = nids[x].nid620; + } else if (fw_ver == FW_630) { + stub->nidtable[i] = nids[x].nid630; + } else if (fw_ver == FW_660) { + stub->nidtable[i] = nids[x].nid660; + } + } + } + } + } + stub_top += (u32)(stub->len * 4); + } +} diff --git a/gcpatches.h b/gcpatches.h index af5552c..4f817aa 100644 --- a/gcpatches.h +++ b/gcpatches.h @@ -1,121 +1,121 @@ -/* - * this file is part of Game Categories Lite - * - * Copyright (C) 2011 Bubbletune - * Copyright (C) 2011 Codestation - * - * 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 . - */ - -#ifndef GCPATCHES_H_ -#define GCPATCHES_H_ - -#include - -typedef struct { - /** main.c (sceSystemMemoryManager) */ - u32 get_compiled_sdk_version[3]; - - /** gcread.c (game_plugin_module) */ - u32 io_dopen_stub[3]; - u32 io_dread_stub[3]; - u32 io_dclose_stub[3]; - - u32 io_open_stub[3]; - u32 io_getstat_stub[3]; - u32 io_chstat_stub[3]; - u32 io_remove_stub[3]; - u32 io_rmdir_stub[3]; - - u32 base_path[3]; - u32 base_path_arg[3]; - - u32 snprintf_call_arg_1[3][2]; - u32 snprintf_call_arg_2[3][2]; - - //u32 sce_paf_get_text_call[2]; - - /** vshitem.c (vshmain) */ - //u32 RegisterCallbacks[3]; - u32 AddVshItem[3]; - u32 GetBackupVshItem[3]; - //u32 ExecuteAction[3][2]; - //u32 UnloadModule[3]; - - u32 AddVshItemOffset[3]; - u32 ExecuteActionOffset[3]; - u32 UnloadModuleOffset[3]; - - //u32 sce_paf_get_text_call; - - /** sysconf.c (sysconf_plugin_module) */ - u32 AddSysconfItem[3]; - u32 GetSysconfItem[3]; - - /** sysconf.c (scePaf) */ - u32 GetPageNodeByIDOffset[3]; - u32 ResolveRefWStringOffset[3]; - - /** sysconf.c (vshmain) */ - u32 vshGetRegistryValueOffset[3]; - u32 vshSetRegistryValueOffset[3]; - - /** vshitem.c (scePaf) */ - u32 scePafGetTextOffset[3]; - /** vshitem.c (commonGui) */ - u32 CommonGuiDisplayContextOffset[3]; - - /** context.c */ - u32 OnXmbPush[3]; - u32 OnXmbContextMenu[3]; - //u32 OnMenuListScrollIn[3]; - - //u32 scePafGetPageChildContext[3]; - - // folder categories patches - u32 current_mode[3]; - u32 categorize_game[3]; - //u32 play_sound[3]; - u32 play_sound_call[3]; - u32 array_index[3]; - u32 add_game_context_call[3][2]; - u32 add_game_context[3]; - u32 setmode_call_arg_1[3][2]; - u32 setmode_call_arg_2[3][2]; - u32 setmode_arg_opcode[3]; - u32 setmode[3]; - u32 on_push_folder_options_call[3]; - u32 on_push_folder_options[3]; - u32 on_push_options_call[3]; - u32 on_push_options[3]; - u32 get_selection[3]; - u32 get_selection_arg[3]; - u32 set_selection_call[3][2]; - int OPTION_BY_CATEGORY[3]; - u32 MODE_BY_EXPIRE_DATE[3]; - u32 struct_addr[3]; - u32 index[3]; - -} GCPatches; - - -enum fw_ver { FW_620, FW_630, FW_660}; - -extern GCPatches patches; -extern int patch_index; - -void ResolveNIDs(); -GCPatches *GetPatches(int fw_group); - -#endif /* GCPATCHES_H_ */ +/* + * this file is part of Game Categories Lite + * + * Copyright (C) 2011 Bubbletune + * Copyright (C) 2011 Codestation + * + * 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 . + */ + +#ifndef GCPATCHES_H_ +#define GCPATCHES_H_ + +#include + +typedef struct { + /** main.c (sceSystemMemoryManager) */ + u32 get_compiled_sdk_version[3]; + + /** gcread.c (game_plugin_module) */ + u32 io_dopen_stub[3]; + u32 io_dread_stub[3]; + u32 io_dclose_stub[3]; + + u32 io_open_stub[3]; + u32 io_getstat_stub[3]; + u32 io_chstat_stub[3]; + u32 io_remove_stub[3]; + u32 io_rmdir_stub[3]; + + u32 base_path[3]; + u32 base_path_arg[3]; + + u32 snprintf_call_arg_1[3][2]; + u32 snprintf_call_arg_2[3][2]; + + //u32 sce_paf_get_text_call[2]; + + /** vshitem.c (vshmain) */ + //u32 RegisterCallbacks[3]; + u32 AddVshItem[3]; + u32 GetBackupVshItem[3]; + //u32 ExecuteAction[3][2]; + //u32 UnloadModule[3]; + + u32 AddVshItemOffset[3]; + u32 ExecuteActionOffset[3]; + u32 UnloadModuleOffset[3]; + + //u32 sce_paf_get_text_call; + + /** sysconf.c (sysconf_plugin_module) */ + u32 AddSysconfItem[3]; + u32 GetSysconfItem[3]; + + /** sysconf.c (scePaf) */ + u32 GetPageNodeByIDOffset[3]; + u32 ResolveRefWStringOffset[3]; + + /** sysconf.c (vshmain) */ + u32 vshGetRegistryValueOffset[3]; + u32 vshSetRegistryValueOffset[3]; + + /** vshitem.c (scePaf) */ + u32 scePafGetTextOffset[3]; + /** vshitem.c (commonGui) */ + u32 CommonGuiDisplayContextOffset[3]; + + /** context.c */ + u32 OnXmbPush[3]; + u32 OnXmbContextMenu[3]; + //u32 OnMenuListScrollIn[3]; + + //u32 scePafGetPageChildContext[3]; + + // folder categories patches + u32 current_mode[3]; + u32 categorize_game[3]; + //u32 play_sound[3]; + u32 play_sound_call[3]; + u32 array_index[3]; + u32 add_game_context_call[3][2]; + u32 add_game_context[3]; + u32 setmode_call_arg_1[3][2]; + u32 setmode_call_arg_2[3][2]; + u32 setmode_arg_opcode[3]; + u32 setmode[3]; + u32 on_push_folder_options_call[3]; + u32 on_push_folder_options[3]; + u32 on_push_options_call[3]; + u32 on_push_options[3]; + u32 get_selection[3]; + u32 get_selection_arg[3]; + u32 set_selection_call[3][2]; + int OPTION_BY_CATEGORY[3]; + u32 MODE_BY_EXPIRE_DATE[3]; + u32 struct_addr[3]; + u32 index[3]; + +} GCPatches; + + +enum fw_ver { FW_620, FW_630, FW_660}; + +extern GCPatches patches; +extern int patch_index; + +void ResolveNIDs(); +GCPatches *GetPatches(int fw_group); + +#endif /* GCPATCHES_H_ */ diff --git a/gcread.c b/gcread.c index b0d77ea..07af0f3 100644 --- a/gcread.c +++ b/gcread.c @@ -1,333 +1,333 @@ -/* - * this file is part of Game Categories Lite - * - * Copyright (C) 2011 Codestation - * - * 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 "categories_lite.h" -#include "psppaf.h" -#include "gcpatches.h" -#include "pspdefs.h" -#include "vshitem.h" -#include "config.h" -#include "filter.h" -#include "language.h" -#include "logger.h" - -#define GAME_FOLDER "/PSP/GAME" - -//extern variables -extern Category *folder_list[2]; - -// global vars -char category[52]; - -// unit vars -static SceUID game_dfd = -1; -static SceUID fakefd = -1; -static SceUID realfd = -1; -static SceUID openfd = -1; -static int uncategorized; -static char user_buffer[256]; -static char mod_base[128]; -static char opened_path[128]; - -#ifdef BENCHMARK -u64 start_mtime; -int display_flag; -#endif - -inline void trim(char *str) { - int i = sce_paf_private_strlen(str); - while(str[i-1] == ' ') { - --i; - } - if(str[i] == ' ') { - str[i] = '\0'; - } -} - -int is_category_folder(SceIoDirent *dir) { - kprintf("checking %s\n", dir->d_name); - if(FIO_S_ISDIR(dir->d_stat.st_mode)) { - if(!*category) { - if(config.mode == MODE_FOLDER) { - kprintf("base: %s\n", opened_path); - if(!config.prefix && (*opened_path && !is_game_folder(opened_path, dir->d_name)) && !FindCategory(folder_list, dir->d_name, global_pos)) { - return 1; - } - } else { - if(!config.prefix && FindCategory(cat_list, dir->d_name, global_pos)) { - return 1; - } - } - if(config.prefix && sce_paf_private_strncmp(dir->d_name, "CAT_", 4) == 0) { - return 1; - } - } - if(!config.prefix && sce_paf_private_strcmp(dir->d_name, category) == 0) { - return 1; - } - if(config.prefix && sce_paf_private_strcmp(dir->d_name + 4, category) == 0) { - return 1; - } - } - return 0; -} - - -SceUID sceIoDopenPatched(const char *path) { - SceUID fd = sceIoDopen(path); - - // only make a backup of the opened path if the game folder is opened in uncategorized mode - if (!*category && sce_paf_private_strcmp(path + 4, GAME_FOLDER) == 0) { - sce_paf_private_strcpy(opened_path, path); - } else { - *opened_path = '\0'; - } - - if(config.mode == MODE_FOLDER && sce_paf_private_strcmp(path + 4, GAME_FOLDER) == 0) { -#ifdef BENCHMARK - display_flag = 0; - sceRtcGetCurrentTick(&start_mtime); -#endif - sce_paf_private_strcpy(opened_path, path); - ClearCategories(folder_list, global_pos); - uncategorized = 0; - game_dfd = fd; - } - - kprintf("opened dir, path: [%s], fd: %08X\n", path, fd); - // we are receiving a kernel mode file descriptor - if(fd > 0xFFFF) { - realfd = fd; - sce_paf_private_strncpy(user_buffer, path, 13); - user_buffer[13]= '\0'; - // lets return a dummy fd instead - fakefd = sceIoDopen(user_buffer); - kprintf("Opening fake dir: [%s], fd: %08X\n", user_buffer, fakefd); - fd = fakefd; - } - return fd; -} - -int sceIoDreadPatchedFolder(SceUID fd, SceIoDirent *dir) { - int res; - - if (fd == game_dfd) { - while (1) { - if (openfd >= 0) { - res = sceIoDread(openfd, dir); - if (res > 0) { - if (dir->d_name[0] != '.' && !check_filter(dir->d_name)) { - sce_paf_private_strcpy(dir->d_name + 128, dir->d_name); - sce_paf_private_snprintf(dir->d_name, 128, "%s/%s", user_buffer + 14, dir->d_name + 128); - if (dir->d_private) { - sce_paf_private_strcpy((char *)dir->d_private + 13, dir->d_name); - } - kprintf("B) exit, dir: [%s]\n", dir->d_name); - return res; - } else { - kprintf("C) ignoring [%s]\n", dir->d_name); - continue; - } - } else { - sceIoDclose(openfd); - openfd = -1; - } - } - - res = sceIoDread(fd, dir); - - if (res > 0) { - kprintf("checking %s\n", dir->d_name); - if (dir->d_name[0] != '.') { - if(is_category_folder(dir) && has_directories(opened_path, dir->d_name)) { - u64 mtime; - - kprintf("category match: %s\n", dir->d_name); - sceRtcGetTick((pspTime *) &dir->d_stat.st_mtime, &mtime); - kprintf("Adding %s\n", dir->d_name); - if(AddCategory(folder_list, dir->d_name, mtime, global_pos)) { - sce_paf_private_snprintf(user_buffer, 128, "%s/%s", opened_path, dir->d_name); - openfd = sceIoDopen(user_buffer); - } - continue; - } else { - if (!global_pos && (config.uncategorized & ONLY_MS)) { - uncategorized = 1; - } else if (global_pos && (config.uncategorized & ONLY_IE)) { - uncategorized = 1; - } else { - kprintf("A) ignoring [%s]\n", dir->d_name); - continue; // ignore this Dread - } - if(dir->d_name[0] == '.' || check_filter(dir->d_name) || (*opened_path && !is_game_folder(opened_path, dir->d_name))) { // ignore non game folders - kprintf("B) ignoring [%s]\n", dir->d_name); - continue; - } - } - } - } - if(res > 0) { - kprintf("A) exit, dir: [%s]\n", dir->d_name); - } else { - kprintf("exit, end of directory\n"); - } - return res; - } - } - - return sceIoDread(fd, dir); -} - -int sceIoDreadPatched(SceUID fd, SceIoDirent *dir) { - SceUID ret; - - //if our fake fd is being used then replace it with the kernel one - if(fd == fakefd) { - kprintf("Replacing fakefd: %08X with realfd: %08X\n", fakefd, realfd); - fd = realfd; - } - - while((ret = sceIoDread(fd, dir)) > 0) { - kprintf("read dir: [%s]\n", dir->d_name); - if(!check_filter(dir->d_name) && (*category || !*opened_path || dir->d_name[0] == '.' || is_game_folder(opened_path, dir->d_name))) { - break; - } - } - if(ret <= 0) { - kprintf("end of directory reached\n"); - } - return ret; -} - -int gcGetStatIso(SceIoStat *stat) { - if(config.prefix) { - sce_paf_private_strcpy(user_buffer, "xxx:/ISO/CAT_"); - sce_paf_private_strcpy(user_buffer + 13, category); - } else { - sce_paf_private_strcpy(user_buffer, "xxx:/ISO/"); - sce_paf_private_strcpy(user_buffer + 9, category); - } - SET_DEVICENAME(user_buffer, global_pos); - - // trim away the ME marker (5 spaces at the end of the category) - trim(user_buffer); - - sce_paf_private_memset(stat, 0, sizeof(SceIoStat)); - kprintf("opening [%s]\n", user_buffer); - return sceIoGetstat(user_buffer, stat); -} - -int sceIoGetstatPatched(char *file, SceIoStat *stat) { - int ret; - - kprintf("checking [%s]\n", file); - ret = sceIoGetstat(file, stat); - if(ret < 0 && *category) { - // lets verify if it was trying to open a ISO category - sce_paf_private_strcpy(user_buffer, GAME_FOLDER); - user_buffer[9] = '/'; - if(config.prefix) { - sce_paf_private_strcpy(user_buffer + 10, "CAT_"); - sce_paf_private_strcpy(user_buffer + 14, category); - } else { - sce_paf_private_strcpy(user_buffer + 10, category); - } - kprintf("comparing to [%s]\n", user_buffer); - if(sce_paf_private_strcmp(user_buffer, file + 4) == 0) { - kprintf("tried to open a iso category, retry\n"); - // check if the category exists in /ISO - ret = gcGetStatIso(stat); - kprintf("gcGetStatIso result: %08X\n", ret); - } - } - return ret; -} - -char *ReturnBasePathPatched(char *base) { - kprintf("orig base: [%s]\n", base); - // only do the patch if a category is being accessed - if(*category && base && sce_paf_private_strcmp(base + 4, GAME_FOLDER) == 0) { - sce_paf_private_strcpy(mod_base, base); - //append the category dir if is available and the original path is /PSP/GAME - if(config.prefix) { - sce_paf_private_strcpy(mod_base + 13, "/CAT_"); - sce_paf_private_strcpy(mod_base + 18, category); - } else { - mod_base[13] = '/'; - sce_paf_private_strcpy(mod_base + 14, category); - } - // force the device name - SET_DEVICENAME(mod_base, global_pos); - kprintf("modified base: [%s]\n", mod_base); - base = mod_base; - } - return base; -} - -int sceIoDclosePatched(SceUID fd) { - kprintf("closing dir, fd: %08X\n", fd); - if(config.mode == MODE_FOLDER && fd == game_dfd) { - // add the uncategorized content in folder mode - if(uncategorized) { - AddCategory(folder_list, lang_container.msg_uncategorized, 1, 0); - } - game_dfd = -1; - } - // close the kernel descriptor along the fake one - if(fd == fakefd) { - kprintf("closing realfd: %08X\n", realfd); - sceIoDclose(realfd); - fakefd = -1; - } - return sceIoDclose(fd); -} - -int sce_paf_private_snprintf_patched(char *a0, int a1, const char *a2, void *a3, void *t0) { - sce_paf_private_strcpy((char *)a1, (char *)t0); - return sce_paf_private_snprintf(a0, 291, a2, a3, t0); -} - - -void PatchGamePluginForGCread(u32 text_addr) { - // hook some sceIo funcs - MAKE_STUB(text_addr + patches.io_dread_stub[patch_index], config.mode == MODE_FOLDER ? sceIoDreadPatchedFolder : sceIoDreadPatched); - MAKE_STUB(text_addr + patches.io_dopen_stub[patch_index], sceIoDopenPatched); - MAKE_STUB(text_addr + patches.io_dclose_stub[patch_index], sceIoDclosePatched); - MAKE_STUB(text_addr + patches.io_getstat_stub[patch_index], sceIoGetstatPatched); - - // hook the base path creation - MAKE_JUMP(text_addr + patches.base_path[patch_index], ReturnBasePathPatched); - _sw(0x00602021, text_addr + patches.base_path_arg[patch_index]); // move $a0, $v1 - - /* SCE renames folders before removal, but it doesn't handle - categories in doing so. It will try to move things out of - the category with the rename function... just get rid of - renaming to fix this lame bug. */ - // #1 - MAKE_CALL(text_addr+patches.snprintf_call_arg_1[patch_index][0], sce_paf_private_snprintf_patched); - _sw(0x02402821, text_addr+patches.snprintf_call_arg_1[patch_index][1]); // li $a1, 291 -> move $a1, $s2 - - // #2 - MAKE_CALL(text_addr+patches.snprintf_call_arg_2[patch_index][0], sce_paf_private_snprintf_patched); - _sw(0x02002821, text_addr+patches.snprintf_call_arg_2[patch_index][1]); // li $a1, 291 -> move $a1, $s0 -} +/* + * this file is part of Game Categories Lite + * + * Copyright (C) 2011 Codestation + * + * 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 "categories_lite.h" +#include "psppaf.h" +#include "gcpatches.h" +#include "pspdefs.h" +#include "vshitem.h" +#include "config.h" +#include "filter.h" +#include "language.h" +#include "logger.h" + +#define GAME_FOLDER "/PSP/GAME" + +//extern variables +extern Category *folder_list[2]; + +// global vars +char category[52]; + +// unit vars +static SceUID game_dfd = -1; +static SceUID fakefd = -1; +static SceUID realfd = -1; +static SceUID openfd = -1; +static int uncategorized; +static char user_buffer[256]; +static char mod_base[128]; +static char opened_path[128]; + +#ifdef BENCHMARK +u64 start_mtime; +int display_flag; +#endif + +inline void trim(char *str) { + int i = sce_paf_private_strlen(str); + while(str[i-1] == ' ') { + --i; + } + if(str[i] == ' ') { + str[i] = '\0'; + } +} + +int is_category_folder(SceIoDirent *dir) { + kprintf("checking %s\n", dir->d_name); + if(FIO_S_ISDIR(dir->d_stat.st_mode)) { + if(!*category) { + if(config.mode == MODE_FOLDER) { + kprintf("base: %s\n", opened_path); + if(!config.prefix && (*opened_path && !is_game_folder(opened_path, dir->d_name)) && !FindCategory(folder_list, dir->d_name, global_pos)) { + return 1; + } + } else { + if(!config.prefix && FindCategory(cat_list, dir->d_name, global_pos)) { + return 1; + } + } + if(config.prefix && sce_paf_private_strncmp(dir->d_name, "CAT_", 4) == 0) { + return 1; + } + } + if(!config.prefix && sce_paf_private_strcmp(dir->d_name, category) == 0) { + return 1; + } + if(config.prefix && sce_paf_private_strcmp(dir->d_name + 4, category) == 0) { + return 1; + } + } + return 0; +} + + +SceUID sceIoDopenPatched(const char *path) { + SceUID fd = sceIoDopen(path); + + // only make a backup of the opened path if the game folder is opened in uncategorized mode + if (!*category && sce_paf_private_strcmp(path + 4, GAME_FOLDER) == 0) { + sce_paf_private_strcpy(opened_path, path); + } else { + *opened_path = '\0'; + } + + if(config.mode == MODE_FOLDER && sce_paf_private_strcmp(path + 4, GAME_FOLDER) == 0) { +#ifdef BENCHMARK + display_flag = 0; + sceRtcGetCurrentTick(&start_mtime); +#endif + sce_paf_private_strcpy(opened_path, path); + ClearCategories(folder_list, global_pos); + uncategorized = 0; + game_dfd = fd; + } + + kprintf("opened dir, path: [%s], fd: %08X\n", path, fd); + // we are receiving a kernel mode file descriptor + if(fd > 0xFFFF) { + realfd = fd; + sce_paf_private_strncpy(user_buffer, path, 13); + user_buffer[13]= '\0'; + // lets return a dummy fd instead + fakefd = sceIoDopen(user_buffer); + kprintf("Opening fake dir: [%s], fd: %08X\n", user_buffer, fakefd); + fd = fakefd; + } + return fd; +} + +int sceIoDreadPatchedFolder(SceUID fd, SceIoDirent *dir) { + int res; + + if (fd == game_dfd) { + while (1) { + if (openfd >= 0) { + res = sceIoDread(openfd, dir); + if (res > 0) { + if (dir->d_name[0] != '.' && !check_filter(dir->d_name)) { + sce_paf_private_strcpy(dir->d_name + 128, dir->d_name); + sce_paf_private_snprintf(dir->d_name, 128, "%s/%s", user_buffer + 14, dir->d_name + 128); + if (dir->d_private) { + sce_paf_private_strcpy((char *)dir->d_private + 13, dir->d_name); + } + kprintf("B) exit, dir: [%s]\n", dir->d_name); + return res; + } else { + kprintf("C) ignoring [%s]\n", dir->d_name); + continue; + } + } else { + sceIoDclose(openfd); + openfd = -1; + } + } + + res = sceIoDread(fd, dir); + + if (res > 0) { + kprintf("checking %s\n", dir->d_name); + if (dir->d_name[0] != '.') { + if(is_category_folder(dir) && has_directories(opened_path, dir->d_name)) { + u64 mtime; + + kprintf("category match: %s\n", dir->d_name); + sceRtcGetTick((pspTime *) &dir->d_stat.st_mtime, &mtime); + kprintf("Adding %s\n", dir->d_name); + if(AddCategory(folder_list, dir->d_name, mtime, global_pos)) { + sce_paf_private_snprintf(user_buffer, 128, "%s/%s", opened_path, dir->d_name); + openfd = sceIoDopen(user_buffer); + } + continue; + } else { + if (!global_pos && (config.uncategorized & ONLY_MS)) { + uncategorized = 1; + } else if (global_pos && (config.uncategorized & ONLY_IE)) { + uncategorized = 1; + } else { + kprintf("A) ignoring [%s]\n", dir->d_name); + continue; // ignore this Dread + } + if(dir->d_name[0] == '.' || check_filter(dir->d_name) || (*opened_path && !is_game_folder(opened_path, dir->d_name))) { // ignore non game folders + kprintf("B) ignoring [%s]\n", dir->d_name); + continue; + } + } + } + } + if(res > 0) { + kprintf("A) exit, dir: [%s]\n", dir->d_name); + } else { + kprintf("exit, end of directory\n"); + } + return res; + } + } + + return sceIoDread(fd, dir); +} + +int sceIoDreadPatched(SceUID fd, SceIoDirent *dir) { + SceUID ret; + + //if our fake fd is being used then replace it with the kernel one + if(fd == fakefd) { + kprintf("Replacing fakefd: %08X with realfd: %08X\n", fakefd, realfd); + fd = realfd; + } + + while((ret = sceIoDread(fd, dir)) > 0) { + kprintf("read dir: [%s]\n", dir->d_name); + if(!check_filter(dir->d_name) && (*category || !*opened_path || dir->d_name[0] == '.' || is_game_folder(opened_path, dir->d_name))) { + break; + } + } + if(ret <= 0) { + kprintf("end of directory reached\n"); + } + return ret; +} + +int gcGetStatIso(SceIoStat *stat) { + if(config.prefix) { + sce_paf_private_strcpy(user_buffer, "xxx:/ISO/CAT_"); + sce_paf_private_strcpy(user_buffer + 13, category); + } else { + sce_paf_private_strcpy(user_buffer, "xxx:/ISO/"); + sce_paf_private_strcpy(user_buffer + 9, category); + } + SET_DEVICENAME(user_buffer, global_pos); + + // trim away the ME marker (5 spaces at the end of the category) + trim(user_buffer); + + sce_paf_private_memset(stat, 0, sizeof(SceIoStat)); + kprintf("opening [%s]\n", user_buffer); + return sceIoGetstat(user_buffer, stat); +} + +int sceIoGetstatPatched(char *file, SceIoStat *stat) { + int ret; + + kprintf("checking [%s]\n", file); + ret = sceIoGetstat(file, stat); + if(ret < 0 && *category) { + // lets verify if it was trying to open a ISO category + sce_paf_private_strcpy(user_buffer, GAME_FOLDER); + user_buffer[9] = '/'; + if(config.prefix) { + sce_paf_private_strcpy(user_buffer + 10, "CAT_"); + sce_paf_private_strcpy(user_buffer + 14, category); + } else { + sce_paf_private_strcpy(user_buffer + 10, category); + } + kprintf("comparing to [%s]\n", user_buffer); + if(sce_paf_private_strcmp(user_buffer, file + 4) == 0) { + kprintf("tried to open a iso category, retry\n"); + // check if the category exists in /ISO + ret = gcGetStatIso(stat); + kprintf("gcGetStatIso result: %08X\n", ret); + } + } + return ret; +} + +char *ReturnBasePathPatched(char *base) { + kprintf("orig base: [%s]\n", base); + // only do the patch if a category is being accessed + if(*category && base && sce_paf_private_strcmp(base + 4, GAME_FOLDER) == 0) { + sce_paf_private_strcpy(mod_base, base); + //append the category dir if is available and the original path is /PSP/GAME + if(config.prefix) { + sce_paf_private_strcpy(mod_base + 13, "/CAT_"); + sce_paf_private_strcpy(mod_base + 18, category); + } else { + mod_base[13] = '/'; + sce_paf_private_strcpy(mod_base + 14, category); + } + // force the device name + SET_DEVICENAME(mod_base, global_pos); + kprintf("modified base: [%s]\n", mod_base); + base = mod_base; + } + return base; +} + +int sceIoDclosePatched(SceUID fd) { + kprintf("closing dir, fd: %08X\n", fd); + if(config.mode == MODE_FOLDER && fd == game_dfd) { + // add the uncategorized content in folder mode + if(uncategorized) { + AddCategory(folder_list, lang_container.msg_uncategorized, 1, 0); + } + game_dfd = -1; + } + // close the kernel descriptor along the fake one + if(fd == fakefd) { + kprintf("closing realfd: %08X\n", realfd); + sceIoDclose(realfd); + fakefd = -1; + } + return sceIoDclose(fd); +} + +int sce_paf_private_snprintf_patched(char *a0, int a1, const char *a2, void *a3, void *t0) { + sce_paf_private_strcpy((char *)a1, (char *)t0); + return sce_paf_private_snprintf(a0, 291, a2, a3, t0); +} + + +void PatchGamePluginForGCread(u32 text_addr) { + // hook some sceIo funcs + MAKE_STUB(text_addr + patches.io_dread_stub[patch_index], config.mode == MODE_FOLDER ? sceIoDreadPatchedFolder : sceIoDreadPatched); + MAKE_STUB(text_addr + patches.io_dopen_stub[patch_index], sceIoDopenPatched); + MAKE_STUB(text_addr + patches.io_dclose_stub[patch_index], sceIoDclosePatched); + MAKE_STUB(text_addr + patches.io_getstat_stub[patch_index], sceIoGetstatPatched); + + // hook the base path creation + MAKE_JUMP(text_addr + patches.base_path[patch_index], ReturnBasePathPatched); + _sw(0x00602021, text_addr + patches.base_path_arg[patch_index]); // move $a0, $v1 + + /* SCE renames folders before removal, but it doesn't handle + categories in doing so. It will try to move things out of + the category with the rename function... just get rid of + renaming to fix this lame bug. */ + // #1 + MAKE_CALL(text_addr+patches.snprintf_call_arg_1[patch_index][0], sce_paf_private_snprintf_patched); + _sw(0x02402821, text_addr+patches.snprintf_call_arg_1[patch_index][1]); // li $a1, 291 -> move $a1, $s2 + + // #2 + MAKE_CALL(text_addr+patches.snprintf_call_arg_2[patch_index][0], sce_paf_private_snprintf_patched); + _sw(0x02002821, text_addr+patches.snprintf_call_arg_2[patch_index][1]); // li $a1, 291 -> move $a1, $s0 +} diff --git a/lang/category_lite_bg.txt b/lang/category_lite_bg.txt index 280c083..59a52a3 100644 --- a/lang/category_lite_bg.txt +++ b/lang/category_lite_bg.txt @@ -13,5 +13,9 @@ Мемори Карта ™ Вътрешна памет И двете +Sort categories +Allows sorting categories using CAT_XX or XXhomebrew. +No +Yes Некатегоризирани По категория diff --git a/lang/category_lite_ch1.txt b/lang/category_lite_ch1.txt index 46a9d41..8701c8f 100644 --- a/lang/category_lite_ch1.txt +++ b/lang/category_lite_ch1.txt @@ -1,17 +1,21 @@ -分類模式 -選擇分類的模式與外觀 -記憶卡圖示 -文字選單 -文件夾 -CAT字頭分類 -以「CAT_」作為資料夾開頭命名進行的分類 -不使用 -使用 -未分類顯示 -顯示或隱藏尚未分類的內容 -不顯示 -顯示記憶卡 -顯示主機硬碟 -顯示全部 -未分類 -依原有分類排列 +分類模式 +選擇分類的模式與外觀 +記憶卡圖示 +文字選單 +文件夾 +CAT字頭分類 +以「CAT_」作為資料夾開頭命名進行的分類 +不使用 +使用 +未分類顯示 +顯示或隱藏尚未分類的內容 +不顯示 +顯示記憶卡 +顯示主機硬碟 +顯示全部 +Sort categories +Allows sorting categories using CAT_XX or XXhomebrew. +No +Yes +未分類 +依原有分類排列 diff --git a/lang/category_lite_ch2.txt b/lang/category_lite_ch2.txt index 48c80ab..77872a7 100644 --- a/lang/category_lite_ch2.txt +++ b/lang/category_lite_ch2.txt @@ -1,17 +1,21 @@ -分类模式 -选择显示的分类模式。 -图标 -文字 -文件夹 -文件夹前缀名 -隐藏文件夹"CAT_"前缀名。 -不使用 -使用 -未分类显示方式 -隐藏未分类的内容。 -不显示 -仅显示记忆棒 -仅显示内部存储 -全部显示 -未分类 -按类别 +分类模式 +选择显示的分类模式。 +图标 +文字 +文件夹 +文件夹前缀名 +隐藏文件夹"CAT_"前缀名。 +不使用 +使用 +未分类显示方式 +隐藏未分类的内容。 +不显示 +仅显示记忆棒 +仅显示内部存储 +全部显示 +Sort categories +Allows sorting categories using CAT_XX or XXhomebrew. +No +Yes +未分类 +按类别 diff --git a/lang/category_lite_de.txt b/lang/category_lite_de.txt index 1f7d8af..caf5a81 100644 --- a/lang/category_lite_de.txt +++ b/lang/category_lite_de.txt @@ -13,5 +13,9 @@ Nein Nur MS™ Nur interner Speicher Alle Medien +Sort categories +Allows sorting categories using CAT_XX or XXhomebrew. +No +Yes Unsortierte Nach Kategorie diff --git a/lang/category_lite_en.txt b/lang/category_lite_en.txt index 0c74a53..5bf224a 100644 --- a/lang/category_lite_en.txt +++ b/lang/category_lite_en.txt @@ -13,5 +13,9 @@ No Only Memory Stick™ Only Internal Storage Both +Sort categories +Allows sorting categories using CAT_XX or XXhomebrew. +No +Yes Uncategorized By Category diff --git a/lang/category_lite_es.txt b/lang/category_lite_es.txt index 80d931f..68cbd90 100644 --- a/lang/category_lite_es.txt +++ b/lang/category_lite_es.txt @@ -13,5 +13,9 @@ No Solo Memory Stick™ Solo memoria interna Ambos +Ordenar categorias +Permite organizar categorias usando CAT_XX o XXhomebrew. +No +Si Sin categorizar Por categorias diff --git a/lang/category_lite_it.txt b/lang/category_lite_it.txt index fcad71f..6181d6d 100644 --- a/lang/category_lite_it.txt +++ b/lang/category_lite_it.txt @@ -1,4 +1,4 @@ -Modo visualizzazione +Modo visualizzazione Permette di visualizzare le sottocartelle presenti nella cartella PSP/GAME in diversi modi. Multi MS Menu contestuale @@ -13,5 +13,9 @@ No Solo Memory Stick™ Solo Internal Storage Entrambe +Sort categories +Allows sorting categories using CAT_XX or XXhomebrew. +No +Yes Senza Categoria Per categoria diff --git a/lang/category_lite_ja.txt b/lang/category_lite_ja.txt index 9276533..fd6e8e1 100644 --- a/lang/category_lite_ja.txt +++ b/lang/category_lite_ja.txt @@ -13,5 +13,9 @@ CAT_を使用する メモリースティックのみ 内部ストレージのみ 両方 +Sort categories +Allows sorting categories using CAT_XX or XXhomebrew. +No +Yes 未分類 カテゴリで diff --git a/lang/category_lite_pl.txt b/lang/category_lite_pl.txt index 35d7db2..b14f4f0 100644 --- a/lang/category_lite_pl.txt +++ b/lang/category_lite_pl.txt @@ -13,5 +13,9 @@ Nie pokazuj Karta pamieci Pamiec wewnetrzna Karta i pamiec +Sort categories +Allows sorting categories using CAT_XX or XXhomebrew. +No +Yes Nieskategoryzowane Wedlug kategorii diff --git a/lang/category_lite_ru.txt b/lang/category_lite_ru.txt index 532e452..9d4c6e7 100644 --- a/lang/category_lite_ru.txt +++ b/lang/category_lite_ru.txt @@ -1,17 +1,21 @@ Режим отображения -Selects the the display mode for the Games/Homebrew. +Выберите режим отображения категорий в меню Игра Карты Памяти Контекстное Меню Папки -Префикс для категорий -Use the "CAT_" prefix to recognize the categories. +Префикс для Категорий +Использование префикса "CAT_" для опознавания категорий +Да Нет -Использовать -Показать без категории -Allows hiding the uncategorized content. +Контент вне Категорий +Отображение приложений, не попавших в категории +Не показывать +Карта Памяти +Память Системы +Оба вида +Сортировка Категорий +Сортировка по префиксу CAT_XX или XXhomebrew в названиях категорий Нет -Только Memory Stick™ -Только Память Системы -Оба -Без Категории -К категориям +Да +Без Категорий +По Категориям diff --git a/language.c b/language.c index cdf98da..aa3c5c5 100644 --- a/language.c +++ b/language.c @@ -48,8 +48,9 @@ int LoadLanguageContainer(void *data, int size) { sce_paf_private_free(((char **) &lang_container)[i]); } for (j = 0; j < sce_paf_private_strlen(line); j++) { - if (line[j] == 0x5c) + if (line[j] == 0x5c) { line[j] = '\n'; + } } ((char **) &lang_container)[i] = sce_paf_private_malloc(sce_paf_private_strlen(line) + 1); diff --git a/language.h b/language.h index d7c2003..7e22dfb 100644 --- a/language.h +++ b/language.h @@ -33,6 +33,10 @@ typedef struct { char *msg_show_sub; char *show[4]; + char *msg_sort; + char *msg_sort_sub; + char *sort[2]; + char *msg_uncategorized; char *by_category; diff --git a/main.c b/main.c index 0ace3c2..c80123d 100644 --- a/main.c +++ b/main.c @@ -1,139 +1,139 @@ -/* - * this file is part of Game Categories Lite - * - * Copyright (C) 2011 Bubbletune - * Copyright (C) 2011 Codestation - * - * 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 "categories_lite.h" -#include "psppaf.h" -#include "gcpatches.h" -#include "pspdefs.h" -#include "config.h" -#include "logger.h" - -// change the module name back to GCLite once PRO stops doing weird things with plugins -PSP_MODULE_INFO("Game_Categories_Light", 0x0807, 1, 5); -PSP_NO_CREATE_MAIN_THREAD(); - -/* Global variables */ -int patch_index; -int model; -int game_plug = 0; -int sysconf_plug = 0; - -char currfw[5]; - -//TODO: remove it from here -u32 text_addr_game; -u32 text_size_game; - -static STMOD_HANDLER previous; - -int OnModuleStart(SceModule2 *mod) { - //kprintf(">> %s: loading %s, text_addr: %08X\n", __func__, mod->modname, mod->text_addr); - if (sce_paf_private_strcmp(mod->modname, "game_plugin_module") == 0) { - - kprintf("loading %s, text_addr: %08X\n", mod->modname, mod->text_addr); - game_plug = 1; - - //TODO: remove it from here - text_addr_game = mod->text_addr; - text_size_game = mod->text_size; - - PatchGamePluginForGCread(mod->text_addr); - if(config.mode == MODE_FOLDER) { - PatchSelection(mod->text_addr); - } - ClearCaches(); - - } else if (sce_paf_private_strcmp(mod->modname, "vsh_module") == 0) { - - kprintf("loading %s, text_addr: %08X\n", mod->modname, mod->text_addr); - PatchVshmain(mod->text_addr); - PatchVshmainForSysconf(mod->text_addr); - PatchVshmainForContext(mod->text_addr); - - /* Make sceKernelGetCompiledSdkVersion clear the caches, - so that we don't have to create a kernel module just - to be able to clear the caches from user mode.*/ - - //6.20: 0xFC114573 [0x00009B0C] - SysMemUserForUser_FC114573 - //6.35: 0xFC114573 [0x000099EC] - SysMemUserForUser_FC114573 - //6.60: 0xFC114573 [0x000098B0] - SysMemUserForUser_FC114573 - kprintf("Patching sceKernelGetCompiledSdkVersion, index: %i\n", patch_index); - MAKE_JUMP(patches.get_compiled_sdk_version[patch_index], ClearCaches); - ClearCaches(); - - } else if (sce_paf_private_strcmp(mod->modname, "sysconf_plugin_module") == 0) { - - kprintf("loading %s, text_addr: %08X\n", mod->modname, mod->text_addr); - sysconf_plug = 1; - PatchSysconf(mod->text_addr); - ClearCaches(); - - } else if (sce_paf_private_strcmp(mod->modname, "scePaf_Module") == 0) { - - kprintf("loading %s, text_addr: %08X\n", mod->modname, mod->text_addr); - PatchPaf(mod->text_addr); - PatchPafForSysconf(mod->text_addr); - ClearCaches(); - - } else if (sce_paf_private_strcmp(mod->modname, "sceVshCommonGui_Module") == 0) { - - kprintf("loading %s, text_addr: %08X\n", mod->modname, mod->text_addr); - PatchVshCommonGui(mod->text_addr); - ClearCaches(); - } - - return previous ? previous(mod) : 0; -} - -int module_start(SceSize args UNUSED, void *argp UNUSED) { - const char *src = "xx0:/category_lite.log"; - char *dest = filebuf; - - model = kuKernelGetModel(); - while((*dest++ = *src++)); - SET_DEVICENAME(filebuf, model == 4 ? INTERNAL_STORAGE : MEMORY_STICK); - // paf isn't loaded yet - kwrite(filebuf, "GCLite 1.5 starting\n", 20); - // Determine fw group - u32 devkit = sceKernelDevkitVersion(); - if (devkit == 0x06020010) { - patch_index = FW_620; - ResolveNIDs(FW_620); - } else if (devkit >= 0x06030010 && devkit < 0x06040010) { - patch_index = FW_630; - } else if (devkit >= 0x06060010 && devkit < 0x06070010) { - patch_index = FW_660; - ResolveNIDs(FW_660); - } else { - return 1; - } - - currfw[0] = ((devkit >> 24) & 0xF) + '0'; - currfw[1] = '.'; - currfw[2] = ((devkit >> 16) & 0xF) + '0'; - currfw[3] = ((devkit >> 8) & 0xF) + '0'; - currfw[4] = 0; - - previous = sctrlHENSetStartModuleHandler(OnModuleStart); - return 0; -} +/* + * this file is part of Game Categories Lite + * + * Copyright (C) 2011 Bubbletune + * Copyright (C) 2011 Codestation + * + * 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 "categories_lite.h" +#include "psppaf.h" +#include "gcpatches.h" +#include "pspdefs.h" +#include "config.h" +#include "logger.h" + +// change the module name back to GCLite once PRO stops doing weird things with plugins +PSP_MODULE_INFO("Game_Categories_Light", 0x0807, 1, 5); +PSP_NO_CREATE_MAIN_THREAD(); + +/* Global variables */ +int patch_index; +int model; +int game_plug = 0; +int sysconf_plug = 0; + +char currfw[5]; + +//TODO: remove it from here +u32 text_addr_game; +u32 text_size_game; + +static STMOD_HANDLER previous; + +int OnModuleStart(SceModule2 *mod) { + //kprintf(">> %s: loading %s, text_addr: %08X\n", __func__, mod->modname, mod->text_addr); + if (sce_paf_private_strcmp(mod->modname, "game_plugin_module") == 0) { + + kprintf("loading %s, text_addr: %08X\n", mod->modname, mod->text_addr); + game_plug = 1; + + //TODO: remove it from here + text_addr_game = mod->text_addr; + text_size_game = mod->text_size; + + PatchGamePluginForGCread(mod->text_addr); + if(config.mode == MODE_FOLDER) { + PatchSelection(mod->text_addr); + } + ClearCaches(); + + } else if (sce_paf_private_strcmp(mod->modname, "vsh_module") == 0) { + + kprintf("loading %s, text_addr: %08X\n", mod->modname, mod->text_addr); + PatchVshmain(mod->text_addr); + PatchVshmainForSysconf(mod->text_addr); + PatchVshmainForContext(mod->text_addr); + + /* Make sceKernelGetCompiledSdkVersion clear the caches, + so that we don't have to create a kernel module just + to be able to clear the caches from user mode.*/ + + //6.20: 0xFC114573 [0x00009B0C] - SysMemUserForUser_FC114573 + //6.35: 0xFC114573 [0x000099EC] - SysMemUserForUser_FC114573 + //6.60: 0xFC114573 [0x000098B0] - SysMemUserForUser_FC114573 + kprintf("Patching sceKernelGetCompiledSdkVersion, index: %i\n", patch_index); + MAKE_JUMP(patches.get_compiled_sdk_version[patch_index], ClearCaches); + ClearCaches(); + + } else if (sce_paf_private_strcmp(mod->modname, "sysconf_plugin_module") == 0) { + + kprintf("loading %s, text_addr: %08X\n", mod->modname, mod->text_addr); + sysconf_plug = 1; + PatchSysconf(mod->text_addr); + ClearCaches(); + + } else if (sce_paf_private_strcmp(mod->modname, "scePaf_Module") == 0) { + + kprintf("loading %s, text_addr: %08X\n", mod->modname, mod->text_addr); + PatchPaf(mod->text_addr); + PatchPafForSysconf(mod->text_addr); + ClearCaches(); + + } else if (sce_paf_private_strcmp(mod->modname, "sceVshCommonGui_Module") == 0) { + + kprintf("loading %s, text_addr: %08X\n", mod->modname, mod->text_addr); + PatchVshCommonGui(mod->text_addr); + ClearCaches(); + } + + return previous ? previous(mod) : 0; +} + +int module_start(SceSize args UNUSED, void *argp UNUSED) { + const char *src = "xx0:/category_lite.log"; + char *dest = filebuf; + + model = kuKernelGetModel(); + while((*dest++ = *src++)); + SET_DEVICENAME(filebuf, model == 4 ? INTERNAL_STORAGE : MEMORY_STICK); + // paf isn't loaded yet + kwrite(filebuf, "Game Categories Lite v1.7-js1 starting\n", 20); + // Determine fw group + u32 devkit = sceKernelDevkitVersion(); + if (devkit == 0x06020010) { + patch_index = FW_620; + ResolveNIDs(FW_620); + } else if (devkit >= 0x06030010 && devkit < 0x06040010) { + patch_index = FW_630; + } else if (devkit >= 0x06060010 && devkit < 0x06070010) { + patch_index = FW_660; + ResolveNIDs(FW_660); + } else { + return 1; + } + + currfw[0] = ((devkit >> 24) & 0xF) + '0'; + currfw[1] = '.'; + currfw[2] = ((devkit >> 16) & 0xF) + '0'; + currfw[3] = ((devkit >> 8) & 0xF) + '0'; + currfw[4] = 0; + + previous = sctrlHENSetStartModuleHandler(OnModuleStart); + return 0; +} diff --git a/mode.c b/mode.c index 91ac6dc..6c117a8 100644 --- a/mode.c +++ b/mode.c @@ -1,394 +1,399 @@ -/* - Game Categories Light v 1.3 - Copyright (C) 2011, Bubbletune - - 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 "psppaf.h" -#include -#include "categories_lite.h" -#include "vshitem.h" -#include "utils.h" -#include "logger.h" - -typedef struct { - u32 addr; - u32 opcode; -} ToggleCategoryPatch; - -/* Function pointers */ -static int (*CategorizeGame)(void *unk, int folder, int unk2); - -/* Global variables */ -extern char currfw[5]; -int by_category_mode; -extern u32 text_addr_game, text_size_game; -//static void *GetSelectionArg; -static void *class_buffer = NULL; -extern char user_buffer[256]; - -Category *folder_list[2] = { NULL, NULL }; - -#ifdef BENCHMARK -extern u64 start_mtime; -u64 now_mtime; -double benchmark_result; -extern int display_flag; -#endif - -static int (*scePafAddGameItems)(void *unk, int count, void *unk2); - -/* Functions */ -int CategorizeGamePatched(void *unk, int folder, int unk2) { - int i; - u32 *array = (u32 *) *(u32 *) ((*(u32 *) (text_addr_game + patches.struct_addr[patch_index])) + ((u32) folder << 2)); - char *title = (char *) array[68 / 4]; - kprintf("called\n"); - Category *p = GetNextCategory(folder_list, NULL, global_pos); - - for (i = patches.index[patch_index]; p; i++) { - char *name = &p->name; - kprintf("name: %s\n", name); - int len = sce_paf_private_strlen(name); - - if (sce_paf_private_strncmp(name, title, len) == 0) { - if (title[len] == '/') { - return CategorizeGame(unk, i, unk2); - } - } - - p = GetNextCategory(folder_list, p, 0); - } - - /* uncategorized */ - return CategorizeGame(unk, i - 1, unk2); -} - -int scePafAddGameItemsPatched(void *unk, int count, void *unk2) { - kprintf("called, count: %i\n", count); - if(count == 3) { - count = CountCategories(folder_list, global_pos); - } - return scePafAddGameItems(unk, count, unk2); -} - -wchar_t* GetGameSubtitle(void *arg0 UNUSED, SfoInfo *sfo) { - const char *game_type; - char subtitle[128]; - char firmware[5]; - char *sfofirm, *sfocat, *sfocode; - - sfofirm = patch_index ? sfo->sfo630.firmware : sfo->sfo620.firmware; - sfocat = patch_index ? sfo->sfo630.category : sfo->sfo620.category; - sfocode = patch_index ? sfo->sfo630.gamecode: sfo->sfo620.gamecode; - - kprintf("called\n"); - - sce_paf_private_strcpy(firmware, sfofirm); - - if (sce_paf_private_strcmp(sfocat, "EG") == 0) { - game_type = "PSN Game"; - - if (sfofirm[0] == 0) { - sce_paf_private_strcpy(firmware, "5.00"); - } - } else if (sce_paf_private_strcmp(sfocat, "ME") == 0) { - game_type = "PS1 Game"; - - if (sfofirm[0] == 0) { - sce_paf_private_strcpy(firmware, "3.03"); - } - } else { - if (sfocode[0] == 0 || sce_paf_private_strcmp(sfocode, "UCJS10041") == 0) { - game_type = "Homebrew Game"; - sce_paf_private_strcpy(firmware, "2.71"); - } else { - game_type = "Game"; - - if (sfofirm[0] == 0) { - sce_paf_private_strcpy(firmware, "1.00"); - } - } - } - - if (firmware[0] >= currfw[0] && firmware[2] >= currfw[2] && firmware[3] >= currfw[3]) { - sce_paf_private_snprintf(subtitle, 128, "%s (requires %s)", game_type, firmware); - } else { - sce_paf_private_snprintf(subtitle, 128, "%s (for %s - %s)", game_type, firmware, currfw); - } - -#ifdef BENCHMARK - sce_paf_private_snprintf(subtitle, 128, "Benchmark result: %.4f seconds", benchmark_result); -#endif - - kprintf("Returning %s\n", subtitle); - gc_utf8_to_unicode((wchar_t*)user_buffer, subtitle); - return (wchar_t*)user_buffer; -} - -wchar_t *GetCategoryTitle(int number) { - char *name; - -#ifdef BENCHMARK - if(!display_flag) { - sceRtcGetCurrentTick(&now_mtime); - benchmark_result = (double)(now_mtime - start_mtime) / sceRtcGetTickResolution(); - display_flag = 1; - } -#endif - - kprintf("called, number: %i\n", number); - Category *p = GetNextCategory(folder_list, NULL, global_pos); - - for (int i = patches.index[patch_index]; p; i++) { - if (i == number) { - name = &p->name; - kprintf("Found category: %s\n", name); - if(sce_paf_private_strncmp(&p->name, "CAT_", 4) == 0) { - name += 4; - } - gc_utf8_to_unicode((wchar_t *) user_buffer, name); - return (wchar_t *) user_buffer; - } - - p = GetNextCategory(folder_list, p, global_pos); - } - kprintf("Cannot find title\n"); - return NULL; -} - -void HijackGameClass(int items) { - if (patch_index) { - // SCE made it a little more dynamic in 6.30+, so this hack is no longer needed :) - return; - } - - /* There's a class inside game_plugin_module that is way to small for - all the crap we want to do. We need to take control of it to supply - a buffer of the size we really want. */ - - u32 text_addr = text_addr_game; - u32 text_end = text_addr + text_size_game; - int size = 816 + (items * 12); - - /* Allocate the buffer */ - if (class_buffer) { - sce_paf_private_free(class_buffer); - } - - class_buffer = sce_paf_private_malloc(size); - - void *original = (void *) (text_addr + 0x2C8E8); - - /* Copy the original to the buffer */ - sce_paf_private_memset(class_buffer, 0, size); - - /* Set a pointer to the buffer */ - *(void **) original = class_buffer; - - /* Patch the size */ - _sh(items - 1, text_addr + 0x197D4); - _sh(items - 1, text_addr + 0x19ECC); - - /* Hijack the opcodes */ - u32 code = 0x24000000 | ((u32) original & 0xFFFF); - - for (; text_addr < text_end; text_addr += 4) { - u32 read = _lw(text_addr); - - /* Check for addiu */ - if ((read & 0xFC00FFFF) == code) { - /* Check if the registers are not $zero */ - if ((read & 0x03E00000) && (read & 0x001F0000)) { - /* addiu -> lw */ - _sw((read & 0x03FFFFFF) | 0x8C000000, text_addr); - } - } - } -} - -ToggleCategoryPatch ToggleCategoryPatches_620[] = { - /* Force the branch to "msgvideoms_info_expired" */ - { 0x0000EBF0, 0x100000C7 }, // beq $s2, $v0, loc_EF10 -> b loc_EF10 - { 0x00011EA4, 0x10000065 }, // beq $v1, $v0, loc_1203C -> b loc_1203C - - /* Move a value we need later to a callee-saved register */ - { 0x00012040, 0x00608821 }, // lw $a0, 4($v0) -> move $s1, $v1 - - /* Patch the call of scePafGetText to GetCategoryTitle */ - { 0x0000EF1C, (u32) GetCategoryTitle }, // jal scePaf_CB608DE5 -> jal GetCategoryTitle - { 0x0000EF20, 0x26440001 }, // addiu $a1, $a1, -21896 -> addiu $a0, $s2, 1 - { 0x00012048, (u32) GetCategoryTitle }, // jal scePaf_CB608DE5 -> jal GetCategoryTitle - { 0x0001204C, 0x26240001 }, // addiu $a1, $a1, -21896 -> addiu $a0, $s1, 1 - - /* Patch a usually hardcoded value to a dynamic one from earlier in the code */ - { 0x0000EF34, 0x26450001 }, // li $a1, 2 -> addiu $a1, $s2, 1 - { 0x00012060, 0x26250001 }, // li $a1, 2 -> addiu $a1, $s1, 1 - - /* Force a branch to be taken regardless of the timelimit situation */ - { 0x00001524, 0x10000012 }, // beqz $v0, loc_1570 -> b loc_1570 - - /* Change a call for hardcoded organization to our own category-based one */ - { 0x0001570, (u32) CategorizeGamePatched }, // jal sub_19B5C -> jal CategorizeGamePatched - { 0x0001528, 0x8E050004 }, // move $a1, $zr -> lw $a1, 4($s0) - - /* Force a branch to be taken regardless of the timelimit situation */ - { 0x0000A52C, 0x100000DC }, // beqz $v0, loc_A8A0 -> b loc_A8A0 - - /* Patch the call of scePafGetText to GetGameSubtitle */ - { 0x0000A8AC, (u32) GetGameSubtitle }, // jal scePaf_CB608DE5 -> jal GetGameSubtitle - { 0x0000A8B0, 0x02402821 }, // addiu $a1, $a1, -21952 -> move $a1, $s2 - - /* Patch the call of scePafAddGameItems to change the number */ - { 0x0000DC38, (u32) scePafAddGameItemsPatched }, // jal scePaf_FBC4392D -> jal scePafAddGameItemsPatched - - /* Patch some checks regarding the number of folders */ - { 0x00019940, 0x00000000 }, { 0x00019A18, 0x00000000 }, { 0x00019AE8, 0x00000000 }, { 0x00019B94, 0x10000006 }, -}; - -ToggleCategoryPatch ToggleCategoryPatches_63x[] = { - /* Change the mode to 'All' in order to avoid all the mess and get to categorizing immediatly */ - { 0x000014C8, 0x10000027 }, // beqz $v1, loc_1568 -> b loc_1568 - - /* Change a call for hardcoded organization to our own category-based one */ - { 0x00001568, (u32) CategorizeGamePatched }, // jal sub_1ABF4 -> jal CategorizeGamePatched - { 0x000014CC, 0x8E050004 }, // li $a1, -1 -> lw $a1, 4($s0) - - /* Patch the call of scePafAddGameItems to change the number */ - { 0x0000E98C, (u32) scePafAddGameItemsPatched }, // jal scePaf_FBC4392D -> jal scePafAddGameItemsPatched - - /* Force the branch to "msgvideoms_info_expired" */ - { 0x0000FDE4, 0x10000019 }, // beq $s3, $v0, loc_FE4C -> b loc_FE4C - { 0x0001288C, 0x1000001B }, // beq $a0, $v0, loc_128FC -> b loc_128FC - - /* Move a value we need later to a callee-saved register */ - { 0x00012900, 0x00809821 }, // lw $a0, 4($v0) -> move $s3, $a0 - - /* Patch the call of scePafGetText to GetCategoryTitle */ - { 0x00012908, (u32) GetCategoryTitle }, // jal scePaf_70082F6F -> jal GetCategoryTitle - { 0x0001290C, 0x02602021 }, // addiu $a1, $a1, -13004 -> move $a0, $s3 - { 0x0000FE54, (u32) GetCategoryTitle }, // jal scePaf_70082F6F -> jal GetCategoryTitle - { 0x0000FE58, 0x02602021 }, // addiu $a1, $a1, -13716 -> move $a0, $s3 - - /* Patch a usually hardcoded value to a dynamic one from earlier in the code */ - /* Where it gets subtitle from? ;-) */ - { 0x00012920, 0x02602821 }, // li $a1, 1 -> move $a1, $s3 - { 0x0000FE6C, 0x02602821 }, // li $a1, 1 -> move $a1, $s3 - - /* Force a branch to be taken regardless of the timelimit situation */ - { 0x0000A0AC, 0x100000D8 }, // beqz $v0, loc_A410 -> b loc_A410 - - /* Patch the call of scePafGetText to GetGameSubtitle */ - { 0x0000A420, (u32) GetGameSubtitle }, // jal scePaf_CB608DE5 -> jal GetGameSubtitle - { 0x0000A424, 0x02602821 }, // addiu $a1, $a1, -21952 -> move $a1, $s3 -}; - -ToggleCategoryPatch ToggleCategoryPatches_66x[] = { - /* Change the mode to 'All' in order to avoid all the mess and get to categorizing immediatly */ - { 0x000014C8, 0x10000027 }, // beqz $v1, loc_1568 -> b loc_1568 - - /* Change a call for hardcoded organization to our own category-based one */ - { 0x00001568, (u32) CategorizeGamePatched }, // jal sub_1AE10 -> jal CategorizeGamePatched - { 0x000014CC, 0x8E050004 }, // li $a1, -1 -> lw $a1, 4($s0) - - /* Patch the call of scePafAddGameItems to change the number */ - { 0x0000EB10, (u32) scePafAddGameItemsPatched }, // jal scePaf_E219FD72 -> jal scePafAddGameItemsPatched - - /* Force the branch to "msgvideoms_info_expired" */ - { 0x0000FF68, 0x10000019 }, // beq $s3, $v0, loc_FE4C -> b loc_FFD0 - { 0x00012A6C, 0x1000001B }, // beq $a0, $v0, loc_128FC -> b loc_12ADC - - /* Move a value we need later to a callee-saved register */ - { 0x00012AE0, 0x00809821 }, // lw $a0, 4($v0) -> move $s3, $a0 - - /* Patch the call of scePafGetText to GetCategoryTitle */ - { 0x00012AE8, (u32) GetCategoryTitle }, // jal scePaf_3874A5F8 -> jal GetCategoryTitle - { 0x00012AEC, 0x02602021 }, // addiu $a1, $a1, -12268 -> move $a0, $s3 - { 0x0000FFD8, (u32) GetCategoryTitle }, // jal scePaf_3874A5F8 -> jal GetCategoryTitle - { 0x0000FFDC, 0x02602021 }, // addiu $a1, $a1, -13828 -> move $a0, $s3 - - /* Patch a usually hardcoded value to a dynamic one from earlier in the code */ - /* Where it gets subtitle from? ;-) */ - { 0x00012B00, 0x02602821 }, // li $a1, 1 -> move $a1, $s3 - { 0x0000FFF0, 0x02602821 }, // li $a1, 1 -> move $a1, $s3 - - /* Force a branch to be taken regardless of the timelimit situation */ - { 0x0000A230, 0x100000D8 }, // beqz $v0, loc_A594 -> b loc_A594 - - /* Patch the call of scePafGetText to GetGameSubtitle */ - { 0x0000A5A4, (u32) GetGameSubtitle }, // jal scePaf_3874A5F8 -> jal GetGameSubtitle - { 0x0000A5A8, 0x02602821 }, // addiu $a1, $a1, -13876 -> move $a1, $s3 -}; - -static u32 backup[sizeof(ToggleCategoryPatches_620) / sizeof(ToggleCategoryPatch)]; - -int ToggleCategoryMode(int mode) { - int total; - ToggleCategoryPatch *ToggleCategoryPatches; - - kprintf("called, mode: %i\n", mode); - - if (patch_index == 0) { - ToggleCategoryPatches = ToggleCategoryPatches_620; - total = sizeof(ToggleCategoryPatches_620) / sizeof(ToggleCategoryPatch); - } else if (patch_index == 1) { - ToggleCategoryPatches = ToggleCategoryPatches_63x; - total = sizeof(ToggleCategoryPatches_63x) / sizeof(ToggleCategoryPatch); - } else if (patch_index == 2) { - ToggleCategoryPatches = ToggleCategoryPatches_66x; - total = sizeof(ToggleCategoryPatches_66x) / sizeof(ToggleCategoryPatch); - - } else { - return -1; - } - - kprintf("text_addr: %08X\n", text_addr_game); - if (by_category_mode == 0 && mode == 1) { - by_category_mode = 1; - for (int i = 0; i < total; i++) { - u32 addr = text_addr_game + ToggleCategoryPatches[i].addr; - u32 opcode = ToggleCategoryPatches[i].opcode; - backup[i] = _lw(addr); - if ((opcode & 0xFF000000) == 0x08000000) { - if(opcode == (u32)scePafAddGameItemsPatched) { - scePafAddGameItems = (void *)U_EXTRACT_CALL(addr); - } else if(opcode == (u32)CategorizeGamePatched) { - CategorizeGame = (void *)U_EXTRACT_CALL(addr); - } - MAKE_CALL(addr, opcode); - } else { - _sw(opcode, addr); - } - } - ClearCachesForUser(); - return 0; - } - - else if (by_category_mode == 1 && mode == 0) { - by_category_mode = 0; - - for (int i = 0; i < total; i++) { - kprintf("restoring backup[%i] == %08X, to addr %08X\n", i, backup[i], text_addr_game + ToggleCategoryPatches[i].addr); - _sw(backup[i], text_addr_game + ToggleCategoryPatches[i].addr); - } - ClearCachesForUser(); - - return 0; - } - return -1; -} +/* + Game Categories Light v 1.3 + Copyright (C) 2011, Bubbletune + + 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 "psppaf.h" +#include +#include "categories_lite.h" +#include "vshitem.h" +#include "utils.h" +#include "logger.h" +#include "config.h" + +typedef struct { + u32 addr; + u32 opcode; +} ToggleCategoryPatch; + +/* Function pointers */ +static int (*CategorizeGame)(void *unk, int folder, int unk2); + +/* Global variables */ +extern char currfw[5]; +int by_category_mode; +extern u32 text_addr_game, text_size_game; +//static void *GetSelectionArg; +static void *class_buffer = NULL; +extern char user_buffer[256]; + +Category *folder_list[2] = { NULL, NULL }; + +#ifdef BENCHMARK +extern u64 start_mtime; +u64 now_mtime; +double benchmark_result; +extern int display_flag; +#endif + +static int (*scePafAddGameItems)(void *unk, int count, void *unk2); + +/* Functions */ +int CategorizeGamePatched(void *unk, int folder, int unk2) { + int i; + u32 *array = (u32 *) *(u32 *) ((*(u32 *) (text_addr_game + patches.struct_addr[patch_index])) + ((u32) folder << 2)); + char *title = (char *) array[68 / 4]; + kprintf("called\n"); + Category *p = GetNextCategory(folder_list, NULL, global_pos); + + for (i = patches.index[patch_index]; p; i++) { + char *name = &p->name; + kprintf("name: %s\n", name); + int len = sce_paf_private_strlen(name); + + if (sce_paf_private_strncmp(name, title, len) == 0) { + if (title[len] == '/') { + return CategorizeGame(unk, i, unk2); + } + } + + p = GetNextCategory(folder_list, p, 0); + } + + /* uncategorized */ + return CategorizeGame(unk, i - 1, unk2); +} + +int scePafAddGameItemsPatched(void *unk, int count, void *unk2) { + kprintf("called, count: %i\n", count); + if(count == 3) { + count = CountCategories(folder_list, global_pos); + } + return scePafAddGameItems(unk, count, unk2); +} + +wchar_t* GetGameSubtitle(void *arg0 UNUSED, SfoInfo *sfo) { + const char *game_type; + char subtitle[128]; + char firmware[5]; + char *sfofirm, *sfocat, *sfocode; + + sfofirm = patch_index ? sfo->sfo630.firmware : sfo->sfo620.firmware; + sfocat = patch_index ? sfo->sfo630.category : sfo->sfo620.category; + sfocode = patch_index ? sfo->sfo630.gamecode: sfo->sfo620.gamecode; + + kprintf("called\n"); + + sce_paf_private_strcpy(firmware, sfofirm); + + if (sce_paf_private_strcmp(sfocat, "EG") == 0) { + game_type = "PSN Game"; + + if (sfofirm[0] == 0) { + sce_paf_private_strcpy(firmware, "5.00"); + } + } else if (sce_paf_private_strcmp(sfocat, "ME") == 0) { + game_type = "PS1 Game"; + + if (sfofirm[0] == 0) { + sce_paf_private_strcpy(firmware, "3.03"); + } + } else { + if (sfocode[0] == 0 || sce_paf_private_strcmp(sfocode, "UCJS10041") == 0) { + game_type = "Homebrew Game"; + sce_paf_private_strcpy(firmware, "2.71"); + } else { + game_type = "Game"; + + if (sfofirm[0] == 0) { + sce_paf_private_strcpy(firmware, "1.00"); + } + } + } + + if (firmware[0] >= currfw[0] && firmware[2] >= currfw[2] && firmware[3] >= currfw[3]) { + sce_paf_private_snprintf(subtitle, 128, "%s (requires %s)", game_type, firmware); + } else { + sce_paf_private_snprintf(subtitle, 128, "%s (for %s - %s)", game_type, firmware, currfw); + } + +#ifdef BENCHMARK + sce_paf_private_snprintf(subtitle, 128, "Benchmark result: %.4f seconds", benchmark_result); +#endif + + kprintf("Returning %s\n", subtitle); + gc_utf8_to_unicode((wchar_t*)user_buffer, subtitle); + return (wchar_t*)user_buffer; +} + +wchar_t *GetCategoryTitle(int number) { + char *name; + +#ifdef BENCHMARK + if(!display_flag) { + sceRtcGetCurrentTick(&now_mtime); + benchmark_result = (double)(now_mtime - start_mtime) / sceRtcGetTickResolution(); + display_flag = 1; + } +#endif + + kprintf("called, number: %i\n", number); + Category *p = GetNextCategory(folder_list, NULL, global_pos); + + for (int i = patches.index[patch_index]; p; i++) { + if (i == number) { + name = &p->name; + kprintf("Found category: %s\n", name); + if(sce_paf_private_strncmp(&p->name, "CAT_", 4) == 0) { + name += 4; + } + if(config.catsort && p->mtime != 1) { + gc_utf8_to_unicode((wchar_t *) user_buffer, name+2); + } else { + gc_utf8_to_unicode((wchar_t *) user_buffer, name); + } + return (wchar_t *) user_buffer; + } + + p = GetNextCategory(folder_list, p, global_pos); + } + kprintf("Cannot find title\n"); + return NULL; +} + +void HijackGameClass(int items) { + if (patch_index) { + // SCE made it a little more dynamic in 6.30+, so this hack is no longer needed :) + return; + } + + /* There's a class inside game_plugin_module that is way to small for + all the crap we want to do. We need to take control of it to supply + a buffer of the size we really want. */ + + u32 text_addr = text_addr_game; + u32 text_end = text_addr + text_size_game; + int size = 816 + (items * 12); + + /* Allocate the buffer */ + if (class_buffer) { + sce_paf_private_free(class_buffer); + } + + class_buffer = sce_paf_private_malloc(size); + + void *original = (void *) (text_addr + 0x2C8E8); + + /* Copy the original to the buffer */ + sce_paf_private_memset(class_buffer, 0, size); + + /* Set a pointer to the buffer */ + *(void **) original = class_buffer; + + /* Patch the size */ + _sh(items - 1, text_addr + 0x197D4); + _sh(items - 1, text_addr + 0x19ECC); + + /* Hijack the opcodes */ + u32 code = 0x24000000 | ((u32) original & 0xFFFF); + + for (; text_addr < text_end; text_addr += 4) { + u32 read = _lw(text_addr); + + /* Check for addiu */ + if ((read & 0xFC00FFFF) == code) { + /* Check if the registers are not $zero */ + if ((read & 0x03E00000) && (read & 0x001F0000)) { + /* addiu -> lw */ + _sw((read & 0x03FFFFFF) | 0x8C000000, text_addr); + } + } + } +} + +ToggleCategoryPatch ToggleCategoryPatches_620[] = { + /* Force the branch to "msgvideoms_info_expired" */ + { 0x0000EBF0, 0x100000C7 }, // beq $s2, $v0, loc_EF10 -> b loc_EF10 + { 0x00011EA4, 0x10000065 }, // beq $v1, $v0, loc_1203C -> b loc_1203C + + /* Move a value we need later to a callee-saved register */ + { 0x00012040, 0x00608821 }, // lw $a0, 4($v0) -> move $s1, $v1 + + /* Patch the call of scePafGetText to GetCategoryTitle */ + { 0x0000EF1C, (u32) GetCategoryTitle }, // jal scePaf_CB608DE5 -> jal GetCategoryTitle + { 0x0000EF20, 0x26440001 }, // addiu $a1, $a1, -21896 -> addiu $a0, $s2, 1 + { 0x00012048, (u32) GetCategoryTitle }, // jal scePaf_CB608DE5 -> jal GetCategoryTitle + { 0x0001204C, 0x26240001 }, // addiu $a1, $a1, -21896 -> addiu $a0, $s1, 1 + + /* Patch a usually hardcoded value to a dynamic one from earlier in the code */ + { 0x0000EF34, 0x26450001 }, // li $a1, 2 -> addiu $a1, $s2, 1 + { 0x00012060, 0x26250001 }, // li $a1, 2 -> addiu $a1, $s1, 1 + + /* Force a branch to be taken regardless of the timelimit situation */ + { 0x00001524, 0x10000012 }, // beqz $v0, loc_1570 -> b loc_1570 + + /* Change a call for hardcoded organization to our own category-based one */ + { 0x0001570, (u32) CategorizeGamePatched }, // jal sub_19B5C -> jal CategorizeGamePatched + { 0x0001528, 0x8E050004 }, // move $a1, $zr -> lw $a1, 4($s0) + + /* Force a branch to be taken regardless of the timelimit situation */ + { 0x0000A52C, 0x100000DC }, // beqz $v0, loc_A8A0 -> b loc_A8A0 + + /* Patch the call of scePafGetText to GetGameSubtitle */ + { 0x0000A8AC, (u32) GetGameSubtitle }, // jal scePaf_CB608DE5 -> jal GetGameSubtitle + { 0x0000A8B0, 0x02402821 }, // addiu $a1, $a1, -21952 -> move $a1, $s2 + + /* Patch the call of scePafAddGameItems to change the number */ + { 0x0000DC38, (u32) scePafAddGameItemsPatched }, // jal scePaf_FBC4392D -> jal scePafAddGameItemsPatched + + /* Patch some checks regarding the number of folders */ + { 0x00019940, 0x00000000 }, { 0x00019A18, 0x00000000 }, { 0x00019AE8, 0x00000000 }, { 0x00019B94, 0x10000006 }, +}; + +ToggleCategoryPatch ToggleCategoryPatches_63x[] = { + /* Change the mode to 'All' in order to avoid all the mess and get to categorizing immediatly */ + { 0x000014C8, 0x10000027 }, // beqz $v1, loc_1568 -> b loc_1568 + + /* Change a call for hardcoded organization to our own category-based one */ + { 0x00001568, (u32) CategorizeGamePatched }, // jal sub_1ABF4 -> jal CategorizeGamePatched + { 0x000014CC, 0x8E050004 }, // li $a1, -1 -> lw $a1, 4($s0) + + /* Patch the call of scePafAddGameItems to change the number */ + { 0x0000E98C, (u32) scePafAddGameItemsPatched }, // jal scePaf_FBC4392D -> jal scePafAddGameItemsPatched + + /* Force the branch to "msgvideoms_info_expired" */ + { 0x0000FDE4, 0x10000019 }, // beq $s3, $v0, loc_FE4C -> b loc_FE4C + { 0x0001288C, 0x1000001B }, // beq $a0, $v0, loc_128FC -> b loc_128FC + + /* Move a value we need later to a callee-saved register */ + { 0x00012900, 0x00809821 }, // lw $a0, 4($v0) -> move $s3, $a0 + + /* Patch the call of scePafGetText to GetCategoryTitle */ + { 0x00012908, (u32) GetCategoryTitle }, // jal scePaf_70082F6F -> jal GetCategoryTitle + { 0x0001290C, 0x02602021 }, // addiu $a1, $a1, -13004 -> move $a0, $s3 + { 0x0000FE54, (u32) GetCategoryTitle }, // jal scePaf_70082F6F -> jal GetCategoryTitle + { 0x0000FE58, 0x02602021 }, // addiu $a1, $a1, -13716 -> move $a0, $s3 + + /* Patch a usually hardcoded value to a dynamic one from earlier in the code */ + /* Where it gets subtitle from? ;-) */ + { 0x00012920, 0x02602821 }, // li $a1, 1 -> move $a1, $s3 + { 0x0000FE6C, 0x02602821 }, // li $a1, 1 -> move $a1, $s3 + + /* Force a branch to be taken regardless of the timelimit situation */ + { 0x0000A0AC, 0x100000D8 }, // beqz $v0, loc_A410 -> b loc_A410 + + /* Patch the call of scePafGetText to GetGameSubtitle */ + { 0x0000A420, (u32) GetGameSubtitle }, // jal scePaf_CB608DE5 -> jal GetGameSubtitle + { 0x0000A424, 0x02602821 }, // addiu $a1, $a1, -21952 -> move $a1, $s3 +}; + +ToggleCategoryPatch ToggleCategoryPatches_66x[] = { + /* Change the mode to 'All' in order to avoid all the mess and get to categorizing immediatly */ + { 0x000014C8, 0x10000027 }, // beqz $v1, loc_1568 -> b loc_1568 + + /* Change a call for hardcoded organization to our own category-based one */ + { 0x00001568, (u32) CategorizeGamePatched }, // jal sub_1AE10 -> jal CategorizeGamePatched + { 0x000014CC, 0x8E050004 }, // li $a1, -1 -> lw $a1, 4($s0) + + /* Patch the call of scePafAddGameItems to change the number */ + { 0x0000EB10, (u32) scePafAddGameItemsPatched }, // jal scePaf_E219FD72 -> jal scePafAddGameItemsPatched + + /* Force the branch to "msgvideoms_info_expired" */ + { 0x0000FF68, 0x10000019 }, // beq $s3, $v0, loc_FE4C -> b loc_FFD0 + { 0x00012A6C, 0x1000001B }, // beq $a0, $v0, loc_128FC -> b loc_12ADC + + /* Move a value we need later to a callee-saved register */ + { 0x00012AE0, 0x00809821 }, // lw $a0, 4($v0) -> move $s3, $a0 + + /* Patch the call of scePafGetText to GetCategoryTitle */ + { 0x00012AE8, (u32) GetCategoryTitle }, // jal scePaf_3874A5F8 -> jal GetCategoryTitle + { 0x00012AEC, 0x02602021 }, // addiu $a1, $a1, -12268 -> move $a0, $s3 + { 0x0000FFD8, (u32) GetCategoryTitle }, // jal scePaf_3874A5F8 -> jal GetCategoryTitle + { 0x0000FFDC, 0x02602021 }, // addiu $a1, $a1, -13828 -> move $a0, $s3 + + /* Patch a usually hardcoded value to a dynamic one from earlier in the code */ + /* Where it gets subtitle from? ;-) */ + { 0x00012B00, 0x02602821 }, // li $a1, 1 -> move $a1, $s3 + { 0x0000FFF0, 0x02602821 }, // li $a1, 1 -> move $a1, $s3 + + /* Force a branch to be taken regardless of the timelimit situation */ + { 0x0000A230, 0x100000D8 }, // beqz $v0, loc_A594 -> b loc_A594 + + /* Patch the call of scePafGetText to GetGameSubtitle */ + { 0x0000A5A4, (u32) GetGameSubtitle }, // jal scePaf_3874A5F8 -> jal GetGameSubtitle + { 0x0000A5A8, 0x02602821 }, // addiu $a1, $a1, -13876 -> move $a1, $s3 +}; + +static u32 backup[sizeof(ToggleCategoryPatches_620) / sizeof(ToggleCategoryPatch)]; + +int ToggleCategoryMode(int mode) { + int total; + ToggleCategoryPatch *ToggleCategoryPatches; + + kprintf("called, mode: %i\n", mode); + + if (patch_index == 0) { + ToggleCategoryPatches = ToggleCategoryPatches_620; + total = sizeof(ToggleCategoryPatches_620) / sizeof(ToggleCategoryPatch); + } else if (patch_index == 1) { + ToggleCategoryPatches = ToggleCategoryPatches_63x; + total = sizeof(ToggleCategoryPatches_63x) / sizeof(ToggleCategoryPatch); + } else if (patch_index == 2) { + ToggleCategoryPatches = ToggleCategoryPatches_66x; + total = sizeof(ToggleCategoryPatches_66x) / sizeof(ToggleCategoryPatch); + + } else { + return -1; + } + + kprintf("text_addr: %08X\n", text_addr_game); + if (by_category_mode == 0 && mode == 1) { + by_category_mode = 1; + for (int i = 0; i < total; i++) { + u32 addr = text_addr_game + ToggleCategoryPatches[i].addr; + u32 opcode = ToggleCategoryPatches[i].opcode; + backup[i] = _lw(addr); + if ((opcode & 0xFF000000) == 0x08000000) { + if(opcode == (u32)scePafAddGameItemsPatched) { + scePafAddGameItems = (void *)U_EXTRACT_CALL(addr); + } else if(opcode == (u32)CategorizeGamePatched) { + CategorizeGame = (void *)U_EXTRACT_CALL(addr); + } + MAKE_CALL(addr, opcode); + } else { + _sw(opcode, addr); + } + } + ClearCachesForUser(); + return 0; + } + + else if (by_category_mode == 1 && mode == 0) { + by_category_mode = 0; + + for (int i = 0; i < total; i++) { + kprintf("restoring backup[%i] == %08X, to addr %08X\n", i, backup[i], text_addr_game + ToggleCategoryPatches[i].addr); + _sw(backup[i], text_addr_game + ToggleCategoryPatches[i].addr); + } + ClearCachesForUser(); + + return 0; + } + return -1; +} diff --git a/readme.txt b/readme.txt index 6a80e89..0035bfe 100644 --- a/readme.txt +++ b/readme.txt @@ -1,76 +1,83 @@ -Game Categories Lite v1.5 - Codestation - -This plugin is based and uses source code from Game Categories Revised v12 (GCR) -and Game Categories Light v1.3 (GCL), both created by Bubbletune. Compatible with -6.20, 6.3x and 6.60 CFW. - -I changed the name of the project (doing a fork in the process) to avoid confusion -with GCL and GCR (the plugin is based heavily in GCL since it doesn't use a -kernel/user approach). - -You can configure the folder prefix (use CAT_ for folders or not), showing uncategorized -content and change the category mode in system settings. - -If you want to hide certain homebrew/game/dlc from the category listing just create a file -named gclite_filter.txt and add the folders name, one per line (make sure that a newline is -added at the end of the file). Next, put the file in your seplugins folder. - -If you want a translation of the visible options then edit the file category_lite_en.txt -and save it using the language code that first you (e.g. "es" for spanish). - -Note: you must use UTF-8 encoding for the translation files (without unicode BOM). - -Languages supported: "ja", "en", "fr", "es", "de", "it", "nl", "pt", "ru", "ko", "ch1", "ch2" - -The source code is also available in https://github.com/codestation/gclite - -Notes: make sure that this is the 1st plugin listed in vsh.txt - -Known issues: ->> Unknown if fixable: -* Change of category in the PSPGo requires a VSH reset. - ->> Unrelated to gclite: -* ME doesn't merge the categories with the same name between /ISO and /PSP/GAME. - ->> Folder mode limitations/bugs: -* Max categories: 8 (included uncategorized). -* Folder name + homebrew folder name: 30 character, e.g.: My homebrews/AwesomeBigHomebrew - is valid but My homebrews/AwesomeBigHomebrews isn't (i am not counting the "/"). - Note: the japanese and other non-ascii characters are 2 bytes wide, e.g.: カラフル counts - as 8 chars. - -Changelog -[!]Fix duplicated entries on iso category in folder mode (PRO). -v1.5: -[+]Support for categories in folder mode like Bubbletune's GCL (thx Nekmo for betatesting). -[+]Support to hide certain homebrews/games/dlc from the categories. -[+]Added subtitles to the config options. -[+]Empty categories are hidden by default. -[+]Non game folders are hidden by default on uncategorized content. -[+]Added folder mode benchmark (compile with BENCHMARK=1) -[+]Added bulgarian translation by Xian Nox. -[+]Added simple chinese translation by phoe-nix. -[+]Added Traditional-Chinese translation by Raiyou. -[+]Added Russian translation by Frostegater. -[+]Added italian translation by stevealexanderames. -[!]Force the uncategorized content to be the last item by default. -[!]Fixed UMD icon malfunction bug introduced in 1.4-r2. -v1.4: -[+]6.60 firmware support -[+]Allow the uncategorized folder to be sorted with your favorite app. -[+]Multiple language support. -[+]Added ja translation by popsdeco. -[+]Added de translation by KOlle and The Z. -v1.3: -[+]Support for categories in contextual menu. -[+]Support for plugin configuration in system settings. -[+]Added runtime detection for ME, so category games are now shown. -[!]Fixed issues with PSPGo (big thanks to raing3 to help me with the debugging). -v1.2: -[!]Fixed PSPGo categories, again (thx RUSTII for the tests). -[!]Fixed the free space display when the psp returns from sleep. -v1.1: -[!]Fixed PSPGo categories (thx RUSTII for the tests). -v1.0: -[+]First release. +Game Categories Lite + +This plugin is based and uses source code from Game Categories Revised v12 (GCR) +and Game Categories Light v1.3 (GCL), both created by Bubbletune. Compatible with +6.20, 6.3x and 6.60 CFW. + +I changed the name of the project (doing a fork in the process) to avoid confusion +with GCL and GCR (the plugin is based heavily in GCL since it doesn't use a +kernel/user approach). + +You can configure the folder prefix (use CAT_ for folders or not), showing uncategorized +content and change the category mode in system settings. + +If you want to hide certain homebrew/game/dlc from the category listing just create a file +named gclite_filter.txt and add the folders name, one per line (make sure that a newline is +added at the end of the file). Next, put the file in your seplugins folder. + +If you want a translation of the visible options then edit the file category_lite_en.txt +and save it using the language code that first you (e.g. "es" for spanish). + +Note: you must use UTF-8 encoding for the translation files (without unicode BOM). + +Languages supported: "ja", "en", "fr", "es", "de", "it", "nl", "pt", "ru", "ko", "ch1", "ch2" + +The source code is also available in https://github.com/codestation/gclite + +Notes: make sure that this is the 1st plugin listed in vsh.txt + +Known issues: +>> Unknown if fixable: +* Change of category in the PSPGo requires a VSH reset. + +>> Unrelated to gclite: +* ME doesn't merge the categories with the same name between /ISO and /PSP/GAME. + +>> Folder mode limitations/bugs: +* Max categories: 8 (included uncategorized). +* Folder name + homebrew folder name: 30 character, e.g.: My homebrews/AwesomeBigHomebrew + is valid but My homebrews/AwesomeBigHomebrews isn't (i am not counting the "/"). + Note: the japanese and other non-ascii characters are 2 bytes wide, e.g.: カラフル counts + as 8 chars. + +Changelog +v1.7-js1 (October 17, 2017): +[!]Fix labels not showing on PSP go internal storage. +v1.6: +[+]Added new option to sort categories: Use CAT_XX or XXcategory_name (XX between 00 and 99). +v1.5-r4 +[+]Added polish translation. +v1.5-r3 +[!]Fix duplicated entries on iso category in folder mode (PRO). +v1.5: +[+]Support for categories in folder mode like Bubbletune's GCL (thx Nekmo for betatesting). +[+]Support to hide certain homebrews/games/dlc from the categories. +[+]Added subtitles to the config options. +[+]Empty categories are hidden by default. +[+]Non game folders are hidden by default on uncategorized content. +[+]Added folder mode benchmark (compile with BENCHMARK=1) +[+]Added bulgarian translation by Xian Nox. +[+]Added simple chinese translation by phoe-nix. +[+]Added Traditional-Chinese translation by Raiyou. +[+]Added Russian translation by Frostegater. +[+]Added italian translation by stevealexanderames. +[!]Force the uncategorized content to be the last item by default. +[!]Fixed UMD icon malfunction bug introduced in 1.4-r2. +v1.4: +[+]6.60 firmware support +[+]Allow the uncategorized folder to be sorted with your favorite app. +[+]Multiple language support. +[+]Added ja translation by popsdeco. +[+]Added de translation by KOlle and The Z. +v1.3: +[+]Support for categories in contextual menu. +[+]Support for plugin configuration in system settings. +[+]Added runtime detection for ME, so category games are now shown. +[!]Fixed issues with PSPGo (big thanks to raing3 to help me with the debugging). +v1.2: +[!]Fixed PSPGo categories, again (thx RUSTII for the tests). +[!]Fixed the free space display when the psp returns from sleep. +v1.1: +[!]Fixed PSPGo categories (thx RUSTII for the tests). +v1.0: +[+]First release. diff --git a/selection.c b/selection.c index 2dc58ae..1edb84e 100644 --- a/selection.c +++ b/selection.c @@ -1,311 +1,311 @@ -/* - Game Categories Light v 1.3 - Copyright (C) 2011, Bubbletune - - 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 "psppaf.h" -#include -#include "categories_lite.h" -#include "logger.h" - -/* Global variables */ -static int already_in_foldermode = 1; -extern int by_category_mode; -extern u32 text_addr_game; -static void *GetSelectionArg; -static u32 sound_call_addr; - -static int defaulted; - -int ToggleCategoryMode(int mode); -void HijackGameClass(int items); - -/* Function pointers */ -int (*AddGameContext)(void *unk, SceGameContext **item); -SceGameContext *(*GetSelection)(void *arg0, u32 arg1); -int (*SetMode)(void *arg0, void *arg1, void *arg2); -int (*OnPushFolderOptionListCascade)(void *arg0, u32 *arg1); -int (*OnPushOptionListCascade)(void *arg0, u32 *arg1); - -int (*scePafSetSelection)(void *arg0, int selection); -int (*vsh_function)(void *arg); - -/* Functions */ -void ToggleSound(int toggle) { - kprintf("called, toggle: %i\n", toggle); - if (toggle == 0) { - sound_call_addr = U_EXTRACT_CALL(text_addr_game + patches.play_sound_call[patch_index]); - _sw(NOP_OPCODE, text_addr_game + patches.play_sound_call[patch_index]); - } - - else { - MAKE_CALL(text_addr_game+patches.play_sound_call[patch_index], sound_call_addr); - } - - ClearCachesForUser(); -} - -int AddGameContextPatched(void *unk, SceGameContext **item) { - /* Allocate buffer for "By Category" */ - SceGameContext *newitem = sce_paf_private_malloc(sizeof(SceGameContext)); - sce_paf_private_memcpy(newitem, *item, sizeof(SceGameContext)); - kprintf("called\n"); - /* Modify buffer for "By Category */ - newitem->text = "msg_by_category"; - newitem->option = patches.OPTION_BY_CATEGORY[patch_index]; - - /* Add the option */ - AddGameContext(unk, &newitem); - - /* Add the original */ - return AddGameContext(unk, item); -} - -#define MODE_ALL 0 -#define OPTION_BY_EXPIRE_DATE 0 - -int SetModePatched(void *arg0, void *arg1, void *arg2, u32 *info) { - /** Square-button cycling **/ - kprintf("called\n"); - /* What's the current mode? */ - if (info[patches.array_index[patch_index]] == MODE_ALL) { - /* All */ - /* Next stop: By Expire Date */ - info[patches.array_index[patch_index]] = patches.MODE_BY_EXPIRE_DATE[patch_index]; - already_in_foldermode = 1; - } else if (info[patches.array_index[patch_index]] == patches.MODE_BY_EXPIRE_DATE[patch_index]) { - if (!by_category_mode) { - /* By Expire Date */ - /* Next stop: By Category */ - ToggleCategoryMode(1); - } else { - /* By Category */ - /* Next stop: All */ - ToggleCategoryMode(0); - info[patches.array_index[patch_index]] = MODE_ALL; - - already_in_foldermode = 0; - } - } - return SetMode(arg0, arg1, arg2); -} - -void QuickSwitchToAll(SceGameContext *selection, void *arg0, u32 *arg1) { - kprintf("called\n"); - u32 backup = selection->option; - - /* Switch to "All" */ - selection->option = 1; - - /* Disable the click sound */ - ToggleSound(0); - - /* Call the function */ - OnPushFolderOptionListCascade(arg0, arg1); - - /* Enable the click sound */ - ToggleSound(1); - - /* Restore the original option */ - selection->option = backup; -} - -int OnPushFolderOptionListCascadePatched(void *arg0, u32 *arg1) { - kprintf("called\n"); - SceGameContext *selection = GetSelection(GetSelectionArg, arg1[3]); - kprintf("GetSelection returned, selection: %08X\n", selection); - /* We're in one of the folder modes in case this function is being used... */ - /* Where do we want to go? */ - if (selection->option == OPTION_BY_EXPIRE_DATE) { - kprintf("OPTION_BY_EXPIRE_DATE\n"); - /* Check if we're already in there */ - if (by_category_mode) { - kprintf("toggle category to 0\n"); - /* Toggle "By Category" off */ - ToggleCategoryMode(0); - - /* We're not... */ - if (already_in_foldermode) { - kprintf("calling QuickSwitchToAll #1\n"); - /* Switch to "All" for a brief second */ - QuickSwitchToAll(selection, arg0, arg1); - } else { - /* We are now! */ - already_in_foldermode = 1; - } - } - } - - else if (selection->option == patches.OPTION_BY_CATEGORY[patch_index]) { - int res; - kprintf("OPTION_BY_CATEGORY\n"); - /* Check if we're already in there */ - if (!by_category_mode) { - /* We're not... */ - if (already_in_foldermode) { - kprintf("calling QuickSwitchToAll #2\n"); - /* Switch to "All" for a brief second */ - QuickSwitchToAll(selection, arg0, arg1); - } else { - /* We are now! */ - already_in_foldermode = 1; - } - kprintf("toggle category to 1\n"); - /* Toggle "By Category" on */ - ToggleCategoryMode(1); - - /** HINT: This mode doesn't *really* exist, so we need to simulate "By Expire Date" */ - /* Switch to "By Expire Date" */ - selection->option = OPTION_BY_EXPIRE_DATE; - kprintf("calling OnPushOptionListCascade\n"); - /* Call the function */ - res = OnPushOptionListCascade(arg0, arg1); - - /* Restore the original */ - selection->option = patches.OPTION_BY_CATEGORY[patch_index]; - } else { - /* We are... */ - /* But darn, you user! You opened a lame context menu! ): */ - /* Now we need to fake another item just to make it dissappear */ - kprintf("faking item\n"); - /* Switch to "By Expire Date" */ - selection->option = OPTION_BY_EXPIRE_DATE; - kprintf("calling OnPushFolderOptionListCascade\n"); - /* Call the function */ - res = OnPushFolderOptionListCascade(arg0, arg1); - - /* Restore the original */ - selection->option = patches.OPTION_BY_CATEGORY[patch_index]; - } - - return res; - } else { // OPTION_ALL && OPTION_BY_FORMAT - already_in_foldermode = 0; - } - kprintf("going out\n"); - return OnPushFolderOptionListCascade(arg0, arg1); -} - -int OnPushOptionListCascadePatched(void *arg0, u32 *arg1) { - kprintf("called\n"); - SceGameContext *selection = GetSelection(GetSelectionArg, arg1[3]); - - /* We're in the "All" mode in case this function is being used... */ - /* Where do we want to go? */ - if (selection->option == OPTION_BY_EXPIRE_DATE) { - already_in_foldermode = 1; - - /* Toggle "By Category" off */ - ToggleCategoryMode(0); - } else if (selection->option == patches.OPTION_BY_CATEGORY[patch_index]) { - already_in_foldermode = 1; - - /* Toggle "By Category" on */ - ToggleCategoryMode(1); - - /** HINT: This mode doesn't *really* exist, so we need to simulate "By Expire Date" */ - /* Switch to "By Expire Date" */ - selection->option = OPTION_BY_EXPIRE_DATE; - - kprintf("Calling OnPushOptionListCascade\n"); - /* Call the function */ - int res = OnPushOptionListCascade(arg0, arg1); - kprintf("Called OnPushOptionListCascade, res: %i\n", res); - /* Restore the original */ - selection->option = patches.OPTION_BY_CATEGORY[patch_index]; - - return res; - } else { - already_in_foldermode = 0; - } - - return OnPushOptionListCascade(arg0, arg1); -} - -int scePafSetSelectionPatched(void *arg0, int selection) { - kprintf("called\n"); - /* "By Expire Date" */ - if (selection == 1) { - /* Should it be "By Category"? */ - if (by_category_mode) { - selection = 2; // yes - } - } - - return scePafSetSelection(arg0, selection); -} - -int vsh_function_patched(void *arg) { - if (!defaulted) { - ToggleCategoryMode(1); - - _sw(patches.MODE_BY_EXPIRE_DATE[patch_index], text_addr_game + patches.current_mode[patch_index] + 56); - ClearCachesForUser(); - - defaulted = 1; - } - - return vsh_function(arg); -} - -void PatchSelection(u32 text_addr) { - /* Patch AddGameContext */ - MAKE_CALL(text_addr+patches.add_game_context_call[patch_index][0], AddGameContextPatched); - MAKE_CALL(text_addr+patches.add_game_context_call[patch_index][1], AddGameContextPatched); - AddGameContext = (void *) (text_addr + patches.add_game_context[patch_index]); - - /* Patch calls to SetMode */ - MAKE_CALL(text_addr+patches.setmode_call_arg_1[patch_index][0], SetModePatched); - _sw(patches.setmode_arg_opcode[patch_index], text_addr + patches.setmode_call_arg_1[patch_index][1]); - - if (patches.setmode_call_arg_2[patch_index][0]) { - kprintf("patching SetMode\n"); - MAKE_CALL(text_addr+patches.setmode_call_arg_2[patch_index][0], SetModePatched); - _sw(patches.setmode_arg_opcode[patch_index], text_addr + patches.setmode_call_arg_2[patch_index][1]); - } - - /* Patch OnPushFolderOptionListCascade */ - _sw((u32) OnPushFolderOptionListCascadePatched, text_addr + patches.on_push_folder_options_call[patch_index]); - OnPushFolderOptionListCascade = (void *) (text_addr + patches.on_push_folder_options[patch_index]); - - /* Patch OnPushOptionListCascade */ - _sw((u32) OnPushOptionListCascadePatched, text_addr + patches.on_push_options_call[patch_index]); - OnPushOptionListCascade = (void *) (text_addr + patches.on_push_options[patch_index]); - - /* Additional function pointers */ - GetSelection = (void *) (text_addr + patches.get_selection[patch_index]); - SetMode = (void *) (text_addr + patches.setmode[patch_index]); - - /* Argument required for GetSelection */ - GetSelectionArg = (void *) (text_addr + patches.get_selection_arg[patch_index]); - - if (patches.set_selection_call[patch_index][0]) { - /* Patch scePafSetSelection */ - scePafSetSelection = (void *)U_EXTRACT_CALL(text_addr+patches.set_selection_call[patch_index][0]); - MAKE_CALL(text_addr+patches.set_selection_call[patch_index][0], scePafSetSelectionPatched); - MAKE_CALL(text_addr+patches.set_selection_call[patch_index][1], scePafSetSelectionPatched); - } - - defaulted = 0; - by_category_mode = 0; - vsh_function = (void *)U_EXTRACT_CALL(text_addr+0x12E0); - MAKE_CALL(text_addr+0x12E0, vsh_function_patched); - - HijackGameClass(32); -} +/* + Game Categories Light v 1.3 + Copyright (C) 2011, Bubbletune + + 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 "psppaf.h" +#include +#include "categories_lite.h" +#include "logger.h" + +/* Global variables */ +static int already_in_foldermode = 1; +extern int by_category_mode; +extern u32 text_addr_game; +static void *GetSelectionArg; +static u32 sound_call_addr; + +static int defaulted; + +int ToggleCategoryMode(int mode); +void HijackGameClass(int items); + +/* Function pointers */ +int (*AddGameContext)(void *unk, SceGameContext **item); +SceGameContext *(*GetSelection)(void *arg0, u32 arg1); +int (*SetMode)(void *arg0, void *arg1, void *arg2); +int (*OnPushFolderOptionListCascade)(void *arg0, u32 *arg1); +int (*OnPushOptionListCascade)(void *arg0, u32 *arg1); + +int (*scePafSetSelection)(void *arg0, int selection); +int (*vsh_function)(void *arg); + +/* Functions */ +void ToggleSound(int toggle) { + kprintf("called, toggle: %i\n", toggle); + if (toggle == 0) { + sound_call_addr = U_EXTRACT_CALL(text_addr_game + patches.play_sound_call[patch_index]); + _sw(NOP_OPCODE, text_addr_game + patches.play_sound_call[patch_index]); + } + + else { + MAKE_CALL(text_addr_game+patches.play_sound_call[patch_index], sound_call_addr); + } + + ClearCachesForUser(); +} + +int AddGameContextPatched(void *unk, SceGameContext **item) { + /* Allocate buffer for "By Category" */ + SceGameContext *newitem = sce_paf_private_malloc(sizeof(SceGameContext)); + sce_paf_private_memcpy(newitem, *item, sizeof(SceGameContext)); + kprintf("called\n"); + /* Modify buffer for "By Category */ + newitem->text = "msg_by_category"; + newitem->option = patches.OPTION_BY_CATEGORY[patch_index]; + + /* Add the option */ + AddGameContext(unk, &newitem); + + /* Add the original */ + return AddGameContext(unk, item); +} + +#define MODE_ALL 0 +#define OPTION_BY_EXPIRE_DATE 0 + +int SetModePatched(void *arg0, void *arg1, void *arg2, u32 *info) { + /** Square-button cycling **/ + kprintf("called\n"); + /* What's the current mode? */ + if (info[patches.array_index[patch_index]] == MODE_ALL) { + /* All */ + /* Next stop: By Expire Date */ + info[patches.array_index[patch_index]] = patches.MODE_BY_EXPIRE_DATE[patch_index]; + already_in_foldermode = 1; + } else if (info[patches.array_index[patch_index]] == patches.MODE_BY_EXPIRE_DATE[patch_index]) { + if (!by_category_mode) { + /* By Expire Date */ + /* Next stop: By Category */ + ToggleCategoryMode(1); + } else { + /* By Category */ + /* Next stop: All */ + ToggleCategoryMode(0); + info[patches.array_index[patch_index]] = MODE_ALL; + + already_in_foldermode = 0; + } + } + return SetMode(arg0, arg1, arg2); +} + +void QuickSwitchToAll(SceGameContext *selection, void *arg0, u32 *arg1) { + kprintf("called\n"); + u32 backup = selection->option; + + /* Switch to "All" */ + selection->option = 1; + + /* Disable the click sound */ + ToggleSound(0); + + /* Call the function */ + OnPushFolderOptionListCascade(arg0, arg1); + + /* Enable the click sound */ + ToggleSound(1); + + /* Restore the original option */ + selection->option = backup; +} + +int OnPushFolderOptionListCascadePatched(void *arg0, u32 *arg1) { + kprintf("called\n"); + SceGameContext *selection = GetSelection(GetSelectionArg, arg1[3]); + kprintf("GetSelection returned, selection: %08X\n", selection); + /* We're in one of the folder modes in case this function is being used... */ + /* Where do we want to go? */ + if (selection->option == OPTION_BY_EXPIRE_DATE) { + kprintf("OPTION_BY_EXPIRE_DATE\n"); + /* Check if we're already in there */ + if (by_category_mode) { + kprintf("toggle category to 0\n"); + /* Toggle "By Category" off */ + ToggleCategoryMode(0); + + /* We're not... */ + if (already_in_foldermode) { + kprintf("calling QuickSwitchToAll #1\n"); + /* Switch to "All" for a brief second */ + QuickSwitchToAll(selection, arg0, arg1); + } else { + /* We are now! */ + already_in_foldermode = 1; + } + } + } + + else if (selection->option == patches.OPTION_BY_CATEGORY[patch_index]) { + int res; + kprintf("OPTION_BY_CATEGORY\n"); + /* Check if we're already in there */ + if (!by_category_mode) { + /* We're not... */ + if (already_in_foldermode) { + kprintf("calling QuickSwitchToAll #2\n"); + /* Switch to "All" for a brief second */ + QuickSwitchToAll(selection, arg0, arg1); + } else { + /* We are now! */ + already_in_foldermode = 1; + } + kprintf("toggle category to 1\n"); + /* Toggle "By Category" on */ + ToggleCategoryMode(1); + + /** HINT: This mode doesn't *really* exist, so we need to simulate "By Expire Date" */ + /* Switch to "By Expire Date" */ + selection->option = OPTION_BY_EXPIRE_DATE; + kprintf("calling OnPushOptionListCascade\n"); + /* Call the function */ + res = OnPushOptionListCascade(arg0, arg1); + + /* Restore the original */ + selection->option = patches.OPTION_BY_CATEGORY[patch_index]; + } else { + /* We are... */ + /* But darn, you user! You opened a lame context menu! ): */ + /* Now we need to fake another item just to make it dissappear */ + kprintf("faking item\n"); + /* Switch to "By Expire Date" */ + selection->option = OPTION_BY_EXPIRE_DATE; + kprintf("calling OnPushFolderOptionListCascade\n"); + /* Call the function */ + res = OnPushFolderOptionListCascade(arg0, arg1); + + /* Restore the original */ + selection->option = patches.OPTION_BY_CATEGORY[patch_index]; + } + + return res; + } else { // OPTION_ALL && OPTION_BY_FORMAT + already_in_foldermode = 0; + } + kprintf("going out\n"); + return OnPushFolderOptionListCascade(arg0, arg1); +} + +int OnPushOptionListCascadePatched(void *arg0, u32 *arg1) { + kprintf("called\n"); + SceGameContext *selection = GetSelection(GetSelectionArg, arg1[3]); + + /* We're in the "All" mode in case this function is being used... */ + /* Where do we want to go? */ + if (selection->option == OPTION_BY_EXPIRE_DATE) { + already_in_foldermode = 1; + + /* Toggle "By Category" off */ + ToggleCategoryMode(0); + } else if (selection->option == patches.OPTION_BY_CATEGORY[patch_index]) { + already_in_foldermode = 1; + + /* Toggle "By Category" on */ + ToggleCategoryMode(1); + + /** HINT: This mode doesn't *really* exist, so we need to simulate "By Expire Date" */ + /* Switch to "By Expire Date" */ + selection->option = OPTION_BY_EXPIRE_DATE; + + kprintf("Calling OnPushOptionListCascade\n"); + /* Call the function */ + int res = OnPushOptionListCascade(arg0, arg1); + kprintf("Called OnPushOptionListCascade, res: %i\n", res); + /* Restore the original */ + selection->option = patches.OPTION_BY_CATEGORY[patch_index]; + + return res; + } else { + already_in_foldermode = 0; + } + + return OnPushOptionListCascade(arg0, arg1); +} + +int scePafSetSelectionPatched(void *arg0, int selection) { + kprintf("called\n"); + /* "By Expire Date" */ + if (selection == 1) { + /* Should it be "By Category"? */ + if (by_category_mode) { + selection = 2; // yes + } + } + + return scePafSetSelection(arg0, selection); +} + +int vsh_function_patched(void *arg) { + if (!defaulted) { + ToggleCategoryMode(1); + + _sw(patches.MODE_BY_EXPIRE_DATE[patch_index], text_addr_game + patches.current_mode[patch_index] + 56); + ClearCachesForUser(); + + defaulted = 1; + } + + return vsh_function(arg); +} + +void PatchSelection(u32 text_addr) { + /* Patch AddGameContext */ + MAKE_CALL(text_addr+patches.add_game_context_call[patch_index][0], AddGameContextPatched); + MAKE_CALL(text_addr+patches.add_game_context_call[patch_index][1], AddGameContextPatched); + AddGameContext = (void *) (text_addr + patches.add_game_context[patch_index]); + + /* Patch calls to SetMode */ + MAKE_CALL(text_addr+patches.setmode_call_arg_1[patch_index][0], SetModePatched); + _sw(patches.setmode_arg_opcode[patch_index], text_addr + patches.setmode_call_arg_1[patch_index][1]); + + if (patches.setmode_call_arg_2[patch_index][0]) { + kprintf("patching SetMode\n"); + MAKE_CALL(text_addr+patches.setmode_call_arg_2[patch_index][0], SetModePatched); + _sw(patches.setmode_arg_opcode[patch_index], text_addr + patches.setmode_call_arg_2[patch_index][1]); + } + + /* Patch OnPushFolderOptionListCascade */ + _sw((u32) OnPushFolderOptionListCascadePatched, text_addr + patches.on_push_folder_options_call[patch_index]); + OnPushFolderOptionListCascade = (void *) (text_addr + patches.on_push_folder_options[patch_index]); + + /* Patch OnPushOptionListCascade */ + _sw((u32) OnPushOptionListCascadePatched, text_addr + patches.on_push_options_call[patch_index]); + OnPushOptionListCascade = (void *) (text_addr + patches.on_push_options[patch_index]); + + /* Additional function pointers */ + GetSelection = (void *) (text_addr + patches.get_selection[patch_index]); + SetMode = (void *) (text_addr + patches.setmode[patch_index]); + + /* Argument required for GetSelection */ + GetSelectionArg = (void *) (text_addr + patches.get_selection_arg[patch_index]); + + if (patches.set_selection_call[patch_index][0]) { + /* Patch scePafSetSelection */ + scePafSetSelection = (void *)U_EXTRACT_CALL(text_addr+patches.set_selection_call[patch_index][0]); + MAKE_CALL(text_addr+patches.set_selection_call[patch_index][0], scePafSetSelectionPatched); + MAKE_CALL(text_addr+patches.set_selection_call[patch_index][1], scePafSetSelectionPatched); + } + + defaulted = 0; + by_category_mode = 0; + vsh_function = (void *)U_EXTRACT_CALL(text_addr+0x12E0); + MAKE_CALL(text_addr+0x12E0, vsh_function_patched); + + HijackGameClass(32); +} diff --git a/sysconf.c b/sysconf.c index e00144d..89a45a1 100644 --- a/sysconf.c +++ b/sysconf.c @@ -36,14 +36,34 @@ char user_buffer[256]; static u32 backup[4] = { 0, 0, 0, 0 }; int context_mode = 0; -static SceSysconfItem *sysconf_item[] = { NULL, NULL, NULL }; +static SceSysconfItem *sysconf_item[] = { NULL, NULL, NULL, NULL }; extern int sysconf_plug; extern int model; -static const char *sysconf_str[] = {"gc0", "gc1" , "gc2"}; -static const char *sysconf_sub[] = {"gcs0", "gcs1" , "gcs2"}; +#define GC_SYSCONF_MODE "gc0" +#define GC_SYSCONF_MODE_SUB "gcs0" +#define GC_SYSCONF_PREFIX "gc1" +#define GC_SYSCONF_PREFIX_SUB "gcs1" +#define GC_SYSCONF_SHOW "gc2" +#define GC_SYSCONF_SHOW_SUB "gcs2" +#define GC_SYSCONF_SORT "gc3" +#define GC_SYSCONF_SORT_SUB "gcs3" + +static const char *sysconf_str[] = { + GC_SYSCONF_MODE, + GC_SYSCONF_PREFIX, + GC_SYSCONF_SHOW, + GC_SYSCONF_SORT +}; + +static const char *sysconf_sub[] = { + GC_SYSCONF_MODE_SUB, + GC_SYSCONF_PREFIX_SUB, + GC_SYSCONF_SHOW_SUB, + GC_SYSCONF_SORT_SUB +}; void (*AddSysconfItem)(u32 *option, SceSysconfItem **item); SceSysconfItem *(*GetSysconfItem)(void *arg0, void *arg1); @@ -108,8 +128,12 @@ void HijackContext(SceRcoEntry *src, char **options, int n) { item_param[0] = 0xDEAD; item_param[1] = (u32)options[i]; - if(i != 0) item->prev_entry = item->next_entry; - if(i == n - 1) item->next_entry = 0; + if(i != 0) { + item->prev_entry = item->next_entry; + } + if(i == n - 1) { + item->next_entry = 0; + } item = (SceRcoEntry *)((u32)item + base->next_entry); item_param = (u32 *)((u32)item + base->param); @@ -160,6 +184,9 @@ int vshGetRegistryValuePatched(u32 *option, char *name, void *arg2, int size, in case 2: *value = config.uncategorized; return 0; + case 3: + *value = config.catsort; + return 0; default: *value = 0; return 0; @@ -186,6 +213,9 @@ int vshSetRegistryValuePatched(u32 *option, char *name, int size, int *value) { case 2: cfg = &config.uncategorized; break; + case 3: + cfg = &config.catsort; + break; default: cfg = NULL; break; @@ -231,6 +261,9 @@ int GetPageNodeByIDPatched(void *resource, char *name, SceRcoEntry **child) { case 3: HijackContext(*child, lang_container.show, ITEMSOF(lang_container.show)); break; + case 4: + HijackContext(*child, lang_container.sort, ITEMSOF(lang_container.sort)); + break; } } } diff --git a/vshitem.c b/vshitem.c index 0598b16..b82d4ac 100644 --- a/vshitem.c +++ b/vshitem.c @@ -45,8 +45,22 @@ int global_pos = 0; Category *cat_list[2] = { NULL, NULL }; -static const char *cat_str[] = { "gc", "gc0", "gc1", "gc2", "gc4", "gc5", "gcv_", "gcw_" }; -static const char *cat_sub[] = {"gcs0", "gcs1" , "gcs2"}; +static const char* GC_PREFIX = "gc"; + +static const char* GC_SYSCONF_MODE = "gc0"; +static const char* GC_SYSCONF_MODE_SUB = "gcs0"; +static const char* GC_SYSCONF_PREFIX = "gc1"; +static const char* GC_SYSCONF_PREFIX_SUB = "gcs1"; +static const char* GC_SYSCONF_SHOW = "gc2"; +static const char* GC_SYSCONF_SHOW_SUB = "gcs2"; +static const char* GC_SYSCONF_SORT = "gc3"; +static const char* GC_SYSCONF_SORT_SUB = "gcs3"; + +static const char* GC_UNCATEGORIZED_MS = "gc4"; +static const char* GC_UNCATEGORIZED_INTERNAL = "gc5"; +static const char* GC_CATEGORY_PREFIX_MS = "gcv_"; +static const char* GC_CATEGORY_PREFIX_INTERNAL = "gcw_"; + int vsh_id[2] = { -1, -1 }; int vsh_action_arg[2] = { -1, -1 }; @@ -181,50 +195,66 @@ int UnloadModulePatched(int skip) { } wchar_t* scePafGetTextPatched(void *arg, char *name) { - if (name && sce_paf_private_strncmp(name, cat_str[0], 2) == 0) { + if (name && sce_paf_private_strncmp(name, GC_PREFIX, 2) == 0) { kprintf("match name: %s\n", name); //TODO: optimize this code // sysconf 1 - if (sce_paf_private_strcmp(name, cat_str[1]) == 0) { + if (sce_paf_private_strcmp(name, GC_SYSCONF_MODE) == 0) { gc_utf8_to_unicode((wchar_t *)user_buffer, lang_container.msg_mode); return (wchar_t *) user_buffer; // sysconf 2 - } else if (sce_paf_private_strcmp(name, cat_str[2]) == 0) { + } else if (sce_paf_private_strcmp(name, GC_SYSCONF_PREFIX) == 0) { gc_utf8_to_unicode((wchar_t *)user_buffer, lang_container.msg_prefix); return (wchar_t *) user_buffer; // sysconf 3 - } else if (sce_paf_private_strcmp(name, cat_str[3]) == 0) { + } else if (sce_paf_private_strcmp(name, GC_SYSCONF_SHOW) == 0) { gc_utf8_to_unicode((wchar_t *)user_buffer, lang_container.msg_show); return (wchar_t *) user_buffer; - // sysconf subtitle 1 - }else if (sce_paf_private_strcmp(name, cat_sub[0]) == 0) { + // sysconf 4 + } else if (sce_paf_private_strcmp(name, GC_SYSCONF_SORT) == 0) { + gc_utf8_to_unicode((wchar_t *)user_buffer, lang_container.msg_sort); + return (wchar_t *) user_buffer; + // sysconf subtitle 1 + } else if (sce_paf_private_strcmp(name, GC_SYSCONF_MODE_SUB) == 0) { gc_utf8_to_unicode((wchar_t *)user_buffer, lang_container.msg_mode_sub); return (wchar_t *) user_buffer; // sysconf subtitle 2 - } else if (sce_paf_private_strcmp(name, cat_sub[1]) == 0) { + } else if (sce_paf_private_strcmp(name, GC_SYSCONF_PREFIX_SUB) == 0) { gc_utf8_to_unicode((wchar_t *)user_buffer, lang_container.msg_prefix_sub); return (wchar_t *) user_buffer; // sysconf subtitle 3 - } else if (sce_paf_private_strcmp(name, cat_sub[2]) == 0) { + } else if (sce_paf_private_strcmp(name, GC_SYSCONF_SHOW_SUB) == 0) { gc_utf8_to_unicode((wchar_t *)user_buffer, lang_container.msg_show_sub); return (wchar_t *) user_buffer; - // Memory Stick - } else if (sce_paf_private_strncmp(name, cat_str[6], 4) == 0) { + // sysconf subtitle 4 + } else if (sce_paf_private_strcmp(name, GC_SYSCONF_SORT_SUB) == 0) { + gc_utf8_to_unicode((wchar_t *)user_buffer, lang_container.msg_sort_sub); + return (wchar_t *) user_buffer; + // Memory Stick + } else if (sce_paf_private_strncmp(name, GC_CATEGORY_PREFIX_MS, 4) == 0) { Category *p = (Category *) sce_paf_private_strtoul(name + 4, NULL, 16); - gc_utf8_to_unicode((wchar_t *) user_buffer, &p->name); + if(config.catsort) { + gc_utf8_to_unicode((wchar_t *) user_buffer, &p->name+2); + } else { + gc_utf8_to_unicode((wchar_t *) user_buffer, &p->name); + } fix_text_padding((wchar_t *) user_buffer, scePafGetText(arg, "msgshare_ms"), 'M', 0x2122); return (wchar_t *) user_buffer; - } else if (sce_paf_private_strcmp(name, cat_str[4]) == 0) { + } else if (sce_paf_private_strcmp(name, GC_UNCATEGORIZED_MS) == 0) { gc_utf8_to_unicode((wchar_t *) user_buffer, lang_container.msg_uncategorized); fix_text_padding((wchar_t *) user_buffer, scePafGetText(arg, "msgshare_ms"), 'M', 0x2122); return (wchar_t *) user_buffer; // Internal Storage - } else if (sce_paf_private_strncmp(name, cat_str[7], 4) == 0) { + } else if (sce_paf_private_strncmp(name, GC_CATEGORY_PREFIX_INTERNAL, 4) == 0) { Category *p = (Category *) sce_paf_private_strtoul(name + 4, NULL, 16); - gc_utf8_to_unicode((wchar_t *) user_buffer, &p->name); + if(config.catsort) { + gc_utf8_to_unicode((wchar_t *) user_buffer, &p->name+2); + } else { + gc_utf8_to_unicode((wchar_t *) user_buffer, &p->name); + } fix_text_padding((wchar_t *) user_buffer, scePafGetText(arg, "msg_em"), 'M', 0x2122); return (wchar_t *) user_buffer; - } else if (sce_paf_private_strcmp(name, cat_str[5]) == 0) { + } else if (sce_paf_private_strcmp(name, GC_UNCATEGORIZED_INTERNAL) == 0) { gc_utf8_to_unicode((wchar_t *) user_buffer, lang_container.msg_uncategorized); fix_text_padding((wchar_t *) user_buffer, scePafGetText(arg, "msg_em"), 'M', 0x2122); return (wchar_t *) user_buffer;