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

Title handler changes.

* Renamed titleRetrieveContentMetaKeysFromDatabase() to titleGenerateTitleInfoFromStorage().

* Moved linked lists generation from titleRetrieveContentMetaKeysFromDatabase() into its own function: titleUpdateTitleInfoLinkedLists().

* Adjusted orphan title checks. It is now explicitly verified if application metadata is available before treating a title as orphan, instead of checking if the parent user application is available.

* Code cleanup in titleRefreshGameCardTitleInfo().

* titleRefreshGameCardTitleInfo() now attempts to update the application metadata pointer in orphan title entries if new application metadata was retrieved after a gamecard was inserted *and* if the orphan title count is currently non-zero.

* Updated titleRemoveGameCardTitleInfoEntries() to make it use titleUpdateTitleInfoLinkedLists().
This commit is contained in:
Pablo Curiel 2021-02-22 17:30:47 -04:00
parent 6df7ff0cba
commit a90d8f2074
2 changed files with 105 additions and 104 deletions

View file

@ -398,8 +398,9 @@ static bool titleOpenNcmDatabaseAndStorageFromGameCard(void);
static void titleCloseNcmDatabaseAndStorageFromGameCard(void); static void titleCloseNcmDatabaseAndStorageFromGameCard(void);
static bool titleLoadPersistentStorageTitleInfo(void); static bool titleLoadPersistentStorageTitleInfo(void);
static bool titleRetrieveContentMetaKeysFromDatabase(u8 storage_id); static bool titleGenerateTitleInfoFromStorage(u8 storage_id);
static bool titleGetContentInfosFromTitle(u8 storage_id, const NcmContentMetaKey *meta_key, NcmContentInfo **out_content_infos, u32 *out_content_count); static bool titleGetContentInfosFromTitle(u8 storage_id, const NcmContentMetaKey *meta_key, NcmContentInfo **out_content_infos, u32 *out_content_count);
static void titleUpdateTitleInfoLinkedLists(void);
static bool titleCreateGameCardInfoThread(void); static bool titleCreateGameCardInfoThread(void);
static void titleDestroyGameCardInfoThread(void); static void titleDestroyGameCardInfoThread(void);
@ -712,7 +713,7 @@ TitleInfo **titleGetInfoFromOrphanTitles(u32 *out_count)
for(u32 i = 0, j = 0; i < g_titleInfoCount && j < g_titleInfoOrphanCount; i++) for(u32 i = 0, j = 0; i < g_titleInfoCount && j < g_titleInfoOrphanCount; i++)
{ {
TitleInfo *title_info = &(g_titleInfo[i]); TitleInfo *title_info = &(g_titleInfo[i]);
if ((title_info->meta_key.type == NcmContentMetaType_Patch || title_info->meta_key.type == NcmContentMetaType_AddOnContent) && !title_info->parent) orphan_info[j++] = title_info; if ((title_info->meta_key.type == NcmContentMetaType_Patch || title_info->meta_key.type == NcmContentMetaType_AddOnContent) && !title_info->app_metadata) orphan_info[j++] = title_info;
} }
/* Sort orphan title info entries by title ID. */ /* Sort orphan title info entries by title ID. */
@ -1270,10 +1271,10 @@ static bool titleLoadPersistentStorageTitleInfo(void)
for(u8 i = NcmStorageId_BuiltInSystem; i <= NcmStorageId_SdCard; i++) for(u8 i = NcmStorageId_BuiltInSystem; i <= NcmStorageId_SdCard; i++)
{ {
/* Retrieve content meta keys from the current storage. */ /* Generate title info from the current storage. */
if (!titleRetrieveContentMetaKeysFromDatabase(i)) if (!titleGenerateTitleInfoFromStorage(i))
{ {
LOGFILE("Failed to retrieve content meta keys from storage ID %u!", i); LOGFILE("Failed to generate title info from storage ID %u!", i);
return false; return false;
} }
} }
@ -1281,7 +1282,7 @@ static bool titleLoadPersistentStorageTitleInfo(void)
return true; return true;
} }
static bool titleRetrieveContentMetaKeysFromDatabase(u8 storage_id) static bool titleGenerateTitleInfoFromStorage(u8 storage_id)
{ {
NcmContentMetaDatabase *ncm_db = NULL; NcmContentMetaDatabase *ncm_db = NULL;
@ -1411,62 +1412,11 @@ static bool titleRetrieveContentMetaKeysFromDatabase(u8 storage_id)
/* Update title info count. */ /* Update title info count. */
g_titleInfoCount += total; g_titleInfoCount += total;
/* Update success flag. Nothing past this point will generate errors. */ /* Update linked lists for user applications, patches and add-on contents if we're not dealing with system titles. */
/* Also jump to the end of this function if we're dealing with eMMC System titles. */ if (storage_id != NcmStorageId_BuiltInSystem) titleUpdateTitleInfoLinkedLists();
/* Update flag. */
success = true; success = true;
if (storage_id == NcmStorageId_BuiltInSystem) goto end;
/* Update linked lists pointers for user applications, patches and add-on contents. */
g_titleInfoOrphanCount = 0;
for(u32 i = 0; i < g_titleInfoCount; i++)
{
TitleInfo *child_info = &(g_titleInfo[i]);
child_info->parent = child_info->previous = child_info->next = NULL;
if (child_info->meta_key.type != NcmContentMetaType_Application && child_info->meta_key.type != NcmContentMetaType_Patch && \
child_info->meta_key.type != NcmContentMetaType_AddOnContent) continue;
if (child_info->meta_key.type == NcmContentMetaType_Patch || child_info->meta_key.type == NcmContentMetaType_AddOnContent)
{
/* Retrieve pointer to 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). */
for(u32 j = 0; j < g_titleInfoCount; j++)
{
TitleInfo *parent_info = &(g_titleInfo[j]);
if (parent_info->meta_key.type == NcmContentMetaType_Application && \
((child_info->meta_key.type == NcmContentMetaType_Patch && titleCheckIfPatchIdBelongsToApplicationId(parent_info->meta_key.id, child_info->meta_key.id)) || \
(child_info->meta_key.type == NcmContentMetaType_AddOnContent && titleCheckIfAddOnContentIdBelongsToApplicationId(parent_info->meta_key.id, child_info->meta_key.id))))
{
child_info->parent = parent_info;
break;
}
}
/* Increase orphan title count if we couldn't find the parent user application. */
if (!child_info->parent)
{
g_titleInfoOrphanCount++;
continue;
}
}
/* 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. */
for(u32 j = i; j > 0; j--)
{
TitleInfo *previous_info = &(g_titleInfo[j - 1]);
if (previous_info->meta_key.type == child_info->meta_key.type && (((child_info->meta_key.type == NcmContentMetaType_Application || child_info->meta_key.type == NcmContentMetaType_Patch) && \
previous_info->meta_key.id == child_info->meta_key.id) || (child_info->meta_key.type == NcmContentMetaType_AddOnContent && \
titleCheckIfAddOnContentIdsAreSiblings(previous_info->meta_key.id, child_info->meta_key.id))))
{
previous_info->next = child_info;
child_info->previous = previous_info;
break;
}
}
}
end: end:
if (meta_keys) free(meta_keys); if (meta_keys) free(meta_keys);
@ -1550,6 +1500,67 @@ end:
return success; return success;
} }
static void titleUpdateTitleInfoLinkedLists(void)
{
/* Reset orphan title count. */
g_titleInfoOrphanCount = 0;
/* Loop through all available titles. */
for(u32 i = 0; i < g_titleInfoCount; i++)
{
/* Get pointer to the current title info and reset its linked list pointers. */
TitleInfo *child_info = &(g_titleInfo[i]);
child_info->parent = child_info->previous = child_info->next = NULL;
/* Only proceed if we're dealing with a user application, a patch or an add-on content. */
if (child_info->meta_key.type != NcmContentMetaType_Application && child_info->meta_key.type != NcmContentMetaType_Patch && \
child_info->meta_key.type != NcmContentMetaType_AddOnContent) continue;
/* Check if we're dealing with a patch or an add-on content. */
if (child_info->meta_key.type == NcmContentMetaType_Patch || child_info->meta_key.type == NcmContentMetaType_AddOnContent)
{
/* 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). */
for(u32 j = 0; j < g_titleInfoCount; j++)
{
TitleInfo *parent_info = &(g_titleInfo[j]);
if (parent_info->meta_key.type == NcmContentMetaType_Application && \
((child_info->meta_key.type == NcmContentMetaType_Patch && titleCheckIfPatchIdBelongsToApplicationId(parent_info->meta_key.id, child_info->meta_key.id)) || \
(child_info->meta_key.type == NcmContentMetaType_AddOnContent && titleCheckIfAddOnContentIdBelongsToApplicationId(parent_info->meta_key.id, child_info->meta_key.id))))
{
child_info->parent = parent_info;
if (!child_info->app_metadata) child_info->app_metadata = parent_info->app_metadata;
break;
}
}
/* Increase orphan title count if we have no application metadata. */
if (!child_info->app_metadata)
{
g_titleInfoOrphanCount++;
continue;
}
}
/* 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. */
for(u32 j = i; j > 0; j--)
{
TitleInfo *previous_info = &(g_titleInfo[j - 1]);
if (previous_info->meta_key.type == child_info->meta_key.type && (((child_info->meta_key.type == NcmContentMetaType_Application || child_info->meta_key.type == NcmContentMetaType_Patch) && \
previous_info->meta_key.id == child_info->meta_key.id) || (child_info->meta_key.type == NcmContentMetaType_AddOnContent && \
titleCheckIfAddOnContentIdsAreSiblings(previous_info->meta_key.id, child_info->meta_key.id))))
{
previous_info->next = child_info;
child_info->previous = previous_info;
break;
}
}
}
}
static bool titleCreateGameCardInfoThread(void) static bool titleCreateGameCardInfoThread(void)
{ {
if (!utilsCreateThread(&g_titleGameCardInfoThread, titleGameCardInfoThreadFunc, NULL, 1)) if (!utilsCreateThread(&g_titleGameCardInfoThread, titleGameCardInfoThreadFunc, NULL, 1))
@ -1636,7 +1647,7 @@ static void titleGameCardInfoThreadFunc(void *arg)
static bool titleRefreshGameCardTitleInfo(void) static bool titleRefreshGameCardTitleInfo(void)
{ {
TitleApplicationMetadata *tmp_app_metadata = NULL; TitleApplicationMetadata *tmp_app_metadata = NULL;
u32 orig_app_count = g_appMetadataCount, cur_app_count = g_appMetadataCount, gamecard_app_count = 0, gamecard_metadata_count = 0; u32 orig_app_count = g_appMetadataCount, cur_app_count = g_appMetadataCount, gamecard_metadata_count = 0;
bool status = false, success = false, cleanup = true; bool status = false, success = false, cleanup = true;
/* Retrieve current gamecard status. */ /* Retrieve current gamecard status. */
@ -1657,10 +1668,10 @@ static bool titleRefreshGameCardTitleInfo(void)
/* Update start index for the gamecard title info entries. */ /* Update start index for the gamecard title info entries. */
g_titleInfoGameCardStartIndex = g_titleInfoCount; g_titleInfoGameCardStartIndex = g_titleInfoCount;
/* Retrieve content meta keys from the gamecard ncm database. */ /* Generate gamecard title info. */
if (!titleRetrieveContentMetaKeysFromDatabase(NcmStorageId_GameCard)) if (!titleGenerateTitleInfoFromStorage(NcmStorageId_GameCard))
{ {
LOGFILE("Failed to retrieve content meta keys from gamecard!"); LOGFILE("Failed to generate gamecard title info!");
goto end; goto end;
} }
@ -1682,15 +1693,8 @@ static bool titleRefreshGameCardTitleInfo(void)
(cur_title_info->meta_key.type == NcmContentMetaType_AddOnContent ? titleGetApplicationIdByAddOnContentId(cur_title_info->meta_key.id) : \ (cur_title_info->meta_key.type == NcmContentMetaType_AddOnContent ? titleGetApplicationIdByAddOnContentId(cur_title_info->meta_key.id) : \
titleGetApplicationIdByDeltaId(cur_title_info->meta_key.id)))); titleGetApplicationIdByDeltaId(cur_title_info->meta_key.id))));
/* Update gamecard application count (if needed). */
if (cur_title_info->meta_key.type == NcmContentMetaType_Application) gamecard_app_count++;
/* Do not proceed if application metadata has already been retrieved, or if we can successfully retrieve it. */ /* Do not proceed if application metadata has already been retrieved, or if we can successfully retrieve it. */
if (cur_title_info->app_metadata != NULL || (cur_title_info->app_metadata = titleFindApplicationMetadataByTitleId(app_id)) != NULL) if (cur_title_info->app_metadata != NULL || (cur_title_info->app_metadata = titleFindApplicationMetadataByTitleId(app_id)) != NULL) continue;
{
gamecard_metadata_count++;
continue;
}
/* Reallocate application metadata buffer (if needed). */ /* Reallocate application metadata buffer (if needed). */
if (cur_app_count < (g_appMetadataCount + 1)) if (cur_app_count < (g_appMetadataCount + 1))
@ -1715,24 +1719,31 @@ static bool titleRefreshGameCardTitleInfo(void)
gamecard_metadata_count++; gamecard_metadata_count++;
} }
/* Check gamecard application count. */ /* Check if we retrieved new application metadata that was previously unavailable. */
if (!gamecard_app_count) if (gamecard_metadata_count)
{ {
LOGFILE("Gamecard application count is zero!");
goto end;
}
/* Check retrieved application metadata count. */
if (!gamecard_metadata_count)
{
LOGFILE("Unable to retrieve application metadata from gamecard! (%u %s).", gamecard_app_count, gamecard_app_count > 1 ? "entries" : "entry");
goto end;
}
/* Sort application metadata entries by name. */ /* Sort application metadata entries by name. */
u32 new_app_count = (g_appMetadataCount - g_systemTitlesCount); qsort(g_appMetadata + g_systemTitlesCount, gamecard_metadata_count, sizeof(TitleApplicationMetadata), &titleUserApplicationMetadataEntrySortFunction);
if (g_appMetadataCount > orig_app_count && new_app_count > 1) qsort(g_appMetadata + g_systemTitlesCount, new_app_count, sizeof(TitleApplicationMetadata), \
&titleUserApplicationMetadataEntrySortFunction); /* Check if the orphan title count is non-zero. */
if (g_titleInfoOrphanCount)
{
/* 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->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++;
}
}
}
success = true; success = true;
cleanup = false; cleanup = false;
@ -1774,19 +1785,6 @@ static void titleRemoveGameCardTitleInfoEntries(void)
/* Free all title info entries. */ /* Free all title info entries. */
titleFreeTitleInfo(); titleFreeTitleInfo();
} else { } else {
/* Update parent, previous and next title info pointers from user application, patch and add-on content entries. */
for(u32 i = 0; i < g_titleInfoGameCardStartIndex; i++)
{
TitleInfo *cur_title_info = &(g_titleInfo[i]);
if (cur_title_info->meta_key.type != NcmContentMetaType_Application && cur_title_info->meta_key.type != NcmContentMetaType_Patch && \
cur_title_info->meta_key.type != NcmContentMetaType_AddOnContent) continue;
if (cur_title_info->parent && cur_title_info->parent->storage_id == NcmStorageId_GameCard) cur_title_info->parent = NULL;
if (cur_title_info->previous && cur_title_info->previous->storage_id == NcmStorageId_GameCard) cur_title_info->previous = NULL;
if (cur_title_info->next && cur_title_info->next->storage_id == NcmStorageId_GameCard) cur_title_info->next = NULL;
}
/* Free content infos from gamecard title info entries. */ /* Free content infos from gamecard title info entries. */
for(u32 i = g_titleInfoGameCardStartIndex; i < g_titleInfoCount; i++) for(u32 i = g_titleInfoGameCardStartIndex; i < g_titleInfoCount; i++)
{ {
@ -1805,6 +1803,9 @@ static void titleRemoveGameCardTitleInfoEntries(void)
/* Update counters. */ /* Update counters. */
g_titleInfoCount = g_titleInfoGameCardStartIndex; g_titleInfoCount = g_titleInfoGameCardStartIndex;
g_titleInfoGameCardStartIndex = g_titleInfoGameCardCount = 0; g_titleInfoGameCardStartIndex = g_titleInfoGameCardCount = 0;
/* Update linked lists for user applications, patches and add-on contents. */
titleUpdateTitleInfoLinkedLists();
} }
} }

View file

@ -31,7 +31,7 @@
#define TITLE_DELTA_TYPE_VALUE (u64)0xC00 #define TITLE_DELTA_TYPE_VALUE (u64)0xC00
/// Retrieved using ns application records and/or ncm content meta keys. /// Generated using ns application records and/or ncm content meta keys.
/// Used by the UI to display title lists. /// Used by the UI to display title lists.
typedef struct { typedef struct {
u64 title_id; ///< Title ID from the application / system title this data belongs to. u64 title_id; ///< Title ID from the application / system title this data belongs to.
@ -40,7 +40,7 @@ typedef struct {
u8 *icon; ///< JPEG icon data. u8 *icon; ///< JPEG icon data.
} TitleApplicationMetadata; } TitleApplicationMetadata;
/// Retrieved using ncm databases. /// Generated using ncm databases.
typedef struct _TitleInfo { typedef struct _TitleInfo {
u8 storage_id; ///< NcmStorageId. u8 storage_id; ///< NcmStorageId.
NcmContentMetaKey meta_key; ///< Used with ncm calls. NcmContentMetaKey meta_key; ///< Used with ncm calls.