From 7189943680b6095edae4c9ac3de94f604b27a17c Mon Sep 17 00:00:00 2001 From: Pablo Curiel Date: Fri, 18 Mar 2022 17:48:16 +0100 Subject: [PATCH] More changes. * gc_dumper: fixed Card ID Set dumping. * nacp: updated structs and enums to match latest changes (big thanks to @0Liam !), added helper macros. * cnmt: added helper macros. * program_info: added helper macros. * exception_handler: added helper macros. * nxdt_utils: only create output directories if the app isn't a PoC build. * todo: changed task priority order. Sparse/compressed section support is mandatory and must be implemented ASAP. --- code_templates/gc_dumper.c | 4 +- include/core/nacp.h | 101 +++++--- libs/libusbhsfs | 2 +- source/core/cnmt.c | 99 ++++---- source/core/nacp.c | 442 ++++++++++++++++++++--------------- source/core/nxdt_utils.c | 3 +- source/core/program_info.c | 135 ++++++----- source/exception_handler.cpp | 46 ++-- todo.txt | 6 +- 9 files changed, 476 insertions(+), 362 deletions(-) diff --git a/code_templates/gc_dumper.c b/code_templates/gc_dumper.c index a76fdb7..45db0e6 100644 --- a/code_templates/gc_dumper.c +++ b/code_templates/gc_dumper.c @@ -696,11 +696,11 @@ static bool saveGameCardIdSet(void) crc = crc32Calculate(&id_set, sizeof(FsGameCardIdSet)); snprintf(path, MAX_ELEMENTS(path), " (Card ID Set) (%08X).bin", crc); - if (!saveFileData(filename, &id_set, sizeof(FsGameCardIdSet))) goto end; - filename = generateOutputFileName(path); if (!filename) goto end; + if (!saveFileData(filename, &id_set, sizeof(FsGameCardIdSet))) goto end; + printf("successfully saved gamecard id set as \"%s\"\n", filename); success = true; diff --git a/include/core/nacp.h b/include/core/nacp.h index 158c6af..6e267ff 100644 --- a/include/core/nacp.h +++ b/include/core/nacp.h @@ -49,7 +49,12 @@ typedef enum { typedef enum { NacpUserAccountSwitchLock_Disable = 0, NacpUserAccountSwitchLock_Enable = 1, - NacpUserAccountSwitchLock_Count = 2 ///< Total values supported by this enum. + NacpUserAccountSwitchLock_Count = 2, ///< Total values supported by this enum. + + // Old. + NacpTouchScreenUsage_None = 0, + NacpTouchScreenUsage_Supported = 1, + NacpTouchScreenUsage_Required = 2 } NacpUserAccountSwitchLock; typedef enum { @@ -61,7 +66,8 @@ typedef enum { typedef enum { NacpAttribute_Demo = BIT(0), NacpAttribute_RetailInteractiveDisplay = BIT(1), - NacpAttribute_Count = 2 ///< Total values supported by this enum. + NacpAttribute_DownloadPlay = BIT(2), ///< Removed. + NacpAttribute_Count = 3 ///< Total values supported by this enum. } NacpAttribute; /// Indexes used to access NACP Title structs. @@ -106,7 +112,7 @@ typedef enum { NacpSupportedLanguage_TraditionalChinese = BIT(13), NacpSupportedLanguage_SimplifiedChinese = BIT(14), NacpSupportedLanguage_BrazilianPortuguese = BIT(15), - NacpSupportedLanguage_Count = 16, ///< Total values supported by this enum. Should always match NacpLanguage_Count. + NacpSupportedLanguage_Count = 16, ///< Total values supported by this enum. Should always match NacpLanguage_Count. ///< Old. NacpSupportedLanguage_Taiwanese = NacpSupportedLanguage_TraditionalChinese, @@ -216,6 +222,14 @@ typedef enum { NacpRuntimeParameterDelivery_Count = 3 ///< Total values supported by this enum. } NacpRuntimeParameterDelivery; +typedef enum { + NacpAppropriateAgeForChina_None = 0, + NacpAppropriateAgeForChina_Age8 = 1, + NacpAppropriateAgeForChina_Age12 = 2, + NacpAppropriateAgeForChina_Age16 = 3, + NacpAppropriateAgeForChina_Count = 4 ///< Total values supported by this enum. +} NacpAppropriateAgeForChina; + typedef enum { NacpUndecidedParameter75b8b_A = 0, NacpUndecidedParameter75b8b_B = 1, @@ -239,6 +253,17 @@ typedef enum { NacpStartupUserAccountOption_Count = 1 ///< Total values supported by this enum. } NacpStartupUserAccountOption; +typedef enum { + NacpRuntimeUpgrade_Deny = 0, + NacpRuntimeUpgrade_Allow = 1, + NacpRuntimeUpgrade_Count = 2 ///< Total values supported by this enum. +} NacpRuntimeUpgrade; + +typedef enum { + NacpSupportingLimitedLicenses_Demo = BIT(1), + NacpSupportingLimitedLicenses_Count = 1 ///< Total values supported by this enum. +} NacpSupportingLimitedLicenses; + typedef enum { NacpPlayLogQueryCapability_None = 0, NacpPlayLogQueryCapability_WhiteList = 1, @@ -257,9 +282,8 @@ typedef enum { } NacpRequiredNetworkServiceLicenseOnLaunch; typedef enum { - NacpJitConfigurationFlag_None = 0, - NacpJitConfigurationFlag_Enabled = 1, - NacpJitConfigurationFlag_Count = 2 ///< Total values supported by this enum. + NacpJitConfigurationFlag_Enabled = BIT_LONG(0), + NacpJitConfigurationFlag_Count = 1 ///< Total values supported by this enum. } NacpJitConfigurationFlag; typedef struct { @@ -269,23 +293,27 @@ typedef struct { NXDT_ASSERT(NacpJitConfiguration, 0x10); -typedef struct { - u16 index : 15; - u16 continue_set : 1; ///< Called "flag" by Nintendo, which isn't really great. -} NacpDescriptors; - -NXDT_ASSERT(NacpDescriptors, 0x2); +typedef enum { + NacpRequiredAddOnContentsSetDescriptorFlag_None = 0, + NacpRequiredAddOnContentsSetDescriptorFlag_Continue = 1 +} NacpRequiredAddOnContentsSetDescriptorFlag; typedef struct { - NacpDescriptors descriptors[0x20]; + u16 index : 15; + u16 flag : 1; ///< NacpRequiredAddOnContentsSetDescriptorFlag. +} NacpRequiredAddOnContentsSetDescriptor; + +NXDT_ASSERT(NacpRequiredAddOnContentsSetDescriptor, 0x2); + +typedef struct { + NacpRequiredAddOnContentsSetDescriptor descriptors[0x20]; } NacpRequiredAddOnContentsSetBinaryDescriptor; NXDT_ASSERT(NacpRequiredAddOnContentsSetBinaryDescriptor, 0x40); typedef enum { - NacpPlayReportPermission_None = 0, - NacpPlayReportPermission_TargetMarketing = 1, - NacpPlayReportPermission_Count = 2 ///< Total values supported by this enum. + NacpPlayReportPermission_TargetMarketing = BIT(0), + NacpPlayReportPermission_Count = 1 ///< Total values supported by this enum. } NacpPlayReportPermission; typedef enum { @@ -300,6 +328,16 @@ typedef enum { NacpCrashScreenshotForDev_Count = 2 ///< Total values supported by this enum. } NacpCrashScreenshotForDev; +typedef enum { + NacpContentsAvailabilityTransitionPolicy_NoPolicy = 0, + NacpContentsAvailabilityTransitionPolicy_Stable = 1, + NacpContentsAvailabilityTransitionPolicy_Changeable = 2, + NacpContentsAvailabilityTransitionPolicy_Count = 3, ///< Total values supported by this enum. + + // Old. + NacpContentsAvailabilityTransitionPolicy_Legacy = NacpContentsAvailabilityTransitionPolicy_NoPolicy +} NacpContentsAvailabilityTransitionPolicy; + typedef struct { u64 application_id[8]; } NacpAccessibleLaunchRequiredVersion; @@ -310,7 +348,7 @@ 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 user_account_switch_lock; ///< NacpUserAccountSwitchLock. u8 add_on_content_registration_type; ///< NacpAddOnContentRegistrationType. u32 attribute; ///< NacpAttribute. u32 supported_language; ///< NacpSupportedLanguage. @@ -335,14 +373,14 @@ typedef struct { u8 logo_handling; ///< NacpLogoHandling. u8 runtime_add_on_content_install; ///< NacpRuntimeAddOnContentInstall. u8 runtime_parameter_delivery; ///< NacpRuntimeParameterDelivery. - u8 reserved_1; + u8 appropriate_age_for_china; ///< NacpAppropriateAgeForChina. u8 undecided_parameter_75b8b; ///< NacpUndecidedParameter75b8b. u8 crash_report; ///< NacpCrashReport. u8 hdcp; ///< NacpHdcp. u64 seed_for_pseudo_device_id; char bcat_passphrase[0x41]; u8 startup_user_account_option; ///< NacpStartupUserAccountOption. - u8 reserved_2[0x6]; + u8 reserved_for_user_account_save_data_operation[0x6]; s64 user_account_save_data_size_max; s64 user_account_save_data_journal_size_max; s64 device_save_data_size_max; @@ -352,22 +390,25 @@ typedef struct { s64 cache_storage_journal_size; s64 cache_storage_data_and_journal_size_max; u16 cache_storage_index_max; - u8 reserved_3[0x6]; + u8 reserved_1[0x1]; + u8 runtime_upgrade; ///< NacpRuntimeUpgrade. + u32 supporting_limited_licenses; ///< NacpSupportingLimitedLicenses. u64 play_log_queryable_application_id[0x10]; u8 play_log_query_capability; ///< NacpPlayLogQueryCapability. u8 repair; ///< NacpRepair. u8 program_index; u8 required_network_service_license_on_launch; ///< NacpRequiredNetworkServiceLicenseOnLaunch. - u8 reserved_4[0x4]; + u8 reserved_2[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[0x5]; + u8 contents_availability_transition_policy; ///< NacpContentsAvailabilityTransitionPolicy. + u8 reserved_3[0x4]; NacpAccessibleLaunchRequiredVersion accessible_launch_required_version; - u8 reserved_6[0xBB8]; + u8 reserved_4[0xBB8]; } _NacpStruct; NXDT_ASSERT(_NacpStruct, 0x4000); @@ -413,8 +454,13 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 requir /// These functions return pointers to string representations of the input flag/value index (e.g. nacpGetLanguageString(NacpLanguage_AmericanEnglish) -> "AmericanEnglish"). /// If the input flag/value index is invalid, "Unknown" will be returned. -/// If dealing with a bitflag field such as NacpAttribute, NacpSupportedLanguage, etc., the provided value must be a 0-based index to the desired flag and not a bitmask from its enum. -/// (e.g. NacpAttribute_RetailInteractiveDisplay -> Use 1 instead). +/// If dealing with a bitflag field such as: +/// * NacpAttribute +/// * NacpSupportedLanguage +/// * NacpParentalControl +/// * NacpStartupUserAccountOption +/// * NacpRepair +/// Then, the provided value must be a 0-based index to the desired flag and not a bitmask from its enum (e.g. NacpAttribute_RetailInteractiveDisplay -> use 1 instead). const char *nacpGetLanguageString(u8 language); /// Can also be used for NacpSupportedLanguage flags with values from the NacpLanguage enum. const char *nacpGetStartupUserAccountString(u8 startup_user_account); const char *nacpGetUserAccountSwitchLockString(u8 user_account_switch_lock); @@ -430,17 +476,18 @@ const char *nacpGetLogoTypeString(u8 logo_type); const char *nacpGetLogoHandlingString(u8 logo_handling); const char *nacpGetRuntimeAddOnContentInstallString(u8 runtime_add_on_content_install); const char *nacpGetRuntimeParameterDeliveryString(u8 runtime_parameter_delivery); +const char *nacpGetAppropriateAgeForChina(u8 appropriate_age_for_china); const char *nacpGetUndecidedParameter75b8bString(u8 undecided_parameter_75b8b); const char *nacpGetCrashReportString(u8 crash_report); const char *nacpGetHdcpString(u8 hdcp); const char *nacpGetStartupUserAccountOptionString(u8 startup_user_account_option); +const char *nacpGetRuntimeUpgradeString(u8 runtime_upgrade); const char *nacpGetPlayLogQueryCapabilityString(u8 play_log_query_capability); const char *nacpGetRepairString(u8 repair); const char *nacpGetRequiredNetworkServiceLicenseOnLaunchString(u8 required_network_service_license_on_launch); -const char *nacpGetJitConfigurationFlagString(u64 jig_configuration_flag); ///< Uses an input u64 value. -const char *nacpGetPlayReportPermissionString(u8 play_report_permission); const char *nacpGetCrashScreenshotForProdString(u8 crash_screenshot_for_prod); const char *nacpGetCrashScreenshotForDevString(u8 crash_screenshot_for_dev); +const char *nacpGetContentsAvailabilityTransitionPolicyString(u8 contents_availability_transition_policy); /// Helper inline functions. diff --git a/libs/libusbhsfs b/libs/libusbhsfs index d6afc3c..0580fc3 160000 --- a/libs/libusbhsfs +++ b/libs/libusbhsfs @@ -1 +1 @@ -Subproject commit d6afc3c2ba17158553397d1f1d3a607da661f2ba +Subproject commit 0580fc38903546a99cc09e4f16418a3863e067b0 diff --git a/source/core/cnmt.c b/source/core/cnmt.c index 35f42e7..0a3dfa2 100644 --- a/source/core/cnmt.c +++ b/source/core/cnmt.c @@ -23,7 +23,10 @@ #include "cnmt.h" #include "title.h" +/* Helper macros. */ + #define CNMT_MINIMUM_FILENAME_LENGTH 23 /* Content Meta Type + "_" + Title ID + ".cnmt". */ +#define CNMT_ADD_FMT_STR(fmt, ...) utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, fmt, ##__VA_ARGS__) /* Global variables. */ @@ -367,31 +370,33 @@ bool cnmtGenerateAuthoringToolXml(ContentMetaContext *cnmt_ctx, NcaContext *nca_ cnmt_ctx->authoring_tool_xml = NULL; cnmt_ctx->authoring_tool_xml_size = 0; - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - "\n" \ - "\n" \ - " %s\n" \ - " 0x%016lx\n" \ - " %u\n" \ - " \n" \ - " \n", - titleGetNcmContentMetaTypeName(cnmt_ctx->packaged_header->content_meta_type), \ - cnmt_ctx->packaged_header->title_id, \ - cnmt_ctx->packaged_header->version.value)) goto end; + if (!CNMT_ADD_FMT_STR("\n" \ + "\n" \ + " %s\n" \ + " 0x%016lx\n" \ + " %u\n" \ + " %u\n" \ + " %u\n", \ + titleGetNcmContentMetaTypeName(cnmt_ctx->packaged_header->content_meta_type), \ + cnmt_ctx->packaged_header->title_id, \ + cnmt_ctx->packaged_header->version.value, \ + cnmt_ctx->packaged_header->version.application_version.release_ver, \ + cnmt_ctx->packaged_header->version.application_version.private_ver)) goto end; /* ContentMetaAttribute. */ for(i = 0; i < ContentMetaAttribute_Count; i++) { if (!(cnmt_ctx->packaged_header->content_meta_attribute & (u8)BIT(i))) continue; - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " %s\n", g_cnmtAttributeStrings[i])) goto end; + if (!CNMT_ADD_FMT_STR(" %s\n", g_cnmtAttributeStrings[i])) goto end; count++; } - if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " \n")) goto end; + if (!count && !CNMT_ADD_FMT_STR(" \n")) goto end; - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " %u\n", \ - cnmt_ctx->packaged_header->required_download_system_version.value)) goto end; + /* RequiredDownloadSystemVersion. */ + if (!CNMT_ADD_FMT_STR(" %u\n", cnmt_ctx->packaged_header->required_download_system_version.value)) goto end; + /* Contents. */ for(i = 0; i < nca_ctx_count; i++) { NcaContext *cur_nca_ctx = &(nca_ctx[i]); @@ -417,34 +422,35 @@ bool cnmtGenerateAuthoringToolXml(ContentMetaContext *cnmt_ctx, NcaContext *nca_ goto end; } - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - " \n" \ - " %s\n" \ - " %s\n" \ - " %lu\n" \ - " %s\n" \ - " %u\n" \ - " %u\n" \ - " \n", \ - titleGetNcmContentTypeName(cur_nca_ctx->content_type), \ - cur_nca_ctx->content_id_str, \ - cur_nca_ctx->content_size, \ - cur_nca_ctx->hash_str, \ - cur_nca_ctx->key_generation, \ - cur_nca_ctx->id_offset)) goto end; + if (!CNMT_ADD_FMT_STR(" \n" \ + " %s\n" \ + " %s\n" \ + " %lu\n" \ + " %s\n" \ + " %u\n" \ + " %u\n" \ + " \n", \ + titleGetNcmContentTypeName(cur_nca_ctx->content_type), \ + cur_nca_ctx->content_id_str, \ + cur_nca_ctx->content_size, \ + cur_nca_ctx->hash_str, \ + cur_nca_ctx->key_generation, \ + cur_nca_ctx->id_offset)) goto end; } utilsGenerateHexStringFromData(digest_str, sizeof(digest_str), cnmt_ctx->digest, CNMT_DIGEST_SIZE, false); - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - " \n" \ - " %s\n" \ - " %u\n" \ - " \n" \ - " \n", \ - digest_str, \ - cnmt_ctx->nca_ctx->key_generation)) goto end; + /* ContentMeta, Digest, KeyGenerationMin, KeepGeneration and KeepGenerationSpecified. */ + if (!CNMT_ADD_FMT_STR(" \n" \ + " %s\n" \ + " %u\n" \ + " \n" \ + " \n", \ + digest_str, \ + cnmt_ctx->nca_ctx->key_generation)) goto end; + /* RequiredSystemVersion (Application, Patch) / RequiredApplicationVersion (AddOnContent). */ + /* PatchId (Application) / ApplicationId (Patch, AddOnContent). */ if (cnmt_ctx->packaged_header->content_meta_type == NcmContentMetaType_Application || cnmt_ctx->packaged_header->content_meta_type == NcmContentMetaType_Patch || \ cnmt_ctx->packaged_header->content_meta_type == NcmContentMetaType_AddOnContent) { @@ -454,21 +460,20 @@ bool cnmtGenerateAuthoringToolXml(ContentMetaContext *cnmt_ctx, NcaContext *nca_ u64 required_title_id = cnmtGetRequiredTitleId(cnmt_ctx); const char *required_title_type_str = cnmtGetRequiredTitleTypeString(cnmt_ctx->packaged_header->content_meta_type); - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - " <%s>%u\n" \ - " <%s>0x%016lx\n", \ - required_title_version_str, required_title_version, required_title_version_str, \ - required_title_type_str, required_title_id, required_title_type_str)) goto end; + if (!CNMT_ADD_FMT_STR(" <%s>%u\n" \ + " <%s>0x%016lx\n", \ + required_title_version_str, required_title_version, required_title_version_str, \ + required_title_type_str, required_title_id, required_title_type_str)) goto end; } + /* RequiredApplicationVersion (Application). */ if (cnmt_ctx->packaged_header->content_meta_type == NcmContentMetaType_Application) { - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - " %u\n", \ - ((ContentMetaApplicationMetaExtendedHeader*)cnmt_ctx->extended_header)->required_application_version.value)) goto end; + if (!CNMT_ADD_FMT_STR(" %u\n", \ + ((ContentMetaApplicationMetaExtendedHeader*)cnmt_ctx->extended_header)->required_application_version.value)) goto end; } - if (!(success = utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, ""))) goto end; + if (!(success = CNMT_ADD_FMT_STR(""))) goto end; /* Update CNMT context. */ cnmt_ctx->authoring_tool_xml = xml_buf; diff --git a/source/core/nacp.c b/source/core/nacp.c index 534dc0c..49df3b1 100644 --- a/source/core/nacp.c +++ b/source/core/nacp.c @@ -23,6 +23,23 @@ #include "nacp.h" #include "title.h" +/* Helper macros. */ + +#define NACP_ADD_FMT_STR_T1(fmt, ...) utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, fmt, ##__VA_ARGS__) +#define NACP_ADD_FMT_STR_T2(fmt, ...) utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, fmt, ##__VA_ARGS__) +#define NACP_ADD_STR(tag_name, value) nacpAddStringFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, tag_name, value) +#define NACP_ADD_ENUM(tag_name, value, str_func) nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, tag_name, value, \ + &str_func) +#define NACP_ADD_BITFLAG(tag_name, flag, flag_width, max_flag_idx, str_func, allow_empty_str) nacpAddBitflagFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, tag_name, flag, \ + flag_width, max_flag_idx, &(str_func), \ + allow_empty_str) +#define NACP_ADD_U16(tag_name, value, hex, prefix) nacpAddU16FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, tag_name, value, hex, \ + prefix) +#define NACP_ADD_U32(tag_name, value, hex, prefix) nacpAddU32FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, tag_name, value, hex, \ + prefix) +#define NACP_ADD_U64(tag_name, value, hex, prefix) nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, tag_name, value, hex, \ + prefix) + /* Type definitions. */ typedef const char *(*NacpStringFunction)(u8 value); /* Used while adding fields to the AuthoringTool-like XML. */ @@ -68,7 +85,8 @@ static const char *g_nacpAddOnContentRegistrationTypeStrings[NacpAddOnContentReg static const char *g_nacpAttributeStrings[NacpAttribute_Count] = { "Demo", - "RetailInteractiveDisplay" + "RetailInteractiveDisplay", + "DownloadPlay" }; static const char *g_nacpParentalControlStrings[NacpParentalControl_Count] = { @@ -137,6 +155,13 @@ static const char *g_nacpRuntimeParameterDeliveryStrings[NacpRuntimeParameterDel "OnRestart" }; +static const char *g_nacpAppropriateAgeForChinaStrings[NacpAppropriateAgeForChina_Count] = { + "None", + "Age8", + "Age12", + "Age16" +}; + static const char *g_nacpUndecidedParameter75b8bStrings[NacpUndecidedParameter75b8b_Count] = { "a", "b" @@ -156,6 +181,11 @@ static const char *g_nacpStartupUserAccountOptionStrings[NacpStartupUserAccountO "IsOptional" }; +static const char *g_nacpRuntimeUpgradeStrings[NacpRuntimeUpgrade_Count] = { + "Deny", + "Allow" +}; + static const char *g_nacpPlayLogQueryCapabilityStrings[NacpPlayLogQueryCapability_Count] = { "None", "WhiteList", @@ -170,16 +200,6 @@ static const char *g_nacpRequiredNetworkServiceLicenseOnLaunchStrings[NacpRequir "Common" }; -static const char *g_nacpJitConfigurationFlagStrings[NacpJitConfigurationFlag_Count] = { - "false", - "true" -}; - -static const char *g_nacpPlayReportPermissionStrings[NacpPlayReportPermission_Count] = { - "Deny", - "Allow" -}; - static const char *g_nacpCrashScreenshotForProdStrings[NacpCrashScreenshotForProd_Count] = { "Deny", "Allow" @@ -190,13 +210,19 @@ static const char *g_nacpCrashScreenshotForDevStrings[NacpCrashScreenshotForDev_ "Allow" }; +static const char *g_nacpContentsAvailabilityTransitionPolicyStrings[NacpContentsAvailabilityTransitionPolicy_Count] = { + "NoPolicy", + "Stable", + "Changeable" +}; + /* Function prototypes. */ NX_INLINE bool nacpCheckBitflagField(const void *flag, u8 flag_bitcount, u8 idx); 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 flag_width, u8 max_flag_idx, NacpStringFunction str_func); +static bool nacpAddBitflagFieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, const void *flag, u8 flag_width, u8 max_flag_idx, NacpStringFunction str_func, bool allow_empty_str); static bool nacpAddU16FieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, u16 value, bool hex, bool prefix); static bool nacpAddU32FieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, u32 value, bool hex, bool prefix); static bool nacpAddU64FieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, u64 value, bool hex, bool prefix); @@ -424,6 +450,8 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 requir _NacpStruct *nacp = nacp_ctx->data; + Version app_ver = { .value = version }; + u8 i = 0, count = 0; char *xml_buf = NULL; u64 xml_buf_size = 0; @@ -437,6 +465,9 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 requir NacpNeighborDetectionClientConfiguration *ndcc = &(nacp->neighbor_detection_client_configuration); NacpRequiredAddOnContentsSetBinaryDescriptor *raocsbd = &(nacp->required_add_on_contents_set_binary_descriptor); + bool raocsbd_available = false; + + bool alrv_available = false; bool success = false; @@ -445,9 +476,8 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 requir nacp_ctx->authoring_tool_xml = NULL; nacp_ctx->authoring_tool_xml_size = 0; - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - "\n" \ - "\n")) goto end; + if (!NACP_ADD_FMT_STR_T1("\n" \ + "\n")) goto end; /* Title. */ for(i = 0, count = 0; i < NacpLanguage_Count; i++) @@ -455,56 +485,53 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 requir NacpTitle *title = &(nacp->title[i]); if (!*(title->name) || !*(title->publisher)) continue; - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - " \n" \ - " <Language>%s</Language>\n" \ - " <Name>%s</Name>\n" \ - " <Publisher>%s</Publisher>\n" \ - " \n", \ - nacpGetLanguageString(i), \ - title->name, \ - title->publisher)) goto end; + if (!NACP_ADD_FMT_STR_T1(" \n" \ + " <Language>%s</Language>\n" \ + " <Name>%s</Name>\n" \ + " <Publisher>%s</Publisher>\n" \ + " \n", \ + nacpGetLanguageString(i), \ + title->name, \ + title->publisher)) goto end; count++; } - if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " \n")) goto end; + if (!count && !NACP_ADD_FMT_STR_T1(" <Title />\n")) goto end; /* Isbn. */ - if (!nacpAddStringFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "Isbn", nacp->isbn)) goto end; + if (!NACP_ADD_STR("Isbn", nacp->isbn)) goto end; /* StartupUserAccount. */ - if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "StartupUserAccount", nacp->startup_user_account, &nacpGetStartupUserAccountString)) goto end; + if (!NACP_ADD_ENUM("StartupUserAccount", nacp->startup_user_account, nacpGetStartupUserAccountString)) goto end; /* StartupUserAccountOption. */ - if (!nacpAddBitflagFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "StartupUserAccountOption", &(nacp->startup_user_account_option), sizeof(nacp->startup_user_account_option), \ - NacpStartupUserAccountOption_Count, &nacpGetStartupUserAccountOptionString)) goto end; + if (!NACP_ADD_BITFLAG("StartupUserAccountOption", &(nacp->startup_user_account_option), sizeof(nacp->startup_user_account_option), NacpStartupUserAccountOption_Count, \ + nacpGetStartupUserAccountOptionString, true)) goto end; /* UserAccountSwitchLock. */ - if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSwitchLock", nacp->user_account_switch_lock, &nacpGetUserAccountSwitchLockString)) goto end; + if (!NACP_ADD_ENUM("UserAccountSwitchLock", nacp->user_account_switch_lock, nacpGetUserAccountSwitchLockString)) goto end; /* Attribute. */ - if (!nacpAddBitflagFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "Attribute", &(nacp->attribute), sizeof(nacp->attribute), NacpAttribute_Count, &nacpGetAttributeString)) goto end; + if (!NACP_ADD_BITFLAG("Attribute", &(nacp->attribute), sizeof(nacp->attribute), NacpAttribute_Count, nacpGetAttributeString, false)) goto end; /* ParentalControl. */ - if (!nacpAddBitflagFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "ParentalControl", &(nacp->parental_control), sizeof(nacp->parental_control), NacpParentalControl_Count, \ - &nacpGetParentalControlString)) goto end; + if (!NACP_ADD_BITFLAG("ParentalControl", &(nacp->parental_control), sizeof(nacp->parental_control), NacpParentalControl_Count, nacpGetParentalControlString, false)) goto end; /* SupportedLanguage. */ - if (!nacpAddBitflagFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "SupportedLanguage", &(nacp->supported_language), sizeof(nacp->supported_language), NacpSupportedLanguage_Count, \ - &nacpGetLanguageString)) goto end; + if (!NACP_ADD_BITFLAG("SupportedLanguage", &(nacp->supported_language), sizeof(nacp->supported_language), NacpSupportedLanguage_Count, nacpGetLanguageString, false)) goto end; /* Screenshot. */ - if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "Screenshot", nacp->screenshot, &nacpGetScreenshotString)) goto end; + if (!NACP_ADD_ENUM("Screenshot", nacp->screenshot, nacpGetScreenshotString)) goto end; /* VideoCapture. */ - if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "VideoCapture", nacp->video_capture, &nacpGetVideoCaptureString)) goto end; + if (!NACP_ADD_ENUM("VideoCapture", nacp->video_capture, nacpGetVideoCaptureString)) goto end; /* PresenceGroupId. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "PresenceGroupId", nacp->presence_group_id, true, true)) goto end; + if (!NACP_ADD_U64("PresenceGroupId", nacp->presence_group_id, true, true)) goto end; /* DisplayVersion. */ - if (!nacpAddStringFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DisplayVersion", nacp->display_version)) goto end; + if (!NACP_ADD_STR("DisplayVersion", nacp->display_version)) goto end; /* Rating. */ for(i = 0, count = 0; i < NacpRatingAgeOrganization_Count; i++) @@ -512,78 +539,75 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 requir s8 age = *(((s8*)&(nacp->rating_age)) + i); if (age < 0) continue; - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - " <Rating>\n" \ - " <Organization>%s</Organization>\n" \ - " <Age>%d</Age>\n" \ - " </Rating>\n", \ - nacpGetRatingAgeOrganizationString(i), \ - age)) goto end; + if (!NACP_ADD_FMT_STR_T1(" <Rating>\n" \ + " <Organization>%s</Organization>\n" \ + " <Age>%d</Age>\n" \ + " </Rating>\n", \ + nacpGetRatingAgeOrganizationString(i), \ + age)) goto end; count++; } - if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " <Rating />\n")) goto end; + if (!count && !NACP_ADD_FMT_STR_T1(" <Rating />\n")) goto end; /* DataLossConfirmation. */ - if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DataLossConfirmation", nacp->data_loss_confirmation, &nacpGetDataLossConfirmationString)) goto end; + if (!NACP_ADD_ENUM("DataLossConfirmation", nacp->data_loss_confirmation, nacpGetDataLossConfirmationString)) goto end; /* PlayLogPolicy. */ - if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "PlayLogPolicy", nacp->play_log_policy, &nacpGetPlayLogPolicyString)) goto end; + if (!NACP_ADD_ENUM("PlayLogPolicy", nacp->play_log_policy, nacpGetPlayLogPolicyString)) goto end; /* SaveDataOwnerId. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "SaveDataOwnerId", nacp->save_data_owner_id, true, true)) goto end; + if (!NACP_ADD_U64("SaveDataOwnerId", nacp->save_data_owner_id, true, true)) goto end; /* UserAccountSaveDataSize. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataSize", (u64)nacp->user_account_save_data_size, true, true)) goto end; + if (!NACP_ADD_U64("UserAccountSaveDataSize", (u64)nacp->user_account_save_data_size, true, true)) goto end; /* UserAccountSaveDataJournalSize. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataJournalSize", (u64)nacp->user_account_save_data_journal_size, true, true)) goto end; + if (!NACP_ADD_U64("UserAccountSaveDataJournalSize", (u64)nacp->user_account_save_data_journal_size, true, true)) goto end; /* UserAccountSaveDataTotalSize. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataTotalSize", (u64)(nacp->user_account_save_data_size + nacp->user_account_save_data_journal_size), true, true)) goto end; + if (!NACP_ADD_U64("UserAccountSaveDataTotalSize", (u64)(nacp->user_account_save_data_size + nacp->user_account_save_data_journal_size), true, true)) goto end; /* DeviceSaveDataSize. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataSize", (u64)nacp->device_save_data_size, true, true)) goto end; + if (!NACP_ADD_U64("DeviceSaveDataSize", (u64)nacp->device_save_data_size, true, true)) goto end; /* DeviceSaveDataJournalSize. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataJournalSize", (u64)nacp->device_save_data_journal_size, true, true)) goto end; + if (!NACP_ADD_U64("DeviceSaveDataJournalSize", (u64)nacp->device_save_data_journal_size, true, true)) goto end; /* BcatDeliveryCacheStorageSize. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "BcatDeliveryCacheStorageSize", (u64)nacp->bcat_delivery_cache_storage_size, true, true)) goto end; + if (!NACP_ADD_U64("BcatDeliveryCacheStorageSize", (u64)nacp->bcat_delivery_cache_storage_size, true, true)) goto end; /* ApplicationErrorCodeCategory. */ - if (!nacpAddStringFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "ApplicationErrorCodeCategory", nacp->application_error_code_category)) goto end; + if (!NACP_ADD_STR("ApplicationErrorCodeCategory", nacp->application_error_code_category)) goto end; /* AddOnContentBaseId. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "AddOnContentBaseId", nacp->add_on_content_base_id, true, true)) goto end; + if (!NACP_ADD_U64("AddOnContentBaseId", nacp->add_on_content_base_id, true, true)) goto end; /* Version. */ - if (!nacpAddU32FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "Version", version, false, false)) goto end; + if (!NACP_ADD_U32("Version", version, false, false)) goto end; - /* ReleaseVersion and PrivateVersion. Unused but kept anyway. */ - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - " <ReleaseVersion />\n" \ - " <PrivateVersion />\n")) goto end; + /* ReleaseVersion. */ + if (!NACP_ADD_U32("ReleaseVersion", app_ver.application_version.release_ver, false, false)) goto end; + + /* PrivateVersion. */ + if (!NACP_ADD_U32("PrivateVersion", app_ver.application_version.private_ver, false, false)) goto end; /* LogoType. */ - if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "LogoType", nacp->logo_type, &nacpGetLogoTypeString)) goto end; + if (!NACP_ADD_ENUM("LogoType", nacp->logo_type, nacpGetLogoTypeString)) goto end; /* RequiredSystemVersion. */ - if (!nacpAddU32FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "RequiredSystemVersion", required_system_version, false, false)) goto end; + if (!NACP_ADD_U32("RequiredSystemVersion", required_system_version, false, false)) goto end; /* LocalCommunicationId. */ - for(i = 0, count = 0; i < 0x8; i++) + for(i = 0; i < 0x8; i++) { if (!nacp->local_communication_id[i]) continue; - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "LocalCommunicationId", nacp->local_communication_id[i], true, true)) goto end; - count++; + if (!NACP_ADD_U64("LocalCommunicationId", nacp->local_communication_id[i], true, true)) goto end; } - if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " <LocalCommunicationId />\n")) goto end; - /* LogoHandling. */ - if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "LogoHandling", nacp->logo_handling, &nacpGetLogoHandlingString)) goto end; + if (!NACP_ADD_ENUM("LogoHandling", nacp->logo_handling, nacpGetLogoHandlingString)) goto end; /* Icon. */ for(i = 0, count = 0; i < nacp_ctx->icon_count; i++) @@ -597,101 +621,96 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 requir utilsGenerateHexStringFromData(icon_hash_str, sizeof(icon_hash_str), icon_hash, sizeof(icon_hash) / 2, false); /* Add XML element. */ - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - " <Icon>\n" \ - " <Language>%s</Language>\n" \ - " <IconPath />\n" \ - " <NxIconPath />\n" \ - " <RawIconHash />\n" \ - " <NxIconHash>%s</NxIconHash>\n" \ - " </Icon>\n", \ - nacpGetLanguageString(icon_ctx->language), \ - icon_hash_str)) goto end; + if (!NACP_ADD_FMT_STR_T1(" <Icon>\n" \ + " <Language>%s</Language>\n" \ + /*" <IconPath />\n" \ + " <NxIconPath />\n" \ + " <RawIconHash />\n" \*/ + " <NxIconHash>%s</NxIconHash>\n" \ + " </Icon>\n", \ + nacpGetLanguageString(icon_ctx->language), \ + icon_hash_str)) goto end; count++; } - if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " <Icon />\n")) goto end; + if (!count && !NACP_ADD_FMT_STR_T1(" <Icon />\n")) goto end; /* HtmlDocumentPath, LegalInformationFilePath and AccessibleUrlsFilePath. Unused but kept anyway. */ - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - " <HtmlDocumentPath />\n" \ - " <LegalInformationFilePath />\n" \ - " <AccessibleUrlsFilePath />\n")) goto end; + if (!NACP_ADD_FMT_STR_T1(" <HtmlDocumentPath UseEnvironmentVariable=\"false\" />\n" \ + " <LegalInformationFilePath UseEnvironmentVariable=\"false\" />\n" \ + " <AccessibleUrlsFilePath UseEnvironmentVariable=\"false\" />\n")) goto end; /* SeedForPseudoDeviceId. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "SeedForPseudoDeviceId", nacp->seed_for_pseudo_device_id, true, false)) goto end; + if (!NACP_ADD_U64("SeedForPseudoDeviceId", nacp->seed_for_pseudo_device_id, true, false)) goto end; /* BcatPassphrase. */ - if (!nacpAddStringFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "BcatPassphrase", nacp->bcat_passphrase)) goto end; + if (!NACP_ADD_STR("BcatPassphrase", nacp->bcat_passphrase)) goto end; /* AddOnContentRegistrationType. */ - if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "AddOnContentRegistrationType", nacp->add_on_content_registration_type, &nacpGetAddOnContentRegistrationTypeString)) goto end; + if (!NACP_ADD_ENUM("AddOnContentRegistrationType", nacp->add_on_content_registration_type, nacpGetAddOnContentRegistrationTypeString)) goto end; /* UserAccountSaveDataSizeMax. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataSizeMax", (u64)nacp->user_account_save_data_size_max, true, true)) goto end; + if (!NACP_ADD_U64("UserAccountSaveDataSizeMax", (u64)nacp->user_account_save_data_size_max, true, true)) goto end; /* UserAccountSaveDataJournalSizeMax. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataJournalSizeMax", (u64)nacp->user_account_save_data_journal_size_max, true, true)) goto end; + if (!NACP_ADD_U64("UserAccountSaveDataJournalSizeMax", (u64)nacp->user_account_save_data_journal_size_max, true, true)) goto end; /* DeviceSaveDataSizeMax. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataSizeMax", (u64)nacp->device_save_data_size_max, true, true)) goto end; + if (!NACP_ADD_U64("DeviceSaveDataSizeMax", (u64)nacp->device_save_data_size_max, true, true)) goto end; /* DeviceSaveDataJournalSizeMax. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataJournalSizeMax", (u64)nacp->device_save_data_journal_size_max, true, true)) goto end; + if (!NACP_ADD_U64("DeviceSaveDataJournalSizeMax", (u64)nacp->device_save_data_journal_size_max, true, true)) goto end; /* TemporaryStorageSize. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "TemporaryStorageSize", (u64)nacp->temporary_storage_size, true, true)) goto end; + if (!NACP_ADD_U64("TemporaryStorageSize", (u64)nacp->temporary_storage_size, true, true)) goto end; /* CacheStorageSize. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageSize", (u64)nacp->cache_storage_size, true, true)) goto end; + if (!NACP_ADD_U64("CacheStorageSize", (u64)nacp->cache_storage_size, true, true)) goto end; /* CacheStorageJournalSize. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageJournalSize", (u64)nacp->cache_storage_journal_size, true, true)) goto end; + if (!NACP_ADD_U64("CacheStorageJournalSize", (u64)nacp->cache_storage_journal_size, true, true)) goto end; /* CacheStorageDataAndJournalSizeMax. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageDataAndJournalSizeMax", (u64)nacp->cache_storage_data_and_journal_size_max, true, true)) goto end; + if (!NACP_ADD_U64("CacheStorageDataAndJournalSizeMax", (u64)nacp->cache_storage_data_and_journal_size_max, true, true)) goto end; /* CacheStorageIndexMax. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageIndexMax", (u64)nacp->cache_storage_index_max, true, true)) goto end; + if (!NACP_ADD_U64("CacheStorageIndexMax", (u64)nacp->cache_storage_index_max, true, true)) goto end; /* Hdcp. */ - if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "Hdcp", nacp->hdcp, &nacpGetHdcpString)) goto end; + if (!NACP_ADD_ENUM("Hdcp", nacp->hdcp, nacpGetHdcpString)) goto end; /* CrashReport. */ - if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CrashReport", nacp->crash_report, &nacpGetCrashReportString)) goto end; + if (!NACP_ADD_ENUM("CrashReport", nacp->crash_report, nacpGetCrashReportString)) goto end; /* CrashScreenshotForProd. */ - if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CrashScreenshotForProd", nacp->crash_screenshot_for_prod, &nacpGetCrashScreenshotForProdString)) goto end; + if (!NACP_ADD_ENUM("CrashScreenshotForProd", nacp->crash_screenshot_for_prod, nacpGetCrashScreenshotForProdString)) goto end; /* CrashScreenshotForDev. */ - if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CrashScreenshotForDev", nacp->crash_screenshot_for_dev, &nacpGetCrashScreenshotForDevString)) goto end; + if (!NACP_ADD_ENUM("CrashScreenshotForDev", nacp->crash_screenshot_for_dev, nacpGetCrashScreenshotForDevString)) goto end; /* RuntimeAddOnContentInstall. */ - if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "RuntimeAddOnContentInstall", nacp->runtime_add_on_content_install, &nacpGetRuntimeAddOnContentInstallString)) goto end; + if (!NACP_ADD_ENUM("RuntimeAddOnContentInstall", nacp->runtime_add_on_content_install, nacpGetRuntimeAddOnContentInstallString)) goto end; /* PlayLogQueryableApplicationId. */ - for(i = 0, count = 0; i < 0x10; i++) + for(i = 0; i < 0x10; i++) { if (!nacp->play_log_queryable_application_id[i]) continue; - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "PlayLogQueryableApplicationId", nacp->play_log_queryable_application_id[i], true, true)) goto end; - count++; + if (!NACP_ADD_U64("PlayLogQueryableApplicationId", nacp->play_log_queryable_application_id[i], true, true)) goto end; } - if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " <PlayLogQueryableApplicationId />\n")) goto end; - /* PlayLogQueryCapability. */ - if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "PlayLogQueryCapability", nacp->play_log_query_capability, &nacpGetPlayLogQueryCapabilityString)) goto end; + if (!NACP_ADD_ENUM("PlayLogQueryCapability", nacp->play_log_query_capability, nacpGetPlayLogQueryCapabilityString)) goto end; /* Repair. */ - if (!nacpAddBitflagFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "Repair", &(nacp->repair), sizeof(nacp->repair), NacpRepair_Count, &nacpGetRepairString)) goto end; + if (!NACP_ADD_BITFLAG("Repair", &(nacp->repair), sizeof(nacp->repair), NacpRepair_Count, nacpGetRepairString, false)) goto end; /* ProgramIndex. */ - if (!nacpAddU16FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "ProgramIndex", nacp->program_index, false, false)) goto end; + if (!NACP_ADD_U16("ProgramIndex", nacp->program_index, false, false)) goto end; /* RequiredNetworkServiceLicenseOnLaunch. */ - if (!nacpAddBitflagFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "RequiredNetworkServiceLicenseOnLaunch", &(nacp->required_network_service_license_on_launch), \ - sizeof(nacp->required_network_service_license_on_launch), NacpRequiredNetworkServiceLicenseOnLaunch_Count, &nacpGetRequiredNetworkServiceLicenseOnLaunchString)) goto end; + if (!NACP_ADD_BITFLAG("RequiredNetworkServiceLicenseOnLaunch", &(nacp->required_network_service_license_on_launch), sizeof(nacp->required_network_service_license_on_launch), \ + NacpRequiredNetworkServiceLicenseOnLaunch_Count, nacpGetRequiredNetworkServiceLicenseOnLaunchString, false)) goto end; /* NeighborDetectionClientConfiguration. */ ndcc_sgc_available = (ndcc->send_group_configuration.group_id && memcmp(ndcc->send_group_configuration.key, null_key, sizeof(null_key))); @@ -704,18 +723,17 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 requir if (ndcc_sgc_available || ndcc_rgc_available) { - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " <NeighborDetectionClientConfiguration>\n")) goto end; + if (!NACP_ADD_FMT_STR_T1(" <NeighborDetectionClientConfiguration>\n")) goto end; /* SendGroupConfiguration. */ utilsGenerateHexStringFromData(key_str, sizeof(key_str), ndcc->send_group_configuration.key, sizeof(ndcc->send_group_configuration.key), false); - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - " <SendGroupConfiguration>\n" \ - " <GroupId>0x%016lx</GroupId>\n" \ - " <Key>%s</Key>\n" \ - " </SendGroupConfiguration>\n", \ - ndcc->send_group_configuration.group_id, \ - key_str)) goto end; + if (!NACP_ADD_FMT_STR_T1(" <SendGroupConfiguration>\n" \ + " <GroupId>0x%016lx</GroupId>\n" \ + " <Key>%s</Key>\n" \ + " </SendGroupConfiguration>\n", \ + ndcc->send_group_configuration.group_id, \ + key_str)) goto end; /* ReceivableGroupConfiguration. */ for(i = 0; i < 0x10; i++) @@ -724,85 +742,122 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 requir utilsGenerateHexStringFromData(key_str, sizeof(key_str), rgc->key, sizeof(rgc->key), false); - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - " <ReceivableGroupConfiguration>\n" \ - " <GroupId>0x%016lx</GroupId>\n" \ - " <Key>%s</Key>\n" \ - " </ReceivableGroupConfiguration>\n", \ - rgc->group_id, \ - key_str)) goto end; + if (!NACP_ADD_FMT_STR_T1(" <ReceivableGroupConfiguration>\n" \ + " <GroupId>0x%016lx</GroupId>\n" \ + " <Key>%s</Key>\n" \ + " </ReceivableGroupConfiguration>\n", \ + rgc->group_id, \ + key_str)) goto end; } - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " </NeighborDetectionClientConfiguration>\n")) goto end; - } else { - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " <NeighborDetectionClientConfiguration />\n")) goto end; + if (!NACP_ADD_FMT_STR_T1(" </NeighborDetectionClientConfiguration>\n")) goto end; } /* JitConfiguration. */ - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - " <Jit>\n" \ - " <IsEnabled>%s</IsEnabled>\n" \ - " <MemorySize>%lu</MemorySize>\n" \ - " </Jit>\n", \ - nacpGetJitConfigurationFlagString(nacp->jit_configuration.jit_configuration_flag), \ - nacp->jit_configuration.memory_size)) goto end; + if (!NACP_ADD_FMT_STR_T1(" <Jit>\n" \ + " <IsEnabled>%s</IsEnabled>\n" \ + " <MemorySize>%lu</MemorySize>\n" \ + " </Jit>\n", \ + (nacp->jit_configuration.jit_configuration_flag & NacpJitConfigurationFlag_Enabled) ? "true" : "false", \ + nacp->jit_configuration.memory_size)) goto end; - /* History. Unused but kept anyway. */ - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " <History />\n")) goto end; + /* History. */ + //if (!NACP_ADD_FMT_STR_T1(" <History />\n")) goto end; /* RuntimeParameterDelivery. */ - if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "RuntimeParameterDelivery", nacp->runtime_parameter_delivery, &nacpGetRuntimeParameterDeliveryString)) goto end; + if (!NACP_ADD_ENUM("RuntimeParameterDelivery", nacp->runtime_parameter_delivery, nacpGetRuntimeParameterDeliveryString)) goto end; + + /* AppropriateAgeForChina. */ + if (!NACP_ADD_ENUM("AppropriateAgeForChina", nacp->appropriate_age_for_china, nacpGetAppropriateAgeForChina)) goto end; /* RequiredAddOnContentsSet. */ - for(i = 0, count = 0; i < 0x20; i++) + for(i = 0; i < 0x20; i++) { - NacpDescriptors *descriptor = &(raocsbd->descriptors[i]); - if (!descriptor->index || !descriptor->continue_set) continue; + NacpRequiredAddOnContentsSetDescriptor *descriptor = &(raocsbd->descriptors[i]); - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - " <RequiredAddOnContentsSet>\n" \ - " <Index>%u</Index>\n" \ - " </RequiredAddOnContentsSet>\n", \ - descriptor->index)) goto end; + if (descriptor->index) + { + raocsbd_available = true; + break; + } - count++; + if (descriptor->flag != NacpRequiredAddOnContentsSetDescriptorFlag_Continue) break; } - if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " <RequiredAddOnContentsSet />\n")) goto end; + if (raocsbd_available) + { + if (!NACP_ADD_FMT_STR_T1(" <RequiredAddOnContentsSet>\n")) goto end; + + for(i = 0; i < 0x20; i++) + { + NacpRequiredAddOnContentsSetDescriptor *descriptor = &(raocsbd->descriptors[i]); + if (!descriptor->index) continue; + + if (!NACP_ADD_FMT_STR_T1(" <Index>%u</Index>\n", descriptor->index)) goto end; + + if (descriptor->flag != NacpRequiredAddOnContentsSetDescriptorFlag_Continue) break; + } + + if (!NACP_ADD_FMT_STR_T1(" </RequiredAddOnContentsSet>\n")) goto end; + } /* PlayReportPermission. */ - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - " <PlayReportPermission>\n" \ - " <TargetMarketing>%s</TargetMarketing>\n" \ - " </PlayReportPermission>\n", \ - nacpGetPlayReportPermissionString(nacp->play_report_permission))) goto end; + if (!NACP_ADD_FMT_STR_T1(" <PlayReportPermission>\n" \ + " <TargetMarketing>%s</TargetMarketing>\n" \ + " </PlayReportPermission>\n", \ + (nacp->play_report_permission & NacpPlayReportPermission_TargetMarketing) ? "Allow" : "Deny")) goto end; /* AccessibleLaunchRequiredVersion. */ - for(i = 0, count = 0; i < 0x8; i++) + for(i = 0; i < 0x8; i++) { - if (!nacp->accessible_launch_required_version.application_id[i]) continue; - - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - " <AccessibleLaunchRequiredVersion>\n" \ - " <ApplicationId>0x%016lx</ApplicationId>\n" \ - " </AccessibleLaunchRequiredVersion>\n", \ - nacp->accessible_launch_required_version.application_id[i])) goto end; - - count++; + if (nacp->accessible_launch_required_version.application_id[i]) + { + alrv_available = true; + break; + } } - if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " <AccessibleLaunchRequiredVersion />\n")) goto end; + if (alrv_available) + { + if (!NACP_ADD_FMT_STR_T1(" <AccessibleLaunchRequiredVersion>\n")) goto end; + + for(i = 0; i < 0x8; i++) + { + u64 id = nacp->accessible_launch_required_version.application_id[i]; + if (!id) continue; + + if (!NACP_ADD_FMT_STR_T1(" <ApplicationId>0x%016lx</ApplicationId>\n", id)) goto end; + } + + if (!NACP_ADD_FMT_STR_T1(" </AccessibleLaunchRequiredVersion>\n")) goto end; + } else { + if (!NACP_ADD_FMT_STR_T1(" <AccessibleLaunchRequiredVersion />\n")) goto end; + } /* UndecidedParameter75b8b. */ - if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UndecidedParameter75b8b", nacp->undecided_parameter_75b8b, &nacpGetUndecidedParameter75b8bString)) goto end; + if (!NACP_ADD_ENUM("UndecidedParameter75b8b", nacp->undecided_parameter_75b8b, nacpGetUndecidedParameter75b8bString)) goto end; /* ApplicationId. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "ApplicationId", nacp_ctx->nca_ctx->header.program_id, true, true)) goto end; + if (!NACP_ADD_U64("ApplicationId", nacp_ctx->nca_ctx->header.program_id, true, true)) goto end; - /* FilterDescriptionFilePath. Unused but kept anyway. */ - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " <FilterDescriptionFilePath />\n")) goto end; + /* FilterDescriptionFilePath and CompressionFileConfigurationFilePath. */ + /*if (!NACP_ADD_FMT_STR_T1(" <FilterDescriptionFilePath />\n" \ + " <CompressionFileConfigurationFilePath />\n")) goto end;*/ - if (!(success = utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, "</Application>"))) goto end; + /* ContentsAvailabilityTransitionPolicy. */ + if (!NACP_ADD_ENUM("ContentsAvailabilityTransitionPolicy", nacp->contents_availability_transition_policy, nacpGetContentsAvailabilityTransitionPolicyString)) goto end; + + /* LimitedLicenseSettings. */ + if (!NACP_ADD_FMT_STR_T1(" <LimitedLicenseSettings>\n" \ + " <RuntimeUpgrade>%s</RuntimeUpgrade>\n" \ + " <SupportingLimitedLicenses>\n" \ + " <LimitedLicense>%s</LimitedLicense>\n" \ + " </SupportingLimitedLicenses>\n" \ + " </LimitedLicenseSettings>\n", \ + nacpGetRuntimeUpgradeString(nacp->runtime_upgrade), \ + (nacp->supporting_limited_licenses & NacpSupportingLimitedLicenses_Demo) ? "Demo" : "None")) goto end; + + if (!(success = NACP_ADD_FMT_STR_T1("</Application>"))) goto end; /* Update NACP context. */ nacp_ctx->authoring_tool_xml = xml_buf; @@ -893,6 +948,11 @@ const char *nacpGetRuntimeParameterDeliveryString(u8 runtime_parameter_delivery) return (runtime_parameter_delivery < NacpRuntimeParameterDelivery_Count ? g_nacpRuntimeParameterDeliveryStrings[runtime_parameter_delivery] : g_unknownString); } +const char *nacpGetAppropriateAgeForChina(u8 appropriate_age_for_china) +{ + return (appropriate_age_for_china < NacpAppropriateAgeForChina_Count ? g_nacpAppropriateAgeForChinaStrings[appropriate_age_for_china] : g_unknownString); +} + const char *nacpGetUndecidedParameter75b8bString(u8 undecided_parameter_75b8b) { return (undecided_parameter_75b8b < NacpUndecidedParameter75b8b_Count ? g_nacpUndecidedParameter75b8bStrings[undecided_parameter_75b8b] : g_unknownString); @@ -913,6 +973,11 @@ const char *nacpGetStartupUserAccountOptionString(u8 startup_user_account_option return (startup_user_account_option < NacpStartupUserAccountOption_Count ? g_nacpStartupUserAccountOptionStrings[startup_user_account_option] : g_unknownString); } +const char *nacpGetRuntimeUpgradeString(u8 runtime_upgrade) +{ + return (runtime_upgrade < NacpRuntimeUpgrade_Count ? g_nacpRuntimeUpgradeStrings[runtime_upgrade] : g_unknownString); +} + const char *nacpGetPlayLogQueryCapabilityString(u8 play_log_query_capability) { return (play_log_query_capability < NacpPlayLogQueryCapability_Count ? g_nacpPlayLogQueryCapabilityStrings[play_log_query_capability] : g_unknownString); @@ -929,16 +994,6 @@ const char *nacpGetRequiredNetworkServiceLicenseOnLaunchString(u8 required_netwo g_nacpRequiredNetworkServiceLicenseOnLaunchStrings[required_network_service_license_on_launch] : g_unknownString); } -const char *nacpGetJitConfigurationFlagString(u64 jig_configuration_flag) -{ - return (jig_configuration_flag < NacpJitConfigurationFlag_Count ? g_nacpJitConfigurationFlagStrings[jig_configuration_flag] : g_unknownString); -} - -const char *nacpGetPlayReportPermissionString(u8 play_report_permission) -{ - return (play_report_permission < NacpPlayReportPermission_Count ? g_nacpPlayReportPermissionStrings[play_report_permission] : g_unknownString); -} - const char *nacpGetCrashScreenshotForProdString(u8 crash_screenshot_for_prod) { return (crash_screenshot_for_prod < NacpCrashScreenshotForProd_Count ? g_nacpCrashScreenshotForProdStrings[crash_screenshot_for_prod] : g_unknownString); @@ -949,6 +1004,12 @@ const char *nacpGetCrashScreenshotForDevString(u8 crash_screenshot_for_dev) return (crash_screenshot_for_dev < NacpCrashScreenshotForDev_Count ? g_nacpCrashScreenshotForDevStrings[crash_screenshot_for_dev] : g_unknownString); } +const char *nacpGetContentsAvailabilityTransitionPolicyString(u8 contents_availability_transition_policy) +{ + return (contents_availability_transition_policy < NacpContentsAvailabilityTransitionPolicy_Count ? \ + g_nacpContentsAvailabilityTransitionPolicyStrings[contents_availability_transition_policy] : g_unknownString); +} + NX_INLINE bool nacpCheckBitflagField(const void *flag, u8 flag_bitcount, u8 idx) { if (!flag || !flag_bitcount || !IS_POWER_OF_TWO(flag_bitcount) || idx >= flag_bitcount) return false; @@ -966,8 +1027,7 @@ static bool nacpAddStringFieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_si return false; } - return (*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)); + return (*value ? NACP_ADD_FMT_STR_T2(" <%s>%s</%s>\n", tag_name, value, tag_name) : NACP_ADD_FMT_STR_T2(" <%s />\n", tag_name)); } static bool nacpAddEnumFieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, u8 value, NacpStringFunction str_func) @@ -978,10 +1038,10 @@ static bool nacpAddEnumFieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size return false; } - return utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <%s>%s</%s>\n", tag_name, str_func(value), tag_name); + return NACP_ADD_FMT_STR_T2(" <%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 flag_width, u8 max_flag_idx, NacpStringFunction str_func) +static bool nacpAddBitflagFieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, const void *flag, u8 flag_width, u8 max_flag_idx, NacpStringFunction str_func, bool allow_empty_str) { u8 flag_bitcount = 0, i = 0, count = 0; const u8 *flag_u8 = (const u8*)flag; @@ -1008,7 +1068,7 @@ static bool nacpAddBitflagFieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_s for(i = 0; i < max_flag_idx; i++) { if (!nacpCheckBitflagField(flag, flag_bitcount, i)) continue; - if (!utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <%s>%s</%s>\n", tag_name, str_func(i), tag_name)) goto end; + if (!NACP_ADD_FMT_STR_T2(" <%s>%s</%s>\n", tag_name, str_func(i), tag_name)) goto end; count++; } @@ -1016,7 +1076,7 @@ static bool nacpAddBitflagFieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_s if (!count) empty_flag = true; } - if (empty_flag && !utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <%s />\n", tag_name)) goto end; + if (empty_flag && allow_empty_str && !NACP_ADD_FMT_STR_T2(" <%s />\n", tag_name)) goto end; success = true; @@ -1034,7 +1094,7 @@ static bool nacpAddU16FieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *str = (hex ? (prefix ? " <%s>0x%04x</%s>\n" : " <%s>%04x</%s>\n") : " <%s>%u</%s>\n"); - return utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, str, tag_name, value, tag_name); + return NACP_ADD_FMT_STR_T2(str, tag_name, value, tag_name); } static bool nacpAddU32FieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, u32 value, bool hex, bool prefix) @@ -1047,7 +1107,7 @@ static bool nacpAddU32FieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *str = (hex ? (prefix ? " <%s>0x%08x</%s>\n" : " <%s>%08x</%s>\n") : " <%s>%u</%s>\n"); - return utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, str, tag_name, value, tag_name); + return NACP_ADD_FMT_STR_T2(str, tag_name, value, tag_name); } static bool nacpAddU64FieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, u64 value, bool hex, bool prefix) @@ -1060,5 +1120,5 @@ static bool nacpAddU64FieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *str = (hex ? (prefix ? " <%s>0x%016lx</%s>\n" : " <%s>%016lx</%s>\n") : " <%s>%lu</%s>\n"); - return utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, str, tag_name, value, tag_name); + return NACP_ADD_FMT_STR_T2(str, tag_name, value, tag_name); } diff --git a/source/core/nxdt_utils.c b/source/core/nxdt_utils.c index a5c4daa..4dd2e78 100644 --- a/source/core/nxdt_utils.c +++ b/source/core/nxdt_utils.c @@ -159,7 +159,8 @@ bool utilsInitializeResources(const int program_argc, const char **program_argv) LOG_MSG("Running under %s mode.", _utilsAppletModeCheck() ? "applet" : "title override"); /* Create output directories (SD card only). */ - utilsCreateOutputDirectories(NULL); + /* TODO: remove the APP_TITLE check whenever we're ready for a release. */ + if (!strcasecmp(APP_TITLE, "nxdumptool")) utilsCreateOutputDirectories(NULL); if (g_appLaunchPath) { diff --git a/source/core/program_info.c b/source/core/program_info.c index 4e9aba7..46df0cb 100644 --- a/source/core/program_info.c +++ b/source/core/program_info.c @@ -25,6 +25,11 @@ #include "program_info.h" #include "elf_symbol.h" +/* Helper macros. */ + +#define PI_ADD_FMT_STR_T1(fmt, ...) utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, fmt, ##__VA_ARGS__) +#define PI_ADD_FMT_STR_T2(fmt, ...) utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, fmt, ##__VA_ARGS__) + /* Global variables. */ static const char *g_trueString = "True", *g_falseString = "False"; @@ -203,36 +208,33 @@ bool programInfoGenerateAuthoringToolXml(ProgramInfoContext *program_info_ctx) /* Get SDK version and build type strings. */ if (!programInfoGetSdkVersionAndBuildTypeFromSdkNso(program_info_ctx, &sdk_version, &build_type)) goto end; - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" \ - "<ProgramInfo>\n")) goto end; + if (!PI_ADD_FMT_STR_T1("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" \ + "<ProgramInfo>\n")) goto end; /* SdkVersion. */ if (!programInfoAddStringFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "SdkVersion", sdk_version)) goto end; - - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - " <ToolVersion />\n" /* Impossible to get. */ \ - " <NxAddonVersion>%s</NxAddonVersion>\n" \ - " <PatchToolVersion />\n" /* Impossible to get. */ \ - " <BuildTarget>%u</BuildTarget>\n", \ - sdk_version, \ - is_64bit ? 64 : 32)) goto end; + + if (!PI_ADD_FMT_STR_T1(" <ToolVersion />\n" /* Impossible to get. */ \ + " <NxAddonVersion>%s</NxAddonVersion>\n" \ + " <PatchToolVersion />\n" /* Impossible to get. */ \ + " <BuildTarget>%u</BuildTarget>\n", \ + sdk_version, \ + is_64bit ? 64 : 32)) goto end; /* BuildType. */ if (!programInfoAddStringFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "BuildType", build_type)) goto end; - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - " <EnableDeadStrip />\n" /* Impossible to get. */ \ - " <EnableDeadStripSpecified />\n" /* Impossible to get. */ \ - " <Desc>%s</Desc>\n" \ - " <DescFileName />\n" /* Impossible to get. */ \ - " <DescFlags>\n" \ - " <Production>%s</Production>\n" \ - " <UnqualifiedApproval>%s</UnqualifiedApproval>\n" \ - " </DescFlags>\n", \ - npdm_acid_b64, \ - program_info_ctx->npdm_ctx.acid_header->flags.production ? g_trueString : g_falseString, \ - program_info_ctx->npdm_ctx.acid_header->flags.unqualified_approval ? g_trueString : g_falseString)) goto end; + if (!PI_ADD_FMT_STR_T1(" <EnableDeadStrip />\n" /* Impossible to get. */ \ + " <EnableDeadStripSpecified />\n" /* Impossible to get. */ \ + " <Desc>%s</Desc>\n" \ + " <DescFileName />\n" /* Impossible to get. */ \ + " <DescFlags>\n" \ + " <Production>%s</Production>\n" \ + " <UnqualifiedApproval>%s</UnqualifiedApproval>\n" \ + " </DescFlags>\n", \ + npdm_acid_b64, \ + program_info_ctx->npdm_ctx.acid_header->flags.production ? g_trueString : g_falseString, \ + program_info_ctx->npdm_ctx.acid_header->flags.unqualified_approval ? g_trueString : g_falseString)) goto end; /* MiddlewareList. */ if (!programInfoAddNsoApiListToAuthoringToolXml(&xml_buf, &xml_buf_size, program_info_ctx, "Middleware", "Module", "SDK MW")) goto end; @@ -252,14 +254,13 @@ bool programInfoGenerateAuthoringToolXml(ProgramInfoContext *program_info_ctx) /* FsAccessControlData. */ if (!programInfoAddFsAccessControlDataToAuthoringToolXml(&xml_buf, &xml_buf_size, program_info_ctx)) goto end; - if (!(success = utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - " <EnableGlobalDestructor />\n" /* Impossible to get. */ \ - " <EnableGlobalDestructorSpecified />\n" /* Impossible to get. */ \ - " <IncludeNssFile />\n" /* Impossible to get. */ \ - " <IncludeNssFileSpecified />\n" /* Impossible to get. */ \ - " <History />\n" /* Impossible to get. */ \ - " <TargetTriplet />\n" /* Impossible to get. */ \ - "</ProgramInfo>"))) goto end; + if (!(success = PI_ADD_FMT_STR_T1(" <EnableGlobalDestructor />\n" /* Impossible to get. */ \ + " <EnableGlobalDestructorSpecified />\n" /* Impossible to get. */ \ + " <IncludeNssFile />\n" /* Impossible to get. */ \ + " <IncludeNssFileSpecified />\n" /* Impossible to get. */ \ + " <History />\n" /* Impossible to get. */ \ + " <TargetTriplet />\n" /* Impossible to get. */ \ + "</ProgramInfo>"))) goto end; /* Update ProgramInfo context. */ program_info_ctx->authoring_tool_xml = xml_buf; @@ -397,11 +398,11 @@ static bool programInfoAddNsoApiListToAuthoringToolXml(char **xml_buf, u64 *xml_ /* Append an empty XML element if no entries for this API list exist. */ if (!api_list_exists) { - success = utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <%sList />\n", api_list_tag); + success = PI_ADD_FMT_STR_T2(" <%sList />\n", api_list_tag); goto end; } - if (!utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <%sList>\n", api_list_tag)) goto end; + if (!PI_ADD_FMT_STR_T2(" <%sList>\n", api_list_tag)) goto end; /* Retrieve full API list. */ for(u32 i = 0; i < program_info_ctx->nso_count; i++) @@ -415,24 +416,23 @@ static bool programInfoAddNsoApiListToAuthoringToolXml(char **xml_buf, u64 *xml_ if (programInfoIsApiInfoEntryValid(sdk_prefix, sdk_prefix_len, sdk_entry, &sdk_entry_vender, &sdk_entry_vender_len, &sdk_entry_name, false)) { - if (!utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, \ - " <%s>\n" \ - " <%sName>%s</%sName>\n" \ - " <VenderName>%.*s</VenderName>\n" \ - " <NsoName>%s</NsoName>\n" \ - " </%s>\n", \ - api_list_tag, \ - api_entry_prefix, sdk_entry_name, api_entry_prefix, \ - sdk_entry_vender_len, sdk_entry_vender, \ - nso_ctx->nso_filename, \ - api_list_tag)) goto end; + if (!PI_ADD_FMT_STR_T2(" <%s>\n" \ + " <%sName>%s</%sName>\n" \ + " <VenderName>%.*s</VenderName>\n" \ + " <NsoName>%s</NsoName>\n" \ + " </%s>\n", \ + api_list_tag, \ + api_entry_prefix, sdk_entry_name, api_entry_prefix, \ + sdk_entry_vender_len, sdk_entry_vender, \ + nso_ctx->nso_filename, \ + api_list_tag)) goto end; } j += strlen(sdk_entry); } } - success = utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " </%sList>\n", api_list_tag); + success = PI_ADD_FMT_STR_T2(" </%sList>\n", api_list_tag); end: return success; @@ -466,8 +466,7 @@ static bool programInfoAddStringFieldToAuthoringToolXml(char **xml_buf, u64 *xml return false; } - return ((value && *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)); + return ((value && *value) ? PI_ADD_FMT_STR_T2(" <%s>%s</%s>\n", tag_name, value, tag_name) : PI_ADD_FMT_STR_T2(" <%s />\n", tag_name)); } static bool programInfoAddNsoSymbolsToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, ProgramInfoContext *program_info_ctx) @@ -488,8 +487,8 @@ static bool programInfoAddNsoSymbolsToAuthoringToolXml(char **xml_buf, u64 *xml_ for(u32 i = 0; i < program_info_ctx->nso_count; i++) { nso_ctx = &(program_info_ctx->nso_ctx[i]); - if (nso_ctx->nso_filename && !strcmp(nso_ctx->nso_filename, "main") && nso_ctx->rodata_dynstr_section && nso_ctx->rodata_dynstr_section_size && nso_ctx->rodata_dynsym_section && \ - nso_ctx->rodata_dynsym_section_size) break; + if (nso_ctx->nso_filename && !strcmp(nso_ctx->nso_filename, "main") && nso_ctx->rodata_dynstr_section && nso_ctx->rodata_dynstr_section_size && \ + nso_ctx->rodata_dynsym_section && nso_ctx->rodata_dynsym_section_size) break; nso_ctx = NULL; } @@ -511,7 +510,7 @@ static bool programInfoAddNsoSymbolsToAuthoringToolXml(char **xml_buf, u64 *xml_ /* Bail out if we couldn't find any valid symbols. */ if (!symbols_exist) goto end; - if (!utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <UnresolvedApiList>\n")) goto end; + if (!PI_ADD_FMT_STR_T2(" <UnresolvedApiList>\n")) goto end; /* Parse ELF dynamic symbol table to retrieve the symbol strings. */ for(u64 i = 0; i < nso_ctx->rodata_dynsym_section_size; i += symbol_size) @@ -520,20 +519,19 @@ static bool programInfoAddNsoSymbolsToAuthoringToolXml(char **xml_buf, u64 *xml_ if (!programInfoIsElfSymbolValid(nso_ctx->rodata_dynsym_section + i, nso_ctx->rodata_dynstr_section, nso_ctx->rodata_dynstr_section_size, is_64bit, &symbol_str)) continue; - if (!utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, \ - " <UnresolvedApi>\n" \ - " <ApiName>%s</ApiName>\n" \ - " <NsoName>%s</NsoName>\n" \ - " </UnresolvedApi>\n", \ - symbol_str, \ - nso_ctx->nso_filename)) goto end; + if (!PI_ADD_FMT_STR_T2(" <UnresolvedApi>\n" \ + " <ApiName>%s</ApiName>\n" \ + " <NsoName>%s</NsoName>\n" \ + " </UnresolvedApi>\n", \ + symbol_str, \ + nso_ctx->nso_filename)) goto end; } - success = utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " </UnresolvedApiList>\n"); + success = PI_ADD_FMT_STR_T2(" </UnresolvedApiList>\n"); end: /* Append an empty XML element if no valid symbols exist. */ - if (!success && (!nso_ctx || !symbols_exist)) success = utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <UnresolvedApiList />\n"); + if (!success && (!nso_ctx || !symbols_exist)) success = PI_ADD_FMT_STR_T2(" <UnresolvedApiList />\n"); return success; } @@ -592,25 +590,24 @@ static bool programInfoAddFsAccessControlDataToAuthoringToolXml(char **xml_buf, /* Padding to a 0x4-byte boundary is needed. Each accessibility field takes up a single byte, so we can get away with it by aligning the ID count. */ save_data_owner_ids = (u64*)((u8*)save_data_owner_block + sizeof(NpdmFsAccessControlDataSaveDataOwnerBlock) + ALIGN_UP(save_data_owner_block->save_data_owner_id_count, 0x4)); - if (!utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <FsAccessControlData>\n")) goto end; + if (!PI_ADD_FMT_STR_T2(" <FsAccessControlData>\n")) goto end; /* Append save data owner IDs. */ for(u32 i = 0; i < save_data_owner_block->save_data_owner_id_count; i++) { - if (!utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, \ - " <SaveDataOwnerIds>\n" \ - " <Accessibility>%s</Accessibility>\n" \ - " <Id>0x%016lx</Id>\n" \ - " </SaveDataOwnerIds>\n", \ - g_facAccessibilityStrings[save_data_owner_block->accessibility[i] & 0x3], \ - save_data_owner_ids[i])) goto end; + if (!PI_ADD_FMT_STR_T2(" <SaveDataOwnerIds>\n" \ + " <Accessibility>%s</Accessibility>\n" \ + " <Id>0x%016lx</Id>\n" \ + " </SaveDataOwnerIds>\n", \ + g_facAccessibilityStrings[save_data_owner_block->accessibility[i] & 0x3], \ + save_data_owner_ids[i])) goto end; } - success = utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " </FsAccessControlData>\n"); + success = PI_ADD_FMT_STR_T2(" </FsAccessControlData>\n"); end: /* Append an empty XML element if no FS access control data exists. */ - if (!success && !sdo_data_available) success = utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <FsAccessControlData />\n"); + if (!success && !sdo_data_available) success = PI_ADD_FMT_STR_T2(" <FsAccessControlData />\n"); return success; } diff --git a/source/exception_handler.cpp b/source/exception_handler.cpp index 36ea9a6..551993b 100644 --- a/source/exception_handler.cpp +++ b/source/exception_handler.cpp @@ -24,9 +24,12 @@ #include <nxdt_utils.h> #include <borealis.hpp> -#define FP_MASK 0xFFFFFFFFFF000000UL -#define STACK_TRACE_SIZE 0x20 -#define IS_HB_ADDR(x) (info.addr && info.size && (x) >= info.addr && (x) < (info.addr + info.size)) +/* Helper macros. */ + +#define FP_MASK 0xFFFFFFFFFF000000UL +#define STACK_TRACE_SIZE 0x20 +#define IS_HB_ADDR(x) (info.addr && info.size && (x) >= info.addr && (x) < (info.addr + info.size)) +#define EH_ADD_FMT_STR(fmt, ...) utilsAppendFormattedStringToBuffer(&exception_str, &exception_str_size, fmt, ##__VA_ARGS__) namespace i18n = brls::i18n; /* For getStr(). */ using namespace i18n::literals; /* For _i18n. */ @@ -168,45 +171,45 @@ extern "C" { break; } - utilsAppendFormattedStringToBuffer(&exception_str, &exception_str_size, "Type: %s (0x%X)\r\n", error_desc_str.c_str(), ctx->error_desc); + EH_ADD_FMT_STR("Type: %s (0x%X)\r\n", error_desc_str.c_str(), ctx->error_desc); /* Log CPU registers. */ - utilsAppendFormattedStringToBuffer(&exception_str, &exception_str_size, "Registers:"); + EH_ADD_FMT_STR("Registers:"); for(size_t i = 0; i < MAX_ELEMENTS(ctx->cpu_gprs); i++) { u64 reg = ctx->cpu_gprs[i].x; - utilsAppendFormattedStringToBuffer(&exception_str, &exception_str_size, "\r\n X%02lu: 0x%lX", i, reg); - if (IS_HB_ADDR(reg)) utilsAppendFormattedStringToBuffer(&exception_str, &exception_str_size, " (BASE + 0x%lX)", reg - info.addr); + EH_ADD_FMT_STR("\r\n X%02lu: 0x%lX", i, reg); + if (IS_HB_ADDR(reg)) EH_ADD_FMT_STR(" (BASE + 0x%lX)", reg - info.addr); } - utilsAppendFormattedStringToBuffer(&exception_str, &exception_str_size, "\r\n FP: 0x%lX", ctx->fp.x); - if (IS_HB_ADDR(ctx->fp.x)) utilsAppendFormattedStringToBuffer(&exception_str, &exception_str_size, " (BASE + 0x%lX)", ctx->fp.x - info.addr); + EH_ADD_FMT_STR("\r\n FP: 0x%lX", ctx->fp.x); + if (IS_HB_ADDR(ctx->fp.x)) EH_ADD_FMT_STR(" (BASE + 0x%lX)", ctx->fp.x - info.addr); - utilsAppendFormattedStringToBuffer(&exception_str, &exception_str_size, "\r\n LR: 0x%lX", ctx->lr.x); - if (IS_HB_ADDR(ctx->lr.x)) utilsAppendFormattedStringToBuffer(&exception_str, &exception_str_size, " (BASE + 0x%lX)", ctx->lr.x - info.addr); + EH_ADD_FMT_STR("\r\n LR: 0x%lX", ctx->lr.x); + if (IS_HB_ADDR(ctx->lr.x)) EH_ADD_FMT_STR(" (BASE + 0x%lX)", ctx->lr.x - info.addr); - utilsAppendFormattedStringToBuffer(&exception_str, &exception_str_size, "\r\n SP: 0x%lX", ctx->sp.x); - if (IS_HB_ADDR(ctx->sp.x)) utilsAppendFormattedStringToBuffer(&exception_str, &exception_str_size, " (BASE + 0x%lX)", ctx->sp.x - info.addr); + EH_ADD_FMT_STR("\r\n SP: 0x%lX", ctx->sp.x); + if (IS_HB_ADDR(ctx->sp.x)) EH_ADD_FMT_STR(" (BASE + 0x%lX)", ctx->sp.x - info.addr); - utilsAppendFormattedStringToBuffer(&exception_str, &exception_str_size, "\r\n PC: 0x%lX", ctx->pc.x); - if (IS_HB_ADDR(ctx->pc.x)) utilsAppendFormattedStringToBuffer(&exception_str, &exception_str_size, " (BASE + 0x%lX)", ctx->pc.x - info.addr); - utilsAppendFormattedStringToBuffer(&exception_str, &exception_str_size, "\r\n"); + EH_ADD_FMT_STR("\r\n PC: 0x%lX", ctx->pc.x); + if (IS_HB_ADDR(ctx->pc.x)) EH_ADD_FMT_STR(" (BASE + 0x%lX)", ctx->pc.x - info.addr); + EH_ADD_FMT_STR("\r\n"); /* Unwind stack. */ if (nxdt::utils::UnwindStack(stack_trace, &stack_trace_size, STACK_TRACE_SIZE, ctx->fp.x)) { /* Log stack trace. */ - utilsAppendFormattedStringToBuffer(&exception_str, &exception_str_size, "Stack Trace:"); + EH_ADD_FMT_STR("Stack Trace:"); for(u32 i = 0; i < stack_trace_size; i++) { u64 addr = stack_trace[i]; - utilsAppendFormattedStringToBuffer(&exception_str, &exception_str_size, "\r\n [%02u]: 0x%lX", stack_trace_size - i - 1, addr); - if (IS_HB_ADDR(addr)) utilsAppendFormattedStringToBuffer(&exception_str, &exception_str_size, " (BASE + 0x%lX)", addr - info.addr); + EH_ADD_FMT_STR("\r\n [%02u]: 0x%lX", stack_trace_size - i - 1, addr); + if (IS_HB_ADDR(addr)) EH_ADD_FMT_STR(" (BASE + 0x%lX)", addr - info.addr); } - utilsAppendFormattedStringToBuffer(&exception_str, &exception_str_size, "\r\n"); + EH_ADD_FMT_STR("\r\n"); } /* Write log string. */ @@ -216,7 +219,8 @@ extern "C" { if (exception_str) free(exception_str); /* Abort program execution. */ - crash_str = (g_borealisInitialized ? i18n::getStr("generic/exception_triggered"_i18n, error_desc_str, ctx->error_desc) : fmt::format("Fatal exception triggered!\nReason: {} (0x{:X}).", error_desc_str, ctx->error_desc)); + crash_str = (g_borealisInitialized ? i18n::getStr("generic/exception_triggered"_i18n, error_desc_str, ctx->error_desc) : \ + fmt::format("Fatal exception triggered!\nReason: {} (0x{:X}).", error_desc_str, ctx->error_desc)); crash_str += (fmt::format("\nPC: 0x{:X}", ctx->pc.x) + (IS_HB_ADDR(ctx->pc.x) ? fmt::format(" (BASE + 0x{:X}).", ctx->pc.x - info.addr) : ".")); nxdt::utils::AbortProgramExecution(crash_str); } diff --git a/todo.txt b/todo.txt index 49fa468..bd1942a 100644 --- a/todo.txt +++ b/todo.txt @@ -1,11 +1,11 @@ todo: + nca: support for sparse sections + nca: support for compressed fs sections + log: verbosity levels log: nxlink output for advanced users - nca: support for compressed fs sections? - nca: support for sparse sections? - title: more functions for title lookup? (filters, patches / aoc, etc.) title: more functions for content lookup? (based on id) title: parse the update partition from gamecards (if available) to generate ncmcontentinfo data for all update titles