aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilippos Karapetis2009-02-19 17:40:55 +0000
committerFilippos Karapetis2009-02-19 17:40:55 +0000
commit6a0ffca914a019221460f005da3c51b46e443eb5 (patch)
tree1f9cb1e302d441f15d4712e22a93e6208f447454
parent6c1b9b6d956dae8c7683dff37008cb41a4f41815 (diff)
downloadscummvm-rg350-6a0ffca914a019221460f005da3c51b46e443eb5.tar.gz
scummvm-rg350-6a0ffca914a019221460f005da3c51b46e443eb5.tar.bz2
scummvm-rg350-6a0ffca914a019221460f005da3c51b46e443eb5.zip
Used the LZEXE unpacker from the teenagent engine. The SCI version detector now works with LZEXE packed executables too
svn-id: r38553
-rw-r--r--engines/sci/exereader.cpp342
1 files changed, 88 insertions, 254 deletions
diff --git a/engines/sci/exereader.cpp b/engines/sci/exereader.cpp
index 1ded9c1df6..0435f8c97f 100644
--- a/engines/sci/exereader.cpp
+++ b/engines/sci/exereader.cpp
@@ -24,38 +24,20 @@
*/
#include "common/endian.h"
+#include "common/util.h"
#include "sci/exereader.h"
#include "sci/include/versions.h"
//namespace Sci {
-#define VERSION_DETECT_BUF_SIZE 4096
-
-// LZEXE related defines
-// The LZEXE code is based on public domain code by Mitugu Kurizono
-
-/* The amount of most recent data (in bytes) that we need to keep in the
-** buffer. lzexe compression is based on copying chunks of previous data to
-** form new data.
-*/
-#define LZEXE_WINDOW VERSION_DETECT_BUF_SIZE * 2
-
-/* Buffer size. */
-#define LZEXE_BUFFER_SIZE VERSION_DETECT_BUF_SIZE * 3
-
-/* Maximum amount of data (in bytes) that can be in the buffer at the start
-** of the decompression loop. The maximum amount of data that can be added
-** to the buffer during a single step of the loop is 256 bytes.
-*/
-#define LZEXE_BUFFER_MAX (LZEXE_BUFFER_SIZE - 256)
-
-int curBits;
-byte lzexeBuf[2];
+int _bitCount;
+uint16 _bits;
bool isGameExe(Common::SeekableReadStream *exeStream) {
byte magic[4];
- if (exeStream->size() < VERSION_DETECT_BUF_SIZE)
+ // Make sure that the executable is at least 4KB big
+ if (exeStream->size() < 4096)
return false;
// Read exe header
@@ -169,90 +151,28 @@ bool isLZEXECompressed(Common::SeekableReadStream *exeStream) {
return true;
}
-byte getBitFromlzexe(Common::SeekableReadStream *exeStream) {
- byte result = lzexeBuf[1] & 1;
-
- if (--curBits == 0) {
- lzexeBuf[0] = exeStream->readByte();
- lzexeBuf[1] = exeStream->readByte();
- curBits = 16;
- } else {
- // Shift buffer to the right by 1 bit
- uint16 curBuffer = (lzexeBuf[0] << 8) | lzexeBuf[1];
- curBuffer >>= 1;
- lzexeBuf[0] = (curBuffer >> 8) & 0xFF;
- lzexeBuf[1] = curBuffer & 0xFF;
- }
-
- return result;
-}
-
-void readLzexe(Common::SeekableReadStream *exeStream, byte *buffer) {
- // TODO: finish this (from lzexe_read)
- printf("TODO: LZEXE support\n");
- return;
-#if 0
- int done = 0;
-
- while (done != VERSION_DETECT_BUF_SIZE) {
- int size, copy, i;
- int left = count - done;
-
- if (!lzexe_decompress(exeStream))
- return done;
+uint getBit(Common::SeekableReadStream *input) {
+ uint bit = _bits & 1;
+ _bitCount--;
- /* Total amount of bytes in buffer. */
- //size = handle->bufptr - handle->buffer;
+ if (_bitCount <= 0) {
+ _bits = input->readByte() | input->readByte() << 8;
- // If we're not at end of data we need to maintain the window
- if (!exeStream->eos())
- copy = size - LZEXE_WINDOW;
- else {
- if (size == 0)
- /* No data left. */
- return done;
-
- copy = size;
+ if (_bitCount == -1) { /* special case for first bit word */
+ bit = _bits & 1;
+ _bits >>= 1;
}
- /* Do not copy more than requested. */
- if (copy > left)
- copy = left;
-
- memcpy((char *) buffer + done, handle->buffer, copy);
-
- /* Move remaining data to start of buffer. */
- for (i = copy; i < size; i++)
- handle->buffer[i - copy] = handle->buffer[i];
-
- handle->bufptr -= copy;
- done += copy;
- }
-
- return done;
-#endif
-}
-
-void readExe(Common::SeekableReadStream *exeStream, byte *buffer) {
- bool isLZEXE = isLZEXECompressed(exeStream);
-
- if (!isLZEXE) {
- // Read the last VERSION_DETECT_BUF_SIZE bytes
- exeStream->seek(exeStream->size() - VERSION_DETECT_BUF_SIZE, SEEK_SET);
- exeStream->read(buffer, VERSION_DETECT_BUF_SIZE);
- } else {
- // Read the two initial bytes
- lzexeBuf[0] = exeStream->readByte();
- lzexeBuf[1] = exeStream->readByte();
-
- curBits = 16;
+ _bitCount += 16;
+ } else
+ _bits >>= 1;
- readLzexe(exeStream, buffer);
- }
+ return bit;
}
bool readSciVersionFromExe(Common::SeekableReadStream *exeStream, int *version) {
- byte buffer[VERSION_DETECT_BUF_SIZE];
+ int len = exeStream->size();
+ unsigned char *buffer = NULL;
char result_string[10]; /* string-encoded result, copied from buf */
int state = 0;
/* 'state' encodes how far we have matched the version pattern
@@ -267,15 +187,77 @@ bool readSciVersionFromExe(Common::SeekableReadStream *exeStream, int *version)
** character.
*/
- readExe(exeStream, buffer);
+ // Read the executable
+ bool isLZEXE = isLZEXECompressed(exeStream);
+
+ if (!isLZEXE) {
+ buffer = new unsigned char[exeStream->size()];
+
+ exeStream->seek(0, SEEK_SET);
+ exeStream->read(buffer, exeStream->size());
+ } else {
+ buffer = new unsigned char[exeStream->size() * 3];
+
+ // Skip LZEXE header
+ exeStream->seek(32, SEEK_SET);
+
+ int pos = 0;
+ int repeat;
+ short offset;
+
+ while (1) {
+ if (exeStream->ioFailed()) {
+ warning("Error reading from input file");
+ delete[] buffer;
+ return false;
+ }
+
+ if (getBit(exeStream)) {
+ buffer[pos++] = exeStream->readByte();
+ } else {
+ if (getBit(exeStream)) {
+ byte tmp[2];
+ exeStream->read(tmp, 2);
+ repeat = (tmp[1] & 0x07);
+ offset = ((tmp[1] & ~0x07) << 5) | tmp[0] | 0xE000;
+
+ if (repeat == 0) {
+ repeat = exeStream->readByte();
+
+ if (repeat == 0) {
+ len = pos;
+ break;
+ }
+ else if (repeat == 1)
+ continue;
+ else
+ repeat++;
+ } else
+ repeat += 2;
+ } else {
+ repeat = ((getBit(exeStream) << 1) | getBit(exeStream)) + 2;
+ offset = exeStream->readByte() | 0xFF00;
+ }
+
+ while (repeat > 0) {
+ buffer[pos] = buffer[pos + offset];
+ pos++;
+ repeat--;
+ }
+ }
+ }
+ }
+
+ // Find SCI version number
int accept;
+ unsigned char *buf = buffer;
- for (int i = 0; i < VERSION_DETECT_BUF_SIZE; i++) {
- const char ch = buffer[i];
- accept = 0; /* By default, we don't like this character */
+ for (int i = 0; i < len; i++) {
+ unsigned char ch = *buf++;
+ accept = 0; // By default, we don't like this character
- if (isalnum((unsigned char) ch)) {
+ if (isalnum(ch)) {
accept = (state != 1
&& state != 5
&& state != 9);
@@ -286,6 +268,7 @@ bool readSciVersionFromExe(Common::SeekableReadStream *exeStream, int *version)
result_string[9] = 0; /* terminate string */
if (!version_parse(result_string, version)) {
+ delete[] buffer;
return true; // success
}
@@ -298,157 +281,8 @@ bool readSciVersionFromExe(Common::SeekableReadStream *exeStream, int *version)
state = 0;
}
+ delete[] buffer;
return false; // failure
}
-#if 0
-//TODO
-// Code from exe_lzexe.cpp (left for reference, to be converted)
-
-static int
-lzexe_decompress(exe_handle_t *handle) {
- while (!handle->eod
- && handle->bufptr - handle->buffer <= LZEXE_BUFFER_MAX) {
- int bit;
- int len, span;
-
- if (!lzexe_get_bit(handle, &bit))
- return 0;
-
- if (bit) {
- /* 1: copy byte verbatim. */
-
- int data;
-
- if (!lzexe_read_uint8(handle->f, &data))
- return 0;
-
- *handle->bufptr++ = data;
-
- continue;
- }
-
- if (!lzexe_get_bit(handle, &bit))
- return 0;
-
- if (!bit) {
- /* 00: copy small block. */
-
- /* Next two bits indicate block length - 2. */
- if (!lzexe_get_bit(handle, &bit))
- return 0;
-
- len = bit << 1;
-
- if (!lzexe_get_bit(handle, &bit))
- return 0;
-
- len |= bit;
- len += 2;
-
- /* Read span byte. This forms the low byte of a
- ** negative two's compliment value.
- */
- if (!lzexe_read_uint8(handle->f, &span))
- return 0;
-
- /* Convert to negative integer. */
- span -= 256;
- } else {
- /* 01: copy large block. */
- int data;
-
- /* Read low byte of span value. */
- if (!lzexe_read_uint8(handle->f, &span))
- return 0;
-
- /* Read next byte. Bits [7..3] contain bits [12..8]
- ** of span value. Bits [2..0] contain block length -
- ** 2.
- */
- if (!lzexe_read_uint8(handle->f, &data))
- return 0;
- span |= (data & 0xf8) << 5;
- /* Convert to negative integer. */
- span -= 8192;
-
- len = (data & 7) + 2;
-
- if (len == 2) {
- /* Next byte is block length value - 1. */
- if (!lzexe_read_uint8(handle->f, &len))
- return 0;
-
- if (len == 0) {
- /* End of data reached. */
- handle->eod = 1;
- break;
- }
-
- if (len == 1)
- /* Segment change marker. */
- continue;
-
- len++;
- }
- }
-
- assert(handle->bufptr + span >= handle->buffer);
-
- /* Copy block. */
- while (len-- > 0) {
- *handle->bufptr = *(handle->bufptr + span);
- handle->bufptr++;
- }
- }
-
- return 1;
-}
-
-static int
-lzexe_read(exe_handle_t *handle, void *buf, int count) {
- int done = 0;
-
- while (done != count) {
- int size, copy, i;
- int left = count - done;
-
- if (!lzexe_decompress(handle))
- return done;
-
- /* Total amount of bytes in buffer. */
- size = handle->bufptr - handle->buffer;
-
- /* If we're not at end of data we need to maintain the
- ** window.
- */
- if (!handle->eod)
- copy = size - LZEXE_WINDOW;
- else {
- if (size == 0)
- /* No data left. */
- return done;
-
- copy = size;
- }
-
- /* Do not copy more than requested. */
- if (copy > left)
- copy = left;
-
- memcpy((char *) buf + done, handle->buffer, copy);
-
- /* Move remaining data to start of buffer. */
- for (i = copy; i < size; i++)
- handle->buffer[i - copy] = handle->buffer[i];
-
- handle->bufptr -= copy;
- done += copy;
- }
-
- return done;
-}
-
-#endif
-
//} // End of namespace Sci