From 553bb74f8c380ee31fb771c6619dad8e83fed8ce Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 16 Jun 2019 13:29:15 -0700 Subject: GLK: Further changeover of sub-engines to use new savegame code --- engines/glk/POTFILES | 1 + engines/glk/advsys/advsys.cpp | 6 ++-- engines/glk/advsys/advsys.h | 9 ++--- engines/glk/alan2/alan2.cpp | 8 ++--- engines/glk/alan2/alan2.h | 9 ++--- engines/glk/frotz/frotz.cpp | 37 +++++++++++++------ engines/glk/frotz/frotz.h | 19 +++++++--- engines/glk/glk.cpp | 42 +++++++++++++++++++--- engines/glk/glk.h | 9 ++--- engines/glk/glulxe/exec.cpp | 8 +++++ engines/glk/glulxe/glulxe.h | 9 ++--- engines/glk/glulxe/serial.cpp | 18 +++++----- engines/glk/hugo/hugo.cpp | 75 ++++++++++++++++++--------------------- engines/glk/hugo/hugo.h | 9 ++--- engines/glk/magnetic/magnetic.cpp | 8 ++--- engines/glk/magnetic/magnetic.h | 9 ++--- engines/glk/quetzal.cpp | 18 +++++----- engines/glk/quetzal.h | 5 +++ engines/glk/scott/scott.cpp | 28 ++++++++------- engines/glk/scott/scott.h | 9 ++--- engines/glk/tads/tads.cpp | 8 ++--- engines/glk/tads/tads.h | 9 ++--- 22 files changed, 217 insertions(+), 136 deletions(-) diff --git a/engines/glk/POTFILES b/engines/glk/POTFILES index 2a9e70d807..cedc0e1d66 100644 --- a/engines/glk/POTFILES +++ b/engines/glk/POTFILES @@ -5,6 +5,7 @@ engines/glk/advsys/advsys.cpp engines/glk/advsys/vm.cpp engines/glk/alan2/alan2.cpp engines/glk/frotz/detection.cpp +engines/glk/frotz/frotz.cpp engines/glk/glulxe/glulxe.cpp engines/glk/magnetic/magnetic.cpp engines/glk/scott/scott.cpp diff --git a/engines/glk/advsys/advsys.cpp b/engines/glk/advsys/advsys.cpp index ad8412843f..51003205b1 100644 --- a/engines/glk/advsys/advsys.cpp +++ b/engines/glk/advsys/advsys.cpp @@ -102,11 +102,13 @@ bool AdvSys::singleAction() { return true; } -Common::Error AdvSys::loadGameData(strid_t save) { +Common::Error AdvSys::readSaveData(Common::SeekableReadStream *rs) { + rs->read(_saveArea, rs->size()); return Common::kNoError; } -Common::Error AdvSys::saveGameData(strid_t save, const Common::String &desc) { +Common::Error AdvSys::writeGameData(Common::WriteStream *ws) { + ws->write(_saveArea, _saveSize); return Common::kNoError; } diff --git a/engines/glk/advsys/advsys.h b/engines/glk/advsys/advsys.h index 688a8fe094..8b7b7fb56b 100644 --- a/engines/glk/advsys/advsys.h +++ b/engines/glk/advsys/advsys.h @@ -67,14 +67,15 @@ public: } /** - * Load a savegame from the passed stream + * Load a savegame from the passed Quetzal file chunk stream */ - virtual Common::Error loadGameData(strid_t save) override; + virtual Common::Error readSaveData(Common::SeekableReadStream *rs) override; /** - * Save the game to the passed stream + * Save the game. The passed write stream represents access to the UMem chunk + * in the Quetzal save file that will be created */ - virtual Common::Error saveGameData(strid_t save, const Common::String &desc) override; + virtual Common::Error writeGameData(Common::WriteStream *ws) override; }; } // End of namespace AdvSys diff --git a/engines/glk/alan2/alan2.cpp b/engines/glk/alan2/alan2.cpp index da9dbf1115..492d425d98 100644 --- a/engines/glk/alan2/alan2.cpp +++ b/engines/glk/alan2/alan2.cpp @@ -61,14 +61,14 @@ void Alan2::runGame() { // TODO } -Common::Error Alan2::loadGameData(strid_t file) { +Common::Error Alan2::readSaveData(Common::SeekableReadStream *rs) { // TODO - return Common::kNoError; + return Common::kReadingFailed; } -Common::Error Alan2::saveGameData(strid_t file, const Common::String &desc) { +Common::Error Alan2::writeGameData(Common::WriteStream *ws) { // TODO - return Common::kNoError; + return Common::kWritingFailed; } bool Alan2::is_gamefile_valid() { diff --git a/engines/glk/alan2/alan2.h b/engines/glk/alan2/alan2.h index a6ded4304a..a8e500a0dd 100644 --- a/engines/glk/alan2/alan2.h +++ b/engines/glk/alan2/alan2.h @@ -68,14 +68,15 @@ public: virtual InterpreterType getInterpreterType() const override { return INTERPRETER_ALAN2; } /** - * Load a savegame from the passed stream + * Load a savegame from the passed Quetzal file chunk stream */ - virtual Common::Error loadGameData(strid_t file) override; + virtual Common::Error readSaveData(Common::SeekableReadStream *rs) override; /** - * Save the game to the passed stream + * Save the game. The passed write stream represents access to the UMem chunk + * in the Quetzal save file that will be created */ - virtual Common::Error saveGameData(strid_t file, const Common::String &desc) override; + virtual Common::Error writeGameData(Common::WriteStream *ws) override; /** * Output a string to the screen diff --git a/engines/glk/frotz/frotz.cpp b/engines/glk/frotz/frotz.cpp index 0c33f417ec..02ee0900c9 100644 --- a/engines/glk/frotz/frotz.cpp +++ b/engines/glk/frotz/frotz.cpp @@ -26,6 +26,7 @@ #include "glk/frotz/quetzal.h" #include "engines/util.h" #include "common/config-manager.h" +#include "common/translation.h" namespace Glk { namespace Frotz { @@ -90,17 +91,13 @@ void Frotz::initialize() { z_restart(); } -Common::Error Frotz::saveGameData(strid_t file, const Common::String &desc) { - Quetzal q(story_fp); - bool success = q.save(*file, this, desc); +Common::Error Frotz::loadGameState(int slot) { + FileReference ref(slot, "", fileusage_SavedGame | fileusage_TextMode); - if (!success) - print_string("Error writing save file\n"); + strid_t file = _streams->openFileStream(&ref, filemode_Read); + if (file == nullptr) + return Common::kReadingFailed; - return Common::kNoError; -} - -Common::Error Frotz::loadGameData(strid_t file) { Quetzal q(story_fp); bool success = q.restore(*file, this) == 2; @@ -123,14 +120,32 @@ Common::Error Frotz::loadGameData(strid_t file) { * seems to cover up most of the resulting badness. */ if (h_version > V3 && h_version != V6 && (h_screen_rows != old_screen_rows - || h_screen_cols != old_screen_cols)) + || h_screen_cols != old_screen_cols)) erase_window(1); } else { - error("Error reading save file"); + error(_("Error reading save file")); } return Common::kNoError; } +Common::Error Frotz::saveGameState(int slot, const Common::String &desc) { + Common::String msg; + FileReference ref(slot, desc, fileusage_BinaryMode | fileusage_SavedGame); + + strid_t file = _streams->openFileStream(&ref, filemode_Write); + if (file == nullptr) + return Common::kWritingFailed; + + Quetzal q(story_fp); + bool success = q.save(*file, this, desc); + + if (!success) + print_string(_("Error writing save file\n")); + + return Common::kNoError; + +} + } // End of namespace Frotz } // End of namespace Glk diff --git a/engines/glk/frotz/frotz.h b/engines/glk/frotz/frotz.h index 8312e16b49..a8083a3093 100644 --- a/engines/glk/frotz/frotz.h +++ b/engines/glk/frotz/frotz.h @@ -72,14 +72,25 @@ public: virtual void runGame() override; /** - * Load a savegame from the passed stream + * Load a savegame from a given slot */ - virtual Common::Error loadGameData(strid_t file) override; + virtual Common::Error loadGameState(int slot) override; /** - * Save the game to the passed stream + * Save the game to a given slot */ - virtual Common::Error saveGameData(strid_t file, const Common::String &desc) override; + virtual Common::Error saveGameState(int slot, const Common::String &desc) override; + + /** + * Loading method not used for Frotz sub-engine + */ + virtual Common::Error readSaveData(Common::SeekableReadStream *rs) override { return Common::kReadingFailed; } + + /** + * Saving method not used for Frotz sub-engine + */ + virtual Common::Error writeGameData(Common::WriteStream *ws) override { return Common::kWritingFailed; } + }; extern Frotz *g_vm; diff --git a/engines/glk/glk.cpp b/engines/glk/glk.cpp index 7155cd8190..b3760cafd4 100644 --- a/engines/glk/glk.cpp +++ b/engines/glk/glk.cpp @@ -33,6 +33,7 @@ #include "glk/conf.h" #include "glk/events.h" #include "glk/picture.h" +#include "glk/quetzal.h" #include "glk/screen.h" #include "glk/selection.h" #include "glk/sound.h" @@ -182,10 +183,32 @@ Common::Error GlkEngine::loadGameState(int slot) { if (file == nullptr) return Common::kReadingFailed; - Common::Error result = loadGameData(file); + Common::ErrorCode errCode = Common::kNoError; + QuetzalReader r; + if (r.open(*file, ID_IFSF)) { + // First scan for a SCVM chunk. It has information of the game the save is for, + // so if present we can validate the save is for this game + for (QuetzalReader::Iterator it = r.begin(); it != r.end(); ++it) { + if ((*it)._id == ID_SCVM) { + + } + } + + if (errCode != Common::kNoError) { + // Scan for an uncompressed memory chunk + errCode = Common::kReadingFailed; // Presume we won't find chunk + for (QuetzalReader::Iterator it = r.begin(); it != r.end(); ++it) { + if ((*it)._id == ID_UMem) { + Common::SeekableReadStream *rs = it.getStream(); + errCode = readSaveData(rs).getCode(); + delete rs; + } + } + } + } file->close(); - return result; + return errCode; } Common::Error GlkEngine::saveGameState(int slot, const Common::String &desc) { @@ -196,10 +219,21 @@ Common::Error GlkEngine::saveGameState(int slot, const Common::String &desc) { if (file == nullptr) return Common::kWritingFailed; - Common::Error result = saveGameData(file, desc); + Common::ErrorCode errCode = Common::kNoError; + QuetzalWriter w; + + // Add the uncompressed memory chunk with the game's save data + { + Common::WriteStream &ws = w.add(ID_UMem); + errCode = writeGameData(&ws).getCode(); + } + + if (errCode != Common::kNoError) { + w.save(*file, desc); + } file->close(); - return result; + return errCode; } void GlkEngine::beep() { diff --git a/engines/glk/glk.h b/engines/glk/glk.h index f96f384027..739f1774d9 100644 --- a/engines/glk/glk.h +++ b/engines/glk/glk.h @@ -198,14 +198,15 @@ public: virtual Common::Error saveGameState(int slot, const Common::String &desc) override; /** - * Load a savegame from the passed file + * Load a savegame from the passed Quetzal file chunk stream */ - virtual Common::Error loadGameData(strid_t file) = 0; + virtual Common::Error readSaveData(Common::SeekableReadStream *rs) = 0; /** - * Save the game to the passed file + * Save the game. The passed write stream represents access to the UMem chunk + * in the Quetzal save file that will be created */ - virtual Common::Error saveGameData(strid_t file, const Common::String &desc) = 0; + virtual Common::Error writeGameData(Common::WriteStream *ws) = 0; /** * Generate a beep diff --git a/engines/glk/glulxe/exec.cpp b/engines/glk/glulxe/exec.cpp index 5fd15a3be6..cd26241700 100644 --- a/engines/glk/glulxe/exec.cpp +++ b/engines/glk/glulxe/exec.cpp @@ -681,12 +681,20 @@ PerformJump: /* goto label for successful jumping... ironic, no? */ case op_save: push_callstub(inst[1].desttype, inst[1].value); +#ifdef TODO value = saveGameData(find_stream_by_id(inst[0].value), "Savegame").getCode() == Common::kNoError ? 0 : 1; +#else + error("TODO"); +#endif pop_callstub(value); break; case op_restore: +#ifdef TODO value = loadGameData(find_stream_by_id(inst[0].value)).getCode() == Common::kNoError ? 0 : 1; +#else + error("TODO"); +#endif if (value == 0) { /* We've succeeded, and the stack now contains the callstub saved during saveundo. Ignore this opcode's operand. */ diff --git a/engines/glk/glulxe/glulxe.h b/engines/glk/glulxe/glulxe.h index 56a912eeca..bf1bad9afe 100644 --- a/engines/glk/glulxe/glulxe.h +++ b/engines/glk/glulxe/glulxe.h @@ -407,14 +407,15 @@ public: } /** - * Load a savegame from the passed stream + * Load a savegame from the passed Quetzal file chunk stream */ - virtual Common::Error loadGameData(strid_t str) override; + virtual Common::Error readSaveData(Common::SeekableReadStream *rs) override; /** - * Save the game to the passed stream + * Save the game. The passed write stream represents access to the UMem chunk + * in the Quetzal save file that will be created */ - virtual Common::Error saveGameData(strid_t str, const Common::String &desc) override; + virtual Common::Error writeGameData(Common::WriteStream *ws) override; /** * \defgroup Main access methods diff --git a/engines/glk/glulxe/serial.cpp b/engines/glk/glulxe/serial.cpp index d485160302..81cfa9e41b 100644 --- a/engines/glk/glulxe/serial.cpp +++ b/engines/glk/glulxe/serial.cpp @@ -232,13 +232,13 @@ uint Glulxe::perform_restoreundo() { return res; } -Common::Error Glulxe::saveGameData(strid_t str, const Common::String &desc) { +Common::Error Glulxe::writeGameData(Common::WriteStream *ws) { dest_t dest; int ix; - uint res, lx, val; + uint res = 0, lx, val; uint memstart = 0, memlen = 0, stackstart = 0, stacklen = 0; uint heapstart = 0, heaplen = 0, filestart = 0, filelen = 0; - +#ifdef TODO stream_get_iosys(&val, &lx); if (val != 2) { /* Not using the Glk I/O system, so bail. This function only @@ -246,14 +246,14 @@ Common::Error Glulxe::saveGameData(strid_t str, const Common::String &desc) { fatal_error("Streams are only available in Glk I/O system."); } - if (str == nullptr) + if (ws == nullptr) return Common::kUnknownError; dest.ismem = false; dest.size = 0; dest.pos = 0; dest.ptr = nullptr; - dest.str = str; + dest.str = ws; res = 0; @@ -357,11 +357,11 @@ Common::Error Glulxe::saveGameData(strid_t str, const Common::String &desc) { } /* All done. */ - +#endif return res ? Common::kUnknownError : Common::kNoError; } -Common::Error Glulxe::loadGameData(strid_t str) { +Common::Error Glulxe::readSaveData(Common::SeekableReadStream *rs) { dest_t dest; int ix; uint lx, res, val; @@ -369,7 +369,7 @@ Common::Error Glulxe::loadGameData(strid_t str) { uint heapsumlen = 0; uint *heapsumarr = nullptr; bool fromshell = false; - +#ifdef TODO /* If profiling is enabled and active then fail. */ #if VM_PROFILING if (profile_profiling_active()) @@ -475,7 +475,7 @@ Common::Error Glulxe::loadGameData(strid_t str) { if (res) return Common::kUnknownError; - +#endif return Common::kNoError; } diff --git a/engines/glk/hugo/hugo.cpp b/engines/glk/hugo/hugo.cpp index cd4660d0ef..72db1a2489 100644 --- a/engines/glk/hugo/hugo.cpp +++ b/engines/glk/hugo/hugo.cpp @@ -152,7 +152,7 @@ void Hugo::runGame() { hugo_closefiles(); } -Common::Error Hugo::loadGameData(strid_t save) { +Common::Error Hugo::readSaveData(Common::SeekableReadStream *rs) { char testid[3], testserial[9]; int lbyte, hbyte; int j; @@ -160,18 +160,18 @@ Common::Error Hugo::loadGameData(strid_t save) { long i; /* Check ID */ - testid[0] = (char)hugo_fgetc(save); - testid[1] = (char)hugo_fgetc(save); + testid[0] = (char)hugo_fgetc(rs); + testid[1] = (char)hugo_fgetc(rs); testid[2] = '\0'; - if (hugo_ferror(save)) goto RestoreError; + if (hugo_ferror(rs)) goto RestoreError; if (strcmp(testid, id)) { - GUIErrorMessage("Incorrect save file."); + GUIErrorMessage("Incorrect rs file."); goto RestoreError; } /* Check serial number */ - if (!hugo_fgets(testserial, 9, save)) goto RestoreError; + if (!hugo_fgets(testserial, 9, rs)) goto RestoreError; if (strcmp(testserial, serial)) { GUIErrorMessage("Save file created by different version."); @@ -181,7 +181,7 @@ Common::Error Hugo::loadGameData(strid_t save) { /* Restore variables */ for (k=0; kreadByte()) != 0) - result += c; - - return result; -} - void QuetzalReader::clear() { _chunks.clear(); _stream = nullptr; @@ -141,6 +132,15 @@ bool QuetzalReader::getSavegameMetaInfo(Common::SeekableReadStream *rs, SaveStat return true; } +Common::String QuetzalReader::readString(Common::ReadStream *src) { + char c; + Common::String result; + while ((c = src->readByte()) != 0) + result += c; + + return result; +} + /*--------------------------------------------------------------------------*/ Common::WriteStream &QuetzalWriter::add(uint32 chunkId) { diff --git a/engines/glk/quetzal.h b/engines/glk/quetzal.h index b398571f38..7f2dd30a71 100644 --- a/engines/glk/quetzal.h +++ b/engines/glk/quetzal.h @@ -143,6 +143,11 @@ public: * Loads a Quetzal save and extract's it's description and meta info */ static bool getSavegameMetaInfo(Common::SeekableReadStream *rs, SaveStateDescriptor &ssd); + + /** + * Support method for reading a string from a stream + */ + static Common::String readString(Common::ReadStream *src); }; /** diff --git a/engines/glk/scott/scott.cpp b/engines/glk/scott/scott.cpp index b918f8cda2..11b01c9e7e 100644 --- a/engines/glk/scott/scott.cpp +++ b/engines/glk/scott/scott.cpp @@ -21,6 +21,7 @@ */ #include "glk/scott/scott.h" +#include "glk/quetzal.h" #include "common/config-manager.h" #include "common/translation.h" @@ -508,41 +509,44 @@ void Scott::lineInput(char *buf, size_t n) { buf[ev.val1] = 0; } -Common::Error Scott::saveGameData(strid_t file, const Common::String &desc) { +Common::Error Scott::writeGameData(Common::WriteStream *ws) { Common::String msg; for (int ct = 0; ct < 16; ct++) { msg = Common::String::format("%d %d\n", _counters[ct], _roomSaved[ct]); - glk_put_string_stream(file, msg.c_str()); + ws->write(msg.c_str(), msg.size()); + ws->writeByte(0); } msg = Common::String::format("%u %d %d %d %d %d\n", _bitFlags, (_bitFlags & (1 << DARKBIT)) ? 1 : 0, MY_LOC, _currentCounter, _savedRoom, _gameHeader._lightTime); - glk_put_string_stream(file, msg.c_str()); + ws->write(msg.c_str(), msg.size()); + ws->writeByte(0); for (int ct = 0; ct <= _gameHeader._numItems; ct++) { msg = Common::String::format("%hd\n", (short)_items[ct]._location); - glk_put_string_stream(file, msg.c_str()); + ws->write(msg.c_str(), msg.size()); + ws->writeByte(0); } output(_("Saved.\n")); return Common::kNoError; } -Common::Error Scott::loadGameData(strid_t file) { - char buf[128]; +Common::Error Scott::readSaveData(Common::SeekableReadStream *rs) { + Common::String line; int ct = 0; short lo; short darkFlag; for (ct = 0; ct < 16; ct++) { - glk_get_line_stream(file, buf, sizeof buf); - sscanf(buf, "%d %d", &_counters[ct], &_roomSaved[ct]); + line = QuetzalReader::readString(rs); + sscanf(line.c_str(), "%d %d", &_counters[ct], &_roomSaved[ct]); } - glk_get_line_stream(file, buf, sizeof buf); - sscanf(buf, "%u %hd %d %d %d %d\n", + line = QuetzalReader::readString(rs); + sscanf(line.c_str(), "%u %hd %d %d %d %d\n", &_bitFlags, &darkFlag, &MY_LOC, &_currentCounter, &_savedRoom, &_gameHeader._lightTime); @@ -550,8 +554,8 @@ Common::Error Scott::loadGameData(strid_t file) { if (darkFlag) _bitFlags |= (1 << 15); for (ct = 0; ct <= _gameHeader._numItems; ct++) { - glk_get_line_stream(file, buf, sizeof buf); - sscanf(buf, "%hd\n", &lo); + line = QuetzalReader::readString(rs); + sscanf(line.c_str(), "%hd\n", &lo); _items[ct]._location = (unsigned char)lo; } diff --git a/engines/glk/scott/scott.h b/engines/glk/scott/scott.h index 4739e9470a..b7527fe6fc 100644 --- a/engines/glk/scott/scott.h +++ b/engines/glk/scott/scott.h @@ -177,14 +177,15 @@ public: virtual void runGame() override; /** - * Load a savegame from the passed stream + * Load a savegame from the passed Quetzal file chunk stream */ - virtual Common::Error loadGameData(strid_t file) override; + virtual Common::Error readSaveData(Common::SeekableReadStream *rs) override; /** - * Save the game to the passed stream + * Save the game. The passed write stream represents access to the UMem chunk + * in the Quetzal save file that will be created */ - virtual Common::Error saveGameData(strid_t file, const Common::String &desc) override; + virtual Common::Error writeGameData(Common::WriteStream *ws) override; }; } // End of namespace Scott diff --git a/engines/glk/tads/tads.cpp b/engines/glk/tads/tads.cpp index 6ce2915469..fc598dbf4a 100644 --- a/engines/glk/tads/tads.cpp +++ b/engines/glk/tads/tads.cpp @@ -42,14 +42,14 @@ bool TADS::hasFeature(EngineFeature f) const { return GlkAPI::hasFeature(f); } -Common::Error TADS::loadGameData(strid_t file) { +Common::Error TADS::readSaveData(Common::SeekableReadStream *rs) { // TODO - return Common::kNoError; + return Common::kReadingFailed; } -Common::Error TADS::saveGameData(strid_t file, const Common::String &desc) { +Common::Error TADS::writeGameData(Common::WriteStream *ws) { // TODO - return Common::kNoError; + return Common::kWritingFailed; } } // End of namespace TADS diff --git a/engines/glk/tads/tads.h b/engines/glk/tads/tads.h index 6ad8780a2b..f30cf9f10d 100644 --- a/engines/glk/tads/tads.h +++ b/engines/glk/tads/tads.h @@ -54,14 +54,15 @@ public: virtual bool hasFeature(EngineFeature f) const override; /** - * Load a savegame from the passed stream + * Load a savegame from the passed Quetzal file chunk stream */ - virtual Common::Error loadGameData(strid_t file) override; + virtual Common::Error readSaveData(Common::SeekableReadStream *rs) override; /** - * Save the game to the passed stream + * Save the game. The passed write stream represents access to the UMem chunk + * in the Quetzal save file that will be created */ - virtual Common::Error saveGameData(strid_t file, const Common::String &desc) override; + virtual Common::Error writeGameData(Common::WriteStream *ws) override; }; extern TADS *g_vm; -- cgit v1.2.3