Rewitten .code extraction to require less of the heap

This commit is contained in:
d0k3 2018-02-08 00:49:34 +01:00
parent 73a8332695
commit 689f6f7cf4
3 changed files with 46 additions and 9 deletions

View File

@ -12,8 +12,19 @@ typedef struct {
u32 addsize_dec; // decompressed size - compressed size
} __attribute__((packed)) CodeLzssFooter;
u32 GetCodeLzssUncompressedSize(void* footer, u32 comp_size) {
if (comp_size < sizeof(CodeLzssFooter)) return 0;
CodeLzssFooter* f = (CodeLzssFooter*) footer;
if ((CODE_COMP_SIZE(f) > comp_size) || (CODE_COMP_END(f) < 0)) return 0;
return CODE_DEC_SIZE(f) + (comp_size - CODE_COMP_SIZE(f));
}
// see: https://github.com/zoogie/DSP1/blob/master/source/main.c#L44
u32 DecompressCodeLzss(u8* data_start, u32* code_size, u32 max_size) {
u32 DecompressCodeLzss(u8* code, u32* code_size, u32 max_size) {
u8* data_start = code;
u8* comp_start = data_start;
// get footer, fix comp_start offset

View File

@ -4,4 +4,5 @@
#define EXEFS_CODE_NAME ".code"
u32 DecompressCodeLzss(u8* data_start, u32* code_size, u32 max_size);
u32 GetCodeLzssUncompressedSize(void* footer, u32 comp_size);
u32 DecompressCodeLzss(u8* code, u32* code_size, u32 max_size);

View File

@ -1497,26 +1497,51 @@ u32 DumpCxiSrlFromTmdFile(const char* path) {
}
u32 ExtractCodeFromCxiFile(const char* path, const char* path_out, char* extstr) {
const u32 code_max_size = 24 * 1024 * 1024; // arbitrary / this may not suffice (!)
char dest[256];
if (!path_out && (fvx_rmkdir(OUTPUT_PATH) != FR_OK)) return 1;
strncpy(dest, path_out ? path_out : OUTPUT_PATH, 256);
if (!CheckWritePermissions(dest)) return 1;
// load all required headers
NcchHeader ncch;
NcchExtHeader exthdr;
ExeFsHeader exefs;
if (LoadNcchHeaders(&ncch, &exthdr, &exefs, path, 0) != 0) return 1;
// find ".code" or ".firm" inside the ExeFS header
u32 code_size = 0;
u32 code_offset = 0;
for (u32 i = 0; i < 10; i++) {
if (exefs.files[i].size &&
((strncmp(exefs.files[i].name, EXEFS_CODE_NAME, 8) == 0) ||
(strncmp(exefs.files[i].name, ".firm", 8) == 0))) {
code_size = exefs.files[i].size;
code_offset = (ncch.offset_exefs * NCCH_MEDIA_UNIT) + sizeof(ExeFsHeader) + exefs.files[i].offset;
}
}
// if code is compressed: find decompressed size
u32 code_max_size = code_size;
if (exthdr.flag & 0x1) {
u8 footer[8];
if (code_size < 8) return 1;
if ((fvx_qread(path, footer, code_offset + code_size - 8, 8, NULL) != FR_OK) ||
(DecryptNcch(footer, code_offset + code_size - 8, 8, &ncch, &exefs) != 0))
return 1;
u32 unc_size = GetCodeLzssUncompressedSize(footer, code_size);
code_max_size = max(code_size, unc_size);
}
// allocate memory
u8* code = (u8*) malloc(code_max_size);
if (!code) {
ShowPrompt(false, "Out of memory.");
return 1;
}
// load ncch, exthdr, .code
u32 code_size;
if ((LoadNcchHeaders(&ncch, &exthdr, NULL, path, 0) != 0) ||
((LoadExeFsFile(code, path, 0, EXEFS_CODE_NAME, code_max_size, &code_size) != 0) &&
(LoadExeFsFile(code, path, 0, ".firm", code_max_size, &code_size) != 0))) {
// load .code
if ((fvx_qread(path, code, code_offset, code_size, NULL) != FR_OK) ||
(DecryptNcch(code, code_offset, code_size, &ncch, &exefs) != 0)) {
free(code);
return 1;
}