diff options
-rw-r--r-- | common/macresman.cpp | 138 | ||||
-rw-r--r-- | common/macresman.h | 11 | ||||
-rw-r--r-- | common/module.mk | 4 | ||||
-rw-r--r-- | common/ne_exe.cpp | 612 | ||||
-rw-r--r-- | common/winexe.cpp | 84 | ||||
-rw-r--r-- | common/winexe.h | 74 | ||||
-rw-r--r-- | common/winexe_ne.cpp | 291 | ||||
-rw-r--r-- | common/winexe_ne.h (renamed from common/ne_exe.h) | 100 | ||||
-rw-r--r-- | common/winexe_pe.cpp | 255 | ||||
-rw-r--r-- | common/winexe_pe.h | 122 | ||||
-rw-r--r-- | engines/mohawk/cursors.cpp | 224 | ||||
-rw-r--r-- | engines/mohawk/cursors.h | 41 | ||||
-rw-r--r-- | engines/mohawk/riven.cpp | 30 | ||||
-rw-r--r-- | engines/mohawk/riven_cursors.h | 670 | ||||
-rw-r--r-- | engines/mohawk/riven_external.cpp | 38 | ||||
-rw-r--r-- | engines/mohawk/riven_scripts.cpp | 1 | ||||
-rw-r--r-- | engines/sci/graphics/cursor.cpp | 12 | ||||
-rw-r--r-- | engines/scumm/he/resource_he.cpp | 1108 | ||||
-rw-r--r-- | engines/scumm/he/resource_he.h | 381 | ||||
-rw-r--r-- | graphics/fonts/winfont.cpp | 89 | ||||
-rw-r--r-- | graphics/fonts/winfont.h | 4 | ||||
-rw-r--r-- | graphics/module.mk | 3 | ||||
-rw-r--r-- | graphics/wincursor.cpp | 317 | ||||
-rw-r--r-- | graphics/wincursor.h | 105 |
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 §ion, 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 §ion, 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 |