diff options
author | Sven Hesse | 2009-05-31 02:15:43 +0000 |
---|---|---|
committer | Sven Hesse | 2009-05-31 02:15:43 +0000 |
commit | 896df6daf337bf83f27193918eb386321c4b0166 (patch) | |
tree | c124f8f102052cdd6207e2507d097aff4bc7f44e /engines | |
parent | c938667d4b60005a926007376305f3da8621f7c7 (diff) | |
download | scummvm-rg350-896df6daf337bf83f27193918eb386321c4b0166.tar.gz scummvm-rg350-896df6daf337bf83f27193918eb386321c4b0166.tar.bz2 scummvm-rg350-896df6daf337bf83f27193918eb386321c4b0166.zip |
- A new save system for the GobEngine, one that is not fundamentally broken and is versioned. Unfortunately, this invalidates most save games created on big-endian machines, since endian-issues was a main problem with the old system
- Removed the now superfluous variables sizes
svn-id: r41056
Diffstat (limited to 'engines')
37 files changed, 5760 insertions, 3219 deletions
diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp index fbdc339c12..ec8b0989a3 100644 --- a/engines/gob/gob.cpp +++ b/engines/gob/gob.cpp @@ -47,7 +47,7 @@ #include "gob/parse.h" #include "gob/scenery.h" #include "gob/videoplayer.h" -#include "gob/saveload.h" +#include "gob/save/saveload.h" namespace Gob { @@ -368,7 +368,7 @@ bool GobEngine::initGameParts() { _map = new Map_v2(this); _goblin = new Goblin_v3(this); _scenery = new Scenery_v2(this); - _saveLoad = new SaveLoad_v3(this, _targetName.c_str()); + _saveLoad = new SaveLoad_v3(this, _targetName.c_str(), SaveLoad_v3::kScreenshotTypeGob3); break; case kGameTypeLostInTime: @@ -382,7 +382,7 @@ bool GobEngine::initGameParts() { _map = new Map_v2(this); _goblin = new Goblin_v3(this); _scenery = new Scenery_v2(this); - _saveLoad = new SaveLoad_v3(this, _targetName.c_str(), 4768, 0, 50); + _saveLoad = new SaveLoad_v3(this, _targetName.c_str(), SaveLoad_v3::kScreenshotTypeLost); break; case kGameTypeWoodruff: @@ -413,7 +413,7 @@ bool GobEngine::initGameParts() { _map = new Map_v4(this); _goblin = new Goblin_v4(this); _scenery = new Scenery_v2(this); - _saveLoad = new SaveLoad_v4(this, _targetName.c_str()); + _saveLoad = new SaveLoad(this, _targetName.c_str()); break; case kGameTypeAdibou4: diff --git a/engines/gob/gob.h b/engines/gob/gob.h index d13c334906..8a6985b0dd 100644 --- a/engines/gob/gob.h +++ b/engines/gob/gob.h @@ -65,8 +65,8 @@ class SaveLoad; #define READ_VARO_UINT32(off) _vm->_inter->_variables->readOff32(off) #define READ_VARO_UINT16(off) _vm->_inter->_variables->readOff16(off) #define READ_VARO_UINT8(off) _vm->_inter->_variables->readOff8(off) -#define GET_VAR_STR(var) _vm->_inter->_variables->getAddressVarString(var, 0) -#define GET_VARO_STR(off) _vm->_inter->_variables->getAddressOffString(off, 0) +#define GET_VAR_STR(var) _vm->_inter->_variables->getAddressVarString(var) +#define GET_VARO_STR(off) _vm->_inter->_variables->getAddressOffString(off) #define GET_VAR_FSTR(var) _vm->_inter->_variables->getAddressVarString(var) #define GET_VARO_FSTR(off) _vm->_inter->_variables->getAddressOffString(off) @@ -78,11 +78,14 @@ class SaveLoad; #define VAR(var) READ_VAR_UINT32(var) +// WARNING: Reordering these will invalidate save games! enum Endianness { kEndiannessLE, kEndiannessBE }; +// WARNING: Reordering these will invalidate save games! +// Add new games to the bottom of the list. enum GameType { kGameTypeNone = 0, kGameTypeGob1, diff --git a/engines/gob/helper.h b/engines/gob/helper.h index 3e4e3387bc..5bedf81014 100644 --- a/engines/gob/helper.h +++ b/engines/gob/helper.h @@ -49,6 +49,22 @@ inline char *strdupcpy(const char *str) { return nstr; } +/** A strcat that new[]s the buffer. */ +inline char *strdupcat(const char *str1, const char *str2) { + if (!str1 || !str2) + return 0; + + size_t len1 = strlen(str1); + size_t len2 = strlen(str2); + + char *nstr = new char[len1 + len2 + 1]; + + memcpy(nstr, str1, len1); + memcpy(nstr + len1, str2, len2 + 1); + + return nstr; +} + /** A "smart" reference counting templated class. */ template<typename T> class ReferenceCounter { diff --git a/engines/gob/inter.cpp b/engines/gob/inter.cpp index 4bcf3c81cd..ce7f2ba319 100644 --- a/engines/gob/inter.cpp +++ b/engines/gob/inter.cpp @@ -56,7 +56,6 @@ Inter::Inter(GobEngine *vm) : _vm(vm) { _soundStopVal = 0; memset(_varStack, 0, 300); - memset(_varSizesStack, 0, 300); _varStackPos = 0; _noBusyWait = false; diff --git a/engines/gob/inter.h b/engines/gob/inter.h index 1ba98141f4..ee49658318 100644 --- a/engines/gob/inter.h +++ b/engines/gob/inter.h @@ -92,7 +92,6 @@ protected: int16 _animPalDir[8]; byte _varStack[300]; - byte _varSizesStack[300]; int16 _varStackPos; // The busy-wait detection in o1_keyFunc breaks fast scrolling in Ween diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp index ecc5ad48c5..a9b4519cca 100644 --- a/engines/gob/inter_v1.cpp +++ b/engines/gob/inter_v1.cpp @@ -948,8 +948,7 @@ void Inter_v1::o1_initMult() { _vm->_mult->_objects[i].pPosY = new VariableReference(*_vm->_inter->_variables, offPosY); _vm->_mult->_objects[i].pAnimData = - (Mult::Mult_AnimData *) _variables->getAddressOff8(offAnim, - _vm->_global->_inter_animDataSize); + (Mult::Mult_AnimData *) _variables->getAddressOff8(offAnim); _vm->_mult->_objects[i].pAnimData->isStatic = 1; _vm->_mult->_objects[i].tick = 0; @@ -2234,7 +2233,7 @@ bool Inter_v1::o1_readData(OpFuncParams ¶ms) { if (((dataVar >> 2) == 59) && (size == 4)) WRITE_VAR(59, stream->readUint32LE()); else - retSize = stream->read((byte *) _variables->getAddressOff8(dataVar, size), size); + retSize = stream->read((byte *) _variables->getAddressOff8(dataVar), size); if (retSize == size) WRITE_VAR(1, 0); diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp index e0ccc06d94..2f501772dc 100644 --- a/engines/gob/inter_v2.cpp +++ b/engines/gob/inter_v2.cpp @@ -42,7 +42,7 @@ #include "gob/parse.h" #include "gob/scenery.h" #include "gob/video.h" -#include "gob/saveload.h" +#include "gob/save/saveload.h" #include "gob/videoplayer.h" #include "gob/sound/sound.h" @@ -890,8 +890,7 @@ void Inter_v2::o2_initMult() { _vm->_mult->_objects[i].pPosY = new VariableReference(*_vm->_inter->_variables, offPosY); _vm->_mult->_objects[i].pAnimData = - (Mult::Mult_AnimData *) _variables->getAddressOff8(offAnim, - _vm->_global->_inter_animDataSize); + (Mult::Mult_AnimData *) _variables->getAddressOff8(offAnim); _vm->_mult->_objects[i].pAnimData->isStatic = 1; _vm->_mult->_objects[i].tick = 0; @@ -1162,23 +1161,18 @@ void Inter_v2::o2_pushVars() { varOff = _vm->_parse->parseVarIndex(); _vm->_global->_inter_execPtr++; - _variables->copyTo(varOff, _varStack + _varStackPos, - _varSizesStack + _varStackPos, - _vm->_global->_inter_animDataSize * 4); + _variables->copyTo(varOff, _varStack + _varStackPos, _vm->_global->_inter_animDataSize * 4); _varStackPos += _vm->_global->_inter_animDataSize * 4; _varStack[_varStackPos] = _vm->_global->_inter_animDataSize * 4; - _varSizesStack[_varStackPos] = _vm->_global->_inter_animDataSize * 4; } else { if (evalExpr(&varOff) != 20) _vm->_global->_inter_resVal = 0; memcpy(_varStack + _varStackPos, &_vm->_global->_inter_resVal, 4); - memcpy(_varSizesStack + _varStackPos, &_vm->_global->_inter_resVal, 4); _varStackPos += 4; _varStack[_varStackPos] = 4; - _varSizesStack[_varStackPos] = 4; } } } @@ -1186,19 +1180,15 @@ void Inter_v2::o2_pushVars() { void Inter_v2::o2_popVars() { byte count; int16 varOff; - int16 sizeV; - int16 sizeS; + int16 size; count = *_vm->_global->_inter_execPtr++; for (int i = 0; i < count; i++) { varOff = _vm->_parse->parseVarIndex(); - sizeV = _varStack[--_varStackPos]; - sizeS = _varSizesStack[_varStackPos]; - assert(sizeV == sizeS); + size = _varStack[--_varStackPos]; - _varStackPos -= sizeV; - _variables->copyFrom(varOff, _varStack + _varStackPos, - _varSizesStack + _varStackPos, sizeV); + _varStackPos -= size; + _variables->copyFrom(varOff, _varStack + _varStackPos, size); } } @@ -1934,7 +1924,7 @@ bool Inter_v2::o2_readData(OpFuncParams ¶ms) { size = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4; } - buf = _variables->getAddressOff8(dataVar, size); + buf = _variables->getAddressOff8(dataVar); if (_vm->_global->_inter_resStr[0] == 0) { WRITE_VAR(1, size); diff --git a/engines/gob/map_v2.cpp b/engines/gob/map_v2.cpp index bd9f5b3efc..db4f2075e1 100644 --- a/engines/gob/map_v2.cpp +++ b/engines/gob/map_v2.cpp @@ -56,12 +56,12 @@ void Map_v2::loadMapObjects(const char *avjFile) { uint32 passPos; var = _vm->_parse->parseVarIndex(); - variables = _vm->_inter->_variables->getAddressOff8(var, 0); + variables = _vm->_inter->_variables->getAddressOff8(var); id = _vm->_inter->load16(); if (id == -1) { - _passMap = (int8 *) _vm->_inter->_variables->getAddressOff8(var, 0); + _passMap = (int8 *) _vm->_inter->_variables->getAddressOff8(var); return; } @@ -105,7 +105,7 @@ void Map_v2::loadMapObjects(const char *avjFile) { tmpPos = mapData.pos(); mapData.seek(passPos); if ((variables != 0) && - (variables != _vm->_inter->_variables->getAddressOff8(0, 0))) { + (variables != _vm->_inter->_variables->getAddressOff8(0))) { _passMap = (int8 *) variables; mapHeight = _screenHeight / _tilesHeight; @@ -114,7 +114,7 @@ void Map_v2::loadMapObjects(const char *avjFile) { for (int i = 0; i < mapHeight; i++) { for (int j = 0; j < mapWidth; j++) setPass(j, i, mapData.readSByte()); - _vm->_inter->_variables->getAddressOff8(var + i * _passWidth, mapWidth); + _vm->_inter->_variables->getAddressOff8(var + i * _passWidth); } } mapData.seek(tmpPos); diff --git a/engines/gob/map_v4.cpp b/engines/gob/map_v4.cpp index 3a74c4b6aa..858e7972bc 100644 --- a/engines/gob/map_v4.cpp +++ b/engines/gob/map_v4.cpp @@ -54,7 +54,7 @@ void Map_v4::loadMapObjects(const char *avjFile) { uint32 passPos; var = _vm->_parse->parseVarIndex(); - variables = _vm->_inter->_variables->getAddressOff8(var, 0); + variables = _vm->_inter->_variables->getAddressOff8(var); id = _vm->_inter->load16(); @@ -62,7 +62,7 @@ void Map_v4::loadMapObjects(const char *avjFile) { warning("Woodruff Stub: loadMapObjects ID >= 65520"); return; } else if (id == -1) { - _passMap = (int8 *) _vm->_inter->_variables->getAddressOff8(var, 0); + _passMap = (int8 *) _vm->_inter->_variables->getAddressOff8(var); return; } @@ -121,7 +121,7 @@ void Map_v4::loadMapObjects(const char *avjFile) { tmpPos = mapData.pos(); mapData.seek(passPos); if ((variables != 0) && - (variables != _vm->_inter->_variables->getAddressOff8(0, 0))) { + (variables != _vm->_inter->_variables->getAddressOff8(0))) { _passMap = (int8 *) variables; mapHeight = _screenHeight / _tilesHeight; @@ -130,7 +130,7 @@ void Map_v4::loadMapObjects(const char *avjFile) { for (int i = 0; i < mapHeight; i++) { for (int j = 0; j < mapWidth; j++) setPass(j, i, mapData.readSByte()); - _vm->_inter->_variables->getAddressOff8(var + i * _passWidth, mapWidth); + _vm->_inter->_variables->getAddressOff8(var + i * _passWidth); } } mapData.seek(tmpPos); diff --git a/engines/gob/module.mk b/engines/gob/module.mk index 3cc16fa5fd..9111db9121 100644 --- a/engines/gob/module.mk +++ b/engines/gob/module.mk @@ -46,11 +46,6 @@ MODULE_OBJS := \ parse.o \ parse_v1.o \ parse_v2.o \ - saveload.o \ - saveload_v2.o \ - saveload_v3.o \ - saveload_v4.o \ - saveload_v6.o \ scenery.o \ scenery_v1.o \ scenery_v2.o \ @@ -63,6 +58,18 @@ MODULE_OBJS := \ demos/demoplayer.o \ demos/scnplayer.o \ demos/batplayer.o \ + save/savefile.o \ + save/savehandler.o \ + save/saveload.o \ + save/saveload_v2.o \ + save/saveload_v3.o \ + save/saveload_v4.o \ + save/saveload_v6.o \ + save/saveconverter.o \ + save/saveconverter_v2.o \ + save/saveconverter_v3.o \ + save/saveconverter_v4.o \ + save/saveconverter_v6.o \ sound/sound.o \ sound/sounddesc.o \ sound/pcspeaker.o \ diff --git a/engines/gob/parse.cpp b/engines/gob/parse.cpp index 4c949183e0..81a7da6389 100644 --- a/engines/gob/parse.cpp +++ b/engines/gob/parse.cpp @@ -44,7 +44,7 @@ int32 Parse::encodePtr(byte *ptr, int type) { offset = ptr - _vm->_game->_totFileData; break; case kInterVar: - offset = ptr - ((byte *) _vm->_inter->_variables->getAddressOff8(0, 0)); + offset = ptr - ((byte *) _vm->_inter->_variables->getAddressOff8(0)); break; case kResStr: offset = ptr - ((byte *) _vm->_global->_inter_resStr); @@ -64,7 +64,7 @@ byte *Parse::decodePtr(int32 n) { ptr = _vm->_game->_totFileData; break; case kInterVar: - ptr = (byte *) _vm->_inter->_variables->getAddressOff8(0, 0); + ptr = (byte *) _vm->_inter->_variables->getAddressOff8(0); break; case kResStr: ptr = (byte *) _vm->_global->_inter_resStr; diff --git a/engines/gob/parse_v1.cpp b/engines/gob/parse_v1.cpp index 427a2b5184..c993d6ca70 100644 --- a/engines/gob/parse_v1.cpp +++ b/engines/gob/parse_v1.cpp @@ -375,7 +375,7 @@ int16 Parse_v1::parseExpr(byte stopToken, byte *arg_2) { case OP_LOAD_VAR_STR: *operPtr = OP_LOAD_IMM_STR; temp = _vm->_inter->load16() * 4; - *valPtr = encodePtr(_vm->_inter->_variables->getAddressOff8(temp, 0), + *valPtr = encodePtr(_vm->_inter->_variables->getAddressOff8(temp), kInterVar); if (*_vm->_global->_inter_execPtr == 13) { _vm->_global->_inter_execPtr++; @@ -404,7 +404,7 @@ int16 Parse_v1::parseExpr(byte stopToken, byte *arg_2) { break; } *valPtr = encodePtr(_vm->_inter->_variables->getAddressOff8( - temp * 4 + offset * _vm->_global->_inter_animDataSize * 4, 0), + temp * 4 + offset * _vm->_global->_inter_animDataSize * 4), kInterVar); if (*_vm->_global->_inter_execPtr == 13) { _vm->_global->_inter_execPtr++; diff --git a/engines/gob/parse_v2.cpp b/engines/gob/parse_v2.cpp index 327638194e..e7f91650b5 100644 --- a/engines/gob/parse_v2.cpp +++ b/engines/gob/parse_v2.cpp @@ -554,7 +554,7 @@ int16 Parse_v2::parseExpr(byte stopToken, byte *arg_2) { *valPtr = (int16) READ_VARO_UINT16(varPos + temp * 2 + offset * 2); else if (operation == OP_ARRAY_STR) { *valPtr = encodePtr(_vm->_inter->_variables->getAddressOff8( - varPos + temp * 4 + offset * _vm->_global->_inter_animDataSize * 4, 0), + varPos + temp * 4 + offset * _vm->_global->_inter_animDataSize * 4), kInterVar); if (*_vm->_global->_inter_execPtr == 13) { _vm->_global->_inter_execPtr++; @@ -612,7 +612,7 @@ int16 Parse_v2::parseExpr(byte stopToken, byte *arg_2) { case OP_LOAD_VAR_STR: *operPtr = OP_LOAD_IMM_STR; temp = _vm->_inter->load16() * 4; - *valPtr = encodePtr(_vm->_inter->_variables->getAddressOff8(varPos + temp, 0), kInterVar); + *valPtr = encodePtr(_vm->_inter->_variables->getAddressOff8(varPos + temp), kInterVar); if (*_vm->_global->_inter_execPtr == 13) { _vm->_global->_inter_execPtr++; temp += parseValExpr(OP_END_MARKER); diff --git a/engines/gob/save/saveconverter.cpp b/engines/gob/save/saveconverter.cpp new file mode 100644 index 0000000000..4b24311e93 --- /dev/null +++ b/engines/gob/save/saveconverter.cpp @@ -0,0 +1,443 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/endian.h" +#include "common/savefile.h" + +#include "gob/gob.h" +#include "gob/save/saveconverter.h" +#include "gob/save/savefile.h" +#include "gob/save/savehandler.h" +#include "gob/helper.h" + +namespace Gob { + +SaveConverter::SaveConverter(GobEngine *vm, const char *fileName) : _vm(vm) { + _fileName = strdupcpy(fileName); + + _data = 0; + _stream = 0; +} + +SaveConverter::~SaveConverter() { + delete[] _fileName; + + delete _stream; + delete[] _data; +} + +void SaveConverter::clear() { + delete[] _data; + delete _stream; + + _data = 0; + _stream = 0; +} + +void SaveConverter::setFileName(const char *fileName) { + clear(); + + delete[] _fileName; + + _fileName = strdupcpy(fileName); +} + +Common::InSaveFile *SaveConverter::openSave() const { + if (!_fileName) + return 0; + + Common::SaveFileManager *saveMan = g_system->getSavefileManager(); + return saveMan->openForLoading(_fileName); +} + +void SaveConverter::displayWarning() const { + warning("Old save format detected, trying to convert. If this does not work, your " + "save is broken and can't be used anymore. Sorry for the inconvenience"); +} + +char *SaveConverter::getDescription(const char *fileName) { + setFileName(fileName); + return getDescription(); +} + +char *SaveConverter::getDescription() const { + Common::InSaveFile *save; + + // Test if it's an old savd + if (!isOldSave(&save) || !save) + return 0; + + char *desc = getDescription(*save); + + delete save; + return desc; +} + +uint32 SaveConverter::getActualSize(Common::InSaveFile **save) const { + Common::InSaveFile *saveFile = openSave(); + + if (!saveFile) + return false; + + // Is it a valid new save? + if (SaveContainer::isSave(*saveFile)) { + delete saveFile; + return false; + } + + int32 saveSize = saveFile->size(); + + if (saveSize <= 0) { + delete saveFile; + return 0; + } + + if (save) + *save = saveFile; + else + delete saveFile; + + return saveSize; +} + +bool SaveConverter::swapDataEndian(byte *data, const byte *sizes, uint32 count) { + if (!data || !sizes || (count == 0)) + return false; + + while (count-- > 0) { + if (*sizes == 3) // 32bit value (3 additional bytes) + *((uint32 *) data) = SWAP_BYTES_32(*((uint32 *) data)); + else if (*sizes == 1) // 16bit value (1 additional byte) + *((uint16 *) data) = SWAP_BYTES_16(*((uint16 *) data)); + else if (*sizes != 0) // else, it has to be an 8bit value + return false; + + count -= *sizes; + data += *sizes + 1; + sizes += *sizes + 1; + } + + return true; +} + +SavePartInfo *SaveConverter::readInfo(Common::SeekableReadStream &stream, + uint32 descLength, bool hasSizes) const { + + uint32 varSize = SaveHandler::getVarSize(_vm); + if (varSize == 0) + return 0; + + char *desc = getDescription(stream); + if (!desc) + return 0; + + // If it has sizes, skip them + if (hasSizes) + if (!stream.skip(descLength)) { + delete[] desc; + return 0; + } + + SavePartInfo *info = new SavePartInfo(descLength, (uint32) _vm->getGameType(), + 0, _vm->getEndianness(), varSize); + + info->setDesc(desc); + + delete[] desc; + + return info; +} + +byte *SaveConverter::readData(Common::SeekableReadStream &stream, + uint32 count, bool endian) const { + + byte *data = new byte[count]; + + // Read variable data + if (stream.read(data, count) != count) { + delete[] data; + return 0; + } + + /* Check the endianness. The old save data was always written + * as little endian, so we might need to swap the bytes. */ + + if (endian && (_vm->getEndianness() == kEndiannessBE)) { + // Big endian => swapping needed + + // Read variable sizes + byte *sizes = new byte[count]; + if (stream.read(sizes, count) != count) { + delete[] data; + delete[] sizes; + return 0; + } + + // Swap bytes + if (!swapDataEndian(data, sizes, count)) { + delete[] data; + delete[] sizes; + return 0; + } + + delete[] sizes; + + } else { + // Little endian => just skip the sizes part + + if (!stream.skip(count)) { + delete[] data; + return 0; + } + } + + return data; +} + +SavePartVars *SaveConverter::readVars(Common::SeekableReadStream &stream, + uint32 count, bool endian) const { + + byte *data = readData(stream, count, endian); + if (!data) + return 0; + + SavePartVars *vars = new SavePartVars(_vm, count); + + // Read variables into part + if (!vars->readFromRaw(data, count)) { + delete[] data; + delete vars; + return 0; + } + + delete[] data; + return vars; +} + +SavePartMem *SaveConverter::readMem(Common::SeekableReadStream &stream, + uint32 count, bool endian) const { + + byte *data = readData(stream, count, endian); + if (!data) + return 0; + + SavePartMem *mem = new SavePartMem(count); + + // Read mem into part + if (!mem->readFrom(data, 0, count)) { + delete[] data; + delete mem; + return 0; + } + + delete[] data; + return mem; +} + +SavePartSprite *SaveConverter::readSprite(Common::SeekableReadStream &stream, + uint32 width, uint32 height, bool palette) const { + + assert((width > 0) && (height > 0)); + + uint32 spriteSize = width * height; + + byte pal[768]; + if (palette) + if (stream.read(pal, 768) != 768) + return 0; + + byte *data = new byte[spriteSize]; + + // Read variable data + if (stream.read(data, spriteSize) != spriteSize) { + delete[] data; + return 0; + } + + SavePartSprite *sprite = new SavePartSprite(width, height); + + if (!sprite->readSpriteRaw(data, spriteSize)) { + delete[] data; + return 0; + } + + delete[] data; + + if (palette) + if (!sprite->readPalette(pal)) + return 0; + + return sprite; +} + +bool SaveConverter::createStream(SaveWriter &writer) { + // Allocate memory for the internal new save data + uint32 contSize = writer.getSize(); + _data = new byte[contSize]; + + // Save the newly created new save data + Common::MemoryWriteStream writeStream(_data, contSize); + if (!writer.save(writeStream)) + return false; + + // Create a reading stream upon that new save data + _stream = new Common::MemoryReadStream(_data, contSize); + + return true; +} + +/* Stream functions. If the new save data stream is available, redirect the stream + * operations to that stream. Normal stream error behaviour if not. */ + +bool SaveConverter::err() const { + if (!_data || !_stream) + return true; + + return _stream->err(); +} + +void SaveConverter::clearErr() { + if (!_data || !_stream) + return; + + _stream->clearErr(); +} + +bool SaveConverter::eos() const { + if (!_data || !_stream) + return true; + + return _stream->eos(); +} + +uint32 SaveConverter::read(void *dataPtr, uint32 dataSize) { + if (!_data || !_stream) + return 0; + + return _stream->read(dataPtr, dataSize); +} + +int32 SaveConverter::pos() const { + if (!_data || !_stream) + return -1; + + return _stream->pos(); +} + +int32 SaveConverter::size() const { + if (!_data || !_stream) + return -1; + + return _stream->size(); +} + +bool SaveConverter::seek(int32 offset, int whence) { + if (!_data || !_stream) + return false; + + return _stream->seek(offset, whence); +} + + +SaveConverter_Notes::SaveConverter_Notes(GobEngine *vm, uint32 notesSize, + const char *fileName) : SaveConverter(vm, fileName) { + + _size = notesSize; +} + +SaveConverter_Notes::~SaveConverter_Notes() { +} + +int SaveConverter_Notes::isOldSave(Common::InSaveFile **save) const { + if (_size == 0) + return 0; + + uint32 saveSize = getActualSize(save); + if (saveSize == 0) + return 0; + + // The size of the old save always follows that rule + if (saveSize == (_size * 2)) + return 1; + + // Not an old save, clean up + if (save) { + delete *save; + *save = 0; + } + + return 0; +} + +char *SaveConverter_Notes::getDescription(Common::SeekableReadStream &save) const { + return 0; +} + +bool SaveConverter_Notes::loadFail(SavePartVars *vars, Common::InSaveFile *save) { + delete vars; + delete save; + + clear(); + + return false; +} + +// Loads the old save by constructing a new save containing the old save's data +bool SaveConverter_Notes::load() { + if (_size == 0) + return false; + + Common::InSaveFile *save; + + // Test if it's an old savd + if (!isOldSave(&save) || !save) + return false; + + displayWarning(); + + SaveWriter writer(1, 0); + + SavePartVars *vars = readVars(*save, _size, false); + if (!vars) + return loadFail(0, save); + + // We don't need the save anymore + delete save; + + // Write all parts + if (!writer.writePart(0, vars)) + return loadFail(0, 0); + + // We don't need this anymore + delete vars; + + // Create the final read stream + if (!createStream(writer)) + return loadFail(0, 0); + + return true; +} + +} // End of namespace Gob diff --git a/engines/gob/save/saveconverter.h b/engines/gob/save/saveconverter.h new file mode 100644 index 0000000000..f40a2d4b40 --- /dev/null +++ b/engines/gob/save/saveconverter.h @@ -0,0 +1,206 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GOB_SAVE_SAVECONVERTER_H +#define GOB_SAVE_SAVECONVERTER_H + +#include "common/stream.h" + +namespace Gob { + +class GobEngine; +class SavePartInfo; +class SavePartVars; +class SavePartMem; +class SavePartSprite; +class SaveWriter; + +/** A wrapping stream class for old saves. */ +class SaveConverter : public Common::SeekableReadStream { +public: + SaveConverter(GobEngine *vm, const char *fileName = 0); + virtual ~SaveConverter(); + + /** Clear the converter. */ + virtual void clear(); + /** Set the filename on which to operate. */ + virtual void setFileName(const char *fileName); + + /** Is it actually an old save? */ + virtual int isOldSave(Common::InSaveFile **save = 0) const = 0; + /** Directly return the description without processing the whole save. */ + virtual char *getDescription(Common::SeekableReadStream &save) const = 0; + /** Load the whole save. */ + virtual bool load() = 0; + + /** Set the name and return the description. */ + char *getDescription(const char *fileName); + /** Get the current fileName's description. */ + char *getDescription() const; + + // Stream + virtual bool err() const; + virtual void clearErr(); + // ReadStream + virtual bool eos() const; + virtual uint32 read(void *dataPtr, uint32 dataSize); + // SeekableReadStream + virtual int32 pos() const; + virtual int32 size() const; + virtual bool seek(int32 offset, int whence = SEEK_SET); + +protected: + GobEngine *_vm; + + char *_fileName; + + byte *_data; + Common::MemoryReadStream *_stream; + + Common::InSaveFile *openSave() const; + + /** Write a warning to stdout to notify the user what's going on. */ + virtual void displayWarning() const; + + virtual uint32 getActualSize(Common::InSaveFile **save = 0) const; + + SavePartInfo *readInfo(Common::SeekableReadStream &stream, + uint32 descLength, bool hasSizes = true) const; + SavePartVars *readVars(Common::SeekableReadStream &stream, + uint32 count, bool endian) const; + SavePartMem *readMem(Common::SeekableReadStream &stream, + uint32 count, bool endian) const; + SavePartSprite *readSprite(Common::SeekableReadStream &stream, + uint32 width, uint32 height, bool palette) const; + + bool createStream(SaveWriter &writer); + + /** Swap the endianness of the complete data area. */ + static bool swapDataEndian(byte *data, const byte *sizes, uint32 count); + +private: + byte *readData(Common::SeekableReadStream &stream, + uint32 count, bool endian) const; +}; + +/** A wrapper for old notes saves. */ +class SaveConverter_Notes : public SaveConverter { +public: + SaveConverter_Notes(GobEngine *vm, uint32 notesSize, const char *fileName = 0); + ~SaveConverter_Notes(); + + int isOldSave(Common::InSaveFile **save = 0) const; + char *getDescription(Common::SeekableReadStream &save) const; + + bool load(); + +private: + uint32 _size; + + bool loadFail(SavePartVars *vars, Common::InSaveFile *save); +}; + +/** A wrapper for old v2-style saves (Gobliins 2, Ween: The Prophecy and Bargon Attack). */ +class SaveConverter_v2 : public SaveConverter { +public: + SaveConverter_v2(GobEngine *vm, const char *fileName = 0); + ~SaveConverter_v2(); + + int isOldSave(Common::InSaveFile **save = 0) const; + char *getDescription(Common::SeekableReadStream &save) const; + + bool load(); + +private: + static const uint32 kSlotCount = 15; + static const uint32 kSlotNameLength = 40; + + bool loadFail(SavePartInfo *info, SavePartVars *vars, + Common::InSaveFile *save); +}; + +/** A wrapper for old v3-style saves (Goblins 3 and Lost in Time). */ +class SaveConverter_v3 : public SaveConverter { +public: + SaveConverter_v3(GobEngine *vm, const char *fileName = 0); + ~SaveConverter_v3(); + + int isOldSave(Common::InSaveFile **save = 0) const; + char *getDescription(Common::SeekableReadStream &save) const; + + bool load(); + +private: + static const uint32 kSlotCount = 30; + static const uint32 kSlotNameLength = 40; + + bool loadFail(SavePartInfo *info, SavePartVars *vars, + SavePartSprite *sprite, Common::InSaveFile *save); + + void getScreenShotProps(int type, + bool &used, uint32 &width, uint32 &height); +}; + +/** A wrapper for old v4-style saves (Woodruff). */ +class SaveConverter_v4 : public SaveConverter { +public: + SaveConverter_v4(GobEngine *vm, const char *fileName = 0); + ~SaveConverter_v4(); + + int isOldSave(Common::InSaveFile **save = 0) const; + char *getDescription(Common::SeekableReadStream &save) const; + + bool load(); + +private: + static const uint32 kSlotCount = 60; + static const uint32 kSlotNameLength = 40; + + bool loadFail(SavePartInfo *info, SavePartVars *vars, + SavePartMem *props, Common::InSaveFile *save); +}; + +/** A wrapper for old v6-style saves (Urban Runner). */ +class SaveConverter_v6 : public SaveConverter { +public: + SaveConverter_v6(GobEngine *vm, const char *fileName = 0); + ~SaveConverter_v6(); + + int isOldSave(Common::InSaveFile **save = 0) const; + char *getDescription(Common::SeekableReadStream &save) const; + + bool load(); + +private: + static const uint32 kSlotCount = 15; + static const uint32 kSlotNameLength = 40; + + bool loadFail(SavePartInfo *info, SavePartVars *vars, + Common::InSaveFile *save); +}; + +} // End of namespace Gob + +#endif // GOB_SAVE_SAVECONVERTER_H diff --git a/engines/gob/save/saveconverter_v2.cpp b/engines/gob/save/saveconverter_v2.cpp new file mode 100644 index 0000000000..96ed949753 --- /dev/null +++ b/engines/gob/save/saveconverter_v2.cpp @@ -0,0 +1,135 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/endian.h" +#include "common/savefile.h" + +#include "gob/gob.h" +#include "gob/save/saveconverter.h" +#include "gob/save/savefile.h" +#include "gob/save/savehandler.h" + +namespace Gob { + +SaveConverter_v2::SaveConverter_v2(GobEngine *vm, const char *fileName) : + SaveConverter(vm, fileName) { +} + +SaveConverter_v2::~SaveConverter_v2() { +} + +int SaveConverter_v2::isOldSave(Common::InSaveFile **save) const { + uint32 varSize = SaveHandler::getVarSize(_vm); + if (varSize == 0) + return 0; + + uint32 saveSize = getActualSize(save); + if (saveSize == 0) + return 0; + + // The size of the old save always follows that rule + if (saveSize == (varSize * 2 + kSlotNameLength * 2)) + return 1; + + // Not an old save, clean up + if (save) { + delete *save; + *save = 0; + } + + return 0; +} + +char *SaveConverter_v2::getDescription(Common::SeekableReadStream &save) const { + char *desc = new char[kSlotNameLength]; + + // Read the description + if (save.read(desc, kSlotNameLength) != kSlotNameLength) { + delete desc; + return 0; + } + + return desc; +} + +bool SaveConverter_v2::loadFail(SavePartInfo *info, SavePartVars *vars, + Common::InSaveFile *save) { + + delete info; + delete vars; + delete save; + + clear(); + + return false; +} + +// Loads the old save by constructing a new save containing the old save's data +bool SaveConverter_v2::load() { + clear(); + + uint32 varSize = SaveHandler::getVarSize(_vm); + if (varSize == 0) + return false; + + Common::InSaveFile *save; + + // Test if it's an old savd + if (!isOldSave(&save) || !save) + return false; + + displayWarning(); + + SaveWriter writer(2, 0); + + SavePartInfo *info = readInfo(*save, kSlotNameLength); + if (!info) + return loadFail(0, 0, save); + + SavePartVars *vars = readVars(*save, varSize, true); + if (!vars) + return loadFail(info, 0, save); + + // We don't need the save anymore + delete save; + + // Write all parts + if (!writer.writePart(0, info)) + return loadFail(info, vars, 0); + if (!writer.writePart(1, vars)) + return loadFail(info, vars, 0); + + // We don't need those anymore + delete info; + delete vars; + + // Create the final read stream + if (!createStream(writer)) + return loadFail(0, 0, 0); + + return true; +} + +} // End of namespace Gob diff --git a/engines/gob/save/saveconverter_v3.cpp b/engines/gob/save/saveconverter_v3.cpp new file mode 100644 index 0000000000..d707268d9c --- /dev/null +++ b/engines/gob/save/saveconverter_v3.cpp @@ -0,0 +1,188 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/endian.h" +#include "common/savefile.h" + +#include "gob/gob.h" +#include "gob/save/saveconverter.h" +#include "gob/save/savefile.h" +#include "gob/save/savehandler.h" + +namespace Gob { + +SaveConverter_v3::SaveConverter_v3(GobEngine *vm, const char *fileName) : + SaveConverter(vm, fileName) { +} + +SaveConverter_v3::~SaveConverter_v3() { +} + +int SaveConverter_v3::isOldSave(Common::InSaveFile **save) const { + uint32 varSize = SaveHandler::getVarSize(_vm); + if (varSize == 0) + return 0; + + uint32 saveSize = getActualSize(save); + if (saveSize == 0) + return 0; + + // The size of the old save always follows one of these rules + if (saveSize == (varSize * 2 + kSlotNameLength + 1000)) + return 1; // No screenshot + if (saveSize == (varSize * 2 + kSlotNameLength + 1000 + 19968)) + return 2; // Big screenshot, Goblins 3 + if (saveSize == (varSize * 2 + kSlotNameLength + 1000 + 4768)) + return 3; // Small screenshot, Lost in Time + + // Not an old save, clean up + if (save) { + delete *save; + *save = 0; + } + + return 0; +} + +char *SaveConverter_v3::getDescription(Common::SeekableReadStream &save) const { + // The description starts at 1000 + if (!save.seek(1000)) + return 0; + + char *desc = new char[kSlotNameLength]; + + // Read the description + if (save.read(desc, kSlotNameLength) != kSlotNameLength) { + delete desc; + return 0; + } + + return desc; +} + +bool SaveConverter_v3::loadFail(SavePartInfo *info, SavePartVars *vars, + SavePartSprite *sprite, Common::InSaveFile *save) { + + delete info; + delete vars; + delete sprite; + delete save; + + clear(); + + return false; +} + +void SaveConverter_v3::getScreenShotProps(int type, + bool &used, uint32 &width, uint32 &height) { + + switch (type) { + case 2: + used = true; + width = 120; + height = 160; + break; + + case 3: + used = true; + width = 80; + height = 50; + break; + + default: + used = false; + width = 0; + height = 0; + break; + } +} + +// Loads the old save by constructing a new save containing the old save's data +bool SaveConverter_v3::load() { + clear(); + + uint32 varSize = SaveHandler::getVarSize(_vm); + if (varSize == 0) + return false; + + Common::InSaveFile *save; + + int type = isOldSave(&save); + + // Test if it's an old savd + if ((type == 0) || !save) + return false; + + displayWarning(); + + bool screenShot; + uint32 screenShotWidth; + uint32 screenShotHeight; + + getScreenShotProps(type, screenShot, screenShotWidth, screenShotHeight); + + SaveWriter writer(screenShot ? 3 : 2, 0); + + SavePartInfo *info = readInfo(*save, kSlotNameLength, false); + if (!info) + return loadFail(0, 0, 0, save); + + SavePartVars *vars = readVars(*save, varSize, true); + if (!vars) + return loadFail(info, 0, 0, save); + + if (screenShot) { + SavePartSprite *sprite = readSprite(*save, screenShotWidth, screenShotHeight, true); + + if (!sprite) + return loadFail(info, vars, 0, save); + + if (!writer.writePart(2, sprite)) + return loadFail(info, vars, sprite, save); + + delete sprite; + } + + // We don't need the save anymore + delete save; + + // Write all parts + if (!writer.writePart(0, info)) + return loadFail(info, vars, 0, 0); + if (!writer.writePart(1, vars)) + return loadFail(info, vars, 0, 0); + + // We don't need those anymore + delete info; + delete vars; + + // Create the final read stream + if (!createStream(writer)) + return loadFail(0, 0, 0, 0); + + return true; +} + +} // End of namespace Gob diff --git a/engines/gob/save/saveconverter_v4.cpp b/engines/gob/save/saveconverter_v4.cpp new file mode 100644 index 0000000000..23273446d1 --- /dev/null +++ b/engines/gob/save/saveconverter_v4.cpp @@ -0,0 +1,147 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/endian.h" +#include "common/savefile.h" + +#include "gob/gob.h" +#include "gob/save/saveconverter.h" +#include "gob/save/savefile.h" +#include "gob/save/savehandler.h" + +namespace Gob { + +SaveConverter_v4::SaveConverter_v4(GobEngine *vm, const char *fileName) : + SaveConverter(vm, fileName) { +} + +SaveConverter_v4::~SaveConverter_v4() { +} + +int SaveConverter_v4::isOldSave(Common::InSaveFile **save) const { + uint32 varSize = SaveHandler::getVarSize(_vm); + if (varSize == 0) + return 0; + + uint32 saveSize = getActualSize(save); + if (saveSize == 0) + return 0; + + // The size of the old save always follows that rule + if (saveSize == (varSize * 2 + kSlotNameLength + 1000 + 512000)) + return 1; + + // Not an old save, clean up + if (save) { + delete *save; + *save = 0; + } + + return 0; +} + +char *SaveConverter_v4::getDescription(Common::SeekableReadStream &save) const { + // The description starts at 1000 + if (!save.seek(1000)) + return 0; + + char *desc = new char[kSlotNameLength]; + + // Read the description + if (save.read(desc, kSlotNameLength) != kSlotNameLength) { + delete desc; + return 0; + } + + return desc; +} + +bool SaveConverter_v4::loadFail(SavePartInfo *info, SavePartVars *vars, + SavePartMem *props, Common::InSaveFile *save) { + + delete info; + delete vars; + delete props; + delete save; + + clear(); + + return false; +} + +// Loads the old save by constructing a new save containing the old save's data +bool SaveConverter_v4::load() { + clear(); + + uint32 varSize = SaveHandler::getVarSize(_vm); + if (varSize == 0) + return false; + + Common::InSaveFile *save; + + // Test if it's an old savd + if (!isOldSave(&save) || !save) + return false; + + displayWarning(); + + SaveWriter writer(3, 0); + + SavePartInfo *info = readInfo(*save, kSlotNameLength, false); + if (!info) + return loadFail(0, 0, 0, save); + + SavePartVars *vars = readVars(*save, varSize, true); + if (!vars) + return loadFail(info, 0, 0, save); + + SavePartMem *props = readMem(*save, 256000, true); + if (!props) + return loadFail(info, vars, 0, save); + + // We don't need the save anymore + delete save; + + // Write all parts + if (!writer.writePart(0, info)) + return loadFail(info, vars, props, 0); + if (!writer.writePart(1, vars)) + return loadFail(info, vars, props, 0); + if (!writer.writePart(2, props)) + return loadFail(info, vars, props, 0); + + // We don't need those anymore + delete info; + delete vars; + delete props; + + // Create the final read stream + if (!createStream(writer)) + return loadFail(0, 0, 0, 0); + + return true; +} + +} // End of namespace Gob diff --git a/engines/gob/save/saveconverter_v6.cpp b/engines/gob/save/saveconverter_v6.cpp new file mode 100644 index 0000000000..01818e8191 --- /dev/null +++ b/engines/gob/save/saveconverter_v6.cpp @@ -0,0 +1,135 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/endian.h" +#include "common/savefile.h" + +#include "gob/gob.h" +#include "gob/save/saveconverter.h" +#include "gob/save/savefile.h" +#include "gob/save/savehandler.h" + +namespace Gob { + +SaveConverter_v6::SaveConverter_v6(GobEngine *vm, const char *fileName) : + SaveConverter(vm, fileName) { +} + +SaveConverter_v6::~SaveConverter_v6() { +} + +int SaveConverter_v6::isOldSave(Common::InSaveFile **save) const { + uint32 varSize = SaveHandler::getVarSize(_vm); + if (varSize == 0) + return 0; + + uint32 saveSize = getActualSize(save); + if (saveSize == 0) + return 0; + + // The size of the old save always follows that rule + if (saveSize == (varSize * 2 + kSlotNameLength * 2)) + return 1; + + // Not an old save, clean up + if (save) { + delete *save; + *save = 0; + } + + return 0; +} + +char *SaveConverter_v6::getDescription(Common::SeekableReadStream &save) const { + char *desc = new char[kSlotNameLength]; + + // Read the description + if (save.read(desc, kSlotNameLength) != kSlotNameLength) { + delete desc; + return 0; + } + + return desc; +} + +bool SaveConverter_v6::loadFail(SavePartInfo *info, SavePartVars *vars, + Common::InSaveFile *save) { + + delete info; + delete vars; + delete save; + + clear(); + + return false; +} + +// Loads the old save by constructing a new save containing the old save's data +bool SaveConverter_v6::load() { + clear(); + + uint32 varSize = SaveHandler::getVarSize(_vm); + if (varSize == 0) + return false; + + Common::InSaveFile *save; + + // Test if it's an old savd + if (!isOldSave(&save) || !save) + return false; + + displayWarning(); + + SaveWriter writer(2, 0); + + SavePartInfo *info = readInfo(*save, kSlotNameLength); + if (!info) + return loadFail(0, 0, save); + + SavePartVars *vars = readVars(*save, varSize, true); + if (!vars) + return loadFail(info, 0, save); + + // We don't need the save anymore + delete save; + + // Write all parts + if (!writer.writePart(0, info)) + return loadFail(info, vars, 0); + if (!writer.writePart(1, vars)) + return loadFail(info, vars, 0); + + // We don't need those anymore + delete info; + delete vars; + + // Create the final read stream + if (!createStream(writer)) + return loadFail(0, 0, 0); + + return true; +} + +} // End of namespace Gob diff --git a/engines/gob/save/savefile.cpp b/engines/gob/save/savefile.cpp new file mode 100644 index 0000000000..0f7ebfd0bf --- /dev/null +++ b/engines/gob/save/savefile.cpp @@ -0,0 +1,979 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/util.h" +#include "common/endian.h" +#include "common/system.h" +#include "common/savefile.h" + +#include "gob/gob.h" +#include "gob/save/savefile.h" +#include "gob/video.h" +#include "gob/helper.h" +#include "gob/inter.h" +#include "gob/variables.h" + +namespace Gob { + +static inline bool flushStream(Common::WriteStream &stream) { + // Flush and check for errors + + if (!stream.flush()) + return false; + if (stream.err()) + return false; + + return true; +} + +SaveHeader::SaveHeader(uint32 type, uint32 version, uint32 size) { + _type = type; + _version = version; + _size = size; +} + +bool SaveHeader::read(Common::ReadStream &stream) { + // Read the header and verify the global IDs + if (stream.readUint32BE() != kID1) + return false; + if (stream.readUint32BE() != kID2) + return false; + + _type = stream.readUint32BE(); + _version = stream.readUint32LE(); + _size = stream.readUint32LE(); + + return !stream.err(); +} + +bool SaveHeader::verify(Common::ReadStream &stream) const { + // Compare the header with the stream's content + + if (stream.readUint32BE() != kID1) + return false; + if (stream.readUint32BE() != kID2) + return false; + if (stream.readUint32BE() != _type) + return false; + if (stream.readUint32LE() != _version) + return false; + if (stream.readUint32LE() != _size) + return false; + + return !stream.err(); +} + +bool SaveHeader::verifyReadSize(Common::ReadStream &stream) { + // Compare the header with the stream's content, expect for the size + + if (stream.readUint32BE() != kID1) + return false; + if (stream.readUint32BE() != kID2) + return false; + if (stream.readUint32BE() != _type) + return false; + if (stream.readUint32LE() != _version) + return false; + + // Read the size out of the stream instead + _size = stream.readUint32LE(); + + return !stream.err(); +} + +bool SaveHeader::write(Common::WriteStream &stream) const { + stream.writeUint32BE(kID1); + stream.writeUint32BE(kID2); + stream.writeUint32BE(_type); + stream.writeUint32LE(_version); + stream.writeUint32LE(_size); + + return flushStream(stream); +} + +uint32 SaveHeader::getType() const { + return _type; +} + +uint32 SaveHeader::getVersion() const { + return _version; +} + +uint32 SaveHeader::getSize() const { + return _size; +} + +void SaveHeader::setType(uint32 type) { + _type = type; +} + +void SaveHeader::setVersion(uint32 version) { + _version = version; +} + +void SaveHeader::setSize(uint32 size) { + _size = size; +} + +SavePart::SavePart() { +} + +SavePart::~SavePart() { +} + +uint32 SavePart::getSize() const { + // A part's size is the content's size plus the header's size + return _header.getSize() + SaveHeader::kSize; +} + +SavePartMem::SavePartMem(uint32 size) : SavePart(), _size(size) { + _header.setType(kID); + _header.setVersion(kVersion); + _header.setSize(size); + + _data = new byte[size]; +} + +SavePartMem::~SavePartMem() { + delete[] _data; +} + +bool SavePartMem::read(Common::ReadStream &stream) { + if (!_header.verify(stream)) + return false; + + if (stream.read(_data, _size) != _size) + return false; + + return !stream.err(); +} + +bool SavePartMem::write(Common::WriteStream &stream) const { + if (!_header.write(stream)) + return false; + + if (stream.write(_data, _size) != _size) + return false; + + return flushStream(stream); +} + +bool SavePartMem::readFrom(const byte *data, uint32 offset, uint32 size) { + if ((offset + size) > _size) + return false; + + memcpy(_data + offset, data, size); + + return true; +} + +bool SavePartMem::writeInto(byte *data, uint32 offset, uint32 size) const { + if ((offset + size) > _size) + return false; + + memcpy(data, _data + offset, size); + + return true; +} + +SavePartVars::SavePartVars(GobEngine *vm, uint32 size) : SavePart(), _size(size), _vm(vm) { + _header.setType(kID); + _header.setVersion(kVersion); + _header.setSize(size); + + _data = new byte[size]; +} + +SavePartVars::~SavePartVars() { + delete[] _data; +} + +bool SavePartVars::read(Common::ReadStream &stream) { + if (!_header.verify(stream)) + return false; + + if (stream.read(_data, _size) != _size) + return false; + + return !stream.err(); +} + +bool SavePartVars::write(Common::WriteStream &stream) const { + if (!_header.write(stream)) + return false; + + if (stream.write(_data, _size) != _size) + return false; + + return flushStream(stream); +} + +bool SavePartVars::readFrom(uint32 var, uint32 offset, uint32 size) { + if (!_vm->_inter->_variables) + return false; + + if ((offset + size) > _size) + return false; + + // Get raw variables + return _vm->_inter->_variables->copyTo(var, _data + offset, size); +} + +bool SavePartVars::readFromRaw(const byte *data, uint32 size) { + if (size != _size) + return false; + + memcpy(_data, data, size); + return true; +} + +bool SavePartVars::writeInto(uint32 var, uint32 offset, uint32 size) const { + if (!_vm->_inter->_variables) + return false; + + if ((offset + size) > _size) + return false; + + // Write raw variables + if (!_vm->_inter->_variables->copyFrom(var, _data + offset, size)) + return false; + + return true; +} + +SavePartSprite::SavePartSprite(uint32 width, uint32 height) { + assert((width > 0) && (height > 0)); + + _width = width; + _height = height; + + _header.setType(kID); + _header.setVersion(kVersion); + // width + height + sprite + palette + _header.setSize(4 + 4 + _width * _height + 768); + + _dataSprite = new byte[_width * _height]; + _dataPalette = new byte[768]; + + memset(_dataSprite, 0, _width * _height); + memset(_dataPalette, 0, 768); +} + +SavePartSprite::~SavePartSprite() { + delete[] _dataSprite; + delete[] _dataPalette; +} + +bool SavePartSprite::read(Common::ReadStream &stream) { + if (!_header.verify(stream)) + return false; + + // The sprite's dimensions have to fit + if (stream.readUint32LE() != _width) + return false; + if (stream.readUint32LE() != _height) + return false; + + // Sprite data + if (stream.read(_dataSprite, _width * _height) != (_width * _height)) + return false; + + // Palette data + if (stream.read(_dataPalette, 768) != 768) + return false; + + return !stream.err(); +} + +bool SavePartSprite::write(Common::WriteStream &stream) const { + if (!_header.write(stream)) + return false; + + // The sprite's dimensions + stream.writeUint32LE(_width); + stream.writeUint32LE(_height); + + // Sprite data + if (stream.write(_dataSprite, _width * _height) != (_width * _height)) + return false; + + // Palette data + if (stream.write(_dataPalette, 768) != 768) + return false; + + return flushStream(stream); +} + +bool SavePartSprite::readPalette(const byte *palette) { + memcpy(_dataPalette, palette, 768); + + return true; +} + +bool SavePartSprite::readSprite(const SurfaceDesc *sprite) { + if (!sprite) + return false; + + // The sprite's dimensions have to fit + if (((uint32) sprite->getWidth()) != _width) + return false; + if (((uint32) sprite->getHeight()) != _height) + return false; + + memcpy(_dataSprite, sprite->getVidMem(), _width * _height); + + return true; +} + +bool SavePartSprite::readSpriteRaw(const byte *data, uint32 size) { + if (size != (_width * _height)) + return false; + + memcpy(_dataSprite, data, size); + return true; +} + +bool SavePartSprite::writePalette(byte *palette) const { + memcpy(palette, _dataPalette, 768); + + return true; +} + +bool SavePartSprite::writeSprite(SurfaceDesc *sprite) const { + if (!sprite) + return false; + + // The sprite's dimensions have to fit + if (((uint32) sprite->getWidth()) != _width) + return false; + if (((uint32) sprite->getHeight()) != _height) + return false; + + memcpy(sprite->getVidMem(), _dataSprite, _width * _height); + + return true; +} + +SavePartInfo::SavePartInfo(uint32 descMaxLength, uint32 gameID, + uint32 gameVersion, byte endian, uint32 varCount) { + + _header.setType(kID); + _header.setVersion(kVersion); + // descMaxLength + gameID + gameVersion + endian + varCount + _header.setSize(descMaxLength + 4 + 4 + 4 + 1 + 4); + + _descMaxLength = descMaxLength; + _gameID = gameID; + _gameVersion = gameVersion; + _endian = endian; + _varCount = varCount; + + _desc = new char[_descMaxLength + 1]; + memset(_desc, 0, _descMaxLength + 1); +} + +SavePartInfo::~SavePartInfo() { + delete[] _desc; +} + +const char *SavePartInfo::getDesc() const { + return _desc; +} + +uint32 SavePartInfo::getDescMaxLength() const { + return _descMaxLength; +} + +void SavePartInfo::setVarCount(uint32 varCount) { + _varCount = varCount; +} + +void SavePartInfo::setDesc(const char *desc) { + if (!desc) { + memset(_desc, 0, _descMaxLength + 1); + return; + } + + uint32 n = MIN<uint32>(strlen(desc), _descMaxLength); + + // Copy the description and fill with 0 + memcpy(_desc, desc, n); + memset(_desc + n, 0, _descMaxLength + 1 - n); +} + +void SavePartInfo::setDesc(const byte *desc, uint32 size) { + if (!desc || !size) { + memset(_desc, 0, _descMaxLength + 1); + return; + } + + uint32 n = MIN<uint32>(size, _descMaxLength); + memcpy(_desc, desc, n); + memset(_desc + n, 0, _descMaxLength + 1 - n); +} + +bool SavePartInfo::read(Common::ReadStream &stream) { + if (!_header.verify(stream)) + return false; + + if (stream.readUint32LE() != _gameID) + return false; + if (stream.readUint32LE() != _gameVersion) + return false; + if (stream.readByte() != _endian) + return false; + if (stream.readUint32LE() != _varCount) + return false; + if (stream.readUint32LE() != _descMaxLength) + return false; + + if (stream.read(_desc, _descMaxLength) != _descMaxLength) + return false; + + _desc[_descMaxLength] = 0; + + return !stream.err(); +} + +bool SavePartInfo::write(Common::WriteStream &stream) const { + if (!_header.write(stream)) + return false; + + stream.writeUint32LE(_gameID); + stream.writeUint32LE(_gameVersion); + stream.writeByte(_endian); + stream.writeUint32LE(_varCount); + stream.writeUint32LE(_descMaxLength); + + if (stream.write(_desc, _descMaxLength) != _descMaxLength) + return false; + + return flushStream(stream); +} + +SaveContainer::Part::Part(uint32 s) { + size = s; + data = new byte[size]; +} + +SaveContainer::Part::~Part() { + delete[] data; +} + +Common::WriteStream *SaveContainer::Part::createWriteStream() { + return new Common::MemoryWriteStream(data, size); +} + +Common::ReadStream *SaveContainer::Part::createReadStream() const { + return new Common::MemoryReadStream(data, size); +} + +SaveContainer::SaveContainer(uint32 partCount, uint32 slot) { + assert(partCount > 0); + + _slot = slot; + _partCount = partCount; + + _parts.resize(partCount); + for (PartIterator it = _parts.begin(); it != _parts.end(); ++it) + *it = 0; + + _header.setType(kID); + _header.setVersion(kVersion); + _header.setSize(4); // uint32 # of parts +} + +SaveContainer::~SaveContainer() { + clear(); +} + +uint32 SaveContainer::getSlot() const { + return _slot; +} + +uint32 SaveContainer::getSize() const { + return _header.getSize() + SaveHeader::kSize; +} + +bool SaveContainer::hasAllParts() const { + for (PartConstIterator it = _parts.begin(); it != _parts.end(); ++it) + if (!*it) + return false; + + return true; +} + +uint32 SaveContainer::calcSize() const { + uint32 size = 4; // uint32 # of parts + + for (PartConstIterator it = _parts.begin(); it != _parts.end(); ++it) + if (*it) + // uint32 part size + size += (*it)->size + 4; + + return size; +} + +void SaveContainer::clear() { + for (PartIterator it = _parts.begin(); it != _parts.end(); ++it) { + Part *&p = *it; + + delete p; + p = 0; + } +} + +bool SaveContainer::writePart(uint32 partN, const SavePart *part) { + // Sanity checks + if (!part) + return false; + if (partN >= _partCount) + return false; + + Part *&p = _parts[partN]; + + delete p; + // Create the part + p = new Part(part->getSize()); + + Common::WriteStream *pStream = p->createWriteStream(); + + // Write + if (!part->write(*pStream)) { + delete p; + p = 0; + + delete pStream; + return false; + } + + delete pStream; + + // Update size + _header.setSize(calcSize()); + + return true; +} + +bool SaveContainer::readPart(uint32 partN, SavePart *part) const { + // Sanity checks + if (!part) + return false; + if (partN >= _partCount) + return false; + + const Part * const &p = _parts[partN]; + + // Check if the part actually exists + if (!p) + return false; + + Common::ReadStream *pStream = p->createReadStream(); + + // Read + if (!part->read(*pStream)) { + delete pStream; + return false; + } + + delete pStream; + return true; +} + +bool SaveContainer::readPartHeader(uint32 partN, SaveHeader *header) const { + // Sanity checks + if (!header) + return false; + if (partN >= _partCount) + return false; + + const Part * const &p = _parts[partN]; + + // Check if the part actually exists + if (!p) + return false; + + Common::ReadStream *pStream = p->createReadStream(); + + // Read + if (!header->read(*pStream)) { + delete pStream; + return false; + } + + delete pStream; + return true; +} + +bool SaveContainer::read(Common::ReadStream &stream) { + // Verify the header and get the container's size + if (!_header.verifyReadSize(stream)) + return false; + + // The part count has to be correct + if (stream.readUint32LE() != _partCount) + return false; + + // Iterate over all parts + for (PartIterator it = _parts.begin(); it != _parts.end(); ++it) { + // Read the size + uint32 size = stream.readUint32LE(); + + if (stream.err()) { + clear(); + return false; + } + + Part *&p = *it; + + delete p; + // Create a suitable part + p = new Part(size); + } + + // Update size + _header.setSize(calcSize()); + + // Iterate over all parts + for (PartIterator it = _parts.begin(); it != _parts.end(); ++it) { + Part *&p = *it; + + // Read the part + if (stream.read(p->data, p->size) != p->size) { + clear(); + return false; + } + } + + return !stream.err(); +} + +bool SaveContainer::write(Common::WriteStream &stream) const { + // Write the header + if (!_header.write(stream)) + return false; + + // Write the part count + stream.writeUint32LE(_partCount); + + // Iterate over all parts + for (PartConstIterator it = _parts.begin(); it != _parts.end(); ++it) { + // Part doesn't actually exist => error + if (!*it) + return false; + + // Write the part's size + stream.writeUint32LE((*it)->size); + } + + if (!flushStream(stream)) + return false; + + // Iterate over all parts + for (PartConstIterator it = _parts.begin(); it != _parts.end(); ++it) { + Part * const &p = *it; + + // Write the part + if (stream.write(p->data, p->size) != p->size) + return false; + } + + return flushStream(stream); +} + +Common::Array<SaveContainer::PartInfo> *SaveContainer::getPartsInfo(Common::SeekableReadStream &stream) { + Common::Array<PartInfo> *parts = 0; + + // Remember the stream's position to seek back to + uint32 startPos = stream.pos(); + + SaveHeader header; + + header.setType(kID); + header.setVersion(kVersion); + + // Verify the header + if (!header.verifyReadSize(stream)) { + // Seek back + stream.seek(startPos); + return 0; + } + + // Read the part count + uint32 partCount = stream.readUint32LE(); + + // Create a part information array + parts = new Common::Array<PartInfo>; + parts->resize(partCount); + + // Read all part sizes + for (uint32 i = 0; i < partCount; i++) + (*parts)[i].size = stream.readUint32LE(); + + // Iterate over all parts + for (uint32 i = 0; i < partCount; i++) { + // The part's offset (from the starting point of the stream) + (*parts)[i].offset = stream.pos() - startPos; + + SaveHeader partHeader; + + // Read the header + if (!partHeader.read(stream)) { + // Seek back + stream.seek(startPos); + delete parts; + return 0; + } + + // Fill in the ID + (*parts)[i].id = partHeader.getType(); + + // Skip the part's content + stream.skip(partHeader.getSize()); + } + + if (stream.err()) { + delete parts; + parts = 0; + } + + // Seek back + stream.seek(startPos); + + return parts; +} + +bool SaveContainer::isSave(Common::SeekableReadStream &stream) { + // Remember the stream's position to seek back to + uint32 startPos = stream.pos(); + + SaveHeader header; + + header.setType(kID); + header.setVersion(kVersion); + + bool result = header.verifyReadSize(stream); + + // Seek back + stream.seek(startPos); + + return result; +} + + +SaveReader::SaveReader(uint32 partCount, uint32 slot, const char *fileName) : + SaveContainer(partCount, slot) { + + _fileName = strdupcpy(fileName); + _stream = 0; + + _loaded = false; +} + +SaveReader::SaveReader(uint32 partCount, uint32 slot, Common::SeekableReadStream &stream) : + SaveContainer(partCount, slot) { + + _fileName = 0; + _stream = &stream; + + _loaded = false; +} + +SaveReader::~SaveReader() { + delete[] _fileName; +} + +// Open the save and read it +bool SaveReader::load() { + + Common::InSaveFile *in = 0; + Common::SeekableReadStream *stream; + + if (_fileName) { + in = openSave(); + + if (!in) + return false; + + stream = in; + } else if (_stream) + stream = _stream; + else + return false; + + if (!SaveContainer::read(*stream)) { + delete in; + return false; + } + + delete in; + _loaded = true; + return true; +} + +bool SaveReader::readPartHeader(uint32 partN, SaveHeader *header) const { + // The save has to be loaded + if (!_loaded) + return false; + + return SaveContainer::readPartHeader(partN, header); +} + +bool SaveReader::readPart(uint32 partN, SavePart *part) const { + // The save has to be loaded + if (!_loaded) + return false; + + if (!SaveContainer::readPart(partN, part)) + return false; + + return true; +} + +Common::InSaveFile *SaveReader::openSave(const char *fileName) { + if (!fileName) + return 0; + + Common::SaveFileManager *saveMan = g_system->getSavefileManager(); + return saveMan->openForLoading(fileName); +} + +Common::InSaveFile *SaveReader::openSave() { + return openSave(_fileName); +} + +bool SaveReader::getInfo(Common::SeekableReadStream &stream, SavePartInfo &info) { + // Remeber the stream's starting position to seek back to + uint32 startPos = stream.pos(); + + // Get parts' basic information + Common::Array<SaveContainer::PartInfo> *partsInfo = getPartsInfo(stream); + + // No parts => fail + if (!partsInfo) { + stream.seek(startPos); + return false; + } + + bool result = false; + // Iterate over all parts + for (Common::Array<SaveContainer::PartInfo>::iterator it = partsInfo->begin(); + it != partsInfo->end(); ++it) { + + // Check for the info part + if (it->id == SavePartInfo::kID) { + if (!stream.seek(it->offset)) + break; + + // Read it + result = info.read(stream); + break; + } + } + + stream.seek(startPos); + + delete partsInfo; + return result; +} + +bool SaveReader::getInfo(const char *fileName, SavePartInfo &info) { + Common::InSaveFile *in = openSave(fileName); + + if (!in) + return false; + + bool result = getInfo(*in, info); + + delete in; + + return result; +} + +SaveWriter::SaveWriter(uint32 partCount, uint32 slot, const char *fileName) : + SaveContainer(partCount, slot) { + + _fileName = strdupcpy(fileName); +} + +SaveWriter::~SaveWriter() { + delete[] _fileName; +} + +bool SaveWriter::writePart(uint32 partN, const SavePart *part) { + // Write the part + if (!SaveContainer::writePart(partN, part)) + return false; + + // If all parts have been written, save and clear + if (hasAllParts() && canSave()) { + if (save()) { + clear(); + return true; + } + + return false; + } + + return true; +} + +bool SaveWriter::save(Common::WriteStream &stream) { + return SaveContainer::write(stream); +} + +bool SaveWriter::save() { + Common::OutSaveFile *out = openSave(); + + if (!out) + return false; + + bool success = save(*out); + + delete out; + + return success; +} + +bool SaveWriter::canSave() const { + if (!_fileName) + return false; + + return true; +} + +Common::OutSaveFile *SaveWriter::openSave(const char *fileName) { + if (!fileName) + return 0; + + Common::SaveFileManager *saveMan = g_system->getSavefileManager(); + return saveMan->openForSaving(fileName); +} + +Common::OutSaveFile *SaveWriter::openSave() { + return openSave(_fileName); +} + +} // End of namespace Gob diff --git a/engines/gob/save/savefile.h b/engines/gob/save/savefile.h new file mode 100644 index 0000000000..a263d97b0e --- /dev/null +++ b/engines/gob/save/savefile.h @@ -0,0 +1,347 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GOB_SAVE_SAVEFILE_H +#define GOB_SAVE_SAVEFILE_H + +#include "common/endian.h" +#include "common/array.h" +#include "common/savefile.h" + +namespace Gob { + +class GobEngine; +class SurfaceDesc; + +/** A class wrapping a save part header. + * + * A save part header consists of 4 fields: + * ID : The 8 character ID \0SCVMGOB + * Type : The 4 character ID for this part's type + * Version : This part's version. Each type has its own version counter + * Size : The size of the contents, i.e. excluding this header +*/ +class SaveHeader { +public: + /** The size of the header. */ + static const int kSize = 20; + static const uint32 kID1 = MKID_BE('\0SCV'); + static const uint32 kID2 = MKID_BE('MGOB'); + + SaveHeader(uint32 type = 0, uint32 version = 0, uint32 size = 0); + + /** Read the header out of a stream into this class. */ + bool read(Common::ReadStream &stream); + /** Read the header out of a stream and checks it against this class's contents. */ + bool verify(Common::ReadStream &stream) const; + /** Read the header out of a stream and checks it against this class's contents, + * but read the size field instead. + */ + bool verifyReadSize(Common::ReadStream &stream); + /** Write this class's contents into a stream. */ + bool write(Common::WriteStream &stream) const; + + uint32 getType() const; + uint32 getVersion() const; + uint32 getSize() const; + + void setType(uint32 type); + void setVersion(uint32 version); + void setSize(uint32 size); + +private: + /** An ID specifying the part's type. */ + uint32 _type; + /** The part's version. */ + uint32 _version; + /** The size of the contents. */ + uint32 _size; +}; + +/** An abstract class for a part in a save file. */ +class SavePart { +public: + SavePart(); + virtual ~SavePart(); + + /** Return the total size of the part. */ + virtual uint32 getSize() const; + + /** Read the part (with header) out of the stream. */ + virtual bool read(Common::ReadStream &stream) = 0; + /** Write the part (with header) into the stream. */ + virtual bool write(Common::WriteStream &stream) const = 0; + +protected: + SaveHeader _header; +}; + +/** A save part consisting of plain memory. */ +class SavePartMem : public SavePart { +public: + static const uint32 kVersion = 1; + static const uint32 kID = MKID_BE('PMEM'); + + SavePartMem(uint32 size); + ~SavePartMem(); + + bool read(Common::ReadStream &stream); + bool write(Common::WriteStream &stream) const; + + /** Read size bytes of data into the part at the specified offset. */ + bool readFrom(const byte *data, uint32 offset, uint32 size); + /** Write size bytes of the part at the specified offset int data. */ + bool writeInto(byte *data, uint32 offset, uint32 size) const; + +private: + uint32 _size; + byte *_data; +}; + +/** A save part holding script variables. */ +class SavePartVars : public SavePart { +public: + static const uint32 kVersion = 1; + static const uint32 kID = MKID_BE('VARS'); + + SavePartVars(GobEngine *vm, uint32 size); + ~SavePartVars(); + + bool read(Common::ReadStream &stream); + bool write(Common::WriteStream &stream) const; + + /** Read size bytes of variables starting at var into the part at the specified offset. */ + bool readFrom(uint32 var, uint32 offset, uint32 size); + /** Write size bytes of the part at the specified offset into the variable starting at var. */ + bool writeInto(uint32 var, uint32 offset, uint32 size) const; + + /** Read size bytes of raw data into the part. */ + bool readFromRaw(const byte *data, uint32 size); + +private: + GobEngine *_vm; + + uint32 _size; + byte *_data; +}; + +/** A save part holding a sprite. */ +class SavePartSprite : public SavePart { +public: + static const uint32 kVersion = 1; + static const uint32 kID = MKID_BE('SPRT'); + + SavePartSprite(uint32 width, uint32 height); + ~SavePartSprite(); + + bool read(Common::ReadStream &stream); + bool write(Common::WriteStream &stream) const; + + /** Read a palette into the part. */ + bool readPalette(const byte *palette); + /** Read a sprite into the part. */ + bool readSprite(const SurfaceDesc *sprite); + + /** Read size bytes of raw data into the sprite. */ + bool readSpriteRaw(const byte *data, uint32 size); + + /** Write a palette out of the part. */ + bool writePalette(byte *palette) const; + /** Write a sprite out of the part. */ + bool writeSprite(SurfaceDesc *sprite) const; + +private: + uint32 _width; + uint32 _height; + + byte *_dataSprite; + byte *_dataPalette; +}; + +/** A save part containing informations about the save's game. */ +class SavePartInfo : public SavePart { +public: + static const uint32 kVersion = 1; + static const uint32 kID = MKID_BE('INFO'); + + /** The constructor. + * + * @param descMaxLength The maximal number of bytes that fit into the description. + * @param gameID An ID for the game (Gob1, Gob2, Gob3, ...). + * @param gameVersion An ID for game specific versioning + * @param endian Endianness of the platform the game originally ran on. + * @param varCount The number of script variables. + */ + SavePartInfo(uint32 descMaxLength, uint32 gameID, + uint32 gameVersion, byte endian, uint32 varCount); + ~SavePartInfo(); + + /** Return the save's description. */ + const char *getDesc() const; + /** Return the description's maximal length. */ + uint32 getDescMaxLength() const; + + /** Set the variable count. */ + void setVarCount(uint32 varCount); + /** Set the save's description. */ + void setDesc(const char *desc = 0); + /** Set the save's description. */ + void setDesc(const byte *desc, uint32 size); + + bool read(Common::ReadStream &stream); + bool write(Common::WriteStream &stream) const; + +private: + char *_desc; + uint32 _descMaxLength; + uint32 _gameID; + uint32 _gameVersion; + uint32 _varCount; + byte _endian; +}; + +/** A container for several save parts. */ +class SaveContainer { +public: + static const uint32 kVersion = 1; + static const uint32 kID = MKID_BE('CONT'); + + /** The constructor. + * + * @param partCount The number parts this container shall hold. + * @param slot The save slot this save's for. + */ + SaveContainer(uint32 partCount, uint32 slot); + ~SaveContainer(); + + uint32 getSlot() const; + uint32 getSize() const; + + /** All parts filled? */ + bool hasAllParts() const; + + /** Empty all parts. */ + void clear(); + + /** Write a SavePart into the container's part. */ + bool writePart(uint32 partN, const SavePart *part); + /** Read the container's part's content into a SavePart. */ + bool readPart(uint32 partN, SavePart *part) const; + /** Read only the container's part's header. */ + bool readPartHeader(uint32 partN, SaveHeader *header) const; + + /** Checks if the stream is a valid save container. */ + static bool isSave(Common::SeekableReadStream &stream); + +protected: + /** A part. */ + struct Part { + uint32 size; + byte *data; + + Part(uint32 s); + ~Part(); + + Common::WriteStream *createWriteStream(); + Common::ReadStream *createReadStream() const; + }; + + /** Basic information about a part. */ + struct PartInfo { + uint32 id; + uint32 offset; + uint32 size; + }; + + typedef Common::Array<Part *>::iterator PartIterator; + typedef Common::Array<Part *>::const_iterator PartConstIterator; + + uint32 _partCount; + uint32 _slot; + + SaveHeader _header; + Common::Array<Part *> _parts; + + uint32 calcSize() const; + + bool read(Common::ReadStream &stream); + bool write(Common::WriteStream &stream) const; + + /** Get an array containing basic information about all parts in the container in the stream. */ + static Common::Array<PartInfo> *getPartsInfo(Common::SeekableReadStream &stream); +}; + +/** Reads a save. */ +class SaveReader : public SaveContainer { +public: + SaveReader(uint32 partCount, uint32 slot, const char *fileName); + SaveReader(uint32 partCount, uint32 slot, Common::SeekableReadStream &stream); + ~SaveReader(); + + bool load(); + + bool readPart(uint32 partN, SavePart *part) const; + bool readPartHeader(uint32 partN, SaveHeader *header) const; + + /** Find and read the save's info part. */ + static bool getInfo(Common::SeekableReadStream &stream, SavePartInfo &info); + /** Find and read the save's info part. */ + static bool getInfo(const char *fileName, SavePartInfo &info); + +protected: + char *_fileName; + Common::SeekableReadStream *_stream; + + bool _loaded; + + static Common::InSaveFile *openSave(const char *fileName); + Common::InSaveFile *openSave(); +}; + +/** Writes a save. */ +class SaveWriter: public SaveContainer { +public: + SaveWriter(uint32 partCount, uint32 slot, const char *fileName = 0); + ~SaveWriter(); + + bool writePart(uint32 partN, const SavePart *part); + + bool save(Common::WriteStream &stream); + +protected: + bool save(); + + char *_fileName; + + /** Is everything ready for saving? */ + bool canSave() const; + + static Common::OutSaveFile *openSave(const char *fileName); + Common::OutSaveFile *openSave(); +}; + +} // End of namespace Gob + +#endif // GOB_SAVE_SAVEFILE_H diff --git a/engines/gob/save/savehandler.cpp b/engines/gob/save/savehandler.cpp new file mode 100644 index 0000000000..744b839653 --- /dev/null +++ b/engines/gob/save/savehandler.cpp @@ -0,0 +1,503 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/endian.h" + +#include "gob/gob.h" +#include "gob/save/savehandler.h" +#include "gob/save/savefile.h" +#include "gob/save/saveconverter.h" +#include "gob/global.h" +#include "gob/video.h" +#include "gob/draw.h" +#include "gob/variables.h" +#include "gob/inter.h" + +namespace Gob { + +SlotFile::SlotFile(GobEngine *vm, uint32 slotCount, const char *base) : _vm(vm) { + _base = strdupcpy(base); + _slotCount = slotCount; +} + +SlotFile::~SlotFile() { + delete[] _base; +} + +const char *SlotFile::getBase() const { + return _base; +} + +uint32 SlotFile::getSlotMax() const { + Common::SaveFileManager *saveMan = g_system->getSavefileManager(); + Common::InSaveFile *in; + + // Find the last filled save slot and base the save file size calculate on that + for (int i = (_slotCount - 1); i >= 0; i--) { + char *slotFile = build(i); + + if (!slotFile) + continue; + + in = saveMan->openForLoading(slotFile); + delete[] slotFile; + + if (in) { + delete in; + return i + 1; + } + } + + return 0; +} + +int32 SlotFile::tallyUpFiles(uint32 slotSize, uint32 indexSize) const { + uint32 maxSlot = getSlotMax(); + + if (maxSlot == 0) + return -1; + + return ((maxSlot * slotSize) + indexSize); +} + +void SlotFile::buildIndex(byte *buffer, SavePartInfo &info, + SaveConverter *converter) const { + + uint32 descLength = info.getDescMaxLength(); + + // Iterate over all files + for (uint32 i = 0; i < _slotCount; i++, buffer += descLength) { + char *slotFile = build(i); + + if (slotFile) { + char *desc = 0; + + if (converter && (desc = converter->getDescription(slotFile))) + // Old style save + memcpy(buffer, desc, descLength); + else if (SaveReader::getInfo(slotFile, info)) + // New style save + memcpy(buffer, info.getDesc(), descLength); + else + // No known format, fill with 0 + memset(buffer, 0, descLength); + + delete[] desc; + + } else + // No valid slot, fill with 0 + memset(buffer, 0, descLength); + + delete[] slotFile; + } +} + +bool SlotFile::exists(const char *name) const { + Common::InSaveFile *in = openRead(name); + bool result = (in != 0); + delete in; + return result; +} + +bool SlotFile::exists(int slot) const { + Common::InSaveFile *in = openRead(slot); + bool result = (in != 0); + delete in; + return result; +} + +bool SlotFile::exists() const { + Common::InSaveFile *in = openRead(); + bool result = (in != 0); + delete in; + return result; +} + +Common::InSaveFile *SlotFile::openRead(const char *name) const { + if (!name) + return 0; + + Common::SaveFileManager *saveMan = g_system->getSavefileManager(); + + return saveMan->openForLoading(name); +} + +Common::InSaveFile *SlotFile::openRead(int slot) const { + char *name = build(slot); + Common::InSaveFile *result = openRead(name); + delete[] name; + return result; +} + +Common::InSaveFile *SlotFile::openRead() const { + char *name = build(); + Common::InSaveFile *result = openRead(name); + delete[] name; + return result; +} + +Common::OutSaveFile *SlotFile::openWrite(const char *name) const { + if (!name) + return 0; + + Common::SaveFileManager *saveMan = g_system->getSavefileManager(); + + return saveMan->openForSaving(name); +} + +Common::OutSaveFile *SlotFile::openWrite(int slot) const { + char *name = build(slot); + Common::OutSaveFile *result = openWrite(name); + delete[] name; + return result; +} + +Common::OutSaveFile *SlotFile::openWrite() const { + char *name = build(); + Common::OutSaveFile *result = openWrite(name); + delete[] name; + return result; +} + + +SlotFileIndexed::SlotFileIndexed(GobEngine *vm, uint32 slotCount, + const char *base, const char *extStub) : SlotFile(vm, slotCount, base) { + + _ext = strdupcpy(extStub); +} + +SlotFileIndexed::~SlotFileIndexed() { + delete[] _ext; +} + +char *SlotFileIndexed::build(int slot) const { + if ((slot < 0) || (((uint32) slot) >= _slotCount)) + return 0; + + size_t len = strlen(_base) + strlen(_ext) + 4; + + char *slotFile = new char[len]; + + snprintf(slotFile, len, "%s.%s%02d", _base, _ext, slot); + + return slotFile; +} + +char *SlotFileIndexed::build() const { + return 0; +} + + +SlotFileStatic::SlotFileStatic(GobEngine *vm, const char *base, + const char *ext) : SlotFile(vm, 1, base) { + + _ext = strdupcat(".", ext); +} + +SlotFileStatic::~SlotFileStatic() { + delete[] _ext; +} + +int SlotFileStatic::getSlot(int32 offset) const { + return -1; +} + +int SlotFileStatic::getSlotRemainder(int32 offset) const { + return -1; +} + +char *SlotFileStatic::build(int slot) const { + return 0; +} + +char *SlotFileStatic::build() const { + return strdupcat(_base, _ext); +} + + +SaveHandler::SaveHandler(GobEngine *vm) : _vm(vm) { +} + +SaveHandler::~SaveHandler() { +} + +uint32 SaveHandler::getVarSize(GobEngine *vm) { + // Sanity checks + if (!vm || !vm->_inter || !vm->_inter->_variables) + return 0; + + return vm->_inter->_variables->getSize(); +} + + +TempSpriteHandler::TempSpriteHandler(GobEngine *vm) : SaveHandler(vm) { + _sprite = 0; +} + +TempSpriteHandler::~TempSpriteHandler() { + delete _sprite; +} + +int32 TempSpriteHandler::getSize() { + if (!_sprite) + return -1; + + return _sprite->getSize(); +} + +bool TempSpriteHandler::load(int16 dataVar, int32 size, int32 offset) { + // Sprite available? + if (!_sprite) + return false; + + // Sprite requested? + if (!isSprite(size)) + return false; + + // Index sane? + int index = getIndex(size); + if ((index < 0) || (index >= SPRITES_COUNT)) + return false; + + SurfaceDesc *sprite = _vm->_draw->_spritesArray[index]; + + // Target sprite exists? + if (!sprite) + return false; + + // Load the sprite + if (!_sprite->writeSprite(sprite)) + return false; + + // Handle palette + if (usesPalette(size)) { + if (!_sprite->writePalette((byte *) _vm->_global->_pPaletteDesc->vgaPal)) + return false; + + _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); + } + + if (index == 21) { + // We wrote into the backbuffer, blit + _vm->_draw->forceBlit(); + _vm->_video->retrace(); + } else if (index == 20) + // We wrote into the frontbuffer, retrace + _vm->_video->retrace(); + + return true; +} + +bool TempSpriteHandler::save(int16 dataVar, int32 size, int32 offset) { + SurfaceDesc *sprite; + + if (!createSprite(dataVar, size, offset, &sprite)) + return false; + + // Save the sprite + if (!_sprite->readSprite(sprite)) + return false; + + // Handle palette + if (usesPalette(size)) { + if (!_sprite->readPalette((const byte *) _vm->_global->_pPaletteDesc->vgaPal)) + return false; + } + + return true; +} + +bool TempSpriteHandler::createSprite(int16 dataVar, int32 size, + int32 offset, SurfaceDesc **sprite) { + + delete _sprite; + _sprite = 0; + + // Sprite requested? + if (!isSprite(size)) + return false; + + // Index sane? + int index = getIndex(size); + if ((index < 0) || (index >= SPRITES_COUNT)) + return false; + + SurfaceDesc *sprt = _vm->_draw->_spritesArray[index]; + + // Sprite exists? + if (!sprt) + return false; + + // Create a new temporary sprite + _sprite = new SavePartSprite(sprt->getWidth(), sprt->getHeight()); + + if (sprite) + *sprite = sprt; + + return true; +} + +// A negative size is the flag for using a sprite +bool TempSpriteHandler::isSprite(int32 size) { + return (size < 0); +} + +// Contruct the index +int TempSpriteHandler::getIndex(int32 size) { + // Palette flag + if (size < -1000) + size += 1000; + + return (-size - 1); +} + +// A size smaller than -1000 indicates palette usage +bool TempSpriteHandler::usesPalette(int32 size) { + return (size < -1000); +} + + +NotesHandler::File::File(GobEngine *vm, const char *base) : + SlotFileStatic(vm, base, "blo") { +} + +NotesHandler::File::~File() { +} + +NotesHandler::NotesHandler(uint32 notesSize, GobEngine *vm, const char *target) : + SaveHandler(vm) { + + _notesSize = notesSize; + + _file = new File(vm, target); + + _notes = new SavePartVars(vm, _notesSize); +} + +NotesHandler::~NotesHandler() { + delete _file; + delete _notes; +} + +int32 NotesHandler::getSize() { + char *fileName = _file->build(); + + if (!fileName) + return -1; + + Common::InSaveFile *saveFile; + + SaveConverter_Notes converter(_vm, _notesSize, fileName); + if (converter.isOldSave(&saveFile)) { + // Old save, get the size olden-style + + int32 size = saveFile->size(); + + delete saveFile; + return size; + } + + SaveReader reader(1, 0, fileName); + SaveHeader header; + + delete[] fileName; + + if (!reader.load()) + return -1; + + if (!reader.readPartHeader(0, &header)) + return -1; + + // Return the part's size + return header.getSize(); +} + +bool NotesHandler::load(int16 dataVar, int32 size, int32 offset) { + if ((dataVar < 0) || (size < 0) || (offset < 0)) + return false; + + char *fileName = _file->build(); + + if (!fileName) + return false; + + SaveReader *reader; + + SaveConverter_Notes converter(_vm, _notesSize, fileName); + if (converter.isOldSave()) { + // Old save, plug the converter in + if (!converter.load()) + return false; + + reader = new SaveReader(1, 0, converter); + + } else + // New save, load directly + reader = new SaveReader(1, 0, fileName); + + SavePartVars vars(_vm, _notesSize); + + delete[] fileName; + + if (!reader->load()) { + delete reader; + return false; + } + + if (!reader->readPart(0, &vars)) { + delete reader; + return false; + } + + if (!vars.writeInto(dataVar, offset, size)) { + delete reader; + return false; + } + + delete reader; + return true; +} + +bool NotesHandler::save(int16 dataVar, int32 size, int32 offset) { + if ((dataVar < 0) || (size < 0) || (offset < 0)) + return false; + + char *fileName = _file->build(); + + if (!fileName) + return false; + + SaveWriter writer(1, 0, fileName); + SavePartVars vars(_vm, _notesSize); + + delete[] fileName; + + if (!vars.readFrom(dataVar, offset, size)) + return false; + + return writer.writePart(0, &vars); +} + +} // End of namespace Gob diff --git a/engines/gob/save/savehandler.h b/engines/gob/save/savehandler.h new file mode 100644 index 0000000000..06c6c39cf8 --- /dev/null +++ b/engines/gob/save/savehandler.h @@ -0,0 +1,191 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GOB_SAVE_SAVEHANDLER_H +#define GOB_SAVE_SAVEHANDLER_H + +#include "common/savefile.h" + +namespace Gob { + +class GobEngine; +class SurfaceDesc; +class SavePartInfo; +class SavePartVars; +class SavePartSprite; +class SaveConverter; + +/** Slot file related class. */ +class SlotFile { +public: + /** The constructor. + * + * @param slotCount Number of slots. + * @param base The file's base string. + */ + SlotFile(GobEngine *vm, uint32 slotCount, const char *base); + virtual ~SlotFile(); + + /** Returns the base string. */ + virtual const char *getBase() const; + + /** Calculates which slot to use. */ + virtual int getSlot(int32 offset) const = 0; + /** Calculates the slot remainder, for error checking. */ + virtual int getSlotRemainder(int32 offset) const = 0; + + /** Build the save file name. */ + virtual char *build(int slot) const = 0; + /** Build the save file name. */ + virtual char *build() const = 0; + + /** Returns the highest filled slot number. */ + virtual uint32 getSlotMax() const; + + /** Returns the size of all existing slots + the index. */ + virtual int32 tallyUpFiles(uint32 slotSize, uint32 indexSize) const; + + /** Creates an index in buffer. */ + virtual void buildIndex(byte *buffer, SavePartInfo &info, + SaveConverter *converter = 0) const; + + virtual bool exists(const char *name) const; + virtual bool exists(int slot) const; + virtual bool exists() const; + + virtual Common::InSaveFile *openRead(const char *name) const; + virtual Common::InSaveFile *openRead(int slot) const; + virtual Common::InSaveFile *openRead() const; + + virtual Common::OutSaveFile *openWrite(const char *name) const; + virtual Common::OutSaveFile *openWrite(int slot) const; + virtual Common::OutSaveFile *openWrite() const; + +protected: + GobEngine *_vm; + char *_base; + + uint32 _slotCount; +}; + +/** An indexed slot file ("foobar.s00", "foobar.s01", ...). */ +class SlotFileIndexed : public SlotFile { +public: + SlotFileIndexed(GobEngine *vm, uint32 slotCount, const char *base, + const char *extStub); + ~SlotFileIndexed(); + + char *build(int slot) const; + char *build() const; + +protected: + char *_ext; +}; + +/** A static slot file ("foo.bar"). */ +class SlotFileStatic : public SlotFile { +public: + SlotFileStatic(GobEngine *vm, const char *base, const char *ext); + ~SlotFileStatic(); + + int getSlot(int32 offset) const; + int getSlotRemainder(int32 offset) const; + + char *build(int slot) const; + char *build() const; + +protected: + char *_ext; +}; + +/** A handler for a specific save file. */ +class SaveHandler { +public: + SaveHandler(GobEngine *vm); + virtual ~SaveHandler(); + + /** Returns the file's (virtual) size. */ + virtual int32 getSize() = 0; + /** Loads (parts of) the file. */ + virtual bool load(int16 dataVar, int32 size, int32 offset) = 0; + /** Saves (parts of) the file. */ + virtual bool save(int16 dataVar, int32 size, int32 offset) = 0; + + static uint32 getVarSize(GobEngine *vm); + +protected: + GobEngine *_vm; +}; + +/** A handler for temporary sprites. */ +class TempSpriteHandler : public SaveHandler { +public: + TempSpriteHandler(GobEngine *vm); + ~TempSpriteHandler(); + + int32 getSize(); + bool load(int16 dataVar, int32 size, int32 offset); + bool save(int16 dataVar, int32 size, int32 offset); + + /** Create a fitting sprite. */ + bool createSprite(int16 dataVar, int32 size, + int32 offset, SurfaceDesc **sprite = 0); + +protected: + SavePartSprite *_sprite; + + /** Determine whether using a sprite was requested. */ + static bool isSprite(int32 size); + /** Determine which sprite is meant. */ + static int getIndex(int32 size); + /** Determine whether the palette should be used too. */ + static bool usesPalette(int32 size); +}; + +/** A handler for notes. */ +class NotesHandler : public SaveHandler { +public: + NotesHandler(uint32 notesSize, GobEngine *vm, const char *target); + ~NotesHandler(); + + int32 getSize(); + bool load(int16 dataVar, int32 size, int32 offset); + bool save(int16 dataVar, int32 size, int32 offset); + +private: + class File : public SlotFileStatic { + public: + File(GobEngine *vm, const char *base); + ~File(); + }; + + uint32 _notesSize; + File *_file; + SavePartVars *_notes; +}; + +} // End of namespace Gob + +#endif // GOB_SAVE_SAVEHANDLER_H diff --git a/engines/gob/save/saveload.cpp b/engines/gob/save/saveload.cpp new file mode 100644 index 0000000000..26cc952add --- /dev/null +++ b/engines/gob/save/saveload.cpp @@ -0,0 +1,135 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/endian.h" +#include "common/savefile.h" + +#include "gob/gob.h" +#include "gob/save/saveload.h" +#include "gob/helper.h" +#include "gob/global.h" +#include "gob/video.h" +#include "gob/draw.h" + +namespace Gob { + +SaveLoad::SaveLoad(GobEngine *vm, const char *targetName) : _vm(vm) { + _targetName = strdupcpy(targetName); +} + +SaveLoad::~SaveLoad() { + delete[] _targetName; +} + +const char *SaveLoad::stripPath(const char *fileName) { + const char *backSlash; + if ((backSlash = strrchr(fileName, '\\'))) + return backSlash + 1; + + return fileName; +} + +int32 SaveLoad::getSize(const char *fileName) { + debugC(3, kDebugSaveLoad, "Requested size of save file \"%s\"", fileName); + + SaveHandler *handler = getHandler(fileName); + + if (!handler) { + warning("No save handler for \"%s\"", fileName); + return -1; + } + + int32 size = handler->getSize(); + + debugC(4, kDebugSaveLoad, "Size is %d", size); + + return size; +} + +bool SaveLoad::load(const char *fileName, int16 dataVar, int32 size, int32 offset) { + debugC(3, kDebugSaveLoad, "Requested loading of save file \"%s\" - %d, %d, %d", + fileName, dataVar, size, offset); + + SaveHandler *handler = getHandler(fileName); + + if (!handler) { + warning("No save handler for \"%s\" (%d, %d, %d)", fileName, dataVar, size, offset); + return false; + } + + if (!handler->load(dataVar, size, offset)) { + const char *desc = getDescription(fileName); + + if (!desc) + desc = "Unkown"; + + warning("Could not load %s (\"%s\" (%d, %d, %d))", + desc, fileName, dataVar, size, offset); + return false; + } + + debugC(3, kDebugSaveLoad, "Successfully loaded game"); + return true; +} + +bool SaveLoad::save(const char *fileName, int16 dataVar, int32 size, int32 offset) { + debugC(3, kDebugSaveLoad, "Requested saving of save file \"%s\" - %d, %d, %d", + fileName, dataVar, size, offset); + + SaveHandler *handler = getHandler(fileName); + + if (!handler) { + warning("No save handler for \"%s\" (%d, %d, %d)", fileName, dataVar, size, offset); + return false; + } + + if (!handler->save(dataVar, size, offset)) { + const char *desc = getDescription(fileName); + + if (!desc) + desc = "Unkown"; + + warning("Could not save %s (\"%s\" (%d, %d, %d))", + desc, fileName, dataVar, size, offset); + return false; + } + + debugC(3, kDebugSaveLoad, "Successfully saved game"); + return true; +} + +SaveLoad::SaveMode SaveLoad::getSaveMode(const char *fileName) const { + return kSaveModeNone; +} + +SaveHandler *SaveLoad::getHandler(const char *fileName) const { + return 0; +} + +const char *SaveLoad::getDescription(const char *fileName) const { + return 0; +} + +} // End of namespace Gob diff --git a/engines/gob/save/saveload.h b/engines/gob/save/saveload.h new file mode 100644 index 0000000000..55a33272a7 --- /dev/null +++ b/engines/gob/save/saveload.h @@ -0,0 +1,452 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GOB_SAVE_SAVELOAD_H +#define GOB_SAVE_SAVELOAD_H + +#include "gob/save/savefile.h" +#include "gob/save/savehandler.h" + +namespace Gob { + +class GobEngine; + +/** A system for saving and loading. */ +class SaveLoad { +public: + /** How to handle the specific save. */ + enum SaveMode { + kSaveModeNone, //!< Don't handle it + kSaveModeIgnore, //!< Ignore it + kSaveModeExists, //!< Just claim it exists + kSaveModeSave //!< A normal save + }; + + /** The constructor. + * + * @param targetName The game's target name. Used as a base for the save names. + */ + SaveLoad(GobEngine *vm, const char *targetName); + virtual ~SaveLoad(); + + /** "foo\bar\quux.bla" => "quux.bla". */ + static const char *stripPath(const char *fileName); + + /** Returns how to handle that file. */ + virtual SaveMode getSaveMode(const char *fileName) const; + + /** Returns the file's (virtual) size. */ + int32 getSize(const char *fileName); + /** Loads size bytes from offset into the variables starting with dataVar. */ + bool load(const char *fileName, int16 dataVar, int32 size, int32 offset); + /** Saves size bytes from the variables starting with data dataVar at offset. */ + bool save(const char *fileName, int16 dataVar, int32 size, int32 offset); + +protected: + GobEngine *_vm; + + char *_targetName; + + virtual SaveHandler *getHandler(const char *fileName) const; + virtual const char *getDescription(const char *fileName) const; +}; + +/** Save/Load class for Gobliins 2, Ween: The Prophecy and Bargon Attack. */ +class SaveLoad_v2 : public SaveLoad { +public: + SaveLoad_v2(GobEngine *vm, const char *targetName); + virtual ~SaveLoad_v2(); + + SaveMode getSaveMode(const char *fileName) const; + +protected: + static const uint32 kSlotCount = 15; + static const uint32 kSlotNameLength = 40; + + struct SaveFile { + const char *sourceName; + SaveMode mode; + SaveHandler *handler; + const char *description; + }; + + /** Handles the save slots. */ + class GameHandler : public SaveHandler { + public: + GameHandler(GobEngine *vm, const char *target); + ~GameHandler(); + + int32 getSize(); + bool load(int16 dataVar, int32 size, int32 offset); + bool save(int16 dataVar, int32 size, int32 offset); + + private: + /** Slot file construction. */ + class File : public SlotFileIndexed { + public: + File(GobEngine *vm, const char *base); + ~File(); + + int getSlot(int32 offset) const; + int getSlotRemainder(int32 offset) const; + }; + + /** The index. kSlotCount * kSlotNameLength bytes. */ + byte _index[600]; + bool _hasIndex; + + File *_slotFile; + + void buildIndex(byte *buffer) const; + }; + + static SaveFile _saveFiles[]; + + GameHandler *_gameHandler; + NotesHandler *_notesHandler; + TempSpriteHandler *_tempSpriteHandler; + + SaveHandler *getHandler(const char *fileName) const; + const char *getDescription(const char *fileName) const; + + const SaveFile *getSaveFile(const char *fileName) const; + SaveFile *getSaveFile(const char *fileName); +}; + +/** Save/Load class for Goblins 3 and Lost in Time. */ +class SaveLoad_v3 : public SaveLoad { +public: + enum ScreenshotType { + kScreenshotTypeGob3, //!< Goblins 3 type screenshot + kScreenshotTypeLost //!< Lost in Time type screenshot + }; + + SaveLoad_v3(GobEngine *vm, const char *targetName, ScreenshotType sShotType); + virtual ~SaveLoad_v3(); + + SaveMode getSaveMode(const char *fileName) const; + +protected: + static const uint32 kSlotCount = 30; + static const uint32 kSlotNameLength = 40; + + struct SaveFile { + const char *sourceName; + SaveMode mode; + SaveHandler *handler; + const char *description; + }; + + class ScreenshotHandler; + + /** Handles the save slots. */ + class GameHandler : public SaveHandler { + friend class SaveLoad_v3::ScreenshotHandler; + public: + + GameHandler(GobEngine *vm, const char *target, bool usesScreenshots); + ~GameHandler(); + + int32 getSize(); + bool load(int16 dataVar, int32 size, int32 offset); + bool save(int16 dataVar, int32 size, int32 offset); + + bool saveScreenshot(int slot, const SavePartSprite *screenshot); + bool loadScreenshot(int slot, SavePartSprite *screenshot); + + private: + /** Slot file construction. */ + class File : public SlotFileIndexed { + public: + File(GobEngine *vm, const char *base); + File(const File &file); + ~File(); + + int getSlot(int32 offset) const; + int getSlotRemainder(int32 offset) const; + }; + + File *_slotFile; + + bool _usesScreenshots; + + bool _firstSize; + + /** Global properties. */ + byte _props[500]; + /** Index. kSlotCount * kSlotNameLength bytes. */ + byte _index[1200]; + bool _hasIndex; + + SaveReader *_reader; + SaveWriter *_writer; + + void buildIndex(byte *buffer) const; + + bool createReader(int slot); + bool createWriter(int slot); + + }; + + /** Handles the screenshots. */ + class ScreenshotHandler : public TempSpriteHandler { + public: + ScreenshotHandler(GobEngine *vm, GameHandler *gameHandler, ScreenshotType sShotType); + ~ScreenshotHandler(); + + int32 getSize(); + bool load(int16 dataVar, int32 size, int32 offset); + bool save(int16 dataVar, int32 size, int32 offset); + + private: + /** Slot file construction. */ + class File : public SaveLoad_v3::GameHandler::File { + public: + File(const SaveLoad_v3::GameHandler::File &file, + uint32 shotSize, uint32 shotIndexSize); + ~File(); + + int getSlot(int32 offset) const; + int getSlotRemainder(int32 offset) const; + + void buildIndex(byte *buffer) const; + + protected: + uint32 _shotSize; + uint32 _shotIndexSize; + }; + + File *_file; + GameHandler *_gameHandler; + ScreenshotType _sShotType; + + uint32 _shotSize; + int32 _shotIndexSize; + byte _index[80]; + }; + + static SaveFile _saveFiles[]; + + ScreenshotType _sShotType; + + GameHandler *_gameHandler; + NotesHandler *_notesHandler; + TempSpriteHandler *_tempSpriteHandler; + ScreenshotHandler *_screenshotHandler; + + SaveHandler *getHandler(const char *fileName) const; + const char *getDescription(const char *fileName) const; + + const SaveFile *getSaveFile(const char *fileName) const; + SaveFile *getSaveFile(const char *fileName); +}; + +/** Save/Load class for Woodruff. */ +class SaveLoad_v4 : public SaveLoad { +public: + SaveLoad_v4(GobEngine *vm, const char *targetName); + virtual ~SaveLoad_v4(); + + SaveMode getSaveMode(const char *fileName) const; + +protected: + static const uint32 kSlotCount = 10; + static const uint32 kSlotNameLength = 40; + + struct SaveFile { + const char *sourceName; + SaveMode mode; + SaveHandler *handler; + const char *description; + }; + + class ScreenPropsHandler; + + /** Handles the save slots. */ + class GameHandler : public SaveHandler { + friend class SaveLoad_v4::ScreenPropsHandler; + public: + GameHandler(GobEngine *vm, const char *target); + ~GameHandler(); + + int32 getSize(); + bool load(int16 dataVar, int32 size, int32 offset); + bool save(int16 dataVar, int32 size, int32 offset); + + bool saveScreenProps(int slot, const byte *props); + bool loadScreenProps(int slot, byte *props); + + private: + /** Slot file construction. */ + class File : public SlotFileIndexed { + public: + File(GobEngine *vm, const char *base); + File(const File &file); + ~File(); + + int getSlot(int32 offset) const; + int getSlotRemainder(int32 offset) const; + }; + + bool _firstSize; + + byte _props[500]; + /** The index. kSlotCount * kSlotNameLength bytes + 800 bytes 0. */ + byte _index[1200]; + bool _hasIndex; + + File *_slotFile; + + SaveReader *_reader; + SaveWriter *_writer; + + void buildIndex(byte *buffer) const; + + bool createReader(int slot); + bool createWriter(int slot); + }; + + class CurScreenPropsHandler : public SaveHandler { + friend class SaveLoad_v4::ScreenPropsHandler; + public: + CurScreenPropsHandler(GobEngine *vm); + ~CurScreenPropsHandler(); + + int32 getSize(); + bool load(int16 dataVar, int32 size, int32 offset); + bool save(int16 dataVar, int32 size, int32 offset); + + private: + byte *_props; + }; + + class ScreenPropsHandler : public SaveHandler { + public: + ScreenPropsHandler(GobEngine *vm, uint32 slot, + CurScreenPropsHandler *curProps, GameHandler *gameHandler); + ~ScreenPropsHandler(); + + int32 getSize(); + bool load(int16 dataVar, int32 size, int32 offset); + bool save(int16 dataVar, int32 size, int32 offset); + + private: + class File : public SaveLoad_v4::GameHandler::File { + public: + File(const SaveLoad_v4::GameHandler::File &file, uint32 slot); + ~File(); + + int getSlot(int32 offset) const; + int getSlotRemainder(int32 offset) const; + + private: + uint32 _slot; + }; + + uint32 _slot; + CurScreenPropsHandler *_curProps; + GameHandler *_gameHandler; + + File *_file; + }; + + static SaveFile _saveFiles[]; + + GameHandler *_gameHandler; + CurScreenPropsHandler *_curProps; + ScreenPropsHandler *_props[10]; + + SaveHandler *getHandler(const char *fileName) const; + const char *getDescription(const char *fileName) const; + + const SaveFile *getSaveFile(const char *fileName) const; + SaveFile *getSaveFile(const char *fileName); +}; + +/** Save/Load class for Urban Runner. */ +class SaveLoad_v6 : public SaveLoad { +public: + SaveLoad_v6(GobEngine *vm, const char *targetName); + virtual ~SaveLoad_v6(); + + SaveMode getSaveMode(const char *fileName) const; + +protected: + static const uint32 kSlotCount = 60; + static const uint32 kSlotNameLength = 40; + + struct SaveFile { + const char *sourceName; + SaveMode mode; + SaveHandler *handler; + const char *description; + }; + + /** Handles the save slots. */ + class GameHandler : public SaveHandler { + public: + GameHandler(GobEngine *vm, const char *target); + ~GameHandler(); + + int32 getSize(); + bool load(int16 dataVar, int32 size, int32 offset); + bool save(int16 dataVar, int32 size, int32 offset); + + private: + /** Slot file construction. */ + class File : public SlotFileIndexed { + public: + File(GobEngine *vm, const char *base); + ~File(); + + int getSlot(int32 offset) const; + int getSlotRemainder(int32 offset) const; + }; + + byte _props[500]; + /** The index. 500 bytes properties + kSlotCount * kSlotNameLength bytes. */ + byte _index[2400]; + + File *_slotFile; + + void buildIndex(byte *buffer) const; + + void refreshProps(); + }; + + static SaveFile _saveFiles[]; + + GameHandler *_gameHandler; + + SaveHandler *getHandler(const char *fileName) const; + const char *getDescription(const char *fileName) const; + + const SaveFile *getSaveFile(const char *fileName) const; + SaveFile *getSaveFile(const char *fileName); +}; + +} // End of namespace Gob + +#endif // GOB_SAVE_SAVELOAD_H diff --git a/engines/gob/save/saveload_v2.cpp b/engines/gob/save/saveload_v2.cpp new file mode 100644 index 0000000000..5746057626 --- /dev/null +++ b/engines/gob/save/saveload_v2.cpp @@ -0,0 +1,328 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "gob/save/saveload.h" +#include "gob/save/saveconverter.h" +#include "gob/helper.h" +#include "gob/inter.h" +#include "gob/variables.h" + +namespace Gob { + +SaveLoad_v2::SaveFile SaveLoad_v2::_saveFiles[] = { + { "cat.inf", kSaveModeSave, 0, "savegame"}, + { "cat.cat", kSaveModeSave, 0, "savegame"}, // Alternative file + { "save.inf", kSaveModeSave, 0, "temporary sprite"}, + { "bloc.inf", kSaveModeSave, 0, "notes"} +}; + + +SaveLoad_v2::GameHandler::File::File(GobEngine *vm, const char *base) : + SlotFileIndexed(vm, SaveLoad_v2::kSlotCount, base, "s") { +} + +SaveLoad_v2::GameHandler::File::~File() { +} + +int SaveLoad_v2::GameHandler::File::getSlot(int32 offset) const { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return -1; + + return ((offset - 600) / varSize); +} + +int SaveLoad_v2::GameHandler::File::getSlotRemainder(int32 offset) const { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return -1; + + return ((offset - 600) % varSize); +} + + +SaveLoad_v2::GameHandler::GameHandler(GobEngine *vm, const char *target) : SaveHandler(vm) { + memset(_index, 0, 600); + _hasIndex = false; + + _slotFile = new File(vm, target); +} + +SaveLoad_v2::GameHandler::~GameHandler() { + delete _slotFile; +} + +int32 SaveLoad_v2::GameHandler::getSize() { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return -1; + + return _slotFile->tallyUpFiles(varSize, 600); +} + +bool SaveLoad_v2::GameHandler::load(int16 dataVar, int32 size, int32 offset) { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return false; + + if (size == 0) { + // Indicator to load all variables + dataVar = 0; + size = varSize; + } + + if (offset == 0) { + // Save index + + if (size != 600) { + warning("Requested index has wrong size (%d)", size); + return false; + } + + // Create/Fake the index + buildIndex(_vm->_inter->_variables->getAddressOff8(dataVar)); + + } else { + // Save slot, whole variable block + + uint32 slot = _slotFile->getSlot(offset); + int slotRem = _slotFile->getSlotRemainder(offset); + + debugC(2, kDebugSaveLoad, "Loading from slot %d", slot); + + if ((slot >= kSlotCount) || (slotRem != 0) || + (dataVar != 0) || (((uint32) size) != varSize)) { + + warning("Invalid loading procedure (%d, %d, %d, %d, %d)", + dataVar, size, offset, slot, slotRem); + return false; + } + + char *slotFile = _slotFile->build(slot); + + SaveReader *reader = 0; + SaveConverter_v2 converter(_vm, slotFile); + + if (converter.isOldSave()) { + // Old save, plug the converter in + if (!converter.load()) + return false; + + reader = new SaveReader(2, slot, converter); + + } else + // New save, load directly + reader = new SaveReader(2, slot, slotFile); + + SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), 0, + _vm->getEndianness(), varSize); + SavePartVars vars(_vm, varSize); + + if (!reader->load()) { + delete reader; + return false; + } + + delete[] slotFile; + + if (!reader->readPart(0, &info)) { + delete reader; + return false; + } + if (!reader->readPart(1, &vars)) { + delete reader; + return false; + } + + // Get all variables + if (!vars.writeInto(0, 0, varSize)) { + delete reader; + return false; + } + + delete reader; + } + + return true; +} + +bool SaveLoad_v2::GameHandler::save(int16 dataVar, int32 size, int32 offset) { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return false; + + if (size == 0) { + // Indicator to save all variables + dataVar = 0; + size = varSize; + } + + if (offset == 0) { + // Save index + + if (size != 600) { + warning("Requested index has wrong size (%d)", size); + return false; + } + + // Just copy the index into our buffer + _vm->_inter->_variables->copyTo(dataVar, _index, 600); + _hasIndex = true; + + } else { + // Save slot, whole variable block + + uint32 slot = _slotFile->getSlot(offset); + int slotRem = _slotFile->getSlotRemainder(offset); + + debugC(2, kDebugSaveLoad, "Saving to slot %d", slot); + + if ((slot >= kSlotCount) || (slotRem != 0) || + (dataVar != 0) || (((uint32) size) != varSize)) { + + warning("Invalid saving procedure (%d, %d, %d, %d, %d)", + dataVar, size, offset, slot, slotRem); + return false; + } + + // An index is needed for the save slot description + if (!_hasIndex) { + warning("No index written yet"); + return false; + } + + _hasIndex = false; + + char *slotFile = _slotFile->build(slot); + + SaveWriter writer(2, slot, slotFile); + SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), 0, + _vm->getEndianness(), varSize); + SavePartVars vars(_vm, varSize); + + delete[] slotFile; + + // Write the description + info.setDesc(_index + (slot * kSlotNameLength), kSlotNameLength); + // Write all variables + if (!vars.readFrom(0, 0, varSize)) + return false; + + if (!writer.writePart(0, &info)) + return false; + if (!writer.writePart(1, &vars)) + return false; + } + + return true; +} + +void SaveLoad_v2::GameHandler::buildIndex(byte *buffer) const { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return; + + SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), + 0, _vm->getEndianness(), varSize); + + SaveConverter_v2 converter(_vm); + + _slotFile->buildIndex(buffer, info, &converter); +} + + +SaveLoad_v2::SaveLoad_v2(GobEngine *vm, const char *targetName) : + SaveLoad(vm, targetName) { + + _gameHandler = new GameHandler(vm, _targetName); + _notesHandler = new NotesHandler(600, vm, _targetName); + _tempSpriteHandler = new TempSpriteHandler(vm); + + _saveFiles[0].handler = _gameHandler; + _saveFiles[1].handler = _gameHandler; + _saveFiles[2].handler = _tempSpriteHandler; + _saveFiles[3].handler = _notesHandler; +} + +SaveLoad_v2::~SaveLoad_v2() { + delete _gameHandler; + delete _notesHandler; + delete _tempSpriteHandler; +} + +const SaveLoad_v2::SaveFile *SaveLoad_v2::getSaveFile(const char *fileName) const { + fileName = stripPath(fileName); + + for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) + if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) + return &_saveFiles[i]; + + return 0; +} + +SaveLoad_v2::SaveFile *SaveLoad_v2::getSaveFile(const char *fileName) { + fileName = stripPath(fileName); + + for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) + if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) + return &_saveFiles[i]; + + return 0; +} + +SaveHandler *SaveLoad_v2::getHandler(const char *fileName) const { + const SaveFile *saveFile = getSaveFile(fileName); + + if (saveFile) + return saveFile->handler; + + return 0; +} + +const char *SaveLoad_v2::getDescription(const char *fileName) const { + const SaveFile *saveFile = getSaveFile(fileName); + + if (saveFile) + return saveFile->description; + + return 0; +} + +SaveLoad::SaveMode SaveLoad_v2::getSaveMode(const char *fileName) const { + const SaveFile *saveFile = getSaveFile(fileName); + + if (saveFile) + return saveFile->mode; + + return kSaveModeNone; +} + +} // End of namespace Gob diff --git a/engines/gob/save/saveload_v3.cpp b/engines/gob/save/saveload_v3.cpp new file mode 100644 index 0000000000..e2af420e08 --- /dev/null +++ b/engines/gob/save/saveload_v3.cpp @@ -0,0 +1,570 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "gob/save/saveload.h" +#include "gob/save/saveconverter.h" +#include "gob/helper.h" +#include "gob/inter.h" +#include "gob/variables.h" + +namespace Gob { + +SaveLoad_v3::SaveFile SaveLoad_v3::_saveFiles[] = { + { "cat.inf", kSaveModeSave , 0, "savegame"}, + { "ima.inf", kSaveModeSave , 0, "screenshot"}, + { "intro.$$$", kSaveModeSave , 0, "temporary sprite"}, + { "bloc.inf", kSaveModeSave , 0, "notes"}, + { "prot", kSaveModeIgnore, 0, 0}, + { "config", kSaveModeIgnore, 0, 0} +}; + + +SaveLoad_v3::GameHandler::File::File(GobEngine *vm, const char *base) : + SlotFileIndexed(vm, SaveLoad_v3::kSlotCount, base, "s") { +} + +SaveLoad_v3::GameHandler::File::File(const File &file) : + SlotFileIndexed(file._vm, file._slotCount, file._base, file._ext) { +} + +SaveLoad_v3::GameHandler::File::~File() { +} + +int SaveLoad_v3::GameHandler::File::getSlot(int32 offset) const { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return -1; + + return ((offset - 1700) / varSize); +} + +int SaveLoad_v3::GameHandler::File::getSlotRemainder(int32 offset) const { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return -1; + + return ((offset - 1700) % varSize); +} + + +SaveLoad_v3::GameHandler::GameHandler(GobEngine *vm, const char *target, + bool usesScreenshots) : SaveHandler(vm) { + + _slotFile = new File(vm, target); + + _usesScreenshots = usesScreenshots; + + _firstSize = true; + memset(_props, 0, 500); + memset(_index, 0, 1200); + _hasIndex = false; + + _writer = 0; + _reader = 0; +} + +SaveLoad_v3::GameHandler::~GameHandler() { + delete _slotFile; + delete _reader; + delete _writer; +} + +int32 SaveLoad_v3::GameHandler::getSize() { + // Fake an empty save file for the very first query, to get clear properties + if (_firstSize) { + _firstSize = false; + return -1; + } + + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return -1; + + return _slotFile->tallyUpFiles(varSize, 1700); +} + +bool SaveLoad_v3::GameHandler::load(int16 dataVar, int32 size, int32 offset) { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return false; + + if (size == 0) { + // Indicator to load all variables + dataVar = 0; + size = varSize; + } + + if (offset < 500) { + // Global properties, like joker usage + + debugC(3, kDebugSaveLoad, "Loading global properties"); + + if ((size + offset) > 500) { + warning("Wrong global properties list size (%d, %d)", size, offset); + return false; + } + + _vm->_inter->_variables->copyFrom(dataVar, _props + offset, size); + + } else if (offset == 500) { + // Save index + + if (size != 1200) { + warning("Requested index has wrong size (%d)", size); + return false; + } + + // Create/Fake the index + buildIndex(_vm->_inter->_variables->getAddressOff8(dataVar)); + + } else { + // Save slot, whole variable block + + uint32 slot = _slotFile->getSlot(offset); + int slotRem = _slotFile->getSlotRemainder(offset); + + debugC(2, kDebugSaveLoad, "Loading from slot %d", slot); + + if ((slot >= kSlotCount) || (slotRem != 0) || + (dataVar != 0) || (((uint32) size) != varSize)) { + + warning("Invalid saving procedure (%d, %d, %d, %d, %d)", + dataVar, size, offset, slot, slotRem); + return false; + } + + _hasIndex = false; + + if (!createReader(slot)) + return false; + + SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), 0, + _vm->getEndianness(), varSize); + SavePartVars vars(_vm, varSize); + + if (!_reader->readPart(0, &info)) + return false; + if (!_reader->readPart(1, &vars)) + return false; + + // Get all variables + if (!vars.writeInto(0, 0, varSize)) + return false; + + } + + return true; +} + +bool SaveLoad_v3::GameHandler::save(int16 dataVar, int32 size, int32 offset) { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return false; + + if (size == 0) { + // Indicator to save all variables + dataVar = 0; + size = varSize; + } + + if (offset < 500) { + // Global properties, like joker usage + + debugC(3, kDebugSaveLoad, "Saving global properties"); + + if ((size + offset) > 500) { + warning("Wrong global properties list size (%d, %d)", size, offset); + return false; + } + + _vm->_inter->_variables->copyTo(dataVar, _props + offset, size); + + } else if (offset == 500) { + // Save index + + if (size != 1200) { + warning("Requested index has wrong size (%d)", size); + return false; + } + + // Just copy the index into our buffer + _vm->_inter->_variables->copyTo(dataVar, _index, 1200); + _hasIndex = true; + + } else { + // Save slot, whole variable block + + uint32 slot = _slotFile->getSlot(offset); + int slotRem = _slotFile->getSlotRemainder(offset); + + debugC(2, kDebugSaveLoad, "Saving to slot %d", slot); + + if ((slot >= kSlotCount) || (slotRem != 0) || + (dataVar != 0) || (((uint32) size) != varSize)) { + + warning("Invalid saving procedure (%d, %d, %d, %d, %d)", + dataVar, size, offset, slot, slotRem); + return false; + } + + // An index is needed for the save slot description + if (!_hasIndex) { + warning("No index written yet"); + return false; + } + + _hasIndex = false; + + if (!createWriter(slot)) + return false; + + SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), 0, + _vm->getEndianness(), varSize); + SavePartVars vars(_vm, varSize); + + // Write the description + info.setDesc(_index + (slot * kSlotNameLength), kSlotNameLength); + // Write all variables + if (!vars.readFrom(0, 0, varSize)) + return false; + + if (!_writer->writePart(0, &info)) + return false; + if (!_writer->writePart(1, &vars)) + return false; + + } + + return true; +} + +bool SaveLoad_v3::GameHandler::saveScreenshot(int slot, + const SavePartSprite *screenshot) { + + if (!createWriter(slot)) + return false; + + return _writer->writePart(2, screenshot); +} + +bool SaveLoad_v3::GameHandler::loadScreenshot(int slot, + SavePartSprite *screenshot) { + + if (!createReader(slot)) + return false; + + return _reader->readPart(2, screenshot); +} + +void SaveLoad_v3::GameHandler::buildIndex(byte *buffer) const { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return; + + SavePartInfo info(40, (uint32) _vm->getGameType(), 0, _vm->getEndianness(), varSize); + + SaveConverter_v3 converter(_vm); + + _slotFile->buildIndex(buffer, info, &converter); +} + +bool SaveLoad_v3::GameHandler::createReader(int slot) { + // If slot < 0, just check if a reader exists + if (slot < 0) + return (_reader != 0); + + if (!_reader || (_reader->getSlot() != ((uint32) slot))) { + char *slotFile = _slotFile->build(slot); + + if (!slotFile) + return false; + + delete _reader; + + SaveConverter_v3 converter(_vm, slotFile); + if (converter.isOldSave()) { + // Old save, plug the converter in + if (!converter.load()) { + delete[] slotFile; + return false; + } + + _reader = new SaveReader(_usesScreenshots ? 3 : 2, slot, converter); + + } else + _reader = new SaveReader(_usesScreenshots ? 3 : 2, slot, slotFile); + + delete[] slotFile; + + if (!_reader->load()) { + delete _reader; + _reader = 0; + return false; + } + } + + return true; +} + +bool SaveLoad_v3::GameHandler::createWriter(int slot) { + // If slot < 0, just check if a writer exists + if (slot < 0) + return (_writer != 0); + + if (!_writer || (_writer->getSlot() != ((uint32) slot))) { + char *slotFile = _slotFile->build(slot); + + if (!slotFile) + return false; + + delete _writer; + _writer = new SaveWriter(_usesScreenshots ? 3 : 2, slot, slotFile); + + delete[] slotFile; + } + + return true; +} + + +SaveLoad_v3::ScreenshotHandler::File::File(const SaveLoad_v3::GameHandler::File &file, + uint32 shotSize, uint32 shotIndexSize) : SaveLoad_v3::GameHandler::File(file) { + + _shotSize = shotSize; + _shotIndexSize = shotIndexSize; +} + +SaveLoad_v3::ScreenshotHandler::File::~File() { +} + +int SaveLoad_v3::ScreenshotHandler::File::getSlot(int32 offset) const { + return ((offset - _shotIndexSize) / _shotSize); +} + +int SaveLoad_v3::ScreenshotHandler::File::getSlotRemainder(int32 offset) const { + return ((offset - _shotIndexSize) % _shotSize); +} + +void SaveLoad_v3::ScreenshotHandler::File::buildIndex(byte *buffer) const { + Common::SaveFileManager *saveMan = g_system->getSavefileManager(); + Common::InSaveFile *in; + + for (uint32 i = 0; i < _slotCount; i++, buffer++) { + char *slotFile = build(i); + + if (slotFile && ((in = saveMan->openForLoading(slotFile)))) { + delete in; + *buffer = 1; + } else + *buffer = 0; + + delete[] slotFile; + } +} + + +SaveLoad_v3::ScreenshotHandler::ScreenshotHandler(GobEngine *vm, + GameHandler *gameHandler, ScreenshotType sShotType) : TempSpriteHandler(vm) { + + assert(gameHandler); + + _gameHandler = gameHandler; + _sShotType = sShotType; + + _shotSize = (_sShotType == kScreenshotTypeLost) ? 4768 : 19968; + _shotIndexSize = (_sShotType == kScreenshotTypeLost) ? 50 : 80; + + _file = new File(*_gameHandler->_slotFile, _shotSize, _shotIndexSize); + + memset(_index, 0, 80); +} + +SaveLoad_v3::ScreenshotHandler::~ScreenshotHandler() { + delete _file; +} + +int32 SaveLoad_v3::ScreenshotHandler::getSize() { + return _file->tallyUpFiles(_shotSize, _shotIndexSize); +} + +bool SaveLoad_v3::ScreenshotHandler::load(int16 dataVar, int32 size, int32 offset) { + if (offset < _shotIndexSize) { + // Screenshot index list + + if ((size + offset) > _shotIndexSize) { + warning("Wrong screenshot index offset (%d, %d)", size, offset); + return false; + } + + if (_sShotType == kScreenshotTypeGob3) { + // Create/Fake the index + _file->buildIndex(_index + 40); + // The last 10 bytes are 0 + memset(_index + 70, 0, 10); + } else if (_sShotType == kScreenshotTypeLost) { + // Create/Fake the index + _file->buildIndex(_index); + // The last byte is 0 + _index[30] = 0; + } + + _vm->_inter->_variables->copyFrom(dataVar, _index + offset, size); + + } else { + // Screenshot + + uint32 slot = _file->getSlot(offset); + int slotRem = _file->getSlotRemainder(offset); + + if ((slot >= kSlotCount) || (slotRem != 0)) + return false; + + if (!TempSpriteHandler::createSprite(dataVar, size, offset)) + return false; + + if (!_gameHandler->loadScreenshot(slot, _sprite)) + return false; + + if (!TempSpriteHandler::load(dataVar, size, offset)) + return false; + } + + return true; +} + +bool SaveLoad_v3::ScreenshotHandler::save(int16 dataVar, int32 size, int32 offset) { + if (offset < _shotIndexSize) { + // Screenshot index list + + if ((size + offset) > _shotIndexSize) { + warning("Wrong screenshot index offset (%d, %d)", size, offset); + return false; + } + + _vm->_inter->_variables->copyTo(dataVar, _index + offset, size); + + } else { + // Screenshot + + if (!TempSpriteHandler::save(dataVar, size, offset)) + return false; + + uint32 slot = _file->getSlot(offset); + int slotRem = _file->getSlotRemainder(offset); + + if ((slot >= kSlotCount) || (slotRem != 0)) + return false; + + return _gameHandler->saveScreenshot(slot, _sprite); + } + + return true; +} + + +SaveLoad_v3::SaveLoad_v3(GobEngine *vm, const char *targetName, ScreenshotType sShotType) : + SaveLoad(vm, targetName) { + + _sShotType = sShotType; + + // The Amiga version doesn't use screenshots + if (_vm->getPlatform() == Common::kPlatformAmiga) { + _gameHandler = new GameHandler(vm, _targetName, false); + _screenshotHandler = 0; + } else { + _gameHandler = new GameHandler(vm, _targetName, true); + _screenshotHandler = new ScreenshotHandler(vm, _gameHandler, sShotType); + } + + _tempSpriteHandler = new TempSpriteHandler(vm); + _notesHandler = new NotesHandler(2560, vm, _targetName); + + _saveFiles[0].handler = _gameHandler; + _saveFiles[1].handler = _screenshotHandler; + _saveFiles[2].handler = _tempSpriteHandler; + _saveFiles[3].handler = _notesHandler; +} + +SaveLoad_v3::~SaveLoad_v3() { + delete _screenshotHandler; + delete _gameHandler; + delete _notesHandler; + delete _tempSpriteHandler; +} + +const SaveLoad_v3::SaveFile *SaveLoad_v3::getSaveFile(const char *fileName) const { + fileName = stripPath(fileName); + + for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) + if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) + return &_saveFiles[i]; + + return 0; +} + +SaveLoad_v3::SaveFile *SaveLoad_v3::getSaveFile(const char *fileName) { + fileName = stripPath(fileName); + + for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) + if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) + return &_saveFiles[i]; + + return 0; +} + +SaveHandler *SaveLoad_v3::getHandler(const char *fileName) const { + const SaveFile *saveFile = getSaveFile(fileName); + + if (saveFile) + return saveFile->handler; + + return 0; +} + +const char *SaveLoad_v3::getDescription(const char *fileName) const { + const SaveFile *saveFile = getSaveFile(fileName); + + if (saveFile) + return saveFile->description; + + return 0; +} + +SaveLoad::SaveMode SaveLoad_v3::getSaveMode(const char *fileName) const { + const SaveFile *saveFile = getSaveFile(fileName); + + if (saveFile) + return saveFile->mode; + + return kSaveModeNone; +} + +} // End of namespace Gob diff --git a/engines/gob/save/saveload_v4.cpp b/engines/gob/save/saveload_v4.cpp new file mode 100644 index 0000000000..fcf9a1fe6f --- /dev/null +++ b/engines/gob/save/saveload_v4.cpp @@ -0,0 +1,555 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "gob/save/saveload.h" +#include "gob/save/saveconverter.h" +#include "gob/helper.h" +#include "gob/inter.h" +#include "gob/variables.h" + +namespace Gob { + +SaveLoad_v4::SaveFile SaveLoad_v4::_saveFiles[] = { + { "cat.inf", kSaveModeSave, 0, "savegame"}, + { "save.tmp", kSaveModeSave, 0, "current screen properties"}, + { "save0.tmp", kSaveModeSave, 0, "savegame screen properties"}, // Slot 0 + { "save1.tmp", kSaveModeSave, 0, "savegame screen properties"}, // Slot 1 + { "save2.tmp", kSaveModeSave, 0, "savegame screen properties"}, // Slot 2 + { "save3.tmp", kSaveModeSave, 0, "savegame screen properties"}, // Slot 3 + { "save4.tmp", kSaveModeSave, 0, "savegame screen properties"}, // Slot 4 + { "save5.tmp", kSaveModeSave, 0, "savegame screen properties"}, // Slot 5 + { "save6.tmp", kSaveModeSave, 0, "savegame screen properties"}, // Slot 6 + { "save7.tmp", kSaveModeSave, 0, "savegame screen properties"}, // Slot 7 + { "save8.tmp", kSaveModeSave, 0, "savegame screen properties"}, // Slot 8 + { "save9.tmp", kSaveModeSave, 0, "savegame screen properties"} // Slot 9 +}; + + +SaveLoad_v4::GameHandler::File::File(GobEngine *vm, const char *base) : + SlotFileIndexed(vm, SaveLoad_v4::kSlotCount, base, "s") { +} + +SaveLoad_v4::GameHandler::File::File(const File &file) : + SlotFileIndexed(file._vm, file._slotCount, file._base, file._ext) { +} + +SaveLoad_v4::GameHandler::File::~File() { +} + +int SaveLoad_v4::GameHandler::File::getSlot(int32 offset) const { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return -1; + + return ((offset - 1700) / varSize); +} + +int SaveLoad_v4::GameHandler::File::getSlotRemainder(int32 offset) const { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return -1; + + return ((offset - 1700) % varSize); +} + + +SaveLoad_v4::GameHandler::GameHandler(GobEngine *vm, const char *target) : SaveHandler(vm) { + _firstSize = true; + memset(_props, 0, 500); + memset(_index, 0, 1200); + _hasIndex = false; + + _slotFile = new File(vm, target); + + _writer = 0; + _reader = 0; +} + +SaveLoad_v4::GameHandler::~GameHandler() { + delete _slotFile; + delete _reader; + delete _writer; +} + +int32 SaveLoad_v4::GameHandler::getSize() { + // Fake an empty save file for the very first query, to get clear properties + if (_firstSize) { + _firstSize = false; + return -1; + } + + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return -1; + + return _slotFile->tallyUpFiles(varSize, 1700); +} + +bool SaveLoad_v4::GameHandler::load(int16 dataVar, int32 size, int32 offset) { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return false; + + if (size == 0) { + // Indicator to load all variables + dataVar = 0; + size = varSize; + } + + if (offset < 500) { + // Global properties + + debugC(3, kDebugSaveLoad, "Loading global properties"); + + if ((size + offset) > 500) { + warning("Wrong global properties list size (%d, %d)", size, offset); + return false; + } + + _vm->_inter->_variables->copyFrom(dataVar, _props + offset, size); + + } else if (offset == 500) { + // Save index + + if (size != 1200) { + warning("Requested index has wrong size (%d)", size); + return false; + } + + // Create/Fake the index + buildIndex(_vm->_inter->_variables->getAddressOff8(dataVar)); + + } else { + // Save slot, whole variable block + + uint32 slot = _slotFile->getSlot(offset); + int slotRem = _slotFile->getSlotRemainder(offset); + + debugC(2, kDebugSaveLoad, "Loading from slot %d", slot); + + if ((slot >= kSlotCount) || (slotRem != 0) || + (dataVar != 0) || (((uint32) size) != varSize)) { + + warning("Invalid saving procedure (%d, %d, %d, %d, %d)", + dataVar, size, offset, slot, slotRem); + return false; + } + + _hasIndex = false; + + if (!createReader(slot)) + return false; + + SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), 0, + _vm->getEndianness(), varSize); + SavePartVars vars(_vm, varSize); + + if (!_reader->readPart(0, &info)) + return false; + if (!_reader->readPart(1, &vars)) + return false; + + // Get all variables + if (!vars.writeInto(0, 0, varSize)) + return false; + + } + + return true; +} + +bool SaveLoad_v4::GameHandler::save(int16 dataVar, int32 size, int32 offset) { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return false; + + if (size == 0) { + // Indicator to load all variables + dataVar = 0; + size = varSize; + } + + if (offset < 500) { + // Global properties + + debugC(3, kDebugSaveLoad, "Saving global properties"); + + if ((size + offset) > 500) { + warning("Wrong global properties list size (%d, %d)", size, offset); + return false; + } + + _vm->_inter->_variables->copyTo(dataVar, _props + offset, size); + + } else if (offset == 500) { + // Save index + + if (size != 1200) { + warning("Requested index has wrong size (%d)", size); + return false; + } + + // Just copy the index into our buffer + _vm->_inter->_variables->copyTo(dataVar, _index, 1200); + _hasIndex = true; + + } else { + // Save slot, whole variable block + + uint32 slot = _slotFile->getSlot(offset); + int slotRem = _slotFile->getSlotRemainder(offset); + + debugC(2, kDebugSaveLoad, "Saving to slot %d", slot); + + if ((slot >= kSlotCount) || (slotRem != 0) || + (dataVar != 0) || (((uint32) size) != varSize)) { + + warning("Invalid saving procedure (%d, %d, %d, %d, %d)", + dataVar, size, offset, slot, slotRem); + return false; + } + + // An index is needed for the save slot description + if (!_hasIndex) { + warning("No index written yet"); + return false; + } + + _hasIndex = false; + + if (!createWriter(slot)) + return false; + + SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), 0, + _vm->getEndianness(), varSize); + SavePartVars vars(_vm, varSize); + + // Write the description + info.setDesc(_index + (slot * kSlotNameLength), kSlotNameLength); + // Write all variables + if (!vars.readFrom(0, 0, varSize)) + return false; + + if (!_writer->writePart(0, &info)) + return false; + if (!_writer->writePart(1, &vars)) + return false; + + } + + return true; +} + +bool SaveLoad_v4::GameHandler::saveScreenProps(int slot, const byte *props) { + if (!createWriter(slot)) + return false; + + SavePartMem mem(256000); + + if (!mem.readFrom(props, 0, 256000)) + return false; + + return _writer->writePart(2, &mem); +} + +bool SaveLoad_v4::GameHandler::loadScreenProps(int slot, byte *props) { + if (!createReader(slot)) + return false; + + SavePartMem mem(256000); + + if (!_reader->readPart(2, &mem)) + return false; + + if (!mem.writeInto(props, 0, 256000)) + return false; + + return true; +} + +void SaveLoad_v4::GameHandler::buildIndex(byte *buffer) const { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return; + + SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), + 0, _vm->getEndianness(), varSize); + + SaveConverter_v4 converter(_vm); + + _slotFile->buildIndex(buffer, info, &converter); + + // 400 bytes index + 800 bytes 0 + memset(buffer + 400, 0, 800); +} + +bool SaveLoad_v4::GameHandler::createReader(int slot) { + // If slot < 0, just check if a reader exists + if (slot < 0) + return (_reader != 0); + + if (!_reader || (_reader->getSlot() != ((uint32) slot))) { + char *slotFile = _slotFile->build(slot); + + if (!slotFile) + return false; + + delete _reader; + + SaveConverter_v4 converter(_vm, slotFile); + if (converter.isOldSave()) { + // Old save, plug the converter in + if (!converter.load()) { + delete[] slotFile; + return false; + } + + _reader = new SaveReader(3, slot, converter); + + } else + _reader = new SaveReader(3, slot, slotFile); + + delete[] slotFile; + + if (!_reader->load()) { + delete _reader; + _reader = 0; + return false; + } + } + + return true; +} + +bool SaveLoad_v4::GameHandler::createWriter(int slot) { + // If slot < 0, just check if a writer exists + if (slot < 0) + return (_writer != 0); + + if (!_writer || (_writer->getSlot() != ((uint32) slot))) { + char *slotFile = _slotFile->build(slot); + + if (!slotFile) + return false; + + delete _writer; + _writer = new SaveWriter(3, slot, slotFile); + + delete[] slotFile; + } + + return true; +} + + +SaveLoad_v4::CurScreenPropsHandler::CurScreenPropsHandler(GobEngine *vm) : + SaveHandler(vm) { + + _props = new byte[256000]; + memset(_props, 0, 256000); +} + +SaveLoad_v4::CurScreenPropsHandler::~CurScreenPropsHandler() { + delete[] _props; +} + +int32 SaveLoad_v4::CurScreenPropsHandler::getSize() { + return 256000; +} + +bool SaveLoad_v4::CurScreenPropsHandler::load(int16 dataVar, + int32 size, int32 offset) { + + // Using a sprite as a buffer + if (size <= 0) + return true; + + if ((offset < 0) || (size + offset) > 256000) { + warning("Invalid size (%d) or offset (%d)", size, offset); + return false; + } + + debugC(3, kDebugSaveLoad, "Loading screen properties (%d, %d, %d)", + dataVar, size, offset); + + _vm->_inter->_variables->copyFrom(dataVar, _props + offset, size); + + return true; +} + +bool SaveLoad_v4::CurScreenPropsHandler::save(int16 dataVar, + int32 size, int32 offset) { + + // Using a sprite as a buffer + if (size <= 0) + return true; + + if ((offset < 0) || (size + offset) > 256000) { + warning("Invalid size (%d) or offset (%d)", size, offset); + return false; + } + + debugC(3, kDebugSaveLoad, "Saving screen properties (%d, %d, %d)", + dataVar, size, offset); + + _vm->_inter->_variables->copyTo(dataVar, _props + offset, size); + + return true; +} + + +SaveLoad_v4::ScreenPropsHandler::File::File(const SaveLoad_v4::GameHandler::File &file, + uint32 slot) : SaveLoad_v4::GameHandler::File(file) { + + _slot = slot; +} + +SaveLoad_v4::ScreenPropsHandler::File::File::~File() { +} + +int SaveLoad_v4::ScreenPropsHandler::File::File::getSlot(int32 offset) const { + return _slot; +} + +int SaveLoad_v4::ScreenPropsHandler::File::File::getSlotRemainder(int32 offset) const { + return 0; +} + + +SaveLoad_v4::ScreenPropsHandler::ScreenPropsHandler(GobEngine *vm, uint32 slot, + CurScreenPropsHandler *curProps, GameHandler *gameHandler) : SaveHandler(vm) { + + _slot = slot; + _curProps = curProps; + _gameHandler = gameHandler; + + _file = new File(*_gameHandler->_slotFile, _slot); +} + +SaveLoad_v4::ScreenPropsHandler::~ScreenPropsHandler() { + delete _file; +} + +int32 SaveLoad_v4::ScreenPropsHandler::getSize() { + if (_file->exists()) + return 256000; + + return 0; +} + +bool SaveLoad_v4::ScreenPropsHandler::load(int16 dataVar, int32 size, int32 offset) { + if (size != -5) { + warning("Invalid saving procedure (%d, %d, %d)", dataVar, size, offset); + return false; + } + + return _gameHandler->loadScreenProps(_file->getSlot(offset), _curProps->_props); +} + +bool SaveLoad_v4::ScreenPropsHandler::save(int16 dataVar, int32 size, int32 offset) { + if (size != -5) { + warning("Invalid saving procedure (%d, %d, %d)", dataVar, size, offset); + return false; + } + + return _gameHandler->saveScreenProps(_file->getSlot(offset), _curProps->_props); +} + + +SaveLoad_v4::SaveLoad_v4(GobEngine *vm, const char *targetName) : + SaveLoad(vm, targetName) { + + _gameHandler = new GameHandler(vm, _targetName); + _curProps = new CurScreenPropsHandler(vm); + for (int i = 0; i < 10; i++) + _props[i] = new ScreenPropsHandler(vm, i, _curProps, _gameHandler); + + _saveFiles[0].handler = _gameHandler; + _saveFiles[1].handler = _curProps; + for (int i = 0; i < 10; i++) + _saveFiles[i + 2].handler = _props[i]; +} + +SaveLoad_v4::~SaveLoad_v4() { + delete _gameHandler; + delete _curProps; + for (int i = 0; i < 10; i++) + delete _props[i]; +} + +const SaveLoad_v4::SaveFile *SaveLoad_v4::getSaveFile(const char *fileName) const { + fileName = stripPath(fileName); + + for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) + if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) + return &_saveFiles[i]; + + return 0; +} + +SaveLoad_v4::SaveFile *SaveLoad_v4::getSaveFile(const char *fileName) { + fileName = stripPath(fileName); + + for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) + if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) + return &_saveFiles[i]; + + return 0; +} + +SaveHandler *SaveLoad_v4::getHandler(const char *fileName) const { + const SaveFile *saveFile = getSaveFile(fileName); + + if (saveFile) + return saveFile->handler; + + return 0; +} + +const char *SaveLoad_v4::getDescription(const char *fileName) const { + const SaveFile *saveFile = getSaveFile(fileName); + + if (saveFile) + return saveFile->description; + + return 0; +} + +SaveLoad::SaveMode SaveLoad_v4::getSaveMode(const char *fileName) const { + const SaveFile *saveFile = getSaveFile(fileName); + + if (saveFile) + return saveFile->mode; + + return kSaveModeNone; +} + +} // End of namespace Gob diff --git a/engines/gob/save/saveload_v6.cpp b/engines/gob/save/saveload_v6.cpp new file mode 100644 index 0000000000..5f772c75f7 --- /dev/null +++ b/engines/gob/save/saveload_v6.cpp @@ -0,0 +1,342 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "gob/save/saveload.h" +#include "gob/save/saveconverter.h" +#include "gob/helper.h" +#include "gob/inter.h" +#include "gob/variables.h" + +namespace Gob { + +SaveLoad_v6::SaveFile SaveLoad_v6::_saveFiles[] = { + { "cat.inf", kSaveModeSave, 0, "savegame"}, // Save file + { "mdo.def", kSaveModeExists, 0, 0}, + {"no_cd.txt", kSaveModeExists, 0, 0}, +}; + + +SaveLoad_v6::GameHandler::File::File(GobEngine *vm, const char *base) : + SlotFileIndexed(vm, SaveLoad_v6::kSlotCount, base, "s") { +} + +SaveLoad_v6::GameHandler::File::~File() { +} + +int SaveLoad_v6::GameHandler::File::getSlot(int32 offset) const { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return -1; + + return ((offset - 2900) / varSize); +} + +int SaveLoad_v6::GameHandler::File::getSlotRemainder(int32 offset) const { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return -1; + + return ((offset - 2900) % varSize); +} + + +SaveLoad_v6::GameHandler::GameHandler(GobEngine *vm, const char *target) : SaveHandler(vm) { + memset(_props, 0, 500); + memset(_index, 0, 2400); + + _slotFile = new File(vm, target); +} + +SaveLoad_v6::GameHandler::~GameHandler() { + delete _slotFile; +} + +int32 SaveLoad_v6::GameHandler::getSize() { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return -1; + + return _slotFile->tallyUpFiles(varSize, 2900); +} + +bool SaveLoad_v6::GameHandler::load(int16 dataVar, int32 size, int32 offset) { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return false; + + if (size == 0) { + // Indicator to load all variables + dataVar = 0; + size = varSize; + } + + if (offset < 500) { + // Properties + + refreshProps(); + + if ((offset + size) > 500) { + warning("Wrong index size (%d, %d)", size, offset); + return false; + } + + _vm->_inter->_variables->copyFrom(dataVar, _props + offset, size); + + } else if (offset < 2900) { + // Save index + + if (size != 2400) { + warning("Wrong index size (%d, %d)", size, offset); + return false; + } + + buildIndex(_vm->_inter->_variables->getAddressOff8(dataVar)); + + } else { + // Save slot, whole variable block + + uint32 slot = _slotFile->getSlot(offset); + int slotRem = _slotFile->getSlotRemainder(offset); + + debugC(2, kDebugSaveLoad, "Loading from slot %d", slot); + + if ((slot >= kSlotCount) || (slotRem != 0) || + (dataVar != 0) || (((uint32) size) != varSize)) { + + warning("Invalid loading procedure (%d, %d, %d, %d, %d)", + dataVar, size, offset, slot, slotRem); + return false; + } + + char *slotFile = _slotFile->build(slot); + + SaveReader *reader = 0; + SaveConverter_v6 converter(_vm, slotFile); + + if (converter.isOldSave()) { + // Old save, plug the converter in + if (!converter.load()) + return false; + + reader = new SaveReader(2, slot, converter); + + } else + // New save, load directly + reader = new SaveReader(2, slot, slotFile); + + SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), 0, + _vm->getEndianness(), varSize); + SavePartVars vars(_vm, varSize); + + if (!reader->load()) { + delete reader; + return false; + } + + delete[] slotFile; + + if (!reader->readPart(0, &info)) { + delete reader; + return false; + } + if (!reader->readPart(1, &vars)) { + delete reader; + return false; + } + + // Get all variables + if (!vars.writeInto(0, 0, varSize)) { + delete reader; + return false; + } + + delete reader; + } + + return true; +} + +bool SaveLoad_v6::GameHandler::save(int16 dataVar, int32 size, int32 offset) { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return false; + + if (size == 0) { + // Indicator to save all variables + dataVar = 0; + size = varSize; + } + + if (offset < 500) { + // Properties + + if ((offset + size) > 500) { + warning("Wrong index size (%d, %d)", size, offset); + return false; + } + + _vm->_inter->_variables->copyTo(dataVar, _props + offset, size); + + refreshProps(); + + } else if (offset < 2900) { + // Save index + + if (size != 2400) { + warning("Wrong index size (%d, %d)", size, offset); + return false; + } + + // Just copy the index into our buffer + _vm->_inter->_variables->copyTo(dataVar, _index, 2400); + + } else { + // Save slot, whole variable block + + uint32 slot = _slotFile->getSlot(offset); + int slotRem = _slotFile->getSlotRemainder(offset); + + debugC(2, kDebugSaveLoad, "Saving to slot %d", slot); + + if ((slot >= kSlotCount) || (slotRem != 0) || + (dataVar != 0) || (((uint32) size) != varSize)) { + + warning("Invalid saving procedure (%d, %d, %d, %d, %d)", + dataVar, size, offset, slot, slotRem); + return false; + } + + char *slotFile = _slotFile->build(slot); + + SaveWriter writer(2, slot, slotFile); + SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), 0, + _vm->getEndianness(), varSize); + SavePartVars vars(_vm, varSize); + + delete[] slotFile; + + // Write the description + info.setDesc(_index + (slot * kSlotNameLength), kSlotNameLength); + // Write all variables + if (!vars.readFrom(0, 0, varSize)) + return false; + + if (!writer.writePart(0, &info)) + return false; + if (!writer.writePart(1, &vars)) + return false; + } + + return true; +} + +void SaveLoad_v6::GameHandler::buildIndex(byte *buffer) const { + uint32 varSize = SaveHandler::getVarSize(_vm); + + if (varSize == 0) + return; + + SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), + 0, _vm->getEndianness(), varSize); + + SaveConverter_v6 converter(_vm); + + _slotFile->buildIndex(buffer, info, &converter); +} + +void SaveLoad_v6::GameHandler::refreshProps() { + uint32 maxSlot = _slotFile->getSlotMax(); + + memset(_props + 40, 0xFF, 40); // Joker + _props[159] = 0x03; // # of joker unused + WRITE_LE_UINT32(_props + 160, maxSlot); // # of saves +} + + +SaveLoad_v6::SaveLoad_v6(GobEngine *vm, const char *targetName) : + SaveLoad(vm, targetName) { + + _gameHandler = new GameHandler(vm, _targetName); + + _saveFiles[0].handler = _gameHandler; +} + +SaveLoad_v6::~SaveLoad_v6() { + delete _gameHandler; +} + +const SaveLoad_v6::SaveFile *SaveLoad_v6::getSaveFile(const char *fileName) const { + fileName = stripPath(fileName); + + for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) + if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) + return &_saveFiles[i]; + + return 0; +} + +SaveLoad_v6::SaveFile *SaveLoad_v6::getSaveFile(const char *fileName) { + fileName = stripPath(fileName); + + for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) + if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) + return &_saveFiles[i]; + + return 0; +} + +SaveHandler *SaveLoad_v6::getHandler(const char *fileName) const { + const SaveFile *saveFile = getSaveFile(fileName); + + if (saveFile) + return saveFile->handler; + + return 0; +} + +const char *SaveLoad_v6::getDescription(const char *fileName) const { + const SaveFile *saveFile = getSaveFile(fileName); + + if (saveFile) + return saveFile->description; + + return 0; +} + +SaveLoad::SaveMode SaveLoad_v6::getSaveMode(const char *fileName) const { + const SaveFile *saveFile = getSaveFile(fileName); + + if (saveFile) + return saveFile->mode; + + return kSaveModeNone; +} + +} // End of namespace Gob diff --git a/engines/gob/saveload.cpp b/engines/gob/saveload.cpp deleted file mode 100644 index 1584cedc95..0000000000 --- a/engines/gob/saveload.cpp +++ /dev/null @@ -1,879 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/endian.h" -#include "common/savefile.h" - -#include "gob/gob.h" -#include "gob/saveload.h" -#include "gob/draw.h" - -namespace Gob { - -TempSprite::TempSprite() { - _sprite = 0; - _width = _height = 0; - _size = -1; - memset(_palette, 0, 768); -} - -TempSprite::~TempSprite() { - delete[] _sprite; -} - -int TempSprite::getSpriteIndex(int32 size) const { - if (size < -1000) - size += 1000; - - return -size - 1; -} - -bool TempSprite::getSpritePalette(int32 size) const { - return size < -1000; -} - -bool TempSprite::getProperties(int16 dataVar, int32 size, int32 offset, - int &index, bool &palette) const { - - if (size >= 0) { - warning("Invalid index (%d)", size); - return false; - } - - index = getSpriteIndex(size); - palette = getSpritePalette(size); - - if ((index < 0) || (index >= SPRITES_COUNT)) { - warning("Index out of range (%d)", index); - return false; - } - - return true; -} - -int32 TempSprite::getSize() const { - return _size; -} - -bool TempSprite::saveSprite(const SurfaceDesc &surfDesc) { - delete[] _sprite; - - _width = surfDesc.getWidth(); - _height = surfDesc.getHeight(); - _size = _width * _height; - _sprite = new byte[_size]; - - memcpy(_sprite, surfDesc.getVidMem(), _size); - - return true; -} - -bool TempSprite::savePalette(const Video::Color *palette) { - memcpy((byte *) _palette, (const byte *) palette, 768); - return true; -} - -bool TempSprite::loadSprite(SurfaceDesc &surfDesc) { - if (!_sprite) { - warning("No sprite saved"); - return false; - } - - if (_size != (surfDesc.getWidth() * surfDesc.getHeight())) { - warning("Dimensions don't match (%dx%d - %dx%d", - _width, _height, surfDesc.getWidth(), surfDesc.getHeight()); - return false; - } - - memcpy(surfDesc.getVidMem(), _sprite, _size); - - return true; -} - -bool TempSprite::loadPalette(Video::Color *palette) { - memcpy((byte *) palette, (byte *) _palette, 768); - return true; -} - -bool TempSprite::toBuffer(byte *buffer, int32 size, bool palette) const { - - int32 haveSize = _size + (palette ? 768 : 0); - if (size != haveSize) { - warning("Sizes don't match (%d != %d)", size, haveSize); - return false; - } - - if (palette) { - memcpy(buffer, (const byte *) _palette, 768); - buffer += 768; - } - - memcpy(buffer, _sprite, _size); - - return true; -} - -bool TempSprite::fromBuffer(const byte *buffer, int32 size, bool palette) { - if (palette) { - memcpy((byte *) _palette, buffer, 768); - buffer += 768; - size -= 768; - } - - _size = size; - - delete[] _sprite; - _sprite = new byte[_size]; - - memcpy(_sprite, buffer, _size); - - return true; -} - - -PlainSave::PlainSave(Endianness endianness) : _endianness(endianness) { -} - -PlainSave::~PlainSave() { -} - -bool PlainSave::save(int16 dataVar, int32 size, int32 offset, const char *name, - const Variables *variables) { - - if ((size <= 0) || (offset != 0)) { - warning("Invalid size (%d) or offset (%d)", size, offset); - return false; - } - - byte *vars = new byte[size]; - byte *varSizes = new byte[size]; - - if (!variables->copyTo(dataVar, vars, varSizes, size)) { - delete[] vars; - delete[] varSizes; - warning("dataVar (%d) or size (%d) out of range", dataVar, size); - return false; - } - - bool result = save(0, size, offset, name, vars, varSizes); - - delete[] vars; - delete[] varSizes; - - return result; -} - -bool PlainSave::load(int16 dataVar, int32 size, int32 offset, const char *name, - Variables *variables) { - - if ((size <= 0) || (offset != 0)) { - warning("Invalid size (%d) or offset (%d)", size, offset); - return false; - } - - byte *vars = new byte[size]; - byte *varSizes = new byte[size]; - - bool result = load(0, size, offset, name, vars, varSizes); - - if (result && variables) { - if (!variables->copyFrom(dataVar, vars, varSizes, size)) { - delete[] vars; - delete[] varSizes; - warning("dataVar (%d) or size (%d) out of range", dataVar, size); - return false; - } - } - - delete[] vars; - delete[] varSizes; - - return result; -} - -bool PlainSave::save(int16 dataVar, int32 size, int32 offset, const char *name, - const byte *variables, const byte *variableSizes) const { - - if ((size <= 0) || (offset != 0)) { - warning("Invalid size (%d) or offset (%d)", size, offset); - return false; - } - - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::OutSaveFile *out = saveMan->openForSaving(name); - - if (!out) { - warning("Can't open file \"%s\" for writing", name); - return false; - } - - bool retVal; - retVal = SaveLoad::saveDataEndian(*out, dataVar, size, - variables, variableSizes, _endianness); - - out->finalize(); - if (out->err()) { - warning("Can't write to file \"%s\"", name); - retVal = false; - } - - delete out; - return retVal; -} - -bool PlainSave::load(int16 dataVar, int32 size, int32 offset, const char *name, - byte *variables, byte *variableSizes) const { - - if ((size <= 0) || (offset != 0)) { - warning("Invalid size (%d) or offset (%d)", size, offset); - return false; - } - - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::InSaveFile *in = saveMan->openForLoading(name); - - if (!in) { - warning("Can't open file \"%s\" for reading", name); - return false; - } - - bool retVal = SaveLoad::loadDataEndian(*in, dataVar, size, - variables, variableSizes, _endianness); - delete in; - return retVal; -} - - -StagedSave::StagedSave(Endianness endianness) : _endianness(endianness) { - _mode = kModeNone; - _name = 0; - _loaded = false; -} - -StagedSave::~StagedSave() { - clear(); -} - -void StagedSave::addStage(int32 size, bool endianed) { - int32 offset = 0; - - if (!_stages.empty()) - offset = _stages[_stages.size() - 1].offset + - _stages[_stages.size() - 1].size; - - Stage stage(size, offset, endianed); - _stages.push_back(stage); -} - -int StagedSave::findStage(int16 dataVar, int32 size, int32 offset) const { - for (uint i = 0; i < _stages.size(); i++) - if ((_stages[i].size == size) && - (_stages[i].offset == offset)) - return i; - - return -1; -} - -bool StagedSave::allSaved() const { - for (uint i = 0; i < _stages.size(); i++) - if (!_stages[i].bufVar) - return false; - - return true; -} - -uint32 StagedSave::getSize() const { - uint32 size = 0; - - for (uint i = 0; i < _stages.size(); i++) { - if (_stages[i].endianed) - size += 2 * _stages[i].size; - else - size += _stages[i].size; - } - - return size; -} - -void StagedSave::clear() { - for (uint i = 0; i < _stages.size(); i++) { - delete[] _stages[i].bufVar; - delete[] _stages[i].bufVarSizes; - _stages[i].bufVar = 0; - _stages[i].bufVarSizes = 0; - } - - delete[] _name; - _name = 0; - - _mode = kModeNone; - _loaded = false; -} - -void StagedSave::assertMode(Mode mode, const char *name) { - if ((_mode != mode) || ((name[0] != '\0') && strcmp(_name, name))) { - clear(); - _mode = mode; - _name = new char[strlen(name) + 1]; - strcpy(_name, name); - } -} - -bool StagedSave::save(int16 dataVar, int32 size, int32 offset, const char *name, - const Variables *variables) { - - if ((dataVar < 0) || (size <= 0) || (offset < 0)) { - warning("Invalid dataVar (%d), size (%d) or offset (%d)", dataVar, size, offset); - return false; - } - - byte *vars = 0, *varSizes = 0; - - if (variables) { - vars = new byte[size]; - varSizes = new byte[size]; - - if (!variables->copyTo(dataVar, vars, varSizes, size)) { - delete[] vars; - delete[] varSizes; - warning("dataVar (%d) or size (%d) out of range", dataVar, size); - return false; - } - } - - bool result = save(0, size, offset, name, vars, varSizes); - - delete[] vars; - delete[] varSizes; - - return result; -} - -bool StagedSave::load(int16 dataVar, int32 size, int32 offset, const char *name, - Variables *variables) { - - if ((dataVar < 0) || (size <= 0) || (offset < 0)) { - warning("Invalid dataVar (%d), size (%d) or offset (%d)", dataVar, size, offset); - return false; - } - - byte *vars = new byte[size]; - byte *varSizes = new byte[size]; - - bool result = load(0, size, offset, name, vars, varSizes); - - if (result && variables) { - if (!variables->copyFrom(dataVar, vars, varSizes, size)) { - delete[] vars; - delete[] varSizes; - warning("dataVar (%d) or size (%d) out of range", dataVar, size); - return false; - } - } - - delete[] vars; - delete[] varSizes; - - return result; -} - -bool StagedSave::save(int16 dataVar, int32 size, int32 offset, const char *name, - const byte *variables, const byte *variableSizes) { - - if ((dataVar < 0) || (size <= 0) || (offset < 0)) { - warning("Invalid dataVar (%d), size (%d) or offset (%d)", dataVar, size, offset); - return false; - } - - int stage = findStage(dataVar, size, offset); - if (stage == -1) { - warning("Invalid saving procedure"); - return false; - } - - if (!variables || (_stages[stage].endianed && !variableSizes)) { - warning("Missing data"); - return false; - } - - assertMode(kModeSave, name); - - _stages[stage].bufVar = new byte[size]; - memcpy(_stages[stage].bufVar, variables + dataVar, size); - - if (_stages[stage].endianed) { - _stages[stage].bufVarSizes = new byte[size]; - memcpy(_stages[stage].bufVarSizes, variableSizes + dataVar, size); - } - - if (allSaved()) { - bool result = write(); - clear(); - return result; - } - - return true; -} - -bool StagedSave::load(int16 dataVar, int32 size, int32 offset, const char *name, - byte *variables, byte *variableSizes) { - - if ((dataVar < 0) || (size <= 0) || (offset < 0)) { - warning("Invalid dataVar (%d), size (%d) or offset (%d)", dataVar, size, offset); - return false; - } - - int stage = findStage(dataVar, size, offset); - if (stage == -1) { - warning("Invalid loading procedure"); - return false; - } - - assertMode(kModeLoad, name); - - if (!_loaded) { - if (!read()) { - clear(); - return false; - } - } - - if (variables) - memcpy(variables + dataVar, _stages[stage].bufVar, size); - if (_stages[stage].endianed && variableSizes) - memcpy(variableSizes + dataVar, _stages[stage].bufVarSizes, size); - - return true; -} - -bool StagedSave::write() const { - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::OutSaveFile *out = saveMan->openForSaving(_name); - - if (!out) { - warning("Can't open file \"%s\" for writing", _name); - return false; - } - - bool result = true; - for (uint i = 0; (i < _stages.size()) && result; i++) { - if (!_stages[i].endianed) { - - uint32 written = out->write(_stages[i].bufVar, _stages[i].size); - - result = (written == ((uint32) _stages[i].size)); - if (!result) - warning("Can't write data: requested %d, wrote %d", _stages[i].size, written); - - } else - result = SaveLoad::saveDataEndian(*out, 0, _stages[i].size, - _stages[i].bufVar, _stages[i].bufVarSizes, _endianness); - } - - if (result) { - out->finalize(); - if (out->err()) { - warning("Can't write to file \"%s\"", _name); - result = false; - } - } - - delete out; - return result; -} - -bool StagedSave::read() { - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::InSaveFile *in = saveMan->openForLoading(_name); - - if (!in) { - warning("Can't open file \"%s\" for reading", _name); - return false; - } - - int32 saveSize = getSize(); - if (in->size() != saveSize) { - warning("Wrong size (%d != %d)", in->size(), saveSize); - return false; - } - - bool result = true; - for (uint i = 0; ((i < _stages.size()) && result); i++) { - _stages[i].bufVar = new byte[_stages[i].size]; - - if (!_stages[i].endianed) { - - uint32 nRead = in->read(_stages[i].bufVar, _stages[i].size); - - result = (nRead == ((uint32) _stages[i].size)); - if (!result) - warning("Can't read data: requested %d, got %d", _stages[i].size, nRead); - - } else { - _stages[i].bufVarSizes = new byte[_stages[i].size]; - - result = SaveLoad::loadDataEndian(*in, 0, _stages[i].size, - _stages[i].bufVar, _stages[i].bufVarSizes, _endianness); - } - } - - if (result) - _loaded = true; - - delete in; - return result; -} - - -PagedBuffer::PagedBuffer(uint32 pageSize) { - - _size = 0; - _pageSize = pageSize; -} - -PagedBuffer::~PagedBuffer() { - clear(); -} - -bool PagedBuffer::empty() const { - return _pages.empty(); -} - -uint32 PagedBuffer::getSize() const { - return _size; -} - -void PagedBuffer::clear() { - for (uint i = 0; i < _pages.size(); i++) - delete[] _pages[i]; - _pages.clear(); - _size = 0; -} - -bool PagedBuffer::write(const byte *buffer, uint32 size, uint32 offset) { - grow(size, offset); - - uint page = offset / _pageSize; - while (size > 0) { - if (!_pages[page]) - _pages[page] = new byte[_pageSize]; - - uint32 pStart = offset % _pageSize; - uint32 n = MIN(size, _pageSize - pStart); - - memcpy(_pages[page] + pStart, buffer, n); - - buffer += n; - offset += n; - size -= n; - page++; - } - - return true; -} - -bool PagedBuffer::read(byte *buffer, uint32 size, uint32 offset) const { - uint page = offset / _pageSize; - - while (size > 0) { - if (offset >= _size) { - memset(buffer, 0, size); - break; - } - - uint32 pStart = offset % _pageSize; - uint32 n = MIN(MIN(size, _pageSize - pStart), _size - offset); - - if (_pages[page]) - memcpy(buffer, _pages[page] + pStart, n); - else - memset(buffer, 0, n); - - buffer += n; - offset += n; - size -= n; - page++; - } - - return true; -} - -uint32 PagedBuffer::writeToStream(Common::WriteStream &out) const { - for (uint i = 0; i < _pages.size(); i++) { - if (!_pages[i]) { - for (uint32 j = 0; j < _pageSize; j++) - out.writeByte(0); - } else - out.write(_pages[i], _pageSize); - } - - return _size; -} - -uint32 PagedBuffer::readFromStream(Common::ReadStream &in) { - clear(); - - while (!in.eos()) { - byte *buffer = new byte[_pageSize]; - - _size += in.read(buffer, _pageSize); - - _pages.push_back(buffer); - } - - return _size; -} - -void PagedBuffer::grow(uint32 size, uint32 offset) { - uint32 eSize = offset + size; - - while (_size < eSize) { - _pages.push_back(0); - _size += MIN(_pageSize, eSize - _size); - } -} - - -SaveLoad::SaveLoad(GobEngine *vm, const char *targetName) : _vm(vm) { - - _targetName = new char[strlen(targetName) + 1]; - strcpy(_targetName, targetName); -} - -SaveLoad::~SaveLoad() { - delete[] _targetName; -} - -int32 SaveLoad::getSize(const char *fileName) { - int type; - - type = getSaveType(stripPath(fileName)); - if (type == -1) - return -1; - - debugC(3, kDebugSaveLoad, "Requested size of save file \"%s\" (type %d)", - fileName, type); - - return getSizeVersioned(type); -} - -bool SaveLoad::load(const char *fileName, int16 dataVar, int32 size, int32 offset) { - int type; - - type = getSaveType(stripPath(fileName)); - if (type == -1) - return false; - - debugC(3, kDebugSaveLoad, "Requested loading of save file \"%s\" (type %d) - %d, %d, %d", - fileName, type, dataVar, size, offset); - - return loadVersioned(type, dataVar, size, offset); -} - -bool SaveLoad::save(const char *fileName, int16 dataVar, int32 size, int32 offset) { - int type; - - type = getSaveType(stripPath(fileName)); - if (type == -1) - return false; - - debugC(3, kDebugSaveLoad, "Requested saving of save file \"%s\" (type %d) - %d, %d, %d", - fileName, type, dataVar, size, offset); - - return saveVersioned(type, dataVar, size, offset); -} - -const char *SaveLoad::stripPath(const char *fileName) { - const char *backSlash; - if ((backSlash = strrchr(fileName, '\\'))) - return backSlash + 1; - - return fileName; -} - -char *SaveLoad::setCurrentSlot(char *destName, int slot) { - char *slotBase = destName + strlen(destName) - 2; - - snprintf(slotBase, 3, "%02d", slot); - - return destName; -} - -void SaveLoad::buildIndex(byte *buffer, char *name, int n, int32 size, int32 offset) { - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::InSaveFile *in; - - for (int i = 0; i < n; i++, buffer += size) { - in = saveMan->openForLoading(setCurrentSlot(name, i)); - if (in) { - in->seek(offset); - in->read(buffer, size); - delete in; - } else - memset(buffer, 0, size); - } -} - -bool SaveLoad::fromEndian(byte *buf, const byte *sizes, uint32 count, Endianness endianness) { - bool LE = (endianness == kEndiannessLE); - - while (count-- > 0) { - if (*sizes == 3) - *((uint32 *) buf) = LE ? READ_LE_UINT32(buf) : READ_BE_UINT32(buf); - else if (*sizes == 1) - *((uint16 *) buf) = LE ? READ_LE_UINT16(buf) : READ_BE_UINT16(buf); - else if (*sizes != 0) { - warning("SaveLoad::fromEndian(): Corrupted variables sizes"); - return false; - } - - count -= *sizes; - buf += *sizes + 1; - sizes += *sizes + 1; - } - - return true; -} - -bool SaveLoad::toEndian(byte *buf, const byte *sizes, uint32 count, Endianness endianness) { - while (count-- > 0) { - if (*sizes == 3) { - if (endianness == kEndiannessLE) - WRITE_LE_UINT32(buf, *((uint32 *) buf)); - else - WRITE_BE_UINT32(buf, *((uint32 *) buf)); - } else if (*sizes == 1) { - if (endianness == kEndiannessLE) - WRITE_LE_UINT16(buf, *((uint16 *) buf)); - else - WRITE_BE_UINT16(buf, *((uint16 *) buf)); - } - else if (*sizes != 0) { - warning("SaveLoad::toEndian(): Corrupted variables sizes"); - return false; - } - - count -= *sizes; - buf += *sizes + 1; - sizes += *sizes + 1; - } - - return true; -} - -uint32 SaveLoad::read(Common::ReadStream &in, - byte *buf, byte *sizes, uint32 count) { - uint32 nRead; - - nRead = in.read(buf, count); - if (nRead != count) { - warning("Can't read data: requested %d, got %d", count, nRead); - return 0; - } - - nRead = in.read(sizes, count); - if (nRead != count) { - warning("Can't read data sizes: requested %d, got %d", count, nRead); - return 0; - } - - return count; -} - -uint32 SaveLoad::write(Common::WriteStream &out, - const byte *buf, const byte *sizes, uint32 count) { - uint32 written; - - written = out.write(buf, count); - if (written != count) { - warning("Can't write data: requested %d, wrote %d", count, written); - return 0; - } - - written = out.write(sizes, count); - if (written != count) { - warning("Can't write data: requested %d, wrote %d", count, written); - return 0; - } - - return count; -} - -bool SaveLoad::loadDataEndian(Common::ReadStream &in, - int16 dataVar, uint32 size, - byte *variables, byte *variableSizes, Endianness endianness) { - - bool retVal = false; - - byte *varBuf = new byte[size]; - byte *sizeBuf = new byte[size]; - - assert(varBuf && sizeBuf); - - if (read(in, varBuf, sizeBuf, size) == size) { - if (fromEndian(varBuf, sizeBuf, size, endianness)) { - memcpy(variables + dataVar, varBuf, size); - memcpy(variableSizes + dataVar, sizeBuf, size); - retVal = true; - } - } - - delete[] varBuf; - delete[] sizeBuf; - - return retVal; -} - -bool SaveLoad::saveDataEndian(Common::WriteStream &out, - int16 dataVar, uint32 size, - const byte *variables, const byte *variableSizes, Endianness endianness) { - - bool retVal = false; - - byte *varBuf = new byte[size]; - byte *sizeBuf = new byte[size]; - - assert(varBuf && sizeBuf); - - memcpy(varBuf, variables + dataVar, size); - memcpy(sizeBuf, variableSizes + dataVar, size); - - if (toEndian(varBuf, sizeBuf, size, endianness)) - if (write(out, varBuf, sizeBuf, size) == size) - retVal = true; - - delete[] varBuf; - delete[] sizeBuf; - - return retVal; -} - -SaveLoad::SaveMode SaveLoad::getSaveMode(const char *fileName) { return kSaveModeNone; } -int SaveLoad::getSaveType(const char *fileName) { return -1; } -int32 SaveLoad::getSizeVersioned(int type) { return -1; } -bool SaveLoad::loadVersioned(int type, int16 dataVar, int32 size, int32 offset) { return false; } -bool SaveLoad::saveVersioned(int type, int16 dataVar, int32 size, int32 offset) { return false; } - -} // End of namespace Gob diff --git a/engines/gob/saveload.h b/engines/gob/saveload.h deleted file mode 100644 index c14b4f2680..0000000000 --- a/engines/gob/saveload.h +++ /dev/null @@ -1,464 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#ifndef GOB_SAVELOAD_H -#define GOB_SAVELOAD_H - -#include "common/array.h" -#include "common/stream.h" - -#include "gob/video.h" -#include "gob/variables.h" - -namespace Gob { - -class TempSprite { -public: - TempSprite(); - ~TempSprite(); - - bool getProperties(int16 dataVar, int32 size, int32 offset, - int &index, bool &palette) const; - - int32 getSize() const; - - bool saveSprite(const SurfaceDesc &surfDesc); - bool savePalette(const Video::Color *palette); - bool loadSprite(SurfaceDesc &surfDesc); - bool loadPalette(Video::Color *palette); - - bool toBuffer(byte *buffer, int32 size, bool palette) const; - bool fromBuffer(const byte *buffer, int32 size, bool palette); - -private: - byte *_sprite; - int16 _width; - int16 _height; - int32 _size; - Video::Color _palette[256]; - - int getSpriteIndex(int32 size) const; - bool getSpritePalette(int32 size) const; -}; - -class PlainSave { -public: - PlainSave(Endianness endianness); - ~PlainSave(); - - bool save(int16 dataVar, int32 size, int32 offset, const char *name, - const Variables *variables); - bool load(int16 dataVar, int32 size, int32 offset, const char *name, - Variables *variables); - - bool save(int16 dataVar, int32 size, int32 offset, const char *name, - const byte *variables, const byte *variableSizes) const; - bool load(int16 dataVar, int32 size, int32 offset, const char *name, - byte *variables, byte *variableSizes) const; - -private: - Endianness _endianness; -}; - -class StagedSave { -public: - StagedSave(Endianness endianness); - ~StagedSave(); - - void addStage(int32 size, bool endianed = true); - - bool save(int16 dataVar, int32 size, int32 offset, const char *name, - const Variables *variables); - bool load(int16 dataVar, int32 size, int32 offset, const char *name, - Variables *variables); - - bool save(int16 dataVar, int32 size, int32 offset, const char *name, - const byte *variables, const byte *variableSizes); - bool load(int16 dataVar, int32 size, int32 offset, const char *name, - byte *variables, byte *variableSizes); - -private: - struct Stage { - byte *bufVar; - byte *bufVarSizes; - int32 size; - int32 offset; - bool endianed; - - Stage(int32 s = 0, int32 off = 0, bool end = true) : - bufVar(0), bufVarSizes(0), size(s), offset(off), endianed(end) {} - }; - - enum Mode { - kModeNone, - kModeSave, - kModeLoad - }; - - Endianness _endianness; - - Common::Array<Stage> _stages; - enum Mode _mode; - char *_name; - - bool _loaded; - - int findStage(int16 dataVar, int32 size, int32 offset) const; - bool allSaved() const; - - uint32 getSize() const; - - void clear(); - void assertMode(Mode mode, const char *name); - - bool write() const; - bool read(); -}; - -class PagedBuffer { -public: - PagedBuffer(uint32 pageSize = 1024); - ~PagedBuffer(); - - bool empty() const; - uint32 getSize() const; - - void clear(); - - bool write(const byte *buffer, uint32 size, uint32 offset); - bool read(byte *buffer, uint32 size, uint32 offset) const; - - uint32 writeToStream(Common::WriteStream &out) const; - uint32 readFromStream(Common::ReadStream &in); - -private: - uint32 _size; - uint32 _pageSize; - Common::Array<byte *> _pages; - - void grow(uint32 size, uint32 offset); -}; - -class SaveLoad { -public: - enum SaveMode { - kSaveModeNone, - kSaveModeIgnore, - kSaveModeExists, - kSaveModeSave - }; - - SaveLoad(GobEngine *vm, const char *targetName); - virtual ~SaveLoad(); - - virtual SaveMode getSaveMode(const char *fileName); - - int32 getSize(const char *fileName); - bool load(const char *fileName, int16 dataVar, int32 size, int32 offset); - bool save(const char *fileName, int16 dataVar, int32 size, int32 offset); - - char *setCurrentSlot(char *destName, int slot); - void buildIndex(byte *buffer, char *name, int n, int32 size, int32 offset = 0); - - static const char *stripPath(const char *fileName); - - static bool fromEndian(byte *buf, const byte *sizes, uint32 count, Endianness endianness); - static bool toEndian(byte *buf, const byte *sizes, uint32 count, Endianness endianness); - static uint32 read(Common::ReadStream &in, - byte *buf, byte *sizes, uint32 count); - static uint32 write(Common::WriteStream &out, - const byte *buf, const byte *sizes, uint32 count); - - static bool loadDataEndian(Common::ReadStream &in, - int16 dataVar, uint32 size, - byte *variables, byte *variableSizes, Endianness endianness); - static bool saveDataEndian(Common::WriteStream &out, - int16 dataVar, uint32 size, - const byte *variables, const byte *variableSizes, Endianness endianness); - -protected: - GobEngine *_vm; - - char *_targetName; - - virtual int getSaveType(const char *fileName); - - virtual int32 getSizeVersioned(int type); - virtual bool loadVersioned(int type, int16 dataVar, int32 size, int32 offset); - virtual bool saveVersioned(int type, int16 dataVar, int32 size, int32 offset); -}; - -class SaveLoad_v2 : public SaveLoad { -public: - enum SaveType { - kSaveGame, - kSaveTempSprite, - kSaveNotes - }; - - SaveLoad_v2(GobEngine *vm, const char *targetName); - virtual ~SaveLoad_v2(); - - virtual SaveMode getSaveMode(const char *fileName); - -protected: - struct SaveFile { - const char *sourceName; - char *destName; - SaveMode mode; - SaveType type; - }; - - static SaveFile _saveFiles[]; - - int32 _varSize; - - TempSprite _tmpSprite; - PlainSave *_notes; - StagedSave *_save; - - byte _indexBuffer[600]; - bool _hasIndex; - - virtual int getSaveType(const char *fileName); - - virtual int32 getSizeVersioned(int type); - virtual bool loadVersioned(int type, int16 dataVar, int32 size, int32 offset); - virtual bool saveVersioned(int type, int16 dataVar, int32 size, int32 offset); - - int getSlot(int32 offset) const; - int getSlotRemainder(int32 offset) const; - - int32 getSizeGame(SaveFile &saveFile); - int32 getSizeTempSprite(SaveFile &saveFile); - int32 getSizeNotes(SaveFile &saveFile); - - bool loadGame(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - bool loadTempSprite(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - bool loadNotes(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - - bool saveGame(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - bool saveTempSprite(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - bool saveNotes(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - - void assertInited(); -}; - -enum SaveType { - kSaveNone = -1, - kSaveGame, - kSaveTempSprite, - kSaveNotes, - kSaveScreenshot, - kSaveIgnore -}; - -class SaveLoad_v3 : public SaveLoad { -public: - enum SaveType { - kSaveNone, - kSaveGame, - kSaveTempSprite, - kSaveNotes, - kSaveScreenshot - }; - - SaveLoad_v3(GobEngine *vm, const char *targetName, - uint32 screenshotSize = 19968, - int32 indexOffset = 40, int32 screenshotOffset = 80); - virtual ~SaveLoad_v3(); - - virtual SaveMode getSaveMode(const char *fileName); - -protected: - struct SaveFile { - const char *sourceName; - char *destName; - SaveMode mode; - SaveType type; - int slot; - }; - - bool _useScreenshots; - bool _firstSizeGame; - - uint32 _screenshotSize; - int32 _indexOffset; - int32 _screenshotOffset; - - static SaveFile _saveFiles[]; - - int32 _varSize; - - TempSprite _screenshot; - TempSprite _tmpSprite; - PlainSave *_notes; - StagedSave *_save; - - byte _propBuffer[1000]; - byte _indexBuffer[1200]; - bool _hasIndex; - - virtual int getSaveType(const char *fileName); - - virtual int32 getSizeVersioned(int type); - virtual bool loadVersioned(int type, int16 dataVar, int32 size, int32 offset); - virtual bool saveVersioned(int type, int16 dataVar, int32 size, int32 offset); - - int getSlot(int32 offset) const; - int getSlotRemainder(int32 offset) const; - - int32 getSizeGame(SaveFile &saveFile); - int32 getSizeTempSprite(SaveFile &saveFile); - int32 getSizeNotes(SaveFile &saveFile); - int32 getSizeScreenshot(SaveFile &saveFile); - - bool loadGame(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - bool loadTempSprite(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - bool loadNotes(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - bool loadScreenshot(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - - bool saveGame(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - bool saveTempSprite(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - bool saveNotes(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - bool saveScreenshot(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - - void assertInited(); - - void buildScreenshotIndex(byte *buffer, char *name, int n); -}; - -class SaveLoad_v4 : public SaveLoad { -public: - enum SaveType { - kSaveNone, - kSaveScreenProps, - kSaveGame, - kSaveGameScreenProps - }; - - bool _firstSizeGame; - - SaveLoad_v4(GobEngine *vm, const char *targetName); - virtual ~SaveLoad_v4(); - - virtual SaveMode getSaveMode(const char *fileName); - -protected: - struct SaveFile { - const char *sourceName; - char *destName; - SaveMode mode; - SaveType type; - }; - - static SaveFile _saveFiles[]; - - int32 _varSize; - - StagedSave *_save; - - byte _propBuffer[1000]; - byte _indexBuffer[1200]; - bool _hasIndex; - - byte *_screenProps; - - virtual int getSaveType(const char *fileName); - - virtual int32 getSizeVersioned(int type); - virtual bool loadVersioned(int type, int16 dataVar, int32 size, int32 offset); - virtual bool saveVersioned(int type, int16 dataVar, int32 size, int32 offset); - - int getSlot(int32 offset) const; - int getSlotRemainder(int32 offset) const; - - int32 getSizeScreenProps(SaveFile &saveFile); - int32 getSizeGame(SaveFile &saveFile); - int32 getSizeGameScreenProps(SaveFile &saveFile); - - bool loadScreenProps(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - bool loadGame(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - bool loadGameScreenProps(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - - bool saveScreenProps(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - bool saveGame(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - bool saveGameScreenProps(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - - void assertInited(); -}; - -class SaveLoad_v6 : public SaveLoad { -public: - enum SaveType { - kSaveNone, - kSaveGame, - kSaveNoCD - }; - - SaveLoad_v6(GobEngine *vm, const char *targetName); - virtual ~SaveLoad_v6(); - - virtual SaveMode getSaveMode(const char *fileName); - -protected: - struct SaveFile { - const char *sourceName; - char *destName; - SaveMode mode; - SaveType type; - }; - - static SaveFile _saveFiles[]; - - int32 _varSize; - - StagedSave *_save; - - byte _indexBuffer[2900]; - - virtual int getSaveType(const char *fileName); - - virtual int32 getSizeVersioned(int type); - virtual bool loadVersioned(int type, int16 dataVar, int32 size, int32 offset); - virtual bool saveVersioned(int type, int16 dataVar, int32 size, int32 offset); - - int getSlot(int32 offset) const; - int getSlotRemainder(int32 offset) const; - - int32 getSizeGame(SaveFile &saveFile); - - bool loadGame(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - - bool saveGame(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - - void assertInited(); - - void refreshIndex(); -}; - -} // End of namespace Gob - -#endif // GOB_SAVELOAD_H diff --git a/engines/gob/saveload_v2.cpp b/engines/gob/saveload_v2.cpp deleted file mode 100644 index e58799a6db..0000000000 --- a/engines/gob/saveload_v2.cpp +++ /dev/null @@ -1,373 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/endian.h" -#include "common/savefile.h" - -#include "gob/gob.h" -#include "gob/saveload.h" -#include "gob/global.h" -#include "gob/game.h" -#include "gob/draw.h" -#include "gob/inter.h" - -namespace Gob { - -SaveLoad_v2::SaveFile SaveLoad_v2::_saveFiles[] = { - { "cat.inf", 0, kSaveModeSave, kSaveGame}, - { "cat.cat", 0, kSaveModeSave, kSaveGame}, - { "save.inf", 0, kSaveModeSave, kSaveTempSprite}, - { "bloc.inf", 0, kSaveModeSave, kSaveNotes} -}; - -SaveLoad_v2::SaveLoad_v2(GobEngine *vm, const char *targetName) : - SaveLoad(vm, targetName) { - - _notes = new PlainSave(_vm->getEndianness()); - _save = new StagedSave(_vm->getEndianness()); - - _saveFiles[0].destName = new char[strlen(targetName) + 5]; - _saveFiles[1].destName = _saveFiles[0].destName; - _saveFiles[2].destName = 0; - _saveFiles[3].destName = new char[strlen(targetName) + 5]; - - sprintf(_saveFiles[0].destName, "%s.s00", targetName); - sprintf(_saveFiles[3].destName, "%s.blo", targetName); - - _varSize = 0; - _hasIndex = false; -} - -SaveLoad_v2::~SaveLoad_v2() { - delete _notes; - delete _save; - - delete[] _saveFiles[0].destName; - delete[] _saveFiles[3].destName; -} - -SaveLoad::SaveMode SaveLoad_v2::getSaveMode(const char *fileName) { - fileName = stripPath(fileName); - - for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) - if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) - return _saveFiles[i].mode; - - return kSaveModeNone; -} - -int SaveLoad_v2::getSaveType(const char *fileName) { - for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) - if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) - return i; - - return -1; -} - -int32 SaveLoad_v2::getSizeVersioned(int type) { - assertInited(); - - switch (_saveFiles[type].type) { - case kSaveGame: - return getSizeGame(_saveFiles[type]); - case kSaveTempSprite: - return getSizeTempSprite(_saveFiles[type]); - case kSaveNotes: - return getSizeNotes(_saveFiles[type]); - } - - return -1; -} - -bool SaveLoad_v2::loadVersioned(int type, int16 dataVar, int32 size, int32 offset) { - assertInited(); - - switch (_saveFiles[type].type) { - case kSaveGame: - if (loadGame(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While loading from slot %d", getSlot(offset)); - break; - - case kSaveTempSprite: - if (loadTempSprite(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While loading the temporary sprite"); - break; - - case kSaveNotes: - if (loadNotes(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While loading the notes"); - break; - } - - return false; -} - -bool SaveLoad_v2::saveVersioned(int type, int16 dataVar, int32 size, int32 offset) { - assertInited(); - - switch (_saveFiles[type].type) { - case kSaveGame: - if (saveGame(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While saving to slot %d", getSlot(offset)); - break; - - case kSaveTempSprite: - if (saveTempSprite(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While saving the temporary sprite"); - break; - - case kSaveNotes: - if (saveNotes(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While saving the notes"); - break; - } - - return false; -} - -int SaveLoad_v2::getSlot(int32 offset) const { - return ((offset - 600) / _varSize); -} - -int SaveLoad_v2::getSlotRemainder(int32 offset) const { - return ((offset - 600) % _varSize); -} - -int32 SaveLoad_v2::getSizeGame(SaveFile &saveFile) { - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::InSaveFile *in; - - for (int i = 14; i >= 0; i--) { - in = saveMan->openForLoading(setCurrentSlot(saveFile.destName, i)); - if (in) { - delete in; - return (i + 1) * _varSize + 600; - } - } - - return -1; -} - -int32 SaveLoad_v2::getSizeTempSprite(SaveFile &saveFile) { - return _tmpSprite.getSize(); -} - -int32 SaveLoad_v2::getSizeNotes(SaveFile &saveFile) { - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::InSaveFile *in; - int32 size = -1; - - in = saveMan->openForLoading(saveFile.destName); - if (in) { - size = in->size(); - delete in; - } - - return size; -} - -bool SaveLoad_v2::loadGame(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - if (size == 0) { - dataVar = 0; - size = _varSize; - } - - if (offset == 0) { - debugC(3, kDebugSaveLoad, "Loading save index"); - - if (size != 600) { - warning("Requested index has wrong size (%d)", size); - return false; - } - - SaveLoad::buildIndex(_vm->_inter->_variables->getAddressOff8(dataVar, 600), - saveFile.destName, 15, 40); - - } else { - int slot = getSlot(offset); - int slotRem = getSlotRemainder(offset); - - debugC(2, kDebugSaveLoad, "Loading from slot %d", slot); - - SaveLoad::setCurrentSlot(saveFile.destName, slot); - - if ((slot >= 15) || (slotRem != 0)) { - warning("Invalid loading procedure (%d, %d, %d, %d, %d)", - dataVar, size, offset, slot, slotRem); - return false; - } - - if (!_save->load(dataVar, size, 40, saveFile.destName, _vm->_inter->_variables)) - return false; - } - - return true; -} - -bool SaveLoad_v2::loadTempSprite(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - debugC(3, kDebugSaveLoad, "Loading from the temporary sprite"); - - int index; - bool palette; - - if (!_tmpSprite.getProperties(dataVar, size, offset, index, palette)) - return false; - - if (!_tmpSprite.loadSprite(*_vm->_draw->_spritesArray[index])) - return false; - - if (palette) { - if (!_tmpSprite.loadPalette(_vm->_global->_pPaletteDesc->vgaPal)) - return false; - - _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); - } - - if (index == 21) { - _vm->_draw->forceBlit(); - _vm->_video->retrace(); - } - - return true; -} - -bool SaveLoad_v2::loadNotes(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - debugC(2, kDebugSaveLoad, "Loading the notes"); - - return _notes->load(dataVar, size, offset, saveFile.destName, _vm->_inter->_variables); -} - -bool SaveLoad_v2::saveGame(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - if (size == 0) { - dataVar = 0; - size = _varSize; - } - - if (offset == 0) { - debugC(3, kDebugSaveLoad, "Saving save index"); - - if (size != 600) { - warning("Requested index has wrong size (%d)", size); - return false; - } - - _vm->_inter->_variables->copyTo(dataVar, _indexBuffer, 0, 600); - _hasIndex = true; - - } else { - int slot = getSlot(offset); - int slotRem = getSlotRemainder(offset); - - debugC(2, kDebugSaveLoad, "Saving to slot %d", slot); - - SaveLoad::setCurrentSlot(saveFile.destName, slot); - - if ((slot >= 15) || (slotRem != 0)) { - warning("Invalid saving procedure (%d, %d, %d, %d, %d)", - dataVar, size, offset, slot, slotRem); - return false; - } - - if (!_hasIndex) { - warning("No index written yet"); - return false; - } - - _hasIndex = false; - - byte sizes[40]; - memset(sizes, 0, 40); - if (!_save->save(0, 40, 0, saveFile.destName, _indexBuffer + (slot * 40), sizes)) - return false; - - if (!_save->save(dataVar, size, 40, saveFile.destName, _vm->_inter->_variables)) - return false; - - } - - return true; -} - -bool SaveLoad_v2::saveTempSprite(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - debugC(3, kDebugSaveLoad, "Saving to the temporary sprite"); - - int index; - bool palette; - - if (!_tmpSprite.getProperties(dataVar, size, offset, index, palette)) - return false; - - if (!_tmpSprite.saveSprite(*_vm->_draw->_spritesArray[index])) - return false; - - if (palette) - if (!_tmpSprite.savePalette(_vm->_global->_pPaletteDesc->vgaPal)) - return false; - - return true; -} - -bool SaveLoad_v2::saveNotes(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - debugC(2, kDebugSaveLoad, "Saving the notes"); - - return _notes->save(dataVar, size, offset, saveFile.destName, _vm->_inter->_variables); - return false; -} - -void SaveLoad_v2::assertInited() { - if (_varSize > 0) - return; - - _varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4; - - _save->addStage(40); - _save->addStage(_varSize); -} - -} // End of namespace Gob diff --git a/engines/gob/saveload_v3.cpp b/engines/gob/saveload_v3.cpp deleted file mode 100644 index 806ac75939..0000000000 --- a/engines/gob/saveload_v3.cpp +++ /dev/null @@ -1,616 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/endian.h" -#include "common/savefile.h" - -#include "gob/gob.h" -#include "gob/saveload.h" -#include "gob/global.h" -#include "gob/game.h" -#include "gob/draw.h" -#include "gob/inter.h" - -namespace Gob { - -SaveLoad_v3::SaveFile SaveLoad_v3::_saveFiles[] = { - { "cat.inf", 0, kSaveModeSave, kSaveGame, -1}, - { "ima.inf", 0, kSaveModeSave, kSaveScreenshot, -1}, - { "intro.$$$", 0, kSaveModeSave, kSaveTempSprite, -1}, - { "bloc.inf", 0, kSaveModeSave, kSaveNotes, -1}, - { "prot", 0, kSaveModeIgnore, kSaveNone, -1}, - { "config", 0, kSaveModeIgnore, kSaveNone, -1}, -}; - -SaveLoad_v3::SaveLoad_v3(GobEngine *vm, const char *targetName, - uint32 screenshotSize, int32 indexOffset, int32 screenshotOffset) : - SaveLoad(vm, targetName) { - - _notes = new PlainSave(_vm->getEndianness()); - _save = new StagedSave(_vm->getEndianness()); - - _screenshotSize = screenshotSize; - _indexOffset = indexOffset; - _screenshotOffset = screenshotOffset; - - _useScreenshots = false; - _firstSizeGame = true; - - _saveFiles[0].destName = new char[strlen(targetName) + 5]; - _saveFiles[1].destName = _saveFiles[0].destName; - _saveFiles[2].destName = 0; - _saveFiles[3].destName = new char[strlen(targetName) + 5]; - _saveFiles[4].destName = 0; - _saveFiles[5].destName = 0; - - sprintf(_saveFiles[0].destName, "%s.s00", targetName); - sprintf(_saveFiles[3].destName, "%s.blo", targetName); - - _varSize = 0; - _hasIndex = false; - memset(_propBuffer, 0, 1000); -} - -SaveLoad_v3::~SaveLoad_v3() { - delete _notes; - delete _save; - - delete[] _saveFiles[0].destName; - delete[] _saveFiles[3].destName; -} - -SaveLoad::SaveMode SaveLoad_v3::getSaveMode(const char *fileName) { - fileName = stripPath(fileName); - - for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) - if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) - return _saveFiles[i].mode; - - return kSaveModeNone; -} - -int SaveLoad_v3::getSaveType(const char *fileName) { - for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) - if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) - return i; - - return -1; -} - -int32 SaveLoad_v3::getSizeVersioned(int type) { - assertInited(); - - switch (_saveFiles[type].type) { - case kSaveGame: - return getSizeGame(_saveFiles[type]); - case kSaveTempSprite: - return getSizeTempSprite(_saveFiles[type]); - case kSaveNotes: - return getSizeNotes(_saveFiles[type]); - case kSaveScreenshot: - return getSizeScreenshot(_saveFiles[type]); - default: - break; - } - - return -1; -} - -bool SaveLoad_v3::loadVersioned(int type, int16 dataVar, int32 size, int32 offset) { - assertInited(); - - switch (_saveFiles[type].type) { - case kSaveGame: - if (loadGame(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While loading from slot %d", getSlot(offset)); - break; - - case kSaveTempSprite: - if (loadTempSprite(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While loading the temporary sprite"); - break; - - case kSaveNotes: - if (loadNotes(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While loading the notes"); - break; - - case kSaveScreenshot: - if (loadScreenshot(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While loading a screenshot"); - break; - - default: - break; - } - - return false; -} - -bool SaveLoad_v3::saveVersioned(int type, int16 dataVar, int32 size, int32 offset) { - assertInited(); - - switch (_saveFiles[type].type) { - case kSaveGame: - if (saveGame(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While saving to slot %d", getSlot(offset)); - break; - - case kSaveTempSprite: - if (saveTempSprite(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While saving the temporary sprite"); - break; - - case kSaveNotes: - if (saveNotes(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While saving the notes"); - break; - - case kSaveScreenshot: - if (saveScreenshot(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While saving a screenshot"); - break; - - default: - break; - } - - return false; -} - -int SaveLoad_v3::getSlot(int32 offset) const { - return ((offset - 1700) / _varSize); -} - -int SaveLoad_v3::getSlotRemainder(int32 offset) const { - return ((offset - 1700) % _varSize); -} - -int32 SaveLoad_v3::getSizeGame(SaveFile &saveFile) { - if (_firstSizeGame) { - _firstSizeGame = false; - return -1; - } - - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::InSaveFile *in; - int32 size = -1; - - int slot = saveFile.slot; - for (int i = 29; i >= 0; i--) { - in = saveMan->openForLoading(setCurrentSlot(saveFile.destName, i)); - if (in) { - delete in; - size = (i + 1) * _varSize + 1700; - break; - } - } - setCurrentSlot(saveFile.destName, slot); - - return size; -} - -int32 SaveLoad_v3::getSizeTempSprite(SaveFile &saveFile) { - return _tmpSprite.getSize(); -} - -int32 SaveLoad_v3::getSizeNotes(SaveFile &saveFile) { - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::InSaveFile *in; - int32 size = -1; - - in = saveMan->openForLoading(saveFile.destName); - if (in) { - size = in->size(); - delete in; - } - - return size; -} - -int32 SaveLoad_v3::getSizeScreenshot(SaveFile &saveFile) { - if (!_useScreenshots) { - _useScreenshots = true; - _save->addStage(_screenshotSize, false); - } - - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::InSaveFile *in; - int32 size = -1; - - int slot = saveFile.slot; - for (int i = 29; i >= 0; i--) { - in = saveMan->openForLoading(setCurrentSlot(saveFile.destName, i)); - if (in) { - delete in; - size = (i + 1) * _screenshotSize + _screenshotOffset; - break; - } - } - setCurrentSlot(saveFile.destName, slot); - - return size; -} - -bool SaveLoad_v3::loadGame(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - if (size == 0) { - dataVar = 0; - size = _varSize; - } - - if (offset < 500) { - debugC(3, kDebugSaveLoad, "Loading global properties"); - - if ((size + offset) > 500) { - warning("Wrong global properties list size (%d, %d)", size, offset); - return false; - } - - _vm->_inter->_variables->copyFrom(dataVar, - _propBuffer + offset, _propBuffer + offset + 500, size); - - } else if (offset == 500) { - debugC(3, kDebugSaveLoad, "Loading save index"); - - if (size != 1200) { - warning("Requested index has wrong size (%d)", size); - return false; - } - - int slot = saveFile.slot; - - SaveLoad::buildIndex(_vm->_inter->_variables->getAddressOff8(dataVar, 1200), - saveFile.destName, 30, 40, 1000); - - setCurrentSlot(saveFile.destName, slot); - - } else { - saveFile.slot = getSlot(offset); - int slotRem = getSlotRemainder(offset); - - debugC(2, kDebugSaveLoad, "Loading from slot %d", saveFile.slot); - - SaveLoad::setCurrentSlot(saveFile.destName, saveFile.slot); - - if ((saveFile.slot < 0) || (saveFile.slot >= 30) || (slotRem != 0)) { - warning("Invalid loading procedure (%d, %d, %d, %d, %d)", - dataVar, size, offset, saveFile.slot, slotRem); - return false; - } - - if (!_save->load(dataVar, size, 540, saveFile.destName, _vm->_inter->_variables)) - return false; - } - - return true; -} - -bool SaveLoad_v3::loadTempSprite(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - debugC(3, kDebugSaveLoad, "Loading from the temporary sprite"); - - int index; - bool palette; - - if (!_tmpSprite.getProperties(dataVar, size, offset, index, palette)) - return false; - - if (!_tmpSprite.loadSprite(*_vm->_draw->_spritesArray[index])) - return false; - - if (palette) { - if (!_tmpSprite.loadPalette(_vm->_global->_pPaletteDesc->vgaPal)) - return false; - - _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); - } - - if (index == 21) { - _vm->_draw->forceBlit(); - _vm->_video->retrace(); - } - - return true; -} - -bool SaveLoad_v3::loadNotes(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - debugC(2, kDebugSaveLoad, "Loading the notes"); - - return _notes->load(dataVar, size, offset, saveFile.destName, _vm->_inter->_variables); -} - -bool SaveLoad_v3::loadScreenshot(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - debugC(3, kDebugSaveLoad, "Loading a screenshot"); - - if (!_useScreenshots) { - _useScreenshots = true; - _save->addStage(_screenshotSize, false); - } - - if (offset == _indexOffset) { - if (size != 40) { - warning("Requested index has wrong size (%d)", size); - return false; - } - - byte buffer[40]; - memset(buffer, 0, 40); - - int slot = saveFile.slot; - buildScreenshotIndex(buffer, saveFile.destName, 30); - setCurrentSlot(saveFile.destName, slot); - - memcpy(_vm->_inter->_variables->getAddressOff8(dataVar, 40), buffer, 40); - - } else { - saveFile.slot = (offset - _screenshotOffset) / _screenshotSize; - int slotRem = (offset - _screenshotOffset) % _screenshotSize; - - SaveLoad::setCurrentSlot(saveFile.destName, saveFile.slot); - - if ((saveFile.slot < 0) || (saveFile.slot >= 30) || (slotRem != 0)) { - warning("Invalid loading procedure (%d, %d, %d, %d, %d)", - dataVar, size, offset, saveFile.slot, slotRem); - return false; - } - - byte *buffer = new byte[_screenshotSize]; - - if (!_save->load(0, _screenshotSize, _varSize + 540, saveFile.destName, buffer, 0)) { - delete[] buffer; - return false; - } - - int index; - bool palette; - - if (!_screenshot.getProperties(dataVar, size, offset, index, palette)) { - delete[] buffer; - return false; - } - - if (!_screenshot.fromBuffer(buffer, _screenshotSize, palette)) { - delete[] buffer; - return false; - } - - if (!_screenshot.loadSprite(*_vm->_draw->_spritesArray[index])) { - delete[] buffer; - return false; - } - - if (palette) { - if (!_screenshot.loadPalette(_vm->_global->_pPaletteDesc->vgaPal)) { - delete[] buffer; - return false; - } - _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); - } - - delete[] buffer; - } - - return true; -} - -bool SaveLoad_v3::saveGame(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - if (size == 0) { - dataVar = 0; - size = _varSize; - } - - if (offset < 500) { - debugC(3, kDebugSaveLoad, "Loading global properties"); - - if ((size + offset) > 500) { - warning("Wrong global properties list size (%d, %d)", size, offset); - return false; - } - - _vm->_inter->_variables->copyTo(dataVar, - _propBuffer + offset, _propBuffer + offset + 500, size); - - } else if (offset == 500) { - debugC(3, kDebugSaveLoad, "Saving save index"); - - if (size != 1200) { - warning("Requested index has wrong size (%d)", size); - return false; - } - - _vm->_inter->_variables->copyTo(dataVar, _indexBuffer, 0, size); - _hasIndex = true; - - } else { - saveFile.slot = getSlot(offset); - int slotRem = getSlotRemainder(offset); - - debugC(2, kDebugSaveLoad, "Saving to slot %d", saveFile.slot); - - SaveLoad::setCurrentSlot(saveFile.destName, saveFile.slot); - - if ((saveFile.slot < 0) || (saveFile.slot >= 30) || (slotRem != 0)) { - warning("Invalid saving procedure (%d, %d, %d, %d, %d)", - dataVar, size, offset, saveFile.slot, slotRem); - return false; - } - - if (!_hasIndex) { - warning("No index written yet"); - return false; - } - - _hasIndex = false; - - if (!_save->save(0, 500, 0, saveFile.destName, _propBuffer, _propBuffer + 500)) - return false; - - if (!_save->save(0, 40, 500, saveFile.destName, _indexBuffer + (saveFile.slot * 40), 0)) - return false; - - if (!_save->save(dataVar, size, 540, saveFile.destName, _vm->_inter->_variables)) - return false; - - } - - return true; -} - -bool SaveLoad_v3::saveTempSprite(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - debugC(3, kDebugSaveLoad, "Saving to the temporary sprite"); - - int index; - bool palette; - - if (!_tmpSprite.getProperties(dataVar, size, offset, index, palette)) - return false; - - if (!_tmpSprite.saveSprite(*_vm->_draw->_spritesArray[index])) - return false; - - if (palette) - if (!_tmpSprite.savePalette(_vm->_global->_pPaletteDesc->vgaPal)) - return false; - - return true; -} - -bool SaveLoad_v3::saveNotes(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - debugC(2, kDebugSaveLoad, "Saving the notes"); - - return _notes->save(dataVar, size - 160, offset, saveFile.destName, _vm->_inter->_variables); - return false; -} - -bool SaveLoad_v3::saveScreenshot(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - debugC(3, kDebugSaveLoad, "Saving a screenshot"); - - if (!_useScreenshots) { - _useScreenshots = true; - _save->addStage(_screenshotSize, false); - } - - if (offset >= _screenshotOffset) { - - saveFile.slot = (offset - _screenshotOffset) / _screenshotSize; - int slotRem = (offset - _screenshotOffset) % _screenshotSize; - - setCurrentSlot(saveFile.destName, saveFile.slot); - - if ((saveFile.slot < 0) || (saveFile.slot >= 30) || (slotRem != 0)) { - warning("Invalid saving procedure (%d, %d, %d, %d, %d)", - dataVar, size, offset, saveFile.slot, slotRem); - return false; - } - - int index; - bool palette; - - if (!_screenshot.getProperties(dataVar, size, offset, index, palette)) - return false; - - if (!_screenshot.saveSprite(*_vm->_draw->_spritesArray[index])) - return false; - - if (palette) - if (!_screenshot.savePalette(_vm->_global->_pPaletteDesc->vgaPal)) - return false; - - - byte *buffer = new byte[_screenshotSize]; - - if (!_screenshot.toBuffer(buffer, _screenshotSize, palette)) { - delete[] buffer; - return false; - } - - if (!_save->save(0, _screenshotSize, _varSize + 540, saveFile.destName, buffer, 0)) { - delete[] buffer; - return false; - } - - delete[] buffer; - } - - return true; -} - -void SaveLoad_v3::assertInited() { - if (_varSize > 0) - return; - - _varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4; - - _save->addStage(500); - _save->addStage(40, false); - _save->addStage(_varSize); -} - -void SaveLoad_v3::buildScreenshotIndex(byte *buffer, char *name, int n) { - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::InSaveFile *in; - - memset(buffer, 0, n); - for (int i = 0; i < n; i++) { - in = saveMan->openForLoading(setCurrentSlot(name, i)); - if (in) { - delete in; - buffer[i] = 1; - } - } -} - -} // End of namespace Gob diff --git a/engines/gob/saveload_v4.cpp b/engines/gob/saveload_v4.cpp deleted file mode 100644 index e7df11f6ad..0000000000 --- a/engines/gob/saveload_v4.cpp +++ /dev/null @@ -1,443 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/endian.h" - -#include "gob/gob.h" -#include "gob/saveload.h" -#include "gob/game.h" -#include "gob/inter.h" - -namespace Gob { - -SaveLoad_v4::SaveFile SaveLoad_v4::_saveFiles[] = { - { "save.tmp", 0, kSaveModeSave, kSaveScreenProps }, - { "cat.inf", 0, kSaveModeSave, kSaveGame }, - { "save0.tmp", 0, kSaveModeSave, kSaveGameScreenProps }, - { "save1.tmp", 0, kSaveModeSave, kSaveGameScreenProps }, - { "save2.tmp", 0, kSaveModeSave, kSaveGameScreenProps }, - { "save3.tmp", 0, kSaveModeSave, kSaveGameScreenProps }, - { "save4.tmp", 0, kSaveModeSave, kSaveGameScreenProps }, - { "save5.tmp", 0, kSaveModeSave, kSaveGameScreenProps }, - { "save6.tmp", 0, kSaveModeSave, kSaveGameScreenProps }, - { "save7.tmp", 0, kSaveModeSave, kSaveGameScreenProps }, - { "save8.tmp", 0, kSaveModeSave, kSaveGameScreenProps }, - { "save9.tmp", 0, kSaveModeSave, kSaveGameScreenProps } -}; - -SaveLoad_v4::SaveLoad_v4(GobEngine *vm, const char *targetName) : - SaveLoad(vm, targetName) { - - _save = new StagedSave(_vm->getEndianness()); - - _firstSizeGame = true; - - _saveFiles[0].destName = 0; - _saveFiles[1].destName = new char[strlen(targetName) + 5]; - _saveFiles[2].destName = _saveFiles[1].destName; - _saveFiles[3].destName = _saveFiles[1].destName; - _saveFiles[4].destName = _saveFiles[1].destName; - _saveFiles[5].destName = _saveFiles[1].destName; - _saveFiles[6].destName = _saveFiles[1].destName; - _saveFiles[7].destName = _saveFiles[1].destName; - _saveFiles[8].destName = _saveFiles[1].destName; - _saveFiles[9].destName = _saveFiles[1].destName; - _saveFiles[10].destName = _saveFiles[1].destName; - _saveFiles[11].destName = _saveFiles[1].destName; - - sprintf(_saveFiles[1].destName, "%s.s00", targetName); - - _varSize = 0; - _hasIndex = false; - memset(_propBuffer, 0, 1000); - - _screenProps = new byte[512000]; - memset(_screenProps, 0, 512000); -} - -SaveLoad_v4::~SaveLoad_v4() { - delete _save; - - delete[] _screenProps; - delete[] _saveFiles[1].destName; -} - -SaveLoad::SaveMode SaveLoad_v4::getSaveMode(const char *fileName) { - fileName = stripPath(fileName); - - for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) - if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) - return _saveFiles[i].mode; - - return kSaveModeNone; -} - -int SaveLoad_v4::getSaveType(const char *fileName) { - for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) - if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) - return i; - - return -1; -} - -int32 SaveLoad_v4::getSizeVersioned(int type) { - assertInited(); - - switch (_saveFiles[type].type) { - case kSaveScreenProps: - return getSizeScreenProps(_saveFiles[type]); - case kSaveGame: - return getSizeGame(_saveFiles[type]); - case kSaveGameScreenProps: - return getSizeGameScreenProps(_saveFiles[type]); - default: - break; - } - - return -1; -} - -bool SaveLoad_v4::loadVersioned(int type, int16 dataVar, int32 size, int32 offset) { - assertInited(); - - switch (_saveFiles[type].type) { - case kSaveScreenProps: - if (loadScreenProps(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While loading screen properties"); - break; - - case kSaveGame: - if (loadGame(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While loading from slot %d", getSlot(offset)); - break; - - case kSaveGameScreenProps: - if (loadGameScreenProps(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While loading screen properties from slot %d", getSlot(offset)); - break; - - default: - break; - } - - return false; -} - -bool SaveLoad_v4::saveVersioned(int type, int16 dataVar, int32 size, int32 offset) { - assertInited(); - - switch (_saveFiles[type].type) { - case kSaveScreenProps: - if (saveScreenProps(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While saving screen properties"); - break; - - case kSaveGame: - if (saveGame(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While saving to slot %d", getSlot(offset)); - break; - - case kSaveGameScreenProps: - if (saveGameScreenProps(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While saving screen properties to slot %d", getSlot(offset)); - break; - - default: - break; - } - - return false; -} - -int SaveLoad_v4::getSlot(int32 offset) const { - return ((offset - 1700) / _varSize); -} - -int SaveLoad_v4::getSlotRemainder(int32 offset) const { - return ((offset - 1700) % _varSize); -} - -int32 SaveLoad_v4::getSizeScreenProps(SaveFile &saveFile) { - return 256000; -} - -int32 SaveLoad_v4::getSizeGame(SaveFile &saveFile) { - if (_firstSizeGame) { - _firstSizeGame = false; - return -1; - } - - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::InSaveFile *in; - int32 size = -1; - - for (int i = 29; i >= 0; i--) { - in = saveMan->openForLoading(setCurrentSlot(saveFile.destName, i)); - if (in) { - delete in; - size = (i + 1) * _varSize + 1700; - break; - } - } - - return size; -} - -int32 SaveLoad_v4::getSizeGameScreenProps(SaveFile &saveFile) { - return -1; - - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::InSaveFile *in; - - setCurrentSlot(saveFile.destName, saveFile.sourceName[4] - '0'); - in = saveMan->openForLoading(saveFile.destName); - - if (!in) - return -1; - - int32 size = in->size(); - - delete in; - - return size; -} - -bool SaveLoad_v4::loadScreenProps(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - // Using a sprite as a buffer - if (size <= 0) - return true; - - if ((offset < 0) || (size + offset) > 256000) { - warning("Invalid size (%d) or offset (%d)", size, offset); - return false; - } - - debugC(3, kDebugSaveLoad, "Loading screen properties (%d, %d, %d)", - dataVar, size, offset); - - _vm->_inter->_variables->copyFrom(dataVar, - _screenProps + offset, _screenProps + 256000 + offset, size); - - return true; -} - -bool SaveLoad_v4::loadGame(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - if (size == 0) { - dataVar = 0; - size = _varSize; - } - - if (offset < 500) { - debugC(3, kDebugSaveLoad, "Loading global properties"); - - if ((size + offset) > 500) { - warning("Wrong global properties list size (%d, %d)", size, offset); - return false; - } - - _vm->_inter->_variables->copyFrom(dataVar, - _propBuffer + offset, _propBuffer + offset + 500, size); - - } else if (offset == 500) { - debugC(3, kDebugSaveLoad, "Loading save index"); - - if (size != 1200) { - warning("Requested index has wrong size (%d)", size); - return false; - } - - SaveLoad::buildIndex(_vm->_inter->_variables->getAddressOff8(dataVar, 1200), - saveFile.destName, 30, 40, 1000); - - } else { - int slot = getSlot(offset); - int slotRem = getSlotRemainder(offset); - - debugC(2, kDebugSaveLoad, "Loading from slot %d", slot); - - SaveLoad::setCurrentSlot(saveFile.destName, slot); - - if ((slot < 0) || (slot >= 30) || (slotRem != 0)) { - warning("Invalid loading procedure (%d, %d, %d, %d, %d)", - dataVar, size, offset, slot, slotRem); - return false; - } - - if (!_save->load(dataVar, size, 540, saveFile.destName, _vm->_inter->_variables)) - return false; - } - - return true; -} - -bool SaveLoad_v4::loadGameScreenProps(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - if (size != -5) { - warning("Invalid loading procedure (%d, %d, %d)", dataVar, size, offset); - return false; - } - - setCurrentSlot(saveFile.destName, saveFile.sourceName[4] - '0'); - - if (!_save->load(0, 256000, _varSize + 540, saveFile.destName, - _screenProps, _screenProps + 256000)) - return false; - - return true; -} - -bool SaveLoad_v4::saveScreenProps(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - // Using a sprite as a buffer - if (size <= 0) - return true; - - if ((offset < 0) || (size + offset) > 256000) { - warning("Invalid size (%d) or offset (%d)", size, offset); - return false; - } - - debugC(3, kDebugSaveLoad, "Saving screen properties (%d, %d, %d)", - dataVar, size, offset); - - _vm->_inter->_variables->copyTo(dataVar, - _screenProps + offset, _screenProps + 256000 + offset, size); - - return true; -} - -bool SaveLoad_v4::saveGame(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - if (size == 0) { - dataVar = 0; - size = _varSize; - } - - if (offset < 500) { - debugC(3, kDebugSaveLoad, "Loading global properties"); - - if ((size + offset) > 500) { - warning("Wrong global properties list size (%d, %d)", size, offset); - return false; - } - - _vm->_inter->_variables->copyTo(dataVar, - _propBuffer + offset, _propBuffer + offset + 500, size); - - } else if (offset == 500) { - debugC(3, kDebugSaveLoad, "Saving save index"); - - if (size != 1200) { - warning("Requested index has wrong size (%d)", size); - return false; - } - - _vm->_inter->_variables->copyTo(dataVar, _indexBuffer, 0, size); - _hasIndex = true; - - } else { - int slot = getSlot(offset); - int slotRem = getSlotRemainder(offset); - - debugC(2, kDebugSaveLoad, "Saving to slot %d", slot); - - SaveLoad::setCurrentSlot(saveFile.destName, slot); - - if ((slot < 0) || (slot >= 30) || (slotRem != 0)) { - warning("Invalid saving procedure (%d, %d, %d, %d, %d)", - dataVar, size, offset, slot, slotRem); - return false; - } - - if (!_hasIndex) { - warning("No index written yet"); - return false; - } - - _hasIndex = false; - - if (!_save->save(0, 500, 0, saveFile.destName, _propBuffer, _propBuffer + 500)) - return false; - - if (!_save->save(0, 40, 500, saveFile.destName, _indexBuffer + (slot * 40), 0)) - return false; - - if (!_save->save(dataVar, size, 540, saveFile.destName, _vm->_inter->_variables)) - return false; - - } - - return true; -} - -bool SaveLoad_v4::saveGameScreenProps(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - if (size != -5) { - warning("Invalid saving procedure (%d, %d, %d)", dataVar, size, offset); - return false; - } - - setCurrentSlot(saveFile.destName, saveFile.sourceName[4] - '0'); - - if (!_save->save(0, 256000, _varSize + 540, saveFile.destName, - _screenProps, _screenProps + 256000)) - return false; - - return true; -} - -void SaveLoad_v4::assertInited() { - if (_varSize > 0) - return; - - _varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4; - - _save->addStage(500); - _save->addStage(40, false); - _save->addStage(_varSize); - _save->addStage(256000); -} - -} // End of namespace Gob diff --git a/engines/gob/saveload_v6.cpp b/engines/gob/saveload_v6.cpp deleted file mode 100644 index f0de4d934a..0000000000 --- a/engines/gob/saveload_v6.cpp +++ /dev/null @@ -1,290 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/endian.h" - -#include "gob/gob.h" -#include "gob/saveload.h" -#include "gob/game.h" -#include "gob/inter.h" - -namespace Gob { - -SaveLoad_v6::SaveFile SaveLoad_v6::_saveFiles[] = { - { "cat.inf", 0, kSaveModeSave, kSaveGame}, - { "mdo.def", 0, kSaveModeExists, kSaveNone}, - {"no_cd.txt", 0, kSaveModeExists, kSaveNoCD}, -}; - -SaveLoad_v6::SaveLoad_v6(GobEngine *vm, const char *targetName) : - SaveLoad(vm, targetName) { - - _save = new StagedSave(_vm->getEndianness()); - - _saveFiles[0].destName = new char[strlen(targetName) + 5]; - _saveFiles[1].destName = 0; - _saveFiles[2].destName = 0; - - sprintf(_saveFiles[0].destName, "%s.s00", targetName); - - _varSize = 0; -} - -SaveLoad_v6::~SaveLoad_v6() { - delete _save; - - delete[] _saveFiles[0].destName; -} - -SaveLoad::SaveMode SaveLoad_v6::getSaveMode(const char *fileName) { - fileName = stripPath(fileName); - - int i; - for (i = 0; i < ARRAYSIZE(_saveFiles); i++) - if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) - break; - - if (i >= ARRAYSIZE(_saveFiles)) - return kSaveModeNone; - - if (_saveFiles[i].type != kSaveNoCD) - return _saveFiles[i].mode; - - if (_vm->_game->_noCd) - return kSaveModeExists; - else - return kSaveModeNone; -} - -int SaveLoad_v6::getSaveType(const char *fileName) { - for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) - if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) - return i; - - return -1; -} - -int32 SaveLoad_v6::getSizeVersioned(int type) { - assertInited(); - - switch (_saveFiles[type].type) { - case kSaveGame: - return getSizeGame(_saveFiles[type]); - default: - return -1; - } - - return -1; -} - -bool SaveLoad_v6::loadVersioned(int type, int16 dataVar, int32 size, int32 offset) { - assertInited(); - - switch (_saveFiles[type].type) { - case kSaveGame: - if (loadGame(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While loading from slot %d", getSlot(offset)); - break; - - default: - return false; - } - - return false; -} - -bool SaveLoad_v6::saveVersioned(int type, int16 dataVar, int32 size, int32 offset) { - assertInited(); - - switch (_saveFiles[type].type) { - case kSaveGame: - if (saveGame(_saveFiles[type], dataVar, size, offset)) - return true; - - warning("While saving to slot %d", getSlot(offset)); - break; - - default: - return false; - } - - return false; -} - -int SaveLoad_v6::getSlot(int32 offset) const { - return ((offset - 2900) / _varSize); -} - -int SaveLoad_v6::getSlotRemainder(int32 offset) const { - return ((offset - 2900) % _varSize); -} - -int32 SaveLoad_v6::getSizeGame(SaveFile &saveFile) { - refreshIndex(); - - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::InSaveFile *in; - - for (int i = 60; i >= 0; i--) { - in = saveMan->openForLoading(setCurrentSlot(saveFile.destName, i)); - if (in) { - delete in; - return (i + 1) * _varSize + 2900; - } - } - - return -1; -} - -bool SaveLoad_v6::loadGame(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - if (size == 0) { - dataVar = 0; - size = _varSize; - } - - if (offset < 2900) { - debugC(3, kDebugSaveLoad, "Saving save index"); - - if ((offset + size) > 2900) { - warning("Wrong index size (%d, %d)", size, offset); - return false; - } - - refreshIndex(); - - byte *sizes = new byte[size]; - memset(sizes, 0, size); - - _vm->_inter->_variables->copyFrom(dataVar, _indexBuffer + offset, sizes, size); - - delete[] sizes; - - - } else { - int slot = getSlot(offset); - int slotRem = getSlotRemainder(offset); - - debugC(2, kDebugSaveLoad, "Loading from slot %d", slot); - - if ((slot >= 60) || (slotRem != 0)) { - warning("Invalid loading procedure (%d, %d, %d, %d, %d)", - dataVar, size, offset, slot, slotRem); - return false; - } - - refreshIndex(); - SaveLoad::setCurrentSlot(saveFile.destName, slot); - - if (!_save->load(dataVar, size, 40, saveFile.destName, _vm->_inter->_variables)) - return false; - - refreshIndex(); - } - - return true; -} - -bool SaveLoad_v6::saveGame(SaveFile &saveFile, - int16 dataVar, int32 size, int32 offset) { - - if (size == 0) { - dataVar = 0; - size = _varSize; - } - - if (offset < 2900) { - debugC(3, kDebugSaveLoad, "Saving save index"); - - if ((offset + size) > 2900) { - warning("Wrong index size (%d, %d)", size, offset); - return false; - } - - _vm->_inter->_variables->copyTo(dataVar, _indexBuffer + offset, 0, size); - - } else { - int slot = getSlot(offset); - int slotRem = getSlotRemainder(offset); - - debugC(2, kDebugSaveLoad, "Saving to slot %d", slot); - - if ((slot >= 60) || (slotRem != 0)) { - warning("Invalid saving procedure (%d, %d, %d, %d, %d)", - dataVar, size, offset, slot, slotRem); - return false; - } - - SaveLoad::setCurrentSlot(saveFile.destName, slot); - - byte sizes[40]; - memset(sizes, 0, 40); - if (!_save->save(0, 40, 0, saveFile.destName, _indexBuffer + 500 + (slot * 40), sizes)) - return false; - - if (!_save->save(dataVar, size, 40, saveFile.destName, _vm->_inter->_variables)) - return false; - - refreshIndex(); - } - - return true; -} - -void SaveLoad_v6::assertInited() { - if (_varSize > 0) - return; - - _varSize = _vm->_inter->_variables->getSize(); - - _save->addStage(40); - _save->addStage(_varSize); -} - -void SaveLoad_v6::refreshIndex() { - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::InSaveFile *in; - - int32 max = -1; - byte *names = _indexBuffer + 500; - for (int i = 0; i < 60; i++, names += 40) { - in = saveMan->openForLoading(setCurrentSlot(_saveFiles[0].destName, i)); - if (in) { - max = i; - in->read(names, 40); - delete in; - } else - memset(names, 0, 40); - } - - memset(_indexBuffer + 40, 0xFF, 40); // Joker - _indexBuffer[159] = 0x03; // # of joker unused - WRITE_LE_UINT32(_indexBuffer + 160, max + 1); // # of saves -} - -} // End of namespace Gob diff --git a/engines/gob/variables.cpp b/engines/gob/variables.cpp index 6929045b20..1183ec21ae 100644 --- a/engines/gob/variables.cpp +++ b/engines/gob/variables.cpp @@ -35,14 +35,12 @@ Variables::Variables(uint32 size) { _size = size; _vars = new byte[_size]; - _sizes = new byte[_size]; clear(); } Variables::~Variables() { delete[] _vars; - delete[] _sizes; } uint32 Variables::getSize() const { @@ -51,39 +49,6 @@ uint32 Variables::getSize() const { void Variables::clear() { memset(_vars, 0, _size); - - // All variables are 32 bit wide per default - memset(_sizes, 0, _size); - for (uint32 i = 0; i < _size; i += 4) - _sizes[i] = kSize32; -} - -void Variables::clearSize(uint32 offset) { - uint32 inVar = offset % 4; - uint32 varOff = (offset >> 2) << 2; - - // Clearing out the old size - for (uint32 i = 0; i < 4; i++) { - if (_sizes[varOff + i] == kSize32) - _sizes[varOff + i] = kSize8; - else if ((inVar == (i + 1)) && (_sizes[varOff + i] == kSize16)) - _sizes[varOff + i] = kSize8; - } -} - -void Variables::writeSize(uint32 offset, byte n) { - clearSize(offset); - - _sizes[offset] = n; - // Setting following bytes of size to 8 bit, for easy clearing out afterwards - for (; n > 0; n--) - _sizes[offset + n] = kSize8; -} - -void Variables::writeSizeString(uint32 offset, uint32 length) { - clearSize(offset); - - memset(_sizes + offset, kSize8, length); } void Variables::writeVar8(uint32 var, uint8 value) { @@ -104,22 +69,18 @@ void Variables::writeVarString(uint32 var, const char *value) { void Variables::writeOff8(uint32 offset, uint8 value) { write8(_vars + offset, value); - writeSize(offset, kSize8); } void Variables::writeOff16(uint32 offset, uint16 value) { write16(_vars + offset, value); - writeSize(offset, kSize16); } void Variables::writeOff32(uint32 offset, uint32 value) { write32(_vars + offset, value); - writeSize(offset, kSize32); } void Variables::writeOffString(uint32 offset, const char *value) { strcpy((char *) (_vars + offset), value); - writeSizeString(offset, strlen(value)); } uint8 Variables::readVar8(uint32 var) const { @@ -158,42 +119,39 @@ const uint8 *Variables::getAddressVar8(uint32 var) const { return getAddressOff8(var * 4); } -uint8 *Variables::getAddressVar8(uint32 var, uint32 n) { - return getAddressOff8(var * 4, n); +uint8 *Variables::getAddressVar8(uint32 var) { + return getAddressOff8(var * 4); } const uint16 *Variables::getAddressVar16(uint32 var) const { return getAddressOff16(var * 4); } -uint16 *Variables::getAddressVar16(uint32 var, uint32 n) { - return getAddressOff16(var * 4, n); +uint16 *Variables::getAddressVar16(uint32 var) { + return getAddressOff16(var * 4); } const uint32 *Variables::getAddressVar32(uint32 var) const { return getAddressOff32(var * 4); } -uint32 *Variables::getAddressVar32(uint32 var, uint32 n) { - return getAddressOff32(var * 4, n); +uint32 *Variables::getAddressVar32(uint32 var) { + return getAddressOff32(var * 4); } const char *Variables::getAddressVarString(uint32 var) const { return getAddressOffString(var * 4); } -char *Variables::getAddressVarString(uint32 var, uint32 n) { - return getAddressOffString(var * 4, n); +char *Variables::getAddressVarString(uint32 var) { + return getAddressOffString(var * 4); } const uint8 *Variables::getAddressOff8(uint32 offset) const { return ((const uint8 *) (_vars + offset)); } -uint8 *Variables::getAddressOff8(uint32 offset, uint32 n) { - for (uint32 i = 0; i < n; i++) - writeSize(offset + i, kSize8); - +uint8 *Variables::getAddressOff8(uint32 offset) { return ((uint8 *) (_vars + offset)); } @@ -201,10 +159,7 @@ const uint16 *Variables::getAddressOff16(uint32 offset) const { return ((const uint16 *) (_vars + offset)); } -uint16 *Variables::getAddressOff16(uint32 offset, uint32 n) { - for (uint32 i = 0; i < n; i++) - writeSize(offset + i * 2, kSize16); - +uint16 *Variables::getAddressOff16(uint32 offset) { return ((uint16 *) (_vars + offset)); } @@ -212,10 +167,7 @@ const uint32 *Variables::getAddressOff32(uint32 offset) const { return ((const uint32 *) (_vars + offset)); } -uint32 *Variables::getAddressOff32(uint32 offset, uint32 n) { - for (uint32 i = 0; i < n; i++) - writeSize(offset + i * 4, kSize32); - +uint32 *Variables::getAddressOff32(uint32 offset) { return ((uint32 *) (_vars + offset)); } @@ -223,30 +175,25 @@ const char *Variables::getAddressOffString(uint32 offset) const { return ((const char *) (_vars + offset)); } -char *Variables::getAddressOffString(uint32 offset, uint32 n) { - writeSizeString(offset, (n == 0xFFFFFFFF) ? strlen((char *) (_vars + offset)) : n); - +char *Variables::getAddressOffString(uint32 offset) { return ((char *) (_vars + offset)); } -bool Variables::copyTo(uint32 offset, byte *variables, byte *sizes, uint32 n) const { +bool Variables::copyTo(uint32 offset, byte *variables, uint32 n) const { if ((offset + n) > _size) return false; if (variables) memcpy(variables, _vars + offset, n); - if (sizes) - memcpy(sizes, _sizes + offset, n); return true; } -bool Variables::copyFrom(uint32 offset, const byte *variables, const byte *sizes, uint32 n) { - if (((offset + n) > _size) || !variables || !sizes) +bool Variables::copyFrom(uint32 offset, const byte *variables, uint32 n) { + if (((offset + n) > _size) || !variables) return false; memcpy(_vars + offset, variables, n); - memcpy(_sizes + offset, sizes, n); return true; } diff --git a/engines/gob/variables.h b/engines/gob/variables.h index c2f2285b80..84a4772baa 100644 --- a/engines/gob/variables.h +++ b/engines/gob/variables.h @@ -67,32 +67,32 @@ public: const uint8 *getAddressVar8(uint32 var) const; - uint8 *getAddressVar8(uint32 var, uint32 n = 1); + uint8 *getAddressVar8(uint32 var); const uint16 *getAddressVar16(uint32 var) const; - uint16 *getAddressVar16(uint32 var, uint32 n = 1); + uint16 *getAddressVar16(uint32 var); const uint32 *getAddressVar32(uint32 var) const; - uint32 *getAddressVar32(uint32 var, uint32 n = 1); + uint32 *getAddressVar32(uint32 var); const char *getAddressVarString(uint32 var) const; - char *getAddressVarString(uint32 var, uint32 n = 0xFFFFFFFF); + char *getAddressVarString(uint32 var); const uint8 *getAddressOff8(uint32 offset) const; - uint8 *getAddressOff8(uint32 offset, uint32 n = 1); + uint8 *getAddressOff8(uint32 offset); const uint16 *getAddressOff16(uint32 offset) const; - uint16 *getAddressOff16(uint32 offset, uint32 n = 1); + uint16 *getAddressOff16(uint32 offset); const uint32 *getAddressOff32(uint32 offset) const; - uint32 *getAddressOff32(uint32 offset, uint32 n = 1); + uint32 *getAddressOff32(uint32 offset); const char *getAddressOffString(uint32 offset) const; - char *getAddressOffString(uint32 offset, uint32 n = 0xFFFFFFFF); + char *getAddressOffString(uint32 offset); - bool copyTo(uint32 offset, byte *variables, byte *sizes, uint32 n) const; - bool copyFrom(uint32 offset, const byte *variables, const byte *sizes, uint32 n); + bool copyTo(uint32 offset, byte *variables, uint32 n) const; + bool copyFrom(uint32 offset, const byte *variables, uint32 n); protected: virtual void write8(byte *buf, uint8 data) const = 0; @@ -104,20 +104,10 @@ protected: virtual uint32 read32(const byte *buf) const = 0; private: - // Basically the number of additional bytes occupied - static const byte kSize8 = 0; - static const byte kSize16 = 1; - static const byte kSize32 = 3; - uint32 _size; - byte *_vars; - byte *_sizes; - void clear(); - void clearSize(uint32 offset); - void writeSize(uint32 offset, byte n); - void writeSizeString(uint32 offset, uint32 length); + void clear(); }; class VariablesLE : public Variables { @@ -151,23 +141,23 @@ protected: }; class VariableReference { - public: - VariableReference(); - VariableReference(Variables &vars, uint32 offset, - Variables::Type type = Variables::kVariableType32); - ~VariableReference(); - - void set(Variables &vars, uint32 offset, Variables::Type type = Variables::kVariableType32); - - VariableReference &operator=(uint32 value); - VariableReference &operator+=(uint32 value); - VariableReference &operator*=(uint32 value); - operator uint32(); - - private: - Variables *_vars; - uint32 _offset; - Variables::Type _type; +public: + VariableReference(); + VariableReference(Variables &vars, uint32 offset, + Variables::Type type = Variables::kVariableType32); + ~VariableReference(); + + void set(Variables &vars, uint32 offset, Variables::Type type = Variables::kVariableType32); + + VariableReference &operator=(uint32 value); + VariableReference &operator+=(uint32 value); + VariableReference &operator*=(uint32 value); + operator uint32(); + +private: + Variables *_vars; + uint32 _offset; + Variables::Type _type; }; } // End of namespace Gob |