diff --git a/arm9/source/common/ui.c b/arm9/source/common/ui.c index 52b8c0d..f139d2b 100644 --- a/arm9/source/common/ui.c +++ b/arm9/source/common/ui.c @@ -27,11 +27,12 @@ static u8 font_bin[FONT_MAX_HEIGHT * FONT_N_SYMBOLS]; u8* GetFontFromPbm(const void* pbm, const u32 pbm_size, u32* w, u32* h) { char* hdr = (char*) pbm; + u32 hdr_max_size = min(512, pbm_size); u32 pbm_w = 0; u32 pbm_h = 0; // minimum size - if (pbm_size < 7) return NULL; + if (hdr_max_size < 7) return NULL; // check header magic, then skip over if (strncmp(hdr, "P4\n", 3) != 0) return NULL; @@ -40,30 +41,30 @@ u8* GetFontFromPbm(const void* pbm, const u32 pbm_size, u32* w, u32* h) { u32 p = 3; while (hdr[p] == '#') { while (hdr[p++] != '\n') { - if (p >= pbm_size) return NULL; + if (p >= hdr_max_size) return NULL; } } // parse width while ((hdr[p] >= '0') && (hdr[p] <= '9')) { - if (p >= pbm_size) return NULL; + if (p >= hdr_max_size) return NULL; pbm_w *= 10; pbm_w += hdr[p++] - '0'; } // whitespace - if ((hdr[p++] != ' ') || (p >= pbm_size)) + if ((hdr[p++] != ' ') || (p >= hdr_max_size)) return NULL; // parse height while ((hdr[p] >= '0') && (hdr[p] <= '9')) { - if (p >= pbm_size) return NULL; + if (p >= hdr_max_size) return NULL; pbm_h *= 10; pbm_h += hdr[p++] - '0'; } // line break - if ((hdr[p++] != '\n') || (p >= pbm_size)) + if ((hdr[p++] != '\n') || (p >= hdr_max_size)) return NULL; // check sizes diff --git a/arm9/source/filesys/filetype.c b/arm9/source/filesys/filetype.c index d5c90b9..3dc81c5 100644 --- a/arm9/source/filesys/filetype.c +++ b/arm9/source/filesys/filetype.c @@ -6,6 +6,7 @@ #include "keydb.h" #include "ctrtransfer.h" #include "scripting.h" +#include "ui.h" // only for font file detection u64 IdentifyFileType(const char* path) { const u8 romfs_magic[] = { ROMFS_MAGIC }; @@ -94,7 +95,9 @@ u64 IdentifyFileType(const char* path) { } } - if ((fsize > sizeof(AgbHeader)) && + if (GetFontFromPbm(data, fsize, NULL, NULL)) { + return FONT_PBM; + } else if ((fsize > sizeof(AgbHeader)) && (ValidateAgbHeader((AgbHeader*) data) == 0)) { return GAME_GBA; } else if ((fsize > sizeof(BossHeader)) && diff --git a/arm9/source/filesys/filetype.h b/arm9/source/filesys/filetype.h index d9fee5b..d173f5a 100644 --- a/arm9/source/filesys/filetype.h +++ b/arm9/source/filesys/filetype.h @@ -27,8 +27,9 @@ #define BIN_LEGKEY (1ULL<<22) #define TXT_SCRIPT (1ULL<<23) #define TXT_GENERIC (1ULL<<24) -#define NOIMG_NAND (1ULL<<25) -#define HDR_NAND (1ULL<<26) +#define FONT_PBM (1ULL<<25) +#define NOIMG_NAND (1ULL<<26) +#define HDR_NAND (1ULL<<27) #define TYPE_BASE 0xFFFFFFFFULL // 32 bit reserved for base types // #define FLAG_FIRM (1ULL<<58) // <--- for CXIs containing FIRMs @@ -58,6 +59,7 @@ #define FTYPE_KEYINIT(tp) (tp&(BIN_KEYDB)) #define FTYPE_KEYINSTALL(tp) (tp&(BIN_KEYDB)) #define FTYPE_SCRIPT(tp) (tp&(TXT_SCRIPT)) +#define FTYPE_FONT(tp) (tp&(FONT_PBM)) #define FTYPE_BOOTABLE(tp) (tp&(SYS_FIRM)) #define FTYPE_INSTALLABLE(tp) (tp&(SYS_FIRM)) #define FTPYE_AGBSAVE(tp) (tp&(SYS_AGBSAVE)) diff --git a/arm9/source/godmode.c b/arm9/source/godmode.c index 5c6b62f..ab56ede 100644 --- a/arm9/source/godmode.c +++ b/arm9/source/godmode.c @@ -952,6 +952,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan bool keyinitable = (FTYPE_KEYINIT(filetype)) && !((drvtype & DRV_VIRTUAL) && (drvtype & DRV_SYSNAND)); bool keyinstallable = (FTYPE_KEYINSTALL(filetype)) && !((drvtype & DRV_VIRTUAL) && (drvtype & DRV_SYSNAND)); bool scriptable = (FTYPE_SCRIPT(filetype)); + bool fontable = (FTYPE_FONT(filetype)); bool bootable = (FTYPE_BOOTABLE(filetype)); bool installable = (FTYPE_INSTALLABLE(filetype)); bool agbexportable = (FTPYE_AGBSAVE(filetype) && (drvtype & DRV_VIRTUAL) && (drvtype & DRV_SYSNAND)); @@ -966,7 +967,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan extrcodeable = (FTYPE_HASCODE(filetype_cxi)); } - bool special_opt = mountable || verificable || decryptable || encryptable || cia_buildable || cia_buildable_legit || cxi_dumpable || tik_buildable || key_buildable || titleinfo || renamable || transferable || hsinjectable || restorable || xorpadable || ebackupable || ncsdfixable || extrcodeable || keyinitable || keyinstallable || bootable || scriptable || installable || agbexportable || agbimportable; + bool special_opt = mountable || verificable || decryptable || encryptable || cia_buildable || cia_buildable_legit || cxi_dumpable || tik_buildable || key_buildable || titleinfo || renamable || transferable || hsinjectable || restorable || xorpadable || ebackupable || ncsdfixable || extrcodeable || keyinitable || keyinstallable || bootable || scriptable || fontable || installable || agbexportable || agbimportable; char pathstr[32+1]; TruncateString(pathstr, file_path, 32, 8); @@ -1016,6 +1017,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan (filetype & BIN_LEGKEY) ? "Build " KEYDB_NAME : (filetype & BIN_NCCHNFO)? "NCCHinfo options..." : (filetype & TXT_SCRIPT) ? "Execute GM9 script" : + (filetype & FONT_PBM) ? "Set as active font" : (filetype & HDR_NAND) ? "Rebuild NCSD header" : (filetype & NOIMG_NAND) ? "Rebuild NCSD header" : "???"; optionstr[hexviewer-1] = "Show in Hexeditor"; @@ -1158,6 +1160,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan int install = (installable) ? ++n_opt : -1; int boot = (bootable) ? ++n_opt : -1; int script = (scriptable) ? ++n_opt : -1; + int font = (fontable) ? ++n_opt : -1; int agbexport = (agbexportable) ? ++n_opt : -1; int agbimport = (agbimportable) ? ++n_opt : -1; if (mount > 0) optionstr[mount-1] = (filetype & GAME_TMD) ? "Mount CXI/NDS to drive" : "Mount image to drive"; @@ -1185,6 +1188,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan if (install > 0) optionstr[install-1] = "Install FIRM"; if (boot > 0) optionstr[boot-1] = "Boot FIRM"; if (script > 0) optionstr[script-1] = "Execute GM9 script"; + if (font > 0) optionstr[font-1] = "Set as active font"; if (agbexport > 0) optionstr[agbexport-1] = "Dump GBA VC save"; if (agbimport > 0) optionstr[agbimport-1] = "Inject GBA VC save"; @@ -1592,6 +1596,12 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan ClearScreenF(true, true, COLOR_STD_BG); return 0; } + else if (user_select == font) { // set font + u32 pbm_size = FileGetData(file_path, TEMP_BUFFER, TEMP_BUFFER_SIZE, 0); + if (pbm_size) SetFontFromPbm(TEMP_BUFFER, pbm_size); + ClearScreenF(true, true, COLOR_STD_BG); + return 0; + } else if (user_select == agbexport) { // export GBA VC save if (DumpGbaVcSavegame(file_path) == 0) ShowPrompt(false, "Savegame dumped to " OUTPUT_PATH);