Skip to content

Commit

Permalink
bktr: perform binary search in bktrGetTreeNodeEntryIndex()
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
DarkMatterCore committed Feb 16, 2024
1 parent 5ffe065 commit 7b70750
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 39 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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)=

Expand Down
2 changes: 2 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
36 changes: 21 additions & 15 deletions code_templates/nxdt_rw_poc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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])
{
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand All @@ -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++)
Expand Down Expand Up @@ -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])
{
Expand All @@ -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);
}
}

Expand Down
56 changes: 34 additions & 22 deletions source/core/bktr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1353,22 +1355,23 @@ 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))
{
LOG_MSG_ERROR("Failed to retrieve Bucket Tree Node entry index for virtual offset 0x%lX! (#1).", virtual_offset);
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))
{
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 7b70750

Please sign in to comment.