aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra/saveload.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/kyra/saveload.cpp')
-rw-r--r--engines/kyra/saveload.cpp152
1 files changed, 106 insertions, 46 deletions
diff --git a/engines/kyra/saveload.cpp b/engines/kyra/saveload.cpp
index 7d6fcaa0c1..9347da4aeb 100644
--- a/engines/kyra/saveload.cpp
+++ b/engines/kyra/saveload.cpp
@@ -29,16 +29,82 @@
#include "kyra/kyra.h"
-#define CURRENT_SAVE_VERSION 8
+#define CURRENT_SAVE_VERSION 9
-#define GF_FLOPPY (1 << 0)
-#define GF_TALKIE (1 << 1)
+#define GF_FLOPPY (1 << 0)
+#define GF_TALKIE (1 << 1)
#define GF_FMTOWNS (1 << 2)
namespace Kyra {
-Common::InSaveFile *KyraEngine::openSaveForReading(const char *filename, uint32 &version, char *saveName) {
- debugC(9, kDebugLevelMain, "KyraEngine::openSaveForReading('%s', %p, %p)", filename, (const void*)&version, saveName);
+KyraEngine::kReadSaveHeaderError KyraEngine::readSaveHeader(Common::InSaveFile *in, SaveHeader &header) {
+ uint32 type = in->readUint32BE();
+ header.originalSave = false;
+ header.oldHeader = false;
+ header.flags = 0;
+
+ if (type == MKID_BE('KYRA') || type == MKID_BE('ARYK')) { // old Kyra1 header ID
+ header.gameID = GI_KYRA1;
+ header.oldHeader = true;
+ } else if (type == MKID_BE('HOFS')) { // old Kyra2 header ID
+ header.gameID = GI_KYRA2;
+ header.oldHeader = true;
+ } else if (type == MKID_BE('WWSV')) {
+ header.gameID = in->readByte();
+ } else {
+ // try checking for original save header
+ const int descriptionSize[2] = { 30, 80 };
+ char descriptionBuffer[81];
+
+ bool saveOk = false;
+
+ for (uint i = 0; i < ARRAYSIZE(descriptionSize) && !saveOk; ++i) {
+ in->seek(0, SEEK_SET);
+ in->read(descriptionBuffer, descriptionSize[i]);
+ descriptionBuffer[descriptionSize[i]] = 0;
+
+ type = in->readUint32BE();
+ header.version = in->readUint16LE();
+ if (type == MKID_BE('MBL3') && header.version == 100) {
+ saveOk = true;
+ header.description = descriptionBuffer;
+ header.gameID = GI_KYRA2;
+ break;
+ }
+ }
+
+ if (saveOk) {
+ header.originalSave = true;
+ header.description = descriptionBuffer;
+ return kRSHENoError;
+ } else {
+ return kRSHEInvalidType;
+ }
+ }
+
+ header.version = in->readUint32BE();
+ if (header.version > CURRENT_SAVE_VERSION || (header.oldHeader && header.version > 8) || (type == MKID_BE('ARYK') && header.version > 3))
+ return kRSHEInvalidVersion;
+
+ // Versions prior to 9 are using a fixed length description field
+ if (header.version <= 8) {
+ char buffer[31];
+ in->read(buffer, 31);
+ header.description = buffer;
+ } else {
+ header.description = "";
+ for (char c = 0; (c = in->readByte()) != 0;)
+ header.description += c;
+ }
+
+ if (header.version >= 2)
+ header.flags = in->readUint32BE();
+
+ return (in->ioFailed() ? kRSHEIoError : kRSHENoError);
+}
+
+Common::InSaveFile *KyraEngine::openSaveForReading(const char *filename, SaveHeader &header) {
+ debugC(9, kDebugLevelMain, "KyraEngine::openSaveForReading('%s', -)", filename);
Common::InSaveFile *in = 0;
if (!(in = _saveFileMan->openForLoading(filename))) {
@@ -46,52 +112,45 @@ Common::InSaveFile *KyraEngine::openSaveForReading(const char *filename, uint32
return 0;
}
- uint32 type = in->readUint32BE();
-
- // FIXME: The kyra savegame code used to be endian unsafe. Uncomment the
- // following line to graciously handle old savegames from LE machines.
- // if (type != MKID_BE('KYRA') && type != MKID_BE('ARYK')) {
- if (type != MKID_BE(saveGameID())) {
- warning("No ScummVM Kyra engine savefile header.");
- delete in;
- return 0;
- }
+ kReadSaveHeaderError errorCode = KyraEngine::readSaveHeader(in, header);
+ if (errorCode != kRSHENoError) {
+ if (errorCode == kRSHEInvalidType)
+ warning("No ScummVM Kyra engine savefile header.");
+ else if (errorCode == kRSHEInvalidVersion)
+ warning("Savegame is not the right version (%u, '%s')", header.version, header.oldHeader ? "true" : "false");
+ else if (errorCode == kRSHEIoError)
+ warning("Load failed ('%s').", filename);
- version = in->readUint32BE();
- if (version > CURRENT_SAVE_VERSION) {
- warning("Savegame is not the right version (%u)", version);
delete in;
return 0;
}
- char saveNameBuffer[31];
- if (!saveName)
- saveName = saveNameBuffer;
- in->read(saveName, 31);
-
- if (_flags.gameID == GI_KYRA1 && version < 2) {
- warning("Make sure your savefile was from this version! (too old savefile version to detect that)");
- } else {
- uint32 flags = in->readUint32BE();
- if ((flags & GF_FLOPPY) && (_flags.isTalkie || _flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)) {
- warning("Can not load DOS Floppy savefile for this (non DOS Floppy) gameversion");
- delete in;
- return 0;
- } else if ((flags & GF_TALKIE) && !(_flags.isTalkie)) {
- warning("Can not load DOS CD-ROM savefile for this (non DOS CD-ROM) gameversion");
- delete in;
- return 0;
- } else if ((flags & GF_FMTOWNS) && !(_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)) {
- warning("Can not load FM-Towns/PC98 savefile for this (non FM-Towns/PC98) gameversion");
- delete in;
- return 0;
+ if (!header.originalSave) {
+ if (!header.oldHeader) {
+ if (header.gameID != _flags.gameID) {
+ warning("Trying to load game state from other game (save game: %u, running game: %u)", header.gameID, _flags.gameID);
+ delete in;
+ return 0;
+ }
}
- }
- if (in->ioFailed()) {
- error("Load failed ('%s', '%s').", filename, saveName);
- delete in;
- return 0;
+ if (header.version < 2) {
+ warning("Make sure your savefile was from this version! (too old savefile version to detect that)");
+ } else {
+ if ((header.flags & GF_FLOPPY) && (_flags.isTalkie || _flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)) {
+ warning("Can not load DOS Floppy savefile for this (non DOS Floppy) gameversion");
+ delete in;
+ return 0;
+ } else if ((header.flags & GF_TALKIE) && !(_flags.isTalkie)) {
+ warning("Can not load DOS CD-ROM savefile for this (non DOS CD-ROM) gameversion");
+ delete in;
+ return 0;
+ } else if ((header.flags & GF_FMTOWNS) && !(_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)) {
+ warning("Can not load FM-Towns/PC98 savefile for this (non FM-Towns/PC98) gameversion");
+ delete in;
+ return 0;
+ }
+ }
}
return in;
@@ -109,9 +168,10 @@ Common::OutSaveFile *KyraEngine::openSaveForWriting(const char *filename, const
}
// Savegame version
- out->writeUint32BE(saveGameID());
+ out->writeUint32BE(MKID_BE('WWSV'));
+ out->writeByte(_flags.gameID);
out->writeUint32BE(CURRENT_SAVE_VERSION);
- out->write(saveName, 31);
+ out->write(saveName, strlen(saveName)+1);
if (_flags.isTalkie)
out->writeUint32BE(GF_TALKIE);
else if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)