aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/macresman.cpp138
-rw-r--r--common/macresman.h11
-rw-r--r--common/module.mk4
-rw-r--r--common/ne_exe.cpp612
-rw-r--r--common/winexe.cpp84
-rw-r--r--common/winexe.h74
-rw-r--r--common/winexe_ne.cpp291
-rw-r--r--common/winexe_ne.h (renamed from common/ne_exe.h)100
-rw-r--r--common/winexe_pe.cpp255
-rw-r--r--common/winexe_pe.h122
-rw-r--r--engines/mohawk/cursors.cpp224
-rw-r--r--engines/mohawk/cursors.h41
-rw-r--r--engines/mohawk/riven.cpp30
-rw-r--r--engines/mohawk/riven_cursors.h670
-rw-r--r--engines/mohawk/riven_external.cpp38
-rw-r--r--engines/mohawk/riven_scripts.cpp1
-rw-r--r--engines/sci/graphics/cursor.cpp12
-rw-r--r--engines/scumm/he/resource_he.cpp1108
-rw-r--r--engines/scumm/he/resource_he.h381
-rw-r--r--graphics/fonts/winfont.cpp89
-rw-r--r--graphics/fonts/winfont.h4
-rw-r--r--graphics/module.mk3
-rw-r--r--graphics/wincursor.cpp317
-rw-r--r--graphics/wincursor.h105
24 files changed, 1637 insertions, 3077 deletions
diff --git a/common/macresman.cpp b/common/macresman.cpp
index 4fd4e72ee3..e7d4a30789 100644
--- a/common/macresman.cpp
+++ b/common/macresman.cpp
@@ -550,118 +550,110 @@ void MacResManager::readMap() {
}
}
-void MacResManager::convertCrsrCursor(byte *data, int datasize, byte **cursor, int *w, int *h,
- int *hotspot_x, int *hotspot_y, int *keycolor, bool colored, byte **palette, int *palSize) {
- MemoryReadStream dis(data, datasize);
- int i, b;
- byte imageByte;
- byte *iconData;
- int pixelsPerByte, bpp;
- int ctSize;
- byte bitmask;
- int iconRowBytes, iconBounds[4];
- int iconDataSize;
-
- dis.readUint16BE(); // type
- dis.readUint32BE(); // offset to pixel map
- dis.readUint32BE(); // offset to pixel data
- dis.readUint32BE(); // expanded cursor data
- dis.readUint16BE(); // expanded data depth
- dis.readUint32BE(); // reserved
+void MacResManager::convertCrsrCursor(SeekableReadStream *data, byte **cursor, int &w, int &h, int &hotspotX,
+ int &hotspotY, int &keycolor, bool colored, byte **palette, int &palSize) {
+
+ data->readUint16BE(); // type
+ data->readUint32BE(); // offset to pixel map
+ data->readUint32BE(); // offset to pixel data
+ data->readUint32BE(); // expanded cursor data
+ data->readUint16BE(); // expanded data depth
+ data->readUint32BE(); // reserved
// Grab B/W icon data
- *cursor = (byte *)malloc(16 * 16);
- for (i = 0; i < 32; i++) {
- imageByte = dis.readByte();
- for (b = 0; b < 8; b++)
- cursor[0][i*8+b] = (byte)((imageByte & (0x80 >> b)) > 0? 0x0F: 0x00);
+ *cursor = new byte[16 * 16];
+ for (int i = 0; i < 32; i++) {
+ byte imageByte = data->readByte();
+ for (int b = 0; b < 8; b++)
+ cursor[0][i * 8 + b] = (byte)((imageByte & (0x80 >> b)) > 0 ? 0x0F : 0x00);
}
// Apply mask data
- for (i = 0; i < 32; i++) {
- imageByte = dis.readByte();
- for (b = 0; b < 8; b++)
+ for (int i = 0; i < 32; i++) {
+ byte imageByte = data->readByte();
+ for (int b = 0; b < 8; b++)
if ((imageByte & (0x80 >> b)) == 0)
- cursor[0][i*8+b] = 0xff;
+ cursor[0][i * 8 + b] = 0xff;
}
- *hotspot_y = dis.readUint16BE();
- *hotspot_x = dis.readUint16BE();
- *w = *h = 16;
- *keycolor = 0xff;
+ hotspotY = data->readUint16BE();
+ hotspotX = data->readUint16BE();
+ w = h = 16;
+ keycolor = 0xff;
// Use b/w cursor on backends which don't support cursor palettes
if (!colored)
return;
- dis.readUint32BE(); // reserved
- dis.readUint32BE(); // cursorID
+ data->readUint32BE(); // reserved
+ data->readUint32BE(); // cursorID
// Color version of cursor
- dis.readUint32BE(); // baseAddr
+ data->readUint32BE(); // baseAddr
// Keep only lowbyte for now
- dis.readByte();
- iconRowBytes = dis.readByte();
+ data->readByte();
+ int iconRowBytes = data->readByte();
if (!iconRowBytes)
return;
- iconBounds[0] = dis.readUint16BE();
- iconBounds[1] = dis.readUint16BE();
- iconBounds[2] = dis.readUint16BE();
- iconBounds[3] = dis.readUint16BE();
+ int iconBounds[4];
+ iconBounds[0] = data->readUint16BE();
+ iconBounds[1] = data->readUint16BE();
+ iconBounds[2] = data->readUint16BE();
+ iconBounds[3] = data->readUint16BE();
- dis.readUint16BE(); // pmVersion
- dis.readUint16BE(); // packType
- dis.readUint32BE(); // packSize
+ data->readUint16BE(); // pmVersion
+ data->readUint16BE(); // packType
+ data->readUint32BE(); // packSize
- dis.readUint32BE(); // hRes
- dis.readUint32BE(); // vRes
+ data->readUint32BE(); // hRes
+ data->readUint32BE(); // vRes
- dis.readUint16BE(); // pixelType
- dis.readUint16BE(); // pixelSize
- dis.readUint16BE(); // cmpCount
- dis.readUint16BE(); // cmpSize
+ data->readUint16BE(); // pixelType
+ data->readUint16BE(); // pixelSize
+ data->readUint16BE(); // cmpCount
+ data->readUint16BE(); // cmpSize
- dis.readUint32BE(); // planeByte
- dis.readUint32BE(); // pmTable
- dis.readUint32BE(); // reserved
+ data->readUint32BE(); // planeByte
+ data->readUint32BE(); // pmTable
+ data->readUint32BE(); // reserved
// Pixel data for cursor
- iconDataSize = iconRowBytes * (iconBounds[3] - iconBounds[1]);
- iconData = (byte *)malloc(iconDataSize);
- dis.read(iconData, iconDataSize);
+ int iconDataSize = iconRowBytes * (iconBounds[3] - iconBounds[1]);
+ byte *iconData = new byte[iconDataSize];
+ data->read(iconData, iconDataSize);
// Color table
- dis.readUint32BE(); // ctSeed
- dis.readUint16BE(); // ctFlag
- ctSize = dis.readUint16BE() + 1;
+ data->readUint32BE(); // ctSeed
+ data->readUint16BE(); // ctFlag
+ uint16 ctSize = data->readUint16BE() + 1;
- *palette = (byte *)malloc(ctSize * 3);
+ *palette = new byte[ctSize * 3];
// Read just high byte of 16-bit color
for (int c = 0; c < ctSize; c++) {
// We just use indices 0..ctSize, so ignore color ID
- dis.readUint16BE(); // colorID[c]
+ data->readUint16BE(); // colorID[c]
- palette[0][c * 3 + 0] = dis.readByte();
- dis.readByte();
+ palette[0][c * 3 + 0] = data->readByte();
+ data->readByte();
- palette[0][c * 3 + 1] = dis.readByte();
- dis.readByte();
+ palette[0][c * 3 + 1] = data->readByte();
+ data->readByte();
- palette[0][c * 3 + 2] = dis.readByte();
- dis.readByte();
+ palette[0][c * 3 + 2] = data->readByte();
+ data->readByte();
}
- *palSize = ctSize;
+ palSize = ctSize;
- pixelsPerByte = (iconBounds[2] - iconBounds[0]) / iconRowBytes;
- bpp = 8 / pixelsPerByte;
+ int pixelsPerByte = (iconBounds[2] - iconBounds[0]) / iconRowBytes;
+ int bpp = 8 / pixelsPerByte;
// build a mask to make sure the pixels are properly shifted out
- bitmask = 0;
+ int bitmask = 0;
for (int m = 0; m < bpp; m++) {
bitmask <<= 1;
bitmask |= 1;
@@ -669,16 +661,16 @@ void MacResManager::convertCrsrCursor(byte *data, int datasize, byte **cursor, i
// Extract pixels from bytes
for (int j = 0; j < iconDataSize; j++)
- for (b = 0; b < pixelsPerByte; b++) {
+ for (int b = 0; b < pixelsPerByte; b++) {
int idx = j * pixelsPerByte + (pixelsPerByte - 1 - b);
if (cursor[0][idx] != 0xff) // if mask is not there
cursor[0][idx] = (byte)((iconData[j] >> (b * bpp)) & bitmask);
}
- free(iconData);
+ delete[] iconData;
- assert(datasize - dis.pos() == 0);
+ assert(data->size() - data->pos() == 0);
}
} // End of namespace Common
diff --git a/common/macresman.h b/common/macresman.h
index 1cbebbcf4b..2ad0b608a1 100644
--- a/common/macresman.h
+++ b/common/macresman.h
@@ -154,14 +154,13 @@ public:
/**
* Convert cursor from crsr format to format suitable for feeding to CursorMan
- * @param data Pointer to the cursor data
- * @param datasize Size of the cursor data
+ * @param data Pointer to the cursor datax
* @param cursor Pointer to memory where result cursor will be stored. The memory
* block will be malloc()'ed
* @param w Pointer to int where the cursor width will be stored
* @param h Pointer to int where the cursor height will be stored
- * @param hotspot_x Storage for cursor hotspot X coordinate
- * @param hotspot_Y Storage for cursor hotspot Y coordinate
+ * @param hotspotX Storage for cursor hotspot X coordinate
+ * @param hotspotY Storage for cursor hotspot Y coordinate
* @param keycolor Pointer to int where the transpared color value will be stored
* @param colored If set to true then colored cursor will be returned (if any).
* b/w version will be used otherwise
@@ -169,8 +168,8 @@ public:
* The memory will be malloc()'ed
* @param palSize Pointer to integer where the palette size will be stored.
*/
- static void convertCrsrCursor(byte *data, int datasize, byte **cursor, int *w, int *h,
- int *hotspot_x, int *hotspot_y, int *keycolor, bool colored, byte **palette, int *palSize);
+ static void convertCrsrCursor(SeekableReadStream *data, byte **cursor, int &w, int &h, int &hotspotX,
+ int &hotspotY, int &keycolor, bool colored, byte **palette, int &palSize);
/**
* Return list of resource IDs with specified type ID
diff --git a/common/module.mk b/common/module.mk
index a4cea5c23f..a57de6a4b8 100644
--- a/common/module.mk
+++ b/common/module.mk
@@ -17,7 +17,6 @@ MODULE_OBJS := \
memorypool.o \
md5.o \
mutex.o \
- ne_exe.o \
random.o \
rational.o \
str.o \
@@ -29,6 +28,9 @@ MODULE_OBJS := \
unarj.o \
unzip.o \
util.o \
+ winexe.o \
+ winexe_ne.o \
+ winexe_pe.o \
xmlparser.o \
zlib.o
diff --git a/common/ne_exe.cpp b/common/ne_exe.cpp
deleted file mode 100644
index 34bb551b06..0000000000
--- a/common/ne_exe.cpp
+++ /dev/null
@@ -1,612 +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 "common/debug.h"
-#include "common/file.h"
-#include "common/memstream.h"
-#include "common/ne_exe.h"
-#include "common/str.h"
-#include "common/stream.h"
-
-namespace Common {
-
-NECursor::NECursor() {
- _width = 0;
- _height = 0;
- _hotspotX = 0;
- _hotspotY = 0;
- _surface = 0;
- memset(_palette, 0, 256 * 3);
-}
-
-NECursor::~NECursor() {
- clear();
-}
-
-uint16 NECursor::getWidth() const {
- return _width;
-}
-
-uint16 NECursor::getHeight() const {
- return _height;
-}
-
-uint16 NECursor::getHotspotX() const {
- return _hotspotX;
-}
-
-uint16 NECursor::getHotspotY() const {
- return _hotspotY;
-}
-
-void NECursor::setDimensions(uint16 width, uint16 height) {
- _width = width;
- _height = height;
-}
-
-void NECursor::setHotspot(uint16 x, uint16 y) {
- _hotspotX = x;
- _hotspotY = y;
-}
-
-bool NECursor::readCursor(SeekableReadStream &stream, uint32 count) {
- clear();
-
- SeekableReadStream *bitmap = stream.readStream(count);
- _surface = new byte[_width * _height];
-
- uint32 width = _width;
- uint32 height = _height * 2;
-
- // Sanity checks
- assert((width > 0) && (height > 0));
-
- // Check header size
- if (bitmap->readUint32LE() != 40)
- return false;
-
- // Check dimensions
- if (bitmap->readUint32LE() != width)
- return false;
- if (bitmap->readUint32LE() != height)
- return false;
-
- // Color planes
- if (bitmap->readUint16LE() != 1)
- return false;
- // Bits per pixel
- if (bitmap->readUint16LE() != 1)
- return false;
- // Compression
- if (bitmap->readUint32LE() != 0)
- return false;
-
- // Image size + X resolution + Y resolution
- bitmap->skip(12);
-
- uint32 numColors = bitmap->readUint32LE();
-
- if (numColors == 0)
- numColors = 2;
- else if (numColors > 2)
- return false;
-
- // Assert that enough data is there for the whole cursor
- if ((uint32)bitmap->size() < 40 + numColors * 4 + width * height / 8)
- return false;
-
- // Height includes AND-mask and XOR-mask
- height /= 2;
-
- // Standard palette: transparent, black, white
- _palette[6] = 0xff;
- _palette[7] = 0xff;
- _palette[8] = 0xff;
-
- // Reading the palette
- bitmap->seek(40);
- for (uint32 i = 0 ; i < numColors; i++) {
- _palette[(i + 1) * 3 + 2] = bitmap->readByte();
- _palette[(i + 1) * 3 + 1] = bitmap->readByte();
- _palette[(i + 1) * 3 + 0] = bitmap->readByte();
- bitmap->readByte();
- }
-
- // Reading the bitmap data
- uint32 dataSize = bitmap->size() - 40 - numColors * 4;
- byte *initialSource = new byte[dataSize];
- bitmap->read(initialSource, dataSize);
- const byte *srcP = initialSource;
- const byte *srcM = srcP + ((width * height) / 8);
- byte *dest = _surface + width * (height - 1);
-
- for (uint32 i = 0; i < height; i++) {
- byte *rowDest = dest;
-
- for (uint32 j = 0; j < (width / 8); j++) {
- byte p = srcP[j];
- byte m = srcM[j];
-
- for (int k = 0; k < 8; k++, rowDest++, p <<= 1, m <<= 1) {
- if ((m & 0x80) != 0x80) {
- if ((p & 0x80) == 0x80)
- *rowDest = 2;
- else
- *rowDest = 1;
- } else
- *rowDest = 0;
- }
- }
-
- dest -= width;
- srcP += width / 8;
- srcM += width / 8;
- }
-
- delete bitmap;
- delete[] initialSource;
- return true;
-}
-
-void NECursor::clear() {
- delete[] _surface; _surface = 0;
-}
-
-NEResourceID &NEResourceID::operator=(String string) {
- _name = string;
- _idType = kIDTypeString;
- return *this;
-}
-
-NEResourceID &NEResourceID::operator=(uint16 x) {
- _id = x;
- _idType = kIDTypeNumerical;
- return *this;
-}
-
-bool NEResourceID::operator==(const String &x) const {
- return _idType == kIDTypeString && _name.equalsIgnoreCase(x);
-}
-
-bool NEResourceID::operator==(const uint16 &x) const {
- return _idType == kIDTypeNumerical && _id == x;
-}
-
-bool NEResourceID::operator==(const NEResourceID &x) const {
- if (_idType != x._idType)
- return false;
- if (_idType == kIDTypeString)
- return _name.equalsIgnoreCase(x._name);
- if (_idType == kIDTypeNumerical)
- return _id == x._id;
- return true;
-}
-
-String NEResourceID::getString() const {
- if (_idType != kIDTypeString)
- return "";
-
- return _name;
-}
-
-uint16 NEResourceID::getID() const {
- if (_idType != kIDTypeNumerical)
- return 0xffff;
-
- return _idType;
-}
-
-String NEResourceID::toString() const {
- if (_idType == kIDTypeString)
- return _name;
- else if (_idType == kIDTypeNumerical)
- return String::format("%04x", _id);
-
- return "";
-}
-
-NEResources::NEResources() {
- _exe = 0;
-}
-
-NEResources::~NEResources() {
- clear();
-}
-
-void NEResources::clear() {
- if (_exe) {
- delete _exe;
- _exe = 0;
- }
-
- _resources.clear();
-
- for (uint32 i = 0; i < _cursors.size(); i++)
- for (uint32 j = 0; j < _cursors[i].cursors.size(); j++)
- delete _cursors[i].cursors[j];
-
- _cursors.clear();
-}
-
-const Array<NECursorGroup> &NEResources::getCursors() const {
- return _cursors;
-}
-
-bool NEResources::loadFromEXE(const String &fileName) {
- if (fileName.empty())
- return false;
-
- File *file = new File();
-
- if (!file->open(fileName)) {
- delete file;
- return false;
- }
-
- return loadFromEXE(file);
-}
-
-bool NEResources::loadFromEXE(SeekableReadStream *stream) {
- clear();
-
- if (!stream)
- return false;
-
- _exe = stream;
-
- uint32 offsetResourceTable = getResourceTableOffset();
- if (offsetResourceTable == 0xFFFFFFFF)
- return false;
- if (offsetResourceTable == 0)
- return true;
-
- if (!readResourceTable(offsetResourceTable))
- return false;
-
- if (!readCursors())
- return false;
-
- return true;
-}
-
-bool NEResources::loadFromCompressedEXE(const String &fileName) {
- // Based on http://www.cabextract.org.uk/libmspack/doc/szdd_kwaj_format.html
-
- File file;
-
- if (!file.open(fileName))
- return false;
-
- // First part of the signature
- if (file.readUint32BE() != MKID_BE('SZDD'))
- return false;
-
- // Second part of the signature
- if (file.readUint32BE() != 0x88F02733)
- return false;
-
- // Compression mode must be 'A'
- if (file.readByte() != 'A')
- return false;
-
- file.readByte(); // file name character change
- uint32 unpackedLength = file.readUint32LE();
-
- byte *window = new byte[0x1000];
- int pos = 0x1000 - 16;
- memset(window, 0x20, 0x1000); // Initialize to all spaces
-
- byte *unpackedData = (byte *)malloc(unpackedLength);
- byte *dataPos = unpackedData;
-
- // Apply simple LZSS decompression
- for (;;) {
- byte controlByte = file.readByte();
-
- if (file.eos())
- break;
-
- for (byte i = 0; i < 8; i++) {
- if (controlByte & (1 << i)) {
- *dataPos++ = window[pos++] = file.readByte();
- pos &= 0xFFF;
- } else {
- int matchPos = file.readByte();
- int matchLen = file.readByte();
- matchPos |= (matchLen & 0xF0) << 4;
- matchLen = (matchLen & 0xF) + 3;
- while (matchLen--) {
- *dataPos++ = window[pos++] = window[matchPos++];
- pos &= 0xFFF;
- matchPos &= 0xFFF;
- }
- }
-
- }
- }
-
- delete[] window;
- SeekableReadStream *stream = new MemoryReadStream(unpackedData, unpackedLength);
-
- return loadFromEXE(stream);
-}
-
-uint32 NEResources::getResourceTableOffset() {
- if (!_exe)
- return 0xFFFFFFFF;
-
- if (!_exe->seek(0))
- return 0xFFFFFFFF;
-
- // 'MZ'
- if (_exe->readUint16BE() != 0x4D5A)
- return 0xFFFFFFFF;
-
- if (!_exe->seek(60))
- return 0xFFFFFFFF;
-
- uint32 offsetSegmentEXE = _exe->readUint16LE();
- if (!_exe->seek(offsetSegmentEXE))
- return 0xFFFFFFFF;
-
- // 'NE'
- if (_exe->readUint16BE() != 0x4E45)
- return 0xFFFFFFFF;
-
- if (!_exe->seek(offsetSegmentEXE + 36))
- return 0xFFFFFFFF;
-
- uint32 offsetResourceTable = _exe->readUint16LE();
- if (offsetResourceTable == 0)
- // No resource table
- return 0;
-
- // Offset relative to the segment _exe header
- offsetResourceTable += offsetSegmentEXE;
- if (!_exe->seek(offsetResourceTable))
- return 0xFFFFFFFF;
-
- return offsetResourceTable;
-}
-
-static const char *s_resTypeNames[] = {
- "", "cursor", "bitmap", "icon", "menu", "dialog", "string",
- "font_dir", "font", "accelerator", "rc_data", "msg_table",
- "group_cursor", "group_icon", "version", "dlg_include",
- "plug_play", "vxd", "ani_cursor", "ani_icon", "html",
- "manifest"
-};
-
-bool NEResources::readResourceTable(uint32 offset) {
- if (!_exe)
- return false;
-
- if (!_exe->seek(offset))
- return false;
-
- uint32 align = 1 << _exe->readUint16LE();
-
- uint16 typeID = _exe->readUint16LE();
- while (typeID != 0) {
- uint16 resCount = _exe->readUint16LE();
-
- _exe->skip(4); // reserved
-
- for (int i = 0; i < resCount; i++) {
- Resource res;
-
- // Resource properties
- res.offset = _exe->readUint16LE() * align;
- res.size = _exe->readUint16LE() * align;
- res.flags = _exe->readUint16LE();
- uint16 id = _exe->readUint16LE();
- res.handle = _exe->readUint16LE();
- res.usage = _exe->readUint16LE();
-
- res.type = typeID;
-
- if ((id & 0x8000) == 0)
- res.id = getResourceString(*_exe, offset + id);
- else
- res.id = id & 0x7FFF;
-
- if (typeID & 0x8000 && ((typeID & 0x7FFF) < ARRAYSIZE(s_resTypeNames)))
- debug(2, "Found resource %s %s", s_resTypeNames[typeID & 0x7FFF], res.id.toString().c_str());
- else
- debug(2, "Found resource %04x %s", typeID, res.id.toString().c_str());
-
- _resources.push_back(res);
- }
-
- typeID = _exe->readUint16LE();
- }
-
- return true;
-}
-
-String NEResources::getResourceString(SeekableReadStream &exe, uint32 offset) {
- uint32 curPos = exe.pos();
-
- if (!exe.seek(offset)) {
- exe.seek(curPos);
- return "";
- }
-
- uint8 length = exe.readByte();
-
- String string;
- for (uint16 i = 0; i < length; i++)
- string += (char)exe.readByte();
-
- exe.seek(curPos);
- return string;
-}
-
-const NEResources::Resource *NEResources::findResource(uint16 type, NEResourceID id) const {
- for (List<Resource>::const_iterator it = _resources.begin(); it != _resources.end(); ++it)
- if (it->type == type && it->id == id)
- return &*it;
-
- return 0;
-}
-
-SeekableReadStream *NEResources::getResource(uint16 type, NEResourceID id) {
- const Resource *res = findResource(type, id);
-
- if (!res)
- return 0;
-
- _exe->seek(res->offset);
- return _exe->readStream(res->size);
-}
-
-const Array<NEResourceID> NEResources::getIDList(uint16 type) const {
- Array<NEResourceID> idArray;
-
- for (List<Resource>::const_iterator it = _resources.begin(); it != _resources.end(); ++it)
- if (it->type == type)
- idArray.push_back(it->id);
-
- return idArray;
-}
-
-bool NEResources::readCursors() {
- uint32 cursorCount = 0;
-
- for (List<Resource>::const_iterator it = _resources.begin(); it != _resources.end(); ++it)
- if (it->type == kNEGroupCursor)
- cursorCount++;
-
- if (cursorCount == 0) {
- _cursors.clear();
- return true;
- }
-
- _cursors.resize(cursorCount);
-
- Array<NECursorGroup>::iterator cursorGroup = _cursors.begin();
- for (List<Resource>::const_iterator it = _resources.begin(); it != _resources.end(); ++it) {
- if (it->type == kNEGroupCursor) {
- if (!readCursorGroup(*cursorGroup, *it))
- return false;
-
- ++cursorGroup;
- }
- }
-
- return true;
-}
-
-bool NEResources::readCursorGroup(NECursorGroup &group, const Resource &resource) {
- if (!_exe)
- return false;
-
- if (resource.size <= 6)
- return false;
-
- if (!_exe->seek(resource.offset))
- return false;
-
- byte *data = new byte[resource.size];
-
- if (!_exe->read(data, resource.size)) {
- delete[] data;
- return false;
- }
-
- uint32 cursorCount = READ_LE_UINT16(data + 4);
- if (resource.size < (6 + cursorCount * 16)) {
- delete[] data;
- return false;
- }
-
- group.cursors.resize(cursorCount);
-
- uint32 offset = 6;
- for (uint32 i = 0; i < cursorCount; i++) {
- group.cursors[i] = new NECursor();
- NECursor *cursor = group.cursors[i];
-
- // Plane count
- if (READ_LE_UINT16(data + offset + 4) != 1) {
- delete[] data;
- return false;
- }
-
- // Bit count
- if (READ_LE_UINT16(data + offset + 6) != 1) {
- delete[] data;
- return false;
- }
-
- uint32 id = READ_LE_UINT32(data + offset + 12);
- const Resource *cursorResource = findResource(kNECursor, id);
- if (!cursorResource) {
- delete[] data;
- return false;
- }
-
- cursor->setDimensions(READ_LE_UINT16(data + offset), READ_LE_UINT16(data + offset + 2) / 2);
-
- uint32 dataSize = READ_LE_UINT32(data + offset + 8);
- if (!readCursor(*cursor, *cursorResource, dataSize)) {
- delete[] data;
- return false;
- }
-
- offset += 16;
- }
-
- group.id = resource.id;
-
- delete[] data;
- return true;
-}
-
-bool NEResources::readCursor(NECursor &cursor, const Resource &resource, uint32 size) {
- if (!_exe)
- return false;
-
- if (size <= 4)
- return false;
- if (resource.size < size)
- return false;
-
- if (!_exe->seek(resource.offset))
- return false;
-
- uint32 hotspotX = _exe->readUint16LE();
- uint32 hotspotY = _exe->readUint16LE();
- cursor.setHotspot(hotspotX, hotspotY);
-
- size -= 4;
-
- if (!cursor.readCursor(*_exe, size))
- return false;
-
- return true;
-}
-
-} // End of namespace Common
diff --git a/common/winexe.cpp b/common/winexe.cpp
new file mode 100644
index 0000000000..9602e84c88
--- /dev/null
+++ b/common/winexe.cpp
@@ -0,0 +1,84 @@
+/* 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/str.h"
+#include "common/winexe.h"
+
+namespace Common {
+
+WinResourceID &WinResourceID::operator=(const String &x) {
+ _name = x;
+ _idType = kIDTypeString;
+ return *this;
+}
+
+WinResourceID &WinResourceID::operator=(uint32 x) {
+ _id = x;
+ _idType = kIDTypeNumerical;
+ return *this;
+}
+
+bool WinResourceID::operator==(const String &x) const {
+ return _idType == kIDTypeString && _name.equalsIgnoreCase(x);
+}
+
+bool WinResourceID::operator==(const uint32 &x) const {
+ return _idType == kIDTypeNumerical && _id == x;
+}
+
+bool WinResourceID::operator==(const WinResourceID &x) const {
+ if (_idType != x._idType)
+ return false;
+ if (_idType == kIDTypeString)
+ return _name.equalsIgnoreCase(x._name);
+ if (_idType == kIDTypeNumerical)
+ return _id == x._id;
+ return true;
+}
+
+String WinResourceID::getString() const {
+ if (_idType != kIDTypeString)
+ return "";
+
+ return _name;
+}
+
+uint32 WinResourceID::getID() const {
+ if (_idType != kIDTypeNumerical)
+ return 0xffffffff;
+
+ return _id;
+}
+
+String WinResourceID::toString() const {
+ if (_idType == kIDTypeString)
+ return _name;
+ else if (_idType == kIDTypeNumerical)
+ return String::format("%08x", _id);
+
+ return "";
+}
+
+} // End of namespace Common
diff --git a/common/winexe.h b/common/winexe.h
new file mode 100644
index 0000000000..af0d70c555
--- /dev/null
+++ b/common/winexe.h
@@ -0,0 +1,74 @@
+/* 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 COMMON_WINEXE_H
+#define COMMON_WINEXE_H
+
+#include "common/hash-str.h"
+
+namespace Common {
+
+class String;
+
+class WinResourceID {
+public:
+ WinResourceID() { _idType = kIDTypeNull; }
+ WinResourceID(String x) { _idType = kIDTypeString; _name = x; }
+ WinResourceID(uint32 x) { _idType = kIDTypeNumerical; _id = x; }
+
+ WinResourceID &operator=(const String &x);
+ WinResourceID &operator=(uint32 x);
+
+ bool operator==(const String &x) const;
+ bool operator==(const uint32 &x) const;
+ bool operator==(const WinResourceID &x) const;
+
+ String getString() const;
+ uint32 getID() const;
+ String toString() const;
+
+private:
+ /** An ID Type. */
+ enum IDType {
+ kIDTypeNull, ///< No type set
+ kIDTypeNumerical, ///< A numerical ID.
+ kIDTypeString ///< A string ID.
+ } _idType;
+
+ String _name; ///< The resource's string ID.
+ uint32 _id; ///< The resource's numerical ID.
+};
+
+struct WinResourceID_Hash {
+ uint operator()(const WinResourceID &id) const { return hashit(id.toString()); }
+};
+
+struct WinResourceID_EqualTo {
+ bool operator()(const WinResourceID &id1, const WinResourceID &id2) const { return id1 == id2; }
+};
+
+} // End of namespace Common
+
+#endif
diff --git a/common/winexe_ne.cpp b/common/winexe_ne.cpp
new file mode 100644
index 0000000000..24e51f1c9e
--- /dev/null
+++ b/common/winexe_ne.cpp
@@ -0,0 +1,291 @@
+/* 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/debug.h"
+#include "common/file.h"
+#include "common/memstream.h"
+#include "common/str.h"
+#include "common/stream.h"
+#include "common/winexe_ne.h"
+
+namespace Common {
+
+NEResources::NEResources() {
+ _exe = 0;
+}
+
+NEResources::~NEResources() {
+ clear();
+}
+
+void NEResources::clear() {
+ if (_exe) {
+ delete _exe;
+ _exe = 0;
+ }
+
+ _resources.clear();
+}
+
+bool NEResources::loadFromEXE(const String &fileName) {
+ if (fileName.empty())
+ return false;
+
+ File *file = new File();
+
+ if (!file->open(fileName)) {
+ delete file;
+ return false;
+ }
+
+ return loadFromEXE(file);
+}
+
+bool NEResources::loadFromEXE(SeekableReadStream *stream) {
+ clear();
+
+ if (!stream)
+ return false;
+
+ _exe = stream;
+
+ uint32 offsetResourceTable = getResourceTableOffset();
+ if (offsetResourceTable == 0xFFFFFFFF)
+ return false;
+ if (offsetResourceTable == 0)
+ return true;
+
+ if (!readResourceTable(offsetResourceTable))
+ return false;
+
+ return true;
+}
+
+bool NEResources::loadFromCompressedEXE(const String &fileName) {
+ // Based on http://www.cabextract.org.uk/libmspack/doc/szdd_kwaj_format.html
+
+ // TODO: Merge this with with loadFromEXE() so the handling of the compressed
+ // EXE's is transparent
+
+ File file;
+
+ if (!file.open(fileName))
+ return false;
+
+ // First part of the signature
+ if (file.readUint32BE() != MKID_BE('SZDD'))
+ return false;
+
+ // Second part of the signature
+ if (file.readUint32BE() != 0x88F02733)
+ return false;
+
+ // Compression mode must be 'A'
+ if (file.readByte() != 'A')
+ return false;
+
+ file.readByte(); // file name character change
+ uint32 unpackedLength = file.readUint32LE();
+
+ byte *window = new byte[0x1000];
+ int pos = 0x1000 - 16;
+ memset(window, 0x20, 0x1000); // Initialize to all spaces
+
+ byte *unpackedData = (byte *)malloc(unpackedLength);
+ assert(unpackedData);
+ byte *dataPos = unpackedData;
+
+ // Apply simple LZSS decompression
+ for (;;) {
+ byte controlByte = file.readByte();
+
+ if (file.eos())
+ break;
+
+ for (byte i = 0; i < 8; i++) {
+ if (controlByte & (1 << i)) {
+ *dataPos++ = window[pos++] = file.readByte();
+ pos &= 0xFFF;
+ } else {
+ int matchPos = file.readByte();
+ int matchLen = file.readByte();
+ matchPos |= (matchLen & 0xF0) << 4;
+ matchLen = (matchLen & 0xF) + 3;
+ while (matchLen--) {
+ *dataPos++ = window[pos++] = window[matchPos++];
+ pos &= 0xFFF;
+ matchPos &= 0xFFF;
+ }
+ }
+
+ }
+ }
+
+ delete[] window;
+ SeekableReadStream *stream = new MemoryReadStream(unpackedData, unpackedLength);
+
+ return loadFromEXE(stream);
+}
+
+uint32 NEResources::getResourceTableOffset() {
+ if (!_exe)
+ return 0xFFFFFFFF;
+
+ if (!_exe->seek(0))
+ return 0xFFFFFFFF;
+
+ // 'MZ'
+ if (_exe->readUint16BE() != 0x4D5A)
+ return 0xFFFFFFFF;
+
+ if (!_exe->seek(60))
+ return 0xFFFFFFFF;
+
+ uint32 offsetSegmentEXE = _exe->readUint16LE();
+ if (!_exe->seek(offsetSegmentEXE))
+ return 0xFFFFFFFF;
+
+ // 'NE'
+ if (_exe->readUint16BE() != 0x4E45)
+ return 0xFFFFFFFF;
+
+ if (!_exe->seek(offsetSegmentEXE + 36))
+ return 0xFFFFFFFF;
+
+ uint32 offsetResourceTable = _exe->readUint16LE();
+ if (offsetResourceTable == 0)
+ // No resource table
+ return 0;
+
+ // Offset relative to the segment _exe header
+ offsetResourceTable += offsetSegmentEXE;
+ if (!_exe->seek(offsetResourceTable))
+ return 0xFFFFFFFF;
+
+ return offsetResourceTable;
+}
+
+static const char *s_resTypeNames[] = {
+ "", "cursor", "bitmap", "icon", "menu", "dialog", "string",
+ "font_dir", "font", "accelerator", "rc_data", "msg_table",
+ "group_cursor", "group_icon", "version", "dlg_include",
+ "plug_play", "vxd", "ani_cursor", "ani_icon", "html",
+ "manifest"
+};
+
+bool NEResources::readResourceTable(uint32 offset) {
+ if (!_exe)
+ return false;
+
+ if (!_exe->seek(offset))
+ return false;
+
+ uint32 align = 1 << _exe->readUint16LE();
+
+ uint16 typeID = _exe->readUint16LE();
+ while (typeID != 0) {
+ uint16 resCount = _exe->readUint16LE();
+
+ _exe->skip(4); // reserved
+
+ for (int i = 0; i < resCount; i++) {
+ Resource res;
+
+ // Resource properties
+ res.offset = _exe->readUint16LE() * align;
+ res.size = _exe->readUint16LE() * align;
+ res.flags = _exe->readUint16LE();
+ uint16 id = _exe->readUint16LE();
+ res.handle = _exe->readUint16LE();
+ res.usage = _exe->readUint16LE();
+
+ res.type = typeID;
+
+ if ((id & 0x8000) == 0)
+ res.id = getResourceString(*_exe, offset + id);
+ else
+ res.id = id & 0x7FFF;
+
+ if (typeID & 0x8000 && ((typeID & 0x7FFF) < ARRAYSIZE(s_resTypeNames)))
+ debug(2, "Found resource %s %s", s_resTypeNames[typeID & 0x7FFF], res.id.toString().c_str());
+ else
+ debug(2, "Found resource %04x %s", typeID, res.id.toString().c_str());
+
+ _resources.push_back(res);
+ }
+
+ typeID = _exe->readUint16LE();
+ }
+
+ return true;
+}
+
+String NEResources::getResourceString(SeekableReadStream &exe, uint32 offset) {
+ uint32 curPos = exe.pos();
+
+ if (!exe.seek(offset)) {
+ exe.seek(curPos);
+ return "";
+ }
+
+ uint8 length = exe.readByte();
+
+ String string;
+ for (uint16 i = 0; i < length; i++)
+ string += (char)exe.readByte();
+
+ exe.seek(curPos);
+ return string;
+}
+
+const NEResources::Resource *NEResources::findResource(uint16 type, WinResourceID id) const {
+ for (List<Resource>::const_iterator it = _resources.begin(); it != _resources.end(); ++it)
+ if (it->type == type && it->id == id)
+ return &*it;
+
+ return 0;
+}
+
+SeekableReadStream *NEResources::getResource(uint16 type, WinResourceID id) {
+ const Resource *res = findResource(type, id);
+
+ if (!res)
+ return 0;
+
+ _exe->seek(res->offset);
+ return _exe->readStream(res->size);
+}
+
+const Array<WinResourceID> NEResources::getIDList(uint16 type) const {
+ Array<WinResourceID> idArray;
+
+ for (List<Resource>::const_iterator it = _resources.begin(); it != _resources.end(); ++it)
+ if (it->type == type)
+ idArray.push_back(it->id);
+
+ return idArray;
+}
+
+} // End of namespace Common
diff --git a/common/ne_exe.h b/common/winexe_ne.h
index 545c8e5eff..c1d04080ba 100644
--- a/common/ne_exe.h
+++ b/common/winexe_ne.h
@@ -23,11 +23,12 @@
*
*/
-#ifndef COMMON_NE_EXE_H
-#define COMMON_NE_EXE_H
+#ifndef COMMON_WINEXE_NE_H
+#define COMMON_WINEXE_NE_H
#include "common/array.h"
#include "common/list.h"
+#include "common/winexe.h"
namespace Common {
@@ -35,80 +36,6 @@ class MemoryReadStream;
class SeekableReadStream;
class String;
-/** A New Executable cursor. */
-class NECursor {
-public:
- NECursor();
- ~NECursor();
-
- /** Return the cursor's width. */
- uint16 getWidth() const;
- /** Return the cursor's height. */
- uint16 getHeight() const;
- /** Return the cursor's hotspot's x coordinate. */
- uint16 getHotspotX() const;
- /** Return the cursor's hotspot's y coordinate. */
- uint16 getHotspotY() const;
-
- const byte *getSurface() const { return _surface; }
- const byte *getPalette() const { return _palette; }
-
- /** Set the cursor's dimensions. */
- void setDimensions(uint16 width, uint16 height);
- /** Set the cursor's hotspot. */
- void setHotspot(uint16 x, uint16 y);
-
- /** Read the cursor's data out of a stream. */
- bool readCursor(SeekableReadStream &stream, uint32 count);
-
-private:
- byte *_surface;
- byte _palette[256 * 3];
-
- uint16 _width; ///< The cursor's width.
- uint16 _height; ///< The cursor's height.
- uint16 _hotspotX; ///< The cursor's hotspot's x coordinate.
- uint16 _hotspotY; ///< The cursor's hotspot's y coordinate.
-
- /** Clear the cursor. */
- void clear();
-};
-
-class NEResourceID {
-public:
- NEResourceID() { _idType = kIDTypeNull; }
- NEResourceID(String x) { _idType = kIDTypeString; _name = x; }
- NEResourceID(uint16 x) { _idType = kIDTypeNumerical; _id = x; }
-
- NEResourceID &operator=(String string);
- NEResourceID &operator=(uint16 x);
-
- bool operator==(const String &x) const;
- bool operator==(const uint16 &x) const;
- bool operator==(const NEResourceID &x) const;
-
- String getString() const;
- uint16 getID() const;
- String toString() const;
-
-private:
- /** An ID Type. */
- enum IDType {
- kIDTypeNull, ///< No type set
- kIDTypeNumerical, ///< A numerical ID.
- kIDTypeString ///< A string ID.
- } _idType;
-
- String _name; ///< The resource's string ID.
- uint16 _id; ///< The resource's numerical ID.
-};
-
-/** A New Executable cursor group. */
-struct NECursorGroup {
- NEResourceID id;
- Array<NECursor *> cursors; ///< The cursors.
-};
-
/** The default Windows resources. */
enum NEResourceType {
kNECursor = 0x8001,
@@ -157,19 +84,16 @@ public:
/** Load from a stream. */
bool loadFromEXE(SeekableReadStream *stream);
- /** Get all cursor's read from the New Executable. */
- const Array<NECursorGroup> &getCursors() const;
-
/** Return a list of resources for a given type. */
- const Array<NEResourceID> getIDList(uint16 type) const;
+ const Array<WinResourceID> getIDList(uint16 type) const;
/** Return a stream to the specified resource (or 0 if non-existent). */
- SeekableReadStream *getResource(uint16 type, NEResourceID id);
+ SeekableReadStream *getResource(uint16 type, WinResourceID id);
private:
/** A resource. */
struct Resource {
- NEResourceID id;
+ WinResourceID id;
uint16 type; ///< Type of the resource.
@@ -186,21 +110,13 @@ private:
/** All resources. */
List<Resource> _resources;
- /** All cursor resources. */
- Array<NECursorGroup> _cursors;
-
/** Read the offset to the resource table. */
uint32 getResourceTableOffset();
/** Read the resource table. */
bool readResourceTable(uint32 offset);
- // Cursor reading helpers
- bool readCursors();
- bool readCursorGroup(NECursorGroup &group, const Resource &resource);
- bool readCursor(NECursor &cursor, const Resource &resource, uint32 size);
-
/** Find a specific resource. */
- const Resource *findResource(uint16 type, NEResourceID id) const;
+ const Resource *findResource(uint16 type, WinResourceID id) const;
/** Read a resource string. */
static String getResourceString(SeekableReadStream &exe, uint32 offset);
@@ -208,4 +124,4 @@ private:
} // End of namespace Common
-#endif // COMMON_NE_EXE_H
+#endif
diff --git a/common/winexe_pe.cpp b/common/winexe_pe.cpp
new file mode 100644
index 0000000000..456093f5b4
--- /dev/null
+++ b/common/winexe_pe.cpp
@@ -0,0 +1,255 @@
+/* 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/debug.h"
+#include "common/file.h"
+#include "common/memstream.h"
+#include "common/str.h"
+#include "common/stream.h"
+#include "common/winexe_pe.h"
+
+namespace Common {
+
+PEResources::PEResources() {
+ _exe = 0;
+}
+
+PEResources::~PEResources() {
+ clear();
+}
+
+void PEResources::clear() {
+ _sections.clear();
+ _resources.clear();
+ delete _exe; _exe = 0;
+}
+
+bool PEResources::loadFromEXE(const String &fileName) {
+ if (fileName.empty())
+ return false;
+
+ File *file = new File();
+
+ if (!file->open(fileName)) {
+ delete file;
+ return false;
+ }
+
+ return loadFromEXE(file);
+}
+
+bool PEResources::loadFromEXE(SeekableReadStream *stream) {
+ clear();
+
+ if (!stream)
+ return false;
+
+ if (stream->readUint16BE() != 'MZ')
+ return false;
+
+ stream->skip(58);
+
+ uint32 peOffset = stream->readUint32LE();
+
+ if (!peOffset || peOffset >= (uint32)stream->size())
+ return false;
+
+ stream->seek(peOffset);
+
+ if (stream->readUint32BE() != MKID_BE('PE\0\0'))
+ return false;
+
+ stream->skip(2);
+ uint16 sectionCount = stream->readUint16LE();
+ stream->skip(12);
+ uint16 optionalHeaderSize = stream->readUint16LE();
+ stream->skip(optionalHeaderSize + 2);
+
+ // Read in all the sections
+ for (uint16 i = 0; i < sectionCount; i++) {
+ char sectionName[9];
+ stream->read(sectionName, 8);
+ sectionName[8] = 0;
+
+ Section section;
+ stream->skip(4);
+ section.virtualAddress = stream->readUint32LE();
+ section.size = stream->readUint32LE();
+ section.offset = stream->readUint32LE();
+ stream->skip(16);
+
+ _sections[sectionName] = section;
+ }
+
+ // Currently, we require loading a resource section
+ if (!_sections.contains(".rsrc")) {
+ clear();
+ return false;
+ }
+
+ _exe = stream;
+
+ Section &resSection = _sections[".rsrc"];
+ parseResourceLevel(resSection, resSection.offset, 0);
+
+ return true;
+}
+
+void PEResources::parseResourceLevel(Section &section, uint32 offset, int level) {
+ _exe->seek(offset + 12);
+
+ uint16 namedEntryCount = _exe->readUint16LE();
+ uint16 intEntryCount = _exe->readUint16LE();
+
+ for (uint32 i = 0; i < namedEntryCount + intEntryCount; i++) {
+ uint32 value = _exe->readUint32LE();
+
+ WinResourceID id;
+
+ if (value & 0x80000000) {
+ value &= 0x7fffffff;
+
+ uint32 startPos = _exe->pos();
+ _exe->seek(section.offset + (value & 0x7fffffff));
+
+ // Read in the name, truncating from unicode to ascii
+ Common::String name;
+ uint16 nameLength = _exe->readUint16LE();
+ while (nameLength--)
+ name += (char)(_exe->readUint16LE() & 0xff);
+
+ _exe->seek(startPos);
+
+ id = name;
+ } else {
+ id = value;
+ }
+
+ uint32 nextOffset = _exe->readUint32LE();
+ uint32 lastOffset = _exe->pos();
+
+ if (level == 0)
+ _curType = id;
+ else if (level == 1)
+ _curName = id;
+ else if (level == 2)
+ _curLang = id;
+
+ if (level < 2) {
+ // Time to dive down further
+ parseResourceLevel(section, section.offset + (nextOffset & 0x7fffffff), level + 1);
+ } else {
+ _exe->seek(section.offset + nextOffset);
+
+ Resource resource;
+ resource.offset = _exe->readUint32LE() + section.offset - section.virtualAddress;
+ resource.size = _exe->readUint32LE();
+
+ debug(4, "Found resource '%s' '%s' '%s' at %d of size %d", _curType.toString().c_str(),
+ _curName.toString().c_str(), _curLang.toString().c_str(), resource.offset, resource.size);
+
+ _resources[_curType][_curName][_curLang] = resource;
+ }
+
+ _exe->seek(lastOffset);
+ }
+}
+
+const Array<WinResourceID> PEResources::getTypeList() const {
+ Array<WinResourceID> array;
+
+ if (!_exe)
+ return array;
+
+ for (TypeMap::const_iterator it = _resources.begin(); it != _resources.end(); it++)
+ array.push_back(it->_key);
+
+ return array;
+}
+
+const Array<WinResourceID> PEResources::getNameList(const WinResourceID &type) const {
+ Array<WinResourceID> array;
+
+ if (!_exe || !_resources.contains(type))
+ return array;
+
+ const NameMap &nameMap = _resources[type];
+
+ for (NameMap::const_iterator it = nameMap.begin(); it != nameMap.end(); it++)
+ array.push_back(it->_key);
+
+ return array;
+}
+
+const Array<WinResourceID> PEResources::getLangList(const WinResourceID &type, const WinResourceID &name) const {
+ Array<WinResourceID> array;
+
+ if (!_exe || !_resources.contains(type))
+ return array;
+
+ const NameMap &nameMap = _resources[type];
+
+ if (!nameMap.contains(name))
+ return array;
+
+ const LangMap &langMap = nameMap[name];
+
+ for (LangMap::const_iterator it = langMap.begin(); it != langMap.end(); it++)
+ array.push_back(it->_key);
+
+ return array;
+}
+
+SeekableReadStream *PEResources::getResource(const WinResourceID &type, const WinResourceID &name) {
+ Array<WinResourceID> langList = getLangList(type, name);
+
+ if (langList.empty())
+ return 0;
+
+ const Resource &resource = _resources[type][name][langList[0]];
+ _exe->seek(resource.offset);
+ return _exe->readStream(resource.size);
+}
+
+SeekableReadStream *PEResources::getResource(const WinResourceID &type, const WinResourceID &name, const WinResourceID &lang) {
+ if (!_exe || !_resources.contains(type))
+ return 0;
+
+ const NameMap &nameMap = _resources[type];
+
+ if (!nameMap.contains(name))
+ return 0;
+
+ const LangMap &langMap = nameMap[name];
+
+ if (!langMap.contains(lang))
+ return 0;
+
+ const Resource &resource = langMap[lang];
+ _exe->seek(resource.offset);
+ return _exe->readStream(resource.size);
+}
+
+} // End of namespace Common
diff --git a/common/winexe_pe.h b/common/winexe_pe.h
new file mode 100644
index 0000000000..5298e993ad
--- /dev/null
+++ b/common/winexe_pe.h
@@ -0,0 +1,122 @@
+/* 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 COMMON_WINEXE_PE_H
+#define COMMON_WINEXE_PE_H
+
+#include "common/array.h"
+#include "common/hashmap.h"
+#include "common/winexe.h"
+
+namespace Common {
+
+class SeekableReadStream;
+class String;
+
+/** The default Windows PE resources. */
+enum PEResourceType {
+ kPECursor = 0x01,
+ kPEBitmap = 0x02,
+ kPEIcon = 0x03,
+ kPEMenu = 0x04,
+ kPEDialog = 0x05,
+ kPEString = 0x06,
+ kPEFontDir = 0x07,
+ kPEFont = 0x08,
+ kPEAccelerator = 0x09,
+ kPERCData = 0x0A,
+ kPEMessageTable = 0x0B,
+ kPEGroupCursor = 0x0C,
+ kPEGroupIcon = 0x0E,
+ kPEVersion = 0x10,
+ kPEDlgInclude = 0x11,
+ kPEPlugPlay = 0x13,
+ kPEVXD = 0x14,
+ kPEAniCursor = 0x15,
+ kPEAniIcon = 0x16
+};
+
+/**
+ * A class able to load resources from a Windows Portable Executable, such
+ * as cursors, bitmaps, and sounds.
+ */
+class PEResources {
+public:
+ PEResources();
+ ~PEResources();
+
+ /** Clear all information. */
+ void clear();
+
+ /** Load from an EXE file. */
+ bool loadFromEXE(const String &fileName);
+
+ /** Load from a stream. */
+ bool loadFromEXE(SeekableReadStream *stream);
+
+ /** Return a list of resource types. */
+ const Array<WinResourceID> getTypeList() const;
+
+ /** Return a list of names for a given type. */
+ const Array<WinResourceID> getNameList(const WinResourceID &type) const;
+
+ /** Return a list of languages for a given type and name. */
+ const Array<WinResourceID> getLangList(const WinResourceID &type, const WinResourceID &name) const;
+
+ /** Return a stream to the specified resource, taking the first language found (or 0 if non-existent). */
+ SeekableReadStream *getResource(const WinResourceID &type, const WinResourceID &name);
+
+ /** Return a stream to the specified resource (or 0 if non-existent). */
+ SeekableReadStream *getResource(const WinResourceID &type, const WinResourceID &name, const WinResourceID &lang);
+
+private:
+ struct Section {
+ uint32 virtualAddress;
+ uint32 size;
+ uint32 offset;
+ };
+
+ HashMap<String, Section, IgnoreCase_Hash, IgnoreCase_EqualTo> _sections;
+
+ SeekableReadStream *_exe;
+
+ void parseResourceLevel(Section &section, uint32 offset, int level);
+ WinResourceID _curType, _curName, _curLang;
+
+ struct Resource {
+ uint32 offset;
+ uint32 size;
+ };
+
+ typedef HashMap<WinResourceID, Resource, WinResourceID_Hash, WinResourceID_EqualTo> LangMap;
+ typedef HashMap<WinResourceID, LangMap, WinResourceID_Hash, WinResourceID_EqualTo> NameMap;
+ typedef HashMap<WinResourceID, NameMap, WinResourceID_Hash, WinResourceID_EqualTo> TypeMap;
+
+ TypeMap _resources;
+};
+
+} // End of namespace Common
+
+#endif
diff --git a/engines/mohawk/cursors.cpp b/engines/mohawk/cursors.cpp
index eb11eb175e..4a9fcb2ff2 100644
--- a/engines/mohawk/cursors.cpp
+++ b/engines/mohawk/cursors.cpp
@@ -28,12 +28,13 @@
#include "mohawk/resource.h"
#include "mohawk/graphics.h"
#include "mohawk/myst.h"
-#include "mohawk/riven_cursors.h"
#include "common/macresman.h"
-#include "common/ne_exe.h"
#include "common/system.h"
+#include "common/winexe_ne.h"
+#include "common/winexe_pe.h"
#include "graphics/cursorman.h"
+#include "graphics/wincursor.h"
namespace Mohawk {
@@ -83,15 +84,16 @@ void CursorManager::setCursor(uint16 id) {
setDefaultCursor();
}
-void CursorManager::decodeMacXorCursor(Common::SeekableReadStream *stream, byte *cursor) {
+void CursorManager::setMacXorCursor(Common::SeekableReadStream *stream) {
assert(stream);
- assert(cursor);
+
+ byte cursorBitmap[16 * 16];
// Get black and white data
for (int i = 0; i < 32; i++) {
byte imageByte = stream->readByte();
for (int b = 0; b < 8; b++)
- cursor[i * 8 + b] = (imageByte & (0x80 >> b)) ? 1 : 2;
+ cursorBitmap[i * 8 + b] = (imageByte & (0x80 >> b)) ? 1 : 2;
}
// Apply mask data
@@ -99,28 +101,18 @@ void CursorManager::decodeMacXorCursor(Common::SeekableReadStream *stream, byte
byte imageByte = stream->readByte();
for (int b = 0; b < 8; b++)
if ((imageByte & (0x80 >> b)) == 0)
- cursor[i * 8 + b] = 0;
+ cursorBitmap[i * 8 + b] = 0;
}
-}
-void CursorManager::setStandardCursor(Common::SeekableReadStream *stream) {
- // The Broderbund devs decided to rip off the Mac format, it seems.
- // However, they reversed the x/y hotspot. That makes it totally different!!!!
- assert(stream);
-
- byte cursorBitmap[16 * 16];
- decodeMacXorCursor(stream, cursorBitmap);
uint16 hotspotY = stream->readUint16BE();
uint16 hotspotX = stream->readUint16BE();
CursorMan.replaceCursor(cursorBitmap, 16, 16, hotspotX, hotspotY, 0);
CursorMan.replaceCursorPalette(s_bwPalette, 1, 2);
-
- delete stream;
}
void DefaultCursorManager::setCursor(uint16 id) {
- setStandardCursor(_vm->getResource(_tag, id));
+ setMacXorCursor(_vm->getResource(_tag, id));
}
MystCursorManager::MystCursorManager(MohawkEngine_Myst *vm) : _vm(vm) {
@@ -167,119 +159,6 @@ void MystCursorManager::setDefaultCursor() {
setCursor(kDefaultMystCursor);
}
-void RivenCursorManager::setCursor(uint16 id) {
- // All of Riven's cursors are hardcoded. See riven_cursors.h for these definitions.
-
- switch (id) {
- case 1002:
- // Zip Mode
- CursorMan.replaceCursor(s_zipModeCursor, 16, 16, 8, 8, 0);
- CursorMan.replaceCursorPalette(s_zipModeCursorPalette, 1, ARRAYSIZE(s_zipModeCursorPalette) / 3);
- break;
- case 2003:
- // Hand Over Object
- CursorMan.replaceCursor(s_objectHandCursor, 16, 16, 8, 8, 0);
- CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 3);
- break;
- case 2004:
- // Grabbing/Using Object
- CursorMan.replaceCursor(s_grabbingHandCursor, 13, 13, 6, 6, 0);
- CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 3);
- break;
- case 3000:
- // Standard Hand
- CursorMan.replaceCursor(s_standardHandCursor, 15, 16, 6, 0, 0);
- CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 3);
- break;
- case 3001:
- // Pointing Left
- CursorMan.replaceCursor(s_pointingLeftCursor, 15, 13, 0, 3, 0);
- CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 3);
- break;
- case 3002:
- // Pointing Right
- CursorMan.replaceCursor(s_pointingRightCursor, 15, 13, 14, 3, 0);
- CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 3);
- break;
- case 3003:
- // Pointing Down (Palm Up)
- CursorMan.replaceCursor(s_pointingDownCursorPalmUp, 13, 16, 3, 15, 0);
- CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 3);
- break;
- case 3004:
- // Pointing Up (Palm Up)
- CursorMan.replaceCursor(s_pointingUpCursorPalmUp, 13, 16, 3, 0, 0);
- CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 3);
- break;
- case 3005:
- // Pointing Left (Curved)
- CursorMan.replaceCursor(s_pointingLeftCursorBent, 15, 13, 0, 5, 0);
- CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 3);
- break;
- case 3006:
- // Pointing Right (Curved)
- CursorMan.replaceCursor(s_pointingRightCursorBent, 15, 13, 14, 5, 0);
- CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 3);
- break;
- case 3007:
- // Pointing Down (Palm Down)
- CursorMan.replaceCursor(s_pointingDownCursorPalmDown, 15, 16, 7, 15, 0);
- CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 3);
- break;
- case 4001:
- // Red Marble
- CursorMan.replaceCursor(s_redMarbleCursor, 12, 12, 5, 5, 0);
- CursorMan.replaceCursorPalette(s_redMarbleCursorPalette, 1, ARRAYSIZE(s_redMarbleCursorPalette) / 3);
- break;
- case 4002:
- // Orange Marble
- CursorMan.replaceCursor(s_orangeMarbleCursor, 12, 12, 5, 5, 0);
- CursorMan.replaceCursorPalette(s_orangeMarbleCursorPalette, 1, ARRAYSIZE(s_orangeMarbleCursorPalette) / 3);
- break;
- case 4003:
- // Yellow Marble
- CursorMan.replaceCursor(s_yellowMarbleCursor, 12, 12, 5, 5, 0);
- CursorMan.replaceCursorPalette(s_yellowMarbleCursorPalette, 1, ARRAYSIZE(s_yellowMarbleCursorPalette) / 3);
- break;
- case 4004:
- // Green Marble
- CursorMan.replaceCursor(s_greenMarbleCursor, 12, 12, 5, 5, 0);
- CursorMan.replaceCursorPalette(s_greenMarbleCursorPalette, 1, ARRAYSIZE(s_greenMarbleCursorPalette) / 3);
- break;
- case 4005:
- // Blue Marble
- CursorMan.replaceCursor(s_blueMarbleCursor, 12, 12, 5, 5, 0);
- CursorMan.replaceCursorPalette(s_blueMarbleCursorPalette, 1, ARRAYSIZE(s_blueMarbleCursorPalette) / 3);
- break;
- case 4006:
- // Violet Marble
- CursorMan.replaceCursor(s_violetMarbleCursor, 12, 12, 5, 5, 0);
- CursorMan.replaceCursorPalette(s_violetMarbleCursorPalette, 1, ARRAYSIZE(s_violetMarbleCursorPalette) / 3);
- break;
- case 5000:
- // Pellet
- CursorMan.replaceCursor(s_pelletCursor, 8, 8, 4, 4, 0);
- CursorMan.replaceCursorPalette(s_pelletCursorPalette, 1, ARRAYSIZE(s_pelletCursorPalette) / 3);
- break;
- case 9000:
- // Hide Cursor
- CursorMan.showMouse(false);
- break;
- default:
- error("Cursor %d does not exist!", id);
- }
-
- if (id != 9000) // Show Cursor
- CursorMan.showMouse(true);
-
- // Should help in cases where we need to hide the cursor immediately.
- g_system->updateScreen();
-}
-
-void RivenCursorManager::setDefaultCursor() {
- setCursor(kRivenMainCursor);
-}
-
NECursorManager::NECursorManager(const Common::String &appName) {
_exe = new Common::NEResources();
@@ -295,16 +174,14 @@ NECursorManager::~NECursorManager() {
}
void NECursorManager::setCursor(uint16 id) {
- if (!_exe) {
- Common::Array<Common::NECursorGroup> cursors = _exe->getCursors();
-
- for (uint32 i = 0; i < cursors.size(); i++) {
- if (cursors[i].id == id) {
- Common::NECursor *cursor = cursors[i].cursors[0];
- CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(), cursor->getHotspotY(), 0);
- CursorMan.replaceCursorPalette(cursor->getPalette(), 0, 256);
- return;
- }
+ if (_exe) {
+ Graphics::WinCursorGroup *cursorGroup = Graphics::WinCursorGroup::createCursorGroup(*_exe, id);
+
+ if (cursorGroup) {
+ Graphics::WinCursor *cursor = cursorGroup->cursors[0].cursor;
+ CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(), cursor->getHotspotY(), cursor->getKeyColor());
+ CursorMan.replaceCursorPalette(cursor->getPalette(), 0, 256);
+ return;
}
}
@@ -321,6 +198,8 @@ MacCursorManager::MacCursorManager(const Common::String &appName) {
delete _resFork;
_resFork = 0;
}
+ } else {
+ _resFork = 0;
}
}
@@ -334,22 +213,33 @@ void MacCursorManager::setCursor(uint16 id) {
return;
}
- Common::SeekableReadStream *stream = _resFork->getResource(MKID_BE('CURS'), id);
+ // Try a color cursor first
+ Common::SeekableReadStream *stream = _resFork->getResource(MKID_BE('crsr'), id);
- if (!stream) {
- setDefaultCursor();
+ if (stream) {
+ byte *cursor, *palette;
+ int width, height, hotspotX, hotspotY, keyColor, palSize;
+
+ _resFork->convertCrsrCursor(stream, &cursor, width, height, hotspotX, hotspotY, keyColor, true, &palette, palSize);
+
+ CursorMan.replaceCursor(cursor, width, height, hotspotX, hotspotY, keyColor);
+ CursorMan.replaceCursorPalette(palette, 0, palSize);
+
+ delete[] cursor;
+ delete[] palette;
+ delete stream;
return;
}
- byte cursorBitmap[16 * 16];
- decodeMacXorCursor(stream, cursorBitmap);
- uint16 hotspotX = stream->readUint16BE();
- uint16 hotspotY = stream->readUint16BE();
+ // Fall back to b&w cursors
+ stream = _resFork->getResource(MKID_BE('CURS'), id);
- CursorMan.replaceCursor(cursorBitmap, 16, 16, hotspotX, hotspotY, 0);
- CursorMan.replaceCursorPalette(s_bwPalette, 1, 2);
-
- delete stream;
+ if (stream) {
+ setMacXorCursor(stream);
+ delete stream;
+ } else {
+ setDefaultCursor();
+ }
}
LivingBooksCursorManager_v2::LivingBooksCursorManager_v2() {
@@ -368,10 +258,40 @@ LivingBooksCursorManager_v2::~LivingBooksCursorManager_v2() {
void LivingBooksCursorManager_v2::setCursor(uint16 id) {
if (_sysArchive && _sysArchive->hasResource(ID_TCUR, id)) {
- setStandardCursor(_sysArchive->getResource(ID_TCUR, id));
+ setMacXorCursor(_sysArchive->getResource(ID_TCUR, id));
} else {
// TODO: Handle generated cursors
}
}
+PECursorManager::PECursorManager(const Common::String &appName) {
+ _exe = new Common::PEResources();
+
+ if (!_exe->loadFromEXE(appName)) {
+ // Not all have cursors anyway, so this is not a problem
+ delete _exe;
+ _exe = 0;
+ }
+}
+
+PECursorManager::~PECursorManager() {
+ delete _exe;
+}
+
+void PECursorManager::setCursor(uint16 id) {
+ if (_exe) {
+ Graphics::WinCursorGroup *cursorGroup = Graphics::WinCursorGroup::createCursorGroup(*_exe, id);
+
+ if (cursorGroup) {
+ Graphics::WinCursor *cursor = cursorGroup->cursors[0].cursor;
+ CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(), cursor->getHotspotY(), cursor->getKeyColor());
+ CursorMan.replaceCursorPalette(cursor->getPalette(), 0, 256);
+ return;
+ }
+ }
+
+ // Last resort (not all have cursors)
+ setDefaultCursor();
+}
+
} // End of namespace Mohawk
diff --git a/engines/mohawk/cursors.h b/engines/mohawk/cursors.h
index a542ddb7c3..e6c417948f 100644
--- a/engines/mohawk/cursors.h
+++ b/engines/mohawk/cursors.h
@@ -31,6 +31,7 @@
namespace Common {
class MacResManager;
class NEResources;
+ class PEResources;
class SeekableReadStream;
class String;
}
@@ -80,13 +81,11 @@ public:
virtual void hideCursor();
virtual void setCursor(uint16 id);
virtual void setDefaultCursor();
+ virtual bool hasSource() const { return false; }
protected:
- // Handles the Mac version of the xor/and map cursor
- void decodeMacXorCursor(Common::SeekableReadStream *stream, byte *cursor);
-
- // Set a tCUR resource as the current cursor
- void setStandardCursor(Common::SeekableReadStream *stream);
+ // Set a Mac XOR/AND map cursor to the screen
+ void setMacXorCursor(Common::SeekableReadStream *stream);
};
// The default Mohawk cursor manager
@@ -97,6 +96,7 @@ public:
~DefaultCursorManager() {}
void setCursor(uint16 id);
+ bool hasSource() const { return true; }
private:
MohawkEngine *_vm;
@@ -114,31 +114,21 @@ public:
void hideCursor();
void setCursor(uint16 id);
void setDefaultCursor();
+ bool hasSource() const { return true; }
private:
MohawkEngine_Myst *_vm;
MystBitmap *_bmpDecoder;
};
-
-// The cursor manager for Riven
-// Uses hardcoded cursors
-class RivenCursorManager : public CursorManager {
-public:
- RivenCursorManager() {}
- ~RivenCursorManager() {}
-
- void setCursor(uint16 id);
- void setDefaultCursor();
-};
-
-// The cursor manager for NE exe's
+// The cursor manager for NE EXE's
class NECursorManager : public CursorManager {
public:
NECursorManager(const Common::String &appName);
~NECursorManager();
void setCursor(uint16 id);
+ bool hasSource() const { return _exe != 0; }
private:
Common::NEResources *_exe;
@@ -151,6 +141,7 @@ public:
~MacCursorManager();
void setCursor(uint16 id);
+ bool hasSource() const { return _resFork != 0; }
private:
Common::MacResManager *_resFork;
@@ -164,11 +155,25 @@ public:
~LivingBooksCursorManager_v2();
void setCursor(uint16 id);
+ bool hasSource() const { return _sysArchive != 0; }
private:
MohawkArchive *_sysArchive;
};
+// The cursor manager for PE EXE's
+class PECursorManager : public CursorManager {
+public:
+ PECursorManager(const Common::String &appName);
+ ~PECursorManager();
+
+ void setCursor(uint16 id);
+ bool hasSource() const { return _exe != 0; }
+
+private:
+ Common::PEResources *_exe;
+};
+
} // End of namespace Mohawk
#endif
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp
index abc7f5304e..d75c98bcd4 100644
--- a/engines/mohawk/riven.cpp
+++ b/engines/mohawk/riven.cpp
@@ -120,21 +120,43 @@ Common::Error MohawkEngine_Riven::run() {
_externalScriptHandler = new RivenExternal(this);
_optionsDialog = new RivenOptionsDialog(this);
_scriptMan = new RivenScriptManager(this);
- _cursor = new RivenCursorManager();
_rnd = new Common::RandomSource();
g_eventRec.registerRandomSource(*_rnd, "riven");
+ // Create the cursor manager
+ if (Common::File::exists("rivendmo.exe"))
+ _cursor = new PECursorManager("rivendmo.exe");
+ else if (Common::File::exists("riven.exe"))
+ _cursor = new PECursorManager("riven.exe");
+ else // last resort: try the Mac executable
+ _cursor = new MacCursorManager("Riven");
+
initVars();
+ // We need to have a cursor source, or the game won't work
+ if (!_cursor->hasSource()) {
+ Common::String message = "You're missing a Riven executable. The Windows executable is 'riven.exe' or 'rivendemo.exe'. ";
+ message += "Using the 'arcriven.z' installer file also works. In addition, you can use the Mac 'Riven' executable.";
+ GUIErrorMessage(message);
+ warning("%s", message.c_str());
+ return Common::kNoGameDataFoundError;
+ }
+
// Open extras.mhk for common images
_extrasFile = new MohawkArchive();
- if (!_extrasFile->open("extras.mhk"))
- error("Could not open extras.mhk");
+ // We need extras.mhk for inventory images, marble images, and credits images
+ if (!_extrasFile->open("extras.mhk")) {
+ Common::String message = "You're missing 'extras.mhk'. Using the 'arcriven.z' installer file also works.";
+ GUIErrorMessage(message);
+ warning("%s", message.c_str());
+ return Common::kNoGameDataFoundError;
+ }
// Start at main cursor
_cursor->setCursor(kRivenMainCursor);
+ _system->updateScreen();
// Let's begin, shall we?
if (getFeatures() & GF_DEMO) {
@@ -488,10 +510,12 @@ void MohawkEngine_Riven::checkHotspotChange() {
if (_curHotspot != hotspotIndex) {
_curHotspot = hotspotIndex;
_cursor->setCursor(_hotspots[_curHotspot].mouse_cursor);
+ _system->updateScreen();
}
} else {
_curHotspot = -1;
_cursor->setCursor(kRivenMainCursor);
+ _system->updateScreen();
}
}
diff --git a/engines/mohawk/riven_cursors.h b/engines/mohawk/riven_cursors.h
deleted file mode 100644
index dadfdf0549..0000000000
--- a/engines/mohawk/riven_cursors.h
+++ /dev/null
@@ -1,670 +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$
- *
- */
-
-namespace Mohawk {
-
-//////////////////////////////////////////////
-// Cursors and Cursor Palettes
-//////////////////////////////////////////////
-
-////////////////////////////////////////
-// Zip Mode Cursor (16x16):
-// Shown when a zip mode spot is active
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Yellow (0xDCFF00)
-////////////////////////////////////////
-static const byte s_zipModeCursor[] = {
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 1, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 2, 1, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 2, 1, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 2, 2, 1, 2, 2, 2, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 2, 2, 2, 1, 2, 2, 1, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 1, 2, 1, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 1, 2, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 1, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
-};
-
-
-////////////////////////////////////////
-// Zip Mode Cursor Palette:
-// Palette For The Zip Mode Cursor
-////////////////////////////////////////
-static const byte s_zipModeCursorPalette[] = {
- 0x00, 0x00, 0x00, // Black
- 0xDC, 0xFF, 0x00 // Yellow
-};
-
-
-////////////////////////////////////////
-// Hand Over Object Cursor (16x16):
-// Shown when over a hotspot that's interactive
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Light Peach (0xEDCD96)
-// 3 = Brown (0x8A672F)
-// 4 = Dark Peach (0xE89A62)
-////////////////////////////////////////
-static const byte s_objectHandCursor[] = {
- 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 1, 0, 1, 2, 3, 1, 1, 1, 0, 0, 0, 0,
- 0, 0, 1, 2, 3, 1, 1, 2, 3, 1, 2, 3, 1, 0, 0, 0,
- 0, 0, 1, 2, 3, 1, 1, 4, 3, 1, 2, 3, 1, 0, 1, 0,
- 0, 0, 0, 1, 2, 3, 1, 2, 3, 1, 4, 3, 1, 1, 2, 1,
- 0, 0, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1,
- 0, 1, 1, 0, 1, 2, 2, 2, 2, 2, 2, 3, 1, 2, 3, 1,
- 1, 2, 2, 1, 1, 2, 2, 2, 4, 2, 4, 2, 2, 4, 2, 1,
- 1, 3, 4, 2, 1, 2, 4, 2, 2, 2, 2, 2, 4, 4, 1, 0,
- 0, 1, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 3, 1, 0,
- 0, 0, 1, 3, 2, 2, 2, 2, 2, 2, 2, 4, 4, 3, 1, 0,
- 0, 0, 1, 3, 2, 2, 2, 2, 2, 2, 2, 4, 3, 1, 0, 0,
- 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 1, 0, 0,
- 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 4, 3, 1, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 4, 3, 1, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 4, 3, 1, 0, 0, 0
-};
-
-
-////////////////////////////////////////
-// Grabbing Hand Cursor (13x13):
-// Shown when interacting with an object
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Light Peach (0xEDCD96)
-// 3 = Brown (0x8A672F)
-// 4 = Dark Peach (0xE89A62)
-////////////////////////////////////////
-static const byte s_grabbingHandCursor[] = {
- 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 1, 1, 2, 3, 1, 1, 1, 0, 0, 0,
- 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 1, 0,
- 0, 1, 2, 2, 2, 2, 2, 2, 2, 3, 1, 2, 1,
- 0, 1, 1, 2, 2, 2, 4, 2, 4, 2, 2, 4, 1,
- 1, 2, 1, 2, 4, 2, 2, 2, 2, 2, 4, 4, 1,
- 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 3, 1,
- 1, 3, 2, 2, 2, 2, 2, 2, 2, 4, 4, 3, 1,
- 1, 3, 2, 2, 2, 2, 2, 2, 2, 4, 3, 1, 0,
- 0, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 1, 0,
- 0, 0, 1, 2, 2, 2, 2, 2, 4, 3, 1, 0, 0,
- 0, 0, 0, 1, 2, 2, 2, 2, 4, 3, 1, 0, 0,
- 0, 0, 0, 1, 2, 2, 2, 2, 4, 3, 1, 0, 0
-};
-
-
-////////////////////////////////////////
-// Standard Hand Cursor (15x16):
-// Standard Cursor
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Light Peach (0xEDCD96)
-// 3 = Brown (0x8A672F)
-// 4 = Dark Peach (0xE89A62)
-////////////////////////////////////////
-static const byte s_standardHandCursor[] = {
- 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 4, 4, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 2, 3, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 2, 4, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 2, 4, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 2, 4, 1, 0, 0, 0, 0, 0, 0,
- 0, 1, 1, 0, 0, 1, 2, 4, 1, 1, 1, 1, 1, 0, 0,
- 1, 4, 2, 1, 0, 1, 2, 4, 1, 4, 1, 4, 1, 1, 1,
- 0, 1, 3, 2, 1, 1, 2, 4, 1, 4, 1, 4, 1, 4, 1,
- 0, 0, 1, 4, 2, 1, 2, 2, 4, 2, 4, 2, 1, 4, 1,
- 0, 0, 1, 4, 2, 1, 2, 2, 2, 2, 2, 2, 2, 3, 1,
- 0, 0, 0, 1, 4, 2, 2, 2, 2, 2, 2, 2, 4, 3, 1,
- 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 4, 3, 1,
- 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 3, 1, 0,
- 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 4, 3, 1, 0,
- 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 4, 3, 1, 0
-};
-
-
-////////////////////////////////////////
-// Pointing Left Cursor (15x13):
-// Cursor When Over A Hotspot That Allows You To Move Left
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Light Peach (0xEDCD96)
-// 3 = Brown (0x8A672F)
-// 4 = Dark Peach (0xE89A62)
-////////////////////////////////////////
-static const byte s_pointingLeftCursor[] = {
- 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 3, 2, 2, 2, 1, 1, 0, 0,
- 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 3, 1, 1,
- 1, 4, 2, 2, 2, 2, 1, 2, 3, 2, 2, 2, 4, 4, 4,
- 1, 4, 4, 4, 4, 4, 1, 2, 1, 3, 4, 2, 2, 2, 2,
- 0, 1, 1, 1, 1, 1, 1, 2, 1, 3, 3, 4, 2, 2, 2,
- 0, 0, 0, 0, 0, 1, 1, 1, 1, 3, 3, 3, 4, 4, 2,
- 0, 0, 0, 0, 0, 1, 2, 2, 2, 4, 1, 3, 4, 2, 2,
- 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 3, 4, 2, 2,
- 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 1, 4, 2, 4,
- 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 4, 4, 1,
- 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 1, 1, 1, 0,
- 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0
-};
-
-
-////////////////////////////////////////
-// Pointing Right Cursor (15x13):
-// Cursor When Over A Hotspot That Allows You To Move Right
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Light Peach (0xEDCD96)
-// 3 = Brown (0x8A672F)
-// 4 = Dark Peach (0xE89A62)
-////////////////////////////////////////
-static const byte s_pointingRightCursor[] = {
- 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 1, 2, 2, 2, 3, 1, 0, 0, 0, 0, 0, 0,
- 1, 1, 3, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0,
- 4, 4, 4, 2, 2, 2, 3, 2, 1, 4, 4, 4, 4, 4, 1,
- 2, 2, 2, 2, 4, 3, 1, 2, 1, 2, 2, 2, 2, 4, 1,
- 2, 2, 2, 4, 3, 3, 1, 2, 1, 1, 1, 1, 1, 1, 0,
- 2, 4, 4, 3, 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 0,
- 2, 2, 4, 3, 1, 4, 2, 2, 2, 1, 0, 0, 0, 0, 0,
- 2, 2, 4, 3, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
- 4, 2, 4, 1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0,
- 1, 4, 4, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
- 0, 1, 1, 1, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0
-};
-
-
-////////////////////////////////////////
-// Pointing Down Cursor (Palm Up)(13x16):
-// Cursor When Over A Hotspot That Allows You To Move Down
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Light Peach (0xEDCD96)
-// 3 = Brown (0x8A672F)
-// 4 = Dark Peach (0xE89A62)
-////////////////////////////////////////
-static const byte s_pointingDownCursorPalmUp[] = {
- 0, 0, 1, 4, 2, 2, 2, 2, 2, 4, 1, 0, 0,
- 0, 0, 1, 4, 2, 2, 4, 2, 2, 2, 4, 1, 0,
- 0, 1, 3, 4, 2, 2, 4, 4, 4, 4, 4, 1, 0,
- 0, 1, 4, 2, 2, 4, 3, 3, 3, 1, 1, 1, 1,
- 1, 2, 2, 2, 4, 3, 3, 1, 1, 2, 1, 2, 1,
- 1, 2, 2, 2, 3, 3, 3, 4, 1, 2, 1, 2, 1,
- 1, 2, 2, 3, 1, 1, 1, 2, 1, 2, 1, 2, 1,
- 1, 3, 2, 2, 2, 2, 1, 2, 1, 2, 1, 2, 1,
- 0, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1,
- 0, 0, 1, 2, 4, 1, 1, 1, 1, 1, 1, 0, 0,
- 0, 0, 1, 2, 4, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 2, 4, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 2, 4, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 2, 4, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-
-////////////////////////////////////////
-// Pointing Up Cursor (Palm Up)(13x16):
-// Cursor When Over A Hotspot That Allows You To Move Up
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Light Peach (0xEDCD96)
-// 3 = Brown (0x8A672F)
-// 4 = Dark Peach (0xE89A62)
-////////////////////////////////////////
-static const byte s_pointingUpCursorPalmUp[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 4, 4, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 1, 0, 0,
- 0, 0, 1, 1, 1, 1, 1, 1, 2, 4, 1, 0, 0,
- 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 0,
- 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 3, 1,
- 1, 2, 1, 2, 1, 2, 1, 1, 1, 3, 2, 2, 1,
- 1, 2, 1, 2, 1, 4, 3, 3, 3, 2, 2, 2, 1,
- 1, 2, 1, 2, 1, 1, 3, 3, 4, 2, 2, 2, 1,
- 1, 1, 1, 1, 3, 3, 3, 4, 2, 2, 4, 1, 0,
- 0, 1, 4, 4, 4, 4, 4, 2, 2, 4, 3, 1, 0,
- 0, 1, 4, 2, 2, 2, 4, 2, 2, 4, 1, 0, 0,
- 0, 0, 1, 4, 2, 2, 2, 2, 2, 4, 1, 0, 0
-};
-
-
-////////////////////////////////////////
-// Pointing Left Cursor (Bent)(15x13):
-// Cursor When Over A Hotspot That Allows You To Turn Left 180 Degrees
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Light Peach (0xEDCD96)
-// 3 = Brown (0x8A672F)
-// 4 = Dark Peach (0xE89A62)
-////////////////////////////////////////
-static const byte s_pointingLeftCursorBent[] = {
- 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 3, 2, 2, 2, 1, 1, 0, 0,
- 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 3, 1, 1,
- 1, 3, 2, 4, 4, 2, 1, 2, 3, 3, 2, 2, 4, 4, 4,
- 1, 2, 4, 3, 3, 4, 1, 2, 1, 3, 4, 2, 2, 2, 2,
- 1, 4, 4, 1, 1, 1, 1, 2, 1, 1, 3, 4, 2, 2, 2,
- 1, 1, 1, 0, 0, 1, 1, 1, 1, 3, 3, 3, 4, 4, 2,
- 0, 0, 0, 0, 0, 1, 2, 2, 2, 4, 1, 3, 4, 3, 2,
- 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 3, 4, 2, 2,
- 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 1, 4, 2, 4,
- 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 4, 4, 1,
- 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 1, 1, 1, 0,
- 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0
-};
-
-
-////////////////////////////////////////
-// Pointing Right Cursor (Bent)(15x13):
-// Cursor When Over A Hotspot That Allows You To Turn Right 180 Degrees
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Light Peach (0xEDCD96)
-// 3 = Brown (0x8A672F)
-// 4 = Dark Peach (0xE89A62)
-////////////////////////////////////////
-static const byte s_pointingRightCursorBent[] = {
- 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 1, 2, 2, 2, 3, 1, 0, 0, 0, 0, 0, 0,
- 1, 1, 3, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0,
- 4, 4, 4, 2, 2, 3, 3, 2, 1, 2, 4, 4, 2, 3, 1,
- 2, 2, 2, 2, 4, 3, 1, 2, 1, 4, 3, 3, 4, 2, 1,
- 2, 2, 2, 4, 3, 1, 1, 2, 1, 1, 1, 1, 4, 4, 1,
- 2, 4, 4, 3, 3, 3, 1, 1, 1, 1, 0, 0, 1, 1, 1,
- 2, 3, 4, 3, 1, 4, 2, 2, 2, 1, 0, 0, 0, 0, 0,
- 2, 2, 4, 3, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
- 4, 2, 4, 1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0,
- 1, 4, 4, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
- 0, 1, 1, 1, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0
-};
-
-
-////////////////////////////////////////
-// Pointing Down Cursor (Palm Down)(15x16):
-// Similar to Standard Cursor
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Light Peach (0xEDCD96)
-// 3 = Brown (0x8A672F)
-// 4 = Dark Peach (0xE89A62)
-////////////////////////////////////////
-static const byte s_pointingDownCursorPalmDown[] = {
- 0, 1, 3, 4, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0,
- 0, 1, 3, 4, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0,
- 0, 1, 3, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0,
- 1, 3, 4, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0,
- 1, 3, 4, 2, 2, 2, 2, 2, 2, 2, 4, 1, 0, 0, 0,
- 1, 3, 2, 3, 2, 2, 2, 2, 2, 1, 2, 4, 1, 0, 0,
- 1, 4, 1, 2, 2, 3, 2, 3, 2, 1, 2, 4, 1, 0, 0,
- 1, 4, 1, 4, 1, 4, 1, 4, 4, 1, 1, 2, 3, 1, 0,
- 0, 1, 1, 4, 1, 4, 1, 4, 2, 1, 0, 1, 2, 4, 1,
- 0, 0, 1, 1, 1, 1, 1, 4, 2, 1, 0, 0, 1, 1, 0,
- 0, 0, 0, 0, 0, 0, 1, 4, 4, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 4, 2, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 4, 2, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 3, 2, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 4, 4, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0
-};
-
-////////////////////////////////////////
-// Hand Cursor Palette:
-// Palette For All Hand Cursors
-////////////////////////////////////////
-static const byte s_handCursorPalette[] = {
- 0x00, 0x00, 0x00, // Black
- 0xED, 0xCD, 0x96, // Light Peach
- 0x8A, 0x67, 0x2F, // Brown
- 0xE8, 0x9A, 0x62 // Dark Peach
-};
-
-
-////////////////////////////////////////
-// Pellet Cursor (8x8):
-// Cursor When Using The Pellet In The Frog Trap
-//
-// 0 = Transparent
-// 1 = Light Olive Green (0x5D6730)
-// 2 = Maroon (0x5E3333)
-// 3 = Light Gray (0x555555)
-// 4 = Medium Gray (0x444444)
-// 5 = Dark Gray (0x333333)
-// 6 = Dark Green (0x2D3300)
-// 7 = Darkest Gray (0x222222)
-////////////////////////////////////////
-static const byte s_pelletCursor[] = {
- 0, 0, 1, 1, 2, 3, 0, 0,
- 0, 2, 1, 4, 1, 2, 5, 0,
- 4, 1, 4, 1, 2, 1, 5, 4,
- 4, 2, 1, 2, 1, 1, 2, 6,
- 6, 4, 2, 1, 4, 4, 1, 5,
- 5, 6, 5, 2, 1, 2, 4, 4,
- 0, 7, 5, 5, 4, 2, 5, 0,
- 0, 0, 5, 6, 6, 5, 0, 0
-};
-
-////////////////////////////////////////
-// Pellet Cursor Palette:
-// Palette For The Pellet Cursor
-////////////////////////////////////////
-static const byte s_pelletCursorPalette[] = {
- 0x5D, 0x67, 0x30,
- 0x5E, 0x33, 0x33,
- 0x55, 0x55, 0x55,
- 0x44, 0x44, 0x44,
- 0x33, 0x33, 0x33,
- 0x2D, 0x33, 0x00,
- 0x22, 0x22, 0x22
-};
-
-////////////////////////////////////////
-// Red Marble Cursor (12x12):
-// Cursor When Holding The Red Marble
-////////////////////////////////////////
-static const byte s_redMarbleCursor[] = {
- 0, 0, 0, 0, 1, 2, 2, 2, 0, 0, 0, 0,
- 0, 0, 3, 4, 2, 5, 2, 2, 2, 2, 0, 0,
- 0, 6, 1, 1, 2, 2, 5, 2, 2, 2, 2, 0,
- 0, 6, 3, 4, 5, 2, 2, 7, 8, 5, 2, 0,
- 9, 6, 10,11,2, 2, 2, 12,13,2, 2, 2,
- 14,10,6, 4, 1, 2, 8, 2, 2, 5, 2, 2,
- 15,16,6, 3, 1, 2, 2, 2, 2, 2, 2, 5,
- 17,9,18, 3, 4, 4, 4, 5, 2, 5, 1, 2,
- 0, 16,9, 6, 6, 19,1, 20,1, 4, 11,0,
- 0, 17,15,18,9, 10,6, 10,3, 21,4, 0,
- 0, 0, 18,15,9, 18,6, 22,10,23,0, 0,
- 0, 0, 0, 0, 15,15,16,9, 0, 0, 0, 0
-};
-
-
-////////////////////////////////////////
-// Red Marble Cursor Palette:
-// Palette For The Red Marble Cursor
-////////////////////////////////////////
-static const byte s_redMarbleCursorPalette[] = {
- 0xb8, 0x33, 0x32,
- 0xe5, 0x33, 0x31,
- 0x98, 0x06, 0x00,
- 0xb8, 0x00, 0x34,
- 0xe6, 0x00, 0x34,
- 0x7a, 0x04, 0x00,
- 0xe8, 0x9a, 0x62,
- 0xea, 0x31, 0x67,
- 0x6a, 0x03, 0x00,
- 0x8c, 0x00, 0x35,
- 0xb6, 0x36, 0x00,
- 0xed, 0xcd, 0x96,
- 0xe9, 0x66, 0x65,
- 0x5b, 0x35, 0x00,
- 0x5b, 0x02, 0x00,
- 0x5f, 0x00, 0x35,
- 0x4c, 0x01, 0x00,
- 0x5e, 0x33, 0x33,
- 0x89, 0x05, 0x00,
- 0xb6, 0x08, 0x00,
- 0xa7, 0x07, 0x00,
- 0x88, 0x36, 0x00,
- 0x8b, 0x33, 0x33
-};
-
-////////////////////////////////////////
-// Orange Marble Cursor (12x12):
-// Cursor When Holding The Orange Marble
-////////////////////////////////////////
-static const byte s_orangeMarbleCursor[] = {
- 0, 0, 0, 0, 1, 2, 2, 3, 0, 0, 0, 0,
- 0, 0, 4, 5, 2, 2, 3, 3, 3, 3, 0, 0,
- 0, 6, 7, 4, 2, 1, 2, 2, 3, 3, 3, 0,
- 0, 6, 6, 7, 1, 2, 3, 8, 9, 2, 10,0,
- 11,12,7, 4, 2, 3, 3, 13,9, 2, 2, 1,
- 14,15,6, 4, 2, 16,3, 3, 2, 1, 1, 1,
- 14,14,12,17,4, 2, 2, 1, 2, 1, 2, 1,
- 14,18,12,6, 4, 4, 4, 19,2, 19,20,4,
- 0, 14,14,15,6, 15,6, 4, 4, 4, 4, 0,
- 0, 14,11,14,14,12,12,12,17,6, 17,0,
- 0, 0, 14,14,17,14,17,6, 6, 17,0, 0,
- 0, 0, 0, 0, 14,11,14,11,0, 0, 0, 0
-};
-
-////////////////////////////////////////
-// Orange Marble Cursor Palette:
-// Palette For The Orange Marble Cursor
-////////////////////////////////////////
-static const byte s_orangeMarbleCursorPalette[] = {
- 0xe1, 0x9e, 0x00,
- 0xe3, 0x9b, 0x28,
- 0xe2, 0xcf, 0x20,
- 0xb5, 0x6a, 0x00,
- 0xb6, 0x9b, 0x29,
- 0x87, 0x69, 0x00,
- 0xb7, 0x67, 0x2f,
- 0xe9, 0xff, 0x93,
- 0xe1, 0xff, 0x5a,
- 0xe0, 0xd0, 0x00,
- 0x5e, 0x33, 0x33,
- 0x88, 0x36, 0x00,
- 0xf3, 0xff, 0xc9,
- 0x5b, 0x35, 0x00,
- 0x8b, 0x33, 0x33,
- 0xe6, 0xce, 0x5f,
- 0x8a, 0x67, 0x2f,
- 0x5d, 0x67, 0x30,
- 0xe2, 0x6a, 0x00,
- 0xb3, 0x9d, 0x00
-};
-
-////////////////////////////////////////
-// Yellow Marble Cursor (12x12):
-// Cursor When Holding The Yellow Marble
-////////////////////////////////////////
-static const byte s_yellowMarbleCursor[] = {
- 0, 0, 0, 0, 1, 1, 1, 2, 0, 0, 0, 0,
- 0, 0, 3, 4, 1, 1, 1, 5, 6, 6, 0, 0,
- 0, 3, 3, 7, 1, 1, 1, 1, 2, 1, 6, 0,
- 0, 3, 3, 3, 3, 1, 1, 8, 6, 1, 6, 0,
- 9, 9, 3, 3, 1, 1, 2, 10,8, 1, 1, 2,
- 11,9, 3, 3, 1, 1, 1, 1, 1, 1, 5, 1,
- 9, 9, 12,3, 3, 1, 1, 1, 1, 1, 1, 1,
- 9, 9, 9, 3, 3, 3, 3, 3, 1, 1, 1, 1,
- 0, 11,9, 9, 12,3, 3, 3, 3, 3, 3, 0,
- 0, 9, 9, 13,9, 14,12,3, 3, 3, 3, 0,
- 0, 0, 9, 9, 9, 12,14,3, 13,3, 0, 0,
- 0, 0, 0, 0, 11,9, 11,9, 0, 0, 0, 0
-};
-
-////////////////////////////////////////
-// Yellow Marble Cursor Palette:
-// Palette For The Yellow Marble Cursor
-////////////////////////////////////////
-static const byte s_yellowMarbleCursorPalette[] = {
- 0xb3, 0xd0, 0x00,
- 0xb0, 0xff, 0x00,
- 0x86, 0x9c, 0x00,
- 0x87, 0xd0, 0x00,
- 0xe0, 0xd0, 0x00,
- 0xdc, 0xff, 0x00,
- 0xb3, 0x9d, 0x00,
- 0xdc, 0xff, 0x11,
- 0x5a, 0x68, 0x00,
- 0xe1, 0xff, 0x5a,
- 0x5d, 0x67, 0x30,
- 0x87, 0x69, 0x00,
- 0x88, 0x9b, 0x2a,
- 0x5a, 0x9c, 0x00
-};
-
-////////////////////////////////////////
-// Green Marble Cursor (12x12):
-// Cursor When Holding The Green Marble
-////////////////////////////////////////
-static const byte s_greenMarbleCursor[] = {
- 0, 0, 0, 0, 1, 2, 3, 3, 0, 0, 0, 0,
- 0, 0, 4, 5, 2, 1, 2, 3, 6, 6, 0, 0,
- 0, 7, 5, 8, 8, 1, 1, 2, 3, 6, 6, 0,
- 0, 7, 7, 4, 8, 1, 2, 9, 6, 2, 6, 0,
- 10,7, 7, 4, 1, 2, 3, 11,12,2, 2, 3,
- 13,13,7, 4, 1, 2, 3, 2, 1, 2, 2, 3,
- 14,13,7, 7, 5, 1, 1, 8, 2, 1, 1, 2,
- 15,16,13,7, 4, 4, 5, 5, 1, 8, 1, 1,
- 0, 15,13,7, 7, 7, 4, 4, 4, 5, 8, 0,
- 0, 14,16,15,13, 7, 7, 7, 4,17,5, 0,
- 0, 0, 10,16,13,13,13,17,18,17,0, 0,
- 0, 0, 0, 0, 15,10,19,10,0, 0, 0, 0
-};
-
-////////////////////////////////////////
-// Green Marble Cursor Palette:
-// Palette For The Green Marble Cursor
-////////////////////////////////////////
-static const byte s_greenMarbleCursorPalette[] = {
- 0x0e, 0xd0, 0x00,
- 0x0f, 0xe1, 0x00,
- 0x10, 0xf2, 0x00,
- 0x0b, 0x9c, 0x00,
- 0x0c, 0xad, 0x00,
- 0x11, 0xff, 0x00,
- 0x09, 0x8a, 0x00,
- 0x0d, 0xbe, 0x00,
- 0x30, 0xff, 0x5a,
- 0x0d, 0x67, 0x30,
- 0x6b, 0xff, 0x92,
- 0x00, 0xff, 0x28,
- 0x08, 0x79, 0x00,
- 0x05, 0x57, 0x00,
- 0x30, 0x67, 0x30,
- 0x06, 0x68, 0x00,
- 0x00, 0x9b, 0x2c,
- 0x2e, 0x9c, 0x00,
- 0x2e, 0x68, 0x00
-};
-
-////////////////////////////////////////
-// Blue Marble Cursor (12x12):
-// Cursor When Holding The Blue Marble
-////////////////////////////////////////
-static const byte s_blueMarbleCursor[] = {
- 0, 0, 0, 0, 1, 2, 3, 3, 0, 0, 0, 0,
- 0, 0, 4, 5, 2, 2, 6, 3, 7, 3, 0, 0,
- 0, 8, 9, 5, 10,11,2, 6, 3, 3, 7, 0,
- 0, 12,13,9, 10,11,6, 14,7, 6, 3, 0,
- 15,8, 4, 13,2, 6, 3, 16,17,6, 6, 3,
- 18,15,19,13,10,7, 3, 6, 2, 2, 6, 7,
- 20,8, 18,4, 21,11,2, 10,6, 2, 2, 2,
- 15,15,18,8, 13,9, 21,5, 11,10,2, 1,
- 0, 8, 15,19,15,13,13,21,21,5, 9, 0,
- 0, 22,20,15, 8,19,15,19,4, 9, 4, 0,
- 0, 0, 15,20,15,15,19,15,9, 15,0, 0,
- 0, 0, 0, 0, 20,15, 8,15,0, 0, 0, 0
-};
-
-////////////////////////////////////////
-// Blue Marble Cursor Palette:
-// Palette For The Blue Marble Cursor
-////////////////////////////////////////
-static const byte s_blueMarbleCursorPalette[] = {
- 0x6b, 0x00, 0xd2,
- 0x66, 0x00, 0xe3,
- 0x72, 0x00, 0xff,
- 0x53, 0x2d, 0x9d,
- 0x4e, 0x00, 0xaf,
- 0x6d, 0x00, 0xf5,
- 0x7d, 0x00, 0xff,
- 0x44, 0x00, 0x69,
- 0x56, 0x00, 0x9d,
- 0x56, 0x00, 0xc0,
- 0x5e, 0x00, 0xd2,
- 0x2b, 0x31, 0x68,
- 0x3f, 0x00, 0x8c,
- 0x91, 0x22, 0xff,
- 0x41, 0x31, 0x68,
- 0xd7, 0x95, 0xff,
- 0x77, 0x22, 0xff,
- 0x2f, 0x00, 0x69,
- 0x37, 0x00, 0x7a,
- 0x27, 0x00, 0x58,
- 0x46, 0x00, 0x9d,
- 0x33, 0x33, 0x33
-};
-
-////////////////////////////////////////
-// Violet Marble Cursor (12x12):
-// Cursor When Holding The Violet Marble
-////////////////////////////////////////
-static const byte s_violetMarbleCursor[] = {
- 0, 0, 0, 0, 1, 1, 1, 2, 0, 0, 0, 0,
- 0, 0, 3, 3, 1, 1, 1, 4, 2, 4, 0, 0,
- 0, 3, 3, 3, 1, 5, 1, 1, 4, 2, 4, 0,
- 0, 3, 3, 3, 3, 1, 1, 6, 4, 1, 2, 0,
- 3, 7, 8, 3, 1, 1, 4, 9, 4, 1, 1, 4,
- 8, 7, 8, 3, 10,4, 1, 1, 1, 1, 4, 1,
- 8, 3, 8, 7, 3, 1, 1, 5, 1, 1, 1, 1,
- 7, 7, 11,3, 3, 3, 3, 3, 1, 3, 1, 1,
- 0, 8, 7, 7, 8, 8, 7, 3, 3, 3, 1, 0,
- 0, 7, 8, 3, 11,7, 3, 11,3, 10,3, 0,
- 0, 0, 8, 7, 3, 3, 7, 3, 3, 3, 0, 0,
- 0, 0, 0, 0, 8, 7, 11,3, 0, 0, 0, 0
-};
-
-////////////////////////////////////////
-// Violet Marble Cursor Palette:
-// Palette For The Violet Marble Cursor
-////////////////////////////////////////
-static const byte s_violetMarbleCursorPalette[] = {
- 0xaa, 0x00, 0xd1,
- 0xd8, 0x00, 0xff,
- 0x76, 0x00, 0x9d,
- 0xb5, 0x00, 0xff,
- 0x87, 0x00, 0xd2,
- 0xd7, 0x22, 0xff,
- 0x68, 0x00, 0x69,
- 0x44, 0x00, 0x69,
- 0xd7, 0x5e, 0xff,
- 0x9c, 0x00, 0x9d,
- 0x56, 0x00, 0x9d
-};
-
-} // End of namespace Mohawk
diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp
index 7da5515411..e6ea25c9a6 100644
--- a/engines/mohawk/riven_external.cpp
+++ b/engines/mohawk/riven_external.cpp
@@ -316,6 +316,7 @@ void RivenExternal::checkSliderCursorChange(uint16 startHotspot) {
_vm->_cursor->setCursor(kRivenOpenHandCursor);
else
_vm->_cursor->setCursor(kRivenMainCursor);
+ _vm->_system->updateScreen();
break;
}
}
@@ -341,6 +342,7 @@ void RivenExternal::dragDomeSlider(uint16 soundId, uint16 resetSlidersHotspot, u
// We've clicked down, so show the closed hand cursor
_vm->_cursor->setCursor(kRivenClosedHandCursor);
+ _vm->_system->updateScreen();
bool done = false;
while (!done) {
@@ -862,6 +864,7 @@ void RivenExternal::xbcheckcatch(uint16 argc, uint16 *argv) {
void RivenExternal::xbait(uint16 argc, uint16 *argv) {
// Set the cursor to the pellet
_vm->_cursor->setCursor(kRivenPelletCursor);
+ _vm->_system->updateScreen();
// Loop until the player lets go (or quits)
Common::Event event;
@@ -881,6 +884,7 @@ void RivenExternal::xbait(uint16 argc, uint16 *argv) {
// Set back the cursor
_vm->_cursor->setCursor(kRivenMainCursor);
+ _vm->_system->updateScreen();
// Set the bait if we put it on the plate
if (_vm->_hotspots[9].rect.contains(_vm->_system->getEventManager()->getMousePos())) {
@@ -899,8 +903,8 @@ void RivenExternal::xbfreeytram(uint16 argc, uint16 *argv) {
void RivenExternal::xbaitplate(uint16 argc, uint16 *argv) {
// Remove the pellet from the plate and put it in your hand
_vm->_gfx->drawPLST(3);
- _vm->_gfx->updateScreen();
_vm->_cursor->setCursor(kRivenPelletCursor);
+ _vm->_gfx->updateScreen();
// Loop until the player lets go (or quits)
Common::Event event;
@@ -920,6 +924,7 @@ void RivenExternal::xbaitplate(uint16 argc, uint16 *argv) {
// Set back the cursor
_vm->_cursor->setCursor(kRivenMainCursor);
+ _vm->_system->updateScreen();
// Set the bait if we put it on the plate, remove otherwise
if (_vm->_hotspots[9].rect.contains(_vm->_system->getEventManager()->getMousePos())) {
@@ -988,23 +993,27 @@ void RivenExternal::xvalvecontrol(uint16 argc, uint16 *argv) {
if (*valve == 0 && changeY <= -10) {
*valve = 1;
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
_vm->_video->playMovieBlockingRiven(2);
_vm->refreshCard();
} else if (*valve == 1) {
if (changeX >= 0 && changeY >= 10) {
*valve = 0;
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
_vm->_video->playMovieBlockingRiven(3);
_vm->refreshCard();
} else if (changeX <= -10 && changeY <= 10) {
*valve = 2;
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
_vm->_video->playMovieBlockingRiven(1);
_vm->refreshCard();
}
} else if (*valve == 2 && changeX >= 10) {
*valve = 1;
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
_vm->_video->playMovieBlockingRiven(4);
_vm->refreshCard();
}
@@ -1219,6 +1228,7 @@ void RivenExternal::xgisland1490_domecheck(uint16 argc, uint16 *argv) {
void RivenExternal::xgplateau3160_dopools(uint16 argc, uint16 *argv) {
// Play the deactivation of a pool if one is active and a different one is activated
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
_vm->_video->playMovieBlockingRiven(*_vm->getVar("glkbtns") * 2);
}
@@ -1522,11 +1532,13 @@ void RivenExternal::xvga1300_carriage(uint16 argc, uint16 *argv) {
// Run the gallows's carriage
_vm->_cursor->setCursor(kRivenHideCursor); // Hide the cursor
- _vm->_video->playMovieBlockingRiven(1); // Play handle movie
+ _vm->_system->updateScreen(); // Update
+ _vm->_video->playMovieBlockingRiven(1); // Play handle movie
_vm->_gfx->scheduleTransition(15); // Set pan down transition
_vm->changeToCard(_vm->matchRMAPToCard(0x18e77)); // Change to card facing up
_vm->_cursor->setCursor(kRivenHideCursor); // Hide the cursor (again)
- _vm->_video->playMovieBlockingRiven(4); // Play carriage beginning to drop
+ _vm->_system->updateScreen(); // Update
+ _vm->_video->playMovieBlockingRiven(4); // Play carriage beginning to drop
_vm->_gfx->scheduleTransition(14); // Set pan up transition
_vm->changeToCard(_vm->matchRMAPToCard(0x183a9)); // Change to card looking straight again
_vm->_video->playMovieBlockingRiven(2);
@@ -1560,19 +1572,22 @@ void RivenExternal::xvga1300_carriage(uint16 argc, uint16 *argv) {
}
_vm->_cursor->setCursor(kRivenHideCursor); // Hide the cursor
+ _vm->_system->updateScreen(); // Update
if (gotClick) {
_vm->_gfx->scheduleTransition(16); // Schedule dissolve transition
_vm->changeToCard(_vm->matchRMAPToCard(0x18d4d)); // Move forward
_vm->_cursor->setCursor(kRivenHideCursor); // Hide the cursor
+ _vm->_system->updateScreen(); // Update
_vm->_system->delayMillis(500); // Delay a half second before changing again
_vm->_gfx->scheduleTransition(12); // Schedule pan left transition
_vm->changeToCard(_vm->matchRMAPToCard(0x18ab5)); // Turn right
_vm->_cursor->setCursor(kRivenHideCursor); // Hide the cursor
- _vm->_video->playMovieBlockingRiven(1); // Play carriage ride movie
+ _vm->_system->updateScreen(); // Update
+ _vm->_video->playMovieBlockingRiven(1); // Play carriage ride movie
_vm->changeToCard(_vm->matchRMAPToCard(0x17167)); // We have arrived at the top
} else
- _vm->_video->playMovieBlockingRiven(3); // Too slow!
+ _vm->_video->playMovieBlockingRiven(3); // Too slow!
}
void RivenExternal::xjdome25_resetsliders(uint16 argc, uint16 *argv) {
@@ -1603,6 +1618,7 @@ int RivenExternal::jspitElevatorLoop() {
_vm->_cursor->setCursor(kRivenClosedHandCursor);
_vm->_system->updateScreen();
+
for (;;) {
while (_vm->_system->getEventManager()->pollEvent(event)) {
switch (event.type) {
@@ -1766,6 +1782,7 @@ void RivenExternal::xschool280_playwhark(uint16 argc, uint16 *argv) {
// Hide the cursor
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
// Play the spin movie
_vm->_video->playMovieBlockingRiven(spinMLST);
@@ -1831,6 +1848,7 @@ void RivenExternal::xorollcredittime(uint16 argc, uint16 *argv) {
void RivenExternal::xbookclick(uint16 argc, uint16 *argv) {
// Hide the cursor
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
// Let's hook onto our video
VideoHandle video = _vm->_video->findVideoHandleRiven(argv[0]);
@@ -1873,6 +1891,8 @@ void RivenExternal::xbookclick(uint16 argc, uint16 *argv) {
_vm->_cursor->setCursor(kRivenOpenHandCursor);
else
_vm->_cursor->setCursor(kRivenMainCursor);
+
+ _vm->_system->updateScreen();
// OK, Gehn has opened the trap book and has asked us to go in. Let's watch
// and see what the player will do...
@@ -1887,7 +1907,7 @@ void RivenExternal::xbookclick(uint16 argc, uint16 *argv) {
_vm->_cursor->setCursor(kRivenOpenHandCursor);
else
_vm->_cursor->setCursor(kRivenMainCursor);
- updateScreen = false; // Don't update twice, changing the cursor already updates the screen
+ updateScreen = true;
break;
case Common::EVENT_LBUTTONUP:
if (hotspotRect.contains(_vm->_system->getEventManager()->getMousePos())) {
@@ -1899,7 +1919,7 @@ void RivenExternal::xbookclick(uint16 argc, uint16 *argv) {
_vm->_gfx->updateScreen(); // Update the screen
_vm->_sound->playSound(0); // Play the link sound
_vm->_video->activateMLST(7, _vm->getCurCard()); // Activate Gehn Link Video
- _vm->_video->playMovieBlockingRiven(1); // Play Gehn Link Video
+ _vm->_video->playMovieBlockingRiven(1); // Play Gehn Link Video
*_vm->getVar("agehn") = 4; // Set Gehn to the trapped state
*_vm->getVar("atrapbook") = 1; // We've got the trap book again
_vm->_sound->playSound(0); // Play the link sound again
@@ -1924,6 +1944,7 @@ void RivenExternal::xbookclick(uint16 argc, uint16 *argv) {
// Hide the cursor again
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
// If there was no click and this is the third time Gehn asks us to
// use the trap book, he will shoot the player. Dead on arrival.
@@ -2012,6 +2033,7 @@ uint16 RivenExternal::getComboDigit(uint32 correctCombo, uint32 digit) {
void RivenExternal::xgwatch(uint16 argc, uint16 *argv) {
// Hide the cursor
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
uint32 *prisonCombo = _vm->getVar("pcorrectorder");
uint32 soundTime = _vm->_system->getMillis() - 500; // Start the first sound instantly
@@ -2173,6 +2195,7 @@ void RivenExternal::xtexterior300_telescopedown(uint16 argc, uint16 *argv) {
// ...the telescope can't move down anymore.
// Play the sound of not being able to move
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
_vm->_sound->playSoundBlocking(13);
}
} else {
@@ -2206,6 +2229,7 @@ void RivenExternal::xtexterior300_telescopeup(uint16 argc, uint16 *argv) {
if (*telescopePos == 5) {
// Play the sound of not being able to move
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
_vm->_sound->playSoundBlocking(13);
return;
}
diff --git a/engines/mohawk/riven_scripts.cpp b/engines/mohawk/riven_scripts.cpp
index 5d459354e9..98452e1e09 100644
--- a/engines/mohawk/riven_scripts.cpp
+++ b/engines/mohawk/riven_scripts.cpp
@@ -424,6 +424,7 @@ void RivenScript::stopSound(uint16 op, uint16 argc, uint16 *argv) {
void RivenScript::changeCursor(uint16 op, uint16 argc, uint16 *argv) {
debug(2, "Change to cursor %d", argv[0]);
_vm->_cursor->setCursor(argv[0]);
+ _vm->_system->updateScreen();
}
// Command 14: pause script execution (delay in ms, u1)
diff --git a/engines/sci/graphics/cursor.cpp b/engines/sci/graphics/cursor.cpp
index 09f08e4b15..9d1c3dabd6 100644
--- a/engines/sci/graphics/cursor.cpp
+++ b/engines/sci/graphics/cursor.cpp
@@ -26,6 +26,7 @@
#include "common/config-manager.h"
#include "common/events.h"
#include "common/macresman.h"
+#include "common/memstream.h"
#include "common/system.h"
#include "common/util.h"
#include "graphics/cursorman.h"
@@ -491,8 +492,8 @@ void GfxCursor::kernelSetMacCursor(GuiResourceId viewNum, int loopNum, int celNu
cursorBitmap[i * 8 + b] = 0; // Doesn't matter, just is transparent
}
- uint16 hotspotX = READ_BE_UINT16(data);
- uint16 hotspotY = READ_BE_UINT16(data + 2);
+ uint16 hotspotY = READ_BE_UINT16(data);
+ uint16 hotspotX = READ_BE_UINT16(data + 2);
static const byte cursorPalette[] = { 0x00, 0x00, 0x00, 0xff, 0xff, 0xff };
@@ -504,11 +505,12 @@ void GfxCursor::kernelSetMacCursor(GuiResourceId viewNum, int loopNum, int celNu
// Mac crsr cursor
byte *cursorBitmap, *palette;
int width, height, hotspotX, hotspotY, palSize, keycolor;
- Common::MacResManager::convertCrsrCursor(resource->data, resource->size, &cursorBitmap, &width, &height, &hotspotX, &hotspotY, &keycolor, true, &palette, &palSize);
+ Common::MemoryReadStream resStream(resource->data, resource->size);
+ Common::MacResManager::convertCrsrCursor(&resStream, &cursorBitmap, width, height, hotspotX, hotspotY, keycolor, true, &palette, palSize);
CursorMan.replaceCursor(cursorBitmap, width, height, hotspotX, hotspotY, keycolor);
CursorMan.replaceCursorPalette(palette, 0, palSize);
- free(cursorBitmap);
- free(palette);
+ delete[] cursorBitmap;
+ delete[] palette;
}
kernelShow();
diff --git a/engines/scumm/he/resource_he.cpp b/engines/scumm/he/resource_he.cpp
index 72e7052034..9349e70eb9 100644
--- a/engines/scumm/he/resource_he.cpp
+++ b/engines/scumm/he/resource_he.cpp
@@ -4,10 +4,6 @@
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
- * Parts of this code are heavily based on:
- * icoutils - A set of programs dealing with MS Windows icons and cursors.
- * Copyright (C) 1998-2001 Oskar Liljeblad
- *
* 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
@@ -36,6 +32,7 @@
#include "audio/decoders/wave.h"
#include "graphics/cursorman.h"
+#include "graphics/wincursor.h"
#include "common/archive.h"
#include "common/memstream.h"
@@ -43,14 +40,6 @@
namespace Scumm {
-#if defined(SCUMM_LITTLE_ENDIAN)
-#define LE16(x)
-#define LE32(x)
-#elif defined(SCUMM_BIG_ENDIAN)
-#define LE16(x) ((x) = TO_LE_16(x))
-#define LE32(x) ((x) = TO_LE_32(x))
-#endif
-
ResExtractor::ResExtractor(ScummEngine_v70he *scumm)
: _vm(scumm) {
@@ -65,1092 +54,112 @@ ResExtractor::~ResExtractor() {
free(cc->palette);
}
}
+
memset(_cursorCache, 0, sizeof(_cursorCache));
}
ResExtractor::CachedCursor *ResExtractor::findCachedCursor(int id) {
- for (int i = 0; i < MAX_CACHED_CURSORS; ++i) {
- CachedCursor *cc = &_cursorCache[i];
- if (cc->valid && cc->id == id) {
- return cc;
- }
- }
+ for (int i = 0; i < MAX_CACHED_CURSORS; ++i)
+ if (_cursorCache[i].valid && _cursorCache[i].id == id)
+ return &_cursorCache[i];
+
return NULL;
}
ResExtractor::CachedCursor *ResExtractor::getCachedCursorSlot() {
- uint32 min_last_used = 0;
+ uint32 minLastUsed = 0;
CachedCursor *r = NULL;
+
for (int i = 0; i < MAX_CACHED_CURSORS; ++i) {
CachedCursor *cc = &_cursorCache[i];
- if (!cc->valid) {
+ if (!cc->valid)
return cc;
- } else {
- if (min_last_used == 0 || cc->last_used < min_last_used) {
- min_last_used = cc->last_used;
- r = cc;
- }
+
+ if (minLastUsed == 0 || cc->lastUsed < minLastUsed) {
+ minLastUsed = cc->lastUsed;
+ r = cc;
}
}
+
assert(r);
- free(r->bitmap);
- free(r->palette);
+ delete[] r->bitmap;
+ delete[] r->palette;
memset(r, 0, sizeof(CachedCursor));
return r;
}
void ResExtractor::setCursor(int id) {
- byte *cursorRes = 0;
- int cursorsize;
- int keycolor = 0;
CachedCursor *cc = findCachedCursor(id);
+
if (cc != NULL) {
debug(7, "Found cursor %d in cache slot %lu", id, (long)(cc - _cursorCache));
} else {
cc = getCachedCursorSlot();
assert(cc && !cc->valid);
- cursorsize = extractResource(id, &cursorRes);
- convertIcons(cursorRes, cursorsize, &cc->bitmap, &cc->w, &cc->h, &cc->hotspot_x, &cc->hotspot_y, &keycolor, &cc->palette, &cc->palSize);
+
+ if (!extractResource(id, cc))
+ error("Could not extract cursor %d", id);
+
debug(7, "Adding cursor %d to cache slot %lu", id, (long)(cc - _cursorCache));
- free(cursorRes);
+
cc->valid = true;
cc->id = id;
- cc->last_used = g_system->getMillis();
+ cc->lastUsed = g_system->getMillis();
}
if (cc->palette)
CursorMan.replaceCursorPalette(cc->palette, 0, cc->palSize);
- _vm->setCursorHotspot(cc->hotspot_x, cc->hotspot_y);
- _vm->setCursorFromBuffer(cc->bitmap, cc->w, cc->h, cc->w);
+ _vm->setCursorHotspot(cc->hotspotX, cc->hotspotY);
+ _vm->setCursorFromBuffer(cc->bitmap, cc->width, cc->height, cc->width);
}
-/*
- * Static variables
- */
-const char *res_types[] = {
- /* 0x01: */
- "cursor", "bitmap", "icon", "menu", "dialog", "string",
- "fontdir", "font", "accelerator", "rcdata", "messagelist",
- "group_cursor", NULL, "group_icon", NULL,
- /* the following are not defined in winbase.h, but found in wrc. */
- /* 0x10: */
- "version", "dlginclude", NULL, "plugplay", "vxd",
- "anicursor", "aniicon"
-};
-#define RES_TYPE_COUNT (sizeof(res_types)/sizeof(char *))
-
Win32ResExtractor::Win32ResExtractor(ScummEngine_v70he *scumm) : ResExtractor(scumm) {
}
-int Win32ResExtractor::extractResource(int resId, byte **data) {
- char buf[20];
-
- snprintf(buf, sizeof(buf), "%d", resId);
-
- return extractResource_("group_cursor", buf, data);
-}
-
-int Win32ResExtractor::extractResource_(const char *resType, char *resName, byte **data) {
- char *arg_language = NULL;
- const char *arg_type = resType;
- char *arg_name = resName;
- int ressize = 0;
-
- _arg_raw = false;
-
- /* translate --type option from resource type string to integer */
- arg_type = res_type_string_to_id(arg_type);
-
- WinLibrary fi;
-
- /* initiate stuff */
- fi.memory = NULL;
- fi.file = NULL;
-
+bool Win32ResExtractor::extractResource(int id, CachedCursor *cc) {
if (_fileName.empty()) { // We are running for the first time
_fileName = _vm->generateFilename(-3);
- }
-
- /* get file size */
- fi.file = SearchMan.createReadStreamForMember(_fileName);
- if (!fi.file) {
- error("Cannot open file %s", _fileName.c_str());
- }
-
- fi.total_size = fi.file->size();
- if (fi.total_size == -1) {
- error("Cannot get size of file %s", _fileName.c_str());
- goto cleanup;
- }
- if (fi.total_size == 0) {
- error("%s: file has a size of 0", _fileName.c_str());
- goto cleanup;
- }
-
- /* read all of file */
- fi.memory = (byte *)malloc(fi.total_size);
- if (fi.file->read(fi.memory, fi.total_size) == 0) {
- error("Cannot read from file %s", _fileName.c_str());
- goto cleanup;
- }
-
- /* identify file and find resource table */
- if (!read_library(&fi)) {
- /* error reported by read_library */
- goto cleanup;
- }
-
- /* errors will be printed by the callback */
- ressize = do_resources(&fi, arg_type, arg_name, arg_language, data);
-
- /* free stuff and close file */
- cleanup:
- delete fi.file;
- free(fi.memory);
-
- return ressize;
-}
-
-
-/**
- * Translate a numeric resource type to it's corresponding string type.
- * (For informative-ness.)
- */
-const char *Win32ResExtractor::res_type_id_to_string(int id) {
- if (id == 241)
- return "toolbar";
- if (id > 0 && id <= (int)RES_TYPE_COUNT)
- return res_types[id-1];
- return NULL;
-}
-
-/**
- * Translate a resource type string to integer.
- * (Used to convert the --type option.)
- */
-const char *Win32ResExtractor::res_type_string_to_id(const char *type) {
- static const char *res_type_ids[] = {
- "-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8", "-9", "-10",
- "-11", "-12", NULL, "-14", NULL, "-16", "-17", NULL, "-19",
- "-20", "-21", "-22"
- };
- int c;
-
- if (type == NULL)
- return NULL;
-
- for (c = 0; c < (int)RES_TYPE_COUNT; c++) {
- if (res_types[c] != NULL && !scumm_stricmp(type, res_types[c]))
- return res_type_ids[c];
- }
-
- return type;
-}
-
-/**
- * Return the resource id quoted if it is a string, otherwise (i.e. if
- * it is numeric) just return it.
- */
-Common::String Win32ResExtractor::WinResource::getQuotedResourceId() const {
- if (numeric_id || id[0] == '\0')
- return id;
- return '"' + Common::String(id) + '"';
-}
-
-int Win32ResExtractor::extract_resources(WinLibrary *fi, WinResource *wr,
- WinResource *type_wr, WinResource *name_wr,
- WinResource *lang_wr, byte **data) {
- int size;
- bool free_it;
- const char *type;
- int32 id;
-
- if (*data) {
- error("Win32ResExtractor::extract_resources() more than one cursor");
- return 0;
- }
-
- *data = extract_resource(fi, wr, &size, &free_it, type_wr->id, (lang_wr == NULL ? NULL : lang_wr->id), _arg_raw);
-
- if (data == NULL) {
- error("Win32ResExtractor::extract_resources() problem with resource extraction");
- return 0;
- }
-
- /* get named resource type if possible */
- type = NULL;
- if ((id = strtol(type_wr->id, 0, 10)) != 0)
- type = res_type_id_to_string(id);
-
- if (lang_wr != NULL && lang_wr->id[0] != '\0') {
- debugC(DEBUG_RESOURCE, "extractCursor(). Found cursor name: %s language: %s [size=%d]",
- name_wr->getQuotedResourceId().c_str(), lang_wr->getQuotedResourceId().c_str(), size);
- } else {
- debugC(DEBUG_RESOURCE, "extractCursor(). Found cursor name: %s [size=%d]",
- name_wr->getQuotedResourceId().c_str(), size);
- }
- return size;
-}
-
-/**
- * Extract a resource, returning pointer to data.
- */
-byte *Win32ResExtractor::extract_resource(WinLibrary *fi, WinResource *wr, int *size,
- bool *free_it, char *type, char *lang, bool raw) {
- char *str;
- int32 intval;
-
- /* just return pointer to data if raw */
- if (raw) {
- *free_it = false;
- /* get_resource_entry will print possible error */
- return get_resource_entry(fi, wr, size);
- }
-
- /* find out how to extract */
- str = type;
- if (str != NULL && (intval = strtol(STRIP_RES_ID_FORMAT(str), 0, 10))) {
- if (intval == (int)RT_GROUP_ICON) {
- *free_it = true;
- return extract_group_icon_cursor_resource(fi, wr, lang, size, true);
- }
- if (intval == (int)RT_GROUP_CURSOR) {
- *free_it = true;
- return extract_group_icon_cursor_resource(fi, wr, lang, size, false);
- }
- }
-
- return NULL;
-}
-
-/**
- * Create a complete RT_GROUP_ICON resource, that can be written to
- * an `.ico' file without modifications. Returns an allocated
- * memory block that should be freed with free() once used.
- *
- * `root' is the offset in file that specifies the resource.
- * `base' is the offset that string pointers are calculated from.
- * `ressize' should point to an integer variable where the size of
- * the returned memory block will be placed.
- * `is_icon' indicates whether resource to be extracted is icon
- * or cursor group.
- */
-byte *Win32ResExtractor::extract_group_icon_cursor_resource(WinLibrary *fi, WinResource *wr, char *lang,
- int *ressize, bool is_icon) {
- Win32CursorIconDir *icondir;
- Win32CursorIconFileDir *fileicondir;
- byte *memory;
- int c, offset, skipped;
- int size;
-
- /* get resource data and size */
- icondir = (Win32CursorIconDir *)get_resource_entry(fi, wr, &size);
- if (icondir == NULL) {
- /* get_resource_entry will print error */
- return NULL;
- }
-
- /* calculate total size of output file */
- RETURN_IF_BAD_POINTER(NULL, icondir->count);
- skipped = 0;
- for (c = 0; c < FROM_LE_16(icondir->count); c++) {
- int level;
- int iconsize;
- char name[14];
- WinResource *fwr;
-
- RETURN_IF_BAD_POINTER(NULL, icondir->entries[c]);
- /*debug("%d. bytes_in_res=%d width=%d height=%d planes=%d bit_count=%d", c,
- FROM_LE_32(icondir->entries[c].bytes_in_res),
- (is_icon ? icondir->entries[c].res_info.icon.width : FROM_LE_16(icondir->entries[c].res_info.cursor.width)),
- (is_icon ? icondir->entries[c].res_info.icon.height : FROM_LE_16(icondir->entries[c].res_info.cursor.height)),
- FROM_LE_16(icondir->entries[c].plane_count),
- FROM_LE_16(icondir->entries[c].bit_count));*/
-
- /* find the corresponding icon resource */
- snprintf(name, sizeof(name)/sizeof(char), "-%d", FROM_LE_16(icondir->entries[c].res_id));
- fwr = find_resource(fi, (is_icon ? "-3" : "-1"), name, lang, &level);
- if (fwr == NULL) {
- error("%s: could not find `%s' in `%s' resource.",
- _fileName.c_str(), &name[1], (is_icon ? "group_icon" : "group_cursor"));
- return NULL;
- }
-
- if (get_resource_entry(fi, fwr, &iconsize) != NULL) {
- if (iconsize == 0) {
- debugC(DEBUG_RESOURCE, "%s: icon resource `%s' is empty, skipping", _fileName.c_str(), name);
- skipped++;
- continue;
- }
- if ((uint32)iconsize != FROM_LE_32(icondir->entries[c].bytes_in_res)) {
- debugC(DEBUG_RESOURCE, "%s: mismatch of size in icon resource `%s' and group (%d != %d)",
- _fileName.c_str(), name, iconsize, FROM_LE_32(icondir->entries[c].bytes_in_res));
- }
- size += iconsize; /* size += FROM_LE_32(icondir->entries[c].bytes_in_res); */
- /* cursor resources have two additional WORDs that contain
- * hotspot info */
- if (!is_icon)
- size -= sizeof(uint16)*2;
- }
- }
- offset = sizeof(Win32CursorIconFileDir) + (FROM_LE_16(icondir->count)-skipped) * sizeof(Win32CursorIconFileDirEntry);
- size += offset;
- *ressize = size;
-
- /* allocate that much memory */
- memory = (byte *)malloc(size);
- fileicondir = (Win32CursorIconFileDir *)memory;
-
- /* transfer Win32CursorIconDir structure members */
- fileicondir->reserved = icondir->reserved;
- fileicondir->type = icondir->type;
- fileicondir->count = TO_LE_16(FROM_LE_16(icondir->count) - skipped);
-
- /* transfer each cursor/icon: Win32CursorIconDirEntry and data */
- skipped = 0;
- for (c = 0; c < FROM_LE_16(icondir->count); c++) {
- int level;
- char name[14];
- WinResource *fwr;
- byte *data;
-
- /* find the corresponding icon resource */
- snprintf(name, sizeof(name)/sizeof(char), "-%d", FROM_LE_16(icondir->entries[c].res_id));
- fwr = find_resource(fi, (is_icon ? "-3" : "-1"), name, lang, &level);
- if (fwr == NULL) {
- error("%s: could not find `%s' in `%s' resource.",
- _fileName.c_str(), &name[1], (is_icon ? "group_icon" : "group_cursor"));
- return NULL;
- }
-
- /* get data and size of that resource */
- data = (byte *)get_resource_entry(fi, fwr, &size);
- if (data == NULL) {
- /* get_resource_entry has printed error */
- return NULL;
- }
- if (size == 0) {
- skipped++;
- continue;
- }
-
- /* copy ICONDIRENTRY (not including last dwImageOffset) */
- memcpy(&fileicondir->entries[c-skipped], &icondir->entries[c],
- sizeof(Win32CursorIconFileDirEntry)-sizeof(uint32));
-
- /* special treatment for cursors */
- if (!is_icon) {
- fileicondir->entries[c-skipped].width = icondir->entries[c].res_info.cursor.width;
- fileicondir->entries[c-skipped].height = TO_LE_16(FROM_LE_16(icondir->entries[c].res_info.cursor.height) / 2);
- fileicondir->entries[c-skipped].color_count = 0;
- fileicondir->entries[c-skipped].reserved = 0;
- }
-
- /* set image offset and increase it */
- fileicondir->entries[c-skipped].dib_offset = TO_LE_32(offset);
-
- /* transfer resource into file memory */
- if (is_icon) {
- memcpy(&memory[offset], data, FROM_LE_32(icondir->entries[c].bytes_in_res));
- } else {
- fileicondir->entries[c-skipped].hotspot_x = ((uint16 *) data)[0];
- fileicondir->entries[c-skipped].hotspot_y = ((uint16 *) data)[1];
- memcpy(&memory[offset], data+sizeof(uint16)*2,
- FROM_LE_32(icondir->entries[c].bytes_in_res)-sizeof(uint16)*2);
- offset -= sizeof(uint16)*2;
- }
-
- /* increase the offset pointer */
- offset += FROM_LE_32(icondir->entries[c].bytes_in_res);
+ if (!_exe.loadFromEXE(_fileName))
+ error("Cannot open file %s", _fileName.c_str());
}
- return memory;
-}
-
-/**
- * Check if a chunk of data (determined by offset and size)
- * is within the bounds of the WinLibrary file.
- * Usually not called directly.
- */
-bool Win32ResExtractor::check_offset(byte *memory, int total_size, const char *name, void *offset, int size) {
- int need_size = (int)((byte *)offset - memory + size);
-
- debugC(DEBUG_RESOURCE, "check_offset: size=%x vs %x offset=%x size=%x",
- need_size, total_size, (uint)((byte *)offset - memory), size);
+ Graphics::WinCursorGroup *group = Graphics::WinCursorGroup::createCursorGroup(_exe, id);
- if (need_size < 0 || need_size > total_size) {
- error("%s: premature end", name);
+ if (!group)
return false;
- }
-
- return true;
-}
-
-
-/**
- * Do something for each resource matching type, name and lang.
- */
-int Win32ResExtractor::do_resources(WinLibrary *fi, const char *type, char *name, char *lang, byte **data) {
- WinResource *type_wr;
- WinResource *name_wr;
- WinResource *lang_wr;
- int size;
-
- type_wr = (WinResource *)calloc(3, sizeof(WinResource));
- name_wr = type_wr + 1;
- lang_wr = type_wr + 2;
-
- size = do_resources_recurs(fi, NULL, type_wr, name_wr, lang_wr, type, name, lang, data);
-
- free(type_wr);
-
- return size;
-}
-
-/* what is each entry in this directory level for? type, name or language? */
-#define WINRESOURCE_BY_LEVEL(x) ((x)==0 ? type_wr : ((x)==1 ? name_wr : lang_wr))
-
-/* does the id of this entry match the specified id? */
-#define LEVEL_MATCHES(x) (x == NULL || x ## _wr->id[0] == '\0' || compare_resource_id(x ## _wr, x))
-int Win32ResExtractor::do_resources_recurs(WinLibrary *fi, WinResource *base,
- WinResource *type_wr, WinResource *name_wr, WinResource *lang_wr,
- const char *type, char *name, char *lang, byte **data) {
- int c, rescnt;
- WinResource *wr;
- uint32 size = 0;
+ Graphics::WinCursor *cursor = group->cursors[0].cursor;
- /* get a list of all resources at this level */
- wr = list_resources(fi, base, &rescnt);
- if (wr == NULL) {
- return size;
- }
-
- /* process each resource listed */
- for (c = 0; c < rescnt; c++) {
- /* (over)write the corresponding WinResource holder with the current */
- memcpy(WINRESOURCE_BY_LEVEL(wr[c].level), wr+c, sizeof(WinResource));
-
- /* go deeper unless there is something that does NOT match */
- if (LEVEL_MATCHES(type) && LEVEL_MATCHES(name) && LEVEL_MATCHES(lang)) {
- if (wr->is_directory)
- size = do_resources_recurs(fi, wr+c, type_wr, name_wr, lang_wr, type, name, lang, data);
- else
- size = extract_resources(fi, wr+c, type_wr, name_wr, lang_wr, data);
- }
- }
-
- /* since we're moving back one level after this, unset the
- * WinResource holder used on this level */
- memset(WINRESOURCE_BY_LEVEL(wr[0].level), 0, sizeof(WinResource));
-
- return size;
-}
-
-bool Win32ResExtractor::compare_resource_id(WinResource *wr, const char *id) {
- if (wr->numeric_id) {
- int32 cmp1, cmp2;
- if (id[0] == '+')
- return false;
- if (id[0] == '-')
- id++;
- cmp1 = strtol(wr->id, 0, 10);
- cmp2 = strtol(id, 0, 10);
- if (!cmp1 || !cmp2 || cmp1 != cmp2)
- return false;
- } else {
- if (id[0] == '-')
- return false;
- if (id[0] == '+')
- id++;
- if (strcmp(wr->id, id))
- return false;
- }
+ cc->bitmap = new byte[cursor->getWidth() * cursor->getHeight()];
+ cc->width = cursor->getWidth();
+ cc->height = cursor->getHeight();
+ cc->hotspotX = cursor->getHotspotX();
+ cc->hotspotY = cursor->getHotspotY();
- return true;
-}
+ // Convert from the paletted format to the SCUMM palette
+ const byte *srcBitmap = cursor->getSurface();
-bool Win32ResExtractor::decode_pe_resource_id(WinLibrary *fi, WinResource *wr, uint32 value) {
- if (value & IMAGE_RESOURCE_NAME_IS_STRING) { /* numeric id */
- int c, len;
- uint16 *mem = (uint16 *)
- (fi->first_resource + (value & ~IMAGE_RESOURCE_NAME_IS_STRING));
-
- /* copy each char of the string, and terminate it */
- RETURN_IF_BAD_POINTER(false, *mem);
- len = FROM_LE_16(mem[0]);
- RETURN_IF_BAD_OFFSET(false, &mem[1], sizeof(uint16) * len);
-
- len = MIN(FROM_LE_16(mem[0]), (uint16)WINRES_ID_MAXLEN);
- for (c = 0; c < len; c++)
- wr->id[c] = FROM_LE_16(mem[c+1]) & 0x00FF;
- wr->id[len] = '\0';
- wr->numeric_id = false;
- } else { /* Unicode string id */
- /* translate id into a string */
- snprintf(wr->id, WINRES_ID_MAXLEN, "%d", value);
- wr->numeric_id = true;
+ for (int i = 0; i < cursor->getWidth() * cursor->getHeight(); i++) {
+ if (srcBitmap[i] == cursor->getKeyColor()) // Transparent
+ cc->bitmap[i] = 255;
+ else if (srcBitmap[i] == 0) // Black
+ cc->bitmap[i] = 253;
+ else // White
+ cc->bitmap[i] = 254;
}
+ delete group;
return true;
}
-byte *Win32ResExtractor::get_resource_entry(WinLibrary *fi, WinResource *wr, int *size) {
- byte *result;
-
- Win32ImageResourceDataEntry *dataent;
-
- dataent = (Win32ImageResourceDataEntry *) wr->children;
- RETURN_IF_BAD_POINTER(NULL, *dataent);
- *size = FROM_LE_32(dataent->size);
-
- result = fi->memory + FROM_LE_32(dataent->offset_to_data);
-
- RETURN_IF_BAD_OFFSET(NULL, result, *size);
-
- return result;
-}
-
-Win32ResExtractor::WinResource *Win32ResExtractor::list_pe_resources(WinLibrary *fi, Win32ImageResourceDirectory *pe_res, int level, int *count) {
- WinResource *wr;
- int c, rescnt;
- Win32ImageResourceDirectoryEntry *dirent
- = (Win32ImageResourceDirectoryEntry *)(pe_res + 1);
-
- /* count number of `type' resources */
- RETURN_IF_BAD_POINTER(NULL, *dirent);
- rescnt = FROM_LE_16(pe_res->number_of_named_entries) + FROM_LE_16(pe_res->number_of_id_entries);
- *count = rescnt;
-
- /* allocate WinResource's */
- wr = (WinResource *)malloc(sizeof(WinResource) * rescnt);
-
- /* fill in the WinResource's */
- for (c = 0; c < rescnt; c++) {
- RETURN_IF_BAD_POINTER(NULL, dirent[c]);
- wr[c].this_ = pe_res;
- wr[c].level = level;
- wr[c].is_directory = ((FROM_LE_32(dirent[c].offset_to_data) & IMAGE_RESOURCE_DATA_IS_DIRECTORY) != 0);
- wr[c].children = fi->first_resource + (FROM_LE_32(dirent[c].offset_to_data) & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY);
-
- /* fill in wr->id, wr->numeric_id */
- if (!decode_pe_resource_id(fi, wr + c, FROM_LE_32(dirent[c].name))) {
- free(wr);
- return NULL;
- }
- }
-
- return wr;
-}
-
-
-/**
- * Return an array of WinResource's in the current
- * resource level specified by _res->
- */
-Win32ResExtractor::WinResource *Win32ResExtractor::list_resources(WinLibrary *fi, WinResource *res, int *count) {
- if (res != NULL && !res->is_directory)
- return NULL;
-
- return list_pe_resources(fi, (Win32ImageResourceDirectory *)
- (res == NULL ? fi->first_resource : res->children),
- (res == NULL ? 0 : res->level+1),
- count);
-}
-
-/**
- * Read header and get resource directory offset in a Windows library
- * (AKA module).
- */
-bool Win32ResExtractor::read_library(WinLibrary *fi) {
- /* check for DOS header signature `MZ' */
- RETURN_IF_BAD_POINTER(false, MZ_HEADER(fi->memory)->magic);
- if (FROM_LE_16(MZ_HEADER(fi->memory)->magic) == IMAGE_DOS_SIGNATURE) {
- DOSImageHeader *mz_header = MZ_HEADER(fi->memory);
-
- RETURN_IF_BAD_POINTER(false, mz_header->lfanew);
-
- // Apply endian fix (currently only lfanew is used from the DOSImageHeader,
- // so we don't bother to 'fix' the rest).
- LE32(mz_header->lfanew);
-
- if (mz_header->lfanew < sizeof(DOSImageHeader)) {
- error("%s: not a Windows library", _fileName.c_str());
- return false;
- }
- }
-
- /* check for NT header signature `PE' */
- RETURN_IF_BAD_POINTER(false, PE_HEADER(fi->memory)->signature);
- if (FROM_LE_32(PE_HEADER(fi->memory)->signature) == IMAGE_NT_SIGNATURE) {
- Win32ImageNTHeaders *pe_header;
- int d;
-
- // Fix image header endianess
- fix_win32_image_header_endian(PE_HEADER(fi->memory));
-
- /* allocate new memory */
- fi->total_size = calc_vma_size(fi);
- if (fi->total_size == 0) {
- /* calc_vma_size has reported error */
- return false;
- }
- byte *ptr = (byte *)realloc(fi->memory, fi->total_size);
- assert(ptr);
- fi->memory = ptr;
-
- /* relocate memory, start from last section */
- pe_header = PE_HEADER(fi->memory);
- RETURN_IF_BAD_POINTER(false, pe_header->file_header.number_of_sections);
-
- /* we don't need to do OFFSET checking for the sections.
- * calc_vma_size has already done that */
- for (d = pe_header->file_header.number_of_sections - 1; d >= 0; d--) {
- Win32ImageSectionHeader *pe_sec = PE_SECTIONS(fi->memory) + d;
-
- if (pe_sec->characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
- continue;
-
- //if (pe_sec->virtual_address + pe_sec->size_of_raw_data > fi->total_size)
-
- RETURN_IF_BAD_OFFSET(0, fi->memory + pe_sec->virtual_address, pe_sec->size_of_raw_data);
- RETURN_IF_BAD_OFFSET(0, fi->memory + pe_sec->pointer_to_raw_data, pe_sec->size_of_raw_data);
- if (FROM_LE_32(pe_sec->virtual_address) != pe_sec->pointer_to_raw_data) {
- memmove(fi->memory + pe_sec->virtual_address,
- fi->memory + pe_sec->pointer_to_raw_data,
- pe_sec->size_of_raw_data);
- }
- }
-
- /* find resource directory */
- RETURN_IF_BAD_POINTER(false, pe_header->optional_header.data_directory[IMAGE_DIRECTORY_ENTRY_RESOURCE]);
- Win32ImageDataDirectory *dir = pe_header->optional_header.data_directory + IMAGE_DIRECTORY_ENTRY_RESOURCE;
- if (dir->size == 0) {
- error("%s: file contains no resources", _fileName.c_str());
- return false;
- }
-
- fix_win32_image_data_directory(dir);
-
- fi->first_resource = fi->memory + dir->virtual_address;
- return true;
- }
-
- /* other (unknown) header signature was found */
- error("%s: not a Windows library", _fileName.c_str());
- return false;
-}
-
-/**
- * Calculate the total amount of memory needed for a 32-bit Windows
- * module. Returns -1 if file was too small.
- */
-int Win32ResExtractor::calc_vma_size(WinLibrary *fi) {
- Win32ImageSectionHeader *seg;
- int c, segcount, size;
-
- size = 0;
- RETURN_IF_BAD_POINTER(-1, PE_HEADER(fi->memory)->file_header.number_of_sections);
- segcount = PE_HEADER(fi->memory)->file_header.number_of_sections;
-
- /* If there are no segments, just process file like it is.
- * This is (probably) not the right thing to do, but problems
- * will be delt with later anyway.
- */
- if (segcount == 0)
- return fi->total_size;
-
- seg = PE_SECTIONS(fi->memory);
- RETURN_IF_BAD_POINTER(-1, *seg);
- for (c = 0; c < segcount; c++) {
- RETURN_IF_BAD_POINTER(0, *seg);
- fix_win32_image_section_header(seg);
-
- size = MAX((uint32)size, seg->virtual_address + seg->size_of_raw_data);
- /* I have no idea what misc.virtual_size is for... */
- size = MAX((uint32)size, seg->virtual_address + seg->misc.virtual_size);
- seg++;
- }
-
- return size;
-}
-
-Win32ResExtractor::WinResource *Win32ResExtractor::find_with_resource_array(WinLibrary *fi, WinResource *wr, const char *id) {
- int c, rescnt;
- WinResource *return_wr;
-
- wr = list_resources(fi, wr, &rescnt);
- if (wr == NULL)
- return NULL;
-
- for (c = 0; c < rescnt; c++) {
- if (compare_resource_id(&wr[c], id)) {
- /* duplicate WinResource and return it */
- return_wr = (WinResource *)malloc(sizeof(WinResource));
- memcpy(return_wr, &wr[c], sizeof(WinResource));
-
- /* free old WinResource */
- free(wr);
- return return_wr;
- }
- }
-
- return NULL;
-}
-
-Win32ResExtractor::WinResource *Win32ResExtractor::find_resource(WinLibrary *fi, const char *type, const char *name, const char *language, int *level) {
- WinResource *wr;
-
- *level = 0;
- if (type == NULL)
- return NULL;
- wr = find_with_resource_array(fi, NULL, type);
- if (wr == NULL || !wr->is_directory)
- return wr;
-
- *level = 1;
- if (name == NULL)
- return wr;
- wr = find_with_resource_array(fi, wr, name);
- if (wr == NULL || !wr->is_directory)
- return wr;
-
- *level = 2;
- if (language == NULL)
- return wr;
- wr = find_with_resource_array(fi, wr, language);
- return wr;
-}
-
-#define ROW_BYTES(bits) ((((bits) + 31) >> 5) << 2)
-
-
-int Win32ResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h,
- int *hotspot_x, int *hotspot_y, int *keycolor, byte **pal, int *palSize) {
- Win32CursorIconFileDir dir;
- Win32CursorIconFileDirEntry *entries = NULL;
- uint32 offset;
- uint32 c, d;
- int completed;
- int matched = 0;
- Common::MemoryReadStream *in = new Common::MemoryReadStream(data, datasize);
-
- if (!in->read(&dir, sizeof(Win32CursorIconFileDir)- sizeof(Win32CursorIconFileDirEntry)))
- goto cleanup;
- fix_win32_cursor_icon_file_dir_endian(&dir);
-
- if (dir.reserved != 0) {
- error("not an icon or cursor file (reserved non-zero)");
- goto cleanup;
- }
- if (dir.type != 1 && dir.type != 2) {
- error("not an icon or cursor file (wrong type)");
- goto cleanup;
- }
-
- entries = (Win32CursorIconFileDirEntry *)malloc(dir.count * sizeof(Win32CursorIconFileDirEntry));
- for (c = 0; c < dir.count; c++) {
- if (!in->read(&entries[c], sizeof(Win32CursorIconFileDirEntry)))
- goto cleanup;
- fix_win32_cursor_icon_file_dir_entry_endian(&entries[c]);
- if (entries[c].reserved != 0)
- error("reserved is not zero");
- }
-
- offset = sizeof(Win32CursorIconFileDir) + (dir.count - 1) * (sizeof(Win32CursorIconFileDirEntry));
-
- for (completed = 0; completed < dir.count; ) {
- uint32 min_offset = 0x7fffffff;
- int previous = completed;
-
- for (c = 0; c < dir.count; c++) {
- if (entries[c].dib_offset == offset) {
- Win32BitmapInfoHeader bitmap;
- Win32RGBQuad *palette = NULL;
- uint32 palette_count = 0;
- uint32 image_size, mask_size;
- uint32 width, height;
- byte *image_data = NULL, *mask_data = NULL;
- byte *row = NULL;
-
- if (!in->read(&bitmap, sizeof(Win32BitmapInfoHeader)))
- goto local_cleanup;
-
- fix_win32_bitmap_info_header_endian(&bitmap);
- if (bitmap.size < sizeof(Win32BitmapInfoHeader)) {
- error("bitmap header is too short");
- goto local_cleanup;
- }
- if (bitmap.compression != 0) {
- error("compressed image data not supported");
- goto local_cleanup;
- }
- if (bitmap.x_pels_per_meter != 0)
- error("x_pels_per_meter field in bitmap should be zero");
- if (bitmap.y_pels_per_meter != 0)
- error("y_pels_per_meter field in bitmap should be zero");
- if (bitmap.clr_important != 0)
- error("clr_important field in bitmap should be zero");
- if (bitmap.planes != 1)
- error("planes field in bitmap should be one");
- if (bitmap.size != sizeof(Win32BitmapInfoHeader)) {
- uint32 skip = bitmap.size - sizeof(Win32BitmapInfoHeader);
- error("skipping %d bytes of extended bitmap header", skip);
- in->seek(skip, SEEK_CUR);
- }
- offset += bitmap.size;
-
- if (bitmap.clr_used != 0 || bitmap.bit_count < 24) {
- palette_count = (bitmap.clr_used != 0 ? bitmap.clr_used : 1 << bitmap.bit_count);
- palette = (Win32RGBQuad *)malloc(sizeof(Win32RGBQuad) * palette_count);
- if (!in->read(palette, sizeof(Win32RGBQuad) * palette_count))
- goto local_cleanup;
- offset += sizeof(Win32RGBQuad) * palette_count;
- }
-
- width = bitmap.width;
- height = ABS(bitmap.height)/2;
-
- image_size = height * ROW_BYTES(width * bitmap.bit_count);
- mask_size = height * ROW_BYTES(width);
-
- if (entries[c].dib_size != bitmap.size + image_size + mask_size + palette_count * sizeof(Win32RGBQuad))
- debugC(DEBUG_RESOURCE, "incorrect total size of bitmap (%d specified; %d real)",
- entries[c].dib_size,
- (int)(bitmap.size + image_size + mask_size + palette_count * sizeof(Win32RGBQuad))
- );
-
- image_data = (byte *)malloc(image_size);
- if (!in->read(image_data, image_size))
- goto local_cleanup;
-
- mask_data = (byte *)malloc(mask_size);
- if (!in->read(mask_data, mask_size))
- goto local_cleanup;
-
- offset += image_size;
- offset += mask_size;
- completed++;
- matched++;
-
- *hotspot_x = entries[c].hotspot_x;
- *hotspot_y = entries[c].hotspot_y;
- *w = width;
- *h = height;
- *keycolor = 0;
- *cursor = (byte *)malloc(width * height);
-
- row = (byte *)malloc(width * 4);
-
- for (d = 0; d < height; d++) {
- uint32 x;
- uint32 y = (bitmap.height < 0 ? d : height - d - 1);
- uint32 imod = y * (image_size / height) * 8 / bitmap.bit_count;
- uint32 mmod = y * (mask_size / height) * 8;
-
- for (x = 0; x < width; x++) {
-
- uint32 color = simple_vec(image_data, x + imod, bitmap.bit_count);
-
- // We set up cursor palette for default cursor, so use it
- if (!simple_vec(mask_data, x + mmod, 1)) {
- if (color) {
- cursor[0][width * d + x] = 254; // white
- } else {
- cursor[0][width * d + x] = 253; // black
- }
- } else {
- cursor[0][width * d + x] = 255; // transparent
- }
- /*
-
- if (bitmap.bit_count <= 16) {
- if (color >= palette_count) {
- error("color out of range in image data");
- goto local_cleanup;
- }
- row[4*x+0] = palette[color].red;
- row[4*x+1] = palette[color].green;
- row[4*x+2] = palette[color].blue;
-
- } else {
- row[4*x+0] = (color >> 16) & 0xFF;
- row[4*x+1] = (color >> 8) & 0xFF;
- row[4*x+2] = (color >> 0) & 0xFF;
- }
- if (bitmap.bit_count == 32)
- row[4*x+3] = (color >> 24) & 0xFF;
- else
- row[4*x+3] = simple_vec(mask_data, x + mmod, 1) ? 0 : 0xFF;
- */
- }
-
- }
-
- free(row);
- free(palette);
- if (image_data != NULL) {
- free(image_data);
- free(mask_data);
- }
- continue;
-
- local_cleanup:
-
- free(row);
- free(palette);
- if (image_data != NULL) {
- free(image_data);
- free(mask_data);
- }
- goto cleanup;
- } else {
- if (entries[c].dib_offset > offset)
- min_offset = MIN(min_offset, entries[c].dib_offset);
- }
- }
-
- if (previous == completed) {
- if (min_offset < offset) {
- error("offset of bitmap header incorrect (too low)");
- goto cleanup;
- }
- assert(min_offset != 0x7fffffff);
- debugC(DEBUG_RESOURCE, "skipping %d bytes of garbage at %d", min_offset-offset, offset);
- in->seek(min_offset - offset, SEEK_CUR);
- offset = min_offset;
- }
- }
-
- free(entries);
- return matched;
-
-cleanup:
-
- free(entries);
- return -1;
-}
-
-uint32 Win32ResExtractor::simple_vec(byte *data, uint32 ofs, byte size) {
- switch (size) {
- case 1:
- return (data[ofs/8] >> (7 - ofs%8)) & 1;
- case 2:
- return (data[ofs/4] >> ((3 - ofs%4) << 1)) & 3;
- case 4:
- return (data[ofs/2] >> ((1 - ofs%2) << 2)) & 15;
- case 8:
- return data[ofs];
- case 16:
- return data[2*ofs] | data[2*ofs+1] << 8;
- case 24:
- return data[3*ofs] | data[3*ofs+1] << 8 | data[3*ofs+2] << 16;
- case 32:
- return data[4*ofs] | data[4*ofs+1] << 8 | data[4*ofs+2] << 16 | data[4*ofs+3] << 24;
- }
-
- return 0;
-}
-
-void Win32ResExtractor::fix_win32_cursor_icon_file_dir_endian(Win32CursorIconFileDir *obj) {
- LE16(obj->reserved);
- LE16(obj->type);
- LE16(obj->count);
-}
-
-void Win32ResExtractor::fix_win32_bitmap_info_header_endian(Win32BitmapInfoHeader *obj) {
- LE32(obj->size);
- LE32(obj->width);
- LE32(obj->height);
- LE16(obj->planes);
- LE16(obj->bit_count);
- LE32(obj->compression);
- LE32(obj->size_image);
- LE32(obj->x_pels_per_meter);
- LE32(obj->y_pels_per_meter);
- LE32(obj->clr_used);
- LE32(obj->clr_important);
-}
-
-void Win32ResExtractor::fix_win32_cursor_icon_file_dir_entry_endian(Win32CursorIconFileDirEntry *obj) {
- LE16(obj->hotspot_x);
- LE16(obj->hotspot_y);
- LE32(obj->dib_size);
- LE32(obj->dib_offset);
-}
-
-void Win32ResExtractor::fix_win32_image_section_header(Win32ImageSectionHeader *obj) {
- LE32(obj->misc.physical_address);
- LE32(obj->virtual_address);
- LE32(obj->size_of_raw_data);
- LE32(obj->pointer_to_raw_data);
- LE32(obj->pointer_to_relocations);
- LE32(obj->pointer_to_linenumbers);
- LE16(obj->number_of_relocations);
- LE16(obj->number_of_linenumbers);
- LE32(obj->characteristics);
-}
-
-/* fix_win32_image_header_endian:
- * NOTE: This assumes that the optional header is always available.
- */
-void Win32ResExtractor::fix_win32_image_header_endian(Win32ImageNTHeaders *obj) {
- LE32(obj->signature);
- LE16(obj->file_header.machine);
- LE16(obj->file_header.number_of_sections);
- LE32(obj->file_header.time_date_stamp);
- LE32(obj->file_header.pointer_to_symbol_table);
- LE32(obj->file_header.number_of_symbols);
- LE16(obj->file_header.size_of_optional_header);
- LE16(obj->file_header.characteristics);
-
- // FIXME: Does this assert ever trigger? If so, we should modify this function
- // to properly deal with it.
- assert(obj->file_header.size_of_optional_header >= sizeof(obj->optional_header));
- LE16(obj->optional_header.magic);
- LE32(obj->optional_header.size_of_code);
- LE32(obj->optional_header.size_of_initialized_data);
- LE32(obj->optional_header.size_of_uninitialized_data);
- LE32(obj->optional_header.address_of_entry_point);
- LE32(obj->optional_header.base_of_code);
- LE32(obj->optional_header.base_of_data);
- LE32(obj->optional_header.image_base);
- LE32(obj->optional_header.section_alignment);
- LE32(obj->optional_header.file_alignment);
- LE16(obj->optional_header.major_operating_system_version);
- LE16(obj->optional_header.minor_operating_system_version);
- LE16(obj->optional_header.major_image_version);
- LE16(obj->optional_header.minor_image_version);
- LE16(obj->optional_header.major_subsystem_version);
- LE16(obj->optional_header.minor_subsystem_version);
- LE32(obj->optional_header.win32_version_value);
- LE32(obj->optional_header.size_of_image);
- LE32(obj->optional_header.size_of_headers);
- LE32(obj->optional_header.checksum);
- LE16(obj->optional_header.subsystem);
- LE16(obj->optional_header.dll_characteristics);
- LE32(obj->optional_header.size_of_stack_reserve);
- LE32(obj->optional_header.size_of_stack_commit);
- LE32(obj->optional_header.size_of_heap_reserve);
- LE32(obj->optional_header.size_of_heap_commit);
- LE32(obj->optional_header.loader_flags);
- LE32(obj->optional_header.number_of_rva_and_sizes);
-}
-
-void Win32ResExtractor::fix_win32_image_data_directory(Win32ImageDataDirectory *obj) {
- LE32(obj->virtual_address);
- LE32(obj->size);
-}
-
-
MacResExtractor::MacResExtractor(ScummEngine_v70he *scumm) : ResExtractor(scumm) {
_resMgr = NULL;
}
-int MacResExtractor::extractResource(int id, byte **buf) {
+bool MacResExtractor::extractResource(int id, CachedCursor *cc) {
// Create the MacResManager if not created already
if (_resMgr == NULL) {
_resMgr = new Common::MacResManager();
@@ -1158,25 +167,18 @@ int MacResExtractor::extractResource(int id, byte **buf) {
error("Cannot open file %s", _fileName.c_str());
}
- Common::SeekableReadStream *dataStream = _resMgr->getResource('crsr', 1000 + id);
+ Common::SeekableReadStream *dataStream = _resMgr->getResource('crsr', id + 1000);
if (!dataStream)
- error("There is no cursor ID #%d", 1000 + id);
-
- uint32 size = dataStream->size();
- *buf = (byte *)malloc(size);
- dataStream->read(*buf, size);
- delete dataStream;
+ return false;
- return size;
-}
+ int keyColor; // HACK: key color is ignored
+ _resMgr->convertCrsrCursor(dataStream, &cc->bitmap, cc->width, cc->height, cc->hotspotX, cc->hotspotY,
+ keyColor, _vm->_system->hasFeature(OSystem::kFeatureCursorHasPalette),
+ &cc->palette, cc->palSize);
-int MacResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h,
- int *hotspot_x, int *hotspot_y, int *keycolor, byte **palette, int *palSize) {
-
- _resMgr->convertCrsrCursor(data, datasize, cursor, w, h, hotspot_x, hotspot_y, keycolor,
- _vm->_system->hasFeature(OSystem::kFeatureCursorHasPalette), palette, palSize);
- return 1;
+ delete dataStream;
+ return true;
}
void ScummEngine_v70he::readRoomsOffsets() {
diff --git a/engines/scumm/he/resource_he.h b/engines/scumm/he/resource_he.h
index 6b4c3fe493..5d7c70db76 100644
--- a/engines/scumm/he/resource_he.h
+++ b/engines/scumm/he/resource_he.h
@@ -4,10 +4,6 @@
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
- * Parts of this code are heavily based on:
- * icoutils - A set of programs dealing with MS Windows icons and cursors.
- * Copyright (C) 1998-2001 Oskar Liljeblad
- *
* 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
@@ -31,89 +27,10 @@
#define SCUMM_HE_RESOURCE_HE_H
#include "common/macresman.h"
+#include "common/winexe_pe.h"
namespace Scumm {
-#define WINRES_ID_MAXLEN (256)
-
-/*
- * Definitions
- */
-
-#define MZ_HEADER(x) ((DOSImageHeader *)(x))
-
-#define STRIP_RES_ID_FORMAT(x) (x != NULL && (x[0] == '-' || x[0] == '+') ? ++x : x)
-
-#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
-#define IMAGE_SIZEOF_SHORT_NAME 8
-
-#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000
-#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000
-
-#define PE_HEADER(module) \
- ((Win32ImageNTHeaders*)((byte *)(module) + \
- (((DOSImageHeader*)(module))->lfanew)))
-
-#define PE_SECTIONS(module) \
- ((Win32ImageSectionHeader *)((byte *) &PE_HEADER(module)->optional_header + \
- PE_HEADER(module)->file_header.size_of_optional_header))
-
-#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */
-#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */
-
-/* The following symbols below and another group a few lines below are defined in
- * the windows header, at least in wince and most likely in plain win32 as well.
- * Defining them out silences a redefinition warning in gcc.
- * If the same problem arises in win32 builds as well, please replace
- * _WIN32_WCE with _WIN32 which is also defined in the wince platform.
- */
-#ifndef _WIN32_WCE
-#define IMAGE_SCN_CNT_CODE 0x00000020
-#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
-#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080
-#endif
-
-// Only IMAGE_DIRECTORY_ENTRY_RESOURCE is used:
-#define IMAGE_DIRECTORY_ENTRY_EXPORT 0
-#define IMAGE_DIRECTORY_ENTRY_IMPORT 1
-#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2
-#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3
-#define IMAGE_DIRECTORY_ENTRY_SECURITY 4
-#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5
-#define IMAGE_DIRECTORY_ENTRY_DEBUG 6
-#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7
-#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* (MIPS GP) */
-#define IMAGE_DIRECTORY_ENTRY_TLS 9
-#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10
-#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11
-#define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */
-#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13
-#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14
-
-#ifndef _WIN32_WCE
-// Only RT_GROUP_CURSOR and RT_GROUP_ICON are used
-#define RT_CURSOR 1
-#define RT_BITMAP 2
-#define RT_ICON 3
-#define RT_MENU 4
-#define RT_DIALOG 5
-#define RT_STRING 6
-#define RT_FONTDIR 7
-#define RT_FONT 8
-#define RT_ACCELERATOR 9
-#define RT_RCDATA 10
-#define RT_MESSAGELIST 11
-#define RT_GROUP_CURSOR 12
-#define RT_GROUP_ICON 14
-#endif
-
-#define RETURN_IF_BAD_POINTER(r, x) \
- if (!check_offset(fi->memory, fi->total_size, _fileName.c_str(), &(x), sizeof(x))) \
- return (r);
-#define RETURN_IF_BAD_OFFSET(r, x, s) \
- if (!check_offset(fi->memory, fi->total_size, _fileName.c_str(), x, s)) \
- return (r);
-
class ScummEngine_v70he;
class ResExtractor {
@@ -123,312 +40,54 @@ public:
void setCursor(int id);
- virtual int extractResource(int id, byte **buf) { return 0; }
- virtual int convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h,
- int *hotspot_x, int *hotspot_y, int *keycolor,
- byte **palette, int *palSize) { return 0; }
-
- enum {
- MAX_CACHED_CURSORS = 10
- };
-
+protected:
struct CachedCursor {
bool valid;
int id;
byte *bitmap;
- int w, h;
- int hotspot_x, hotspot_y;
- uint32 last_used;
+ int width, height;
+ int hotspotX, hotspotY;
+ uint32 lastUsed;
byte *palette;
int palSize;
};
+ Common::String _fileName;
ScummEngine_v70he *_vm;
+ virtual bool extractResource(int id, CachedCursor *cc) = 0;
+
+private:
+ enum {
+ MAX_CACHED_CURSORS = 10
+ };
+
ResExtractor::CachedCursor *findCachedCursor(int id);
ResExtractor::CachedCursor *getCachedCursorSlot();
-
- bool _arg_raw;
- Common::String _fileName;
+
CachedCursor _cursorCache[MAX_CACHED_CURSORS];
};
class Win32ResExtractor : public ResExtractor {
- public:
+public:
Win32ResExtractor(ScummEngine_v70he *scumm);
~Win32ResExtractor() {}
- int extractResource(int id, byte **data);
- void setCursor(int id);
- int convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h,
- int *hotspot_x, int *hotspot_y, int *keycolor, byte **palette, int *palSize);
- private:
- int extractResource_(const char *resType, char *resName, byte **data);
-/*
- * Structures
- */
-
-#include "common/pack-start.h" // START STRUCT PACKING
-
- struct WinLibrary {
- Common::SeekableReadStream *file;
- byte *memory;
- byte *first_resource;
- int total_size;
- } PACKED_STRUCT;
-
- struct WinResource {
- char id[256];
- void *this_;
- void *children;
- int level;
- bool numeric_id;
- bool is_directory;
-
- Common::String getQuotedResourceId() const;
- } PACKED_STRUCT;
-
-
- struct Win32IconResDir {
- byte width;
- byte height;
- byte color_count;
- byte reserved;
- } PACKED_STRUCT;
-
- struct Win32CursorDir {
- uint16 width;
- uint16 height;
- } PACKED_STRUCT;
-
- struct Win32CursorIconDirEntry {
- union {
- Win32IconResDir icon;
- Win32CursorDir cursor;
- } res_info;
- uint16 plane_count;
- uint16 bit_count;
- uint32 bytes_in_res;
- uint16 res_id;
- } PACKED_STRUCT;
-
- struct Win32CursorIconDir {
- uint16 reserved;
- uint16 type;
- uint16 count;
- Win32CursorIconDirEntry entries[1];
- } PACKED_STRUCT;
-
- struct Win32CursorIconFileDirEntry {
- byte width;
- byte height;
- byte color_count;
- byte reserved;
- uint16 hotspot_x;
- uint16 hotspot_y;
- uint32 dib_size;
- uint32 dib_offset;
- } PACKED_STRUCT;
-
- struct Win32CursorIconFileDir {
- uint16 reserved;
- uint16 type;
- uint16 count;
- Win32CursorIconFileDirEntry entries[1];
- } PACKED_STRUCT;
-
- struct Win32BitmapInfoHeader {
- uint32 size;
- int32 width;
- int32 height;
- uint16 planes;
- uint16 bit_count;
- uint32 compression;
- uint32 size_image;
- int32 x_pels_per_meter;
- int32 y_pels_per_meter;
- uint32 clr_used;
- uint32 clr_important;
- } PACKED_STRUCT;
-
- struct Win32RGBQuad {
- byte blue;
- byte green;
- byte red;
- byte reserved;
- } PACKED_STRUCT;
-
- struct Win32ImageResourceDirectoryEntry {
- uint32 name;
- uint32 offset_to_data;
- } PACKED_STRUCT;
-
- struct Win16NETypeInfo {
- uint16 type_id;
- uint16 count;
- uint32 resloader; // FARPROC16 - smaller? uint16?
- } PACKED_STRUCT;
-
- struct DOSImageHeader {
- uint16 magic;
- uint16 cblp;
- uint16 cp;
- uint16 crlc;
- uint16 cparhdr;
- uint16 minalloc;
- uint16 maxalloc;
- uint16 ss;
- uint16 sp;
- uint16 csum;
- uint16 ip;
- uint16 cs;
- uint16 lfarlc;
- uint16 ovno;
- uint16 res[4];
- uint16 oemid;
- uint16 oeminfo;
- uint16 res2[10];
- uint32 lfanew;
- } PACKED_STRUCT;
-
- struct Win32ImageFileHeader {
- uint16 machine;
- uint16 number_of_sections;
- uint32 time_date_stamp;
- uint32 pointer_to_symbol_table;
- uint32 number_of_symbols;
- uint16 size_of_optional_header;
- uint16 characteristics;
- } PACKED_STRUCT;
-
- struct Win32ImageDataDirectory {
- uint32 virtual_address;
- uint32 size;
- } PACKED_STRUCT;
-
- struct Win32ImageOptionalHeader {
- uint16 magic;
- byte major_linker_version;
- byte minor_linker_version;
- uint32 size_of_code;
- uint32 size_of_initialized_data;
- uint32 size_of_uninitialized_data;
- uint32 address_of_entry_point;
- uint32 base_of_code;
- uint32 base_of_data;
- uint32 image_base;
- uint32 section_alignment;
- uint32 file_alignment;
- uint16 major_operating_system_version;
- uint16 minor_operating_system_version;
- uint16 major_image_version;
- uint16 minor_image_version;
- uint16 major_subsystem_version;
- uint16 minor_subsystem_version;
- uint32 win32_version_value;
- uint32 size_of_image;
- uint32 size_of_headers;
- uint32 checksum;
- uint16 subsystem;
- uint16 dll_characteristics;
- uint32 size_of_stack_reserve;
- uint32 size_of_stack_commit;
- uint32 size_of_heap_reserve;
- uint32 size_of_heap_commit;
- uint32 loader_flags;
- uint32 number_of_rva_and_sizes;
- Win32ImageDataDirectory data_directory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
- } PACKED_STRUCT;
-
- struct Win32ImageNTHeaders {
- uint32 signature;
- Win32ImageFileHeader file_header;
- Win32ImageOptionalHeader optional_header;
- } PACKED_STRUCT;
-
- struct Win32ImageSectionHeader {
- byte name[IMAGE_SIZEOF_SHORT_NAME];
- union {
- uint32 physical_address;
- uint32 virtual_size;
- } misc;
- uint32 virtual_address;
- uint32 size_of_raw_data;
- uint32 pointer_to_raw_data;
- uint32 pointer_to_relocations;
- uint32 pointer_to_linenumbers;
- uint16 number_of_relocations;
- uint16 number_of_linenumbers;
- uint32 characteristics;
- } PACKED_STRUCT;
-
- struct Win32ImageResourceDataEntry {
- uint32 offset_to_data;
- uint32 size;
- uint32 code_page;
- uint32 resource_handle;
- } PACKED_STRUCT;
-
- struct Win32ImageResourceDirectory {
- uint32 characteristics;
- uint32 time_date_stamp;
- uint16 major_version;
- uint16 minor_version;
- uint16 number_of_named_entries;
- uint16 number_of_id_entries;
- } PACKED_STRUCT;
-
-#include "common/pack-end.h" // END STRUCT PACKING
-
-/*
- * Function Prototypes
- */
-
- WinResource *list_resources(WinLibrary *, WinResource *, int *);
- bool read_library(WinLibrary *);
- WinResource *find_resource(WinLibrary *, const char *, const char *, const char *, int *);
- byte *get_resource_entry(WinLibrary *, WinResource *, int *);
- int do_resources(WinLibrary *, const char *, char *, char *, byte **);
- bool compare_resource_id(WinResource *, const char *);
- const char *res_type_string_to_id(const char *);
-
- const char *res_type_id_to_string(int);
- char *get_destination_name(WinLibrary *, char *, char *, char *);
-
- byte *extract_resource(WinLibrary *, WinResource *, int *, bool *, char *, char *, bool);
- int extract_resources(WinLibrary *, WinResource *, WinResource *, WinResource *, WinResource *, byte **);
- byte *extract_group_icon_cursor_resource(WinLibrary *, WinResource *, char *, int *, bool);
-
- bool decode_pe_resource_id(WinLibrary *, WinResource *, uint32);
- WinResource *list_pe_resources(WinLibrary *, Win32ImageResourceDirectory *, int, int *);
- int calc_vma_size(WinLibrary *);
- int do_resources_recurs(WinLibrary *, WinResource *, WinResource *, WinResource *, WinResource *, const char *, char *, char *, byte **);
- WinResource *find_with_resource_array(WinLibrary *, WinResource *, const char *);
-
- bool check_offset(byte *, int, const char *, void *, int);
-
- uint32 simple_vec(byte *data, uint32 ofs, byte size);
+private:
+ Common::PEResources _exe;
- void fix_win32_cursor_icon_file_dir_endian(Win32CursorIconFileDir *obj);
- void fix_win32_bitmap_info_header_endian(Win32BitmapInfoHeader *obj);
- void fix_win32_cursor_icon_file_dir_entry_endian(Win32CursorIconFileDirEntry *obj);
- void fix_win32_image_section_header(Win32ImageSectionHeader *obj);
- void fix_win32_image_header_endian(Win32ImageNTHeaders *obj);
- void fix_win32_image_data_directory(Win32ImageDataDirectory *obj);
+ bool extractResource(int id, CachedCursor *cc);
};
class MacResExtractor : public ResExtractor {
-
public:
MacResExtractor(ScummEngine_v70he *scumm);
- ~MacResExtractor() { }
+ ~MacResExtractor() {}
private:
Common::MacResManager *_resMgr;
- int extractResource(int id, byte **buf);
- int convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h,
- int *hotspot_x, int *hotspot_y, int *keycolor, byte **palette, int *palSize);
+ bool extractResource(int id, CachedCursor *cc);
};
} // End of namespace Scumm
diff --git a/graphics/fonts/winfont.cpp b/graphics/fonts/winfont.cpp
index fb37c8ddef..12509fd9e1 100644
--- a/graphics/fonts/winfont.cpp
+++ b/graphics/fonts/winfont.cpp
@@ -23,8 +23,9 @@
*/
#include "common/file.h"
-#include "common/ne_exe.h"
#include "common/str.h"
+#include "common/winexe_ne.h"
+#include "common/winexe_pe.h"
#include "graphics/fonts/winfont.h"
namespace Graphics {
@@ -75,8 +76,15 @@ static WinFontDirEntry readDirEntry(Common::SeekableReadStream &stream) {
}
bool WinFont::loadFromFON(const Common::String &fileName, const WinFontDirEntry &dirEntry) {
- // TODO: PE libraries (If it's used anywhere by a ScummVM game)
+ // First try loading via the NE code
+ if (loadFromNE(fileName, dirEntry))
+ return true;
+ // Then try loading via the PE code
+ return loadFromPE(fileName, dirEntry);
+}
+
+bool WinFont::loadFromNE(const Common::String &fileName, const WinFontDirEntry &dirEntry) {
Common::NEResources exe;
if (!exe.loadFromEXE(fileName))
@@ -89,44 +97,53 @@ bool WinFont::loadFromFON(const Common::String &fileName, const WinFontDirEntry
return false;
}
- uint16 numFonts = fontDirectory->readUint16LE();
+ uint32 fontId = getFontIndex(*fontDirectory, dirEntry);
+
+ delete fontDirectory;
- // Probably not possible, so this is really a sanity check
- if (numFonts == 0) {
- warning("No fonts in '%s'", fileName.c_str());
+ // Couldn't match the face name
+ if (fontId == 0xffffffff) {
+ warning("Could not find face '%s' in '%s'", dirEntry.faceName.c_str(), fileName.c_str());
return false;
}
- // Scour the directory for our matching name
- int fontId = -1;
- for (uint16 i = 0; i < numFonts; i++) {
- uint16 id = fontDirectory->readUint16LE();
+ // Actually go get our font now...
+ Common::SeekableReadStream *fontStream = exe.getResource(Common::kNEFont, fontId);
+ if (!fontStream) {
+ warning("Could not find font %d in %s", fontId, fileName.c_str());
+ return false;
+ }
- if (dirEntry.faceName.empty()) {
- // Use the first name when empty
- fontId = id;
- break;
- }
+ bool ok = loadFromFNT(*fontStream);
+ delete fontStream;
+ return ok;
+}
- WinFontDirEntry entry = readDirEntry(*fontDirectory);
+bool WinFont::loadFromPE(const Common::String &fileName, const WinFontDirEntry &dirEntry) {
+ Common::PEResources exe;
- if (dirEntry.faceName.equalsIgnoreCase(entry.faceName) && dirEntry.points == entry.points) {
- // Match!
- fontId = id;
- break;
- }
+ if (!exe.loadFromEXE(fileName))
+ return false;
+
+ // Let's pull out the font directory
+ Common::SeekableReadStream *fontDirectory = exe.getResource(Common::kPEFontDir, Common::String("FONTDIR"));
+ if (!fontDirectory) {
+ warning("No font directory in '%s'", fileName.c_str());
+ return false;
}
+ uint32 fontId = getFontIndex(*fontDirectory, dirEntry);
+
delete fontDirectory;
// Couldn't match the face name
- if (fontId < 0) {
+ if (fontId == 0xffffffff) {
warning("Could not find face '%s' in '%s'", dirEntry.faceName.c_str(), fileName.c_str());
return false;
}
// Actually go get our font now...
- Common::SeekableReadStream *fontStream = exe.getResource(Common::kNEFont, fontId);
+ Common::SeekableReadStream *fontStream = exe.getResource(Common::kPEFont, fontId);
if (!fontStream) {
warning("Could not find font %d in %s", fontId, fileName.c_str());
return false;
@@ -137,6 +154,32 @@ bool WinFont::loadFromFON(const Common::String &fileName, const WinFontDirEntry
return ok;
}
+uint32 WinFont::getFontIndex(Common::SeekableReadStream &stream, const WinFontDirEntry &dirEntry) {
+ uint16 numFonts = stream.readUint16LE();
+
+ // Probably not possible, so this is really a sanity check
+ if (numFonts == 0) {
+ warning("No fonts in exe");
+ return 0xffffffff;
+ }
+
+ // Scour the directory for our matching name
+ for (uint16 i = 0; i < numFonts; i++) {
+ uint16 id = stream.readUint16LE();
+
+ // Use the first name when empty
+ if (dirEntry.faceName.empty())
+ return id;
+
+ WinFontDirEntry entry = readDirEntry(stream);
+
+ if (dirEntry.faceName.equalsIgnoreCase(entry.faceName) && dirEntry.points == entry.points) // Match!
+ return id;
+ }
+
+ return 0xffffffff;
+}
+
bool WinFont::loadFromFNT(const Common::String &fileName) {
Common::File file;
diff --git a/graphics/fonts/winfont.h b/graphics/fonts/winfont.h
index b23455e2d5..fbe4a778e2 100644
--- a/graphics/fonts/winfont.h
+++ b/graphics/fonts/winfont.h
@@ -69,6 +69,10 @@ public:
void drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const;
private:
+ bool loadFromPE(const Common::String &fileName, const WinFontDirEntry &dirEntry);
+ bool loadFromNE(const Common::String &fileName, const WinFontDirEntry &dirEntry);
+
+ uint32 getFontIndex(Common::SeekableReadStream &stream, const WinFontDirEntry &dirEntry);
bool loadFromFNT(Common::SeekableReadStream &stream);
char indexToCharacter(uint16 index) const;
uint16 characterToIndex(byte character) const;
diff --git a/graphics/module.mk b/graphics/module.mk
index c962f0617d..cb3a07e691 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -23,7 +23,8 @@ MODULE_OBJS := \
surface.o \
thumbnail.o \
VectorRenderer.o \
- VectorRendererSpec.o
+ VectorRendererSpec.o \
+ wincursor.o
ifdef USE_SCALERS
MODULE_OBJS += \
diff --git a/graphics/wincursor.cpp b/graphics/wincursor.cpp
new file mode 100644
index 0000000000..d3c9414e03
--- /dev/null
+++ b/graphics/wincursor.cpp
@@ -0,0 +1,317 @@
+/* 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/debug.h"
+#include "common/file.h"
+#include "common/memstream.h"
+#include "common/ptr.h"
+#include "common/str.h"
+#include "common/stream.h"
+#include "common/winexe_ne.h"
+#include "common/winexe_pe.h"
+
+#include "graphics/wincursor.h"
+
+namespace Graphics {
+
+WinCursor::WinCursor() {
+ _width = 0;
+ _height = 0;
+ _hotspotX = 0;
+ _hotspotY = 0;
+ _surface = 0;
+ _keyColor = 0;
+ memset(_palette, 0, 256 * 3);
+}
+
+WinCursor::~WinCursor() {
+ clear();
+}
+
+uint16 WinCursor::getWidth() const {
+ return _width;
+}
+
+uint16 WinCursor::getHeight() const {
+ return _height;
+}
+
+uint16 WinCursor::getHotspotX() const {
+ return _hotspotX;
+}
+
+uint16 WinCursor::getHotspotY() const {
+ return _hotspotY;
+}
+
+byte WinCursor::getKeyColor() const {
+ return _keyColor;
+}
+
+bool WinCursor::readFromStream(Common::SeekableReadStream &stream) {
+ clear();
+
+ _hotspotX = stream.readUint16LE();
+ _hotspotY = stream.readUint16LE();
+
+ // Check header size
+ if (stream.readUint32LE() != 40)
+ return false;
+
+ // Check dimensions
+ _width = stream.readUint32LE();
+ _height = stream.readUint32LE() / 2;
+
+ if (_width & 3) {
+ // Cursors should always be a power of 2
+ // Of course, it wouldn't be hard to handle but if we have no examples...
+ warning("Non-divisible-by-4 width cursor found");
+ return false;
+ }
+
+ // Color planes
+ if (stream.readUint16LE() != 1)
+ return false;
+
+ // Only 1bpp and 8bpp supported
+ uint16 bitsPerPixel = stream.readUint16LE();
+ if (bitsPerPixel != 1 && bitsPerPixel != 8)
+ return false;
+
+ // Compression
+ if (stream.readUint32LE() != 0)
+ return false;
+
+ // Image size + X resolution + Y resolution
+ stream.skip(12);
+
+ uint32 numColors = stream.readUint32LE();
+
+ // If the color count is 0, then it uses up the maximum amount
+ if (numColors == 0)
+ numColors = 1 << bitsPerPixel;
+
+ // Reading the palette
+ stream.seek(40 + 4);
+ for (uint32 i = 0 ; i < numColors; i++) {
+ _palette[i * 3 + 2] = stream.readByte();
+ _palette[i * 3 + 1] = stream.readByte();
+ _palette[i * 3 ] = stream.readByte();
+ stream.readByte();
+ }
+
+ // Reading the bitmap data
+ uint32 dataSize = stream.size() - stream.pos();
+ byte *initialSource = new byte[dataSize];
+ stream.read(initialSource, dataSize);
+
+ // Parse the XOR map
+ const byte *src = initialSource;
+ _surface = new byte[_width * _height];
+ byte *dest = _surface + _width * (_height - 1);
+ uint32 imagePitch = _width * bitsPerPixel / 8;
+
+ for (uint32 i = 0; i < _height; i++) {
+ byte *rowDest = dest;
+
+ if (bitsPerPixel == 1) {
+ // 1bpp
+ for (uint32 j = 0; j < (_width / 8); j++) {
+ byte p = src[j];
+
+ for (int k = 0; k < 8; k++, rowDest++, p <<= 1) {
+ if ((p & 0x80) == 0x80)
+ *rowDest = 1;
+ else
+ *rowDest = 0;
+ }
+ }
+ } else {
+ // 8bpp
+ memcpy(rowDest, src, _width);
+ }
+
+ dest -= _width;
+ src += imagePitch;
+ }
+
+ // Calculate our key color
+ if (numColors < 256) {
+ // If we're not using the maximum colors in a byte, we can fit it in
+ _keyColor = numColors;
+ } else {
+ // HACK: Try to find a color that's not being used so it can become
+ // our keycolor. It's quite impossible to fit 257 entries into 256...
+ for (uint32 i = 0; i < 256; i++) {
+ for (int j = 0; j < _width * _height; j++) {
+ // TODO: Also check to see if the space is transparent
+
+ if (_surface[j] == i)
+ break;
+
+ if (j == _width * _height - 1) {
+ _keyColor = i;
+ i = 256;
+ break;
+ }
+ }
+ }
+ }
+
+ // Now go through and apply the AND map to get the transparency
+ uint32 andWidth = (_width + 7) / 8;
+ src += andWidth * (_height - 1);
+
+ for (uint32 y = 0; y < _height; y++) {
+ for (uint32 x = 0; x < _width; x++)
+ if (src[x / 8] & (1 << (7 - x % 8)))
+ _surface[y * _width + x] = _keyColor;
+
+ src -= andWidth;
+ }
+
+ delete[] initialSource;
+ return true;
+}
+
+void WinCursor::clear() {
+ delete[] _surface; _surface = 0;
+}
+
+WinCursorGroup::WinCursorGroup() {
+}
+
+WinCursorGroup::~WinCursorGroup() {
+ for (uint32 i = 0; i < cursors.size(); i++)
+ delete cursors[i].cursor;
+}
+
+WinCursorGroup *WinCursorGroup::createCursorGroup(Common::NEResources &exe, const Common::WinResourceID &id) {
+ Common::ScopedPtr<Common::SeekableReadStream> stream(exe.getResource(Common::kNEGroupCursor, id));
+
+ if (!stream || stream->size() <= 6)
+ return 0;
+
+ stream->skip(4);
+ uint32 cursorCount = stream->readUint16LE();
+ if ((uint32)stream->size() < (6 + cursorCount * 16))
+ return 0;
+
+ WinCursorGroup *group = new WinCursorGroup();
+ group->cursors.reserve(cursorCount);
+
+ for (uint32 i = 0; i < cursorCount; i++) {
+ stream->readUint16LE(); // width
+ stream->readUint16LE(); // height
+
+ // Plane count
+ if (stream->readUint16LE() != 1) {
+ delete group;
+ return 0;
+ }
+
+ // Bits per pixel
+ // NE cursors can only be 1bpp
+ if (stream->readUint16LE() != 1) {
+ delete group;
+ return 0;
+ }
+
+ stream->readUint32LE(); // data size
+ uint32 cursorId = stream->readUint32LE();
+
+ Common::ScopedPtr<Common::SeekableReadStream> cursorStream(exe.getResource(Common::kNECursor, cursorId));
+ if (!cursorStream) {
+ delete group;
+ return 0;
+ }
+
+ WinCursor *cursor = new WinCursor();
+ if (!cursor->readFromStream(*cursorStream)) {
+ delete cursor;
+ delete group;
+ return 0;
+ }
+
+ CursorItem item;
+ item.id = cursorId;
+ item.cursor = cursor;
+ group->cursors.push_back(item);
+ }
+
+ return group;
+}
+
+WinCursorGroup *WinCursorGroup::createCursorGroup(Common::PEResources &exe, const Common::WinResourceID &id) {
+ Common::ScopedPtr<Common::SeekableReadStream> stream(exe.getResource(Common::kPEGroupCursor, id));
+
+ if (!stream || stream->size() <= 6)
+ return 0;
+
+ stream->skip(4);
+ uint32 cursorCount = stream->readUint16LE();
+ if ((uint32)stream->size() < (6 + cursorCount * 14))
+ return 0;
+
+ WinCursorGroup *group = new WinCursorGroup();
+ group->cursors.reserve(cursorCount);
+
+ for (uint32 i = 0; i < cursorCount; i++) {
+ stream->readUint16LE(); // width
+ stream->readUint16LE(); // height
+
+ // Plane count
+ if (stream->readUint16LE() != 1) {
+ delete group;
+ return 0;
+ }
+
+ stream->readUint16LE(); // bits per pixel
+ stream->readUint32LE(); // data size
+ uint32 cursorId = stream->readUint16LE();
+
+ Common::ScopedPtr<Common::SeekableReadStream> cursorStream(exe.getResource(Common::kPECursor, cursorId));
+ if (!cursorStream) {
+ delete group;
+ return 0;
+ }
+
+ WinCursor *cursor = new WinCursor();
+ if (!cursor->readFromStream(*cursorStream)) {
+ delete cursor;
+ delete group;
+ return 0;
+ }
+
+ CursorItem item;
+ item.id = cursorId;
+ item.cursor = cursor;
+ group->cursors.push_back(item);
+ }
+
+ return group;
+}
+
+} // End of namespace Graphics
diff --git a/graphics/wincursor.h b/graphics/wincursor.h
new file mode 100644
index 0000000000..ca0abf6fe1
--- /dev/null
+++ b/graphics/wincursor.h
@@ -0,0 +1,105 @@
+/* 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 GRAPHICS_WINCURSOR_H
+#define GRAPHICS_WINCURSOR_H
+
+#include "common/array.h"
+#include "common/winexe.h"
+
+namespace Common {
+ class NEResources;
+ class PEResources;
+ class SeekableReadStream;
+}
+
+namespace Graphics {
+
+/** A Windows cursor. */
+class WinCursor {
+public:
+ WinCursor();
+ ~WinCursor();
+
+ /** Return the cursor's width. */
+ uint16 getWidth() const;
+ /** Return the cursor's height. */
+ uint16 getHeight() const;
+ /** Return the cursor's hotspot's x coordinate. */
+ uint16 getHotspotX() const;
+ /** Return the cursor's hotspot's y coordinate. */
+ uint16 getHotspotY() const;
+ /** Return the cursor's transparent key. */
+ byte getKeyColor() const;
+
+ const byte *getSurface() const { return _surface; }
+ const byte *getPalette() const { return _palette; }
+
+ /** Read the cursor's data out of a stream. */
+ bool readFromStream(Common::SeekableReadStream &stream);
+
+private:
+ byte *_surface;
+ byte _palette[256 * 3];
+
+ uint16 _width; ///< The cursor's width.
+ uint16 _height; ///< The cursor's height.
+ uint16 _hotspotX; ///< The cursor's hotspot's x coordinate.
+ uint16 _hotspotY; ///< The cursor's hotspot's y coordinate.
+ byte _keyColor; ///< The cursor's transparent key
+
+ /** Clear the cursor. */
+ void clear();
+};
+
+/**
+ * A structure holding an array of cursors from a single Windows Executable cursor group.
+ *
+ * Windows lumps different versions of the same cursors/icons together and decides which one
+ * to use based on the screen's color depth and resolution. For instance, one cursor group
+ * could hold a 1bpp 16x16 cursorand a 8bpp 16x16 cursor. This will hold all cursors in the
+ * group. This class should be used to actually parse the cursors, whereas WinCursor is just
+ * the representation used by this struct to store the cursors.
+ */
+struct WinCursorGroup {
+ WinCursorGroup();
+ ~WinCursorGroup();
+
+ struct CursorItem {
+ Common::WinResourceID id;
+ WinCursor *cursor;
+ };
+
+ Common::Array<CursorItem> cursors;
+
+ /** Create a cursor group from an NE EXE, returns 0 on failure */
+ static WinCursorGroup *createCursorGroup(Common::NEResources &exe, const Common::WinResourceID &id);
+ /** Create a cursor group from an PE EXE, returns 0 on failure */
+ static WinCursorGroup *createCursorGroup(Common::PEResources &exe, const Common::WinResourceID &id);
+};
+
+} // End of namespace Graphics
+
+#endif