#include "lib.h" // Private Prototypes void DisplayHelp(char *app_name); void SetDefaults(user_settings *set); int SetArgument(int argc, int i, char *argv[], user_settings *set); int CheckArgumentCombination(user_settings *set); void PrintNeedsArg(char *arg); void PrintArgInvalid(char *arg); void PrintArgReqParam(char *arg, u32 paramNum); void PrintNoNeedParam(char *arg); int ParseArgs(int argc, char *argv[], user_settings *set) { if(argv == NULL || set == NULL) return USR_PTR_PASS_FAIL; if(argc < 2){ DisplayHelp(argv[0]); return USR_HELP; } // Detecting Help Requried for(int i = 1; i < argc; i++){ if(strcmp(argv[i],"-help") == 0){ DisplayHelp(argv[0]); return USR_HELP; } } // Allocating Memory for Content Path Ptrs set->common.contentPath = calloc(CIA_MAX_CONTENT,sizeof(char*)); if(set->common.contentPath == NULL){ fprintf(stderr,"[SETTING ERROR] Not Enough Memory\n"); return USR_MEM_ERROR; } // Initialise Keys InitKeys(&set->common.keys); // Setting Defaults SetDefaults(set); // Parsing Arguments int set_result; int i = 1; while(i < argc){ set_result = SetArgument(argc,i,argv,set); if(set_result < 1){ fprintf(stderr,"[RESULT] Invalid arguments, see '%s -help'\n",argv[0]); return set_result; } i += set_result; } // Checking arguments if((set_result = CheckArgumentCombination(set)) != 0) return set_result; // Setting Keys if((set_result = SetKeys(&set->common.keys)) != 0) return set_result; // Generating outpath if required if(!set->common.outFileName){ char *source_path = NULL; if(set->ncch.buildNcch0) source_path = set->common.rsfPath; else if(set->common.workingFileType == infile_ncsd || set->common.workingFileType == infile_cia || set->common.workingFileType == infile_srl) source_path = set->common.workingFilePath; else source_path = set->common.contentPath[0]; u16 outfile_len = strlen(source_path) + 0x10; set->common.outFileName = calloc(outfile_len,sizeof(char)); if(!set->common.outFileName){ fprintf(stderr,"[SETTING ERROR] Not Enough Memory\n"); return USR_MEM_ERROR; } set->common.outFileName_mallocd = true; append_filextention(set->common.outFileName,outfile_len,source_path,(char*)&output_extention[set->common.outFormat-1]); } return 0; } void SetDefaults(user_settings *set) { // Target Info set->common.keys.keyset = pki_TEST; set->common.keys.accessDescSign.presetType = desc_preset_NONE; // Build NCCH Info set->ncch.useSecCrypto = false; set->ncch.buildNcch0 = false; set->ncch.includeExefsLogo = false; set->common.outFormat = NCCH; set->ncch.ncchType = format_not_set; // RSF Settings clrmem(&set->common.rsfSet,sizeof(rsf_settings)); set->common.rsfSet.Option.EnableCompress = true; set->common.rsfSet.Option.EnableCrypt = true; set->common.rsfSet.Option.UseOnSD = false; set->common.rsfSet.Option.FreeProductCode = false; // Working File Info set->common.workingFileType = infile_ncch; // CCI Info set->cci.useSDKStockData = false; // CIA Info set->cia.includeUpdateNcch = false; set->cia.deviceId = 0; set->cia.eshopAccId = 0; set->cia.useDataTitleVer = false; set->cia.titleVersion[VER_MAJOR] = MAX_U16; // invalid so changes can be detected set->cia.randomTitleKey = false; set->common.keys.aes.currentCommonKey = MAX_U8 + 1; // invalid so changes can be detected for(int i = 0; i < CIA_MAX_CONTENT; i++) set->cia.contentId[i] = MAX_U32 + 1; // invalid so changes can be detected } int SetArgument(int argc, int i, char *argv[], user_settings *set) { u16 ParamNum = 0; for(int j = i+1; j < argc && argv[j][0] != '-'; j++) ParamNum++; // Global Settings if(strcmp(argv[i],"-rsf") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->common.rsfPath = argv[i+1]; return 2; } else if(strcmp(argv[i],"-f") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } if(strcasecmp(argv[i+1],"ncch") == 0 || strcasecmp(argv[i+1],"cxi") == 0 || strcasecmp(argv[i+1],"cfa") == 0) set->common.outFormat = NCCH; else if(strcasecmp(argv[i+1],"cci") == 0) set->common.outFormat = CCI; else if(strcasecmp(argv[i+1],"cia") == 0) set->common.outFormat = CIA; else { fprintf(stderr,"[SETTING ERROR] Invalid output format '%s'\n",argv[i+1]); return USR_BAD_ARG; } return 2; } else if(strcmp(argv[i],"-o") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->common.outFileName = argv[i+1]; set->common.outFileName_mallocd = false; return 2; } else if(strcmp(argv[i],"-v") == 0){ if(ParamNum){ PrintNoNeedParam(argv[i]); return USR_BAD_ARG; } set->common.verbose = true; return 1; } // Key Options else if(strcmp(argv[i],"-target") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } if(strcasecmp(argv[i+1],"test") == 0 || strcasecmp(argv[i+1],"t") == 0) set->common.keys.keyset = pki_TEST; else if(strcasecmp(argv[i+1],"debug") == 0 || strcasecmp(argv[i+1],"development") == 0 || strcasecmp(argv[i+1],"d") == 0) set->common.keys.keyset = pki_DEVELOPMENT; else if(strcasecmp(argv[i+1],"retail") == 0 || strcasecmp(argv[i+1],"production") == 0 || strcasecmp(argv[i+1],"p") == 0) set->common.keys.keyset = pki_PRODUCTION; //else if(strcasecmp(argv[i+1],"custom") == 0 || strcasecmp(argv[i+1],"c") == 0) // given all known keys are here, this isn't needed // set->common.keys.keyset = pki_CUSTOM; else{ fprintf(stderr,"[SETTING ERROR] Unrecognised target '%s'\n",argv[i+1]); return USR_BAD_ARG; } return 2; } else if(strcmp(argv[i],"-ckeyid") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->common.keys.aes.currentCommonKey = strtol(argv[i+1],NULL,0); if(set->common.keys.aes.currentCommonKey > MAX_CMN_KEY) { fprintf(stderr,"[SETTING ERROR] Invalid Common Key Index: 0x%x\n",set->common.keys.aes.currentCommonKey); return USR_BAD_ARG; } return 2; } else if(strcmp(argv[i],"-ncchseckey") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->ncch.useSecCrypto = true; set->ncch.keyXID = strtol(argv[i+1],NULL,0); if(set->ncch.keyXID > MAX_NCCH_KEYX) { fprintf(stderr,"[SETTING ERROR] Invalid NCCH KeyX Index: 0x%x\n",set->ncch.keyXID); return USR_BAD_ARG; } return 2; } else if(strcmp(argv[i],"-showkeys") == 0){ if(ParamNum){ PrintNoNeedParam(argv[i]); return USR_BAD_ARG; } set->common.keys.dumpkeys = true; return 1; } else if(strcmp(argv[i],"-fsign") == 0){ if(ParamNum){ PrintNoNeedParam(argv[i]); return USR_BAD_ARG; } set->common.keys.rsa.isFalseSign = true; return 1; } // Ncch Options else if(strcmp(argv[i],"-elf") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->ncch.elfPath = argv[i+1]; set->ncch.ncchType |= CXI; return 2; } else if(strcmp(argv[i],"-icon") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->ncch.iconPath = argv[i+1]; set->ncch.ncchType |= CFA; return 2; } else if(strcmp(argv[i],"-banner") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->ncch.bannerPath = argv[i+1]; set->ncch.ncchType |= CFA; return 2; } else if(strcmp(argv[i],"-logo") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->ncch.logoPath = argv[i+1]; set->ncch.ncchType |= CFA; return 2; } else if(strcmp(argv[i],"-desc") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } char *tmp = argv[i+1]; char *tmp2 = strstr(tmp,":"); if(!tmp2){ fprintf(stderr,"[SETTING ERROR] Bad argument '%s %s', correct format:\n",argv[i],argv[i+1]); fprintf(stderr," -desc :\n"); } if(strlen(tmp2) < 2){ fprintf(stderr,"[SETTING ERROR] Bad argument '%s %s', correct format:\n",argv[i],argv[i+1]); fprintf(stderr," -desc :\n"); } u32 app_type_len = (u32)(tmp2-tmp); char *app_type = calloc(app_type_len+1,sizeof(char)); memcpy(app_type,tmp,app_type_len); if(strcasecmp(app_type,"App") == 0 || strcasecmp(app_type,"SDApp") == 0) set->common.keys.accessDescSign.presetType = desc_preset_APP; else if(strcasecmp(app_type,"ECApp") == 0) set->common.keys.accessDescSign.presetType = desc_preset_EC_APP; else if(strcasecmp(app_type,"Demo") == 0) set->common.keys.accessDescSign.presetType = desc_preset_DEMO; else if(strcasecmp(app_type,"DlpChild") == 0 || strcasecmp(app_type,"Dlp") == 0) set->common.keys.accessDescSign.presetType = desc_preset_DLP; else if(strcasecmp(app_type,"FIRM") == 0) set->common.keys.accessDescSign.presetType = desc_preset_FIRM; else{ fprintf(stderr,"[SETTING ERROR] Accessdesc AppType preset '%s' not valid, please manually configure RSF\n",app_type); return USR_BAD_ARG; } char *target_firmware = (tmp2+1); set->common.keys.accessDescSign.targetFirmware = strtoul(target_firmware,NULL,0); switch(set->common.keys.accessDescSign.targetFirmware){ case 1: set->common.keys.accessDescSign.targetFirmware = 0x1B; // or 0x1C break; case 2: set->common.keys.accessDescSign.targetFirmware = 0x1D; // or 0x1E/0x1F break; case 3: set->common.keys.accessDescSign.targetFirmware = 0x20; break; case 4: set->common.keys.accessDescSign.targetFirmware = 0x21; // or 0x22 break; case 5: set->common.keys.accessDescSign.targetFirmware = 0x23; // or 0x24 break; case 6: set->common.keys.accessDescSign.targetFirmware = 0x25; // or 0x26 break; case 7: set->common.keys.accessDescSign.targetFirmware = 0x27; // or 0x28 break; case 8: set->common.keys.accessDescSign.targetFirmware = 0x2C; break; default: break; } set->ncch.ncchType |= CXI; return 2; } else if(strcmp(argv[i],"-exefslogo") == 0){ if(ParamNum){ PrintNoNeedParam(argv[i]); return USR_BAD_ARG; } set->ncch.includeExefsLogo = true; set->ncch.ncchType |= CFA; return 1; } // Ncch Rebuild Options else if(strcmp(argv[i],"-code") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->ncch.codePath = argv[i+1]; set->ncch.ncchType |= CXI; return 2; } else if(strcmp(argv[i],"-exheader") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->ncch.exheaderPath = argv[i+1]; set->ncch.ncchType |= CXI; return 2; } else if(strcmp(argv[i],"-plainrgn") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->ncch.plainRegionPath = argv[i+1]; set->ncch.ncchType |= CXI; return 2; } else if(strcmp(argv[i],"-romfs") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->ncch.romfsPath = argv[i+1]; set->ncch.ncchType |= CFA; return 2; } // Cci Options else if(strcmp(argv[i],"-devcci") == 0){ if(ParamNum){ PrintNoNeedParam(argv[i]); return USR_BAD_ARG; } set->cci.useSDKStockData = true; return 1; } else if(strcmp(argv[i],"-nomodtid") == 0){ if(ParamNum){ PrintNoNeedParam(argv[i]); return USR_BAD_ARG; } set->cci.dontModifyNcchTitleID = true; return 1; } else if(strcmp(argv[i],"-alignwr") == 0){ if(ParamNum){ PrintNoNeedParam(argv[i]); return USR_BAD_ARG; } set->cci.closeAlignWritableRegion = true; return 1; } else if(strcmp(argv[i],"-cverinfo") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_BAD_ARG; } char *pos = strstr(argv[i+1],":"); if(!pos || strlen(pos) < 2){ fprintf(stderr,"[SETTING ERROR] Bad argument '%s %s', correct format:\n",argv[i],argv[i+1]); fprintf(stderr," %s :<'cia'/'tmd'>\n",argv[i]); return USR_BAD_ARG; } char *dtype = pos + 1; if(strcasecmp(dtype,"tmd") == 0) set->cci.cverDataType = CVER_DTYPE_TMD; else if(strcasecmp(dtype,"cia") == 0) set->cci.cverDataType = CVER_DTYPE_CIA; else{ fprintf(stderr,"[SETTING ERROR] Unrecognised cver data type:\"%s\"\n",dtype); return USR_BAD_ARG; } u32 path_len = (pos-argv[i+1])+1; set->cci.cverDataPath = calloc(path_len,sizeof(char)); strncpy(set->cci.cverDataPath,argv[i+1],path_len-1); if(!AssertFile(set->cci.cverDataPath)){ fprintf(stderr,"[SETTING ERROR] Failed to open '%s'\n",set->cci.cverDataPath); return USR_BAD_ARG; } return 2; } // Cia Options else if(strcmp(argv[i],"-major") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->cia.useNormTitleVer = true; u32 ver = strtoul(argv[i+1],NULL,10); if(ver > VER_MAJOR_MAX){ fprintf(stderr,"[SETTING ERROR] Major version: '%d' is too large, max: '%d'\n",ver,VER_MAJOR_MAX); return USR_BAD_ARG; } set->cia.titleVersion[VER_MAJOR] = ver; return 2; } else if(strcmp(argv[i],"-minor") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->cia.useNormTitleVer = true; u32 ver = strtoul(argv[i+1],NULL,10); if(ver > VER_MINOR_MAX){ fprintf(stderr,"[SETTING ERROR] Minor version: '%d' is too large, max: '%d'\n",ver,VER_MINOR_MAX); return USR_BAD_ARG; } set->cia.titleVersion[VER_MINOR] = ver; return 2; } else if(strcmp(argv[i],"-micro") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } u32 ver = strtoul(argv[i+1],NULL,10); if(ver > VER_MICRO_MAX){ fprintf(stderr,"[SETTING ERROR] Micro version: '%d' is too large, max: '%d'\n",ver,VER_MICRO_MAX); return USR_BAD_ARG; } set->cia.titleVersion[VER_MICRO] = ver; return 2; } else if(strcmp(argv[i],"-dver") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->cia.useDataTitleVer = true; u32 ver = strtoul(argv[i+1],NULL,10); if(ver > VER_DVER_MAX){ fprintf(stderr,"[SETTING ERROR] Data version: '%d' is too large, max: '%d'\n",ver,VER_DVER_MAX); return USR_BAD_ARG; } set->cia.titleVersion[VER_MAJOR] = (ver >> 6) & VER_MAJOR_MAX; set->cia.titleVersion[VER_MINOR] = ver & VER_MINOR_MAX; return 2; } else if(strcmp(argv[i],"-deviceid") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->cia.deviceId = strtoul(argv[i+1],NULL,16); return 2; } else if(strcmp(argv[i],"-esaccid") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->cia.eshopAccId = strtoul(argv[i+1],NULL,16); return 2; } else if(strcmp(argv[i],"-rand") == 0){ if(ParamNum){ PrintNoNeedParam(argv[i]); return USR_BAD_ARG; } set->cia.randomTitleKey = true; return 1; } else if(strcmp(argv[i],"-dlc") == 0){ if(ParamNum){ PrintNoNeedParam(argv[i]); return USR_BAD_ARG; } set->cia.DlcContent = true; return 1; } else if(strcmp(argv[i],"-srl") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->ncch.buildNcch0 = false; set->common.workingFileType = infile_srl; set->common.workingFilePath = argv[i+1]; set->common.outFormat = CIA; return 2; } // Ncch Container Conversion else if(strcmp(argv[i],"-ccitocia") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->ncch.buildNcch0 = false; set->common.workingFileType = infile_ncsd; set->common.workingFilePath = argv[i+1]; set->common.outFormat = CIA; return 2; } else if(strcmp(argv[i],"-ciatocci") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->ncch.buildNcch0 = false; set->common.workingFileType = infile_cia; set->common.workingFilePath = argv[i+1]; set->common.outFormat = CCI; return 2; } else if(strcmp(argv[i],"-inclupd") == 0){ if(ParamNum){ PrintNoNeedParam(argv[i]); return USR_BAD_ARG; } set->cia.includeUpdateNcch = true; return 1; } // Other Setting else if(strcmp(argv[i],"-content") == 0 || strcmp(argv[i],"-i") == 0){ if(ParamNum != 1){ PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } char *pos = strstr(argv[i+1],":"); if(!pos || strlen(pos) < 2){ fprintf(stderr,"[SETTING ERROR] Bad argument '%s %s', correct format:\n",argv[i],argv[i+1]); fprintf(stderr," %s :\n",argv[i]); fprintf(stderr," If generating a CIA, then use the format:\n"); fprintf(stderr," %s ::\n",argv[i]); return USR_BAD_ARG; } /* Getting Content Index */ u16 content_index = strtol((char*)(pos+1),NULL,0); /* Storing Content Filepath */ u32 path_len = (u32)(pos-argv[i+1])+1; if(set->common.contentPath[content_index] != NULL){ fprintf(stderr,"[SETTING ERROR] Content %d is already specified\n",content_index); return USR_BAD_ARG; } set->common.contentPath[content_index] = calloc(path_len,sizeof(char)); if(set->common.contentPath[content_index] == NULL){ fprintf(stderr,"[SETTING ERROR] Not enough memory\n"); return USR_MEM_ERROR; } strncpy(set->common.contentPath[content_index],argv[i+1],path_len-1); if(!AssertFile(set->common.contentPath[content_index])){ fprintf(stderr,"[SETTING ERROR] '%s' could not be opened\n",set->common.contentPath[content_index]); return USR_BAD_ARG; } set->common.contentSize[content_index] = GetFileSize64(set->common.contentPath[content_index]); /* Get ContentID for CIA gen */ char *pos2 = strstr(pos+1,":"); if(pos2) set->cia.contentId[content_index] = strtoul((pos2+1),NULL,0); /* Return Next Arg Pos*/ return 2; } // RSF Value Substitution else if(strncmp(argv[i],"-D",2) == 0){ if(ParamNum){ PrintNoNeedParam("-DNAME=VALUE"); return USR_BAD_ARG; } if(set->dname.m_items == 0){ set->dname.m_items = 10; set->dname.u_items = 0; set->dname.items = calloc(set->dname.m_items,sizeof(dname_item)); if(!set->dname.items){ fprintf(stderr,"[SETTING ERROR] Not enough memory\n"); return MEM_ERROR; } } else if(set->dname.m_items == set->dname.u_items){ set->dname.m_items *= 2; /* dname_item *tmp = malloc(sizeof(dname_item)*set->dname.m_items); if(!tmp){ fprintf(stderr,"[SETTING ERROR] Not enough memory\n"); return MEM_ERROR; } memset(tmp,0,sizeof(dname_item)*set->dname.m_items); memcpy(tmp,set->dname.items,sizeof(dname_item)*set->dname.u_items); free(set->dname.items); set->dname.items = tmp; */ set->dname.items = realloc(set->dname.items,sizeof(dname_item)*set->dname.m_items); if(!set->dname.items){ fprintf(stderr,"[SETTING ERROR] Not enough memory\n"); return MEM_ERROR; } } char *name_pos = (char*)(argv[i]+2); u32 name_len = 0; char *val_pos = strstr(name_pos,"="); u32 val_len = 0; if(!val_pos){ fprintf(stderr,"[SETTING ERROR] Format: '%s' is invalid\n",argv[i]); return USR_BAD_ARG; } if(strlen(val_pos) < 2){ fprintf(stderr,"[SETTING ERROR] Format: '%s' is invalid\n",argv[i]); return USR_BAD_ARG; } val_pos = (val_pos + 1); name_len = (val_pos - 1 - name_pos); set->dname.items[set->dname.u_items].name = malloc(name_len+1); memset(set->dname.items[set->dname.u_items].name,0,name_len+1); memcpy(set->dname.items[set->dname.u_items].name,name_pos,name_len); val_len = strlen(val_pos); set->dname.items[set->dname.u_items].value = malloc(val_len+1); memset(set->dname.items[set->dname.u_items].value,0,val_len+1); memcpy(set->dname.items[set->dname.u_items].value,val_pos,val_len); set->dname.u_items++; return 1; } // If not a valid argument fprintf(stderr,"[SETTING ERROR] Unrecognised argument '%s'\n",argv[i]); return USR_UNK_ARG; } int CheckArgumentCombination(user_settings *set) { if(set->ncch.ncchType & (CXI|CFA)){ set->ncch.buildNcch0 = true; if(set->ncch.ncchType & CXI) set->ncch.ncchType = CXI; else set->ncch.ncchType = CFA; } if(set->common.outFormat == NCCH){ set->ncch.buildNcch0 = true; if(set->ncch.ncchType) set->common.outFormat = set->ncch.ncchType; else{ set->ncch.ncchType = CFA; set->common.outFormat = CFA; } } for(int i = 0; i < CIA_MAX_CONTENT; i++){ if( i > CCI_MAX_CONTENT-1 && set->common.contentPath[i] && set->common.outFormat == CCI){ fprintf(stderr,"[SETTING ERROR] Content indexes > %d are invalid for CCI\n",CCI_MAX_CONTENT-1); return USR_BAD_ARG; } if(set->common.contentPath[i] && (set->common.outFormat == CXI || set->common.outFormat == CFA)){ fprintf(stderr,"[SETTING ERROR] You cannot specify content while outputting CXI/CFA files\n"); return USR_BAD_ARG; } } if(set->common.contentPath[0] && set->ncch.buildNcch0){ fprintf(stderr,"[SETTING ERROR] You cannot both import and build content 0\n"); return USR_BAD_ARG; } if(set->common.outFormat == CIA && set->cci.cverDataPath){ fprintf(stderr,"[SETTING ERROR] You cannot use argument \"-cverinfo\" when generating a CIA\n"); return USR_BAD_ARG; } if(set->cia.useDataTitleVer && set->cia.useNormTitleVer){ fprintf(stderr,"[SETTING ERROR] Arguments \"-dver\" and \"-major\"/\"-minor\" cannot be used together\n"); return USR_BAD_ARG; } if(set->ncch.elfPath && set->ncch.codePath){ fprintf(stderr,"[SETTING ERROR] Arguments \"-elf\" and \"-code\" cannot be used together\n"); return USR_BAD_ARG; } bool buildCXI = set->ncch.ncchType == CXI; bool buildCFA = set->ncch.ncchType == CFA; // Detecting Required Arguments if(buildCXI && !set->ncch.elfPath && !set->ncch.codePath){ PrintNeedsArg("-elf"); return USR_BAD_ARG; } if((buildCXI || buildCFA) && !set->common.rsfPath){ PrintNeedsArg("-rsf"); return USR_BAD_ARG; } if(buildCXI && set->ncch.codePath && !set->ncch.exheaderPath){ PrintNeedsArg("-exheader"); return USR_BAD_ARG; } // Reporting bad arguments if(!buildCXI && set->ncch.elfPath){ PrintArgInvalid("-elf"); return USR_BAD_ARG; } if(!buildCXI && set->ncch.codePath){ PrintArgInvalid("-code"); return USR_BAD_ARG; } if(!buildCXI && set->ncch.exheaderPath){ PrintArgInvalid("-exheader"); return USR_BAD_ARG; } if(!buildCXI && set->ncch.plainRegionPath){ PrintArgInvalid("-plainrgn"); return USR_BAD_ARG; } if(!set->ncch.buildNcch0 && set->ncch.includeExefsLogo){ PrintArgInvalid("-exefslogo"); return USR_BAD_ARG; } if(!set->ncch.buildNcch0 && set->ncch.romfsPath){ PrintArgInvalid("-romfs"); return USR_BAD_ARG; } return 0; } void init_UserSettings(user_settings *set) { memset(set,0,sizeof(user_settings)); } void free_UserSettings(user_settings *set) { // Free Content Paths if(set->common.contentPath){ for(int i = 0; i < CIA_MAX_CONTENT; i++) free(set->common.contentPath[i]); free(set->common.contentPath); } // free -DNAME=VALUE for(u32 i = 0; i < set->dname.u_items; i++){ free(set->dname.items[i].name); free(set->dname.items[i].value); } free(set->dname.items); free(set->cci.cverDataPath); // Free Spec File Setting free_RsfSettings(&set->common.rsfSet); // Free Key Data FreeKeys(&set->common.keys); // Free Working File free(set->common.workingFile.buffer); // Free outfile path, if malloc'd if(set->common.outFileName_mallocd) free(set->common.outFileName); // Clear settings init_UserSettings(set); // Free free(set); } void PrintNeedsArg(char *arg) { fprintf(stderr,"[SETTING ERROR] Argument \"%s\" is required\n",arg); } void PrintArgInvalid(char *arg) { fprintf(stderr,"[SETTING ERROR] Argument \"%s\" is invalid\n",arg); } void PrintArgReqParam(char *arg, u32 paramNum) { if(paramNum == 1) fprintf(stderr,"[SETTING ERROR] \"%s\" takes one parameter\n",arg); else fprintf(stderr,"[SETTING ERROR] \"%s\" requires %d parameters\n",arg,paramNum); } void PrintNoNeedParam(char *arg) { fprintf(stderr,"[SETTING ERROR] \"%s\" does not take a parameter\n",arg); } void DisplayHelp(char *app_name) { printf("CTR MAKEROM %d.%d\n",MAKEROM_VER_MAJOR,MAKEROM_VER_MINOR); printf("(C) 3DSGuy 2014\n"); printf("Usage: %s [options... ]\n",app_name); printf("Option Parameter Explanation\n"); printf("GLOBAL OPTIONS:\n"); printf(" -help Display this text\n"); printf(" -rsf ROM Spec File (*.rsf)\n"); printf(" -f Output format, defaults to 'ncch'\n"); printf(" -o Output file\n"); printf(" -v Verbose output\n"); printf(" -DNAME=VALUE Substitute values in RSF file\n"); printf("KEY OPTIONS:\n"); printf(" -target Target for crypto, defaults to 't'\n"); printf(" 't' Test(false) Keys & prod Certs\n"); printf(" 'd' Development Keys & Certs\n"); printf(" 'p' Production Keys & Certs\n"); printf(" -ckeyid Override the automatic common key selection\n"); printf(" -ncchseckey Ncch keyX index ('0'=1.0+, '1'=7.0+)\n"); printf(" -showkeys Display the loaded key chain\n"); printf(" -fsign Ignore invalid signatures\n"); printf("NCCH OPTIONS:\n"); printf(" -elf ELF file\n"); printf(" -icon Icon file\n"); printf(" -banner Banner file\n"); printf(" -logo Logo file (Overrides \"BasicInfo/Logo\" in RSF)\n"); printf(" -desc : Specify Access Descriptor template\n"); printf(" -exefslogo Include Logo in ExeFS (Required for usage on <5.0 systems)\n"); printf("NCCH REBUILD OPTIONS:\n"); printf(" -code Decompressed ExeFS \".code\"\n"); printf(" -exheader Exheader template\n"); printf(" -plainrgn Plain Region binary\n"); printf(" -romfs RomFS binary\n"); printf("CCI OPTIONS:\n"); printf(" -content : Specify content files\n"); printf(" -devcci Use external CTRSDK \"CardInfo\" method\n"); printf(" -nomodtid Don't Modify Content TitleIDs\n"); printf(" -alignwr Align writeable region to the end of last NCCH\n"); printf(" -cverinfo : Include cver title info\n"); printf("CIA OPTIONS:\n"); printf(" -content :: Specify content files\n"); printf(" -major Major version\n"); printf(" -minor Minor version\n"); printf(" -micro Micro version\n"); printf(" -dver Data-title version\n"); printf(" -deviceid 3DS unique device ID\n"); printf(" -esaccid e-Shop account ID\n"); printf(" -rand Use a random title key\n"); printf(" -dlc Create DLC CIA\n"); printf(" -srl Package a TWL SRL in a CIA\n"); printf("NCCH CONTAINER CONVERSION:\n"); printf(" -ccitocia Convert CCI to CIA\n"); printf(" -ciatocci Convert CIA to CCI\n"); printf(" -inclupd Include \"Update NCCH\" in CCI to CIA conversion\n"); }