mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-22 18:26:39 +00:00
NACP parsing (part 1).
God, I'm so tired. I'll go play some good old MGS3 and continue this stuff at a later time. It builds, though.
This commit is contained in:
parent
fa1b9c70a5
commit
d385d40862
10 changed files with 1070 additions and 21 deletions
2
build.sh
2
build.sh
|
@ -3,6 +3,8 @@ cd "$(dirname "${BASH_SOURCE[0]}")"
|
|||
|
||||
tar_filename="nxdumptool-rewrite_poc_$(shell git rev-parse --short HEAD).tar.bz2"
|
||||
|
||||
rm -f $tar_filename
|
||||
|
||||
rm -rf ./code_templates/tmp
|
||||
mkdir ./code_templates/tmp
|
||||
|
||||
|
|
|
@ -241,7 +241,7 @@ bool cnmtGenerateAuthoringToolXml(ContentMetaContext *cnmt_ctx, NcaContext *nca_
|
|||
return false;
|
||||
}
|
||||
|
||||
u16 i, j;
|
||||
u32 i, j;
|
||||
char *xml_buf = NULL;
|
||||
u64 xml_buf_size = 0;
|
||||
char digest_str[0x41] = {0};
|
||||
|
@ -437,8 +437,6 @@ static const char *cnmtGetRequiredTitleTypeString(u8 content_meta_type)
|
|||
str = "PatchId";
|
||||
break;
|
||||
case NcmContentMetaType_Patch:
|
||||
str = "OriginalId";
|
||||
break;
|
||||
case NcmContentMetaType_AddOnContent:
|
||||
str = "ApplicationId";
|
||||
break;
|
||||
|
|
|
@ -274,7 +274,7 @@ NX_INLINE bool cnmtIsValidContext(ContentMetaContext *cnmt_ctx)
|
|||
|
||||
NX_INLINE bool cnmtIsNcaPatchRequired(ContentMetaContext *cnmt_ctx)
|
||||
{
|
||||
if (!cnmtIsValidContext(cnmt_ctx) || cnmt_ctx->nca_patch.hash_region_count) return false;
|
||||
if (!cnmtIsValidContext(cnmt_ctx)) return false;
|
||||
u8 tmp_hash[SHA256_HASH_SIZE] = {0};
|
||||
sha256CalculateHash(tmp_hash, cnmt_ctx->raw_data, cnmt_ctx->raw_data_size);
|
||||
return (memcmp(tmp_hash, cnmt_ctx->raw_data_hash, SHA256_HASH_SIZE) != 0);
|
||||
|
@ -282,7 +282,7 @@ NX_INLINE bool cnmtIsNcaPatchRequired(ContentMetaContext *cnmt_ctx)
|
|||
|
||||
NX_INLINE bool cnmtGenerateNcaPatch(ContentMetaContext *cnmt_ctx)
|
||||
{
|
||||
return (cnmtIsValidContext(cnmt_ctx) ? pfsGenerateEntryPatch(&(cnmt_ctx->pfs_ctx), cnmt_ctx->pfs_entry, cnmt_ctx->raw_data, cnmt_ctx->raw_data_size, 0, &(cnmt_ctx->nca_patch)) : false);
|
||||
return (cnmtIsValidContext(cnmt_ctx) && pfsGenerateEntryPatch(&(cnmt_ctx->pfs_ctx), cnmt_ctx->pfs_entry, cnmt_ctx->raw_data, cnmt_ctx->raw_data_size, 0, &(cnmt_ctx->nca_patch)));
|
||||
}
|
||||
|
||||
NX_INLINE u32 cnmtGetVersionInteger(ContentMetaVersion *version)
|
||||
|
|
|
@ -121,8 +121,7 @@ static const char *g_gameCardHfsPartitionNames[] = {
|
|||
[GameCardHashFileSystemPartitionType_Logo] = "logo",
|
||||
[GameCardHashFileSystemPartitionType_Normal] = "normal",
|
||||
[GameCardHashFileSystemPartitionType_Secure] = "secure",
|
||||
[GameCardHashFileSystemPartitionType_Boot] = "boot",
|
||||
[GameCardHashFileSystemPartitionType_Boot + 1] = "unknown"
|
||||
[GameCardHashFileSystemPartitionType_Boot] = "boot"
|
||||
};
|
||||
|
||||
/* Function prototypes. */
|
||||
|
@ -372,8 +371,7 @@ bool gamecardGetBundledFirmwareUpdateVersion(u32 *out)
|
|||
|
||||
const char *gamecardGetHashFileSystemPartitionName(u8 hfs_partition_type)
|
||||
{
|
||||
u8 idx = (hfs_partition_type > GameCardHashFileSystemPartitionType_Boot ? (GameCardHashFileSystemPartitionType_Boot + 1) : hfs_partition_type);
|
||||
return g_gameCardHfsPartitionNames[idx];
|
||||
return (hfs_partition_type < GameCardHashFileSystemPartitionType_Count ? g_gameCardHfsPartitionNames[hfs_partition_type] : NULL);
|
||||
}
|
||||
|
||||
bool gamecardGetEntryCountFromHashFileSystemPartition(u8 hfs_partition_type, u32 *out_count)
|
||||
|
|
|
@ -187,7 +187,8 @@ typedef enum {
|
|||
GameCardHashFileSystemPartitionType_Logo = 2, ///< Only available in GameCardFwVersion_Since400NUP gamecards.
|
||||
GameCardHashFileSystemPartitionType_Normal = 3,
|
||||
GameCardHashFileSystemPartitionType_Secure = 4,
|
||||
GameCardHashFileSystemPartitionType_Boot = 5 ///< Only available in Terra (Tencent) gamecards.
|
||||
GameCardHashFileSystemPartitionType_Boot = 5, ///< Only available in Terra (Tencent) gamecards.
|
||||
GameCardHashFileSystemPartitionType_Count = 6 ///< Not a real value.
|
||||
} GameCardHashFileSystemPartitionType;
|
||||
|
||||
/// Initializes data needed to access raw gamecard storage areas.
|
||||
|
@ -220,7 +221,7 @@ bool gamecardGetTrimmedSize(u64 *out);
|
|||
bool gamecardGetRomCapacity(u64 *out); ///< Not the same as gamecardGetTotalSize().
|
||||
bool gamecardGetBundledFirmwareUpdateVersion(u32 *out);
|
||||
|
||||
/// Returns a pointer to a string holding the name of the provided hash file system partition type.
|
||||
/// Returns a pointer to a string holding the name of the provided hash file system partition type. Returns NULL if the provided value is invalid.
|
||||
const char *gamecardGetHashFileSystemPartitionName(u8 hfs_partition_type);
|
||||
|
||||
/// Retrieves the entry count from a hash FS partition.
|
||||
|
|
565
source/nacp.c
Normal file
565
source/nacp.c
Normal file
|
@ -0,0 +1,565 @@
|
|||
/*
|
||||
* nacp.c
|
||||
*
|
||||
* Copyright (c) 2020, DarkMatterCore <pabloacurielz@gmail.com>.
|
||||
*
|
||||
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).
|
||||
*
|
||||
* nxdumptool is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* nxdumptool is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "utils.h"
|
||||
#include "nacp.h"
|
||||
#include "title.h"
|
||||
|
||||
/* Type definitions. */
|
||||
|
||||
typedef const char *(*NacpStringFunction)(u8 value); /* Used while adding fields to the AuthoringTool-like XML. */
|
||||
|
||||
/* Global variables. */
|
||||
|
||||
static const char *g_unknownString = "Unknown";
|
||||
|
||||
static const char *g_nacpLanguageStrings[] = {
|
||||
[NacpLanguage_AmericanEnglish] = "AmericanEnglish",
|
||||
[NacpLanguage_BritishEnglish] = "BritishEnglish",
|
||||
[NacpLanguage_Japanese] = "Japanese",
|
||||
[NacpLanguage_French] = "French",
|
||||
[NacpLanguage_German] = "German",
|
||||
[NacpLanguage_LatinAmericanSpanish] = "LatinAmericanSpanish",
|
||||
[NacpLanguage_Spanish] = "Spanish",
|
||||
[NacpLanguage_Italian] = "Italian",
|
||||
[NacpLanguage_Dutch] = "Dutch",
|
||||
[NacpLanguage_CanadianFrench] = "CanadianFrench",
|
||||
[NacpLanguage_Portuguese] = "Portuguese",
|
||||
[NacpLanguage_Russian] = "Russian",
|
||||
[NacpLanguage_Korean] = "Korean",
|
||||
[NacpLanguage_TraditionalChinese] = "TraditionalChinese",
|
||||
[NacpLanguage_SimplifiedChinese] = "SimplifiedChinese",
|
||||
[NacpLanguage_BrazilianPortuguese] = "BrazilianPortuguese"
|
||||
};
|
||||
|
||||
static const char *g_nacpStartupUserAccountStrings[] = {
|
||||
[NacpStartupUserAccount_None] = "None",
|
||||
[NacpStartupUserAccount_Required] = "Required",
|
||||
[NacpStartupUserAccount_RequiredWithNetworkServiceAccountAvailable] = "RequiredWithNetworkServiceAccountAvailable"
|
||||
};
|
||||
|
||||
static const char *g_nacpUserAccountSwitchLockStrings[] = {
|
||||
[NacpUserAccountSwitchLock_Disable] = "Disable",
|
||||
[NacpUserAccountSwitchLock_Enable] = "Enable"
|
||||
};
|
||||
|
||||
static const char *g_nacpAddOnContentRegistrationTypeStrings[] = {
|
||||
[NacpAddOnContentRegistrationType_AllOnLaunch] = "AllOnLaunch",
|
||||
[NacpAddOnContentRegistrationType_OnDemand] = "OnDemand"
|
||||
};
|
||||
|
||||
static const char *g_nacpAttributeStrings[] = {
|
||||
[NacpAttribute_Demo] = "Demo",
|
||||
[NacpAttribute_RetailInteractiveDisplay] = "RetailInteractiveDisplay"
|
||||
};
|
||||
|
||||
static const char *g_nacpParentalControlStrings[] = {
|
||||
[NacpParentalControl_FreeCommunication] = "FreeCommunication"
|
||||
};
|
||||
|
||||
static const char *g_nacpScreenshotStrings[] = {
|
||||
[NacpScreenshot_Allow] = "Allow",
|
||||
[NacpScreenshot_Deny] = "Deny"
|
||||
};
|
||||
|
||||
static const char *g_nacpVideoCaptureStrings[] = {
|
||||
[NacpVideoCapture_Disable] = "Disable",
|
||||
[NacpVideoCapture_Manual] = "Manual",
|
||||
[NacpVideoCapture_Enable] = "Enable"
|
||||
};
|
||||
|
||||
static const char *g_nacpDataLossConfirmationStrings[] = {
|
||||
[NacpDataLossConfirmation_None] = "None",
|
||||
[NacpDataLossConfirmation_Required] = "Required"
|
||||
};
|
||||
|
||||
static const char *g_nacpPlayLogPolicyStrings[] = {
|
||||
[NacpPlayLogPolicy_Open] = "Open",
|
||||
[NacpPlayLogPolicy_LogOnly] = "LogOnly",
|
||||
[NacpPlayLogPolicy_None] = "None",
|
||||
[NacpPlayLogPolicy_Closed] = "Closed"
|
||||
};
|
||||
|
||||
static const char *g_nacpRatingAgeOrganizationStrings[] = {
|
||||
[NacpRatingAgeOrganization_CERO] = "CERO",
|
||||
[NacpRatingAgeOrganization_GRACGCRB] = "GRACGCRB",
|
||||
[NacpRatingAgeOrganization_GSRMR] = "GSRMR",
|
||||
[NacpRatingAgeOrganization_ESRB] = "ESRB",
|
||||
[NacpRatingAgeOrganization_ClassInd] = "ClassInd",
|
||||
[NacpRatingAgeOrganization_USK] = "USK",
|
||||
[NacpRatingAgeOrganization_PEGI] = "PEGI",
|
||||
[NacpRatingAgeOrganization_PEGIPortugal] = "PEGIPortugal",
|
||||
[NacpRatingAgeOrganization_PEGIBBFC] = "PEGIBBFC",
|
||||
[NacpRatingAgeOrganization_Russian] = "Russian",
|
||||
[NacpRatingAgeOrganization_ACB] = "ACB",
|
||||
[NacpRatingAgeOrganization_OFLC] = "OFLC",
|
||||
[NacpRatingAgeOrganization_IARCGeneric] = "IARCGeneric"
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Function prototypes. */
|
||||
|
||||
static bool nacpAddStringFieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, const char *value);
|
||||
static bool nacpAddEnumFieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, u8 value, NacpStringFunction str_func);
|
||||
static bool nacpAddBitflagFieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, const void *flag, u8 max_flag_idx, NacpStringFunction str_func);
|
||||
static bool nacpAddU64FieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, u64 value);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool nacpInitializeContext(NacpContext *out, NcaContext *nca_ctx)
|
||||
{
|
||||
if (!out || !nca_ctx || !strlen(nca_ctx->content_id_str) || nca_ctx->content_type != NcmContentType_Control || nca_ctx->content_size < NCA_FULL_HEADER_LENGTH || \
|
||||
(nca_ctx->storage_id != NcmStorageId_GameCard && !nca_ctx->ncm_storage) || (nca_ctx->storage_id == NcmStorageId_GameCard && !nca_ctx->gamecard_offset) || \
|
||||
nca_ctx->header.content_type != NcaContentType_Control || !out)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *language_str = NULL;
|
||||
char icon_path[0x80] = {0};
|
||||
RomFileSystemFileEntry *icon_entry = NULL;
|
||||
NacpIconContext *tmp_icon_ctx = NULL;
|
||||
|
||||
bool success = false;
|
||||
|
||||
/* Free output context beforehand. */
|
||||
nacpFreeContext(out);
|
||||
|
||||
/* Initialize RomFS context. */
|
||||
if (!romfsInitializeContext(&(out->romfs_ctx), &(nca_ctx->fs_contexts[0])))
|
||||
{
|
||||
LOGFILE("Failed to initialize RomFS context!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Retrieve RomFS file entry for 'control.nacp'. */
|
||||
if (!(out->romfs_file_entry = romfsGetFileEntryByPath(&(out->romfs_ctx), "/control.nacp")))
|
||||
{
|
||||
LOGFILE("Failed to retrieve file entry for \"control.nacp\" from RomFS!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
//LOGFILE("Found 'control.nacp' entry in Control NCA \"%s\".", nca_ctx->content_id_str);
|
||||
|
||||
/* Verify NACP size. */
|
||||
if (out->romfs_file_entry->size != sizeof(_NacpStruct))
|
||||
{
|
||||
LOGFILE("Invalid NACP size!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Allocate memory for the NACP data. */
|
||||
out->data = malloc(sizeof(_NacpStruct));
|
||||
if (!out->data)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for the NACP data!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read NACP data into memory buffer. */
|
||||
if (!romfsReadFileEntryData(&(out->romfs_ctx), out->romfs_file_entry, out->data, sizeof(_NacpStruct), 0))
|
||||
{
|
||||
LOGFILE("Failed to read NACP data!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Calculate SHA-256 checksum for the whole NACP. */
|
||||
sha256CalculateHash(out->data_hash, out->data, sizeof(_NacpStruct));
|
||||
|
||||
/* Save pointer to NCA context to the output NACP context. */
|
||||
out->nca_ctx = nca_ctx;
|
||||
|
||||
/* Retrieve NACP icon data. */
|
||||
for(u8 i = 0; i < NacpLanguage_Count; i++)
|
||||
{
|
||||
NacpIconContext *icon_ctx = NULL;
|
||||
|
||||
/* Check if the current language is supported. */
|
||||
if (!nacpCheckBitflagField(&(out->data->supported_language_flag), i, NacpLanguage_Count)) continue;
|
||||
|
||||
/* Get language string. */
|
||||
language_str = nacpGetLanguageString(i);
|
||||
|
||||
/* Generate icon path. */
|
||||
sprintf(icon_path, "/icon_%s.dat", language_str);
|
||||
|
||||
/* Retrieve RomFS file entry for this icon. */
|
||||
if (!(icon_entry = romfsGetFileEntryByPath(&(out->romfs_ctx), icon_path))) continue;
|
||||
|
||||
/* Check icon size. */
|
||||
if (!icon_entry->size || icon_entry->size > NACP_MAX_ICON_SIZE)
|
||||
{
|
||||
LOGFILE("Invalid NACP icon size!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Reallocate icon context buffer. */
|
||||
if (!(tmp_icon_ctx = realloc(out->icon_ctx, (out->icon_count + 1) * sizeof(NacpIconContext))))
|
||||
{
|
||||
LOGFILE("Failed to reallocate NACP icon context buffer!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
out->icon_ctx = tmp_icon_ctx;
|
||||
tmp_icon_ctx = NULL;
|
||||
|
||||
icon_ctx = &(out->icon_ctx[out->icon_count]);
|
||||
memset(icon_ctx, 0, sizeof(NacpIconContext));
|
||||
|
||||
/* Allocate memory for this icon data. */
|
||||
if (!(icon_ctx->icon_data = malloc(icon_entry->size)))
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for NACP icon data!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read icon data. */
|
||||
if (!romfsReadFileEntryData(&(out->romfs_ctx), icon_entry, icon_ctx->icon_data, icon_entry->size, 0))
|
||||
{
|
||||
LOGFILE("Failed to read NACP icon data!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Fill icon context. */
|
||||
icon_ctx->language = i;
|
||||
icon_ctx->icon_size = icon_entry->size;
|
||||
|
||||
/* Update icon count. */
|
||||
out->icon_count++;
|
||||
}
|
||||
|
||||
success = true;
|
||||
|
||||
end:
|
||||
if (!success) nacpFreeContext(out);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx)
|
||||
{
|
||||
if (!nacpIsValidContext(nacp_ctx))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
_NacpStruct *nacp = nacp_ctx->data;
|
||||
u8 i = 0, count = 0;
|
||||
char *xml_buf = NULL;
|
||||
u64 xml_buf_size = 0;
|
||||
bool success = false;
|
||||
|
||||
/* Free AuthoringTool-like XML data if needed. */
|
||||
if (nacp_ctx->authoring_tool_xml) free(nacp_ctx->authoring_tool_xml);
|
||||
nacp_ctx->authoring_tool_xml = NULL;
|
||||
nacp_ctx->authoring_tool_xml_size = 0;
|
||||
|
||||
if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" \
|
||||
"<Application>\n")) goto end;
|
||||
|
||||
/* Title. */
|
||||
for(i = 0, count = 0; i < NacpLanguage_Count; i++)
|
||||
{
|
||||
if (!strlen(nacp->title[i].name) || !strlen(nacp->title[i].publisher)) continue;
|
||||
|
||||
if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \
|
||||
" <Title>\n" \
|
||||
" <Language>%s</Language>\n" \
|
||||
" <Name>%s</Name>\n" \
|
||||
" <Publisher>%s</Publisher>\n" \
|
||||
" </Title>\n", \
|
||||
nacpGetLanguageString(i),
|
||||
nacp->title[i].name,
|
||||
nacp->title[i].publisher)) goto end;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " <Title />\n")) goto end;
|
||||
|
||||
/* Isbn. */
|
||||
if (!nacpAddStringFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "Isbn", nacp->isbn)) goto end;
|
||||
|
||||
/* StartupUserAccount. */
|
||||
if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "StartupUserAccount", nacp->startup_user_account, &nacpGetStartupUserAccountString)) goto end;
|
||||
|
||||
/* UserAccountSwitchLock. */
|
||||
if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSwitchLock", nacp->user_account_switch_lock, &nacpGetUserAccountSwitchLockString)) goto end;
|
||||
|
||||
/* AddOnContentRegistrationType. */
|
||||
if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "AddOnContentRegistrationType", nacp->add_on_content_registration_type, &nacpGetAddOnContentRegistrationTypeString)) goto end;
|
||||
|
||||
/* AttributeFlag. */
|
||||
if (!nacpAddBitflagFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "Attribute", &(nacp->attribute_flag), NacpAttribute_Count, &nacpGetAttributeString)) goto end;
|
||||
|
||||
/* SupportedLanguageFlag. */
|
||||
/* Even though this is a bitflag field, it doesn't follow the same format as the rest. */
|
||||
for(i = 0, count = 0; i < NacpLanguage_Count; i++)
|
||||
{
|
||||
if (!nacpCheckBitflagField(&(nacp->supported_language_flag), i, NacpLanguage_Count)) continue;
|
||||
if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "SupportedLanguage", i, &nacpGetLanguageString)) goto end;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " <SupportedLanguage />\n")) goto end;
|
||||
|
||||
/* ParentalControlFlag. */
|
||||
if (!nacpAddBitflagFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "ParentalControl", &(nacp->parental_control_flag), NacpParentalControl_Count, &nacpGetParentalControlString)) goto end;
|
||||
|
||||
/* Screenshot. */
|
||||
if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "Screenshot", nacp->screenshot, &nacpGetScreenshotString)) goto end;
|
||||
|
||||
/* VideoCapture. */
|
||||
if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "VideoCapture", nacp->video_capture, &nacpGetVideoCaptureString)) goto end;
|
||||
|
||||
/* DataLossConfirmation. */
|
||||
if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DataLossConfirmation", nacp->data_loss_confirmation, &nacpGetDataLossConfirmationString)) goto end;
|
||||
|
||||
/* PlayLogPolicy. */
|
||||
if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "PlayLogPolicy", nacp->play_log_policy, &nacpGetPlayLogPolicyString)) goto end;
|
||||
|
||||
/* PresenceGroupId. */
|
||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "PresenceGroupId", nacp->presence_group_id)) goto end;
|
||||
|
||||
/* RatingAge. */
|
||||
for(i = 0, count = 0; i < NacpRatingAgeOrganization_Count; i++)
|
||||
{
|
||||
u8 age = *((u8*)&(nacp->rating_age) + i);
|
||||
if (age == 0xFF) continue;
|
||||
|
||||
if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \
|
||||
" <Rating>\n" \
|
||||
" <Organization>%s</Organization>\n" \
|
||||
" <Age>%u</Age>\n" \
|
||||
" </Rating>\n", \
|
||||
nacpGetRatingAgeOrganizationString(i),
|
||||
age)) goto end;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " <Rating />\n")) goto end;
|
||||
|
||||
/* DisplayVersion. */
|
||||
if (!nacpAddStringFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DisplayVersion", nacp->display_version)) goto end;
|
||||
|
||||
/* AddOnContentBaseId. */
|
||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "AddOnContentBaseId", nacp->add_on_content_base_id)) goto end;
|
||||
|
||||
/* SaveDataOwnerId. */
|
||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "SaveDataOwnerId", nacp->save_data_owner_id)) goto end;
|
||||
|
||||
/* UserAccountSaveDataSize. */
|
||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataSize", nacp->user_account_save_data_size)) goto end;
|
||||
|
||||
/* UserAccountSaveDataJournalSize. */
|
||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataJournalSize", nacp->user_account_save_data_journal_size)) goto end;
|
||||
|
||||
/* DeviceSaveDataSize. */
|
||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataSize", nacp->device_save_data_size)) goto end;
|
||||
|
||||
/* DeviceSaveDataJournalSize. */
|
||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataJournalSize", nacp->device_save_data_journal_size)) goto end;
|
||||
|
||||
/* BcatDeliveryCacheStorageSize. */
|
||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "BcatDeliveryCacheStorageSize", nacp->bcat_delivery_cache_storage_size)) goto end;
|
||||
|
||||
/* ApplicationErrorCodeCategory. */
|
||||
if (!nacpAddStringFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "ApplicationErrorCodeCategory", nacp->application_error_code_category)) goto end;
|
||||
|
||||
/* LocalCommunicationId. */
|
||||
for(i = 0, count = 0; i < 0x8; i++)
|
||||
{
|
||||
if (!nacp->local_communication_id[i]) continue;
|
||||
if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "LocalCommunicationId", nacp->local_communication_id[i])) goto end;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " <LocalCommunicationId />\n")) goto end;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (!(success = utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, "</Application>"))) goto end;
|
||||
|
||||
/* Update NACP context. */
|
||||
nacp_ctx->authoring_tool_xml = xml_buf;
|
||||
nacp_ctx->authoring_tool_xml_size = strlen(xml_buf);
|
||||
|
||||
end:
|
||||
if (!success)
|
||||
{
|
||||
if (xml_buf) free(xml_buf);
|
||||
LOGFILE("Failed to generate NACP AuthoringTool XML!");
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
const char *nacpGetLanguageString(u8 language)
|
||||
{
|
||||
return (language < NacpLanguage_Count ? g_nacpLanguageStrings[language] : g_unknownString);
|
||||
}
|
||||
|
||||
const char *nacpGetStartupUserAccountString(u8 startup_user_account)
|
||||
{
|
||||
return (startup_user_account < NacpStartupUserAccount_Count ? g_nacpStartupUserAccountStrings[startup_user_account] : g_unknownString);
|
||||
}
|
||||
|
||||
const char *nacpGetUserAccountSwitchLockString(u8 user_account_switch_lock)
|
||||
{
|
||||
return (user_account_switch_lock < NacpUserAccountSwitchLock_Count ? g_nacpUserAccountSwitchLockStrings[user_account_switch_lock] : g_unknownString);
|
||||
}
|
||||
|
||||
const char *nacpGetAddOnContentRegistrationTypeString(u8 add_on_content_registration_type)
|
||||
{
|
||||
return (add_on_content_registration_type < NacpAddOnContentRegistrationType_Count ? g_nacpAddOnContentRegistrationTypeStrings[add_on_content_registration_type] : g_unknownString);
|
||||
}
|
||||
|
||||
const char *nacpGetAttributeString(u8 attribute)
|
||||
{
|
||||
return (attribute < NacpAttribute_Count ? g_nacpAttributeStrings[attribute] : g_unknownString);
|
||||
}
|
||||
|
||||
const char *nacpGetParentalControlString(u8 parental_control)
|
||||
{
|
||||
return (parental_control < NacpParentalControl_Count ? g_nacpParentalControlStrings[parental_control] : g_unknownString);
|
||||
}
|
||||
|
||||
const char *nacpGetScreenshotString(u8 screenshot)
|
||||
{
|
||||
return (screenshot < NacpScreenshot_Count ? g_nacpScreenshotStrings[screenshot] : g_unknownString);
|
||||
}
|
||||
|
||||
const char *nacpGetVideoCaptureString(u8 video_capture)
|
||||
{
|
||||
return (video_capture < NacpVideoCapture_Count ? g_nacpVideoCaptureStrings[video_capture] : g_unknownString);
|
||||
}
|
||||
|
||||
const char *nacpGetDataLossConfirmationString(u8 data_loss_confirmation)
|
||||
{
|
||||
return (data_loss_confirmation < NacpDataLossConfirmation_Count ? g_nacpDataLossConfirmationStrings[data_loss_confirmation] : g_unknownString);
|
||||
}
|
||||
|
||||
const char *nacpGetPlayLogPolicyString(u8 play_log_policy)
|
||||
{
|
||||
return (play_log_policy < NacpPlayLogPolicy_Count ? g_nacpPlayLogPolicyStrings[play_log_policy] : g_unknownString);
|
||||
}
|
||||
|
||||
const char *nacpGetRatingAgeOrganizationString(u8 rating_age_organization)
|
||||
{
|
||||
return (rating_age_organization < NacpRatingAgeOrganization_Count ? g_nacpRatingAgeOrganizationStrings[rating_age_organization] : g_unknownString);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static bool nacpAddStringFieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, const char *value)
|
||||
{
|
||||
if (!xml_buf || !xml_buf_size || !tag_name || !strlen(tag_name) || !value) return false;
|
||||
return (strlen(value) ? utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <%s>%s</%s>\n", tag_name, value, tag_name) : \
|
||||
utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <%s />\n", tag_name));
|
||||
}
|
||||
|
||||
static bool nacpAddEnumFieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, u8 value, NacpStringFunction str_func)
|
||||
{
|
||||
if (!xml_buf || !xml_buf_size || !tag_name || !strlen(tag_name) || !str_func) return false;
|
||||
return utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <%s>%s</%s>\n", tag_name, str_func(value), tag_name);
|
||||
}
|
||||
|
||||
static bool nacpAddBitflagFieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, const void *flag, u8 max_flag_idx, NacpStringFunction str_func)
|
||||
{
|
||||
if (!xml_buf || !xml_buf_size || !tag_name || !strlen(tag_name) || !flag || max_flag_idx >= 0x20 || !str_func) return false;
|
||||
|
||||
u8 i = 0, count = 0;
|
||||
bool success = false;
|
||||
|
||||
if (!utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <%s>", tag_name)) goto end;
|
||||
|
||||
if (*((u32*)flag))
|
||||
{
|
||||
for(i = 0; i < max_flag_idx; i++)
|
||||
{
|
||||
if (!nacpCheckBitflagField(flag, i, max_flag_idx)) continue;
|
||||
if (count && !utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, ",")) goto end;
|
||||
if (!utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, "%s", str_func(i))) goto end;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!count && !utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, "%s", g_unknownString)) goto end;
|
||||
} else {
|
||||
if (!utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, "None")) goto end;
|
||||
}
|
||||
|
||||
success = utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, "</%s>\n", tag_name);
|
||||
|
||||
end:
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool nacpAddU64FieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, u64 value)
|
||||
{
|
||||
if (!xml_buf || !xml_buf_size || !tag_name || !strlen(tag_name)) return false;
|
||||
return utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <%s>0x%016lx</%s>\n", tag_name, value, tag_name);
|
||||
}
|
488
source/nacp.h
Normal file
488
source/nacp.h
Normal file
|
@ -0,0 +1,488 @@
|
|||
/*
|
||||
* nacp.h
|
||||
*
|
||||
* Copyright (c) 2020, DarkMatterCore <pabloacurielz@gmail.com>.
|
||||
*
|
||||
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).
|
||||
*
|
||||
* nxdumptool is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* nxdumptool is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __NACP_H__
|
||||
#define __NACP_H__
|
||||
|
||||
#include "romfs.h"
|
||||
|
||||
#define NACP_MAX_ICON_SIZE 0x20000 /* 128 KiB. */
|
||||
|
||||
typedef struct {
|
||||
char name[0x200];
|
||||
char publisher[0x100];
|
||||
} NacpTitle;
|
||||
|
||||
typedef enum {
|
||||
NacpStartupUserAccount_None = 0,
|
||||
NacpStartupUserAccount_Required = 1,
|
||||
NacpStartupUserAccount_RequiredWithNetworkServiceAccountAvailable = 2,
|
||||
NacpStartupUserAccount_Count = 3 ///< Not a real value.
|
||||
} NacpStartupUserAccount;
|
||||
|
||||
typedef enum {
|
||||
NacpUserAccountSwitchLock_Disable = 0,
|
||||
NacpUserAccountSwitchLock_Enable = 1,
|
||||
NacpUserAccountSwitchLock_Count = 2 ///< Not a real value.
|
||||
} NacpUserAccountSwitchLock;
|
||||
|
||||
typedef enum {
|
||||
NacpAddOnContentRegistrationType_AllOnLaunch = 0,
|
||||
NacpAddOnContentRegistrationType_OnDemand = 1,
|
||||
NacpAddOnContentRegistrationType_Count = 2 ///< Not a real value.
|
||||
} NacpAddOnContentRegistrationType;
|
||||
|
||||
/// Indexes used to access NACP attribute info.
|
||||
typedef enum {
|
||||
NacpAttribute_Demo = 0,
|
||||
NacpAttribute_RetailInteractiveDisplay = 1,
|
||||
NacpAttribute_Count = 2 ///< Not a real value.
|
||||
} NacpAttribute;
|
||||
|
||||
typedef struct {
|
||||
u32 NacpAttributeFlag_Demo : 1;
|
||||
u32 NacpAttributeFlag_RetailInteractiveDisplay : 1;
|
||||
u32 NacpAttributeFlag_Reserved : 30;
|
||||
} NacpAttributeFlag;
|
||||
|
||||
/// Indexes used to access NACP language info.
|
||||
typedef enum {
|
||||
NacpLanguage_AmericanEnglish = 0,
|
||||
NacpLanguage_BritishEnglish = 1,
|
||||
NacpLanguage_Japanese = 2,
|
||||
NacpLanguage_French = 3,
|
||||
NacpLanguage_German = 4,
|
||||
NacpLanguage_LatinAmericanSpanish = 5,
|
||||
NacpLanguage_Spanish = 6,
|
||||
NacpLanguage_Italian = 7,
|
||||
NacpLanguage_Dutch = 8,
|
||||
NacpLanguage_CanadianFrench = 9,
|
||||
NacpLanguage_Portuguese = 10,
|
||||
NacpLanguage_Russian = 11,
|
||||
NacpLanguage_Korean = 12,
|
||||
NacpLanguage_TraditionalChinese = 13,
|
||||
NacpLanguage_SimplifiedChinese = 14,
|
||||
NacpLanguage_BrazilianPortuguese = 15,
|
||||
NacpLanguage_Count = 16 ///< Not a real value.
|
||||
} NacpLanguage;
|
||||
|
||||
typedef struct {
|
||||
u32 NacpSupportedLanguageFlag_AmericanEnglish : 1;
|
||||
u32 NacpSupportedLanguageFlag_BritishEnglish : 1;
|
||||
u32 NacpSupportedLanguageFlag_Japanese : 1;
|
||||
u32 NacpSupportedLanguageFlag_French : 1;
|
||||
u32 NacpSupportedLanguageFlag_German : 1;
|
||||
u32 NacpSupportedLanguageFlag_LatinAmericanSpanish : 1;
|
||||
u32 NacpSupportedLanguageFlag_Spanish : 1;
|
||||
u32 NacpSupportedLanguageFlag_Italian : 1;
|
||||
u32 NacpSupportedLanguageFlag_Dutch : 1;
|
||||
u32 NacpSupportedLanguageFlag_CanadianFrench : 1;
|
||||
u32 NacpSupportedLanguageFlag_Portuguese : 1;
|
||||
u32 NacpSupportedLanguageFlag_Russian : 1;
|
||||
u32 NacpSupportedLanguageFlag_Korean : 1;
|
||||
u32 NacpSupportedLanguageFlag_TraditionalChinese : 1; ///< Old: NacpSupportedLanguageFlag_Taiwanese.
|
||||
u32 NacpSupportedLanguageFlag_SimplifiedChinese : 1; ///< Old: NacpSupportedLanguageFlag_Chinese.
|
||||
u32 NacpSupportedLanguageFlag_BrazilianPortuguese : 1;
|
||||
u32 NacpSupportedLanguageFlag_Reserved : 16;
|
||||
} NacpSupportedLanguageFlag;
|
||||
|
||||
/// Indexes used to access NACP parental control info.
|
||||
typedef enum {
|
||||
NacpParentalControl_FreeCommunication = 0,
|
||||
NacpParentalControl_Count = 1 ///< Not a real value.
|
||||
} NacpParentalControl;
|
||||
|
||||
typedef struct {
|
||||
u32 NacpParentalControlFlag_FreeCommunication : 1;
|
||||
u32 NacpParentalControlFlag_Reserved : 31;
|
||||
} NacpParentalControlFlag;
|
||||
|
||||
typedef enum {
|
||||
NacpScreenshot_Allow = 0,
|
||||
NacpScreenshot_Deny = 1,
|
||||
NacpScreenshot_Count = 2 ///< Not a real value.
|
||||
} NacpScreenshot;
|
||||
|
||||
typedef enum {
|
||||
NacpVideoCapture_Disable = 0,
|
||||
NacpVideoCapture_Manual = 1,
|
||||
NacpVideoCapture_Enable = 2,
|
||||
NacpVideoCapture_Count = 3, ///< Not a real value.
|
||||
|
||||
/// Old.
|
||||
NacpVideoCapture_Deny = NacpVideoCapture_Disable,
|
||||
NacpVideoCapture_Allow = NacpVideoCapture_Manual
|
||||
} NacpVideoCapture;
|
||||
|
||||
typedef enum {
|
||||
NacpDataLossConfirmation_None = 0,
|
||||
NacpDataLossConfirmation_Required = 1,
|
||||
NacpDataLossConfirmation_Count = 2 ///< Not a real value.
|
||||
} NacpDataLossConfirmation;
|
||||
|
||||
typedef enum {
|
||||
NacpPlayLogPolicy_Open = 0,
|
||||
NacpPlayLogPolicy_LogOnly = 1,
|
||||
NacpPlayLogPolicy_None = 2,
|
||||
NacpPlayLogPolicy_Closed = 3,
|
||||
NacpPlayLogPolicy_Count = 4, ///< Not a real value.
|
||||
|
||||
/// Old.
|
||||
NacpPlayLogPolicy_All = NacpPlayLogPolicy_Open
|
||||
} NacpPlayLogPolicy;
|
||||
|
||||
/// Indexes used to access NACP rating age info.
|
||||
typedef enum {
|
||||
NacpRatingAgeOrganization_CERO = 0,
|
||||
NacpRatingAgeOrganization_GRACGCRB = 1,
|
||||
NacpRatingAgeOrganization_GSRMR = 2,
|
||||
NacpRatingAgeOrganization_ESRB = 3,
|
||||
NacpRatingAgeOrganization_ClassInd = 4,
|
||||
NacpRatingAgeOrganization_USK = 5,
|
||||
NacpRatingAgeOrganization_PEGI = 6,
|
||||
NacpRatingAgeOrganization_PEGIPortugal = 7,
|
||||
NacpRatingAgeOrganization_PEGIBBFC = 8,
|
||||
NacpRatingAgeOrganization_Russian = 9,
|
||||
NacpRatingAgeOrganization_ACB = 10,
|
||||
NacpRatingAgeOrganization_OFLC = 11,
|
||||
NacpRatingAgeOrganization_IARCGeneric = 12,
|
||||
NacpRatingAgeOrganization_Count = 13
|
||||
} NacpRatingAgeOrganization;
|
||||
|
||||
typedef struct {
|
||||
u8 cero;
|
||||
u8 gracgcrb;
|
||||
u8 gsrmr;
|
||||
u8 esrb;
|
||||
u8 class_ind;
|
||||
u8 usk;
|
||||
u8 pegi;
|
||||
u8 pegi_portugal;
|
||||
u8 pegibbfc;
|
||||
u8 russian;
|
||||
u8 acb;
|
||||
u8 oflc;
|
||||
u8 iarc_generic;
|
||||
u8 reserved[0x13];
|
||||
} NacpRatingAge;
|
||||
|
||||
typedef enum {
|
||||
NacpLogoType_LicensedByNintendo = 0,
|
||||
NacpLogoType_DistributedByNintendo = 1, ///< Removed.
|
||||
NacpLogoType_Nintendo = 2
|
||||
} NacpLogoType;
|
||||
|
||||
typedef enum {
|
||||
NacpLogoHandling_Auto = 0,
|
||||
NacpLogoHandling_Manual = 1
|
||||
} NacpLogoHandling;
|
||||
|
||||
typedef enum {
|
||||
NacpRuntimeAddOnContentInstall_Deny = 0,
|
||||
NacpRuntimeAddOnContentInstall_AllowAppend = 1,
|
||||
NacpRuntimeAddOnContentInstall_AllowAppendButDontDownloadWhenUsingNetwork = 2
|
||||
} NacpRuntimeAddOnContentInstall;
|
||||
|
||||
typedef enum {
|
||||
NacpRuntimeParameterDelivery_Always = 0,
|
||||
NacpRuntimeParameterDelivery_AlwaysIfUserStateMatched = 1,
|
||||
NacpRuntimeParameterDelivery_OnRestart = 2
|
||||
} NacpRuntimeParameterDelivery;
|
||||
|
||||
typedef enum {
|
||||
NacpCrashReport_Deny = 0,
|
||||
NacpCrashReport_Allow = 1
|
||||
} NacpCrashReport;
|
||||
|
||||
typedef enum {
|
||||
NacpHdcp_None = 0,
|
||||
NacpHdcp_Required = 1
|
||||
} NacpHdcp;
|
||||
|
||||
typedef struct {
|
||||
u8 NacpStartupUserAccountOption_IsOptional : 1;
|
||||
u8 NacpStartupUserAccountOption_Reserved : 7;
|
||||
} NacpStartupUserAccountOption;
|
||||
|
||||
typedef enum {
|
||||
NacpPlayLogQueryCapability_None = 0,
|
||||
NacpPlayLogQueryCapability_WhiteList = 1,
|
||||
NacpPlayLogQueryCapability_All = 2
|
||||
} NacpPlayLogQueryCapability;
|
||||
|
||||
typedef struct {
|
||||
u8 NacpRepairFlag_SuppressGameCardAccess : 1;
|
||||
u8 NacpRepairFlag_Reserved : 7;
|
||||
} NacpRepairFlag;
|
||||
|
||||
typedef struct {
|
||||
u8 NacpRequiredNetworkServiceLicenseOnLaunchFlag_Common : 1;
|
||||
u8 NacpRequiredNetworkServiceLicenseOnLaunchFlag_Reserved : 7;
|
||||
} NacpRequiredNetworkServiceLicenseOnLaunchFlag;
|
||||
|
||||
typedef enum {
|
||||
NacpJitConfigurationFlag_None = 0,
|
||||
NacpJitConfigurationFlag_Enabled = 1
|
||||
} NacpJitConfigurationFlag;
|
||||
|
||||
typedef struct {
|
||||
u64 jit_configuration_flag; ///< NacpJitConfigurationFlag.
|
||||
u64 memory_size;
|
||||
} NacpJitConfiguration;
|
||||
|
||||
typedef struct {
|
||||
u16 NacpDescriptors_Index : 15;
|
||||
u16 NacpDescriptors_ContinueSet : 1; ///< Not given a name by Nintendo.
|
||||
} NacpDescriptors;
|
||||
|
||||
typedef struct {
|
||||
NacpDescriptors descriptors[0x20];
|
||||
} NacpRequiredAddOnContentsSetBinaryDescriptor;
|
||||
|
||||
typedef enum {
|
||||
NacpPlayReportPermission_None = 0,
|
||||
NacpPlayReportPermission_TargetMarketing = 1
|
||||
} NacpPlayReportPermission;
|
||||
|
||||
typedef enum {
|
||||
NacpCrashScreenshotForProd_Deny = 0,
|
||||
NacpCrashScreenshotForProd_Allow = 1
|
||||
} NacpCrashScreenshotForProd;
|
||||
|
||||
typedef enum {
|
||||
NacpCrashScreenshotForDev_Deny = 0,
|
||||
NacpCrashScreenshotForDev_Allow = 1
|
||||
} NacpCrashScreenshotForDev;
|
||||
|
||||
typedef struct {
|
||||
NacpTitle title[0x10];
|
||||
char isbn[0x25];
|
||||
u8 startup_user_account; ///< NacpStartupUserAccount.
|
||||
u8 user_account_switch_lock; ///< NacpUserAccountSwitchLock. Old: touch_screen_usage (None, Supported, Required).
|
||||
u8 add_on_content_registration_type; ///< NacpAddOnContentRegistrationType.
|
||||
NacpAttributeFlag attribute_flag;
|
||||
NacpSupportedLanguageFlag supported_language_flag;
|
||||
NacpParentalControlFlag parental_control_flag;
|
||||
u8 screenshot; ///< NacpScreenshot.
|
||||
u8 video_capture; ///< NacpVideoCapture.
|
||||
u8 data_loss_confirmation; ///< NacpDataLossConfirmation.
|
||||
u8 play_log_policy; ///< NacpPlayLogPolicy.
|
||||
u64 presence_group_id;
|
||||
NacpRatingAge rating_age;
|
||||
char display_version[0x10];
|
||||
u64 add_on_content_base_id;
|
||||
u64 save_data_owner_id;
|
||||
u64 user_account_save_data_size;
|
||||
u64 user_account_save_data_journal_size;
|
||||
u64 device_save_data_size;
|
||||
u64 device_save_data_journal_size;
|
||||
u64 bcat_delivery_cache_storage_size;
|
||||
char application_error_code_category[0x8];
|
||||
u64 local_communication_id[8];
|
||||
u8 logo_type; ///< NacpLogoType.
|
||||
u8 logo_handling; ///< NacpLogoHandling.
|
||||
u8 runtime_add_on_content_install; ///< NacpRuntimeAddOnContentInstall.
|
||||
u8 runtime_parameter_delivery; ///< NacpRuntimeParameterDelivery.
|
||||
u8 reserved_1[0x2];
|
||||
u8 crash_report; ///< NacpCrashReport.
|
||||
u8 hdcp; ///< NacpHdcp.
|
||||
u64 seed_for_pseudo_device_id;
|
||||
char bcat_passphrase[0x41];
|
||||
NacpStartupUserAccountOption startup_user_account_option;
|
||||
u8 reserved_2[0x6];
|
||||
u64 user_account_save_data_size_max;
|
||||
u64 user_account_save_data_journal_size_max;
|
||||
u64 device_save_data_size_max;
|
||||
u64 device_save_data_journal_size_max;
|
||||
u64 temporary_storage_size;
|
||||
u64 cache_storage_size;
|
||||
u64 cache_storage_journal_size;
|
||||
u64 cache_storage_data_and_journal_size_max;
|
||||
u16 cache_storage_index_max;
|
||||
u8 reserved_3[0x6];
|
||||
u64 play_log_queryable_application_id[0x10];
|
||||
u8 play_log_query_capability; ///< NacpPlayLogQueryCapability.
|
||||
NacpRepairFlag repair_flag;
|
||||
u8 program_index;
|
||||
NacpRequiredNetworkServiceLicenseOnLaunchFlag required_network_service_license_on_launch_flag;
|
||||
u8 reserved_4[0x4];
|
||||
NacpNeighborDetectionClientConfiguration neighbor_detection_client_configuration;
|
||||
NacpJitConfiguration jit_configuration;
|
||||
NacpRequiredAddOnContentsSetBinaryDescriptor required_add_on_contents_set_binary_descriptor;
|
||||
u8 play_report_permission; ///< NacpPlayReportPermission.
|
||||
u8 crash_screenshot_for_prod; ///< NacpCrashScreenshotForProd.
|
||||
u8 crash_screenshot_for_dev; ///< NacpCrashScreenshotForDev.
|
||||
u8 reserved_5[0xBFD];
|
||||
} _NacpStruct;
|
||||
|
||||
typedef struct {
|
||||
u8 language; ///< NacpLanguage.
|
||||
u64 icon_size; ///< JPG icon size. Must not exceed NACP_MAX_ICON_SIZE.
|
||||
u8 *icon_data; ///< Pointer to a dynamically allocated buffer that holds the JPG icon data.
|
||||
} NacpIconContext;
|
||||
|
||||
typedef struct {
|
||||
NcaContext *nca_ctx; ///< Pointer to the NCA context for the Control NCA from which NACP data is retrieved.
|
||||
RomFileSystemContext romfs_ctx; ///< RomFileSystemContext for the Control NCA FS section #0, which is where the NACP is stored.
|
||||
RomFileSystemFileEntry *romfs_file_entry; ///< RomFileSystemFileEntry for the NACP in the Control NCA FS section #0. Used to generate a RomFileSystemFileEntryPatch if needed.
|
||||
RomFileSystemFileEntryPatch nca_patch; ///< RomFileSystemFileEntryPatch generated if NACP modifications are needed. Used to seamlessly replace Control NCA data while writing it.
|
||||
///< Bear in mind that generating a patch modifies the NCA context.
|
||||
_NacpStruct *data; ///< Pointer to a dynamically allocated buffer that holds the full NACP.
|
||||
u8 data_hash[SHA256_HASH_SIZE]; ///< SHA-256 checksum calculated over the whole NACP. Used to determine if NcaHierarchicalSha256Patch generation is truly needed.
|
||||
u32 icon_count; ///< NACP icon count. May be zero if no icons are available.
|
||||
NacpIconContext *icon_ctx; ///< Pointer to a dynamically allocated buffer that holds 'icon_count' NACP icon contexts. May be NULL if no icons are available.
|
||||
char *authoring_tool_xml; ///< Pointer to a dynamically allocated, NULL-terminated buffer that holds AuthoringTool-like XML data.
|
||||
///< This is always NULL unless nacpGenerateAuthoringToolXml() is used on this NacpContext.
|
||||
u64 authoring_tool_xml_size; ///< Size for the AuthoringTool-like XML. This is essentially the same as using strlen() on 'authoring_tool_xml'.
|
||||
///< This is always 0 unless nacpGenerateAuthoringToolXml() is used on this NacpContext.
|
||||
} NacpContext;
|
||||
|
||||
/// Initializes a NacpContext using a previously initialized NcaContext (which must belong to a Control NCA).
|
||||
bool nacpInitializeContext(NacpContext *out, NcaContext *nca_ctx);
|
||||
|
||||
/// Generates an AuthoringTool-like XML using information from a previously initialized 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);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// Returns a pointer to a string holding the name of the provided NacpLanguage value. Returns "Unknown" if the provided value is invalid.
|
||||
const char *nacpGetLanguageString(u8 language);
|
||||
|
||||
/// Returns a pointer to a string holding the name of the provided NacpStartupUserAccount value. Returns "Unknown" if the provided value is invalid.
|
||||
const char *nacpGetStartupUserAccountString(u8 startup_user_account);
|
||||
|
||||
/// Returns a pointer to a string holding the name of the provided NacpUserAccountSwitchLock value. Returns "Unknown" if the provided value is invalid.
|
||||
const char *nacpGetUserAccountSwitchLockString(u8 user_account_switch_lock);
|
||||
|
||||
/// Returns a pointer to a string holding the name of the provided NacpAddOnContentRegistrationType value. Returns "Unknown" if the provided value is invalid.
|
||||
const char *nacpGetAddOnContentRegistrationTypeString(u8 add_on_content_registration_type);
|
||||
|
||||
/// Returns a pointer to a string holding the name of the provided NacpAttribute value. Returns "Unknown" if the provided value is invalid.
|
||||
const char *nacpGetAttributeString(u8 attribute);
|
||||
|
||||
/// Returns a pointer to a string holding the name of the provided NacpParentalControl value. Returns "Unknown" if the provided value is invalid.
|
||||
const char *nacpGetParentalControlString(u8 parental_control);
|
||||
|
||||
/// Returns a pointer to a string holding the name of the provided NacpScreenshot value. Returns "Unknown" if the provided value is invalid.
|
||||
const char *nacpGetScreenshotString(u8 screenshot);
|
||||
|
||||
/// Returns a pointer to a string holding the name of the provided NacpVideoCapture value. Returns "Unknown" if the provided value is invalid.
|
||||
const char *nacpGetVideoCaptureString(u8 video_capture);
|
||||
|
||||
/// Returns a pointer to a string holding the name of the provided NacpDataLossConfirmation value. Returns "Unknown" if the provided value is invalid.
|
||||
const char *nacpGetDataLossConfirmationString(u8 data_loss_confirmation);
|
||||
|
||||
/// Returns a pointer to a string holding the name of the provided NacpPlayLogPolicy value. Returns "Unknown" if the provided value is invalid.
|
||||
const char *nacpGetPlayLogPolicyString(u8 play_log_policy);
|
||||
|
||||
/// Returns a pointer to a string holding the name of the provided NacpRatingAgeOrganization value. Returns "Unknown" if the provided value is invalid.
|
||||
const char *nacpGetRatingAgeOrganizationString(u8 rating_age_organization);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// Helper inline functions.
|
||||
|
||||
NX_INLINE void nacpFreeContext(NacpContext *nacp_ctx)
|
||||
{
|
||||
if (!nacp_ctx) return;
|
||||
|
||||
romfsFreeContext(&(nacp_ctx->romfs_ctx));
|
||||
romfsFreeFileEntryPatch(&(nacp_ctx->nca_patch));
|
||||
if (nacp_ctx->data) free(nacp_ctx->data);
|
||||
|
||||
if (nacp_ctx->icon_ctx)
|
||||
{
|
||||
for(u32 i = 0; i < nacp_ctx->icon_count; i++)
|
||||
{
|
||||
if (nacp_ctx->icon_ctx[i].icon_data) free(nacp_ctx->icon_ctx[i].icon_data);
|
||||
}
|
||||
|
||||
free(nacp_ctx->icon_ctx);
|
||||
}
|
||||
|
||||
if (nacp_ctx->authoring_tool_xml) free(nacp_ctx->authoring_tool_xml);
|
||||
memset(nacp_ctx, 0, sizeof(NacpContext));
|
||||
}
|
||||
|
||||
NX_INLINE bool nacpIsValidIconContext(NacpIconContext *icon_ctx)
|
||||
{
|
||||
return (icon_ctx && icon_ctx->language < NacpLanguage_Count && icon_ctx->icon_size && icon_ctx->icon_data);
|
||||
}
|
||||
|
||||
NX_INLINE bool nacpIsValidContext(NacpContext *nacp_ctx)
|
||||
{
|
||||
if (!nacp_ctx || !nacp_ctx->nca_ctx || !nacp_ctx->romfs_file_entry || !nacp_ctx->data || (!nacp_ctx->icon_count && nacp_ctx->icon_ctx) || (nacp_ctx->icon_count && !nacp_ctx->icon_ctx)) return false;
|
||||
|
||||
for(u32 i = 0; i < nacp_ctx->icon_count; i++)
|
||||
{
|
||||
if (!nacpIsValidIconContext(&(nacp_ctx->icon_ctx[i]))) return false;
|
||||
}
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
NX_INLINE bool nacpCheckBitflagField(const void *flag, u8 idx, u8 max_flag_idx)
|
||||
{
|
||||
return (flag && idx < 0x20 && idx < max_flag_idx && ((*((const u32*)flag) >> idx) & 0x1));
|
||||
}
|
||||
|
||||
#endif /* __NACP_H__ */
|
|
@ -88,7 +88,7 @@ bool ncaInitializeContext(NcaContext *out, u8 storage_id, u8 hfs_partition_type,
|
|||
NcmContentStorage *ncm_storage = NULL;
|
||||
|
||||
if (!out || (storage_id != NcmStorageId_GameCard && !(ncm_storage = titleGetNcmStorageByStorageId(storage_id))) || \
|
||||
(storage_id == NcmStorageId_GameCard && hfs_partition_type > GameCardHashFileSystemPartitionType_Boot) || !content_info || content_info->content_type > NcmContentType_DeltaFragment || !tik)
|
||||
(storage_id == NcmStorageId_GameCard && hfs_partition_type >= GameCardHashFileSystemPartitionType_Count) || !content_info || content_info->content_type > NcmContentType_DeltaFragment || !tik)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
return false;
|
||||
|
|
|
@ -57,8 +57,7 @@ static const char *g_titleNcmContentTypeNames[] = {
|
|||
[NcmContentType_Control] = "Control",
|
||||
[NcmContentType_HtmlDocument] = "HtmlDocument",
|
||||
[NcmContentType_LegalInformation] = "LegalInformation",
|
||||
[NcmContentType_DeltaFragment] = "DeltaFragment",
|
||||
[NcmContentType_DeltaFragment + 1] = "Unknown"
|
||||
[NcmContentType_DeltaFragment] = "DeltaFragment"
|
||||
};
|
||||
|
||||
static const char *g_titleNcmContentMetaTypeNames[] = {
|
||||
|
@ -862,15 +861,13 @@ end:
|
|||
|
||||
const char *titleGetNcmContentTypeName(u8 content_type)
|
||||
{
|
||||
u8 idx = (content_type > NcmContentType_DeltaFragment ? (NcmContentType_DeltaFragment + 1) : content_type);
|
||||
return g_titleNcmContentTypeNames[idx];
|
||||
return (content_type <= NcmContentType_DeltaFragment ? g_titleNcmContentTypeNames[content_type] : NULL);
|
||||
}
|
||||
|
||||
const char *titleGetNcmContentMetaTypeName(u8 content_meta_type)
|
||||
{
|
||||
u8 idx = (content_meta_type <= NcmContentMetaType_BootImagePackageSafe ? content_meta_type : \
|
||||
((content_meta_type < NcmContentMetaType_Application || content_meta_type > NcmContentMetaType_Delta) ? 0 : (content_meta_type - 0x7A)));
|
||||
return g_titleNcmContentMetaTypeNames[idx];
|
||||
return ((content_meta_type <= NcmContentMetaType_BootImagePackageSafe || (content_meta_type >= NcmContentMetaType_Application && content_meta_type <= NcmContentMetaType_Delta)) ? \
|
||||
g_titleNcmContentMetaTypeNames[content_meta_type] : NULL);
|
||||
}
|
||||
|
||||
NX_INLINE void titleFreeApplicationMetadata(void)
|
||||
|
|
|
@ -130,10 +130,10 @@ char *titleGenerateFileName(const TitleInfo *title_info, u8 name_convention, u8
|
|||
/// Returns NULL if an error occurs.
|
||||
char *titleGenerateGameCardFileName(u8 name_convention, u8 illegal_char_replace_type);
|
||||
|
||||
/// Returns a pointer to a string holding the name of the provided NcmContentType value.
|
||||
/// Returns a pointer to a string holding the name of the provided NcmContentType value. Returns NULL if the provided value is invalid.
|
||||
const char *titleGetNcmContentTypeName(u8 content_type);
|
||||
|
||||
/// Returns a pointer to a string holding the name of the provided NcmContentMetaType value.
|
||||
/// Returns a pointer to a string holding the name of the provided NcmContentMetaType value. Returns NULL if the provided value is invalid.
|
||||
const char *titleGetNcmContentMetaTypeName(u8 content_meta_type);
|
||||
|
||||
/// Miscellaneous functions.
|
||||
|
|
Loading…
Reference in a new issue