diff --git a/arm9/source/filesys/support.h b/arm9/source/filesys/support.h index 1146157..b750323 100644 --- a/arm9/source/filesys/support.h +++ b/arm9/source/filesys/support.h @@ -3,6 +3,7 @@ #include "common.h" // scripts / payloads dir names +#define LANGUAGES_DIR "languages" #define SCRIPTS_DIR "scripts" #define PAYLOADS_DIR "payloads" @@ -11,5 +12,6 @@ size_t LoadSupportFile(const char* fname, void* buffer, size_t max_len); bool SaveSupportFile(const char* fname, void* buffer, size_t len); bool SetAsSupportFile(const char* fname, const char* source); +bool GetSupportDir(char* path, const char* dname); bool CheckSupportDir(const char* fpath); bool FileSelectorSupport(char* result, const char* text, const char* dname, const char* pattern); diff --git a/arm9/source/godmode.c b/arm9/source/godmode.c index e914415..9c338d9 100644 --- a/arm9/source/godmode.c +++ b/arm9/source/godmode.c @@ -2446,6 +2446,34 @@ u32 GodMode(int entrypoint) { if (!language_loaded) { SetLanguage(NULL, 0); + + char loadpath[256]; + if (LanguageMenu(loadpath, "Select Language for GodMode9:")) { + size_t fsize = FileGetSize(loadpath); + if (fsize > 0) { + char* data = (char*)malloc(fsize); + if (data) { + FileGetData(loadpath, data, fsize, 0); + SaveSupportFile("language.trf", data, fsize); + SetLanguage(data, fsize); + free(data); + } + } + + // Try load font with the same name + char *ext = strstr(loadpath, ".trf"); + strcpy(ext, ".frf"); + fsize = FileGetSize(loadpath); + if (fsize > 0) { + char* data = (char*)malloc(fsize); + if (data) { + FileGetData(loadpath, data, fsize, 0); + SaveSupportFile("font.frf", data, fsize); + SetFont(data, fsize); + free(data); + } + } + } } // check for embedded essential backup @@ -2888,6 +2916,7 @@ u32 GodMode(int entrypoint) { u32 n_opt = 0; int poweroff = ++n_opt; int reboot = ++n_opt; + int language = ++n_opt; int brick = (HID_ReadState() & BUTTON_R1) ? ++n_opt : 0; int titleman = ++n_opt; int scripts = ++n_opt; @@ -2896,6 +2925,7 @@ u32 GodMode(int entrypoint) { if (poweroff > 0) optionstr[poweroff - 1] = STR_POWEROFF_SYSTEM; if (reboot > 0) optionstr[reboot - 1] = STR_REBOOT_SYSTEM; if (titleman > 0) optionstr[titleman - 1] = STR_TITLE_MANAGER; + if (language > 0) optionstr[language - 1] = STR_LANGUAGE; if (brick > 0) optionstr[brick - 1] = STR_BRICK_MY_3DS; if (scripts > 0) optionstr[scripts - 1] = STR_SCRIPTS; if (payloads > 0) optionstr[payloads - 1] = STR_PAYLOADS; @@ -2934,6 +2964,38 @@ u32 GodMode(int entrypoint) { break; } else ShowPrompt(false, "%s", STR_FAILED_SETTING_UP_TITLE_MANAGER); } + } else if (user_select == language) { + if (!CheckSupportDir(LANGUAGES_DIR)) { + ShowPrompt(false, STR_LANGUAGES_DIRECTORY_NOT_FOUND, LANGUAGES_DIR); + } else if (LanguageMenu(loadpath, STR_HOME_LANGUAGE_MENU_SELECT_LANGUAGE)) { + size_t fsize = FileGetSize(loadpath); + if (fsize > 0) { + char* data = (char*)malloc(fsize); + if (data) { + FileGetData(loadpath, data, fsize, 0); + SaveSupportFile("language.trf", data, fsize); + SetLanguage(data, fsize); + free(data); + } + + // Try load font with the same name + char *ext = strstr(loadpath, ".trf"); + strcpy(ext, ".frf"); + fsize = FileGetSize(loadpath); + if (fsize > 0) { + char* data = (char*)malloc(fsize); + if (data) { + FileGetData(loadpath, data, fsize, 0); + SaveSupportFile("font.frf", data, fsize); + SetFont(data, fsize); + free(data); + } + } + } + GetDirContents(current_dir, current_path); + ClearScreenF(true, true, COLOR_STD_BG); + break; + } } else if (user_select == scripts) { if (!CheckSupportDir(SCRIPTS_DIR)) { ShowPrompt(false, STR_SCRIPTS_DIRECTORY_NOT_FOUND, SCRIPTS_DIR); diff --git a/arm9/source/language.c b/arm9/source/language.c index f0a1259..0bd2c9b 100644 --- a/arm9/source/language.c +++ b/arm9/source/language.c @@ -1,4 +1,8 @@ #include "language.h" +#include "fsdrive.h" +#include "fsutil.h" +#include "support.h" +#include "ui.h" #define STRING(what, def) const char* STR_##what = NULL; #include "language.inl" @@ -133,3 +137,52 @@ const void* GetLanguage(const void* riff, const u32 riff_size, u32* version, u32 return NULL; } + +int compLanguage(const void *e1, const void *e2) { + const Language *entry2 = (const Language *) e2; + const Language *entry1 = (const Language *) e1; + return strncasecmp(entry1->name, entry2->name, 256); +} + +bool LanguageMenu(char* result, const char* title) { + DirStruct* langDir = (DirStruct*)malloc(sizeof(DirStruct)); + if (!langDir) return false; + + char path[256]; + if (!GetSupportDir(path, LANGUAGES_DIR)) return false; + GetDirContents(langDir, path); + + char* header = (char*)malloc(0x2C0); + Language* langs = (Language*)malloc(langDir->n_entries * sizeof(Language)); + int langCount = 0; + + // Find all valid files and get their language names + for (u32 i = 0; i < langDir->n_entries; i++) { + if (langDir->entry[i].type == T_FILE) { + size_t fsize = FileGetSize(langDir->entry[i].path); + FileGetData(langDir->entry[i].path, header, 0x2C0, 0); + if (GetLanguage(header, fsize, NULL, NULL, langs[langCount].name)) { + memcpy(langs[langCount].path, langDir->entry[i].path, 256); + langCount++; + } + } + } + + free(langDir); + free(header); + + qsort(langs, langCount, sizeof(Language), compLanguage); + + // Make an array of just the names for the select promt + const char* langNames[langCount]; + for (int i = 0; i < langCount; i++) { + langNames[i] = langs[i].name; + } + + u32 selected = ShowSelectPrompt(langCount, langNames, "%s", title); + if (selected > 0 && result) { + memcpy(result, langs[selected - 1].path, 256); + } + + return selected > 0; +} diff --git a/arm9/source/language.h b/arm9/source/language.h index a548322..d2972ee 100644 --- a/arm9/source/language.h +++ b/arm9/source/language.h @@ -8,3 +8,5 @@ bool SetLanguage(const void* translation, u32 translation_size); const void* GetLanguage(const void* riff, u32 riff_size, u32* version, u32* count, char* language_name); + +bool LanguageMenu(char* result, const char* title); diff --git a/arm9/source/language.inl b/arm9/source/language.inl index 8a5f0a7..547f10b 100644 --- a/arm9/source/language.inl +++ b/arm9/source/language.inl @@ -458,6 +458,7 @@ STRING(FAILED_CREATING_FOLDER_PATH, "Failed creating folder:\n%s") STRING(FAILED_CREATING_FILE_PATH, "Failed creating file:\n%s") STRING(TITLE_MANAGER, "Title manager") STRING(BRICK_MY_3DS, "Brick my 3DS") +STRING(LANGUAGE, "Language...") STRING(SCRIPTS, "Scripts...") STRING(PAYLOADS, "Payloads...") STRING(MORE, "More...") @@ -469,7 +470,9 @@ STRING(4_DRIVE_NAND_TWL, "[4:] NAND / TWL") STRING(A_DRIVE_SD_CARD, "[A:] SD CARD") STRING(B_DRIVE_SD_CARD, "[B:] SD CARD") STRING(TITLE_MANAGER_MENU_SELECT_TITLES_SOURCE, "Title manager menu.\nSelect titles source:") +STRING(LANGUAGES_DIRECTORY_NOT_FOUND, "Languages directory not found.\n(default path: 0:/gm9/%s)") STRING(SCRIPTS_DIRECTORY_NOT_FOUND, "Scripts directory not found.\n(default path: 0:/gm9/%s)") +STRING(HOME_LANGUAGE_MENU_SELECT_LANGUAGE, "HOME language... menu.\nSelect language:") STRING(HOME_SCRIPTS_MENU_SELECT_SCRIPT, "HOME scripts... menu.\nSelect script:") STRING(PAYLOADS_DIRECTORY_NOT_FOUND, "Payloads directory not found.\n(default path: 0:/gm9/%s)") STRING(HOME_PAYLOADS_MENU_SELECT_PAYLOAD, "HOME payloads... menu.\nSelect payload:") diff --git a/resources/languages/source.json b/resources/languages/source.json index b9dc8e4..79be425 100644 --- a/resources/languages/source.json +++ b/resources/languages/source.json @@ -456,6 +456,7 @@ "FAILED_CREATING_FILE_PATH": "Failed creating file:\n%s", "TITLE_MANAGER": "Title manager", "BRICK_MY_3DS": "Brick my 3DS", + "LANGUAGE": "Language...", "SCRIPTS": "Scripts...", "PAYLOADS": "Payloads...", "MORE": "More...", @@ -467,7 +468,9 @@ "A_DRIVE_SD_CARD": "[A:] SD CARD", "B_DRIVE_SD_CARD": "[B:] SD CARD", "TITLE_MANAGER_MENU_SELECT_TITLES_SOURCE": "Title manager menu.\nSelect titles source:", + "LANGUAGES_DIRECTORY_NOT_FOUND": "Languages directory not found.\n(default path: 0:/gm9/%s)", "SCRIPTS_DIRECTORY_NOT_FOUND": "Scripts directory not found.\n(default path: 0:/gm9/%s)", + "HOME_LANGUAGE_MENU_SELECT_LANGUAGE": "HOME language... menu.\nSelect language:", "HOME_SCRIPTS_MENU_SELECT_SCRIPT": "HOME scripts... menu.\nSelect script:", "PAYLOADS_DIRECTORY_NOT_FOUND": "Payloads directory not found.\n(default path: 0:/gm9/%s)", "HOME_PAYLOADS_MENU_SELECT_PAYLOAD": "HOME payloads... menu.\nSelect payload:",