From d413e71c01d3e3bd3e4a9dec193f40cd4815855d Mon Sep 17 00:00:00 2001 From: d0k3 Date: Sun, 29 Oct 2017 15:32:25 +0100 Subject: [PATCH] Show title info for 3DSX files --- source/filesys/filetype.c | 5 +++++ source/filesys/filetype.h | 29 +++++++++++++++-------------- source/game/3dsx.h | 23 +++++++++++++++++++++++ source/game/game.h | 1 + source/godmode.c | 1 + source/utils/gameutil.c | 13 +++++++++---- 6 files changed, 54 insertions(+), 18 deletions(-) create mode 100644 source/game/3dsx.h diff --git a/source/filesys/filetype.c b/source/filesys/filetype.c index 59010c2..3d1a384 100644 --- a/source/filesys/filetype.c +++ b/source/filesys/filetype.c @@ -11,6 +11,8 @@ u64 IdentifyFileType(const char* path) { const u8 romfs_magic[] = { ROMFS_MAGIC }; const u8 tickdb_magic[] = { TICKDB_MAGIC }; const u8 smdh_magic[] = { SMDH_MAGIC }; + const u8 threedsx_magic[] = { THREEDSX_EXT_MAGIC }; + if (!path) return 0; // safety u8 header[0x200] __attribute__((aligned(32))); // minimum required size void* data = (void*) header; @@ -95,6 +97,9 @@ u64 IdentifyFileType(const char* path) { } else if ((fsize > sizeof(BossHeader)) && (ValidateBossHeader((BossHeader*) data, fsize) == 0)) { return GAME_BOSS; // BOSS (SpotPass) file + } else if ((fsize > sizeof(ThreedsxHeader)) && + (memcmp(data, threedsx_magic, sizeof(threedsx_magic)) == 0)) { + return GAME_3DSX; // 3DSX (executable) file } else if ((fsize > sizeof(NcchInfoHeader)) && (GetNcchInfoVersion((NcchInfoHeader*) data)) && fname && (strncasecmp(fname, NCCHINFO_NAME, 32) == 0)) { diff --git a/source/filesys/filetype.h b/source/filesys/filetype.h index a741214..7eaf96e 100644 --- a/source/filesys/filetype.h +++ b/source/filesys/filetype.h @@ -14,19 +14,20 @@ #define GAME_NUSCDN (1ULL<<9) #define GAME_TICKET (1ULL<<10) #define GAME_SMDH (1ULL<<11) -#define GAME_NDS (1ULL<<12) -#define GAME_GBA (1ULL<<13) -#define SYS_FIRM (1ULL<<14) -#define SYS_AGBSAVE (1ULL<<15) -#define SYS_TICKDB (1ULL<<16) -#define BIN_NCCHNFO (1ULL<<17) -#define BIN_TIKDB (1ULL<<18) -#define BIN_KEYDB (1ULL<<19) -#define BIN_LEGKEY (1ULL<<20) -#define TXT_SCRIPT (1ULL<<21) -#define TXT_GENERIC (1ULL<<22) -#define NOIMG_NAND (1ULL<<23) -#define HDR_NAND (1ULL<<24) +#define GAME_3DSX (1ULL<<12) +#define GAME_NDS (1ULL<<13) +#define GAME_GBA (1ULL<<14) +#define SYS_FIRM (1ULL<<15) +#define SYS_AGBSAVE (1ULL<<16) +#define SYS_TICKDB (1ULL<<17) +#define BIN_NCCHNFO (1ULL<<18) +#define BIN_TIKDB (1ULL<<19) +#define BIN_KEYDB (1ULL<<20) +#define BIN_LEGKEY (1ULL<<21) +#define TXT_SCRIPT (1ULL<<22) +#define TXT_GENERIC (1ULL<<23) +#define NOIMG_NAND (1ULL<<24) +#define HDR_NAND (1ULL<<25) #define TYPE_BASE 0xFFFFFFFFULL // 32 bit reserved for base types #define FLAG_GBAVC (1ULL<<59) @@ -44,7 +45,7 @@ #define FTYPE_CXIDUMP(tp) (tp&(GAME_TMD)) #define FTYPE_TIKBUILD(tp) (tp&(GAME_TICKET|SYS_TICKDB|BIN_TIKDB)) #define FTYPE_KEYBUILD(tp) (tp&(BIN_KEYDB|BIN_LEGKEY)) -#define FTYPE_TITLEINFO(tp) (tp&(GAME_SMDH|GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_TMD|GAME_NDS|GAME_GBA)) +#define FTYPE_TITLEINFO(tp) (tp&(GAME_SMDH|GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_TMD|GAME_NDS|GAME_GBA|GAME_3DSX)) #define FTYPE_RENAMABLE(tp) (tp&(GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_NDS|GAME_GBA)) #define FTYPE_TRANSFERABLE(tp) ((u64) (tp&(IMG_FAT|FLAG_CTR)) == (u64) (IMG_FAT|FLAG_CTR)) #define FTYPE_NCSDFIXABLE(tp) (tp&(HDR_NAND|NOIMG_NAND)) diff --git a/source/game/3dsx.h b/source/game/3dsx.h new file mode 100644 index 0000000..f8b5f36 --- /dev/null +++ b/source/game/3dsx.h @@ -0,0 +1,23 @@ +#pragma once + +#include "common.h" + +#define THREEDSX_MAGIC '3', 'D', 'S', 'X' +#define THREEDSX_EXT_MAGIC THREEDSX_MAGIC, 0x2C, 0x00 + + +// see: http://3dbrew.org/wiki/3DSX_Format +typedef struct { + u8 magic[4]; // "3DSX" + u16 size_hdr; // 0x2C with extended header + u16 size_reloc_hdr; // 0x08 if existing + u32 version; // should be zero + u32 flags; // should be zero, too + u32 size_code; + u32 size_rodata; + u32 size_data_bss; + u32 size_bss; + u32 offset_smdh; + u32 size_smdh; + u32 size_romfs_lv3; +} __attribute__((packed)) ThreedsxHeader; diff --git a/source/game/game.h b/source/game/game.h index 6aa11d8..fdfdb57 100644 --- a/source/game/game.h +++ b/source/game/game.h @@ -11,4 +11,5 @@ #include "codelzss.h" #include "nds.h" #include "gba.h" +#include "3dsx.h" #include "ncchinfo.h" diff --git a/source/godmode.c b/source/godmode.c index 56b8557..c44713f 100644 --- a/source/godmode.c +++ b/source/godmode.c @@ -924,6 +924,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan (filetype & GAME_NDS) ? "NDS image options..." : (filetype & GAME_GBA) ? "GBA image options..." : (filetype & GAME_TICKET)? "Ticket options..." : + (filetype & GAME_3DSX) ? "Show 3DSX title info" : (filetype & SYS_FIRM ) ? "FIRM image options..." : (filetype & SYS_AGBSAVE)? (agbimportable) ? "AGBSAVE options..." : "Dump GBA VC save" : (filetype & SYS_TICKDB) ? (tik_buildable) ? "Ticket.db options..." : "Mount as ticket.db" : diff --git a/source/utils/gameutil.c b/source/utils/gameutil.c index a440889..63d2faf 100644 --- a/source/utils/gameutil.c +++ b/source/utils/gameutil.c @@ -1469,17 +1469,22 @@ u32 LoadSmdhFromGameFile(const char* path, Smdh* smdh) { if (LoadExeFsFile(smdh, path, NCSD_CNT0_OFFSET, "icon", sizeof(Smdh), NULL) == 0) return 0; } else if (filetype & GAME_CIA) { // CIA file CiaInfo info; - UINT btr; - if ((fvx_qread(path, &info, 0, 0x20, &btr) != FR_OK) || (btr != 0x20) || + if ((fvx_qread(path, &info, 0, 0x20, NULL) != FR_OK) || (GetCiaInfo(&info, (CiaHeader*) &info) != 0)) return 1; - if ((info.offset_meta) && (fvx_qread(path, smdh, info.offset_meta + 0x400, sizeof(Smdh), &btr) == FR_OK) && - (btr == sizeof(Smdh))) return 0; + if ((info.offset_meta) && (fvx_qread(path, smdh, info.offset_meta + 0x400, sizeof(Smdh), NULL) == FR_OK)) return 0; else if (LoadExeFsFile(smdh, path, info.offset_content, "icon", sizeof(Smdh), NULL) == 0) return 0; } else if (filetype & GAME_TMD) { char path_content[256]; if (GetTmdContentPath(path_content, path) != 0) return 1; return LoadSmdhFromGameFile(path_content, smdh); + } else if (filetype & GAME_3DSX) { + ThreedsxHeader threedsx; + if ((fvx_qread(path, &threedsx, 0, sizeof(ThreedsxHeader), NULL) != FR_OK) || + (!threedsx.offset_smdh || (threedsx.size_smdh != sizeof(Smdh))) || + (fvx_qread(path, smdh, threedsx.offset_smdh, sizeof(Smdh), NULL) != FR_OK)) + return 1; + return 0; } return 1;