00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027
00028 #include <wx/wxprec.h>
00029
00030 #ifndef WX_PRECOMP
00031 #include <wx/wx.h>
00032 #endif
00033
00034 #include <cstring>
00035 #include <fstream>
00036
00037 #include "model/sramfile.hh"
00038
00039 using namespace dwsrame;
00040
00041 const std::pair<int, int> SRAMFile::QUEST_OFFSETS[] =
00042 {
00043 std::pair<int, int>(0xB, 0x04),
00044 std::pair<int, int>(0xB, 0x08),
00045 std::pair<int, int>(0xB, 0x10),
00046 std::pair<int, int>(0xB, 0x20),
00047 std::pair<int, int>(0xB, 0x40),
00048 std::pair<int, int>(0xB, 0x80),
00049
00050 std::pair<int, int>(0xC, 0x01),
00051 std::pair<int, int>(0xC, 0x02),
00052 std::pair<int, int>(0xC, 0x08),
00053
00054 std::pair<int, int>(0xD, 0x02),
00055 std::pair<int, int>(0xD, 0x04),
00056 std::pair<int, int>(0xD, 0x40),
00057 };
00058
00059 SRAMFile::SRAMFile(const wxString &filename)
00060 throw(InvalidSRAMFileException) : modified(false) {
00061 std::ifstream file(filename.mb_str(),
00062 std::ios_base::in | std::ios_base::binary);
00063
00064 if (!file) {
00065 throw InvalidSRAMFileException(ISFE_FILENOTFOUND);
00066 }
00067
00068 file.seekg(0, std::ios_base::end);
00069
00070 if (file.tellg() != static_cast<std::streampos>(SRAM_SIZE)) {
00071 throw InvalidSRAMFileException(ISFE_INVALIDSIZE);
00072 }
00073
00074 file.seekg(0, std::ios_base::beg);
00075 file.read(sram, SRAM_SIZE);
00076 file.close();
00077
00078
00079 if (std::strncmp("KEN MASUTA", (sram + KENMASUTA_OFFSET), 10) != 0) {
00080 throw InvalidSRAMFileException(ISFE_NOVALIDGAMES);
00081 }
00082
00083
00084 std::memset(valid, 0, 3 * sizeof(bool));
00085
00086 bool foundValid = false;
00087
00088 for (int game = 2; game >= 0; --game) {
00089 if (sram[SLOT_OFFSET + game] == MAGIC_NUMBER) {
00090 if (checksum(game) == getChecksum(game)) {
00091 valid[game] = foundValid = true;
00092 setGame(game);
00093 }
00094 }
00095 }
00096
00097 if (!foundValid) {
00098 throw InvalidSRAMFileException(ISFE_NOVALIDGAMES);
00099 }
00100 }
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136 wxUint16 SRAMFile::checksum(int game) const {
00137 wxASSERT((game >= 0) && (game < 3));
00138
00139 unsigned char cl = 0x1D, ch = 0x1D, carry = 0;
00140 unsigned char al, bl, temp;
00141
00142 for (int i = 0x1D; i >= 0; --i) {
00143 al = sram[GAME_OFFSET + (game * GAME_SIZE) + i];
00144
00145 for (int j = 8; j > 0; --j) {
00146 bl = al ^ ch;
00147
00148
00149 carry = (cl & 0x80) ? 1 : 0;
00150 cl <<= 1;
00151
00152
00153 temp = (ch & 0x80) ? 1 : 0;
00154 ch = (ch << 1) | carry;
00155 carry = temp;
00156
00157
00158 carry = (al & 0x80) ? 1 : 0;
00159 al <<= 1;
00160
00161
00162 carry = (bl & 0x80) ? 1 : 0;
00163 bl <<= 1;
00164
00165 if (carry) {
00166 cl ^= 0x21;
00167 ch ^= 0x10;
00168 }
00169 }
00170 }
00171
00172 return (cl | (ch << 8));
00173 }
00174
00175 char SRAMFile::fromASCII(char asciiChar) const {
00176 char ch;
00177
00178 switch (asciiChar) {
00179 case '0': case '1': case '2': case '3': case '4': case '5': case '6':
00180 case '7': case '8': case '9':
00181 ch = static_cast<char>(asciiChar - '0');
00182 break;
00183
00184 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
00185 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
00186 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
00187 case 'v': case 'w': case 'x': case 'y': case 'z':
00188 ch = static_cast<char>(asciiChar - 'a' + 0xA);
00189 break;
00190
00191 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
00192 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
00193 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
00194 case 'V': case 'W': case 'X': case 'Y': case 'Z':
00195 ch = static_cast<char>(asciiChar - 'A' + 0x24);
00196 break;
00197
00198 case '\'': ch = 0x40; break;
00199 case '.': ch = 0x47; break;
00200 case ',': ch = 0x48; break;
00201 case '-': ch = 0x49; break;
00202 case '?': ch = 0x4B; break;
00203 case '!': ch = 0x4C; break;
00204 case ')': ch = 0x4E; break;
00205 case '(': ch = 0x4F; break;
00206 case ' ': ch = 0x60; break;
00207
00208 default:
00209
00210 wxASSERT(false);
00211
00212 ch = 0x60;
00213 break;
00214 }
00215
00216 return ch;
00217 }
00218
00219 bool SRAMFile::save(const wxString &filename) {
00220 std::ofstream file(filename.mb_str(),
00221 std::ios_base::out | std::ios_base::binary);
00222
00223 if (!file) {
00224 return false;
00225 }
00226
00227 for (int i = 0; i < 3; ++i) {
00228 setChecksum(i, checksum(i));
00229 }
00230
00231 file.write(sram, SRAM_SIZE);
00232 file.close();
00233
00234 modified = false;
00235
00236 return true;
00237 }
00238
00239 char SRAMFile::toASCII(char dwChar) const {
00240 char ch;
00241
00242 switch (dwChar) {
00243 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8:
00244 case 9:
00245 ch = static_cast<char>('0' + dwChar);
00246 break;
00247
00248 case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17:
00249 case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25:
00250 case 26: case 27: case 28: case 29: case 30: case 31: case 32: case 33:
00251 case 34: case 35:
00252 ch = static_cast<char>('a' + dwChar - 0xA);
00253 break;
00254
00255 case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43:
00256 case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51:
00257 case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 59:
00258 case 60: case 61:
00259 ch = static_cast<char>('A' + dwChar - 0x24);
00260 break;
00261
00262 case 0x40: ch = '\''; break;
00263 case 0x47: ch = '.'; break;
00264 case 0x48: ch = ','; break;
00265 case 0x49: ch = '-'; break;
00266 case 0x4B: ch = '?'; break;
00267 case 0x4C: ch = '!'; break;
00268 case 0x4E: ch = ')'; break;
00269 case 0x4F: ch = '('; break;
00270 case 0x60: ch = ' '; break;
00271
00272 default:
00273
00274 wxASSERT(false);
00275
00276 ch = '_';
00277 break;
00278 }
00279
00280 return ch;
00281 }
00282
00283 void SRAMFile::setArmor(enum dw_armor armor) {
00284 unsigned char *ptr =
00285 reinterpret_cast<unsigned char *>(offset + EQUIPMENT_OFFSET);
00286
00287 *ptr &= ~ARMOR_MASK;
00288 *ptr |= armor;
00289
00290 modified = true;
00291 }
00292
00293 wxUint16 SRAMFile::getChecksum(int game) const {
00294 wxASSERT((game >= 0) && (game < 3));
00295
00296 const wxUint16 *ptr = reinterpret_cast<const wxUint16 *>
00297 (sram + GAME_OFFSET + (GAME_SIZE * game) + CHECKSUM_OFFSET);
00298
00299 return wxUINT16_SWAP_ON_BE(*ptr);
00300 }
00301
00302 void SRAMFile::setChecksum(int game, wxUint16 checksum) {
00303 wxASSERT((game >= 0) && (game < 3));
00304
00305 wxUint16 *ptr = reinterpret_cast<wxUint16 *>
00306 (sram + GAME_OFFSET + (GAME_SIZE * game) + CHECKSUM_OFFSET);
00307
00308 *ptr = wxUINT16_SWAP_ON_BE(checksum);
00309 }
00310
00311 wxUint16 SRAMFile::getExperience() const {
00312 const wxUint16 *ptr = reinterpret_cast<const wxUint16 *>
00313 (offset + EXP_OFFSET);
00314
00315 return wxUINT16_SWAP_ON_BE(*ptr);
00316 }
00317
00318 void SRAMFile::setExperience(wxUint16 experience) {
00319 wxUint16 *ptr = reinterpret_cast<wxUint16 *>(offset + EXP_OFFSET);
00320
00321 *ptr = wxUINT16_SWAP_ON_BE(experience);
00322
00323 modified = true;
00324 }
00325
00326 void SRAMFile::setGame(int game) {
00327 wxASSERT((game >= 0) && (game < 3));
00328 wxASSERT(isValid(game));
00329
00330 this->game = game;
00331 offset = reinterpret_cast<unsigned char *>
00332 (sram + GAME_OFFSET + (GAME_SIZE * game));
00333 }
00334
00335 wxUint16 SRAMFile::getGold() const {
00336 const wxUint16 *ptr = reinterpret_cast<const wxUint16 *>
00337 (offset + GOLD_OFFSET);
00338
00339 return wxUINT16_SWAP_ON_BE(*ptr);
00340 }
00341
00342 void SRAMFile::setGold(wxUint16 gold) {
00343 wxUint16 *ptr = reinterpret_cast<wxUint16 *>(offset + GOLD_OFFSET);
00344
00345 *ptr = wxUINT16_SWAP_ON_BE(gold);
00346
00347 modified = true;
00348 }
00349
00350 void SRAMFile::setHerbs(int herbs) {
00351 offset[HERBS_OFFSET] = herbs;
00352 modified = true;
00353 }
00354
00355 void SRAMFile::setHP(unsigned int hp) {
00356 offset[HP_OFFSET] = hp;
00357 modified = true;
00358 }
00359
00360 enum dw_item SRAMFile::getItem(int number) const {
00361 unsigned char value =
00362 static_cast<unsigned char>(*(offset + ITEM_OFFSET + (number / 2)));
00363
00364 if ((number % 2) == 1) {
00365 value >>= 4;
00366 }
00367
00368 return static_cast<enum dw_item>(value & 0xF);
00369 }
00370
00371 void SRAMFile::setItem(enum dw_item item, int number) {
00372 unsigned char value = item;
00373 unsigned char *ptr =
00374 reinterpret_cast<unsigned char *>(offset + ITEM_OFFSET + (number / 2));
00375
00376 if ((number % 2) == 1) {
00377 value <<= 4;
00378 *ptr &= 0xF;
00379 } else {
00380 *ptr &= 0xF0;
00381 }
00382
00383 *ptr |= value;
00384
00385 modified = true;
00386 }
00387
00388 void SRAMFile::setKeys(int keys) {
00389 offset[KEYS_OFFSET] = keys;
00390 modified = true;
00391 }
00392
00393 void SRAMFile::setMP(unsigned int mp) {
00394 offset[MP_OFFSET] = mp;
00395 modified = true;
00396 }
00397
00398 wxString SRAMFile::getName() const {
00399 wxString name;
00400 const char *ptr = reinterpret_cast<const char *>(offset + NAME_OFFSET);
00401
00402 for (int i = 0; i < 2; ++i) {
00403 for (int j = 3; j >= 0; --j) {
00404 name.Append(toASCII(ptr[j]));
00405 }
00406
00407 ptr += 4;
00408 }
00409
00410 return name.Trim();
00411 }
00412
00413 void SRAMFile::setName(const wxString &name) {
00414 char *ptr = reinterpret_cast<char *>(offset + NAME_OFFSET);
00415 unsigned int count = 0;
00416
00417 for (int i = 0; i < 2; ++i) {
00418 for (int j = 3; j >= 0; --j) {
00419 if (count < name.Length()) {
00420 ptr[j] = fromASCII(name[count]);
00421 } else {
00422 ptr[j] = fromASCII(' ');
00423 }
00424
00425 ++count;
00426 }
00427
00428 ptr += 4;
00429 }
00430
00431 modified = true;
00432 }
00433
00434 void SRAMFile::setQuestMarker(enum dw_quest marker, bool set) {
00435 if (set) {
00436 offset[QUEST_OFFSETS[marker].first] |= QUEST_OFFSETS[marker].second;
00437 } else {
00438 offset[QUEST_OFFSETS[marker].first] &= ~QUEST_OFFSETS[marker].second;
00439 }
00440
00441 modified = true;
00442 }
00443
00444 void SRAMFile::setShield(enum dw_shield shield) {
00445 unsigned char *ptr =
00446 reinterpret_cast<unsigned char *>(offset + EQUIPMENT_OFFSET);
00447
00448 *ptr &= ~SHIELD_MASK;
00449 *ptr |= shield;
00450
00451 modified = true;
00452 }
00453
00454 void SRAMFile::setWeapon(enum dw_weapon weapon) {
00455 unsigned char *ptr =
00456 reinterpret_cast<unsigned char *>(offset + EQUIPMENT_OFFSET);
00457
00458 *ptr &= ~WEAPON_MASK;
00459 *ptr |= weapon;
00460
00461 modified = true;
00462 }
00463