mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-22 18:26:39 +00:00
poc: add browser for gamecard HFS partitions
Just in time for New Year's Eve. Other changes include: * title: use snprintf() in filename generation functions + reduce array sizes.
This commit is contained in:
parent
c585e8f9d3
commit
62c15ca7cf
2 changed files with 171 additions and 42 deletions
|
@ -70,19 +70,20 @@ typedef enum {
|
||||||
MenuId_Root = 0,
|
MenuId_Root = 0,
|
||||||
MenuId_GameCard = 1,
|
MenuId_GameCard = 1,
|
||||||
MenuId_XCI = 2,
|
MenuId_XCI = 2,
|
||||||
MenuId_HFS = 3,
|
MenuId_DumpHFS = 3,
|
||||||
MenuId_UserTitles = 4,
|
MenuId_BrowseHFS = 4,
|
||||||
MenuId_UserTitlesSubMenu = 5,
|
MenuId_UserTitles = 5,
|
||||||
MenuId_NSPTitleTypes = 6,
|
MenuId_UserTitlesSubMenu = 6,
|
||||||
MenuId_NSP = 7,
|
MenuId_NSPTitleTypes = 7,
|
||||||
MenuId_TicketTitleTypes = 8,
|
MenuId_NSP = 8,
|
||||||
MenuId_Ticket = 9,
|
MenuId_TicketTitleTypes = 9,
|
||||||
MenuId_NcaTitleTypes = 10,
|
MenuId_Ticket = 10,
|
||||||
MenuId_Nca = 11,
|
MenuId_NcaTitleTypes = 11,
|
||||||
MenuId_NcaFsSections = 12,
|
MenuId_Nca = 12,
|
||||||
MenuId_NcaFsSectionsSubMenu = 13,
|
MenuId_NcaFsSections = 13,
|
||||||
MenuId_SystemTitles = 14,
|
MenuId_NcaFsSectionsSubMenu = 14,
|
||||||
MenuId_Count = 15
|
MenuId_SystemTitles = 15,
|
||||||
|
MenuId_Count = 16
|
||||||
} MenuId;
|
} MenuId;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -213,6 +214,7 @@ static bool saveGameCardUid(void *userdata);
|
||||||
static bool saveGameCardHfsPartition(void *userdata);
|
static bool saveGameCardHfsPartition(void *userdata);
|
||||||
static bool saveGameCardRawHfsPartition(HashFileSystemContext *hfs_ctx);
|
static bool saveGameCardRawHfsPartition(HashFileSystemContext *hfs_ctx);
|
||||||
static bool saveGameCardExtractedHfsPartition(HashFileSystemContext *hfs_ctx);
|
static bool saveGameCardExtractedHfsPartition(HashFileSystemContext *hfs_ctx);
|
||||||
|
static bool browseGameCardHfsPartition(void *userdata);
|
||||||
|
|
||||||
static bool saveConsoleLafwBlob(void *userdata);
|
static bool saveConsoleLafwBlob(void *userdata);
|
||||||
|
|
||||||
|
@ -411,7 +413,7 @@ static u32 g_hfsLogoPartition = HashFileSystemPartitionType_Logo;
|
||||||
static u32 g_hfsNormalPartition = HashFileSystemPartitionType_Normal;
|
static u32 g_hfsNormalPartition = HashFileSystemPartitionType_Normal;
|
||||||
static u32 g_hfsSecurePartition = HashFileSystemPartitionType_Secure;
|
static u32 g_hfsSecurePartition = HashFileSystemPartitionType_Secure;
|
||||||
|
|
||||||
static MenuElement *g_gameCardHfsMenuElements[] = {
|
static MenuElement *g_gameCardHfsDumpMenuElements[] = {
|
||||||
&(MenuElement){
|
&(MenuElement){
|
||||||
.str = "dump root hfs partition",
|
.str = "dump root hfs partition",
|
||||||
.child_menu = NULL,
|
.child_menu = NULL,
|
||||||
|
@ -464,6 +466,46 @@ static MenuElement *g_gameCardHfsMenuElements[] = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static MenuElement *g_gameCardHfsBrowseMenuElements[] = {
|
||||||
|
&(MenuElement){
|
||||||
|
.str = "browse root hfs partition",
|
||||||
|
.child_menu = NULL,
|
||||||
|
.task_func = &browseGameCardHfsPartition,
|
||||||
|
.element_options = NULL,
|
||||||
|
.userdata = &g_hfsRootPartition
|
||||||
|
},
|
||||||
|
&(MenuElement){
|
||||||
|
.str = "browse update hfs partition",
|
||||||
|
.child_menu = NULL,
|
||||||
|
.task_func = &browseGameCardHfsPartition,
|
||||||
|
.element_options = NULL,
|
||||||
|
.userdata = &g_hfsUpdatePartition
|
||||||
|
},
|
||||||
|
&(MenuElement){
|
||||||
|
.str = "browse logo hfs partition",
|
||||||
|
.child_menu = NULL,
|
||||||
|
.task_func = &browseGameCardHfsPartition,
|
||||||
|
.element_options = NULL,
|
||||||
|
.userdata = &g_hfsLogoPartition
|
||||||
|
},
|
||||||
|
&(MenuElement){
|
||||||
|
.str = "browse normal hfs partition",
|
||||||
|
.child_menu = NULL,
|
||||||
|
.task_func = &browseGameCardHfsPartition,
|
||||||
|
.element_options = NULL,
|
||||||
|
.userdata = &g_hfsNormalPartition
|
||||||
|
},
|
||||||
|
&(MenuElement){
|
||||||
|
.str = "browse secure hfs partition",
|
||||||
|
.child_menu = NULL,
|
||||||
|
.task_func = &browseGameCardHfsPartition,
|
||||||
|
.element_options = NULL,
|
||||||
|
.userdata = &g_hfsSecurePartition
|
||||||
|
},
|
||||||
|
&g_storageMenuElement,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
static MenuElement *g_gameCardMenuElements[] = {
|
static MenuElement *g_gameCardMenuElements[] = {
|
||||||
&(MenuElement){
|
&(MenuElement){
|
||||||
.str = "dump gamecard image (xci)",
|
.str = "dump gamecard image (xci)",
|
||||||
|
@ -530,11 +572,24 @@ static MenuElement *g_gameCardMenuElements[] = {
|
||||||
&(MenuElement){
|
&(MenuElement){
|
||||||
.str = "dump hfs partitions (optional)",
|
.str = "dump hfs partitions (optional)",
|
||||||
.child_menu = &(Menu){
|
.child_menu = &(Menu){
|
||||||
.id = MenuId_HFS,
|
.id = MenuId_DumpHFS,
|
||||||
.parent = NULL,
|
.parent = NULL,
|
||||||
.selected = 0,
|
.selected = 0,
|
||||||
.scroll = 0,
|
.scroll = 0,
|
||||||
.elements = g_gameCardHfsMenuElements
|
.elements = g_gameCardHfsDumpMenuElements
|
||||||
|
},
|
||||||
|
.task_func = NULL,
|
||||||
|
.element_options = NULL,
|
||||||
|
.userdata = NULL
|
||||||
|
},
|
||||||
|
&(MenuElement){
|
||||||
|
.str = "browse hfs partitions (optional)",
|
||||||
|
.child_menu = &(Menu){
|
||||||
|
.id = MenuId_BrowseHFS,
|
||||||
|
.parent = NULL,
|
||||||
|
.selected = 0,
|
||||||
|
.scroll = 0,
|
||||||
|
.elements = g_gameCardHfsBrowseMenuElements
|
||||||
},
|
},
|
||||||
.task_func = NULL,
|
.task_func = NULL,
|
||||||
.element_options = NULL,
|
.element_options = NULL,
|
||||||
|
@ -1276,16 +1331,28 @@ int main(int argc, char *argv[])
|
||||||
} else
|
} else
|
||||||
if (selected_element->task_func)
|
if (selected_element->task_func)
|
||||||
{
|
{
|
||||||
|
bool show_button_prompt = true;
|
||||||
|
|
||||||
consoleClear();
|
consoleClear();
|
||||||
|
|
||||||
/* Wait for gamecard (if needed). */
|
/* Wait for gamecard (if needed). */
|
||||||
if (((cur_menu->id >= MenuId_GameCard && cur_menu->id <= MenuId_HFS) || (title_info && title_info->storage_id == NcmStorageId_GameCard)) && !waitForGameCard())
|
if (((cur_menu->id >= MenuId_GameCard && cur_menu->id <= MenuId_BrowseHFS) || (title_info && title_info->storage_id == NcmStorageId_GameCard)) && !waitForGameCard())
|
||||||
{
|
{
|
||||||
if (g_appletStatus) continue;
|
if (g_appletStatus) continue;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cur_menu->id > MenuId_Root && (cur_menu->id != MenuId_NcaFsSectionsSubMenu || cur_menu->selected != 1))
|
if ((cur_menu->id == MenuId_NcaFsSectionsSubMenu && cur_menu->selected != 1) || cur_menu->id == MenuId_BrowseHFS)
|
||||||
|
{
|
||||||
|
show_button_prompt = false;
|
||||||
|
|
||||||
|
/* Ignore result. */
|
||||||
|
selected_element->task_func(selected_element->userdata);
|
||||||
|
|
||||||
|
/* Update free space. */
|
||||||
|
if (!useUsbHost()) updateStorageList();
|
||||||
|
} else
|
||||||
|
if (cur_menu->id > MenuId_Root)
|
||||||
{
|
{
|
||||||
/* Wait for USB session (if needed). */
|
/* Wait for USB session (if needed). */
|
||||||
if (useUsbHost() && !waitForUsb())
|
if (useUsbHost() && !waitForUsb())
|
||||||
|
@ -1303,12 +1370,9 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
utilsSetLongRunningProcessState(false);
|
utilsSetLongRunningProcessState(false);
|
||||||
} else {
|
|
||||||
/* Ignore result. */
|
|
||||||
selected_element->task_func(selected_element->userdata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_appletStatus && (cur_menu->id != MenuId_NcaFsSectionsSubMenu || cur_menu->selected != 1))
|
if (g_appletStatus && show_button_prompt)
|
||||||
{
|
{
|
||||||
/* Display prompt. */
|
/* Display prompt. */
|
||||||
consolePrint("press any button to continue");
|
consolePrint("press any button to continue");
|
||||||
|
@ -2919,6 +2983,60 @@ end:
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool browseGameCardHfsPartition(void *userdata)
|
||||||
|
{
|
||||||
|
u32 hfs_partition_type = (userdata ? *((u32*)userdata) : HashFileSystemPartitionType_None);
|
||||||
|
HashFileSystemContext hfs_ctx = {0};
|
||||||
|
char mount_name[DEVOPTAB_MOUNT_NAME_LENGTH] = {0}, subdir[0x20] = {0}, *base_out_path = NULL;
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
if (hfs_partition_type < HashFileSystemPartitionType_Root || hfs_partition_type > HashFileSystemPartitionType_Secure)
|
||||||
|
{
|
||||||
|
consolePrint("invalid hfs partition type! (%u)\n", hfs_partition_type);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gamecardGetHashFileSystemContext(hfs_partition_type, &hfs_ctx))
|
||||||
|
{
|
||||||
|
consolePrint("get hfs ctx failed! this partition type may not exist within the inserted gamecard\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mount devoptab device. */
|
||||||
|
snprintf(mount_name, MAX_ELEMENTS(mount_name), "hfs%s", hfs_ctx.name);
|
||||||
|
|
||||||
|
if (!devoptabMountHashFileSystemDevice(&hfs_ctx, mount_name))
|
||||||
|
{
|
||||||
|
consolePrint("hfs ctx devoptab mount failed!\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate output base path. */
|
||||||
|
snprintf(subdir, MAX_ELEMENTS(subdir), "/%s", hfs_ctx.name);
|
||||||
|
base_out_path = generateOutputGameCardFileName("HFS/Extracted", subdir, true);
|
||||||
|
if (!base_out_path) goto end;
|
||||||
|
|
||||||
|
/* Display file browser. */
|
||||||
|
success = fsBrowser(mount_name, base_out_path);
|
||||||
|
|
||||||
|
/* Unmount devoptab device. */
|
||||||
|
devoptabUnmountDevice(mount_name);
|
||||||
|
|
||||||
|
end:
|
||||||
|
/* Free data. */
|
||||||
|
if (base_out_path) free(base_out_path);
|
||||||
|
hfsFreeContext(&hfs_ctx);
|
||||||
|
|
||||||
|
if (!success && g_appletStatus)
|
||||||
|
{
|
||||||
|
consolePrint("press any button to continue\n");
|
||||||
|
utilsWaitForButtonPress(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
static bool saveConsoleLafwBlob(void *userdata)
|
static bool saveConsoleLafwBlob(void *userdata)
|
||||||
{
|
{
|
||||||
NX_IGNORE_ARG(userdata);
|
NX_IGNORE_ARG(userdata);
|
||||||
|
@ -3529,7 +3647,9 @@ static bool fsBrowser(const char *mount_name, const char *base_out_path)
|
||||||
depth++;
|
depth++;
|
||||||
} else {
|
} else {
|
||||||
/* Dump file. */
|
/* Dump file. */
|
||||||
|
utilsSetLongRunningProcessState(true);
|
||||||
fsBrowserDumpFile(dir_path, selected_entry, base_out_path);
|
fsBrowserDumpFile(dir_path, selected_entry, base_out_path);
|
||||||
|
utilsSetLongRunningProcessState(false);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
if (btn_down & HidNpadButton_B)
|
if (btn_down & HidNpadButton_B)
|
||||||
|
@ -3592,7 +3712,9 @@ static bool fsBrowser(const char *mount_name, const char *base_out_path)
|
||||||
if ((btn_down & HidNpadButton_Y) && entries_count && highlighted)
|
if ((btn_down & HidNpadButton_Y) && entries_count && highlighted)
|
||||||
{
|
{
|
||||||
/* Dump highlighted entries. */
|
/* Dump highlighted entries. */
|
||||||
|
utilsSetLongRunningProcessState(true);
|
||||||
fsBrowserDumpHighlightedEntries(dir_path, entries, entries_count, base_out_path);
|
fsBrowserDumpHighlightedEntries(dir_path, entries, entries_count, base_out_path);
|
||||||
|
utilsSetLongRunningProcessState(false);
|
||||||
|
|
||||||
/* Unhighlight all entries. */
|
/* Unhighlight all entries. */
|
||||||
for(u32 i = 0; i < entries_count; i++) entries[i].highlight = false;
|
for(u32 i = 0; i < entries_count; i++) entries[i].highlight = false;
|
||||||
|
@ -3683,7 +3805,7 @@ static bool fsBrowserGetDirEntries(const char *dir_path, FsBrowserEntry **out_en
|
||||||
while((dt = readdir(dp)))
|
while((dt = readdir(dp)))
|
||||||
{
|
{
|
||||||
/* Skip "." and ".." entries. */
|
/* Skip "." and ".." entries. */
|
||||||
if (!strcmp(dt->d_name, ".") || !strcmp(dt->d_name, "..") != 0) continue;
|
if (!strcmp(dt->d_name, ".") || !strcmp(dt->d_name, "..")) continue;
|
||||||
|
|
||||||
/* Reallocate directory entries buffer. */
|
/* Reallocate directory entries buffer. */
|
||||||
if (!(entries_tmp = realloc(entries, (count + 1) * sizeof(FsBrowserEntry))))
|
if (!(entries_tmp = realloc(entries, (count + 1) * sizeof(FsBrowserEntry))))
|
||||||
|
|
|
@ -1096,31 +1096,35 @@ char *titleGenerateFileName(TitleInfo *title_info, u8 naming_convention, u8 ille
|
||||||
u8 type_idx = title_info->meta_key.type;
|
u8 type_idx = title_info->meta_key.type;
|
||||||
if (type_idx >= NcmContentMetaType_Application) type_idx -= NCM_CMT_APP_OFFSET;
|
if (type_idx >= NcmContentMetaType_Application) type_idx -= NCM_CMT_APP_OFFSET;
|
||||||
|
|
||||||
char title_name[0x400] = {0}, *version_str = NULL, *filename = NULL;
|
char title_name[0x300] = {0}, *filename = NULL;
|
||||||
|
size_t title_name_len = 0;
|
||||||
|
|
||||||
/* Generate filename for this title. */
|
/* Generate filename for this title. */
|
||||||
if (naming_convention == TitleNamingConvention_Full)
|
if (naming_convention == TitleNamingConvention_Full)
|
||||||
{
|
{
|
||||||
if (title_info->app_metadata && *(title_info->app_metadata->lang_entry.name))
|
if (title_info->app_metadata && *(title_info->app_metadata->lang_entry.name))
|
||||||
{
|
{
|
||||||
/* Retrieve display version string if we're dealing with a Patch. */
|
snprintf(title_name, MAX_ELEMENTS(title_name), "%s ", title_info->app_metadata->lang_entry.name);
|
||||||
if (title_info->meta_key.type == NcmContentMetaType_Patch) version_str = titleGetPatchVersionString(title_info);
|
|
||||||
|
|
||||||
sprintf(title_name, "%s ", title_info->app_metadata->lang_entry.name);
|
/* Retrieve display version string if we're dealing with a Patch. */
|
||||||
|
char *version_str = (title_info->meta_key.type == NcmContentMetaType_Patch ? titleGetPatchVersionString(title_info) : NULL);
|
||||||
if (version_str)
|
if (version_str)
|
||||||
{
|
{
|
||||||
sprintf(title_name + strlen(title_name), "%s ", version_str);
|
title_name_len = strlen(title_name);
|
||||||
|
snprintf(title_name + title_name_len, MAX_ELEMENTS(title_name) - title_name_len, "%s ", version_str);
|
||||||
free(version_str);
|
free(version_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (illegal_char_replace_type) utilsReplaceIllegalCharacters(title_name, illegal_char_replace_type == TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly);
|
if (illegal_char_replace_type) utilsReplaceIllegalCharacters(title_name, illegal_char_replace_type == TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(title_name + strlen(title_name), "[%016lX][v%u][%s]", title_info->meta_key.id, title_info->meta_key.version, g_filenameTypeStrings[type_idx]);
|
title_name_len = strlen(title_name);
|
||||||
|
snprintf(title_name + title_name_len, MAX_ELEMENTS(title_name) - title_name_len, "[%016lX][v%u][%s]", title_info->meta_key.id, title_info->meta_key.version, \
|
||||||
|
g_filenameTypeStrings[type_idx]);
|
||||||
} else
|
} else
|
||||||
if (naming_convention == TitleNamingConvention_IdAndVersionOnly)
|
if (naming_convention == TitleNamingConvention_IdAndVersionOnly)
|
||||||
{
|
{
|
||||||
sprintf(title_name, "%016lX_v%u_%s", title_info->meta_key.id, title_info->meta_key.version, g_filenameTypeStrings[type_idx]);
|
snprintf(title_name, MAX_ELEMENTS(title_name), "%016lX_v%u_%s", title_info->meta_key.id, title_info->meta_key.version, g_filenameTypeStrings[type_idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Duplicate generated filename. */
|
/* Duplicate generated filename. */
|
||||||
|
@ -1141,8 +1145,8 @@ char *titleGenerateGameCardFileName(u8 naming_convention, u8 illegal_char_replac
|
||||||
u32 title_count = title_storage->title_count;
|
u32 title_count = title_storage->title_count;
|
||||||
|
|
||||||
GameCardHeader gc_header = {0};
|
GameCardHeader gc_header = {0};
|
||||||
size_t cur_filename_len = 0;
|
size_t cur_filename_len = 0, app_name_len = 0;
|
||||||
char app_name[0x400] = {0};
|
char app_name[0x300] = {0};
|
||||||
bool error = false;
|
bool error = false;
|
||||||
|
|
||||||
if (!g_titleInterfaceInit || !g_titleGameCardAvailable || naming_convention > TitleNamingConvention_IdAndVersionOnly || \
|
if (!g_titleInterfaceInit || !g_titleGameCardAvailable || naming_convention > TitleNamingConvention_IdAndVersionOnly || \
|
||||||
|
@ -1170,8 +1174,8 @@ char *titleGenerateGameCardFileName(u8 naming_convention, u8 illegal_char_replac
|
||||||
if (j == i) continue;
|
if (j == i) continue;
|
||||||
|
|
||||||
TitleInfo *cur_title_info = titles[j];
|
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) || \
|
if (!cur_title_info || cur_title_info->meta_key.type != NcmContentMetaType_Patch || \
|
||||||
cur_title_info->meta_key.version <= app_version) continue;
|
!titleCheckIfPatchIdBelongsToApplicationId(app_info->meta_key.id, cur_title_info->meta_key.id) || cur_title_info->meta_key.version <= app_version) continue;
|
||||||
|
|
||||||
patch_info = cur_title_info;
|
patch_info = cur_title_info;
|
||||||
app_version = cur_title_info->meta_key.version;
|
app_version = cur_title_info->meta_key.version;
|
||||||
|
@ -1186,30 +1190,33 @@ char *titleGenerateGameCardFileName(u8 naming_convention, u8 illegal_char_replac
|
||||||
|
|
||||||
if (app_info->app_metadata && *(app_info->app_metadata->lang_entry.name))
|
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. */
|
app_name_len = strlen(app_name);
|
||||||
char *version_str = NULL;
|
snprintf(app_name + app_name_len, MAX_ELEMENTS(app_name) - app_name_len, "%s ", app_info->app_metadata->lang_entry.name);
|
||||||
if (patch_info) version_str = titleGetPatchVersionString(patch_info);
|
|
||||||
|
|
||||||
sprintf(app_name + strlen(app_name), "%s ", 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 = (patch_info ? titleGetPatchVersionString(patch_info) : NULL);
|
||||||
if (version_str)
|
if (version_str)
|
||||||
{
|
{
|
||||||
sprintf(app_name + strlen(app_name), "%s ", version_str);
|
app_name_len = strlen(app_name);
|
||||||
|
snprintf(app_name + app_name_len, MAX_ELEMENTS(app_name) - app_name_len, "%s ", version_str);
|
||||||
free(version_str);
|
free(version_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (illegal_char_replace_type) utilsReplaceIllegalCharacters(app_name, illegal_char_replace_type == TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly);
|
if (illegal_char_replace_type) utilsReplaceIllegalCharacters(app_name, illegal_char_replace_type == TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(app_name + strlen(app_name), "[%016lX][v%u]", app_info->meta_key.id, app_version);
|
app_name_len = strlen(app_name);
|
||||||
|
snprintf(app_name + app_name_len, MAX_ELEMENTS(app_name) - app_name_len, "[%016lX][v%u]", app_info->meta_key.id, app_version);
|
||||||
} else
|
} else
|
||||||
if (naming_convention == TitleNamingConvention_IdAndVersionOnly)
|
if (naming_convention == TitleNamingConvention_IdAndVersionOnly)
|
||||||
{
|
{
|
||||||
if (cur_filename_len) strcat(app_name, "+");
|
if (cur_filename_len) strcat(app_name, "+");
|
||||||
sprintf(app_name + strlen(app_name), "%016lX_v%u", app_info->meta_key.id, app_version);
|
app_name_len = strlen(app_name);
|
||||||
|
snprintf(app_name + app_name_len, MAX_ELEMENTS(app_name) - app_name_len, "%016lX_v%u", app_info->meta_key.id, app_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reallocate output buffer. */
|
/* Reallocate output buffer. */
|
||||||
size_t app_name_len = strlen(app_name);
|
app_name_len = strlen(app_name);
|
||||||
|
|
||||||
char *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)
|
if (!tmp_filename)
|
||||||
|
|
Loading…
Reference in a new issue