aboutsummaryrefslogtreecommitdiff
path: root/engines/gob
diff options
context:
space:
mode:
authorSven Hesse2009-05-31 02:15:43 +0000
committerSven Hesse2009-05-31 02:15:43 +0000
commit896df6daf337bf83f27193918eb386321c4b0166 (patch)
treec124f8f102052cdd6207e2507d097aff4bc7f44e /engines/gob
parentc938667d4b60005a926007376305f3da8621f7c7 (diff)
downloadscummvm-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/gob')
-rw-r--r--engines/gob/gob.cpp8
-rw-r--r--engines/gob/gob.h7
-rw-r--r--engines/gob/helper.h16
-rw-r--r--engines/gob/inter.cpp1
-rw-r--r--engines/gob/inter.h1
-rw-r--r--engines/gob/inter_v1.cpp5
-rw-r--r--engines/gob/inter_v2.cpp26
-rw-r--r--engines/gob/map_v2.cpp8
-rw-r--r--engines/gob/map_v4.cpp8
-rw-r--r--engines/gob/module.mk17
-rw-r--r--engines/gob/parse.cpp4
-rw-r--r--engines/gob/parse_v1.cpp4
-rw-r--r--engines/gob/parse_v2.cpp4
-rw-r--r--engines/gob/save/saveconverter.cpp443
-rw-r--r--engines/gob/save/saveconverter.h206
-rw-r--r--engines/gob/save/saveconverter_v2.cpp135
-rw-r--r--engines/gob/save/saveconverter_v3.cpp188
-rw-r--r--engines/gob/save/saveconverter_v4.cpp147
-rw-r--r--engines/gob/save/saveconverter_v6.cpp135
-rw-r--r--engines/gob/save/savefile.cpp979
-rw-r--r--engines/gob/save/savefile.h347
-rw-r--r--engines/gob/save/savehandler.cpp503
-rw-r--r--engines/gob/save/savehandler.h191
-rw-r--r--engines/gob/save/saveload.cpp135
-rw-r--r--engines/gob/save/saveload.h452
-rw-r--r--engines/gob/save/saveload_v2.cpp328
-rw-r--r--engines/gob/save/saveload_v3.cpp570
-rw-r--r--engines/gob/save/saveload_v4.cpp555
-rw-r--r--engines/gob/save/saveload_v6.cpp342
-rw-r--r--engines/gob/saveload.cpp879
-rw-r--r--engines/gob/saveload.h464
-rw-r--r--engines/gob/saveload_v2.cpp373
-rw-r--r--engines/gob/saveload_v3.cpp616
-rw-r--r--engines/gob/saveload_v4.cpp443
-rw-r--r--engines/gob/saveload_v6.cpp290
-rw-r--r--engines/gob/variables.cpp83
-rw-r--r--engines/gob/variables.h66
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 &params) {
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 &params) {
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