From 7b707509c7b034f789d1e1c7de984b45e063a401 Mon Sep 17 00:00:00 2001 From: Pablo Curiel Date: Fri, 16 Feb 2024 23:31:24 +0100 Subject: [PATCH] bktr: perform binary search in bktrGetTreeNodeEntryIndex() Other changes include: * poc: fix switching to a different title entry via L/R/ZL/ZR if the content counts don't match. Fixes issues with MGS Master Collection games. --- Makefile | 4 +-- build.sh | 2 ++ code_templates/nxdt_rw_poc.c | 36 +++++++++++++---------- source/core/bktr.c | 56 ++++++++++++++++++++++-------------- 4 files changed, 59 insertions(+), 39 deletions(-) diff --git a/Makefile b/Makefile index 9bda507..7c80329 100644 --- a/Makefile +++ b/Makefile @@ -86,8 +86,8 @@ ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE CFLAGS := -g -Wall -Werror -O2 -ffunction-sections $(ARCH) $(DEFINES) $(INCLUDE) -D__SWITCH__ CFLAGS += -DVERSION_MAJOR=${VERSION_MAJOR} -DVERSION_MINOR=${VERSION_MINOR} -DVERSION_MICRO=${VERSION_MICRO} -CFLAGS += -DAPP_TITLE=\"${APP_TITLE}\" -DAPP_AUTHOR=\"${APP_AUTHOR}\" -DAPP_VERSION=\"${APP_VERSION}\" -CFLAGS += -DGIT_BRANCH=\"${GIT_BRANCH}\" -DGIT_COMMIT=\"${GIT_COMMIT}\" -DGIT_REV=\"${GIT_REV}\" +CFLAGS += -DAPP_TITLE="\"${APP_TITLE}\"" -DAPP_AUTHOR="\"${APP_AUTHOR}\"" -DAPP_VERSION="\"${APP_VERSION}\"" +CFLAGS += -DGIT_BRANCH="\"${GIT_BRANCH}\"" -DGIT_COMMIT="\"${GIT_COMMIT}\"" -DGIT_REV="\"${GIT_REV}\"" CFLAGS += -DBUILD_TIMESTAMP="\"${BUILD_TIMESTAMP}\"" -DBOREALIS_RESOURCES="\"${BOREALIS_RESOURCES}\"" -D_GNU_SOURCE CFLAGS += -fmacro-prefix-map=$(ROOTDIR)= diff --git a/build.sh b/build.sh index 2600c7f..553ccd0 100644 --- a/build.sh +++ b/build.sh @@ -31,3 +31,5 @@ make clean_all rm -f ./source/main.c mv -f ./main.cpp ./source/main.cpp + +read -rsp $'Press any key to continue...\n' -n 1 key diff --git a/code_templates/nxdt_rw_poc.c b/code_templates/nxdt_rw_poc.c index 2075b8f..a4ac5c7 100644 --- a/code_templates/nxdt_rw_poc.c +++ b/code_templates/nxdt_rw_poc.c @@ -181,8 +181,8 @@ void updateTitleList(Menu *menu, Menu *submenu, bool is_system); static TitleInfo *getLatestTitleInfo(TitleInfo *title_info, u32 *out_idx, u32 *out_count); void freeNcaList(void); -void updateNcaList(TitleInfo *title_info); -static void switchNcaListTitle(Menu *cur_menu, u32 *element_count, TitleInfo *title_info); +void updateNcaList(TitleInfo *title_info, u32 *element_count); +static void switchNcaListTitle(Menu **cur_menu, u32 *element_count, TitleInfo *title_info); void freeNcaFsSectionsList(void); void updateNcaFsSectionsList(NcaUserData *nca_user_data); @@ -1272,7 +1272,7 @@ int main(int argc, char *argv[]) if (child_menu->id == MenuId_Nca) { - updateNcaList(title_info); + updateNcaList(title_info, &element_count); if (!g_ncaMenuElements || !g_ncaMenuElements[0]) { @@ -1516,13 +1516,13 @@ int main(int argc, char *argv[]) { title_info = title_info->previous; title_info_idx--; - switchNcaListTitle(cur_menu, &element_count, title_info); + switchNcaListTitle(&cur_menu, &element_count, title_info); } else if (((btn_down & (HidNpadButton_R)) || (btn_held & HidNpadButton_ZR)) && (cur_menu->id == MenuId_NSP || cur_menu->id == MenuId_Ticket || cur_menu->id == MenuId_Nca) && title_info->next) { title_info = title_info->next; title_info_idx++; - switchNcaListTitle(cur_menu, &element_count, title_info); + switchNcaListTitle(&cur_menu, &element_count, title_info); } else if ((btn_down & HidNpadButton_Y) && cur_menu->id == MenuId_Nca) { @@ -1883,7 +1883,7 @@ void freeNcaList(void) g_ncaMenu.elements = NULL; } -void updateNcaList(TitleInfo *title_info) +void updateNcaList(TitleInfo *title_info, u32 *element_count) { u32 content_count = title_info->content_count, idx = 0; NcmContentInfo *content_infos = title_info->content_infos; @@ -1894,6 +1894,7 @@ void updateNcaList(TitleInfo *title_info) /* Allocate buffer. */ g_ncaMenuElements = calloc(content_count + 2, sizeof(MenuElement*)); // Output storage, NULL terminator + if (!g_ncaMenuElements) return; /* Generate menu elements. */ for(u32 i = 0; i < content_count; i++) @@ -1937,16 +1938,21 @@ void updateNcaList(TitleInfo *title_info) idx++; } - g_ncaMenuElements[content_count] = &g_storageMenuElement; + if (idx > 0) + { + g_ncaMenuElements[idx] = &g_storageMenuElement; - g_ncaMenu.elements = g_ncaMenuElements; + g_ncaMenu.elements = g_ncaMenuElements; + + if (element_count) *element_count = (idx + 1); + } } -static void switchNcaListTitle(Menu *cur_menu, u32 *element_count, TitleInfo *title_info) +static void switchNcaListTitle(Menu **cur_menu, u32 *element_count, TitleInfo *title_info) { - if (!cur_menu || cur_menu->id != MenuId_Nca || !element_count) return; + if (!cur_menu || !*cur_menu || (*cur_menu)->id != MenuId_Nca || !element_count || !title_info) return; - updateNcaList(title_info); + updateNcaList(title_info, element_count); if (!g_ncaMenuElements || !g_ncaMenuElements[0]) { @@ -1955,11 +1961,11 @@ static void switchNcaListTitle(Menu *cur_menu, u32 *element_count, TitleInfo *ti consoleRefresh(); utilsWaitForButtonPress(0); - cur_menu->selected = 0; - cur_menu->scroll = 0; + (*cur_menu)->selected = 0; + (*cur_menu)->scroll = 0; - cur_menu = cur_menu->parent; - *element_count = menuGetElementCount(cur_menu); + *cur_menu = (*cur_menu)->parent; + *element_count = menuGetElementCount(*cur_menu); } } diff --git a/source/core/bktr.c b/source/core/bktr.c index 2ae41a6..25515ca 100644 --- a/source/core/bktr.c +++ b/source/core/bktr.c @@ -1253,10 +1253,12 @@ static bool bktrValidateTableOffsetNode(const BucketTreeTable *table, u64 node_s u32 offset_count = bktrGetOffsetCount(node_size); u32 entry_set_count = bktrGetEntrySetCount(node_size, entry_size, entry_count); - const u64 start_offset = ((offset_count < entry_set_count && node_header->count < offset_count) ? *bktrGetOffsetNodeEnd(offset_node) : *bktrGetOffsetNodeBegin(offset_node)); + u64 node_start_offset = *bktrGetOffsetNodeBegin(offset_node); + + u64 start_offset = ((offset_count < entry_set_count && node_header->count < offset_count) ? *bktrGetOffsetNodeEnd(offset_node) : node_start_offset); u64 end_offset = node_header->offset; - if (start_offset > *bktrGetOffsetNodeBegin(offset_node) || start_offset >= end_offset || node_header->count != entry_set_count) + if (start_offset > node_start_offset || start_offset >= end_offset || node_header->count != entry_set_count) { LOG_MSG_ERROR("Invalid Bucket Tree Offset Node!"); return false; @@ -1353,13 +1355,14 @@ static bool bktrFindStorageEntry(BucketTreeContext *ctx, u64 virtual_offset, Buc /* Get the entry node index. */ u32 entry_set_index = 0; + const u64 *node_start_ptr = bktrGetOffsetNodeBegin(offset_node), *node_end_ptr = bktrGetOffsetNodeEnd(offset_node); const u64 *start_ptr = NULL, *end_ptr = NULL; bool success = false; - if (bktrIsExistOffsetL2OnL1(ctx) && virtual_offset < *bktrGetOffsetNodeBegin(offset_node)) + if (bktrIsExistOffsetL2OnL1(ctx) && virtual_offset < *node_start_ptr) { - start_ptr = bktrGetOffsetNodeEnd(offset_node); - end_ptr = (bktrGetOffsetNodeBegin(offset_node) + ctx->offset_count); + start_ptr = node_end_ptr; + end_ptr = (node_start_ptr + ctx->offset_count); if (!bktrGetTreeNodeEntryIndex(start_ptr, end_ptr, virtual_offset, &entry_set_index)) { @@ -1367,8 +1370,8 @@ static bool bktrFindStorageEntry(BucketTreeContext *ctx, u64 virtual_offset, Buc goto end; } } else { - start_ptr = bktrGetOffsetNodeBegin(offset_node); - end_ptr = bktrGetOffsetNodeEnd(offset_node); + start_ptr = node_start_ptr; + end_ptr = node_end_ptr; if (!bktrGetTreeNodeEntryIndex(start_ptr, end_ptr, virtual_offset, &entry_set_index)) { @@ -1410,28 +1413,37 @@ static bool bktrGetTreeNodeEntryIndex(const u64 *start_ptr, const u64 *end_ptr, return false; } - u64 *pos = (u64*)start_ptr; - u32 index = 0; + /* Perform a binary search. */ + u32 offset_count = (u32)(end_ptr - start_ptr), low = 0, high = (offset_count - 1); + bool ret = false; - while(pos < end_ptr) + while(low <= high) { - if (start_ptr < pos) + /* Get the index to the middle offset within our current lookup range. */ + u32 half = ((low + high) / 2); + + /* Check middle offset value. */ + const u64 *ptr = (start_ptr + half); + if (*ptr > virtual_offset) { - /* Stop looking if we have found the right offset node. */ - if (*pos > virtual_offset) break; + /* Update our upper limit. */ + high = (half - 1); + } else { + /* Check for success. */ + if (half == (offset_count - 1) || *(ptr + 1) > virtual_offset) + { + /* Update output. */ + *out_index = half; + ret = true; + break; + } - /* Increment index. */ - index++; + /* Update our lower limit. */ + low = (half + 1); } - - /* Increment offset node pointer. */ - pos++; } - /* Update output index. */ - *out_index = index; - - return true; + return ret; } static bool bktrGetEntryNodeEntryIndex(const BucketTreeNodeHeader *node_header, u64 entry_size, u64 virtual_offset, u32 *out_index)