From 3d299df77344fc580e17fd613fda9dfefc6c585f Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sat, 15 Jun 2019 22:28:55 -0700 Subject: GLK: FROTZ: Change Quetzal restoring to use new base Quetzal reader --- engines/glk/frotz/quetzal.cpp | 102 ++++++++++++++++-------------------------- engines/glk/frotz/quetzal.h | 12 ----- engines/glk/quetzal.cpp | 6 ++- engines/glk/quetzal.h | 40 ++++++++++++----- 4 files changed, 72 insertions(+), 88 deletions(-) (limited to 'engines/glk') diff --git a/engines/glk/frotz/quetzal.cpp b/engines/glk/frotz/quetzal.cpp index 0ae6d2f239..d12d41da88 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 ce6b1bdcb2..ee3f3b3205 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 4a3ea8b88e..fb2f70cb78 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 706fb9fe43..19dd9397a2 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 &_chunks; int _index; - int _size; public: /** * Constructor */ - Iterator(Common::SeekableReadStream *stream, Common::Array &chunks, int index, int size) : - _stream(stream), _chunks(chunks), _index(index), _size(size) {} + Iterator(Common::SeekableReadStream *stream, Common::Array &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()); } }; /** -- cgit v1.2.3