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.
This commit is contained in:
Pablo Curiel 2024-02-16 23:31:24 +01:00
parent 5ffe06508e
commit 7b707509c7
4 changed files with 59 additions and 39 deletions

View File

@ -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 := -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 += -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 += -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 += -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 += -DBUILD_TIMESTAMP="\"${BUILD_TIMESTAMP}\"" -DBOREALIS_RESOURCES="\"${BOREALIS_RESOURCES}\"" -D_GNU_SOURCE
CFLAGS += -fmacro-prefix-map=$(ROOTDIR)= CFLAGS += -fmacro-prefix-map=$(ROOTDIR)=

View File

@ -31,3 +31,5 @@ make clean_all
rm -f ./source/main.c rm -f ./source/main.c
mv -f ./main.cpp ./source/main.cpp mv -f ./main.cpp ./source/main.cpp
read -rsp $'Press any key to continue...\n' -n 1 key

View File

@ -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); static TitleInfo *getLatestTitleInfo(TitleInfo *title_info, u32 *out_idx, u32 *out_count);
void freeNcaList(void); void freeNcaList(void);
void updateNcaList(TitleInfo *title_info); void updateNcaList(TitleInfo *title_info, u32 *element_count);
static void switchNcaListTitle(Menu *cur_menu, u32 *element_count, TitleInfo *title_info); static void switchNcaListTitle(Menu **cur_menu, u32 *element_count, TitleInfo *title_info);
void freeNcaFsSectionsList(void); void freeNcaFsSectionsList(void);
void updateNcaFsSectionsList(NcaUserData *nca_user_data); void updateNcaFsSectionsList(NcaUserData *nca_user_data);
@ -1272,7 +1272,7 @@ int main(int argc, char *argv[])
if (child_menu->id == MenuId_Nca) if (child_menu->id == MenuId_Nca)
{ {
updateNcaList(title_info); updateNcaList(title_info, &element_count);
if (!g_ncaMenuElements || !g_ncaMenuElements[0]) if (!g_ncaMenuElements || !g_ncaMenuElements[0])
{ {
@ -1516,13 +1516,13 @@ int main(int argc, char *argv[])
{ {
title_info = title_info->previous; title_info = title_info->previous;
title_info_idx--; title_info_idx--;
switchNcaListTitle(cur_menu, &element_count, title_info); switchNcaListTitle(&cur_menu, &element_count, title_info);
} else } 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) 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 = title_info->next;
title_info_idx++; title_info_idx++;
switchNcaListTitle(cur_menu, &element_count, title_info); switchNcaListTitle(&cur_menu, &element_count, title_info);
} else } else
if ((btn_down & HidNpadButton_Y) && cur_menu->id == MenuId_Nca) if ((btn_down & HidNpadButton_Y) && cur_menu->id == MenuId_Nca)
{ {
@ -1883,7 +1883,7 @@ void freeNcaList(void)
g_ncaMenu.elements = NULL; 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; u32 content_count = title_info->content_count, idx = 0;
NcmContentInfo *content_infos = title_info->content_infos; NcmContentInfo *content_infos = title_info->content_infos;
@ -1894,6 +1894,7 @@ void updateNcaList(TitleInfo *title_info)
/* Allocate buffer. */ /* Allocate buffer. */
g_ncaMenuElements = calloc(content_count + 2, sizeof(MenuElement*)); // Output storage, NULL terminator g_ncaMenuElements = calloc(content_count + 2, sizeof(MenuElement*)); // Output storage, NULL terminator
if (!g_ncaMenuElements) return;
/* Generate menu elements. */ /* Generate menu elements. */
for(u32 i = 0; i < content_count; i++) for(u32 i = 0; i < content_count; i++)
@ -1937,16 +1938,21 @@ void updateNcaList(TitleInfo *title_info)
idx++; 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]) if (!g_ncaMenuElements || !g_ncaMenuElements[0])
{ {
@ -1955,11 +1961,11 @@ static void switchNcaListTitle(Menu *cur_menu, u32 *element_count, TitleInfo *ti
consoleRefresh(); consoleRefresh();
utilsWaitForButtonPress(0); utilsWaitForButtonPress(0);
cur_menu->selected = 0; (*cur_menu)->selected = 0;
cur_menu->scroll = 0; (*cur_menu)->scroll = 0;
cur_menu = cur_menu->parent; *cur_menu = (*cur_menu)->parent;
*element_count = menuGetElementCount(cur_menu); *element_count = menuGetElementCount(*cur_menu);
} }
} }

View File

@ -1253,10 +1253,12 @@ static bool bktrValidateTableOffsetNode(const BucketTreeTable *table, u64 node_s
u32 offset_count = bktrGetOffsetCount(node_size); u32 offset_count = bktrGetOffsetCount(node_size);
u32 entry_set_count = bktrGetEntrySetCount(node_size, entry_size, entry_count); 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; 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!"); LOG_MSG_ERROR("Invalid Bucket Tree Offset Node!");
return false; return false;
@ -1353,13 +1355,14 @@ static bool bktrFindStorageEntry(BucketTreeContext *ctx, u64 virtual_offset, Buc
/* Get the entry node index. */ /* Get the entry node index. */
u32 entry_set_index = 0; 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; const u64 *start_ptr = NULL, *end_ptr = NULL;
bool success = false; bool success = false;
if (bktrIsExistOffsetL2OnL1(ctx) && virtual_offset < *bktrGetOffsetNodeBegin(offset_node)) if (bktrIsExistOffsetL2OnL1(ctx) && virtual_offset < *node_start_ptr)
{ {
start_ptr = bktrGetOffsetNodeEnd(offset_node); start_ptr = node_end_ptr;
end_ptr = (bktrGetOffsetNodeBegin(offset_node) + ctx->offset_count); end_ptr = (node_start_ptr + ctx->offset_count);
if (!bktrGetTreeNodeEntryIndex(start_ptr, end_ptr, virtual_offset, &entry_set_index)) 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; goto end;
} }
} else { } else {
start_ptr = bktrGetOffsetNodeBegin(offset_node); start_ptr = node_start_ptr;
end_ptr = bktrGetOffsetNodeEnd(offset_node); end_ptr = node_end_ptr;
if (!bktrGetTreeNodeEntryIndex(start_ptr, end_ptr, virtual_offset, &entry_set_index)) 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; return false;
} }
u64 *pos = (u64*)start_ptr; /* Perform a binary search. */
u32 index = 0; 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. */ /* Update our upper limit. */
if (*pos > virtual_offset) break; 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. */ /* Update our lower limit. */
index++; low = (half + 1);
} }
/* Increment offset node pointer. */
pos++;
} }
/* Update output index. */ return ret;
*out_index = index;
return true;
} }
static bool bktrGetEntryNodeEntryIndex(const BucketTreeNodeHeader *node_header, u64 entry_size, u64 virtual_offset, u32 *out_index) static bool bktrGetEntryNodeEntryIndex(const BucketTreeNodeHeader *node_header, u64 entry_size, u64 virtual_offset, u32 *out_index)