1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-11-13 22:16:45 +00:00
nxdumptool/include/core/title.h

317 lines
14 KiB
C
Raw Normal View History

2020-07-25 06:56:35 +01:00
/*
* title.h
*
2022-03-17 12:58:40 +00:00
* Copyright (c) 2020-2022, DarkMatterCore <pabloacurielz@gmail.com>.
2020-07-25 06:56:35 +01:00
*
* 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 of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
2020-07-25 06:56:35 +01:00
*
* nxdumptool is distributed in the hope that 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.
2020-07-25 06:56:35 +01:00
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
2020-07-25 06:56:35 +01:00
*/
#pragma once
#ifndef __TITLE_H__
#define __TITLE_H__
2021-03-23 14:06:52 +00:00
#ifdef __cplusplus
extern "C" {
#endif
2020-07-28 07:20:19 +01:00
#define TITLE_PATCH_TYPE_VALUE (u64)0x800
2020-07-25 06:56:35 +01:00
2020-07-28 07:20:19 +01:00
#define TITLE_ADDONCONTENT_TYPE_VALUE (u64)0x1000
#define TITLE_ADDONCONTENT_CONVERSION_MASK (u64)0xFFFFFFFFFFFFF000
#define TITLE_ADDONCONTENT_MAX_ENTRIES 2000
2020-07-28 07:20:19 +01:00
#define TITLE_DELTA_TYPE_VALUE (u64)0xC00
/// Generated using ns application records and/or ncm content meta keys.
/// Used by the UI to display title lists.
2020-07-25 06:56:35 +01:00
typedef struct {
u64 title_id; ///< Title ID from the application / system title this data belongs to.
NacpLanguageEntry lang_entry; ///< UTF-8 strings in the console language.
2020-07-25 06:56:35 +01:00
u32 icon_size; ///< JPEG icon size.
u8 *icon; ///< JPEG icon data.
2020-07-25 06:56:35 +01:00
} TitleApplicationMetadata;
/// Generated using ncm calls.
/// User applications: the previous/next pointers reference other user applications with the same ID.
/// Patches: the previous/next pointers reference other patches with the same ID.
/// Add-on contents: the previous/next pointers reference sibling add-on contents.
/// Add-on content patches: the previous/next pointers reference other patches with the same ID and/or other patches for sibling add-on contents.
typedef struct _TitleInfo {
u8 storage_id; ///< NcmStorageId.
NcmContentMetaKey meta_key; ///< Used with ncm calls.
Version 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 size; ///< Total title size.
char size_str[32]; ///< Total title size string.
TitleApplicationMetadata *app_metadata; ///< User application metadata.
struct _TitleInfo *previous, *next; ///< Linked lists.
2020-07-25 06:56:35 +01:00
} TitleInfo;
/// Used to deal with user applications stored in the eMMC, SD card and/or gamecard.
/// The previous and next pointers from the TitleInfo elements are used to traverse through multiple user applications, patches, add-on contents and or add-on content patches.
typedef struct {
TitleInfo *app_info; ///< Pointer to a TitleInfo element for the first detected user application entry matching the provided application ID.
TitleInfo *patch_info; ///< Pointer to a TitleInfo element for the first detected patch entry matching the provided application ID.
TitleInfo *aoc_info; ///< Pointer to a TitleInfo element for the first detected add-on content entry matching the provided application ID.
TitleInfo *aoc_patch_info; ///< Pointer to a TitleInfo element for the first detected add-on content patch entry matching the provided application ID.
} TitleUserApplicationData;
typedef enum {
TitleNamingConvention_Full = 0, ///< Individual titles: "{Name} [{Id}][v{Version}][{Type}]".
///< Gamecards: "{Name1} [{Id1}][v{Version1}] + ... + {NameN} [{IdN}][v{VersionN}]".
TitleNamingConvention_IdAndVersionOnly = 1, ///< Individual titles: "{Id}_v{Version}_{Type}".
///< Gamecards: "{TitleId1}_v{TitleVersion1}_{TitleType1} + ... + {TitleIdN}_v{TitleVersionN}_{TitleTypeN}".
TitleNamingConvention_Count = 2
} TitleNamingConvention;
typedef enum {
TitleFileNameIllegalCharReplaceType_None = 0,
TitleFileNameIllegalCharReplaceType_IllegalFsChars = 1,
TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly = 2
} TitleFileNameIllegalCharReplaceType;
/// Initializes the title interface.
bool titleInitialize(void);
2020-07-25 06:56:35 +01:00
/// Closes the title interface.
void titleExit(void);
2020-07-25 06:56:35 +01:00
/// Returns a pointer to a ncm database handle using a NcmStorageId value.
NcmContentMetaDatabase *titleGetNcmDatabaseByStorageId(u8 storage_id);
/// Returns a pointer to a ncm storage handle using a NcmStorageId value.
NcmContentStorage *titleGetNcmStorageByStorageId(u8 storage_id);
/// Returns a pointer to a dynamically allocated array of pointers to TitleApplicationMetadata entries, as well as their count. Returns NULL if an error occurs.
/// If 'is_system' is true, TitleApplicationMetadata entries from available system titles (NcmStorageId_BuiltInSystem) will be returned.
/// Otherwise, TitleApplicationMetadata entries from user applications with available content data (NcmStorageId_BuiltInUser, NcmStorageId_SdCard, NcmStorageId_GameCard) will be returned.
/// The allocated buffer must be freed by the calling function using free().
TitleApplicationMetadata **titleGetApplicationMetadataEntries(bool is_system, u32 *out_count);
/// Returns a pointer to a dynamically allocated array of pointers to TitleApplicationMetadata entries with matching gamecard user titles, as well as their count. Returns NULL if an error occurs.
/// The allocated buffer must be freed by the calling function using free().
TitleApplicationMetadata **titleGetGameCardApplicationMetadataEntries(u32 *out_count);
/// Returns a pointer to a dynamically allocated TitleInfo element with a matching storage ID and title ID. Returns NULL if an error occurs.
/// If NcmStorageId_Any is used, the first entry with a matching title ID is returned.
/// Use titleFreeTitleInfo() to free the returned data.
TitleInfo *titleGetInfoFromStorageByTitleId(u8 storage_id, u64 title_id);
2020-07-25 06:56:35 +01:00
/// Frees a dynamically allocated TitleInfo element.
void titleFreeTitleInfo(TitleInfo **info);
/// Populates a TitleUserApplicationData element with dynamically allocated data using a user application ID.
/// Use titleFreeUserApplicationData() to free the populated data.
bool titleGetUserApplicationData(u64 app_id, TitleUserApplicationData *out);
/// Frees data populated by titleGetUserApplicationData().
void titleFreeUserApplicationData(TitleUserApplicationData *user_app_data);
/// Returns true if orphan titles are available.
/// Orphan titles are patches or add-on contents with no NsApplicationControlData available for their parent user application ID.
bool titleAreOrphanTitlesAvailable(void);
/// Returns a pointer to a dynamically allocated array of orphan TitleInfo entries, as well as their count. Returns NULL if an error occurs.
/// Use titleFreeOrphanTitles() to free the returned data.
TitleInfo **titleGetOrphanTitles(u32 *out_count);
/// Frees orphan title info data returned by titleGetInfoFromOrphanTitles().
void titleFreeOrphanTitles(TitleInfo ***orphan_info);
/// Checks if a gamecard status update has been detected by the background gamecard title info thread (e.g. after a new gamecard has been inserted, of after the current one has been taken out).
/// If this function returns true and functions such as titleGetInfoFromStorageByTitleId(), titleGetUserApplicationData() or titleGetInfoFromOrphanTitles() have been previously called:
/// 1. Their returned data must be freed.
/// 2. They must be called again.
bool titleIsGameCardInfoUpdated(void);
/// Returns a pointer to a dynamically allocated buffer that holds a filename string suitable for output title dumps. Returns NULL if an error occurs.
char *titleGenerateFileName(TitleInfo *title_info, u8 naming_convention, u8 illegal_char_replace_type);
/// Returns a pointer to a dynamically allocated buffer that holds a filename string suitable for output gamecard dumps. Returns NULL if an error occurs.
/// A valid gamecard must be inserted, and title info must have been loaded from it accordingly.
char *titleGenerateGameCardFileName(u8 naming_convention, u8 illegal_char_replace_type);
/// Returns a pointer to a string holding a user-friendly name for the provided NcmStorageId value. Returns NULL if the provided value is invalid.
const char *titleGetNcmStorageIdName(u8 storage_id);
/// Returns a pointer to a string holding the name of the provided NcmContentType value. Returns NULL if the provided value is invalid.
const char *titleGetNcmContentTypeName(u8 content_type);
/// Returns a pointer to a string holding the name of the provided NcmContentMetaType value. Returns NULL if the provided value is invalid.
const char *titleGetNcmContentMetaTypeName(u8 content_meta_type);
2020-07-25 06:56:35 +01:00
/// Miscellaneous functions.
NX_INLINE u64 titleGetPatchIdByApplicationId(u64 app_id)
{
2020-07-28 07:20:19 +01:00
return (app_id + TITLE_PATCH_TYPE_VALUE);
2020-07-25 06:56:35 +01:00
}
NX_INLINE u64 titleGetApplicationIdByPatchId(u64 patch_id)
{
2020-07-28 07:20:19 +01:00
return (patch_id - TITLE_PATCH_TYPE_VALUE);
2020-07-25 06:56:35 +01:00
}
NX_INLINE bool titleCheckIfPatchIdBelongsToApplicationId(u64 app_id, u64 patch_id)
{
return (patch_id == titleGetPatchIdByApplicationId(app_id));
}
NX_INLINE u64 titleGetAddOnContentBaseIdByApplicationId(u64 app_id)
{
2020-07-28 07:20:19 +01:00
return ((app_id & TITLE_ADDONCONTENT_CONVERSION_MASK) + TITLE_ADDONCONTENT_TYPE_VALUE);
}
Preliminar 15.x support. This commit uses my yet unmerged libnx PR to update ncm_types.h. PoC code hasn't been updated yet, so proper support for DLC updates will arrive at a later time. Note to self: implement a way to provide access to loaded DataPatch TitleInfo entries (linked list hell). * bktr: renamed bktrBucketInitializeSubStorageReadParams to bktrInitializeSubStorageReadParams to avoid redundancy, added debug code to dump BucketInfo and BucketTree tables if BucketTree storage initialization fails. * cnmt: updated ContentMetaAddOnContentMetaExtendedHeader struct to its 15.x equivalent, added ContentMetaLegacyAddOnContentMetaExtendedHeader struct, added ContentMetaDataPatchMetaExtendedHeader struct, updated the cnmtGetRequiredTitleId and cnmtGetRequiredTitleVersion functions to support DataPatch titles, updated cnmtInitializeContext to support both the new AddOnContent extended header and DataPatch titles, added debug code to dump the whole CNMT if context initialization fails, updated cnmtGenerateAuthoringToolXml to support DataPatch titles. * keys: updated block hashes to match 15.x keyset, use case-insensitive comparison while looking for entry names in keysReadKeysFromFile, make sure the eticket_rsa_kek is non-zero before proceeding in keysGetDecryptedEticketRsaDeviceKey. * nca: updated NcaKeyGeneration enum, added reminder about updating NcaSignatureKeyGeneration if necessary, replaced ncaFsSectionCheckHashRegionAccess with ncaFsSectionCheckPlaintextHashRegionAccess, removed all extents checks on Patch RomFS and sparse sections, updated ncaGetFsSectionTypeName to reflect if a FS section holds a sparse layer or not. * nca_storage: updated ncaStorageInitializeContext to avoid initializing a compressed storage if a sparse layer is also used (fixes issues with Them's Fightin' Herds), updated ncaStorageSetPatchOriginalSubStorage to enforce the presence of a compressed storage in a patch if the base FS holds a compressed storage. * npdm: added reminder about updating NpdmSignatureKeyGeneration if necessary, updated NpdmFsAccessControlFlags enum, updated NpdmAccessibility enum, updated NpdmSystemCallId enum, fixed typos. * title: updated all relevant functions that deal with NcmContentMetaType values to also handle DataPatch titles, added functions to handle DataPatchId values, removed titleConvertNcmContentSizeToU64 and titleConvertU64ToNcmContentSize functions in favor of ncmContentInfoSizeToU64 and ncmU64ToContentInfoSize from my unmerged libnx PR, updated internal arrays to match 15.x changes, renamed titleOrphanTitleInfoSortFunction to titleInfoEntrySortFunction and updated it to also sort entries by version and storage ID, updated titleGenerateTitleInfoEntriesForTitleStorage to sort TitleInfo entries, simplified titleDuplicateTitleInfo a bit by using macros.
2022-10-23 15:44:47 +01:00
NX_INLINE u64 titleGetAddOnContentIdByApplicationIdAndIndex(u64 app_id, u16 idx)
{
return (titleGetAddOnContentBaseIdByApplicationId(app_id) + idx + 1);
}
NX_INLINE u64 titleGetApplicationIdByAddOnContentId(u64 aoc_id)
{
2020-07-28 07:20:19 +01:00
return ((aoc_id - TITLE_ADDONCONTENT_TYPE_VALUE) & TITLE_ADDONCONTENT_CONVERSION_MASK);
}
NX_INLINE u64 titleGetAddOnContentMaxIdByBaseId(u64 aoc_base_id)
{
return (aoc_base_id + TITLE_ADDONCONTENT_MAX_ENTRIES + 1);
}
NX_INLINE bool titleIsAddOnContentIdValid(u64 aoc_id, u64 aoc_base_id, u64 aoc_max_id)
{
return (aoc_id > aoc_base_id && aoc_id < aoc_max_id);
2020-07-25 06:56:35 +01:00
}
NX_INLINE bool titleCheckIfAddOnContentIdBelongsToApplicationId(u64 app_id, u64 aoc_id)
{
u64 aoc_base_id = titleGetAddOnContentBaseIdByApplicationId(app_id);
u64 aoc_max_id = titleGetAddOnContentMaxIdByBaseId(aoc_base_id);
return titleIsAddOnContentIdValid(aoc_id, aoc_base_id, aoc_max_id);
}
NX_INLINE bool titleCheckIfAddOnContentIdsAreSiblings(u64 aoc_id_1, u64 aoc_id_2)
{
u64 app_id_1 = titleGetApplicationIdByAddOnContentId(aoc_id_1);
u64 app_id_2 = titleGetApplicationIdByAddOnContentId(aoc_id_2);
return (app_id_1 == app_id_2 && titleCheckIfAddOnContentIdBelongsToApplicationId(app_id_1, aoc_id_1) && titleCheckIfAddOnContentIdBelongsToApplicationId(app_id_2, aoc_id_2));
2020-07-25 06:56:35 +01:00
}
NX_INLINE u64 titleGetDeltaIdByApplicationId(u64 app_id)
{
return (app_id + TITLE_DELTA_TYPE_VALUE);
}
NX_INLINE u64 titleGetApplicationIdByDeltaId(u64 delta_id)
{
return (delta_id - TITLE_DELTA_TYPE_VALUE);
}
NX_INLINE bool titleCheckIfDeltaIdBelongsToApplicationId(u64 app_id, u64 delta_id)
{
return (delta_id == titleGetDeltaIdByApplicationId(app_id));
}
Preliminar 15.x support. This commit uses my yet unmerged libnx PR to update ncm_types.h. PoC code hasn't been updated yet, so proper support for DLC updates will arrive at a later time. Note to self: implement a way to provide access to loaded DataPatch TitleInfo entries (linked list hell). * bktr: renamed bktrBucketInitializeSubStorageReadParams to bktrInitializeSubStorageReadParams to avoid redundancy, added debug code to dump BucketInfo and BucketTree tables if BucketTree storage initialization fails. * cnmt: updated ContentMetaAddOnContentMetaExtendedHeader struct to its 15.x equivalent, added ContentMetaLegacyAddOnContentMetaExtendedHeader struct, added ContentMetaDataPatchMetaExtendedHeader struct, updated the cnmtGetRequiredTitleId and cnmtGetRequiredTitleVersion functions to support DataPatch titles, updated cnmtInitializeContext to support both the new AddOnContent extended header and DataPatch titles, added debug code to dump the whole CNMT if context initialization fails, updated cnmtGenerateAuthoringToolXml to support DataPatch titles. * keys: updated block hashes to match 15.x keyset, use case-insensitive comparison while looking for entry names in keysReadKeysFromFile, make sure the eticket_rsa_kek is non-zero before proceeding in keysGetDecryptedEticketRsaDeviceKey. * nca: updated NcaKeyGeneration enum, added reminder about updating NcaSignatureKeyGeneration if necessary, replaced ncaFsSectionCheckHashRegionAccess with ncaFsSectionCheckPlaintextHashRegionAccess, removed all extents checks on Patch RomFS and sparse sections, updated ncaGetFsSectionTypeName to reflect if a FS section holds a sparse layer or not. * nca_storage: updated ncaStorageInitializeContext to avoid initializing a compressed storage if a sparse layer is also used (fixes issues with Them's Fightin' Herds), updated ncaStorageSetPatchOriginalSubStorage to enforce the presence of a compressed storage in a patch if the base FS holds a compressed storage. * npdm: added reminder about updating NpdmSignatureKeyGeneration if necessary, updated NpdmFsAccessControlFlags enum, updated NpdmAccessibility enum, updated NpdmSystemCallId enum, fixed typos. * title: updated all relevant functions that deal with NcmContentMetaType values to also handle DataPatch titles, added functions to handle DataPatchId values, removed titleConvertNcmContentSizeToU64 and titleConvertU64ToNcmContentSize functions in favor of ncmContentInfoSizeToU64 and ncmU64ToContentInfoSize from my unmerged libnx PR, updated internal arrays to match 15.x changes, renamed titleOrphanTitleInfoSortFunction to titleInfoEntrySortFunction and updated it to also sort entries by version and storage ID, updated titleGenerateTitleInfoEntriesForTitleStorage to sort TitleInfo entries, simplified titleDuplicateTitleInfo a bit by using macros.
2022-10-23 15:44:47 +01:00
NX_INLINE u64 titleGetDataPatchIdByAddOnContentId(u64 aoc_id)
{
return (aoc_id + TITLE_PATCH_TYPE_VALUE);
}
NX_INLINE u64 titleGetAddOnContentIdByDataPatchId(u64 data_patch_id)
{
return (data_patch_id - TITLE_PATCH_TYPE_VALUE);
}
NX_INLINE bool titleCheckIfDataPatchIdBelongsToAddOnContentId(u64 aoc_id, u64 data_patch_id)
{
return (data_patch_id == titleGetDataPatchIdByAddOnContentId(aoc_id));
}
NX_INLINE u64 titleGetApplicationIdByDataPatchId(u64 data_patch_id)
{
return titleGetApplicationIdByAddOnContentId(titleGetAddOnContentIdByDataPatchId(data_patch_id));
}
NX_INLINE bool titleCheckIfDataPatchIdBelongsToApplicationId(u64 app_id, u64 data_patch_id)
{
return titleCheckIfAddOnContentIdBelongsToApplicationId(app_id, titleGetAddOnContentIdByDataPatchId(data_patch_id));
}
NX_INLINE bool titleCheckIfDataPatchIdsAreSiblings(u64 data_patch_id_1, u64 data_patch_id_2)
{
u64 app_id_1 = titleGetApplicationIdByDataPatchId(data_patch_id_1);
u64 app_id_2 = titleGetApplicationIdByDataPatchId(data_patch_id_2);
return (app_id_1 == app_id_2 && titleCheckIfDataPatchIdBelongsToApplicationId(app_id_1, data_patch_id_1) && titleCheckIfDataPatchIdBelongsToApplicationId(app_id_2, data_patch_id_2));
}
NX_INLINE u32 titleGetContentCountByType(TitleInfo *info, u8 content_type)
{
if (!info || !info->content_count || !info->content_infos || content_type > NcmContentType_DeltaFragment) return 0;
u32 cnt = 0;
for(u32 i = 0; i < info->content_count; i++)
{
if (info->content_infos[i].content_type == content_type) cnt++;
}
return cnt;
}
NX_INLINE NcmContentInfo *titleGetContentInfoByTypeAndIdOffset(TitleInfo *info, u8 content_type, u8 id_offset)
{
if (!info || !info->content_count || !info->content_infos || content_type > NcmContentType_DeltaFragment) return NULL;
for(u32 i = 0; i < info->content_count; i++)
{
2020-10-14 19:58:33 +01:00
NcmContentInfo *cur_content_info = &(info->content_infos[i]);
if (cur_content_info->content_type == content_type && cur_content_info->id_offset == id_offset) return cur_content_info;
}
return NULL;
}
NX_INLINE u32 titleGetCountFromInfoBlock(TitleInfo *title_info)
{
if (!title_info) return 0;
u32 count = 1;
TitleInfo *cur_info = title_info->previous;
while(cur_info)
{
count++;
cur_info = cur_info->previous;
}
cur_info = title_info->next;
while(cur_info)
{
count++;
cur_info = cur_info->next;
}
return count;
}
2021-03-23 14:06:52 +00:00
#ifdef __cplusplus
}
#endif
#endif /* __TITLE_H__ */