sramfile.cc

Go to the documentation of this file.
00001 /*
00002  * Secret of Evermore SRAM Editor
00003  * Copyright (C) 2006 emuWorks
00004  * http://games.technoplaza.net/
00005  *
00006  * This file is part of Secret of Evermore SRAM Editor.
00007  *
00008  * Secret of Evermore SRAM Editor is free software; you can redistribute it
00009  * and/or modify it under the terms of the GNU General Public License as
00010  * published by the Free Software Foundation; either version 2 of the License,
00011  * or (at your option) any later version.
00012  *
00013  * Secret of Evermore SRAM Editor is distributed in the hope that it will be
00014  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with Secret of Evermore SRAM Editor; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00021  */
00022  
00023 // $Id: sramfile.cc,v 1.22 2006/09/06 14:22:00 technoplaza Exp $
00024 
00025 #include <cstring>
00026 #include <fstream>
00027 
00028 #include <QtCore/qendian.h>
00029 
00030 #include "model/sramfile.hh"
00031 
00032 using namespace soesrame;
00033 
00034 const std::pair<int, int> SRAMFile::SRAM_ALCHEMY_OFFSETS[] =
00035     {
00036         std::pair<int, int>(0x1F7, 0x01),  // acid rain
00037         std::pair<int, int>(0x1F7, 0x02),  // atlas
00038         std::pair<int, int>(0x1F7, 0x04),  // barrier
00039         std::pair<int, int>(0x1F7, 0x08),  // call up
00040         std::pair<int, int>(0x1F7, 0x10),  // corrosion
00041         std::pair<int, int>(0x1F7, 0x20),  // crush
00042         std::pair<int, int>(0x1F7, 0x40),  // cure
00043         std::pair<int, int>(0x1F7, 0x80),  // defend
00044         
00045         std::pair<int, int>(0x1F8, 0x01),  // double drain
00046         std::pair<int, int>(0x1F8, 0x02),  // drain
00047         std::pair<int, int>(0x1F8, 0x04),  // energize
00048         std::pair<int, int>(0x1F8, 0x08),  // escape
00049         std::pair<int, int>(0x1F8, 0x10),  // explosion
00050         std::pair<int, int>(0x1F8, 0x20),  // fireball
00051         std::pair<int, int>(0x1F8, 0x40),  // fire power
00052         std::pair<int, int>(0x1F8, 0x80),  // flash
00053         
00054         std::pair<int, int>(0x1F9, 0x01),  // force field
00055         std::pair<int, int>(0x1F9, 0x02),  // hard ball
00056         std::pair<int, int>(0x1F9, 0x04),  // heal
00057         std::pair<int, int>(0x1F9, 0x08),  // lance
00058         std::pair<int, int>(0x1F9, 0x10),  // laser (dummied spell)
00059         std::pair<int, int>(0x1F9, 0x20),  // levitate
00060         std::pair<int, int>(0x1F9, 0x40),  // lightning storm
00061         std::pair<int, int>(0x1F9, 0x80),  // miracle cure
00062         
00063         std::pair<int, int>(0x1FA, 0x01),  // nitro
00064         std::pair<int, int>(0x1FA, 0x02),  // one up
00065         std::pair<int, int>(0x1FA, 0x04),  // reflect
00066         std::pair<int, int>(0x1FA, 0x08),  // regrowth
00067         std::pair<int, int>(0x1FA, 0x10),  // revealer
00068         std::pair<int, int>(0x1FA, 0x20),  // revive
00069         std::pair<int, int>(0x1FA, 0x40),  // slow burn
00070         std::pair<int, int>(0x1FA, 0x80),  // speed
00071         
00072         std::pair<int, int>(0x1FB, 0x01),  // sting
00073         std::pair<int, int>(0x1FB, 0x02),  // stop
00074         std::pair<int, int>(0x1FB, 0x04)   // super heal
00075     };
00076     
00077 const std::pair<int, int> SRAMFile::SRAM_CHARM_OFFSETS[] =
00078     {
00079         std::pair<int, int>(0x200, 0x20),   // armor polish
00080         std::pair<int, int>(0x200, 0x40),   // chocobo egg
00081         std::pair<int, int>(0x200, 0x80),   // insect incense
00082         
00083         std::pair<int, int>(0x201, 0x01),   // jade disk
00084         std::pair<int, int>(0x201, 0x02),   // jaguar ring
00085         std::pair<int, int>(0x201, 0x04),   // magic gourd
00086         std::pair<int, int>(0x201, 0x08),   // moxa stick
00087         std::pair<int, int>(0x201, 0x10),   // oracle bone
00088         std::pair<int, int>(0x201, 0x20),   // ruby heart
00089         std::pair<int, int>(0x201, 0x40),   // silver sheath
00090         std::pair<int, int>(0x201, 0x80),   // staff of life
00091         
00092         std::pair<int, int>(0x202, 0x01),   // sun stone
00093         std::pair<int, int>(0x202, 0x02),   // thug's cloak
00094         std::pair<int, int>(0x202, 0x04)    // wizard's coin
00095     };
00096     
00097 const std::pair<int, int> SRAMFile::SRAM_WEAPON_OFFSETS[] =
00098     {
00099         std::pair<int, int>(0x279, 0x02),  // bone crusher
00100         std::pair<int, int>(0x279, 0x04),  // gladiator sword
00101         std::pair<int, int>(0x279, 0x08),  // crusader sword
00102         std::pair<int, int>(0x279, 0x10),  // neutron blade
00103         
00104         std::pair<int, int>(0x279, 0x20),  // spider's claw
00105         std::pair<int, int>(0x279, 0x40),  // bronze axe
00106         std::pair<int, int>(0x279, 0x80),  // knight basher
00107         std::pair<int, int>(0x27A, 0x01),  // atom smasher
00108         
00109         std::pair<int, int>(0x27A, 0x02),  // horn spear
00110         std::pair<int, int>(0x27A, 0x04),  // bronze spear
00111         std::pair<int, int>(0x27A, 0x08),  // lance
00112         std::pair<int, int>(0x27A, 0x10),  // laser lance
00113         
00114         std::pair<int, int>(0x27A, 0x20)   // bazooka
00115     };
00116 
00117 SRAMFile::SRAMFile(const QString &filename) throw(InvalidSRAMFileException)
00118     : modified(false) {
00119     std::ifstream file(filename.toAscii().data(), 
00120                        std::ios_base::in | std::ios_base::binary);
00121     
00122     if (!file) {
00123         throw InvalidSRAMFileException(ISFE_FILENOTFOUND);
00124     }
00125     
00126     file.seekg(0, std::ios_base::end);
00127     
00128     if (file.tellg() != static_cast<std::streampos>(SRAM_FILE_SIZE)) {
00129         throw InvalidSRAMFileException(ISFE_INVALIDSIZE);
00130     }
00131     
00132     file.seekg(0, std::ios_base::beg);
00133     file.read(reinterpret_cast<char *>(sram), SRAM_FILE_SIZE);
00134     file.close();
00135     
00136     bool valid = false;
00137     
00138     for (int game = 3; game >= 0; --game) {
00139         if (checksum(game) == getChecksum(game)) {
00140             valid = true;
00141             this->valid[game] = true;
00142             setGame(game);
00143         }
00144     }
00145     
00146     if (!valid) {
00147         throw InvalidSRAMFileException(ISFE_NOVALIDGAMES);
00148     }
00149 }
00150 
00151 quint16 SRAMFile::checksum(int game) const {
00152     quint32 checksum = 0x43F;
00153     
00154     for (int i = 2; i < SRAM_GAME_SIZE - 1; ++i) {
00155         unsigned char temp = checksum;
00156         temp += sram[SRAM_GAME_OFFSET + i + game * SRAM_GAME_SIZE];
00157         
00158         checksum &= 0xFF00;
00159         checksum |= temp;
00160         checksum <<= 1;
00161         
00162         if (checksum > 0xFFFF) {
00163             checksum -= 0xFFFF;
00164         }
00165     }
00166     
00167     return static_cast<quint16>(checksum);
00168 }
00169 
00170 bool SRAMFile::save(const QString &filename) {
00171     for (int game = 0; game < 4; ++game) {
00172         if (isValid(game)) {
00173             setChecksum(game, checksum(game));
00174         }
00175     }
00176     
00177     std::ofstream file(filename.toAscii().data(),
00178                        std::ios_base::out | std::ios_base::binary);
00179     
00180     if (!file) {
00181         return false;
00182     }
00183     
00184     file.write(reinterpret_cast<char *>(sram), SRAM_FILE_SIZE);
00185     
00186     if (file.tellp() != static_cast<std::streampos>(SRAM_FILE_SIZE)) {
00187         return false;
00188     }
00189     
00190     file.close();
00191     modified = false;
00192     
00193     return true;
00194 }
00195 
00196 bool SRAMFile::hasAlchemy(enum sf_alchemy alchemy) const {
00197     Q_ASSERT(isValid(getGame()));
00198     
00199     return (offset[SRAM_ALCHEMY_OFFSETS[alchemy].first] &
00200             SRAM_ALCHEMY_OFFSETS[alchemy].second);
00201 }
00202 
00203 void SRAMFile::setAlchemy(enum sf_alchemy alchemy, bool have) {
00204     Q_ASSERT(isValid(getGame()));
00205     
00206     unsigned char *data = offset + SRAM_ALCHEMY_OFFSETS[alchemy].first;
00207     
00208     if (have) {
00209         *data |= SRAM_ALCHEMY_OFFSETS[alchemy].second;
00210     } else {
00211         *data &= ~SRAM_ALCHEMY_OFFSETS[alchemy].second;
00212     }
00213     
00214     modified = true;
00215 }
00216 
00217 std::pair<int, int> SRAMFile::getAlchemyLevel(enum sf_alchemy alchemy) const {
00218     Q_ASSERT(isValid(getGame()));
00219     
00220     return std::pair<int, int>
00221         (offset[SRAM_ALCHEMYMAJORLEVELS_OFFSET + (alchemy * 2)],
00222          offset[SRAM_ALCHEMYMINORLEVELS_OFFSET + (alchemy * 2)]); 
00223 }
00224 
00225 void SRAMFile::setAlchemyLevel(enum sf_alchemy alchemy,
00226                                std::pair<int, int> level) {
00227     Q_ASSERT(isValid(getGame()));
00228     Q_ASSERT((level.first >= 0) && (level.first < 10));
00229     Q_ASSERT((level.second >= 0) && (level.second < 100));
00230     
00231     offset[SRAM_ALCHEMYMAJORLEVELS_OFFSET + (alchemy * 2)] = level.first;
00232     offset[SRAM_ALCHEMYMINORLEVELS_OFFSET + (alchemy * 2)] = level.second;
00233     
00234     modified = true;
00235 }
00236 
00237 std::pair<int, int> SRAMFile::getAttackLevel() const {
00238     Q_ASSERT(isValid(getGame()));
00239     
00240     return std::pair<int, int>
00241         (offset[SRAM_DOG_ATTACKLEVEL_OFFSET + 1],
00242          offset[SRAM_DOG_ATTACKLEVEL_OFFSET]);
00243 }
00244 
00245 void SRAMFile::setAttackLevel(std::pair<int, int> level) {
00246     Q_ASSERT(isValid(getGame()));
00247     Q_ASSERT((level.first >= 1) && (level.first < 4));
00248     Q_ASSERT((level.second >= 0) && (level.second < 256));
00249     
00250     offset[SRAM_DOG_ATTACKLEVEL_OFFSET + 1] = level.first;
00251     offset[SRAM_DOG_ATTACKLEVEL_OFFSET] = level.second;
00252     
00253     modified = true;
00254 }
00255 
00256 bool SRAMFile::hasCharm(enum sf_charm charm) const {
00257     Q_ASSERT(isValid(getGame()));
00258     
00259     return (offset[SRAM_CHARM_OFFSETS[charm].first] &
00260             SRAM_CHARM_OFFSETS[charm].second);
00261 }
00262 
00263 void SRAMFile::setCharm(enum sf_charm charm, bool have) {
00264     Q_ASSERT(isValid(getGame()));
00265     
00266     unsigned char *data = offset + SRAM_CHARM_OFFSETS[charm].first;
00267     
00268     if (have) {
00269         *data |= SRAM_CHARM_OFFSETS[charm].second;
00270     } else {
00271         *data &= ~SRAM_CHARM_OFFSETS[charm].second;
00272     }
00273     
00274     modified = true;
00275 }
00276 
00277 quint16 SRAMFile::getChecksum(int game) const {
00278     const quint16 *data =
00279         reinterpret_cast<const quint16 *>(sram + SRAM_GAME_OFFSET +
00280                                           game * SRAM_GAME_SIZE +
00281                                           SRAM_CHECKSUM_OFFSET);
00282     
00283     return qFromLittleEndian(*data);
00284 }
00285 
00286 void SRAMFile::setChecksum(int game, quint16 checksum) {
00287     quint16 *data = reinterpret_cast<quint16 *>(sram + SRAM_GAME_OFFSET +
00288                                                 game * SRAM_GAME_SIZE +
00289                                                 SRAM_CHECKSUM_OFFSET);
00290     
00291     *data = qToLittleEndian(checksum);
00292 }
00293 
00294 quint16 SRAMFile::getCurrentHP(enum sf_hero hero) const {
00295     Q_ASSERT(isValid(getGame()));
00296     
00297     const quint16 *data =
00298         reinterpret_cast<const quint16 *>(offset +
00299                                           ((hero == SF_BOY) ?
00300                                            SRAM_BOY_CURRENTHP_OFFSET :
00301                                            SRAM_DOG_CURRENTHP_OFFSET));
00302                                       
00303     return qFromLittleEndian(*data);
00304 }
00305 
00306 void SRAMFile::setCurrentHP(enum sf_hero hero, quint16 hp) {
00307     Q_ASSERT(isValid(getGame()));
00308     Q_ASSERT((hp >= 0) && (hp < 1000));
00309     
00310     quint16 *data = reinterpret_cast<quint16 *>(offset +
00311                                                 ((hero == SF_BOY) ?
00312                                                  SRAM_BOY_CURRENTHP_OFFSET :
00313                                                  SRAM_DOG_CURRENTHP_OFFSET));
00314                                                  
00315     *data = qToLittleEndian(hp);
00316     modified = true;
00317 }
00318 
00319 quint32 SRAMFile::getExperience(enum sf_hero hero) const {
00320     Q_ASSERT(isValid(getGame()));
00321     
00322     const quint32 *data =
00323         reinterpret_cast<const quint32 *>(offset +
00324                                           ((hero == SF_BOY) ?
00325                                            SRAM_BOY_EXPERIENCE_OFFSET :
00326                                            SRAM_DOG_EXPERIENCE_OFFSET));
00327                                            
00328     return (qFromLittleEndian(*data) & 0xFFFFFF);
00329 }
00330 
00331 void SRAMFile::setExperience(enum sf_hero hero, quint32 experience) {
00332     Q_ASSERT(isValid(getGame()));
00333     Q_ASSERT((experience >= 0) && (experience < 16777216));
00334     
00335     unsigned char *data = offset + ((hero == SF_BOY) ?
00336                                     SRAM_BOY_EXPERIENCE_OFFSET :
00337                                     SRAM_DOG_EXPERIENCE_OFFSET);
00338     
00339     data[0] = experience;
00340     data[1] = experience >> 8;
00341     data[2] = experience >> 16;
00342     
00343     modified = true;
00344 }
00345 
00346 void SRAMFile::setGame(int game) {
00347     Q_ASSERT((game >= 0) && (game < 4));
00348     
00349     this->game = game;
00350     offset = sram + SRAM_GAME_OFFSET + (game * SRAM_GAME_SIZE);
00351 }
00352 
00353 int SRAMFile::getIngredient(enum sf_ingredient ingredient) const {
00354     Q_ASSERT(isValid(getGame()));
00355     
00356     return offset[SRAM_INGREDIENTS_OFFSET + ingredient];
00357 }
00358 
00359 void SRAMFile::setIngredient(enum sf_ingredient ingredient, int count) {
00360     Q_ASSERT(isValid(getGame()));
00361     Q_ASSERT((count >= 0) && (count < 100));
00362     
00363     offset[SRAM_INGREDIENTS_OFFSET + ingredient] = count;
00364     modified = true;
00365 }
00366 
00367 int SRAMFile::getItem(enum sf_item item) const {
00368     Q_ASSERT(isValid(getGame()));
00369     
00370     return offset[SRAM_ITEMS_OFFSET + item];
00371 }
00372 
00373 void SRAMFile::setItem(enum sf_item item, int count) {
00374     Q_ASSERT(isValid(getGame()));
00375     Q_ASSERT((count >= 0) && (count < 100));
00376     
00377     offset[SRAM_ITEMS_OFFSET + item] = count;
00378     modified = true;
00379 }
00380 
00381 int SRAMFile::getLevel(enum sf_hero hero) const {
00382     Q_ASSERT(isValid(getGame()));
00383     
00384     return offset[((hero == SF_BOY) ?
00385                    SRAM_BOY_LEVEL_OFFSET :
00386                    SRAM_DOG_LEVEL_OFFSET)];
00387 }
00388 
00389 void SRAMFile::setLevel(enum sf_hero hero, int level) {
00390     Q_ASSERT(isValid(getGame()));
00391     Q_ASSERT((level >= 1) && (level < 100));
00392     
00393     offset[((hero == SF_BOY) ?
00394             SRAM_BOY_LEVEL_OFFSET :
00395             SRAM_DOG_LEVEL_OFFSET)] = level;
00396     modified = true;
00397 }
00398 
00399 quint16 SRAMFile::getMaxHP(enum sf_hero hero) const {
00400     Q_ASSERT(isValid(getGame()));
00401     
00402     const quint16 *data =
00403         reinterpret_cast<const quint16 *>(offset +
00404                                           ((hero == SF_BOY) ?
00405                                            SRAM_BOY_MAXHP_OFFSET :
00406                                            SRAM_DOG_MAXHP_OFFSET));
00407                                       
00408     return qFromLittleEndian(*data);
00409 }
00410 
00411 void SRAMFile::setMaxHP(enum sf_hero hero, quint16 hp) {
00412     Q_ASSERT(isValid(getGame()));
00413     Q_ASSERT((hp >= 0) && (hp < 1000));
00414     
00415     quint16 *data = reinterpret_cast<quint16 *>(offset +
00416                                                 ((hero == SF_BOY) ?
00417                                                  SRAM_BOY_MAXHP_OFFSET :
00418                                                  SRAM_DOG_MAXHP_OFFSET));
00419                                                  
00420     *data = qToLittleEndian(hp);
00421     modified = true;
00422 }
00423 
00424 quint32 SRAMFile::getMoney(enum sf_money money) const {
00425     Q_ASSERT(isValid(getGame()));
00426     
00427     const quint32 *data =
00428         reinterpret_cast<const quint32 *>(offset +
00429                                           SRAM_MONEY_OFFSET + (money * 3));
00430                                           
00431     return (qFromLittleEndian(*data) & 0xFFFFFF);
00432 }
00433 
00434 void SRAMFile::setMoney(enum sf_money money, quint32 count) {
00435     Q_ASSERT(isValid(getGame()));
00436     Q_ASSERT((count >= 0) && (count < 16777216));
00437     
00438     unsigned char *data = offset + SRAM_MONEY_OFFSET + (money * 3);
00439     
00440     data[0] = count;
00441     data[1] = count >> 8;
00442     data[2] = count >> 16;
00443     
00444     modified = true;
00445 }
00446 
00447 QString SRAMFile::getName(enum sf_hero hero) const {
00448     Q_ASSERT(isValid(getGame()));
00449     
00450     const char *data =
00451         reinterpret_cast<const char *>(offset +
00452                                        ((hero == SF_BOY) ?
00453                                         SRAM_BOY_NAME_OFFSET :
00454                                         SRAM_DOG_NAME_OFFSET));
00455                                                
00456     return QString::fromAscii(data);
00457 }
00458 
00459 void SRAMFile::setName(enum sf_hero hero, const QString &name) {
00460     Q_ASSERT(isValid(getGame()));
00461     Q_ASSERT(name.length() <= 15);
00462     
00463     char *data = reinterpret_cast<char *>(offset + ((hero == SF_BOY) ?
00464                                                     SRAM_BOY_NAME_OFFSET :
00465                                                     SRAM_DOG_NAME_OFFSET));
00466                                                     
00467     std::strcpy(data, name.left(15).toAscii().data());
00468     
00469     modified = true;
00470 }
00471 
00472 quint16 SRAMFile::getTradeGood(enum sf_tradegood tradegood) const {
00473     Q_ASSERT(isValid(getGame()));
00474     
00475     const quint16 *data =
00476         reinterpret_cast<const quint16 *>(offset + SRAM_TRADEGOODS_OFFSET);
00477     
00478     return qFromLittleEndian(data[tradegood]);
00479 }
00480 
00481 void SRAMFile::setTradeGood(enum sf_tradegood tradegood, quint16 count) {
00482     Q_ASSERT(isValid(getGame()));
00483     Q_ASSERT((count >= 0) && (count < 100));
00484     
00485     quint16 *data =
00486         reinterpret_cast<quint16 *>(offset + SRAM_TRADEGOODS_OFFSET);
00487     
00488     data[tradegood] = qToLittleEndian(count);
00489     modified = true;
00490 }
00491 
00492 bool SRAMFile::hasWeapon(enum sf_weapon weapon) const {
00493     Q_ASSERT(isValid(getGame()));
00494     
00495     return (offset[SRAM_WEAPON_OFFSETS[weapon].first] &
00496             SRAM_WEAPON_OFFSETS[weapon].second);
00497 }
00498 
00499 void SRAMFile::setWeapon(enum sf_weapon weapon, bool have) {
00500     Q_ASSERT(isValid(getGame()));
00501     
00502     unsigned char *data = offset + SRAM_WEAPON_OFFSETS[weapon].first;
00503     
00504     if (have) {
00505         *data |= SRAM_WEAPON_OFFSETS[weapon].second;
00506     } else {
00507         *data &= ~SRAM_WEAPON_OFFSETS[weapon].second;
00508     }
00509     
00510     modified = true;
00511 }
00512 
00513 std::pair<int, int> SRAMFile::getWeaponLevel(enum sf_weapon weapon) const {
00514     Q_ASSERT(isValid(getGame()));
00515     Q_ASSERT(weapon != SF_BAZOOKA);
00516     
00517     const unsigned char *data =
00518         offset + SRAM_WEAPONLEVELS_OFFSET + (weapon * 2);
00519     
00520     return std::pair<int, int>(data[1], data[0]);
00521 }
00522 
00523 void SRAMFile::setWeaponLevel(enum sf_weapon weapon,
00524                               std::pair<int, int> level) {
00525     Q_ASSERT(isValid(getGame()));
00526     Q_ASSERT(weapon != SF_BAZOOKA);
00527     Q_ASSERT((level.first >= 1) && (level.first < 4));
00528     Q_ASSERT((level.second >= 0) && (level.second < 256));
00529     
00530     unsigned char *data = offset + SRAM_WEAPONLEVELS_OFFSET + (weapon * 2);
00531     
00532     data[1] = level.first;
00533     data[0] = level.second;
00534     
00535     modified = true;
00536 }
00537 

Generated on Wed Sep 6 23:11:55 2006 for Secret of Evermore SRAM Editor by  doxygen 1.4.7