Exemple #1
0
bool PatchedFile::seek(int32 offset, int whence) {
	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();
			break;
		default:
			error("%s: Invalid seek instruction", _patchName.c_str());
	}

	if (relOffset == 0)
		return true;

	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);
		instrLeft = _ctrl->size() / (3 * sizeof(uint32));
		readNextInst();
		int p = pos() + relOffset;
		_pos = 0;
		return seek(p, SEEK_SET);
	}

	while (relOffset > 0) {
		if (diffCopy > 0) {
			skipSize = MIN(diffCopy, (uint32)relOffset);
			diffCopy -= skipSize;
			relOffset -= skipSize;
			skipDiff += skipSize;
			totJump += skipSize;
		}
		if (relOffset == 0)
			break;

		if (extraCopy > 0) {
			skipSize = MIN(extraCopy, (uint32)relOffset);
			extraCopy -= skipSize;
			relOffset -= skipSize;
			skipExtra += skipSize;
		}

		if (diffCopy == 0 && extraCopy == 0) {
			totJump += jump;
			readNextInst();
		}
	}
	_diff->seek(skipDiff, SEEK_CUR);
	_extra->seek(skipExtra, SEEK_CUR);
	_file->seek(totJump, SEEK_CUR);

	return true;
}
Exemple #2
0
bool PatchedFile::load(Common::SeekableReadStream *file, const Common::String &patchName) {
	uint8 md5_p[16], md5_f[16];
	uint32 zctrllen, zdatalen, zextralen;
	Common::File patch;

	_patchName = patchName;

	// Open the patch
	if (!patch.open(_patchName)) {
		error("Unable to open patchfile %s", _patchName.c_str());
		return false;
	}

	// Check for appropriate signature
	if (patch.readUint32BE() != MKTAG('P','A','T','R')) {
		error("%s patchfile is corrupted", _patchName.c_str());
		return false;
	}

	// Check the version number
	if (patch.readUint16LE() != _kVersionMajor || patch.readUint16LE() > _kVersionMinor) {
		error("%s has a wrong version number (must be major = %d, minor <= %d)", _patchName.c_str(), _kVersionMajor, _kVersionMinor);
		return false;
	}

	_flags = patch.readUint32LE();

	// Check if the file to patch match
	Common::computeStreamMD5(*file, md5_f, _kMd5size);
	file->seek(0, SEEK_SET);
	patch.read(md5_p, 16);
	if (memcmp(md5_p, md5_f, 16) != 0 || (uint32)file->size() != patch.readUint32LE()) {
		Debug::debug(Debug::Patchr,"%s targets a different file", _patchName.c_str());
		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;
	tmp->open(_patchName);
	_ctrl = new Common::SeekableSubReadStream(tmp, _kHeaderSize, _kHeaderSize + zctrllen, DisposeAfterUse::YES);
	if (_flags & FLAG_COMPRESS_CTRL)
		_ctrl = Common::wrapCompressedReadStream(_ctrl);

	//ctrl stream sanity checks
	if (_ctrl->size() % (3 * sizeof(uint32)) != 0) {
		error("%s patchfile is corrupted", _patchName.c_str());
		return false;
	}

	instrLeft = _ctrl->size() / (3 * sizeof(uint32));

	tmp = new Common::File;
	tmp->open(_patchName);
	_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;
		tmp->open(_patchName);
		_extra = new Common::SeekableSubReadStream(tmp, _kHeaderSize + zctrllen + zdatalen, _kHeaderSize + zctrllen + zdatalen + zextralen, DisposeAfterUse::YES);
		_extra = Common::wrapCompressedReadStream(_extra);
	}

	_file = file;

	readNextInst();

	return true;
}
Exemple #3
0
uint32 PatchedFile::read(void *dataPtr, uint32 dataSize) {
	uint32 readSize, diffRead, toRead, rd;
	byte *data = (byte*)dataPtr;

	toRead = dataSize;
	while (toRead > 0) {
		// Read data from original file and apply the differences
		if (diffCopy > 0) {
			readSize = MIN(toRead, diffCopy);
			rd = _file->read(data, readSize);
			if (_file->err() || rd != readSize)
				error("%s: Corrupted patchfile", _patchName.c_str());

			toRead -= readSize;
			diffCopy -= readSize;

			//Read data from diff as blocks of size _kDiffBufferSize,
			// then xor original data with them in groups of 4 or 8
			// bytes, depending on the architecture
			while (readSize > 0) {
				diffRead = MIN(readSize, _kDiffBufferSize);
				rd = _diff->read(diffBuffer, diffRead);
				if (_diff->err() || rd != diffRead)
					error("%s: Corrupted patchfile", _patchName.c_str());

				#ifdef SCUMM_64BITS
				for (uint32 i = 0; i < diffRead/8; ++i)
					*((uint64*)data + i) ^= *((uint64*)diffBuffer + i);
				for (uint32 i = diffRead - diffRead % 8; i < diffRead; ++i)
					data[i] ^= diffBuffer[i];
				#else
				for (uint32 i = 0; i < diffRead/4; ++i)
					*((uint32*)data + i) ^= *((uint32*)diffBuffer + i);
				for (uint32 i = diffRead - diffRead % 4; i < diffRead; ++i)
					data[i] ^= diffBuffer[i];
				#endif

				readSize -= diffRead;
				data += diffRead;
			}
		}

		if (toRead == 0)
			break;

		// Read data from extra
		if (extraCopy > 0) {
			readSize = MIN(toRead, extraCopy);
			rd = _extra->read(data, readSize);
			if (_extra->err() || rd != readSize)
				error("%s: Corrupted patchfile", _patchName.c_str());

			data += readSize;
			toRead -= readSize;
			extraCopy -= readSize;
		}

		// Jump and read next instructions
		if (diffCopy == 0 && extraCopy == 0) {
			if (jump != 0)
				_file->seek(jump, SEEK_CUR);

			//If there aren't new instructions, breaks here
			if (!readNextInst())
				break;
		}
	}

	_pos += dataSize - toRead;
	return (dataSize - toRead);
}
Exemple #4
0
uint32 PatchedFile::read(void *dataPtr, uint32 dataSize) {
	uint32 readSize, diffRead, toRead, rd;
	byte *data = (byte*)dataPtr;

	toRead = dataSize;
	while (toRead > 0) {
		// Read data from original file and apply the differences
		if (_diffCopy > 0) {
			readSize = MIN(toRead, _diffCopy);
			rd = _file->read(data, readSize);
			if (_file->err() || rd != readSize)
				error("%s: Corrupted patchfile", _patchName.c_str());

			toRead -= readSize;
			_diffCopy -= readSize;

			//Read data from diff as blocks of size _kDiffBufferSize,
			// then xor original data with them in groups of 4 bytes
			while (readSize > 0) {
				diffRead = MIN(readSize, _kDiffBufferSize);
				rd = _diff->read(_diffBuffer, diffRead);
				if (_diff->err() || rd != diffRead)
					error("%s: Corrupted patchfile", _patchName.c_str());

				for (uint32 i = 0; i < diffRead / 4; ++i)
					WRITE_UINT32((uint32 *)data + i, READ_UINT32((uint32 *)data + i) ^ READ_UINT32((uint32 *)_diffBuffer + i));
				for (uint32 i = diffRead - diffRead % 4; i < diffRead; ++i)
					data[i] ^= _diffBuffer[i];
				
				readSize -= diffRead;
				data += diffRead;
			}
		}

		if (toRead == 0)
			break;

		// Read data from extra
		if (_extraCopy > 0) {
			readSize = MIN(toRead, _extraCopy);
			rd = _extra->read(data, readSize);
			if (_extra->err() || rd != readSize)
				error("%s: Corrupted patchfile", _patchName.c_str());

			data += readSize;
			toRead -= readSize;
			_extraCopy -= readSize;
		}

		// Jump and read next instructions
		if (_diffCopy == 0 && _extraCopy == 0) {
			if (_jump != 0)
				_file->seek(_jump, SEEK_CUR);

			//If there aren't new instructions, breaks here
			if (!readNextInst())
				break;
		}
	}

	_pos += dataSize - toRead;
	return (dataSize - toRead);
}