mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-12-27 19:06:01 +00:00
title: retrieve display version string from patches while generating output filenames.
This commit is contained in:
parent
5bb5f0c858
commit
986b19868f
7 changed files with 113 additions and 36 deletions
|
@ -200,13 +200,14 @@ typedef enum {
|
|||
} GameCardStatus;
|
||||
|
||||
typedef enum {
|
||||
GameCardHashFileSystemPartitionType_Root = 0,
|
||||
GameCardHashFileSystemPartitionType_Update = 1,
|
||||
GameCardHashFileSystemPartitionType_Logo = 2, ///< Only available in GameCardFwVersion_Since400NUP or greater gamecards.
|
||||
GameCardHashFileSystemPartitionType_Normal = 3,
|
||||
GameCardHashFileSystemPartitionType_Secure = 4,
|
||||
GameCardHashFileSystemPartitionType_Boot = 5,
|
||||
GameCardHashFileSystemPartitionType_Count = 6 ///< Not a real value.
|
||||
GameCardHashFileSystemPartitionType_None = 0, ///< Not a real value.
|
||||
GameCardHashFileSystemPartitionType_Root = 1,
|
||||
GameCardHashFileSystemPartitionType_Update = 2,
|
||||
GameCardHashFileSystemPartitionType_Logo = 3, ///< Only available in GameCardFwVersion_Since400NUP or greater gamecards.
|
||||
GameCardHashFileSystemPartitionType_Normal = 4,
|
||||
GameCardHashFileSystemPartitionType_Secure = 5,
|
||||
GameCardHashFileSystemPartitionType_Boot = 6,
|
||||
GameCardHashFileSystemPartitionType_Count = 7 ///< Not a real value.
|
||||
} GameCardHashFileSystemPartitionType;
|
||||
|
||||
/// Initializes data needed to access raw gamecard storage areas.
|
||||
|
|
|
@ -130,7 +130,7 @@ void titleFreeOrphanTitles(TitleInfo ***orphan_info);
|
|||
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(const TitleInfo *title_info, u8 name_convention, u8 illegal_char_replace_type);
|
||||
char *titleGenerateFileName(TitleInfo *title_info, u8 name_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.
|
||||
|
|
|
@ -97,6 +97,7 @@ bool bfttfInitialize(void)
|
|||
}
|
||||
|
||||
/* Initialize NCA context. */
|
||||
/* NCA contexts don't need to be freed beforehand. */
|
||||
bool nca_ctx_init = ncaInitializeContext(nca_ctx, NcmStorageId_BuiltInSystem, 0, titleGetContentInfoByTypeAndIdOffset(title_info, NcmContentType_Data, 0), NULL);
|
||||
|
||||
/* Free title info. */
|
||||
|
|
|
@ -285,7 +285,7 @@ bool cnmtUpdateContentInfo(ContentMetaContext *cnmt_ctx, NcaContext *nca_ctx)
|
|||
/* Jackpot. Copy content ID and hash to our raw CNMT. */
|
||||
memcpy(packaged_content_info->hash, nca_ctx->hash, sizeof(nca_ctx->hash));
|
||||
memcpy(&(content_info->content_id), &(nca_ctx->content_id), sizeof(NcmContentId));
|
||||
LOG_MSG("Updated CNMT content record #%u (Title ID %016lX, size 0x%lX, type 0x%02X, ID offset 0x%02X).", i, cnmt_ctx->packaged_header->title_id, content_size, content_info->content_type, \
|
||||
LOG_MSG("Updated CNMT content record #%u (title ID %016lX, size 0x%lX, type 0x%02X, ID offset 0x%02X).", i, cnmt_ctx->packaged_header->title_id, content_size, content_info->content_type, \
|
||||
content_info->id_offset);
|
||||
success = true;
|
||||
break;
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
|
||||
#define GAMECARD_STORAGE_AREA_NAME(x) ((x) == GameCardStorageArea_Normal ? "normal" : ((x) == GameCardStorageArea_Secure ? "secure" : "none"))
|
||||
|
||||
#define GAMECARD_HFS_PARTITION_NAME_INDEX(x) ((x) - 1)
|
||||
|
||||
#define LAFW_MAGIC 0x4C414657 /* "LAFW". */
|
||||
|
||||
/* Type definitions. */
|
||||
|
@ -139,12 +141,12 @@ static MemoryLocation g_fsProgramMemory = {
|
|||
};
|
||||
|
||||
static const char *g_gameCardHfsPartitionNames[] = {
|
||||
[GameCardHashFileSystemPartitionType_Root] = "root",
|
||||
[GameCardHashFileSystemPartitionType_Update] = "update",
|
||||
[GameCardHashFileSystemPartitionType_Logo] = "logo",
|
||||
[GameCardHashFileSystemPartitionType_Normal] = "normal",
|
||||
[GameCardHashFileSystemPartitionType_Secure] = "secure",
|
||||
[GameCardHashFileSystemPartitionType_Boot] = "boot"
|
||||
[GAMECARD_HFS_PARTITION_NAME_INDEX(GameCardHashFileSystemPartitionType_Root)] = "root",
|
||||
[GAMECARD_HFS_PARTITION_NAME_INDEX(GameCardHashFileSystemPartitionType_Update)] = "update",
|
||||
[GAMECARD_HFS_PARTITION_NAME_INDEX(GameCardHashFileSystemPartitionType_Logo)] = "logo",
|
||||
[GAMECARD_HFS_PARTITION_NAME_INDEX(GameCardHashFileSystemPartitionType_Normal)] = "normal",
|
||||
[GAMECARD_HFS_PARTITION_NAME_INDEX(GameCardHashFileSystemPartitionType_Secure)] = "secure",
|
||||
[GAMECARD_HFS_PARTITION_NAME_INDEX(GameCardHashFileSystemPartitionType_Boot)] = "boot"
|
||||
};
|
||||
|
||||
/* Function prototypes. */
|
||||
|
@ -424,7 +426,7 @@ bool gamecardGetBundledFirmwareUpdateVersion(VersionType1 *out)
|
|||
|
||||
bool gamecardGetHashFileSystemContext(u8 hfs_partition_type, HashFileSystemContext *out)
|
||||
{
|
||||
if (hfs_partition_type >= GameCardHashFileSystemPartitionType_Count || !out)
|
||||
if (!hfs_partition_type || hfs_partition_type >= GameCardHashFileSystemPartitionType_Count || !out)
|
||||
{
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
|
@ -474,7 +476,7 @@ bool gamecardGetHashFileSystemContext(u8 hfs_partition_type, HashFileSystemConte
|
|||
|
||||
bool gamecardGetHashFileSystemEntryInfoByName(u8 hfs_partition_type, const char *entry_name, u64 *out_offset, u64 *out_size)
|
||||
{
|
||||
if (!entry_name || !*entry_name || (!out_offset && !out_size))
|
||||
if (!hfs_partition_type || hfs_partition_type >= GameCardHashFileSystemPartitionType_Count || !entry_name || !*entry_name || (!out_offset && !out_size))
|
||||
{
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
|
@ -1163,7 +1165,7 @@ static HashFileSystemContext *gamecardInitializeHashFileSystemContext(const char
|
|||
}
|
||||
|
||||
/* Duplicate partition name. */
|
||||
fs_ctx->name = (name ? strdup(name) : strdup(g_gameCardHfsPartitionNames[GameCardHashFileSystemPartitionType_Root]));
|
||||
fs_ctx->name = (name ? strdup(name) : strdup(g_gameCardHfsPartitionNames[GAMECARD_HFS_PARTITION_NAME_INDEX(GameCardHashFileSystemPartitionType_Root)]));
|
||||
if (!fs_ctx->name)
|
||||
{
|
||||
LOG_MSG("Failed to duplicate Hash FS partition name! (offset 0x%lX).", offset);
|
||||
|
@ -1173,7 +1175,7 @@ static HashFileSystemContext *gamecardInitializeHashFileSystemContext(const char
|
|||
/* Determine Hash FS partition type. */
|
||||
for(i = GameCardHashFileSystemPartitionType_Root; i < GameCardHashFileSystemPartitionType_Count; i++)
|
||||
{
|
||||
if (!strcmp(g_gameCardHfsPartitionNames[i], fs_ctx->name)) break;
|
||||
if (!strcmp(g_gameCardHfsPartitionNames[GAMECARD_HFS_PARTITION_NAME_INDEX(i)], fs_ctx->name)) break;
|
||||
}
|
||||
|
||||
if (i >= GameCardHashFileSystemPartitionType_Count)
|
||||
|
@ -1273,9 +1275,9 @@ end:
|
|||
static HashFileSystemContext *_gamecardGetHashFileSystemContext(u8 hfs_partition_type)
|
||||
{
|
||||
HashFileSystemContext *fs_ctx = NULL;
|
||||
const char *partition_name = NULL;
|
||||
|
||||
if (!g_gameCardInterfaceInit || g_gameCardStatus != GameCardStatus_InsertedAndInfoLoaded || !g_gameCardHfsCount || !g_gameCardHfsCtx || hfs_partition_type >= GameCardHashFileSystemPartitionType_Count)
|
||||
if (!g_gameCardInterfaceInit || g_gameCardStatus != GameCardStatus_InsertedAndInfoLoaded || !g_gameCardHfsCount || !g_gameCardHfsCtx || !hfs_partition_type || \
|
||||
hfs_partition_type >= GameCardHashFileSystemPartitionType_Count)
|
||||
{
|
||||
LOG_MSG("Invalid parameters!");
|
||||
goto end;
|
||||
|
@ -1288,18 +1290,15 @@ static HashFileSystemContext *_gamecardGetHashFileSystemContext(u8 hfs_partition
|
|||
goto end;
|
||||
}
|
||||
|
||||
/* Get requested partition name. */
|
||||
partition_name = g_gameCardHfsPartitionNames[hfs_partition_type];
|
||||
|
||||
/* Try to find the requested partition by looping through our Hash FS contexts. */
|
||||
for(u32 i = 1; i < g_gameCardHfsCount; i++)
|
||||
{
|
||||
fs_ctx = g_gameCardHfsCtx[i];
|
||||
if (!strcmp(fs_ctx->name, partition_name)) break;
|
||||
if (fs_ctx->type == hfs_partition_type) break;
|
||||
fs_ctx = NULL;
|
||||
}
|
||||
|
||||
if (!fs_ctx) LOG_MSG("Failed to locate Hash FS partition \"%s\"!", partition_name);
|
||||
if (!fs_ctx) LOG_MSG("Failed to locate Hash FS partition with type %u!", hfs_partition_type);
|
||||
|
||||
end:
|
||||
return fs_ctx;
|
||||
|
|
|
@ -95,7 +95,8 @@ bool ncaInitializeContext(NcaContext *out, u8 storage_id, u8 hfs_partition_type,
|
|||
u8 valid_fs_section_cnt = 0;
|
||||
|
||||
if (!out || (storage_id != NcmStorageId_GameCard && !(ncm_storage = titleGetNcmStorageByStorageId(storage_id))) || \
|
||||
(storage_id == NcmStorageId_GameCard && hfs_partition_type >= GameCardHashFileSystemPartitionType_Count) || !content_info || content_info->content_type > NcmContentType_DeltaFragment)
|
||||
(storage_id == NcmStorageId_GameCard && (!hfs_partition_type || hfs_partition_type >= GameCardHashFileSystemPartitionType_Count)) || !content_info || \
|
||||
content_info->content_type > NcmContentType_DeltaFragment)
|
||||
{
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "nxdt_utils.h"
|
||||
#include "title.h"
|
||||
#include "gamecard.h"
|
||||
#include "nacp.h"
|
||||
|
||||
#define NS_APPLICATION_RECORD_LIMIT 4096
|
||||
|
||||
|
@ -465,6 +466,8 @@ static int titleSystemTitleMetadataEntrySortFunction(const void *a, const void *
|
|||
static int titleUserApplicationMetadataEntrySortFunction(const void *a, const void *b);
|
||||
static int titleOrphanTitleInfoSortFunction(const void *a, const void *b);
|
||||
|
||||
static char *titleGetPatchVersionString(TitleInfo *title_info);
|
||||
|
||||
bool titleInitialize(void)
|
||||
{
|
||||
bool ret = false;
|
||||
|
@ -869,7 +872,7 @@ bool titleIsGameCardInfoUpdated(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
char *titleGenerateFileName(const TitleInfo *title_info, u8 name_convention, u8 illegal_char_replace_type)
|
||||
char *titleGenerateFileName(TitleInfo *title_info, u8 name_convention, u8 illegal_char_replace_type)
|
||||
{
|
||||
if (!title_info || title_info->meta_key.type < NcmContentMetaType_Application || title_info->meta_key.type > NcmContentMetaType_Delta || name_convention > TitleFileNameConvention_IdAndVersionOnly || \
|
||||
(name_convention == TitleFileNameConvention_Full && illegal_char_replace_type > TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly))
|
||||
|
@ -878,15 +881,24 @@ char *titleGenerateFileName(const TitleInfo *title_info, u8 name_convention, u8
|
|||
return NULL;
|
||||
}
|
||||
|
||||
char title_name[0x400] = {0}, *filename = NULL;
|
||||
u8 type = (title_info->meta_key.type - 0x80);
|
||||
char title_name[0x400] = {0}, *version_str = NULL, *filename = NULL;
|
||||
|
||||
/* Generate filename for this title. */
|
||||
if (name_convention == TitleFileNameConvention_Full)
|
||||
{
|
||||
if (title_info->app_metadata && *(title_info->app_metadata->lang_entry.name))
|
||||
{
|
||||
/* Retrieve display version string if we're dealing with a Patch. */
|
||||
if (title_info->meta_key.type == NcmContentMetaType_Patch) version_str = titleGetPatchVersionString(title_info);
|
||||
|
||||
sprintf(title_name, "%s ", title_info->app_metadata->lang_entry.name);
|
||||
if (version_str)
|
||||
{
|
||||
sprintf(title_name + strlen(title_name), "%s ", version_str);
|
||||
free(version_str);
|
||||
}
|
||||
|
||||
if (illegal_char_replace_type) utilsReplaceIllegalCharacters(title_name, illegal_char_replace_type == TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly);
|
||||
}
|
||||
|
||||
|
@ -923,12 +935,12 @@ char *titleGenerateGameCardFileName(u8 name_convention, u8 illegal_char_replace_
|
|||
|
||||
GameCardHeader gc_header = {0};
|
||||
size_t cur_filename_len = 0;
|
||||
char app_name[0x400] = {0}, *tmp_filename = NULL;
|
||||
char app_name[0x400] = {0};
|
||||
bool error = false;
|
||||
|
||||
for(u32 i = 0; i < title_count; i++)
|
||||
{
|
||||
TitleInfo *app_info = titles[i];
|
||||
TitleInfo *app_info = titles[i], *patch_info = NULL;
|
||||
if (!app_info || app_info->meta_key.type != NcmContentMetaType_Application) continue;
|
||||
|
||||
u32 app_version = app_info->meta_key.version;
|
||||
|
@ -939,11 +951,12 @@ char *titleGenerateGameCardFileName(u8 name_convention, u8 illegal_char_replace_
|
|||
{
|
||||
if (j == i) continue;
|
||||
|
||||
TitleInfo *patch_info = titles[j];
|
||||
if (!patch_info || patch_info->meta_key.type != NcmContentMetaType_Patch || !titleCheckIfPatchIdBelongsToApplicationId(app_info->meta_key.id, patch_info->meta_key.id) || \
|
||||
patch_info->meta_key.version <= app_version) continue;
|
||||
TitleInfo *cur_title_info = titles[j];
|
||||
if (!cur_title_info || cur_title_info->meta_key.type != NcmContentMetaType_Patch || !titleCheckIfPatchIdBelongsToApplicationId(app_info->meta_key.id, cur_title_info->meta_key.id) || \
|
||||
cur_title_info->meta_key.version <= app_version) continue;
|
||||
|
||||
app_version = patch_info->meta_key.version;
|
||||
patch_info = cur_title_info;
|
||||
app_version = cur_title_info->meta_key.version;
|
||||
}
|
||||
|
||||
/* Generate current user application name. */
|
||||
|
@ -955,7 +968,17 @@ char *titleGenerateGameCardFileName(u8 name_convention, u8 illegal_char_replace_
|
|||
|
||||
if (app_info->app_metadata && *(app_info->app_metadata->lang_entry.name))
|
||||
{
|
||||
/* Retrieve display version string if the inserted gamecard holds a patch for the current user application. */
|
||||
char *version_str = NULL;
|
||||
if (patch_info) version_str = titleGetPatchVersionString(patch_info);
|
||||
|
||||
sprintf(app_name + strlen(app_name), "%s ", app_info->app_metadata->lang_entry.name);
|
||||
if (version_str)
|
||||
{
|
||||
sprintf(app_name + strlen(app_name), "%s ", version_str);
|
||||
free(version_str);
|
||||
}
|
||||
|
||||
if (illegal_char_replace_type) utilsReplaceIllegalCharacters(app_name, illegal_char_replace_type == TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly);
|
||||
}
|
||||
|
||||
|
@ -970,7 +993,7 @@ char *titleGenerateGameCardFileName(u8 name_convention, u8 illegal_char_replace_
|
|||
/* Reallocate output buffer. */
|
||||
size_t app_name_len = strlen(app_name);
|
||||
|
||||
tmp_filename = realloc(filename, (cur_filename_len + app_name_len + 1) * sizeof(char));
|
||||
char *tmp_filename = realloc(filename, (cur_filename_len + app_name_len + 1) * sizeof(char));
|
||||
if (!tmp_filename)
|
||||
{
|
||||
LOG_MSG("Failed to reallocate filename buffer!");
|
||||
|
@ -2403,3 +2426,55 @@ static int titleOrphanTitleInfoSortFunction(const void *a, const void *b)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *titleGetPatchVersionString(TitleInfo *title_info)
|
||||
{
|
||||
NcmContentInfo *nacp_content = NULL;
|
||||
u8 storage_id = 0, hfs_partition_type = 0;
|
||||
NcaContext *nca_ctx = NULL;
|
||||
NacpContext nacp_ctx = {0};
|
||||
char *str = NULL;
|
||||
|
||||
if (!title_info || title_info->meta_key.type != NcmContentMetaType_Patch || !(nacp_content = titleGetContentInfoByTypeAndIdOffset(title_info, NcmContentType_Control, 0)))
|
||||
{
|
||||
LOG_MSG("Invalid parameters!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Update parameters. */
|
||||
storage_id = title_info->storage_id;
|
||||
if (storage_id == NcmStorageId_GameCard) hfs_partition_type = GameCardHashFileSystemPartitionType_Secure;
|
||||
|
||||
/* Allocate memory for the NCA context. */
|
||||
nca_ctx = calloc(1, sizeof(NcaContext));
|
||||
if (!nca_ctx)
|
||||
{
|
||||
LOG_MSG("Failed to allocate memory for NCA context!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Initialize NCA context. */
|
||||
if (!ncaInitializeContext(nca_ctx, storage_id, hfs_partition_type, nacp_content, NULL))
|
||||
{
|
||||
LOG_MSG("Failed to initialize NCA context for Control NCA from %016lX!", title_info->meta_key.id);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Initialize NACP context. */
|
||||
if (!nacpInitializeContext(&nacp_ctx, nca_ctx))
|
||||
{
|
||||
LOG_MSG("Failed to initialize NACP context for %016lX!", title_info->meta_key.id);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Get version string. */
|
||||
str = strndup(nacp_ctx.data->display_version, sizeof(nacp_ctx.data->display_version));
|
||||
if (!str) LOG_MSG("Failed to duplicate version string from %016lX!", title_info->meta_key.id);
|
||||
|
||||
end:
|
||||
nacpFreeContext(&nacp_ctx);
|
||||
|
||||
if (nca_ctx) free(nca_ctx);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue