mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2025-01-10 03:27:23 -03:00
NACP changes.
Fixed types for some NACP struct entries (thanks @0Liam !) + added functions to generate and write NACP patches.
This commit is contained in:
parent
2b8e80c283
commit
0229124173
11 changed files with 185 additions and 101 deletions
|
@ -47,8 +47,11 @@ typedef struct {
|
||||||
static options_t options[] = {
|
static options_t options[] = {
|
||||||
{ "set download distribution type", false },
|
{ "set download distribution type", false },
|
||||||
{ "remove console specific data", false },
|
{ "remove console specific data", false },
|
||||||
{ "remove titlekey crypto (implies previous option)", false },
|
{ "remove titlekey crypto (overrides previous option)", false },
|
||||||
{ "change acid rsa key/sig", false }
|
{ "change acid rsa key/sig", false },
|
||||||
|
{ "disable linked account requirement", false },
|
||||||
|
{ "enable screenshots", false },
|
||||||
|
{ "enable video capture", false }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const u32 options_count = MAX_ELEMENTS(options);
|
static const u32 options_count = MAX_ELEMENTS(options);
|
||||||
|
@ -85,7 +88,14 @@ static void nspDump(TitleInfo *title_info)
|
||||||
for(u32 i = 0; i < options_count; i++) printf("%s: %s\n", options[i].str, options[i].val ? "yes" : "no");
|
for(u32 i = 0; i < options_count; i++) printf("%s: %s\n", options[i].str, options[i].val ? "yes" : "no");
|
||||||
printf("______________________________\n\n");
|
printf("______________________________\n\n");
|
||||||
|
|
||||||
bool set_download_type = options[0].val, remove_console_data = options[1].val, remove_titlekey_crypto = options[2].val, change_acid_rsa = options[3].val, success = false;
|
bool set_download_type = options[0].val;
|
||||||
|
bool remove_console_data = options[1].val;
|
||||||
|
bool remove_titlekey_crypto = options[2].val;
|
||||||
|
bool change_acid_rsa = options[3].val;
|
||||||
|
bool patch_sua = options[4].val;
|
||||||
|
bool patch_screenshot = options[5].val;
|
||||||
|
bool patch_video_capture = options[6].val;
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
u8 *buf = NULL;
|
u8 *buf = NULL;
|
||||||
char *dump_name = NULL, *path = NULL;
|
char *dump_name = NULL, *path = NULL;
|
||||||
|
@ -263,7 +273,11 @@ static void nspDump(TitleInfo *title_info)
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add nacp mods here
|
if (!nacpGenerateNcaPatch(cur_nacp_ctx, patch_sua, patch_screenshot, patch_video_capture))
|
||||||
|
{
|
||||||
|
consolePrint("nacp nca patch failed (%s)\n", cur_nca_ctx->content_id_str);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
if (!nacpGenerateAuthoringToolXml(cur_nacp_ctx, title_info->version.value, cnmtGetRequiredTitleVersion(&cnmt_ctx)))
|
if (!nacpGenerateAuthoringToolXml(cur_nacp_ctx, title_info->version.value, cnmtGetRequiredTitleVersion(&cnmt_ctx)))
|
||||||
{
|
{
|
||||||
|
@ -505,18 +519,13 @@ static void nspDump(TitleInfo *title_info)
|
||||||
switch(cur_nca_ctx->content_type)
|
switch(cur_nca_ctx->content_type)
|
||||||
{
|
{
|
||||||
case NcmContentType_Meta:
|
case NcmContentType_Meta:
|
||||||
{
|
|
||||||
cnmtWriteNcaPatch(&cnmt_ctx, buf, blksize, offset);
|
cnmtWriteNcaPatch(&cnmt_ctx, buf, blksize, offset);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case NcmContentType_Program:
|
case NcmContentType_Program:
|
||||||
{
|
programInfoWriteNcaPatch((ProgramInfoContext*)cur_nca_ctx->content_type_ctx, buf, blksize, offset);
|
||||||
ProgramInfoContext *cur_program_info_ctx = (ProgramInfoContext*)cur_nca_ctx->content_type_ctx;
|
|
||||||
programInfoWriteNcaPatch(cur_program_info_ctx, buf, blksize, offset);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case NcmContentType_Control:
|
case NcmContentType_Control:
|
||||||
// write nacp patches here
|
nacpWriteNcaPatch((NacpContext*)cur_nca_ctx->content_type_ctx, buf, blksize, offset);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -46,8 +46,11 @@ typedef struct {
|
||||||
static options_t options[] = {
|
static options_t options[] = {
|
||||||
{ "set download distribution type", false },
|
{ "set download distribution type", false },
|
||||||
{ "remove console specific data", false },
|
{ "remove console specific data", false },
|
||||||
{ "remove titlekey crypto (implies previous option)", false },
|
{ "remove titlekey crypto (overrides previous option)", false },
|
||||||
{ "change acid rsa key/sig", false }
|
{ "change acid rsa key/sig", false },
|
||||||
|
{ "disable linked account requirement", false },
|
||||||
|
{ "enable screenshots", false },
|
||||||
|
{ "enable video capture", false }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const u32 options_count = MAX_ELEMENTS(options);
|
static const u32 options_count = MAX_ELEMENTS(options);
|
||||||
|
@ -84,7 +87,13 @@ static void nspDump(TitleInfo *title_info)
|
||||||
for(u32 i = 0; i < options_count; i++) printf("%s: %s\n", options[i].str, options[i].val ? "yes" : "no");
|
for(u32 i = 0; i < options_count; i++) printf("%s: %s\n", options[i].str, options[i].val ? "yes" : "no");
|
||||||
printf("______________________________\n\n");
|
printf("______________________________\n\n");
|
||||||
|
|
||||||
bool set_download_type = options[0].val, remove_console_data = options[1].val, remove_titlekey_crypto = options[2].val, change_acid_rsa = options[3].val;
|
bool set_download_type = options[0].val;
|
||||||
|
bool remove_console_data = options[1].val;
|
||||||
|
bool remove_titlekey_crypto = options[2].val;
|
||||||
|
bool change_acid_rsa = options[3].val;
|
||||||
|
bool patch_sua = options[4].val;
|
||||||
|
bool patch_screenshot = options[5].val;
|
||||||
|
bool patch_video_capture = options[6].val;
|
||||||
|
|
||||||
u8 *buf = NULL;
|
u8 *buf = NULL;
|
||||||
char *dump_name = NULL, *path = NULL;
|
char *dump_name = NULL, *path = NULL;
|
||||||
|
@ -262,7 +271,11 @@ static void nspDump(TitleInfo *title_info)
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add nacp mods here
|
if (!nacpGenerateNcaPatch(cur_nacp_ctx, patch_sua, patch_screenshot, patch_video_capture))
|
||||||
|
{
|
||||||
|
consolePrint("nacp nca patch failed (%s)\n", cur_nca_ctx->content_id_str);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
if (!nacpGenerateAuthoringToolXml(cur_nacp_ctx, title_info->version.value, cnmtGetRequiredTitleVersion(&cnmt_ctx)))
|
if (!nacpGenerateAuthoringToolXml(cur_nacp_ctx, title_info->version.value, cnmtGetRequiredTitleVersion(&cnmt_ctx)))
|
||||||
{
|
{
|
||||||
|
@ -523,18 +536,13 @@ static void nspDump(TitleInfo *title_info)
|
||||||
switch(cur_nca_ctx->content_type)
|
switch(cur_nca_ctx->content_type)
|
||||||
{
|
{
|
||||||
case NcmContentType_Meta:
|
case NcmContentType_Meta:
|
||||||
{
|
|
||||||
cnmtWriteNcaPatch(&cnmt_ctx, buf, blksize, offset);
|
cnmtWriteNcaPatch(&cnmt_ctx, buf, blksize, offset);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case NcmContentType_Program:
|
case NcmContentType_Program:
|
||||||
{
|
programInfoWriteNcaPatch((ProgramInfoContext*)cur_nca_ctx->content_type_ctx, buf, blksize, offset);
|
||||||
ProgramInfoContext *cur_program_info_ctx = (ProgramInfoContext*)cur_nca_ctx->content_type_ctx;
|
|
||||||
programInfoWriteNcaPatch(cur_program_info_ctx, buf, blksize, offset);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case NcmContentType_Control:
|
case NcmContentType_Control:
|
||||||
// write nacp patches here
|
nacpWriteNcaPatch((NacpContext*)cur_nca_ctx->content_type_ctx, buf, blksize, offset);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -320,14 +320,14 @@ void cnmtWriteNcaPatch(ContentMetaContext *cnmt_ctx, void *buf, u64 buf_size, u6
|
||||||
/* Using cnmtIsValidContext() here would probably take up precious CPU cycles. */
|
/* Using cnmtIsValidContext() here would probably take up precious CPU cycles. */
|
||||||
if (!cnmt_ctx || !cnmt_ctx->nca_ctx || cnmt_ctx->nca_ctx->content_type != NcmContentType_Meta || !cnmt_ctx->nca_ctx->content_type_ctx_patch || cnmt_ctx->nca_patch.written) return;
|
if (!cnmt_ctx || !cnmt_ctx->nca_ctx || cnmt_ctx->nca_ctx->content_type != NcmContentType_Meta || !cnmt_ctx->nca_ctx->content_type_ctx_patch || cnmt_ctx->nca_patch.written) return;
|
||||||
|
|
||||||
/* Attempt to write Partition FS entry. */
|
/* Attempt to write Partition FS entry patch. */
|
||||||
pfsWriteEntryPatchToMemoryBuffer(&(cnmt_ctx->pfs_ctx), &(cnmt_ctx->nca_patch), buf, buf_size, buf_offset);
|
pfsWriteEntryPatchToMemoryBuffer(&(cnmt_ctx->pfs_ctx), &(cnmt_ctx->nca_patch), buf, buf_size, buf_offset);
|
||||||
|
|
||||||
/* Check if we need to update the NCA content type context patch status. */
|
/* Check if we need to update the NCA content type context patch status. */
|
||||||
if (cnmt_ctx->nca_patch.written)
|
if (cnmt_ctx->nca_patch.written)
|
||||||
{
|
{
|
||||||
cnmt_ctx->nca_ctx->content_type_ctx_patch = false;
|
cnmt_ctx->nca_ctx->content_type_ctx_patch = false;
|
||||||
LOGFILE("CNMT Partition FS file entry patch successfully written to NCA \"%s\"!", cnmt_ctx->nca_ctx->content_id_str);
|
LOGFILE("CNMT Partition FS entry patch successfully written to NCA \"%s\"!", cnmt_ctx->nca_ctx->content_id_str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -247,7 +247,7 @@ bool cnmtUpdateContentInfo(ContentMetaContext *cnmt_ctx, NcaContext *nca_ctx);
|
||||||
/// Generates a Partition FS entry patch for the NcaContext pointed to by the input ContentMetaContext, using its raw CNMT data.
|
/// Generates a Partition FS entry patch for the NcaContext pointed to by the input ContentMetaContext, using its raw CNMT data.
|
||||||
bool cnmtGenerateNcaPatch(ContentMetaContext *cnmt_ctx);
|
bool cnmtGenerateNcaPatch(ContentMetaContext *cnmt_ctx);
|
||||||
|
|
||||||
/// Writes data from the Partition FS patch in the input ContentMetaContext to the provided buffer.
|
/// Writes data from the Partition FS entry patch in the input ContentMetaContext to the provided buffer.
|
||||||
void cnmtWriteNcaPatch(ContentMetaContext *cnmt_ctx, void *buf, u64 buf_size, u64 buf_offset);
|
void cnmtWriteNcaPatch(ContentMetaContext *cnmt_ctx, void *buf, u64 buf_size, u64 buf_offset);
|
||||||
|
|
||||||
/// Generates an AuthoringTool-like XML using information from a previously initialized ContentMetaContext, as well as a pointer to 'nca_ctx_count' NcaContext with content information.
|
/// Generates an AuthoringTool-like XML using information from a previously initialized ContentMetaContext, as well as a pointer to 'nca_ctx_count' NcaContext with content information.
|
||||||
|
|
|
@ -329,6 +329,71 @@ end:
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool nacpGenerateNcaPatch(NacpContext *nacp_ctx, bool patch_sua, bool patch_screenshot, bool patch_video_capture)
|
||||||
|
{
|
||||||
|
if (!nacpIsValidContext(nacp_ctx))
|
||||||
|
{
|
||||||
|
LOGFILE("Invalid parameters!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_NacpStruct *data = nacp_ctx->data;
|
||||||
|
u8 nacp_hash[SHA256_HASH_SIZE] = {0};
|
||||||
|
|
||||||
|
/* Check if we're not patching anything. */
|
||||||
|
if (!patch_sua && !patch_screenshot && !patch_video_capture) return true;
|
||||||
|
|
||||||
|
/* Patch StartupUserAccount, StartupUserAccountOption and UserAccountSwitchLock. */
|
||||||
|
if (patch_sua)
|
||||||
|
{
|
||||||
|
data->startup_user_account = NacpStartupUserAccount_None;
|
||||||
|
data->startup_user_account_option &= ~NacpStartupUserAccountOption_IsOptional;
|
||||||
|
data->user_account_switch_lock = NacpUserAccountSwitchLock_Disable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Patch Screenshot. */
|
||||||
|
if (patch_screenshot) data->screenshot = NacpScreenshot_Allow;
|
||||||
|
|
||||||
|
/* Patch VideoCapture. */
|
||||||
|
if (patch_video_capture) data->video_capture = NacpVideoCapture_Enable;
|
||||||
|
|
||||||
|
/* Check if we really need to generate this patch. */
|
||||||
|
sha256CalculateHash(nacp_hash, data, sizeof(_NacpStruct));
|
||||||
|
if (!memcmp(nacp_hash, nacp_ctx->data_hash, sizeof(nacp_hash)))
|
||||||
|
{
|
||||||
|
LOGFILE("Skipping NACP patching - no flags have changed.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate RomFS file entry patch. */
|
||||||
|
if (!romfsGenerateFileEntryPatch(&(nacp_ctx->romfs_ctx), nacp_ctx->romfs_file_entry, data, sizeof(_NacpStruct), 0, &(nacp_ctx->nca_patch)))
|
||||||
|
{
|
||||||
|
LOGFILE("Failed to generate RomFS file entry patch!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update NCA content type context patch status. */
|
||||||
|
nacp_ctx->nca_ctx->content_type_ctx_patch = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nacpWriteNcaPatch(NacpContext *nacp_ctx, void *buf, u64 buf_size, u64 buf_offset)
|
||||||
|
{
|
||||||
|
/* Using nacpIsValidContext() here would probably take up precious CPU cycles. */
|
||||||
|
if (!nacp_ctx || !nacp_ctx->nca_ctx || nacp_ctx->nca_ctx->content_type != NcmContentType_Control || !nacp_ctx->nca_ctx->content_type_ctx_patch || nacp_ctx->nca_patch.written) return;
|
||||||
|
|
||||||
|
/* Attempt to write RomFS file entry patch. */
|
||||||
|
romfsWriteFileEntryPatchToMemoryBuffer(&(nacp_ctx->romfs_ctx), &(nacp_ctx->nca_patch), buf, buf_size, buf_offset);
|
||||||
|
|
||||||
|
/* Check if we need to update the NCA content type context patch status. */
|
||||||
|
if (nacp_ctx->nca_patch.written)
|
||||||
|
{
|
||||||
|
nacp_ctx->nca_ctx->content_type_ctx_patch = false;
|
||||||
|
LOGFILE("NACP RomFS file entry patch successfully written to NCA \"%s\"!", nacp_ctx->nca_ctx->content_id_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 required_system_version)
|
bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 required_system_version)
|
||||||
{
|
{
|
||||||
if (!nacpIsValidContext(nacp_ctx))
|
if (!nacpIsValidContext(nacp_ctx))
|
||||||
|
@ -424,13 +489,13 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 requir
|
||||||
/* Rating. */
|
/* Rating. */
|
||||||
for(i = 0, count = 0; i < NacpRatingAgeOrganization_Count; i++)
|
for(i = 0, count = 0; i < NacpRatingAgeOrganization_Count; i++)
|
||||||
{
|
{
|
||||||
u8 age = *((u8*)&(nacp->rating_age) + i);
|
s8 age = *(((s8*)&(nacp->rating_age)) + i);
|
||||||
if (age == 0xFF) continue;
|
if (age < 0) continue;
|
||||||
|
|
||||||
if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \
|
if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \
|
||||||
" <Rating>\n" \
|
" <Rating>\n" \
|
||||||
" <Organization>%s</Organization>\n" \
|
" <Organization>%s</Organization>\n" \
|
||||||
" <Age>%u</Age>\n" \
|
" <Age>%d</Age>\n" \
|
||||||
" </Rating>\n", \
|
" </Rating>\n", \
|
||||||
nacpGetRatingAgeOrganizationString(i),
|
nacpGetRatingAgeOrganizationString(i),
|
||||||
age)) goto end;
|
age)) goto end;
|
||||||
|
@ -450,19 +515,19 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 requir
|
||||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "SaveDataOwnerId", nacp->save_data_owner_id)) goto end;
|
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "SaveDataOwnerId", nacp->save_data_owner_id)) goto end;
|
||||||
|
|
||||||
/* UserAccountSaveDataSize. */
|
/* UserAccountSaveDataSize. */
|
||||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataSize", nacp->user_account_save_data_size)) goto end;
|
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataSize", (u64)nacp->user_account_save_data_size)) goto end;
|
||||||
|
|
||||||
/* UserAccountSaveDataJournalSize. */
|
/* UserAccountSaveDataJournalSize. */
|
||||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataJournalSize", nacp->user_account_save_data_journal_size)) goto end;
|
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataJournalSize", (u64)nacp->user_account_save_data_journal_size)) goto end;
|
||||||
|
|
||||||
/* DeviceSaveDataSize. */
|
/* DeviceSaveDataSize. */
|
||||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataSize", nacp->device_save_data_size)) goto end;
|
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataSize", (u64)nacp->device_save_data_size)) goto end;
|
||||||
|
|
||||||
/* DeviceSaveDataJournalSize. */
|
/* DeviceSaveDataJournalSize. */
|
||||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataJournalSize", nacp->device_save_data_journal_size)) goto end;
|
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataJournalSize", (u64)nacp->device_save_data_journal_size)) goto end;
|
||||||
|
|
||||||
/* BcatDeliveryCacheStorageSize. */
|
/* BcatDeliveryCacheStorageSize. */
|
||||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "BcatDeliveryCacheStorageSize", nacp->bcat_delivery_cache_storage_size)) goto end;
|
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "BcatDeliveryCacheStorageSize", (u64)nacp->bcat_delivery_cache_storage_size)) goto end;
|
||||||
|
|
||||||
/* ApplicationErrorCodeCategory. */
|
/* ApplicationErrorCodeCategory. */
|
||||||
if (!nacpAddStringFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "ApplicationErrorCodeCategory", nacp->application_error_code_category)) goto end;
|
if (!nacpAddStringFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "ApplicationErrorCodeCategory", nacp->application_error_code_category)) goto end;
|
||||||
|
@ -541,28 +606,28 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 requir
|
||||||
if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "AddOnContentRegistrationType", nacp->add_on_content_registration_type, &nacpGetAddOnContentRegistrationTypeString)) goto end;
|
if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "AddOnContentRegistrationType", nacp->add_on_content_registration_type, &nacpGetAddOnContentRegistrationTypeString)) goto end;
|
||||||
|
|
||||||
/* UserAccountSaveDataSizeMax. */
|
/* UserAccountSaveDataSizeMax. */
|
||||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataSizeMax", nacp->user_account_save_data_size_max)) goto end;
|
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataSizeMax", (u64)nacp->user_account_save_data_size_max)) goto end;
|
||||||
|
|
||||||
/* UserAccountSaveDataJournalSizeMax. */
|
/* UserAccountSaveDataJournalSizeMax. */
|
||||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataJournalSizeMax", nacp->user_account_save_data_journal_size_max)) goto end;
|
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataJournalSizeMax", (u64)nacp->user_account_save_data_journal_size_max)) goto end;
|
||||||
|
|
||||||
/* DeviceSaveDataSizeMax. */
|
/* DeviceSaveDataSizeMax. */
|
||||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataSizeMax", nacp->device_save_data_size_max)) goto end;
|
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataSizeMax", (u64)nacp->device_save_data_size_max)) goto end;
|
||||||
|
|
||||||
/* DeviceSaveDataJournalSizeMax. */
|
/* DeviceSaveDataJournalSizeMax. */
|
||||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataJournalSizeMax", nacp->device_save_data_journal_size_max)) goto end;
|
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataJournalSizeMax", (u64)nacp->device_save_data_journal_size_max)) goto end;
|
||||||
|
|
||||||
/* TemporaryStorageSize. */
|
/* TemporaryStorageSize. */
|
||||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "TemporaryStorageSize", nacp->temporary_storage_size)) goto end;
|
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "TemporaryStorageSize", (u64)nacp->temporary_storage_size)) goto end;
|
||||||
|
|
||||||
/* CacheStorageSize. */
|
/* CacheStorageSize. */
|
||||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageSize", nacp->cache_storage_size)) goto end;
|
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageSize", (u64)nacp->cache_storage_size)) goto end;
|
||||||
|
|
||||||
/* CacheStorageJournalSize. */
|
/* CacheStorageJournalSize. */
|
||||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageJournalSize", nacp->cache_storage_journal_size)) goto end;
|
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageJournalSize", (u64)nacp->cache_storage_journal_size)) goto end;
|
||||||
|
|
||||||
/* CacheStorageDataAndJournalSizeMax. */
|
/* CacheStorageDataAndJournalSizeMax. */
|
||||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageDataAndJournalSizeMax", nacp->cache_storage_data_and_journal_size_max)) goto end;
|
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageDataAndJournalSizeMax", (u64)nacp->cache_storage_data_and_journal_size_max)) goto end;
|
||||||
|
|
||||||
/* CacheStorageIndexMax. */
|
/* CacheStorageIndexMax. */
|
||||||
if (!nacpAddU16FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageIndexMax", nacp->cache_storage_index_max, true)) goto end;
|
if (!nacpAddU16FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageIndexMax", nacp->cache_storage_index_max, true)) goto end;
|
||||||
|
|
|
@ -75,7 +75,11 @@ typedef enum {
|
||||||
NacpLanguage_TraditionalChinese = 13,
|
NacpLanguage_TraditionalChinese = 13,
|
||||||
NacpLanguage_SimplifiedChinese = 14,
|
NacpLanguage_SimplifiedChinese = 14,
|
||||||
NacpLanguage_BrazilianPortuguese = 15,
|
NacpLanguage_BrazilianPortuguese = 15,
|
||||||
NacpLanguage_Count = 16 ///< Total values supported by this enum.
|
NacpLanguage_Count = 16, ///< Total values supported by this enum.
|
||||||
|
|
||||||
|
/// Old.
|
||||||
|
NacpLanguage_Taiwanese = NacpLanguage_TraditionalChinese,
|
||||||
|
NacpLanguage_Chinese = NacpLanguage_SimplifiedChinese
|
||||||
} NacpLanguage;
|
} NacpLanguage;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -156,20 +160,20 @@ typedef enum {
|
||||||
} NacpRatingAgeOrganization;
|
} NacpRatingAgeOrganization;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u8 cero;
|
s8 cero;
|
||||||
u8 gracgcrb;
|
s8 grac_gcrb;
|
||||||
u8 gsrmr;
|
s8 gsrmr;
|
||||||
u8 esrb;
|
s8 esrb;
|
||||||
u8 class_ind;
|
s8 class_ind;
|
||||||
u8 usk;
|
s8 usk;
|
||||||
u8 pegi;
|
s8 pegi;
|
||||||
u8 pegi_portugal;
|
s8 pegi_portugal;
|
||||||
u8 pegibbfc;
|
s8 pegi_bbfc;
|
||||||
u8 russian;
|
s8 russian;
|
||||||
u8 acb;
|
s8 acb;
|
||||||
u8 oflc;
|
s8 oflc;
|
||||||
u8 iarc_generic;
|
s8 iarc_generic;
|
||||||
u8 reserved[0x13];
|
s8 reserved[0x13];
|
||||||
} NacpRatingAge;
|
} NacpRatingAge;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -293,11 +297,11 @@ typedef struct {
|
||||||
char display_version[0x10];
|
char display_version[0x10];
|
||||||
u64 add_on_content_base_id;
|
u64 add_on_content_base_id;
|
||||||
u64 save_data_owner_id;
|
u64 save_data_owner_id;
|
||||||
u64 user_account_save_data_size;
|
s64 user_account_save_data_size;
|
||||||
u64 user_account_save_data_journal_size;
|
s64 user_account_save_data_journal_size;
|
||||||
u64 device_save_data_size;
|
s64 device_save_data_size;
|
||||||
u64 device_save_data_journal_size;
|
s64 device_save_data_journal_size;
|
||||||
u64 bcat_delivery_cache_storage_size;
|
s64 bcat_delivery_cache_storage_size;
|
||||||
char application_error_code_category[0x8];
|
char application_error_code_category[0x8];
|
||||||
u64 local_communication_id[8];
|
u64 local_communication_id[8];
|
||||||
u8 logo_type; ///< NacpLogoType.
|
u8 logo_type; ///< NacpLogoType.
|
||||||
|
@ -311,14 +315,14 @@ typedef struct {
|
||||||
char bcat_passphrase[0x41];
|
char bcat_passphrase[0x41];
|
||||||
u8 startup_user_account_option; ///< NacpStartupUserAccountOption.
|
u8 startup_user_account_option; ///< NacpStartupUserAccountOption.
|
||||||
u8 reserved_2[0x6];
|
u8 reserved_2[0x6];
|
||||||
u64 user_account_save_data_size_max;
|
s64 user_account_save_data_size_max;
|
||||||
u64 user_account_save_data_journal_size_max;
|
s64 user_account_save_data_journal_size_max;
|
||||||
u64 device_save_data_size_max;
|
s64 device_save_data_size_max;
|
||||||
u64 device_save_data_journal_size_max;
|
s64 device_save_data_journal_size_max;
|
||||||
u64 temporary_storage_size;
|
s64 temporary_storage_size;
|
||||||
u64 cache_storage_size;
|
s64 cache_storage_size;
|
||||||
u64 cache_storage_journal_size;
|
s64 cache_storage_journal_size;
|
||||||
u64 cache_storage_data_and_journal_size_max;
|
s64 cache_storage_data_and_journal_size_max;
|
||||||
u16 cache_storage_index_max;
|
u16 cache_storage_index_max;
|
||||||
u8 reserved_3[0x6];
|
u8 reserved_3[0x6];
|
||||||
u64 play_log_queryable_application_id[0x10];
|
u64 play_log_queryable_application_id[0x10];
|
||||||
|
@ -363,6 +367,15 @@ typedef struct {
|
||||||
/// Initializes a NacpContext using a previously initialized NcaContext (which must belong to a Control NCA).
|
/// Initializes a NacpContext using a previously initialized NcaContext (which must belong to a Control NCA).
|
||||||
bool nacpInitializeContext(NacpContext *out, NcaContext *nca_ctx);
|
bool nacpInitializeContext(NacpContext *out, NcaContext *nca_ctx);
|
||||||
|
|
||||||
|
/// Changes flags in the NACP from the input NacpContext and generates a RomFS file entry patch if needed.
|
||||||
|
/// If 'patch_sua' is true, StartupUserAccount is set to None, the IsOptional bit in StartupUserAccountOption is cleared and UserAccountSwitchLock is set to Disable.
|
||||||
|
/// If 'patch_screenshot' is true, Screenshot is set to Allow.
|
||||||
|
/// If 'patch_video_capture' is true, VideoCapture is set to Enable.
|
||||||
|
bool nacpGenerateNcaPatch(NacpContext *nacp_ctx, bool patch_sua, bool patch_screenshot, bool patch_video_capture);
|
||||||
|
|
||||||
|
/// Writes data from the RomFS file entry patch in the input NacpContext to the provided buffer.
|
||||||
|
void nacpWriteNcaPatch(NacpContext *nacp_ctx, void *buf, u64 buf_size, u64 buf_offset);
|
||||||
|
|
||||||
/// Generates an AuthoringTool-like XML using information from a previously initialized NacpContext, as well as the Application/Patch version and the required system version.
|
/// Generates an AuthoringTool-like XML using information from a previously initialized NacpContext, as well as the Application/Patch version and the required system version.
|
||||||
/// If the function succeeds, XML data and size will get saved to the 'authoring_tool_xml' and 'authoring_tool_xml_size' members from the NacpContext.
|
/// If the function succeeds, XML data and size will get saved to the 'authoring_tool_xml' and 'authoring_tool_xml_size' members from the NacpContext.
|
||||||
bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 required_system_version);
|
bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 required_system_version);
|
||||||
|
@ -438,17 +451,4 @@ NX_INLINE bool nacpIsValidContext(NacpContext *nacp_ctx)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
NX_INLINE bool nacpIsNcaPatchRequired(NacpContext *nacp_ctx)
|
|
||||||
{
|
|
||||||
if (!nacpIsValidContext(nacp_ctx)) return false;
|
|
||||||
u8 tmp_hash[SHA256_HASH_SIZE] = {0};
|
|
||||||
sha256CalculateHash(tmp_hash, nacp_ctx->data, sizeof(_NacpStruct));
|
|
||||||
return (memcmp(tmp_hash, nacp_ctx->data_hash, SHA256_HASH_SIZE) != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
NX_INLINE bool nacpGenerateNcaPatch(NacpContext *nacp_ctx)
|
|
||||||
{
|
|
||||||
return (nacpIsValidContext(nacp_ctx) && romfsGenerateFileEntryPatch(&(nacp_ctx->romfs_ctx), nacp_ctx->romfs_file_entry, nacp_ctx->data, sizeof(_NacpStruct), 0, &(nacp_ctx->nca_patch)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* __NACP_H__ */
|
#endif /* __NACP_H__ */
|
||||||
|
|
|
@ -306,13 +306,13 @@ void npdmWriteNcaPatch(NpdmContext *npdm_ctx, void *buf, u64 buf_size, u64 buf_o
|
||||||
if (!npdm_ctx || !npdm_ctx->pfs_ctx || !npdm_ctx->pfs_ctx->nca_fs_ctx || !(nca_ctx = (NcaContext*)npdm_ctx->pfs_ctx->nca_fs_ctx->nca_ctx) || nca_ctx->content_type != NcmContentType_Program || \
|
if (!npdm_ctx || !npdm_ctx->pfs_ctx || !npdm_ctx->pfs_ctx->nca_fs_ctx || !(nca_ctx = (NcaContext*)npdm_ctx->pfs_ctx->nca_fs_ctx->nca_ctx) || nca_ctx->content_type != NcmContentType_Program || \
|
||||||
!nca_ctx->content_type_ctx_patch || npdm_ctx->nca_patch.written) return;
|
!nca_ctx->content_type_ctx_patch || npdm_ctx->nca_patch.written) return;
|
||||||
|
|
||||||
/* Attempt to write Partition FS entry. */
|
/* Attempt to write Partition FS entry patch. */
|
||||||
pfsWriteEntryPatchToMemoryBuffer(npdm_ctx->pfs_ctx, &(npdm_ctx->nca_patch), buf, buf_size, buf_offset);
|
pfsWriteEntryPatchToMemoryBuffer(npdm_ctx->pfs_ctx, &(npdm_ctx->nca_patch), buf, buf_size, buf_offset);
|
||||||
|
|
||||||
/* Check if we need to update the NCA content type context patch status. */
|
/* Check if we need to update the NCA content type context patch status. */
|
||||||
if (npdm_ctx->nca_patch.written)
|
if (npdm_ctx->nca_patch.written)
|
||||||
{
|
{
|
||||||
nca_ctx->content_type_ctx_patch = false;
|
nca_ctx->content_type_ctx_patch = false;
|
||||||
LOGFILE("NPDM Partition FS file entry patch successfully written to NCA \"%s\"!", nca_ctx->content_id_str);
|
LOGFILE("NPDM Partition FS entry patch successfully written to NCA \"%s\"!", nca_ctx->content_id_str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -557,7 +557,7 @@ bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx
|
||||||
/// Changes the ACID public key from the NPDM in the input NpdmContext, updates the ACID signature from the NCA header in the underlying NCA context and generates a Partition FS entry patch.
|
/// Changes the ACID public key from the NPDM in the input NpdmContext, updates the ACID signature from the NCA header in the underlying NCA context and generates a Partition FS entry patch.
|
||||||
bool npdmGenerateNcaPatch(NpdmContext *npdm_ctx);
|
bool npdmGenerateNcaPatch(NpdmContext *npdm_ctx);
|
||||||
|
|
||||||
/// Writes data from the Partition FS patch in the input NpdmContext to the provided buffer.
|
/// Writes data from the Partition FS entry patch in the input NpdmContext to the provided buffer.
|
||||||
void npdmWriteNcaPatch(NpdmContext *npdm_ctx, void *buf, u64 buf_size, u64 buf_offset);
|
void npdmWriteNcaPatch(NpdmContext *npdm_ctx, void *buf, u64 buf_size, u64 buf_offset);
|
||||||
|
|
||||||
/// Helper inline functions.
|
/// Helper inline functions.
|
||||||
|
|
|
@ -524,6 +524,8 @@ bool romfsGenerateFileEntryPatch(RomFileSystemContext *ctx, RomFileSystemFileEnt
|
||||||
success = ncaGenerateHierarchicalIntegrityPatch(ctx->nca_fs_ctx, data, data_size, fs_offset, &(out->cur_format_patch));
|
success = ncaGenerateHierarchicalIntegrityPatch(ctx->nca_fs_ctx, data, data_size, fs_offset, &(out->cur_format_patch));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out->written = false;
|
||||||
|
|
||||||
if (!success) LOGFILE("Failed to generate 0x%lX bytes Hierarchical%s patch at offset 0x%lX for RomFS file entry!", data_size, \
|
if (!success) LOGFILE("Failed to generate 0x%lX bytes Hierarchical%s patch at offset 0x%lX for RomFS file entry!", data_size, \
|
||||||
ctx->nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? "Sha256" : "Integrity", fs_offset);
|
ctx->nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? "Sha256" : "Integrity", fs_offset);
|
||||||
|
|
||||||
|
|
|
@ -106,6 +106,7 @@ typedef struct {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool use_old_format_patch; ///< Old format patch flag.
|
bool use_old_format_patch; ///< Old format patch flag.
|
||||||
|
bool written; ///< Set to true if the patch has been completely written.
|
||||||
NcaHierarchicalSha256Patch old_format_patch; ///< Used with NCA0 RomFS sections.
|
NcaHierarchicalSha256Patch old_format_patch; ///< Used with NCA0 RomFS sections.
|
||||||
NcaHierarchicalIntegrityPatch cur_format_patch; ///< Used with NCA2/NCA3 RomFS sections.
|
NcaHierarchicalIntegrityPatch cur_format_patch; ///< Used with NCA2/NCA3 RomFS sections.
|
||||||
} RomFileSystemFileEntryPatch;
|
} RomFileSystemFileEntryPatch;
|
||||||
|
@ -183,17 +184,19 @@ NX_INLINE void romfsWriteFileEntryPatchToMemoryBuffer(RomFileSystemContext *ctx,
|
||||||
if (patch->use_old_format_patch)
|
if (patch->use_old_format_patch)
|
||||||
{
|
{
|
||||||
ncaWriteHierarchicalSha256PatchToMemoryBuffer((NcaContext*)ctx->nca_fs_ctx->nca_ctx, &(patch->old_format_patch), buf, buf_size, buf_offset);
|
ncaWriteHierarchicalSha256PatchToMemoryBuffer((NcaContext*)ctx->nca_fs_ctx->nca_ctx, &(patch->old_format_patch), buf, buf_size, buf_offset);
|
||||||
|
patch->written = patch->old_format_patch.written;
|
||||||
} else {
|
} else {
|
||||||
ncaWriteHierarchicalIntegrityPatchToMemoryBuffer((NcaContext*)ctx->nca_fs_ctx->nca_ctx, &(patch->cur_format_patch), buf, buf_size, buf_offset);
|
ncaWriteHierarchicalIntegrityPatchToMemoryBuffer((NcaContext*)ctx->nca_fs_ctx->nca_ctx, &(patch->cur_format_patch), buf, buf_size, buf_offset);
|
||||||
|
patch->written = patch->cur_format_patch.written;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NX_INLINE void romfsFreeFileEntryPatch(RomFileSystemFileEntryPatch *patch)
|
NX_INLINE void romfsFreeFileEntryPatch(RomFileSystemFileEntryPatch *patch)
|
||||||
{
|
{
|
||||||
if (!patch) return;
|
if (!patch) return;
|
||||||
patch->use_old_format_patch = false;
|
|
||||||
ncaFreeHierarchicalSha256Patch(&(patch->old_format_patch));
|
ncaFreeHierarchicalSha256Patch(&(patch->old_format_patch));
|
||||||
ncaFreeHierarchicalIntegrityPatch(&(patch->cur_format_patch));
|
ncaFreeHierarchicalIntegrityPatch(&(patch->cur_format_patch));
|
||||||
|
memset(patch, 0, sizeof(RomFileSystemFileEntryPatch));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* __ROMFS_H__ */
|
#endif /* __ROMFS_H__ */
|
||||||
|
|
27
todo.txt
27
todo.txt
|
@ -7,31 +7,28 @@ list of top level functions designed to alter nca data in order of (possible) us
|
||||||
|
|
||||||
* ncaRemoveTitlekeyCrypto (can be used with digital titles + game updates in gamecards)
|
* ncaRemoveTitlekeyCrypto (can be used with digital titles + game updates in gamecards)
|
||||||
|
|
||||||
* cnmtGenerateNcaPatch (Meta)
|
|
||||||
* calls pfsGenerateEntryPatch
|
|
||||||
* calls ncaGenerateHierarchicalSha256Patch
|
|
||||||
|
|
||||||
* programInfoGenerateNcaPatch (Program)
|
* programInfoGenerateNcaPatch (Program)
|
||||||
* calls npdmChangeAcidPublicKeyAndNcaSignature
|
* calls npdmGenerateNcaPatch
|
||||||
* calls pfsGenerateEntryPatch
|
* calls pfsGenerateEntryPatch
|
||||||
* calls ncaGenerateHierarchicalSha256Patch
|
* calls ncaGenerateHierarchicalSha256Patch
|
||||||
|
|
||||||
* nacpGenerateNcaPatch (Control)
|
* nacpGenerateNcaPatch (Control)
|
||||||
* calls romfsGenerateFileEntryPatch
|
* calls romfsGenerateFileEntryPatch
|
||||||
* calls ncaGenerateHierarchicalSha256Patch / ncaGenerateHierarchicalIntegrityPatch
|
* calls ncaGenerateHierarchicalSha256Patch / ncaGenerateHierarchicalIntegrityPatch
|
||||||
* nacpIsNcaPatchRequired is used to check if a nacp patch was applied
|
|
||||||
* missing wrapper for romfsWriteFileEntryPatchToMemoryBuffer !!!
|
|
||||||
* missing functions for nacp mods !!!
|
|
||||||
|
|
||||||
* ncaEncryptHeader (doesn't modify anything per se, but it's used to generate new encrypted header data if needed)
|
* ncaEncryptHeader (doesn't modify anything per se, but it's used to generate new encrypted header data if needed)
|
||||||
|
|
||||||
inside dump loop:
|
inside dump loop:
|
||||||
|
* cnmtGenerateNcaPatch (Meta)
|
||||||
|
* calls pfsGenerateEntryPatch
|
||||||
|
* calls ncaGenerateHierarchicalSha256Patch
|
||||||
|
* returns true if cnmt needs no patching
|
||||||
|
* demands an immediate ncaEncryptHeader call
|
||||||
|
|
||||||
* ncaIsHeaderDirty (doesn't modify anything per se, but it's used to check if any of the functions above has been used, basically - and by extension, if the functions below need to be used)
|
* ncaIsHeaderDirty (doesn't modify anything per se, but it's used to check if any of the functions above has been used, basically - and by extension, if the functions below need to be used)
|
||||||
|
|
||||||
* ncaWriteEncryptedHeaderDataToMemoryBuffer (write encrypted nca header data)
|
* ncaWriteEncryptedHeaderDataToMemoryBuffer (write encrypted nca header data)
|
||||||
|
|
||||||
* cnmtUpdateContentInfo (used to update content entry info in the raw cnmt copy after dumping each one)
|
|
||||||
|
|
||||||
* cnmtWriteNcaPatch (writes cnmt patch)
|
* cnmtWriteNcaPatch (writes cnmt patch)
|
||||||
* calls pfsWriteEntryPatchToMemoryBuffer
|
* calls pfsWriteEntryPatchToMemoryBuffer
|
||||||
* calls ncaWriteHierarchicalSha256PatchToMemoryBuffer
|
* calls ncaWriteHierarchicalSha256PatchToMemoryBuffer
|
||||||
|
@ -41,16 +38,16 @@ list of top level functions designed to alter nca data in order of (possible) us
|
||||||
* calls pfsWriteEntryPatchToMemoryBuffer
|
* calls pfsWriteEntryPatchToMemoryBuffer
|
||||||
* calls ncaWriteHierarchicalSha256PatchToMemoryBuffer
|
* calls ncaWriteHierarchicalSha256PatchToMemoryBuffer
|
||||||
|
|
||||||
* pfsWriteEntryPatchToMemoryBuffer
|
* nacpWriteNcaPatch (writes nacp patch)
|
||||||
* calls ncaWriteHierarchicalSha256PatchToMemoryBuffer
|
* calls romfsWriteFileEntryPatchToMemoryBuffer
|
||||||
|
* calls ncaWriteHierarchicalSha256PatchToMemoryBuffer / ncaWriteHierarchicalIntegrityPatchToMemoryBuffer
|
||||||
|
|
||||||
* romfsWriteFileEntryPatchToMemoryBuffer
|
* cnmtUpdateContentInfo (used to update content entry info in the raw cnmt copy after dumping each one - ignores the current content if its a meta nca)
|
||||||
* calls ncaWriteHierarchicalSha256PatchToMemoryBuffer / ncaWriteHierarchicalIntegrityPatchToMemoryBuffer
|
|
||||||
* missing nacp wrapper
|
|
||||||
|
|
||||||
minor steps to take into account:
|
minor steps to take into account:
|
||||||
|
|
||||||
* check if rights_id_available == true and titlekey_retrieved == false (preload handling)
|
* check if rights_id_available == true and titlekey_retrieved == false (preload handling)
|
||||||
|
* actually, just inform the user about it - this is being handled
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue