mirror of
https://github.com/SciresM/hactool
synced 2024-11-12 23:47:09 +00:00
Add two new options to nca extraction
This commit is contained in:
parent
e37d4d2da2
commit
864e7ee86b
6 changed files with 197 additions and 56 deletions
15
filepath.c
15
filepath.c
|
@ -113,6 +113,21 @@ void filepath_set(filepath_t *fpath, const char *path) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void filepath_set_format(filepath_t *fpath, const char *format, ...) {
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
if (fpath->valid == VALIDITY_INVALID)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memset(fpath->char_path, 0, MAX_PATH);
|
||||||
|
|
||||||
|
va_start(args, format);
|
||||||
|
vsnprintf(fpath->char_path, MAX_PATH, format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
filepath_update(fpath);
|
||||||
|
}
|
||||||
|
|
||||||
oschar_t *filepath_get(filepath_t *fpath) {
|
oschar_t *filepath_get(filepath_t *fpath) {
|
||||||
if (fpath->valid == VALIDITY_INVALID)
|
if (fpath->valid == VALIDITY_INVALID)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -39,6 +39,7 @@ void filepath_copy(filepath_t *fpath, filepath_t *copy);
|
||||||
void filepath_append(filepath_t *fpath, const char *format, ...);
|
void filepath_append(filepath_t *fpath, const char *format, ...);
|
||||||
void filepath_append_n(filepath_t *fpath, uint32_t n, const char *format, ...);
|
void filepath_append_n(filepath_t *fpath, uint32_t n, const char *format, ...);
|
||||||
void filepath_set(filepath_t *fpath, const char *path);
|
void filepath_set(filepath_t *fpath, const char *path);
|
||||||
|
void filepath_set_format(filepath_t *fpath, const char *format, ...);
|
||||||
oschar_t *filepath_get(filepath_t *fpath);
|
oschar_t *filepath_get(filepath_t *fpath);
|
||||||
|
|
||||||
|
|
||||||
|
|
32
main.c
32
main.c
|
@ -3,6 +3,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
@ -57,6 +58,8 @@ static void usage(void) {
|
||||||
" --basenca Set Base NCA to use with update partitions.\n"
|
" --basenca Set Base NCA to use with update partitions.\n"
|
||||||
" --basefake Use a fake Base RomFS with update partitions (all reads will return 0xCC).\n"
|
" --basefake Use a fake Base RomFS with update partitions (all reads will return 0xCC).\n"
|
||||||
" --onlyupdated Ignore non-updated files in update partitions.\n"
|
" --onlyupdated Ignore non-updated files in update partitions.\n"
|
||||||
|
" --xcontenttype= Only extract contents if the content type matches an expected one.\n"
|
||||||
|
" --appendsectypes Append a section type string to section paths.\n"
|
||||||
"NPDM options:\n"
|
"NPDM options:\n"
|
||||||
" --json=file Specify file path for saving JSON representation of program permissions to.\n"
|
" --json=file Specify file path for saving JSON representation of program permissions to.\n"
|
||||||
"KIP1 options:\n"
|
"KIP1 options:\n"
|
||||||
|
@ -185,6 +188,8 @@ int main(int argc, char **argv) {
|
||||||
{"uncompressed", 1, NULL, 39},
|
{"uncompressed", 1, NULL, 39},
|
||||||
{"disablekeywarns", 0, NULL, 40},
|
{"disablekeywarns", 0, NULL, 40},
|
||||||
{"listfiles", 0, NULL, 41},
|
{"listfiles", 0, NULL, 41},
|
||||||
|
{"xcontenttype", 1, NULL, 42},
|
||||||
|
{"appendsectypes", 0, NULL, 43},
|
||||||
{NULL, 0, NULL, 0},
|
{NULL, 0, NULL, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -400,6 +405,33 @@ int main(int argc, char **argv) {
|
||||||
case 41:
|
case 41:
|
||||||
nca_ctx.tool_ctx->action |= ACTION_LISTFILES;
|
nca_ctx.tool_ctx->action |= ACTION_LISTFILES;
|
||||||
break;
|
break;
|
||||||
|
case 42:
|
||||||
|
if (strlen(optarg) > 0) {
|
||||||
|
nca_ctx.tool_ctx->settings.has_expected_content_type = 1;
|
||||||
|
if (strcasecmp(optarg, "program") == 0) {
|
||||||
|
nca_ctx.tool_ctx->settings.expected_content_type = NCACONTENTTYPE_PROGRAM;
|
||||||
|
} else if (strcasecmp(optarg, "meta") == 0) {
|
||||||
|
nca_ctx.tool_ctx->settings.expected_content_type = NCACONTENTTYPE_META;
|
||||||
|
} else if (strcasecmp(optarg, "control") == 0) {
|
||||||
|
nca_ctx.tool_ctx->settings.expected_content_type = NCACONTENTTYPE_CONTROL;
|
||||||
|
} else if (strcasecmp(optarg, "manual") == 0) {
|
||||||
|
nca_ctx.tool_ctx->settings.expected_content_type = NCACONTENTTYPE_MANUAL;
|
||||||
|
} else if (strcasecmp(optarg, "data") == 0) {
|
||||||
|
nca_ctx.tool_ctx->settings.expected_content_type = NCACONTENTTYPE_DATA;
|
||||||
|
} else if (strcasecmp(optarg, "publicdata") == 0) {
|
||||||
|
nca_ctx.tool_ctx->settings.expected_content_type = NCACONTENTTPYE_PUBLICDATA;
|
||||||
|
} else if ('0' <= optarg[0] && optarg[1] <= '9') {
|
||||||
|
nca_ctx.tool_ctx->settings.expected_content_type = (optarg[0] - '0');
|
||||||
|
} else {
|
||||||
|
/* Failure to parse expected content type. */
|
||||||
|
printf("[WARN] Unknown expected content type (%s).\n", optarg);
|
||||||
|
nca_ctx.tool_ctx->settings.has_expected_content_type = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 43:
|
||||||
|
nca_ctx.tool_ctx->settings.append_section_types = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|
81
nca.c
81
nca.c
|
@ -311,6 +311,19 @@ void nca_free_section_contexts(nca_ctx_t *ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *nca_get_section_type_name(enum nca_section_type type) {
|
||||||
|
switch (type) {
|
||||||
|
case PFS0:
|
||||||
|
return "pfs0";
|
||||||
|
case ROMFS:
|
||||||
|
case BKTR:
|
||||||
|
case NCA0_ROMFS:
|
||||||
|
return "romfs";
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void nca_save(nca_ctx_t *ctx) {
|
static void nca_save(nca_ctx_t *ctx) {
|
||||||
/* Save header. */
|
/* Save header. */
|
||||||
filepath_t *header_path = &ctx->tool_ctx->settings.header_path;
|
filepath_t *header_path = &ctx->tool_ctx->settings.header_path;
|
||||||
|
@ -427,6 +440,13 @@ void nca_process(nca_ctx_t *ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Enforce content type for extraction if required. */
|
||||||
|
if (ctx->tool_ctx->settings.has_expected_content_type) {
|
||||||
|
if (ctx->tool_ctx->settings.expected_content_type != ctx->header.content_type) {
|
||||||
|
ctx->tool_ctx->action &= ~(ACTION_EXTRACT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Decrypt key area if required. */
|
/* Decrypt key area if required. */
|
||||||
if (!ctx->has_rights_id) {
|
if (!ctx->has_rights_id) {
|
||||||
nca_decrypt_key_area(ctx);
|
nca_decrypt_key_area(ctx);
|
||||||
|
@ -1389,7 +1409,20 @@ void nca_save_section(nca_section_ctx_t *ctx) {
|
||||||
} else if ((ctx->type == ROMFS || ctx->type == NCA0_ROMFS) && ctx->tool_ctx->settings.romfs_path.enabled && ctx->tool_ctx->settings.romfs_path.path.valid == VALIDITY_VALID) {
|
} else if ((ctx->type == ROMFS || ctx->type == NCA0_ROMFS) && ctx->tool_ctx->settings.romfs_path.enabled && ctx->tool_ctx->settings.romfs_path.path.valid == VALIDITY_VALID) {
|
||||||
secpath = &ctx->tool_ctx->settings.romfs_path.path;
|
secpath = &ctx->tool_ctx->settings.romfs_path.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (secpath != NULL && secpath->valid == VALIDITY_VALID) {
|
if (secpath != NULL && secpath->valid == VALIDITY_VALID) {
|
||||||
|
filepath_t appended_path;
|
||||||
|
filepath_init(&appended_path);
|
||||||
|
filepath_copy(&appended_path, secpath);
|
||||||
|
if (ctx->tool_ctx->settings.append_section_types) {
|
||||||
|
filepath_set_format(&appended_path, "%s.%s", secpath->char_path, nca_get_section_type_name(ctx->type));
|
||||||
|
if (appended_path.valid == VALIDITY_VALID) {
|
||||||
|
secpath = &appended_path;
|
||||||
|
} else {
|
||||||
|
printf("[WARN] Failed to append section type to path\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
printf("Saving Section %"PRId32" to %s...\n", ctx->section_num, secpath->char_path);
|
printf("Saving Section %"PRId32" to %s...\n", ctx->section_num, secpath->char_path);
|
||||||
printf("Size: %012"PRIx64"\n", size);
|
printf("Size: %012"PRIx64"\n", size);
|
||||||
nca_save_section_file(ctx, offset, size, secpath);
|
nca_save_section_file(ctx, offset, size, secpath);
|
||||||
|
@ -1428,6 +1461,18 @@ void nca_save_pfs0_section(nca_section_ctx_t *ctx) {
|
||||||
dirpath = &ctx->tool_ctx->settings.section_dir_paths[ctx->section_num];
|
dirpath = &ctx->tool_ctx->settings.section_dir_paths[ctx->section_num];
|
||||||
}
|
}
|
||||||
if (dirpath != NULL && dirpath->valid == VALIDITY_VALID) {
|
if (dirpath != NULL && dirpath->valid == VALIDITY_VALID) {
|
||||||
|
filepath_t appended_path;
|
||||||
|
filepath_init(&appended_path);
|
||||||
|
filepath_copy(&appended_path, dirpath);
|
||||||
|
if (ctx->tool_ctx->settings.append_section_types) {
|
||||||
|
filepath_set_format(&appended_path, "%s_%s", dirpath->char_path, nca_get_section_type_name(ctx->type));
|
||||||
|
if (appended_path.valid == VALIDITY_VALID) {
|
||||||
|
dirpath = &appended_path;
|
||||||
|
} else {
|
||||||
|
printf("[WARN] Failed to append section type to path\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
os_makedir(dirpath->os_path);
|
os_makedir(dirpath->os_path);
|
||||||
for (uint32_t i = 0; i < ctx->pfs0_ctx.header->num_files; i++) {
|
for (uint32_t i = 0; i < ctx->pfs0_ctx.header->num_files; i++) {
|
||||||
nca_save_pfs0_file(ctx, i, dirpath);
|
nca_save_pfs0_file(ctx, i, dirpath);
|
||||||
|
@ -1640,6 +1685,18 @@ void nca_save_ivfc_section(nca_section_ctx_t *ctx) {
|
||||||
dirpath = &ctx->tool_ctx->settings.section_dir_paths[ctx->section_num];
|
dirpath = &ctx->tool_ctx->settings.section_dir_paths[ctx->section_num];
|
||||||
}
|
}
|
||||||
if (dirpath != NULL && dirpath->valid == VALIDITY_VALID) {
|
if (dirpath != NULL && dirpath->valid == VALIDITY_VALID) {
|
||||||
|
filepath_t appended_path;
|
||||||
|
filepath_init(&appended_path);
|
||||||
|
filepath_copy(&appended_path, dirpath);
|
||||||
|
if (ctx->tool_ctx->settings.append_section_types) {
|
||||||
|
filepath_set_format(&appended_path, "%s_%s", dirpath->char_path, nca_get_section_type_name(ctx->type));
|
||||||
|
if (appended_path.valid == VALIDITY_VALID) {
|
||||||
|
dirpath = &appended_path;
|
||||||
|
} else {
|
||||||
|
printf("[WARN] Failed to append section type to path\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
os_makedir(dirpath->os_path);
|
os_makedir(dirpath->os_path);
|
||||||
nca_visit_romfs_dir(ctx, 0, dirpath);
|
nca_visit_romfs_dir(ctx, 0, dirpath);
|
||||||
}
|
}
|
||||||
|
@ -1671,6 +1728,18 @@ void nca_save_nca0_romfs_section(nca_section_ctx_t *ctx) {
|
||||||
dirpath = &ctx->tool_ctx->settings.section_dir_paths[ctx->section_num];
|
dirpath = &ctx->tool_ctx->settings.section_dir_paths[ctx->section_num];
|
||||||
}
|
}
|
||||||
if (dirpath != NULL && dirpath->valid == VALIDITY_VALID) {
|
if (dirpath != NULL && dirpath->valid == VALIDITY_VALID) {
|
||||||
|
filepath_t appended_path;
|
||||||
|
filepath_init(&appended_path);
|
||||||
|
filepath_copy(&appended_path, dirpath);
|
||||||
|
if (ctx->tool_ctx->settings.append_section_types) {
|
||||||
|
filepath_set_format(&appended_path, "%s_%s", dirpath->char_path, nca_get_section_type_name(ctx->type));
|
||||||
|
if (appended_path.valid == VALIDITY_VALID) {
|
||||||
|
dirpath = &appended_path;
|
||||||
|
} else {
|
||||||
|
printf("[WARN] Failed to append section type to path\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
os_makedir(dirpath->os_path);
|
os_makedir(dirpath->os_path);
|
||||||
nca_visit_nca0_romfs_dir(ctx, 0, dirpath);
|
nca_visit_nca0_romfs_dir(ctx, 0, dirpath);
|
||||||
}
|
}
|
||||||
|
@ -1701,6 +1770,18 @@ void nca_save_bktr_section(nca_section_ctx_t *ctx) {
|
||||||
dirpath = &ctx->tool_ctx->settings.section_dir_paths[ctx->section_num];
|
dirpath = &ctx->tool_ctx->settings.section_dir_paths[ctx->section_num];
|
||||||
}
|
}
|
||||||
if (dirpath != NULL && dirpath->valid == VALIDITY_VALID) {
|
if (dirpath != NULL && dirpath->valid == VALIDITY_VALID) {
|
||||||
|
filepath_t appended_path;
|
||||||
|
filepath_init(&appended_path);
|
||||||
|
filepath_copy(&appended_path, dirpath);
|
||||||
|
if (ctx->tool_ctx->settings.append_section_types) {
|
||||||
|
filepath_set_format(&appended_path, "%s_%s", dirpath->char_path, nca_get_section_type_name(ctx->type));
|
||||||
|
if (appended_path.valid == VALIDITY_VALID) {
|
||||||
|
dirpath = &appended_path;
|
||||||
|
} else {
|
||||||
|
printf("[WARN] Failed to append section type to path\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
os_makedir(dirpath->os_path);
|
os_makedir(dirpath->os_path);
|
||||||
nca_visit_romfs_dir(ctx, 0, dirpath);
|
nca_visit_romfs_dir(ctx, 0, dirpath);
|
||||||
}
|
}
|
||||||
|
|
9
nca.h
9
nca.h
|
@ -135,6 +135,15 @@ enum nca_version {
|
||||||
NCAVERSION_NCA3
|
NCAVERSION_NCA3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum nca_content_type {
|
||||||
|
NCACONTENTTYPE_PROGRAM = 0,
|
||||||
|
NCACONTENTTYPE_META = 1,
|
||||||
|
NCACONTENTTYPE_CONTROL = 2,
|
||||||
|
NCACONTENTTYPE_MANUAL = 3,
|
||||||
|
NCACONTENTTYPE_DATA = 4,
|
||||||
|
NCACONTENTTPYE_PUBLICDATA = 5,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int is_present;
|
int is_present;
|
||||||
enum nca_section_type type;
|
enum nca_section_type type;
|
||||||
|
|
|
@ -81,6 +81,9 @@ typedef struct {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
nca_keyset_t keyset;
|
nca_keyset_t keyset;
|
||||||
int skip_key_warnings;
|
int skip_key_warnings;
|
||||||
|
int has_expected_content_type;
|
||||||
|
unsigned int expected_content_type;
|
||||||
|
int append_section_types;
|
||||||
int has_cli_titlekey;
|
int has_cli_titlekey;
|
||||||
unsigned char cli_titlekey[0x10];
|
unsigned char cli_titlekey[0x10];
|
||||||
unsigned char dec_cli_titlekey[0x10];
|
unsigned char dec_cli_titlekey[0x10];
|
||||||
|
|
Loading…
Reference in a new issue