int main(int argc, char* argv[]) { toolcontext ctx; u8 magic[4]; char infname[512]; int c; u32 ncchoffset = ~0; char keysetfname[512] = "keys.xml"; keyset tmpkeys; unsigned int checkkeysetfile = 0; memset(&ctx, 0, sizeof(toolcontext)); ctx.actions = InfoFlag | ExtractFlag; ctx.filetype = FILETYPE_UNKNOWN; settings_init(&ctx.usersettings); keyset_init(&ctx.usersettings.keys); keyset_init(&tmpkeys); while (1) { int option_index; static struct option long_options[] = { {"extract", 0, NULL, 'x'}, {"plain", 0, NULL, 'p'}, {"info", 0, NULL, 'i'}, {"exefs", 1, NULL, 0}, {"romfs", 1, NULL, 1}, {"exheader", 1, NULL, 2}, {"certs", 1, NULL, 3}, {"tik", 1, NULL, 4}, {"tmd", 1, NULL, 5}, {"contents", 1, NULL, 6}, {"meta", 1, NULL, 7}, {"exefsdir", 1, NULL, 8}, {"keyset", 1, NULL, 'k'}, {"ncch", 1, NULL, 'n'}, {"verbose", 0, NULL, 'v'}, {"verify", 0, NULL, 'y'}, {"raw", 0, NULL, 'r'}, {"unitsize", 1, NULL, 9}, {"showkeys", 0, NULL, 10}, {"commonkey", 1, NULL, 11}, {"ncchkey", 1, NULL, 12}, {"intype", 1, NULL, 't'}, {"lzssout", 1, NULL, 13}, {"firmdir", 1, NULL, 14}, {"ncchsyskey", 1, NULL, 15}, {"wav", 1, NULL, 16}, {"romfsdir", 1, NULL, 17}, {"listromfs", 0, NULL, 18}, {"wavloops", 1, NULL, 19}, {"logo", 1, NULL, 20}, {NULL}, }; c = getopt_long(argc, argv, "ryxivpk:n:t:", long_options, &option_index); if (c == -1) break; switch (c) { case 'x': ctx.actions |= ExtractFlag; break; case 'v': ctx.actions |= VerboseFlag; break; case 'y': ctx.actions |= VerifyFlag; break; case 'p': ctx.actions |= PlainFlag; break; case 'r': ctx.actions |= RawFlag; break; case 'i': ctx.actions |= InfoFlag; break; case 'n': ncchoffset = strtoul(optarg, 0, 0); break; case 'k': strncpy(keysetfname, optarg, sizeof(keysetfname)); checkkeysetfile = 1; break; case 't': if (!strcmp(optarg, "exheader")) ctx.filetype = FILETYPE_EXHEADER; else if (!strcmp(optarg, "ncch")) ctx.filetype = FILETYPE_CXI; else if (!strcmp(optarg, "ncsd")) ctx.filetype = FILETYPE_CCI; else if (!strcmp(optarg, "cia")) ctx.filetype = FILETYPE_CIA; else if (!strcmp(optarg, "tmd")) ctx.filetype = FILETYPE_TMD; else if (!strcmp(optarg, "lzss")) ctx.filetype = FILETYPE_LZSS; else if (!strcmp(optarg, "firm")) ctx.filetype = FILETYPE_FIRM; else if (!strcmp(optarg, "cwav")) ctx.filetype = FILETYPE_CWAV; else if (!strcmp(optarg, "romfs")) ctx.filetype = FILETYPE_ROMFS; break; case 0: settings_set_exefs_path(&ctx.usersettings, optarg); break; case 1: settings_set_romfs_path(&ctx.usersettings, optarg); break; case 2: settings_set_exheader_path(&ctx.usersettings, optarg); break; case 3: settings_set_certs_path(&ctx.usersettings, optarg); break; case 4: settings_set_tik_path(&ctx.usersettings, optarg); break; case 5: settings_set_tmd_path(&ctx.usersettings, optarg); break; case 6: settings_set_content_path(&ctx.usersettings, optarg); break; case 7: settings_set_content_path(&ctx.usersettings, optarg); break; case 8: settings_set_exefs_dir_path(&ctx.usersettings, optarg); break; case 9: settings_set_mediaunit_size(&ctx.usersettings, strtoul(optarg, 0, 0)); break; case 10: ctx.actions |= ShowKeysFlag; break; case 11: keyset_parse_commonkey(&tmpkeys, optarg, strlen(optarg)); break; case 12: keyset_parse_ncchkey(&tmpkeys, optarg, strlen(optarg)); break; case 13: settings_set_lzss_path(&ctx.usersettings, optarg); break; case 14: settings_set_firm_dir_path(&ctx.usersettings, optarg); break; case 15: keyset_parse_ncchfixedsystemkey(&tmpkeys, optarg, strlen(optarg)); break; case 16: settings_set_wav_path(&ctx.usersettings, optarg); break; case 17: settings_set_romfs_dir_path(&ctx.usersettings, optarg); break; case 18: settings_set_list_romfs_files(&ctx.usersettings, 1); break; case 19: settings_set_cwav_loopcount(&ctx.usersettings, strtoul(optarg, 0, 0)); break; case 20: settings_set_logo_path(&ctx.usersettings, optarg); break; default: usage(argv[0]); } } if (optind == argc - 1) { // Exactly one extra argument - an input file strncpy(infname, argv[optind], sizeof(infname)); } else if ( (optind < argc) || (argc == 1) ) { // Too many extra args usage(argv[0]); } keyset_load(&ctx.usersettings.keys, keysetfname, (ctx.actions & VerboseFlag) | checkkeysetfile); keyset_merge(&ctx.usersettings.keys, &tmpkeys); if (ctx.actions & ShowKeysFlag) keyset_dump(&ctx.usersettings.keys); ctx.infile = fopen(infname, "rb"); if (ctx.infile == 0) { fprintf(stderr, "error: could not open input file!\n"); return -1; } fseek(ctx.infile, 0, SEEK_END); ctx.infilesize = ftell(ctx.infile); fseek(ctx.infile, 0, SEEK_SET); if (ctx.filetype == FILETYPE_UNKNOWN) { fseek(ctx.infile, 0x100, SEEK_SET); fread(&magic, 1, 4, ctx.infile); switch(getle32(magic)) { case MAGIC_NCCH: ctx.filetype = FILETYPE_CXI; break; case MAGIC_NCSD: ctx.filetype = FILETYPE_CCI; break; default: break; } } if (ctx.filetype == FILETYPE_UNKNOWN) { fseek(ctx.infile, 0, SEEK_SET); fread(magic, 1, 4, ctx.infile); switch(getle32(magic)) { case 0x2020: ctx.filetype = FILETYPE_CIA; break; case MAGIC_FIRM: ctx.filetype = FILETYPE_FIRM; break; case MAGIC_CWAV: ctx.filetype = FILETYPE_CWAV; break; case MAGIC_IVFC: ctx.filetype = FILETYPE_ROMFS; // TODO: need to determine more here.. savegames use IVFC too, but is not ROMFS. break; } } if (ctx.filetype == FILETYPE_UNKNOWN) { fprintf(stdout, "Unknown file\n"); exit(1); } switch(ctx.filetype) { case FILETYPE_CCI: { ncsd_context ncsdctx; ncsd_init(&ncsdctx); ncsd_set_file(&ncsdctx, ctx.infile); ncsd_set_size(&ncsdctx, ctx.infilesize); ncsd_set_usersettings(&ncsdctx, &ctx.usersettings); ncsd_process(&ncsdctx, ctx.actions); break; } case FILETYPE_FIRM: { firm_context firmctx; firm_init(&firmctx); firm_set_file(&firmctx, ctx.infile); firm_set_size(&firmctx, ctx.infilesize); firm_set_usersettings(&firmctx, &ctx.usersettings); firm_process(&firmctx, ctx.actions); break; } case FILETYPE_CXI: { ncch_context ncchctx; ncch_init(&ncchctx); ncch_set_file(&ncchctx, ctx.infile); ncch_set_size(&ncchctx, ctx.infilesize); ncch_set_usersettings(&ncchctx, &ctx.usersettings); ncch_process(&ncchctx, ctx.actions); break; } case FILETYPE_CIA: { cia_context ciactx; cia_init(&ciactx); cia_set_file(&ciactx, ctx.infile); cia_set_size(&ciactx, ctx.infilesize); cia_set_usersettings(&ciactx, &ctx.usersettings); cia_process(&ciactx, ctx.actions); break; } case FILETYPE_EXHEADER: { exheader_context exheaderctx; exheader_init(&exheaderctx); exheader_set_file(&exheaderctx, ctx.infile); exheader_set_size(&exheaderctx, ctx.infilesize); settings_set_ignore_programid(&ctx.usersettings, 1); exheader_set_usersettings(&exheaderctx, &ctx.usersettings); exheader_process(&exheaderctx, ctx.actions); break; } case FILETYPE_TMD: { tmd_context tmdctx; tmd_init(&tmdctx); tmd_set_file(&tmdctx, ctx.infile); tmd_set_size(&tmdctx, ctx.infilesize); tmd_set_usersettings(&tmdctx, &ctx.usersettings); tmd_process(&tmdctx, ctx.actions); break; } case FILETYPE_LZSS: { lzss_context lzssctx; lzss_init(&lzssctx); lzss_set_file(&lzssctx, ctx.infile); lzss_set_size(&lzssctx, ctx.infilesize); lzss_set_usersettings(&lzssctx, &ctx.usersettings); lzss_process(&lzssctx, ctx.actions); break; } case FILETYPE_CWAV: { cwav_context cwavctx; cwav_init(&cwavctx); cwav_set_file(&cwavctx, ctx.infile); cwav_set_size(&cwavctx, ctx.infilesize); cwav_set_usersettings(&cwavctx, &ctx.usersettings); cwav_process(&cwavctx, ctx.actions); break; } case FILETYPE_ROMFS: { romfs_context romfsctx; romfs_init(&romfsctx); romfs_set_file(&romfsctx, ctx.infile); romfs_set_size(&romfsctx, ctx.infilesize); romfs_set_usersettings(&romfsctx, &ctx.usersettings); romfs_process(&romfsctx, ctx.actions); break; } } if (ctx.infile) fclose(ctx.infile); return 0; }
int main(int argc, char* argv[]) { toolcontext ctx; char fname[512]; int c; u32 ncchoffset = ~0; char keysetfname[512] = "keys.xml"; keyset tmpkeys; unsigned int checkkeysetfile = 0; memset(&ctx, 0, sizeof(toolcontext)); ctx.actions = InfoFlag | ExtractFlag | ParseFlag; ctx.filetype = FILETYPE_UNKNOWN; settings_init(&ctx.usersettings); keyset_init(&ctx.usersettings.keys); keyset_init(&tmpkeys); while (1) { int option_index; static struct option long_options[] = { {"create", 0, NULL, 'c'}, {"extract", 0, NULL, 'x'}, {"plain", 0, NULL, 'p'}, {"info", 0, NULL, 'i'}, {"exefs", 1, NULL, 0}, {"romfs", 1, NULL, 1}, {"exheader", 1, NULL, 2}, {"certs", 1, NULL, 3}, {"tik", 1, NULL, 4}, {"tmd", 1, NULL, 5}, {"contents", 1, NULL, 6}, {"meta", 1, NULL, 7}, {"exefsdir", 1, NULL, 8}, {"keyset", 1, NULL, 'k'}, {"ncch", 1, NULL, 'n'}, {"verbose", 0, NULL, 'v'}, {"verify", 0, NULL, 'y'}, {"raw", 0, NULL, 'r'}, {"unitsize", 1, NULL, 9}, {"showkeys", 0, NULL, 10}, {"commonkey", 1, NULL, 11}, {"ncchkey", 1, NULL, 12}, {"intype", 1, NULL, 't'}, {"lzssout", 1, NULL, 13}, {"firmdir", 1, NULL, 14}, {"ncchsyskey", 1, NULL, 15}, {"wav", 1, NULL, 16}, {"romfsdir", 1, NULL, 17}, {"listromfs", 0, NULL, 18}, {"wavloops", 1, NULL, 19}, {"section0file", 1, NULL, SECTION_FILE_ARG_BASE+0}, {"section1file", 1, NULL, SECTION_FILE_ARG_BASE+1}, {"section2file", 1, NULL, SECTION_FILE_ARG_BASE+2}, {"section3file", 1, NULL, SECTION_FILE_ARG_BASE+3}, {"section4file", 1, NULL, SECTION_FILE_ARG_BASE+4}, {"section5file", 1, NULL, SECTION_FILE_ARG_BASE+5}, {"section6file", 1, NULL, SECTION_FILE_ARG_BASE+6}, {"section7file", 1, NULL, SECTION_FILE_ARG_BASE+7}, {"section0name", 1, NULL, SECTION_NAME_ARG_BASE+0}, {"section1name", 1, NULL, SECTION_NAME_ARG_BASE+1}, {"section2name", 1, NULL, SECTION_NAME_ARG_BASE+2}, {"section3name", 1, NULL, SECTION_NAME_ARG_BASE+3}, {"section4name", 1, NULL, SECTION_NAME_ARG_BASE+4}, {"section5name", 1, NULL, SECTION_NAME_ARG_BASE+5}, {"section6name", 1, NULL, SECTION_NAME_ARG_BASE+6}, {"section7name", 1, NULL, SECTION_NAME_ARG_BASE+7}, {"compresscode", 0, NULL, 40}, {NULL}, }; c = getopt_long(argc, argv, "ryxcivpk:n:t:", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': ctx.actions |= CreateFlag; ctx.actions &= ~ParseFlag; break; case 'x': ctx.actions |= ExtractFlag; break; case 'v': ctx.actions |= VerboseFlag; break; case 'y': ctx.actions |= VerifyFlag; break; case 'p': ctx.actions |= PlainFlag; break; case 'r': ctx.actions |= RawFlag; break; case 'i': ctx.actions |= InfoFlag; break; case 'n': ncchoffset = strtoul(optarg, 0, 0); break; case 'k': strncpy(keysetfname, optarg, sizeof(keysetfname)); checkkeysetfile = 1; break; case 't': if (!strcmp(optarg, "exheader")) ctx.filetype = FILETYPE_EXHEADER; else if (!strcmp(optarg, "ncch")) ctx.filetype = FILETYPE_CXI; else if (!strcmp(optarg, "ncsd")) ctx.filetype = FILETYPE_CCI; else if (!strcmp(optarg, "cia")) ctx.filetype = FILETYPE_CIA; else if (!strcmp(optarg, "tmd")) ctx.filetype = FILETYPE_TMD; else if (!strcmp(optarg, "lzss")) ctx.filetype = FILETYPE_LZSS; else if (!strcmp(optarg, "firm")) ctx.filetype = FILETYPE_FIRM; else if (!strcmp(optarg, "cwav")) ctx.filetype = FILETYPE_CWAV; else if (!strcmp(optarg, "exefs")) ctx.filetype = FILETYPE_EXEFS; else if (!strcmp(optarg, "romfs")) ctx.filetype = FILETYPE_ROMFS; break; case 0: settings_set_exefs_path(&ctx.usersettings, optarg); break; case 1: settings_set_romfs_path(&ctx.usersettings, optarg); break; case 2: settings_set_exheader_path(&ctx.usersettings, optarg); break; case 3: settings_set_certs_path(&ctx.usersettings, optarg); break; case 4: settings_set_tik_path(&ctx.usersettings, optarg); break; case 5: settings_set_tmd_path(&ctx.usersettings, optarg); break; case 6: settings_set_content_path(&ctx.usersettings, optarg); break; case 7: settings_set_content_path(&ctx.usersettings, optarg); break; case 8: settings_set_exefs_dir_path(&ctx.usersettings, optarg); break; case 9: settings_set_mediaunit_size(&ctx.usersettings, strtoul(optarg, 0, 0)); break; case 10: ctx.actions |= ShowKeysFlag; break; case 11: keyset_parse_commonkey(&tmpkeys, optarg, strlen(optarg)); break; case 12: keyset_parse_ncchkey(&tmpkeys, optarg, strlen(optarg)); break; case 13: settings_set_lzss_path(&ctx.usersettings, optarg); break; case 14: settings_set_firm_dir_path(&ctx.usersettings, optarg); break; case 15: keyset_parse_ncchfixedsystemkey(&tmpkeys, optarg, strlen(optarg)); break; case 16: settings_set_wav_path(&ctx.usersettings, optarg); break; case 17: settings_set_romfs_dir_path(&ctx.usersettings, optarg); break; case 18: settings_set_list_romfs_files(&ctx.usersettings, 1); break; case 19: settings_set_cwav_loopcount(&ctx.usersettings, strtoul(optarg, 0, 0)); break; case 40: ctx.actions |= CompressCodeFlag; break; case SECTION_FILE_ARG_BASE+0: case SECTION_FILE_ARG_BASE+1: case SECTION_FILE_ARG_BASE+2: case SECTION_FILE_ARG_BASE+3: case SECTION_FILE_ARG_BASE+4: case SECTION_FILE_ARG_BASE+5: case SECTION_FILE_ARG_BASE+6: case SECTION_FILE_ARG_BASE+7: settings_set_exefs_section_path(&ctx.usersettings, c-SECTION_FILE_ARG_BASE, optarg); break; case SECTION_NAME_ARG_BASE+0: case SECTION_NAME_ARG_BASE+1: case SECTION_NAME_ARG_BASE+2: case SECTION_NAME_ARG_BASE+3: case SECTION_NAME_ARG_BASE+4: case SECTION_NAME_ARG_BASE+5: case SECTION_NAME_ARG_BASE+6: case SECTION_NAME_ARG_BASE+7: settings_set_exefs_section_name(&ctx.usersettings, c-SECTION_NAME_ARG_BASE, optarg); break; default: usage(argv[0]); } } if (optind == argc - 1) { // Exactly one extra argument - an input file strncpy(fname, argv[optind], sizeof(fname)); } else if ( (optind < argc) || (argc == 1) ) { // Too many extra args usage(argv[0]); } keyset_load(&ctx.usersettings.keys, keysetfname, (ctx.actions & VerboseFlag) | checkkeysetfile); keyset_merge(&ctx.usersettings.keys, &tmpkeys); if (ctx.actions & ShowKeysFlag) keyset_dump(&ctx.usersettings.keys); if(ctx.actions & ParseFlag)return action_parse(&ctx, fname); else if(ctx.actions & CreateFlag)return action_create(&ctx, fname); return -1; //shouldn't happen ffs }