2021-12-26 20:19:38 +00:00
|
|
|
/* ScummVM - Graphic Adventure Engine
|
2011-12-30 17:59:03 +00:00
|
|
|
*
|
2021-12-26 20:19:38 +00:00
|
|
|
* ScummVM is the legal property of its developers, whose names
|
2011-12-30 17:59:03 +00:00
|
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
|
|
* file distributed with this source distribution.
|
|
|
|
*
|
2021-12-26 17:47:58 +00:00
|
|
|
* 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 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
2014-04-05 16:18:42 +00:00
|
|
|
*
|
2012-12-19 22:15:43 +00:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
2011-12-30 17:59:03 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2012-12-19 22:15:43 +00:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
2014-04-05 16:18:42 +00:00
|
|
|
*
|
2012-12-19 22:15:43 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
2021-12-26 17:47:58 +00:00
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2011-12-30 17:59:03 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2012-04-10 15:14:27 +00:00
|
|
|
#include "common/substream.h"
|
2011-12-30 17:59:03 +00:00
|
|
|
#include "common/md5.h"
|
|
|
|
#include "common/file.h"
|
2022-12-01 10:53:02 +00:00
|
|
|
#include "common/compression/zlib.h"
|
2012-04-10 15:14:27 +00:00
|
|
|
#include "common/bufferedstream.h"
|
2011-12-30 17:59:03 +00:00
|
|
|
|
|
|
|
#include "engines/grim/patchr.h"
|
|
|
|
#include "engines/grim/debug.h"
|
|
|
|
|
|
|
|
namespace Grim {
|
|
|
|
|
2012-04-10 15:14:27 +00:00
|
|
|
class PatchedFile : public Common::SeekableReadStream {
|
|
|
|
public:
|
|
|
|
PatchedFile();
|
|
|
|
virtual ~PatchedFile();
|
|
|
|
|
2013-07-08 03:52:54 +00:00
|
|
|
bool load(Common::SeekableReadStream *file, const Common::String &patchName);
|
2012-04-10 15:14:27 +00:00
|
|
|
|
|
|
|
// Common::ReadStream implementation
|
2021-11-13 21:20:07 +00:00
|
|
|
bool eos() const override;
|
|
|
|
uint32 read(void *dataPtr, uint32 dataSize) override;
|
2012-04-10 15:14:27 +00:00
|
|
|
|
|
|
|
// Common::SeekableReadStream implementation
|
2021-11-13 21:20:07 +00:00
|
|
|
int64 pos() const override;
|
|
|
|
int64 size() const override;
|
|
|
|
bool seek(int64 offset, int whence = SEEK_SET) override;
|
2012-04-10 15:14:27 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
// Consts
|
|
|
|
static const uint32 _kDiffBufferSize, _kHeaderSize, _kMd5size;
|
|
|
|
static const uint16 _kVersionMajor, _kVersionMinor;
|
|
|
|
|
2022-06-07 23:12:00 +00:00
|
|
|
// Flags
|
2012-04-10 15:14:27 +00:00
|
|
|
enum Flags {
|
|
|
|
FLAG_MIX_DIFF_EXTRA = 1 << 0,
|
|
|
|
FLAG_COMPRESS_CTRL = 1 << 1
|
|
|
|
};
|
|
|
|
|
|
|
|
// Streams
|
|
|
|
Common::SeekableReadStream *_file;
|
|
|
|
Common::SeekableReadStream *_ctrl, *_diff, *_extra;
|
|
|
|
|
|
|
|
// Current instruction
|
2014-01-07 10:29:26 +00:00
|
|
|
uint32 _diffCopy, _extraCopy;
|
|
|
|
int32 _jump;
|
|
|
|
int32 _instrLeft;
|
2012-08-01 10:51:46 +00:00
|
|
|
bool readNextInst();
|
2012-04-10 15:14:27 +00:00
|
|
|
|
|
|
|
int32 _pos;
|
|
|
|
uint32 _flags, _newSize;
|
|
|
|
|
2014-01-07 10:29:26 +00:00
|
|
|
uint8 *_diffBuffer;
|
2012-07-31 06:31:32 +00:00
|
|
|
|
|
|
|
Common::String _patchName;
|
2012-04-10 15:14:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const uint16 PatchedFile::_kVersionMajor = 2;
|
|
|
|
const uint16 PatchedFile::_kVersionMinor = 0;
|
|
|
|
const uint32 PatchedFile::_kDiffBufferSize = 1024;
|
|
|
|
const uint32 PatchedFile::_kHeaderSize = 48;
|
|
|
|
const uint32 PatchedFile::_kMd5size = 5000;
|
|
|
|
|
|
|
|
PatchedFile::PatchedFile():
|
2014-05-29 22:35:46 +00:00
|
|
|
_file(nullptr), _ctrl(nullptr), _diff(nullptr), _extra(nullptr), _pos(0),
|
2014-01-07 10:29:26 +00:00
|
|
|
_instrLeft(0), _jump(0), _newSize(0), _flags(0), _extraCopy(0),
|
|
|
|
_diffCopy(0) {
|
|
|
|
_diffBuffer = new uint8[_kDiffBufferSize];
|
2011-12-30 17:59:03 +00:00
|
|
|
}
|
|
|
|
|
2012-04-10 15:14:27 +00:00
|
|
|
PatchedFile::~PatchedFile() {
|
2014-01-07 10:29:26 +00:00
|
|
|
delete[] _diffBuffer;
|
2012-04-10 15:14:27 +00:00
|
|
|
|
2013-07-08 04:11:34 +00:00
|
|
|
delete _file;
|
2011-12-30 17:59:03 +00:00
|
|
|
|
2013-07-08 04:11:34 +00:00
|
|
|
delete _ctrl;
|
|
|
|
delete _diff;
|
|
|
|
if (!(_flags & FLAG_MIX_DIFF_EXTRA))
|
2012-04-10 15:14:27 +00:00
|
|
|
delete _extra;
|
2011-12-30 17:59:03 +00:00
|
|
|
}
|
|
|
|
|
2013-07-08 03:52:54 +00:00
|
|
|
bool PatchedFile::load(Common::SeekableReadStream *file, const Common::String &patchName) {
|
2012-04-10 15:14:27 +00:00
|
|
|
uint8 md5_p[16], md5_f[16];
|
|
|
|
uint32 zctrllen, zdatalen, zextralen;
|
|
|
|
Common::File patch;
|
2011-12-30 17:59:03 +00:00
|
|
|
|
2012-07-31 06:31:32 +00:00
|
|
|
_patchName = patchName;
|
|
|
|
|
2012-04-10 15:14:27 +00:00
|
|
|
// Open the patch
|
2012-07-31 06:31:32 +00:00
|
|
|
if (!patch.open(_patchName)) {
|
|
|
|
error("Unable to open patchfile %s", _patchName.c_str());
|
2012-03-26 09:02:24 +00:00
|
|
|
return false;
|
|
|
|
}
|
2012-04-10 15:14:27 +00:00
|
|
|
|
|
|
|
// Check for appropriate signature
|
|
|
|
if (patch.readUint32BE() != MKTAG('P','A','T','R')) {
|
2013-09-10 19:56:41 +00:00
|
|
|
error("%s patchfile is corrupted, wrong siganture", _patchName.c_str());
|
2012-03-26 09:02:24 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-04-10 15:14:27 +00:00
|
|
|
// Check the version number
|
|
|
|
if (patch.readUint16LE() != _kVersionMajor || patch.readUint16LE() > _kVersionMinor) {
|
2012-07-31 06:31:32 +00:00
|
|
|
error("%s has a wrong version number (must be major = %d, minor <= %d)", _patchName.c_str(), _kVersionMajor, _kVersionMinor);
|
2012-04-10 15:14:27 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
_flags = patch.readUint32LE();
|
|
|
|
|
|
|
|
// Check if the file to patch match
|
|
|
|
Common::computeStreamMD5(*file, md5_f, _kMd5size);
|
2011-12-30 17:59:03 +00:00
|
|
|
file->seek(0, SEEK_SET);
|
2012-04-10 15:14:27 +00:00
|
|
|
patch.read(md5_p, 16);
|
2013-09-10 19:56:41 +00:00
|
|
|
uint32 fileSize = patch.readUint32LE();
|
|
|
|
if (memcmp(md5_p, md5_f, 16) != 0 || (uint32)file->size() != fileSize) {
|
2013-07-09 19:12:55 +00:00
|
|
|
Debug::debug(Debug::Patchr, "%s targets a different file", _patchName.c_str());
|
2013-09-10 19:56:41 +00:00
|
|
|
if (Debug::isChannelEnabled(Debug::Patchr)) {
|
|
|
|
Common::String md5_ps, md5_fs;
|
|
|
|
for (int i = 0; i < 16; i++) {
|
|
|
|
md5_ps += Common::String::format("%02x", (int)md5_p[i]);
|
|
|
|
md5_fs += Common::String::format("%02x", (int)md5_f[i]);
|
|
|
|
}
|
|
|
|
Debug::debug(Debug::Patchr, "Patch target: size = %d, md5 = %s", fileSize, md5_ps.c_str());
|
|
|
|
Debug::debug(Debug::Patchr, "Actual file : size = %d, md5 = %s", (uint32)file->size(), md5_fs.c_str());
|
|
|
|
}
|
2012-04-10 15:14:27 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read lengths from header
|
|
|
|
_newSize = patch.readUint32LE();
|
|
|
|
zctrllen = patch.readUint32LE();
|
|
|
|
zdatalen = patch.readUint32LE();
|
|
|
|
zextralen = patch.readUint32LE();
|
|
|
|
|
|
|
|
patch.close();
|
|
|
|
|
|
|
|
// Opens ctrl, diff and extra substreams
|
|
|
|
Common::File *tmp;
|
|
|
|
tmp = new Common::File;
|
2012-07-31 06:31:32 +00:00
|
|
|
tmp->open(_patchName);
|
2012-04-10 15:14:27 +00:00
|
|
|
_ctrl = new Common::SeekableSubReadStream(tmp, _kHeaderSize, _kHeaderSize + zctrllen, DisposeAfterUse::YES);
|
|
|
|
if (_flags & FLAG_COMPRESS_CTRL)
|
|
|
|
_ctrl = Common::wrapCompressedReadStream(_ctrl);
|
|
|
|
|
2012-08-01 10:51:46 +00:00
|
|
|
//ctrl stream sanity checks
|
|
|
|
if (_ctrl->size() % (3 * sizeof(uint32)) != 0) {
|
|
|
|
error("%s patchfile is corrupted", _patchName.c_str());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-01-07 10:29:26 +00:00
|
|
|
_instrLeft = _ctrl->size() / (3 * sizeof(uint32));
|
2012-08-01 10:51:46 +00:00
|
|
|
|
2012-04-10 15:14:27 +00:00
|
|
|
tmp = new Common::File;
|
2012-07-31 06:31:32 +00:00
|
|
|
tmp->open(_patchName);
|
2012-04-10 15:14:27 +00:00
|
|
|
_diff = new Common::SeekableSubReadStream(tmp, _kHeaderSize + zctrllen, _kHeaderSize + zctrllen + zdatalen, DisposeAfterUse::YES);
|
|
|
|
_diff = Common::wrapCompressedReadStream(_diff);
|
|
|
|
|
|
|
|
if (_flags & FLAG_MIX_DIFF_EXTRA)
|
|
|
|
_extra = _diff;
|
|
|
|
else {
|
|
|
|
tmp = new Common::File;
|
2012-07-31 06:31:32 +00:00
|
|
|
tmp->open(_patchName);
|
2012-04-10 15:14:27 +00:00
|
|
|
_extra = new Common::SeekableSubReadStream(tmp, _kHeaderSize + zctrllen + zdatalen, _kHeaderSize + zctrllen + zdatalen + zextralen, DisposeAfterUse::YES);
|
|
|
|
_extra = Common::wrapCompressedReadStream(_extra);
|
|
|
|
}
|
|
|
|
|
|
|
|
_file = file;
|
|
|
|
|
|
|
|
readNextInst();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2011-12-30 17:59:03 +00:00
|
|
|
|
2012-04-10 15:14:27 +00:00
|
|
|
uint32 PatchedFile::read(void *dataPtr, uint32 dataSize) {
|
|
|
|
uint32 readSize, diffRead, toRead, rd;
|
|
|
|
byte *data = (byte*)dataPtr;
|
|
|
|
|
|
|
|
toRead = dataSize;
|
2012-08-01 10:51:46 +00:00
|
|
|
while (toRead > 0) {
|
2012-04-10 15:14:27 +00:00
|
|
|
// Read data from original file and apply the differences
|
2014-01-07 10:29:26 +00:00
|
|
|
if (_diffCopy > 0) {
|
|
|
|
readSize = MIN(toRead, _diffCopy);
|
2012-04-10 15:14:27 +00:00
|
|
|
rd = _file->read(data, readSize);
|
|
|
|
if (_file->err() || rd != readSize)
|
2012-07-31 06:31:32 +00:00
|
|
|
error("%s: Corrupted patchfile", _patchName.c_str());
|
2012-04-10 15:14:27 +00:00
|
|
|
|
|
|
|
toRead -= readSize;
|
2014-01-07 10:29:26 +00:00
|
|
|
_diffCopy -= readSize;
|
2012-04-10 15:14:27 +00:00
|
|
|
|
|
|
|
//Read data from diff as blocks of size _kDiffBufferSize,
|
2015-01-12 21:17:55 +00:00
|
|
|
// then xor original data with them in groups of 4 bytes
|
2012-04-10 15:14:27 +00:00
|
|
|
while (readSize > 0) {
|
|
|
|
diffRead = MIN(readSize, _kDiffBufferSize);
|
2014-01-07 10:29:26 +00:00
|
|
|
rd = _diff->read(_diffBuffer, diffRead);
|
2012-04-10 15:14:27 +00:00
|
|
|
if (_diff->err() || rd != diffRead)
|
2012-07-31 06:31:32 +00:00
|
|
|
error("%s: Corrupted patchfile", _patchName.c_str());
|
2012-04-10 15:14:27 +00:00
|
|
|
|
2013-07-09 19:12:55 +00:00
|
|
|
for (uint32 i = 0; i < diffRead / 4; ++i)
|
2015-01-12 21:17:55 +00:00
|
|
|
WRITE_UINT32((uint32 *)data + i, READ_UINT32((uint32 *)data + i) ^ READ_UINT32((uint32 *)_diffBuffer + i));
|
2012-04-10 15:14:27 +00:00
|
|
|
for (uint32 i = diffRead - diffRead % 4; i < diffRead; ++i)
|
2014-01-08 22:12:20 +00:00
|
|
|
data[i] ^= _diffBuffer[i];
|
2021-05-04 08:45:03 +00:00
|
|
|
|
2012-04-10 15:14:27 +00:00
|
|
|
readSize -= diffRead;
|
|
|
|
data += diffRead;
|
2011-12-30 17:59:03 +00:00
|
|
|
}
|
2012-04-10 15:14:27 +00:00
|
|
|
}
|
2011-12-30 17:59:03 +00:00
|
|
|
|
2012-04-10 15:14:27 +00:00
|
|
|
if (toRead == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Read data from extra
|
2014-01-07 10:29:26 +00:00
|
|
|
if (_extraCopy > 0) {
|
|
|
|
readSize = MIN(toRead, _extraCopy);
|
2012-04-10 15:14:27 +00:00
|
|
|
rd = _extra->read(data, readSize);
|
|
|
|
if (_extra->err() || rd != readSize)
|
2012-07-31 06:31:32 +00:00
|
|
|
error("%s: Corrupted patchfile", _patchName.c_str());
|
2012-04-10 15:14:27 +00:00
|
|
|
|
|
|
|
data += readSize;
|
|
|
|
toRead -= readSize;
|
2014-01-07 10:29:26 +00:00
|
|
|
_extraCopy -= readSize;
|
2012-04-10 15:14:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Jump and read next instructions
|
2014-01-07 10:29:26 +00:00
|
|
|
if (_diffCopy == 0 && _extraCopy == 0) {
|
|
|
|
if (_jump != 0)
|
|
|
|
_file->seek(_jump, SEEK_CUR);
|
2012-08-01 10:51:46 +00:00
|
|
|
|
|
|
|
//If there aren't new instructions, breaks here
|
|
|
|
if (!readNextInst())
|
|
|
|
break;
|
2012-04-10 15:14:27 +00:00
|
|
|
}
|
2011-12-30 17:59:03 +00:00
|
|
|
}
|
|
|
|
|
2012-04-10 15:14:27 +00:00
|
|
|
_pos += dataSize - toRead;
|
|
|
|
return (dataSize - toRead);
|
|
|
|
}
|
|
|
|
|
2012-08-01 10:51:46 +00:00
|
|
|
bool PatchedFile::readNextInst() {
|
2014-01-07 10:29:26 +00:00
|
|
|
if (_instrLeft == 0) {
|
|
|
|
_diffCopy = 0;
|
|
|
|
_extraCopy = 0;
|
|
|
|
_jump = 0;
|
2012-08-01 10:51:46 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-01-07 10:29:26 +00:00
|
|
|
_diffCopy = _ctrl->readUint32LE();
|
|
|
|
_extraCopy = _ctrl->readUint32LE();
|
|
|
|
_jump = _ctrl->readSint32LE();
|
2012-04-10 15:14:27 +00:00
|
|
|
|
|
|
|
//Sanity checks
|
|
|
|
if (_ctrl->err() ||
|
2022-06-07 23:12:00 +00:00
|
|
|
(int32(_diffCopy) > _file->size() - _file->pos()) ||
|
|
|
|
(int32(_diffCopy) > _diff->size() - _diff->pos()) ||
|
|
|
|
(int32(_extraCopy) > _extra->size() - _extra->pos()) ||
|
|
|
|
(_jump > _file->size() - _file->pos())) {
|
2014-01-07 10:29:26 +00:00
|
|
|
error("%s: Corrupted patchfile. istrleft = %d", _patchName.c_str(), _instrLeft);
|
2022-06-07 23:12:00 +00:00
|
|
|
}
|
2012-08-01 10:51:46 +00:00
|
|
|
|
2014-01-07 10:29:26 +00:00
|
|
|
--_instrLeft;
|
2012-08-01 10:51:46 +00:00
|
|
|
return true;
|
2012-04-10 15:14:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool PatchedFile::eos() const {
|
2012-08-01 10:51:46 +00:00
|
|
|
if (_pos >= (int32)_newSize)
|
2012-04-10 15:14:27 +00:00
|
|
|
return true;
|
|
|
|
else
|
2011-12-30 17:59:03 +00:00
|
|
|
return false;
|
2012-04-10 15:14:27 +00:00
|
|
|
}
|
|
|
|
|
2021-07-04 03:30:41 +00:00
|
|
|
int64 PatchedFile::pos() const {
|
2012-04-10 15:14:27 +00:00
|
|
|
return _pos;
|
|
|
|
}
|
|
|
|
|
2021-07-04 03:30:41 +00:00
|
|
|
int64 PatchedFile::size() const {
|
2012-04-10 15:14:27 +00:00
|
|
|
return _newSize;
|
|
|
|
}
|
|
|
|
|
2021-07-04 03:30:41 +00:00
|
|
|
bool PatchedFile::seek(int64 offset, int whence) {
|
2012-04-10 15:14:27 +00:00
|
|
|
int32 totJump, relOffset;
|
|
|
|
uint32 skipDiff, skipExtra, skipSize;
|
|
|
|
relOffset = 0;
|
|
|
|
skipDiff = 0;
|
|
|
|
skipExtra = 0;
|
|
|
|
totJump = 0;
|
|
|
|
|
|
|
|
switch (whence) {
|
|
|
|
case SEEK_SET:
|
|
|
|
relOffset = offset - pos();
|
|
|
|
break;
|
|
|
|
case SEEK_CUR:
|
|
|
|
relOffset = offset;
|
|
|
|
break;
|
|
|
|
case SEEK_END:
|
|
|
|
relOffset = (size() + offset) - pos();
|
2013-01-23 04:18:41 +00:00
|
|
|
break;
|
2012-04-10 15:14:27 +00:00
|
|
|
default:
|
2012-07-31 06:31:32 +00:00
|
|
|
error("%s: Invalid seek instruction", _patchName.c_str());
|
2011-12-30 17:59:03 +00:00
|
|
|
}
|
|
|
|
|
2012-04-10 15:14:27 +00:00
|
|
|
if (relOffset == 0)
|
|
|
|
return true;
|
2013-01-26 20:38:14 +00:00
|
|
|
|
|
|
|
if (relOffset < 0) {
|
|
|
|
Debug::debug(Debug::Patchr, "Seeking back to start %s", _patchName.c_str());
|
|
|
|
_file->seek(0, SEEK_SET);
|
|
|
|
_ctrl->seek(0, SEEK_SET);
|
|
|
|
_extra->seek(0, SEEK_SET);
|
2014-01-07 10:29:26 +00:00
|
|
|
_instrLeft = _ctrl->size() / (3 * sizeof(uint32));
|
2013-01-26 20:38:14 +00:00
|
|
|
readNextInst();
|
|
|
|
int p = pos() + relOffset;
|
|
|
|
_pos = 0;
|
|
|
|
return seek(p, SEEK_SET);
|
|
|
|
}
|
2012-04-10 15:14:27 +00:00
|
|
|
|
|
|
|
while (relOffset > 0) {
|
2014-01-07 10:29:26 +00:00
|
|
|
if (_diffCopy > 0) {
|
|
|
|
skipSize = MIN(_diffCopy, (uint32)relOffset);
|
|
|
|
_diffCopy -= skipSize;
|
2012-04-10 15:14:27 +00:00
|
|
|
relOffset -= skipSize;
|
|
|
|
skipDiff += skipSize;
|
|
|
|
totJump += skipSize;
|
|
|
|
}
|
|
|
|
if (relOffset == 0)
|
|
|
|
break;
|
|
|
|
|
2014-01-07 10:29:26 +00:00
|
|
|
if (_extraCopy > 0) {
|
|
|
|
skipSize = MIN(_extraCopy, (uint32)relOffset);
|
|
|
|
_extraCopy -= skipSize;
|
2012-04-10 15:14:27 +00:00
|
|
|
relOffset -= skipSize;
|
|
|
|
skipExtra += skipSize;
|
2011-12-30 17:59:03 +00:00
|
|
|
}
|
|
|
|
|
2014-01-07 10:29:26 +00:00
|
|
|
if (_diffCopy == 0 && _extraCopy == 0) {
|
|
|
|
totJump += _jump;
|
2012-04-10 15:14:27 +00:00
|
|
|
readNextInst();
|
|
|
|
}
|
2011-12-30 17:59:03 +00:00
|
|
|
}
|
2012-04-10 15:14:27 +00:00
|
|
|
_diff->seek(skipDiff, SEEK_CUR);
|
2012-05-07 07:07:05 +00:00
|
|
|
_extra->seek(skipExtra, SEEK_CUR);
|
2012-04-10 15:14:27 +00:00
|
|
|
_file->seek(totJump, SEEK_CUR);
|
2011-12-30 17:59:03 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-04-10 15:14:27 +00:00
|
|
|
Common::SeekableReadStream *wrapPatchedFile(Common::SeekableReadStream *rs, const Common::String &filename) {
|
|
|
|
if (!rs)
|
2014-05-29 22:35:46 +00:00
|
|
|
return nullptr;
|
2012-04-10 15:14:27 +00:00
|
|
|
|
|
|
|
Common::String patchfile = filename + ".patchr";
|
|
|
|
int i = 1;
|
|
|
|
while (SearchMan.hasFile(patchfile)) {
|
2013-09-10 19:56:41 +00:00
|
|
|
Debug::debug(Debug::Patchr, "Patch requested for %s (patch filename %s)", filename.c_str(), patchfile.c_str());
|
2012-04-10 15:14:27 +00:00
|
|
|
|
|
|
|
PatchedFile *pf = new PatchedFile;
|
|
|
|
if (pf->load(rs, patchfile)) {
|
|
|
|
rs = Common::wrapBufferedSeekableReadStream(pf, 1024, DisposeAfterUse::YES);
|
2013-03-28 04:30:08 +00:00
|
|
|
Debug::debug(Debug::Patchr, "Patch for %s successfully loaded", filename.c_str());
|
2012-04-10 15:14:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete pf;
|
|
|
|
patchfile = Common::String::format("%s_%d.patchr", filename.c_str(), i++);
|
|
|
|
}
|
2011-12-30 17:59:03 +00:00
|
|
|
|
2012-04-10 15:14:27 +00:00
|
|
|
return rs;
|
2011-12-30 17:59:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // end of namespace Grim
|