diff options
Diffstat (limited to 'common')
| -rw-r--r-- | common/array.h | 2 | ||||
| -rw-r--r-- | common/coroutines.cpp | 10 | ||||
| -rw-r--r-- | common/cosinetables.cpp | 2 | ||||
| -rw-r--r-- | common/endian.h | 6 | ||||
| -rw-r--r-- | common/gui_options.h | 2 | ||||
| -rw-r--r-- | common/installshield_cab.cpp | 212 | ||||
| -rw-r--r-- | common/installshield_cab.h | 43 | ||||
| -rw-r--r-- | common/keyboard.h | 9 | ||||
| -rw-r--r-- | common/macresman.cpp | 22 | ||||
| -rw-r--r-- | common/macresman.h | 3 | ||||
| -rw-r--r-- | common/memstream.h | 11 | ||||
| -rw-r--r-- | common/module.mk | 1 | ||||
| -rw-r--r-- | common/quicktime.h | 3 | ||||
| -rw-r--r-- | common/rational.h | 3 | ||||
| -rw-r--r-- | common/rect.h | 14 | ||||
| -rw-r--r-- | common/savefile.h | 4 | ||||
| -rw-r--r-- | common/sinetables.cpp | 2 | ||||
| -rw-r--r-- | common/winexe_pe.cpp | 2 | ||||
| -rw-r--r-- | common/xmlparser.cpp | 18 | ||||
| -rw-r--r-- | common/zlib.cpp | 63 | ||||
| -rw-r--r-- | common/zlib.h | 29 | 
21 files changed, 424 insertions, 37 deletions
| diff --git a/common/array.h b/common/array.h index a2c3023362..ca89523a0b 100644 --- a/common/array.h +++ b/common/array.h @@ -332,7 +332,7 @@ protected:  				// Copy a part of the new data to the position inside the  				// initialized space.  				copy(first, first + (_size - idx), pos); -				 +  				// Copy a part of the new data to the position inside the  				// uninitialized space.  				uninitialized_copy(first + (_size - idx), last, _storage + _size); diff --git a/common/coroutines.cpp b/common/coroutines.cpp index 042b15b5d7..849b881177 100644 --- a/common/coroutines.cpp +++ b/common/coroutines.cpp @@ -433,9 +433,9 @@ void CoroutineScheduler::waitForMultipleObjects(CORO_PARAM, int nCount, uint32 *  			// Determine the signalled state  			_ctx->pidSignalled = (_ctx->pProcess) || !_ctx->pEvent ? false : _ctx->pEvent->signalled; -			if (bWaitAll && _ctx->pidSignalled) +			if (bWaitAll && !_ctx->pidSignalled)  				_ctx->signalled = false; -			else if (!bWaitAll & _ctx->pidSignalled) +			else if (!bWaitAll && _ctx->pidSignalled)  				_ctx->signalled = true;  		} @@ -445,7 +445,7 @@ void CoroutineScheduler::waitForMultipleObjects(CORO_PARAM, int nCount, uint32 *  			for (_ctx->i = 0; _ctx->i < nCount; ++_ctx->i) {  				_ctx->pEvent = getEvent(pidList[_ctx->i]); -				if (_ctx->pEvent->manualReset) +				if (!_ctx->pEvent->manualReset)  					_ctx->pEvent->signalled = false;  			} @@ -717,12 +717,12 @@ void CoroutineScheduler::pulseEvent(uint32 pidEvent) {  	EVENT *evt = getEvent(pidEvent);  	if (!evt)  		return; -	 +  	// Set the event as signalled and pulsing  	evt->signalled = true;  	evt->pulsing = true; -	// If there's an active process, and it's not the first in the queue, then reschedule all  +	// If there's an active process, and it's not the first in the queue, then reschedule all  	// the other prcoesses in the queue to run again this frame  	if (pCurrent && pCurrent != active->pNext)  		rescheduleAll(); diff --git a/common/cosinetables.cpp b/common/cosinetables.cpp index bf158e904f..fe8f454e14 100644 --- a/common/cosinetables.cpp +++ b/common/cosinetables.cpp @@ -36,7 +36,7 @@ CosineTable::CosineTable(int bitPrecision) {  	double freq = 2 * M_PI / m;  	_table = new float[m]; -	// Table contains cos(2*pi*x/n) for 0<=x<=n/4,  +	// Table contains cos(2*pi*x/n) for 0<=x<=n/4,  	// followed by its reverse  	for (int i = 0; i <= m / 4; i++)  		_table[i] = cos(i * freq); diff --git a/common/endian.h b/common/endian.h index 394437ec67..759513efef 100644 --- a/common/endian.h +++ b/common/endian.h @@ -146,6 +146,12 @@   */  #define MKTAG(a0,a1,a2,a3) ((uint32)((a3) | ((a2) << 8) | ((a1) << 16) | ((a0) << 24))) +/** + * A wrapper macro used around two character constants, like 'wb', to + * ensure portability. Typical usage: MKTAG16('w','b'). + */ +#define MKTAG16(a0,a1) ((uint16)((a1) | ((a0) << 8))) +  // Functions for reading/writing native integers.  // They also transparently handle the need for alignment. diff --git a/common/gui_options.h b/common/gui_options.h index 9da19b1c3e..447fff43ed 100644 --- a/common/gui_options.h +++ b/common/gui_options.h @@ -55,7 +55,7 @@  #define GUIO_RENDERPC9821	"\037"  #define GUIO_RENDERPC9801	"\040" -// Special GUIO flags for the AdvancedDetector's caching of game specific  +// Special GUIO flags for the AdvancedDetector's caching of game specific  // options.  #define GUIO_GAMEOPTIONS1	"\041"  #define GUIO_GAMEOPTIONS2	"\042" diff --git a/common/installshield_cab.cpp b/common/installshield_cab.cpp new file mode 100644 index 0000000000..e25d14741a --- /dev/null +++ b/common/installshield_cab.cpp @@ -0,0 +1,212 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +// The following code is based on unshield +// Original copyright: + +// Copyright (c) 2003 David Eriksson <twogood@users.sourceforge.net> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +// of the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "common/archive.h" +#include "common/debug.h" +#include "common/hash-str.h" +#include "common/installshield_cab.h" +#include "common/memstream.h" +#include "common/zlib.h" + +namespace Common { + +class InstallShieldCabinet : public Archive { +public: +	InstallShieldCabinet(SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse); +	~InstallShieldCabinet(); + +	// Archive API implementation +	bool hasFile(const String &name) const; +	int listMembers(ArchiveMemberList &list) const; +	const ArchiveMemberPtr getMember(const String &name) const; +	SeekableReadStream *createReadStreamForMember(const String &name) const; + +private: +	struct FileEntry { +		uint32 uncompressedSize; +		uint32 compressedSize; +		uint32 offset; +		uint16 flags; +	}; + +	typedef HashMap<String, FileEntry, IgnoreCase_Hash, IgnoreCase_EqualTo> FileMap; +	FileMap _map; +	Common::SeekableReadStream *_stream; +	DisposeAfterUse::Flag _disposeAfterUse; +}; + +InstallShieldCabinet::~InstallShieldCabinet() { +	_map.clear(); + +	if (_disposeAfterUse == DisposeAfterUse::YES) +		delete _stream; +} + +InstallShieldCabinet::InstallShieldCabinet(SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) : _stream(stream), _disposeAfterUse(disposeAfterUse) { +	// Note that we only support a limited subset of cabinet files +	// Only single cabinet files and ones without data shared between +	// cabinets. + +	// Check for the magic uint32 +	if (_stream->readUint32LE() != 0x28635349) { +		warning("InstallShieldCabinet::InstallShieldCabinet(): Magic ID doesn't match"); +		return; +	} + +	uint32 version = _stream->readUint32LE(); + +	if (version != 0x01000004) { +		warning("Unsupported CAB version %08x", version); +		return; +	} + +	/* uint32 volumeInfo = */ _stream->readUint32LE(); +	uint32 cabDescriptorOffset = _stream->readUint32LE(); +	/* uint32 cabDescriptorSize = */ _stream->readUint32LE(); + +	_stream->seek(cabDescriptorOffset); + +	_stream->skip(12); +	uint32 fileTableOffset = _stream->readUint32LE(); +	_stream->skip(4); +	uint32 fileTableSize = _stream->readUint32LE(); +	uint32 fileTableSize2 = _stream->readUint32LE(); +	uint32 directoryCount = _stream->readUint32LE(); +	_stream->skip(8); +	uint32 fileCount = _stream->readUint32LE(); + +	if (fileTableSize != fileTableSize2) +		warning("file table sizes do not match"); + +	// We're ignoring file groups and components since we +	// should not need them. Moving on to the files... + +	_stream->seek(cabDescriptorOffset + fileTableOffset); +	uint32 fileTableCount = directoryCount + fileCount; +	uint32 *fileTableOffsets = new uint32[fileTableCount]; +	for (uint32 i = 0; i < fileTableCount; i++) +		fileTableOffsets[i] = _stream->readUint32LE(); + +	for (uint32 i = directoryCount; i < fileCount + directoryCount; i++) { +		_stream->seek(cabDescriptorOffset + fileTableOffset + fileTableOffsets[i]); +		uint32 nameOffset = _stream->readUint32LE(); +		/* uint32 directoryIndex = */ _stream->readUint32LE(); + +		// First read in data needed by us to get at the file data +		FileEntry entry; +		entry.flags = _stream->readUint16LE(); +		entry.uncompressedSize = _stream->readUint32LE(); +		entry.compressedSize = _stream->readUint32LE(); +		_stream->skip(20); +		entry.offset = _stream->readUint32LE(); + +		// Then let's get the string +		_stream->seek(cabDescriptorOffset + fileTableOffset + nameOffset); +		String fileName; + +		char c = _stream->readByte(); +		while (c) { +			fileName += c; +			c = _stream->readByte(); +		} +		_map[fileName] = entry; +	} + +	delete[] fileTableOffsets; +} + +bool InstallShieldCabinet::hasFile(const String &name) const { +	return _map.contains(name); +} + +int InstallShieldCabinet::listMembers(ArchiveMemberList &list) const { +	for (FileMap::const_iterator it = _map.begin(); it != _map.end(); it++) +		list.push_back(getMember(it->_key)); + +	return _map.size(); +} + +const ArchiveMemberPtr InstallShieldCabinet::getMember(const String &name) const { +	return ArchiveMemberPtr(new GenericArchiveMember(name, this)); +} + +SeekableReadStream *InstallShieldCabinet::createReadStreamForMember(const String &name) const { +	if (!_map.contains(name)) +		return 0; + +	const FileEntry &entry = _map[name]; + +	_stream->seek(entry.offset); + +	if (!(entry.flags & 0x04)) // Not compressed +		return _stream->readStream(entry.uncompressedSize); + +#ifdef USE_ZLIB +	byte *src = (byte *)malloc(entry.compressedSize); +	byte *dst = (byte *)malloc(entry.uncompressedSize); + +	_stream->read(src, entry.compressedSize); + +	bool result = inflateZlibInstallShield(dst, entry.uncompressedSize, src, entry.compressedSize); +	free(src); + +	if (!result) { +		warning("failed to inflate CAB file '%s'", name.c_str()); +		free(dst); +		return 0; +	} + +	return new MemoryReadStream(dst, entry.uncompressedSize, DisposeAfterUse::YES); +#else +	warning("zlib required to extract compressed CAB file '%s'", name.c_str()); +	return 0; +#endif +} + +Archive *makeInstallShieldArchive(SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) { +	return new InstallShieldCabinet(stream, disposeAfterUse); +} + +} // End of namespace AGOS diff --git a/common/installshield_cab.h b/common/installshield_cab.h new file mode 100644 index 0000000000..7c4f294578 --- /dev/null +++ b/common/installshield_cab.h @@ -0,0 +1,43 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef COMMON_INSTALLSHIELD_CAB_H +#define COMMON_INSTALLSHIELD_CAB_H + +#include "common/types.h" + +namespace Common { + +class Archive; +class SeekableReadStream; + +/** + * This factory method creates an Archive instance corresponding to the content + * of the InstallShield compressed stream. + * + * May return 0 in case of a failure. + */ +Archive *makeInstallShieldArchive(SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES); + +} // End of namespace Common + +#endif diff --git a/common/keyboard.h b/common/keyboard.h index f9e94e6656..3262a15c3f 100644 --- a/common/keyboard.h +++ b/common/keyboard.h @@ -224,12 +224,13 @@ enum {  	KBD_CTRL  = 1 << 0,  	KBD_ALT   = 1 << 1,  	KBD_SHIFT = 1 << 2, -	KBD_NON_STICKY = (KBD_CTRL|KBD_ALT|KBD_SHIFT), +	KBD_META  = 1 << 3, +	KBD_NON_STICKY = (KBD_CTRL|KBD_ALT|KBD_SHIFT|KBD_META),  	// Sticky modifier flags -	KBD_NUM   = 1 << 3, -	KBD_CAPS  = 1 << 4, -	KBD_SCRL  = 1 << 5, +	KBD_NUM   = 1 << 4, +	KBD_CAPS  = 1 << 5, +	KBD_SCRL  = 1 << 6,  	KBD_STICKY = (KBD_NUM|KBD_CAPS|KBD_SCRL)  }; diff --git a/common/macresman.cpp b/common/macresman.cpp index 14bdfa7080..f2f020c6de 100644 --- a/common/macresman.cpp +++ b/common/macresman.cpp @@ -124,7 +124,7 @@ bool MacResManager::open(String filename) {  	File *file = new File();  	// First, let's try to see if the Mac converted name exists -	if (file->open("._" + filename) && loadFromAppleDouble(*file)) { +	if (file->open(constructAppleDoubleName(filename)) && loadFromAppleDouble(*file)) {  		_baseFileName = filename;  		return true;  	} @@ -185,7 +185,7 @@ bool MacResManager::open(FSNode path, String filename) {  #endif  	// First, let's try to see if the Mac converted name exists -	FSNode fsNode = path.getChild("._" + filename); +	FSNode fsNode = path.getChild(constructAppleDoubleName(filename));  	if (fsNode.exists() && !fsNode.isDirectory()) {  		SeekableReadStream *stream = fsNode.createReadStream();  		if (loadFromAppleDouble(*stream)) { @@ -253,7 +253,7 @@ bool MacResManager::exists(const String &filename) {  		return true;  	// Check if we have an AppleDouble file -	if (tempFile.open("._" + filename) && tempFile.readUint32BE() == 0x00051607) +	if (tempFile.open(constructAppleDoubleName(filename)) && tempFile.readUint32BE() == 0x00051607)  		return true;  	return false; @@ -574,4 +574,20 @@ void MacResManager::readMap() {  	}  } +Common::String MacResManager::constructAppleDoubleName(Common::String name) { +	// Insert "._" before the last portion of a path name +	for (int i = name.size() - 1; i >= 0; i--) { +		if (i == 0) { +			name.insertChar('_', 0); +			name.insertChar('.', 0); +		} else if (name[i] == '/') { +			name.insertChar('_', i + 1); +			name.insertChar('.', i + 1); +			break; +		} +	} + +	return name; +} +  } // End of namespace Common diff --git a/common/macresman.h b/common/macresman.h index 6820106925..ed74da9cc6 100644 --- a/common/macresman.h +++ b/common/macresman.h @@ -25,6 +25,7 @@   * Macintosh resource fork manager used in engines:   * - groovie   * - mohawk + * - pegasus   * - sci   * - scumm   */ @@ -175,6 +176,8 @@ private:  	bool loadFromMacBinary(SeekableReadStream &stream);  	bool loadFromAppleDouble(SeekableReadStream &stream); +	static Common::String constructAppleDoubleName(Common::String name); +  	enum {  		kResForkNone = 0,  		kResForkRaw, diff --git a/common/memstream.h b/common/memstream.h index 69fe6ec18e..497a178ab9 100644 --- a/common/memstream.h +++ b/common/memstream.h @@ -92,13 +92,17 @@ private:  	byte *_ptr;  	const uint32 _bufSize;  	uint32 _pos; +	bool _err;  public: -	MemoryWriteStream(byte *buf, uint32 len) : _ptr(buf), _bufSize(len), _pos(0) {} +	MemoryWriteStream(byte *buf, uint32 len) : _ptr(buf), _bufSize(len), _pos(0), _err(false) {}  	uint32 write(const void *dataPtr, uint32 dataSize) {  		// Write at most as many bytes as are still available... -		if (dataSize > _bufSize - _pos) +		if (dataSize > _bufSize - _pos) {  			dataSize = _bufSize - _pos; +			// We couldn't write all the data => set error indicator +			_err = true; +		}  		memcpy(_ptr, dataPtr, dataSize);  		_ptr += dataSize;  		_pos += dataSize; @@ -107,6 +111,9 @@ public:  	uint32 pos() const { return _pos; }  	uint32 size() const { return _bufSize; } + +	virtual bool err() const { return _err; } +	virtual void clearErr() { _err = false; }  };  /** diff --git a/common/module.mk b/common/module.mk index 92279740e5..d96b11ee40 100644 --- a/common/module.mk +++ b/common/module.mk @@ -16,6 +16,7 @@ MODULE_OBJS := \  	gui_options.o \  	hashmap.o \  	iff_container.o \ +	installshield_cab.o \  	language.o \  	localization.o \  	macresman.o \ diff --git a/common/quicktime.h b/common/quicktime.h index 974502d075..641718e13a 100644 --- a/common/quicktime.h +++ b/common/quicktime.h @@ -35,6 +35,7 @@  #include "common/scummsys.h"  #include "common/stream.h"  #include "common/rational.h" +#include "common/types.h"  namespace Common {  	class MacResManager; @@ -167,7 +168,7 @@ protected:  	Rational _scaleFactorX;  	Rational _scaleFactorY;  	Array<Track *> _tracks; -	 +  	void init();  private: diff --git a/common/rational.h b/common/rational.h index 45aa6a7a20..8270d2194e 100644 --- a/common/rational.h +++ b/common/rational.h @@ -80,6 +80,9 @@ public:  	double toDouble() const;  	frac_t toFrac() const; +	int getNumerator() const { return _num; } +	int getDenominator() const { return _denom; } +  	void debugPrint(int debuglevel = 0, const char *caption = "Rational:") const;  private: diff --git a/common/rect.h b/common/rect.h index 2bd3affafe..8d1243f7e4 100644 --- a/common/rect.h +++ b/common/rect.h @@ -170,6 +170,20 @@ struct Rect {  	}  	/** +	 * Find the intersecting rectangle between this rectangle and the given rectangle +	 * +	 * @param r the intersecting rectangle +	 * +	 * @return the intersection of the rectangles or an empty rectangle if not intersecting +	 */ +	Rect findIntersectingRect(const Rect &r) const { +		if (!intersects(r)) +			return Rect(); + +		return Rect(MAX(r.left, left), MAX(r.top, top), MIN(r.right, right), MIN(r.bottom, bottom)); +	} + +	/**  	 * Extend this rectangle so that it contains r  	 *  	 * @param r the rectangle to extend by diff --git a/common/savefile.h b/common/savefile.h index da787289ee..19536da54f 100644 --- a/common/savefile.h +++ b/common/savefile.h @@ -109,12 +109,12 @@ public:  	 *  	 * Saved games are compressed by default, and engines are expected to  	 * always write compressed saves. -	 *  +	 *  	 * A notable exception is if uncompressed files are needed for  	 * compatibility with games not supported by ScummVM, such as character  	 * exports from the Quest for Glory series. QfG5 is a 3D game and won't be  	 * supported by ScummVM. -	 *  +	 *  	 * @param name		the name of the savefile  	 * @param compress	toggles whether to compress the resulting save file  	 * 					(default) or not. diff --git a/common/sinetables.cpp b/common/sinetables.cpp index a4467383cc..a6ec99469d 100644 --- a/common/sinetables.cpp +++ b/common/sinetables.cpp @@ -36,7 +36,7 @@ SineTable::SineTable(int bitPrecision) {  	double freq = 2 * M_PI / m;  	_table = new float[m]; -	// Table contains sin(2*pi*x/n) for 0<=x<=n/4,  +	// Table contains sin(2*pi*x/n) for 0<=x<=n/4,  	// followed by its reverse  	for (int i = 0; i <= m / 4; i++)  		_table[i] = sin(i * freq); diff --git a/common/winexe_pe.cpp b/common/winexe_pe.cpp index 6c0f9c9962..b3c45ffe73 100644 --- a/common/winexe_pe.cpp +++ b/common/winexe_pe.cpp @@ -64,7 +64,7 @@ bool PEResources::loadFromEXE(SeekableReadStream *stream) {  	if (!stream)  		return false; -	if (stream->readUint16BE() != 'MZ') +	if (stream->readUint16BE() != MKTAG16('M', 'Z'))  		return false;  	stream->skip(58); diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index ea3d44cf87..f0b7f1cc81 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -20,15 +20,11 @@   *   */ -// FIXME: Avoid using fprintf -#define FORBIDDEN_SYMBOL_EXCEPTION_fprintf -#define FORBIDDEN_SYMBOL_EXCEPTION_stderr - -  #include "common/xmlparser.h"  #include "common/archive.h"  #include "common/fs.h"  #include "common/memstream.h" +#include "common/system.h"  namespace Common { @@ -123,17 +119,19 @@ bool XMLParser::parserError(const String &errStr) {  			keyClosing = currentPosition;  	} -	fprintf(stderr, "\n  File <%s>, line %d:\n", _fileName.c_str(), lineCount); +	Common::String errorMessage = Common::String::format("\n  File <%s>, line %d:\n", _fileName.c_str(), lineCount);  	currentPosition = (keyClosing - keyOpening);  	_stream->seek(keyOpening, SEEK_SET);  	while (currentPosition--) -		fprintf(stderr, "%c", _stream->readByte()); +		errorMessage += (char)_stream->readByte(); + +	errorMessage += "\n\nParser error: "; +	errorMessage += errStr; +	errorMessage += "\n\n"; -	fprintf(stderr, "\n\nParser error: "); -	fprintf(stderr, "%s", errStr.c_str()); -	fprintf(stderr, "\n\n"); +	g_system->logMessage(LogMessageType::kError, errorMessage.c_str());  	return false;  } diff --git a/common/zlib.cpp b/common/zlib.cpp index 7d765fc539..fc8f351054 100644 --- a/common/zlib.cpp +++ b/common/zlib.cpp @@ -85,6 +85,60 @@ bool inflateZlibHeaderless(byte *dst, uint dstLen, const byte *src, uint srcLen,  	return true;  } +enum { +	kTempBufSize = 65536 +}; + +bool inflateZlibInstallShield(byte *dst, uint dstLen, const byte *src, uint srcLen) { +	if (!dst || !dstLen || !src || !srcLen) +		return false; + +	// See if we have sync bytes. If so, just use our function for that. +	if (srcLen >= 4 && READ_BE_UINT32(src + srcLen - 4) == 0xFFFF) +		return inflateZlibHeaderless(dst, dstLen, src, srcLen); + +	// Otherwise, we have some custom code we get to use here. + +	byte *temp = (byte *)malloc(kTempBufSize); + +	uint32 bytesRead = 0, bytesProcessed = 0; +	while (bytesRead < srcLen) { +		uint16 chunkSize = READ_LE_UINT16(src + bytesRead); +		bytesRead += 2; + +		// Initialize zlib +		z_stream stream; +		stream.next_in = const_cast<byte *>(src + bytesRead); +		stream.avail_in = chunkSize; +		stream.next_out = temp; +		stream.avail_out = kTempBufSize; +		stream.zalloc = Z_NULL; +		stream.zfree = Z_NULL; +		stream.opaque = Z_NULL; + +		// Negative MAX_WBITS tells zlib there's no zlib header +		int err = inflateInit2(&stream, -MAX_WBITS); +		if (err != Z_OK) +			return false; + +		err = inflate(&stream, Z_FINISH); +		if (err != Z_OK && err != Z_STREAM_END) { +			inflateEnd(&stream); +			free(temp); +			return false; +		} + +		memcpy(dst + bytesProcessed, temp, stream.total_out); +		bytesProcessed += stream.total_out; + +		inflateEnd(&stream); +		bytesRead += chunkSize; +	} + +	free(temp); +	return true; +} +  /**   * A simple wrapper class which can be used to wrap around an arbitrary   * other SeekableReadStream and will then provide on-the-fly decompression support. @@ -107,7 +161,7 @@ protected:  public: -	GZipReadStream(SeekableReadStream *w) : _wrapped(w), _stream() { +	GZipReadStream(SeekableReadStream *w, uint32 knownSize = 0) : _wrapped(w), _stream() {  		assert(w != 0);  		// Verify file header is correct @@ -122,7 +176,8 @@ public:  			_origSize = w->readUint32LE();  		} else {  			// Original size not available in zlib format -			_origSize = 0; +			// use an otherwise known size if supplied. +			_origSize = knownSize;  		}  		_pos = 0;  		w->seek(0, SEEK_SET); @@ -336,7 +391,7 @@ public:  #endif	// USE_ZLIB -SeekableReadStream *wrapCompressedReadStream(SeekableReadStream *toBeWrapped) { +SeekableReadStream *wrapCompressedReadStream(SeekableReadStream *toBeWrapped, uint32 knownSize) {  #if defined(USE_ZLIB)  	if (toBeWrapped) {  		uint16 header = toBeWrapped->readUint16BE(); @@ -345,7 +400,7 @@ SeekableReadStream *wrapCompressedReadStream(SeekableReadStream *toBeWrapped) {  				      header % 31 == 0));  		toBeWrapped->seek(-2, SEEK_CUR);  		if (isCompressed) -			return new GZipReadStream(toBeWrapped); +			return new GZipReadStream(toBeWrapped, knownSize);  	}  #endif  	return toBeWrapped; diff --git a/common/zlib.h b/common/zlib.h index 61322c286a..6a840f5fdc 100644 --- a/common/zlib.h +++ b/common/zlib.h @@ -77,6 +77,25 @@ bool uncompress(byte *dst, unsigned long *dstLen, const byte *src, unsigned long   */  bool inflateZlibHeaderless(byte *dst, uint dstLen, const byte *src, uint srcLen, const byte *dict = 0, uint dictLen = 0); +/** + * Wrapper around zlib's inflate functions. This function will call the + * necessary inflate functions to uncompress data compressed for InstallShield + * cabinet files. + * + * Decompresses the src buffer into the dst buffer. + * srcLen is the byte length of the source buffer, dstLen is the byte + * length of the output buffer. + * It decompress as much data as possible, up to dstLen bytes. + * + * @param dst       the buffer to store into. + * @param dstLen    the size of the destination buffer. + * @param src       the data to be decompressed. + * @param dstLen    the size of the compressed data. + * + * @return true on success (Z_OK or Z_STREAM_END), false otherwise. + */ +bool inflateZlibInstallShield(byte *dst, uint dstLen, const byte *src, uint srcLen); +  #endif  /** @@ -86,10 +105,18 @@ bool inflateZlibHeaderless(byte *dst, uint dstLen, const byte *src, uint srcLen,   * format. In the former case, the original stream is returned unmodified   * (and in particular, not wrapped).   * + * Certain GZip-formats don't supply an easily readable length, if you + * still need the length carried along with the stream, and you know + * the decompressed length at wrap-time, then it can be supplied as knownSize + * here. knownSize will be ignored if the GZip-stream DOES include a length. + *   * It is safe to call this with a NULL parameter (in this case, NULL is   * returned). + * + * @param toBeWrapped	the stream to be wrapped (if it is in gzip-format) + * @param knownSize		a supplied length of the compressed data (if not available directly)   */ -SeekableReadStream *wrapCompressedReadStream(SeekableReadStream *toBeWrapped); +SeekableReadStream *wrapCompressedReadStream(SeekableReadStream *toBeWrapped, uint32 knownSize = 0);  /**   * Take an arbitrary WriteStream and wrap it in a custom stream which provides | 
