diff options
-rw-r--r-- | engines/sci/detection.cpp | 46 | ||||
-rw-r--r-- | engines/sci/exereader.cpp | 451 | ||||
-rw-r--r-- | engines/sci/exereader.h (renamed from engines/sci/scicore/exe_raw.cpp) | 45 | ||||
-rw-r--r-- | engines/sci/include/versions.h | 6 | ||||
-rw-r--r-- | engines/sci/module.mk | 4 | ||||
-rw-r--r-- | engines/sci/scicore/exe.cpp | 80 | ||||
-rw-r--r-- | engines/sci/scicore/exe.h | 58 | ||||
-rw-r--r-- | engines/sci/scicore/exe_dec.h | 64 | ||||
-rw-r--r-- | engines/sci/scicore/exe_lzexe.cpp | 328 | ||||
-rw-r--r-- | engines/sci/scicore/versions.cpp | 190 |
10 files changed, 499 insertions, 773 deletions
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index 61139122d2..90f8954c33 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -27,6 +27,7 @@ #include "base/plugins.h" #include "sci/sci.h" +#include "sci/exereader.h" #include "sci/include/versions.h" // Titles of the games @@ -1053,7 +1054,7 @@ static const struct SciGameDescription SciGameDescriptions[] = { {}, SCI_VERSION(0, 000, 000) // FIXME: add version here }, -#if 0 + // Space Quest 1 VGA Remake - English Amiga (from www.back2roots.org) {{"sq1sci", "VGA Remake", { {"resource.map", 0, "106484b372af1d4cbf866472cc2813dc", 6396}, @@ -1094,7 +1095,7 @@ static const struct SciGameDescription SciGameDescriptions[] = { {}, SCI_VERSION(1, 000, 510) }, -#endif + // Space Quest 3 - English Amiga (from www.back2roots.org) {{"sq3", "", { {"resource.map", 0, "bad41385acde6d677a8d55a7b20437e3", 5868}, @@ -1387,6 +1388,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl int exeVersion = 0; bool foundResMap = false; bool foundRes000 = false; + bool foundExe = false; // First grab all filenames for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { @@ -1401,18 +1403,46 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl || filename.contains("ressci.000") || filename.contains("ressci.001")) foundRes000 = true; - // FIXME: This is all quite hackish + // Check if it's a known executable name if (filename.contains("scidhuv") || filename.contains("sciv") || filename.contains("sierra") || filename.contains("sciw")) { - exeVersion = version_detect_from_executable((char *)file->getPath().c_str()); - break; - } + // Is it really an executable file? + Common::SeekableReadStream *fileStream = file->createReadStream(); + bool isExe = isGameExe(fileStream); + int exeVersion = -1; + + if (isExe) { + if (!readSciVersionFromExe(fileStream, &exeVersion)) { + printf("Error while reading SCI version from the game executable\n"); + delete fileStream; + return 0; + } else { + // All ok, we got the version from the executable successfully + foundExe = true; + delete fileStream; + break; + } + } else { + printf("The original game executable seems to be corrupted\n"); + delete fileStream; + return 0; + } + + } + } + if (!foundExe) { + printf("The original game executable wasn't found\n"); + return 0; + } + // If these files aren't found, it can't be SCI - if (!foundResMap && !foundRes000) + if (!foundResMap && !foundRes000) { + printf("Necessary data files are missing, or this isn't a SCI game\n"); return 0; - + } + // Set some defaults g_fallbackDesc.desc.gameid = "sci"; g_fallbackDesc.desc.extra = ""; diff --git a/engines/sci/exereader.cpp b/engines/sci/exereader.cpp new file mode 100644 index 0000000000..111e1f2931 --- /dev/null +++ b/engines/sci/exereader.cpp @@ -0,0 +1,451 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "common/endian.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]; + +bool isGameExe(Common::SeekableReadStream *exeStream) { + byte magic[4]; + if (exeStream->size() < VERSION_DETECT_BUF_SIZE) + return false; + + // Read exe header + exeStream->read(magic, 4); + + // Check if the header contains known magic bytes + + // Information obtained from http://magicdb.org/magic.db + // Check if it's a DOS executable + if (magic[0] == 'M' && magic[1] == 'Z') { + return true; + } + + // Check if it's an Amiga executable + if ((magic[0] == 0x03 && magic[1] == 0xF3) || + (magic[0] == 0x7F && magic[1] == 'E' && magic[2] == 'L' && magic[3] == 'F')) { + return true; + } + + // Check if it's an Atari executable + if ((magic[0] == 0x60 && magic[1] == 0x1A)) + return true; + + // Check if it's a Mac exe + // Is there a better way to do this? + int32 offset = MKID_BE(magic) + 28; // Resource map offset + if (exeStream->size() <= offset) + return false; + + // Skip number of types in map + exeStream->skip(2); + uint16 val = exeStream->readUint16BE() + 1; + + // Keep reading till we find the "CODE" bit + while (!exeStream->eos()) { + exeStream->skip(4); + if (exeStream->eos()) + return false; + + exeStream->read(magic, 4); + if (exeStream->eos()) + return false; + + if (!memcmp(magic, "CODE", 4)) { + return true; + } + // Skip to the next list entry + exeStream->skip(4); + if (exeStream->eos()) + return false; + } + + // If we've reached here, the file type is unknown + return false; +} + +bool isLZEXECompressed(Common::SeekableReadStream *exeStream) { + uint32 filepos = 0; + + exeStream->seek(0, SEEK_SET); + + // First 2 bytes should be "MZ" (0x5A4D) + if (exeStream->readUint16LE() != 0x5A4D) // at pos 0, +2 + return false; + + exeStream->skip(6); + + // Header size should be 2 + filepos = exeStream->readUint16LE(); + if (filepos != 2) // at pos 8, +2 + return false; + + exeStream->skip(12); + + // Calculate code segment offset in exe file + filepos += exeStream->readUint16LE(); // at pos 22, +2 + + // First relocation item offset should be 0x1c + if (exeStream->readUint16LE() != 0x1c) // at pos 24, +2 + return false; + + // Number of overlays should be 0 + if (exeStream->readUint16LE() != 0) // at pos 26, +2 + return false; + + // Look for LZEXE signature + byte magic[4]; + exeStream->read(magic, 4); + + if (memcmp(magic, "LZ09", 4) && memcmp(magic, "LZ91", 4)) + return false; + + // Seek to offset 8 of info table at start of code segment + exeStream->seek(filepos + 8, SEEK_SET); + if (exeStream->err()) + return false; + + // Read size of compressed data in paragraphs + uint16 size = exeStream->readUint16LE(); + + // Move file pointer to start of compressed data + filepos -= size << 4; + exeStream->seek(filepos, SEEK_SET); + if (exeStream->err()) + return false; + + // All conditions met, this is an LZEXE packed file + // We are currently at the start of the compressed file data + 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; + + /* 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 (!exeStream->eos()) + 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 *) 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) { + exeStream->seek(0, 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; + + readLzexe(exeStream, buffer); + } +} + +bool readSciVersionFromExe(Common::SeekableReadStream *exeStream, int *version) { + byte buffer[VERSION_DETECT_BUF_SIZE]; + char result_string[10]; /* string-encoded result, copied from buf */ + int state = 0; + /* 'state' encodes how far we have matched the version pattern + ** "n.nnn.nnn" + ** + ** n.nnn.nnn + ** 0123456789 + ** + ** Since we cannot be certain that the pattern does not begin with an + ** alphanumeric character, some states are ambiguous. + ** The pattern is expected to be terminated with a non-alphanumeric + ** character. + */ + + readExe(exeStream, buffer); + + int accept; + + 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 */ + + if (isalnum((unsigned char) ch)) { + accept = (state != 1 + && state != 5 + && state != 9); + } else if (ch == '.') { + accept = (state == 1 + || state == 5); + } else if (state == 9) { + result_string[9] = 0; /* terminate string */ + + if (!version_parse(result_string, version)) { + return true; // success + } + + // Continue searching + } + + if (accept) + result_string[state++] = ch; + else + state = 0; + } + + 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 diff --git a/engines/sci/scicore/exe_raw.cpp b/engines/sci/exereader.h index 69daaca45f..32f070a59a 100644 --- a/engines/sci/scicore/exe_raw.cpp +++ b/engines/sci/exereader.h @@ -23,44 +23,17 @@ * */ -#include "sci/include/sci_memory.h" +#ifndef EXEREADER_H +#define EXEREADER_H -struct _exe_handle { - FILE *f; -}; +#include "common/file.h" +#include "common/str.h" -#include "sci/scicore/exe_dec.h" +//namespace Sci { -static exe_handle_t * -raw_open(const char *filename) { - FILE *f = fopen(filename, "rb"); - exe_handle_t *handle; +bool isGameExe(Common::SeekableReadStream *exeStream); +bool readSciVersionFromExe(Common::SeekableReadStream *exeStream, int *version); - if (!f) - return NULL; +//} // End of namespace Sci - handle = (exe_handle_t*)sci_malloc(sizeof(exe_handle_t)); - handle->f = f; - - return handle; -} - -static int -raw_read(exe_handle_t *handle, void *buf, int count) { - return fread(buf, 1, count, handle->f); -} - -static void -raw_close(exe_handle_t *handle) { - fclose(handle->f); - - free(handle); -} - -exe_decompressor_t -exe_decompressor_raw = { - "raw", - raw_open, - raw_read, - raw_close -}; +#endif // SCI_H diff --git a/engines/sci/include/versions.h b/engines/sci/include/versions.h index 15c7e332e9..c18840598a 100644 --- a/engines/sci/include/versions.h +++ b/engines/sci/include/versions.h @@ -147,10 +147,4 @@ version_parse(const char *vn, sci_version_t *result); ** (sci_version_t) *result: The resulting version number on success */ -int -version_detect_from_executable(char *filename); -/* Try to detect version from Sierra executable in cwd -** Returns : (int) The version number detected, or 0 if we weren't successful -*/ - #endif /* !_SCI_VERSIONS_H_ */ diff --git a/engines/sci/module.mk b/engines/sci/module.mk index 9cb5241b3d..9911375eb3 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -2,6 +2,7 @@ MODULE := engines/sci MODULE_OBJS = \ detection.o \ + exereader.o \ sci.o \ engine/game.o \ engine/gc.o \ @@ -55,9 +56,6 @@ MODULE_OBJS = \ scicore/decompress01.o \ scicore/decompress1.o \ scicore/decompress11.o \ - scicore/exe.o \ - scicore/exe_lzexe.o \ - scicore/exe_raw.o \ scicore/resource.o \ scicore/resource_map.o \ scicore/resource_patch.o \ diff --git a/engines/sci/scicore/exe.cpp b/engines/sci/scicore/exe.cpp deleted file mode 100644 index 518818ff33..0000000000 --- a/engines/sci/scicore/exe.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* 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. - * - * $URL$ - * $Id$ - * - */ - -#include "sci/include/sci_memory.h" - -#include "sci/scicore/exe.h" -#include "sci/scicore/exe_dec.h" - -extern exe_decompressor_t exe_decompressor_lzexe; -extern exe_decompressor_t exe_decompressor_raw; - -exe_decompressor_t *exe_decompressors[] = { - &exe_decompressor_lzexe, - &exe_decompressor_raw, - NULL -}; - -struct _exe_file { - struct _exe_decompressor *decompressor; - struct _exe_handle *handle; -}; - -exe_file_t * -exe_open(const char *filename) { - int i = 0; - exe_decompressor_t *dec; - - while ((dec = exe_decompressors[i])) { - exe_handle_t *handle = dec->open(filename); - - if (handle) { - exe_file_t *file = (exe_file_t*)sci_malloc(sizeof(exe_file_t)); - - sciprintf("Scanning '%s' with decompressor '%s'\n", - filename, dec->name); - - file->handle = handle; - file->decompressor = dec; - return file; - } - - i++; - } - - return NULL; -} - -int -exe_read(exe_file_t *file, void *buf, int count) { - return file->decompressor->read(file->handle, buf, count); -} - -void -exe_close(exe_file_t *file) { - file->decompressor->close(file->handle); - - free(file); -} diff --git a/engines/sci/scicore/exe.h b/engines/sci/scicore/exe.h deleted file mode 100644 index db40d3689c..0000000000 --- a/engines/sci/scicore/exe.h +++ /dev/null @@ -1,58 +0,0 @@ -/* 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. - * - * $URL$ - * $Id$ - * - */ - -#ifndef _SCI_EXE_H_ -#define _SCI_EXE_H_ - -typedef struct _exe_file exe_file_t; - -exe_file_t * -exe_open(const char *filename); -/* Opens an executable file -** Parameters: (const char *) filename: Filename of executable to open -** Returns : (exe_file_t *) File handle, or NULL on error -** This function will try to find a decompressor that can handle this type -** of executable -*/ - -int -exe_read(exe_file_t *file, void *buf, int count); -/* Reads from an executable file -** Parameters: (exe_file_t *) file: File handle -** (void *) buf: Buffer to store decompressed data -** (int) count: Size of decompressed data requested, in bytes -** Returns : (int) Number of bytes of decompressed data that was stored in -** buf. If this value is less than count an error has -** occured, or end-of-file was reached. -*/ - -void -exe_close(exe_file_t *handle); -/* Closes an executable file -** Parameters: (exe_file_t *) file: File handle -** Returns : (void) -*/ - -#endif /* !_SCI_EXE_H_ */ diff --git a/engines/sci/scicore/exe_dec.h b/engines/sci/scicore/exe_dec.h deleted file mode 100644 index 45c1f58382..0000000000 --- a/engines/sci/scicore/exe_dec.h +++ /dev/null @@ -1,64 +0,0 @@ -/* 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. - * - * $URL$ - * $Id$ - * - */ - -#ifndef _SCI_EXE_DEC_H_ -#define _SCI_EXE_DEC_H_ - -typedef struct _exe_handle exe_handle_t; - -typedef struct _exe_decompressor { - const char *name; /* Decompressor name. Unique identifier, should consist - ** of lower-case (where applicable) alphanumerics - */ - - exe_handle_t * (*open)(const char *filename); - /* Opens an executable file - ** Parameters: (const char *) filename: Filename of executable to open. - ** Returns : (exe_handle_t *) Decompressor file handle, or NULL on - ** error. - ** This function will verify that the file can be handled by the - ** decompressor. If this is not the case the function will fail. - */ - - int (*read)(exe_handle_t *handle, void *buf, int count); - /* Reads from executable file - ** Parameters: (exe_handle_t *) handle: Decompressor file handle. - ** (void *) buf: Buffer to store decompressed data. - ** (int) count: Size of decompressed data requested, in - ** bytes. - ** Returns : (int) Number of bytes of decompressed data that was - ** stored in buf. If this value is less than count - ** an error has occured, or end-of-file was - ** reached. - */ - - void (*close)(exe_handle_t *handle); - /* Closes a decompressor file handle. - ** Parameters: (exe_handle_t *) handle: Decompressor file handle. - ** Returns : (void) - */ -} exe_decompressor_t; - -#endif /* !_SCI_EXE_DEC_H_ */ diff --git a/engines/sci/scicore/exe_lzexe.cpp b/engines/sci/scicore/exe_lzexe.cpp deleted file mode 100644 index a7a1c31a08..0000000000 --- a/engines/sci/scicore/exe_lzexe.cpp +++ /dev/null @@ -1,328 +0,0 @@ -/* 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. - * - * $URL$ - * $Id$ - * - */ - -/* Based on public domain code by Mitugu Kurizono. */ - -#include "sci/include/sci_memory.h" -#include "sci/scicore/exe_dec.h" - -/* Macro to interpret two sequential bytes as an unsigned integer. */ -#define UINT16(A) ((*((A) + 1) << 8) + *(A)) - -/* 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 8192 - -/* Buffer size. */ -#define LZEXE_BUFFER_SIZE (LZEXE_WINDOW + 4096) - -/* 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) - -struct _exe_handle { - FILE *f; - - /* Output buffer. */ - guint8 buffer[LZEXE_BUFFER_SIZE]; - guint8 *bufptr; - - /* Bit buffer. Bits [0..count) still contain unprocessed data. */ - int buf; - int count; - - /* End of data flag. */ - int eod; -}; - -static int -lzexe_read_uint16(FILE *f, int *value) { - int data; - - if ((*value = fgetc(f)) == EOF) - return 0; - - if ((data = fgetc(f)) == EOF) - return 0; - - *value |= data << 8; - return 1; -} - -static int -lzexe_read_uint8(FILE *f, int *value) { - if ((*value = fgetc(f)) == EOF) - return 0; - - return 1; -} - -static int -lzexe_init(exe_handle_t *handle, FILE *f) { - handle->f = f; - handle->bufptr = handle->buffer; - handle->eod = 0; - - if (!lzexe_read_uint16(handle->f, &handle->buf)) - return 0; - - handle->count = 16; - return 1; -} - -static int -lzexe_get_bit(exe_handle_t *handle, int *bit) { - *bit = handle->buf & 1; - - if (--handle->count == 0) { - if (!lzexe_read_uint16(handle->f, &handle->buf)) - return 0; - handle->count = 16; - } else - handle->buf >>= 1; - - return 1; -} - -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 exe_handle_t * -lzexe_open(const char *filename) { - exe_handle_t *handle; - guint8 head[0x20]; - guint8 size[2]; - off_t fpos; - - FILE *f = fopen(filename, "rb"); - - if (!f) - return NULL; - - /* Read exe header plus possible lzexe signature. */ - if (fread(head, 1, 0x20, f) != 0x20) - return NULL; - - /* Verify "MZ" signature, header size == 2 paragraphs and number of - ** overlays == 0. - */ - if (UINT16(head) != 0x5a4d || UINT16(head + 8) != 2 - || UINT16(head + 0x1a) != 0) - return NULL; - - /* Verify that first relocation item offset is 0x1c. */ - if (UINT16(head + 0x18) != 0x1c) - return NULL; - - /* Look for lzexe signature. */ - if (memcmp(head + 0x1c, "LZ09", 4) - && memcmp(head + 0x1c, "LZ91", 4)) { - return NULL; - } - - /* Calculate code segment offset in exe file. */ - fpos = (UINT16(head + 0x16) + UINT16(head + 8)) << 4; - /* Seek to offset 8 of info table at start of code segment. */ - if (fseek(f, fpos + 8, SEEK_SET) == -1) - return NULL; - - /* Read size of compressed data in paragraphs. */ - if (fread(size, 1, 2, f) != 2) - return NULL; - - /* Move file pointer to start of compressed data. */ - fpos -= UINT16(size) << 4; - if (fseek(f, fpos, SEEK_SET) == -1) - return NULL; - - handle = (exe_handle_t*)sci_malloc(sizeof(exe_handle_t)); - - if (!lzexe_init(handle, f)) { - free(handle); - return NULL; - } - - return handle; -} - -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; -} - -static void -lzexe_close(exe_handle_t *handle) { - fclose(handle->f); - - free(handle); -} - -exe_decompressor_t -exe_decompressor_lzexe = { - "lzexe", - lzexe_open, - lzexe_read, - lzexe_close -}; diff --git a/engines/sci/scicore/versions.cpp b/engines/sci/scicore/versions.cpp index 6680fcb430..e05106ce88 100644 --- a/engines/sci/scicore/versions.cpp +++ b/engines/sci/scicore/versions.cpp @@ -31,7 +31,6 @@ #include "sci/include/versions.h" #include "sci/include/engine.h" #include "sci/include/resource.h" -#include "sci/scicore/exe.h" // for reading version from the executable void version_require_earlier_than(state_t *s, sci_version_t version) { @@ -88,193 +87,4 @@ version_parse(const char *vn, sci_version_t *result) { return 0; } -// Exe scanning functions - -/* Maxmimum number of bytes to hash from start of file */ -#define VERSION_DETECT_HASH_SIZE 1000000 - -#define VERSION_DETECT_BUF_SIZE 4096 - -static int -scan_file(char *filename, sci_version_t *version) { - char buf[VERSION_DETECT_BUF_SIZE]; - char result_string[10]; /* string-encoded result, copied from buf */ - int characters_left; - int state = 0; - /* 'state' encodes how far we have matched the version pattern - ** "n.nnn.nnn" - ** - ** n.nnn.nnn - ** 0123456789 - ** - ** Since we cannot be certain that the pattern does not begin with an - ** alphanumeric character, some states are ambiguous. - ** The pattern is expected to be terminated with a non-alphanumeric - ** character. - */ - - exe_file_t *f = exe_open(filename); - - if (!f) - return 1; - - do { - int i; - int accept; - - characters_left = exe_read(f, buf, VERSION_DETECT_BUF_SIZE); - - for (i = 0; i < characters_left; i++) { - const char ch = buf[i]; - accept = 0; /* By default, we don't like this character */ - - if (isalnum((unsigned char) ch)) { - accept = (state != 1 - && state != 5 - && state != 9); - } else if (ch == '.') { - accept = (state == 1 - || state == 5); - } else if (state == 9) { - result_string[9] = 0; /* terminate string */ - - if (!version_parse(result_string, version)) { - exe_close(f); - return 0; /* success! */ - } - - /* Continue searching. */ - } - - if (accept) - result_string[state++] = ch; - else - state = 0; - - } - - } while (characters_left == VERSION_DETECT_BUF_SIZE); - - exe_close(f); - return 1; /* failure */ -} - -static guint32 -read_uint32(byte *data) { - return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; -} - -static guint16 -read_uint16(byte *data) { - return (data[0] << 8) | data[1]; -} - -static int -is_mac_exe(char *filename) { - FILE *file; - byte buf[4]; - guint32 val; - unsigned int i; - - /* Mac executables have no extension */ - if (strchr(filename, '.')) - return 0; - - file = fopen(filename, "rb"); - if (!file) - return 0; - - if (fseek(file, 4, SEEK_SET) == -1) { - fclose(file); - return 0; - } - - /* Read resource map offset */ - if (fread(buf, 1, 4, file) < 4) { - fclose(file); - return 0; - } - - val = read_uint32(buf); - - if (fseek(file, val + 28, SEEK_SET) == -1) { - fclose(file); - return 0; - } - - /* Read number of types in map */ - if (fread(buf, 1, 2, file) < 2) { - fclose(file); - return 0; - } - - val = read_uint16(buf) + 1; - - for (i = 0; i < val; i++) { - if (fread(buf, 1, 4, file) < 4) { - fclose(file); - return 0; - } - - /* Look for executable code */ - if (!memcmp(buf, "CODE", 4)) { - fclose(file); - return 1; - } - - /* Skip to next list entry */ - if (fseek(file, 4, SEEK_CUR) == -1) { - fclose(file); - return 0; - } - } - - fclose(file); - return 0; -} - -static int -is_exe(char *filename) { - FILE *file; - char buf[4]; - unsigned char header[] = {0x00, 0x00, 0x03, 0xf3}; - - /* PC and Atari ST executable extensions */ - if (strstr(filename, ".exe") || strstr(filename, ".EXE") - || strstr(filename, ".prg") || strstr(filename, ".PRG")) - return 1; - - /* Check for Amiga executable */ - if (strchr(filename, '.')) - return 0; - - file = fopen(filename, "rb"); - if (!file) - return 0; - - if (fread(buf, 1, 4, file) < 4) { - fclose(file); - return 0; - } - - fclose(file); - - /* Check header bytes */ - return memcmp(buf, header, 4) == 0; -} - -int -version_detect_from_executable(char *filename) { - int mac = 0; - int result; - - if (mac ? is_mac_exe(filename) : is_exe(filename)) { - if (scan_file(filename, &result) == 0) { - return result; - } - } - - return 0; -} - #undef VERSION_DETECT_BUF_SIZE |