From 89c0a7b04972e3bbd49a4662337c94f7c52c62cb Mon Sep 17 00:00:00 2001 From: spacy51 Date: Thu, 16 Oct 2008 13:56:49 +0000 Subject: [PATCH] Patches by chrono: [CORE] Add UPS/PPF patch support [SDL] Add UPS/PPF patch support [SDL] Fix memory leak --- CMakeLists.txt | 5 +- src/Patch.cpp | 464 ++++++++++++++++++++++++++++++++++++++++++++++++ src/Patch.h | 27 +++ src/Util.cpp | 92 +--------- src/sdl/SDL.cpp | 103 ++++++----- 5 files changed, 551 insertions(+), 140 deletions(-) create mode 100644 src/Patch.cpp create mode 100644 src/Patch.h diff --git a/CMakeLists.txt b/CMakeLists.txt index daf928f1..6bee0997 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,7 +95,7 @@ IF( NO_DEBUGGER ) MESSAGE(STATUS "The SDL port can't be built without debugging support") SET( CAN_BUILD_VBAM 0 ) ENDIF( CAN_BUILD_VBAM ) - + ADD_DEFINITIONS (-DNO_DEBUGGER) ELSE( NO_DEBUGGER ) ADD_DEFINITIONS (-DBKPT_SUPPORT) @@ -123,7 +123,7 @@ SET(SRC_MAIN src/bios.cpp src/Cheats.cpp src/CheatSearch.cpp - src/EEprom.cpp + src/EEprom.cpp src/Flash.cpp src/Globals.cpp src/interframe.cpp @@ -134,6 +134,7 @@ SET(SRC_MAIN src/Mode3.cpp src/Mode4.cpp src/Mode5.cpp + src/Patch.cpp src/pixel.cpp src/RTC.cpp src/scanline.cpp diff --git a/src/Patch.cpp b/src/Patch.cpp new file mode 100644 index 00000000..04401e79 --- /dev/null +++ b/src/Patch.cpp @@ -0,0 +1,464 @@ +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004-2006 Forgotten and the VBA development team +// Copyright (C) 2007-2008 VBA-M development team and Shay Green +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include +#include +#include +#include + +#include "System.h" +// #include "NLS.h" +// #include "Util.h" +// #include "Flash.h" +// #include "agb/GBA.h" +// #include "Globals.h" +// #include "RTC.h" +// #include "Port.h" + +#ifndef _MSC_VER +#define _stricmp strcasecmp +#endif // ! _MSC_VER + +#if defined(__APPLE__) || defined (MACOSX) +#define fseeko64 fseeko +#define ftello64 ftello +typedef off_t __off64_t; +#endif /* __APPLE__ || MACOSX */ + +static int readInt2(FILE *f) +{ + int res = 0; + int c = fgetc(f); + if(c == EOF) + return -1; + res = c; + c = fgetc(f); + if(c == EOF) + return -1; + return c + (res<<8); +} + +static int readInt3(FILE *f) +{ + int res = 0; + int c = fgetc(f); + if(c == EOF) + return -1; + res = c; + c = fgetc(f); + if(c == EOF) + return -1; + res = c + (res<<8); + c = fgetc(f); + if(c == EOF) + return -1; + return c + (res<<8); +} + +static s64 readInt4(FILE *f) +{ + s64 tmp, res = 0; + int c; + + for (int i = 0; i < 4; i++) { + c = fgetc(f); + if (c == EOF) + return -1; + tmp = c; + res = res + (tmp << (i*8)); + } + + return res; +} + +static s64 readInt8(FILE *f) +{ + s64 tmp, res = 0; + int c; + + for (int i = 0; i < 8; i++) { + c = fgetc(f); + if (c == EOF) + return -1; + tmp = c; + res = res + (tmp << (i*8)); + } + + return res; +} + +static s64 readVarPtr(FILE *f) +{ + s64 offset = 0, shift = 1; + for (;;) { + int c = fgetc(f); + if (c == EOF) return 0; + offset += (c & 0x7F) * shift; + if (c & 0x80) break; + shift <<= 7; + offset += shift; + } + return offset; +} + +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +static uLong computePatchCRC(FILE *f, unsigned int size) +{ + Bytef buf[4096]; + long readed; + + uLong crc = crc32(0L, Z_NULL, 0); + do { + readed = fread(buf, 1, MIN(size, sizeof(buf)), f); + crc = crc32(crc, buf, readed); + size -= readed; + } while (readed > 0); + return crc; +} + +static bool patchApplyIPS(const char *patchname, u8 **r, int *s) +{ + // from the IPS spec at http://zerosoft.zophar.net/ips.htm + FILE *f = fopen(patchname, "rb"); + if(!f) + return false; + + bool result = false; + + u8 *rom = *r; + int size = *s; + if(fgetc(f) == 'P' && + fgetc(f) == 'A' && + fgetc(f) == 'T' && + fgetc(f) == 'C' && + fgetc(f) == 'H') { + int b; + int offset; + int len; + + result = true; + + for(;;) { + // read offset + offset = readInt3(f); + // if offset == EOF, end of patch + if(offset == 0x454f46 || offset == -1) + break; + // read length + len = readInt2(f); + if(!len) { + // len == 0, RLE block + len = readInt2(f); + // byte to fill + int c = fgetc(f); + if(c == -1) + break; + b = (u8)c; + } else + b= -1; + // check if we need to reallocate our ROM + if((offset + len) >= size) { + size *= 2; + rom = (u8 *)realloc(rom, size); + *r = rom; + *s = size; + } + if(b == -1) { + // normal block, just read the data + if(fread(&rom[offset], 1, len, f) != (size_t)len) + break; + } else { + // fill the region with the given byte + while(len--) { + rom[offset++] = b; + } + } + } + } + // close the file + fclose(f); + + return result; +} + +static bool patchApplyUPS(const char *patchname, u8 **rom, int *size) +{ + s64 srcCRC, dstCRC, patchCRC; + + FILE *f = fopen(patchname, "rb"); + if (!f) + return false; + + fseeko64(f, 0, SEEK_END); + __off64_t patchSize = ftello64(f); + if (patchSize < 20) { + fclose(f); + return false; + } + + fseeko64(f, 0, SEEK_SET); + if(fgetc(f) != 'U' || fgetc(f) != 'P' || fgetc(f) != 'S' || fgetc(f) != '1') { + fclose(f); + return false; + } + + fseeko64(f, -12, SEEK_END); + srcCRC = readInt4(f); + dstCRC = readInt4(f); + patchCRC = readInt4(f); + if (srcCRC == -1 || dstCRC == -1 || patchCRC == -1) { + fclose(f); + return false; + } + + fseeko64(f, 0, SEEK_SET); + u32 crc = computePatchCRC(f, patchSize-4); + + if (crc != patchCRC) { + fclose(f); + return false; + } + + crc = crc32(0L, Z_NULL, 0); + crc = crc32(crc, *rom, *size); + + fseeko64(f, 4, SEEK_SET); + s64 dataSize; + s64 srcSize = readVarPtr(f); + s64 dstSize = readVarPtr(f); + + if (crc == srcCRC) { + dataSize = srcSize; + } else if (crc == dstCRC) { + dataSize = dstSize; + } else { + fclose(f); + return false; + } + if (dataSize != *size) { + fclose(f); + return false; + } + + s64 relative = 0; + u8 *mem; + while(ftello64(f) < patchSize - 12) { + relative += readVarPtr(f); + if (relative > dataSize) continue; + mem = *rom + relative; + for(s64 i = relative; i < dataSize; i++) { + int x = fgetc(f); + relative++; + if (!x) break; + if (i < dataSize) { + *mem++ ^= x; + } + } + } + + fclose(f); + return true; +} + +static int ppfVersion(FILE *f) +{ + fseeko64(f, 0, SEEK_SET); + if (fgetc(f) != 'P' || fgetc(f) != 'P' || fgetc(f) != 'F') + return 0; + switch(fgetc(f)){ + case '1': return 1; + case '2': return 2; + case '3': return 3; + default: return 0; + } +} + +int ppfFileIdLen(FILE *f, int version) +{ + if (version == 2) { + fseeko64(f, -8, SEEK_END); + } else { + fseeko64(f, -6, SEEK_END); + } + + if (fgetc(f) != '.' || fgetc(f) != 'D' || fgetc(f) != 'I' || fgetc(f) != 'Z') + return 0; + + return (version == 2) ? readInt4(f) : readInt2(f); +} + +static bool patchApplyPPF1(FILE *f, u8 **rom, int *size) +{ + fseek(f, 0, SEEK_END); + int count = ftell(f); + if (count < 56) + return false; + count -= 56; + + fseek(f, 56, SEEK_SET); + + u8 *mem = *rom; + + while (count > 0) { + int offset = readInt4(f); + if (offset == -1) + break; + int len = fgetc(f); + if (len == EOF) + break; + if (offset+len > *size) + break; + if (fread(&mem[offset], 1, len, f) != (size_t)len) + break; + count -= 4 + 1 + len; + } + + return (count == 0); +} + +static bool patchApplyPPF2(FILE *f, u8 **rom, int *size) +{ + fseek(f, 0, SEEK_END); + int count = ftell(f); + if (count < 56+4+1024) + return false; + count -= 56+4+1024; + + fseek(f, 56, SEEK_SET); + + int datalen = readInt4(f); + if (datalen != *size) + return false; + + u8 *mem = *rom; + + u8 block[1024]; + fread(&block, 1, 1024, f); + if (memcmp(&mem[0x9320], &block, 1024) != 0) + return false; + + int idlen = ppfFileIdLen(f, 2); + if (idlen > 0) + count -= 16 + 16 + idlen; + + fseek(f, 56+4+1024, SEEK_SET); + + while (count > 0) { + int offset = readInt4(f); + if (offset == -1) + break; + int len = fgetc(f); + if (len == EOF) + break; + if (offset+len > *size) + break; + if (fread(&mem[offset], 1, len, f) != (size_t)len) + break; + count -= 4 + 1 + len; + } + + return (count == 0); +} + +static bool patchApplyPPF3(FILE *f, u8 **rom, int *size) +{ + fseek(f, 0, SEEK_END); + int count = ftell(f); + if (count < 56+4+1024) + return false; + count -= 56+4; + + fseek(f, 56, SEEK_SET); + + int imagetype = fgetc(f); + int blockcheck = fgetc(f); + int undo = fgetc(f); + fgetc(f); + + u8 *mem = *rom; + + if (blockcheck) { + u8 block[1024]; + fread(&block, 1, 1024, f); + if (memcmp(&mem[(imagetype == 0) ? 0x9320 : 0x80A0], &block, 1024) != 0) + return false; + count -= 1024; + } + + int idlen = ppfFileIdLen(f, 2); + if (idlen > 0) + count -= 16 + 16 + idlen; + + fseek(f, 56+4+(blockcheck ? 1024 : 0), SEEK_SET); + + while (count > 0) { + __off64_t offset = readInt8(f); + if (offset == -1) + break; + int len = fgetc(f); + if (len == EOF) + break; + if (offset+len > *size) + break; + if (fread(&mem[offset], 1, len, f) != (size_t)len) + break; + if (undo) fseeko64(f, len, SEEK_CUR); + count -= 8 + 1 + len; + if (undo) count -= len; + } + + return (count == 0); +} + +static bool patchApplyPPF(const char *patchname, u8 **rom, int *size) +{ + FILE *f = fopen(patchname, "rb"); + if (!f) + return false; + + bool res = false; + + int version = ppfVersion(f); + switch (version) { + case 1: res = patchApplyPPF1(f, rom, size); break; + case 2: res = patchApplyPPF2(f, rom, size); break; + case 3: res = patchApplyPPF3(f, rom, size); break; + } + + fclose(f); + return res; +} + +bool applyPatch(const char *patchname, u8 **rom, int *size) +{ + if (strlen(patchname) < 5) + return false; + const char * p = strrchr(patchname, '.'); + if (p == NULL) + return false; + if (_stricmp(p, ".ips") == 0) + return patchApplyIPS(patchname, rom, size); + if (_stricmp(p, ".ups") == 0) + return patchApplyUPS(patchname, rom, size); + if (_stricmp(p, ".ppf") == 0) + return patchApplyPPF(patchname, rom, size); + return false; +} diff --git a/src/Patch.h b/src/Patch.h new file mode 100644 index 00000000..45f2c3b9 --- /dev/null +++ b/src/Patch.h @@ -0,0 +1,27 @@ +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef VBA_PATCH_H +#define VBA_PATCH_H + +#include "System.h" + +bool applyPatch(const char *patchname, u8 **rom, int *size); + +#endif diff --git a/src/Util.cpp b/src/Util.cpp index cde98abf..6d2e20a8 100644 --- a/src/Util.cpp +++ b/src/Util.cpp @@ -34,6 +34,7 @@ extern "C" { #include "agb/GBA.h" #include "Globals.h" #include "RTC.h" +#include "Patch.h" #include "Port.h" #include "fex.h" @@ -330,96 +331,9 @@ bool utilWriteBMPFile(const char *fileName, int w, int h, u8 *pix) return true; } -static int utilReadInt2(FILE *f) -{ - int res = 0; - int c = fgetc(f); - if(c == EOF) - return -1; - res = c; - c = fgetc(f); - if(c == EOF) - return -1; - return c + (res<<8); -} - -static int utilReadInt3(FILE *f) -{ - int res = 0; - int c = fgetc(f); - if(c == EOF) - return -1; - res = c; - c = fgetc(f); - if(c == EOF) - return -1; - res = c + (res<<8); - c = fgetc(f); - if(c == EOF) - return -1; - return c + (res<<8); -} - -void utilApplyIPS(const char *ips, u8 **r, int *s) -{ - // from the IPS spec at http://zerosoft.zophar.net/ips.htm - FILE *f = fopen(ips, "rb"); - if(!f) - return; - u8 *rom = *r; - int size = *s; - if(fgetc(f) == 'P' && - fgetc(f) == 'A' && - fgetc(f) == 'T' && - fgetc(f) == 'C' && - fgetc(f) == 'H') { - int b; - int offset; - int len; - for(;;) { - // read offset - offset = utilReadInt3(f); - // if offset == EOF, end of patch - if(offset == 0x454f46) - break; - // read length - len = utilReadInt2(f); - if(!len) { - // len == 0, RLE block - len = utilReadInt2(f); - // byte to fill - int c = fgetc(f); - if(c == -1) - break; - b = (u8)c; - } else - b= -1; - // check if we need to reallocate our ROM - if((offset + len) >= size) { - size *= 2; - rom = (u8 *)realloc(rom, size); - *r = rom; - *s = size; - } - if(b == -1) { - // normal block, just read the data - if(fread(&rom[offset], 1, len, f) != (size_t)len) - break; - } else { - // fill the region with the given byte - while(len--) { - rom[offset++] = b; - } - } - } - } - // close the file - fclose(f); -} - -//TODO: Modify ZSNES code for this -void utilApplyUPS(const char *ips, u8 **r, int *s) +void utilApplyIPS(const char *ips, u8 **rom, int *size) { + applyPatch(ips, rom, size); } extern bool cpuIsMultiBoot; diff --git a/src/sdl/SDL.cpp b/src/sdl/SDL.cpp index 59e19d8d..f1298289 100644 --- a/src/sdl/SDL.cpp +++ b/src/sdl/SDL.cpp @@ -40,6 +40,7 @@ #include "../agb/GBA.h" #include "../agb/agbprint.h" #include "../Flash.h" +#include "../Patch.h" #include "../RTC.h" #include "../Sound.h" #include "../Util.h" @@ -150,7 +151,6 @@ FilterFunc filterFunction = 0; IFBFilterFunc ifbFunction = 0; IFBFilter ifbType = kIFBNone; char filename[2048]; -char ipsname[2048]; char biosFileName[2048]; char gbBiosFileName[2048]; char captureDir[2048]; @@ -185,10 +185,10 @@ static int saveSlotPosition = 0; // default is the slot from normal F1 static int sdlOpenglScale = 1; // will scale window on init by this much static int sdlSoundToggledOff = 0; -// allow up to 100 IPS patches given on commandline -#define IPS_MAX_NUM 100 -int sdl_ips_num = 0; -char * (sdl_ips_names[IPS_MAX_NUM]) = { NULL }; // and so on +// allow up to 100 IPS/UPS/PPF patches given on commandline +#define PATCH_MAX_NUM 100 +int sdl_patch_num = 0; +char * (sdl_patch_names[PATCH_MAX_NUM]) = { NULL }; // and so on #define REWIND_NUM 8 #define REWIND_SIZE 400000 @@ -214,7 +214,7 @@ bool debugger = false; bool debuggerStub = false; int fullscreen = 0; int sdlFlashSize = 0; -int sdlAutoIPS = 1; +int sdlAutoPatch = 1; int sdlRtcEnable = 0; int sdlAgbPrint = 0; int sdlMirroringEnable = 0; @@ -259,11 +259,11 @@ struct option sdlOptions[] = { { "fullscreen", no_argument, &fullscreen, 1 }, { "gdb", required_argument, 0, 'G' }, { "help", no_argument, &sdlPrintUsage, 1 }, - { "ips", required_argument, 0, 'i' }, + { "patch", required_argument, 0, 'i' }, { "no-agb-print", no_argument, &sdlAgbPrint, 0 }, { "no-auto-frameskip", no_argument, &autoFrameSkip, 0 }, { "no-debug", no_argument, 0, 'N' }, - { "no-ips", no_argument, &sdlAutoIPS, 0 }, + { "no-patch", no_argument, &sdlAutoPatch, 0 }, { "no-opengl", no_argument, &openGL, 0 }, { "no-pause-when-inactive", no_argument, &pauseWhenInactive, 0 }, { "no-rtc", no_argument, &sdlRtcEnable, 0 }, @@ -1760,7 +1760,7 @@ Options:\n\ printf(" %d - %s\n", i, getFilterName((Filter)i)); printf("\ -h, --help Print this help\n\ - -i, --ips=PATCH Apply given IPS patch\n\ + -i, --patch=PATCH Apply given patch\n\ -p, --profile=[HERTZ] Enable profiling\n\ -s, --frameskip=FRAMESKIP Set frame skip (0...9)\n\ -t, --save-type=TYPE Set the available save type\n\ @@ -1787,7 +1787,7 @@ Long options only:\n\ --auto-frameskip Enable auto frameskipping\n\ --no-agb-print Disable AGBPrint support\n\ --no-auto-frameskip Disable auto frameskipping\n\ - --no-ips Do not apply IPS patch\n\ + --no-patch Do not automatically apply patch\n\ --no-pause-when-inactive Don't pause when inactive\n\ --no-rtc Disable RTC support\n\ --no-show-speed Don't show emulation speed\n\ @@ -1796,7 +1796,7 @@ Long options only:\n\ --rtc Enable RTC support\n\ --show-speed-normal Show emulation speed\n\ --show-speed-detailed Show detailed speed data\n\ - --cheat 'CHEAT' add a cheat\n\ + --cheat 'CHEAT' Add a cheat\n\ "); } @@ -1848,7 +1848,6 @@ int main(int argc, char **argv) captureDir[0] = 0; saveDir[0] = 0; batteryDir[0] = 0; - ipsname[0] = 0; int op = -1; @@ -1933,16 +1932,15 @@ int main(int argc, char **argv) break; case 'i': if(optarg == NULL) { - fprintf(stderr, "Missing IPS name\n"); + fprintf(stderr, "Missing patch name\n"); exit(-1); } -// strcpy(ipsname, optarg); - if (sdl_ips_num >= IPS_MAX_NUM) { - fprintf(stderr, "Too many IPS patches given at %s (max is %d). Ignoring.\n", optarg, IPS_MAX_NUM); + if (sdl_patch_num >= PATCH_MAX_NUM) { + fprintf(stderr, "Too many patches given at %s (max is %d). Ignoring.\n", optarg, PATCH_MAX_NUM); } else { - sdl_ips_names[sdl_ips_num] = (char *)malloc(1 + strlen(optarg)); - strcpy(sdl_ips_names[sdl_ips_num], optarg); - sdl_ips_num++; + sdl_patch_names[sdl_patch_num] = (char *)malloc(1 + strlen(optarg)); + strcpy(sdl_patch_names[sdl_patch_num], optarg); + sdl_patch_num++; } break; case 'G': @@ -2110,14 +2108,26 @@ int main(int argc, char **argv) if(p) *p = 0; -// if(ipsname[0] == 0) -// sprintf(ipsname, "%s.ips", filename); - if (sdl_ips_num == 0) + if (sdlAutoPatch && sdl_patch_num == 0) { + char * tmp; // no patch given yet - look for ROMBASENAME.ips - sprintf(ipsname, "%s.ips", filename); - sdl_ips_names[0] = ipsname; - sdl_ips_num++; + tmp = (char *)malloc(strlen(filename) + 4 + 1); + sprintf(tmp, "%s.ips", filename); + sdl_patch_names[sdl_patch_num] = tmp; + sdl_patch_num++; + + // no patch given yet - look for ROMBASENAME.ups + tmp = (char *)malloc(strlen(filename) + 4 + 1); + sprintf(tmp, "%s.ups", filename); + sdl_patch_names[sdl_patch_num] = tmp; + sdl_patch_num++; + + // no patch given yet - look for ROMBASENAME.ppf + tmp = (char *)malloc(strlen(filename) + 4 + 1); + sprintf(tmp, "%s.ppf", filename); + sdl_patch_names[sdl_patch_num] = tmp; + sdl_patch_num++; } bool failed = false; @@ -2139,22 +2149,19 @@ int main(int argc, char **argv) if (gbHardware & 5) gbCPUInit(gbBiosFileName, useBios); - gbReset(); cartridgeType = IMAGE_GB; emulator = GBSystem; - if(sdlAutoIPS) { - int size = gbRomSize, patchnum; -// utilApplyIPS(ipsname, &gbRom, &size); - for (patchnum = 0; patchnum < sdl_ips_num; patchnum++) { - fprintf(stdout, "Trying IPS patch %s.\n", sdl_ips_names[patchnum]); - utilApplyIPS(sdl_ips_names[patchnum], &gbRom, &size); - } - if(size != gbRomSize) { - extern bool gbUpdateSizes(); - gbUpdateSizes(); - gbReset(); - } + int size = gbRomSize, patchnum; + for (patchnum = 0; patchnum < sdl_patch_num; patchnum++) { + fprintf(stdout, "Trying patch %s%s\n", sdl_patch_names[patchnum], + applyPatch(sdl_patch_names[patchnum], &gbRom, &size) ? " [success]" : ""); } + if(size != gbRomSize) { + extern bool gbUpdateSizes(); + gbUpdateSizes(); + gbReset(); + } + gbReset(); } } else if(type == IMAGE_GBA) { int size = CPULoadRom(szFile); @@ -2168,18 +2175,12 @@ int main(int argc, char **argv) emulator = GBASystem; CPUInit(biosFileName, useBios); - CPUReset(); - if(sdlAutoIPS) { - int size = 0x2000000, patchnum; -// utilApplyIPS(ipsname, &rom, &size); - for (patchnum = 0; patchnum < sdl_ips_num; patchnum++) { - fprintf(stdout, "Trying IPS patch %s.\n", sdl_ips_names[patchnum]); - utilApplyIPS(sdl_ips_names[patchnum], &rom, &size); - } - if(size != 0x2000000) { - CPUReset(); - } + int patchnum; + for (patchnum = 0; patchnum < sdl_patch_num; patchnum++) { + fprintf(stdout, "Trying patch %s%s\n", sdl_patch_names[patchnum], + applyPatch(sdl_patch_names[patchnum], &rom, &size) ? " [success]" : ""); } + CPUReset(); } } @@ -2361,6 +2362,10 @@ int main(int argc, char **argv) filterPix = NULL; } + for (int i = 0; i < sdl_patch_num; i++) { + free(sdl_patch_names[i]); + } + #if WITH_LIRC StopLirc(); #endif