From e943e843807e0064add2a5c49381fe21bec0ead7 Mon Sep 17 00:00:00 2001 From: Pablo Curiel Date: Tue, 6 Oct 2020 11:41:26 -0400 Subject: [PATCH] Unified XML generator + finished NACP parsing. Big thanks to 0Liam. --- code_templates/dump_title_infos.c | 6 +- code_templates/nacp_xml_generator.c | 266 ----------------- .../{cnmt_xml_generator.c => xml_generator.c} | 79 ++++- source/cnmt.c | 4 +- source/cnmt.h | 14 + source/nacp.c | 272 +++++++++++------- source/nacp.h | 15 +- source/romfs.c | 8 +- source/title.c | 3 +- source/title.h | 2 +- 10 files changed, 275 insertions(+), 394 deletions(-) delete mode 100644 code_templates/nacp_xml_generator.c rename code_templates/{cnmt_xml_generator.c => xml_generator.c} (73%) diff --git a/code_templates/dump_title_infos.c b/code_templates/dump_title_infos.c index 78b0f37..2e3cffa 100644 --- a/code_templates/dump_title_infos.c +++ b/code_templates/dump_title_infos.c @@ -12,9 +12,9 @@ { fprintf(title_infos_txt, "Storage ID: 0x%02X\r\n", g_titleInfo[i].storage_id); fprintf(title_infos_txt, "Title ID: %016lX\r\n", g_titleInfo[i].meta_key.id); - fprintf(title_infos_txt, "Version: %u (%u.%u.%u-%u.%u)\r\n", g_titleInfo[i].meta_key.version, g_titleInfo[i].dot_version.TitleVersion_Major, \ - g_titleInfo[i].dot_version.TitleVersion_Minor, g_titleInfo[i].dot_version.TitleVersion_Micro, g_titleInfo[i].dot_version.TitleVersion_MajorRelstep, \ - g_titleInfo[i].dot_version.TitleVersion_MinorRelstep); + fprintf(title_infos_txt, "Version: %u (%u.%u.%u-%u.%u)\r\n", g_titleInfo[i].meta_key.version, g_titleInfo[i].version.TitleVersion_Major, \ + g_titleInfo[i].version.TitleVersion_Minor, g_titleInfo[i].version.TitleVersion_Micro, g_titleInfo[i].version.TitleVersion_MajorRelstep, \ + g_titleInfo[i].version.TitleVersion_MinorRelstep); fprintf(title_infos_txt, "Type: 0x%02X\r\n", g_titleInfo[i].meta_key.type); fprintf(title_infos_txt, "Install Type: 0x%02X\r\n", g_titleInfo[i].meta_key.install_type); fprintf(title_infos_txt, "Title Size: %s (0x%lX)\r\n", g_titleInfo[i].title_size_str, g_titleInfo[i].title_size); diff --git a/code_templates/nacp_xml_generator.c b/code_templates/nacp_xml_generator.c deleted file mode 100644 index 5153ad8..0000000 --- a/code_templates/nacp_xml_generator.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * 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", nca_ctx->content_id_str); - - xml_fd = fopen(path, "wb"); - if (xml_fd) - { - fwrite(nacp_ctx.data, 1, sizeof(_NacpStruct), xml_fd); - fclose(xml_fd); - xml_fd = NULL; - } - - 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/code_templates/cnmt_xml_generator.c b/code_templates/xml_generator.c similarity index 73% rename from code_templates/cnmt_xml_generator.c rename to code_templates/xml_generator.c index 6abe5ea..3809468 100644 --- a/code_templates/cnmt_xml_generator.c +++ b/code_templates/xml_generator.c @@ -22,6 +22,7 @@ #include "gamecard.h" #include "title.h" #include "cnmt.h" +#include "nacp.h" static void consolePrint(const char *text, ...) { @@ -60,7 +61,12 @@ int main(int argc, char *argv[]) NcaContext *nca_ctx = NULL; Ticket tik = {0}; + ContentMetaContext cnmt_ctx = {0}; + NacpContext nacp_ctx = {0}; + + FILE *xml_fd = NULL; + char path[FS_MAX_PATH] = {0}; app_metadata = titleGetApplicationMetadataEntries(false, &app_count); if (!app_metadata || !app_count) @@ -182,6 +188,8 @@ int main(int argc, char *argv[]) consolePrint("nca ctx calloc succeeded\n"); + u32 meta_idx = (user_app_data.app_info->content_count - 1), control_idx = 0; + for(u32 i = 0, j = 0; i < user_app_data.app_info->content_count; i++) { if (user_app_data.app_info->content_infos[i].content_type == NcmContentType_Meta) continue; @@ -193,12 +201,12 @@ int main(int argc, char *argv[]) goto out2; } + if (user_app_data.app_info->content_infos[i].content_type == NcmContentType_Control && user_app_data.app_info->content_infos[i].id_offset == 0) control_idx = j; + consolePrint("%s nca initialize ctx succeeded\n", titleGetNcmContentTypeName(user_app_data.app_info->content_infos[i].content_type)); j++; } - u32 meta_idx = (user_app_data.app_info->content_count - 1); - if (!ncaInitializeContext(&(nca_ctx[meta_idx]), 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_Meta, 0), &tik)) { @@ -208,6 +216,9 @@ int main(int argc, char *argv[]) consolePrint("Meta nca initialize ctx succeeded\n"); + sprintf(path, "sdmc:/%016lX_xml", app_metadata[selected_idx]->title_id); + mkdir(path, 0777); + if (!cnmtInitializeContext(&cnmt_ctx, &(nca_ctx[meta_idx]))) { consolePrint("cnmt initialize ctx failed\n"); @@ -220,21 +231,79 @@ int main(int argc, char *argv[]) { consolePrint("cnmt xml succeeded\n"); - FILE *xml_fd = NULL; - char path[FS_MAX_PATH] = {0}; + sprintf(path, "sdmc:/%016lX_xml/%s.cnmt", app_metadata[selected_idx]->title_id, nca_ctx[meta_idx].content_id_str); - sprintf(path, "sdmc:/%s.cnmt.xml", nca_ctx[meta_idx].content_id_str); + xml_fd = fopen(path, "wb"); + if (xml_fd) + { + fwrite(cnmt_ctx.raw_data, 1, cnmt_ctx.raw_data_size, xml_fd); + fclose(xml_fd); + xml_fd = NULL; + } + + sprintf(path, "sdmc:/%016lX_xml/%s.cnmt.xml", app_metadata[selected_idx]->title_id, nca_ctx[meta_idx].content_id_str); xml_fd = fopen(path, "wb"); if (xml_fd) { fwrite(cnmt_ctx.authoring_tool_xml, 1, cnmt_ctx.authoring_tool_xml_size, xml_fd); fclose(xml_fd); + xml_fd = NULL; } } else { consolePrint("cnmt xml failed\n"); } + if (!nacpInitializeContext(&nacp_ctx, &(nca_ctx[control_idx]))) + { + consolePrint("nacp initialize ctx failed\n"); + goto out2; + } + + consolePrint("nacp initialize ctx succeeded\n"); + + if (nacpGenerateAuthoringToolXml(&nacp_ctx, titleGetVersionInteger(&(user_app_data.app_info->version)), cnmtGetRequiredTitleVersion(&cnmt_ctx))) + { + consolePrint("nacp xml succeeded\n"); + + sprintf(path, "sdmc:/%016lX_xml/%s.nacp", app_metadata[selected_idx]->title_id, nca_ctx[control_idx].content_id_str); + + xml_fd = fopen(path, "wb"); + if (xml_fd) + { + fwrite(nacp_ctx.data, 1, sizeof(_NacpStruct), xml_fd); + fclose(xml_fd); + xml_fd = NULL; + } + + sprintf(path, "sdmc:/%016lX_xml/%s.nacp.xml", app_metadata[selected_idx]->title_id, nca_ctx[control_idx].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:/%016lX_xml/%s.nx.%s.jpg", app_metadata[selected_idx]->title_id, nca_ctx[control_idx].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) { diff --git a/source/cnmt.c b/source/cnmt.c index a737cc5..0ba6273 100644 --- a/source/cnmt.c +++ b/source/cnmt.c @@ -315,10 +315,10 @@ bool cnmtGenerateAuthoringToolXml(ContentMetaContext *cnmt_ctx, NcaContext *nca_ 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) { - u32 required_title_version = cnmtGetVersionInteger((ContentMetaVersion*)(cnmt_ctx->extended_header + sizeof(u64))); + u32 required_title_version = cnmtGetRequiredTitleVersion(cnmt_ctx); const char *required_title_version_str = cnmtGetRequiredTitleVersionString(cnmt_ctx->packaged_header->content_meta_type); - u64 required_title_id = *((u64*)cnmt_ctx->extended_header); + 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, \ diff --git a/source/cnmt.h b/source/cnmt.h index 383fd17..3a66388 100644 --- a/source/cnmt.h +++ b/source/cnmt.h @@ -290,4 +290,18 @@ NX_INLINE u32 cnmtGetVersionInteger(ContentMetaVersion *version) return (version ? *((u32*)version) : 0); } +NX_INLINE u64 cnmtGetRequiredTitleId(ContentMetaContext *cnmt_ctx) +{ + return ((cnmtIsValidContext(cnmt_ctx) && (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)) ? \ + *((u64*)cnmt_ctx->extended_header) : 0); +} + +NX_INLINE u32 cnmtGetRequiredTitleVersion(ContentMetaContext *cnmt_ctx) +{ + return ((cnmtIsValidContext(cnmt_ctx) && (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)) ? \ + cnmtGetVersionInteger((ContentMetaVersion*)(cnmt_ctx->extended_header + sizeof(u64))) : 0); +} + #endif /* __CNMT_H__ */ diff --git a/source/nacp.c b/source/nacp.c index 432a54f..d2df0cb 100644 --- a/source/nacp.c +++ b/source/nacp.c @@ -150,6 +150,12 @@ static const char *g_nacpStartupUserAccountOptionStrings[] = { [NacpStartupUserAccountOption_IsOptional] = "IsOptional" }; +static const char *g_nacpPlayLogQueryCapabilityStrings[] = { + [NacpPlayLogQueryCapability_None] = "None", + [NacpPlayLogQueryCapability_WhiteList] = "WhiteList", + [NacpPlayLogQueryCapability_All] = "All" +}; + static const char *g_nacpRepairStrings[] = { [NacpRepair_SuppressGameCardAccess] = "SuppressGameCardAccess" }; @@ -185,8 +191,9 @@ 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 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); +static bool nacpAddU32FieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, u32 value); +static bool nacpAddU64FieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, u64 value); bool nacpInitializeContext(NacpContext *out, NcaContext *nca_ctx) { @@ -319,7 +326,7 @@ end: return success; } -bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx) +bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 required_system_version) { if (!nacpIsValidContext(nacp_ctx)) { @@ -341,7 +348,6 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx) bool ndcc_sgc_available = false, ndcc_rgc_available = false; NacpNeighborDetectionClientConfiguration *ndcc = &(nacp->neighbor_detection_client_configuration); - bool raocsbd_available = false; NacpRequiredAddOnContentsSetBinaryDescriptor *raocsbd = &(nacp->required_add_on_contents_set_binary_descriptor); bool success = false; @@ -381,46 +387,37 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx) /* StartupUserAccount. */ if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "StartupUserAccount", nacp->startup_user_account, &nacpGetStartupUserAccountString)) 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; + /* UserAccountSwitchLock. */ if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSwitchLock", nacp->user_account_switch_lock, &nacpGetUserAccountSwitchLockString)) goto end; - /* AddOnContentRegistrationType. */ - if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "AddOnContentRegistrationType", nacp->add_on_content_registration_type, &nacpGetAddOnContentRegistrationTypeString)) goto end; - - /* AttributeFlag. */ + /* Attribute. */ if (!nacpAddBitflagFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "Attribute", &(nacp->attribute_flag), sizeof(nacp->attribute_flag), NacpAttribute_Count, &nacpGetAttributeString)) goto end; - /* 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), 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; - /* ParentalControl. */ if (!nacpAddBitflagFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "ParentalControl", &(nacp->parental_control_flag), sizeof(nacp->parental_control_flag), NacpParentalControl_Count, \ &nacpGetParentalControlString)) goto end; + /* SupportedLanguage. */ + if (!nacpAddBitflagFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "SupportedLanguage", &(nacp->supported_language_flag), sizeof(nacp->supported_language_flag), NacpLanguage_Count, \ + &nacpGetLanguageString)) goto end; + /* Screenshot. */ if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "Screenshot", nacp->screenshot, &nacpGetScreenshotString)) goto end; /* VideoCapture. */ if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "VideoCapture", nacp->video_capture, &nacpGetVideoCaptureString)) goto end; - /* DataLossConfirmation. */ - if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DataLossConfirmation", nacp->data_loss_confirmation, &nacpGetDataLossConfirmationString)) goto end; - - /* PlayLogPolicy. */ - if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "PlayLogPolicy", nacp->play_log_policy, &nacpGetPlayLogPolicyString)) goto end; - /* PresenceGroupId. */ if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "PresenceGroupId", nacp->presence_group_id)) goto end; - /* RatingAge. */ + /* DisplayVersion. */ + if (!nacpAddStringFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DisplayVersion", nacp->display_version)) goto end; + + /* Rating. */ for(i = 0, count = 0; i < NacpRatingAgeOrganization_Count; i++) { u8 age = *((u8*)&(nacp->rating_age) + i); @@ -439,11 +436,11 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx) if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " \n")) goto end; - /* DisplayVersion. */ - if (!nacpAddStringFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DisplayVersion", nacp->display_version)) goto end; + /* DataLossConfirmation. */ + if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "DataLossConfirmation", nacp->data_loss_confirmation, &nacpGetDataLossConfirmationString)) goto end; - /* AddOnContentBaseId. */ - if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "AddOnContentBaseId", nacp->add_on_content_base_id)) goto end; + /* PlayLogPolicy. */ + if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "PlayLogPolicy", nacp->play_log_policy, &nacpGetPlayLogPolicyString)) goto end; /* SaveDataOwnerId. */ if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "SaveDataOwnerId", nacp->save_data_owner_id)) goto end; @@ -466,6 +463,23 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx) /* ApplicationErrorCodeCategory. */ if (!nacpAddStringFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "ApplicationErrorCodeCategory", nacp->application_error_code_category)) goto end; + /* AddOnContentBaseId. */ + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "AddOnContentBaseId", nacp->add_on_content_base_id)) goto end; + + /* Version. */ + if (!nacpAddU32FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "Version", version)) goto end; + + /* ReleaseVersion and PrivateVersion. Unused but kept anyway. */ + if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ + " \n" \ + " \n")) goto end; + + /* LogoType. */ + if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "LogoType", nacp->logo_type, &nacpGetLogoTypeString)) goto end; + + /* RequiredSystemVersion. */ + if (!nacpAddU32FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "RequiredSystemVersion", required_system_version)) goto end; + /* LocalCommunicationId. */ for(i = 0, count = 0; i < 0x8; i++) { @@ -476,23 +490,42 @@ 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; + /* 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. Only the first half from the hash is used. */ + 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" \ + " \n" \ + " \n" \ + " \n" \ + " %s\n" \ + " \n", \ + nacpGetLanguageString(icon_ctx->language), \ + icon_hash_str)) goto end; + + count++; + } - /* RuntimeParameterDelivery. */ - if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "RuntimeParameterDelivery", nacp->runtime_parameter_delivery, &nacpGetRuntimeParameterDeliveryString)) goto end; + if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " \n")) 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; + /* HtmlDocumentPath, LegalInformationFilePath and AccessibleUrlsFilePath. Unused but kept anyway. */ + if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ + " \n" \ + " \n" \ + " \n")) goto end; /* SeedForPseudoDeviceId. */ if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "SeedForPseudoDeviceId", nacp->seed_for_pseudo_device_id)) goto end; @@ -500,9 +533,8 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx) /* 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; + /* AddOnContentRegistrationType. */ + if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "AddOnContentRegistrationType", nacp->add_on_content_registration_type, &nacpGetAddOnContentRegistrationTypeString)) goto end; /* UserAccountSaveDataSizeMax. */ if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "UserAccountSaveDataSizeMax", nacp->user_account_save_data_size_max)) goto end; @@ -531,6 +563,15 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx) /* CacheStorageIndexMax. */ if (!nacpAddU16FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CacheStorageIndexMax", nacp->cache_storage_index_max, true)) goto end; + /* Hdcp. */ + if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "Hdcp", nacp->hdcp, &nacpGetHdcpString)) goto end; + + /* CrashReport. */ + if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "CrashReport", nacp->crash_report, &nacpGetCrashReportString)) goto end; + + /* RuntimeAddOnContentInstall. */ + if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "RuntimeAddOnContentInstall", nacp->runtime_add_on_content_install, &nacpGetRuntimeAddOnContentInstallString)) goto end; + /* PlayLogQueryableApplicationId. */ for(i = 0, count = 0; i < 0x10; i++) { @@ -541,6 +582,9 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx) if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " \n")) goto end; + /* PlayLogQueryCapability. */ + if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "PlayLogQueryCapability", nacp->play_log_query_capability, &nacpGetPlayLogQueryCapabilityString)) goto end; + /* Repair. */ if (!nacpAddBitflagFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "Repair", &(nacp->repair_flag), sizeof(nacp->repair_flag), NacpRepair_Count, &nacpGetRepairString)) goto end; @@ -564,27 +608,27 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx) { if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " \n")) goto end; - /* SendDataConfiguration. */ + /* SendGroupConfiguration. */ utilsGenerateHexStringFromData(key_str, sizeof(key_str), ndcc->send_group_configuration.key, sizeof(ndcc->send_group_configuration.key)); if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - " \n" \ - " 0x%016lx\n" \ + " \n" \ + " 0x%016lx\n" \ " %s\n" \ - " \n", \ + " \n", \ ndcc->send_group_configuration.group_id, key_str)) goto end; - /* ReceivableDataConfiguration. */ + /* ReceivableGroupConfiguration. */ for(i = 0; i < 0x10; i++) { utilsGenerateHexStringFromData(key_str, sizeof(key_str), ndcc->receivable_group_configurations[i].key, sizeof(ndcc->receivable_group_configurations[i].key)); if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - " \n" \ - " 0x%016lx\n" \ + " \n" \ + " 0x%016lx\n" \ " %s\n" \ - " \n", \ + " \n", \ ndcc->receivable_group_configurations[i].group_id, key_str)) goto end; } @@ -603,32 +647,21 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx) nacpGetJitConfigurationFlagString(nacp->jit_configuration.jit_configuration_flag), nacp->jit_configuration.memory_size)) goto end; - /* RequiredAddOnContentsSetBinaryDescriptor. */ - for(i = 0; i < 0x20; i++) + /* RequiredAddOnContentsSet. */ + for(i = 0, count = 0; i < 0x20; i++) { - if (!raocsbd->descriptors[i].NacpDescriptors_ContinueSet) continue; - if ((raocsbd_available = (raocsbd->descriptors[i].NacpDescriptors_Index != 0))) break; + if (!raocsbd->descriptors[i].NacpDescriptors_Index || !raocsbd->descriptors[i].NacpDescriptors_ContinueSet) continue; + + if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ + " \n" \ + " %u\n" \ + " \n", + raocsbd->descriptors[i].NacpDescriptors_Index)) goto end; + + count++; } - if (raocsbd_available) - { - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " \n")) goto end; - - for(i = 0; i < 0x20; i++) - { - if (!raocsbd->descriptors[i].NacpDescriptors_Index || !raocsbd->descriptors[i].NacpDescriptors_ContinueSet) continue; - - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \ - " \n" \ - " %u\n" - " \n", - raocsbd->descriptors[i].NacpDescriptors_Index)) goto end; - } - - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " \n")) goto end; - } else { - if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " \n")) goto end; - } + if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " \n")) goto end; /* PlayReportPermission. */ if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "PlayReportPermission", nacp->play_report_permission, &nacpGetPlayReportPermissionString)) goto end; @@ -639,30 +672,33 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx) /* 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++) + /* AccessibleLaunchRequiredVersion. */ + for(i = 0, count = 0; i < 0x8; i++) { - NacpIconContext *icon_ctx = &(nacp_ctx->icon_ctx[i]); + if (!nacp->accessible_launch_required_version.application_id[i]) continue; - /* Calculate icon hash. */ - sha256CalculateHash(icon_hash, icon_ctx->icon_data, icon_ctx->icon_size); - - /* Generate icon hash string. Only the first half from the hash is used. */ - 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; + " \n" \ + " 0x%016lx\n" \ + " \n", + nacp->accessible_launch_required_version.application_id[i])) goto end; count++; } - if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " \n")) goto end; + if (!count && !utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " \n")) goto end; + + /* History. Unused but kept anyway. */ + if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " \n")) goto end; + + /* RuntimeParameterDelivery. */ + if (!nacpAddEnumFieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "RuntimeParameterDelivery", nacp->runtime_parameter_delivery, &nacpGetRuntimeParameterDeliveryString)) goto end; + + /* ApplicationId. */ + if (!nacpAddU64FieldToAuthoringToolXml(&xml_buf, &xml_buf_size, "ApplicationId", nacp_ctx->nca_ctx->header.program_id)) goto end; + + /* FilterDescriptionFilePath. Unused but kept anyway. */ + if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, " \n")) goto end; if (!(success = utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, ""))) goto end; @@ -770,6 +806,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 *nacpGetPlayLogQueryCapabilityString(u8 play_log_query_capability) +{ + return (play_log_query_capability < NacpPlayLogQueryCapability_Count ? g_nacpPlayLogQueryCapabilityStrings[play_log_query_capability] : g_unknownString); +} + const char *nacpGetRepairString(u8 repair) { return (repair < NacpRepair_Count ? g_nacpRepairStrings[repair] : g_unknownString); @@ -846,8 +887,6 @@ static bool nacpAddBitflagFieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_s return false; } - if (!utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <%s>", tag_name)) goto end; - for(i = 0; i < flag_width; i++) { if (flag_u8[i]) @@ -862,33 +901,22 @@ 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 (count && !utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, ",")) goto end; - if (!utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, "%s", str_func(i))) goto end; + if (!utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <%s>%s\n", tag_name, str_func(i), tag_name)) goto end; count++; } - if (!count && !utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, "%s", g_unknownString)) goto end; - } else { - if (!utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, "None")) goto end; + /* Edge case for new, unsupported flags. */ + if (!count) empty_flag = true; } - success = utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, "\n", tag_name); + if (empty_flag && !utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <%s />\n", tag_name)) goto end; + + success = true; end: return success; } -static bool nacpAddU64FieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, u64 value) -{ - if (!xml_buf || !xml_buf_size || !tag_name || !strlen(tag_name)) - { - 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)) @@ -900,3 +928,25 @@ static bool nacpAddU16FieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, 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)); } + +static bool nacpAddU32FieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size, const char *tag_name, u32 value) +{ + if (!xml_buf || !xml_buf_size || !tag_name || !strlen(tag_name)) + { + LOGFILE("Invalid parameters!"); + return false; + } + + return utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <%s>%u\n", tag_name, value, tag_name); +} + +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)) + { + LOGFILE("Invalid parameters!"); + return false; + } + + return utilsAppendFormattedStringToBuffer(xml_buf, xml_buf_size, " <%s>0x%016lx\n", tag_name, value, tag_name); +} diff --git a/source/nacp.h b/source/nacp.h index caaa4d2..b7bc0d5 100644 --- a/source/nacp.h +++ b/source/nacp.h @@ -277,7 +277,7 @@ typedef struct { typedef struct { u16 NacpDescriptors_Index : 15; - u16 NacpDescriptors_ContinueSet : 1; ///< Called "flag" by Nintendo. + u16 NacpDescriptors_ContinueSet : 1; ///< Called "flag" by Nintendo, which isn't really great... } NacpDescriptors; typedef struct { @@ -302,6 +302,10 @@ typedef enum { NacpCrashScreenshotForDev_Count = 2 ///< Not a real value. } NacpCrashScreenshotForDev; +typedef struct { + u64 application_id[8]; +} NacpAccessibleLaunchRequiredVersion; + typedef struct { NacpTitle title[0x10]; char isbn[0x25]; @@ -360,7 +364,9 @@ typedef struct { u8 play_report_permission; ///< NacpPlayReportPermission. u8 crash_screenshot_for_prod; ///< NacpCrashScreenshotForProd. u8 crash_screenshot_for_dev; ///< NacpCrashScreenshotForDev. - u8 reserved_5[0xBFD]; + u8 reserved_5[0x5]; + NacpAccessibleLaunchRequiredVersion accessible_launch_required_version; + u8 reserved_6[0xBB8]; } _NacpStruct; typedef struct { @@ -388,9 +394,9 @@ typedef struct { /// Initializes a NacpContext using a previously initialized NcaContext (which must belong to a Control NCA). bool nacpInitializeContext(NacpContext *out, NcaContext *nca_ctx); -/// Generates an AuthoringTool-like XML using information from a previously initialized NacpContext. +/// Generates an AuthoringTool-like XML using information from a previously initialized NacpContext, as well as the Application/Patch version and the required system version. /// If the function succeeds, XML data and size will get saved to the 'authoring_tool_xml' and 'authoring_tool_xml_size' members from the NacpContext. -bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx); +bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 required_system_version); /// These functions return pointers to string representations of the input value. /// If the provided value is invalid, "Unknown" is returned. @@ -412,6 +418,7 @@ 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 *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); diff --git a/source/romfs.c b/source/romfs.c index c103c78..c0f9650 100644 --- a/source/romfs.c +++ b/source/romfs.c @@ -357,7 +357,13 @@ RomFileSystemFileEntry *romfsGetFileEntryByPath(RomFileSystemContext *ctx, const } /* Retrieve file entry. */ - if (!(file_entry = romfsGetChildFileEntryByName(ctx, dir_entry, filename))) LOGFILE("Failed to retrieve file entry by name for \"%s\"! (\"%s\").", filename, path); + if (!(file_entry = romfsGetChildFileEntryByName(ctx, dir_entry, filename))) + { + /* Only log error if we're not dealing with NACP icons. */ + int res = strncmp("/icon_", path, 6); + if (res != 0 || (res == 0 && ((NcaContext*)ctx->nca_fs_ctx->nca_ctx)->content_type != NcmContentType_Control)) + LOGFILE("Failed to retrieve file entry by name for \"%s\"! (\"%s\").", filename, path); + } end: if (path_dup) free(path_dup); diff --git a/source/title.c b/source/title.c index 3a94678..605e901 100644 --- a/source/title.c +++ b/source/title.c @@ -1357,8 +1357,9 @@ static bool titleRetrieveContentMetaKeysFromDatabase(u8 storage_id) /* Fill information. */ cur_title_info->storage_id = storage_id; - memcpy(&(cur_title_info->dot_version), &(meta_keys[i].version), sizeof(u32)); memcpy(&(cur_title_info->meta_key), &(meta_keys[i]), sizeof(NcmContentMetaKey)); + memcpy(&(cur_title_info->version), &(meta_keys[i].version), sizeof(u32)); + if (cur_title_info->meta_key.type <= NcmContentMetaType_Application) cur_title_info->app_metadata = titleFindApplicationMetadataByTitleId(meta_keys[i].id); /* Retrieve content infos. */ diff --git a/source/title.h b/source/title.h index 61fb48e..d57afd6 100644 --- a/source/title.h +++ b/source/title.h @@ -52,8 +52,8 @@ typedef struct { /// Retrieved using ncm databases. typedef struct _TitleInfo { u8 storage_id; ///< NcmStorageId. - TitleVersion dot_version; ///< Holds the same value from meta_key.version. NcmContentMetaKey meta_key; ///< Used with ncm calls. + TitleVersion version; ///< Holds the same value from meta_key.version. u32 content_count; ///< Content info count. NcmContentInfo *content_infos; ///< Content info entries from this title. u64 title_size; ///< Total title size.