ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

savegame.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the AUTHORS
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/endian.h"
00024 #include "common/savefile.h"
00025 #include "common/system.h"
00026 
00027 #include "math/vector3d.h"
00028 
00029 #include "engines/grim/savegame.h"
00030 #include "engines/grim/color.h"
00031 
00032 namespace Grim {
00033 
00034 #define SAVEGAME_HEADERTAG  'RSAV'
00035 #define SAVEGAME_FOOTERTAG  'ESAV'
00036 
00037 uint SaveGame::SAVEGAME_MAJOR_VERSION = 22;
00038 uint SaveGame::SAVEGAME_MINOR_VERSION = 27;
00039 
00040 SaveGame *SaveGame::openForLoading(const Common::String &filename) {
00041     Common::InSaveFile *inSaveFile = g_system->getSavefileManager()->openForLoading(filename);
00042     if (!inSaveFile) {
00043         warning("SaveGame::openForLoading() Error opening savegame file %s", filename.c_str());
00044         return nullptr;
00045     }
00046 
00047     SaveGame *save = new SaveGame();
00048 
00049     save->_saving = false;
00050     save->_inSaveFile = inSaveFile;
00051 
00052     uint32 tag = inSaveFile->readUint32BE();
00053     if (tag != SAVEGAME_HEADERTAG) {
00054         delete save;
00055         return nullptr;
00056     }
00057     save->_majorVersion = inSaveFile->readUint32BE();
00058     save->_minorVersion = inSaveFile->readUint32BE();
00059 
00060     return save;
00061 }
00062 
00063 SaveGame *SaveGame::openForSaving(const Common::String &filename) {
00064     Common::OutSaveFile *outSaveFile =  g_system->getSavefileManager()->openForSaving(filename);
00065     if (!outSaveFile) {
00066         warning("SaveGame::openForSaving() Error creating savegame file %s", filename.c_str());
00067         return nullptr;
00068     }
00069 
00070     SaveGame *save = new SaveGame();
00071 
00072     save->_saving = true;
00073     save->_outSaveFile = outSaveFile;
00074 
00075     outSaveFile->writeUint32BE(SAVEGAME_HEADERTAG);
00076     outSaveFile->writeUint32BE(SAVEGAME_MAJOR_VERSION);
00077     outSaveFile->writeUint32BE(SAVEGAME_MINOR_VERSION);
00078 
00079     save->_majorVersion = SAVEGAME_MAJOR_VERSION;
00080     save->_minorVersion = SAVEGAME_MINOR_VERSION;
00081 
00082     return save;
00083 }
00084 
00085 SaveGame::SaveGame() :
00086         _currentSection(0), _sectionBuffer(nullptr), _majorVersion(0),
00087         _minorVersion(0), _saving(false), _inSaveFile(nullptr), _outSaveFile(nullptr),
00088         _sectionSize(0), _sectionAlloc(0), _sectionPtr(0) {
00089 
00090 }
00091 
00092 SaveGame::~SaveGame() {
00093     if (_saving) {
00094         _outSaveFile->writeUint32BE(SAVEGAME_FOOTERTAG);
00095         _outSaveFile->finalize();
00096         if (_outSaveFile->err())
00097             warning("SaveGame::~SaveGame() Can't write file. (Disk full?)");
00098         delete _outSaveFile;
00099     } else {
00100         delete _inSaveFile;
00101     }
00102     free(_sectionBuffer);
00103 }
00104 
00105 bool SaveGame::isCompatible() const {
00106     return _majorVersion == SAVEGAME_MAJOR_VERSION && _minorVersion <= SAVEGAME_MINOR_VERSION;
00107 }
00108 
00109 uint SaveGame::saveMajorVersion() const {
00110     return _majorVersion;
00111 }
00112 
00113 uint SaveGame::saveMinorVersion() const {
00114     return _minorVersion;
00115 }
00116 
00117 uint32 SaveGame::beginSection(uint32 sectionTag) {
00118     assert(_majorVersion == SAVEGAME_MAJOR_VERSION);
00119 
00120     if (_currentSection != 0)
00121         error("Tried to begin a new save game section with ending old section");
00122     _currentSection = sectionTag;
00123     _sectionSize = 0;
00124     if (!_saving) {
00125         uint32 tag = 0;
00126 
00127         while (tag != sectionTag) {
00128             tag = _inSaveFile->readUint32BE();
00129             if (tag == SAVEGAME_FOOTERTAG)
00130                 error("Unable to find requested section of savegame");
00131             _sectionSize = _inSaveFile->readUint32BE();
00132             _inSaveFile->seek(_sectionSize, SEEK_CUR);
00133         }
00134         if (!_sectionBuffer || _sectionAlloc < _sectionSize) {
00135             _sectionAlloc = _sectionSize;
00136             byte *buff = (byte *)realloc(_sectionBuffer, _sectionAlloc);
00137             if (buff == nullptr) {
00138                 free(_sectionBuffer);
00139                 error("Could not allocate memory for save game");
00140             }
00141             _sectionBuffer = buff;
00142         }
00143 
00144         _inSaveFile->seek(-(int32)_sectionSize, SEEK_CUR);
00145         _inSaveFile->read(_sectionBuffer, _sectionSize);
00146 
00147     } else {
00148         if (!_sectionBuffer) {
00149             _sectionAlloc = _allocAmmount;
00150             _sectionBuffer = (byte *)malloc(_sectionAlloc);
00151         }
00152     }
00153     _sectionPtr = 0;
00154     return _sectionSize;
00155 }
00156 
00157 void SaveGame::endSection() {
00158     if (_currentSection == 0)
00159         error("Tried to end a save game section without starting a section");
00160     if (_saving) {
00161         _outSaveFile->writeUint32BE(_currentSection);
00162         _outSaveFile->writeUint32BE(_sectionSize);
00163         _outSaveFile->write(_sectionBuffer, _sectionSize);
00164     }
00165     _currentSection = 0;
00166 }
00167 
00168 void SaveGame::read(void *data, int size) {
00169     if (_saving)
00170         error("SaveGame::readBlock called when storing a savegame");
00171     if (_currentSection == 0)
00172         error("Tried to read a block without starting a section");
00173     memcpy(data, &_sectionBuffer[_sectionPtr], size);
00174     _sectionPtr += size;
00175 }
00176 
00177 uint64 SaveGame::readLEUint64() {
00178     if (_saving)
00179         error("SaveGame::readBlock called when storing a savegame");
00180     if (_currentSection == 0)
00181         error("Tried to read a block without starting a section");
00182     uint32 data = READ_LE_UINT64(&_sectionBuffer[_sectionPtr]);
00183     _sectionPtr += 8;
00184     return data;
00185 }
00186 
00187 uint32 SaveGame::readLEUint32() {
00188     if (_saving)
00189         error("SaveGame::readBlock called when storing a savegame");
00190     if (_currentSection == 0)
00191         error("Tried to read a block without starting a section");
00192     uint32 data = READ_LE_UINT32(&_sectionBuffer[_sectionPtr]);
00193     _sectionPtr += 4;
00194     return data;
00195 }
00196 
00197 uint16 SaveGame::readLEUint16() {
00198     if (_saving)
00199         error("SaveGame::readBlock called when storing a savegame");
00200     if (_currentSection == 0)
00201         error("Tried to read a block without starting a section");
00202     uint16 data = READ_LE_UINT16(&_sectionBuffer[_sectionPtr]);
00203     _sectionPtr += 2;
00204     return data;
00205 }
00206 
00207 int32 SaveGame::readLESint32() {
00208     if (_saving)
00209         error("SaveGame::readBlock called when storing a savegame");
00210     if (_currentSection == 0)
00211         error("Tried to read a block without starting a section");
00212     int32 data = (int32)READ_LE_UINT32(&_sectionBuffer[_sectionPtr]);
00213     _sectionPtr += 4;
00214     return data;
00215 }
00216 
00217 byte SaveGame::readByte() {
00218     if (_saving)
00219         error("SaveGame::readBlock called when storing a savegame");
00220     if (_currentSection == 0)
00221         error("Tried to read a block without starting a section");
00222     byte data = _sectionBuffer[_sectionPtr];
00223     _sectionPtr++;
00224     return data;
00225 }
00226 
00227 bool SaveGame::readBool() {
00228     return readByte() != 0;
00229 }
00230 
00231 void SaveGame::checkAlloc(int size) {
00232     if (_sectionSize + size > _sectionAlloc) {
00233         while (_sectionSize + size > _sectionAlloc)
00234             _sectionAlloc += _allocAmmount;
00235         _sectionBuffer = (byte *)realloc(_sectionBuffer, _sectionAlloc);
00236         if (!_sectionBuffer)
00237             error("Failed to allocate space for buffer");
00238     }
00239 }
00240 
00241 void SaveGame::write(const void *data, int size) {
00242     if (!_saving)
00243         error("SaveGame::writeBlock called when restoring a savegame");
00244     if (_currentSection == 0)
00245         error("Tried to write a block without starting a section");
00246 
00247     checkAlloc(size);
00248 
00249     memcpy(&_sectionBuffer[_sectionSize], data, size);
00250     _sectionSize += size;
00251 }
00252 
00253 void SaveGame::writeLEUint64(uint64 data) {
00254     if (!_saving)
00255         error("SaveGame::writeBlock called when restoring a savegame");
00256     if (_currentSection == 0)
00257         error("Tried to write a block without starting a section");
00258 
00259     checkAlloc(8);
00260 
00261     WRITE_LE_UINT64(&_sectionBuffer[_sectionSize], data);
00262     _sectionSize += 8;
00263 }
00264 
00265 void SaveGame::writeLEUint32(uint32 data) {
00266     if (!_saving)
00267         error("SaveGame::writeBlock called when restoring a savegame");
00268     if (_currentSection == 0)
00269         error("Tried to write a block without starting a section");
00270 
00271     checkAlloc(4);
00272 
00273     WRITE_LE_UINT32(&_sectionBuffer[_sectionSize], data);
00274     _sectionSize += 4;
00275 }
00276 
00277 void SaveGame::writeLEUint16(uint16 data) {
00278     if (!_saving)
00279         error("SaveGame::writeBlock called when restoring a savegame");
00280     if (_currentSection == 0)
00281         error("Tried to write a block without starting a section");
00282 
00283     checkAlloc(2);
00284 
00285     WRITE_LE_UINT16(&_sectionBuffer[_sectionSize], data);
00286     _sectionSize += 2;
00287 }
00288 
00289 void SaveGame::writeLESint32(int32 data) {
00290     if (!_saving)
00291         error("SaveGame::writeBlock called when restoring a savegame");
00292     if (_currentSection == 0)
00293         error("Tried to write a block without starting a section");
00294 
00295     checkAlloc(4);
00296 
00297     WRITE_LE_UINT32(&_sectionBuffer[_sectionSize], (uint32)data);
00298     _sectionSize += 4;
00299 }
00300 
00301 void SaveGame::writeBool(bool data) {
00302     writeByte(data);
00303 }
00304 
00305 void SaveGame::writeByte(byte data) {
00306     if (!_saving)
00307         error("SaveGame::writeBlock called when restoring a savegame");
00308     if (_currentSection == 0)
00309         error("Tried to write a block without starting a section");
00310 
00311     checkAlloc(1);
00312 
00313     _sectionBuffer[_sectionSize] = data;
00314     _sectionSize++;
00315 }
00316 
00317 void SaveGame::writeVector3d(const Math::Vector3d &vec) {
00318     writeFloat(vec.x());
00319     writeFloat(vec.y());
00320     writeFloat(vec.z());
00321 }
00322 
00323 void SaveGame::writeColor(const Grim::Color &color) {
00324     writeByte(color.getRed());
00325     writeByte(color.getGreen());
00326     writeByte(color.getBlue());
00327 }
00328 
00329 void SaveGame::writeFloat(float data) {
00330     uint32 v;
00331     memcpy(&v, &data, 4);
00332     writeLEUint32(v);
00333 }
00334 
00335 void SaveGame::writeString(const Common::String &string) {
00336     int32 len = string.size();
00337     writeLESint32(len);
00338     write(string.c_str(), len);
00339 }
00340 
00341 Math::Vector3d SaveGame::readVector3d() {
00342     float x = readFloat();
00343     float y = readFloat();
00344     float z = readFloat();
00345     return Math::Vector3d(x, y, z);
00346 }
00347 
00348 Grim::Color SaveGame::readColor() {
00349     Color color;
00350     color.getRed() = readByte();
00351     color.getGreen() = readByte();
00352     color.getBlue() = readByte();
00353 
00354     return color;
00355 }
00356 
00357 float SaveGame::readFloat() {
00358     float f;
00359     uint32 v = readLEUint32();
00360     memcpy(&f, &v, 4);
00361 
00362     return f;
00363 }
00364 
00365 Common::String SaveGame::readString() {
00366     int32 len = readLESint32();
00367     Common::String s((const char *)&_sectionBuffer[_sectionPtr], len);
00368     _sectionPtr += len;
00369     return s;
00370 }
00371 
00372 } // end of namespace Grim


Generated on Sat Feb 9 2019 05:00:40 for ResidualVM by doxygen 1.7.1
curved edge   curved edge