aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/zlib.cpp73
-rw-r--r--common/zlib.h12
-rw-r--r--engines/glk/adrift/os_glk.cpp7
-rw-r--r--engines/glk/adrift/sctaffil.cpp155
4 files changed, 124 insertions, 123 deletions
diff --git a/common/zlib.cpp b/common/zlib.cpp
index 6afffb14d2..e4a3d47e35 100644
--- a/common/zlib.cpp
+++ b/common/zlib.cpp
@@ -141,6 +141,79 @@ bool inflateZlibInstallShield(byte *dst, uint dstLen, const byte *src, uint srcL
return true;
}
+bool inflateZlibHeaderless(Common::WriteStream *dst, Common::SeekableReadStream *src) {
+ byte *inBuffer, *outBuffer;
+ z_stream stream;
+ int status;
+
+ // Allocate buffers
+ inBuffer = new byte[kTempBufSize];
+ outBuffer = new byte[kTempBufSize];
+
+ /* Initialize Zlib inflation functions. */
+ stream.next_out = outBuffer;
+ stream.avail_out = kTempBufSize;
+ stream.next_in = inBuffer;
+ stream.avail_in = 0;
+
+ stream.zalloc = Z_NULL;
+ stream.zfree = Z_NULL;
+ stream.opaque = Z_NULL;
+
+ status = inflateInit(&stream);
+ if (status != Z_OK) {
+ delete[] inBuffer;
+ delete[] outBuffer;
+ return false;
+ }
+
+ // Inflate the input buffers. */
+ for (;;) {
+ int inBytes, outBytes;
+
+ /* If the input buffer is empty, try to obtain more data. */
+ if (stream.avail_in == 0) {
+ inBytes = src->read(inBuffer, kTempBufSize);
+ stream.next_in = inBuffer;
+ stream.avail_in = inBytes;
+ }
+
+ // Decompress as much stream data as we can. */
+ status = inflate(&stream, Z_SYNC_FLUSH);
+ if (status != Z_STREAM_END && status != Z_OK) {
+ delete[] inBuffer;
+ delete[] outBuffer;
+ return false;
+ }
+ outBytes = kTempBufSize - stream.avail_out;
+
+ // See if decompressed data is available. */
+ if (outBytes > 0) {
+ // Add data from the buffer to the output
+ int consumed = dst->write(outBuffer, outBytes);
+
+ // Move unused buffer data to buffer start
+ memmove(outBuffer, outBuffer + consumed, kTempBufSize - consumed);
+
+ // Reset inflation stream for available space
+ stream.next_out = outBuffer + outBytes - consumed;
+ stream.avail_out += consumed;
+ }
+
+ // If at inflation stream end and output is empty, leave loop
+ if (status == Z_STREAM_END && stream.avail_out == kTempBufSize)
+ break;
+ }
+
+ // End inflation buffers
+ status = inflateEnd(&stream);
+ delete[] inBuffer;
+ delete[] outBuffer;
+
+ // Return result
+ return (status == Z_OK);
+}
+
#ifndef RELEASE_BUILD
static bool _shownBackwardSeekingWarning = false;
#endif
diff --git a/common/zlib.h b/common/zlib.h
index eb0548344d..a172399511 100644
--- a/common/zlib.h
+++ b/common/zlib.h
@@ -96,6 +96,18 @@ bool inflateZlibHeaderless(byte *dst, uint dstLen, const byte *src, uint srcLen,
*/
bool inflateZlibInstallShield(byte *dst, uint dstLen, const byte *src, uint srcLen);
+/**
+ * Wrapper around zlib's inflate functions. This function is used by Glk to
+ * decompress TAF 4.0 files, which are headerless Zlib compressed streams with a
+ * custom header
+ *
+ * @param dst the destination stream to write decompressed data out to
+ * @param src the Source stream
+ *
+ * @return true on success (Z_OK or Z_STREAM_END), false otherwise.
+ */
+bool inflateZlibHeaderless(Common::WriteStream *dst, Common::SeekableReadStream *src);
+
#endif
/**
diff --git a/engines/glk/adrift/os_glk.cpp b/engines/glk/adrift/os_glk.cpp
index 41409cb2eb..243aca63ae 100644
--- a/engines/glk/adrift/os_glk.cpp
+++ b/engines/glk/adrift/os_glk.cpp
@@ -3112,12 +3112,10 @@ gsc_startup_code(Common::SeekableReadStream *game_stream, strid_t restore_stream
if (!gsc_game)
{
gsc_game = nullptr;
- gsc_game_message = "Unable to load an Adrift game from the"
- " requested file.";
+ gsc_game_message = "Unable to load an Adrift game from the requested file.";
}
else
gsc_game_message = nullptr;
- delete game_stream;
/*
* If the game was created successfully and there is a restore stream, try
@@ -3129,8 +3127,7 @@ gsc_startup_code(Common::SeekableReadStream *game_stream, strid_t restore_stream
{
sc_free_game(gsc_game);
gsc_game = nullptr;
- gsc_game_message = "Unable to restore this Adrift game from the"
- " requested file.";
+ gsc_game_message = "Unable to restore this Adrift game from the requested file.";
}
else
gsc_game_message = nullptr;
diff --git a/engines/glk/adrift/sctaffil.cpp b/engines/glk/adrift/sctaffil.cpp
index 6f0ebae171..6868580b5b 100644
--- a/engines/glk/adrift/sctaffil.cpp
+++ b/engines/glk/adrift/sctaffil.cpp
@@ -23,6 +23,20 @@
#include "glk/adrift/scare.h"
#include "glk/adrift/scprotos.h"
#include "common/textconsole.h"
+#include "common/zlib.h"
+#include "common/memstream.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 Glk {
namespace Adrift {
@@ -426,130 +440,35 @@ taf_unobfuscate (sc_tafref_t taf, sc_read_callbackref_t callback,
return TRUE;
}
+#define BUFFER_SIZE 16384
/*
* taf_decompress()
*
- * Decompress a version 4.0 TAF file from data read by repeated calls to the
- * callback() function. Callback() should return the count of bytes placed
- * in the buffer, 0 if no more (end of file). Assumes that the file has been
- * read past the header.
+ * Decompress a version 4.0 TAF
*/
static sc_bool taf_decompress(sc_tafref_t taf, sc_read_callbackref_t callback,
- void *opaque, sc_bool is_gamefile)
-{
- error("TODO: decompress");
-#ifdef TODO
- sc_byte *in_buffer, *out_buffer;
-// z_stream stream;
- sc_int status;
- sc_bool is_first_block;
-
- /*
- * Malloc buffers, done this way rather than as stack variables for systems
- * such as PalmOS that may have limited stacks.
- */
- in_buffer = sc_malloc (IN_BUFFER_SIZE);
- out_buffer = sc_malloc (OUT_BUFFER_SIZE);
-
- /* Initialize Zlib inflation functions. */
- stream.next_out = out_buffer;
- stream.avail_out = OUT_BUFFER_SIZE;
- stream.next_in = in_buffer;
- stream.avail_in = 0;
-
- stream.zalloc = Z_NULL;
- stream.zfree = Z_NULL;
- stream.opaque = Z_NULL;
-
- status = inflateInit (&stream);
- if (status != Z_OK)
- {
- sc_error ("taf_decompress: inflateInit: error %ld\n", status);
- sc_free (in_buffer);
- sc_free (out_buffer);
- return FALSE;
- }
-
- /*
- * Attempts to restore non-savefiles can arrive here, because there's no
- * up-front header check, like the one for TAF files, applied to them. The
- * first we see of the problem is when the first inflate() fails, so it's
- * handy to use a flag here to block the error report for such cases.
- */
- is_first_block = TRUE;
-
- /* Inflate the input buffers. */
- while (TRUE)
- {
- sc_int in_bytes, out_bytes;
-
- /* If the input buffer is empty, try to obtain more data. */
- if (stream.avail_in == 0)
- {
- in_bytes = callback (opaque, in_buffer, IN_BUFFER_SIZE);
- stream.next_in = in_buffer;
- stream.avail_in = in_bytes;
- }
-
- /* Decompress as much stream data as we can. */
- status = inflate (&stream, Z_SYNC_FLUSH);
- if (status != Z_STREAM_END && status != Z_OK)
- {
- if (is_gamefile || !is_first_block)
- sc_error ("taf_decompress: inflate: error %ld\n", status);
- sc_free (in_buffer);
- sc_free (out_buffer);
- return FALSE;
- }
- out_bytes = OUT_BUFFER_SIZE - stream.avail_out;
-
- /* See if decompressed data is available. */
- if (out_bytes > 0)
- {
- sc_int consumed;
-
- /* Add lines from this buffer to the TAF. */
- consumed = taf_append_buffer (taf, out_buffer, out_bytes);
-
- /* Move unused buffer data to buffer start. */
- memmove (out_buffer,
- out_buffer + consumed, OUT_BUFFER_SIZE - consumed);
-
- /* Reset inflation stream for available space. */
- stream.next_out = out_buffer + out_bytes - consumed;
- stream.avail_out += consumed;
- }
-
- /* Enable full error reporting for non-gamefiles. */
- is_first_block = FALSE;
-
- /* If at inflation stream end and output is empty, leave loop. */
- if (status == Z_STREAM_END && stream.avail_out == OUT_BUFFER_SIZE)
- break;
- }
-
- /*
- * Decompression completed, note the total bytes read for use when locating
- * resources later on in the file. For what it's worth, this value is only
- * used in version 4.0 games.
- */
- taf->total_in_bytes = stream.total_in;
- if (is_gamefile)
- taf->total_in_bytes += VERSION_HEADER_SIZE + V400_HEADER_EXTRA;
-
- /* End inflation. */
- status = inflateEnd (&stream);
- if (status != Z_OK)
- sc_error ("taf_decompress: warning: inflateEnd: error %ld\n", status);
-
- if (taf->is_unterminated)
- sc_fatal ("taf_decompress: unterminated final data slab\n");
-
- /* Return successfully. */
- sc_free (in_buffer);
- sc_free (out_buffer);
- return TRUE;
+ void *opaque, sc_bool is_gamefile) {
+#if USE_ZLIB
+ Common::SeekableReadStream *src = (Common::SeekableReadStream *)opaque;
+ assert(src);
+ Common::MemoryWriteStreamDynamic dest(DisposeAfterUse::YES);
+
+ if (!Common::inflateZlibHeaderless(&dest, src))
+ return false;
+
+ // Iterate through pushing data out to the taf file
+ const byte *pTemp = dest.getData();
+ int bytesRemaining = dest.size();
+
+ while (bytesRemaining > 0) {
+ int consumed = taf_append_buffer(taf, pTemp, bytesRemaining);
+ bytesRemaining -= consumed;
+ }
+
+ return true;
+#else
+ return true;
#endif
}