152 lines
3.1 KiB
C++
152 lines
3.1 KiB
C++
|
|
#include "burner.h"
|
|
|
|
#ifndef FALSE
|
|
#define FALSE 0
|
|
#define TRUE 1
|
|
#endif
|
|
// Game patching
|
|
|
|
#define UTF8_SIGNATURE "\xef\xbb\xbf"
|
|
#define IPS_SIGNATURE "PATCH"
|
|
#define IPS_TAG_EOF "EOF"
|
|
#define IPS_EXT ".ips"
|
|
|
|
#define BYTE3_TO_UINT(bp) \
|
|
(((unsigned int)(bp)[0] << 16) & 0x00FF0000) | \
|
|
(((unsigned int)(bp)[1] << 8) & 0x0000FF00) | \
|
|
((unsigned int)(bp)[2] & 0x000000FF)
|
|
|
|
#define BYTE2_TO_UINT(bp) \
|
|
(((unsigned int)(bp)[0] << 8) & 0xFF00) | \
|
|
((unsigned int) (bp)[1] & 0x00FF)
|
|
|
|
bool bDoIpsPatch = FALSE;
|
|
|
|
static void PatchFile(const char* ips_path, UINT8* base)
|
|
{
|
|
char buf[6];
|
|
FILE* f = NULL;
|
|
int Offset, Size;
|
|
UINT8* mem8 = NULL;
|
|
|
|
if (NULL == (f = fopen(ips_path, "rb")))
|
|
return;
|
|
|
|
memset(buf, 0, sizeof buf);
|
|
fread(buf, 1, 5, f);
|
|
if (strcmp(buf, IPS_SIGNATURE)) {
|
|
return;
|
|
} else {
|
|
UINT8 ch = 0;
|
|
int bRLE = 0;
|
|
while (!feof(f)) {
|
|
// read patch address offset
|
|
fread(buf, 1, 3, f);
|
|
buf[3] = 0;
|
|
if (strcmp(buf, IPS_TAG_EOF) == 0)
|
|
break;
|
|
|
|
Offset = BYTE3_TO_UINT(buf);
|
|
|
|
// read patch length
|
|
fread(buf, 1, 2, f);
|
|
Size = BYTE2_TO_UINT(buf);
|
|
|
|
bRLE = (Size == 0);
|
|
if (bRLE) {
|
|
fread(buf, 1, 2, f);
|
|
Size = BYTE2_TO_UINT(buf);
|
|
ch = fgetc(f);
|
|
}
|
|
|
|
while (Size--) {
|
|
mem8 = base + Offset;
|
|
Offset++;
|
|
*mem8 = bRLE ? ch : fgetc(f);
|
|
}
|
|
}
|
|
}
|
|
|
|
fclose(f);
|
|
}
|
|
|
|
static void DoPatchGame(const char* patch_name, char* game_name, UINT8* base)
|
|
{
|
|
char s[MAX_PATH];
|
|
char* p = NULL;
|
|
char* rom_name = NULL;
|
|
char* ips_name = NULL;
|
|
FILE* fp = NULL;
|
|
unsigned long nIpsSize;
|
|
|
|
if ((fp = fopen(patch_name, "rb")) != NULL) {
|
|
// get ips size
|
|
fseek(fp, 0, SEEK_END);
|
|
nIpsSize = ftell(fp);
|
|
fseek(fp, 0, SEEK_SET);
|
|
|
|
while (!feof(fp)) {
|
|
if (fgets(s, sizeof s, fp) != NULL) {
|
|
p = s;
|
|
|
|
// skip UTF-8 sig
|
|
if (strncmp(p, UTF8_SIGNATURE, strlen(UTF8_SIGNATURE)) == 0)
|
|
p += strlen(UTF8_SIGNATURE);
|
|
|
|
if (p[0] == '[') // '['
|
|
break;
|
|
|
|
rom_name = strtok(p, " \t\r\n");
|
|
if (!rom_name)
|
|
continue;
|
|
if (*rom_name == '#')
|
|
continue;
|
|
if (_stricmp(rom_name, game_name))
|
|
continue;
|
|
|
|
ips_name = strtok(NULL, " \t\r\n");
|
|
if (!ips_name)
|
|
continue;
|
|
|
|
// skip CRC check
|
|
strtok(NULL, "\r\n");
|
|
|
|
char ips_path[MAX_PATH];
|
|
char ips_dir[MAX_PATH];
|
|
TCHARToANSI(szAppIpsPath, ips_dir, sizeof(ips_dir));
|
|
|
|
if (strchr(ips_name, '\\')) {
|
|
// ips in parent's folder
|
|
sprintf(ips_path, "%s\\%s%s", ips_dir, ips_name, IPS_EXT);
|
|
} else {
|
|
sprintf(ips_path, "%s%s\\%s%s", ips_dir, BurnDrvGetTextA(DRV_NAME), ips_name, IPS_EXT);
|
|
}
|
|
|
|
PatchFile(ips_path, base);
|
|
}
|
|
}
|
|
fclose(fp);
|
|
}
|
|
}
|
|
|
|
void IpsApplyPatches(UINT8* base, char* rom_name)
|
|
{
|
|
#if 0
|
|
char ips_data[MAX_PATH];
|
|
|
|
int nActivePatches = GetIpsNumActivePatches();
|
|
|
|
for (int i = 0; i < nActivePatches; i++) {
|
|
memset(ips_data, 0, MAX_PATH);
|
|
TCHARToANSI(szIpsActivePatches[i], ips_data, sizeof(ips_data));
|
|
DoPatchGame(ips_data, rom_name, base);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void IpsPatchExit()
|
|
{
|
|
bDoIpsPatch = FALSE;
|
|
}
|