00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <cstring>
00025 #include <fstream>
00026
00027 #include <QtCore/qendian.h>
00028
00029 #include "model/sramfile.hh"
00030
00031 using namespace lozsrame;
00032
00033 SRAMFile::SRAMFile(const QString &filename) throw(InvalidSRAMFileException) :
00034 modified(false) {
00035 std::ifstream file(filename.toAscii().data(),
00036 std::ios_base::in | std::ios_base::binary);
00037
00038 if (!file) {
00039 throw InvalidSRAMFileException(ISFE_FILENOTFOUND);
00040 }
00041
00042 file.seekg(0, std::ios_base::end);
00043
00044 if (file.tellg() != static_cast<std::streampos>(SRAM_SIZE)) {
00045 throw InvalidSRAMFileException(ISFE_INVALIDSIZE);
00046 }
00047
00048 file.seekg(0, std::ios_base::beg);
00049 file.read(sram, SRAM_SIZE);
00050 file.close();
00051
00052
00053 std::memset(valid, 0, 3 * sizeof(bool));
00054
00055 bool foundValid = false;
00056 QString emptyName(" ");
00057
00058 for (int game = 2; game >= 0; --game) {
00059 if (checksum(game) == getChecksum(game)) {
00060 valid[game] = true;
00061 setGame(game);
00062
00063 if (getName() == emptyName) {
00064
00065 valid[game] = false;
00066 } else {
00067 foundValid = true;
00068 }
00069 }
00070 }
00071
00072 if (!foundValid) {
00073 throw InvalidSRAMFileException(ISFE_NOVALIDGAMES);
00074 }
00075 }
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
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
00137 quint16 SRAMFile::checksum(int game) const {
00138 Q_ASSERT((game >= 0) && (game < 3));
00139
00140 quint16 checksum = 0;
00141
00142
00143 for (int i = 0; i < NAME_DATA_SIZE; ++i) {
00144 checksum += static_cast<unsigned char>
00145 (sram[NAME_DATA + i + (game * NAME_DATA_SIZE)]);
00146 }
00147
00148
00149 for (int i = 0; i < INVENTORY_DATA_SIZE; ++i) {
00150 checksum += static_cast<unsigned char>
00151 (sram[INVENTORY_DATA + i + (game * INVENTORY_DATA_SIZE)]);
00152 }
00153
00154
00155 for (int i = 0; i < MAP_DATA_SIZE; ++i) {
00156 checksum += static_cast<unsigned char>
00157 (sram[MAP_DATA + i + (game * MAP_DATA_SIZE)]);
00158 }
00159
00160
00161 for (int i = 0; i < MISC_DATA_SIZE; ++i) {
00162 checksum += static_cast<unsigned char>
00163 (sram[MISC_DATA + (i * 3) + game]);
00164 }
00165
00166 return checksum;
00167 }
00168
00169 bool SRAMFile::save(const QString &filename) {
00170 for (int i = 0; i < 3; ++i) {
00171 if (isValid(i)) {
00172 setChecksum(i, checksum(i));
00173 }
00174 }
00175
00176 std::ofstream file(filename.toAscii().data(),
00177 std::ios_base::out | std::ios_base::binary);
00178
00179 if (!file) {
00180 return false;
00181 }
00182
00183 file.write(sram, SRAM_SIZE);
00184
00185 if (file.tellp() != static_cast<std::streampos>(SRAM_SIZE)) {
00186 return false;
00187 }
00188
00189 file.close();
00190 modified = false;
00191
00192 return true;
00193 }
00194
00195 enum sf_arrow SRAMFile::getArrows() const {
00196 Q_ASSERT(isValid(game));
00197
00198 const char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00199
00200 return static_cast<enum sf_arrow>(ptr[ARROWS_OFFSET]);
00201 }
00202
00203 void SRAMFile::setArrows(sf_arrow arrows) {
00204 Q_ASSERT(isValid(game));
00205
00206 char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00207
00208 ptr[ARROWS_OFFSET] = arrows;
00209 modified = true;
00210 }
00211
00212 int SRAMFile::getBombCapacity() const {
00213 Q_ASSERT(isValid(game));
00214
00215 const char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00216
00217 return ptr[BOMBCAPACITY_OFFSET];
00218 }
00219
00220 void SRAMFile::setBombCapacity(int capacity) {
00221 Q_ASSERT(isValid(game));
00222 Q_ASSERT((capacity >= 0) && (capacity <= 16));
00223
00224 char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00225
00226 ptr[BOMBCAPACITY_OFFSET] = capacity;
00227 modified = true;
00228 }
00229
00230 int SRAMFile::getBombs() const {
00231 Q_ASSERT(isValid(game));
00232
00233 const char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00234
00235 return ptr[BOMBS_OFFSET];
00236 }
00237
00238 void SRAMFile::setBombs(int bombs) {
00239 Q_ASSERT(isValid(game));
00240 Q_ASSERT((bombs >= 0) && (bombs <= 16));
00241
00242 char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00243
00244 ptr[BOMBS_OFFSET] = bombs;
00245 modified = true;
00246 }
00247
00248 enum sf_candle SRAMFile::getCandle() const {
00249 Q_ASSERT(isValid(game));
00250
00251 const char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00252
00253 return static_cast<enum sf_candle>(ptr[CANDLE_OFFSET]);
00254 }
00255
00256 void SRAMFile::setCandle(enum sf_candle candle) {
00257 Q_ASSERT(isValid(game));
00258
00259 char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00260
00261 ptr[CANDLE_OFFSET] = candle;
00262 modified = true;
00263 }
00264
00265 quint16 SRAMFile::getChecksum(int game) const {
00266 Q_ASSERT((game >= 0) && (game < 3));
00267
00268 const quint16 *ptr = reinterpret_cast<const quint16 *>
00269 (sram + CHECKSUM_OFFSET);
00270
00271 return qFromBigEndian(ptr[game]);
00272 }
00273
00274 void SRAMFile::setChecksum(int game, quint16 checksum) {
00275 Q_ASSERT((game >= 0) && (game < 3));
00276
00277 quint16 *ptr = reinterpret_cast<quint16 *>
00278 (sram + CHECKSUM_OFFSET);
00279
00280 ptr[game] = qToBigEndian(checksum);
00281 }
00282
00283 bool SRAMFile::hasCompass(int level) const {
00284 Q_ASSERT(isValid(game));
00285 Q_ASSERT((level >= 1) && (level <= 9));
00286
00287 const char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00288
00289 if (level == 9) {
00290 return (ptr[COMPASS9_OFFSET] == 1);
00291 }
00292
00293 return (ptr[COMPASS_OFFSET] & (1 << (level - 1)));
00294 }
00295
00296 void SRAMFile::setCompass(int level, bool give) {
00297 Q_ASSERT(isValid(game));
00298 Q_ASSERT((level >= 1) && (level <= 9));
00299
00300 char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00301
00302 if (level == 9) {
00303 ptr[COMPASS9_OFFSET] = (give ? 1 : 0);
00304 }
00305
00306 if (give) {
00307 ptr[COMPASS_OFFSET] |= (1 << (level - 1));
00308 } else {
00309 ptr[COMPASS_OFFSET] &= ~(1 << (level - 1));
00310 }
00311
00312 modified = true;
00313 }
00314
00315 int SRAMFile::getHeartContainers() const {
00316 Q_ASSERT(isValid(game));
00317
00318 const char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00319
00320 return ((static_cast<unsigned char>(ptr[HEARTCONTAINERS_OFFSET]) >> 4) + 1);
00321 }
00322
00323 void SRAMFile::setHeartContainers(int containers) {
00324 Q_ASSERT(isValid(game));
00325 Q_ASSERT((containers > 0) && (containers <= 16));
00326
00327 char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00328
00329 ptr[HEARTCONTAINERS_OFFSET] &= 0x0F;
00330 ptr[HEARTCONTAINERS_OFFSET] |= ((containers - 1) << 4);
00331 modified = true;
00332 }
00333
00334 bool SRAMFile::hasItem(enum sf_item item) const {
00335 Q_ASSERT(isValid(game));
00336
00337 const char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00338
00339 return (ptr[item] == 1);
00340 }
00341
00342 void SRAMFile::setItem(enum sf_item item, bool give) {
00343 Q_ASSERT(isValid(game));
00344
00345 char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00346
00347 ptr[item] = (give ? 1 : 0);
00348 modified = true;
00349 }
00350
00351 int SRAMFile::getKeys() const {
00352 Q_ASSERT(isValid(game));
00353
00354 const char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00355
00356 return ptr[KEYS_OFFSET];
00357 }
00358
00359 void SRAMFile::setKeys(int keys) {
00360 Q_ASSERT(isValid(game));
00361 Q_ASSERT((keys >= 0) && (keys <= 99));
00362
00363 char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00364
00365 ptr[KEYS_OFFSET] = keys;
00366 modified = true;
00367 }
00368
00369 bool SRAMFile::hasMap(int level) const {
00370 Q_ASSERT(isValid(game));
00371 Q_ASSERT((level >= 1) && (level <= 9));
00372
00373 const char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00374
00375 if (level == 9) {
00376 return (ptr[MAP9_OFFSET] == 1);
00377 }
00378
00379 return (ptr[MAP_OFFSET] & (1 << (level - 1)));
00380 }
00381
00382 void SRAMFile::setMap(int level, bool give) {
00383 Q_ASSERT(isValid(game));
00384 Q_ASSERT((level >= 1) && (level <= 9));
00385
00386 char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00387
00388 if (level == 9) {
00389 ptr[MAP9_OFFSET] = (give ? 1 : 0);
00390 }
00391
00392 if (give) {
00393 ptr[MAP_OFFSET] |= (1 << (level - 1));
00394 } else {
00395 ptr[MAP_OFFSET] &= ~(1 << (level - 1));
00396 }
00397
00398 modified = true;
00399 }
00400
00401 QString SRAMFile::getName() const {
00402 Q_ASSERT(isValid(game));
00403
00404 QString name;
00405 const char *ptr = (sram + NAME_DATA + (game * NAME_DATA_SIZE));
00406
00407 for (int i = 0; i < NAME_DATA_SIZE; ++i) {
00408 char ch = ptr[i];
00409
00410 if ((ch >= 0) && (ch <= 9)) {
00411 name += ('0' + ch);
00412 } else if ((ch >= 0xA) && (ch <= 0x23)) {
00413 name += ('A' + ch - 0xA);
00414 } else if (ch == 0x24) {
00415 name += ' ';
00416 } else if (ch == 0x28) {
00417 name += ',';
00418 } else if (ch == 0x29) {
00419 name += '!';
00420 } else if (ch == 0x2A) {
00421 name += '\'';
00422 } else if (ch == 0x2B) {
00423 name += '&';
00424 } else if (ch == 0x2C) {
00425 name += '.';
00426 } else if (ch == 0x2D) {
00427 name += '\"';
00428 } else if (ch == 0x2E) {
00429 name += '?';
00430 } else if (ch == 0x2F) {
00431 name += '_';
00432 } else {
00433
00434 Q_ASSERT(false);
00435 }
00436 }
00437
00438 return name;
00439 }
00440
00441 void SRAMFile::setName(const QString &name) {
00442 Q_ASSERT(isValid(game));
00443
00444 char *ptr = (sram + NAME_DATA + (game * NAME_DATA_SIZE));
00445
00446 for (int count = 0; count < 8; ++count) {
00447 if (name.length() > count) {
00448 char ch = name[count].toAscii();
00449
00450 if ((ch >= '0') && (ch <= '9')) {
00451 ptr[count] = (ch - '0');
00452 } else if ((ch >= 'A') && (ch <= 'Z')) {
00453 ptr[count] = (ch - 'A' + 0xA);
00454 } else if (ch == ' ') {
00455 ptr[count] = 0x24;
00456 } else if (ch == ',') {
00457 ptr[count] = 0x28;
00458 } else if (ch == '!') {
00459 ptr[count] = 0x29;
00460 } else if (ch == '\'') {
00461 ptr[count] = 0x2A;
00462 } else if (ch == '&') {
00463 ptr[count] = 0x2B;
00464 } else if (ch == '.') {
00465 ptr[count] = 0x2C;
00466 } else if (ch == '\"') {
00467 ptr[count] = 0x2D;
00468 } else if (ch == '?') {
00469 ptr[count] = 0x2E;
00470 } else if (ch == '_') {
00471 ptr[count] = 0x2F;
00472 } else {
00473 Q_ASSERT(false);
00474 }
00475 } else {
00476
00477 ptr[count] = 0x24;
00478 }
00479 }
00480
00481 modified = true;
00482 }
00483
00484 enum sf_note SRAMFile::getNote() const {
00485 Q_ASSERT(isValid(game));
00486
00487 const char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00488
00489 return static_cast<enum sf_note>(ptr[NOTE_OFFSET]);
00490 }
00491
00492 void SRAMFile::setNote(enum sf_note note) {
00493 Q_ASSERT(isValid(game));
00494
00495 char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00496
00497 ptr[NOTE_OFFSET] = note;
00498 modified = true;
00499 }
00500
00501 int SRAMFile::getPlayCount() const {
00502 Q_ASSERT(isValid(game));
00503
00504 const unsigned char *ptr = (reinterpret_cast<const unsigned char *>(sram)
00505 + MISC_DATA + PLAYCOUNT_OFFSET);
00506
00507 return ptr[game];
00508 }
00509
00510 void SRAMFile::setPlayCount(int count) {
00511 Q_ASSERT(isValid(game));
00512 Q_ASSERT((count >= 0) && (count <= 255));
00513
00514 unsigned char *ptr = (reinterpret_cast<unsigned char *>(sram)
00515 + MISC_DATA + PLAYCOUNT_OFFSET);
00516
00517 ptr[game] = count;
00518 modified = true;
00519 }
00520
00521 enum sf_potion SRAMFile::getPotion() const {
00522 Q_ASSERT(isValid(game));
00523
00524 const char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00525
00526 return static_cast<sf_potion>(ptr[POTION_OFFSET]);
00527 }
00528
00529 void SRAMFile::setPotion(enum sf_potion potion) {
00530 Q_ASSERT(isValid(game));
00531
00532 char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00533
00534 ptr[POTION_OFFSET] = potion;
00535 modified = true;
00536 }
00537
00538 enum sf_quest SRAMFile::getQuest() const {
00539 Q_ASSERT(isValid(game));
00540
00541 const char *ptr = (sram + MISC_DATA + QUEST_OFFSET);
00542
00543 return static_cast<enum sf_quest>(ptr[game]);
00544 }
00545
00546 void SRAMFile::setQuest(enum sf_quest quest) {
00547 Q_ASSERT(isValid(game));
00548
00549 char *ptr = (sram + MISC_DATA + QUEST_OFFSET);
00550
00551 ptr[game] = quest;
00552 modified = true;
00553 }
00554
00555 enum sf_ring SRAMFile::getRing() const {
00556 Q_ASSERT(isValid(game));
00557
00558 const char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00559
00560 return static_cast<enum sf_ring>(ptr[RING_OFFSET]);
00561 }
00562
00563 void SRAMFile::setRing(enum sf_ring ring) {
00564 Q_ASSERT(isValid(game));
00565
00566 char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00567
00568 ptr[RING_OFFSET] = ring;
00569 modified = true;
00570 }
00571
00572 int SRAMFile::getRupees() const {
00573 Q_ASSERT(isValid(game));
00574
00575 const unsigned char *ptr = (reinterpret_cast<const unsigned char *>(sram)
00576 + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00577
00578 return ptr[RUPEES_OFFSET];
00579 }
00580
00581 void SRAMFile::setRupees(int rupees) {
00582 Q_ASSERT(isValid(game));
00583 Q_ASSERT((rupees >= 0) && (rupees <= 255));
00584
00585 unsigned char *ptr = (reinterpret_cast<unsigned char *>(sram)
00586 + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00587
00588 ptr[RUPEES_OFFSET] = rupees;
00589 modified = true;
00590 }
00591
00592 enum sf_sword SRAMFile::getSword() const {
00593 Q_ASSERT(isValid(game));
00594
00595 const char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00596
00597 return static_cast<enum sf_sword>(ptr[SWORD_OFFSET]);
00598 }
00599
00600 void SRAMFile::setSword(enum sf_sword sword) {
00601 Q_ASSERT(isValid(game));
00602
00603 char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00604
00605 ptr[SWORD_OFFSET] = sword;
00606 modified = true;
00607 }
00608
00609 bool SRAMFile::hasTriforce(int piece) const {
00610 Q_ASSERT(isValid(game));
00611 Q_ASSERT((piece >= 1) && (piece <= 8));
00612
00613 const char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00614
00615 return (ptr[TRIFORCE_OFFSET] & (1 << (piece - 1)));
00616 }
00617
00618 void SRAMFile::setTriforce(int piece, bool give) {
00619 Q_ASSERT(isValid(game));
00620 Q_ASSERT((piece >= 1) && (piece <= 8));
00621
00622 char *ptr = (sram + INVENTORY_DATA + (game * INVENTORY_DATA_SIZE));
00623
00624 if (give) {
00625 ptr[TRIFORCE_OFFSET] |= (1 << (piece - 1));
00626 } else {
00627 ptr[TRIFORCE_OFFSET] &= ~(1 << (piece - 1));
00628 }
00629
00630 modified = true;
00631 }
00632