#include <stdlib.h>
#include "cheat.h"
#include "memory.h"
#include "sh2core.h"
cheatlist_struct *cheatlist=NULL;
int numcheats=0;
int cheatsize;
#define DoubleWordSwap(x) x = (((x & 0xFF000000) >> 24) + \
((x & 0x00FF0000) >> 8) + \
((x & 0x0000FF00) << 8) + \
((x & 0x000000FF) << 24));
int CheatInit(void)
{
cheatsize = 10;
if ((cheatlist = (cheatlist_struct *)calloc(cheatsize, sizeof(cheatlist_struct))) == NULL)
return -1;
cheatlist[0].type = CHEATTYPE_NONE;
return 0;
}
void CheatDeInit(void)
{
if (cheatlist)
free(cheatlist);
cheatlist = NULL;
}
int CheatAddCode(int type, u32 addr, u32 val)
{
cheatlist[numcheats].type = type;
cheatlist[numcheats].addr = addr;
cheatlist[numcheats].val = val;
cheatlist[numcheats].desc = NULL;
cheatlist[numcheats].enable = 1;
numcheats++;
if (numcheats >= cheatsize)
{
cheatlist = realloc(cheatlist, sizeof(cheatlist_struct) * (cheatsize * 2));
cheatsize *= 2;
}
cheatlist[numcheats].type = CHEATTYPE_NONE;
return 0;
}
int CheatAddARCode(const char *code)
{
unsigned long addr;
unsigned short val;
sscanf(code, "%08lX %04hX", &addr, &val);
switch (addr >> 28)
{
case 0x0:
return -1;
case 0x1:
return CheatAddCode(CHEATTYPE_WORDWRITE, addr & 0x0FFFFFFF, val);
case 0x3:
return CheatAddCode(CHEATTYPE_BYTEWRITE, addr & 0x0FFFFFFF, val);
case 0xD:
return CheatAddCode(CHEATTYPE_ENABLE, addr & 0x0FFFFFFF, val);
default: return -1;
}
return 0;
}
static int FindCheat(int type, u32 addr, u32 val)
{
int i;
for (i = 0; i < numcheats; i++)
{
if (cheatlist[i].type == type &&
cheatlist[i].addr == addr &&
cheatlist[i].val == val)
return i;
}
return -1;
}
int CheatChangeDescription(int type, u32 addr, u32 val, char *desc)
{
int i;
if ((i = FindCheat(type, addr, val)) == -1)
return -1;
return CheatChangeDescriptionByIndex(i, desc);
}
int CheatChangeDescriptionByIndex(int i, char *desc)
{
if (cheatlist[i].desc)
free(cheatlist[i].desc);
cheatlist[i].desc = strdup(desc);
return 0;
}
int CheatRemoveCode(int type, u32 addr, u32 val)
{
int i;
if ((i = FindCheat(type, addr, val)) == -1)
return -1;
return CheatRemoveCodeByIndex(i);
}
int CheatRemoveCodeByIndex(int i)
{
if (cheatlist[i].desc)
{
free(cheatlist[i].desc);
cheatlist[i].desc = NULL;
}
for (; i < numcheats-1; i++)
memcpy(&cheatlist[i], &cheatlist[i+1], sizeof(cheatlist_struct));
numcheats--;
cheatlist[numcheats].type = CHEATTYPE_NONE;
return 0;
}
int CheatRemoveARCode(const char *code)
{
unsigned long addr;
unsigned short val;
sscanf(code, "%08lX %04hX", &addr, &val);
switch (addr >> 28)
{
case 0x1:
return CheatRemoveCode(CHEATTYPE_WORDWRITE, addr & 0x0FFFFFFF, val);
case 0x3:
return CheatRemoveCode(CHEATTYPE_BYTEWRITE, addr & 0x0FFFFFFF, val);
case 0xD:
return CheatRemoveCode(CHEATTYPE_ENABLE, addr & 0x0FFFFFFF, val);
default: return -1;
}
}
void CheatClearCodes(void)
{
while (numcheats > 0)
CheatRemoveCodeByIndex(numcheats-1);
}
void CheatEnableCode(int index)
{
cheatlist[index].enable = 1;
}
void CheatDisableCode(int index)
{
cheatlist[index].enable = 0;
}
void CheatDoPatches(void)
{
int i;
for (i = 0; ; i++)
{
switch (cheatlist[i].type)
{
case CHEATTYPE_NONE:
return;
case CHEATTYPE_ENABLE:
if (cheatlist[i].enable == 0)
continue;
if (MappedMemoryReadWord(cheatlist[i].addr) != cheatlist[i].val)
return;
break;
case CHEATTYPE_BYTEWRITE:
if (cheatlist[i].enable == 0)
continue;
MappedMemoryWriteByte(cheatlist[i].addr, (u8)cheatlist[i].val);
SH2WriteNotify(cheatlist[i].addr, 1);
break;
case CHEATTYPE_WORDWRITE:
if (cheatlist[i].enable == 0)
continue;
MappedMemoryWriteWord(cheatlist[i].addr, (u16)cheatlist[i].val);
SH2WriteNotify(cheatlist[i].addr, 2);
break;
case CHEATTYPE_LONGWRITE:
if (cheatlist[i].enable == 0)
continue;
MappedMemoryWriteLong(cheatlist[i].addr, cheatlist[i].val);
SH2WriteNotify(cheatlist[i].addr, 4);
break;
}
}
}
cheatlist_struct *CheatGetList(int *cheatnum)
{
if (cheatnum == NULL)
return NULL;
*cheatnum = numcheats;
return cheatlist;
}
int CheatSave(const char *filename)
{
FILE *fp;
int i;
int num;
IOCheck_struct check;
if (!filename)
return -1;
if ((fp = fopen(filename, "wb")) == NULL)
return -1;
fprintf(fp, "YCHT");
num = numcheats;
#ifndef WORDS_BIGENDIAN
DoubleWordSwap(num);
#endif
ywrite(&check, (void *)&num, sizeof(int), 1, fp);
for(i = 0; i < numcheats; i++)
{
u8 descsize;
cheatlist_struct cheat;
memcpy(&cheat, &cheatlist[i], sizeof(cheatlist_struct));
#ifndef WORDS_BIGENDIAN
DoubleWordSwap(cheat.type);
DoubleWordSwap(cheat.addr);
DoubleWordSwap(cheat.val);
DoubleWordSwap(cheat.enable);
#endif
ywrite(&check, (void *)&cheat.type, sizeof(int), 1, fp);
ywrite(&check, (void *)&cheat.addr, sizeof(u32), 1, fp);
ywrite(&check, (void *)&cheat.val, sizeof(u32), 1, fp);
descsize = (u8)strlen(cheatlist[i].desc)+1;
ywrite(&check, (void *)&descsize, sizeof(u8), 1, fp);
ywrite(&check, (void *)cheatlist[i].desc, sizeof(char), descsize, fp);
ywrite(&check, (void *)&cheat.enable, sizeof(int), 1, fp);
}
fclose (fp);
return 0;
}
int CheatLoad(const char *filename)
{
FILE *fp;
int i;
char id[4];
char desc[256];
IOCheck_struct check;
if (!filename)
return -1;
if ((fp = fopen(filename, "rb")) == NULL)
return -1;
yread(&check, (void *)id, 1, 4, fp);
if (strncmp(id, "YCHT", 4) != 0)
{
fclose(fp);
return -2;
}
CheatClearCodes();
yread(&check, (void *)&numcheats, sizeof(int), 1, fp);
#ifndef WORDS_BIGENDIAN
DoubleWordSwap(numcheats);
#endif
if (numcheats >= cheatsize)
{
cheatlist = realloc(cheatlist, sizeof(cheatlist_struct) * (cheatsize * 2));
memset((void *)cheatlist, 0, sizeof(cheatlist_struct) * (cheatsize * 2));
cheatsize *= 2;
}
for(i = 0; i < numcheats; i++)
{
u8 descsize;
yread(&check, (void *)&cheatlist[i].type, sizeof(int), 1, fp);
yread(&check, (void *)&cheatlist[i].addr, sizeof(u32), 1, fp);
yread(&check, (void *)&cheatlist[i].val, sizeof(u32), 1, fp);
yread(&check, (void *)&descsize, sizeof(u8), 1, fp);
yread(&check, (void *)desc, sizeof(char), descsize, fp);
CheatChangeDescriptionByIndex(i, desc);
yread(&check, (void *)&cheatlist[i].enable, sizeof(int), 1, fp);
#ifndef WORDS_BIGENDIAN
DoubleWordSwap(cheatlist[i].type);
DoubleWordSwap(cheatlist[i].addr);
DoubleWordSwap(cheatlist[i].val);
DoubleWordSwap(cheatlist[i].enable);
#endif
}
fclose (fp);
return 0;
}