mirror of
https://github.com/SciresM/hactool
synced 2024-11-10 06:34:14 +00:00
Implement real BKTR support
This commit is contained in:
parent
a93a926345
commit
3d12b43f7b
4 changed files with 72 additions and 29 deletions
47
bktr.c
47
bktr.c
|
@ -4,23 +4,31 @@
|
||||||
/* Get a relocation entry from offset and relocation block. */
|
/* Get a relocation entry from offset and relocation block. */
|
||||||
bktr_relocation_entry_t *bktr_get_relocation(bktr_relocation_block_t *block, uint64_t offset) {
|
bktr_relocation_entry_t *bktr_get_relocation(bktr_relocation_block_t *block, uint64_t offset) {
|
||||||
/* Weak check for invalid offset. */
|
/* Weak check for invalid offset. */
|
||||||
if (offset > block->patch_romfs_size) {
|
if (offset > block->total_size) {
|
||||||
fprintf(stderr, "Too big offset looked up in BKTR relocation table!\n");
|
fprintf(stderr, "Too big offset looked up in BKTR relocation table!\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
if (block->num_entries == 1) { /* Check for edge case, short circuit. */
|
|
||||||
return &block->entries[0];
|
bktr_relocation_bucket_t *bucket = &block->buckets[0];
|
||||||
|
for (unsigned int i = 1; i < block->num_buckets; i++) {
|
||||||
|
if (block->bucket_virtual_offsets[i] < offset) {
|
||||||
|
bucket++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bucket->num_entries == 1) { /* Check for edge case, short circuit. */
|
||||||
|
return &bucket->entries[0];
|
||||||
}
|
}
|
||||||
/* Binary search. */
|
/* Binary search. */
|
||||||
uint32_t low = 0, high = block->num_entries - 1;
|
uint32_t low = 0, high = bucket->num_entries - 1;
|
||||||
while (low <= high) {
|
while (low <= high) {
|
||||||
uint32_t mid = (low + high) / 2;
|
uint32_t mid = (low + high) / 2;
|
||||||
if (block->entries[mid].virt_offset > offset) { /* Too high. */
|
if (bucket->entries[mid].virt_offset > offset) { /* Too high. */
|
||||||
high = mid - 1;
|
high = mid - 1;
|
||||||
} else { /* block->entries[mid].offset <= offset. */
|
} else { /* block->entries[mid].offset <= offset. */
|
||||||
/* Check for success. */
|
/* Check for success. */
|
||||||
if (mid == block->num_entries - 1 || block->entries[mid+1].virt_offset > offset) {
|
if (mid == bucket->num_entries - 1 || bucket->entries[mid+1].virt_offset > offset) {
|
||||||
return &block->entries[mid];
|
return &bucket->entries[mid];
|
||||||
}
|
}
|
||||||
low = mid + 1;
|
low = mid + 1;
|
||||||
}
|
}
|
||||||
|
@ -32,22 +40,31 @@ bktr_relocation_entry_t *bktr_get_relocation(bktr_relocation_block_t *block, uin
|
||||||
/* Get a subsection entry from offset and subsection block .*/
|
/* Get a subsection entry from offset and subsection block .*/
|
||||||
bktr_subsection_entry_t *bktr_get_subsection(bktr_subsection_block_t *block, uint64_t offset) {
|
bktr_subsection_entry_t *bktr_get_subsection(bktr_subsection_block_t *block, uint64_t offset) {
|
||||||
/* If offset is past the virtual, we're reading from the BKTR_HEADER subsection. */
|
/* If offset is past the virtual, we're reading from the BKTR_HEADER subsection. */
|
||||||
if (offset >= block->entries[block->num_entries].offset) {
|
if (offset >= block->buckets[block->num_buckets - 1].entries[block->buckets[block->num_buckets - 1].num_entries].offset) {
|
||||||
return &block->entries[block->num_entries];
|
return &block->buckets[block->num_buckets - 1].entries[block->buckets[block->num_buckets - 1].num_entries];
|
||||||
}
|
}
|
||||||
if (block->num_entries == 1) { /* Check for edge case, short circuit. */
|
|
||||||
return &block->entries[0];
|
bktr_subsection_bucket_t *bucket = &block->buckets[0];
|
||||||
|
for (unsigned int i = 1; i < block->num_buckets; i++) {
|
||||||
|
if (block->bucket_physical_offsets[i] < offset) {
|
||||||
|
bucket++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bucket->num_entries == 1) { /* Check for edge case, short circuit. */
|
||||||
|
return &bucket->entries[0];
|
||||||
|
}
|
||||||
|
|
||||||
/* Binary search. */
|
/* Binary search. */
|
||||||
uint32_t low = 0, high = block->num_entries - 1;
|
uint32_t low = 0, high = bucket->num_entries - 1;
|
||||||
while (low <= high) {
|
while (low <= high) {
|
||||||
uint32_t mid = (low + high) / 2;
|
uint32_t mid = (low + high) / 2;
|
||||||
if (block->entries[mid].offset > offset) { /* Too high. */
|
if (bucket->entries[mid].offset > offset) { /* Too high. */
|
||||||
high = mid - 1;
|
high = mid - 1;
|
||||||
} else { /* block->entries[mid].offset <= offset. */
|
} else { /* block->entries[mid].offset <= offset. */
|
||||||
/* Check for success. */
|
/* Check for success. */
|
||||||
if (mid == block->num_entries - 1 || block->entries[mid+1].offset > offset) {
|
if (mid == bucket->num_entries - 1 || bucket->entries[mid+1].offset > offset) {
|
||||||
return &block->entries[mid];
|
return &bucket->entries[mid];
|
||||||
}
|
}
|
||||||
low = mid + 1;
|
low = mid + 1;
|
||||||
}
|
}
|
||||||
|
|
33
bktr.h
33
bktr.h
|
@ -24,10 +24,21 @@ typedef struct {
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t _0x0[0x4004]; /* lol. */
|
uint32_t _0x0;
|
||||||
uint32_t num_entries;
|
uint32_t num_entries;
|
||||||
uint64_t patch_romfs_size;
|
uint64_t virtual_offset_end;
|
||||||
bktr_relocation_entry_t entries[];
|
bktr_relocation_entry_t entries[0x3FF0/sizeof(bktr_relocation_entry_t)];
|
||||||
|
uint8_t padding[0x3FF0 % sizeof(bktr_relocation_entry_t)];
|
||||||
|
} bktr_relocation_bucket_t;
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
typedef struct {
|
||||||
|
uint32_t _0x0;
|
||||||
|
uint32_t num_buckets;
|
||||||
|
uint64_t total_size;
|
||||||
|
uint64_t bucket_virtual_offsets[0x3FF0/sizeof(uint64_t)];
|
||||||
|
bktr_relocation_bucket_t buckets[];
|
||||||
} bktr_relocation_block_t;
|
} bktr_relocation_block_t;
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
@ -41,10 +52,20 @@ typedef struct {
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t _0x0[0x4004]; /* lol. */
|
uint32_t _0x0;
|
||||||
uint32_t num_entries;
|
uint32_t num_entries;
|
||||||
uint64_t bktr_entry_offset;
|
uint64_t physical_offset_end;
|
||||||
bktr_subsection_entry_t entries[];
|
bktr_subsection_entry_t entries[0x3FF];
|
||||||
|
} bktr_subsection_bucket_t;
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
typedef struct {
|
||||||
|
uint32_t _0x0;
|
||||||
|
uint32_t num_buckets;
|
||||||
|
uint64_t total_size;
|
||||||
|
uint64_t bucket_physical_offsets[0x3FF0/sizeof(uint64_t)];
|
||||||
|
bktr_subsection_bucket_t buckets[];
|
||||||
} bktr_subsection_block_t;
|
} bktr_subsection_block_t;
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,10 @@
|
||||||
|
|
||||||
#include "ConvertUTF.h"
|
#include "ConvertUTF.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <wchar.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
void os_strcpy(oschar_t *dst, const char *src) {
|
void os_strcpy(oschar_t *dst, const char *src) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (src == NULL) return;
|
if (src == NULL) return;
|
||||||
|
|
17
nca.c
17
nca.c
|
@ -947,7 +947,7 @@ void nca_process_bktr_section(nca_section_ctx_t *ctx) {
|
||||||
ctx->bktr_ctx.relocation_block = relocs;
|
ctx->bktr_ctx.relocation_block = relocs;
|
||||||
ctx->bktr_ctx.subsection_block = subs;
|
ctx->bktr_ctx.subsection_block = subs;
|
||||||
|
|
||||||
if (ctx->bktr_ctx.subsection_block->bktr_entry_offset != sb->subsection_header.offset) {
|
if (ctx->bktr_ctx.subsection_block->total_size != sb->subsection_header.offset) {
|
||||||
free(relocs);
|
free(relocs);
|
||||||
free(subs);
|
free(subs);
|
||||||
ctx->bktr_ctx.relocation_block = NULL;
|
ctx->bktr_ctx.relocation_block = NULL;
|
||||||
|
@ -957,12 +957,13 @@ void nca_process_bktr_section(nca_section_ctx_t *ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This simplifies logic greatly... */
|
/* This simplifies logic greatly... */
|
||||||
ctx->bktr_ctx.relocation_block->entries[ctx->bktr_ctx.relocation_block->num_entries].virt_offset = ctx->bktr_ctx.relocation_block->patch_romfs_size;
|
bktr_relocation_bucket_t *last_reloc_bucket = &ctx->bktr_ctx.relocation_block->buckets[ctx->bktr_ctx.relocation_block->num_buckets - 1];
|
||||||
ctx->bktr_ctx.subsection_block->entries[ctx->bktr_ctx.subsection_block->num_entries].offset = sb->relocation_header.offset;
|
bktr_subsection_bucket_t *last_subsec_bucket = &ctx->bktr_ctx.subsection_block->buckets[ctx->bktr_ctx.subsection_block->num_buckets - 1];
|
||||||
ctx->bktr_ctx.subsection_block->entries[ctx->bktr_ctx.subsection_block->num_entries].ctr_val = ctx->header->section_ctr_low;
|
last_reloc_bucket->entries[last_reloc_bucket->num_entries].virt_offset = ctx->bktr_ctx.relocation_block->total_size;
|
||||||
ctx->bktr_ctx.subsection_block->entries[ctx->bktr_ctx.subsection_block->num_entries + 1].offset = ctx->size;
|
last_subsec_bucket->entries[last_subsec_bucket->num_entries].offset = sb->relocation_header.offset;
|
||||||
ctx->bktr_ctx.subsection_block->entries[ctx->bktr_ctx.subsection_block->num_entries + 1].ctr_val = 0;
|
last_subsec_bucket->entries[last_subsec_bucket->num_entries].ctr_val = ctx->header->section_ctr_low;
|
||||||
|
last_subsec_bucket->entries[last_subsec_bucket->num_entries + 1].offset = ctx->size;
|
||||||
|
last_subsec_bucket->entries[last_subsec_bucket->num_entries + 1].ctr_val = 0;
|
||||||
|
|
||||||
/* Now parse out the romfs stuff. */
|
/* Now parse out the romfs stuff. */
|
||||||
for (unsigned int i = 0; i < IVFC_MAX_LEVEL; i++) {
|
for (unsigned int i = 0; i < IVFC_MAX_LEVEL; i++) {
|
||||||
|
@ -1156,7 +1157,7 @@ void nca_save_section(nca_section_ctx_t *ctx) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (ctx->type == BKTR && ctx->bktr_ctx.subsection_block != NULL && ctx->tool_ctx->base_file != NULL) {
|
} else if (ctx->type == BKTR && ctx->bktr_ctx.subsection_block != NULL && ctx->tool_ctx->base_file != NULL) {
|
||||||
size = ctx->bktr_ctx.relocation_block->patch_romfs_size;
|
size = ctx->bktr_ctx.relocation_block->total_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Extract to file. */
|
/* Extract to file. */
|
||||||
|
|
Loading…
Reference in a new issue