[Scummvm-git-logs] scummvm master -> 3d299df77344fc580e17fd613fda9dfefc6c585f
dreammaster
paulfgilbert at gmail.com
Sun Jun 16 07:32:45 CEST 2019
This automated email contains information about 7 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
acc90002f6 GLK: ADVSYS: Added code for loading savegames from launcher
b6542b78fc GLK: Fix debug channels setup
1b6ac1a67c GLK: ADVSYS: Fix variable range checks
f3dc9a86b3 GLK: Added missing files to POTFILES
ec8409c115 GLK: Adding Quetzal classes to the base Glk namespace
c405203cde GLK: FROTZ: Change Quetzal saving to use new base Quetzal writer
3d299df773 GLK: FROTZ: Change Quetzal restoring to use new base Quetzal reader
Commit: acc90002f6937896e1f8063227b0423a653da0d2
https://github.com/scummvm/scummvm/commit/acc90002f6937896e1f8063227b0423a653da0d2
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-06-15T22:31:50-07:00
Commit Message:
GLK: ADVSYS: Added code for loading savegames from launcher
Changed paths:
engines/glk/advsys/advsys.cpp
engines/glk/advsys/glk_interface.cpp
engines/glk/advsys/glk_interface.h
engines/glk/advsys/vm.cpp
diff --git a/engines/glk/advsys/advsys.cpp b/engines/glk/advsys/advsys.cpp
index 26f298d..ad84128 100644
--- a/engines/glk/advsys/advsys.cpp
+++ b/engines/glk/advsys/advsys.cpp
@@ -22,11 +22,15 @@
#include "glk/advsys/advsys.h"
#include "common/translation.h"
+#include "common/config-manager.h"
namespace Glk {
namespace AdvSys {
void AdvSys::runGame() {
+ // Check for savegame
+ _saveSlot = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1;
+
if (!initialize()) {
GUIErrorMessage(_("Could not start AdvSys game"));
return;
@@ -37,6 +41,13 @@ void AdvSys::runGame() {
// Run game startup
execute(_initCodeOffset);
+ if (_saveSlot != -1) {
+ Common::ErrorCode err = loadGameState(_saveSlot).getCode();
+ _saveSlot = -1;
+ if (err != Common::kNoError)
+ print(_("Sorry, the savegame couldn't be restored"));
+ }
+
// Gameplay loop
while (!shouldQuit() && !shouldRestart()) {
// Run update code
diff --git a/engines/glk/advsys/glk_interface.cpp b/engines/glk/advsys/glk_interface.cpp
index 01abd2f..20f9f4d 100644
--- a/engines/glk/advsys/glk_interface.cpp
+++ b/engines/glk/advsys/glk_interface.cpp
@@ -31,7 +31,10 @@ bool GlkInterface::initialize() {
}
void GlkInterface::print(const Common::String &msg) {
- glk_put_string_stream(glk_window_get_stream(_window), msg.c_str());
+ // Don't print out text if loading a savegame directly from the launcher, since we don't
+ // want any of the intro text displayed by the startup code to show
+ if (_saveSlot == -1)
+ glk_put_string_stream(glk_window_get_stream(_window), msg.c_str());
}
void GlkInterface::print(int number) {
diff --git a/engines/glk/advsys/glk_interface.h b/engines/glk/advsys/glk_interface.h
index 95dcfa8..9048818 100644
--- a/engines/glk/advsys/glk_interface.h
+++ b/engines/glk/advsys/glk_interface.h
@@ -36,6 +36,8 @@ class GlkInterface : public GlkAPI {
private:
winid_t _window;
protected:
+ int _saveSlot;
+protected:
/**
* GLK initialization
*/
@@ -61,7 +63,8 @@ public:
/**
* Constructor
*/
- GlkInterface(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc) {}
+ GlkInterface(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc),
+ _saveSlot(-1) {}
};
} // End of namespace AdvSys
diff --git a/engines/glk/advsys/vm.cpp b/engines/glk/advsys/vm.cpp
index 8c6072c..33712bc 100644
--- a/engines/glk/advsys/vm.cpp
+++ b/engines/glk/advsys/vm.cpp
@@ -310,12 +310,12 @@ void VM::opYORN() {
void VM::opSAVE() {
if (saveGame().getCode() != Common::kNoError)
- print("Sorry, the savegame couldn't be created");
+ print(_("Sorry, the savegame couldn't be created"));
}
void VM::opRESTORE() {
if (saveGame().getCode() != Common::kNoError)
- print("Sorry, the savegame couldn't be restored");
+ print(_("Sorry, the savegame couldn't be restored"));
}
void VM::opARG() {
Commit: b6542b78fcb2270ab29839f16c2eb5ac1d904c7e
https://github.com/scummvm/scummvm/commit/b6542b78fcb2270ab29839f16c2eb5ac1d904c7e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-06-15T22:31:50-07:00
Commit Message:
GLK: Fix debug channels setup
Changed paths:
engines/glk/glk.cpp
diff --git a/engines/glk/glk.cpp b/engines/glk/glk.cpp
index 5d99fc9..7155cd8 100644
--- a/engines/glk/glk.cpp
+++ b/engines/glk/glk.cpp
@@ -50,6 +50,12 @@ GlkEngine::GlkEngine(OSystem *syst, const GlkGameDescription &gameDesc) :
_copySelect(false), _terminated(false), _pcSpeaker(nullptr),
gli_register_obj(nullptr), gli_unregister_obj(nullptr), gli_register_arr(nullptr),
gli_unregister_arr(nullptr) {
+ // Set up debug channels
+ DebugMan.addDebugChannel(kDebugCore, "core", "Core engine debug level");
+ DebugMan.addDebugChannel(kDebugScripts, "scripts", "Game scripts");
+ DebugMan.addDebugChannel(kDebugGraphics, "graphics", "Graphics handling");
+ DebugMan.addDebugChannel(kDebugSound, "sound", "Sound and Music handling");
+
g_vm = this;
}
@@ -68,12 +74,6 @@ GlkEngine::~GlkEngine() {
}
void GlkEngine::initialize() {
- // Set up debug channels
- DebugMan.addDebugChannel(kDebugCore, "core", "Core engine debug level");
- DebugMan.addDebugChannel(kDebugScripts, "scripts", "Game scripts");
- DebugMan.addDebugChannel(kDebugGraphics, "graphics", "Graphics handling");
- DebugMan.addDebugChannel(kDebugSound, "sound", "Sound and Music handling");
-
initGraphicsMode();
_conf = new Conf(getInterpreterType());
Commit: 1b6ac1a67cc65ca5fcb5c076f3f48b7ce8c6e6a8
https://github.com/scummvm/scummvm/commit/1b6ac1a67cc65ca5fcb5c076f3f48b7ce8c6e6a8
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-06-15T22:31:50-07:00
Commit Message:
GLK: ADVSYS: Fix variable range checks
Changed paths:
engines/glk/advsys/game.cpp
diff --git a/engines/glk/advsys/game.cpp b/engines/glk/advsys/game.cpp
index 3b6133d..d051a35 100644
--- a/engines/glk/advsys/game.cpp
+++ b/engines/glk/advsys/game.cpp
@@ -250,12 +250,16 @@ int Game::getActionLocation(int action) const {
}
int Game::getVariable(int variableNum) {
- assert(variableNum < _variableCount);
+ if (variableNum < 1 || variableNum > _variableCount)
+ error("Invalid ariable number %d", variableNum);
+
return READ_LE_UINT16(_variableTable + variableNum * 2);
}
void Game::setVariable(int variableNum, int value) {
- assert(variableNum < _variableCount);
+ if (variableNum < 1 || variableNum > _variableCount)
+ error("Invalid ariable number %d", variableNum);
+
WRITE_LE_UINT16(_variableTable + variableNum * 2, value);
}
Commit: f3dc9a86b3d5e12c564a7e764eba7239f3872359
https://github.com/scummvm/scummvm/commit/f3dc9a86b3d5e12c564a7e764eba7239f3872359
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-06-15T22:31:50-07:00
Commit Message:
GLK: Added missing files to POTFILES
Changed paths:
engines/glk/POTFILES
diff --git a/engines/glk/POTFILES b/engines/glk/POTFILES
index 935c263..895fabd 100644
--- a/engines/glk/POTFILES
+++ b/engines/glk/POTFILES
@@ -1,4 +1,9 @@
+engines/glk/glk_api.cpp
engines/glk/streams.cpp
-engines/glk/scott/scott.cpp
+engines/glk/advsys/advsys.cpp
+engines/glk/advsys/vm.cpp
+engines/glk/alan2/alan2.cpp
engines/glk/frotz/detection.cpp
engines/glk/glulxe/glulxe.cpp
+engines/glk/magnetic/magnetic.cpp
+engines/glk/scott/scott.cpp
Commit: ec8409c115d7fe99e9d917e81218e3677ba9a18f
https://github.com/scummvm/scummvm/commit/ec8409c115d7fe99e9d917e81218e3677ba9a18f
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-06-15T22:31:50-07:00
Commit Message:
GLK: Adding Quetzal classes to the base Glk namespace
Changed paths:
A engines/glk/quetzal.cpp
A engines/glk/quetzal.h
engines/glk/frotz/quetzal.h
engines/glk/module.mk
diff --git a/engines/glk/frotz/quetzal.h b/engines/glk/frotz/quetzal.h
index 98765b8..10effff 100644
--- a/engines/glk/frotz/quetzal.h
+++ b/engines/glk/frotz/quetzal.h
@@ -24,22 +24,12 @@
#define GLK_FROTZ_QUETZAL
#include "glk/glk_types.h"
+#include "glk/quetzal.h"
#include "glk/frotz/frotz_types.h"
namespace Glk {
namespace Frotz {
-enum QueztalTag {
- ID_FORM = MKTAG('F', 'O', 'R', 'M'),
- ID_IFZS = MKTAG('I', 'F', 'Z', 'S'),
- ID_IFhd = MKTAG('I', 'F', 'h', 'd'),
- ID_UMem = MKTAG('U', 'M', 'e', 'm'),
- ID_CMem = MKTAG('C', 'M', 'e', 'm'),
- ID_Stks = MKTAG('S', 't', 'k', 's'),
- ID_ANNO = MKTAG('A', 'N', 'N', 'O'),
- ID_SCVM = MKTAG('S', 'C', 'V', 'M')
-};
-
class Processor;
class Quetzal {
@@ -63,7 +53,7 @@ private:
void write_word(zword w) { _out->writeUint16BE(w); }
void write_long(uint l) { _out->writeUint32BE(l); }
void write_run(zword run) { write_byte(0); write_byte(run); }
- void write_chnk(QueztalTag id, zword len) {
+ void write_chnk(uint32 id, zword len) {
_out->writeUint32BE(id);
_out->writeUint32BE(len);
}
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index b599f02..19dc6c9 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -11,6 +11,7 @@ MODULE_OBJS := \
glk_dispa.o \
pc_speaker.o \
picture.o \
+ quetzal.o \
raw_decoder.o \
screen.o \
selection.o \
diff --git a/engines/glk/quetzal.cpp b/engines/glk/quetzal.cpp
new file mode 100644
index 0000000..7a53e59
--- /dev/null
+++ b/engines/glk/quetzal.cpp
@@ -0,0 +1,105 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "glk/quetzal.h"
+#include "common/memstream.h"
+
+namespace Glk {
+
+bool QuetzalReader::open(Common::SeekableReadStream *stream, uint32 formType) {
+ _chunks.clear();
+ stream->seek(0);
+ if (stream->readUint32BE() != ID_FORM)
+ return false;
+
+ uint32 size = stream->readUint32BE();
+ uint32 fileFormType = stream->readUint32BE();
+
+ if (formType != ID_IFSF && fileFormType != formType)
+ return false;
+ if ((int)size > stream->size() || (size & 1) || (size < 4))
+ return false;
+ size -= 4;
+
+ // Iterate through reading chunk headers
+ while (size > 0) {
+ if (size < 8)
+ // Couldn't contain a chunk
+ return false;
+
+ // Get in the chunk header
+ Chunk c;
+ c._id = stream->readUint32BE();
+ c._size = stream->readUint32BE() - 8;
+ c._offset = stream->pos();
+ _chunks.push_back(c);
+
+ int chunkRemainder = c._size + (c._size & 1);
+ if ((stream->pos() + chunkRemainder) > stream->size())
+ // Chunk goes beyond the file size
+ return false;
+
+ size -= 8 + chunkRemainder;
+ stream->skip(chunkRemainder);
+ }
+
+ return true;
+}
+
+/*--------------------------------------------------------------------------*/
+
+Common::WriteStream &QuetzalWriter::add(uint32 chunkId) {
+ // Sanity check to prevent adding the same chunk multiple times
+ for (uint idx = 0; idx < _chunks.size(); ++idx) {
+ if (_chunks[idx]._id == chunkId)
+ error("Duplicate chunk added");
+ }
+
+ _chunks.push_back(Chunk());
+ return _chunks.back()._stream;
+}
+
+void QuetzalWriter::save(Common::WriteStream *out, uint32 formType) {
+ // Calculate the size of the chunks
+ uint size = 4;
+ for (uint idx = 0; idx < _chunks.size(); ++idx)
+ size += _chunks[idx]._stream.size();
+
+ // Write out the header
+ out->writeUint32BE(ID_FORM);
+ out->writeUint32BE(size);
+ out->writeUint32BE(formType);
+
+ // Loop through writing the chunks
+ for (uint idx = 0; idx < _chunks.size(); ++idx) {
+ Common::MemoryWriteStreamDynamic &s = _chunks[idx]._stream;
+ uint chunkSize = s.size() + (s.size() & 1);
+
+ out->writeUint32BE(_chunks[idx]._id);
+ out->writeUint32BE(chunkSize);
+ out->write(s.getData(), s.size());
+ if (s.size() & 1)
+ out->writeByte(0);
+ }
+}
+
+} // End of namespace Glk
diff --git a/engines/glk/quetzal.h b/engines/glk/quetzal.h
new file mode 100644
index 0000000..2badf35
--- /dev/null
+++ b/engines/glk/quetzal.h
@@ -0,0 +1,144 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GLK_QUETZAL
+#define GLK_QUETZAL
+
+#include "common/array.h"
+#include "common/endian.h"
+#include "common/memstream.h"
+#include "common/stream.h"
+#include "glk/blorb.h"
+
+namespace Glk {
+
+enum QueztalTag {
+ ID_IFSF = MKTAG('I', 'F', 'S', 'F'),
+ ID_IFZS = MKTAG('I', 'F', 'Z', 'S'),
+ ID_IFhd = MKTAG('I', 'F', 'h', 'd'),
+ ID_UMem = MKTAG('U', 'M', 'e', 'm'),
+ ID_CMem = MKTAG('C', 'M', 'e', 'm'),
+ ID_Stks = MKTAG('S', 't', 'k', 's'),
+ ID_SCVM = MKTAG('S', 'C', 'V', 'M')
+};
+
+/**
+ * Quetzal save file reader
+ */
+class QuetzalReader {
+ struct Chunk {
+ uint32 _id;
+ size_t _offset, _size;
+ };
+public:
+ /**
+ * Iterator for the chunks list
+ */
+ struct Iterator : public Chunk {
+ private:
+ Common::SeekableReadStream *_stream;
+ Common::Array<Chunk> &_chunks;
+ int _index;
+ int _size;
+ public:
+ /**
+ * Constructor
+ */
+ Iterator(Common::SeekableReadStream *stream, Common::Array<Chunk> &chunks, int index, int size) :
+ _stream(stream), _chunks(chunks), _index(index), _size(size) {}
+
+ /**
+ * Incrementer
+ */
+ Iterator &operator++() { ++_index; }
+
+ /**
+ * Decrementer
+ */
+ Iterator &operator--() { --_index; }
+
+ /**
+ * Get a read stream for the contents of a chunk
+ */
+ Common::SeekableReadStream *getStream() {
+ _stream->seek(_offset);
+ return _stream->readStream(_size);
+ }
+ };
+private:
+ Common::SeekableReadStream *_stream;
+ Common::Array<Chunk> _chunks;
+public:
+ /**
+ * Constructor
+ */
+ QuetzalReader() : _stream(nullptr) {}
+
+ /**
+ * Opens a Quetzal file for access
+ */
+ bool open(Common::SeekableReadStream *stream, uint32 formType = ID_IFSF);
+
+ /**
+ * Return an iterator for the beginning of the chunks list
+ */
+ Iterator begin() { return Iterator(_stream, _chunks, 0, _chunks.size()); }
+
+ /**
+ * Return an iterator for the beginning of the chunks list
+ */
+ Iterator end() { return Iterator(_stream, _chunks, 0, _chunks.size()); }
+};
+
+/**
+ * Quetzal save file writer
+ */
+class QuetzalWriter {
+ /**
+ * Chunk entry
+ */
+ struct Chunk {
+ uint32 _id;
+ Common::MemoryWriteStreamDynamic _stream;
+
+ /**
+ * Constructor
+ */
+ Chunk() : _id(0), _stream(DisposeAfterUse::YES) {}
+ };
+private:
+ Common::Array<Chunk> _chunks;
+public:
+ /**
+ * Add a chunk
+ */
+ Common::WriteStream &add(uint32 chunkId);
+
+ /**
+ * Save the added chunks to file
+ */
+ void save(Common::WriteStream *out, uint32 formType = ID_IFSF);
+};
+
+} // End of namespace Glk
+
+#endif
Commit: c405203cdeb9310325a3db8ec698d09f86c9a0a1
https://github.com/scummvm/scummvm/commit/c405203cdeb9310325a3db8ec698d09f86c9a0a1
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-06-15T22:31:50-07:00
Commit Message:
GLK: FROTZ: Change Quetzal saving to use new base Quetzal writer
Changed paths:
engines/glk/frotz/quetzal.cpp
engines/glk/frotz/quetzal.h
engines/glk/quetzal.cpp
engines/glk/quetzal.h
diff --git a/engines/glk/frotz/quetzal.cpp b/engines/glk/frotz/quetzal.cpp
index e025b2b..0ae6d2f 100644
--- a/engines/glk/frotz/quetzal.cpp
+++ b/engines/glk/frotz/quetzal.cpp
@@ -39,178 +39,139 @@ enum ParseState {
GOT_ERROR = 0x80
};
-
-bool Quetzal::read_word(Common::ReadStream *f, zword *result) {
- *result = f->readUint16BE();
- return true;
-}
-
-bool Quetzal::read_long(Common::ReadStream *f, uint *result) {
- *result = f->readUint32BE();
- return true;
-}
+#define WRITE_RUN(RUN) ws.writeByte(0); ws.writeByte((byte)(RUN))
bool Quetzal::save(Common::WriteStream *svf, Processor *proc, const Common::String &desc) {
Processor &p = *proc;
- uint ifzslen = 0, cmemlen = 0, stkslen = 0, descLen = 0;
offset_t pc;
zword i, j, n;
zword nvars, nargs, nstk;
zbyte var;
- long cmempos, stkspos;
int c;
- // Set a temporary memory stream for writing out the data. This is needed, since we need to
- // do some seeking within it at the end to fill out totals before properly writing it all out
- Common::MemoryWriteStreamDynamic saveData(DisposeAfterUse::YES);
- _out = &saveData;
-
- // Write `IFZS' header.
- write_chnk(ID_FORM, 0);
- write_long(ID_IFZS);
+ // Reset Quetzal writer
+ _writer.clear();
// Write `IFhd' chunk
- pc = p.getPC();
- write_chnk(ID_IFhd, 13);
- write_word(p.h_release);
- for (i = H_SERIAL; i<H_SERIAL + 6; ++i)
- write_byte(p[i]);
-
- write_word(p.h_checksum);
- write_long(pc << 8); // Includes pad
+ {
+ Common::WriteStream &ws = _writer.add(ID_IFhd);
+ pc = p.getPC();
+ ws.writeUint16BE(p.h_release);
+ ws.write(&p[H_SERIAL], 6);
+ ws.writeUint16BE(p.h_checksum);
+
+ ws.writeByte((pc >> 16) & 0xff);
+ ws.writeByte((pc >> 8) & 0xff);
+ ws.writeByte(pc & 0xff);
+ }
// Write 'ANNO' chunk
- descLen = desc.size() + 1;
- write_chnk(ID_ANNO, descLen);
- saveData.write(desc.c_str(), desc.size());
- write_byte(0);
- if ((desc.size() % 2) == 0) {
- write_byte(0);
- ++descLen;
+ {
+ Common::WriteStream &ws = _writer.add(ID_ANNO);
+ ws.write(desc.c_str(), desc.size());
+ ws.writeByte(0);
}
// Write `CMem' chunk.
- cmempos = saveData.pos();
- write_chnk(ID_CMem, 0);
- _storyFile->seek(0);
-
- // j holds current run length.
- for (i = 0, j = 0, cmemlen = 0; i < p.h_dynamic_size; ++i) {
- c = _storyFile->readByte();
- c ^= p[i];
-
- if (c == 0) {
- // It's a run of equal bytes
- ++j;
- } else {
- // Write out any run there may be.
- if (j > 0) {
- for (; j > 0x100; j -= 0x100) {
- write_run(0xFF);
- cmemlen += 2;
- }
- write_run(j - 1);
- cmemlen += 2;
- j = 0;
+ {
+ Common::WriteStream &ws = _writer.add(ID_CMem);
+ _storyFile->seek(0);
+
+ // j holds current run length.
+ for (i = 0, j = 0; i < p.h_dynamic_size; ++i) {
+ c = _storyFile->readByte();
+ c ^= p[i];
+
+ if (c == 0) {
+ // It's a run of equal bytes
+ ++j;
}
+ else {
+ // Write out any run there may be.
+ if (j > 0) {
+ for (; j > 0x100; j -= 0x100) {
+ WRITE_RUN(0xFF);
+ }
+ WRITE_RUN(j - 1);
+ j = 0;
+ }
- // Any runs are now written. Write this (nonzero) byte
- write_byte((zbyte)c);
- ++cmemlen;
+ // Any runs are now written. Write this (nonzero) byte
+ ws.writeByte(c);
+ }
}
}
- // Reached end of dynamic memory. We ignore any unwritten run there may be at this point.
- if (cmemlen & 1)
- // Chunk length must be even.
- write_byte(0);
-
// Write `Stks' chunk. You are not expected to understand this. ;)
- stkspos = saveData.pos();
- write_chnk(ID_Stks, 0);
-
- // We construct a list of frame indices, most recent first, in `frames'.
- // These indices are the offsets into the `stack' array of the word before
- // the first word pushed in each frame.
- frames[0] = p._sp - p._stack; // The frame we'd get by doing a call now.
- for (i = p._fp - p._stack + 4, n = 0; i < STACK_SIZE + 4; i = p._stack[i - 3] + 5)
- frames[++n] = i;
-
- // All versions other than V6 can use evaluation stack outside a function
- // context. We write a faked stack frame (most fields zero) to cater for this.
- if (p.h_version != V6) {
- for (i = 0; i < 6; ++i)
- write_byte(0);
- nstk = STACK_SIZE - frames[n];
- write_word(nstk);
- for (j = STACK_SIZE - 1; j >= frames[n]; --j)
- write_word(p._stack[j]);
- stkslen = 8 + 2 * nstk;
- }
-
- // Write out the rest of the stack frames.
- for (i = n; i > 0; --i) {
- zword *pf = p._stack + frames[i] - 4; // Points to call frame
- nvars = (pf[0] & 0x0F00) >> 8;
- nargs = pf[0] & 0x00FF;
- nstk = frames[i] - frames[i - 1] - nvars - 4;
- pc = ((uint)pf[3] << 9) | pf[2];
-
- // Check type of call
- switch (pf[0] & 0xF000) {
- case 0x0000:
- // Function
- var = p[pc];
- pc = ((pc + 1) << 8) | nvars;
- break;
-
- case 0x1000:
- // Procedure
- var = 0;
- pc = (pc << 8) | 0x10 | nvars; // Set procedure flag
- break;
-
- default:
- p.runtimeError(ERR_SAVE_IN_INTER);
- return 0;
+ {
+ Common::WriteStream &ws = _writer.add(ID_Stks);
+
+ // We construct a list of frame indices, most recent first, in `frames'.
+ // These indices are the offsets into the `stack' array of the word before
+ // the first word pushed in each frame.
+ frames[0] = p._sp - p._stack; // The frame we'd get by doing a call now.
+ for (i = p._fp - p._stack + 4, n = 0; i < STACK_SIZE + 4; i = p._stack[i - 3] + 5)
+ frames[++n] = i;
+
+ // All versions other than V6 can use evaluation stack outside a function
+ // context. We write a faked stack frame (most fields zero) to cater for this.
+ if (p.h_version != V6) {
+ for (i = 0; i < 6; ++i)
+ ws.writeByte(0);
+ nstk = STACK_SIZE - frames[n];
+ ws.writeUint16BE(nstk);
+ for (j = STACK_SIZE - 1; j >= frames[n]; --j)
+ ws.writeUint16BE(p._stack[j]);
}
- if (nargs != 0)
- nargs = (1 << nargs) - 1; // Make args into bitmap
- // Write the main part of the frame...
- write_long(pc);
- write_byte(var);
- write_byte(nargs);
- write_word(nstk);
+ // Write out the rest of the stack frames.
+ for (i = n; i > 0; --i) {
+ zword *pf = p._stack + frames[i] - 4; // Points to call frame
+ nvars = (pf[0] & 0x0F00) >> 8;
+ nargs = pf[0] & 0x00FF;
+ nstk = frames[i] - frames[i - 1] - nvars - 4;
+ pc = ((uint)pf[3] << 9) | pf[2];
+
+ // Check type of call
+ switch (pf[0] & 0xF000) {
+ case 0x0000:
+ // Function
+ var = p[pc];
+ pc = ((pc + 1) << 8) | nvars;
+ break;
- // Write the variables and eval stack
- for (j = 0, --pf; j<nvars + nstk; ++j, --pf)
- write_word(*pf);
+ case 0x1000:
+ // Procedure
+ var = 0;
+ pc = (pc << 8) | 0x10 | nvars; // Set procedure flag
+ break;
- // Calculate length written thus far
- stkslen += 8 + 2 * (nvars + nstk);
+ default:
+ p.runtimeError(ERR_SAVE_IN_INTER);
+ return 0;
+ }
+ if (nargs != 0)
+ nargs = (1 << nargs) - 1; // Make args into bitmap
+
+ // Write the main part of the frame...
+ ws.writeUint32BE(pc);
+ ws.writeByte(var);
+ ws.writeByte(nargs);
+ ws.writeUint16BE(nstk);
+
+ // Write the variables and eval stack
+ for (j = 0, --pf; j<nvars + nstk; ++j, --pf)
+ ws.writeUint16BE(*pf);
+ }
}
- // Fill in variable chunk lengths
- ifzslen = 4 * 8 + 4 + 14 + cmemlen + stkslen + descLen;
- if (cmemlen & 1)
- ++ifzslen;
-
- saveData.seek(4);
- saveData.writeUint32BE(ifzslen);
- saveData.seek(cmempos + 4);
- saveData.writeUint32BE(cmemlen);
- saveData.seek(stkspos + 4);
- saveData.writeUint32BE(stkslen);
-
// Write the save data out
- svf->write(saveData.getData(), saveData.size());
+ _writer.save(svf, ID_IFZS);
// After all that, still nothing went wrong!
return true;
}
-
int Quetzal::restore(Common::SeekableReadStream *svf, Processor *proc) {
Processor &p = *proc;
uint ifzslen, currlen, tmpl;
diff --git a/engines/glk/frotz/quetzal.h b/engines/glk/frotz/quetzal.h
index 10effff..ce6b1bd 100644
--- a/engines/glk/frotz/quetzal.h
+++ b/engines/glk/frotz/quetzal.h
@@ -35,19 +35,11 @@ class Processor;
class Quetzal {
private:
Common::SeekableReadStream *_storyFile;
- Common::WriteStream *_out;
+ QuetzalReader _reader;
+ QuetzalWriter _writer;
zword frames[STACK_SIZE / 4 + 1];
+/*
private:
- /**
- * Read a 16-bit value from the file
- */
- bool read_word(Common::ReadStream *f, zword *result);
-
- /**
- * Read 32-bit value from the file
- */
- bool read_long(Common::ReadStream *f, uint *result);
-
void write_byte(zbyte b) { _out->writeByte(b); }
void write_bytx(zword b) { _out->writeByte(b & 0xFF); }
void write_word(zword w) { _out->writeUint16BE(w); }
@@ -57,6 +49,7 @@ private:
_out->writeUint32BE(id);
_out->writeUint32BE(len);
}
+ */
public:
/**
* Constructor
diff --git a/engines/glk/quetzal.cpp b/engines/glk/quetzal.cpp
index 7a53e59..4a3ea8b 100644
--- a/engines/glk/quetzal.cpp
+++ b/engines/glk/quetzal.cpp
@@ -25,6 +25,11 @@
namespace Glk {
+void QuetzalReader::clear() {
+ _chunks.clear();
+ _stream = nullptr;
+}
+
bool QuetzalReader::open(Common::SeekableReadStream *stream, uint32 formType) {
_chunks.clear();
stream->seek(0);
@@ -74,7 +79,7 @@ Common::WriteStream &QuetzalWriter::add(uint32 chunkId) {
error("Duplicate chunk added");
}
- _chunks.push_back(Chunk());
+ _chunks.push_back(Chunk(chunkId));
return _chunks.back()._stream;
}
@@ -82,7 +87,7 @@ void QuetzalWriter::save(Common::WriteStream *out, uint32 formType) {
// Calculate the size of the chunks
uint size = 4;
for (uint idx = 0; idx < _chunks.size(); ++idx)
- size += _chunks[idx]._stream.size();
+ size += 8 + _chunks[idx]._stream.size() + (_chunks[idx]._stream.size() & 1);
// Write out the header
out->writeUint32BE(ID_FORM);
@@ -92,10 +97,9 @@ void QuetzalWriter::save(Common::WriteStream *out, uint32 formType) {
// Loop through writing the chunks
for (uint idx = 0; idx < _chunks.size(); ++idx) {
Common::MemoryWriteStreamDynamic &s = _chunks[idx]._stream;
- uint chunkSize = s.size() + (s.size() & 1);
out->writeUint32BE(_chunks[idx]._id);
- out->writeUint32BE(chunkSize);
+ out->writeUint32BE(s.size());
out->write(s.getData(), s.size());
if (s.size() & 1)
out->writeByte(0);
diff --git a/engines/glk/quetzal.h b/engines/glk/quetzal.h
index 2badf35..706fb9f 100644
--- a/engines/glk/quetzal.h
+++ b/engines/glk/quetzal.h
@@ -94,6 +94,11 @@ public:
QuetzalReader() : _stream(nullptr) {}
/**
+ * Clear
+ */
+ void clear();
+
+ /**
* Opens a Quetzal file for access
*/
bool open(Common::SeekableReadStream *stream, uint32 formType = ID_IFSF);
@@ -124,11 +129,21 @@ class QuetzalWriter {
* Constructor
*/
Chunk() : _id(0), _stream(DisposeAfterUse::YES) {}
+
+ /**
+ * Constructor
+ */
+ Chunk(uint32 id) : _id(id), _stream(DisposeAfterUse::YES) {}
};
private:
Common::Array<Chunk> _chunks;
public:
/**
+ * Clear
+ */
+ void clear() { _chunks.clear(); }
+
+ /**
* Add a chunk
*/
Common::WriteStream &add(uint32 chunkId);
Commit: 3d299df77344fc580e17fd613fda9dfefc6c585f
https://github.com/scummvm/scummvm/commit/3d299df77344fc580e17fd613fda9dfefc6c585f
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-06-15T22:31:50-07:00
Commit Message:
GLK: FROTZ: Change Quetzal restoring to use new base Quetzal reader
Changed paths:
engines/glk/frotz/quetzal.cpp
engines/glk/frotz/quetzal.h
engines/glk/quetzal.cpp
engines/glk/quetzal.h
diff --git a/engines/glk/frotz/quetzal.cpp b/engines/glk/frotz/quetzal.cpp
index 0ae6d2f..d12d41d 100644
--- a/engines/glk/frotz/quetzal.cpp
+++ b/engines/glk/frotz/quetzal.cpp
@@ -172,47 +172,27 @@ bool Quetzal::save(Common::WriteStream *svf, Processor *proc, const Common::Stri
return true;
}
-int Quetzal::restore(Common::SeekableReadStream *svf, Processor *proc) {
+int Quetzal::restore(Common::SeekableReadStream *sv, Processor *proc) {
Processor &p = *proc;
- uint ifzslen, currlen, tmpl;
+ uint tmpl, currlen;
offset_t pc;
- zword i, tmpw;
+ zword tmpw;
int fatal = 0; // Set to -1 when errors must be fatal.
- zbyte skip, progress = GOT_NONE;
- int x, y;
-
- // Check it's really an `IFZS' file.
- tmpl = svf->readUint32BE();
- ifzslen = svf->readUint32BE();
- currlen = svf->readUint32BE();
- if (tmpl != ID_FORM || currlen != ID_IFZS) {
+ zbyte progress = GOT_NONE;
+ int i, x, y;
+
+ // Load the savefile for reading
+ if (!_reader.open(sv, ID_IFZS)) {
p.print_string("This is not a saved game file!\n");
return 0;
}
- if ((ifzslen & 1) || ifzslen<4)
- // Sanity checks
- return 0;
- ifzslen -= 4;
// Read each chunk and process it
- while (ifzslen > 0) {
- // Read chunk header
- if (ifzslen < 8)
- // Couldn't contain a chunk
- return 0;
-
- tmpl = svf->readUint32BE();
- currlen = svf->readUint32BE();
- ifzslen -= 8; // Reduce remaining by size of header
-
- // Handle chunk body
- if (ifzslen < currlen)
- // Chunk goes past EOF?!
- return 0;
- skip = currlen & 1;
- ifzslen -= currlen + (uint)skip;
-
- switch (tmpl) {
+ for (QuetzalReader::Iterator it = _reader.begin(); it != _reader.end(); ++it) {
+ Common::SeekableReadStream *s = it.getStream();
+ currlen = (*it)._size;
+
+ switch ((*it)._id) {
// `IFhd' header chunk; must be first in file
case ID_IFhd:
if (progress & GOT_HEADER) {
@@ -223,17 +203,17 @@ int Quetzal::restore(Common::SeekableReadStream *svf, Processor *proc) {
if (currlen < 13)
return fatal;
- tmpw = svf->readUint16BE();
+ tmpw = s->readUint16BE();
if (tmpw != p.h_release)
progress = GOT_ERROR;
- for (i = H_SERIAL; i < H_SERIAL + 6; ++i) {
- x = svf->readByte();
- if (x != p[i])
+ for (int idx = H_SERIAL; idx < H_SERIAL + 6; ++idx) {
+ x = s->readByte();
+ if (x != p[idx])
progress = GOT_ERROR;
}
- tmpw = svf->readUint16BE();
+ tmpw = s->readUint16BE();
if (tmpw != p.h_checksum)
progress = GOT_ERROR;
@@ -242,17 +222,15 @@ int Quetzal::restore(Common::SeekableReadStream *svf, Processor *proc) {
return fatal;
}
- x = svf->readByte();
+ x = s->readByte();
pc = (uint)x << 16;
- x = svf->readByte();
+ x = s->readByte();
pc |= (uint)x << 8;
- x = svf->readByte();
+ x = s->readByte();
pc |= (uint)x;
fatal = -1; // Setting PC means errors must be fatal
p.setPC(pc);
-
- svf->skip(currlen - 13); // Skip rest of chunk
break;
// `Stks' stacks chunk; restoring this is quite complex. ;)
@@ -273,8 +251,8 @@ int Quetzal::restore(Common::SeekableReadStream *svf, Processor *proc) {
if (currlen < 8)
return fatal;
- svf->skip(6);
- tmpw = svf->readUint16BE();
+ s->skip(6);
+ tmpw = s->readUint16BE();
if (tmpw > STACK_SIZE) {
p.print_string("Save-file has too much stack (and I can't cope).\n");
@@ -285,7 +263,7 @@ int Quetzal::restore(Common::SeekableReadStream *svf, Processor *proc) {
if (currlen < (uint)tmpw * 2)
return fatal;
for (i = 0; i < tmpw; ++i)
- *--p._sp = svf->readUint16BE();
+ *--p._sp = s->readUint16BE();
currlen -= tmpw * 2;
}
@@ -300,12 +278,12 @@ int Quetzal::restore(Common::SeekableReadStream *svf, Processor *proc) {
}
// Read PC, procedure flag and formal param count
- tmpl = svf->readUint32BE();
+ tmpl = s->readUint32BE();
y = (int)(tmpl & 0x0F); // Number of formals
tmpw = y << 8;
// Read result variable
- x = svf->readByte();
+ x = s->readByte();
// Check the procedure flag...
if (tmpl & 0x10) {
@@ -328,7 +306,7 @@ int Quetzal::restore(Common::SeekableReadStream *svf, Processor *proc) {
*--p._sp = (zword)(p._fp - p._stack - 1); // FP
// Read and process argument mask
- x = svf->readByte();
+ x = s->readByte();
++x; // Should now be a power of 2
for (i = 0; i<8; ++i)
if (x & (1 << i))
@@ -343,7 +321,7 @@ int Quetzal::restore(Common::SeekableReadStream *svf, Processor *proc) {
p._fp = p._sp; // FP for next frame
// Read amount of eval stack used
- tmpw = svf->readUint16BE();
+ tmpw = s->readUint16BE();
tmpw += y; // Amount of stack + number of locals
if (p._sp - p._stack <= tmpw) {
@@ -354,14 +332,13 @@ int Quetzal::restore(Common::SeekableReadStream *svf, Processor *proc) {
return fatal;
for (i = 0; i < tmpw; ++i)
- --*p._sp = svf->readUint16BE();
+ --*p._sp = s->readUint16BE();
currlen -= tmpw * 2;
}
// End of `Stks' processing...
break;
- // Any more special chunk types must go in HERE or ABOVE
// `CMem' compressed memory chunk; uncompress it
case ID_CMem:
if (!(progress & GOT_MEMORY)) {
@@ -369,13 +346,13 @@ int Quetzal::restore(Common::SeekableReadStream *svf, Processor *proc) {
i = 0; // Bytes written to data area
for (; currlen > 0; --currlen) {
- x = svf->readByte();
+ x = s->readByte();
if (x == 0) {
// Start of run
// Check for bogus run
if (currlen < 2) {
p.print_string("File contains bogus `CMem' chunk.\n");
- svf->skip(currlen);
+ s->skip(currlen);
currlen = 1;
i = 0xFFFF;
@@ -384,7 +361,7 @@ int Quetzal::restore(Common::SeekableReadStream *svf, Processor *proc) {
// Copy story file to memory during the run
--currlen;
- x = svf->readByte();
+ x = s->readByte();
for (; x >= 0 && i < p.h_dynamic_size; --x, ++i)
p[i] = _storyFile->readByte();
} else {
@@ -397,7 +374,7 @@ int Quetzal::restore(Common::SeekableReadStream *svf, Processor *proc) {
// Make sure we don't load too much
if (i > p.h_dynamic_size) {
p.print_string("warning: `CMem' chunk too long!\n");
- svf->skip(currlen);
+ s->skip(currlen);
break; // Keep going; there may be a `UMem' too
}
}
@@ -410,14 +387,14 @@ int Quetzal::restore(Common::SeekableReadStream *svf, Processor *proc) {
progress |= GOT_MEMORY; // Only if succeeded
break;
}
+ break;
- // fall through
-
+ // 'UMem' Uncompressed memory chunk
case ID_UMem:
if (!(progress & GOT_MEMORY)) {
// Must be exactly the right size
if (currlen == p.h_dynamic_size) {
- if (svf->read(p.zmp, currlen) == currlen) {
+ if (s->read(p.zmp, currlen) == currlen) {
progress |= GOT_MEMORY; // Only on success
break;
}
@@ -427,16 +404,13 @@ int Quetzal::restore(Common::SeekableReadStream *svf, Processor *proc) {
// Fall into default action (skip chunk) on errors
}
-
- // fall through
+ break;
default:
- svf->seek(currlen, SEEK_CUR); // Skip chunk
break;
}
- if (skip)
- svf->skip(1); // Skip pad byte
+ delete s;
}
// We've reached the end of the file. For the restoration to have been a
diff --git a/engines/glk/frotz/quetzal.h b/engines/glk/frotz/quetzal.h
index ce6b1bd..ee3f3b3 100644
--- a/engines/glk/frotz/quetzal.h
+++ b/engines/glk/frotz/quetzal.h
@@ -38,18 +38,6 @@ private:
QuetzalReader _reader;
QuetzalWriter _writer;
zword frames[STACK_SIZE / 4 + 1];
-/*
-private:
- void write_byte(zbyte b) { _out->writeByte(b); }
- void write_bytx(zword b) { _out->writeByte(b & 0xFF); }
- void write_word(zword w) { _out->writeUint16BE(w); }
- void write_long(uint l) { _out->writeUint32BE(l); }
- void write_run(zword run) { write_byte(0); write_byte(run); }
- void write_chnk(uint32 id, zword len) {
- _out->writeUint32BE(id);
- _out->writeUint32BE(len);
- }
- */
public:
/**
* Constructor
diff --git a/engines/glk/quetzal.cpp b/engines/glk/quetzal.cpp
index 4a3ea8b..fb2f70c 100644
--- a/engines/glk/quetzal.cpp
+++ b/engines/glk/quetzal.cpp
@@ -31,8 +31,10 @@ void QuetzalReader::clear() {
}
bool QuetzalReader::open(Common::SeekableReadStream *stream, uint32 formType) {
- _chunks.clear();
+ clear();
stream->seek(0);
+ _stream = stream;
+
if (stream->readUint32BE() != ID_FORM)
return false;
@@ -54,7 +56,7 @@ bool QuetzalReader::open(Common::SeekableReadStream *stream, uint32 formType) {
// Get in the chunk header
Chunk c;
c._id = stream->readUint32BE();
- c._size = stream->readUint32BE() - 8;
+ c._size = stream->readUint32BE();
c._offset = stream->pos();
_chunks.push_back(c);
diff --git a/engines/glk/quetzal.h b/engines/glk/quetzal.h
index 706fb9f..19dd939 100644
--- a/engines/glk/quetzal.h
+++ b/engines/glk/quetzal.h
@@ -53,35 +53,55 @@ public:
/**
* Iterator for the chunks list
*/
- struct Iterator : public Chunk {
+ struct Iterator {
private:
Common::SeekableReadStream *_stream;
Common::Array<Chunk> &_chunks;
int _index;
- int _size;
public:
/**
* Constructor
*/
- Iterator(Common::SeekableReadStream *stream, Common::Array<Chunk> &chunks, int index, int size) :
- _stream(stream), _chunks(chunks), _index(index), _size(size) {}
+ Iterator(Common::SeekableReadStream *stream, Common::Array<Chunk> &chunks, int index) :
+ _stream(stream), _chunks(chunks), _index(index) {}
+
+ /**
+ * Deference
+ */
+ Chunk &operator*() const { return _chunks[_index]; }
/**
* Incrementer
*/
- Iterator &operator++() { ++_index; }
+ Iterator &operator++() {
+ ++_index;
+ return *this;
+ }
/**
* Decrementer
*/
- Iterator &operator--() { --_index; }
+ Iterator &operator--() {
+ --_index;
+ return *this;
+ }
+
+ /**
+ * Equality test
+ */
+ bool operator==(const Iterator &rhs) { return _index == rhs._index; }
+
+ /**
+ * Inequality test
+ */
+ bool operator!=(const Iterator &rhs) { return _index != rhs._index; }
/**
* Get a read stream for the contents of a chunk
*/
Common::SeekableReadStream *getStream() {
- _stream->seek(_offset);
- return _stream->readStream(_size);
+ _stream->seek(_chunks[_index]._offset);
+ return _stream->readStream(_chunks[_index]._size);
}
};
private:
@@ -106,12 +126,12 @@ public:
/**
* Return an iterator for the beginning of the chunks list
*/
- Iterator begin() { return Iterator(_stream, _chunks, 0, _chunks.size()); }
+ Iterator begin() { return Iterator(_stream, _chunks, 0); }
/**
* Return an iterator for the beginning of the chunks list
*/
- Iterator end() { return Iterator(_stream, _chunks, 0, _chunks.size()); }
+ Iterator end() { return Iterator(_stream, _chunks, _chunks.size()); }
};
/**
More information about the Scummvm-git-logs
mailing list