diff --git a/code_templates/cnmt_xml_generator.c b/code_templates/cnmt_xml_generator.c index e9d3d8f..6abe5ea 100644 --- a/code_templates/cnmt_xml_generator.c +++ b/code_templates/cnmt_xml_generator.c @@ -232,7 +232,7 @@ int main(int argc, char *argv[]) fclose(xml_fd); } } else { - consolePrint("cnmt initialize ctx failed\n"); + consolePrint("cnmt xml failed\n"); } out2: diff --git a/code_templates/nacp_xml_generator.c b/code_templates/nacp_xml_generator.c new file mode 100644 index 0000000..f758bd4 --- /dev/null +++ b/code_templates/nacp_xml_generator.c @@ -0,0 +1,256 @@ +/* + * main.c + * + * Copyright (c) 2020, DarkMatterCore . + * + * 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 . + */ + +#include "utils.h" +#include "gamecard.h" +#include "title.h" +#include "nacp.h" + +static void consolePrint(const char *text, ...) +{ + va_list v; + va_start(v, text); + vfprintf(stdout, text, v); + va_end(v); + consoleUpdate(NULL); +} + +int main(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + + int ret = 0; + + LOGFILE(APP_TITLE " starting."); + + consoleInit(NULL); + + consolePrint("initializing...\n"); + + if (!utilsInitializeResources()) + { + ret = -1; + goto out; + } + + u32 app_count = 0; + TitleApplicationMetadata **app_metadata = NULL; + TitleUserApplicationData user_app_data = {0}; + + u32 selected_idx = 0, page_size = 30, scroll = 0; + bool exit_prompt = true; + + NcaContext *nca_ctx = NULL; + Ticket tik = {0}; + NacpContext nacp_ctx = {0}; + + app_metadata = titleGetApplicationMetadataEntries(false, &app_count); + if (!app_metadata || !app_count) + { + consolePrint("app metadata failed\n"); + goto out2; + } + + consolePrint("app metadata succeeded\n"); + + utilsSleep(1); + + while(true) + { + consoleClear(); + printf("select an user application to generate a nacp xml for.\npress b to exit.\n\n"); + printf("title: %u / %u\n\n", selected_idx + 1, app_count); + + for(u32 i = scroll; i < app_count; i++) + { + if (i >= (scroll + page_size)) break; + printf("%s%016lX - %s\n", i == selected_idx ? " -> " : " ", app_metadata[i]->title_id, app_metadata[i]->lang_entry.name); + } + + printf("\n"); + + consoleUpdate(NULL); + + u64 btn_down = 0, btn_held = 0; + while(true) + { + hidScanInput(); + btn_down = utilsHidKeysAllDown(); + btn_held = utilsHidKeysAllHeld(); + if (btn_down || btn_held) break; + + if (titleIsGameCardInfoUpdated()) + { + free(app_metadata); + + app_metadata = titleGetApplicationMetadataEntries(false, &app_count); + if (!app_metadata) + { + consolePrint("\napp metadata failed\n"); + goto out2; + } + + selected_idx = scroll = 0; + break; + } + } + + if (btn_down & KEY_A) + { + if (!titleGetUserApplicationData(app_metadata[selected_idx]->title_id, &user_app_data) || !user_app_data.app_info) + { + consolePrint("\nthe selected title doesn't have available base content.\n"); + utilsSleep(3); + continue; + } + + break; + } else + if ((btn_down & KEY_DDOWN) || (btn_held & (KEY_LSTICK_DOWN | KEY_RSTICK_DOWN))) + { + selected_idx++; + + if (selected_idx >= app_count) + { + if (btn_down & KEY_DDOWN) + { + selected_idx = scroll = 0; + } else { + selected_idx = (app_count - 1); + } + } else + if (selected_idx >= (scroll + (page_size / 2)) && app_count > (scroll + page_size)) + { + scroll++; + } + } else + if ((btn_down & KEY_DUP) || (btn_held & (KEY_LSTICK_UP | KEY_RSTICK_UP))) + { + selected_idx--; + + if (selected_idx == UINT32_MAX) + { + if (btn_down & KEY_DUP) + { + selected_idx = (app_count - 1); + scroll = (app_count >= page_size ? (app_count - page_size) : 0); + } else { + selected_idx = 0; + } + } else + if (selected_idx < (scroll + (page_size / 2)) && scroll > 0) + { + scroll--; + } + } else + if (btn_down & KEY_B) + { + exit_prompt = false; + goto out2; + } + + if (btn_held & (KEY_LSTICK_DOWN | KEY_RSTICK_DOWN | KEY_LSTICK_UP | KEY_RSTICK_UP)) svcSleepThread(50000000); // 50 ms + } + + consoleClear(); + consolePrint("selected title:\n%s (%016lX)\n\n", app_metadata[selected_idx]->lang_entry.name, app_metadata[selected_idx]->title_id); + + nca_ctx = calloc(1, sizeof(NcaContext)); + if (!nca_ctx) + { + consolePrint("nca ctx calloc failed\n"); + goto out2; + } + + consolePrint("nca ctx calloc succeeded\n"); + + if (!ncaInitializeContext(nca_ctx, user_app_data.app_info->storage_id, (user_app_data.app_info->storage_id == NcmStorageId_GameCard ? GameCardHashFileSystemPartitionType_Secure : 0), \ + titleGetContentInfoByTypeAndIdOffset(user_app_data.app_info, NcmContentType_Control, 0), &tik)) + { + consolePrint("Control nca initialize ctx failed\n"); + goto out2; + } + + consolePrint("Control nca initialize ctx succeeded\n"); + + if (!nacpInitializeContext(&nacp_ctx, nca_ctx)) + { + consolePrint("nacp initialize ctx failed\n"); + goto out2; + } + + consolePrint("nacp initialize ctx succeeded\n"); + + if (nacpGenerateAuthoringToolXml(&nacp_ctx)) + { + consolePrint("nacp xml succeeded\n"); + + FILE *xml_fd = NULL; + char path[FS_MAX_PATH] = {0}; + + sprintf(path, "sdmc:/%s.nacp.xml", nca_ctx->content_id_str); + + xml_fd = fopen(path, "wb"); + if (xml_fd) + { + fwrite(nacp_ctx.authoring_tool_xml, 1, nacp_ctx.authoring_tool_xml_size, xml_fd); + fclose(xml_fd); + xml_fd = NULL; + } + + for(u8 i = 0; i < nacp_ctx.icon_count; i++) + { + NacpIconContext *icon_ctx = &(nacp_ctx.icon_ctx[i]); + + sprintf(path, "sdmc:/%s.nx.%s.jpg", nca_ctx->content_id_str, nacpGetLanguageString(icon_ctx->language)); + + xml_fd = fopen(path, "wb"); + if (xml_fd) + { + fwrite(icon_ctx->icon_data, 1, icon_ctx->icon_size, xml_fd); + fclose(xml_fd); + xml_fd = NULL; + } + } + } else { + consolePrint("nacp xml failed\n"); + } + +out2: + if (exit_prompt) + { + consolePrint("press any button to exit\n"); + utilsWaitForButtonPress(KEY_NONE); + } + + nacpFreeContext(&nacp_ctx); + + if (nca_ctx) free(nca_ctx); + + if (app_metadata) free(app_metadata); + +out: + utilsCloseResources(); + + consoleExit(NULL); + + return ret; +} diff --git a/source/nacp.c b/source/nacp.c index 8856149..a72dca7 100644 --- a/source/nacp.c +++ b/source/nacp.c @@ -113,34 +113,80 @@ static const char *g_nacpRatingAgeOrganizationStrings[] = { [NacpRatingAgeOrganization_IARCGeneric] = "IARCGeneric" }; +static const char *g_nacpLogoTypeStrings[] = { + [NacpLogoType_LicensedByNintendo] = "LicensedByNintendo", + [NacpLogoType_DistributedByNintendo] = "DistributedByNintendo", + [NacpLogoType_Nintendo] = "Nintendo" +}; +static const char *g_nacpLogoHandlingStrings[] = { + [NacpLogoHandling_Auto] = "Auto", + [NacpLogoHandling_Manual] = "Manual" +}; +static const char *g_nacpRuntimeAddOnContentInstallStrings[] = { + [NacpRuntimeAddOnContentInstall_Deny] = "Deny", + [NacpRuntimeAddOnContentInstall_AllowAppend] = "AllowAppend", + [NacpRuntimeAddOnContentInstall_AllowAppendButDontDownloadWhenUsingNetwork] = "AllowAppendButDontDownloadWhenUsingNetwork" +}; +static const char *g_nacpNacpRuntimeParameterDeliveryStrings[] = { + [NacpRuntimeParameterDelivery_Always] = "Always", + [NacpRuntimeParameterDelivery_AlwaysIfUserStateMatched] = "AlwaysIfUserStateMatched", + [NacpRuntimeParameterDelivery_OnRestart] = "OnRestart" +}; +static const char *g_nacpCrashReportStrings[] = { + [NacpCrashReport_Deny] = "Deny", + [NacpCrashReport_Allow] = "Allow" +}; +static const char *g_nacpHdcpStrings[] = { + [NacpHdcp_None] = "None", + [NacpHdcp_Required] = "Required" +}; +static const char *g_nacpStartupUserAccountOptionStrings[] = { + [NacpStartupUserAccountOption_IsOptional] = "IsOptional" +}; +static const char *g_nacpRepairStrings[] = { + [NacpRepair_SuppressGameCardAccess] = "SuppressGameCardAccess" +}; +static const char *g_nacpRequiredNetworkServiceLicenseOnLaunchStrings[] = { + [NacpRequiredNetworkServiceLicenseOnLaunch_Common] = "RequiredNetworkServiceLicenseOnLaunch" +}; +static const char *g_nacpJitConfigurationFlagStrings[] = { + [NacpJitConfigurationFlag_None] = "None", + [NacpJitConfigurationFlag_Enabled] = "Enabled" +}; +static const char *g_nacpPlayReportPermissionStrings[] = { + [NacpPlayReportPermission_None] = "None", + [NacpPlayReportPermission_TargetMarketing] = "TargetMarketing" +}; +static const char *g_nacpCrashScreenshotForProdStrings[] = { + [NacpCrashScreenshotForProd_Deny] = "Deny", + [NacpCrashScreenshotForProd_Allow] = "Allow" +}; + +static const char *g_nacpCrashScreenshotForDevStrings[] = { + [NacpCrashScreenshotForDev_Deny] = "Deny", + [NacpCrashScreenshotForDev_Allow] = "Allow" +}; /* 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 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); static bool nacpAddU64FieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, u64 value); - - - - - - - - - - +static bool nacpAddU16FieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, u16 value, bool hex); bool nacpInitializeContext(NacpContext *out, NcaContext *nca_ctx) { @@ -212,7 +258,7 @@ bool nacpInitializeContext(NacpContext *out, NcaContext *nca_ctx) NacpIconContext *icon_ctx = NULL; /* Check if the current language is supported. */ - if (!nacpCheckBitflagField(&(out->data->supported_language_flag), i, NacpLanguage_Count)) continue; + if (!nacpCheckBitflagField(&(out->data->supported_language_flag), sizeof(out->data->supported_language_flag) * 8, i)) continue; /* Get language string. */ language_str = nacpGetLanguageString(i); @@ -282,9 +328,14 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx) } _NacpStruct *nacp = nacp_ctx->data; + u8 i = 0, count = 0; char *xml_buf = NULL; u64 xml_buf_size = 0; + + u8 icon_hash[SHA256_HASH_SIZE] = {0}; + char icon_hash_str[SHA256_HASH_SIZE + 1] = {0}; + bool success = false; /* Free AuthoringTool-like XML data if needed. */ @@ -329,21 +380,22 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx) 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; + if (!nacpAddBitflagFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "Attribute", &(nacp->attribute_flag), sizeof(nacp->attribute_flag), NacpAttribute_Count, &nacpGetAttributeString)) goto end; - /* SupportedLanguageFlag. */ + /* SupportedLanguage. */ /* 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 (!nacpCheckBitflagField(&(nacp->supported_language_flag), sizeof(nacp->supported_language_flag) * 8, i)) continue; if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "SupportedLanguage", i, &nacpGetLanguageString)) goto end; count++; } if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " \n")) goto end; - /* ParentalControlFlag. */ - if (!nacpAddBitflagFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "ParentalControl", &(nacp->parental_control_flag), NacpParentalControl_Count, &nacpGetParentalControlString)) goto end; + /* ParentalControl. */ + if (!nacpAddBitflagFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "ParentalControl", &(nacp->parental_control_flag), sizeof(nacp->parental_control_flag), NacpParentalControl_Count, \ + &nacpGetParentalControlString)) goto end; /* Screenshot. */ if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "Screenshot", nacp->screenshot, &nacpGetScreenshotString)) goto end; @@ -416,14 +468,127 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx) if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " \n")) goto end; + /* LogoType. */ + if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "LogoType", nacp->logo_type, &nacpGetLogoTypeString)) goto end; + /* LogoHandling. */ + if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "LogoHandling", nacp->logo_handling, &nacpGetLogoHandlingString)) goto end; + /* RuntimeAddOnContentInstall. */ + if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "RuntimeAddOnContentInstall", nacp->runtime_add_on_content_install, &nacpGetRuntimeAddOnContentInstallString)) goto end; + /* RuntimeParameterDelivery. */ + if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "RuntimeParameterDelivery", nacp->runtime_parameter_delivery, &nacpGetRuntimeParameterDeliveryString)) goto end; + /* CrashReport. */ + if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CrashReport", nacp->crash_report, &nacpGetCrashReportString)) goto end; + /* Hdcp. */ + if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "Hdcp", nacp->hdcp, &nacpGetHdcpString)) goto end; + /* SeedForPseudoDeviceId. */ + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "SeedForPseudoDeviceId", nacp->seed_for_pseudo_device_id)) goto end; + /* BcatPassphrase. */ + if (!nacpAddStringFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "BcatPassphrase", nacp->bcat_passphrase)) goto end; + /* StartupUserAccountOption. */ + if (!nacpAddBitflagFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "StartupUserAccountOption", &(nacp->startup_user_account_option_flag), sizeof(nacp->startup_user_account_option_flag), \ + NacpStartupUserAccountOption_Count, &nacpGetStartupUserAccountOptionString)) goto end; + + /* UserAccountSaveDataSizeMax. */ + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataSizeMax", nacp->user_account_save_data_size_max)) goto end; + + /* UserAccountSaveDataJournalSizeMax. */ + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataJournalSizeMax", nacp->user_account_save_data_journal_size_max)) goto end; + + /* DeviceSaveDataSizeMax. */ + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataSizeMax", nacp->device_save_data_size_max)) goto end; + + /* DeviceSaveDataJournalSizeMax. */ + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DeviceSaveDataJournalSizeMax", nacp->device_save_data_journal_size_max)) goto end; + + /* TemporaryStorageSize. */ + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "TemporaryStorageSize", nacp->temporary_storage_size)) goto end; + + /* CacheStorageSize. */ + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageSize", nacp->cache_storage_size)) goto end; + + /* CacheStorageJournalSize. */ + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageJournalSize", nacp->cache_storage_journal_size)) goto end; + + /* CacheStorageDataAndJournalSizeMax. */ + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageDataAndJournalSizeMax", nacp->cache_storage_data_and_journal_size_max)) goto end; + + /* CacheStorageIndexMax. */ + if (!nacpAddU16FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageIndexMax", nacp->cache_storage_index_max, true)) goto end; + + /* PlayLogQueryableApplicationId. */ + for(i = 0, count = 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])) goto end; + count++; + } + + if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " \n")) goto end; + + /* Repair. */ + if (!nacpAddBitflagFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "Repair", &(nacp->repair_flag), sizeof(nacp->repair_flag), NacpRepair_Count, &nacpGetRepairString)) goto end; + + /* ProgramIndex. */ + if (!nacpAddU16FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "ProgramIndex", nacp->program_index, false)) goto end; + + /* RequiredNetworkServiceLicenseOnLaunch. */ + if (!nacpAddBitflagFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "RequiredNetworkServiceLicenseOnLaunch", &(nacp->required_network_service_license_on_launch_flag), \ + sizeof(nacp->required_network_service_license_on_launch_flag), NacpRequiredNetworkServiceLicenseOnLaunch_Count, &nacpGetRequiredNetworkServiceLicenseOnLaunchString)) goto end; + + /* TO DO: add NacpNeighborDetectionClientConfiguration. */ + + /* JitConfiguration. */ + if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ + " \n" \ + " %s\n" \ + " 0x%016lx\n" \ + " \n", \ + nacpGetJitConfigurationFlagString(nacp->jit_configuration.jit_configuration_flag), + nacp->jit_configuration.memory_size)) goto end; + + /* TO DO: add NacpRequiredAddOnContentsSetBinaryDescriptor. */ + + /* PlayReportPermission. */ + if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "PlayReportPermission", nacp->play_report_permission, &nacpGetPlayReportPermissionString)) goto end; + + /* CrashScreenshotForProd. */ + if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "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; + + /* Icon. */ + for(i = 0, count = 0; i < nacp_ctx->icon_count; i++) + { + NacpIconContext *icon_ctx = &(nacp_ctx->icon_ctx[i]); + + /* Calculate icon hash. */ + sha256CalculateHash(icon_hash, icon_ctx->icon_data, icon_ctx->icon_size); + + /* Generate icon hash string. */ + utilsGenerateHexStringFromData(icon_hash_str, SHA256_HASH_SIZE + 1, icon_hash, SHA256_HASH_SIZE / 2); + + /* Add XML element. */ + if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ + " \n" \ + " %s\n" \ + " %s\n" \ + " \n", \ + nacpGetLanguageString(icon_ctx->language), \ + icon_hash_str)) goto end; + + count++; + } + + if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " \n")) goto end; if (!(success = utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, ""))) goto end; @@ -496,52 +661,133 @@ const char *nacpGetRatingAgeOrganizationString(u8 rating_age_organization) return (rating_age_organization < NacpRatingAgeOrganization_Count ? g_nacpRatingAgeOrganizationStrings[rating_age_organization] : g_unknownString); } +const char *nacpGetLogoTypeString(u8 logo_type) +{ + return (logo_type < NacpLogoType_Count ? g_nacpLogoTypeStrings[logo_type] : g_unknownString); +} +const char *nacpGetLogoHandlingString(u8 logo_handling) +{ + return (logo_handling < NacpLogoHandling_Count ? g_nacpLogoHandlingStrings[logo_handling] : g_unknownString); +} +const char *nacpGetRuntimeAddOnContentInstallString(u8 runtime_add_on_content_install) +{ + return (runtime_add_on_content_install < NacpRuntimeAddOnContentInstall_Count ? g_nacpRuntimeAddOnContentInstallStrings[runtime_add_on_content_install] : g_unknownString); +} +const char *nacpGetRuntimeParameterDeliveryString(u8 runtime_parameter_delivery) +{ + return (runtime_parameter_delivery < NacpRuntimeParameterDelivery_Count ? g_nacpNacpRuntimeParameterDeliveryStrings[runtime_parameter_delivery] : g_unknownString); +} +const char *nacpGetCrashReportString(u8 crash_report) +{ + return (crash_report < NacpCrashReport_Count ? g_nacpCrashReportStrings[crash_report] : g_unknownString); +} +const char *nacpGetHdcpString(u8 hdcp) +{ + return (hdcp < NacpHdcp_Count ? g_nacpHdcpStrings[hdcp] : g_unknownString); +} +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 *nacpGetRepairString(u8 repair) +{ + return (repair < NacpRepair_Count ? g_nacpRepairStrings[repair] : g_unknownString); +} +const char *nacpGetRequiredNetworkServiceLicenseOnLaunchString(u8 required_network_service_license_on_launch) +{ + return (required_network_service_license_on_launch < NacpRequiredNetworkServiceLicenseOnLaunch_Count ? \ + 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); +} +const char *nacpGetCrashScreenshotForDevString(u8 crash_screenshot_for_dev) +{ + return (crash_screenshot_for_dev < NacpCrashScreenshotForDev_Count ? g_nacpCrashScreenshotForDevStrings[crash_screenshot_for_dev] : 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; + const u8 *flag_u8 = (const u8*)flag; + u8 byte_idx = (idx >> 3); + u8 bitmask = BIT(idx - ALIGN_DOWN(idx, 8)); + return (flag_u8[byte_idx] & bitmask); +} 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; + if (!xml_buf || !xml_buf_size || !tag_name || !strlen(tag_name) || !value) + { + LOGFILE("Invalid parameters!"); + return false; + } + return (strlen(value) ? utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <%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; + if (!xml_buf || !xml_buf_size || !tag_name || !strlen(tag_name) || !str_func) + { + LOGFILE("Invalid parameters!"); + return false; + } + return utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <%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) +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) { - if (!xml_buf || !xml_buf_size || !tag_name || !strlen(tag_name) || !flag || max_flag_idx >= 0x20 || !str_func) return false; + u8 flag_bitcount = 0, i = 0, count = 0; + const u8 *flag_u8 = (const u8*)flag; + bool success = false, empty_flag = true; - u8 i = 0, count = 0; - bool success = false; + if (!xml_buf || !xml_buf_size || !tag_name || !strlen(tag_name) || !flag || !flag_width || (flag_width > 1 && !IS_POWER_OF_TWO(flag_width)) || flag_width > 0x10 || \ + (flag_bitcount = (flag_width * 8)) < max_flag_idx || !str_func) + { + LOGFILE("Invalid parameters!"); + return false; + } if (!utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <%s>", tag_name)) goto end; - if (*((u32*)flag)) + for(i = 0; i < flag_width; i++) + { + if (flag_u8[i]) + { + empty_flag = false; + break; + } + } + + if (!empty_flag) { for(i = 0; i < max_flag_idx; i++) { - if (!nacpCheckBitflagField(flag, i, max_flag_idx)) continue; + if (!nacpCheckBitflagField(flag, flag_bitcount, i)) 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++; @@ -560,6 +806,23 @@ end: 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; + if (!xml_buf || !xml_buf_size || !tag_name || !strlen(tag_name)) + { + LOGFILE("Invalid parameters!"); + return false; + } + return utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <%s>0x%016lx\n", tag_name, value, tag_name); } + +static bool nacpAddU16FieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, u16 value, bool hex) +{ + if (!xml_buf || !xml_buf_size || !tag_name || !strlen(tag_name)) + { + LOGFILE("Invalid parameters!"); + return false; + } + + return (hex ? utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <%s>0x%04x\n", tag_name, value, tag_name) : \ + utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <%s>%u\n", tag_name, value, tag_name)); +} diff --git a/source/nacp.h b/source/nacp.h index c934afc..caaa4d2 100644 --- a/source/nacp.h +++ b/source/nacp.h @@ -165,7 +165,7 @@ typedef enum { NacpRatingAgeOrganization_ACB = 10, NacpRatingAgeOrganization_OFLC = 11, NacpRatingAgeOrganization_IARCGeneric = 12, - NacpRatingAgeOrganization_Count = 13 + NacpRatingAgeOrganization_Count = 13 ///< Not a real value. } NacpRatingAgeOrganization; typedef struct { @@ -188,52 +188,77 @@ typedef struct { typedef enum { NacpLogoType_LicensedByNintendo = 0, NacpLogoType_DistributedByNintendo = 1, ///< Removed. - NacpLogoType_Nintendo = 2 + NacpLogoType_Nintendo = 2, + NacpLogoType_Count = 3 ///< Not a real value. } NacpLogoType; typedef enum { NacpLogoHandling_Auto = 0, - NacpLogoHandling_Manual = 1 + NacpLogoHandling_Manual = 1, + NacpLogoHandling_Count = 2 ///< Not a real value. } NacpLogoHandling; typedef enum { NacpRuntimeAddOnContentInstall_Deny = 0, NacpRuntimeAddOnContentInstall_AllowAppend = 1, - NacpRuntimeAddOnContentInstall_AllowAppendButDontDownloadWhenUsingNetwork = 2 + NacpRuntimeAddOnContentInstall_AllowAppendButDontDownloadWhenUsingNetwork = 2, + NacpRuntimeAddOnContentInstall_Count = 3 ///< Not a real value. } NacpRuntimeAddOnContentInstall; typedef enum { NacpRuntimeParameterDelivery_Always = 0, NacpRuntimeParameterDelivery_AlwaysIfUserStateMatched = 1, - NacpRuntimeParameterDelivery_OnRestart = 2 + NacpRuntimeParameterDelivery_OnRestart = 2, + NacpRuntimeParameterDelivery_Count = 3 ///< Not a real value. } NacpRuntimeParameterDelivery; typedef enum { NacpCrashReport_Deny = 0, - NacpCrashReport_Allow = 1 + NacpCrashReport_Allow = 1, + NacpCrashReport_Count = 2 ///< Not a real value. } NacpCrashReport; typedef enum { NacpHdcp_None = 0, - NacpHdcp_Required = 1 + NacpHdcp_Required = 1, + NacpHdcp_Count = 2 ///< Not a real value. } NacpHdcp; -typedef struct { - u8 NacpStartupUserAccountOption_IsOptional : 1; - u8 NacpStartupUserAccountOption_Reserved : 7; +/// Indexes used to access NACP startup user account option info. +typedef enum { + NacpStartupUserAccountOption_IsOptional = 0, + NacpStartupUserAccountOption_Count = 1 ///< Not a real value. } NacpStartupUserAccountOption; +typedef struct { + u8 NacpStartupUserAccountOptionFlag_IsOptional : 1; + u8 NacpStartupUserAccountOptionFlag_Reserved : 7; +} NacpStartupUserAccountOptionFlag; + typedef enum { NacpPlayLogQueryCapability_None = 0, NacpPlayLogQueryCapability_WhiteList = 1, - NacpPlayLogQueryCapability_All = 2 + NacpPlayLogQueryCapability_All = 2, + NacpPlayLogQueryCapability_Count = 3 ///< Not a real value. } NacpPlayLogQueryCapability; +/// Indexes used to access NACP repair info. +typedef enum { + NacpRepair_SuppressGameCardAccess = 0, + NacpRepair_Count = 1 ///< Not a real value. +} NacpRepair; + typedef struct { u8 NacpRepairFlag_SuppressGameCardAccess : 1; u8 NacpRepairFlag_Reserved : 7; } NacpRepairFlag; +/// Indexes used to access NACP required network service license on launch info. +typedef enum { + NacpRequiredNetworkServiceLicenseOnLaunch_Common = 0, + NacpRequiredNetworkServiceLicenseOnLaunch_Count = 1 ///< Not a real value. +} NacpRequiredNetworkServiceLicenseOnLaunch; + typedef struct { u8 NacpRequiredNetworkServiceLicenseOnLaunchFlag_Common : 1; u8 NacpRequiredNetworkServiceLicenseOnLaunchFlag_Reserved : 7; @@ -241,7 +266,8 @@ typedef struct { typedef enum { NacpJitConfigurationFlag_None = 0, - NacpJitConfigurationFlag_Enabled = 1 + NacpJitConfigurationFlag_Enabled = 1, + NacpJitConfigurationFlag_Count = 2 ///< Not a real value. } NacpJitConfigurationFlag; typedef struct { @@ -251,7 +277,7 @@ typedef struct { typedef struct { u16 NacpDescriptors_Index : 15; - u16 NacpDescriptors_ContinueSet : 1; ///< Not given a name by Nintendo. + u16 NacpDescriptors_ContinueSet : 1; ///< Called "flag" by Nintendo. } NacpDescriptors; typedef struct { @@ -260,17 +286,20 @@ typedef struct { typedef enum { NacpPlayReportPermission_None = 0, - NacpPlayReportPermission_TargetMarketing = 1 + NacpPlayReportPermission_TargetMarketing = 1, + NacpPlayReportPermission_Count = 2 ///< Not a real value. } NacpPlayReportPermission; typedef enum { NacpCrashScreenshotForProd_Deny = 0, - NacpCrashScreenshotForProd_Allow = 1 + NacpCrashScreenshotForProd_Allow = 1, + NacpCrashScreenshotForProd_Count = 2 ///< Not a real value. } NacpCrashScreenshotForProd; typedef enum { NacpCrashScreenshotForDev_Deny = 0, - NacpCrashScreenshotForDev_Allow = 1 + NacpCrashScreenshotForDev_Allow = 1, + NacpCrashScreenshotForDev_Count = 2 ///< Not a real value. } NacpCrashScreenshotForDev; typedef struct { @@ -307,7 +336,7 @@ typedef struct { u8 hdcp; ///< NacpHdcp. u64 seed_for_pseudo_device_id; char bcat_passphrase[0x41]; - NacpStartupUserAccountOption startup_user_account_option; + NacpStartupUserAccountOptionFlag startup_user_account_option_flag; u8 reserved_2[0x6]; u64 user_account_save_data_size_max; u64 user_account_save_data_journal_size_max; @@ -348,7 +377,7 @@ typedef struct { ///< 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. + u8 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. @@ -363,68 +392,32 @@ bool nacpInitializeContext(NacpContext *out, NcaContext *nca_ctx); /// 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. +/// These functions return pointers to string representations of the input value. +/// If the provided value is invalid, "Unknown" is returned. 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); - - - - - - - - - - - - - - - - - +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 *nacpGetCrashReportString(u8 crash_report); +const char *nacpGetHdcpString(u8 hdcp); +const char *nacpGetStartupUserAccountOptionString(u8 startup_user_account_option); +const char *nacpGetRepairString(u8 repair); +const char *nacpGetRequiredNetworkServiceLicenseOnLaunchString(u8 required_network_service_license_on_launch); +const char *nacpGetJitConfigurationFlagString(u64 jig_configuration_flag); +const char *nacpGetPlayReportPermissionString(u8 play_report_permission); +const char *nacpGetCrashScreenshotForProdString(u8 crash_screenshot_for_prod); +const char *nacpGetCrashScreenshotForDevString(u8 crash_screenshot_for_dev); /// Helper inline functions. @@ -438,7 +431,7 @@ NX_INLINE void nacpFreeContext(NacpContext *nacp_ctx) if (nacp_ctx->icon_ctx) { - for(u32 i = 0; i < nacp_ctx->icon_count; i++) + for(u8 i = 0; i < nacp_ctx->icon_count; i++) { if (nacp_ctx->icon_ctx[i].icon_data) free(nacp_ctx->icon_ctx[i].icon_data); } @@ -459,7 +452,7 @@ 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++) + for(u8 i = 0; i < nacp_ctx->icon_count; i++) { if (!nacpIsValidIconContext(&(nacp_ctx->icon_ctx[i]))) return false; } @@ -480,9 +473,4 @@ 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__ */ diff --git a/source/utils.h b/source/utils.h index f6de759..4d9dff5 100644 --- a/source/utils.h +++ b/source/utils.h @@ -50,6 +50,7 @@ #define ALIGN_DOWN(x, y) ((x) & ~((y) - 1)) #define ALIGN_UP(x, y) ((((y) - 1) + (x)) & ~((y) - 1)) #define IS_ALIGNED(x, y) (((x) & ((y) - 1)) == 0) +#define IS_POWER_OF_TWO(x) (((x) & ((x) - 1)) == 0) #define BIS_SYSTEM_PARTITION_MOUNT_NAME "sys:"