mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 21:52:48 +00:00
Limited GBA rom image support
... support for: * proper extension when extracting from .code * showing title info * renaming cartridge images
This commit is contained in:
parent
5462f2d5e8
commit
5d4d122543
@ -2,7 +2,7 @@
|
|||||||
#include "vff.h"
|
#include "vff.h"
|
||||||
|
|
||||||
static FIL mount_file;
|
static FIL mount_file;
|
||||||
static u32 mount_state = 0;
|
static u64 mount_state = 0;
|
||||||
|
|
||||||
static char mount_path[256] = { 0 };
|
static char mount_path[256] = { 0 };
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ u64 GetMountSize(void) {
|
|||||||
return mount_state ? fvx_size(&mount_file) : 0;
|
return mount_state ? fvx_size(&mount_file) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GetMountState(void) {
|
u64 GetMountState(void) {
|
||||||
return mount_state;
|
return mount_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,8 +55,8 @@ const char* GetMountPath(void) {
|
|||||||
return mount_path;
|
return mount_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 MountImage(const char* path) {
|
u64 MountImage(const char* path) {
|
||||||
u32 type = (path) ? IdentifyFileType(path) : 0;
|
u64 type = (path) ? IdentifyFileType(path) : 0;
|
||||||
if (mount_state) {
|
if (mount_state) {
|
||||||
fvx_close(&mount_file);
|
fvx_close(&mount_file);
|
||||||
mount_state = 0;
|
mount_state = 0;
|
||||||
|
@ -10,6 +10,6 @@ int WriteImageSectors(const void* buffer, u32 sector, u32 count);
|
|||||||
int SyncImage(void);
|
int SyncImage(void);
|
||||||
|
|
||||||
u64 GetMountSize(void);
|
u64 GetMountSize(void);
|
||||||
u32 GetMountState(void);
|
u64 GetMountState(void);
|
||||||
const char* GetMountPath(void);
|
const char* GetMountPath(void);
|
||||||
u32 MountImage(const char* path);
|
u64 MountImage(const char* path);
|
||||||
|
@ -3,12 +3,11 @@
|
|||||||
#include "fatmbr.h"
|
#include "fatmbr.h"
|
||||||
#include "nand.h"
|
#include "nand.h"
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
#include "agbsave.h"
|
|
||||||
#include "keydb.h"
|
#include "keydb.h"
|
||||||
#include "ctrtransfer.h"
|
#include "ctrtransfer.h"
|
||||||
#include "scripting.h"
|
#include "scripting.h"
|
||||||
|
|
||||||
u32 IdentifyFileType(const char* path) {
|
u64 IdentifyFileType(const char* path) {
|
||||||
const u8 romfs_magic[] = { ROMFS_MAGIC };
|
const u8 romfs_magic[] = { ROMFS_MAGIC };
|
||||||
const u8 tickdb_magic[] = { TICKDB_MAGIC };
|
const u8 tickdb_magic[] = { TICKDB_MAGIC };
|
||||||
const u8 smdh_magic[] = { SMDH_MAGIC };
|
const u8 smdh_magic[] = { SMDH_MAGIC };
|
||||||
@ -20,7 +19,7 @@ u32 IdentifyFileType(const char* path) {
|
|||||||
char* ext = (fname) ? strrchr(++fname, '.') : NULL;
|
char* ext = (fname) ? strrchr(++fname, '.') : NULL;
|
||||||
u32 id = 0;
|
u32 id = 0;
|
||||||
if (ext) ext++;
|
if (ext) ext++;
|
||||||
if (FileGetData(path, header, 0x200, 0) < ((fsize > 0x200) ? 0x200 : fsize)) return 0;
|
if (FileGetData(path, header, 0x200, 0) < min(0x200, fsize)) return 0;
|
||||||
|
|
||||||
if (!fsize) return 0;
|
if (!fsize) return 0;
|
||||||
if (fsize >= 0x200) {
|
if (fsize >= 0x200) {
|
||||||
@ -49,7 +48,15 @@ u32 IdentifyFileType(const char* path) {
|
|||||||
return GAME_NCSD; // NCSD (".3DS") file
|
return GAME_NCSD; // NCSD (".3DS") file
|
||||||
} else if (ValidateNcchHeader((NcchHeader*) data) == 0) {
|
} else if (ValidateNcchHeader((NcchHeader*) data) == 0) {
|
||||||
NcchHeader* ncch = (NcchHeader*) data;
|
NcchHeader* ncch = (NcchHeader*) data;
|
||||||
u32 type = GAME_NCCH | (NCCH_IS_CXI(ncch) ? FLAG_CXI : 0);
|
u32 type = GAME_NCCH;
|
||||||
|
if (NCCH_IS_CXI(ncch)) {
|
||||||
|
type |= FLAG_CXI;
|
||||||
|
NcchExtHeader exhdr;
|
||||||
|
if ((FileGetData(path, &exhdr, 0x400, 0x200) == 0x400) && // read only what we need
|
||||||
|
(DecryptNcch(&exhdr, 0x200, 0x400, ncch, NULL) == 0) &&
|
||||||
|
NCCH_IS_GBAVC(&exhdr))
|
||||||
|
type |= FLAG_GBAVC;
|
||||||
|
}
|
||||||
if (fsize >= (ncch->size * NCCH_MEDIA_UNIT))
|
if (fsize >= (ncch->size * NCCH_MEDIA_UNIT))
|
||||||
return type; // NCCH (".APP") file
|
return type; // NCCH (".APP") file
|
||||||
} else if (ValidateExeFsHeader((ExeFsHeader*) data, fsize) == 0) {
|
} else if (ValidateExeFsHeader((ExeFsHeader*) data, fsize) == 0) {
|
||||||
@ -77,14 +84,16 @@ u32 IdentifyFileType(const char* path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((fsize > sizeof(BossHeader)) &&
|
if ((fsize > sizeof(AgbHeader)) &&
|
||||||
|
(ValidateAgbHeader((AgbHeader*) data) == 0)) {
|
||||||
|
return GAME_GBA;
|
||||||
|
} else if ((fsize > sizeof(BossHeader)) &&
|
||||||
(ValidateBossHeader((BossHeader*) data, fsize) == 0)) {
|
(ValidateBossHeader((BossHeader*) data, fsize) == 0)) {
|
||||||
return GAME_BOSS; // BOSS (SpotPass) file
|
return GAME_BOSS; // BOSS (SpotPass) file
|
||||||
} else if ((fsize > sizeof(NcchInfoHeader)) &&
|
} else if ((fsize > sizeof(NcchInfoHeader)) &&
|
||||||
(GetNcchInfoVersion((NcchInfoHeader*) data)) &&
|
(GetNcchInfoVersion((NcchInfoHeader*) data)) &&
|
||||||
fname && (strncasecmp(fname, NCCHINFO_NAME, 32) == 0)) {
|
fname && (strncasecmp(fname, NCCHINFO_NAME, 32) == 0)) {
|
||||||
return BIN_NCCHNFO; // ncchinfo.bin file
|
return BIN_NCCHNFO; // ncchinfo.bin file
|
||||||
|
|
||||||
} else if (ext && ((strncasecmp(ext, "cdn", 4) == 0) || (strncasecmp(ext, "nus", 4) == 0))) {
|
} else if (ext && ((strncasecmp(ext, "cdn", 4) == 0) || (strncasecmp(ext, "nus", 4) == 0))) {
|
||||||
char path_cetk[256];
|
char path_cetk[256];
|
||||||
char* ext_cetk = path_cetk + (ext - path);
|
char* ext_cetk = path_cetk + (ext - path);
|
||||||
|
@ -2,36 +2,38 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#define IMG_FAT (1UL<<0)
|
#define IMG_FAT (1ULL<<0)
|
||||||
#define IMG_NAND (1UL<<1)
|
#define IMG_NAND (1ULL<<1)
|
||||||
#define GAME_CIA (1UL<<2)
|
#define GAME_CIA (1ULL<<2)
|
||||||
#define GAME_NCSD (1UL<<3)
|
#define GAME_NCSD (1ULL<<3)
|
||||||
#define GAME_NCCH (1UL<<4)
|
#define GAME_NCCH (1ULL<<4)
|
||||||
#define GAME_TMD (1UL<<5)
|
#define GAME_TMD (1ULL<<5)
|
||||||
#define GAME_EXEFS (1UL<<6)
|
#define GAME_EXEFS (1ULL<<6)
|
||||||
#define GAME_ROMFS (1UL<<7)
|
#define GAME_ROMFS (1ULL<<7)
|
||||||
#define GAME_BOSS (1UL<<8)
|
#define GAME_BOSS (1ULL<<8)
|
||||||
#define GAME_NUSCDN (1UL<<9)
|
#define GAME_NUSCDN (1ULL<<9)
|
||||||
#define GAME_TICKET (1UL<<10)
|
#define GAME_TICKET (1ULL<<10)
|
||||||
#define GAME_SMDH (1UL<<11)
|
#define GAME_SMDH (1ULL<<11)
|
||||||
#define GAME_NDS (1UL<<12)
|
#define GAME_NDS (1ULL<<12)
|
||||||
#define SYS_FIRM (1UL<<13)
|
#define GAME_GBA (1ULL<<13)
|
||||||
#define SYS_AGBSAVE (1UL<<14)
|
#define SYS_FIRM (1ULL<<14)
|
||||||
#define SYS_TICKDB (1UL<<15)
|
#define SYS_AGBSAVE (1ULL<<15)
|
||||||
#define BIN_NCCHNFO (1UL<<16)
|
#define SYS_TICKDB (1ULL<<16)
|
||||||
#define BIN_TIKDB (1UL<<17)
|
#define BIN_NCCHNFO (1ULL<<17)
|
||||||
#define BIN_KEYDB (1UL<<18)
|
#define BIN_TIKDB (1ULL<<18)
|
||||||
#define BIN_LEGKEY (1UL<<19)
|
#define BIN_KEYDB (1ULL<<19)
|
||||||
#define TXT_SCRIPT (1UL<<20)
|
#define BIN_LEGKEY (1ULL<<20)
|
||||||
#define TXT_GENERIC (1UL<<21)
|
#define TXT_SCRIPT (1ULL<<21)
|
||||||
#define NOIMG_NAND (1UL<<22)
|
#define TXT_GENERIC (1ULL<<22)
|
||||||
#define HDR_NAND (1UL<<23)
|
#define NOIMG_NAND (1ULL<<23)
|
||||||
#define TYPE_BASE 0x00FFFFFF // 24 bit reserved for base types
|
#define HDR_NAND (1ULL<<24)
|
||||||
|
#define TYPE_BASE 0xFFFFFFFFULL // 32 bit reserved for base types
|
||||||
|
|
||||||
#define FLAG_ENC (1UL<<28)
|
#define FLAG_GBAVC (1ULL<<59)
|
||||||
#define FLAG_CTR (1UL<<29)
|
#define FLAG_ENC (1ULL<<60)
|
||||||
#define FLAG_NUSCDN (1UL<<30)
|
#define FLAG_CTR (1ULL<<61)
|
||||||
#define FLAG_CXI (1UL<<31)
|
#define FLAG_NUSCDN (1ULL<<62)
|
||||||
|
#define FLAG_CXI (1ULL<<63)
|
||||||
|
|
||||||
#define FTYPE_MOUNTABLE(tp) (tp&(IMG_FAT|IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_EXEFS|GAME_ROMFS|GAME_NDS|SYS_FIRM|SYS_TICKDB|BIN_KEYDB))
|
#define FTYPE_MOUNTABLE(tp) (tp&(IMG_FAT|IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_EXEFS|GAME_ROMFS|GAME_NDS|SYS_FIRM|SYS_TICKDB|BIN_KEYDB))
|
||||||
#define FYTPE_VERIFICABLE(tp) (tp&(IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_TMD|GAME_BOSS|SYS_FIRM))
|
#define FYTPE_VERIFICABLE(tp) (tp&(IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_TMD|GAME_BOSS|SYS_FIRM))
|
||||||
@ -42,8 +44,8 @@
|
|||||||
#define FTYPE_CXIDUMP(tp) (tp&(GAME_TMD))
|
#define FTYPE_CXIDUMP(tp) (tp&(GAME_TMD))
|
||||||
#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_SMDH|GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_TMD|GAME_NDS))
|
#define FTYPE_TITLEINFO(tp) (tp&(GAME_SMDH|GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_TMD|GAME_NDS|GAME_GBA))
|
||||||
#define FTYPE_RENAMABLE(tp) (tp&(GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_NDS))
|
#define FTYPE_RENAMABLE(tp) (tp&(GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_NDS|GAME_GBA))
|
||||||
#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_NCSDFIXABLE(tp) (tp&(HDR_NAND|NOIMG_NAND))
|
#define FTYPE_NCSDFIXABLE(tp) (tp&(HDR_NAND|NOIMG_NAND))
|
||||||
#define FTYPE_HASCODE(tp) ((u32) (tp&(GAME_NCCH|FLAG_CXI)) == (u32) (GAME_NCCH|FLAG_CXI))
|
#define FTYPE_HASCODE(tp) ((u32) (tp&(GAME_NCCH|FLAG_CXI)) == (u32) (GAME_NCCH|FLAG_CXI))
|
||||||
@ -56,4 +58,4 @@
|
|||||||
#define FTYPE_INSTALLABLE(tp) (tp&(SYS_FIRM))
|
#define FTYPE_INSTALLABLE(tp) (tp&(SYS_FIRM))
|
||||||
#define FTPYE_AGBSAVE(tp) (tp&(SYS_AGBSAVE))
|
#define FTPYE_AGBSAVE(tp) (tp&(SYS_AGBSAVE))
|
||||||
|
|
||||||
u32 IdentifyFileType(const char* path);
|
u64 IdentifyFileType(const char* path);
|
||||||
|
@ -44,7 +44,7 @@ bool InitImgFS(const char* path) {
|
|||||||
// deinit image filesystem
|
// deinit image filesystem
|
||||||
DismountDriveType(DRV_IMAGE);
|
DismountDriveType(DRV_IMAGE);
|
||||||
// (re)mount image, done if path == NULL
|
// (re)mount image, done if path == NULL
|
||||||
u32 type = MountImage(path);
|
u64 type = MountImage(path);
|
||||||
InitVirtualImageDrive();
|
InitVirtualImageDrive();
|
||||||
if ((type&IMG_NAND) && (drv_i < NORM_FS)) drv_i = NORM_FS;
|
if ((type&IMG_NAND) && (drv_i < NORM_FS)) drv_i = NORM_FS;
|
||||||
else if ((type&IMG_FAT) && (drv_i < NORM_FS - IMGN_FS + 1)) drv_i = NORM_FS - IMGN_FS + 1;
|
else if ((type&IMG_FAT) && (drv_i < NORM_FS - IMGN_FS + 1)) drv_i = NORM_FS - IMGN_FS + 1;
|
||||||
|
@ -10,4 +10,5 @@
|
|||||||
#include "smdh.h"
|
#include "smdh.h"
|
||||||
#include "codelzss.h"
|
#include "codelzss.h"
|
||||||
#include "nds.h"
|
#include "nds.h"
|
||||||
|
#include "gba.h"
|
||||||
#include "ncchinfo.h"
|
#include "ncchinfo.h"
|
||||||
|
51
source/game/gba.c
Normal file
51
source/game/gba.c
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#include "gba.h"
|
||||||
|
#include "sha.h"
|
||||||
|
#include "sdmmc.h"
|
||||||
|
|
||||||
|
#define AGBLOGO_SHA256 \
|
||||||
|
0x08, 0xA0, 0x15, 0x3C, 0xFD, 0x6B, 0x0E, 0xA5, 0x4B, 0x93, 0x8F, 0x7D, 0x20, 0x99, 0x33, 0xFA, \
|
||||||
|
0x84, 0x9D, 0xA0, 0xD5, 0x6F, 0x5A, 0x34, 0xC4, 0x81, 0x06, 0x0C, 0x9F, 0xF2, 0xFA, 0xD8, 0x18
|
||||||
|
|
||||||
|
u32 ValidateAgbSaveHeader(AgbSaveHeader* header) {
|
||||||
|
u8 magic[] = { AGBSAVE_MAGIC };
|
||||||
|
|
||||||
|
// basic checks
|
||||||
|
if ((memcmp(header->magic, magic, sizeof(magic)) != 0) ||
|
||||||
|
(header->unknown0 != 1) || (header->save_start != 0x200) ||
|
||||||
|
(header->save_size > AGBSAVE_MAX_SSIZE) || !(GBASAVE_VALID(header->save_size)))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// reserved area checks
|
||||||
|
for (u32 i = 0; i < sizeof(header->reserved0); i++) if (header->reserved0[i] != 0xFF) return 1;
|
||||||
|
for (u32 i = 0; i < sizeof(header->reserved1); i++) if (header->reserved1[i] != 0xFF) return 1;
|
||||||
|
for (u32 i = 0; i < sizeof(header->reserved2); i++) if (header->reserved2[i] != 0xFF) return 1;
|
||||||
|
for (u32 i = 0; i < sizeof(header->reserved3); i++) if (header->reserved3[i] != 0xFF) return 1;
|
||||||
|
|
||||||
|
// all fine if arriving here
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://problemkaputt.de/gbatek.htm#gbacartridgeheader
|
||||||
|
u32 ValidateAgbHeader(AgbHeader* agb) {
|
||||||
|
const u8 logo_sha[0x20] = { AGBLOGO_SHA256 };
|
||||||
|
u8 logo[0x9C];
|
||||||
|
|
||||||
|
// check fixed value
|
||||||
|
if (agb->fixed != 0x96) return 1;
|
||||||
|
|
||||||
|
// header checksum
|
||||||
|
u8* hdr = (u8*) agb;
|
||||||
|
u8 checksum = 0x00 - 0x19;
|
||||||
|
for (u32 i = 0xA0; i < 0xBD; i++)
|
||||||
|
checksum -= hdr[i];
|
||||||
|
if (agb->checksum != checksum) return 1;
|
||||||
|
|
||||||
|
// logo SHA check
|
||||||
|
memcpy(logo, agb->logo, 0x9C);
|
||||||
|
logo[0x98] &= ~0x84;
|
||||||
|
logo[0x9A] &= ~0x03;
|
||||||
|
if (sha_cmp(logo_sha, logo, 0x9C, SHA256_MODE) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
94
source/game/gba.h
Normal file
94
source/game/gba.h
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "gba.h"
|
||||||
|
|
||||||
|
#define GBAVC_MAGIC '.', 'C', 'A', 'A'
|
||||||
|
#define AGBSAVE_MAGIC '.', 'S', 'A', 'V'
|
||||||
|
#define AGBSAVE_MAX_SIZE (0x000180 * 0x200) // standard size of the NAND partition
|
||||||
|
#define AGBSAVE_MAX_SSIZE (AGBSAVE_MAX_SIZE - sizeof(AgbSaveHeader))
|
||||||
|
|
||||||
|
// see: http://3dbrew.org/wiki/3DS_Virtual_Console#Footer
|
||||||
|
#define GBASAVE_EEPROM_512 (512)
|
||||||
|
#define GBASAVE_EEPROM_8K (8 * 1024)
|
||||||
|
#define GBASAVE_SRAM_32K (32 * 1024)
|
||||||
|
#define GBASAVE_FLASH_64K (64 * 1024)
|
||||||
|
#define GBASAVE_FLASH_128K (128 * 1024)
|
||||||
|
|
||||||
|
#define GBASAVE_SIZE(tp) \
|
||||||
|
(((tp == 0x0) || (tp == 0x1)) ? GBASAVE_EEPROM_512 : \
|
||||||
|
((tp == 0x2) || (tp == 0x3)) ? GBASAVE_EEPROM_8K : \
|
||||||
|
((tp >= 0x4) && (tp <= 0x9)) ? GBASAVE_FLASH_64K : \
|
||||||
|
((tp >= 0xA) && (tp <= 0xD)) ? GBASAVE_FLASH_128K : \
|
||||||
|
(tp == 0xE) ? GBASAVE_SRAM_32K : 0); // last one means invalid
|
||||||
|
|
||||||
|
#define GBASAVE_VALID(size) \
|
||||||
|
(((size) == GBASAVE_EEPROM_512) || \
|
||||||
|
((size) == GBASAVE_EEPROM_8K) || \
|
||||||
|
((size) == GBASAVE_SRAM_32K) || \
|
||||||
|
((size) == GBASAVE_FLASH_64K) || \
|
||||||
|
((size) == GBASAVE_FLASH_128K))
|
||||||
|
|
||||||
|
// see: http://problemkaputt.de/gbatek.htm#gbacartridgeheader
|
||||||
|
#define AGB_DESTSTR(code) \
|
||||||
|
(((code)[3] == 'J') ? "Japan" : \
|
||||||
|
((code)[3] == 'E') ? "USA/English" : \
|
||||||
|
((code)[3] == 'P') ? "Europe/Elsewhere" : \
|
||||||
|
((code)[3] == 'D') ? "German" : \
|
||||||
|
((code)[3] == 'F') ? "French" : \
|
||||||
|
((code)[3] == 'I') ? "Italian" : \
|
||||||
|
((code)[3] == 'S') ? "Spanish" : "Unknown")
|
||||||
|
|
||||||
|
|
||||||
|
// see: http://3dbrew.org/wiki/3DS_Virtual_Console#Footer
|
||||||
|
// still a lot of unknowns in here, also redundant stuff left out
|
||||||
|
typedef struct {
|
||||||
|
u8 unknown0[4];
|
||||||
|
u32 rom_size;
|
||||||
|
u32 save_type;
|
||||||
|
u8 unknown1[20];
|
||||||
|
u32 lcd_ghosting;
|
||||||
|
u8 video_lut[0x300];
|
||||||
|
u8 unknown2[44];
|
||||||
|
u8 magic[4]; // ".CAA"
|
||||||
|
u8 unknown3[12];
|
||||||
|
} __attribute__((packed)) AgbVcFooter;
|
||||||
|
|
||||||
|
// see: http://3dbrew.org/wiki/3DS_Virtual_Console#NAND_Savegame
|
||||||
|
typedef struct {
|
||||||
|
u8 magic[4]; // ".SAV"
|
||||||
|
u8 reserved0[0xC]; // always 0xFF
|
||||||
|
u8 cmac[0x10];
|
||||||
|
u8 reserved1[0x10]; // always 0xFF
|
||||||
|
u32 unknown0; // always 0x01
|
||||||
|
u32 times_saved;
|
||||||
|
u64 title_id;
|
||||||
|
u8 sd_cid[0x10];
|
||||||
|
u32 save_start; // always 0x200
|
||||||
|
u32 save_size;
|
||||||
|
u8 reserved2[0x8]; // always 0xFF
|
||||||
|
u32 unknown1; // has to do with ARM7?
|
||||||
|
u32 unknown2; // has to do with ARM7?
|
||||||
|
u8 reserved3[0x198]; // always 0xFF
|
||||||
|
} __attribute__((packed)) AgbSaveHeader;
|
||||||
|
|
||||||
|
// see: http://problemkaputt.de/gbatek.htm#gbacartridgeheader
|
||||||
|
typedef struct {
|
||||||
|
u32 arm7_rom_entry;
|
||||||
|
u8 logo[0x9C];
|
||||||
|
char game_title[12];
|
||||||
|
char game_code[4];
|
||||||
|
char maker_code[2];
|
||||||
|
u8 fixed; // 0x96, required!
|
||||||
|
u8 unit_code; // 0x00 for current GBA
|
||||||
|
u8 device_type; // 0x00 usually
|
||||||
|
u8 reserved0[7]; // always 0x00
|
||||||
|
u8 software_version; // 0x00 usually
|
||||||
|
u8 checksum; // header checksum, required
|
||||||
|
u8 reserved[2]; // always 0x00
|
||||||
|
// stuff for multiboot not included
|
||||||
|
} __attribute__((packed)) AgbHeader;
|
||||||
|
|
||||||
|
|
||||||
|
u32 ValidateAgbSaveHeader(AgbSaveHeader* header);
|
||||||
|
u32 ValidateAgbHeader(AgbHeader* agb);
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#define NCCH_ENCRYPTED(ncch) (!((ncch)->flags[7] & 0x04))
|
#define NCCH_ENCRYPTED(ncch) (!((ncch)->flags[7] & 0x04))
|
||||||
#define NCCH_IS_CXI(ncch) ((ncch)->flags[5] & 0x02)
|
#define NCCH_IS_CXI(ncch) ((ncch)->flags[5] & 0x02)
|
||||||
|
#define NCCH_IS_GBAVC(exhdr) (getle32((exhdr)->aci_data + 8) == 0x00000202)
|
||||||
|
|
||||||
#define NCCH_NOCRYPTO 0x0004
|
#define NCCH_NOCRYPTO 0x0004
|
||||||
#define NCCH_STDCRYPTO 0x0000
|
#define NCCH_STDCRYPTO 0x0000
|
||||||
|
@ -835,7 +835,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
|||||||
// check for file lock
|
// check for file lock
|
||||||
if (!FileUnlock(curr_entry->path)) return 1;
|
if (!FileUnlock(curr_entry->path)) return 1;
|
||||||
|
|
||||||
u32 filetype = IdentifyFileType(curr_entry->path);
|
u64 filetype = IdentifyFileType(curr_entry->path);
|
||||||
u32 drvtype = DriveType(curr_entry->path);
|
u32 drvtype = DriveType(curr_entry->path);
|
||||||
|
|
||||||
bool in_output_path = (strncmp(current_path, OUTPUT_PATH, 256) == 0);
|
bool in_output_path = (strncmp(current_path, OUTPUT_PATH, 256) == 0);
|
||||||
@ -905,6 +905,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
|||||||
(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) ? "NDS image options..." :
|
(filetype & GAME_NDS) ? "NDS image options..." :
|
||||||
|
(filetype & GAME_GBA) ? "GBA image options..." :
|
||||||
(filetype & GAME_TICKET)? "Ticket options..." :
|
(filetype & GAME_TICKET)? "Ticket options..." :
|
||||||
(filetype & SYS_FIRM ) ? "FIRM image options..." :
|
(filetype & SYS_FIRM ) ? "FIRM image options..." :
|
||||||
(filetype & SYS_AGBSAVE)? (agbimportable) ? "AGBSAVE options..." : "Dump GBA VC save" :
|
(filetype & SYS_AGBSAVE)? (agbimportable) ? "AGBSAVE options..." : "Dump GBA VC save" :
|
||||||
@ -1398,9 +1399,10 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if (user_select == extrcode) { // -> Extract code
|
else if (user_select == extrcode) { // -> Extract code
|
||||||
|
char extstr[8] = { 0 };
|
||||||
ShowString("%s\nExtracting .code, please wait...", pathstr);
|
ShowString("%s\nExtracting .code, please wait...", pathstr);
|
||||||
if (ExtractCodeFromCxiFile(curr_entry->path, NULL) == 0) {
|
if (ExtractCodeFromCxiFile(curr_entry->path, NULL, extstr) == 0) {
|
||||||
ShowPrompt(false, "%s\n.code extracted to " OUTPUT_PATH, pathstr);
|
ShowPrompt(false, "%s\n%s extracted to " OUTPUT_PATH, pathstr, extstr);
|
||||||
} else ShowPrompt(false, "%s\n.code extract failed", pathstr);
|
} else ShowPrompt(false, "%s\n.code extract failed", pathstr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
#include "agbsave.h"
|
|
||||||
#include "sha.h"
|
|
||||||
#include "aes.h"
|
|
||||||
|
|
||||||
|
|
||||||
u32 ValidateAgbSaveHeader(AgbSaveHeader* header) {
|
|
||||||
u8 magic[] = { AGBSAVE_MAGIC };
|
|
||||||
|
|
||||||
// basic checks
|
|
||||||
if ((memcmp(header->magic, magic, sizeof(magic)) != 0) ||
|
|
||||||
(header->unknown0 != 1) || (header->save_start != 0x200) ||
|
|
||||||
(header->save_size > AGBSAVE_MAX_SSIZE) || !(GBASAVE_VALID(header->save_size)))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
// reserved area checks
|
|
||||||
for (u32 i = 0; i < sizeof(header->reserved0); i++) if (header->reserved0[i] != 0xFF) return 1;
|
|
||||||
for (u32 i = 0; i < sizeof(header->reserved1); i++) if (header->reserved1[i] != 0xFF) return 1;
|
|
||||||
for (u32 i = 0; i < sizeof(header->reserved2); i++) if (header->reserved2[i] != 0xFF) return 1;
|
|
||||||
for (u32 i = 0; i < sizeof(header->reserved3); i++) if (header->reserved3[i] != 0xFF) return 1;
|
|
||||||
|
|
||||||
// all fine if arriving here
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "nand.h"
|
|
||||||
|
|
||||||
#define AGBSAVE_MAGIC '.', 'S', 'A', 'V'
|
|
||||||
#define AGBSAVE_MAX_SIZE (0x000180 * 0x200) // standard size of the NAND partition
|
|
||||||
#define AGBSAVE_MAX_SSIZE (AGBSAVE_MAX_SIZE - sizeof(AgbSaveHeader))
|
|
||||||
|
|
||||||
// see: http://3dbrew.org/wiki/3DS_Virtual_Console#GBA_VC
|
|
||||||
#define GBASAVE_EEPROM_512 (512)
|
|
||||||
#define GBASAVE_EEPROM_8K (8 * 1024)
|
|
||||||
#define GBASAVE_SRAM_32K (32 * 1024)
|
|
||||||
#define GBASAVE_FLASH_64K (64 * 1024)
|
|
||||||
#define GBASAVE_FLASH_128K (128 * 1024)
|
|
||||||
#define GBASAVE_VALID(size) \
|
|
||||||
(((size) == GBASAVE_EEPROM_512) || \
|
|
||||||
((size) == GBASAVE_EEPROM_8K) || \
|
|
||||||
((size) == GBASAVE_SRAM_32K) || \
|
|
||||||
((size) == GBASAVE_FLASH_64K) || \
|
|
||||||
((size) == GBASAVE_FLASH_128K))
|
|
||||||
|
|
||||||
// see: http://3dbrew.org/wiki/3DS_Virtual_Console#NAND_Savegame
|
|
||||||
typedef struct {
|
|
||||||
u8 magic[4]; // ".SAV"
|
|
||||||
u8 reserved0[0xC]; // always 0xFF
|
|
||||||
u8 cmac[0x10];
|
|
||||||
u8 reserved1[0x10]; // always 0xFF
|
|
||||||
u32 unknown0; // always 0x01
|
|
||||||
u32 times_saved;
|
|
||||||
u64 title_id;
|
|
||||||
u8 sd_cid[0x10];
|
|
||||||
u32 save_start; // always 0x200
|
|
||||||
u32 save_size;
|
|
||||||
u8 reserved2[0x8]; // always 0xFF
|
|
||||||
u32 unknown1; // has to do with ARM7?
|
|
||||||
u32 unknown2; // has to do with ARM7?
|
|
||||||
u8 reserved3[0x198]; // always 0xFF
|
|
||||||
} __attribute__((packed)) AgbSaveHeader;
|
|
||||||
|
|
||||||
u32 ValidateAgbSaveHeader(AgbSaveHeader* header);
|
|
@ -1,6 +1,6 @@
|
|||||||
#include "nandcmac.h"
|
#include "nandcmac.h"
|
||||||
#include "fsperm.h"
|
#include "fsperm.h"
|
||||||
#include "agbsave.h"
|
#include "gba.h"
|
||||||
#include "sha.h"
|
#include "sha.h"
|
||||||
#include "aes.h"
|
#include "aes.h"
|
||||||
#include "vff.h"
|
#include "vff.h"
|
||||||
|
@ -595,7 +595,7 @@ u32 VerifyBossFile(const char* path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u32 VerifyGameFile(const char* path) {
|
u32 VerifyGameFile(const char* path) {
|
||||||
u32 filetype = IdentifyFileType(path);
|
u64 filetype = IdentifyFileType(path);
|
||||||
if (filetype & GAME_CIA)
|
if (filetype & GAME_CIA)
|
||||||
return VerifyCiaFile(path);
|
return VerifyCiaFile(path);
|
||||||
else if (filetype & GAME_NCSD)
|
else if (filetype & GAME_NCSD)
|
||||||
@ -704,7 +704,7 @@ u32 CheckEncryptedBossFile(const char* path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u32 CheckEncryptedGameFile(const char* path) {
|
u32 CheckEncryptedGameFile(const char* path) {
|
||||||
u32 filetype = IdentifyFileType(path);
|
u64 filetype = IdentifyFileType(path);
|
||||||
if (filetype & GAME_CIA)
|
if (filetype & GAME_CIA)
|
||||||
return CheckEncryptedCiaFile(path);
|
return CheckEncryptedCiaFile(path);
|
||||||
else if (filetype & GAME_NCSD)
|
else if (filetype & GAME_NCSD)
|
||||||
@ -985,7 +985,7 @@ u32 CryptCdnFile(const char* orig, const char* dest, u16 crypto) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u32 CryptGameFile(const char* path, bool inplace, bool encrypt) {
|
u32 CryptGameFile(const char* path, bool inplace, bool encrypt) {
|
||||||
u32 filetype = IdentifyFileType(path);
|
u64 filetype = IdentifyFileType(path);
|
||||||
u16 crypto = encrypt ? CRYPTO_ENCRYPT : CRYPTO_DECRYPT;
|
u16 crypto = encrypt ? CRYPTO_ENCRYPT : CRYPTO_DECRYPT;
|
||||||
char dest[256];
|
char dest[256];
|
||||||
char* destptr = (char*) path;
|
char* destptr = (char*) path;
|
||||||
@ -1345,7 +1345,7 @@ u32 BuildCiaFromNcsdFile(const char* path_ncsd, const char* path_cia) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u32 BuildCiaFromGameFile(const char* path, bool force_legit) {
|
u32 BuildCiaFromGameFile(const char* path, bool force_legit) {
|
||||||
u32 filetype = IdentifyFileType(path);
|
u64 filetype = IdentifyFileType(path);
|
||||||
char dest[256];
|
char dest[256];
|
||||||
u32 ret = 0;
|
u32 ret = 0;
|
||||||
|
|
||||||
@ -1388,7 +1388,7 @@ u32 BuildCiaFromGameFile(const char* path, bool force_legit) {
|
|||||||
|
|
||||||
// this has very limited uses right now
|
// this has very limited uses right now
|
||||||
u32 DumpCxiSrlFromTmdFile(const char* path) {
|
u32 DumpCxiSrlFromTmdFile(const char* path) {
|
||||||
u32 filetype = 0;
|
u64 filetype = 0;
|
||||||
char path_cxi[256];
|
char path_cxi[256];
|
||||||
char dest[256];
|
char dest[256];
|
||||||
|
|
||||||
@ -1412,7 +1412,7 @@ u32 DumpCxiSrlFromTmdFile(const char* path) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 ExtractCodeFromCxiFile(const char* path, const char* path_out) {
|
u32 ExtractCodeFromCxiFile(const char* path, const char* path_out, char* extstr) {
|
||||||
u8* code = (u8*) TEMP_BUFFER;
|
u8* code = (u8*) TEMP_BUFFER;
|
||||||
u32 code_max_size = TEMP_BUFFER_EXTSIZE; // uses the extended temp buffer size
|
u32 code_max_size = TEMP_BUFFER_EXTSIZE; // uses the extended temp buffer size
|
||||||
|
|
||||||
@ -1422,19 +1422,28 @@ u32 ExtractCodeFromCxiFile(const char* path, const char* path_out) {
|
|||||||
// load ncch, exthdr, .code
|
// load ncch, exthdr, .code
|
||||||
u32 code_size;
|
u32 code_size;
|
||||||
if ((LoadNcchHeaders(&ncch, &exthdr, NULL, path, 0) != 0) ||
|
if ((LoadNcchHeaders(&ncch, &exthdr, NULL, path, 0) != 0) ||
|
||||||
(LoadExeFsFile(code, path, 0, EXEFS_CODE_NAME, code_max_size, &code_size)))
|
((LoadExeFsFile(code, path, 0, EXEFS_CODE_NAME, code_max_size, &code_size) != 0) &&
|
||||||
|
(LoadExeFsFile(code, path, 0, ".firm", code_max_size, &code_size) != 0)))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// decompress code (only if required)
|
// decompress code (only if required)
|
||||||
if ((exthdr.flag & 0x1) && (DecompressCodeLzss(code, &code_size, code_max_size) != 0))
|
if ((exthdr.flag & 0x1) && (DecompressCodeLzss(code, &code_size, code_max_size) != 0))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
// decide extension
|
||||||
|
char* ext = EXEFS_CODE_NAME;
|
||||||
|
if (code_size >= 0x200) {
|
||||||
|
if (ValidateFirmHeader((FirmHeader*)(void*) code, code_size) == 0) ext = ".firm";
|
||||||
|
else if (ValidateAgbHeader((AgbHeader*)(void*) code) == 0) ext = ".gba";
|
||||||
|
}
|
||||||
|
if (extstr) strncpy(extstr, ext, 7);
|
||||||
|
|
||||||
// build or take over output path
|
// build or take over output path
|
||||||
char dest[256];
|
char dest[256];
|
||||||
if (!path_out) {
|
if (!path_out) {
|
||||||
// ensure the output dir exists
|
// ensure the output dir exists
|
||||||
if (fvx_rmkdir(OUTPUT_PATH) != FR_OK) return 1;
|
if (fvx_rmkdir(OUTPUT_PATH) != FR_OK) return 1;
|
||||||
snprintf(dest, 256, OUTPUT_PATH "/%016llX%s%s", ncch.programId, (exthdr.flag & 0x1) ? ".dec" : "", EXEFS_CODE_NAME);
|
snprintf(dest, 256, OUTPUT_PATH "/%016llX%s%s", ncch.programId, (exthdr.flag & 0x1) ? ".dec" : "", ext);
|
||||||
} else strncpy(dest, path_out, 256);
|
} else strncpy(dest, path_out, 256);
|
||||||
if (!CheckWritePermissions(dest)) return 1;
|
if (!CheckWritePermissions(dest)) return 1;
|
||||||
|
|
||||||
@ -1449,7 +1458,7 @@ u32 ExtractCodeFromCxiFile(const char* path, const char* path_out) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u32 LoadSmdhFromGameFile(const char* path, Smdh* smdh) {
|
u32 LoadSmdhFromGameFile(const char* path, Smdh* smdh) {
|
||||||
u32 filetype = IdentifyFileType(path);
|
u64 filetype = IdentifyFileType(path);
|
||||||
|
|
||||||
if (filetype & GAME_SMDH) { // SMDH file
|
if (filetype & GAME_SMDH) { // SMDH file
|
||||||
UINT btr;
|
UINT btr;
|
||||||
@ -1496,6 +1505,17 @@ u32 ShowSmdhTitleInfo(Smdh* smdh) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 ShowGbaFileTitleInfo(const char* path) {
|
||||||
|
AgbHeader agb;
|
||||||
|
if ((fvx_qread(path, &agb, 0, sizeof(AgbHeader), NULL) != FR_OK) ||
|
||||||
|
(ValidateAgbHeader(&agb) != 0)) return 1;
|
||||||
|
ShowString("%.12s (AGB-%.4s)\n%s", agb.game_title, agb.game_code, AGB_DESTSTR(agb.game_code));
|
||||||
|
InputWait(0);
|
||||||
|
ClearScreenF(true, false, COLOR_STD_BG);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
u32 ShowNdsFileTitleInfo(const char* path) {
|
u32 ShowNdsFileTitleInfo(const char* path) {
|
||||||
const u32 lwrap = 24;
|
const u32 lwrap = 24;
|
||||||
TwlIconData* twl_icon = (TwlIconData*) TEMP_BUFFER;
|
TwlIconData* twl_icon = (TwlIconData*) TEMP_BUFFER;
|
||||||
@ -1522,10 +1542,11 @@ u32 ShowGameFileTitleInfo(const char* path) {
|
|||||||
path = path_content;
|
path = path_content;
|
||||||
}
|
}
|
||||||
|
|
||||||
// try loading SMDH, then try NDS
|
// try loading SMDH, then try NDS / GBA
|
||||||
if (LoadSmdhFromGameFile(path, smdh) == 0)
|
if (LoadSmdhFromGameFile(path, smdh) == 0)
|
||||||
return ShowSmdhTitleInfo(smdh);
|
return ShowSmdhTitleInfo(smdh);
|
||||||
else return ShowNdsFileTitleInfo(path);
|
else if (ShowNdsFileTitleInfo(path) == 0) return 0;
|
||||||
|
else return ShowGbaFileTitleInfo(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 BuildNcchInfoXorpads(const char* destdir, const char* path) {
|
u32 BuildNcchInfoXorpads(const char* destdir, const char* path) {
|
||||||
@ -1715,7 +1736,7 @@ u32 BuildTitleKeyInfo(const char* path, bool dec, bool dump) {
|
|||||||
else return 0;
|
else return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 filetype = path_in ? IdentifyFileType(path_in) : 0;
|
u64 filetype = path_in ? IdentifyFileType(path_in) : 0;
|
||||||
if (filetype & GAME_TICKET) {
|
if (filetype & GAME_TICKET) {
|
||||||
Ticket* ticket = (Ticket*) TEMP_BUFFER;
|
Ticket* ticket = (Ticket*) TEMP_BUFFER;
|
||||||
if ((fvx_qread(path_in, ticket, 0, TICKET_SIZE, &br) != FR_OK) || (br != TICKET_SIZE) ||
|
if ((fvx_qread(path_in, ticket, 0, TICKET_SIZE, &br) != FR_OK) || (br != TICKET_SIZE) ||
|
||||||
@ -1852,7 +1873,7 @@ u32 BuildSeedInfo(const char* path, bool dump) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u32 LoadNcchFromGameFile(const char* path, NcchHeader* ncch) {
|
u32 LoadNcchFromGameFile(const char* path, NcchHeader* ncch) {
|
||||||
u32 filetype = IdentifyFileType(path);
|
u64 filetype = IdentifyFileType(path);
|
||||||
UINT br;
|
UINT br;
|
||||||
|
|
||||||
if (filetype & GAME_NCCH) {
|
if (filetype & GAME_NCCH) {
|
||||||
@ -1899,14 +1920,16 @@ u32 GetGoodName(char* name, const char* path, bool quick) {
|
|||||||
// name scheme (TWL+ICON): <title_id> <title_name> (<product_code>) (<DSi unitcode>) (<region>).<extension>
|
// name scheme (TWL+ICON): <title_id> <title_name> (<product_code>) (<DSi unitcode>) (<region>).<extension>
|
||||||
// name scheme (NTR): <name_short> (<product_code>).<extension>
|
// name scheme (NTR): <name_short> (<product_code>).<extension>
|
||||||
// name scheme (TWL): <title_id> (<product_code>).<extension>
|
// name scheme (TWL): <title_id> (<product_code>).<extension>
|
||||||
|
// name scheme (AGB): <name_short> (<product_code>).<extension>
|
||||||
|
|
||||||
const char* path_donor = path;
|
const char* path_donor = path;
|
||||||
u32 type_donor = IdentifyFileType(path);
|
u64 type_donor = IdentifyFileType(path);
|
||||||
char* ext =
|
char* ext =
|
||||||
(type_donor & GAME_CIA) ? "cia" :
|
(type_donor & GAME_CIA) ? "cia" :
|
||||||
(type_donor & GAME_NCSD) ? "3ds" :
|
(type_donor & GAME_NCSD) ? "3ds" :
|
||||||
(type_donor & GAME_NCCH) ? ((type_donor & FLAG_CXI) ? "cxi" : "cfa") :
|
(type_donor & GAME_NCCH) ? ((type_donor & FLAG_CXI) ? "cxi" : "cfa") :
|
||||||
(type_donor & GAME_NDS) ? "nds" :
|
(type_donor & GAME_NDS) ? "nds" :
|
||||||
|
(type_donor & GAME_GBA) ? "gba" :
|
||||||
(type_donor & GAME_TMD) ? "tmd" : "";
|
(type_donor & GAME_TMD) ? "tmd" : "";
|
||||||
if (!*ext) return 1;
|
if (!*ext) return 1;
|
||||||
|
|
||||||
@ -1925,7 +1948,11 @@ u32 GetGoodName(char* name, const char* path, bool quick) {
|
|||||||
type_donor = IdentifyFileType(path_donor);
|
type_donor = IdentifyFileType(path_donor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type_donor & GAME_NDS) { // NTR or TWL
|
if (type_donor & GAME_GBA) { // AGB
|
||||||
|
AgbHeader* agb = (AgbHeader*) TEMP_BUFFER;
|
||||||
|
if (fvx_qread(path_donor, agb, 0, sizeof(AgbHeader), NULL) != FR_OK) return 1;
|
||||||
|
snprintf(name, 128, "%.12s (AGB-%.4s).%s", agb->game_title, agb->game_code, ext);
|
||||||
|
} else if (type_donor & GAME_NDS) { // NTR or TWL
|
||||||
TwlHeader* twl = (TwlHeader*) TEMP_BUFFER;
|
TwlHeader* twl = (TwlHeader*) TEMP_BUFFER;
|
||||||
TwlIconData* icon = (TwlIconData*) (TEMP_BUFFER + sizeof(TwlHeader));
|
TwlIconData* icon = (TwlIconData*) (TEMP_BUFFER + sizeof(TwlHeader));
|
||||||
if (LoadTwlMetaData(path_donor, twl, quick ? NULL : icon) != 0) return 1;
|
if (LoadTwlMetaData(path_donor, twl, quick ? NULL : icon) != 0) return 1;
|
||||||
|
@ -7,7 +7,7 @@ u32 CheckEncryptedGameFile(const char* path);
|
|||||||
u32 CryptGameFile(const char* path, bool inplace, bool encrypt);
|
u32 CryptGameFile(const char* path, bool inplace, bool encrypt);
|
||||||
u32 BuildCiaFromGameFile(const char* path, bool force_legit);
|
u32 BuildCiaFromGameFile(const char* path, bool force_legit);
|
||||||
u32 DumpCxiSrlFromTmdFile(const char* path);
|
u32 DumpCxiSrlFromTmdFile(const char* path);
|
||||||
u32 ExtractCodeFromCxiFile(const char* path, const char* path_out);
|
u32 ExtractCodeFromCxiFile(const char* path, const char* path_out, char* extstr);
|
||||||
u32 ShowGameFileTitleInfo(const char* path);
|
u32 ShowGameFileTitleInfo(const char* path);
|
||||||
u32 BuildNcchInfoXorpads(const char* destdir, const char* path);
|
u32 BuildNcchInfoXorpads(const char* destdir, const char* path);
|
||||||
u32 CheckHealthAndSafetyInject(const char* hsdrv);
|
u32 CheckHealthAndSafetyInject(const char* hsdrv);
|
||||||
|
@ -78,7 +78,7 @@ u32 BuildKeyDb(const char* path, bool dump) {
|
|||||||
else return 0;
|
else return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 filetype = path_in ? IdentifyFileType(path_in) : 0;
|
u64 filetype = path_in ? IdentifyFileType(path_in) : 0;
|
||||||
if (filetype & BIN_KEYDB) { // AES key database
|
if (filetype & BIN_KEYDB) { // AES key database
|
||||||
AesKeyInfo* key_info_merge = (AesKeyInfo*) TEMP_BUFFER;
|
AesKeyInfo* key_info_merge = (AesKeyInfo*) TEMP_BUFFER;
|
||||||
if ((fvx_qread(path_in, key_info_merge, 0, TEMP_BUFFER_SIZE, &br) != FR_OK) ||
|
if ((fvx_qread(path_in, key_info_merge, 0, TEMP_BUFFER_SIZE, &br) != FR_OK) ||
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#include "fatmbr.h"
|
#include "fatmbr.h"
|
||||||
#include "essentials.h" // for essential backup struct
|
#include "essentials.h" // for essential backup struct
|
||||||
#include "nandcmac.h"
|
#include "nandcmac.h"
|
||||||
#include "agbsave.h"
|
#include "gba.h"
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
#include "fsinit.h"
|
#include "fsinit.h"
|
||||||
#include "fsperm.h"
|
#include "fsperm.h"
|
||||||
|
@ -689,19 +689,19 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) {
|
|||||||
if (err_str) snprintf(err_str, _ERR_STR_LEN, "fixcmac failed");
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "fixcmac failed");
|
||||||
}
|
}
|
||||||
else if (id == CMD_ID_VERIFY) {
|
else if (id == CMD_ID_VERIFY) {
|
||||||
u32 filetype = IdentifyFileType(argv[0]);
|
u64 filetype = IdentifyFileType(argv[0]);
|
||||||
if (filetype & IMG_NAND) ret = (ValidateNandDump(argv[0]) == 0);
|
if (filetype & IMG_NAND) ret = (ValidateNandDump(argv[0]) == 0);
|
||||||
else ret = (VerifyGameFile(argv[0]) == 0);
|
else ret = (VerifyGameFile(argv[0]) == 0);
|
||||||
if (err_str) snprintf(err_str, _ERR_STR_LEN, "verification failed");
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "verification failed");
|
||||||
}
|
}
|
||||||
else if (id == CMD_ID_DECRYPT) {
|
else if (id == CMD_ID_DECRYPT) {
|
||||||
u32 filetype = IdentifyFileType(argv[0]);
|
u64 filetype = IdentifyFileType(argv[0]);
|
||||||
if (filetype & BIN_KEYDB) ret = (CryptAesKeyDb(argv[0], true, false) == 0);
|
if (filetype & BIN_KEYDB) ret = (CryptAesKeyDb(argv[0], true, false) == 0);
|
||||||
else ret = (CryptGameFile(argv[0], true, false) == 0);
|
else ret = (CryptGameFile(argv[0], true, false) == 0);
|
||||||
if (err_str) snprintf(err_str, _ERR_STR_LEN, "decrypt failed");
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "decrypt failed");
|
||||||
}
|
}
|
||||||
else if (id == CMD_ID_ENCRYPT) {
|
else if (id == CMD_ID_ENCRYPT) {
|
||||||
u32 filetype = IdentifyFileType(argv[0]);
|
u64 filetype = IdentifyFileType(argv[0]);
|
||||||
if (filetype & BIN_KEYDB) ret = (CryptAesKeyDb(argv[0], true, true) == 0);
|
if (filetype & BIN_KEYDB) ret = (CryptAesKeyDb(argv[0], true, true) == 0);
|
||||||
else ret = (CryptGameFile(argv[0], true, true) == 0);
|
else ret = (CryptGameFile(argv[0], true, true) == 0);
|
||||||
if (err_str) snprintf(err_str, _ERR_STR_LEN, "encrypt failed");
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "encrypt failed");
|
||||||
@ -711,13 +711,13 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) {
|
|||||||
if (err_str) snprintf(err_str, _ERR_STR_LEN, "build CIA failed");
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "build CIA failed");
|
||||||
}
|
}
|
||||||
else if (id == CMD_ID_EXTRCODE) {
|
else if (id == CMD_ID_EXTRCODE) {
|
||||||
u32 filetype = IdentifyFileType(argv[0]);
|
u64 filetype = IdentifyFileType(argv[0]);
|
||||||
if ((filetype&(GAME_NCCH|FLAG_CXI)) != (GAME_NCCH|FLAG_CXI)) {
|
if ((filetype&(GAME_NCCH|FLAG_CXI)) != (GAME_NCCH|FLAG_CXI)) {
|
||||||
ret = false;
|
ret = false;
|
||||||
if (err_str) snprintf(err_str, _ERR_STR_LEN, "not a CXI file");
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "not a CXI file");
|
||||||
} else {
|
} else {
|
||||||
ShowString("Extracting .code, please wait...");
|
ShowString("Extracting .code, please wait...");
|
||||||
ret = (ExtractCodeFromCxiFile(argv[0], argv[1]) == 0);
|
ret = (ExtractCodeFromCxiFile(argv[0], argv[1], NULL) == 0);
|
||||||
if (err_str) snprintf(err_str, _ERR_STR_LEN, "extract .code failed");
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "extract .code failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@
|
|||||||
#define NAME_NDS_DATADIR "data"
|
#define NAME_NDS_DATADIR "data"
|
||||||
|
|
||||||
|
|
||||||
static u32 vgame_type = 0;
|
static u64 vgame_type = 0;
|
||||||
static u32 base_vdir = 0;
|
static u32 base_vdir = 0;
|
||||||
|
|
||||||
static VirtualFile* templates_cia = (VirtualFile*) VGAME_BUFFER; // first 56kb reserved (enough for 1024 entries)
|
static VirtualFile* templates_cia = (VirtualFile*) VGAME_BUFFER; // first 56kb reserved (enough for 1024 entries)
|
||||||
@ -634,8 +634,8 @@ bool BuildVGameFirmDir(void) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 InitVGameDrive(void) { // prerequisite: game file mounted as image
|
u64 InitVGameDrive(void) { // prerequisite: game file mounted as image
|
||||||
u32 type = GetMountState();
|
u64 type = GetMountState();
|
||||||
|
|
||||||
vgame_type = 0;
|
vgame_type = 0;
|
||||||
offset_firm = (u64) -1;
|
offset_firm = (u64) -1;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include "filetype.h"
|
#include "filetype.h"
|
||||||
#include "virtual.h"
|
#include "virtual.h"
|
||||||
|
|
||||||
u32 InitVGameDrive(void);
|
u64 InitVGameDrive(void);
|
||||||
u32 CheckVGameDrive(void);
|
u32 CheckVGameDrive(void);
|
||||||
|
|
||||||
bool OpenVGameDir(VirtualDir* vdir, VirtualFile* ventry);
|
bool OpenVGameDir(VirtualDir* vdir, VirtualFile* ventry);
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include "vnand.h"
|
#include "vnand.h"
|
||||||
#include "nand.h"
|
#include "nand.h"
|
||||||
#include "agbsave.h"
|
|
||||||
#include "essentials.h"
|
#include "essentials.h"
|
||||||
#include "unittype.h"
|
#include "unittype.h"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user