XEEN: Fixes for encryption and resource offsets in save files
This commit is contained in:
parent
a506a8f7eb
commit
700bcc73e1
3 changed files with 44 additions and 14 deletions
|
@ -88,12 +88,13 @@ void BaseCCArchive::loadIndex(Common::SeekableReadStream &stream) {
|
||||||
void BaseCCArchive::saveIndex(Common::WriteStream &stream) {
|
void BaseCCArchive::saveIndex(Common::WriteStream &stream) {
|
||||||
// Fill up the data for the index entries into a raw data block
|
// Fill up the data for the index entries into a raw data block
|
||||||
byte *rawIndex = new byte[_index.size() * 8];
|
byte *rawIndex = new byte[_index.size() * 8];
|
||||||
|
byte b;
|
||||||
|
|
||||||
byte *entryP = rawIndex;
|
byte *entryP = rawIndex;
|
||||||
for (uint i = 0; i < _index.size(); ++i, entryP += 8) {
|
for (uint i = 0; i < _index.size(); ++i, entryP += 8) {
|
||||||
CCEntry &entry = _index[i];
|
CCEntry &entry = _index[i];
|
||||||
WRITE_LE_UINT16(&entryP[0], entry._id);
|
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);
|
WRITE_LE_UINT16(&entryP[5], entry._size);
|
||||||
entryP[7] = 0;
|
entryP[7] = 0;
|
||||||
}
|
}
|
||||||
|
@ -101,8 +102,11 @@ void BaseCCArchive::saveIndex(Common::WriteStream &stream) {
|
||||||
// Encrypt the index
|
// Encrypt the index
|
||||||
int seed = 0xac;
|
int seed = 0xac;
|
||||||
for (uint i = 0; i < _index.size() * 8; ++i, seed += 0x67) {
|
for (uint i = 0; i < _index.size() * 8; ++i, seed += 0x67) {
|
||||||
byte b = (rawIndex[i] - seed) & 0xff;
|
b = (rawIndex[i] - seed) & 0xff;
|
||||||
rawIndex[i] = (byte)((b >> 2) | (b << 6));
|
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
|
// Write out the number of entries and the encrypted index data
|
||||||
|
@ -489,19 +493,19 @@ void SaveArchive::save(Common::WriteStream &s) {
|
||||||
_party->synchronize(sPty);
|
_party->synchronize(sPty);
|
||||||
pty.finalize();
|
pty.finalize();
|
||||||
|
|
||||||
// First caclculate file offsets for each resource, since replaced resources
|
// First caclculate new offsets and total filesize
|
||||||
// will shift file offsets for even the succeeding unchanged resources
|
_dataSize = _index.size() * 8 + 2;
|
||||||
for (uint idx = 1, pos = _index[0]._offset + _index[0]._size; idx < _index.size(); ++idx) {
|
for (uint idx = 0; idx < _index.size(); ++idx) {
|
||||||
_index[idx]._offset = pos;
|
_index[idx]._writeOffset = (idx == 0) ? _dataSize :
|
||||||
pos += _index[idx]._size;
|
_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);
|
s.writeUint32LE(_dataSize);
|
||||||
|
|
||||||
// Save out the index
|
// Save out the index
|
||||||
saveIndex(s);
|
SubWriteStream dataStream(&s);
|
||||||
|
saveIndex(dataStream);
|
||||||
|
|
||||||
// Save out each resource in turn
|
// Save out each resource in turn
|
||||||
for (uint idx = 0; idx < _index.size(); ++idx) {
|
for (uint idx = 0; idx < _index.size(); ++idx) {
|
||||||
|
@ -511,7 +515,8 @@ void SaveArchive::save(Common::WriteStream &s) {
|
||||||
entry->read(data, entry->size());
|
entry->read(data, entry->size());
|
||||||
|
|
||||||
// Write it out to the savegame
|
// 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[] data;
|
||||||
delete entry;
|
delete entry;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,8 +64,9 @@ struct CCEntry {
|
||||||
uint16 _id;
|
uint16 _id;
|
||||||
uint32 _offset;
|
uint32 _offset;
|
||||||
uint16 _size;
|
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)
|
CCEntry(uint16 id, uint32 offset, uint32 size)
|
||||||
: _id(id), _offset(offset), _size(size) {
|
: _id(id), _offset(offset), _size(size) {
|
||||||
}
|
}
|
||||||
|
@ -185,6 +186,30 @@ public:
|
||||||
static bool exists(const Common::String &filename, int ccMode);
|
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 {
|
class StringArray : public Common::StringArray {
|
||||||
public:
|
public:
|
||||||
StringArray() {}
|
StringArray() {}
|
||||||
|
|
|
@ -143,7 +143,7 @@ Common::Error SavesManager::saveGameState(int slot, const Common::String &desc)
|
||||||
Map &map = *g_vm->_map;
|
Map &map = *g_vm->_map;
|
||||||
map.saveMaze();
|
map.saveMaze();
|
||||||
|
|
||||||
|
// Write the savegame header
|
||||||
XeenSavegameHeader header;
|
XeenSavegameHeader header;
|
||||||
header._saveName = desc;
|
header._saveName = desc;
|
||||||
writeSavegameHeader(out, header);
|
writeSavegameHeader(out, header);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue