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 += -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)=

View File

@ -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

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);
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);
}
}

View File

@ -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)