mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 13:42:47 +00:00
Add title info display for NDS files
This commit is contained in:
parent
b9501318c5
commit
c19bc1c464
@ -63,6 +63,8 @@ u32 IdentifyFileType(const char* path) {
|
|||||||
return SYS_TICKDB; // ticket.db
|
return SYS_TICKDB; // ticket.db
|
||||||
} else if (memcmp(header, smdh_magic, sizeof(smdh_magic)) == 0) {
|
} else if (memcmp(header, smdh_magic, sizeof(smdh_magic)) == 0) {
|
||||||
return GAME_SMDH; // SMDH file
|
return GAME_SMDH; // SMDH file
|
||||||
|
} else if (ValidateTwlHeader((TwlHeader*) data) == 0) {
|
||||||
|
return GAME_NDS; // NDS rom file
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((fsize > sizeof(BossHeader)) &&
|
if ((fsize > sizeof(BossHeader)) &&
|
||||||
|
@ -14,11 +14,12 @@
|
|||||||
#define GAME_NUSCDN (1UL<<9)
|
#define GAME_NUSCDN (1UL<<9)
|
||||||
#define GAME_TICKET (1UL<<10)
|
#define GAME_TICKET (1UL<<10)
|
||||||
#define GAME_SMDH (1UL<<11)
|
#define GAME_SMDH (1UL<<11)
|
||||||
#define SYS_FIRM (1UL<<12)
|
#define GAME_NDS (1UL<<12)
|
||||||
#define SYS_TICKDB (1UL<<13)
|
#define SYS_FIRM (1UL<<13)
|
||||||
#define BIN_NCCHNFO (1UL<<14)
|
#define SYS_TICKDB (1UL<<14)
|
||||||
#define BIN_LAUNCH (1UL<<15)
|
#define BIN_NCCHNFO (1UL<<15)
|
||||||
#define BIN_SUPPORT (1UL<<16)
|
#define BIN_LAUNCH (1UL<<16)
|
||||||
|
#define BIN_SUPPORT (1UL<<17)
|
||||||
#define TYPE_BASE 0x00FFFFFF // 24 bit reserved for base types
|
#define TYPE_BASE 0x00FFFFFF // 24 bit reserved for base types
|
||||||
|
|
||||||
#define FLAG_CTR (1UL<<29)
|
#define FLAG_CTR (1UL<<29)
|
||||||
@ -31,7 +32,7 @@
|
|||||||
#define FYTPE_ENCRYPTABLE(tp) (tp&(GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_BOSS))
|
#define FYTPE_ENCRYPTABLE(tp) (tp&(GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_BOSS))
|
||||||
#define FTYPE_BUILDABLE(tp) (tp&(GAME_NCSD|GAME_NCCH|GAME_TMD))
|
#define FTYPE_BUILDABLE(tp) (tp&(GAME_NCSD|GAME_NCCH|GAME_TMD))
|
||||||
#define FTYPE_BUILDABLE_L(tp) (FTYPE_BUILDABLE(tp) && (tp&(GAME_TMD)))
|
#define FTYPE_BUILDABLE_L(tp) (FTYPE_BUILDABLE(tp) && (tp&(GAME_TMD)))
|
||||||
#define FTYPE_TITLEINFO(tp) (tp&(GAME_SMDH|GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_TMD))
|
#define FTYPE_TITLEINFO(tp) (tp&(GAME_SMDH|GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_TMD|GAME_NDS))
|
||||||
#define FTYPE_TRANSFERABLE(tp) ((u32) (tp&(IMG_FAT|FLAG_CTR)) == (u32) (IMG_FAT|FLAG_CTR))
|
#define FTYPE_TRANSFERABLE(tp) ((u32) (tp&(IMG_FAT|FLAG_CTR)) == (u32) (IMG_FAT|FLAG_CTR))
|
||||||
#define FTYPE_HSINJECTABLE(tp) ((u32) (tp&(GAME_NCCH|FLAG_CXI)) == (u32) (GAME_NCCH|FLAG_CXI))
|
#define FTYPE_HSINJECTABLE(tp) ((u32) (tp&(GAME_NCCH|FLAG_CXI)) == (u32) (GAME_NCCH|FLAG_CXI))
|
||||||
#define FTYPE_RESTORABLE(tp) (tp&(IMG_NAND))
|
#define FTYPE_RESTORABLE(tp) (tp&(IMG_NAND))
|
||||||
|
@ -8,4 +8,5 @@
|
|||||||
#include "firm.h"
|
#include "firm.h"
|
||||||
#include "boss.h"
|
#include "boss.h"
|
||||||
#include "smdh.h"
|
#include "smdh.h"
|
||||||
|
#include "nds.h"
|
||||||
#include "ncchinfo.h"
|
#include "ncchinfo.h"
|
||||||
|
@ -1455,6 +1455,23 @@ u32 ShowTmdFileTitleInfo(const char* path) {
|
|||||||
return ShowGameFileTitleInfo(path_content);
|
return ShowGameFileTitleInfo(path_content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 ShowNdsFileTitleInfo(const char* path) {
|
||||||
|
const u32 lwrap = 24;
|
||||||
|
TwlIconData* twl_icon = (TwlIconData*) TEMP_BUFFER;
|
||||||
|
u8* icon = (u8*) (TEMP_BUFFER + sizeof(TwlIconData));
|
||||||
|
char* desc = (char*) icon + TWLICON_SIZE_ICON;
|
||||||
|
if ((LoadTwlIconData(path, twl_icon) != 0) ||
|
||||||
|
(GetTwlIcon(icon, twl_icon) != 0) ||
|
||||||
|
(GetTwlTitle(desc, twl_icon) != 0))
|
||||||
|
return 1;
|
||||||
|
WordWrapString(desc, lwrap);
|
||||||
|
ShowIconString(icon, TWLICON_DIM_ICON, TWLICON_DIM_ICON, "%s", desc);
|
||||||
|
InputWait();
|
||||||
|
ClearScreenF(true, false, COLOR_STD_BG);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
u32 ShowGameFileTitleInfo(const char* path) {
|
u32 ShowGameFileTitleInfo(const char* path) {
|
||||||
u32 filetype = IdentifyFileType(path);
|
u32 filetype = IdentifyFileType(path);
|
||||||
u32 ret = 1;
|
u32 ret = 1;
|
||||||
@ -1470,6 +1487,8 @@ u32 ShowGameFileTitleInfo(const char* path) {
|
|||||||
ret = ShowCiaFileTitleInfo(path);
|
ret = ShowCiaFileTitleInfo(path);
|
||||||
} else if (filetype & GAME_TMD) {
|
} else if (filetype & GAME_TMD) {
|
||||||
ret = ShowTmdFileTitleInfo(path);
|
ret = ShowTmdFileTitleInfo(path);
|
||||||
|
} else if (filetype & GAME_NDS) {
|
||||||
|
ret = ShowNdsFileTitleInfo(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
75
source/game/nds.c
Normal file
75
source/game/nds.c
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#include "nds.h"
|
||||||
|
#include "vff.h"
|
||||||
|
|
||||||
|
#define CRC16_TABVAL 0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400
|
||||||
|
|
||||||
|
// see: https://github.com/TASVideos/desmume/blob/master/desmume/src/bios.cpp#L1070tions
|
||||||
|
u16 crc16_quick(const void* src, u32 len) {
|
||||||
|
const u16 tabval[] = { CRC16_TABVAL };
|
||||||
|
u16* data = (u16*) src;
|
||||||
|
u16 crc = 0xFFFF;
|
||||||
|
|
||||||
|
for (len >>= 1; len; len--) {
|
||||||
|
u16 curr = *(data++);
|
||||||
|
for (u32 i = 0; i < 4; i++) {
|
||||||
|
u16 tval = tabval[crc&0xF];
|
||||||
|
crc >>= 4;
|
||||||
|
crc ^= tval;
|
||||||
|
tval = tabval[(curr >> (4*i))&0xF];
|
||||||
|
crc ^= tval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 ValidateTwlHeader(TwlHeader* twl) {
|
||||||
|
if (twl->logo_crc != NDS_LOGO_CRC16) return 1;
|
||||||
|
return (crc16_quick(twl->logo, sizeof(twl->logo)) == NDS_LOGO_CRC16) ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 LoadTwlIconData(const char* path, TwlIconData* icon) {
|
||||||
|
u8 ntr_header[0x200]; // we only need the NTR header (ignore TWL stuff)
|
||||||
|
TwlHeader* twl = (TwlHeader*) ntr_header;
|
||||||
|
UINT br;
|
||||||
|
if ((fvx_qread(path, ntr_header, 0, 0x200, &br) != FR_OK) || (br != 0x200) ||
|
||||||
|
(ValidateTwlHeader(twl) != 0))
|
||||||
|
return 1;
|
||||||
|
// we also don't need anything beyond the v0x0001 icon, so ignore this, too
|
||||||
|
if ((fvx_qread(path, icon, twl->icon_offset, TWLICON_SIZE_DATA(0x0001), &br) != FR_OK) || (br != TWLICON_SIZE_DATA(0x0001)) ||
|
||||||
|
(!TWLICON_SIZE_DATA(icon->version)) || (crc16_quick(((u8*) icon) + 0x20, TWLICON_SIZE_DATA(0x0001) - 0x20) != icon->crc_0x0020_0x0840))
|
||||||
|
return 1;
|
||||||
|
icon->version = 0x0001; // just to be safe
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TWL title is max 128(+1) chars long
|
||||||
|
u32 GetTwlTitle(char* desc, const TwlIconData* twl_icon) {
|
||||||
|
const u16* title = twl_icon->title_eng; // english title
|
||||||
|
memset(desc, 0, TWLICON_SIZE_DESC + 1);
|
||||||
|
for (u32 i = 0; i < TWLICON_SIZE_DESC; i++) desc[i] = title[i];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TWL icon: 32x32 pixel, 8x8 tiles
|
||||||
|
u32 GetTwlIcon(u8* icon, const TwlIconData* twl_icon) {
|
||||||
|
const u32 h = TWLICON_DIM_ICON; // fixed size
|
||||||
|
const u32 w = TWLICON_DIM_ICON; // fixed size
|
||||||
|
u16* palette = twl_icon->palette;
|
||||||
|
u8* pix4 = (u8*) twl_icon->icon;
|
||||||
|
for (u32 y = 0; y < h; y += 8) {
|
||||||
|
for (u32 x = 0; x < w; x += 8) {
|
||||||
|
for (u32 i = 0; i < 8*8; i++) {
|
||||||
|
u32 ix = x + (i & 0x7);
|
||||||
|
u32 iy = y + (i >> 3);
|
||||||
|
u16 pix555 = palette[((i%2) ? (*pix4 >> 4) : *pix4) & 0xF];
|
||||||
|
u8* pix888 = icon + ((iy * w) + ix) * 3;
|
||||||
|
*(pix888++) = ((pix555 >> 10) & 0x1F) << 3; // B
|
||||||
|
*(pix888++) = ((pix555 >> 5) & 0x1F) << 3; // G
|
||||||
|
*(pix888++) = ((pix555 >> 0) & 0x1F) << 3; // R
|
||||||
|
if (i % 2) pix4++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
115
source/game/nds.h
Normal file
115
source/game/nds.h
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
// size of the icon struct:
|
||||||
|
// see: http://problemkaputt.de/gbatek.htm#dscartridgeicontitle
|
||||||
|
// v0x0001 -> 0x0840 byte (contains JAP, USA, FRE, GER, ITA, ESP titles)
|
||||||
|
// v0x0002 -> 0x0940 byte (adds CHN title)
|
||||||
|
// v0x0003 -> 0x0A40 byte (adds KOR title)
|
||||||
|
// v0x0103 -> 0x23C0 byte (adds TWL animated icon data)
|
||||||
|
#define TWLICON_SIZE_DATA(v) ((v == 0x0001) ? 0x0840 : (v == 0x0002) ? 0x0940 : \
|
||||||
|
(v == 0x0003) ? 0x1240 : (v == 0x0103) ? 0x23C0 : 0x0000)
|
||||||
|
#define TWLICON_SIZE_DESC 128
|
||||||
|
#define TWLICON_DIM_ICON 32
|
||||||
|
#define TWLICON_SIZE_ICON (TWLICON_DIM_ICON * TWLICON_DIM_ICON * 3) // w * h * bpp (rgb888)
|
||||||
|
#define NDS_LOGO_CRC16 0xCF56
|
||||||
|
|
||||||
|
// see: http://problemkaputt.de/gbatek.htm#dscartridgeicontitle
|
||||||
|
typedef struct {
|
||||||
|
u16 version;
|
||||||
|
u16 crc_0x0020_0x0840;
|
||||||
|
u16 crc_0x0020_0x0940;
|
||||||
|
u16 crc_0x0020_0x0A40;
|
||||||
|
u16 crc_0x1240_0x23C0;
|
||||||
|
u8 reserved[0x16];
|
||||||
|
u8 icon[0x200]; // 32x32x4bpp / 4x4 tiles
|
||||||
|
u16 palette[0x10]; // palette[0] is transparent
|
||||||
|
u16 title_jap[0x80];
|
||||||
|
u16 title_eng[0x80];
|
||||||
|
u16 title_fre[0x80];
|
||||||
|
u16 title_ger[0x80];
|
||||||
|
u16 title_ita[0x80];
|
||||||
|
u16 title_spa[0x80];
|
||||||
|
u16 title_chn[0x80];
|
||||||
|
u16 title_kor[0x80];
|
||||||
|
u16 title_reserved[0x8 * 0x80];
|
||||||
|
u8 icon_anim[0x200 * 0x8]; // 32x32x4bpp / 8 frames
|
||||||
|
u16 palette_anim[0x10 * 0x8]; // 8 frames
|
||||||
|
u16 sequence_anim[0x40];
|
||||||
|
} __attribute__((packed)) TwlIconData;
|
||||||
|
|
||||||
|
// very limited, information taken from here:
|
||||||
|
// https://github.com/devkitPro/ndstool/blob/dsi-support/source/header.h
|
||||||
|
// http://problemkaputt.de/gbatek.htm#dscartridgeheader
|
||||||
|
// http://problemkaputt.de/gbatek.htm#dsicartridgeheader
|
||||||
|
typedef struct {
|
||||||
|
// common stuff (DS + DSi)
|
||||||
|
char game_title[12];
|
||||||
|
char game_code[4];
|
||||||
|
char maker_code[2];
|
||||||
|
u8 unit_code; // (0x00=NDS, 0x02=NDS+DSi, 0x03=DSi)
|
||||||
|
u8 seed_select;
|
||||||
|
u8 device_capacity; // cartridge size: (128 * 1024) << this
|
||||||
|
u8 reserved0[7];
|
||||||
|
u8 dsi_flags;
|
||||||
|
u8 nds_region;
|
||||||
|
u8 rom_version;
|
||||||
|
u8 autostart; // bit2: skip "press button" after Health & Safety
|
||||||
|
u32 arm9_rom_offset;
|
||||||
|
u32 arm9_entry_address;
|
||||||
|
u32 arm9_ram_address;
|
||||||
|
u32 arm9_size;
|
||||||
|
u32 arm7_rom_offset;
|
||||||
|
u32 arm7_entry_address;
|
||||||
|
u32 arm7_ram_address;
|
||||||
|
u32 arm7_size;
|
||||||
|
u32 fnt_offset;
|
||||||
|
u32 fnt_size;
|
||||||
|
u32 fat_offset;
|
||||||
|
u32 fat_size;
|
||||||
|
u32 arm9_overlay_offset;
|
||||||
|
u32 arm9_overlay_size;
|
||||||
|
u32 arm7_overlay_offset;
|
||||||
|
u32 arm7_overlay_size;
|
||||||
|
u32 rom_control_normal; // 0x00416657 for OneTimePROM
|
||||||
|
u32 rom_control_key1; // 0x081808F8 for OneTimePROM
|
||||||
|
u32 icon_offset;
|
||||||
|
u16 secure_area_crc;
|
||||||
|
u16 secure_area_delay;
|
||||||
|
u32 arm9_auto_load;
|
||||||
|
u32 arm7_auto_load;
|
||||||
|
u64 secure_area_disable;
|
||||||
|
u32 ntr_rom_size; // in byte
|
||||||
|
u32 header_size;
|
||||||
|
u8 reserved1[56];
|
||||||
|
u8 logo[156];
|
||||||
|
u16 logo_crc;
|
||||||
|
u16 header_crc;
|
||||||
|
u8 debugger_reserved[0x20];
|
||||||
|
// extended mode stuff (DSi only)
|
||||||
|
u8 ignored0[0x40]; // ignored
|
||||||
|
u32 arm9i_rom_offset;
|
||||||
|
u32 reserved2;
|
||||||
|
u32 arm9i_load_adress;
|
||||||
|
u32 arm9i_size;
|
||||||
|
u32 arm7i_rom_offset;
|
||||||
|
u32 unknown1;
|
||||||
|
u32 arm7i_load_adress;
|
||||||
|
u32 arm7i_size;
|
||||||
|
u8 ignored1[0x30]; // ignored
|
||||||
|
u32 ntr_twl_rom_size;
|
||||||
|
u8 unknown2[12];
|
||||||
|
u8 ignored2[0x10]; // ignored
|
||||||
|
u64 title_id;
|
||||||
|
u32 pubsav_size;
|
||||||
|
u32 prvsav_size;
|
||||||
|
u8 reserved3[176];
|
||||||
|
u8 unknown3[0x10];
|
||||||
|
u8 ignored3[0xD00]; // ignored
|
||||||
|
} __attribute__((packed)) TwlHeader;
|
||||||
|
|
||||||
|
u32 ValidateTwlHeader(TwlHeader* twl);
|
||||||
|
u32 LoadTwlIconData(const char* path, TwlIconData* icon);
|
||||||
|
u32 GetTwlTitle(char* desc, const TwlIconData* twl_icon);
|
||||||
|
u32 GetTwlIcon(u8* icon, const TwlIconData* twl_icon);
|
@ -3,7 +3,7 @@
|
|||||||
#include "command_ctr.h"
|
#include "command_ctr.h"
|
||||||
#include "command_ntr.h"
|
#include "command_ntr.h"
|
||||||
#include "card_eeprom.h"
|
#include "card_eeprom.h"
|
||||||
#include "ndsheader.h"
|
#include "nds.h"
|
||||||
#include "ncch.h"
|
#include "ncch.h"
|
||||||
#include "ncsd.h"
|
#include "ncsd.h"
|
||||||
|
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
// very limited, information taken from here:
|
|
||||||
// https://github.com/devkitPro/ndstool/blob/dsi-support/source/header.h
|
|
||||||
typedef struct {
|
|
||||||
// common stuff (DS + DSi)
|
|
||||||
char game_title[12];
|
|
||||||
char game_code[4];
|
|
||||||
char maker_code[2];
|
|
||||||
u8 unit_code; // (0x00=NDS, 0x02=NDS+DSi, 0x03=DSi)
|
|
||||||
u8 seed_select;
|
|
||||||
u8 device_capacity; // cartridge size: (128 * 1024) << this
|
|
||||||
u8 reserved0[7];
|
|
||||||
u8 unknown0[2];
|
|
||||||
u8 rom_version;
|
|
||||||
u8 flags;
|
|
||||||
u8 ignored0[0x60]; // ignored
|
|
||||||
u32 ntr_rom_size; // in byte
|
|
||||||
u32 header_size;
|
|
||||||
u8 reserved1[56];
|
|
||||||
u8 logo[156];
|
|
||||||
u16 logo_crc;
|
|
||||||
u16 header_crc;
|
|
||||||
u8 debugger_reserved[0x20];
|
|
||||||
// extended mode stuff (DSi only)
|
|
||||||
u8 ignored1[0x40]; // ignored
|
|
||||||
u32 arm9i_rom_offset;
|
|
||||||
u32 reserved2;
|
|
||||||
u32 arm9i_load_adress;
|
|
||||||
u32 arm9i_size;
|
|
||||||
u32 arm7i_rom_offset;
|
|
||||||
u32 unknown1;
|
|
||||||
u32 arm7i_load_adress;
|
|
||||||
u32 arm7i_size;
|
|
||||||
u8 ignored2[0x30]; // ignored
|
|
||||||
u32 ntr_twl_rom_size;
|
|
||||||
u8 unknown2[12];
|
|
||||||
u8 ignored3[0x10]; // ignored
|
|
||||||
u64 title_id;
|
|
||||||
u32 pubsav_size;
|
|
||||||
u32 prvsav_size;
|
|
||||||
u8 reserved3[176];
|
|
||||||
u8 unknown3[0x10];
|
|
||||||
u8 ignored4[0xD00]; // ignored
|
|
||||||
} __attribute__((packed)) TwlHeader;
|
|
@ -697,6 +697,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
(filetype & GAME_BOSS ) ? "BOSS file options..." :
|
(filetype & GAME_BOSS ) ? "BOSS file options..." :
|
||||||
(filetype & GAME_NUSCDN)? "Decrypt NUS/CDN file" :
|
(filetype & GAME_NUSCDN)? "Decrypt NUS/CDN file" :
|
||||||
(filetype & GAME_SMDH) ? "Show SMDH title info" :
|
(filetype & GAME_SMDH) ? "Show SMDH title info" :
|
||||||
|
(filetype & GAME_NDS) ? "Show NDS title info" :
|
||||||
(filetype & SYS_FIRM ) ? "FIRM image options..." :
|
(filetype & SYS_FIRM ) ? "FIRM image options..." :
|
||||||
(filetype & SYS_TICKDB) ? "Mount as ticket.db" :
|
(filetype & SYS_TICKDB) ? "Mount as ticket.db" :
|
||||||
(filetype & BIN_NCCHNFO)? "NCCHinfo options..." :
|
(filetype & BIN_NCCHNFO)? "NCCHinfo options..." :
|
||||||
|
Loading…
x
Reference in New Issue
Block a user