mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-26 04:02:11 +00:00
title: pre-generate gamecard filenames
Changes include: * title: define a global string array for the pre-generated gamecard filenames. * title: move gamecard filename generation logic into a new function, _titleGenerateGameCardFileName(). * title: update background gamecard thread logic to make it generate gamecard filenames on any status changes. * title: update titleGenerateFileName() to make it return a duplicate of the gamecard filename requested by the caller.
This commit is contained in:
parent
00497b5181
commit
5a40167a13
2 changed files with 149 additions and 100 deletions
|
@ -35,18 +35,16 @@ typedef struct {
|
||||||
u8 type; ///< NsoSegmentType.
|
u8 type; ///< NsoSegmentType.
|
||||||
const char *name; ///< Pointer to a string that holds the segment name.
|
const char *name; ///< Pointer to a string that holds the segment name.
|
||||||
NsoSegmentInfo info; ///< Copied from the NSO header.
|
NsoSegmentInfo info; ///< Copied from the NSO header.
|
||||||
u8 *data; ///< Dynamically allocated buffer with the decompressed segment data.
|
u8 *data; ///< Dynamically allocated buffer for the decompressed segment data.
|
||||||
} NsoSegment;
|
} NsoSegment;
|
||||||
|
|
||||||
/* Global variables. */
|
/* Global variables. */
|
||||||
|
|
||||||
#if LOG_LEVEL < LOG_LEVEL_NONE
|
|
||||||
static const char *g_nsoSegmentTypeNames[NsoSegmentType_Count] = {
|
static const char *g_nsoSegmentTypeNames[NsoSegmentType_Count] = {
|
||||||
[NsoSegmentType_Text] = ".text",
|
[NsoSegmentType_Text] = ".text",
|
||||||
[NsoSegmentType_RoData] = ".rodata",
|
[NsoSegmentType_RoData] = ".rodata",
|
||||||
[NsoSegmentType_Data] = ".data",
|
[NsoSegmentType_Data] = ".data",
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Function prototypes. */
|
/* Function prototypes. */
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,8 @@ static u32 g_filteredSystemMetadataCount = 0, g_filteredUserMetadataCount = 0;
|
||||||
static TitleGameCardApplicationMetadata *g_titleGameCardApplicationMetadata = NULL;
|
static TitleGameCardApplicationMetadata *g_titleGameCardApplicationMetadata = NULL;
|
||||||
static u32 g_titleGameCardApplicationMetadataCount = 0;
|
static u32 g_titleGameCardApplicationMetadataCount = 0;
|
||||||
|
|
||||||
|
static char *g_titleGameCardFileNames[TitleNamingConvention_Count] = {NULL};
|
||||||
|
|
||||||
static TitleStorage g_titleStorage[TITLE_STORAGE_COUNT] = {0};
|
static TitleStorage g_titleStorage[TITLE_STORAGE_COUNT] = {0};
|
||||||
|
|
||||||
static TitleInfo **g_orphanTitleInfo = NULL;
|
static TitleInfo **g_orphanTitleInfo = NULL;
|
||||||
|
@ -577,6 +579,10 @@ static void titleGameCardInfoThreadFunc(void *arg);
|
||||||
|
|
||||||
static bool titleRefreshGameCardTitleInfo(void);
|
static bool titleRefreshGameCardTitleInfo(void);
|
||||||
|
|
||||||
|
NX_INLINE void titleFreeGameCardFileNames(void);
|
||||||
|
NX_INLINE void titleGenerateGameCardFileNames(void);
|
||||||
|
static char *_titleGenerateGameCardFileName(u8 naming_convention);
|
||||||
|
|
||||||
static bool titleIsUserApplicationContentAvailable(u64 app_id);
|
static bool titleIsUserApplicationContentAvailable(u64 app_id);
|
||||||
static TitleInfo *_titleGetInfoFromStorageByTitleId(u8 storage_id, u64 title_id);
|
static TitleInfo *_titleGetInfoFromStorageByTitleId(u8 storage_id, u64 title_id);
|
||||||
|
|
||||||
|
@ -1060,8 +1066,7 @@ bool titleIsGameCardInfoUpdated(void)
|
||||||
char *titleGenerateFileName(TitleInfo *title_info, u8 naming_convention, u8 illegal_char_replace_type)
|
char *titleGenerateFileName(TitleInfo *title_info, u8 naming_convention, u8 illegal_char_replace_type)
|
||||||
{
|
{
|
||||||
if (!title_info || (title_info->meta_key.type > NcmContentMetaType_BootImagePackageSafe && title_info->meta_key.type < NcmContentMetaType_Application) || \
|
if (!title_info || (title_info->meta_key.type > NcmContentMetaType_BootImagePackageSafe && title_info->meta_key.type < NcmContentMetaType_Application) || \
|
||||||
title_info->meta_key.type > NcmContentMetaType_DataPatch || naming_convention > TitleNamingConvention_IdAndVersionOnly || \
|
title_info->meta_key.type > NcmContentMetaType_DataPatch || naming_convention >= TitleNamingConvention_Count || illegal_char_replace_type >= TitleFileNameIllegalCharReplaceType_Count)
|
||||||
(naming_convention == TitleNamingConvention_Full && illegal_char_replace_type > TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly))
|
|
||||||
{
|
{
|
||||||
LOG_MSG_ERROR("Invalid parameters!");
|
LOG_MSG_ERROR("Invalid parameters!");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1114,101 +1119,23 @@ char *titleGenerateGameCardFileName(u8 naming_convention, u8 illegal_char_replac
|
||||||
|
|
||||||
SCOPED_LOCK(&g_titleMutex)
|
SCOPED_LOCK(&g_titleMutex)
|
||||||
{
|
{
|
||||||
GameCardHeader gc_header = {0};
|
if (!g_titleInterfaceInit || !g_titleGameCardAvailable || naming_convention >= TitleNamingConvention_Count || \
|
||||||
char app_name[0x300] = {0};
|
illegal_char_replace_type >= TitleFileNameIllegalCharReplaceType_Count || !g_titleGameCardFileNames[naming_convention])
|
||||||
size_t cur_filename_len = 0, app_name_len = 0;
|
|
||||||
bool error = false;
|
|
||||||
|
|
||||||
if (!g_titleInterfaceInit || !g_titleGameCardAvailable || naming_convention > TitleNamingConvention_IdAndVersionOnly || \
|
|
||||||
(naming_convention == TitleNamingConvention_Full && illegal_char_replace_type > TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly))
|
|
||||||
{
|
{
|
||||||
LOG_MSG_ERROR("Invalid parameters!");
|
LOG_MSG_ERROR("Invalid parameters!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_MSG_DEBUG("Generating %s gamecard filename...", naming_convention == TitleNamingConvention_Full ? "full" : "ID and version");
|
/* Duplicate generated filename. */
|
||||||
|
filename = strdup(g_titleGameCardFileNames[naming_convention]);
|
||||||
/* Check if we don't have any gamecard application metadata records we can work with. */
|
if (!filename)
|
||||||
/* This is especially true for Kiosk / Quest gamecards. */
|
|
||||||
if (!g_titleGameCardApplicationMetadata || !g_titleGameCardApplicationMetadataCount) goto fallback;
|
|
||||||
|
|
||||||
/* Loop through our gamecard application metadata entries. */
|
|
||||||
for(u32 i = 0; i < g_titleGameCardApplicationMetadataCount; i++)
|
|
||||||
{
|
{
|
||||||
const TitleGameCardApplicationMetadata *cur_gc_app_metadata = &(g_titleGameCardApplicationMetadata[i]);
|
LOG_MSG_ERROR("Failed to duplicate generated filename!");
|
||||||
|
|
||||||
/* Generate current user application name. */
|
|
||||||
*app_name = '\0';
|
|
||||||
|
|
||||||
if (naming_convention == TitleNamingConvention_Full)
|
|
||||||
{
|
|
||||||
if (cur_filename_len) strcat(app_name, " + ");
|
|
||||||
|
|
||||||
if (cur_gc_app_metadata->app_metadata && cur_gc_app_metadata->app_metadata->lang_entry.name[0])
|
|
||||||
{
|
|
||||||
app_name_len = strlen(app_name);
|
|
||||||
snprintf(app_name + app_name_len, MAX_ELEMENTS(app_name) - app_name_len, "%s ", cur_gc_app_metadata->app_metadata->lang_entry.name);
|
|
||||||
|
|
||||||
/* Append display version string if the inserted gamecard holds a patch for the current user application. */
|
|
||||||
if (cur_gc_app_metadata->has_patch && cur_gc_app_metadata->display_version[0])
|
|
||||||
{
|
|
||||||
app_name_len = strlen(app_name);
|
|
||||||
snprintf(app_name + app_name_len, MAX_ELEMENTS(app_name) - app_name_len, "%s ", cur_gc_app_metadata->display_version);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (illegal_char_replace_type) utilsReplaceIllegalCharacters(app_name, illegal_char_replace_type == TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly);
|
|
||||||
}
|
|
||||||
|
|
||||||
app_name_len = strlen(app_name);
|
|
||||||
snprintf(app_name + app_name_len, MAX_ELEMENTS(app_name) - app_name_len, "[%016lX][v%u]", cur_gc_app_metadata->app_metadata->title_id, cur_gc_app_metadata->version.value);
|
|
||||||
} else
|
|
||||||
if (naming_convention == TitleNamingConvention_IdAndVersionOnly)
|
|
||||||
{
|
|
||||||
if (cur_filename_len) strcat(app_name, "+");
|
|
||||||
app_name_len = strlen(app_name);
|
|
||||||
snprintf(app_name + app_name_len, MAX_ELEMENTS(app_name) - app_name_len, "%016lX_v%u", cur_gc_app_metadata->app_metadata->title_id, cur_gc_app_metadata->version.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reallocate output buffer. */
|
|
||||||
app_name_len = strlen(app_name);
|
|
||||||
|
|
||||||
char *tmp_filename = realloc(filename, (cur_filename_len + app_name_len + 1) * sizeof(char));
|
|
||||||
if (!tmp_filename)
|
|
||||||
{
|
|
||||||
LOG_MSG_ERROR("Failed to reallocate filename buffer!");
|
|
||||||
if (filename) free(filename);
|
|
||||||
filename = NULL;
|
|
||||||
error = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
filename = tmp_filename;
|
/* Replace illegal characters, if requested. */
|
||||||
tmp_filename = NULL;
|
if (illegal_char_replace_type) utilsReplaceIllegalCharacters(filename, illegal_char_replace_type == TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly);
|
||||||
|
|
||||||
/* Concatenate current user application name. */
|
|
||||||
filename[cur_filename_len] = '\0';
|
|
||||||
strcat(filename, app_name);
|
|
||||||
cur_filename_len += app_name_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
fallback:
|
|
||||||
if (!filename && !error)
|
|
||||||
{
|
|
||||||
LOG_MSG_ERROR("Error: the inserted gamecard doesn't hold any user applications!");
|
|
||||||
|
|
||||||
/* Fallback string if no applications can be found. */
|
|
||||||
sprintf(app_name, "gamecard");
|
|
||||||
|
|
||||||
if (gamecardGetHeader(&gc_header))
|
|
||||||
{
|
|
||||||
strcat(app_name, "_");
|
|
||||||
cur_filename_len = strlen(app_name);
|
|
||||||
utilsGenerateHexString(app_name + cur_filename_len, sizeof(app_name) - cur_filename_len, gc_header.package_id, sizeof(gc_header.package_id), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
filename = strdup(app_name);
|
|
||||||
if (!filename) LOG_MSG_ERROR("Failed to duplicate fallback filename!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return filename;
|
return filename;
|
||||||
|
@ -2491,20 +2418,23 @@ static void titleGameCardInfoThreadFunc(void *arg)
|
||||||
{
|
{
|
||||||
g_titleGameCardInfoUpdated = titleRefreshGameCardTitleInfo();
|
g_titleGameCardInfoUpdated = titleRefreshGameCardTitleInfo();
|
||||||
|
|
||||||
if (g_titleGameCardInfoUpdated)
|
|
||||||
{
|
|
||||||
/* Generate filtered user application metadata pointer array. */
|
|
||||||
titleGenerateFilteredApplicationMetadataPointerArray(false);
|
|
||||||
|
|
||||||
/* Generate gamecard application metadata array. */
|
/* Generate gamecard application metadata array. */
|
||||||
titleGenerateGameCardApplicationMetadataArray();
|
titleGenerateGameCardApplicationMetadataArray();
|
||||||
}
|
|
||||||
|
/* Generate gamecard file names. */
|
||||||
|
titleGenerateGameCardFileNames();
|
||||||
|
|
||||||
|
/* Generate filtered user application metadata pointer array. */
|
||||||
|
if (g_titleGameCardInfoUpdated) titleGenerateFilteredApplicationMetadataPointerArray(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update gamecard flags. */
|
/* Update gamecard flags. */
|
||||||
g_titleGameCardAvailable = g_titleGameCardInfoUpdated = false;
|
g_titleGameCardAvailable = g_titleGameCardInfoUpdated = false;
|
||||||
|
|
||||||
|
/* Free gamecard file names. */
|
||||||
|
titleFreeGameCardFileNames();
|
||||||
|
|
||||||
threadExit();
|
threadExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2647,6 +2577,127 @@ end:
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NX_INLINE void titleFreeGameCardFileNames(void)
|
||||||
|
{
|
||||||
|
for(u8 i = 0; i < TitleNamingConvention_Count; i++)
|
||||||
|
{
|
||||||
|
if (g_titleGameCardFileNames[i])
|
||||||
|
{
|
||||||
|
free(g_titleGameCardFileNames[i]);
|
||||||
|
g_titleGameCardFileNames[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_INLINE void titleGenerateGameCardFileNames(void)
|
||||||
|
{
|
||||||
|
titleFreeGameCardFileNames();
|
||||||
|
|
||||||
|
if (g_titleGameCardAvailable)
|
||||||
|
{
|
||||||
|
for(u8 i = 0; i < TitleNamingConvention_Count; i++) g_titleGameCardFileNames[i] = _titleGenerateGameCardFileName(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *_titleGenerateGameCardFileName(u8 naming_convention)
|
||||||
|
{
|
||||||
|
if (naming_convention >= TitleNamingConvention_Count)
|
||||||
|
{
|
||||||
|
LOG_MSG_ERROR("Invalid parameters!");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *filename = NULL;
|
||||||
|
GameCardHeader gc_header = {0};
|
||||||
|
char app_name[0x300] = {0};
|
||||||
|
size_t cur_filename_len = 0, app_name_len = 0;
|
||||||
|
bool error = false;
|
||||||
|
|
||||||
|
LOG_MSG_DEBUG("Generating %s gamecard filename...", naming_convention == TitleNamingConvention_Full ? "full" : "ID and version");
|
||||||
|
|
||||||
|
/* Check if we don't have any gamecard application metadata records we can work with. */
|
||||||
|
/* This is especially true for Kiosk / Quest gamecards. */
|
||||||
|
if (!g_titleGameCardApplicationMetadata || !g_titleGameCardApplicationMetadataCount) goto fallback;
|
||||||
|
|
||||||
|
/* Loop through our gamecard application metadata entries. */
|
||||||
|
for(u32 i = 0; i < g_titleGameCardApplicationMetadataCount; i++)
|
||||||
|
{
|
||||||
|
const TitleGameCardApplicationMetadata *cur_gc_app_metadata = &(g_titleGameCardApplicationMetadata[i]);
|
||||||
|
|
||||||
|
/* Generate current user application name. */
|
||||||
|
*app_name = '\0';
|
||||||
|
|
||||||
|
if (naming_convention == TitleNamingConvention_Full)
|
||||||
|
{
|
||||||
|
if (cur_filename_len) strcat(app_name, " + ");
|
||||||
|
|
||||||
|
if (cur_gc_app_metadata->app_metadata && cur_gc_app_metadata->app_metadata->lang_entry.name[0])
|
||||||
|
{
|
||||||
|
app_name_len = strlen(app_name);
|
||||||
|
snprintf(app_name + app_name_len, MAX_ELEMENTS(app_name) - app_name_len, "%s ", cur_gc_app_metadata->app_metadata->lang_entry.name);
|
||||||
|
|
||||||
|
/* Append display version string if the inserted gamecard holds a patch for the current user application. */
|
||||||
|
if (cur_gc_app_metadata->has_patch && cur_gc_app_metadata->display_version[0])
|
||||||
|
{
|
||||||
|
app_name_len = strlen(app_name);
|
||||||
|
snprintf(app_name + app_name_len, MAX_ELEMENTS(app_name) - app_name_len, "%s ", cur_gc_app_metadata->display_version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
app_name_len = strlen(app_name);
|
||||||
|
snprintf(app_name + app_name_len, MAX_ELEMENTS(app_name) - app_name_len, "[%016lX][v%u]", cur_gc_app_metadata->app_metadata->title_id, cur_gc_app_metadata->version.value);
|
||||||
|
} else
|
||||||
|
if (naming_convention == TitleNamingConvention_IdAndVersionOnly)
|
||||||
|
{
|
||||||
|
if (cur_filename_len) strcat(app_name, "+");
|
||||||
|
app_name_len = strlen(app_name);
|
||||||
|
snprintf(app_name + app_name_len, MAX_ELEMENTS(app_name) - app_name_len, "%016lX_v%u", cur_gc_app_metadata->app_metadata->title_id, cur_gc_app_metadata->version.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reallocate output buffer. */
|
||||||
|
app_name_len = strlen(app_name);
|
||||||
|
|
||||||
|
char *tmp_filename = realloc(filename, (cur_filename_len + app_name_len + 1) * sizeof(char));
|
||||||
|
if (!tmp_filename)
|
||||||
|
{
|
||||||
|
LOG_MSG_ERROR("Failed to reallocate filename buffer!");
|
||||||
|
if (filename) free(filename);
|
||||||
|
filename = NULL;
|
||||||
|
error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
filename = tmp_filename;
|
||||||
|
tmp_filename = NULL;
|
||||||
|
|
||||||
|
/* Concatenate current user application name. */
|
||||||
|
filename[cur_filename_len] = '\0';
|
||||||
|
strcat(filename, app_name);
|
||||||
|
cur_filename_len += app_name_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
fallback:
|
||||||
|
if (!filename && !error)
|
||||||
|
{
|
||||||
|
LOG_MSG_ERROR("Error: the inserted gamecard doesn't hold any user applications!");
|
||||||
|
|
||||||
|
/* Fallback string if no applications can be found. */
|
||||||
|
sprintf(app_name, "gamecard");
|
||||||
|
|
||||||
|
if (gamecardGetHeader(&gc_header))
|
||||||
|
{
|
||||||
|
strcat(app_name, "_");
|
||||||
|
cur_filename_len = strlen(app_name);
|
||||||
|
utilsGenerateHexString(app_name + cur_filename_len, sizeof(app_name) - cur_filename_len, gc_header.package_id, sizeof(gc_header.package_id), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
filename = strdup(app_name);
|
||||||
|
if (!filename) LOG_MSG_ERROR("Failed to duplicate fallback filename!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
static bool titleIsUserApplicationContentAvailable(u64 app_id)
|
static bool titleIsUserApplicationContentAvailable(u64 app_id)
|
||||||
{
|
{
|
||||||
if (!app_id) return false;
|
if (!app_id) return false;
|
||||||
|
@ -2704,7 +2755,7 @@ static TitleInfo *_titleGetInfoFromStorageByTitleId(u8 storage_id, u64 title_id)
|
||||||
if (out) break;
|
if (out) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!out) LOG_MSG_DEBUG("Unable to find title info entry with ID \"%016lX\" in %s.", title_id, titleGetNcmStorageIdName(storage_id));
|
if (!out && storage_id != NcmStorageId_BuiltInSystem) LOG_MSG_DEBUG("Unable to find title info entry with ID \"%016lX\" in %s.", title_id, titleGetNcmStorageIdName(storage_id));
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue