[Scummvm-git-logs] scummvm master -> f132cbcf8570eb2a125d6c079997762ffffdab08

dreammaster dreammaster at scummvm.org
Sun Aug 13 02:09:28 CEST 2017


This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
6a5c520194 DEVTOOLS: Add compression for titanic.dat bitmaps
f132cbcf85 TITANIC: Add support for compressed bitmaps in titanic.dat


Commit: 6a5c52019458e13941abb3f6ab3f4cd1607c3989
    https://github.com/scummvm/scummvm/commit/6a5c52019458e13941abb3f6ab3f4cd1607c3989
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2017-08-12T20:08:49-04:00

Commit Message:
DEVTOOLS: Add compression for titanic.dat bitmaps

Changed paths:
  A devtools/create_titanic/zlib.cpp
  A devtools/create_titanic/zlib.h
    devtools/create_titanic/create_titanic_dat.cpp
    devtools/create_titanic/module.mk
    dists/engine-data/titanic.dat


diff --git a/devtools/create_titanic/create_titanic_dat.cpp b/devtools/create_titanic/create_titanic_dat.cpp
index 6d9b713..4a24ec9 100644
--- a/devtools/create_titanic/create_titanic_dat.cpp
+++ b/devtools/create_titanic/create_titanic_dat.cpp
@@ -29,11 +29,17 @@
 #undef main
 #endif // main
 
+#ifndef USE_ZLIB
+#error "Project should have USE_ZLIB defined"
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include "common/language.h"
+#include "common/memstream.h"
 #include "common/rect.h"
+#include "zlib.h"
 #include "winexe_pe.h"
 #include "file.h"
 #include "script_preresponses.h"
@@ -54,8 +60,8 @@
  * ASCIIZ  - name of the resource
  */
 
-#define VERSION_NUMBER 1
-#define HEADER_SIZE 0x1200
+#define VERSION_NUMBER 2
+#define HEADER_SIZE 0x1380
 
 Common::File inputFile, outputFile;
 Common::PEResources resEng, resGer;
@@ -1022,14 +1028,24 @@ void NORETURN_PRE error(const char *s, ...) {
 	exit(1);
 }
 
-void writeEntryHeader(const char *name, uint offset, uint size) {
+void writeEntryHeader(const char *name, uint offset, uint size, uint flags) {
 	assert(headerOffset < HEADER_SIZE);
 	outputFile.seek(headerOffset);
 	outputFile.writeLong(offset);
 	outputFile.writeLong(size);
+	outputFile.writeWord(flags);
 	outputFile.writeString(name);
 
-	headerOffset += 8 + strlen(name) + 1;
+	headerOffset += 10 + strlen(name) + 1;
+}
+
+void writeEntryHeader(const char *name, uint offset, uint size) {
+	writeEntryHeader(name, offset, size, 0);
+}
+
+void writeEntryHeader(const char *name, uint offset, uint size, bool isCompressed) {
+	uint flags = isCompressed ? 1 : 0;
+	writeEntryHeader(name, offset, size, flags);
 }
 
 void writeFinalEntryHeader() {
@@ -1039,6 +1055,10 @@ void writeFinalEntryHeader() {
 	outputFile.writeLong(0);
 }
 
+void writeCompressedRes(Common::File *src) {
+
+}
+
 void writeStringArray(const char *name, uint offset, int count) {
 	outputFile.seek(dataOffset);
 
@@ -1130,18 +1150,36 @@ void writeResource(const char *sectionStr, const char *resId, bool isEnglish = t
 void writeBitmap(const char *name, Common::File *file) {
 	outputFile.seek(dataOffset);
 
+	// Set up a memory stream for the compressed data, and wrap
+	// it with a zlib compressor
+	Common::MemoryWriteStreamDynamic *compressedData =
+		new Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES);
+	Common::WriteStream *zlib = Common::wrapCompressedWriteStream(compressedData);
+
 	// Write out the necessary bitmap header so that the ScummVM
 	// BMP decoder can properly handle decoding the bitmaps
-	outputFile.write("BM", 2);
-	outputFile.writeLong(file->size() + 14);	// Filesize
-	outputFile.writeLong(0);					// res1 & res2
-	outputFile.writeLong(0x436);				// image offset
+	zlib->write("BM", 2);
+	zlib->writeUint32LE(file->size() + 14);	// Filesize
+	zlib->writeUint32LE(0);					// res1 & res2
+	zlib->writeUint32LE(0x436);				// image offset
 
-	outputFile.write(*file, file->size());
+	// Transfer the bitmap data
+	int srcSize = file->size();
+	byte *data = new byte[srcSize];
+	file->read(data, srcSize);
+	zlib->write(data, srcSize);
 
-	writeEntryHeader(name, dataOffset, file->size() + 14);
-	dataOffset += file->size() + 14;
-	delete file;
+	delete[] data;
+	zlib->finalize();
+
+	// Write out the compressed data
+	outputFile.write(compressedData->getData(), compressedData->size());
+
+	writeEntryHeader(name, dataOffset, compressedData->size() + 14, true);
+	dataOffset += compressedData->size() + 14;
+
+	// Free the zlib write stream
+	delete zlib;
 }
 
 void writeBitmap(const char *sectionStr, const char *resId, bool isEnglish = true) {
diff --git a/devtools/create_titanic/module.mk b/devtools/create_titanic/module.mk
index 9f77866..a762af3 100644
--- a/devtools/create_titanic/module.mk
+++ b/devtools/create_titanic/module.mk
@@ -13,7 +13,8 @@ MODULE_OBJS := \
 	str.o \
 	tag_maps.o \
 	winexe.o \
-	winexe_pe.o
+	winexe_pe.o \
+	zlib.o
 
 # Set the name of the executable
 TOOL_EXECUTABLE := create_titanic
diff --git a/devtools/create_titanic/zlib.cpp b/devtools/create_titanic/zlib.cpp
new file mode 100644
index 0000000..3221d61
--- /dev/null
+++ b/devtools/create_titanic/zlib.cpp
@@ -0,0 +1,455 @@
+/* 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.
+ *
+ */
+
+// Disable symbol overrides so that we can use zlib.h
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+#include "zlib.h"
+#include "common/ptr.h"
+#include "common/util.h"
+#include "common/stream.h"
+
+#if defined(USE_ZLIB)
+  #ifdef __SYMBIAN32__
+    #include <zlib\zlib.h>
+  #else
+    #include <zlib.h>
+  #endif
+
+  #if ZLIB_VERNUM < 0x1204
+  #error Version 1.2.0.4 or newer of zlib is required for this code
+  #endif
+#endif
+
+
+namespace Common {
+
+/**
+ * Stubs for ScummVM stuff I don't want to have to link in
+ */
+void debug(int level, const char *s, ...) {}
+
+char *SeekableReadStream::readLine(char *buf, size_t bufSize) {
+	return nullptr;
+}
+
+String SeekableReadStream::readLine() {
+	return String();
+}
+
+#if defined(USE_ZLIB)
+
+bool uncompress(byte *dst, unsigned long *dstLen, const byte *src, unsigned long srcLen) {
+	return Z_OK == ::uncompress(dst, dstLen, src, srcLen);
+}
+
+bool inflateZlibHeaderless(byte *dst, uint dstLen, const byte *src, uint srcLen, const byte *dict, uint dictLen) {
+	if (!dst || !dstLen || !src || !srcLen)
+		return false;
+
+	// Initialize zlib
+	z_stream stream;
+	stream.next_in = const_cast<byte *>(src);
+	stream.avail_in = srcLen;
+	stream.next_out = dst;
+	stream.avail_out = dstLen;
+	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;
+
+	// Set the dictionary, if provided
+	if (dict != 0) {
+		err = inflateSetDictionary(&stream, const_cast<byte *>(dict), dictLen);
+		if (err != Z_OK)
+			return false;
+	}
+
+	err = inflate(&stream, Z_SYNC_FLUSH);
+	if (err != Z_OK && err != Z_STREAM_END) {
+		inflateEnd(&stream);
+		return false;
+	}
+
+	inflateEnd(&stream);
+	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;
+}
+
+#ifndef RELEASE_BUILD
+static bool _shownBackwardSeekingWarning = false;
+#endif
+
+/**
+ * A simple wrapper class which can be used to wrap around an arbitrary
+ * other SeekableReadStream and will then provide on-the-fly decompression support.
+ * Assumes the compressed data to be in gzip format.
+ */
+class GZipReadStream : public SeekableReadStream {
+protected:
+	enum {
+		BUFSIZE = 16384		// 1 << MAX_WBITS
+	};
+
+	byte	_buf[BUFSIZE];
+
+	ScopedPtr<SeekableReadStream> _wrapped;
+	z_stream _stream;
+	int _zlibErr;
+	uint32 _pos;
+	uint32 _origSize;
+	bool _eos;
+
+public:
+
+	GZipReadStream(SeekableReadStream *w, uint32 knownSize = 0) : _wrapped(w), _stream() {
+		assert(w != 0);
+
+		// Verify file header is correct
+		w->seek(0, SEEK_SET);
+		uint16 header = w->readUint16BE();
+		assert(header == 0x1F8B ||
+		       ((header & 0x0F00) == 0x0800 && header % 31 == 0));
+
+		if (header == 0x1F8B) {
+			// Retrieve the original file size
+			w->seek(-4, SEEK_END);
+			_origSize = w->readUint32LE();
+		} else {
+			// Original size not available in zlib format
+			// use an otherwise known size if supplied.
+			_origSize = knownSize;
+		}
+		_pos = 0;
+		w->seek(0, SEEK_SET);
+		_eos = false;
+
+		// Adding 32 to windowBits indicates to zlib that it is supposed to
+		// automatically detect whether gzip or zlib headers are used for
+		// the compressed file. This feature was added in zlib 1.2.0.4,
+		// released 10 August 2003.
+		// Note: This is *crucial* for savegame compatibility, do *not* remove!
+		_zlibErr = inflateInit2(&_stream, MAX_WBITS + 32);
+		if (_zlibErr != Z_OK)
+			return;
+
+		// Setup input buffer
+		_stream.next_in = _buf;
+		_stream.avail_in = 0;
+	}
+
+	~GZipReadStream() {
+		inflateEnd(&_stream);
+	}
+
+	bool err() const { return (_zlibErr != Z_OK) && (_zlibErr != Z_STREAM_END); }
+	void clearErr() {
+		// only reset _eos; I/O errors are not recoverable
+		_eos = false;
+	}
+
+	uint32 read(void *dataPtr, uint32 dataSize) {
+		_stream.next_out = (byte *)dataPtr;
+		_stream.avail_out = dataSize;
+
+		// Keep going while we get no error
+		while (_zlibErr == Z_OK && _stream.avail_out) {
+			if (_stream.avail_in == 0 && !_wrapped->eos()) {
+				// If we are out of input data: Read more data, if available.
+				_stream.next_in = _buf;
+				_stream.avail_in = _wrapped->read(_buf, BUFSIZE);
+			}
+			_zlibErr = inflate(&_stream, Z_NO_FLUSH);
+		}
+
+		// Update the position counter
+		_pos += dataSize - _stream.avail_out;
+
+		if (_zlibErr == Z_STREAM_END && _stream.avail_out > 0)
+			_eos = true;
+
+		return dataSize - _stream.avail_out;
+	}
+
+	bool eos() const {
+		return _eos;
+	}
+	int32 pos() const {
+		return _pos;
+	}
+	int32 size() const {
+		return _origSize;
+	}
+	bool seek(int32 offset, int whence = SEEK_SET) {
+		int32 newPos = 0;
+		switch (whence) {
+		case SEEK_SET:
+			newPos = offset;
+			break;
+		case SEEK_CUR:
+			newPos = _pos + offset;
+			break;
+		case SEEK_END:
+			// NOTE: This can be an expensive operation (see below).
+			newPos = size() + offset;
+			break;
+		}
+
+		assert(newPos >= 0);
+
+		if ((uint32)newPos < _pos) {
+			// To search backward, we have to restart the whole decompression
+			// from the start of the file. A rather wasteful operation, best
+			// to avoid it. :/
+
+#ifndef RELEASE_BUILD
+			if (!_shownBackwardSeekingWarning) {
+				// We only throw this warning once per stream, to avoid
+				// getting the console swarmed with warnings when consecutive
+				// seeks are made.
+				debug(1, "Backward seeking in GZipReadStream detected");
+				_shownBackwardSeekingWarning = true;
+			}
+#endif
+
+			_pos = 0;
+			_wrapped->seek(0, SEEK_SET);
+			_zlibErr = inflateReset(&_stream);
+			if (_zlibErr != Z_OK)
+				return false;	// FIXME: STREAM REWRITE
+			_stream.next_in = _buf;
+			_stream.avail_in = 0;
+		}
+
+		offset = newPos - _pos;
+
+		// Skip the given amount of data (very inefficient if one tries to skip
+		// huge amounts of data, but usually client code will only skip a few
+		// bytes, so this should be fine.
+		byte tmpBuf[1024];
+		while (!err() && offset > 0) {
+			offset -= read(tmpBuf, MIN((int32)sizeof(tmpBuf), offset));
+		}
+
+		_eos = false;
+		return true;	// FIXME: STREAM REWRITE
+	}
+};
+
+/**
+ * A simple wrapper class which can be used to wrap around an arbitrary
+ * other WriteStream and will then provide on-the-fly compression support.
+ * The compressed data is written in the gzip format.
+ */
+class GZipWriteStream : public WriteStream {
+protected:
+	enum {
+		BUFSIZE = 16384		// 1 << MAX_WBITS
+	};
+
+	byte	_buf[BUFSIZE];
+	ScopedPtr<WriteStream> _wrapped;
+	z_stream _stream;
+	int _zlibErr;
+	uint32 _pos;
+
+	void processData(int flushType) {
+		// This function is called by both write() and finalize().
+		while (_zlibErr == Z_OK && (_stream.avail_in || flushType == Z_FINISH)) {
+			if (_stream.avail_out == 0) {
+				if (_wrapped->write(_buf, BUFSIZE) != BUFSIZE) {
+					_zlibErr = Z_ERRNO;
+					break;
+				}
+				_stream.next_out = _buf;
+				_stream.avail_out = BUFSIZE;
+			}
+			_zlibErr = deflate(&_stream, flushType);
+		}
+	}
+
+public:
+	GZipWriteStream(WriteStream *w) : _wrapped(w), _stream(), _pos(0) {
+		assert(w != 0);
+
+		// Adding 16 to windowBits indicates to zlib that it is supposed to
+		// write gzip headers. This feature was added in zlib 1.2.0.4,
+		// released 10 August 2003.
+		// Note: This is *crucial* for savegame compatibility, do *not* remove!
+		_zlibErr = deflateInit2(&_stream,
+		                 Z_DEFAULT_COMPRESSION,
+		                 Z_DEFLATED,
+		                 MAX_WBITS + 16,
+		                 8,
+				 Z_DEFAULT_STRATEGY);
+		assert(_zlibErr == Z_OK);
+
+		_stream.next_out = _buf;
+		_stream.avail_out = BUFSIZE;
+		_stream.avail_in = 0;
+		_stream.next_in = 0;
+	}
+
+	~GZipWriteStream() {
+		finalize();
+		deflateEnd(&_stream);
+	}
+
+	bool err() const {
+		// CHECKME: does Z_STREAM_END make sense here?
+		return (_zlibErr != Z_OK && _zlibErr != Z_STREAM_END) || _wrapped->err();
+	}
+
+	void clearErr() {
+		// Note: we don't reset the _zlibErr here, as it is not
+		// clear in general how
+		_wrapped->clearErr();
+	}
+
+	void finalize() {
+		if (_zlibErr != Z_OK)
+			return;
+
+		// Process whatever remaining data there is.
+		processData(Z_FINISH);
+
+		// Since processData only writes out blocks of size BUFSIZE,
+		// we may have to flush some stragglers.
+		uint remainder = BUFSIZE - _stream.avail_out;
+		if (remainder > 0) {
+			if (_wrapped->write(_buf, remainder) != remainder) {
+				_zlibErr = Z_ERRNO;
+			}
+		}
+
+		// Finalize the wrapped savefile, too
+		_wrapped->finalize();
+	}
+
+	uint32 write(const void *dataPtr, uint32 dataSize) {
+		if (err())
+			return 0;
+
+		// Hook in the new data ...
+		// Note: We need to make a const_cast here, as zlib is not aware
+		// of the const keyword.
+		_stream.next_in = const_cast<byte *>((const byte *)dataPtr);
+		_stream.avail_in = dataSize;
+
+		// ... and flush it to disk
+		processData(Z_NO_FLUSH);
+
+		_pos += dataSize - _stream.avail_in;
+		return dataSize - _stream.avail_in;
+	}
+
+	virtual int32 pos() const { return _pos; }
+};
+
+#endif	// USE_ZLIB
+
+SeekableReadStream *wrapCompressedReadStream(SeekableReadStream *toBeWrapped, uint32 knownSize) {
+	if (toBeWrapped) {
+		uint16 header = toBeWrapped->readUint16BE();
+		bool isCompressed = (header == 0x1F8B ||
+				     ((header & 0x0F00) == 0x0800 &&
+				      header % 31 == 0));
+		toBeWrapped->seek(-2, SEEK_CUR);
+		if (isCompressed) {
+#if defined(USE_ZLIB)
+			return new GZipReadStream(toBeWrapped, knownSize);
+#else
+			delete toBeWrapped;
+			return NULL;
+#endif
+		}
+	}
+	return toBeWrapped;
+}
+
+WriteStream *wrapCompressedWriteStream(WriteStream *toBeWrapped) {
+#if defined(USE_ZLIB)
+	if (toBeWrapped)
+		return new GZipWriteStream(toBeWrapped);
+#endif
+	return toBeWrapped;
+}
+
+
+} // End of namespace Common
diff --git a/devtools/create_titanic/zlib.h b/devtools/create_titanic/zlib.h
new file mode 100644
index 0000000..5adba64
--- /dev/null
+++ b/devtools/create_titanic/zlib.h
@@ -0,0 +1,136 @@
+/* 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_ZLIB_H
+#define COMMON_ZLIB_H
+
+#include "common/scummsys.h"
+
+namespace Common {
+
+class SeekableReadStream;
+class WriteStream;
+
+#if defined(USE_ZLIB)
+
+/**
+ * Thin wrapper around zlib's uncompress() function. This wrapper makes
+ * it possible to uncompress data in engines without being forced to link
+ * them against zlib, thus simplifying the build system.
+ *
+ * Taken from the zlib manual:
+ * Decompresses the src buffer into the dst buffer.
+ * srcLen is the byte length of the source buffer. Upon entry, dstLen is the
+ * total size of the destination buffer, which must be large enough to hold
+ * the entire uncompressed data. Upon exit, dstLen is the actual size of the
+ * compressed buffer.
+ *
+ * @param dst       the buffer to store into.
+ * @param dstLen    a pointer to the size of the destination buffer.
+ * @param src       the data to be decompressed.
+ * @param srcLen    the size of the compressed data.
+ *
+ * @return true on success (i.e. Z_OK), false otherwise.
+ */
+bool uncompress(byte *dst, unsigned long *dstLen, const byte *src, unsigned long srcLen);
+
+/**
+ * Wrapper around zlib's inflate functions. This function will call the
+ * necessary inflate functions to uncompress data compressed with deflate
+ * but *not* with the standard zlib header.
+ *
+ * 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.
+ * If a dictionary is provided through the dict buffer, uses it to initializes
+ * the internal decompression dictionary, before the decompression takes place.
+ *
+ * @param dst       the buffer to store into.
+ * @param dstLen    the size of the destination buffer.
+ * @param src       the data to be decompressed.
+ * @param srcLen    the size of the compressed data.
+ * @param dict      (optional) a decompress dictionary.
+ * @param dictLen   (optional) the size of the dictionary.
+ *                  Mandatory if dict is not 0.
+ *
+ * @return true on success (Z_OK or Z_STREAM_END), false otherwise.
+ */
+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 srcLen    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
+
+/**
+ * Take an arbitrary SeekableReadStream and wrap it in a custom stream which
+ * provides transparent on-the-fly decompression. Assumes the data it
+ * retrieves from the wrapped stream to be either uncompressed or in gzip
+ * format. In the former case, the original stream is returned unmodified
+ * (and in particular, not wrapped). In the latter case the stream is
+ * returned wrapped, unless there is no ZLIB support, then NULL is returned
+ * and the old stream is destroyed.
+ *
+ * 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, uint32 knownSize = 0);
+
+/**
+ * Take an arbitrary WriteStream and wrap it in a custom stream which provides
+ * transparent on-the-fly compression. The compressed data is written in the
+ * gzip format, unless ZLIB support has been disabled, in which case the given
+ * stream is returned unmodified (and in particular, not wrapped).
+ *
+ * It is safe to call this with a NULL parameter (in this case, NULL is
+ * returned).
+ */
+WriteStream *wrapCompressedWriteStream(WriteStream *toBeWrapped);
+
+} // End of namespace Common
+
+#endif
diff --git a/dists/engine-data/titanic.dat b/dists/engine-data/titanic.dat
index 910bb9a..2a9d601 100644
Binary files a/dists/engine-data/titanic.dat and b/dists/engine-data/titanic.dat differ


Commit: f132cbcf8570eb2a125d6c079997762ffffdab08
    https://github.com/scummvm/scummvm/commit/f132cbcf8570eb2a125d6c079997762ffffdab08
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2017-08-12T20:09:18-04:00

Commit Message:
TITANIC: Add support for compressed bitmaps in titanic.dat

Changed paths:
    engines/titanic/configure.engine
    engines/titanic/support/files_manager.cpp
    engines/titanic/support/files_manager.h


diff --git a/engines/titanic/configure.engine b/engines/titanic/configure.engine
index 1697a77..23a3b4e 100644
--- a/engines/titanic/configure.engine
+++ b/engines/titanic/configure.engine
@@ -1,3 +1,3 @@
 # This file is included from the main "configure" script
 # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine titanic "Starship Titanic" no "" "" "16bit jpeg highres mad"
+add_engine titanic "Starship Titanic" no "" "" "16bit jpeg highres mad zlib"
diff --git a/engines/titanic/support/files_manager.cpp b/engines/titanic/support/files_manager.cpp
index 5fc9379..eebd56c 100644
--- a/engines/titanic/support/files_manager.cpp
+++ b/engines/titanic/support/files_manager.cpp
@@ -22,6 +22,7 @@
 
 #include "common/file.h"
 #include "common/memstream.h"
+#include "common/zlib.h"
 #include "titanic/support/files_manager.h"
 #include "titanic/game_manager.h"
 #include "titanic/titanic.h"
@@ -29,7 +30,7 @@
 namespace Titanic {
 
 CFilesManager::CFilesManager(TitanicEngine *vm) : _vm(vm), _gameManager(nullptr),
-		_assetsPath("Assets"), _drive(-1) {
+		_assetsPath("Assets"), _drive(-1), _version(0) {
 }
 
 CFilesManager::~CFilesManager() {
@@ -43,19 +44,21 @@ bool CFilesManager::loadResourceIndex() {
 	}
 
 	uint headerId = _datFile.readUint32BE();
-	uint version = _datFile.readUint16LE();
-	if (headerId != MKTAG('S', 'V', 'T', 'N') || version < 1) {
+	_version = _datFile.readUint16LE();
+	if (headerId != MKTAG('S', 'V', 'T', 'N') || _version < 1) {
 		g_vm->GUIError("titanic.dat has invalid contents");
 		return false;
 	}
 
 	// Read in entries
-	uint offset, size;
+	uint offset, size, flags;
 	char c;
 	Common::String resourceName;
 	for (;;) {
 		offset = _datFile.readUint32LE();
 		size = _datFile.readUint32LE();
+		flags = (_version == 1) ? 0 : _datFile.readUint16LE();
+
 		if (offset == 0 && size == 0)
 			break;
 
@@ -63,7 +66,7 @@ bool CFilesManager::loadResourceIndex() {
 		while ((c = _datFile.readByte()) != '\0')
 			resName += c;
 
-		_resources[resName] = ResourceEntry(offset, size);
+		_resources[resName] = ResourceEntry(offset, size, flags);
 	}
 
 	return true;
@@ -136,8 +139,13 @@ Common::SeekableReadStream *CFilesManager::getResource(const CString &str) {
 
 	_datFile.seek(resEntry._offset);
 
-	return (resEntry._size > 0) ? _datFile.readStream(resEntry._size) :
+	Common::SeekableReadStream *stream = (resEntry._size > 0) ?
+		_datFile.readStream(resEntry._size) :
 		new Common::MemoryReadStream(nullptr, 0);
+	if (resEntry._flags & FLAG_COMPRESSED)
+		stream = Common::wrapCompressedReadStream(stream);
+
+	return stream;
 }
 
 } // End of namespace Titanic
diff --git a/engines/titanic/support/files_manager.h b/engines/titanic/support/files_manager.h
index 7627ece..c1e3c3b 100644
--- a/engines/titanic/support/files_manager.h
+++ b/engines/titanic/support/files_manager.h
@@ -29,6 +29,8 @@
 
 namespace Titanic {
 
+enum ResourceFlag { FLAG_COMPRESSED = 1 };
+
 class TitanicEngine;
 class CGameManager;
 
@@ -39,9 +41,11 @@ class CFilesManager {
 	struct ResourceEntry {
 		uint _offset;
 		uint _size;
+		uint _flags;
 
-		ResourceEntry() : _offset(0), _size(0) {}
-		ResourceEntry(uint offset, uint size) : _offset(offset), _size(size) {}
+		ResourceEntry() : _offset(0), _size(0), _flags(0) {}
+		ResourceEntry(uint offset, uint size, uint flags) :
+			_offset(offset), _size(size), _flags(flags) {}
 	};
 	typedef Common::HashMap<Common::String, ResourceEntry> ResourceHash;
 private:
@@ -52,6 +56,7 @@ private:
 	CFilesManagerList _list;
 	int _drive;
 	const CString _assetsPath;
+	int _version;
 public:
 	CFilesManager(TitanicEngine *vm);
 	~CFilesManager();





More information about the Scummvm-git-logs mailing list