From 8333aed5c2952ff7aa46870cac93acb595a67f14 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sat, 3 Nov 2018 20:41:59 -0700 Subject: GLK: Adding extra fields to the savegame format for validation --- engines/gargoyle/detection.cpp | 46 +++++++++++++++++++++++++----------------- engines/gargoyle/gargoyle.h | 21 ++++++++++++++++++- engines/gargoyle/glk.cpp | 2 +- engines/gargoyle/streams.cpp | 30 +++++++++++++++++++++++---- engines/gargoyle/streams.h | 7 +++++-- 5 files changed, 79 insertions(+), 27 deletions(-) diff --git a/engines/gargoyle/detection.cpp b/engines/gargoyle/detection.cpp index 63ada3e5dd..ffd7fa9cd5 100644 --- a/engines/gargoyle/detection.cpp +++ b/engines/gargoyle/detection.cpp @@ -23,11 +23,12 @@ #include "gargoyle/gargoyle.h" #include "base/plugins.h" +#include "common/md5.h" +#include "common/memstream.h" #include "common/savefile.h" #include "common/str-array.h" -#include "common/memstream.h" -#include "engines/advancedDetector.h" #include "common/system.h" +#include "engines/advancedDetector.h" #include "graphics/colormasks.h" #include "graphics/surface.h" @@ -36,28 +37,33 @@ namespace Gargoyle { struct GargoyleGameDescription { - ADGameDescription desc; - Common::String filename; - InterpreterType interpType; + ADGameDescription _desc; + Common::String _filename; + InterpreterType _interpType; + Common::String _md5; }; const Common::String &GargoyleEngine::getFilename() const { - return _gameDescription->filename; + return _gameDescription->_filename; } uint32 GargoyleEngine::getFeatures() const { - return _gameDescription->desc.flags; + return _gameDescription->_desc.flags; } bool GargoyleEngine::isDemo() const { - return (bool)(_gameDescription->desc.flags & ADGF_DEMO); + return (bool)(_gameDescription->_desc.flags & ADGF_DEMO); } Common::Language GargoyleEngine::getLanguage() const { - return _gameDescription->desc.language; + return _gameDescription->_desc.language; } InterpreterType GargoyleEngine::getInterpreterType() const { - return _gameDescription->interpType; + return _gameDescription->_interpType; +} + +const Common::String &GargoyleEngine::getGameMD5() const { + return _gameDescription->_md5; } } // End of namespace Gargoyle @@ -117,9 +123,9 @@ bool Gargoyle::GargoyleEngine::hasFeature(EngineFeature f) const { bool GargoyleMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { Gargoyle::GargoyleGameDescription *gd = (Gargoyle::GargoyleGameDescription *)desc; - gd->filename = ConfMan.get("filename"); + gd->_filename = ConfMan.get("filename"); - switch (gd->interpType) { + switch (gd->_interpType) { case Gargoyle::INTERPRETER_SCOTT: *engine = new Gargoyle::Scott::Scott(syst, gd); break; @@ -160,13 +166,15 @@ ADDetectedGames GargoyleMetaEngine::detectGame(const Common::FSNode &parent, con static char gameId[100]; strcpy(gameId, ConfMan.get("gameid").c_str()); Common::String filename = ConfMan.get("filename"); - - if (parent.getChild(filename).exists()) { - gameDescription.desc.gameId = gameId; - gameDescription.desc.language = language; - gameDescription.desc.platform = platform; - gameDescription.desc.extra = extra.c_str(); - gameDescription.filename = filename; + Common::File f; + + if (f.open(parent.getChild(filename))) { + gameDescription._desc.gameId = gameId; + gameDescription._desc.language = language; + gameDescription._desc.platform = platform; + gameDescription._desc.extra = extra.c_str(); + gameDescription._filename = filename; + gameDescription._md5 = Common::computeStreamMD5AsString(f, 5000); ADDetectedGame dg((ADGameDescription *)&gameDescription); detectedGames.push_back(dg); diff --git a/engines/gargoyle/gargoyle.h b/engines/gargoyle/gargoyle.h index 88859b4d68..5ec804e7db 100644 --- a/engines/gargoyle/gargoyle.h +++ b/engines/gargoyle/gargoyle.h @@ -43,7 +43,21 @@ class Windows; class WindowMask; enum InterpreterType { - INTERPRETER_SCOTT + INTERPRETER_ADVSYS = 0, + INTERPRETER_AGILITY = 1, + INTERPRETER_ALAN2 = 2, + INTERPRETER_ALAN3 = 3, + INTERPRETER_BOCFEL = 4, + INTERPRETER_FROTZ = 5, + INTERPRETER_GEAS = 6, + INTERPRETER_HUGO = 7, + INTERPRETER_JACL = 8, + INTERPRETER_LEVEL9 = 9, + INTERPRETER_MAGNETIC = 10, + INTERPRETER_NITFOL = 11, + INTERPRETER_SCARE = 12, + INTERPRETER_SCOTT = 13, + INTERPRETER_TADS = 14 }; enum GargoyleDebugChannels { @@ -132,6 +146,11 @@ public: */ InterpreterType getInterpreterType() const; + /** + * Returns the game's md5 + */ + const Common::String &getGameMD5() const; + /** * Returns the primary filename for the game */ diff --git a/engines/gargoyle/glk.cpp b/engines/gargoyle/glk.cpp index fb140a3390..2f0f0b4a46 100644 --- a/engines/gargoyle/glk.cpp +++ b/engines/gargoyle/glk.cpp @@ -59,7 +59,7 @@ Glk::Glk(OSystem *syst, const GargoyleGameDescription *gameDesc) : } void Glk::glk_exit(void) { - glk_put_string("[ press any key to exit ]"); + glk_put_string("[ press any key to exit ]"); _events->waitForPress(); quitGame(); diff --git a/engines/gargoyle/streams.cpp b/engines/gargoyle/streams.cpp index 7995f4d04e..a8c85a177f 100644 --- a/engines/gargoyle/streams.cpp +++ b/engines/gargoyle/streams.cpp @@ -963,6 +963,15 @@ glui32 FileStream::getLineUni(glui32 *ubuf, glui32 len) { } } +static Common::String readString(Common::ReadStream *src) { + char c; + Common::String result; + while ((c = src->readByte()) != 0) + result += c; + + return result; +} + bool FileStream::readSavegameHeader(Common::SeekableReadStream *stream, SavegameHeader &header) { header._totalFrames = 0; @@ -975,10 +984,17 @@ bool FileStream::readSavegameHeader(Common::SeekableReadStream *stream, Savegame if (header._version > SAVEGAME_VERSION) error("Savegame is too recent"); + // Read the interpreter, language, and game Id + header._interpType = stream->readByte(); + header._language = stream->readByte(); + header._md5 = readString(stream); + + if (header._interpType != g_vm->getInterpreterType() || header._language != g_vm->getLanguage() + || header._md5 != g_vm->getGameMD5()) + return false; + // Read in name - char c; - while ((c = stream->readByte()) != '\0') - header._saveName += c; + header._saveName = readString(stream); // Read in save date/time header._year = stream->readUint16LE(); @@ -994,9 +1010,15 @@ bool FileStream::readSavegameHeader(Common::SeekableReadStream *stream, Savegame void FileStream::writeSavegameHeader(Common::WriteStream *stream, const Common::String &saveName) { // Write out a savegame header stream->writeUint32BE(MKTAG('G', 'A', 'R', 'G')); - stream->writeByte(SAVEGAME_VERSION); + // Write out intrepreter type, language, and game Id + stream->writeByte(g_vm->getInterpreterType()); + stream->writeByte(g_vm->getLanguage()); + Common::String md5 = g_vm->getGameMD5(); + stream->write(md5.c_str(), md5.size()); + stream->writeByte('\0'); + // Write savegame name stream->write(saveName.c_str(), saveName.size()); stream->writeByte('\0'); diff --git a/engines/gargoyle/streams.h b/engines/gargoyle/streams.h index 517192af3f..dad67816e3 100644 --- a/engines/gargoyle/streams.h +++ b/engines/gargoyle/streams.h @@ -68,6 +68,9 @@ typedef StreamResult stream_result_t; struct SavegameHeader { uint8 _version; + byte _interpType; + byte _language; + Common::String _md5; Common::String _saveName; int _year, _month, _day; int _hour, _minute; @@ -76,8 +79,8 @@ struct SavegameHeader { /** * Constructor */ - SavegameHeader() : _version(0), _year(0), _month(0), _day(0), _hour(0), - _minute(0), _totalFrames(0) {} + SavegameHeader() : _version(0), _interpType(0), _language(0), _year(0), _month(0), _day(0), + _hour(0), _minute(0), _totalFrames(0) {} }; /** -- cgit v1.2.3