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:
parent
6df7ff0cba
commit
a90d8f2074
2 changed files with 105 additions and 104 deletions
205
source/title.c
205
source/title.c
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in a new issue