2008-09-23 01:00:10 +02:00
|
|
|
// 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.
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "CheatSearch.h"
|
|
|
|
|
|
|
|
CheatSearchBlock cheatSearchBlocks[4];
|
|
|
|
|
|
|
|
CheatSearchData cheatSearchData = {
|
|
|
|
0,
|
|
|
|
cheatSearchBlocks
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool cheatSearchEQ(u32 a, u32 b)
|
|
|
|
{
|
|
|
|
return a == b;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool cheatSearchNE(u32 a, u32 b)
|
|
|
|
{
|
|
|
|
return a != b;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool cheatSearchLT(u32 a, u32 b)
|
|
|
|
{
|
|
|
|
return a < b;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool cheatSearchLE(u32 a, u32 b)
|
|
|
|
{
|
|
|
|
return a <= b;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool cheatSearchGT(u32 a, u32 b)
|
|
|
|
{
|
|
|
|
return a > b;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool cheatSearchGE(u32 a, u32 b)
|
|
|
|
{
|
|
|
|
return a >= b;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool cheatSearchSignedEQ(s32 a, s32 b)
|
|
|
|
{
|
|
|
|
return a == b;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool cheatSearchSignedNE(s32 a, s32 b)
|
|
|
|
{
|
|
|
|
return a != b;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool cheatSearchSignedLT(s32 a, s32 b)
|
|
|
|
{
|
|
|
|
return a < b;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool cheatSearchSignedLE(s32 a, s32 b)
|
|
|
|
{
|
|
|
|
return a <= b;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool cheatSearchSignedGT(s32 a, s32 b)
|
|
|
|
{
|
|
|
|
return a > b;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool cheatSearchSignedGE(s32 a, s32 b)
|
|
|
|
{
|
|
|
|
return a >= b;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool (*cheatSearchFunc[])(u32,u32) = {
|
|
|
|
cheatSearchEQ,
|
|
|
|
cheatSearchNE,
|
|
|
|
cheatSearchLT,
|
|
|
|
cheatSearchLE,
|
|
|
|
cheatSearchGT,
|
|
|
|
cheatSearchGE
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool (*cheatSearchSignedFunc[])(s32,s32) = {
|
|
|
|
cheatSearchSignedEQ,
|
|
|
|
cheatSearchSignedNE,
|
|
|
|
cheatSearchSignedLT,
|
|
|
|
cheatSearchSignedLE,
|
|
|
|
cheatSearchSignedGT,
|
|
|
|
cheatSearchSignedGE
|
|
|
|
};
|
|
|
|
|
|
|
|
void cheatSearchCleanup(CheatSearchData *cs)
|
|
|
|
{
|
|
|
|
int count = cs->count;
|
|
|
|
|
|
|
|
for(int i = 0; i < count; i++) {
|
|
|
|
free(cs->blocks[i].saved);
|
|
|
|
free(cs->blocks[i].bits);
|
|
|
|
}
|
|
|
|
cs->count = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cheatSearchStart(const CheatSearchData *cs)
|
|
|
|
{
|
|
|
|
int count = cs->count;
|
|
|
|
|
|
|
|
for(int i = 0; i < count; i++) {
|
|
|
|
CheatSearchBlock *block = &cs->blocks[i];
|
|
|
|
|
|
|
|
memset(block->bits, 0xff, block->size >> 3);
|
|
|
|
memcpy(block->saved, block->data, block->size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
s32 cheatSearchSignedRead(u8 *data, int off, int size)
|
|
|
|
{
|
|
|
|
u32 res = data[off++];
|
|
|
|
|
|
|
|
switch(size) {
|
|
|
|
case BITS_8:
|
|
|
|
res <<= 24;
|
|
|
|
return ((s32)res) >> 24;
|
|
|
|
case BITS_16:
|
|
|
|
res |= ((u32)data[off++])<<8;
|
|
|
|
res <<= 16;
|
|
|
|
return ((s32)res) >> 16;
|
|
|
|
case BITS_32:
|
|
|
|
res |= ((u32)data[off++])<<8;
|
|
|
|
res |= ((u32)data[off++])<<16;
|
|
|
|
res |= ((u32)data[off++])<<24;
|
|
|
|
return (s32)res;
|
|
|
|
}
|
|
|
|
return (s32)res;
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 cheatSearchRead(u8 *data, int off, int size)
|
|
|
|
{
|
|
|
|
u32 res = data[off++];
|
|
|
|
if(size == BITS_16)
|
|
|
|
res |= ((u32)data[off++])<<8;
|
|
|
|
else if(size == BITS_32) {
|
|
|
|
res |= ((u32)data[off++])<<8;
|
|
|
|
res |= ((u32)data[off++])<<16;
|
|
|
|
res |= ((u32)data[off++])<<24;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cheatSearch(const CheatSearchData *cs, int compare, int size,
|
|
|
|
bool isSigned)
|
|
|
|
{
|
|
|
|
if(compare < 0 || compare > SEARCH_GE)
|
|
|
|
return;
|
|
|
|
int inc = 1;
|
|
|
|
if(size == BITS_16)
|
|
|
|
inc = 2;
|
|
|
|
else if(size == BITS_32)
|
|
|
|
inc = 4;
|
|
|
|
|
|
|
|
if(isSigned) {
|
|
|
|
bool (*func)(s32,s32) = cheatSearchSignedFunc[compare];
|
|
|
|
|
|
|
|
for(int i = 0; i < cs->count; i++) {
|
|
|
|
CheatSearchBlock *block = &cs->blocks[i];
|
|
|
|
int size2 = block->size;
|
|
|
|
u8 *bits = block->bits;
|
|
|
|
u8 *data = block->data;
|
|
|
|
u8 *saved = block->saved;
|
|
|
|
|
|
|
|
for(int j = 0; j < size2; j += inc) {
|
|
|
|
if(IS_BIT_SET(bits, j)) {
|
|
|
|
s32 a = cheatSearchSignedRead(data, j, size);
|
|
|
|
s32 b = cheatSearchSignedRead(saved,j, size);
|
|
|
|
|
|
|
|
if(!func(a, b)) {
|
|
|
|
CLEAR_BIT(bits, j);
|
|
|
|
if(size == BITS_16)
|
|
|
|
CLEAR_BIT(bits, j+1);
|
|
|
|
if(size == BITS_32) {
|
|
|
|
CLEAR_BIT(bits, j+2);
|
|
|
|
CLEAR_BIT(bits, j+3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
bool (*func)(u32,u32) = cheatSearchFunc[compare];
|
|
|
|
|
|
|
|
for(int i = 0; i < cs->count; i++) {
|
|
|
|
CheatSearchBlock *block = &cs->blocks[i];
|
|
|
|
int size2 = block->size;
|
|
|
|
u8 *bits = block->bits;
|
|
|
|
u8 *data = block->data;
|
|
|
|
u8 *saved = block->saved;
|
|
|
|
|
|
|
|
for(int j = 0; j < size2; j += inc) {
|
|
|
|
if(IS_BIT_SET(bits, j)) {
|
|
|
|
u32 a = cheatSearchRead(data, j, size);
|
|
|
|
u32 b = cheatSearchRead(saved,j, size);
|
|
|
|
|
|
|
|
if(!func(a, b)) {
|
|
|
|
CLEAR_BIT(bits, j);
|
|
|
|
if(size == BITS_16)
|
|
|
|
CLEAR_BIT(bits, j+1);
|
|
|
|
if(size == BITS_32) {
|
|
|
|
CLEAR_BIT(bits, j+2);
|
|
|
|
CLEAR_BIT(bits, j+3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void cheatSearchValue(const CheatSearchData *cs, int compare, int size,
|
|
|
|
bool isSigned, u32 value)
|
|
|
|
{
|
|
|
|
if(compare < 0 || compare > SEARCH_GE)
|
|
|
|
return;
|
|
|
|
int inc = 1;
|
|
|
|
if(size == BITS_16)
|
|
|
|
inc = 2;
|
|
|
|
else if(size == BITS_32)
|
|
|
|
inc = 4;
|
|
|
|
|
|
|
|
if(isSigned) {
|
|
|
|
bool (*func)(s32,s32) = cheatSearchSignedFunc[compare];
|
|
|
|
|
|
|
|
for(int i = 0; i < cs->count; i++) {
|
|
|
|
CheatSearchBlock *block = &cs->blocks[i];
|
|
|
|
int size2 = block->size;
|
|
|
|
u8 *bits = block->bits;
|
|
|
|
u8 *data = block->data;
|
|
|
|
|
|
|
|
for(int j = 0; j < size2; j += inc) {
|
|
|
|
if(IS_BIT_SET(bits, j)) {
|
|
|
|
s32 a = cheatSearchSignedRead(data, j, size);
|
|
|
|
s32 b = (s32)value;
|
|
|
|
|
|
|
|
if(!func(a, b)) {
|
|
|
|
CLEAR_BIT(bits, j);
|
|
|
|
if(size == BITS_16)
|
|
|
|
CLEAR_BIT(bits, j+1);
|
|
|
|
if(size == BITS_32) {
|
|
|
|
CLEAR_BIT(bits, j+2);
|
|
|
|
CLEAR_BIT(bits, j+3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
bool (*func)(u32,u32) = cheatSearchFunc[compare];
|
|
|
|
|
|
|
|
for(int i = 0; i < cs->count; i++) {
|
|
|
|
CheatSearchBlock *block = &cs->blocks[i];
|
|
|
|
int size2 = block->size;
|
|
|
|
u8 *bits = block->bits;
|
|
|
|
u8 *data = block->data;
|
|
|
|
|
|
|
|
for(int j = 0; j < size2; j += inc) {
|
|
|
|
if(IS_BIT_SET(bits, j)) {
|
|
|
|
u32 a = cheatSearchRead(data, j, size);
|
|
|
|
|
|
|
|
if(!func(a, value)) {
|
|
|
|
CLEAR_BIT(bits, j);
|
|
|
|
if(size == BITS_16)
|
|
|
|
CLEAR_BIT(bits, j+1);
|
|
|
|
if(size == BITS_32) {
|
|
|
|
CLEAR_BIT(bits, j+2);
|
|
|
|
CLEAR_BIT(bits, j+3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int cheatSearchGetCount(const CheatSearchData *cs, int size)
|
|
|
|
{
|
|
|
|
int res = 0;
|
|
|
|
int inc = 1;
|
|
|
|
if(size == BITS_16)
|
|
|
|
inc = 2;
|
|
|
|
else if(size == BITS_32)
|
|
|
|
inc = 4;
|
|
|
|
|
|
|
|
for(int i = 0; i < cs->count; i++) {
|
|
|
|
CheatSearchBlock *block = &cs->blocks[i];
|
|
|
|
|
|
|
|
int size2 = block->size;
|
|
|
|
u8 *bits = block->bits;
|
|
|
|
for(int j = 0; j < size2; j += inc) {
|
|
|
|
if(IS_BIT_SET(bits, j))
|
|
|
|
res++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cheatSearchUpdateValues(const CheatSearchData *cs)
|
|
|
|
{
|
|
|
|
for(int i = 0; i < cs->count; i++) {
|
|
|
|
CheatSearchBlock *block = &cs->blocks[i];
|
|
|
|
|
|
|
|
memcpy(block->saved, block->data, block->size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|