aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorPaul Gilbert2018-01-14 14:16:58 -0500
committerPaul Gilbert2018-01-14 14:16:58 -0500
commit700bcc73e1b829cb15b1dcc56027b8da364c2468 (patch)
treefec52bf51ef2908a4e653409deb833be4e4c9db4 /engines
parenta506a8f7eb7d5d4897afda90bb0c5501c0d556ab (diff)
downloadscummvm-rg350-700bcc73e1b829cb15b1dcc56027b8da364c2468.tar.gz
scummvm-rg350-700bcc73e1b829cb15b1dcc56027b8da364c2468.tar.bz2
scummvm-rg350-700bcc73e1b829cb15b1dcc56027b8da364c2468.zip
XEEN: Fixes for encryption and resource offsets in save files
Diffstat (limited to 'engines')
-rw-r--r--engines/xeen/files.cpp29
-rw-r--r--engines/xeen/files.h27
-rw-r--r--engines/xeen/saves.cpp2
3 files changed, 44 insertions, 14 deletions
diff --git a/engines/xeen/files.cpp b/engines/xeen/files.cpp
index 164313ca4c..0c6ff1d0cf 100644
--- a/engines/xeen/files.cpp
+++ b/engines/xeen/files.cpp
@@ -88,12 +88,13 @@ void BaseCCArchive::loadIndex(Common::SeekableReadStream &stream) {
void BaseCCArchive::saveIndex(Common::WriteStream &stream) {
// Fill up the data for the index entries into a raw data block
byte *rawIndex = new byte[_index.size() * 8];
+ byte b;
byte *entryP = rawIndex;
for (uint i = 0; i < _index.size(); ++i, entryP += 8) {
CCEntry &entry = _index[i];
WRITE_LE_UINT16(&entryP[0], entry._id);
- WRITE_LE_UINT32(&entryP[2], entry._offset);
+ WRITE_LE_UINT32(&entryP[2], entry._writeOffset);
WRITE_LE_UINT16(&entryP[5], entry._size);
entryP[7] = 0;
}
@@ -101,8 +102,11 @@ void BaseCCArchive::saveIndex(Common::WriteStream &stream) {
// Encrypt the index
int seed = 0xac;
for (uint i = 0; i < _index.size() * 8; ++i, seed += 0x67) {
- byte b = (rawIndex[i] - seed) & 0xff;
- rawIndex[i] = (byte)((b >> 2) | (b << 6));
+ b = (rawIndex[i] - seed) & 0xff;
+ b = (byte)((b >> 2) | (b << 6));
+
+ assert(rawIndex[i] == (byte)((((b << 2) | (b >> 6)) + seed) & 0xff));
+ rawIndex[i] = b;
}
// Write out the number of entries and the encrypted index data
@@ -489,19 +493,19 @@ void SaveArchive::save(Common::WriteStream &s) {
_party->synchronize(sPty);
pty.finalize();
- // First caclculate file offsets for each resource, since replaced resources
- // will shift file offsets for even the succeeding unchanged resources
- for (uint idx = 1, pos = _index[0]._offset + _index[0]._size; idx < _index.size(); ++idx) {
- _index[idx]._offset = pos;
- pos += _index[idx]._size;
+ // First caclculate new offsets and total filesize
+ _dataSize = _index.size() * 8 + 2;
+ for (uint idx = 0; idx < _index.size(); ++idx) {
+ _index[idx]._writeOffset = (idx == 0) ? _dataSize :
+ _index[idx - 1]._writeOffset + _index[idx - 1]._size;
+ _dataSize += _index[idx]._size;
}
- // Write out the size of the save archive
- _dataSize = _index.back()._offset + _index.back()._size;
s.writeUint32LE(_dataSize);
// Save out the index
- saveIndex(s);
+ SubWriteStream dataStream(&s);
+ saveIndex(dataStream);
// Save out each resource in turn
for (uint idx = 0; idx < _index.size(); ++idx) {
@@ -511,7 +515,8 @@ void SaveArchive::save(Common::WriteStream &s) {
entry->read(data, entry->size());
// Write it out to the savegame
- s.write(data, entry->size());
+ assert(dataStream.pos() == _index[idx]._writeOffset);
+ dataStream.write(data, entry->size());
delete[] data;
delete entry;
}
diff --git a/engines/xeen/files.h b/engines/xeen/files.h
index ff10db5228..37b2422e2d 100644
--- a/engines/xeen/files.h
+++ b/engines/xeen/files.h
@@ -64,8 +64,9 @@ struct CCEntry {
uint16 _id;
uint32 _offset;
uint16 _size;
+ uint32 _writeOffset;
- CCEntry() : _id(0), _offset(0), _size(0) {}
+ CCEntry() : _id(0), _offset(0), _size(0), _writeOffset(0) {}
CCEntry(uint16 id, uint32 offset, uint32 size)
: _id(id), _offset(offset), _size(size) {
}
@@ -185,6 +186,30 @@ public:
static bool exists(const Common::String &filename, int ccMode);
};
+/**
+ * SubWriteStream provides a way of compartmentalizing writing to a subsection of
+ * a file. This is primarily useful for the pos() function which can, for example,
+ * be used in asserts to ensure writing is being done at the correct offset within
+ * the bounds of the structure being written.
+*/
+class SubWriteStream : virtual public Common::WriteStream {
+protected:
+ Common::WriteStream *_parentStream;
+ uint32 _begin;
+ DisposeAfterUse::Flag _disposeAfterUse;
+public:
+ SubWriteStream(Common::WriteStream *parentStream) :
+ _parentStream(parentStream), _begin(parentStream->pos()) {
+ }
+
+ virtual uint32 write(const void *dataPtr, uint32 dataSize) {
+ return _parentStream->write(dataPtr, dataSize);
+ }
+ virtual bool flush() { return _parentStream->flush(); }
+ virtual void finalize() {}
+ virtual int32 pos() const { return _parentStream->pos() - _begin; }
+};
+
class StringArray : public Common::StringArray {
public:
StringArray() {}
diff --git a/engines/xeen/saves.cpp b/engines/xeen/saves.cpp
index f84176c935..166cf6fdec 100644
--- a/engines/xeen/saves.cpp
+++ b/engines/xeen/saves.cpp
@@ -143,7 +143,7 @@ Common::Error SavesManager::saveGameState(int slot, const Common::String &desc)
Map &map = *g_vm->_map;
map.saveMaze();
-
+ // Write the savegame header
XeenSavegameHeader header;
header._saveName = desc;
writeSavegameHeader(out, header);