/[pcsx2_0.9.7]/trunk/pcsx2/DataBase_Loader.h
ViewVC logotype

Contents of /trunk/pcsx2/DataBase_Loader.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (show annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (9 years, 5 months ago) by william
File MIME type: text/plain
File size: 12734 byte(s)
committing r3113 initial commit again...
1 /* PCSX2 - PS2 Emulator for PCs
2 * Copyright (C) 2002-2010 PCSX2 Dev Team
3 *
4 * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU Lesser General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with PCSX2.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #pragma once
17
18 #include "File_Reader.h"
19 #include "AppConfig.h"
20
21 struct key_pair {
22 string key;
23 string value;
24
25 key_pair() {}
26 key_pair(const string& _key, const string& _value)
27 : key(_key) , value(_value) {}
28 string toString() {
29 string t;
30
31 if (key[0] == '[') {
32 t = key + "\n";
33 t += value;
34
35 stringstream ss(key);
36 string t2;
37 ss >> t2;
38 t += "[/" + t2.substr(1, t2.length()-1);
39 if (t2.compare(t)) t += "]";
40 }
41 else {
42 t = key;
43 for (int a = 6 - key.length(); a > 0; a--) {
44 t += " "; // Padding for nice formatting on small key-names
45 }
46 t += " = " + value;
47 }
48 return t;
49 }
50 };
51
52 class Game_Data {
53 public:
54 string id; // Serial Identification Code
55 deque<key_pair> kList; // List of all (key, value) pairs for game data
56 Game_Data(const string& _id)
57 : id(_id) {}
58 };
59
60 // DataBase_Loader:
61 // Give the starting Key and Value you're looking for,
62 // and it will extract the necessary data from the database.
63 // Example:
64 // ---------------------------------------------
65 // Serial = SLUS-20486
66 // Name = Marvel vs. Capcom 2
67 // Region = NTSC-U
68 // ---------------------------------------------
69 // To Load this game data, use "Serial" as the initial Key
70 // then specify "SLUS-20486" as the value in the constructor.
71 // After the constructor loads the game data, you can use the
72 // DataBase_Loader class's methods to get the other key's values.
73 // Such as dbLoader.getString("Region") returns "NTSC-U"
74
75 class DataBase_Loader {
76 private:
77 template<class T> string toString(const T& value) {
78 stringstream ss(ios_base::in | ios_base::out);
79 string tString;
80 ss << value;
81 ss >> tString;
82 return tString;
83 }
84 string toLower(const string& s) {
85 string retval( s );
86 for (uint i = 0; i < s.length(); i++) {
87 char& c = retval[i];
88 if (c >= 'A' && c <= 'Z') {
89 c += 'a' - 'A';
90 }
91 }
92 return retval;
93 }
94 bool strCompare(const string& s1, const string& s2) {
95 const string t1( toLower(s1) );
96 const string t2( toLower(s2) );
97 return !t1.compare(t2);
98 }
99 bool isComment(const string& s) {
100 const string sub( s.substr(0, 2) );
101 return (sub.compare("--") == 0) || (sub.compare("//") == 0);
102 }
103 void doError(const string& line, key_pair& keyPair, bool doMsg = false) {
104 if (doMsg) Console.Error("DataBase_Loader: Bad file data [%s]", line.c_str());
105 keyPair.key.clear();
106 }
107 void extractMultiLine(const string& line, key_pair& keyPair, File_Reader& reader, const stringstream& ss) {
108 string t;
109 string endString;
110 endString = "[/" + keyPair.key.substr(1, keyPair.key.length()-1);
111 if (keyPair.key[keyPair.key.length()-1] != ']') {
112 endString += "]";
113 keyPair.key = line;
114 }
115 for(;;) {
116 t = reader.getLine();
117
118 if (!t.compare(endString)) break;
119 keyPair.value += t + "\n";
120 }
121 }
122 void extract(const string& line, key_pair& keyPair, File_Reader& reader) {
123 stringstream ss(line);
124 string t;
125 keyPair.key.clear();
126 keyPair.value.clear();
127 ss >> keyPair.key;
128 if (!line.length() || isComment(keyPair.key)) {
129 doError(line, keyPair);
130 return;
131 }
132 if (keyPair.key[0] == '[') {
133 extractMultiLine(line, keyPair, reader, ss);
134 return;
135 }
136 ss >> t;
137 if (t.compare("=") != 0) {
138 doError(line, keyPair, true);
139 return;
140 }
141 ss >> t;
142 if (isComment(t)) {
143 doError(line, keyPair, true);
144 return;
145 }
146 keyPair.value = t;
147 while (!ss.eof() && !ss.fail()) {
148 ss >> t;
149 if (isComment(t)) break;
150 keyPair.value += " " + t;
151 }
152 if (ss.fail()) {
153 doError(line, keyPair);
154 return;
155 }
156 }
157 public:
158 deque<Game_Data*> gList; // List of all game data
159 Game_Data* curGame; // Current game data
160 String_Stream header; // Header of the database
161 string baseKey; // Key to separate games by ("Serial")
162
163 DataBase_Loader(const string& file, const string& key = "Serial", const string& value = "" ) {
164 curGame = NULL;
165 baseKey = key;
166 if (!fileExists(file)) {
167 Console.Error("DataBase_Loader: DataBase Not Found! [%s]", file.c_str());
168 }
169 File_Reader reader(file);
170 key_pair keyPair;
171 string s0;
172 Game_Data* game = NULL;
173 try {
174 for(;;) {
175 for(;;) { // Find first game
176 s0 = reader.getLine();
177 extract(s0, keyPair, reader);
178 if (keyPair.key.compare(key) == 0) break;
179 header.write(s0);
180 header.write("\n");
181 }
182 game = new Game_Data(keyPair.value);
183 game->kList.push_back(keyPair);
184 for (;;) { // Fill game data, find new game, repeat...
185 s0 = reader.getLine();
186 extract(s0, keyPair, reader);
187 if (keyPair.key.compare("") == 0) continue;
188 if (keyPair.key.compare(key) == 0) {
189 gList.push_back(game);
190 game = new Game_Data(keyPair.value);
191 }
192 game->kList.push_back(keyPair);
193 }
194 }
195 }
196 catch(int& i) { // Add Last Game if EOF
197 if (i==1 && game) gList.push_back(game);
198 }
199 if (!value.compare("")) return;
200 if (setGame(value)) Console.WriteLn("DataBase_Loader: Found Game! [%s]", value.c_str());
201 else Console.Warning("DataBase_Loader: Game Not Found! [%s]", value.c_str());
202 }
203
204 virtual ~DataBase_Loader() throw() {
205 deque<Game_Data*>::iterator it = gList.begin();
206 for ( ; it != gList.end(); ++it) {
207 delete *it;
208 }
209 }
210
211 // Sets the current game to the one matching the serial id given
212 // Returns true if game found, false if not found...
213 bool setGame(const string& id) {
214 deque<Game_Data*>::iterator it = gList.begin();
215 for ( ; it != gList.end(); ++it) {
216 if (strCompare(it[0]->id, id)) {
217 curGame = it[0];
218 return true;
219 }
220 }
221 curGame = NULL;
222 return false;
223 }
224
225 // Returns true if a game is currently loaded into the database
226 // Returns false if otherwise (this means you need to call setGame()
227 // or it could mean the game was not found in the database at all...)
228 bool gameLoaded() {
229 return !!curGame;
230 }
231
232 // Saves changes to the database
233 void saveToFile(const string& file = "DataBase.dbf") {
234 File_Writer writer(file);
235 writer.write(header.toString());
236 deque<Game_Data*>::iterator it = gList.begin();
237 for ( ; it != gList.end(); ++it) {
238 deque<key_pair>::iterator i = it[0]->kList.begin();
239 for ( ; i != it[0]->kList.end(); ++i) {
240 writer.write(i[0].toString() + "\n");
241 }
242 writer.write("---------------------------------------------\n");
243 }
244 }
245
246 // Adds new game data to the database, and sets curGame to the new game...
247 // If searchDB is true, it searches the database to see if game already exists.
248 void addGame(const string& id, bool searchDB = true) {
249 if (searchDB && setGame(id)) return;
250 Game_Data* game = new Game_Data(id);
251 key_pair kp(baseKey, id);
252 game->kList.push_back(kp);
253 gList.push_back(game);
254 curGame = game;
255 }
256
257 // Searches the current game's data to see if the given key exists
258 bool keyExists(const string& key) {
259 if (curGame) {
260 deque<key_pair>::iterator it = curGame->kList.begin();
261 for ( ; it != curGame->kList.end(); ++it) {
262 if (strCompare(it[0].key, key)) {
263 return true;
264 }
265 }
266 }
267 else Console.Error("DataBase_Loader: Game not set!");
268 return false;
269 }
270
271 // Gets a string representation of the 'value' for the given key
272 string getString(const string& key) {
273 if (curGame) {
274 deque<key_pair>::iterator it = curGame->kList.begin();
275 for ( ; it != curGame->kList.end(); ++it) {
276 if (strCompare(it[0].key, key)) {
277 return it[0].value;
278 }
279 }
280 }
281 else Console.Error("DataBase_Loader: Game not set!");
282 return string();
283 }
284
285 // Gets a wxString representation of the 'value' for the given key
286 wxString getStringWX(const string& key) {
287 return wxString(fromUTF8(getString(key).c_str()));
288 }
289
290 // Gets a double representation of the 'value' for the given key
291 double getDouble(const string& key) {
292 return atof(getString(key).c_str());
293 }
294
295 // Gets a float representation of the 'value' for the given key
296 float getFloat(const string& key) {
297 return (float)atof(getString(key).c_str());
298 }
299
300 // Gets an integer representation of the 'value' for the given key
301 int getInt(const string& key) {
302 return strtoul(getString(key).c_str(), NULL, 0);
303 }
304
305 // Gets a u8 representation of the 'value' for the given key
306 u8 getU8(const string& key) {
307 return (u8)atoi(getString(key).c_str());
308 }
309
310 // Gets a bool representation of the 'value' for the given key
311 bool getBool(const string& key) {
312 return !!atoi(getString(key).c_str());
313 }
314
315 // Write a string value to the specified key
316 void writeString(const string& key, const string& value) {
317 if (curGame) {
318 deque<key_pair>::iterator it = curGame->kList.begin();
319 for ( ; it != curGame->kList.end(); ++it) {
320 if (strCompare(it[0].key, key)) {
321 it[0].value = value;
322 return;
323 }
324 }
325 key_pair tKey(key, value);
326 curGame->kList.push_back(tKey);
327 }
328 else Console.Error("DataBase_Loader: Game not set!");
329 }
330
331 // Write a wxString value to the specified key
332 void writeStringWX(const string& key, const wxString& value) {
333 writeString(key, value.ToUTF8().data());
334 }
335
336 // Write a double value to the specified key
337 void writeDouble(const string& key, double value) {
338 writeString(key, toString(value));
339 }
340
341 // Write a float value to the specified key
342 void writeFloat(const string& key, float value) {
343 writeString(key, toString(value));
344 }
345
346 // Write an integer value to the specified key
347 void writeInt(const string& key, int value) {
348 writeString(key, toString(value));
349 }
350
351 // Write a u8 value to the specified key
352 void writeU8(const string& key, u8 value) {
353 writeString(key, toString(value));
354 }
355
356 // Write a bool value to the specified key
357 void writeBool(const string& key, bool value) {
358 writeString(key, toString(value?1:0));
359 }
360 };
361
362 static wxString compatToStringWX(int compat) {
363 switch (compat) {
364 case 6: return wxString(L"Perfect");
365 case 5: return wxString(L"Playable");
366 case 4: return wxString(L"In-Game");
367 case 3: return wxString(L"Menu");
368 case 2: return wxString(L"Intro");
369 case 1: return wxString(L"Nothing");
370 default: return wxString(L"Unknown");
371 }
372 }
373
374 #define checkGamefix(gFix) { \
375 if (gameDB->keyExists(#gFix)) { \
376 SetGameFixConfig().gFix = gameDB->getBool(#gFix); \
377 Console.WriteLn("Loading Gamefix: " #gFix); \
378 gf++; \
379 } \
380 }
381
382 // Load Game Settings found in database
383 // (game fixes, round modes, clamp modes, etc...)
384 // Returns number of gamefixes set
385 static int loadGameSettings(DataBase_Loader* gameDB) {
386 if (gameDB && gameDB->gameLoaded()) {
387 SSE_MXCSR eeMX = EmuConfig.Cpu.sseMXCSR;
388 SSE_MXCSR vuMX = EmuConfig.Cpu.sseVUMXCSR;
389 int eeRM = eeMX.GetRoundMode();
390 int vuRM = vuMX.GetRoundMode();
391 bool rm = 0;
392 int gf = 0;
393 if (gameDB->keyExists("eeRoundMode")) { eeRM = gameDB->getInt("eeRoundMode"); rm=1; gf++; }
394 if (gameDB->keyExists("vuRoundMode")) { vuRM = gameDB->getInt("vuRoundMode"); rm=1; gf++; }
395 if (rm && eeRM<4 && vuRM<4) {
396 Console.WriteLn("Game DataBase: Changing roundmodes! [ee=%d] [vu=%d]", eeRM, vuRM);
397 SetCPUState(eeMX.SetRoundMode((SSE_RoundMode)eeRM), vuMX.SetRoundMode((SSE_RoundMode)vuRM));
398 }
399 if (gameDB->keyExists("eeClampMode")) {
400 int clampMode = gameDB->getInt("eeClampMode");
401 Console.WriteLn("Game DataBase: Changing EE/FPU clamp mode [mode=%d]", clampMode);
402 SetRecompilerConfig().fpuOverflow = clampMode >= 1;
403 SetRecompilerConfig().fpuExtraOverflow = clampMode >= 2;
404 SetRecompilerConfig().fpuFullMode = clampMode >= 3;
405 gf++;
406 }
407 if (gameDB->keyExists("vuClampMode")) {
408 int clampMode = gameDB->getInt("vuClampMode");
409 Console.WriteLn("Game DataBase: Changing VU0/VU1 clamp mode [mode=%d]", clampMode);
410 SetRecompilerConfig().vuOverflow = clampMode >= 1;
411 SetRecompilerConfig().vuExtraOverflow = clampMode >= 2;
412 SetRecompilerConfig().vuSignOverflow = clampMode >= 3;
413 gf++;
414 }
415 checkGamefix(VuAddSubHack);
416 checkGamefix(VuClipFlagHack);
417 checkGamefix(FpuCompareHack);
418 checkGamefix(FpuMulHack);
419 checkGamefix(FpuNegDivHack);
420 checkGamefix(XgKickHack);
421 checkGamefix(IPUWaitHack);
422 checkGamefix(EETimingHack);
423 return gf;
424 }
425 return 0;
426 }
427
428 extern ScopedPtr<DataBase_Loader> GameDB;

  ViewVC Help
Powered by ViewVC 1.1.22