Combine & improve game info and CIA/title checker

This commit is contained in:
d0k3 2021-03-11 20:24:39 +01:00
parent 8b5af2c22f
commit ddfdf81cf7
5 changed files with 116 additions and 49 deletions

View File

@ -60,7 +60,6 @@
#define FTYPE_TIKBUILD(tp) (tp&(GAME_TICKET|SYS_TICKDB|BIN_TIKDB)) #define FTYPE_TIKBUILD(tp) (tp&(GAME_TICKET|SYS_TICKDB|BIN_TIKDB))
#define FTYPE_KEYBUILD(tp) (tp&(BIN_KEYDB|BIN_LEGKEY)) #define FTYPE_KEYBUILD(tp) (tp&(BIN_KEYDB|BIN_LEGKEY))
#define FTYPE_TITLEINFO(tp) (tp&(GAME_TIE|GAME_TICKET|GAME_SMDH|GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_TMD|GAME_CDNTMD|GAME_TWLTMD|GAME_NDS|GAME_GBA|GAME_TAD|GAME_3DSX)) #define FTYPE_TITLEINFO(tp) (tp&(GAME_TIE|GAME_TICKET|GAME_SMDH|GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_TMD|GAME_CDNTMD|GAME_TWLTMD|GAME_NDS|GAME_GBA|GAME_TAD|GAME_3DSX))
#define FTYPE_CIACHECK(tp) (tp&(GAME_CIA|GAME_TIE))
#define FTYPE_RENAMABLE(tp) (tp&(GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_NDS|GAME_GBA)) #define FTYPE_RENAMABLE(tp) (tp&(GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_NDS|GAME_GBA))
#define FTYPE_TRIMABLE(tp) (tp&(IMG_NAND|GAME_NCCH|GAME_NCSD|GAME_NDS|GAME_GBA|SYS_FIRM)) #define FTYPE_TRIMABLE(tp) (tp&(IMG_NAND|GAME_NCCH|GAME_NCSD|GAME_NDS|GAME_GBA|SYS_FIRM))
#define FTYPE_TRANSFERABLE(tp) ((u64) (tp&(IMG_FAT|FLAG_CTR)) == (u64) (IMG_FAT|FLAG_CTR)) #define FTYPE_TRANSFERABLE(tp) ((u64) (tp&(IMG_FAT|FLAG_CTR)) == (u64) (IMG_FAT|FLAG_CTR))

View File

@ -1102,7 +1102,6 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
bool key_buildable = (FTYPE_KEYBUILD(filetype)) && !in_output_path && bool key_buildable = (FTYPE_KEYBUILD(filetype)) && !in_output_path &&
!((drvtype & DRV_VIRTUAL) && (drvtype & DRV_SYSNAND)); !((drvtype & DRV_VIRTUAL) && (drvtype & DRV_SYSNAND));
bool titleinfo = (FTYPE_TITLEINFO(filetype)); bool titleinfo = (FTYPE_TITLEINFO(filetype));
bool ciacheckable = (FTYPE_CIACHECK(filetype));
bool renamable = (FTYPE_RENAMABLE(filetype)) && !(drvtype & DRV_VIRTUAL) && !(drvtype & DRV_ALIAS) && bool renamable = (FTYPE_RENAMABLE(filetype)) && !(drvtype & DRV_VIRTUAL) && !(drvtype & DRV_ALIAS) &&
!(drvtype & DRV_CTRNAND) && !(drvtype & DRV_TWLNAND) && !(drvtype & DRV_IMAGE); !(drvtype & DRV_CTRNAND) && !(drvtype & DRV_TWLNAND) && !(drvtype & DRV_IMAGE);
bool trimable = (FTYPE_TRIMABLE(filetype)) && !(drvtype & DRV_VIRTUAL) && !(drvtype & DRV_ALIAS) && bool trimable = (FTYPE_TRIMABLE(filetype)) && !(drvtype & DRV_VIRTUAL) && !(drvtype & DRV_ALIAS) &&
@ -1327,7 +1326,6 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
// stuff for special menu starts here // stuff for special menu starts here
n_opt = 0; n_opt = 0;
int show_info = (titleinfo) ? ++n_opt : -1; int show_info = (titleinfo) ? ++n_opt : -1;
int ciacheck = (ciacheckable) ? ++n_opt : -1;
int mount = (mountable) ? ++n_opt : -1; int mount = (mountable) ? ++n_opt : -1;
int restore = (restorable) ? ++n_opt : -1; int restore = (restorable) ? ++n_opt : -1;
int ebackup = (ebackupable) ? ++n_opt : -1; int ebackup = (ebackupable) ? ++n_opt : -1;
@ -1367,7 +1365,6 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
if (ebackup > 0) optionstr[ebackup-1] = "Update embedded backup"; if (ebackup > 0) optionstr[ebackup-1] = "Update embedded backup";
if (ncsdfix > 0) optionstr[ncsdfix-1] = "Rebuild NCSD header"; if (ncsdfix > 0) optionstr[ncsdfix-1] = "Rebuild NCSD header";
if (show_info > 0) optionstr[show_info-1] = "Show title info"; if (show_info > 0) optionstr[show_info-1] = "Show title info";
if (ciacheck > 0) optionstr[ciacheck-1] = (filetype & GAME_TIE) ? "Title checker tool" : "CIA checker tool";
if (decrypt > 0) optionstr[decrypt-1] = (cryptable_inplace) ? "Decrypt file (...)" : "Decrypt file (" OUTPUT_PATH ")"; if (decrypt > 0) optionstr[decrypt-1] = (cryptable_inplace) ? "Decrypt file (...)" : "Decrypt file (" OUTPUT_PATH ")";
if (encrypt > 0) optionstr[encrypt-1] = (cryptable_inplace) ? "Encrypt file (...)" : "Encrypt file (" OUTPUT_PATH ")"; if (encrypt > 0) optionstr[encrypt-1] = (cryptable_inplace) ? "Encrypt file (...)" : "Encrypt file (" OUTPUT_PATH ")";
if (cia_build > 0) optionstr[cia_build-1] = (cia_build_legit < 0) ? "Build CIA from file" : "Build CIA (standard)"; if (cia_build > 0) optionstr[cia_build-1] = (cia_build_legit < 0) ? "Build CIA from file" : "Build CIA (standard)";
@ -1889,10 +1886,6 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
ShowPrompt(false, "Title info: not found"); ShowPrompt(false, "Title info: not found");
return 0; return 0;
} }
else if (user_select == ciacheck) { // -> CIA checker tool
ShowCiaTieCheckerInfo(file_path);
return 0;
}
else if (user_select == hsinject) { // -> Inject to Health & Safety else if (user_select == hsinject) { // -> Inject to Health & Safety
char* destdrv[2] = { NULL }; char* destdrv[2] = { NULL };
n_opt = 0; n_opt = 0;

View File

@ -308,10 +308,9 @@ u32 LoadTicketForTitleId(Ticket** ticket, const u64 title_id) {
// path to ticket.db // path to ticket.db
char path_ticketdb[32]; char path_ticketdb[32];
char* drv = path_store; char drv = *path_store;
snprintf(path_ticketdb, 32, "%2.2s/dbs/ticket.db", snprintf(path_ticketdb, 32, "%2.2s/dbs/ticket.db",
((*drv == 'A') || (*drv == '2')) ? "1:" : ((drv == 'B') || (drv == '5') || (drv == '4')) ? "4:" : "1:");
((*drv == 'B') || (*drv == '5')) ? "4:" : drv);
// load ticket // load ticket
if (!InitImgFS(path_ticketdb) || if (!InitImgFS(path_ticketdb) ||
@ -2711,11 +2710,9 @@ u64 GetGameFileTitleId(const char* path) {
tid64 = getbe64(cia->tmd.title_id); tid64 = getbe64(cia->tmd.title_id);
free(cia); free(cia);
} else if (filetype & (GAME_TMD|GAME_CDNTMD|GAME_TWLTMD)) { } else if (filetype & (GAME_TMD|GAME_CDNTMD|GAME_TWLTMD)) {
TitleMetaData* tmd = (TitleMetaData*) malloc(TMD_SIZE_MAX); u8 tid[8];
if (!tmd) return 0; if (fvx_qread(path, tid, 0x18C, 8, NULL) == FR_OK)
if (LoadTmdFile(tmd, path) == 0) tid64 = getbe64(tid);
tid64 = getbe64(tmd->title_id);
free(tmd);
} else if (filetype & GAME_NCCH) { } else if (filetype & GAME_NCCH) {
NcchHeader ncch; NcchHeader ncch;
if (LoadNcchHeaders(&ncch, NULL, NULL, path, 0) == 0) if (LoadNcchHeaders(&ncch, NULL, NULL, path, 0) == 0)
@ -2726,7 +2723,7 @@ u64 GetGameFileTitleId(const char* path) {
tid64 = ncsd.mediaId; tid64 = ncsd.mediaId;
} else if (filetype & GAME_NDS) { } else if (filetype & GAME_NDS) {
TwlHeader twl; TwlHeader twl;
if ((fvx_qread(path, &twl, 0, sizeof(TwlHeader), NULL) == FR_OK) && (twl.unit_code & 0x02)) if ((fvx_qread(path, &twl, 0, 0x300, NULL) == FR_OK) && (twl.unit_code & 0x02))
tid64 = twl.title_id; tid64 = twl.title_id;
} else if (filetype & GAME_TIE) { } else if (filetype & GAME_TIE) {
if ((*path == 'T') && (sscanf(path, "T:/%016llx", &tid64) != 1)) if ((*path == 'T') && (sscanf(path, "T:/%016llx", &tid64) != 1))
@ -2738,6 +2735,28 @@ u64 GetGameFileTitleId(const char* path) {
return tid64; return tid64;
} }
u32 GetGameFileTitleVersion(const char* path) {
u64 filetype = IdentifyFileType(path);
u32 version = (u32) -1;
if (filetype & (GAME_TMD|GAME_CDNTMD|GAME_TWLTMD)) {
TitleMetaData tmd;
if (fvx_qread(path, &tmd, 0, TMD_SIZE_STUB, NULL) == FR_OK)
version = getbe16(tmd.title_version);
} else if (filetype & GAME_TIE) {
TitleInfoEntry tie;
if (fvx_qread(path, &tie, 0, sizeof(TitleInfoEntry), NULL) == FR_OK)
version = tie.title_version & 0xFFFF;
} else if (filetype & GAME_CIA) {
CiaStub* cia = (CiaStub*) malloc(sizeof(CiaStub));
if (cia && LoadCiaStub(cia, path) != 0)
version = getbe16(cia->tmd.title_version);
if (cia) free(cia);
}
return version;
}
u32 BuildCiaFromGameFile(const char* path, bool force_legit) { u32 BuildCiaFromGameFile(const char* path, bool force_legit) {
u64 filetype = IdentifyFileType(path); u64 filetype = IdentifyFileType(path);
char dest[256]; char dest[256];
@ -3288,7 +3307,7 @@ u32 ShowGbaFileTitleInfo(const char* path, u16* screen) {
return 0; return 0;
} }
u32 ShowGameFileTitleInfoF(const char* path, u16* screen, bool clear) { u32 ShowGameFileTitleInfoF(const char* path, u16* screen, const char* str, bool clear) {
char path_content[256]; char path_content[256];
u64 itype = IdentifyFileType(path); // initial type u64 itype = IdentifyFileType(path); // initial type
if (itype & GAME_TMD) { if (itype & GAME_TMD) {
@ -3306,22 +3325,20 @@ u32 ShowGameFileTitleInfoF(const char* path, u16* screen, bool clear) {
Smdh* smdh = (Smdh*) buffer; Smdh* smdh = (Smdh*) buffer;
TwlIconData* twl_icon = (TwlIconData*) buffer; TwlIconData* twl_icon = (TwlIconData*) buffer;
// title id available? char disp_str[64];
u64 tid = GetGameFileTitleId(path); snprintf(disp_str, 64, str ? "%s\n" : "", str);
char tidstr[32] = { '\0' };
if (tid) snprintf(tidstr, 32, "<%016llX>\n", tid);
// try loading SMDH, then try NDS / encrypted / GBA // try loading SMDH, then try NDS / encrypted / GBA
u32 ret = 1; u32 ret = 1;
u32 tp = 0; u32 tp = 0;
if (LoadSmdhFromGameFile(path, smdh) == 0) if (LoadSmdhFromGameFile(path, smdh) == 0)
ret = ShowSmdhTitleInfo(smdh, tidstr, screen); ret = ShowSmdhTitleInfo(smdh, disp_str, screen);
else if ((LoadTwlMetaData(path, NULL, twl_icon) == 0) || else if ((LoadTwlMetaData(path, NULL, twl_icon) == 0) ||
((itype & GAME_TAD) && (fvx_qread(path, twl_icon, TAD_BANNER_OFFSET, sizeof(TwlIconData), NULL) == FR_OK))) ((itype & GAME_TAD) && (fvx_qread(path, twl_icon, TAD_BANNER_OFFSET, sizeof(TwlIconData), NULL) == FR_OK)))
ret = ShowTwlIconTitleInfo(twl_icon, tidstr, screen); ret = ShowTwlIconTitleInfo(twl_icon, disp_str, screen);
else if ((tp = LoadEncryptedIconFromCiaTmd(path, buffer, NULL, false)) != 0) else if ((tp = LoadEncryptedIconFromCiaTmd(path, buffer, NULL, false)) != 0)
ret = (tp == GAME_NCCH) ? ShowSmdhTitleInfo(smdh, tidstr, screen) : ret = (tp == GAME_NCCH) ? ShowSmdhTitleInfo(smdh, disp_str, screen) :
(tp == GAME_NDS ) ? ShowTwlIconTitleInfo(twl_icon, tidstr, screen) : 1; (tp == GAME_NDS ) ? ShowTwlIconTitleInfo(twl_icon, disp_str, screen) : 1;
else ret = ShowGbaFileTitleInfo(path, screen); else ret = ShowGbaFileTitleInfo(path, screen);
if (!ret && clear) { if (!ret && clear) {
@ -3333,15 +3350,14 @@ u32 ShowGameFileTitleInfoF(const char* path, u16* screen, bool clear) {
return ret; return ret;
} }
u32 ShowGameFileTitleInfo(const char* path) { u32 ShowGameCheckerInfo(const char* path) {
return ShowGameFileTitleInfoF(path, MAIN_SCREEN, true);
}
u32 ShowCiaTieCheckerInfo(const char* path) {
u64 type = IdentifyFileType(path); // filetype u64 type = IdentifyFileType(path); // filetype
if (!(type & (GAME_CIA|GAME_TIE|GAME_TMD|GAME_CDNTMD|GAME_TWLTMD)))
return 1;
u32 content_count = 0; u32 content_count = 0;
u32 content_found = 0; u32 content_found = 0;
bool sd_title = false;
bool missing_first = false; bool missing_first = false;
Ticket* ticket = NULL; Ticket* ticket = NULL;
@ -3360,12 +3376,20 @@ u32 ShowCiaTieCheckerInfo(const char* path) {
(LoadTmdFile(tmd, path_tmd) != 0)) { (LoadTmdFile(tmd, path_tmd) != 0)) {
free(tmd); free(tmd);
tmd = NULL; tmd = NULL;
} else content_found = content_count = getbe16(tmd->content_count); } else {
content_found = content_count = getbe16(tmd->content_count);
sd_title = (*path_tmd == 'A') || (*path_tmd == 'B');
}
// load ticket // load ticket
u64 tid64 = tmd ? getbe64(tmd->title_id) : 0; u64 tid64 = tmd ? getbe64(tmd->title_id) : 0;
if (LoadTicketForTitleId(&ticket, tid64) != 0) if (LoadTicketForTitleId(&ticket, tid64) != 0)
ticket = NULL; ticket = NULL;
} else if (type & (GAME_TMD|GAME_CDNTMD|GAME_TWLTMD)) {
if (LoadTmdFile(tmd, path) != 0) {
free(tmd);
tmd = NULL;
} else content_found = content_count = getbe16(tmd->content_count);
} else if (type & GAME_CIA) { } else if (type & GAME_CIA) {
CiaStub* cia = (CiaStub*) malloc(sizeof(CiaStub)); CiaStub* cia = (CiaStub*) malloc(sizeof(CiaStub));
if (!cia) { if (!cia) {
@ -3403,14 +3427,26 @@ u32 ShowCiaTieCheckerInfo(const char* path) {
u32 state_ticket = 0; u32 state_ticket = 0;
u32 state_tmd = 0; u32 state_tmd = 0;
u64 title_id = 0; u64 title_id = 0;
u32 console_id = 0xFFFFFFFF; u32 console_id = 0;
u32 title_version = 0;
u64 content_size = 0;
bool is_dlc = false; bool is_dlc = false;
// basic info // basic info
if (tmd) title_id = getbe64(tmd->title_id); if (tmd) title_id = getbe64(tmd->title_id);
if (tmd) title_version = getbe16(tmd->title_version);
if (ticket) console_id = getbe32(ticket->console_id); if (ticket) console_id = getbe32(ticket->console_id);
is_dlc = ((title_id >> 32) == 0x0004008C); is_dlc = ((title_id >> 32) == 0x0004008C);
// size of contents
char bytestr[32];
if (tmd && content_count) {
TmdContentChunk* chunk = (TmdContentChunk*) (tmd + 1);
for (u32 i = 0; i < content_count; i++, chunk++)
content_size += getbe64(chunk->size);
}
FormatBytes(bytestr, content_size);
// check ticket // check ticket
if (ticket && ValidateTicket(ticket) == 0) if (ticket && ValidateTicket(ticket) == 0)
state_ticket = (ValidateTicketSignature(ticket) == 0) ? 2 : 1; state_ticket = (ValidateTicketSignature(ticket) == 0) ? 2 : 1;
@ -3421,33 +3457,73 @@ u32 ShowCiaTieCheckerInfo(const char* path) {
// CIA / title type string // CIA / title type string
char typestr[32]; char typestr[32];
if (!state_ticket || !state_tmd || missing_first || (!is_dlc && (content_found != content_count))) if ((!state_ticket && (type&(GAME_CIA|GAME_TIE))) || !state_tmd || missing_first ||
snprintf(typestr, 32, "Possibly Broken %s", (type & GAME_TIE) ? "Title" : "CIA File"); (!is_dlc && (content_found != content_count)))
else snprintf(typestr, 32, "%s %s%s %s", snprintf(typestr, 32, "Possibly Broken");
else snprintf(typestr, 32, "%s %s%s",
console_id ? "Personal" : "Universal", console_id ? "Personal" : "Universal",
((state_ticket == 2) && (state_tmd == 2)) ? "Legit" : ((state_ticket == 2) && (state_tmd == 2)) ? "Legit" :
(state_tmd == 2) ? "Pirate Legit" : "Custom", (state_tmd == 2) ? "Pirate Legit" : "Custom",
is_dlc ? " DLC" : "", is_dlc ? " DLC" : "");
(type & GAME_TIE) ? "Title" : "CIA File");
char srcstr[5];
snprintf(srcstr, 5, "%s",
(type & GAME_TIE) ? (tmd ? (sd_title ? "SD" : "NAND") : "UNK") :
(type & GAME_CIA) ? "CIA" :
(type & GAME_TMD) ? "TMD" :
(type & GAME_CDNTMD) ? "CDN" :
(type & GAME_TWLTMD) ? "TWL" : "UNK");
char contents_str[64];
if (type & GAME_CIA) snprintf(contents_str, 64, "Contents in CIA: %lu/%lu", content_found, content_count);
else snprintf(contents_str, 64, "Contents in TMD: %lu", content_count);
char conid_str[32] = { '\0' };
if (type & (GAME_CIA|GAME_TIE)) snprintf(conid_str, 64, "Console ID: %08lX\n", console_id);
// show icon on top
u32 icon_res = ShowGameFileTitleInfoF(path, ALT_SCREEN, NULL, false);
// output results // output results
char contents_str[64];
s32 state_verify = -1; s32 state_verify = -1;
if (type & GAME_TIE) snprintf(contents_str, 64, "Contents in TMD: %lu", content_count);
else snprintf(contents_str, 64, "Contents in CIA: %lu/%lu", content_found, content_count);
while (true) { while (true) {
if (!ShowPrompt(state_verify < 0, "%s\n%s\n \nTitle ID: %016llX\nConsole ID: %08lX\n%s\nTicket/TMD: %s/%s\nVerification: %s", if (!ShowPrompt(state_verify < 0,
pathstr, typestr, title_id, console_id, contents_str, "%s\n%s %s Title\n \n"
(state_ticket == 0) ? "invalid" : (state_ticket == 2) ? "legit" : "illegit", "Title ID: %016llX\n"
"Title version: %u.%u.%u\n"
"Contents size: %s\n"
"%s\n%s \n"
"Ticket/TMD: %s/%s\n"
"Icon data: %s\n"
"Verification: %s",
pathstr, typestr, srcstr, title_id,
(title_version>>10)&0x3F, (title_version>>4)&0x3F, (title_version)&0xF,
bytestr, contents_str, conid_str,
(state_ticket == 0) ? "unknown" : (state_ticket == 2) ? "legit" : "illegit",
(state_tmd == 0) ? "invalid" : (state_tmd == 2) ? "legit" : "illegit", (state_tmd == 0) ? "invalid" : (state_tmd == 2) ? "legit" : "illegit",
(icon_res) ? "unavailable" : "(see other screen)",
(state_verify < 0) ? "pending\n \nProceed with verification?" : (state_verify == 0) ? "passed" : "failed") || (state_verify < 0) ? "pending\n \nProceed with verification?" : (state_verify == 0) ? "passed" : "failed") ||
(state_verify >= 0)) break; (state_verify >= 0)) break;
state_verify = (type & GAME_TIE) ? VerifyTieFile(path) : VerifyCiaFile(path); state_verify = VerifyGameFile(path);
} }
if (tmd) free(tmd); if (tmd) free(tmd);
if (ticket) free(ticket); if (ticket) free(ticket);
return (state_ticket && state_tmd) ? 0 : 1; ClearScreenF(true, true, COLOR_STD_BG);
return 0;
}
u32 ShowGameFileTitleInfo(const char* path) {
// try the checker tool first
if (ShowGameCheckerInfo(path) == 0)
return 0;
// title id available?
char tidstr[32] = { '\0' };
u64 tid = GetGameFileTitleId(path);
if (tid) snprintf(tidstr, 32, "<%016llX>", tid);
return ShowGameFileTitleInfoF(path, MAIN_SCREEN, tidstr, true);
} }
u32 BuildNcchInfoXorpads(const char* destdir, const char* path) { u32 BuildNcchInfoXorpads(const char* destdir, const char* path) {

View File

@ -14,9 +14,8 @@ u32 ExtractCodeFromCxiFile(const char* path, const char* path_out, char* extstr)
u32 CompressCode(const char* path, const char* path_out); u32 CompressCode(const char* path, const char* path_out);
u64 GetGameFileTrimmedSize(const char* path); u64 GetGameFileTrimmedSize(const char* path);
u32 TrimGameFile(const char* path); u32 TrimGameFile(const char* path);
u32 ShowGameFileTitleInfoF(const char* path, u16* screen, bool clear); u32 ShowGameFileTitleInfoF(const char* path, u16* screen, const char* str, bool clear);
u32 ShowGameFileTitleInfo(const char* path); u32 ShowGameFileTitleInfo(const char* path);
u32 ShowCiaTieCheckerInfo(const char* path);
u32 UninstallGameDataTie(const char* path, bool remove_tie, bool remove_ticket, bool remove_save); u32 UninstallGameDataTie(const char* path, bool remove_tie, bool remove_ticket, bool remove_save);
u32 GetTmdContentPath(char* path_content, const char* path_tmd); u32 GetTmdContentPath(char* path_content, const char* path_tmd);
u32 GetTieContentPath(char* path_content, const char* path_tie); u32 GetTieContentPath(char* path_content, const char* path_tie);

View File

@ -1880,7 +1880,7 @@ bool ExecuteGM9Script(const char* path_script) {
if (bitmap) { if (bitmap) {
DrawBitmap(TOP_SCREEN, -1, -1, bitmap_width, bitmap_height, bitmap); DrawBitmap(TOP_SCREEN, -1, -1, bitmap_width, bitmap_height, bitmap);
free(bitmap); free(bitmap);
} else if (ShowGameFileTitleInfoF(preview_str, TOP_SCREEN, false) != 0) { } else if (ShowGameFileTitleInfoF(preview_str, TOP_SCREEN, NULL, false) != 0) {
if (strncmp(preview_str, "off", _VAR_CNT_LEN) == 0) preview_str = "(preview disabled)"; if (strncmp(preview_str, "off", _VAR_CNT_LEN) == 0) preview_str = "(preview disabled)";
DrawStringCenter(TOP_SCREEN, COLOR_STD_FONT, COLOR_STD_BG, "%s", preview_str); DrawStringCenter(TOP_SCREEN, COLOR_STD_FONT, COLOR_STD_BG, "%s", preview_str);
} }