1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-11-26 12:12:02 +00:00

Keep indexes and counters for all supported storage IDs.

Speeds up title lookups using a specific storage ID.

Also reworked a bit the way orphan titles are handled. Should be better now.
This commit is contained in:
Pablo Curiel 2021-03-10 09:10:43 -04:00
parent 34c15d92cc
commit 0ec60092df
3 changed files with 121 additions and 72 deletions

View file

@ -49,7 +49,15 @@ static NcmContentMetaDatabase g_ncmDbGameCard = {0}, g_ncmDbEmmcSystem = {0}, g_
static NcmContentStorage g_ncmStorageGameCard = {0}, g_ncmStorageEmmcSystem = {0}, g_ncmStorageEmmcUser = {0}, g_ncmStorageSdCard = {0}; static NcmContentStorage g_ncmStorageGameCard = {0}, g_ncmStorageEmmcSystem = {0}, g_ncmStorageEmmcUser = {0}, g_ncmStorageSdCard = {0};
static TitleInfo **g_titleInfo = NULL; static TitleInfo **g_titleInfo = NULL;
static u32 g_titleInfoCount = 0, g_titleInfoGameCardStartIndex = 0, g_titleInfoGameCardCount = 0, g_titleInfoOrphanCount = 0; static u32 g_titleInfoCount = 0;
static u32 g_titleInfoBuiltInSystemCount = 0; /* Start index is always zero. */
static u32 g_titleInfoBuiltInUserStartIndex = 0, g_titleInfoBuiltInUserCount = 0;
static u32 g_titleInfoSdCardStartIndex = 0, g_titleInfoSdCardCount = 0;
static u32 g_titleInfoGameCardStartIndex = 0, g_titleInfoGameCardCount = 0;
static TitleInfo **g_orphanTitleInfo = NULL;
static u32 g_orphanTitleInfoCount = 0;
static const char *g_titleNcmContentTypeNames[] = { static const char *g_titleNcmContentTypeNames[] = {
[NcmContentType_Meta] = "Meta", [NcmContentType_Meta] = "Meta",
@ -385,6 +393,9 @@ static bool titleReallocateApplicationMetadata(u32 extra_app_count, bool free_en
NX_INLINE void titleFreeTitleInfo(void); NX_INLINE void titleFreeTitleInfo(void);
static bool titleReallocateTitleInfo(u32 extra_title_count, bool free_entries); static bool titleReallocateTitleInfo(u32 extra_title_count, bool free_entries);
NX_INLINE void titleFreeOrphanTitleInfo(void);
static void titleAddOrphanTitleInfoEntry(TitleInfo *orphan_title);
NX_INLINE TitleApplicationMetadata *titleFindApplicationMetadataByTitleId(u64 title_id); NX_INLINE TitleApplicationMetadata *titleFindApplicationMetadataByTitleId(u64 title_id);
static bool titleGenerateMetadataEntriesFromSystemTitles(void); static bool titleGenerateMetadataEntriesFromSystemTitles(void);
@ -600,6 +611,7 @@ TitleApplicationMetadata **titleGetApplicationMetadataEntries(bool is_system, u3
for(u32 i = start_idx; i < max_val; i++) for(u32 i = start_idx; i < max_val; i++)
{ {
TitleApplicationMetadata *cur_app_metadata = g_appMetadata[i]; TitleApplicationMetadata *cur_app_metadata = g_appMetadata[i];
if (!cur_app_metadata) continue;
/* Skip current metadata entry if content data for this title isn't available. */ /* Skip current metadata entry if content data for this title isn't available. */
if ((is_system && !_titleGetInfoFromStorageByTitleId(NcmStorageId_BuiltInSystem, cur_app_metadata->title_id, false)) || \ if ((is_system && !_titleGetInfoFromStorageByTitleId(NcmStorageId_BuiltInSystem, cur_app_metadata->title_id, false)) || \
@ -660,7 +672,7 @@ bool titleGetUserApplicationData(u64 app_id, TitleUserApplicationData *out)
out->patch_info = _titleGetInfoFromStorageByTitleId(NcmStorageId_Any, titleGetPatchIdByApplicationId(app_id), false); out->patch_info = _titleGetInfoFromStorageByTitleId(NcmStorageId_Any, titleGetPatchIdByApplicationId(app_id), false);
/* Get first add-on content title info. */ /* Get first add-on content title info. */
for(u32 i = 0; i < g_titleInfoCount; i++) for(u32 i = g_titleInfoBuiltInUserStartIndex; i < g_titleInfoCount; i++)
{ {
TitleInfo *title_info = g_titleInfo[i]; TitleInfo *title_info = g_titleInfo[i];
if (title_info && title_info->meta_key.type == NcmContentMetaType_AddOnContent && titleCheckIfAddOnContentIdBelongsToApplicationId(app_id, title_info->meta_key.id)) if (title_info && title_info->meta_key.type == NcmContentMetaType_AddOnContent && titleCheckIfAddOnContentIdBelongsToApplicationId(app_id, title_info->meta_key.id))
@ -687,7 +699,7 @@ end:
bool titleAreOrphanTitlesAvailable(void) bool titleAreOrphanTitlesAvailable(void)
{ {
mutexLock(&g_titleMutex); mutexLock(&g_titleMutex);
bool ret = (g_titleInterfaceInit && g_titleInfoOrphanCount > 0); bool ret = (g_titleInterfaceInit && g_orphanTitleInfo && *g_orphanTitleInfo && g_orphanTitleInfoCount > 0);
mutexUnlock(&g_titleMutex); mutexUnlock(&g_titleMutex);
return ret; return ret;
} }
@ -698,14 +710,14 @@ TitleInfo **titleGetInfoFromOrphanTitles(u32 *out_count)
TitleInfo **orphan_info = NULL; TitleInfo **orphan_info = NULL;
if (!g_titleInterfaceInit || !g_titleInfo || !*g_titleInfo || !g_titleInfoCount || !g_titleInfoOrphanCount || !out_count) if (!g_titleInterfaceInit || !g_titleInfo || !*g_titleInfo || !g_titleInfoCount || !g_orphanTitleInfo || !*g_orphanTitleInfo || !g_orphanTitleInfoCount || !out_count)
{ {
LOG_MSG("Invalid parameters!"); LOG_MSG("Invalid parameters!");
goto end; goto end;
} }
/* Allocate orphan title info pointer array. */ /* Allocate orphan title info pointer array. */
orphan_info = calloc(g_titleInfoOrphanCount, sizeof(TitleInfo*)); orphan_info = calloc(g_orphanTitleInfoCount, sizeof(TitleInfo*));
if (!orphan_info) if (!orphan_info)
{ {
LOG_MSG("Failed to allocate memory for orphan title info pointer array!"); LOG_MSG("Failed to allocate memory for orphan title info pointer array!");
@ -713,17 +725,10 @@ TitleInfo **titleGetInfoFromOrphanTitles(u32 *out_count)
} }
/* Get pointers to orphan title info entries. */ /* Get pointers to orphan title info entries. */
for(u32 i = 0, j = 0; i < g_titleInfoCount && j < g_titleInfoOrphanCount; i++) for(u32 i = 0; i < g_orphanTitleInfoCount; i++) orphan_info[i] = g_orphanTitleInfo[i];
{
TitleInfo *title_info = g_titleInfo[i];
if (title_info && title_info->meta_key.type != NcmContentMetaType_Application && !title_info->app_metadata) orphan_info[j++] = title_info;
}
/* Sort orphan title info entries by title ID. */
if (g_titleInfoOrphanCount > 1) qsort(orphan_info, g_titleInfoOrphanCount, sizeof(TitleInfo*), &titleOrphanTitleInfoSortFunction);
/* Update output counter. */ /* Update output counter. */
*out_count = g_titleInfoOrphanCount; *out_count = g_orphanTitleInfoCount;
end: end:
mutexUnlock(&g_titleMutex); mutexUnlock(&g_titleMutex);
@ -804,9 +809,9 @@ char *titleGenerateGameCardFileName(u8 name_convention, u8 illegal_char_replace_
char *filename = NULL, *tmp_filename = NULL; char *filename = NULL, *tmp_filename = NULL;
char app_name[0x400] = {0}; char app_name[0x400] = {0};
if (!g_titleInterfaceInit || !g_titleGameCardAvailable || !g_titleInfo || !*g_titleInfo || !g_titleInfoCount || !g_titleInfoGameCardCount || g_titleInfoGameCardCount > g_titleInfoCount || \ if (!g_titleInterfaceInit || !g_titleInfo || !*g_titleInfo || !g_titleInfoCount || !g_titleGameCardAvailable || !g_titleInfoGameCardCount || \
g_titleInfoGameCardStartIndex != (g_titleInfoCount - g_titleInfoGameCardCount) || name_convention > TitleFileNameConvention_IdAndVersionOnly || \ name_convention > TitleFileNameConvention_IdAndVersionOnly || (name_convention == TitleFileNameConvention_Full && \
(name_convention == TitleFileNameConvention_Full && illegal_char_replace_type > TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly)) illegal_char_replace_type > TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly))
{ {
LOG_MSG("Invalid parameters!"); LOG_MSG("Invalid parameters!");
goto end; goto end;
@ -992,7 +997,12 @@ NX_INLINE void titleFreeTitleInfo(void)
g_titleInfo = NULL; g_titleInfo = NULL;
} }
g_titleInfoCount = g_titleInfoGameCardStartIndex = g_titleInfoGameCardCount = g_titleInfoOrphanCount = 0; titleFreeOrphanTitleInfo();
g_titleInfoCount = g_titleInfoBuiltInSystemCount = 0;
g_titleInfoBuiltInUserStartIndex = g_titleInfoBuiltInUserCount = 0;
g_titleInfoSdCardStartIndex = g_titleInfoSdCardCount = 0;
g_titleInfoGameCardStartIndex = g_titleInfoGameCardCount = 0;
} }
static bool titleReallocateTitleInfo(u32 extra_title_count, bool free_entries) static bool titleReallocateTitleInfo(u32 extra_title_count, bool free_entries)
@ -1051,6 +1061,39 @@ end:
return success; return success;
} }
NX_INLINE void titleFreeOrphanTitleInfo(void)
{
if (g_orphanTitleInfo)
{
free(g_orphanTitleInfo);
g_orphanTitleInfo = NULL;
}
g_orphanTitleInfoCount = 0;
}
static void titleAddOrphanTitleInfoEntry(TitleInfo *orphan_title)
{
if (!orphan_title) return;
/* Reallocate orphan title info pointer array. */
TitleInfo **tmp_orphan_info = realloc(g_orphanTitleInfo, (g_orphanTitleInfoCount + 1) * sizeof(TitleInfo*));
if (!tmp_orphan_info)
{
LOG_MSG("Failed to reallocate orphan title info pointer array!");
return;
}
g_orphanTitleInfo = tmp_orphan_info;
tmp_orphan_info = NULL;
/* Set orphan title info entry pointer. */
g_orphanTitleInfo[g_orphanTitleInfoCount++] = orphan_title;
/* Sort orphan title info entries by title ID. */
if (g_orphanTitleInfoCount > 1) qsort(g_orphanTitleInfo, g_orphanTitleInfoCount, sizeof(TitleInfo*), &titleOrphanTitleInfoSortFunction);
}
NX_INLINE TitleApplicationMetadata *titleFindApplicationMetadataByTitleId(u64 title_id) NX_INLINE TitleApplicationMetadata *titleFindApplicationMetadataByTitleId(u64 title_id)
{ {
if (!g_appMetadata || !*g_appMetadata || !g_appMetadataCount || !title_id) return NULL; if (!g_appMetadata || !*g_appMetadata || !g_appMetadataCount || !title_id) return NULL;
@ -1058,7 +1101,7 @@ NX_INLINE TitleApplicationMetadata *titleFindApplicationMetadataByTitleId(u64 ti
for(u32 i = 0; i < g_appMetadataCount; i++) for(u32 i = 0; i < g_appMetadataCount; i++)
{ {
TitleApplicationMetadata *cur_app_metadata = g_appMetadata[i]; TitleApplicationMetadata *cur_app_metadata = g_appMetadata[i];
if (cur_app_metadata->title_id == title_id) return cur_app_metadata; if (cur_app_metadata && cur_app_metadata->title_id == title_id) return cur_app_metadata;
} }
return NULL; return NULL;
@ -1411,12 +1454,37 @@ static bool titleLoadPersistentStorageTitleInfo(void)
for(u8 i = NcmStorageId_BuiltInSystem; i <= NcmStorageId_SdCard; i++) for(u8 i = NcmStorageId_BuiltInSystem; i <= NcmStorageId_SdCard; i++)
{ {
u32 cur_title_count = 0;
/* Generate title info from the current storage. */ /* Generate title info from the current storage. */
if (!titleGenerateTitleInfoFromStorage(i)) if (!titleGenerateTitleInfoFromStorage(i))
{ {
LOG_MSG("Failed to generate title info from storage ID %u!", i); LOG_MSG("Failed to generate title info from storage ID %u!", i);
return false; return false;
} }
/* Update title info counters and indexes. */
switch(i)
{
case NcmStorageId_BuiltInSystem:
g_titleInfoBuiltInSystemCount = g_titleInfoCount;
cur_title_count = g_titleInfoBuiltInSystemCount;
break;
case NcmStorageId_BuiltInUser:
g_titleInfoBuiltInUserStartIndex = g_titleInfoBuiltInSystemCount;
g_titleInfoBuiltInUserCount = (g_titleInfoCount - g_titleInfoBuiltInUserStartIndex);
cur_title_count = g_titleInfoBuiltInUserCount;
break;
case NcmStorageId_SdCard:
g_titleInfoSdCardStartIndex = (g_titleInfoBuiltInUserStartIndex + g_titleInfoBuiltInUserCount);
g_titleInfoSdCardCount = (g_titleInfoCount - g_titleInfoSdCardStartIndex);
cur_title_count = g_titleInfoSdCardCount;
break;
default:
break;
}
LOG_MSG("Loaded info for %u title(s) from storage ID %u.", cur_title_count, i);
} }
return true; return true;
@ -1667,32 +1735,24 @@ end:
static void titleUpdateTitleInfoLinkedLists(void) static void titleUpdateTitleInfoLinkedLists(void)
{ {
/* Reset orphan title count. */ /* Free orphan title info. */
g_titleInfoOrphanCount = 0; titleFreeOrphanTitleInfo();
/* Loop through all available titles. */ /* Loop through all available user titles. */
for(u32 i = 0; i < g_titleInfoCount; i++) for(u32 i = g_titleInfoBuiltInUserStartIndex; i < g_titleInfoCount; i++)
{ {
/* Get pointer to the current title info and reset its linked list pointers. */ /* Get pointer to the current title info and reset its linked list pointers. */
TitleInfo *child_info = g_titleInfo[i]; TitleInfo *child_info = g_titleInfo[i];
if (!child_info) continue; if (!child_info || child_info->meta_key.type < NcmContentMetaType_Application || child_info->meta_key.type > NcmContentMetaType_AddOnContent) continue;
child_info->parent = child_info->previous = child_info->next = NULL; child_info->parent = child_info->previous = child_info->next = NULL;
if (child_info->meta_key.type < NcmContentMetaType_Application)
{
/* We're dealing with a system title. */
/* Increase orphan title count if we have no application metadata. Immediately proceed onto the next loop iteration. */
/* We don't generate linked lists for system titles. */
if (!child_info->app_metadata) g_titleInfoOrphanCount++;
continue;
} else
if (child_info->meta_key.type == NcmContentMetaType_Patch || child_info->meta_key.type == NcmContentMetaType_AddOnContent) if (child_info->meta_key.type == NcmContentMetaType_Patch || child_info->meta_key.type == NcmContentMetaType_AddOnContent)
{ {
/* We're dealing with a patch or an add-on content. */ /* We're dealing with a patch or an add-on content. */
/* Retrieve pointer to the first parent user application entry for patches and add-on contents. */ /* Retrieve pointer to the first parent user application entry for patches and add-on contents. */
/* Since gamecard title info entries are always appended to the end of the buffer, this guarantees we will first retrieve an eMMC / SD card entry (if available). */ /* Since gamecard title info entries are always appended to the end of the buffer, this guarantees we will first retrieve an eMMC / SD card entry (if available). */
for(u32 j = 0; j < g_titleInfoCount; j++) for(u32 j = g_titleInfoBuiltInUserStartIndex; j < g_titleInfoCount; j++)
{ {
TitleInfo *parent_info = g_titleInfo[j]; TitleInfo *parent_info = g_titleInfo[j];
if (!parent_info) continue; if (!parent_info) continue;
@ -1707,13 +1767,13 @@ static void titleUpdateTitleInfoLinkedLists(void)
} }
} }
/* If we have no application metadata, increase orphan title count. */ /* If we have no application metadata, add orphan title info entry. */
if (!child_info->app_metadata) g_titleInfoOrphanCount++; if (!child_info->app_metadata) titleAddOrphanTitleInfoEntry(child_info);
} }
/* Locate previous user application, patch or add-on content entry. */ /* Locate previous user application, patch or add-on content entry. */
/* If it's found, we will update both its next pointer and the previous pointer from the current entry. */ /* If it's found, we will update both its next pointer and the previous pointer from the current entry. */
for(u32 j = i; j > 0; j--) for(u32 j = i; j > g_titleInfoBuiltInUserStartIndex; j--)
{ {
TitleInfo *previous_info = g_titleInfo[j - 1]; TitleInfo *previous_info = g_titleInfo[j - 1];
if (!previous_info) continue; if (!previous_info) continue;
@ -1924,24 +1984,9 @@ static bool titleRefreshGameCardTitleInfo(void)
u32 user_app_metadata_count = (g_appMetadataCount - g_systemTitlesCount); u32 user_app_metadata_count = (g_appMetadataCount - g_systemTitlesCount);
if (user_app_metadata_count > 1) qsort(g_appMetadata + g_systemTitlesCount, user_app_metadata_count, sizeof(TitleApplicationMetadata*), &titleUserApplicationMetadataEntrySortFunction); if (user_app_metadata_count > 1) qsort(g_appMetadata + g_systemTitlesCount, user_app_metadata_count, sizeof(TitleApplicationMetadata*), &titleUserApplicationMetadataEntrySortFunction);
/* Check if the orphan title count is non-zero. */ /* Update linked lists for user applications, patches and add-on contents. */
if (g_titleInfoOrphanCount) /* This will take care of orphan titles we might now have application metadata for. */
{ titleUpdateTitleInfoLinkedLists();
/* Reset orphan title count. */
g_titleInfoOrphanCount = 0;
/* Try to update the application metadata pointer in orphan entries, hopefully reducing the orphan title count in the process. */
for(u32 i = 0; i < g_titleInfoCount; i++)
{
TitleInfo *title_info = g_titleInfo[i];
if (!title_info || (title_info->meta_key.type != NcmContentMetaType_Patch && title_info->meta_key.type != NcmContentMetaType_AddOnContent) || title_info->app_metadata) continue;
u64 app_id = (title_info->meta_key.type == NcmContentMetaType_Patch ? titleGetApplicationIdByPatchId(title_info->meta_key.id) : \
titleGetApplicationIdByAddOnContentId(title_info->meta_key.id));
if (!(title_info->app_metadata = titleFindApplicationMetadataByTitleId(app_id))) g_titleInfoOrphanCount++;
}
}
} else { } else {
/* Free leftover application metadata entry (if needed). */ /* Free leftover application metadata entry (if needed). */
if (g_appMetadata[g_appMetadataCount]) free(g_appMetadata[g_appMetadataCount]); if (g_appMetadata[g_appMetadataCount]) free(g_appMetadata[g_appMetadataCount]);
@ -1973,8 +2018,7 @@ end:
static void titleRemoveGameCardTitleInfoEntries(void) static void titleRemoveGameCardTitleInfoEntries(void)
{ {
if (!g_titleInfo || !*g_titleInfo || !g_titleInfoCount || !g_titleInfoGameCardCount || g_titleInfoGameCardCount > g_titleInfoCount || \ if (!g_titleInfo || !*g_titleInfo || !g_titleInfoCount || !g_titleInfoGameCardCount) return;
g_titleInfoGameCardStartIndex != (g_titleInfoCount - g_titleInfoGameCardCount)) return;
/* Update title info count. */ /* Update title info count. */
g_titleInfoCount = g_titleInfoGameCardStartIndex; g_titleInfoCount = g_titleInfoGameCardStartIndex;
@ -1994,7 +2038,7 @@ static bool titleIsUserApplicationContentAvailable(u64 app_id)
{ {
if (!g_titleInfo || !*g_titleInfo || !g_titleInfoCount || !app_id) return false; if (!g_titleInfo || !*g_titleInfo || !g_titleInfoCount || !app_id) return false;
for(u32 i = 0; i < g_titleInfoCount; i++) for(u32 i = g_titleInfoBuiltInUserStartIndex; i < g_titleInfoCount; i++)
{ {
TitleInfo *cur_title_info = g_titleInfo[i]; TitleInfo *cur_title_info = g_titleInfo[i];
if (!cur_title_info) continue; if (!cur_title_info) continue;
@ -2013,29 +2057,32 @@ static TitleInfo *_titleGetInfoFromStorageByTitleId(u8 storage_id, u64 title_id,
TitleInfo *info = NULL; TitleInfo *info = NULL;
if (!g_titleInterfaceInit || !g_titleInfo || !*g_titleInfo || !g_titleInfoCount || storage_id < NcmStorageId_GameCard || storage_id > NcmStorageId_Any || (storage_id == NcmStorageId_GameCard && \ u32 start_idx = ((storage_id == NcmStorageId_BuiltInSystem || storage_id == NcmStorageId_Any) ? 0 : (storage_id == NcmStorageId_BuiltInUser ? g_titleInfoBuiltInUserStartIndex : \
(!g_titleInfoGameCardCount || g_titleInfoGameCardCount > g_titleInfoCount || g_titleInfoGameCardStartIndex != (g_titleInfoCount - g_titleInfoGameCardCount))) || !title_id) (storage_id == NcmStorageId_SdCard ? g_titleInfoSdCardStartIndex : g_titleInfoGameCardStartIndex)));
u32 max_val = (storage_id == NcmStorageId_BuiltInSystem ? g_titleInfoBuiltInSystemCount : (storage_id == NcmStorageId_BuiltInUser ? g_titleInfoBuiltInUserCount : \
(storage_id == NcmStorageId_SdCard ? g_titleInfoSdCardCount : (storage_id == NcmStorageId_GameCard ? g_titleInfoGameCardCount : g_titleInfoCount))));
max_val += start_idx;
if (!g_titleInterfaceInit || !g_titleInfo || !*g_titleInfo || !g_titleInfoCount || storage_id < NcmStorageId_GameCard || storage_id > NcmStorageId_Any || max_val == start_idx || \
max_val > g_titleInfoCount || start_idx > g_titleInfoCount || !title_id)
{ {
LOG_MSG("Invalid parameters!"); LOG_MSG("Invalid parameters!");
goto end; goto end;
} }
/* Speed up gamecard lookups. */
u32 start_idx = (storage_id == NcmStorageId_GameCard ? g_titleInfoGameCardStartIndex : 0);
u32 max_val = ((storage_id == NcmStorageId_GameCard || storage_id == NcmStorageId_Any) ? g_titleInfoCount : (g_titleInfoGameCardCount ? g_titleInfoGameCardStartIndex : g_titleInfoCount));
for(u32 i = start_idx; i < max_val; i++) for(u32 i = start_idx; i < max_val; i++)
{ {
TitleInfo *title_info = g_titleInfo[i]; TitleInfo *title_info = g_titleInfo[i];
if (title_info && title_info->meta_key.id == title_id)
if (title_info && title_info->meta_key.id == title_id && (storage_id == NcmStorageId_Any || (storage_id != NcmStorageId_Any && title_info->storage_id == storage_id)))
{ {
info = title_info; info = title_info;
break; break;
} }
} }
if (!info && lock) LOG_MSG("Unable to find TitleInfo entry with ID \"%016lX\"! (storage ID %u).", title_id, storage_id); if (!info && lock) LOG_MSG("Unable to find title info entry with ID \"%016lX\"! (storage ID %u).", title_id, storage_id);
end: end:
if (lock) mutexUnlock(&g_titleMutex); if (lock) mutexUnlock(&g_titleMutex);

View file

@ -88,7 +88,7 @@ NcmContentStorage *titleGetNcmStorageByStorageId(u8 storage_id);
/// Returns a pointer to a dynamically allocated array of pointers to TitleApplicationMetadata entries, as well as their count. The allocated buffer must be freed by the calling function. /// Returns a pointer to a dynamically allocated array of pointers to TitleApplicationMetadata entries, as well as their count. The allocated buffer must be freed by the calling function.
/// If 'is_system' is true, TitleApplicationMetadata entries from available system titles (NcmStorageId_BuiltInSystem) will be returned. /// 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_Any) will be returned. /// Otherwise, TitleApplicationMetadata entries from user applications with available content data (NcmStorageId_BuiltInUser, NcmStorageId_SdCard, NcmStorageId_GameCard) will be returned.
/// Returns NULL if an error occurs. /// Returns NULL if an error occurs.
TitleApplicationMetadata **titleGetApplicationMetadataEntries(bool is_system, u32 *out_count); TitleApplicationMetadata **titleGetApplicationMetadataEntries(bool is_system, u32 *out_count);
@ -110,7 +110,9 @@ TitleInfo **titleGetInfoFromOrphanTitles(u32 *out_count);
/// 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). /// 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 so, gamecard title info entries will be updated or freed during this call, depending on the current gamecard status. /// If so, gamecard title info entries will be updated or freed during this call, depending on the current gamecard status.
/// If this function returns true and titleGetApplicationMetadataEntries() has been previously called, its returned buffer should be freed and it should be called again. /// If this function returns true and titleGetApplicationMetadataEntries() or titleGetInfoFromOrphanTitles() have been previously called:
/// 1. Their returned buffers should be freed.
/// 2. They must be called again.
bool titleIsGameCardInfoUpdated(void); bool titleIsGameCardInfoUpdated(void);
/// Returns a pointer to a dynamically allocated buffer that holds a filename string suitable for output title dumps. /// Returns a pointer to a dynamically allocated buffer that holds a filename string suitable for output title dumps.

View file

@ -124,6 +124,10 @@ bool utilsInitializeResources(void)
if (!_utilsIsDevelopmentUnit()) goto end; if (!_utilsIsDevelopmentUnit()) goto end;
LOG_MSG("Running under %s unit.", g_isDevUnit ? "development" : "retail"); LOG_MSG("Running under %s unit.", g_isDevUnit ? "development" : "retail");
/* Get applet type. */
g_programAppletType = appletGetAppletType();
LOG_MSG("Running under %s mode.", utilsAppletModeCheck() ? "applet" : "title override");
/* Initialize USB interface. */ /* Initialize USB interface. */
if (!usbInitialize()) if (!usbInitialize())
{ {
@ -172,10 +176,6 @@ bool utilsInitializeResources(void)
/* Mount eMMC BIS System partition. */ /* Mount eMMC BIS System partition. */
if (!utilsMountEmmcBisSystemPartitionStorage()) goto end; if (!utilsMountEmmcBisSystemPartitionStorage()) goto end;
/* Get applet type. */
g_programAppletType = appletGetAppletType();
LOG_MSG("Running under %s mode.", utilsAppletModeCheck() ? "applet" : "title override");
/* Disable screen dimming and auto sleep. */ /* Disable screen dimming and auto sleep. */
appletSetMediaPlaybackState(true); appletSetMediaPlaybackState(true);