From 90c6d8a9f8711c8e00420dec9ba830e35a4f89a0 Mon Sep 17 00:00:00 2001 From: Pablo Curiel Date: Thu, 13 Aug 2020 14:12:33 -0400 Subject: [PATCH] Use linked lists to deal with user applications available in multiple storages at the same time. --- source/title.c | 58 ++++++++++++++++++++++++++------------------------ source/title.h | 12 +++++------ 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/source/title.c b/source/title.c index 09b6505..0556bb6 100644 --- a/source/title.c +++ b/source/title.c @@ -629,7 +629,7 @@ bool titleGetUserApplicationData(u64 app_id, TitleUserApplicationData *out) /* Clear output. */ memset(out, 0, sizeof(TitleUserApplicationData)); - /* Get user application title info. */ + /* Get first user application title info. */ out->app_info = _titleGetInfoFromStorageByTitleId(NcmStorageId_Any, app_id, false); /* Get first patch title info. */ @@ -653,9 +653,6 @@ bool titleGetUserApplicationData(u64 app_id, TitleUserApplicationData *out) goto end; } - /* Update 'gamecard_available' flag. */ - out->gamecard_available = (out->app_info && (out->app_info->storage_id == NcmStorageId_GameCard || _titleGetInfoFromStorageByTitleId(NcmStorageId_GameCard, app_id, false) != NULL)); - end: mutexUnlock(&g_titleMutex); @@ -1219,46 +1216,51 @@ static bool titleRetrieveContentMetaKeysFromDatabase(u8 storage_id) /* Update title info count. */ g_titleInfoCount += total; - /* Fill patch / add-on content specific info. */ + /* 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]); - if (child_info->meta_key.type != NcmContentMetaType_Patch && child_info->meta_key.type != NcmContentMetaType_AddOnContent) continue; + child_info->parent = child_info->previous = child_info->next = NULL; - /* Retrieve pointer to parent entry. */ - /* 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++) + 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) { - 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)))) + /* 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++) { - child_info->parent = parent_info; - break; + 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; } } - /* Increase orphan title count if we couldn't find the parent user application. */ - if (!child_info->parent) - { - g_titleInfoOrphanCount++; - continue; - } - - /* Locate previous patch / 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. */ - /* We will also update its parent entry pointer. */ 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_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)))) + 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->parent = child_info->parent; previous_info->next = child_info; child_info->previous = previous_info; break; diff --git a/source/title.h b/source/title.h index f2834d1..f2ca40b 100644 --- a/source/title.h +++ b/source/title.h @@ -59,15 +59,15 @@ typedef struct _TitleInfo { u64 title_size; ///< Total title size. char title_size_str[32]; ///< Total title size string. TitleApplicationMetadata *app_metadata; ///< Only available for system titles and applications. - struct _TitleInfo *parent, *previous, *next; ///< Used with TitleInfo entries from patches and add-on contents. + struct _TitleInfo *parent, *previous, *next; ///< Used with TitleInfo entries from user applications, patches and add-on contents. The parent pointer is unused in user applications. } TitleInfo; /// Used to deal with user applications stored in the eMMC, SD card and/or gamecard. +/// The parent, previous and next pointers from the TitleInfo elements are used to traverse through multiple user applications, patches and/or add-on contents. typedef struct { - bool gamecard_available; ///< Set to true if one or more titles matching this user application are stored in the inserted gamecard. - TitleInfo *app_info; ///< Pointer to a TitleInfo element for this application. - TitleInfo *patch_info; ///< Pointer to a TitleInfo element for the first detected patch. - TitleInfo *aoc_info; ///< Pointer to a TitleInfo element for the first detected add-on content. + TitleInfo *app_info; ///< Pointer to a TitleInfo element holding info for the first detected user application entry matching the provided application ID. + TitleInfo *patch_info; ///< Pointer to a TitleInfo element holding info for the first detected patch entry matching the provided application ID. + TitleInfo *aoc_info; ///< Pointer to a TitleInfo element holding info for the first detected add-on content entry matching the provided application ID. } TitleUserApplicationData; /// Initializes the title interface. @@ -97,7 +97,7 @@ TitleInfo *titleGetInfoFromStorageByTitleId(u8 storage_id, u64 title_id); bool titleGetUserApplicationData(u64 app_id, TitleUserApplicationData *out); /// Returns true if orphan titles are available. -/// Orphan titles are patches or add-on contents with no NsApplicationControlData available for its parent user application ID. +/// Orphan titles are patches or add-on contents with no NsApplicationControlData available for their parent user application ID. bool titleAreOrphanTitlesAvailable(void); /// Returns a pointer to a dynamically allocated buffer of pointers to TitleInfo entries from orphan titles, as well as their count. The allocated buffer must be freed by the calling function.