mirror of
https://github.com/dborth/vbagx.git
synced 2024-11-22 18:49:18 +01:00
add UPS/IPS/PPF patch support
This commit is contained in:
parent
4e0ff85b3f
commit
6864390b7f
@ -249,6 +249,15 @@ LoadFATSzFile(char * filepath, unsigned char * rbuffer)
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
int
|
int
|
||||||
LoadBufferFromFAT (char *filepath, bool silent)
|
LoadBufferFromFAT (char *filepath, bool silent)
|
||||||
|
{
|
||||||
|
return LoadBufferFromFAT((char *)savebuffer, filepath, silent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Load buffer from FAT file
|
||||||
|
***************************************************************************/
|
||||||
|
int
|
||||||
|
LoadBufferFromFAT (char * buffer, char *filepath, bool silent)
|
||||||
{
|
{
|
||||||
int size = 0;
|
int size = 0;
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ int LoadFATFile (char * fbuffer, int length);
|
|||||||
int LoadFATSzFile(char * filepath, unsigned char * rbuffer);
|
int LoadFATSzFile(char * filepath, unsigned char * rbuffer);
|
||||||
int SaveBufferToFAT (char *filepath, int datasize, bool silent);
|
int SaveBufferToFAT (char *filepath, int datasize, bool silent);
|
||||||
int LoadBufferFromFAT (char *filepath, bool silent);
|
int LoadBufferFromFAT (char *filepath, bool silent);
|
||||||
|
int LoadBufferFromFAT (char *buffer, char *filepath, bool silent);
|
||||||
|
|
||||||
extern char currFATdir[MAXPATHLEN];
|
extern char currFATdir[MAXPATHLEN];
|
||||||
extern FILE * fatfile;
|
extern FILE * fatfile;
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define SAVEBUFFERSIZE (512 * 1024)
|
#define SAVEBUFFERSIZE (1024 * 1024 * 2)
|
||||||
#define MAXJOLIET 255
|
#define MAXJOLIET 255
|
||||||
#define MAXDISPLAY 40
|
#define MAXDISPLAY 40
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "unzip.h"
|
#include "unzip.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include "Flash.h"
|
#include "Flash.h"
|
||||||
|
#include "Patch.h"
|
||||||
#include "Port.h"
|
#include "Port.h"
|
||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
#include "Sound.h"
|
#include "Sound.h"
|
||||||
@ -589,6 +590,80 @@ static void ApplyPerImagePreferences()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LoadPatch(int method)
|
||||||
|
{
|
||||||
|
int patchsize = 0;
|
||||||
|
int patchtype = -1;
|
||||||
|
|
||||||
|
AllocSaveBuffer ();
|
||||||
|
|
||||||
|
char patchpath[3][512];
|
||||||
|
memset(patchpath, 0, sizeof(patchpath));
|
||||||
|
sprintf(patchpath[0], "%s/%s.ips",currentdir,ROMFilename);
|
||||||
|
sprintf(patchpath[1], "%s/%s.ups",currentdir,ROMFilename);
|
||||||
|
sprintf(patchpath[2], "%s/%s.ppf",currentdir,ROMFilename);
|
||||||
|
|
||||||
|
ShowAction((char *)"Loading patch...");
|
||||||
|
|
||||||
|
switch (method)
|
||||||
|
{
|
||||||
|
case METHOD_SD:
|
||||||
|
case METHOD_USB:
|
||||||
|
for(int i=0; i<3; i++)
|
||||||
|
{
|
||||||
|
patchsize = LoadBufferFromFAT (patchpath[i], SILENT);
|
||||||
|
|
||||||
|
if(patchsize)
|
||||||
|
{
|
||||||
|
patchtype = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case METHOD_SMB:
|
||||||
|
for(int i=0; i<3; i++)
|
||||||
|
{
|
||||||
|
patchsize = LoadBufferFromSMB (patchpath[i], SILENT);
|
||||||
|
|
||||||
|
if(patchsize)
|
||||||
|
{
|
||||||
|
patchtype = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(patchsize > 0)
|
||||||
|
{
|
||||||
|
// create memory file
|
||||||
|
MFILE * mf = memfopen((char *)savebuffer, patchsize);
|
||||||
|
|
||||||
|
if(cartridgeType == 1)
|
||||||
|
{
|
||||||
|
if(patchtype == 0)
|
||||||
|
patchApplyIPS(mf, &gbRom, &gbRomSize);
|
||||||
|
else if(patchtype == 1)
|
||||||
|
patchApplyUPS(mf, &gbRom, &gbRomSize);
|
||||||
|
else
|
||||||
|
patchApplyPPF(mf, &gbRom, &gbRomSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(patchtype == 0)
|
||||||
|
patchApplyIPS(mf, &rom, &GBAROMSize);
|
||||||
|
else if(patchtype == 1)
|
||||||
|
patchApplyUPS(mf, &rom, &GBAROMSize);
|
||||||
|
else
|
||||||
|
patchApplyPPF(mf, &rom, &GBAROMSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
memfclose(mf); // close memory file
|
||||||
|
}
|
||||||
|
|
||||||
|
FreeSaveBuffer ();
|
||||||
|
}
|
||||||
|
|
||||||
extern bool gbUpdateSizes();
|
extern bool gbUpdateSizes();
|
||||||
|
|
||||||
bool LoadGBROM(int method)
|
bool LoadGBROM(int method)
|
||||||
@ -729,7 +804,7 @@ bool LoadVBAROM(int method)
|
|||||||
//if (gbHardware & 5)
|
//if (gbHardware & 5)
|
||||||
//gbCPUInit(gbBiosFileName, useBios);
|
//gbCPUInit(gbBiosFileName, useBios);
|
||||||
|
|
||||||
//applyPatch(patch, &gbRom, &size);
|
LoadPatch(method);
|
||||||
|
|
||||||
gbSoundReset();
|
gbSoundReset();
|
||||||
gbSoundSetQuality(soundQuality);
|
gbSoundSetQuality(soundQuality);
|
||||||
@ -752,7 +827,7 @@ bool LoadVBAROM(int method)
|
|||||||
soundReset();
|
soundReset();
|
||||||
soundSetQuality(soundQuality);
|
soundSetQuality(soundQuality);
|
||||||
CPUInit("BIOS.GBA", 1);
|
CPUInit("BIOS.GBA", 1);
|
||||||
//applyPatch(patch, &gbRom, &size);
|
LoadPatch(method);
|
||||||
CPUReset();
|
CPUReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ extern "C" {
|
|||||||
|
|
||||||
unsigned int MEM2Storage = 0x91000000;
|
unsigned int MEM2Storage = 0x91000000;
|
||||||
|
|
||||||
static u32 GBAROMSize = 0;
|
int GBAROMSize = 0;
|
||||||
|
|
||||||
#ifdef USE_VM
|
#ifdef USE_VM
|
||||||
//extern u32 loadtimeradjust;
|
//extern u32 loadtimeradjust;
|
||||||
|
@ -20,5 +20,7 @@ u16 VMRead16( u32 address );
|
|||||||
u8 VMRead8( u32 address );
|
u8 VMRead8( u32 address );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern int GBAROMSize;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
467
source/vba/Patch.cpp
Normal file
467
source/vba/Patch.cpp
Normal file
@ -0,0 +1,467 @@
|
|||||||
|
// 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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
#include "System.h"
|
||||||
|
#include "memfile.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
#ifdef __GNUC__
|
||||||
|
typedef off64_t __off64_t;
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#define _stricmp strcasecmp
|
||||||
|
#endif // ! _MSC_VER
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define fseeko64 _fseeki64
|
||||||
|
#define ftello64 _ftelli64
|
||||||
|
typedef __int64 __off64_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__APPLE__) || defined (MACOSX)
|
||||||
|
#define fseeko64 fseeko
|
||||||
|
#define ftello64 ftello
|
||||||
|
typedef off_t __off64_t;
|
||||||
|
#endif /* __APPLE__ || MACOSX */
|
||||||
|
|
||||||
|
static int readInt2(MFILE *f) {
|
||||||
|
int res = 0;
|
||||||
|
int c = memfgetc(f);
|
||||||
|
if (c == MEOF)
|
||||||
|
return -1;
|
||||||
|
res = c;
|
||||||
|
c = memfgetc(f);
|
||||||
|
if (c == MEOF)
|
||||||
|
return -1;
|
||||||
|
return c + (res << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int readInt3(MFILE *f) {
|
||||||
|
int res = 0;
|
||||||
|
int c = memfgetc(f);
|
||||||
|
if (c == MEOF)
|
||||||
|
return -1;
|
||||||
|
res = c;
|
||||||
|
c = memfgetc(f);
|
||||||
|
if (c == MEOF)
|
||||||
|
return -1;
|
||||||
|
res = c + (res << 8);
|
||||||
|
c = memfgetc(f);
|
||||||
|
if (c == MEOF)
|
||||||
|
return -1;
|
||||||
|
return c + (res << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static s64 readInt4(MFILE *f) {
|
||||||
|
s64 tmp, res = 0;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
c = memfgetc(f);
|
||||||
|
if (c == MEOF)
|
||||||
|
return -1;
|
||||||
|
tmp = c;
|
||||||
|
res = res + (tmp << (i * 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static s64 readInt8(MFILE *f) {
|
||||||
|
s64 tmp, res = 0;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
c = memfgetc(f);
|
||||||
|
if (c == MEOF)
|
||||||
|
return -1;
|
||||||
|
tmp = c;
|
||||||
|
res = res + (tmp << (i * 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static s64 readVarPtr(MFILE *f) {
|
||||||
|
s64 offset = 0, shift = 1;
|
||||||
|
for (;;) {
|
||||||
|
int c = memfgetc(f);
|
||||||
|
if (c == MEOF)
|
||||||
|
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(MFILE *f, unsigned int size) {
|
||||||
|
Bytef buf[4096];
|
||||||
|
long readed;
|
||||||
|
|
||||||
|
uLong crc = crc32(0L, Z_NULL, 0);
|
||||||
|
do {
|
||||||
|
readed = memfread(buf, 1, MIN(size, sizeof(buf)), f);
|
||||||
|
crc = crc32(crc, buf, readed);
|
||||||
|
size -= readed;
|
||||||
|
} while (readed > 0);
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool patchApplyIPS(MFILE * f, u8 **r, int *s) {
|
||||||
|
// from the IPS spec at http://zerosoft.zophar.net/ips.htm
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
u8 *rom = *r;
|
||||||
|
int size = *s;
|
||||||
|
if (memfgetc(f) == 'P' && memfgetc(f) == 'A' && memfgetc(f) == 'T'
|
||||||
|
&& memfgetc(f) == 'C' && memfgetc(f) == 'H') {
|
||||||
|
int b;
|
||||||
|
int offset;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
result = true;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
// read offset
|
||||||
|
offset = readInt3(f);
|
||||||
|
// if offset == MEOF, 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 = memfgetc(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 (memfread(&rom[offset], 1, len, f) != (size_t) len)
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// fill the region with the given byte
|
||||||
|
while (len--) {
|
||||||
|
rom[offset++] = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool patchApplyUPS(MFILE * f, u8 **rom, int *size) {
|
||||||
|
|
||||||
|
s64 srcCRC, dstCRC, patchCRC;
|
||||||
|
|
||||||
|
memfseek(f, 0, MSEEK_END);
|
||||||
|
long int patchSize = memftell(f);
|
||||||
|
if (patchSize < 20) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memfseek(f, 0, MSEEK_SET);
|
||||||
|
|
||||||
|
if (memfgetc(f) != 'U' || memfgetc(f) != 'P' || memfgetc(f) != 'S'
|
||||||
|
|| memfgetc(f) != '1') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memfseek(f, -12, MSEEK_END);
|
||||||
|
srcCRC = readInt4(f);
|
||||||
|
dstCRC = readInt4(f);
|
||||||
|
patchCRC = readInt4(f);
|
||||||
|
if (srcCRC == -1 || dstCRC == -1 || patchCRC == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memfseek(f, 0, MSEEK_SET);
|
||||||
|
u32 crc = computePatchCRC(f, patchSize - 4);
|
||||||
|
|
||||||
|
if (crc != patchCRC) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
crc = crc32(0L, Z_NULL, 0);
|
||||||
|
crc = crc32(crc, *rom, *size);
|
||||||
|
|
||||||
|
memfseek(f, 4, MSEEK_SET);
|
||||||
|
s64 dataSize;
|
||||||
|
s64 srcSize = readVarPtr(f);
|
||||||
|
s64 dstSize = readVarPtr(f);
|
||||||
|
|
||||||
|
if (crc == srcCRC) {
|
||||||
|
dataSize = srcSize;
|
||||||
|
} else if (crc == dstCRC) {
|
||||||
|
dataSize = dstSize;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (dataSize != *size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 relative = 0;
|
||||||
|
u8 *mem;
|
||||||
|
while (memftell(f) < patchSize - 12) {
|
||||||
|
relative += readVarPtr(f);
|
||||||
|
if (relative > dataSize)
|
||||||
|
continue;
|
||||||
|
mem = *rom + relative;
|
||||||
|
for (s64 i = relative; i < dataSize; i++) {
|
||||||
|
int x = memfgetc(f);
|
||||||
|
relative++;
|
||||||
|
if (!x)
|
||||||
|
break;
|
||||||
|
if (i < dataSize) {
|
||||||
|
*mem++ ^= x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ppfVersion(MFILE *f) {
|
||||||
|
memfseek(f, 0, MSEEK_SET);
|
||||||
|
if (memfgetc(f) != 'P' || memfgetc(f) != 'P' || memfgetc(f) != 'F')
|
||||||
|
return 0;
|
||||||
|
switch (memfgetc(f)) {
|
||||||
|
case '1':
|
||||||
|
return 1;
|
||||||
|
case '2':
|
||||||
|
return 2;
|
||||||
|
case '3':
|
||||||
|
return 3;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ppfFileIdLen(MFILE *f, int version) {
|
||||||
|
if (version == 2) {
|
||||||
|
memfseek(f, -8, MSEEK_END);
|
||||||
|
} else {
|
||||||
|
memfseek(f, -6, MSEEK_END);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memfgetc(f) != '.' || memfgetc(f) != 'D' || memfgetc(f) != 'I'
|
||||||
|
|| memfgetc(f) != 'Z')
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (version == 2) ? readInt4(f) : readInt2(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool patchApplyPPF1(MFILE *f, u8 **rom, int *size) {
|
||||||
|
memfseek(f, 0, MSEEK_END);
|
||||||
|
int count = memftell(f);
|
||||||
|
if (count < 56)
|
||||||
|
return false;
|
||||||
|
count -= 56;
|
||||||
|
|
||||||
|
memfseek(f, 56, MSEEK_SET);
|
||||||
|
|
||||||
|
u8 *mem = *rom;
|
||||||
|
|
||||||
|
while (count > 0) {
|
||||||
|
int offset = readInt4(f);
|
||||||
|
if (offset == -1)
|
||||||
|
break;
|
||||||
|
int len = memfgetc(f);
|
||||||
|
if (len == MEOF)
|
||||||
|
break;
|
||||||
|
if (offset + len > *size)
|
||||||
|
break;
|
||||||
|
if (memfread(&mem[offset], 1, len, f) != (size_t) len)
|
||||||
|
break;
|
||||||
|
count -= 4 + 1 + len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (count == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool patchApplyPPF2(MFILE *f, u8 **rom, int *size) {
|
||||||
|
memfseek(f, 0, MSEEK_END);
|
||||||
|
int count = memftell(f);
|
||||||
|
if (count < 56 + 4 + 1024)
|
||||||
|
return false;
|
||||||
|
count -= 56 + 4 + 1024;
|
||||||
|
|
||||||
|
memfseek(f, 56, MSEEK_SET);
|
||||||
|
|
||||||
|
int datalen = readInt4(f);
|
||||||
|
if (datalen != *size)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
u8 *mem = *rom;
|
||||||
|
|
||||||
|
u8 block[1024];
|
||||||
|
memfread(&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;
|
||||||
|
|
||||||
|
memfseek(f, 56 + 4 + 1024, MSEEK_SET);
|
||||||
|
|
||||||
|
while (count > 0) {
|
||||||
|
int offset = readInt4(f);
|
||||||
|
if (offset == -1)
|
||||||
|
break;
|
||||||
|
int len = memfgetc(f);
|
||||||
|
if (len == MEOF)
|
||||||
|
break;
|
||||||
|
if (offset + len > *size)
|
||||||
|
break;
|
||||||
|
if (memfread(&mem[offset], 1, len, f) != (size_t) len)
|
||||||
|
break;
|
||||||
|
count -= 4 + 1 + len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (count == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool patchApplyPPF3(MFILE *f, u8 **rom, int *size) {
|
||||||
|
memfseek(f, 0, MSEEK_END);
|
||||||
|
int count = memftell(f);
|
||||||
|
if (count < 56 + 4 + 1024)
|
||||||
|
return false;
|
||||||
|
count -= 56 + 4;
|
||||||
|
|
||||||
|
memfseek(f, 56, MSEEK_SET);
|
||||||
|
|
||||||
|
int imagetype = memfgetc(f);
|
||||||
|
int blockcheck = memfgetc(f);
|
||||||
|
int undo = memfgetc(f);
|
||||||
|
memfgetc(f);
|
||||||
|
|
||||||
|
u8 *mem = *rom;
|
||||||
|
|
||||||
|
if (blockcheck) {
|
||||||
|
u8 block[1024];
|
||||||
|
memfread(&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;
|
||||||
|
|
||||||
|
memfseek(f, 56 + 4 + (blockcheck ? 1024 : 0), MSEEK_SET);
|
||||||
|
|
||||||
|
while (count > 0) {
|
||||||
|
s64 offset = readInt8(f);
|
||||||
|
if (offset == -1)
|
||||||
|
break;
|
||||||
|
int len = memfgetc(f);
|
||||||
|
if (len == MEOF)
|
||||||
|
break;
|
||||||
|
if (offset + len > *size)
|
||||||
|
break;
|
||||||
|
if (memfread(&mem[offset], 1, len, f) != (size_t) len)
|
||||||
|
break;
|
||||||
|
if (undo)
|
||||||
|
memfseek(f, len, MSEEK_CUR);
|
||||||
|
count -= 8 + 1 + len;
|
||||||
|
if (undo)
|
||||||
|
count -= len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (count == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool patchApplyPPF(MFILE *f, u8 **rom, int *size)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool applyPatch(const char *patchname, u8 **rom, int *size)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
if (strlen(patchname) < 5)
|
||||||
|
return false;
|
||||||
|
const char * p = strrchr(patchname, '.');
|
||||||
|
if (p == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
FILE *f = fopen(patchname, "rb");
|
||||||
|
if (!f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// read in file
|
||||||
|
fseek(f, 0, SEEK_END); // go to end of file
|
||||||
|
int filesize = ftell(f); // get filesize
|
||||||
|
fseek(f, 0, SEEK_SET); // go to start of file
|
||||||
|
char * pbuffer = (char *) malloc(filesize);
|
||||||
|
fread (pbuffer, 1, filesize, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
MFILE * mf = memfopen(pbuffer, filesize); // create memory file
|
||||||
|
|
||||||
|
if (_stricmp(p, ".ips") == 0)
|
||||||
|
result = patchApplyIPS(mf, rom, size);
|
||||||
|
else if (_stricmp(p, ".ups") == 0)
|
||||||
|
result = patchApplyUPS(mf, rom, size);
|
||||||
|
else if (_stricmp(p, ".ppf") == 0)
|
||||||
|
result = patchApplyPPF(mf, rom, size);
|
||||||
|
|
||||||
|
memfclose(mf); // close memory file
|
||||||
|
free(pbuffer); // free buffer
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
31
source/vba/Patch.h
Normal file
31
source/vba/Patch.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// -*- 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 "memfile.h"
|
||||||
|
#include "System.h"
|
||||||
|
|
||||||
|
bool applyPatch(const char *patchname, u8 **rom, int *size);
|
||||||
|
bool patchApplyIPS(MFILE * f, u8 **r, int *s);
|
||||||
|
bool patchApplyUPS(MFILE * f, u8 **rom, int *size);
|
||||||
|
bool patchApplyPPF(MFILE *f, u8 **rom, int *size);
|
||||||
|
|
||||||
|
#endif
|
132
source/vba/memfile.cpp
Normal file
132
source/vba/memfile.cpp
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* Memory-based replacement for standard C file functions
|
||||||
|
* This allows standard file calls to be replaced by memory based ones
|
||||||
|
* With little modification required to the code
|
||||||
|
*
|
||||||
|
* Written By: Daryl Borth, October 2008
|
||||||
|
*
|
||||||
|
* This code 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.
|
||||||
|
***************************************************************************/
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "memfile.h"
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* memfopen
|
||||||
|
* memory replacement for fopen
|
||||||
|
*
|
||||||
|
* Creates a memory-based file
|
||||||
|
***************************************************************************/
|
||||||
|
MFILE * memfopen(char * buffer, int size)
|
||||||
|
{
|
||||||
|
MFILE *f = (MFILE *)malloc(sizeof(MFILE));
|
||||||
|
|
||||||
|
f->buffer = buffer;
|
||||||
|
f->offset = 0;
|
||||||
|
f->size = size;
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* memfclose
|
||||||
|
* memory replacement for fclose
|
||||||
|
*
|
||||||
|
* 'Closes' the memory file specified
|
||||||
|
***************************************************************************/
|
||||||
|
int memfclose(MFILE * src)
|
||||||
|
{
|
||||||
|
free(src);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* memfseek
|
||||||
|
* memory replacement for fseek
|
||||||
|
*
|
||||||
|
* Sets the position indicator associated with the stream to a new position
|
||||||
|
* defined by adding offset to a reference position specified by origin.
|
||||||
|
***************************************************************************/
|
||||||
|
int memfseek ( MFILE * m, long int offset, int origin )
|
||||||
|
{
|
||||||
|
int success = 0; // 0 indicates success
|
||||||
|
|
||||||
|
switch(origin)
|
||||||
|
{
|
||||||
|
case MSEEK_SET:
|
||||||
|
if(offset >= 0 && offset <= m->size)
|
||||||
|
m->offset = offset;
|
||||||
|
else
|
||||||
|
success = 1; // failure
|
||||||
|
break;
|
||||||
|
case MSEEK_CUR:
|
||||||
|
if((m->offset + offset) >= 0 && (m->offset + offset) <= m->size)
|
||||||
|
m->offset += offset;
|
||||||
|
else
|
||||||
|
success = 1; // failure
|
||||||
|
break;
|
||||||
|
case MSEEK_END:
|
||||||
|
if((m->size + offset) >= 0 && (m->size + offset) <= m->size)
|
||||||
|
m->offset = m->size + offset;
|
||||||
|
else
|
||||||
|
success = 1; // failure
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* memftell
|
||||||
|
* memory replacement for ftell
|
||||||
|
*
|
||||||
|
* Get current position in stream (offset + 1)
|
||||||
|
***************************************************************************/
|
||||||
|
long int memftell (MFILE * stream)
|
||||||
|
{
|
||||||
|
return stream->offset; // to emulate ftell behavior
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* memfread
|
||||||
|
* memory replacement for fread
|
||||||
|
*
|
||||||
|
* Reads an array of count elements, each one with a size of size bytes, from
|
||||||
|
* the buffer and stores them in the block of memory specified by ptr. The
|
||||||
|
* postion indicator of the buffer is advanced by the total amount of bytes
|
||||||
|
* read. The total amount of bytes read if successful is (size * count).
|
||||||
|
***************************************************************************/
|
||||||
|
size_t memfread(void * dst, size_t size, size_t count, MFILE * src)
|
||||||
|
{
|
||||||
|
if(src->offset >= src->size) // reached end of buffer
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int numbytes = size*count;
|
||||||
|
|
||||||
|
if((src->offset + numbytes) > src->size) // can't read full # requested
|
||||||
|
numbytes = src->size - src->offset; // do a partial read
|
||||||
|
|
||||||
|
if(numbytes > 0)
|
||||||
|
memcpy(dst, src->buffer+src->offset, numbytes);
|
||||||
|
|
||||||
|
src->offset += numbytes;
|
||||||
|
return numbytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* memfgetc
|
||||||
|
* memory replacement for fgetc
|
||||||
|
*
|
||||||
|
* Returns the next character in the buffer specified, and advances the
|
||||||
|
* postion indicator of the buffer by 1.
|
||||||
|
***************************************************************************/
|
||||||
|
int memfgetc(MFILE * src)
|
||||||
|
{
|
||||||
|
if(src->offset >= src->size) // reached end of buffer
|
||||||
|
return MEOF;
|
||||||
|
else
|
||||||
|
return src->buffer[src->offset++];
|
||||||
|
}
|
30
source/vba/memfile.h
Normal file
30
source/vba/memfile.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* Memory-based replacement for standard C file functions
|
||||||
|
* This allows standard file calls to be replaced by memory based ones
|
||||||
|
* With little modification required to the code
|
||||||
|
*
|
||||||
|
* Written By: Daryl Borth, October 2008
|
||||||
|
*
|
||||||
|
* This code 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.
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
typedef struct MFile {
|
||||||
|
char *buffer; // pointer to buffer memory
|
||||||
|
long int offset; // current position indicator in buffer
|
||||||
|
long int size; // total file (buffer) size
|
||||||
|
} MFILE;
|
||||||
|
|
||||||
|
#define MSEEK_SET 0
|
||||||
|
#define MSEEK_CUR 1
|
||||||
|
#define MSEEK_END 2
|
||||||
|
#define MEOF (-1)
|
||||||
|
|
||||||
|
MFILE * memfopen(char * buffer, int size);
|
||||||
|
int memfclose(MFILE * src);
|
||||||
|
int memfseek ( MFILE * m, long int offset, int origin );
|
||||||
|
long int memftell (MFILE * stream);
|
||||||
|
size_t memfread(void * dst, size_t size, size_t count, MFILE * src);
|
||||||
|
int memfgetc(MFILE * src);
|
Loading…
Reference in New Issue
Block a user