// create the reference movie - write the 'moov' header and populate the 'rmra' atom static void write_moov( FILE *outputFile, struct Options *options ) { off_t headerOffset; writeHeader( outputFile, 'moov', &headerOffset ); write_rmra( outputFile, options ); patchHeader( outputFile, headerOffset ); }
// write the 'rmra' and add each Reference Movie Descriptor Atom 'rmda' // NOTE: The order DOES matter here -- the last one that passes all of // its checks (data rate, version check) wins. Since we can only describe // "data rate >= x" and "we are on iPhone" and not the opposites of those checks, // there's only one order to put the 'rmra' atoms in such that they can all be effective. static void write_rmra( FILE *outputFile, struct Options *options ) { off_t headerOffset; writeHeader( outputFile, 'rmra', &headerOffset ); write_rmda( outputFile, options->desktopPath, kNoRequirements, kDataRate288ModemRate ); write_rmda( outputFile, options->lowPath, kRequireiPhone, kDataRateLowRate ); write_rmda( outputFile, options->highPath, kRequireiPhone, kDataRate1MbpsRate ); patchHeader( outputFile, headerOffset ); }
// for each reference, create the appropriate 'rmda' // in each reference write a data reference atom 'rdrf' and a data rate atom 'rmdr' // in the iPhone cases "kRequireiPhone" also write a version check atom 'rmvc' static void write_rmda( FILE *outputFile, const char *path, int requirements, uint32_t dataRate ) { off_t headerOffset; writeHeader( outputFile, 'rmda', &headerOffset ); write_rdrf( outputFile, path ); write_rmdr( outputFile, dataRate ); if( requirements & kRequireiPhone ) write_iPhone_rmvc( outputFile ); patchHeader( outputFile, headerOffset ); }
// write the data reference atom 'rdrf' static void write_rmdr( FILE *outputFile, uint32_t dataRate ) { off_t headerOffset; uint32_t flags = 0; dataRate = OSSwapHostToBigInt32( dataRate ); writeHeader( outputFile, 'rmdr', &headerOffset ); fwrite( &flags, sizeof(flags), 1, outputFile ); fwrite( &dataRate, sizeof(dataRate), 1, outputFile ); patchHeader( outputFile, headerOffset ); }
// write the data rate atom 'rmdr' static void write_rdrf( FILE *outputFile, const char *path ) { off_t headerOffset; size_t pathSize = strlen( path ) + 1; // include NULL uint32_t flags = 0; uint32_t dataRefType = OSSwapHostToBigInt32( 'url ' ); uint32_t dataRefSize = OSSwapHostToBigInt32( pathSize ); writeHeader( outputFile, 'rdrf', &headerOffset ); fwrite( &flags, sizeof(flags), 1, outputFile ); fwrite( &dataRefType, sizeof(dataRefType), 1, outputFile ); fwrite( &dataRefSize, sizeof(dataRefSize), 1, outputFile ); fwrite( path, pathSize, 1, outputFile ); patchHeader( outputFile, headerOffset ); }
// write the iPhone version check atom 'rmvc' static void write_iPhone_rmvc( FILE *outputFile ) { off_t headerOffset; uint32_t flags = 0; uint32_t gestaltTag = OSSwapHostToBigInt32( 'mobi' ); uint32_t val1 = OSSwapHostToBigInt32( 1 ); // bitflags is 1 uint32_t val2 = OSSwapHostToBigInt32( 1 ); // bitmask is 1 uint16_t checkType = OSSwapHostToBigInt16( 1 ); // type is mask writeHeader( outputFile, 'rmvc', &headerOffset ); fwrite( &flags, sizeof(flags), 1, outputFile ); fwrite( &gestaltTag, sizeof(gestaltTag), 1, outputFile ); fwrite( &val1, sizeof(val1), 1, outputFile ); fwrite( &val2, sizeof(val2), 1, outputFile ); fwrite( &checkType, sizeof(checkType), 1, outputFile ); patchHeader( outputFile, headerOffset ); }
// patches given game file to make it compatible with WinXP extern "C" void CALLBACK PatchFile(HWND hwnd, HINSTANCE hinst, LPCSTR lpszCmdLine, int nCmdShow) { std::FILE *fp = std::fopen(lpszCmdLine, "r+b"); if (fp) { // save backup copy of original file std::stringstream backup; backup << lpszCmdLine << ".bak"; CopyFile(lpszCmdLine, backup.str().c_str(), FALSE); // patch file patchImports(lpszCmdLine); patchHeader(lpszCmdLine); MessageBox(NULL, "Game patched!", "Stellaris WinXP fix", MB_OK); } else { std::stringstream ss; ss << "Can't open " << lpszCmdLine; MessageBox(NULL, ss.str().c_str(), "Stellaris WinXP fix", MB_OK); } }