mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 05:32:47 +00:00
Add LARGEDLC mode for titles with > 1024 contents
Fixes #703 and is only active with `make LARGEDLC=1` and will break compatibility with other titles and CIAs. Thanks @luigoalma for new ticket builder code!
This commit is contained in:
parent
33a115b75c
commit
c9b6a335f7
@ -25,6 +25,12 @@ else ifeq ($(FLAVOR),ZuishMode9)
|
|||||||
CFLAGS += -DDEFAULT_FONT=\"font_zuish_8x8.pbm\"
|
CFLAGS += -DDEFAULT_FONT=\"font_zuish_8x8.pbm\"
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(LARGEDLC),1)
|
||||||
|
CFLAGS += -DTITLE_MAX_CONTENTS=1536
|
||||||
|
else
|
||||||
|
CFLAGS += -DTITLE_MAX_CONTENTS=1024
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(SALTMODE),1)
|
ifeq ($(SALTMODE),1)
|
||||||
CFLAGS += -DSALTMODE
|
CFLAGS += -DSALTMODE
|
||||||
endif
|
endif
|
||||||
|
@ -41,28 +41,91 @@ u32 ValidateTicketSignature(Ticket* ticket) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 BuildFakeTicket(Ticket* ticket, u8* title_id) {
|
u32 BuildVariableFakeTicket(Ticket** ticket, u32* ticket_size, const u8* title_id, u32 index_max) {
|
||||||
static const u8 sig_type[4] = { TICKET_SIG_TYPE }; // RSA_2048 SHA256
|
if (!ticket || !ticket_size)
|
||||||
static const u8 ticket_cnt_index[] = { // whatever this is
|
return 1;
|
||||||
0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0xAC, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x14,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x84,
|
|
||||||
0x00, 0x00, 0x00, 0x84, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
|
||||||
};
|
|
||||||
// set ticket all zero for a clean start
|
|
||||||
memset(ticket, 0x00, TICKET_COMMON_SIZE); // 0xAC being size of this fake ticket's content index
|
|
||||||
// fill ticket values
|
|
||||||
memcpy(ticket->sig_type, sig_type, 4);
|
|
||||||
memset(ticket->signature, 0xFF, 0x100);
|
|
||||||
snprintf((char*) ticket->issuer, 0x40, IS_DEVKIT ? TICKET_ISSUER_DEV : TICKET_ISSUER);
|
|
||||||
memset(ticket->ecdsa, 0xFF, 0x3C);
|
|
||||||
ticket->version = 0x01;
|
|
||||||
memset(ticket->titlekey, 0xFF, 16);
|
|
||||||
memcpy(ticket->title_id, title_id, 8);
|
|
||||||
ticket->commonkey_idx = 0x00; // eshop
|
|
||||||
ticket->audit = 0x01; // whatever
|
|
||||||
memcpy(ticket->content_index, ticket_cnt_index, sizeof(ticket_cnt_index));
|
|
||||||
memset(&ticket->content_index[sizeof(ticket_cnt_index)], 0xFF, 0x80); // 1024 content indexes
|
|
||||||
|
|
||||||
|
static const u8 sig_type[4] = { TICKET_SIG_TYPE }; // RSA_2048 SHA256
|
||||||
|
|
||||||
|
// calculate sizes and determine pointers to use
|
||||||
|
u32 rights_field_count = (min(index_max, 0x10000) + 1023) >> 10; // round up to 1024 and cap at 65536, and div by 1024
|
||||||
|
u32 content_index_size = sizeof(TicketContentIndexMainHeader) + sizeof(TicketContentIndexDataHeader) + sizeof(TicketRightsField) * rights_field_count;
|
||||||
|
u32 _ticket_size = sizeof(Ticket) + content_index_size;
|
||||||
|
Ticket *_ticket;
|
||||||
|
|
||||||
|
if (*ticket) { // if a pointer was pregiven
|
||||||
|
if (*ticket_size < _ticket_size) { // then check given boundary size
|
||||||
|
*ticket_size = _ticket_size; // if not enough, inform the actual needed size
|
||||||
|
return 2; // indicate a size error
|
||||||
|
}
|
||||||
|
_ticket = *ticket; // get the pointer if we good to go
|
||||||
|
} else // if not pregiven, allocate one
|
||||||
|
_ticket = (Ticket*)malloc(_ticket_size);
|
||||||
|
|
||||||
|
if (!_ticket)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// set ticket all zero for a clean start
|
||||||
|
memset(_ticket, 0x00, _ticket_size);
|
||||||
|
// fill ticket values
|
||||||
|
memcpy(_ticket->sig_type, sig_type, 4);
|
||||||
|
memset(_ticket->signature, 0xFF, 0x100);
|
||||||
|
snprintf((char*) _ticket->issuer, 0x40, IS_DEVKIT ? TICKET_ISSUER_DEV : TICKET_ISSUER);
|
||||||
|
memset(_ticket->ecdsa, 0xFF, 0x3C);
|
||||||
|
_ticket->version = 0x01;
|
||||||
|
memset(_ticket->titlekey, 0xFF, 16);
|
||||||
|
memcpy(_ticket->title_id, title_id, 8);
|
||||||
|
_ticket->commonkey_idx = 0x00; // eshop
|
||||||
|
_ticket->audit = 0x01; // whatever
|
||||||
|
|
||||||
|
// fill in rights
|
||||||
|
TicketContentIndexMainHeader* mheader = (TicketContentIndexMainHeader*)&_ticket->content_index[0];
|
||||||
|
TicketContentIndexDataHeader* dheader = (TicketContentIndexDataHeader*)&_ticket->content_index[0x14];
|
||||||
|
TicketRightsField* rights = (TicketRightsField*)&_ticket->content_index[0x28];
|
||||||
|
|
||||||
|
// first main data header
|
||||||
|
mheader->unk1[1] = 0x1; mheader->unk2[1] = 0x14;
|
||||||
|
mheader->content_index_size[3] = (u8)(content_index_size >> 0);
|
||||||
|
mheader->content_index_size[2] = (u8)(content_index_size >> 8);
|
||||||
|
mheader->content_index_size[1] = (u8)(content_index_size >> 16);
|
||||||
|
mheader->content_index_size[0] = (u8)(content_index_size >> 24);
|
||||||
|
mheader->data_header_relative_offset[3] = 0x14; // relative offset for TicketContentIndexDataHeader
|
||||||
|
mheader->unk3[1] = 0x1; mheader->unk4[1] = 0x14;
|
||||||
|
|
||||||
|
// then the data header
|
||||||
|
dheader->data_relative_offset[3] = 0x28; // relative offset for TicketRightsField
|
||||||
|
dheader->max_entry_count[3] = (u8)(rights_field_count >> 0);
|
||||||
|
dheader->max_entry_count[2] = (u8)(rights_field_count >> 8);
|
||||||
|
dheader->max_entry_count[1] = (u8)(rights_field_count >> 16);
|
||||||
|
dheader->max_entry_count[0] = (u8)(rights_field_count >> 24);
|
||||||
|
dheader->size_per_entry[3] = (u8)sizeof(TicketRightsField); // sizeof should be 0x84
|
||||||
|
dheader->total_size_used[3] = (u8)((sizeof(TicketRightsField) * rights_field_count) >> 0);
|
||||||
|
dheader->total_size_used[2] = (u8)((sizeof(TicketRightsField) * rights_field_count) >> 8);
|
||||||
|
dheader->total_size_used[1] = (u8)((sizeof(TicketRightsField) * rights_field_count) >> 16);
|
||||||
|
dheader->total_size_used[0] = (u8)((sizeof(TicketRightsField) * rights_field_count) >> 24);
|
||||||
|
dheader->data_type[1] = 3; // right fields
|
||||||
|
|
||||||
|
// now the right fields
|
||||||
|
// indexoffets must be in accending order to have the desired effect
|
||||||
|
for (u32 i = 0; i < rights_field_count; ++i) {
|
||||||
|
rights[i].indexoffset[1] = (u8)((1024 * i) >> 0);
|
||||||
|
rights[i].indexoffset[0] = (u8)((1024 * i) >> 8);
|
||||||
|
memset(&rights[i].rightsbitfield[0], 0xFF, sizeof(rights[0].rightsbitfield));
|
||||||
|
}
|
||||||
|
|
||||||
|
*ticket = _ticket;
|
||||||
|
*ticket_size = _ticket_size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 BuildFakeTicket(Ticket* ticket, const u8* title_id) {
|
||||||
|
Ticket* tik;
|
||||||
|
u32 ticket_size = sizeof(TicketCommon);
|
||||||
|
u32 res = BuildVariableFakeTicket(&tik, &ticket_size, title_id, TICKET_MAX_CONTENTS);
|
||||||
|
if (res != 0) return res;
|
||||||
|
memcpy(ticket, tik, ticket_size);
|
||||||
|
free(tik);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "tmd.h"
|
||||||
|
|
||||||
#define TICKET_COMMON_SIZE sizeof(TicketCommon)
|
#define TICKET_COMMON_SIZE sizeof(TicketCommon)
|
||||||
#define TICKET_MINIMUM_SIZE sizeof(TicketMinimum)
|
#define TICKET_MINIMUM_SIZE sizeof(TicketMinimum)
|
||||||
#define TICKET_TWL_SIZE sizeof(Ticket)
|
#define TICKET_TWL_SIZE sizeof(Ticket)
|
||||||
#define TICKET_CDNCERT_SIZE 0x700
|
#define TICKET_CDNCERT_SIZE 0x700
|
||||||
|
#define TICKET_MAX_CONTENTS TITLE_MAX_CONTENTS // should be TMD_MAX_CONTENTS
|
||||||
|
#define TICKET_COMMON_CNT_INDEX_SIZE (0x28 + (((TICKET_MAX_CONTENTS + 1023) >> 10) * 0x84))
|
||||||
|
|
||||||
#define TICKET_ISSUER "Root-CA00000003-XS0000000c"
|
#define TICKET_ISSUER "Root-CA00000003-XS0000000c"
|
||||||
#define TICKET_ISSUER_DEV "Root-CA00000004-XS00000009"
|
#define TICKET_ISSUER_DEV "Root-CA00000004-XS00000009"
|
||||||
@ -54,7 +57,7 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
TICKETBASE;
|
TICKETBASE;
|
||||||
u8 content_index[0xAC];
|
u8 content_index[TICKET_COMMON_CNT_INDEX_SIZE];
|
||||||
} PACKED_STRUCT TicketCommon;
|
} PACKED_STRUCT TicketCommon;
|
||||||
|
|
||||||
// minimum allowed content_index is 0x14
|
// minimum allowed content_index is 0x14
|
||||||
@ -97,7 +100,7 @@ typedef struct {
|
|||||||
u32 ValidateTicket(Ticket* ticket);
|
u32 ValidateTicket(Ticket* ticket);
|
||||||
u32 ValidateTwlTicket(Ticket* ticket);
|
u32 ValidateTwlTicket(Ticket* ticket);
|
||||||
u32 ValidateTicketSignature(Ticket* ticket);
|
u32 ValidateTicketSignature(Ticket* ticket);
|
||||||
u32 BuildFakeTicket(Ticket* ticket, u8* title_id);
|
u32 BuildFakeTicket(Ticket* ticket, const u8* title_id);
|
||||||
u32 GetTicketContentIndexSize(const Ticket* ticket);
|
u32 GetTicketContentIndexSize(const Ticket* ticket);
|
||||||
u32 GetTicketSize(const Ticket* ticket);
|
u32 GetTicketSize(const Ticket* ticket);
|
||||||
u32 BuildTicketCert(u8* tickcert);
|
u32 BuildTicketCert(u8* tickcert);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#define TMD_MAX_CONTENTS 1000 // 383 // theme CIAs contain maximum 100 themes + 1 index content
|
#define TMD_MAX_CONTENTS TITLE_MAX_CONTENTS // 1024 // 383 // theme CIAs contain maximum 100 themes + 1 index content
|
||||||
|
|
||||||
#define TMD_SIZE_MIN sizeof(TitleMetaData)
|
#define TMD_SIZE_MIN sizeof(TitleMetaData)
|
||||||
#define TMD_SIZE_MAX (sizeof(TitleMetaData) + (TMD_MAX_CONTENTS*sizeof(TmdContentChunk)))
|
#define TMD_SIZE_MAX (sizeof(TitleMetaData) + (TMD_MAX_CONTENTS*sizeof(TmdContentChunk)))
|
||||||
|
@ -225,6 +225,10 @@ u32 LoadTmdFile(TitleMetaData* tmd, const char* path) {
|
|||||||
if (fvx_qread(path, tmd, 0, TMD_SIZE_STUB, NULL) != FR_OK)
|
if (fvx_qread(path, tmd, 0, TMD_SIZE_STUB, NULL) != FR_OK)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
// sanity check
|
||||||
|
if (getbe16(tmd->content_count) > TMD_MAX_CONTENTS)
|
||||||
|
return 1;
|
||||||
|
|
||||||
// second part (read full size)
|
// second part (read full size)
|
||||||
if (ValidateTmd(tmd) == 0) {
|
if (ValidateTmd(tmd) == 0) {
|
||||||
if (fvx_qread(path, tmd, 0, TMD_SIZE_N(getbe16(tmd->content_count)), NULL) != FR_OK)
|
if (fvx_qread(path, tmd, 0, TMD_SIZE_N(getbe16(tmd->content_count)), NULL) != FR_OK)
|
||||||
@ -348,7 +352,7 @@ u32 GetTmdContentPath(char* path_content, const char* path_tmd) {
|
|||||||
free(tmd);
|
free(tmd);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
snprintf(name_content, 256 - (name_content - path_content), cdn ? "%08lx" :
|
snprintf(name_content, 255 - (name_content - path_content), cdn ? "%08lx" :
|
||||||
(memcmp(tmd->title_id, dlc_tid_high, sizeof(dlc_tid_high)) == 0) ? "00000000/%08lx.app" : "%08lx.app", getbe32(chunk->id));
|
(memcmp(tmd->title_id, dlc_tid_high, sizeof(dlc_tid_high)) == 0) ? "00000000/%08lx.app" : "%08lx.app", getbe32(chunk->id));
|
||||||
|
|
||||||
free(tmd);
|
free(tmd);
|
||||||
@ -2173,19 +2177,12 @@ u32 BuildCiaLegitTicket(Ticket* ticket, u8* title_id, const char* path_cnt, bool
|
|||||||
bool copy = true;
|
bool copy = true;
|
||||||
|
|
||||||
if ((cdn && (LoadCdnTicketFile(&ticket_tmp, path_cnt) != 0)) ||
|
if ((cdn && (LoadCdnTicketFile(&ticket_tmp, path_cnt) != 0)) ||
|
||||||
(!cdn && (FindTicket(&ticket_tmp, title_id, true, src_emunand) != 0))) {
|
(!cdn && (FindTicket(&ticket_tmp, title_id, true, src_emunand) != 0)) ||
|
||||||
|
(GetTicketSize(ticket_tmp) != TICKET_COMMON_SIZE)) {
|
||||||
FindTitleKey(ticket, title_id);
|
FindTitleKey(ticket, title_id);
|
||||||
copy = false;
|
copy = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// either, it's a ticket without ways to check ownership data, smaller sized
|
|
||||||
// or, it's title ticket with > 1024 contents, of which can't make it work with current CiaStub
|
|
||||||
if (copy && GetTicketSize(ticket_tmp) != TICKET_COMMON_SIZE) {
|
|
||||||
ShowPrompt(false, "ID %016llX\nLegit ticket of unsupported size.", getbe64(title_id));
|
|
||||||
free(ticket_tmp);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check the tickets' console id, warn if it isn't zero
|
// check the tickets' console id, warn if it isn't zero
|
||||||
if (copy && getbe32(ticket_tmp->console_id)) {
|
if (copy && getbe32(ticket_tmp->console_id)) {
|
||||||
static u32 default_action = 0;
|
static u32 default_action = 0;
|
||||||
@ -2392,9 +2389,9 @@ u32 BuildInstallFromTmdFileBuffered(const char* path_tmd, const char* path_dest,
|
|||||||
TicketRightsCheck rights_ctx;
|
TicketRightsCheck rights_ctx;
|
||||||
TicketRightsCheck_InitContext(&rights_ctx, (Ticket*)&(cia->ticket));
|
TicketRightsCheck_InitContext(&rights_ctx, (Ticket*)&(cia->ticket));
|
||||||
snprintf(name_content, 256 - (name_content - path_content),
|
snprintf(name_content, 256 - (name_content - path_content),
|
||||||
(cdn) ? "%08lx" : (dlc && !cdn) ? "00000000/%08lx.app" : "%08lx.app", getbe32(chunk->id));
|
(cdn) ? "%08lx" : (dlc) ? "00000000/%08lx.app" : "%08lx.app", getbe32(chunk->id));
|
||||||
if ((fvx_stat(path_content, &fno) != FR_OK) || (fno.fsize != (u32) getbe64(chunk->size)) ||
|
if ((fvx_stat(path_content, &fno) != FR_OK) || (fno.fsize != (u32) getbe64(chunk->size)) ||
|
||||||
!TicketRightsCheck_CheckIndex(&rights_ctx, getbe16(chunk->index))) {
|
(!cdn && !TicketRightsCheck_CheckIndex(&rights_ctx, getbe16(chunk->index)))) {
|
||||||
present[i / 8] ^= 1 << (i % 8);
|
present[i / 8] ^= 1 << (i % 8);
|
||||||
|
|
||||||
u16 index = getbe16(chunk->index);
|
u16 index = getbe16(chunk->index);
|
||||||
|
@ -108,11 +108,11 @@ static u64 offset_ccnt = (u64) -1;
|
|||||||
static u64 offset_tad = (u64) -1;
|
static u64 offset_tad = (u64) -1;
|
||||||
static u32 index_ccnt = (u32) -1;
|
static u32 index_ccnt = (u32) -1;
|
||||||
|
|
||||||
static CiaStub* cia = NULL;
|
// static CiaStub* cia = NULL; *unused*
|
||||||
static TwlHeader* twl = NULL;
|
static TwlHeader* twl = NULL;
|
||||||
|
static NcsdHeader* ncsd = NULL;
|
||||||
static FirmA9LHeader* a9l = NULL;
|
static FirmA9LHeader* a9l = NULL;
|
||||||
static FirmHeader* firm = NULL;
|
static FirmHeader* firm = NULL;
|
||||||
static NcsdHeader* ncsd = NULL;
|
|
||||||
static NcchHeader* ncch = NULL;
|
static NcchHeader* ncch = NULL;
|
||||||
static ExeFsHeader* exefs = NULL;
|
static ExeFsHeader* exefs = NULL;
|
||||||
static RomFsLv3Index lv3idx;
|
static RomFsLv3Index lv3idx;
|
||||||
@ -357,7 +357,7 @@ bool BuildVGameNcsdDir(void) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BuildVGameCiaDir(void) {
|
bool BuildVGameCiaDir(CiaStub* cia) {
|
||||||
CiaInfo info;
|
CiaInfo info;
|
||||||
VirtualFile* templates = templates_cia;
|
VirtualFile* templates = templates_cia;
|
||||||
u32 n = 0;
|
u32 n = 0;
|
||||||
@ -777,21 +777,20 @@ u64 InitVGameDrive(void) { // prerequisite: game file mounted as image
|
|||||||
vgame_buffer = (void*) malloc(0x40000);
|
vgame_buffer = (void*) malloc(0x40000);
|
||||||
if (!vgame_buffer) return 0;
|
if (!vgame_buffer) return 0;
|
||||||
|
|
||||||
templates_cia = (void*) ((u8*) vgame_buffer); // first 184kb reserved (enough for 3364 entries)
|
templates_cia = (void*) ((u8*) vgame_buffer); // first 180kb reserved (enough for 3291 entries)
|
||||||
templates_firm = (void*) (((u8*) vgame_buffer) + 0x2E000); // 2kb reserved (enough for 36 entries)
|
templates_firm = (void*) (((u8*) vgame_buffer) + 0x2D000); // 2kb reserved (enough for 36 entries)
|
||||||
templates_ncsd = (void*) (((u8*) vgame_buffer) + 0x2E800); // 2kb reserved (enough for 36 entries)
|
templates_ncsd = (void*) (((u8*) vgame_buffer) + 0x2D800); // 2kb reserved (enough for 36 entries)
|
||||||
templates_ncch = (void*) (((u8*) vgame_buffer) + 0x2F000); // 1kb reserved (enough for 18 entries)
|
templates_ncch = (void*) (((u8*) vgame_buffer) + 0x2E000); // 1kb reserved (enough for 18 entries)
|
||||||
templates_nds = (void*) (((u8*) vgame_buffer) + 0x2F400); // 1kb reserved (enough for 18 entries)
|
templates_nds = (void*) (((u8*) vgame_buffer) + 0x2E400); // 1kb reserved (enough for 18 entries)
|
||||||
templates_exefs = (void*) (((u8*) vgame_buffer) + 0x2F800); // 1kb reserved (enough for 18 entries)
|
templates_exefs = (void*) (((u8*) vgame_buffer) + 0x2E800); // 1kb reserved (enough for 18 entries)
|
||||||
templates_tad = (void*) (((u8*) vgame_buffer) + 0x2FC00); // 1kb reserved (enough for 18 entries)
|
templates_tad = (void*) (((u8*) vgame_buffer) + 0x2EC00); // 1kb reserved (enough for 18 entries)
|
||||||
cia = (CiaStub*) (void*) (((u8*) vgame_buffer) + 0x30000); // 61kB reserved - should be enough by far
|
twl = (TwlHeader*) (void*) (((u8*) vgame_buffer) + 0x2F000); // 512 byte reserved (not the full thing)
|
||||||
twl = (TwlHeader*) (void*) (((u8*) vgame_buffer) + 0x3F400); // 512 byte reserved (not the full thing)
|
a9l = (FirmA9LHeader*) (void*) (((u8*) vgame_buffer) + 0x2F200); // 512 byte reserved
|
||||||
a9l = (FirmA9LHeader*) (void*) (((u8*) vgame_buffer) + 0x3F600); // 512 byte reserved
|
firm = (FirmHeader*) (void*) (((u8*) vgame_buffer) + 0x2F400); // 512 byte reserved
|
||||||
firm = (FirmHeader*) (void*) (((u8*) vgame_buffer) + 0x3F800); // 512 byte reserved
|
ncsd = (NcsdHeader*) (void*) (((u8*) vgame_buffer) + 0x2F600); // 512 byte reserved
|
||||||
ncsd = (NcsdHeader*) (void*) (((u8*) vgame_buffer) + 0x3FA00); // 512 byte reserved
|
ncch = (NcchHeader*) (void*) (((u8*) vgame_buffer) + 0x2F800); // 512 byte reserved
|
||||||
ncch = (NcchHeader*) (void*) (((u8*) vgame_buffer) + 0x3FC00); // 512 byte reserved
|
exefs = (ExeFsHeader*) (void*) (((u8*) vgame_buffer) + 0x2FA00); // 512 byte reserved (1kb reserve)
|
||||||
exefs = (ExeFsHeader*) (void*) (((u8*) vgame_buffer) + 0x3FE00); // 512 byte reserved
|
// filesystem stuff (RomFS / NitroFS) and CIA/TADX will be allocated on demand
|
||||||
// filesystem stuff (RomFS / NitroFS) will be allocated on demand
|
|
||||||
|
|
||||||
vgame_type = type;
|
vgame_type = type;
|
||||||
return type;
|
return type;
|
||||||
@ -842,14 +841,24 @@ bool OpenVGameDir(VirtualDir* vdir, VirtualFile* ventry) {
|
|||||||
if (!BuildVGameTadDir()) return false;
|
if (!BuildVGameTadDir()) return false;
|
||||||
} else if ((vdir->flags & VFLAG_CIA) && (offset_cia != vdir->offset)) {
|
} else if ((vdir->flags & VFLAG_CIA) && (offset_cia != vdir->offset)) {
|
||||||
CiaInfo info;
|
CiaInfo info;
|
||||||
if ((ReadImageBytes((u8*) cia, 0, 0x20) != 0) ||
|
CiaStub* cia;
|
||||||
(ValidateCiaHeader(&(cia->header)) != 0) ||
|
u8 __attribute__((aligned(32))) hdr[0x20];
|
||||||
(GetCiaInfo(&info, &(cia->header)) != 0) ||
|
if ((ReadImageBytes(hdr, 0, 0x20) != 0) ||
|
||||||
(ReadImageBytes((u8*) cia, 0, info.offset_content) != 0))
|
(ValidateCiaHeader((CiaHeader*) (void*) hdr) != 0) ||
|
||||||
|
(GetCiaInfo(&info, (CiaHeader*) (void*) hdr) != 0) ||
|
||||||
|
!(cia = (CiaStub*) malloc(info.offset_content)))
|
||||||
return false;
|
return false;
|
||||||
|
if (ReadImageBytes((u8*) cia, 0, info.offset_content) != 0) {
|
||||||
|
free(cia);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
offset_cia = vdir->offset; // always zero(!)
|
offset_cia = vdir->offset; // always zero(!)
|
||||||
GetTitleKey(cia_titlekey, (Ticket*)&(cia->ticket));
|
GetTitleKey(cia_titlekey, (Ticket*)&(cia->ticket));
|
||||||
if (!BuildVGameCiaDir()) return false;
|
if (!BuildVGameCiaDir(cia)) {
|
||||||
|
free(cia);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
free(cia);
|
||||||
} else if ((vdir->flags & VFLAG_NCSD) && (offset_ncsd != vdir->offset)) {
|
} else if ((vdir->flags & VFLAG_NCSD) && (offset_ncsd != vdir->offset)) {
|
||||||
if ((ReadImageBytes((u8*) ncsd, 0, sizeof(NcsdHeader)) != 0) ||
|
if ((ReadImageBytes((u8*) ncsd, 0, sizeof(NcsdHeader)) != 0) ||
|
||||||
(ValidateNcsdHeader(ncsd) != 0))
|
(ValidateNcsdHeader(ncsd) != 0))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user