forked from Mirror/GodMode9
Fix CMD & NCSD handling
This commit is contained in:
parent
b8798f2aff
commit
d8aeb056cb
@ -124,7 +124,7 @@ u64 IdentifyFileType(const char* path) {
|
|||||||
(memcmp(data, threedsx_magic, sizeof(threedsx_magic)) == 0)) {
|
(memcmp(data, threedsx_magic, sizeof(threedsx_magic)) == 0)) {
|
||||||
return GAME_3DSX; // 3DSX (executable) file
|
return GAME_3DSX; // 3DSX (executable) file
|
||||||
} else if ((fsize > sizeof(CmdHeader)) &&
|
} else if ((fsize > sizeof(CmdHeader)) &&
|
||||||
CheckCmdSize((CmdHeader*) data, fsize) == 0) {
|
(CMD_SIZE((CmdHeader*) data) == fsize)) {
|
||||||
return GAME_CMD; // CMD file
|
return GAME_CMD; // CMD file
|
||||||
} else if ((fsize > sizeof(NcchInfoHeader)) &&
|
} else if ((fsize > sizeof(NcchInfoHeader)) &&
|
||||||
(GetNcchInfoVersion((NcchInfoHeader*) data)) &&
|
(GetNcchInfoVersion((NcchInfoHeader*) data)) &&
|
||||||
|
@ -1,50 +1,62 @@
|
|||||||
#include "cmd.h"
|
#include "cmd.h"
|
||||||
|
|
||||||
|
|
||||||
u32 CheckCmdSize(CmdHeader* cmd, u64 fsize) {
|
CmdHeader* BuildAllocCmdData(TitleMetaData* tmd) {
|
||||||
u64 cmdsize = sizeof(CmdHeader) +
|
CmdHeader proto;
|
||||||
(cmd->n_entries * sizeof(u32)) +
|
CmdHeader* cmd = NULL;
|
||||||
(cmd->n_cmacs * sizeof(u32)) +
|
|
||||||
(cmd->n_entries * 0x10);
|
|
||||||
|
|
||||||
return (fsize == cmdsize) ? 0 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 BuildCmdData(CmdHeader* cmd, TitleMetaData* tmd) {
|
|
||||||
u32 content_count = getbe16(tmd->content_count);
|
u32 content_count = getbe16(tmd->content_count);
|
||||||
|
u32 max_cnt_id = 0;
|
||||||
|
|
||||||
// header basic info
|
// sanity check
|
||||||
cmd->cmd_id = 0x1;
|
if (!content_count)
|
||||||
cmd->n_entries = content_count;
|
return NULL;
|
||||||
cmd->n_cmacs = content_count;
|
|
||||||
|
// find max content id
|
||||||
|
TmdContentChunk* chunk = (TmdContentChunk*) (tmd + 1);
|
||||||
|
for (u32 i = 0; (i < content_count) && (i < TMD_MAX_CONTENTS); i++, chunk++)
|
||||||
|
if (getbe32(chunk->id) > max_cnt_id) max_cnt_id = getbe32(chunk->id);
|
||||||
|
|
||||||
|
// allocate memory for CMD / basic setup
|
||||||
|
proto.cmd_id = 1;
|
||||||
|
proto.n_entries = max_cnt_id + 1;
|
||||||
|
proto.n_cmacs = content_count;
|
||||||
|
proto.unknown = 1;
|
||||||
|
cmd = (CmdHeader*) malloc(CMD_SIZE(&proto));
|
||||||
|
if (!cmd) return NULL;
|
||||||
|
memcpy(cmd, &proto, sizeof(CmdHeader));
|
||||||
cmd->unknown = 0x0; // this means no CMACs, only valid for NAND
|
cmd->unknown = 0x0; // this means no CMACs, only valid for NAND
|
||||||
|
|
||||||
// copy content ids
|
// copy content ids
|
||||||
u32* cnt_id = (u32*) (cmd + 1);
|
u32* cnt_id = (u32*) (cmd + 1);
|
||||||
u32* cnt_id_cpy = cnt_id + content_count;
|
u32* cnt_id_2nd = cnt_id + cmd->n_entries;
|
||||||
TmdContentChunk* chunk = (TmdContentChunk*) (tmd + 1);
|
chunk = (TmdContentChunk*) (tmd + 1);
|
||||||
|
memset(cnt_id, 0xFF, cmd->n_entries * sizeof(u32));
|
||||||
for (u32 i = 0; (i < content_count) && (i < TMD_MAX_CONTENTS); i++, chunk++) {
|
for (u32 i = 0; (i < content_count) && (i < TMD_MAX_CONTENTS); i++, chunk++) {
|
||||||
cnt_id[i] = getbe32(chunk->id);
|
u32 chunk_id = getbe32(chunk->id);
|
||||||
cnt_id_cpy[i] = cnt_id[i];
|
cnt_id[chunk_id] = chunk_id;
|
||||||
|
*(cnt_id_2nd++) = chunk_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// bubble sort the second content id list
|
// bubble sort the second content id list
|
||||||
u32 b = 0;
|
bool bs_finished = false;
|
||||||
while ((b < content_count) && (b < TMD_MAX_CONTENTS)) {
|
cnt_id_2nd = cnt_id + cmd->n_entries;
|
||||||
for (b = 1; (b < content_count) && (b < TMD_MAX_CONTENTS); b++) {
|
while (!bs_finished) {
|
||||||
if (cnt_id_cpy[b] < cnt_id_cpy[b-1]) {
|
bs_finished = true;
|
||||||
u32 swp = cnt_id_cpy[b];
|
for (u32 b = 1; b < cmd->n_cmacs; b++) {
|
||||||
cnt_id_cpy[b] = cnt_id_cpy[b-1];
|
if (cnt_id_2nd[b] < cnt_id_2nd[b-1]) {
|
||||||
cnt_id_cpy[b-1] = swp;
|
u32 swp = cnt_id_2nd[b];
|
||||||
|
cnt_id_2nd[b] = cnt_id_2nd[b-1];
|
||||||
|
cnt_id_2nd[b-1] = swp;
|
||||||
|
bs_finished = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set CMACs to 0xFF
|
// set CMACs to 0xFF
|
||||||
u8* cnt_cmac = (u8*) (cnt_id + (2*cmd->n_entries));
|
u8* cnt_cmac = (u8*) (cnt_id_2nd + cmd->n_cmacs);
|
||||||
memset(cmd->cmac, 0xFF, 0x10);
|
memset(cmd->cmac, 0xFF, 0x10);
|
||||||
memset(cnt_cmac, 0xFF, 0x10 * content_count);
|
memset(cnt_cmac, 0xFF, 0x10 * cmd->n_entries);
|
||||||
|
|
||||||
// we still need to fix / set the CMACs inside the CMD file!
|
// we still need to fix / set the CMACs inside the CMD file!
|
||||||
return 0;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,10 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "tmd.h"
|
#include "tmd.h"
|
||||||
|
|
||||||
#define CMD_SIZE_N(n) (sizeof(CmdHeader) + ((n)*(sizeof(u32)+sizeof(u32)+0x10)))
|
#define CMD_SIZE(cmd) (sizeof(CmdHeader) + \
|
||||||
#define CMD_SIZE_NS(n) (sizeof(CmdHeader) + ((n)*(sizeof(u32)+sizeof(u32))))
|
(((cmd)->n_entries) * sizeof(u32)) + \
|
||||||
|
(((cmd)->n_cmacs) * sizeof(u32)) + \
|
||||||
|
(((cmd)->unknown) ? (((cmd)->n_entries) * 0x10) : 0))
|
||||||
|
|
||||||
// from: http://3dbrew.org/wiki/Titles#Data_Structure
|
// from: http://3dbrew.org/wiki/Titles#Data_Structure
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -19,5 +20,4 @@ typedef struct {
|
|||||||
// followed by <n_entries> CMACs (may contain garbage)
|
// followed by <n_entries> CMACs (may contain garbage)
|
||||||
} __attribute__((packed, aligned(4))) CmdHeader;
|
} __attribute__((packed, aligned(4))) CmdHeader;
|
||||||
|
|
||||||
u32 CheckCmdSize(CmdHeader* cmd, u64 fsize);
|
CmdHeader* BuildAllocCmdData(TitleMetaData* tmd);
|
||||||
u32 BuildCmdData(CmdHeader* cmd, TitleMetaData* tmd);
|
|
||||||
|
@ -25,7 +25,7 @@ u32 BuildTitleInfoEntryTmd(TitleInfoEntry* tie, TitleMetaData* tmd, bool sd) {
|
|||||||
tie->title_size =
|
tie->title_size =
|
||||||
(align_size * 3) + // base folder + 'content' + 'cmd'
|
(align_size * 3) + // base folder + 'content' + 'cmd'
|
||||||
align(TMD_SIZE_N(content_count), align_size) + // TMD
|
align(TMD_SIZE_N(content_count), align_size) + // TMD
|
||||||
align(CMD_SIZE_N(content_count), align_size); // CMD
|
align_size; // CMD, placeholder
|
||||||
for (u32 i = 0; (i < content_count) && (i < TMD_MAX_CONTENTS); i++, chunk++) {
|
for (u32 i = 0; (i < content_count) && (i < TMD_MAX_CONTENTS); i++, chunk++) {
|
||||||
if (getbe32(chunk->id) == 1) has_id1 = true; // will be useful later
|
if (getbe32(chunk->id) == 1) has_id1 = true; // will be useful later
|
||||||
tie->title_size += align(getbe64(chunk->size), align_size);
|
tie->title_size += align(getbe64(chunk->size), align_size);
|
||||||
|
@ -1402,10 +1402,9 @@ u32 InstallCiaSystemData(CiaStub* cia, const char* drv) {
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// build the cmd
|
// build the cmd
|
||||||
cmd = (CmdHeader*) malloc(CMD_SIZE_N(content_count));
|
cmd = BuildAllocCmdData(tmd);
|
||||||
if (!cmd) return 1;
|
if (!cmd) return 1;
|
||||||
BuildCmdData(cmd, tmd);
|
cmd->unknown = 0xFFFFFFFE; // mark this as custom built
|
||||||
if (!syscmd) cmd->unknown = 0xFFFFFFFE; // mark this as custom built
|
|
||||||
|
|
||||||
// generate all the paths
|
// generate all the paths
|
||||||
snprintf(path_titledb, 32, "%2.2s/dbs/title.db",
|
snprintf(path_titledb, 32, "%2.2s/dbs/title.db",
|
||||||
@ -1423,8 +1422,7 @@ u32 InstallCiaSystemData(CiaStub* cia, const char* drv) {
|
|||||||
fvx_rmkpath(path_tmd);
|
fvx_rmkpath(path_tmd);
|
||||||
fvx_rmkpath(path_cmd);
|
fvx_rmkpath(path_cmd);
|
||||||
if ((fvx_qwrite(path_tmd, tmd, 0, TMD_SIZE_N(content_count), NULL) != FR_OK) ||
|
if ((fvx_qwrite(path_tmd, tmd, 0, TMD_SIZE_N(content_count), NULL) != FR_OK) ||
|
||||||
(fvx_qwrite(path_cmd, cmd, 0,
|
(fvx_qwrite(path_cmd, cmd, 0, CMD_SIZE(cmd), NULL) != FR_OK)) {
|
||||||
syscmd ? CMD_SIZE_NS(content_count) : CMD_SIZE_N(content_count), NULL) != FR_OK)) {
|
|
||||||
free(cmd);
|
free(cmd);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -1963,7 +1961,7 @@ u32 BuildInstallFromNcsdFile(const char* path_ncsd, const char* path_dest, bool
|
|||||||
if ((!install && (InsertCiaContent(path_dest, path_ncsd,
|
if ((!install && (InsertCiaContent(path_dest, path_ncsd,
|
||||||
offset, size, chunk++, NULL, false, (i == 0), false) != 0)) ||
|
offset, size, chunk++, NULL, false, (i == 0), false) != 0)) ||
|
||||||
(install && (InstallCiaContent(path_dest, path_ncsd,
|
(install && (InstallCiaContent(path_dest, path_ncsd,
|
||||||
offset, size, chunk, title_id, NULL, (i == 0)) != 0))) {
|
offset, size, chunk++, title_id, NULL, (i == 0)) != 0))) {
|
||||||
free(cia);
|
free(cia);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -2161,9 +2159,8 @@ u32 InstallGameFile(const char* path, bool to_emunand, bool force_nand) {
|
|||||||
to_sd = true;
|
to_sd = true;
|
||||||
|
|
||||||
// does the title.db exist?
|
// does the title.db exist?
|
||||||
if (to_sd && !fvx_qsize(to_emunand ? "B:/dbs/title.db" : "A:/dbs/title.db"))
|
if ((to_sd && !fvx_qsize(to_emunand ? "B:/dbs/title.db" : "A:/dbs/title.db")) ||
|
||||||
to_sd = false;
|
(!to_sd && !fvx_qsize(to_emunand ? "4:/dbs/title.db" : "1:/dbs/title.db")))
|
||||||
if (!to_sd && !fvx_qsize(to_emunand ? "4:/dbs/title.db" : "1:/dbs/title.db"))
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// now we know the correct drive
|
// now we know the correct drive
|
||||||
@ -2401,7 +2398,7 @@ u32 TrimGameFile(const char* path) {
|
|||||||
|
|
||||||
u32 LoadSmdhFromGameFile(const char* path, Smdh* smdh) {
|
u32 LoadSmdhFromGameFile(const char* path, Smdh* smdh) {
|
||||||
u64 filetype = IdentifyFileType(path);
|
u64 filetype = IdentifyFileType(path);
|
||||||
|
|
||||||
if (filetype & GAME_SMDH) { // SMDH file
|
if (filetype & GAME_SMDH) { // SMDH file
|
||||||
UINT btr;
|
UINT btr;
|
||||||
if ((fvx_qread(path, smdh, 0, sizeof(Smdh), &btr) == FR_OK) || (btr == sizeof(Smdh))) return 0;
|
if ((fvx_qread(path, smdh, 0, sizeof(Smdh), &btr) == FR_OK) || (btr == sizeof(Smdh))) return 0;
|
||||||
@ -2410,8 +2407,7 @@ u32 LoadSmdhFromGameFile(const char* path, Smdh* smdh) {
|
|||||||
} else if (filetype & GAME_NCSD) { // NCSD file
|
} else if (filetype & GAME_NCSD) { // NCSD file
|
||||||
if (LoadExeFsFile(smdh, path, NCSD_CNT0_OFFSET, "icon", sizeof(Smdh), NULL) == 0) return 0;
|
if (LoadExeFsFile(smdh, path, NCSD_CNT0_OFFSET, "icon", sizeof(Smdh), NULL) == 0) return 0;
|
||||||
} else if (filetype & GAME_CIA) { // CIA file
|
} else if (filetype & GAME_CIA) { // CIA file
|
||||||
CiaInfo info;
|
CiaInfo info;
|
||||||
|
|
||||||
if ((fvx_qread(path, &info, 0, 0x20, NULL) != FR_OK) ||
|
if ((fvx_qread(path, &info, 0, 0x20, NULL) != FR_OK) ||
|
||||||
(GetCiaInfo(&info, (CiaHeader*) &info) != 0)) return 1;
|
(GetCiaInfo(&info, (CiaHeader*) &info) != 0)) return 1;
|
||||||
if ((info.offset_meta) && (fvx_qread(path, smdh, info.offset_meta + 0x400, sizeof(Smdh), NULL) == FR_OK)) return 0;
|
if ((info.offset_meta) && (fvx_qread(path, smdh, info.offset_meta + 0x400, sizeof(Smdh), NULL) == FR_OK)) return 0;
|
||||||
@ -2479,7 +2475,7 @@ u32 ShowGameFileTitleInfoF(const char* path, u16* screen, bool clear) {
|
|||||||
if (GetTmdContentPath(path_content, path) != 0) return 1;
|
if (GetTmdContentPath(path_content, path) != 0) return 1;
|
||||||
path = path_content;
|
path = path_content;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* buffer = (void*) malloc(max(sizeof(Smdh), sizeof(TwlIconData)));
|
void* buffer = (void*) malloc(max(sizeof(Smdh), sizeof(TwlIconData)));
|
||||||
Smdh* smdh = (Smdh*) buffer;
|
Smdh* smdh = (Smdh*) buffer;
|
||||||
TwlIconData* twl_icon = (TwlIconData*) buffer;
|
TwlIconData* twl_icon = (TwlIconData*) buffer;
|
||||||
|
@ -374,7 +374,7 @@ u32 CheckFixCmdCmac(const char* path, bool fix) {
|
|||||||
|
|
||||||
// read the full file to memory and check it (we may write it back later)
|
// read the full file to memory and check it (we may write it back later)
|
||||||
if ((fvx_qread(path, cmd_data, 0, cmd_size, NULL) != FR_OK) ||
|
if ((fvx_qread(path, cmd_data, 0, cmd_size, NULL) != FR_OK) ||
|
||||||
(CheckCmdSize(cmd, cmd_size) != 0)) {
|
(CMD_SIZE(cmd) != cmd_size)) {
|
||||||
free(cmd_data);
|
free(cmd_data);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user