forked from Mirror/GodMode9
Rewitten .code extraction to require less of the heap
This commit is contained in:
parent
73a8332695
commit
689f6f7cf4
@ -12,8 +12,19 @@ typedef struct {
|
|||||||
u32 addsize_dec; // decompressed size - compressed size
|
u32 addsize_dec; // decompressed size - compressed size
|
||||||
} __attribute__((packed)) CodeLzssFooter;
|
} __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
|
// 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;
|
u8* comp_start = data_start;
|
||||||
|
|
||||||
// get footer, fix comp_start offset
|
// get footer, fix comp_start offset
|
||||||
|
@ -4,4 +4,5 @@
|
|||||||
|
|
||||||
#define EXEFS_CODE_NAME ".code"
|
#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);
|
||||||
|
@ -1497,26 +1497,51 @@ u32 DumpCxiSrlFromTmdFile(const char* path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u32 ExtractCodeFromCxiFile(const char* path, const char* path_out, char* extstr) {
|
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];
|
char dest[256];
|
||||||
if (!path_out && (fvx_rmkdir(OUTPUT_PATH) != FR_OK)) return 1;
|
if (!path_out && (fvx_rmkdir(OUTPUT_PATH) != FR_OK)) return 1;
|
||||||
strncpy(dest, path_out ? path_out : OUTPUT_PATH, 256);
|
strncpy(dest, path_out ? path_out : OUTPUT_PATH, 256);
|
||||||
if (!CheckWritePermissions(dest)) return 1;
|
if (!CheckWritePermissions(dest)) return 1;
|
||||||
|
|
||||||
|
// load all required headers
|
||||||
NcchHeader ncch;
|
NcchHeader ncch;
|
||||||
NcchExtHeader exthdr;
|
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);
|
u8* code = (u8*) malloc(code_max_size);
|
||||||
if (!code) {
|
if (!code) {
|
||||||
ShowPrompt(false, "Out of memory.");
|
ShowPrompt(false, "Out of memory.");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// load ncch, exthdr, .code
|
// load .code
|
||||||
u32 code_size;
|
if ((fvx_qread(path, code, code_offset, code_size, NULL) != FR_OK) ||
|
||||||
if ((LoadNcchHeaders(&ncch, &exthdr, NULL, path, 0) != 0) ||
|
(DecryptNcch(code, code_offset, code_size, &ncch, &exefs) != 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))) {
|
|
||||||
free(code);
|
free(code);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user