diff options
author | Adrian Frühwirth | 2018-04-06 00:06:38 +0200 |
---|---|---|
committer | Eugene Sandulenko | 2018-04-07 09:26:20 +0200 |
commit | 00e59a312211c0b49433ad3e9923460ed85edc50 (patch) | |
tree | d604e3f19249c6a6436a83cc868fda9d12e57165 /engines | |
parent | 07775ca71723ddb02de32b840b90742a173dca35 (diff) | |
download | scummvm-rg350-00e59a312211c0b49433ad3e9923460ed85edc50.tar.gz scummvm-rg350-00e59a312211c0b49433ad3e9923460ed85edc50.tar.bz2 scummvm-rg350-00e59a312211c0b49433ad3e9923460ed85edc50.zip |
ALL: Load savegame thumbnail only when necessary
This commit introduces the following changes:
1. Graphics::loadThumbnail()
Now returns a boolean and takes a new argument skipThumbnail which
defaults to false. In case of true, loadThumbnail() reads past the
thumbnail data in the input stream instead of actually loading the
thumbnail. This simplifies savegame handling where, up until now,
many engines always read the whole savegame metadata (including
the thumbnail) and then threw away the thumbnail when not needed
(which is in almost all cases, the most common exception being
MetaEngine::querySaveMetaInfos() which is responsible for loading
savegame metadata for displaying it in the GUI launcher.
2. readSavegameHeader()
Engines which already implement such a method (name varies) now take
a new argument skipThumbnail (default: true) which is passed
through to loadThumbnail(). This means that the default case for
readSavegameHeader() is now _not_ loading the thumbnail from a
savegame and just reading past it. In those cases, e.g.
querySaveMetaInfos(), where we actually are interested in loading
the thumbnail readSavegameHeader() needs to explicitely be called
with skipThumbnail == false.
Engines whose readSavegameHeader() (name varies) already takes an
argument loadThumbnail have been adapted to have a similar
prototype and semantics.
I.e. readSaveHeader(in, loadThumbnail, header) now is
readSaveHeader(in, header, skipThumbnail).
3. Error handling
Engines which previously did not check the return value of
readSavegameHeader() (name varies) now do so ensuring that possibly
broken savegames (be it a broken thumbnail or something else) don't
make it into the GUI launcher list in the first place.
Diffstat (limited to 'engines')
93 files changed, 322 insertions, 323 deletions
diff --git a/engines/access/access.cpp b/engines/access/access.cpp index 1855280a24..c1af19026b 100644 --- a/engines/access/access.cpp +++ b/engines/access/access.cpp @@ -488,11 +488,6 @@ Common::Error AccessEngine::loadGameState(int slot) { if (!readSavegameHeader(saveFile, header)) error("Invalid savegame"); - if (header._thumbnail) { - header._thumbnail->free(); - delete header._thumbnail; - } - // Load most of the savegame data synchronize(s); delete saveFile; @@ -537,9 +532,8 @@ void AccessEngine::synchronize(Common::Serializer &s) { const char *const SAVEGAME_STR = "ACCESS"; #define SAVEGAME_STR_SIZE 6 -bool AccessEngine::readSavegameHeader(Common::InSaveFile *in, AccessSavegameHeader &header) { +WARN_UNUSED_RESULT bool AccessEngine::readSavegameHeader(Common::InSaveFile *in, AccessSavegameHeader &header, bool skipThumbnail) { char saveIdentBuffer[SAVEGAME_STR_SIZE + 1]; - header._thumbnail = nullptr; // Validate the header Id in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1); @@ -557,9 +551,9 @@ bool AccessEngine::readSavegameHeader(Common::InSaveFile *in, AccessSavegameHead header._saveName += ch; // Get the thumbnail - header._thumbnail = Graphics::loadThumbnail(*in); - if (!header._thumbnail) + if (!Graphics::loadThumbnail(*in, header._thumbnail, skipThumbnail)) { return false; + } // Read in save date/time header._year = in->readSint16LE(); diff --git a/engines/access/access.h b/engines/access/access.h index 972dd4c380..56646f01c9 100644 --- a/engines/access/access.h +++ b/engines/access/access.h @@ -306,7 +306,7 @@ public: /** * Read in a savegame header */ - static bool readSavegameHeader(Common::InSaveFile *in, AccessSavegameHeader &header); + WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, AccessSavegameHeader &header, bool skipThumbnail = true); /** * Write out a savegame header diff --git a/engines/access/detection.cpp b/engines/access/detection.cpp index 3e70de3635..186fcbdf06 100644 --- a/engines/access/detection.cpp +++ b/engines/access/detection.cpp @@ -157,11 +157,9 @@ SaveStateList AccessMetaEngine::listSaves(const char *target) const { Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file); if (in) { - Access::AccessEngine::readSavegameHeader(in, header); - saveList.push_back(SaveStateDescriptor(slot, header._saveName)); + if (Access::AccessEngine::readSavegameHeader(in, header)) + saveList.push_back(SaveStateDescriptor(slot, header._saveName)); - header._thumbnail->free(); - delete header._thumbnail; delete in; } } @@ -187,7 +185,11 @@ SaveStateDescriptor AccessMetaEngine::querySaveMetaInfos(const char *target, int if (f) { Access::AccessSavegameHeader header; - Access::AccessEngine::readSavegameHeader(f, header); + if (!Access::AccessEngine::readSavegameHeader(f, header, false)) { + delete f; + return SaveStateDescriptor(); + } + delete f; // Create the return descriptor diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp index e63beb2c07..ab634bc02a 100644 --- a/engines/adl/detection.cpp +++ b/engines/adl/detection.cpp @@ -401,7 +401,11 @@ SaveStateDescriptor AdlMetaEngine::querySaveMetaInfos(const char *target, int sl return SaveStateDescriptor(); } - Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*inFile); + Graphics::Surface *thumbnail; + if (!Graphics::loadThumbnail(*inFile, thumbnail)) { + delete inFile; + return SaveStateDescriptor(); + } sd.setThumbnail(thumbnail); delete inFile; diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp index e26f5c84fc..817be08f2c 100644 --- a/engines/agi/detection.cpp +++ b/engines/agi/detection.cpp @@ -375,7 +375,11 @@ SaveStateDescriptor AgiMetaEngine::querySaveMetaInfos(const char *target, int sl char saveVersion = in->readByte(); if (saveVersion >= 4) { - Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in); + Graphics::Surface *thumbnail; + if (!Graphics::loadThumbnail(*in, thumbnail)) { + delete in; + return SaveStateDescriptor(); + } descriptor.setThumbnail(thumbnail); diff --git a/engines/avalanche/detection.cpp b/engines/avalanche/detection.cpp index def395b77f..64634dc017 100644 --- a/engines/avalanche/detection.cpp +++ b/engines/avalanche/detection.cpp @@ -193,7 +193,12 @@ SaveStateDescriptor AvalancheMetaEngine::querySaveMetaInfos(const char *target, SaveStateDescriptor desc(slot, description); - Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*f); + Graphics::Surface *thumbnail; + if (!Graphics::loadThumbnail(*f, thumbnail)) { + warning("Cannot read thumbnail data, possibly broken savegame"); + delete f; + return SaveStateDescriptor(); + } desc.setThumbnail(thumbnail); delete f; diff --git a/engines/bbvs/bbvs.h b/engines/bbvs/bbvs.h index 9fb6b9cac3..a9d37c2551 100644 --- a/engines/bbvs/bbvs.h +++ b/engines/bbvs/bbvs.h @@ -417,7 +417,7 @@ public: const char *getSavegameFilename(int num); bool existsSavegame(int num); static Common::String getSavegameFilename(const Common::String &target, int num); - static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header); + WARN_UNUSED_RESULT static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header, bool skipThumbnail = true); void allocSnapshot(); void freeSnapshot(); diff --git a/engines/bbvs/detection.cpp b/engines/bbvs/detection.cpp index 1b2c644dda..b30c6d3f2d 100644 --- a/engines/bbvs/detection.cpp +++ b/engines/bbvs/detection.cpp @@ -124,7 +124,7 @@ SaveStateList BbvsMetaEngine::listSaves(const char *target) const { if (slotNum >= 0 && slotNum <= 999) { Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); if (in) { - if (Bbvs::BbvsEngine::readSaveHeader(in, false, header) == Bbvs::BbvsEngine::kRSHENoError) { + if (Bbvs::BbvsEngine::readSaveHeader(in, header) == Bbvs::BbvsEngine::kRSHENoError) { saveList.push_back(SaveStateDescriptor(slotNum, header.description)); } delete in; @@ -142,7 +142,7 @@ SaveStateDescriptor BbvsMetaEngine::querySaveMetaInfos(const char *target, int s if (in) { Bbvs::BbvsEngine::SaveHeader header; Bbvs::BbvsEngine::kReadSaveHeaderError error; - error = Bbvs::BbvsEngine::readSaveHeader(in, true, header); + error = Bbvs::BbvsEngine::readSaveHeader(in, header, false); delete in; if (error == Bbvs::BbvsEngine::kRSHENoError) { SaveStateDescriptor desc(slot, header.description); diff --git a/engines/bbvs/saveload.cpp b/engines/bbvs/saveload.cpp index 74c255c860..d4782aad39 100644 --- a/engines/bbvs/saveload.cpp +++ b/engines/bbvs/saveload.cpp @@ -27,7 +27,7 @@ namespace Bbvs { -BbvsEngine::kReadSaveHeaderError BbvsEngine::readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header) { +WARN_UNUSED_RESULT BbvsEngine::kReadSaveHeaderError BbvsEngine::readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header, bool skipThumbnail) { header.version = in->readUint32LE(); if (header.version > BBVS_SAVEGAME_VERSION) @@ -38,10 +38,8 @@ BbvsEngine::kReadSaveHeaderError BbvsEngine::readSaveHeader(Common::SeekableRead while (descriptionLen--) header.description += (char)in->readByte(); - if (loadThumbnail) { - header.thumbnail = Graphics::loadThumbnail(*in); - } else { - Graphics::skipThumbnail(*in); + if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) { + return kRSHEIoError; } // Not used yet, reserved for future usage @@ -101,7 +99,7 @@ void BbvsEngine::loadgame(const char *filename) { SaveHeader header; - kReadSaveHeaderError errorCode = readSaveHeader(in, false, header); + kReadSaveHeaderError errorCode = readSaveHeader(in, header); if (errorCode != kRSHENoError) { warning("Error loading savegame '%s'", filename); diff --git a/engines/cge/cge.h b/engines/cge/cge.h index d3f8a93c1d..668224d2f7 100644 --- a/engines/cge/cge.h +++ b/engines/cge/cge.h @@ -246,7 +246,7 @@ public: void mainLoop(); void handleFrame(); void saveGame(int slotNumber, const Common::String &desc); - static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header); + WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header, bool skipThumbnail = true); void switchMusic(); void selectPocket(int n); void expandSprite(Sprite *spr); diff --git a/engines/cge/cge_main.cpp b/engines/cge/cge_main.cpp index b60f201cb0..fcbbf34a4d 100644 --- a/engines/cge/cge_main.cpp +++ b/engines/cge/cge_main.cpp @@ -242,10 +242,6 @@ bool CGEEngine::loadGame(int slotNumber, SavegameHeader *header, bool tiny) { delete readStream; return true; } - - // Delete the thumbnail - saveHeader.thumbnail->free(); - delete saveHeader.thumbnail; } // Get in the savegame @@ -424,9 +420,7 @@ void CGEEngine::syncGame(Common::SeekableReadStream *readStream, Common::WriteSt } } -bool CGEEngine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header) { - header.thumbnail = nullptr; - +WARN_UNUSED_RESULT bool CGEEngine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header, bool skipThumbnail) { // Get the savegame version header.version = in->readByte(); if (header.version > kSavegameVersion) @@ -439,9 +433,9 @@ bool CGEEngine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &heade header.saveName += ch; // Get the thumbnail - header.thumbnail = Graphics::loadThumbnail(*in); - if (!header.thumbnail) + if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) { return false; + } // Read in save date/time header.saveYear = in->readSint16LE(); diff --git a/engines/cge/detection.cpp b/engines/cge/detection.cpp index 482591bf50..cae2e036b9 100644 --- a/engines/cge/detection.cpp +++ b/engines/cge/detection.cpp @@ -221,10 +221,6 @@ SaveStateList CGEMetaEngine::listSaves(const char *target) const { // Valid savegame if (CGE::CGEEngine::readSavegameHeader(file, header)) { saveList.push_back(SaveStateDescriptor(slotNum, header.saveName)); - if (header.thumbnail) { - header.thumbnail->free(); - delete header.thumbnail; - } } } else { // Must be an original format savegame @@ -253,7 +249,7 @@ SaveStateDescriptor CGEMetaEngine::querySaveMetaInfos(const char *target, int sl f->read(buffer, kSavegameStrSize + 1); bool hasHeader = !strncmp(buffer, CGE::savegameStr, kSavegameStrSize + 1) && - CGE::CGEEngine::readSavegameHeader(f, header); + CGE::CGEEngine::readSavegameHeader(f, header, false); delete f; if (!hasHeader) { diff --git a/engines/cge2/cge2.h b/engines/cge2/cge2.h index 18f919b5eb..899520c6dd 100644 --- a/engines/cge2/cge2.h +++ b/engines/cge2/cge2.h @@ -161,7 +161,7 @@ public: virtual Common::Error loadGameState(int slot); virtual Common::Error run(); - static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header); + WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header, bool skipThumbnail = true); GUI::Debugger *getDebugger() { return _console; diff --git a/engines/cge2/detection.cpp b/engines/cge2/detection.cpp index d05dfffedc..68f16d8dc9 100644 --- a/engines/cge2/detection.cpp +++ b/engines/cge2/detection.cpp @@ -221,10 +221,6 @@ SaveStateList CGE2MetaEngine::listSaves(const char *target) const { // Valid savegame if (CGE2::CGE2Engine::readSavegameHeader(file, header)) { saveList.push_back(SaveStateDescriptor(slotNum, header.saveName)); - if (header.thumbnail) { - header.thumbnail->free(); - delete header.thumbnail; - } } } else { // Must be an original format savegame @@ -253,7 +249,7 @@ SaveStateDescriptor CGE2MetaEngine::querySaveMetaInfos(const char *target, int s f->read(buffer, kSavegameStrSize + 1); bool hasHeader = !strncmp(buffer, kSavegameStr, kSavegameStrSize + 1) && - CGE2::CGE2Engine::readSavegameHeader(f, header); + CGE2::CGE2Engine::readSavegameHeader(f, header, false); delete f; if (!hasHeader) { diff --git a/engines/cge2/saveload.cpp b/engines/cge2/saveload.cpp index cd0be84567..83cba5316d 100644 --- a/engines/cge2/saveload.cpp +++ b/engines/cge2/saveload.cpp @@ -117,10 +117,6 @@ bool CGE2Engine::loadGame(int slotNumber) { delete readStream; return false; } - - // Delete the thumbnail - saveHeader.thumbnail->free(); - delete saveHeader.thumbnail; } resetGame(); @@ -180,9 +176,7 @@ void CGE2Engine::writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &h out->writeSint16LE(td.tm_min); } -bool CGE2Engine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header) { - header.thumbnail = nullptr; - +WARN_UNUSED_RESULT bool CGE2Engine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header, bool skipThumbnail) { // Get the savegame version header.version = in->readByte(); if (header.version > kSavegameVersion) @@ -195,9 +189,9 @@ bool CGE2Engine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &head header.saveName += ch; // Get the thumbnail - header.thumbnail = Graphics::loadThumbnail(*in); - if (!header.thumbnail) + if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) { return false; + } // Read in save date/time header.saveYear = in->readSint16LE(); diff --git a/engines/cruise/detection.cpp b/engines/cruise/detection.cpp index 6f5d236173..3dfd414fd2 100644 --- a/engines/cruise/detection.cpp +++ b/engines/cruise/detection.cpp @@ -241,9 +241,8 @@ SaveStateList CruiseMetaEngine::listSaves(const char *target) const { Common::InSaveFile *in = saveFileMan->openForLoading(*file); if (in) { Cruise::CruiseSavegameHeader header; - Cruise::readSavegameHeader(in, header); - saveList.push_back(SaveStateDescriptor(slotNum, header.saveName)); - delete header.thumbnail; + if (Cruise::readSavegameHeader(in, header)) + saveList.push_back(SaveStateDescriptor(slotNum, header.saveName)); delete in; } } @@ -264,7 +263,11 @@ SaveStateDescriptor CruiseMetaEngine::querySaveMetaInfos(const char *target, int if (f) { Cruise::CruiseSavegameHeader header; - Cruise::readSavegameHeader(f, header); + if (!Cruise::readSavegameHeader(f, header, false)) { + delete f; + return SaveStateDescriptor(); + } + delete f; // Create the return descriptor diff --git a/engines/cruise/saveload.cpp b/engines/cruise/saveload.cpp index a62648df08..7aaeb06905 100644 --- a/engines/cruise/saveload.cpp +++ b/engines/cruise/saveload.cpp @@ -43,9 +43,8 @@ struct overlayRestoreTemporary { overlayRestoreTemporary ovlRestoreData[90]; -bool readSavegameHeader(Common::InSaveFile *in, CruiseSavegameHeader &header) { +WARN_UNUSED_RESULT bool readSavegameHeader(Common::InSaveFile *in, CruiseSavegameHeader &header, bool skipThumbnail) { char saveIdentBuffer[6]; - header.thumbnail = NULL; // Validate the header Id in->read(saveIdentBuffer, 6); @@ -62,9 +61,9 @@ bool readSavegameHeader(Common::InSaveFile *in, CruiseSavegameHeader &header) { while ((ch = (char)in->readByte()) != '\0') header.saveName += ch; // Get the thumbnail - header.thumbnail = Graphics::loadThumbnail(*in); - if (!header.thumbnail) + if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) { return false; + } return true; } @@ -827,8 +826,10 @@ Common::Error loadSavegameData(int saveGameIdx) { // Skip over the savegame header CruiseSavegameHeader header; - readSavegameHeader(f, header); - delete header.thumbnail; + if (!readSavegameHeader(f, header)) { + delete f; + return Common::kReadingFailed; + } // Synchronise the remaining data of the savegame Common::Serializer s(f, NULL); diff --git a/engines/cruise/saveload.h b/engines/cruise/saveload.h index 6fb1f4b545..c92f0e9da5 100644 --- a/engines/cruise/saveload.h +++ b/engines/cruise/saveload.h @@ -38,7 +38,7 @@ struct CruiseSavegameHeader { Common::Error saveSavegameData(int saveGameIdx, const Common::String &saveName); Common::Error loadSavegameData(int saveGameIdx); -bool readSavegameHeader(Common::InSaveFile *in, CruiseSavegameHeader &header); +WARN_UNUSED_RESULT bool readSavegameHeader(Common::InSaveFile *in, CruiseSavegameHeader &header, bool skipThumbnail = true); void initVars(); } // End of namespace Cruise diff --git a/engines/dm/dm.h b/engines/dm/dm.h index 16307778ba..e330cb6be7 100644 --- a/engines/dm/dm.h +++ b/engines/dm/dm.h @@ -332,7 +332,7 @@ public: Thing _thingParty; // @ C0xFFFF_THING_PARTY }; -bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader *header); +WARN_UNUSED_RESULT bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader *header, bool skipThumbnail = true); } // End of namespace DM diff --git a/engines/dm/loadsave.cpp b/engines/dm/loadsave.cpp index 3d8f76c33f..864a726367 100644 --- a/engines/dm/loadsave.cpp +++ b/engines/dm/loadsave.cpp @@ -70,7 +70,10 @@ LoadgameResult DMEngine::loadgame(int16 slot) { file = saveFileManager->openForLoading(fileName); SaveGameHeader header; - readSaveGameHeader(file, &header); + if (!readSaveGameHeader(file, &header)) { + delete file; + return kDMLoadgameFailure; + } warning("MISSING CODE: missing check for matching format and platform in save in f435_loadgame"); @@ -397,7 +400,7 @@ bool DMEngine::writeCompleteSaveFile(int16 saveSlot, Common::String& saveDescrip return true; } -bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader *header) { +WARN_UNUSED_RESULT bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader *header, bool skipThumbnail) { uint32 id = in->readUint32BE(); // Check if it's a valid ScummVM savegame @@ -419,7 +422,11 @@ bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader *header) { header->_descr.setDescription(saveName); // Get the thumbnail - header->_descr.setThumbnail(Graphics::loadThumbnail(*in)); + Graphics::Surface *thumbnail; + if (!Graphics::loadThumbnail(*in, thumbnail, skipThumbnail)) { + return false; + } + header->_descr.setThumbnail(thumbnail); uint32 saveDate = in->readUint32BE(); uint16 saveTime = in->readUint16BE(); diff --git a/engines/draci/detection.cpp b/engines/draci/detection.cpp index 65427bd8cd..9a76e3890c 100644 --- a/engines/draci/detection.cpp +++ b/engines/draci/detection.cpp @@ -132,10 +132,6 @@ SaveStateList DraciMetaEngine::listSaves(const char *target) const { Draci::DraciSavegameHeader header; if (Draci::readSavegameHeader(in, header)) { saveList.push_back(SaveStateDescriptor(slotNum, header.saveName)); - if (header.thumbnail) { - header.thumbnail->free(); - delete header.thumbnail; - } } delete in; } @@ -157,7 +153,11 @@ SaveStateDescriptor DraciMetaEngine::querySaveMetaInfos(const char *target, int if (f) { Draci::DraciSavegameHeader header; - Draci::readSavegameHeader(f, header); + if (!Draci::readSavegameHeader(f, header, false)) { + delete f; + return SaveStateDescriptor(); + } + delete f; // Create the return descriptor diff --git a/engines/draci/saveload.cpp b/engines/draci/saveload.cpp index 3e7f8651c1..e30af5375e 100644 --- a/engines/draci/saveload.cpp +++ b/engines/draci/saveload.cpp @@ -35,9 +35,8 @@ namespace Draci { static const char *const draciIdentString = "DRACI"; -bool readSavegameHeader(Common::InSaveFile *in, DraciSavegameHeader &header) { +WARN_UNUSED_RESULT bool readSavegameHeader(Common::InSaveFile *in, DraciSavegameHeader &header, bool skipThumbnail) { char saveIdentBuffer[6]; - header.thumbnail = NULL; // Validate the header Id in->read(saveIdentBuffer, 6); @@ -59,9 +58,9 @@ bool readSavegameHeader(Common::InSaveFile *in, DraciSavegameHeader &header) { header.playtime = in->readUint32LE(); // Get the thumbnail - header.thumbnail = Graphics::loadThumbnail(*in); - if (!header.thumbnail) + if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) { return false; + } return true; } @@ -130,10 +129,6 @@ Common::Error loadSavegameData(int saveGameIdx, DraciEngine *vm) { if (!readSavegameHeader(f, header)) { return Common::kNoGameDataFoundError; } - if (header.thumbnail) { - header.thumbnail->free(); - delete header.thumbnail; - } // Pre-processing vm->_game->rememberRoomNumAsPrevious(); diff --git a/engines/draci/saveload.h b/engines/draci/saveload.h index 6f951a3409..bceaebb468 100644 --- a/engines/draci/saveload.h +++ b/engines/draci/saveload.h @@ -42,7 +42,7 @@ struct DraciSavegameHeader { class DraciEngine; -bool readSavegameHeader(Common::InSaveFile *in, DraciSavegameHeader &header); +WARN_UNUSED_RESULT bool readSavegameHeader(Common::InSaveFile *in, DraciSavegameHeader &header, bool skipThumbnail = true); void writeSavegameHeader(Common::OutSaveFile *out, const DraciSavegameHeader &header); Common::Error saveSavegameData(int saveGameIdx, const Common::String &saveName, DraciEngine &vm); Common::Error loadSavegameData(int saveGameIdx, DraciEngine *vm); diff --git a/engines/drascula/detection.cpp b/engines/drascula/detection.cpp index 5f453839e7..a1f2f3e117 100644 --- a/engines/drascula/detection.cpp +++ b/engines/drascula/detection.cpp @@ -430,7 +430,11 @@ SaveStateDescriptor DrasculaMetaEngine::querySaveMetaInfos(const char *target, i return SaveStateDescriptor(); } - Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in); + Graphics::Surface *thumbnail; + if (!Graphics::loadThumbnail(*in, thumbnail)) { + delete in; + return SaveStateDescriptor(); + } desc.setThumbnail(thumbnail); delete in; diff --git a/engines/dreamweb/detection.cpp b/engines/dreamweb/detection.cpp index 11966047b0..36af0c3811 100644 --- a/engines/dreamweb/detection.cpp +++ b/engines/dreamweb/detection.cpp @@ -198,7 +198,12 @@ SaveStateDescriptor DreamWebMetaEngine::querySaveMetaInfos(const char *target, i uint32 saveDate = in->readUint32LE(); uint32 saveTime = in->readUint32LE(); uint32 playTime = in->readUint32LE(); - Graphics::Surface *thumbnail = Graphics::loadThumbnail(*in); + Graphics::Surface *thumbnail; + if (!Graphics::loadThumbnail(*in, thumbnail)) { + warning("Missing or broken thumbnail - skipping"); + delete in; + return desc; + } int day = (saveDate >> 24) & 0xFF; int month = (saveDate >> 16) & 0xFF; diff --git a/engines/fullpipe/detection.cpp b/engines/fullpipe/detection.cpp index 9dd1d6beb4..3144a0ebff 100644 --- a/engines/fullpipe/detection.cpp +++ b/engines/fullpipe/detection.cpp @@ -184,7 +184,9 @@ SaveStateList FullpipeMetaEngine::listSaves(const char *target) const { Common::ScopedPtr<Common::InSaveFile> in(saveFileMan->openForLoading(*file)); if (in) { Fullpipe::FullpipeSavegameHeader header; - Fullpipe::readSavegameHeader(in.get(), header); + if (!Fullpipe::readSavegameHeader(in.get(), header)) { + continue; + } SaveStateDescriptor desc; @@ -212,7 +214,9 @@ SaveStateDescriptor FullpipeMetaEngine::querySaveMetaInfos(const char *target, i if (f) { Fullpipe::FullpipeSavegameHeader header; - Fullpipe::readSavegameHeader(f.get(), header); + if (!Fullpipe::readSavegameHeader(f.get(), header, false)) { + return SaveStateDescriptor(); + } // Create the return descriptor SaveStateDescriptor desc; diff --git a/engines/fullpipe/gameloader.h b/engines/fullpipe/gameloader.h index 03c3093086..eb5957c78e 100644 --- a/engines/fullpipe/gameloader.h +++ b/engines/fullpipe/gameloader.h @@ -84,7 +84,7 @@ struct FullpipeSavegameHeader { uint32 date; uint16 time; uint32 playtime; - Common::SharedPtr<Graphics::Surface> thumbnail; + Graphics::Surface *thumbnail; }; struct SaveHeader { @@ -142,7 +142,7 @@ class GameLoader : public CObject { }; const char *getSavegameFile(int saveGameIdx); -bool readSavegameHeader(Common::InSaveFile *in, FullpipeSavegameHeader &header); +WARN_UNUSED_RESULT bool readSavegameHeader(Common::InSaveFile *in, FullpipeSavegameHeader &header, bool skipThumbnail = true); void parseSavegameHeader(Fullpipe::FullpipeSavegameHeader &header, SaveStateDescriptor &desc); Inventory2 *getGameLoaderInventory(); diff --git a/engines/fullpipe/modal.cpp b/engines/fullpipe/modal.cpp index be1e73ff70..45ccabc7d5 100644 --- a/engines/fullpipe/modal.cpp +++ b/engines/fullpipe/modal.cpp @@ -2142,7 +2142,8 @@ bool ModalSaveGame::getFileInfo(int slot, FileInfo *fileinfo) { return false; Fullpipe::FullpipeSavegameHeader header; - Fullpipe::readSavegameHeader(f.get(), header); + if (!Fullpipe::readSavegameHeader(f.get(), header)) + return false; // Create the return descriptor SaveStateDescriptor desc(slot, header.saveName); diff --git a/engines/fullpipe/stateloader.cpp b/engines/fullpipe/stateloader.cpp index 9d4d5ab09a..250c527f40 100644 --- a/engines/fullpipe/stateloader.cpp +++ b/engines/fullpipe/stateloader.cpp @@ -193,7 +193,7 @@ void fillDummyHeader(Fullpipe::FullpipeSavegameHeader &header) { header.playtime = 0; } -bool readSavegameHeader(Common::InSaveFile *in, FullpipeSavegameHeader &header) { +WARN_UNUSED_RESULT bool readSavegameHeader(Common::InSaveFile *in, FullpipeSavegameHeader &header, bool skipThumbnail) { uint oldPos = in->pos(); in->seek(-4, SEEK_END); @@ -237,13 +237,13 @@ bool readSavegameHeader(Common::InSaveFile *in, FullpipeSavegameHeader &header) header.description = header.saveName; // Get the thumbnail - header.thumbnail = Common::SharedPtr<Graphics::Surface>(Graphics::loadThumbnail(*in), Graphics::SurfaceDeleter()); + if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) { + in->seek(oldPos, SEEK_SET); // Rewind the file + return false; + } in->seek(oldPos, SEEK_SET); // Rewind the file - if (!header.thumbnail) - return false; - return true; } diff --git a/engines/gnap/detection.cpp b/engines/gnap/detection.cpp index d19d420ff8..97c9128002 100644 --- a/engines/gnap/detection.cpp +++ b/engines/gnap/detection.cpp @@ -141,13 +141,8 @@ SaveStateList GnapMetaEngine::listSaves(const char *target) const { Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file); if (in) { - Gnap::GnapEngine::readSavegameHeader(in, header); - saveList.push_back(SaveStateDescriptor(slot, header._saveName)); - - if (header._thumbnail) { - header._thumbnail->free(); - delete header._thumbnail; - } + if (Gnap::GnapEngine::readSavegameHeader(in, header)) + saveList.push_back(SaveStateDescriptor(slot, header._saveName)); delete in; } } @@ -179,7 +174,11 @@ SaveStateDescriptor GnapMetaEngine::querySaveMetaInfos(const char *target, int s SaveStateDescriptor desc(slot, saveName); if (version != 1) { - Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*file); + Graphics::Surface *thumbnail; + if (!Graphics::loadThumbnail(*file, thumbnail)) { + delete file; + return SaveStateDescriptor(); + } desc.setThumbnail(thumbnail); } diff --git a/engines/gnap/gnap.h b/engines/gnap/gnap.h index dbefa31795..dd653304e7 100644 --- a/engines/gnap/gnap.h +++ b/engines/gnap/gnap.h @@ -319,7 +319,7 @@ public: Common::String generateSaveName(int slot); void synchronize(Common::Serializer &s); void writeSavegameHeader(Common::OutSaveFile *out, GnapSavegameHeader &header); - static bool readSavegameHeader(Common::InSaveFile *in, GnapSavegameHeader &header); + WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, GnapSavegameHeader &header, bool skipThumbnail = true); void delayTicks(int val, int idx, bool updateCursor); void delayTicksA(int val, int idx); diff --git a/engines/gnap/menu.cpp b/engines/gnap/menu.cpp index 9606273b4c..34b5f18473 100644 --- a/engines/gnap/menu.cpp +++ b/engines/gnap/menu.cpp @@ -589,9 +589,8 @@ void GnapEngine::writeSavegameHeader(Common::OutSaveFile *out, GnapSavegameHeade out->writeSint16LE(td.tm_min); } -bool GnapEngine::readSavegameHeader(Common::InSaveFile *in, GnapSavegameHeader &header) { +WARN_UNUSED_RESULT bool GnapEngine::readSavegameHeader(Common::InSaveFile *in, GnapSavegameHeader &header, bool skipThumbnail) { char saveIdentBuffer[SAVEGAME_STR_SIZE + 1]; - header._thumbnail = nullptr; // Validate the header Id in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1); @@ -612,9 +611,9 @@ bool GnapEngine::readSavegameHeader(Common::InSaveFile *in, GnapSavegameHeader & if (header._version == 1) header._thumbnail = nullptr; else { - header._thumbnail = Graphics::loadThumbnail(*in); - if (!header._thumbnail) + if (!Graphics::loadThumbnail(*in, header._thumbnail, skipThumbnail)) { return false; + } } // Read in save date/time diff --git a/engines/hopkins/detection.cpp b/engines/hopkins/detection.cpp index 041afecaa8..ebefee6278 100644 --- a/engines/hopkins/detection.cpp +++ b/engines/hopkins/detection.cpp @@ -168,9 +168,6 @@ SaveStateList HopkinsMetaEngine::listSaves(const char *target) const { if (in) { if (Hopkins::SaveLoadManager::readSavegameHeader(in, header)) { saveList.push_back(SaveStateDescriptor(slot, header._saveName)); - - header._thumbnail->free(); - delete header._thumbnail; } delete in; @@ -198,7 +195,11 @@ SaveStateDescriptor HopkinsMetaEngine::querySaveMetaInfos(const char *target, in if (f) { Hopkins::hopkinsSavegameHeader header; - Hopkins::SaveLoadManager::readSavegameHeader(f, header); + if (!Hopkins::SaveLoadManager::readSavegameHeader(f, header, false)) { + delete f; + return SaveStateDescriptor(); + } + delete f; // Create the return descriptor diff --git a/engines/hopkins/dialogs.cpp b/engines/hopkins/dialogs.cpp index fc613f892d..b8f1c73304 100644 --- a/engines/hopkins/dialogs.cpp +++ b/engines/hopkins/dialogs.cpp @@ -692,7 +692,7 @@ void DialogsManager::showSaveLoad(SaveLoadMode mode) { for (int slotNumber = 1; slotNumber <= 6; ++slotNumber) { hopkinsSavegameHeader header; - if (_vm->_saveLoad->readSavegameHeader(slotNumber, header)) { + if (_vm->_saveLoad->readSavegameHeader(slotNumber, header, false)) { Graphics::Surface thumb8; _vm->_saveLoad->convertThumb16To8(header._thumbnail, &thumb8); diff --git a/engines/hopkins/saveload.cpp b/engines/hopkins/saveload.cpp index 05c7fb8119..35a80458ff 100644 --- a/engines/hopkins/saveload.cpp +++ b/engines/hopkins/saveload.cpp @@ -77,9 +77,8 @@ void SaveLoadManager::load(const Common::String &file, byte *buf) { delete savefile; } -bool SaveLoadManager::readSavegameHeader(Common::InSaveFile *in, hopkinsSavegameHeader &header) { +WARN_UNUSED_RESULT bool SaveLoadManager::readSavegameHeader(Common::InSaveFile *in, hopkinsSavegameHeader &header, bool skipThumbnail) { char saveIdentBuffer[SAVEGAME_STR_SIZE + 1]; - header._thumbnail = NULL; // Validate the header Id in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1); @@ -96,9 +95,9 @@ bool SaveLoadManager::readSavegameHeader(Common::InSaveFile *in, hopkinsSavegame while ((ch = (char)in->readByte()) != '\0') header._saveName += ch; // Get the thumbnail - header._thumbnail = Graphics::loadThumbnail(*in); - if (!header._thumbnail) + if (!Graphics::loadThumbnail(*in, header._thumbnail, skipThumbnail)) { return false; + } // Read in save date/time header._year = in->readSint16LE(); @@ -186,10 +185,10 @@ Common::Error SaveLoadManager::loadGame(int slot) { // Read in the savegame header hopkinsSavegameHeader header; - readSavegameHeader(savefile, header); - if (header._thumbnail) - header._thumbnail->free(); - delete header._thumbnail; + if (!readSavegameHeader(savefile, header)) { + delete savefile; + return Common::kReadingFailed; + } // Read in the savegame data syncSavegameData(serializer, header._version); @@ -212,14 +211,14 @@ Common::Error SaveLoadManager::loadGame(int slot) { return Common::kNoError; } -bool SaveLoadManager::readSavegameHeader(int slot, hopkinsSavegameHeader &header) { +WARN_UNUSED_RESULT bool SaveLoadManager::readSavegameHeader(int slot, hopkinsSavegameHeader &header, bool skipThumbnail) { // Try and open the save file for reading Common::InSaveFile *savefile = g_system->getSavefileManager()->openForLoading( _vm->generateSaveName(slot)); if (!savefile) return false; - bool result = readSavegameHeader(savefile, header); + bool result = readSavegameHeader(savefile, header, skipThumbnail); delete savefile; return result; } diff --git a/engines/hopkins/saveload.h b/engines/hopkins/saveload.h index 7b4ec307f5..33234f49fa 100644 --- a/engines/hopkins/saveload.h +++ b/engines/hopkins/saveload.h @@ -61,9 +61,9 @@ public: bool saveFile(const Common::String &file, const void *buf, size_t n); void load(const Common::String &file, byte *buf); - static bool readSavegameHeader(Common::InSaveFile *in, hopkinsSavegameHeader &header); + WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, hopkinsSavegameHeader &header, bool skipThumbnail = true); void writeSavegameHeader(Common::OutSaveFile *out, hopkinsSavegameHeader &header); - bool readSavegameHeader(int slot, hopkinsSavegameHeader &header); + WARN_UNUSED_RESULT bool readSavegameHeader(int slot, hopkinsSavegameHeader &header, bool skipThumbnail = true); Common::Error saveGame(int slot, const Common::String &saveName); Common::Error loadGame(int slot); diff --git a/engines/hugo/detection.cpp b/engines/hugo/detection.cpp index 4e4746c002..6d2fec5421 100644 --- a/engines/hugo/detection.cpp +++ b/engines/hugo/detection.cpp @@ -241,7 +241,12 @@ SaveStateDescriptor HugoMetaEngine::querySaveMetaInfos(const char *target, int s SaveStateDescriptor desc(slot, saveName); - Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*file); + Graphics::Surface *thumbnail; + if (!Graphics::loadThumbnail(*file, thumbnail)) { + warning("Missing or broken savegame thumbnail"); + delete file; + return SaveStateDescriptor(); + } desc.setThumbnail(thumbnail); uint32 saveDate = file->readUint32BE(); diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp index 70c7e7c93c..79e1d9f494 100644 --- a/engines/kyra/detection.cpp +++ b/engines/kyra/detection.cpp @@ -256,7 +256,7 @@ SaveStateList KyraMetaEngine::listSaves(const char *target) const { if (slotNum >= 0 && slotNum <= 999) { Common::InSaveFile *in = saveFileMan->openForLoading(*file); if (in) { - if (Kyra::KyraEngine_v1::readSaveHeader(in, false, header) == Kyra::KyraEngine_v1::kRSHENoError) { + if (Kyra::KyraEngine_v1::readSaveHeader(in, header) == Kyra::KyraEngine_v1::kRSHENoError) { // WORKAROUND: Old savegames are using 'German' as description for kyra3 restart game save (slot 0), // since that looks odd we replace it by "New Game". if (slotNum == 0 && header.gameID == Kyra::GI_KYRA3) @@ -298,7 +298,7 @@ SaveStateDescriptor KyraMetaEngine::querySaveMetaInfos(const char *target, int s Kyra::KyraEngine_v1::SaveHeader header; Kyra::KyraEngine_v1::ReadSaveHeaderError error; - error = Kyra::KyraEngine_v1::readSaveHeader(in, true, header); + error = Kyra::KyraEngine_v1::readSaveHeader(in, header, false); delete in; if (error == Kyra::KyraEngine_v1::kRSHENoError) { diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h index 4de7494510..bbbd59a4b8 100644 --- a/engines/kyra/kyra_v1.h +++ b/engines/kyra/kyra_v1.h @@ -416,7 +416,7 @@ protected: kRSHEIoError = 3 }; - static ReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *file, bool loadThumbnail, SaveHeader &header); + WARN_UNUSED_RESULT static ReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *file, SaveHeader &header, bool skipThumbnail = true); void loadGameStateCheck(int slot); virtual Common::Error loadGameState(int slot) = 0; diff --git a/engines/kyra/saveload.cpp b/engines/kyra/saveload.cpp index b44850f5c9..c306d6cb5d 100644 --- a/engines/kyra/saveload.cpp +++ b/engines/kyra/saveload.cpp @@ -37,12 +37,11 @@ namespace Kyra { -KyraEngine_v1::ReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header) { +WARN_UNUSED_RESULT KyraEngine_v1::ReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header, bool skipThumbnail) { uint32 type = in->readUint32BE(); header.originalSave = false; header.oldHeader = false; header.flags = 0; - header.thumbnail = 0; if (type == MKTAG('K', 'Y', 'R', 'A') || type == MKTAG('A', 'R', 'Y', 'K')) { // old Kyra1 header ID header.gameID = GI_KYRA1; @@ -125,10 +124,8 @@ KyraEngine_v1::ReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::Seekabl header.flags = in->readUint32BE(); if (header.version >= 14) { - if (loadThumbnail) { - header.thumbnail = Graphics::loadThumbnail(*in); - } else { - Graphics::skipThumbnail(*in); + if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) { + return kRSHEIoError; } } @@ -140,7 +137,7 @@ Common::SeekableReadStream *KyraEngine_v1::openSaveForReading(const char *filena if (!(in = _saveFileMan->openForLoading(filename))) return 0; - ReadSaveHeaderError errorCode = KyraEngine_v1::readSaveHeader(in, false, header); + ReadSaveHeaderError errorCode = KyraEngine_v1::readSaveHeader(in, header); if (errorCode != kRSHENoError) { if (errorCode == kRSHEInvalidType) warning("No ScummVM Kyra engine savefile header"); diff --git a/engines/lab/lab.h b/engines/lab/lab.h index 2a1e527098..aedf0181ec 100644 --- a/engines/lab/lab.h +++ b/engines/lab/lab.h @@ -502,7 +502,7 @@ private: void handleTrialWarning(); }; -bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &header); +WARN_UNUSED_RESULT bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &header, bool skipThumbnail = true); } // End of namespace Lab diff --git a/engines/lab/savegame.cpp b/engines/lab/savegame.cpp index 656595e3e5..46ef1486f0 100644 --- a/engines/lab/savegame.cpp +++ b/engines/lab/savegame.cpp @@ -76,7 +76,7 @@ void LabEngine::writeSaveGameHeader(Common::OutSaveFile *out, const Common::Stri out->writeUint32BE(playTime); } -bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &header) { +WARN_UNUSED_RESULT bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &header, bool skipThumbnail) { uint32 id = in->readUint32BE(); // Check if it's a valid ScummVM savegame @@ -98,7 +98,11 @@ bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &header) { header._descr.setDescription(saveName); // Get the thumbnail - header._descr.setThumbnail(Graphics::loadThumbnail(*in)); + Graphics::Surface *thumbnail; + if (!Graphics::loadThumbnail(*in, thumbnail, skipThumbnail)) { + return false; + } + header._descr.setThumbnail(thumbnail); uint32 saveDate = in->readUint32BE(); uint16 saveTime = in->readUint16BE(); @@ -174,7 +178,11 @@ bool LabEngine::loadGame(int slot) { return false; SaveGameHeader header; - readSaveGameHeader(file, header); + if (!readSaveGameHeader(file, header)) { + delete file; + return false; + } + _roomNum = file->readUint16LE(); _music->checkRoomMusic(1, _roomNum); _direction = file->readUint16LE(); diff --git a/engines/lilliput/detection.cpp b/engines/lilliput/detection.cpp index a09e5f05de..466c89e362 100644 --- a/engines/lilliput/detection.cpp +++ b/engines/lilliput/detection.cpp @@ -233,7 +233,11 @@ SaveStateDescriptor LilliputMetaEngine::querySaveMetaInfos(const char *target, i SaveStateDescriptor desc(slot, saveName); - Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*file); + Graphics::Surface *thumbnail; + if (!Graphics::loadThumbnail(*file, thumbnail)) { + delete file; + return SaveStateDescriptor(); + } desc.setThumbnail(thumbnail); desc.setDeletableFlag(true); diff --git a/engines/macventure/detection.cpp b/engines/macventure/detection.cpp index c179647121..5eda420cb2 100644 --- a/engines/macventure/detection.cpp +++ b/engines/macventure/detection.cpp @@ -54,7 +54,7 @@ static const PlainGameDescriptor macventureGames[] = { namespace MacVenture { -SaveStateDescriptor loadMetaData(Common::SeekableReadStream *s, int slot); +SaveStateDescriptor loadMetaData(Common::SeekableReadStream *s, int slot, bool skipThumbnail = true); class MacVentureMetaEngine : public AdvancedMetaEngine { public: @@ -164,7 +164,7 @@ SaveStateDescriptor MacVentureMetaEngine::querySaveMetaInfos(const char *target, Common::InSaveFile *in = saveFileMan->openForLoading(saveFileName); if (in) { - desc = loadMetaData(in, slot); + desc = loadMetaData(in, slot, false); delete in; return desc; } diff --git a/engines/macventure/saveload.cpp b/engines/macventure/saveload.cpp index 89a6301318..c63b6a6951 100644 --- a/engines/macventure/saveload.cpp +++ b/engines/macventure/saveload.cpp @@ -42,7 +42,7 @@ namespace MacVenture { #define MACVENTURE_SAVE_VERSION 1 //1 BYTE #define MACVENTURE_DESC_LENGTH 4 //4 BYTE for the metadata length -SaveStateDescriptor loadMetaData(Common::SeekableReadStream *s, int slot) { +SaveStateDescriptor loadMetaData(Common::SeekableReadStream *s, int slot, bool skipThumbnail) { // Metadata is stored at the end of the file // |THUMBNAIL | // | | @@ -65,8 +65,11 @@ SaveStateDescriptor loadMetaData(Common::SeekableReadStream *s, int slot) { s->seek(-(5 + MACVENTURE_DESC_LENGTH + metaSize), SEEK_END); // Load the thumbnail - Graphics::Surface *thumb = Graphics::loadThumbnail(*s); - desc.setThumbnail(thumb); + Graphics::Surface *thumbnail; + if (!Graphics::loadThumbnail(*s, thumbnail, skipThumbnail)) { + return desc; + } + desc.setThumbnail(thumbnail); // Load the description Common::String name; diff --git a/engines/mads/detection.cpp b/engines/mads/detection.cpp index 4fb8b82eb3..8eb3b4eee9 100644 --- a/engines/mads/detection.cpp +++ b/engines/mads/detection.cpp @@ -203,11 +203,8 @@ SaveStateList MADSMetaEngine::listSaves(const char *target) const { Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file); if (in) { - MADS::Game::readSavegameHeader(in, header); - saveList.push_back(SaveStateDescriptor(slot, header._saveName)); - - header._thumbnail->free(); - delete header._thumbnail; + if (MADS::Game::readSavegameHeader(in, header)) + saveList.push_back(SaveStateDescriptor(slot, header._saveName)); delete in; } } @@ -233,7 +230,10 @@ SaveStateDescriptor MADSMetaEngine::querySaveMetaInfos(const char *target, int s if (f) { MADS::MADSSavegameHeader header; - MADS::Game::readSavegameHeader(f, header); + if (!MADS::Game::readSavegameHeader(f, header, false)) { + delete f; + return SaveStateDescriptor(); + } delete f; // Create the return descriptor diff --git a/engines/mads/game.cpp b/engines/mads/game.cpp index 0a6741ba7a..bea0ea3bb4 100644 --- a/engines/mads/game.cpp +++ b/engines/mads/game.cpp @@ -485,11 +485,6 @@ void Game::loadGame(int slotNumber) { if (!readSavegameHeader(_saveFile, header)) error("Invalid savegame"); - if (header._thumbnail) { - header._thumbnail->free(); - delete header._thumbnail; - } - // Load most of the savegame data with the exception of scene specific info synchronize(s, true); @@ -527,9 +522,8 @@ void Game::saveGame(int slotNumber, const Common::String &saveName) { const char *const SAVEGAME_STR = "MADS"; #define SAVEGAME_STR_SIZE 4 -bool Game::readSavegameHeader(Common::InSaveFile *in, MADSSavegameHeader &header) { +WARN_UNUSED_RESULT bool Game::readSavegameHeader(Common::InSaveFile *in, MADSSavegameHeader &header, bool skipThumbnail) { char saveIdentBuffer[SAVEGAME_STR_SIZE + 1]; - header._thumbnail = nullptr; // Validate the header Id in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1); @@ -546,9 +540,9 @@ bool Game::readSavegameHeader(Common::InSaveFile *in, MADSSavegameHeader &header while ((ch = (char)in->readByte()) != '\0') header._saveName += ch; // Get the thumbnail - header._thumbnail = Graphics::loadThumbnail(*in); - if (!header._thumbnail) + if (!Graphics::loadThumbnail(*in, header._thumbnail, skipThumbnail)) { return false; + } // Read in save date/time header._year = in->readSint16LE(); diff --git a/engines/mads/game.h b/engines/mads/game.h index 9defb58b1a..b979160f3d 100644 --- a/engines/mads/game.h +++ b/engines/mads/game.h @@ -237,7 +237,7 @@ public: /** * Read in a savegame header */ - static bool readSavegameHeader(Common::InSaveFile *in, MADSSavegameHeader &header); + WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, MADSSavegameHeader &header, bool skipThumbnail = true); /** * Creates a temporary thumbnail for use in saving games diff --git a/engines/mohawk/myst_state.cpp b/engines/mohawk/myst_state.cpp index 213a976413..20b8ec47ae 100644 --- a/engines/mohawk/myst_state.cpp +++ b/engines/mohawk/myst_state.cpp @@ -272,7 +272,12 @@ SaveStateDescriptor MystGameState::querySaveMetaInfos(int slot) { desc.setSaveDate(metadata.saveYear, metadata.saveMonth, metadata.saveDay); desc.setSaveTime(metadata.saveHour, metadata.saveMinute); desc.setPlayTime(metadata.totalPlayTime); - desc.setThumbnail(Graphics::loadThumbnail(*metadataFile)); + Graphics::Surface *thumbnail; + if (!Graphics::loadThumbnail(*metadataFile, thumbnail)) { + delete metadataFile; + return SaveStateDescriptor(); + } + desc.setThumbnail(thumbnail); delete metadataFile; diff --git a/engines/mohawk/riven_saveload.cpp b/engines/mohawk/riven_saveload.cpp index 7165166d8f..1d9ae211d9 100644 --- a/engines/mohawk/riven_saveload.cpp +++ b/engines/mohawk/riven_saveload.cpp @@ -148,7 +148,11 @@ SaveStateDescriptor RivenSaveLoad::querySaveMetaInfos(const int slot) { return descriptor; } - descriptor.setThumbnail(Graphics::loadThumbnail(*thmbStream)); + Graphics::Surface *thumbnail; + if (!Graphics::loadThumbnail(*thmbStream, thumbnail)) { + return descriptor; + } + descriptor.setThumbnail(thumbnail); delete thmbStream; diff --git a/engines/mortevielle/saveload.cpp b/engines/mortevielle/saveload.cpp index 3032c96690..078338a0b5 100644 --- a/engines/mortevielle/saveload.cpp +++ b/engines/mortevielle/saveload.cpp @@ -92,8 +92,10 @@ bool SavegameManager::loadSavegame(const Common::String &filename) { if (!strncmp(&buffer[0], &SAVEGAME_ID[0], 4)) { // Yes, it is, so skip over the savegame header SavegameHeader header; - readSavegameHeader(stream, header); - delete header.thumbnail; + if (!readSavegameHeader(stream, header)) { + delete stream; + return false; + } } else { stream->seek(0); } @@ -208,9 +210,7 @@ void SavegameManager::writeSavegameHeader(Common::OutSaveFile *out, const Common out->writeSint16LE(td.tm_min); } -bool SavegameManager::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header) { - header.thumbnail = NULL; - +WARN_UNUSED_RESULT bool SavegameManager::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header, bool skipThumbnail) { // Get the savegame version header.version = in->readByte(); @@ -221,9 +221,9 @@ bool SavegameManager::readSavegameHeader(Common::InSaveFile *in, SavegameHeader header.saveName += ch; // Get the thumbnail - header.thumbnail = Graphics::loadThumbnail(*in); - if (!header.thumbnail) + if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) { return false; + } // Read in save date/time header.saveYear = in->readSint16LE(); @@ -263,7 +263,6 @@ SaveStateList SavegameManager::listSaves(const Common::String &target) { validFlag = readSavegameHeader(in, header); if (validFlag) { - delete header.thumbnail; saveDescription = header.saveName; } } else if (file->size() == 497) { @@ -311,7 +310,10 @@ SaveStateDescriptor SavegameManager::querySaveMetaInfos(const Common::String &fi } else { // Get the savegame header information SavegameHeader header; - readSavegameHeader(f, header); + if (!readSavegameHeader(f, header, false)) { + delete f; + return SaveStateDescriptor(); + } delete f; // Create the return descriptor diff --git a/engines/mortevielle/saveload.h b/engines/mortevielle/saveload.h index a0de05b920..b401823938 100644 --- a/engines/mortevielle/saveload.h +++ b/engines/mortevielle/saveload.h @@ -65,7 +65,7 @@ public: Common::Error saveGame(int slot); void writeSavegameHeader(Common::OutSaveFile *out, const Common::String &saveName); - static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header); + WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header, bool skipThumbnail = true); static SaveStateList listSaves(const Common::String &target); static SaveStateDescriptor querySaveMetaInfos(const Common::String &fileName); }; diff --git a/engines/neverhood/detection.cpp b/engines/neverhood/detection.cpp index 46605bb2f7..920d149659 100644 --- a/engines/neverhood/detection.cpp +++ b/engines/neverhood/detection.cpp @@ -271,7 +271,7 @@ SaveStateList NeverhoodMetaEngine::listSaves(const char *target) const { if (slotNum >= 0 && slotNum <= 999) { Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); if (in) { - if (Neverhood::NeverhoodEngine::readSaveHeader(in, false, header) == Neverhood::NeverhoodEngine::kRSHENoError) { + if (Neverhood::NeverhoodEngine::readSaveHeader(in, header) == Neverhood::NeverhoodEngine::kRSHENoError) { saveList.push_back(SaveStateDescriptor(slotNum, header.description)); } delete in; @@ -302,7 +302,7 @@ SaveStateDescriptor NeverhoodMetaEngine::querySaveMetaInfos(const char *target, Neverhood::NeverhoodEngine::SaveHeader header; Neverhood::NeverhoodEngine::kReadSaveHeaderError error; - error = Neverhood::NeverhoodEngine::readSaveHeader(in, true, header); + error = Neverhood::NeverhoodEngine::readSaveHeader(in, header, false); delete in; if (error == Neverhood::NeverhoodEngine::kRSHENoError) { diff --git a/engines/neverhood/menumodule.cpp b/engines/neverhood/menumodule.cpp index e3996a2507..b64f4dcdd2 100644 --- a/engines/neverhood/menumodule.cpp +++ b/engines/neverhood/menumodule.cpp @@ -291,7 +291,7 @@ void MenuModule::loadSavegameList() { if (slotNum >= 0 && slotNum <= 999) { Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); if (in) { - if (Neverhood::NeverhoodEngine::readSaveHeader(in, false, header) == Neverhood::NeverhoodEngine::kRSHENoError) { + if (Neverhood::NeverhoodEngine::readSaveHeader(in, header) == Neverhood::NeverhoodEngine::kRSHENoError) { SavegameItem savegameItem; savegameItem.slotNum = slotNum; savegameItem.description = header.description; diff --git a/engines/neverhood/neverhood.h b/engines/neverhood/neverhood.h index 4c5f9c3303..90055eeb9d 100644 --- a/engines/neverhood/neverhood.h +++ b/engines/neverhood/neverhood.h @@ -129,7 +129,7 @@ public: bool loadgame(const char *filename); const char *getSavegameFilename(int num); static Common::String getSavegameFilename(const Common::String &target, int num); - static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header); + WARN_UNUSED_RESULT static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header, bool skipThumbnail = true); GameState& gameState() { return _gameState; } GameModule *gameModule() { return _gameModule; } diff --git a/engines/neverhood/saveload.cpp b/engines/neverhood/saveload.cpp index 8fe6c9a155..d7e6f1ebfe 100644 --- a/engines/neverhood/saveload.cpp +++ b/engines/neverhood/saveload.cpp @@ -32,7 +32,7 @@ namespace Neverhood { #define NEVERHOOD_SAVEGAME_VERSION 0 -NeverhoodEngine::kReadSaveHeaderError NeverhoodEngine::readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header) { +WARN_UNUSED_RESULT NeverhoodEngine::kReadSaveHeaderError NeverhoodEngine::readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header, bool skipThumbnail) { header.version = in->readUint32LE(); if (header.version > NEVERHOOD_SAVEGAME_VERSION) @@ -43,10 +43,8 @@ NeverhoodEngine::kReadSaveHeaderError NeverhoodEngine::readSaveHeader(Common::Se while (descriptionLen--) header.description += (char)in->readByte(); - if (loadThumbnail) { - header.thumbnail = Graphics::loadThumbnail(*in); - } else { - Graphics::skipThumbnail(*in); + if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) { + return kRSHEIoError; } // Not used yet, reserved for future usage @@ -110,7 +108,7 @@ bool NeverhoodEngine::loadgame(const char *filename) { SaveHeader header; - kReadSaveHeaderError errorCode = readSaveHeader(in, false, header); + kReadSaveHeaderError errorCode = readSaveHeader(in, header); if (errorCode != kRSHENoError) { warning("Error loading savegame '%s'", filename); diff --git a/engines/prince/detection.cpp b/engines/prince/detection.cpp index ce80fe5cab..ef3128ae09 100644 --- a/engines/prince/detection.cpp +++ b/engines/prince/detection.cpp @@ -208,10 +208,6 @@ SaveStateList PrinceMetaEngine::listSaves(const char *target) const { // Valid savegame if (Prince::PrinceEngine::readSavegameHeader(file, header)) { saveList.push_back(SaveStateDescriptor(slotNum, header.saveName)); - if (header.thumbnail) { - header.thumbnail->free(); - delete header.thumbnail; - } } } else { // Must be an original format savegame @@ -239,7 +235,7 @@ SaveStateDescriptor PrinceMetaEngine::querySaveMetaInfos(const char *target, int f->read(buffer, kSavegameStrSize + 1); bool hasHeader = !strncmp(buffer, kSavegameStr, kSavegameStrSize + 1) && - Prince::PrinceEngine::readSavegameHeader(f, header); + Prince::PrinceEngine::readSavegameHeader(f, header, false); delete f; if (!hasHeader) { diff --git a/engines/prince/prince.h b/engines/prince/prince.h index 32e37e0774..c264125895 100644 --- a/engines/prince/prince.h +++ b/engines/prince/prince.h @@ -290,7 +290,7 @@ public: void playVideo(Common::String videoFilename); - static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header); + WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header, bool skipThumbnail = true); Common::String generateSaveName(int slot); void writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &header); void syncGame(Common::SeekableReadStream *readStream, Common::WriteStream *writeStream); diff --git a/engines/prince/saveload.cpp b/engines/prince/saveload.cpp index 14f6078910..8832a6d1d2 100644 --- a/engines/prince/saveload.cpp +++ b/engines/prince/saveload.cpp @@ -44,9 +44,7 @@ namespace Prince { class InterpreterFlags; class Interpreter; -bool PrinceEngine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header) { - header.thumbnail = nullptr; - +WARN_UNUSED_RESULT bool PrinceEngine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header, bool skipThumbnail) { // Get the savegame version header.version = in->readByte(); if (header.version > kSavegameVersion) @@ -59,9 +57,9 @@ bool PrinceEngine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &he header.saveName += ch; // Get the thumbnail - header.thumbnail = Graphics::loadThumbnail(*in); - if (!header.thumbnail) + if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) { return false; + } // Read in save date/time header.saveYear = in->readSint16LE(); @@ -416,10 +414,6 @@ bool PrinceEngine::loadGame(int slotNumber) { delete readStream; return false; } - - // Delete the thumbnail - saveHeader.thumbnail->free(); - delete saveHeader.thumbnail; } // Get in the savegame diff --git a/engines/saga/detection.cpp b/engines/saga/detection.cpp index 6fe4277c27..fcd78502d9 100644 --- a/engines/saga/detection.cpp +++ b/engines/saga/detection.cpp @@ -256,7 +256,11 @@ SaveStateDescriptor SagaMetaEngine::querySaveMetaInfos(const char *target, int s } if (version >= 6) { - Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in); + Graphics::Surface *thumbnail; + if (!Graphics::loadThumbnail(*in, thumbnail)) { + delete in; + return SaveStateDescriptor(); + } desc.setThumbnail(thumbnail); uint32 saveDate = in->readUint32BE(); diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index aa7a63d224..bc7241269d 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -871,7 +871,14 @@ SaveStateDescriptor SciMetaEngine::querySaveMetaInfos(const char *target, int sl descriptor.setDescription(meta.name); - Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in); + Graphics::Surface *thumbnail; + if (!Graphics::loadThumbnail(*in, thumbnail)) { + // invalid + delete in; + + descriptor.setDescription("*Invalid*"); + return descriptor; + } descriptor.setThumbnail(thumbnail); int day = (meta.saveDate >> 24) & 0xFF; diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index d04b3bb5ad..84dd16efa6 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -706,7 +706,9 @@ bool ScummEngine::querySaveMetaInfos(const char *target, int slot, int heversion if (hdr.ver > VER(52)) { if (Graphics::checkThumbnailHeader(*in)) { - thumbnail = Graphics::loadThumbnail(*in); + if (!Graphics::loadThumbnail(*in, thumbnail)) { + return false; + } } if (hdr.ver > VER(57)) { diff --git a/engines/sherlock/detection.cpp b/engines/sherlock/detection.cpp index 9184fd8e88..a0598dcb46 100644 --- a/engines/sherlock/detection.cpp +++ b/engines/sherlock/detection.cpp @@ -233,7 +233,10 @@ SaveStateDescriptor SherlockMetaEngine::querySaveMetaInfos(const char *target, i if (f) { Sherlock::SherlockSavegameHeader header; - Sherlock::SaveManager::readSavegameHeader(f, header); + if (!Sherlock::SaveManager::readSavegameHeader(f, header, false)) { + delete f; + return SaveStateDescriptor(); + } delete f; // Create the return descriptor diff --git a/engines/sherlock/saveload.cpp b/engines/sherlock/saveload.cpp index 9d203a6a27..ca27f57a97 100644 --- a/engines/sherlock/saveload.cpp +++ b/engines/sherlock/saveload.cpp @@ -103,13 +103,9 @@ SaveStateList SaveManager::getSavegameList(const Common::String &target) { Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file); if (in) { - if (!readSavegameHeader(in, header)) - continue; + if (readSavegameHeader(in, header)) + saveList.push_back(SaveStateDescriptor(slot, header._saveName)); - saveList.push_back(SaveStateDescriptor(slot, header._saveName)); - - header._thumbnail->free(); - delete header._thumbnail; delete in; } } @@ -119,9 +115,8 @@ SaveStateList SaveManager::getSavegameList(const Common::String &target) { return saveList; } -bool SaveManager::readSavegameHeader(Common::InSaveFile *in, SherlockSavegameHeader &header) { +WARN_UNUSED_RESULT bool SaveManager::readSavegameHeader(Common::InSaveFile *in, SherlockSavegameHeader &header, bool skipThumbnail) { char saveIdentBuffer[SAVEGAME_STR_SIZE + 1]; - header._thumbnail = nullptr; // Validate the header Id in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1); @@ -138,9 +133,9 @@ bool SaveManager::readSavegameHeader(Common::InSaveFile *in, SherlockSavegameHea while ((ch = (char)in->readByte()) != '\0') header._saveName += ch; // Get the thumbnail - header._thumbnail = Graphics::loadThumbnail(*in); - if (!header._thumbnail) + if (!Graphics::loadThumbnail(*in, header._thumbnail, skipThumbnail)) { return false; + } // Read in save date/time header._year = in->readSint16LE(); @@ -212,11 +207,6 @@ void SaveManager::loadGame(int slot) { if (!readSavegameHeader(saveFile, header)) error("Invalid savegame"); - if (header._thumbnail) { - header._thumbnail->free(); - delete header._thumbnail; - } - // Synchronize the savegame data Serializer s(saveFile, nullptr); s.setVersion(header._version); diff --git a/engines/sherlock/saveload.h b/engines/sherlock/saveload.h index 59b0b26d6e..6348b0f668 100644 --- a/engines/sherlock/saveload.h +++ b/engines/sherlock/saveload.h @@ -105,7 +105,7 @@ public: /** * Read in the header information for a savegame */ - static bool readSavegameHeader(Common::InSaveFile *in, SherlockSavegameHeader &header); + WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, SherlockSavegameHeader &header, bool skipThumbnail = true); /** * Return the index of the button the mouse is over, if any diff --git a/engines/supernova/detection.cpp b/engines/supernova/detection.cpp index 8e9db14db4..7fd2da1760 100644 --- a/engines/supernova/detection.cpp +++ b/engines/supernova/detection.cpp @@ -200,7 +200,11 @@ SaveStateDescriptor SupernovaMetaEngine::querySaveMetaInfos(const char *target, desc.setPlayTime(playTime * 1000); if (Graphics::checkThumbnailHeader(*savefile)) { - Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*savefile); + Graphics::Surface *thumbnail; + if (!Graphics::loadThumbnail(*savefile, thumbnail)) { + delete savefile; + return SaveStateDescriptor(); + } desc.setThumbnail(thumbnail); } diff --git a/engines/sword1/detection.cpp b/engines/sword1/detection.cpp index d4343c8a9f..0b81690bc5 100644 --- a/engines/sword1/detection.cpp +++ b/engines/sword1/detection.cpp @@ -300,7 +300,11 @@ SaveStateDescriptor SwordMetaEngine::querySaveMetaInfos(const char *target, int in->skip(1); if (Graphics::checkThumbnailHeader(*in)) { - Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in); + Graphics::Surface *thumbnail; + if (!Graphics::loadThumbnail(*in, thumbnail)) { + delete in; + return SaveStateDescriptor(); + } desc.setThumbnail(thumbnail); } diff --git a/engines/teenagent/detection.cpp b/engines/teenagent/detection.cpp index caa7bdbec9..e35e7033d5 100644 --- a/engines/teenagent/detection.cpp +++ b/engines/teenagent/detection.cpp @@ -178,8 +178,11 @@ public: SaveStateDescriptor ssd(slot, desc); //checking for the thumbnail - if (Graphics::Surface *const thumb = Graphics::loadThumbnail(*in)) - ssd.setThumbnail(thumb); + Graphics::Surface *thumbnail; + if (!Graphics::loadThumbnail(*in, thumbnail)) { + return SaveStateDescriptor(); + } + ssd.setThumbnail(thumbnail); return ssd; } diff --git a/engines/titanic/core/project_item.cpp b/engines/titanic/core/project_item.cpp index b2bd5cd92b..6da891c417 100644 --- a/engines/titanic/core/project_item.cpp +++ b/engines/titanic/core/project_item.cpp @@ -190,10 +190,6 @@ void CProjectItem::loadGame(int slotId) { // Load the savegame header in TitanicSavegameHeader header; readSavegameHeader(&file, header); - if (header._thumbnail) { - header._thumbnail->free(); - delete header._thumbnail; - } g_vm->_events->setTotalPlayTicks(header._totalFrames); @@ -488,13 +484,9 @@ SaveStateList CProjectItem::getSavegameList(const Common::String &target) { if (in) { SimpleFile f; f.open(in); - if (!readSavegameHeader(&f, header)) - continue; - - saveList.push_back(SaveStateDescriptor(slot, header._saveName)); + if (readSavegameHeader(&f, header)) + saveList.push_back(SaveStateDescriptor(slot, header._saveName)); - header._thumbnail->free(); - delete header._thumbnail; delete in; } } @@ -503,7 +495,7 @@ SaveStateList CProjectItem::getSavegameList(const Common::String &target) { return saveList; } -bool CProjectItem::readSavegameHeader(SimpleFile *file, TitanicSavegameHeader &header) { +bool CProjectItem::readSavegameHeader(SimpleFile *file, TitanicSavegameHeader &header, bool skipThumbnail) { char saveIdentBuffer[SAVEGAME_STR_SIZE + 1]; header._thumbnail = nullptr; header._totalFrames = 0; @@ -526,8 +518,7 @@ bool CProjectItem::readSavegameHeader(SimpleFile *file, TitanicSavegameHeader &h while ((ch = (char)file->readByte()) != '\0') header._saveName += ch; // Get the thumbnail - header._thumbnail = Graphics::loadThumbnail(*file); - if (!header._thumbnail) + if (!Graphics::loadThumbnail(*file, header._thumbnail, skipThumbnail)) return false; // Read in save date/time diff --git a/engines/titanic/core/project_item.h b/engines/titanic/core/project_item.h index c9fd6f97cb..ef557f7f9d 100644 --- a/engines/titanic/core/project_item.h +++ b/engines/titanic/core/project_item.h @@ -155,7 +155,7 @@ public: /** * Read in the header information for a savegame */ - static bool readSavegameHeader(SimpleFile *file, TitanicSavegameHeader &header); + static bool readSavegameHeader(SimpleFile *file, TitanicSavegameHeader &header, bool loadThumbnail = false); public: CLASSDEF; CProjectItem(); diff --git a/engines/titanic/detection.cpp b/engines/titanic/detection.cpp index b33ac51bed..c98fbbdade 100644 --- a/engines/titanic/detection.cpp +++ b/engines/titanic/detection.cpp @@ -128,11 +128,6 @@ SaveStateList TitanicMetaEngine::listSaves(const char *target) const { if (Titanic::CProjectItem::readSavegameHeader(&cf, header)) saveList.push_back(SaveStateDescriptor(slot, header._saveName)); - if (header._thumbnail) { - header._thumbnail->free(); - delete header._thumbnail; - } - cf.close(); } } @@ -161,7 +156,10 @@ SaveStateDescriptor TitanicMetaEngine::querySaveMetaInfos(const char *target, in file.open(f); Titanic::TitanicSavegameHeader header; - Titanic::CProjectItem::readSavegameHeader(&file, header); + if (!Titanic::CProjectItem::readSavegameHeader(&file, header, false)) { + file.close(); + return SaveStateDescriptor(); + } file.close(); diff --git a/engines/titanic/pet_control/pet_load_save.cpp b/engines/titanic/pet_control/pet_load_save.cpp index d918478fb1..72770b9eb2 100644 --- a/engines/titanic/pet_control/pet_load_save.cpp +++ b/engines/titanic/pet_control/pet_load_save.cpp @@ -135,11 +135,6 @@ void CPetLoadSave::resetSlots() { _slotNames[idx].setText(header._saveName); } - if (header._thumbnail) { - header._thumbnail->free(); - delete header._thumbnail; - } - file.close(); } } diff --git a/engines/titanic/titanic.cpp b/engines/titanic/titanic.cpp index e0e4a07ce6..5daf399b04 100644 --- a/engines/titanic/titanic.cpp +++ b/engines/titanic/titanic.cpp @@ -49,7 +49,6 @@ #include "common/translation.h" #include "engines/util.h" #include "graphics/scaler.h" -#include "graphics/thumbnail.h" #include "graphics/screen.h" #include "gui/saveload.h" @@ -256,11 +255,6 @@ CString TitanicEngine::getSavegameName(int slot) { TitanicSavegameHeader header; bool isValid = CProjectItem::readSavegameHeader(&file, header); - if (header._thumbnail) { - header._thumbnail->free(); - delete header._thumbnail; - } - file.close(); if (isValid) diff --git a/engines/toltecs/detection.cpp b/engines/toltecs/detection.cpp index 9303760057..0cd9596c8c 100644 --- a/engines/toltecs/detection.cpp +++ b/engines/toltecs/detection.cpp @@ -276,7 +276,7 @@ SaveStateList ToltecsMetaEngine::listSaves(const char *target) const { if (slotNum >= 0 && slotNum <= 999) { Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); if (in) { - if (Toltecs::ToltecsEngine::readSaveHeader(in, false, header) == Toltecs::ToltecsEngine::kRSHENoError) { + if (Toltecs::ToltecsEngine::readSaveHeader(in, header) == Toltecs::ToltecsEngine::kRSHENoError) { saveList.push_back(SaveStateDescriptor(slotNum, header.description)); } delete in; @@ -325,7 +325,7 @@ SaveStateDescriptor ToltecsMetaEngine::querySaveMetaInfos(const char *target, in Toltecs::ToltecsEngine::SaveHeader header; Toltecs::ToltecsEngine::kReadSaveHeaderError error; - error = Toltecs::ToltecsEngine::readSaveHeader(in, true, header); + error = Toltecs::ToltecsEngine::readSaveHeader(in, header, false); delete in; if (error == Toltecs::ToltecsEngine::kRSHENoError) { diff --git a/engines/toltecs/menu.cpp b/engines/toltecs/menu.cpp index 5fc0599c2a..c4373265e6 100644 --- a/engines/toltecs/menu.cpp +++ b/engines/toltecs/menu.cpp @@ -525,7 +525,7 @@ int MenuSystem::loadSavegamesList() { if (slotNum >= 0 && slotNum <= 999) { Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); if (in) { - if (Toltecs::ToltecsEngine::readSaveHeader(in, false, header) == Toltecs::ToltecsEngine::kRSHENoError) { + if (Toltecs::ToltecsEngine::readSaveHeader(in, header) == Toltecs::ToltecsEngine::kRSHENoError) { _savegames.push_back(SavegameItem(slotNum, header.description)); //debug("%s -> %s", file->c_str(), header.description.c_str()); } diff --git a/engines/toltecs/saveload.cpp b/engines/toltecs/saveload.cpp index 409fc97076..1f2198fc35 100644 --- a/engines/toltecs/saveload.cpp +++ b/engines/toltecs/saveload.cpp @@ -41,7 +41,7 @@ namespace Toltecs { #define TOLTECS_SAVEGAME_VERSION 4 -ToltecsEngine::kReadSaveHeaderError ToltecsEngine::readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header) { +WARN_UNUSED_RESULT ToltecsEngine::kReadSaveHeaderError ToltecsEngine::readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header, bool skipThumbnail) { header.version = in->readUint32LE(); if (header.version > TOLTECS_SAVEGAME_VERSION) @@ -52,10 +52,8 @@ ToltecsEngine::kReadSaveHeaderError ToltecsEngine::readSaveHeader(Common::Seekab while (descriptionLen--) header.description += (char)in->readByte(); - if (loadThumbnail) { - header.thumbnail = Graphics::loadThumbnail(*in); - } else { - Graphics::skipThumbnail(*in); + if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) { + return kRSHEIoError; } // Not used yet, reserved for future usage @@ -147,7 +145,7 @@ void ToltecsEngine::loadgame(const char *filename) { SaveHeader header; - kReadSaveHeaderError errorCode = readSaveHeader(in, false, header); + kReadSaveHeaderError errorCode = readSaveHeader(in, header); if (errorCode != kRSHENoError) { warning("Error loading savegame '%s'", filename); diff --git a/engines/toltecs/toltecs.h b/engines/toltecs/toltecs.h index ece82f4a1a..1c9e9366c7 100644 --- a/engines/toltecs/toltecs.h +++ b/engines/toltecs/toltecs.h @@ -225,7 +225,7 @@ public: const char *getSavegameFilename(int num); static Common::String getSavegameFilename(const Common::String &target, int num); - static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header); + WARN_UNUSED_RESULT static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header, bool skipThumbnail = true); }; diff --git a/engines/toon/detection.cpp b/engines/toon/detection.cpp index e93d676d87..6eb38c4883 100644 --- a/engines/toon/detection.cpp +++ b/engines/toon/detection.cpp @@ -232,7 +232,11 @@ SaveStateDescriptor ToonMetaEngine::querySaveMetaInfos(const char *target, int s SaveStateDescriptor desc(slot, saveName); - Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*file); + Graphics::Surface *thumbnail; + if (!Graphics::loadThumbnail(*file, thumbnail)) { + delete file; + return SaveStateDescriptor(); + } desc.setThumbnail(thumbnail); uint32 saveDate = file->readUint32BE(); diff --git a/engines/tsage/detection.cpp b/engines/tsage/detection.cpp index e476391f71..5d31cca75e 100644 --- a/engines/tsage/detection.cpp +++ b/engines/tsage/detection.cpp @@ -131,9 +131,6 @@ public: if (in) { if (TsAGE::Saver::readSavegameHeader(in, header)) { saveList.push_back(SaveStateDescriptor(slot, header._saveName)); - - header._thumbnail->free(); - delete header._thumbnail; } delete in; @@ -161,7 +158,11 @@ public: if (f) { TsAGE::tSageSavegameHeader header; - TsAGE::Saver::readSavegameHeader(f, header); + if (!TsAGE::Saver::readSavegameHeader(f, header, false)) { + delete f; + return SaveStateDescriptor(); + } + delete f; // Create the return descriptor diff --git a/engines/tsage/saveload.cpp b/engines/tsage/saveload.cpp index 03f615db21..81bb973d02 100644 --- a/engines/tsage/saveload.cpp +++ b/engines/tsage/saveload.cpp @@ -189,10 +189,10 @@ Common::Error Saver::restore(int slot) { // Read in the savegame header tSageSavegameHeader header; - readSavegameHeader(saveFile, header); - if (header._thumbnail) - header._thumbnail->free(); - delete header._thumbnail; + if (!readSavegameHeader(saveFile, header)) { + delete saveFile; + return Common::kReadingFailed; + } serializer.setSaveVersion(header._version); @@ -247,9 +247,8 @@ Common::Error Saver::restore(int slot) { const char *SAVEGAME_STR = "SCUMMVM_TSAGE"; #define SAVEGAME_STR_SIZE 13 -bool Saver::readSavegameHeader(Common::InSaveFile *in, tSageSavegameHeader &header) { +WARN_UNUSED_RESULT bool Saver::readSavegameHeader(Common::InSaveFile *in, tSageSavegameHeader &header, bool skipThumbnail) { char saveIdentBuffer[SAVEGAME_STR_SIZE + 1]; - header._thumbnail = NULL; // Validate the header Id in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1); @@ -266,9 +265,9 @@ bool Saver::readSavegameHeader(Common::InSaveFile *in, tSageSavegameHeader &head while ((ch = (char)in->readByte()) != '\0') header._saveName += ch; // Get the thumbnail - header._thumbnail = Graphics::loadThumbnail(*in); - if (!header._thumbnail) + if (!Graphics::loadThumbnail(*in, header._thumbnail, skipThumbnail)) { return false; + } // Read in save date/time header._saveYear = in->readSint16LE(); diff --git a/engines/tsage/saveload.h b/engines/tsage/saveload.h index 04a1e02b28..3de34489fd 100644 --- a/engines/tsage/saveload.h +++ b/engines/tsage/saveload.h @@ -221,7 +221,7 @@ public: Common::Error save(int slot, const Common::String &saveName); Common::Error restore(int slot); - static bool readSavegameHeader(Common::InSaveFile *in, tSageSavegameHeader &header); + WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, tSageSavegameHeader &header, bool skipThumbnail = true); static void writeSavegameHeader(Common::OutSaveFile *out, tSageSavegameHeader &header); void addListener(SaveListener *obj); diff --git a/engines/tucker/detection.cpp b/engines/tucker/detection.cpp index 7d07edabd3..119d60f23a 100644 --- a/engines/tucker/detection.cpp +++ b/engines/tucker/detection.cpp @@ -175,7 +175,7 @@ public: if (ext && (slot = atoi(ext + 1)) >= 0 && slot <= Tucker::kLastSaveSlot) { Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file); if (in) { - if (Tucker::TuckerEngine::readSavegameHeader(in, header, false) == Tucker::TuckerEngine::kSavegameNoError) { + if (Tucker::TuckerEngine::readSavegameHeader(in, header) == Tucker::TuckerEngine::kSavegameNoError) { saveList.push_back(SaveStateDescriptor(slot, header.description)); } @@ -207,7 +207,7 @@ public: } Tucker::TuckerEngine::SavegameHeader header; - Tucker::TuckerEngine::SavegameError savegameError = Tucker::TuckerEngine::readSavegameHeader(file, header, true); + Tucker::TuckerEngine::SavegameError savegameError = Tucker::TuckerEngine::readSavegameHeader(file, header, false); if (savegameError) { delete file; return SaveStateDescriptor(); diff --git a/engines/tucker/saveload.cpp b/engines/tucker/saveload.cpp index a56ced915e..484c47e5da 100644 --- a/engines/tucker/saveload.cpp +++ b/engines/tucker/saveload.cpp @@ -141,7 +141,7 @@ Common::Error TuckerEngine::loadGameState(int slot) { } -TuckerEngine::SavegameError TuckerEngine::readSavegameHeader(const char *target, int slot, SavegameHeader &header) { +WARN_UNUSED_RESULT TuckerEngine::SavegameError TuckerEngine::readSavegameHeader(const char *target, int slot, SavegameHeader &header) { Common::String fileName = generateGameStateFileName(target, slot); Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(fileName); @@ -155,7 +155,7 @@ TuckerEngine::SavegameError TuckerEngine::readSavegameHeader(const char *target, return savegameError; } -TuckerEngine::SavegameError TuckerEngine::readSavegameHeader(Common::InSaveFile *file, SavegameHeader &header, bool loadThumbnail) { +WARN_UNUSED_RESULT TuckerEngine::SavegameError TuckerEngine::readSavegameHeader(Common::InSaveFile *file, SavegameHeader &header, bool skipThumbnail) { header.version = -1; header.flags = 0; header.description.clear(); @@ -196,10 +196,8 @@ TuckerEngine::SavegameError TuckerEngine::readSavegameHeader(Common::InSaveFile header.saveTime = file->readUint32LE(); header.playTime = file->readUint32LE(); - if (loadThumbnail) { - header.thumbnail = Graphics::loadThumbnail(*file); - } else { - Graphics::skipThumbnail(*file); + if (!Graphics::loadThumbnail(*file, header.thumbnail, skipThumbnail)) { + return kSavegameIoError; } } diff --git a/engines/tucker/tucker.h b/engines/tucker/tucker.h index 4cb427fe35..e3748680fe 100644 --- a/engines/tucker/tucker.h +++ b/engines/tucker/tucker.h @@ -452,8 +452,8 @@ public: virtual bool hasFeature(EngineFeature f) const; GUI::Debugger *getDebugger() { return _console; } - static SavegameError readSavegameHeader(Common::InSaveFile *file, SavegameHeader &header, bool loadThumbnail = false); - static SavegameError readSavegameHeader(const char *target, int slot, SavegameHeader &header); + WARN_UNUSED_RESULT static SavegameError readSavegameHeader(Common::InSaveFile *file, SavegameHeader &header, bool skipThumbnail = true); + WARN_UNUSED_RESULT static SavegameError readSavegameHeader(const char *target, int slot, SavegameHeader &header); bool isAutosaveAllowed(); static bool isAutosaveAllowed(const char *target); protected: diff --git a/engines/voyeur/detection.cpp b/engines/voyeur/detection.cpp index eefe174e94..6452e5741f 100644 --- a/engines/voyeur/detection.cpp +++ b/engines/voyeur/detection.cpp @@ -132,7 +132,6 @@ SaveStateList VoyeurMetaEngine::listSaves(const char *target) const { if (in) { if (header.read(in)) { saveList.push_back(SaveStateDescriptor(slot, header._saveName)); - header._thumbnail->free(); } delete in; } @@ -159,7 +158,7 @@ SaveStateDescriptor VoyeurMetaEngine::querySaveMetaInfos(const char *target, int if (f) { Voyeur::VoyeurSavegameHeader header; - header.read(f); + header.read(f, false); delete f; // Create the return descriptor diff --git a/engines/voyeur/voyeur.cpp b/engines/voyeur/voyeur.cpp index 7f2f0e312e..b7769c1fd4 100644 --- a/engines/voyeur/voyeur.cpp +++ b/engines/voyeur/voyeur.cpp @@ -789,9 +789,6 @@ void VoyeurEngine::loadGame(int slot) { VoyeurSavegameHeader header; if (!header.read(saveFile)) return; - if (header._thumbnail) - header._thumbnail->free(); - delete header._thumbnail; serializer.setVersion(header._version); synchronize(serializer); @@ -856,9 +853,7 @@ void VoyeurEngine::synchronize(Common::Serializer &s) { /*------------------------------------------------------------------------*/ -bool VoyeurSavegameHeader::read(Common::InSaveFile *f) { - _thumbnail = NULL; - +bool VoyeurSavegameHeader::read(Common::InSaveFile *f, bool skipThumbnail) { uint32 signature = f->readUint32BE(); if (signature != MKTAG('V', 'O', 'Y', 'R')) { warning("Invalid savegame"); @@ -875,9 +870,9 @@ bool VoyeurSavegameHeader::read(Common::InSaveFile *f) { _saveName += c; // Get the thumbnail - _thumbnail = Graphics::loadThumbnail(*f); - if (!_thumbnail) + if (!Graphics::loadThumbnail(*f, _thumbnail, skipThumbnail)) { return false; + } // Read in the save datet/ime _saveYear = f->readSint16LE(); diff --git a/engines/voyeur/voyeur.h b/engines/voyeur/voyeur.h index dcd82b24a9..a098ba9e62 100644 --- a/engines/voyeur/voyeur.h +++ b/engines/voyeur/voyeur.h @@ -312,7 +312,7 @@ struct VoyeurSavegameHeader { /** * Read in the header from the specified file */ - bool read(Common::InSaveFile *f); + bool read(Common::InSaveFile *f, bool skipThumbnail = true); /** * Write out header information to the specified file diff --git a/engines/xeen/detection.cpp b/engines/xeen/detection.cpp index 49b74b24a2..abf82188a9 100644 --- a/engines/xeen/detection.cpp +++ b/engines/xeen/detection.cpp @@ -170,12 +170,9 @@ SaveStateList XeenMetaEngine::listSaves(const char *target) const { Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file); if (in) { - Xeen::SavesManager::readSavegameHeader(in, header); - saveList.push_back(SaveStateDescriptor(slot, header._saveName)); + if (Xeen::SavesManager::readSavegameHeader(in, header)) + saveList.push_back(SaveStateDescriptor(slot, header._saveName)); - if (header._thumbnail) - header._thumbnail->free(); - delete header._thumbnail; delete in; } } @@ -200,7 +197,11 @@ SaveStateDescriptor XeenMetaEngine::querySaveMetaInfos(const char *target, int s if (f) { Xeen::XeenSavegameHeader header; - Xeen::SavesManager::readSavegameHeader(f, header); + if (!Xeen::SavesManager::readSavegameHeader(f, header, false)) { + delete f; + return SaveStateDescriptor(); + } + delete f; // Create the return descriptor diff --git a/engines/xeen/saves.cpp b/engines/xeen/saves.cpp index 1f58562bf0..2f290960d3 100644 --- a/engines/xeen/saves.cpp +++ b/engines/xeen/saves.cpp @@ -48,9 +48,8 @@ SavesManager::~SavesManager() { const char *const SAVEGAME_STR = "XEEN"; #define SAVEGAME_STR_SIZE 6 -bool SavesManager::readSavegameHeader(Common::InSaveFile *in, XeenSavegameHeader &header) { +WARN_UNUSED_RESULT bool SavesManager::readSavegameHeader(Common::InSaveFile *in, XeenSavegameHeader &header, bool skipThumbnail) { char saveIdentBuffer[SAVEGAME_STR_SIZE + 1]; - header._thumbnail = nullptr; // Validate the header Id in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1); @@ -68,9 +67,9 @@ bool SavesManager::readSavegameHeader(Common::InSaveFile *in, XeenSavegameHeader header._saveName += ch; // Get the thumbnail - header._thumbnail = Graphics::loadThumbnail(*in); - if (!header._thumbnail) + if (!Graphics::loadThumbnail(*in, header._thumbnail, skipThumbnail)) { return false; + } // Read in save date/time header._year = in->readSint16LE(); @@ -168,11 +167,6 @@ Common::Error SavesManager::loadGameState(int slot) { if (!readSavegameHeader(saveFile, header)) error("Invalid savegame"); - if (header._thumbnail) { - header._thumbnail->free(); - delete header._thumbnail; - } - // Set the total play time events.setPlayTime(header._totalFrames); diff --git a/engines/xeen/saves.h b/engines/xeen/saves.h index b18e04a822..9b1bea62a3 100644 --- a/engines/xeen/saves.h +++ b/engines/xeen/saves.h @@ -65,7 +65,7 @@ public: /** * Read in a savegame header */ - static bool readSavegameHeader(Common::InSaveFile *in, XeenSavegameHeader &header); + WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, XeenSavegameHeader &header, bool skipThumbnail = true); /** * Write out a savegame header diff --git a/engines/zvision/detection.cpp b/engines/zvision/detection.cpp index 5e535a9954..896ea52344 100644 --- a/engines/zvision/detection.cpp +++ b/engines/zvision/detection.cpp @@ -178,7 +178,7 @@ SaveStateDescriptor ZVisionMetaEngine::querySaveMetaInfos(const char *target, in // We only use readSaveGameHeader() here, which doesn't need an engine callback ZVision::SaveManager *zvisionSaveMan = new ZVision::SaveManager(NULL); - bool successfulRead = zvisionSaveMan->readSaveGameHeader(in, header); + bool successfulRead = zvisionSaveMan->readSaveGameHeader(in, header, false); delete zvisionSaveMan; delete in; diff --git a/engines/zvision/file/save_manager.cpp b/engines/zvision/file/save_manager.cpp index 4259937a3b..b33d33cdf1 100644 --- a/engines/zvision/file/save_manager.cpp +++ b/engines/zvision/file/save_manager.cpp @@ -189,7 +189,7 @@ Common::Error SaveManager::loadGame(int slot) { return Common::kNoError; } -bool SaveManager::readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &header) { +bool SaveManager::readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &header, bool skipThumbnail) { uint32 tag = in->readUint32BE(); // Check if it's original savegame than fill header structure if (tag == MKTAG('Z', 'N', 'S', 'G')) { @@ -232,9 +232,9 @@ bool SaveManager::readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &hea header.saveName += ch; // Get the thumbnail - header.thumbnail = Graphics::loadThumbnail(*in); - if (!header.thumbnail) + if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) { return false; + } // Read in save date/time header.saveYear = in->readSint16LE(); diff --git a/engines/zvision/file/save_manager.h b/engines/zvision/file/save_manager.h index 9e816373ea..94885b650b 100644 --- a/engines/zvision/file/save_manager.h +++ b/engines/zvision/file/save_manager.h @@ -94,7 +94,7 @@ public: Common::Error loadGame(int slot); Common::SeekableReadStream *getSlotFile(uint slot); - bool readSaveGameHeader(Common::SeekableReadStream *in, SaveGameHeader &header); + bool readSaveGameHeader(Common::SeekableReadStream *in, SaveGameHeader &header, bool skipThumbnail = true); void prepareSaveBuffer(); void flushSaveBuffer(); |