Database Loader code cleanups: added proper use of "const string&" to the class APIs (improves compiler code generation, protects against unwanted or unexpected modification of parameter contents). As a result, fixed a potential bug in toLower; it was modifying the input string.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3101 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2010-05-28 16:46:51 +00:00
parent 6ec36fa37d
commit 6282570b9c
1 changed files with 416 additions and 418 deletions

View File

@ -1,423 +1,421 @@
/* PCSX2 - PS2 Emulator for PCs /* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team * Copyright (C) 2002-2010 PCSX2 Dev Team
* *
* PCSX2 is free software: you can redistribute it and/or modify it under the terms * PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found- * of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version. * ation, either version 3 of the License, or (at your option) any later version.
* *
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * PCSX2 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 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details. * PURPOSE. See the GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License along with PCSX2. * You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "File_Reader.h" #include "File_Reader.h"
#include "AppConfig.h" #include "AppConfig.h"
struct key_pair { struct key_pair {
string key; string key;
string value; string value;
key_pair(string _key, string _value)
: key(_key) , value(_value) {} key_pair() {}
string toString() { key_pair(const string& _key, const string& _value)
: key(_key) , value(_value) {}
string toString() {
string t; string t;
if (key[0] == '[') { if (key[0] == '[') {
t = key + "\n"; t = key + "\n";
t += value; t += value;
stringstream ss(key); stringstream ss(key);
string t2; string t2;
ss >> t2; ss >> t2;
t += "[/" + t2.substr(1, t2.length()-1); t += "[/" + t2.substr(1, t2.length()-1);
if (t2.compare(t)) t += "]"; if (t2.compare(t)) t += "]";
} }
else { else {
t = key; t = key;
for (int a = 6 - key.length(); a > 0; a--) { for (int a = 6 - key.length(); a > 0; a--) {
t += " "; // Padding for nice formatting on small key-names t += " "; // Padding for nice formatting on small key-names
} }
t += " = " + value; t += " = " + value;
} }
return t; return t;
} }
}; };
class Game_Data { class Game_Data {
public: public:
string id; // Serial Identification Code string id; // Serial Identification Code
deque<key_pair> kList; // List of all (key, value) pairs for game data deque<key_pair> kList; // List of all (key, value) pairs for game data
Game_Data(string _id) Game_Data(const string& _id)
: id(_id) {} : id(_id) {}
}; };
// DataBase_Loader: // DataBase_Loader:
// Give the starting Key and Value you're looking for, // Give the starting Key and Value you're looking for,
// and it will extract the necessary data from the database. // and it will extract the necessary data from the database.
// Example: // Example:
// --------------------------------------------- // ---------------------------------------------
// Serial = SLUS-20486 // Serial = SLUS-20486
// Name = Marvel vs. Capcom 2 // Name = Marvel vs. Capcom 2
// Region = NTSC-U // Region = NTSC-U
// --------------------------------------------- // ---------------------------------------------
// To Load this game data, use "Serial" as the initial Key // To Load this game data, use "Serial" as the initial Key
// then specify "SLUS-20486" as the value in the constructor. // then specify "SLUS-20486" as the value in the constructor.
// After the constructor loads the game data, you can use the // After the constructor loads the game data, you can use the
// DataBase_Loader class's methods to get the other key's values. // DataBase_Loader class's methods to get the other key's values.
// Such as dbLoader.getString("Region") returns "NTSC-U" // Such as dbLoader.getString("Region") returns "NTSC-U"
class DataBase_Loader { class DataBase_Loader {
private: private:
template<class T> string toString(T value) { template<class T> string toString(T value) {
stringstream ss(ios_base::in | ios_base::out); stringstream ss(ios_base::in | ios_base::out);
string tString; string tString;
ss << value; ss << value;
ss >> tString; ss >> tString;
return tString; return tString;
} }
string toLower(string s) { string toLower(const string& s) {
for (uint i = 0; i < s.length(); i++) { string retval( s );
char& c = s[i]; for (uint i = 0; i < s.length(); i++) {
if (c >= 'A' && c <= 'Z') { char& c = retval[i];
c += 'a' - 'A'; if (c >= 'A' && c <= 'Z') {
} c += 'a' - 'A';
} }
return s; }
} return retval;
bool strCompare(string& s1, string& s2) { }
string t1 = toLower(s1); bool strCompare(const string& s1, const string& s2) {
string t2 = toLower(s2); const string t1( toLower(s1) );
return !t1.compare(t2); const string t2( toLower(s2) );
} return !t1.compare(t2);
bool isComment(string& s) { }
string sub = s.substr(0, 2); bool isComment(const string& s) {
return (sub.compare("--") == 0) || (sub.compare("//") == 0); const string sub( s.substr(0, 2) );
} return (sub.compare("--") == 0) || (sub.compare("//") == 0);
void doError(string& line, key_pair& keyPair, bool doMsg = false) { }
if (doMsg) Console.Error("DataBase_Loader: Bad file data [%s]", line.c_str()); void doError(const string& line, key_pair& keyPair, bool doMsg = false) {
keyPair.key = ""; if (doMsg) Console.Error("DataBase_Loader: Bad file data [%s]", line.c_str());
} keyPair.key.clear();
void extractMultiLine(string& line, key_pair& keyPair, File_Reader& reader, stringstream& ss) { }
string t = ""; void extractMultiLine(const string& line, key_pair& keyPair, File_Reader& reader, const stringstream& ss) {
string endString; string t;
endString = "[/" + keyPair.key.substr(1, keyPair.key.length()-1); string endString;
if (keyPair.key[keyPair.key.length()-1] != ']') { endString = "[/" + keyPair.key.substr(1, keyPair.key.length()-1);
endString += "]"; if (keyPair.key[keyPair.key.length()-1] != ']') {
keyPair.key = line; endString += "]";
} keyPair.key = line;
for(;;) { }
for(;;) {
t = reader.getLine(); t = reader.getLine();
if (!t.compare(endString)) break; if (!t.compare(endString)) break;
keyPair.value += t + "\n"; keyPair.value += t + "\n";
} }
} }
void extract(string& line, key_pair& keyPair, File_Reader& reader) { void extract(const string& line, key_pair& keyPair, File_Reader& reader) {
stringstream ss(line); stringstream ss(line);
string t; string t;
keyPair.key = ""; keyPair.key.clear();
keyPair.value = ""; keyPair.value.clear();
ss >> keyPair.key; ss >> keyPair.key;
if (!line.length() || isComment(keyPair.key)) { if (!line.length() || isComment(keyPair.key)) {
doError(line, keyPair); doError(line, keyPair);
return; return;
} }
if (keyPair.key[0] == '[') { if (keyPair.key[0] == '[') {
extractMultiLine(line, keyPair, reader, ss); extractMultiLine(line, keyPair, reader, ss);
return; return;
} }
ss >> t; ss >> t;
if (t.compare("=") != 0) { if (t.compare("=") != 0) {
doError(line, keyPair, true); doError(line, keyPair, true);
return; return;
} }
ss >> t; ss >> t;
if (isComment(t)) { if (isComment(t)) {
doError(line, keyPair, true); doError(line, keyPair, true);
return; return;
} }
keyPair.value = t; keyPair.value = t;
while (!ss.eof() && !ss.fail()) { while (!ss.eof() && !ss.fail()) {
ss >> t; ss >> t;
if (isComment(t)) break; if (isComment(t)) break;
keyPair.value += " " + t; keyPair.value += " " + t;
} }
if (ss.fail()) { if (ss.fail()) {
doError(line, keyPair); doError(line, keyPair);
return; return;
} }
} }
public: public:
deque<Game_Data*> gList; // List of all game data deque<Game_Data*> gList; // List of all game data
Game_Data* curGame; // Current game data Game_Data* curGame; // Current game data
String_Stream header; // Header of the database String_Stream header; // Header of the database
string baseKey; // Key to separate games by ("Serial") string baseKey; // Key to separate games by ("Serial")
DataBase_Loader(string file, string key = "Serial", string value = "") { DataBase_Loader(const string& file, const string& key = "Serial", const string& value = "" ) {
curGame = NULL; curGame = NULL;
baseKey = key; baseKey = key;
if (!fileExists(file)) { if (!fileExists(file)) {
Console.Error("DataBase_Loader: DataBase Not Found! [%s]", file.c_str()); Console.Error("DataBase_Loader: DataBase Not Found! [%s]", file.c_str());
} }
File_Reader reader(file); File_Reader reader(file);
key_pair keyPair("", ""); key_pair keyPair;
string s0; string s0;
Game_Data* game = NULL; Game_Data* game = NULL;
try { try {
for(;;) { for(;;) {
for(;;) { // Find first game for(;;) { // Find first game
s0 = reader.getLine(); s0 = reader.getLine();
extract(s0, keyPair, reader); extract(s0, keyPair, reader);
if (keyPair.key.compare(key) == 0) break; if (keyPair.key.compare(key) == 0) break;
header.write(s0); header.write(s0);
header.write("\n"); header.write("\n");
} }
game = new Game_Data(keyPair.value); game = new Game_Data(keyPair.value);
game->kList.push_back(keyPair); game->kList.push_back(keyPair);
for (;;) { // Fill game data, find new game, repeat... for (;;) { // Fill game data, find new game, repeat...
s0 = reader.getLine(); s0 = reader.getLine();
extract(s0, keyPair, reader); extract(s0, keyPair, reader);
if (keyPair.key.compare("") == 0) continue; if (keyPair.key.compare("") == 0) continue;
if (keyPair.key.compare(key) == 0) { if (keyPair.key.compare(key) == 0) {
gList.push_back(game); gList.push_back(game);
game = new Game_Data(keyPair.value); game = new Game_Data(keyPair.value);
} }
game->kList.push_back(keyPair); game->kList.push_back(keyPair);
} }
} }
} }
catch(int& i) { // Add Last Game if EOF catch(int& i) { // Add Last Game if EOF
if (i==1 && game) gList.push_back(game); if (i==1 && game) gList.push_back(game);
} }
if (!value.compare("")) return; if (!value.compare("")) return;
if (setGame(value)) Console.WriteLn("DataBase_Loader: Found Game! [%s]", value.c_str()); if (setGame(value)) Console.WriteLn("DataBase_Loader: Found Game! [%s]", value.c_str());
else Console.Warning("DataBase_Loader: Game Not Found! [%s]", value.c_str()); else Console.Warning("DataBase_Loader: Game Not Found! [%s]", value.c_str());
} }
~DataBase_Loader() { virtual ~DataBase_Loader() throw() {
deque<Game_Data*>::iterator it = gList.begin(); deque<Game_Data*>::iterator it = gList.begin();
for ( ; it != gList.end(); ++it) { for ( ; it != gList.end(); ++it) {
delete it[0]; delete *it;
} }
} }
// Sets the current game to the one matching the serial id given // Sets the current game to the one matching the serial id given
// Returns true if game found, false if not found... // Returns true if game found, false if not found...
bool setGame(string id) { bool setGame(const string& id) {
deque<Game_Data*>::iterator it = gList.begin(); deque<Game_Data*>::iterator it = gList.begin();
for ( ; it != gList.end(); ++it) { for ( ; it != gList.end(); ++it) {
if (strCompare(it[0]->id, id)) { if (strCompare(it[0]->id, id)) {
curGame = it[0]; curGame = it[0];
return true; return true;
} }
} }
curGame = NULL; curGame = NULL;
return false; return false;
} }
// Returns true if a game is currently loaded into the database // Returns true if a game is currently loaded into the database
// Returns false if otherwise (this means you need to call setGame() // Returns false if otherwise (this means you need to call setGame()
// or it could mean the game was not found in the database at all...) // or it could mean the game was not found in the database at all...)
bool gameLoaded() { bool gameLoaded() {
return !!curGame; return !!curGame;
} }
// Saves changes to the database // Saves changes to the database
void saveToFile(string file = "DataBase.dbf") { void saveToFile(const string& file = "DataBase.dbf") {
File_Writer writer(file); File_Writer writer(file);
writer.write(header.toString()); writer.write(header.toString());
deque<Game_Data*>::iterator it = gList.begin(); deque<Game_Data*>::iterator it = gList.begin();
for ( ; it != gList.end(); ++it) { for ( ; it != gList.end(); ++it) {
deque<key_pair>::iterator i = it[0]->kList.begin(); deque<key_pair>::iterator i = it[0]->kList.begin();
for ( ; i != it[0]->kList.end(); ++i) { for ( ; i != it[0]->kList.end(); ++i) {
writer.write(i[0].toString() + "\n"); writer.write(i[0].toString() + "\n");
} }
writer.write("---------------------------------------------\n"); writer.write("---------------------------------------------\n");
} }
} }
// Adds new game data to the database, and sets curGame to the new game... // Adds new game data to the database, and sets curGame to the new game...
// If searchDB is true, it searches the database to see if game already exists. // If searchDB is true, it searches the database to see if game already exists.
void addGame(string id, bool searchDB = true) { void addGame(const string& id, bool searchDB = true) {
if (searchDB && setGame(id)) return; if (searchDB && setGame(id)) return;
Game_Data* game = new Game_Data(id); Game_Data* game = new Game_Data(id);
key_pair kp(baseKey, id); key_pair kp(baseKey, id);
game->kList.push_back(kp); game->kList.push_back(kp);
gList.push_back(game); gList.push_back(game);
curGame = game; curGame = game;
} }
// Searches the current game's data to see if the given key exists // Searches the current game's data to see if the given key exists
bool keyExists(string key) { bool keyExists(const string& key) {
if (curGame) { if (curGame) {
deque<key_pair>::iterator it = curGame->kList.begin(); deque<key_pair>::iterator it = curGame->kList.begin();
for ( ; it != curGame->kList.end(); ++it) { for ( ; it != curGame->kList.end(); ++it) {
if (strCompare(it[0].key, key)) { if (strCompare(it[0].key, key)) {
return true; return true;
} }
} }
} }
else Console.Error("DataBase_Loader: Game not set!"); else Console.Error("DataBase_Loader: Game not set!");
return false; return false;
} }
// Gets a string representation of the 'value' for the given key // Gets a string representation of the 'value' for the given key
string getString(string key) { string getString(const string& key) {
if (curGame) { if (curGame) {
deque<key_pair>::iterator it = curGame->kList.begin(); deque<key_pair>::iterator it = curGame->kList.begin();
for ( ; it != curGame->kList.end(); ++it) { for ( ; it != curGame->kList.end(); ++it) {
if (strCompare(it[0].key, key)) { if (strCompare(it[0].key, key)) {
return it[0].value; return it[0].value;
} }
} }
} }
else Console.Error("DataBase_Loader: Game not set!"); else Console.Error("DataBase_Loader: Game not set!");
return string(""); return string();
} }
// Gets a wxString representation of the 'value' for the given key // Gets a wxString representation of the 'value' for the given key
wxString getStringWX(string key) { wxString getStringWX(const string& key) {
string s = getString(key); return wxString(fromUTF8(getString(key).c_str()));
return wxString(fromUTF8(s.c_str())); }
}
// Gets a double representation of the 'value' for the given key
// Gets a double representation of the 'value' for the given key double getDouble(const string& key) {
double getDouble(string key) { return atof(getString(key).c_str());
string v = getString(key); }
return atof(v.c_str());
} // Gets a float representation of the 'value' for the given key
float getFloat(const string& key) {
// Gets a float representation of the 'value' for the given key return (float)atof(getString(key).c_str());
float getFloat(string key) { }
string v = getString(key);
return (float)atof(v.c_str()); // Gets an integer representation of the 'value' for the given key
} int getInt(const string& key) {
return strtoul(getString(key).c_str(), NULL, 0);
// Gets an integer representation of the 'value' for the given key }
int getInt(string key) {
string v = getString(key); // Gets a u8 representation of the 'value' for the given key
return strtoul(v.c_str(), NULL, 0); u8 getU8(const string& key) {
} return (u8)atoi(getString(key).c_str());
}
// Gets a u8 representation of the 'value' for the given key
u8 getU8(string key) { // Gets a bool representation of the 'value' for the given key
string v = getString(key); bool getBool(const string& key) {
return (u8)atoi(v.c_str()); return !!atoi(getString(key).c_str());
} }
// Gets a bool representation of the 'value' for the given key // Write a string value to the specified key
bool getBool(string key) { void writeString(const string& key, const string& value) {
string v = getString(key); if (curGame) {
return !!atoi(v.c_str()); deque<key_pair>::iterator it = curGame->kList.begin();
} for ( ; it != curGame->kList.end(); ++it) {
if (strCompare(it[0].key, key)) {
// Write a string value to the specified key it[0].value = value;
void writeString(string key, string value) { return;
if (curGame) { }
deque<key_pair>::iterator it = curGame->kList.begin(); }
for ( ; it != curGame->kList.end(); ++it) { key_pair tKey(key, value);
if (strCompare(it[0].key, key)) { curGame->kList.push_back(tKey);
it[0].value = value; }
return; else Console.Error("DataBase_Loader: Game not set!");
} }
}
key_pair tKey(key, value); // Write a wxString value to the specified key
curGame->kList.push_back(tKey); void writeStringWX(const string& key, const wxString& value) {
} writeString(key, value.ToUTF8().data());
else Console.Error("DataBase_Loader: Game not set!"); }
}
// Write a double value to the specified key
// Write a wxString value to the specified key void writeDouble(const string& key, double value) {
void writeStringWX(string key, wxString value) { writeString(key, toString(value));
writeString(key, string(value.ToUTF8().data())); }
}
// Write a float value to the specified key
// Write a double value to the specified key void writeFloat(const string& key, float value) {
void writeDouble(string key, double value) { writeString(key, toString(value));
writeString(key, toString(value)); }
}
// Write an integer value to the specified key
// Write a float value to the specified key void writeInt(const string& key, int value) {
void writeFloat(string key, float value) { writeString(key, toString(value));
writeString(key, toString(value)); }
}
// Write a u8 value to the specified key
// Write an integer value to the specified key void writeU8(const string& key, u8 value) {
void writeInt(string key, int value) { writeString(key, toString(value));
writeString(key, toString(value)); }
}
// Write a bool value to the specified key
// Write a u8 value to the specified key void writeBool(const string& key, bool value) {
void writeU8(string key, u8 value) { writeString(key, toString(value?1:0));
writeString(key, toString(value)); }
} };
// Write a bool value to the specified key static wxString compatToStringWX(int compat) {
void writeBool(string key, bool value) { switch (compat) {
writeString(key, toString(value?1:0)); case 6: return wxString(L"Perfect");
} case 5: return wxString(L"Playable");
}; case 4: return wxString(L"In-Game");
case 3: return wxString(L"Menu");
static wxString compatToStringWX(int compat) { case 2: return wxString(L"Intro");
switch (compat) { case 1: return wxString(L"Nothing");
case 6: return wxString(L"Perfect"); default: return wxString(L"Unknown");
case 5: return wxString(L"Playable"); }
case 4: return wxString(L"In-Game"); }
case 3: return wxString(L"Menu");
case 2: return wxString(L"Intro"); #define checkGamefix(gFix) { \
case 1: return wxString(L"Nothing"); if (gameDB->keyExists(#gFix)) { \
default: return wxString(L"Unknown"); SetGameFixConfig().gFix = gameDB->getBool(#gFix); \
} Console.WriteLn("Loading Gamefix: " #gFix); \
} } \
}
#define checkGamefix(gFix) { \
if (gameDB->keyExists(#gFix)) { \ // Load Game Settings found in database
SetGameFixConfig().gFix = gameDB->getBool(#gFix); \ // (game fixes, round modes, clamp modes, etc...)
Console.WriteLn("Loading Gamefix: " #gFix); \ static void loadGameSettings(DataBase_Loader* gameDB) {
} \ if (gameDB && gameDB->gameLoaded()) {
} SSE_MXCSR eeMX = EmuConfig.Cpu.sseMXCSR;
SSE_MXCSR vuMX = EmuConfig.Cpu.sseVUMXCSR;
// Load Game Settings found in database int eeRM = eeMX.GetRoundMode();
// (game fixes, round modes, clamp modes, etc...) int vuRM = vuMX.GetRoundMode();
static void loadGameSettings(DataBase_Loader* gameDB) { bool rm = 0;
if (gameDB && gameDB->gameLoaded()) { if (gameDB->keyExists("eeRoundMode")) { eeRM = gameDB->getInt("eeRoundMode"); rm=1; }
SSE_MXCSR eeMX = EmuConfig.Cpu.sseMXCSR; if (gameDB->keyExists("vuRoundMode")) { vuRM = gameDB->getInt("vuRoundMode"); rm=1; }
SSE_MXCSR vuMX = EmuConfig.Cpu.sseVUMXCSR; if (rm && eeRM<4 && vuRM<4) {
int eeRM = eeMX.GetRoundMode(); Console.WriteLn("Game DataBase: Changing roundmodes! [ee=%d] [vu=%d]", eeRM, vuRM);
int vuRM = vuMX.GetRoundMode(); SetCPUState(eeMX.SetRoundMode((SSE_RoundMode)eeRM), vuMX.SetRoundMode((SSE_RoundMode)vuRM));
bool rm = 0; }
if (gameDB->keyExists("eeRoundMode")) { eeRM = gameDB->getInt("eeRoundMode"); rm=1; } if (gameDB->keyExists("eeClampMode")) {
if (gameDB->keyExists("vuRoundMode")) { vuRM = gameDB->getInt("vuRoundMode"); rm=1; } int clampMode = gameDB->getInt("eeClampMode");
if (rm && eeRM<4 && vuRM<4) { Console.WriteLn("Game DataBase: Changing EE/FPU clamp mode [mode=%d]", clampMode);
Console.WriteLn("Game DataBase: Changing roundmodes! [ee=%d] [vu=%d]", eeRM, vuRM); SetRecompilerConfig().fpuOverflow = clampMode >= 1;
SetCPUState(eeMX.SetRoundMode((SSE_RoundMode)eeRM), vuMX.SetRoundMode((SSE_RoundMode)vuRM)); SetRecompilerConfig().fpuExtraOverflow = clampMode >= 2;
} SetRecompilerConfig().fpuFullMode = clampMode >= 3;
if (gameDB->keyExists("eeClampMode")) { }
int clampMode = gameDB->getInt("eeClampMode"); if (gameDB->keyExists("vuClampMode")) {
Console.WriteLn("Game DataBase: Changing EE/FPU clamp mode [mode=%d]", clampMode); int clampMode = gameDB->getInt("vuClampMode");
SetRecompilerConfig().fpuOverflow = clampMode >= 1; Console.WriteLn("Game DataBase: Changing VU0/VU1 clamp mode [mode=%d]", clampMode);
SetRecompilerConfig().fpuExtraOverflow = clampMode >= 2; SetRecompilerConfig().vuOverflow = clampMode >= 1;
SetRecompilerConfig().fpuFullMode = clampMode >= 3; SetRecompilerConfig().vuExtraOverflow = clampMode >= 2;
} SetRecompilerConfig().vuSignOverflow = clampMode >= 3;
if (gameDB->keyExists("vuClampMode")) { }
int clampMode = gameDB->getInt("vuClampMode"); checkGamefix(VuAddSubHack);
Console.WriteLn("Game DataBase: Changing VU0/VU1 clamp mode [mode=%d]", clampMode); checkGamefix(VuClipFlagHack);
SetRecompilerConfig().vuOverflow = clampMode >= 1; checkGamefix(FpuCompareHack);
SetRecompilerConfig().vuExtraOverflow = clampMode >= 2; checkGamefix(FpuMulHack);
SetRecompilerConfig().vuSignOverflow = clampMode >= 3; checkGamefix(FpuNegDivHack);
} checkGamefix(XgKickHack);
checkGamefix(VuAddSubHack); checkGamefix(IPUWaitHack);
checkGamefix(VuClipFlagHack); checkGamefix(EETimingHack);
checkGamefix(FpuCompareHack); }
checkGamefix(FpuMulHack); }
checkGamefix(FpuNegDivHack);
checkGamefix(XgKickHack); extern ScopedPtr<DataBase_Loader> GameDB;
checkGamefix(IPUWaitHack);
checkGamefix(EETimingHack);
}
}
extern ScopedPtr<DataBase_Loader> GameDB;