void Game::parseCmdLine(const mkString& cmd_line) { std::vector<mkString> tokens; extractTokens(cmd_line, tokens); for (size_t i = 0; i < tokens.size(); ++i) { const mkString& token = tokens[i]; const mkString* next_token_ptr = (i < tokens.size() - 1) ? &tokens[i+1] : NULL; if (token == "-freelook") m_startWithFreelook = true; else if (token == "-disable_shadows") m_disableShadows = true; else if (token == "-level") { CHK_ARG("-level"); m_levelName = *next_token_ptr; ++i; } else { Ogre::StringStream ss; ss << "Unrecognized command line parameter '" << token << "'"; MessageBoxA(NULL, ss.str().c_str(), NULL, MB_OK); } } }
int main(int argc, char **argv) { int i, j; int input = -1, output = -1, src_fmt = -1, dst_fmt = -1; if (argc == 9) { for (i = 1; i < argc; i++) { if (CHK_ARG("-i")) { if (input < 0) { /* Get index value for the input file name */ i++; input = i; } else { input = -1; break; } } else if (CHK_ARG("-o")) { if (output < 0) { /* Get index value for the output file name */ i++; output = i; } else { output = -1; break; } } else if (CHK_ARG("-s")) { if (src_fmt < 0) { i++; /* Validate option */ for (j = 0; j < format_cnt; j++) { if (CHK_ARG(formats[j])) { /* Get index value for the input file format */ src_fmt = j; break; } } if (src_fmt < 0) break; } else { src_fmt = -1; break; } } else if (CHK_ARG("-d")) { if (dst_fmt < 0) { i++; /* Validate option */ for (j = 0; j < format_cnt; j++) { if (CHK_ARG(formats[j])) { /* Get index value for the input file format */ dst_fmt = j; break; } } if (dst_fmt < 0) break; } else { dst_fmt = -1; break; } } } } if (input < 0 || output < 0 || src_fmt < 0 || dst_fmt < 0) { usage(argv); return 1; } if (src_fmt == dst_fmt) { printf("\n\tDestination file format cannot be the same as the source file format.\n\tProcess aborted.\n"); return 1; } sixty_t *sixty_header = malloc(sizeof(sixty_t)); if (!sixty_header) { printf("\n\tError allocating memory for the save header.\n"); return 1; } memset(sixty_header, 0, sizeof(sixty_t)); FILE *infile = fopen(argv[input], "rb"); if (!infile) { printf("\n\tError opening \"%s\" for reading.\n", argv[input]); free(sixty_header); return 1; } fseek(infile, 0, SEEK_END); uint32_t fsize = ftell(infile); rewind(infile); if (fsize == 0 || fsize > CtrlPakx8 || (fsize % 4) != 0) { printf("\n\tInvalid N64 save file.\n"); if (fsize == 0) printf("\n\tFile size is zero!\n"); if (fsize > CtrlPakx8) printf("\n\tFile size is greater than %u KiB!\n", CtrlPakx8 / 1024); if ((fsize % 4) != 0) printf("\n\tFile size is not a multiple of 4!\n"); free(sixty_header); fclose(infile); return 1; } if (src_fmt == 3 && fsize < sizeof(sixty_t)) { printf("\n\tInput save file is not big enough to store a Sixtyforce save header!\n"); free(sixty_header); fclose(infile); return 1; } FILE *outfile = fopen(argv[output], "wb"); if (!outfile) { printf("\n\tError opening \"%s\" for writing.\n", argv[output]); free(sixty_header); fclose(infile); return 1; } char tmp[256] = {0}; bool sixty_cp = false; uint32_t data = 0, save_size = 0; if (src_fmt == 3) { /* Check if this is a Sixtyforce save */ fread(sixty_header, sizeof(sixty_t), 1, infile); rewind(infile); if (!strncmp(sixty_header->magic1, "60cs", 4) && !strncmp(sixty_header->magic2, "head", 4) && !strncmp(sixty_header->magic3, "time", 4) && \ !strncmp(sixty_header->magic4, "save", 4) && !strncmp(sixty_header->magic5, "type", 4) && !strncmp(sixty_header->magic6, "size", 4) && \ !strncmp(sixty_header->magic7, "data", 4)) { #ifdef DEBUG print_sixty_header(sixty_header); #endif /* Get save size */ save_size = bswap_32(sixty_header->datasize2); // Stored in Big Endian /* Check if this file contains a Controller Pak save */ if (fsize > (0x84 + save_size + 8)) // Sixtyforce header + save data + "pak0" block { fseek(infile, 0x84 + save_size, SEEK_SET); fread(&data, 4, 1, infile); rewind(infile); sixty_cp = (data == bswap_32(PAK0_MAGIC)); } /* Prepare file stream position for data access */ fseek(infile, 0x84, SEEK_SET); } else { printf("\n\tInput save file is not a Sixtyforce save!\n"); free(sixty_header); fclose(infile); fclose(outfile); remove(argv[output]); return 1; } } else { /* Get save size */ save_size = fsize; } /* Try to guess the most probable save type using the save file size */ int type = -1; uint32_t type_size = 0; if (save_size <= EEPROM) { type = 0; type_size = EEPROM; } else if (save_size <= EEPROMx4) { type = 0; type_size = EEPROMx4; } else if (save_size <= EEPROMx8) { type = 0; type_size = EEPROMx8; } else if (save_size <= EEPROMx32) { type = 0; type_size = EEPROMx32; } else if (save_size <= SRAM) { /* Even though this is the real size for Controller Pak saves, only Sixtyforce seems to use it */ /* Let's just assume it's a SRAM save and call it a day */ type = 1; type_size = SRAM; } else if (save_size <= FlashRAM) { /* Also applies to Controller Pak saves from Wii64. We'll ask about this later. */ type = 2; type_size = FlashRAM; } else if (save_size <= CtrlPakx8) { type = 3; type_size = CtrlPakx8; } if (src_fmt == 0 && type == 2) // Input: Wii64 FlashRAM { if (!strncasecmp(argv[input] + strlen(argv[input]) - 4, ".fla", 4)) { /* Assume that the input file is actually a FlashRAM save and remain unchanged */ } else if (!strncasecmp(argv[input] + strlen(argv[input]) - 4, ".mpk", 4)) { /* Assume that the input file is actually a Controller Pak save */ type = 3; } else { /* Ask the user if the input save is actually a Controller Pak save */ while(true) { if (getLine("\n\tIs the input file a Controller Pak save? (yes/no): ", tmp, sizeof(tmp)) == 0) { if (strlen(tmp) == 3 && !strncmp(tmp, "yes", 3)) { /* Change save type */ type = 3; break; } else if (strlen(tmp) == 2 && !strncmp(tmp, "no", 2)) { /* Remain unchanged */ break; } else { printf("\tInvalid input. Please answer with \"yes\" or \"no\".\n"); } } else { printf("\tInvalid input. Please answer with \"yes\" or \"no\".\n"); } } } } printf("\n\tDetected save type: %s (%u Kbits).\n", SAVE_TYPE_STR(type), ((type_size * 8) / 1024)); if (src_fmt == 3 && sixty_cp && (dst_fmt == 0 || dst_fmt == 1)) printf("\n\tDetected Sixtyforce Controller Pak save data (SRAM %u Kbits).\n", ((CtrlPak * 8) / 1024)); /* Redundancy checks: */ /* Wii64 EEPROM -> Project64 EEPROM */ /* Project64 EEPROM -> Wii64 EEPROM */ /* Wii64 SRAM -> Wii N64 VC SRAM */ /* Wii N64 VC SRAM -> Wii64 SRAM */ /* Wii64 FlashRAM -> Wii N64 VC FlashRAM */ /* Wii N64 VC FlashRAM -> Wii64 FlashRAM */ if ((((src_fmt == 0 && dst_fmt == 1) || (src_fmt == 1 && dst_fmt == 0)) && type == 0) || \ (((src_fmt == 0 && dst_fmt == 2) || (src_fmt == 2 && dst_fmt == 0)) && (type == 1 || type == 2))) { printf("\n\tThis %s save file doesn't need to be modified.\n\tJust try it with %s.\n", \ SAVE_TYPE_STR(type), \ (dst_fmt == 0 ? "Wii64" : (dst_fmt == 1 ? "Project64" : "your Wii N64 Virtual Console title"))); free(sixty_header); fclose(infile); fclose(outfile); remove(argv[output]); return 1; } if (dst_fmt == 2 && type == 3) // Output: Wii N64 VC Controller Pak { printf("\n\tWii N64 Virtual Console isn't compatible with\n\tController Pak save data.\n"); free(sixty_header); fclose(infile); fclose(outfile); remove(argv[output]); return 1; } if (dst_fmt == 3 && type == 3) // Output: Sixtyforce Controller Pak { printf("\n\tConversion of Controller Pak data to the Sixtyforce format\n\tisn't supported (yet).\n"); free(sixty_header); fclose(infile); fclose(outfile); remove(argv[output]); return 1; } uint32_t outsize = 0; bool byteswap = false; switch(type) { case 0: // EEPROM /* Byteswapping isn't needed */ byteswap = false; /* Adjust output save size according to the destination format */ outsize = ((dst_fmt == 0 || dst_fmt == 1) ? EEPROMx4 : (dst_fmt == 2 ? EEPROMx32 : EEPROMx8)); break; case 1: // SRAM /* Only apply 32-bit byteswapping if either the source or destiny format is Project64 */ byteswap = (src_fmt == 1 || dst_fmt == 1); /* Adjust output save size */ outsize = SRAM; break; case 2: // Flash RAM /* Only apply 32-bit byteswapping if either the source or destiny format is Project64 */ byteswap = (src_fmt == 1 || dst_fmt == 1); /* Adjust output save size */ outsize = FlashRAM; break; case 3: // Controller Pak /* Byteswapping isn't needed */ byteswap = false; /* Adjust output save size according to the destination format */ outsize = (dst_fmt == 0 ? CtrlPakx4 : CtrlPakx8); break; default: break; } /* Time to do the magic */ if (dst_fmt == 3) // Sixtyforce { /* Generate Sixtyforce header */ strcpy(sixty_header->magic1, "60cs"); sixty_header->filesize = bswap_32((uint32_t)(0x84 - 0x08 + outsize)); strcpy(sixty_header->magic2, "head"); strcpy(sixty_header->magic3, "time"); sixty_header->unk1 = bswap_32((uint32_t)0x04); strcpy(sixty_header->magic4, "save"); sixty_header->savesize = bswap_32((uint32_t)(0x84 - 0x64 + outsize)); strcpy(sixty_header->magic5, "type"); sixty_header->unk2 = bswap_32((uint32_t)0x04); sixty_header->type = bswap_32((uint32_t)(type == 0 ? 0x01 : (type == 1 ? 0x03 : 0x04))); strcpy(sixty_header->magic6, "size"); sixty_header->unk3 = bswap_32((uint32_t)0x04); sixty_header->datasize1 = bswap_32(outsize); strcpy(sixty_header->magic7, "data"); sixty_header->datasize2 = bswap_32(outsize); #ifdef DEBUG print_sixty_header(sixty_header); #endif /* Write header to the output file */ fwrite(sixty_header, sizeof(sixty_t), 1, outfile); } /* Write save data */ write_data(data, infile, outfile, (outsize > save_size ? save_size : outsize), byteswap); if (outsize > save_size) pad_data((dst_fmt == 2), (outsize - save_size), outfile); /* Extract the Controller Pak data from the Sixtyforce save (if available) */ if (sixty_cp && (dst_fmt == 0 || dst_fmt == 1)) { rewind(infile); fseek(infile, (0x84 + save_size + 8), SEEK_SET); // Sixtyforce header + save data + "pak0" block uint32_t pak0_size = (fsize - (0x84 + save_size + 8)); // Remaining data snprintf(tmp, strlen(argv[output]), argv[output]); for(i = strlen(tmp); tmp[i] != '.'; i--); if (i > 0) tmp[i] = '\0'; strncat(tmp, ".mpk", 4); FILE *cpak = fopen(tmp, "wb"); if (!cpak) { printf("\n\tError opening \"%s\" for writing.\n", tmp); } else { write_data(data, infile, cpak, pak0_size, false); pad_data(false, (dst_fmt == 0 ? (CtrlPakx4 - pak0_size) : (CtrlPakx8 - pak0_size)), cpak); fclose(cpak); printf("\n\tSaved additional Controller Pak data to \"%s\".", tmp); printf("\n\tYou can use it with %s.\n", (dst_fmt == 0 ? "Wii64" : "Project64")); } } printf("\n\tConversion process successfully completed!\n"); free(sixty_header); fclose(infile); fclose(outfile); return 0; }