aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorEugene Sandulenko2016-10-26 10:08:17 +0200
committerEugene Sandulenko2016-10-26 10:48:37 +0200
commit814db5fd38ae87a23674f07461ca35358bd77eb5 (patch)
tree254d522031dc8055274ddab3a2a540c4e074ca46 /engines
parentdf2bd1a94c17b4cf4e6981b85d80d23172d31ba0 (diff)
downloadscummvm-rg350-814db5fd38ae87a23674f07461ca35358bd77eb5.tar.gz
scummvm-rg350-814db5fd38ae87a23674f07461ca35358bd77eb5.tar.bz2
scummvm-rg350-814db5fd38ae87a23674f07461ca35358bd77eb5.zip
DIRECTOR: Renamed resource/archive files to better reflect reality
Diffstat (limited to 'engines')
-rw-r--r--engines/director/archive.cpp527
-rw-r--r--engines/director/archive.h (renamed from engines/director/resource.h)4
-rw-r--r--engines/director/director.cpp2
-rw-r--r--engines/director/frame.cpp2
-rw-r--r--engines/director/resource.cpp527
-rw-r--r--engines/director/score.cpp2
6 files changed, 532 insertions, 532 deletions
diff --git a/engines/director/archive.cpp b/engines/director/archive.cpp
index 9976c253f7..829764513f 100644
--- a/engines/director/archive.cpp
+++ b/engines/director/archive.cpp
@@ -20,233 +20,430 @@
*
*/
-#include "common/macresman.h"
+#include "director/archive.h"
-#include "director/director.h"
-#include "director/resource.h"
-#include "director/lingo/lingo.h"
+#include "common/debug.h"
+#include "common/macresman.h"
namespace Director {
-Archive *DirectorEngine::createArchive() {
- if (getPlatform() == Common::kPlatformMacintosh) {
- if (getVersion() < 4)
- return new MacArchive();
- else
- return new RIFXArchive();
- } else {
- return new RIFFArchive();
- }
+// Base Archive code
+
+Archive::Archive() {
+ _stream = 0;
+ _isBigEndian = true;
}
-void DirectorEngine::loadMainArchive() {
- if (getPlatform() == Common::kPlatformWindows)
- loadEXE();
- else
- loadMac();
-}
-
-void DirectorEngine::cleanupMainArchive() {
- delete _mainArchive;
- delete _macBinary;
-}
-
-void DirectorEngine::loadEXE() {
- Common::SeekableReadStream *exeStream = SearchMan.createReadStreamForMember(getEXEName());
- if (!exeStream)
- error("Failed to open EXE '%s'", getEXEName().c_str());
-
- _lingo->processEvent(kEventStart, 0);
-
- exeStream->seek(-4, SEEK_END);
- exeStream->seek(exeStream->readUint32LE());
-
- switch (getVersion()) {
- case 3:
- loadEXEv3(exeStream);
- break;
- case 4:
- loadEXEv4(exeStream);
- break;
- case 5:
- loadEXEv5(exeStream);
- break;
- case 7:
- loadEXEv7(exeStream);
- break;
- default:
- error("Unhandled Windows EXE version %d", getVersion());
+Archive::~Archive() {
+ close();
+}
+
+bool Archive::openFile(const Common::String &fileName) {
+ Common::File *file = new Common::File();
+
+ if (!file->open(fileName)) {
+ delete file;
+ return false;
+ }
+
+ if (!openStream(file)) {
+ close();
+ return false;
}
+
+ _fileName = fileName;
+
+ return true;
}
-void DirectorEngine::loadEXEv3(Common::SeekableReadStream *stream) {
- uint16 entryCount = stream->readUint16LE();
- if (entryCount != 1)
- error("Unhandled multiple entry v3 EXE");
+void Archive::close() {
+ _types.clear();
- stream->skip(5); // unknown
+ if (_stream)
+ delete _stream;
- stream->readUint32LE(); // Main MMM size
- Common::String mmmFileName = readPascalString(*stream);
- Common::String directoryName = readPascalString(*stream);
+ _stream = 0;
+}
- debugC(1, kDebugLoading, "Main MMM: '%s'", mmmFileName.c_str());
- debugC(1, kDebugLoading, "Directory Name: '%s'", directoryName.c_str());
+bool Archive::hasResource(uint32 tag, uint16 id) const {
+ if (!_types.contains(tag))
+ return false;
- _mainArchive = new RIFFArchive();
+ return _types[tag].contains(id);
+}
+
+bool Archive::hasResource(uint32 tag, const Common::String &resName) const {
+ if (!_types.contains(tag) || resName.empty())
+ return false;
+
+ const ResourceMap &resMap = _types[tag];
+
+ for (ResourceMap::const_iterator it = resMap.begin(); it != resMap.end(); it++)
+ if (it->_value.name.matchString(resName))
+ return true;
+
+ return false;
+}
- if (!_mainArchive->openFile(mmmFileName))
- error("Could not open '%s'", mmmFileName.c_str());
+Common::SeekableSubReadStreamEndian *Archive::getResource(uint32 tag, uint16 id) {
+ if (!_types.contains(tag))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
- delete stream;
+ const ResourceMap &resMap = _types[tag];
+
+ if (!resMap.contains(id))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
+
+ const Resource &res = resMap[id];
+
+ return new Common::SeekableSubReadStreamEndian(_stream, res.offset, res.offset + res.size, _isBigEndian, DisposeAfterUse::NO);
}
-void DirectorEngine::loadEXEv4(Common::SeekableReadStream *stream) {
- if (stream->readUint32BE() != MKTAG('P', 'J', '9', '3'))
- error("Invalid projector tag found in v4 EXE");
+uint32 Archive::getOffset(uint32 tag, uint16 id) const {
+ if (!_types.contains(tag))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
- uint32 rifxOffset = stream->readUint32LE();
- /* uint32 fontMapOffset = */ stream->readUint32LE();
- /* uint32 resourceForkOffset1 = */ stream->readUint32LE();
- /* uint32 resourceForkOffset2 = */ stream->readUint32LE();
- stream->readUint32LE(); // graphics DLL offset
- stream->readUint32LE(); // sound DLL offset
- /* uint32 rifxOffsetAlt = */ stream->readUint32LE(); // equivalent to rifxOffset
+ const ResourceMap &resMap = _types[tag];
- loadEXERIFX(stream, rifxOffset);
+ if (!resMap.contains(id))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
+
+ return resMap[id].offset;
}
-void DirectorEngine::loadEXEv5(Common::SeekableReadStream *stream) {
- if (stream->readUint32LE() != MKTAG('P', 'J', '9', '5'))
- error("Invalid projector tag found in v5 EXE");
+uint16 Archive::findResourceID(uint32 tag, const Common::String &resName) const {
+ if (!_types.contains(tag) || resName.empty())
+ return 0xFFFF;
+
+ const ResourceMap &resMap = _types[tag];
+
+ for (ResourceMap::const_iterator it = resMap.begin(); it != resMap.end(); it++)
+ if (it->_value.name.matchString(resName))
+ return it->_key;
- uint32 rifxOffset = stream->readUint32LE();
- stream->readUint32LE(); // unknown
- stream->readUint32LE(); // unknown
- stream->readUint32LE(); // unknown
- /* uint16 screenWidth = */ stream->readUint16LE();
- /* uint16 screenHeight = */ stream->readUint16LE();
- stream->readUint32LE(); // unknown
- stream->readUint32LE(); // unknown
- /* uint32 fontMapOffset = */ stream->readUint32LE();
+ return 0xFFFF;
+}
+
+Common::String Archive::getName(uint32 tag, uint16 id) const {
+ if (!_types.contains(tag))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
+
+ const ResourceMap &resMap = _types[tag];
+
+ if (!resMap.contains(id))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
+
+ return resMap[id].name;
+}
+
+Common::Array<uint32> Archive::getResourceTypeList() const {
+ Common::Array<uint32> typeList;
+
+ for (TypeMap::const_iterator it = _types.begin(); it != _types.end(); it++)
+ typeList.push_back(it->_key);
+
+ return typeList;
+}
+
+Common::Array<uint16> Archive::getResourceIDList(uint32 type) const {
+ Common::Array<uint16> idList;
+
+ if (!_types.contains(type))
+ return idList;
+
+ const ResourceMap &resMap = _types[type];
+
+ for (ResourceMap::const_iterator it = resMap.begin(); it != resMap.end(); it++)
+ idList.push_back(it->_key);
+
+ return idList;
+}
+
+uint32 Archive::convertTagToUppercase(uint32 tag) {
+ uint32 newTag = toupper(tag >> 24) << 24;
+ newTag |= toupper((tag >> 16) & 0xFF) << 16;
+ newTag |= toupper((tag >> 8) & 0xFF) << 8;
+
+ return newTag | toupper(tag & 0xFF);
+}
+
+// Mac Archive code
+
+MacArchive::MacArchive() : Archive(), _resFork(0) {
+}
+
+MacArchive::~MacArchive() {
+ delete _resFork;
+}
- loadEXERIFX(stream, rifxOffset);
+void MacArchive::close() {
+ Archive::close();
+ delete _resFork;
+ _resFork = 0;
}
-void DirectorEngine::loadEXEv7(Common::SeekableReadStream *stream) {
- if (stream->readUint32LE() != MKTAG('P', 'J', '0', '0'))
- error("Invalid projector tag found in v7 EXE");
+bool MacArchive::openFile(const Common::String &fileName) {
+ close();
- uint32 rifxOffset = stream->readUint32LE();
- stream->readUint32LE(); // unknown
- stream->readUint32LE(); // unknown
- stream->readUint32LE(); // unknown
- stream->readUint32LE(); // unknown
- stream->readUint32LE(); // some DLL offset
+ _resFork = new Common::MacResManager();
- loadEXERIFX(stream, rifxOffset);
+ if (!_resFork->open(fileName) || !_resFork->hasResFork()) {
+ close();
+ return false;
+ }
+
+ _fileName = _resFork->getBaseFileName();
+ if (_fileName.hasSuffix(".bin")) {
+ for (int i = 0; i < 4; i++)
+ _fileName.deleteLastChar();
+ }
+
+ Common::MacResTagArray tagArray = _resFork->getResTagArray();
+
+ for (uint32 i = 0; i < tagArray.size(); i++) {
+ ResourceMap &resMap = _types[tagArray[i]];
+ Common::MacResIDArray idArray = _resFork->getResIDArray(tagArray[i]);
+
+ for (uint32 j = 0; j < idArray.size(); j++) {
+ Resource &res = resMap[idArray[j]];
+
+ res.offset = res.size = 0; // unused
+ res.name = _resFork->getResName(tagArray[i], idArray[j]);
+ debug(3, "Found MacArchive resource '%s' %d: %s", tag2str(tagArray[i]), idArray[j], res.name.c_str());
+ }
+ }
+
+ return true;
}
-void DirectorEngine::loadEXERIFX(Common::SeekableReadStream *stream, uint32 offset) {
- _mainArchive = new RIFXArchive();
+bool MacArchive::openStream(Common::SeekableReadStream *stream, uint32 startOffset) {
+ // TODO: Add support for this (v4 Windows games)
+ return false;
+}
- if (!_mainArchive->openStream(stream, offset))
- error("Failed to load RIFX from EXE");
+Common::SeekableSubReadStreamEndian *MacArchive::getResource(uint32 tag, uint16 id) {
+ assert(_resFork);
+ Common::SeekableReadStream *stream = _resFork->getResource(tag, id);
+ return new Common::SeekableSubReadStreamEndian(stream, 0, stream->size(), true, DisposeAfterUse::NO);
}
-void DirectorEngine::loadMac() {
- if (getVersion() < 4) {
- // The data is part of the resource fork of the executable
- _mainArchive = new MacArchive();
+// RIFF Archive code
+
+bool RIFFArchive::openStream(Common::SeekableReadStream *stream, uint32 startOffset) {
+ close();
+
+ stream->seek(startOffset);
- if (!_mainArchive->openFile(getEXEName()))
- error("Failed to open Mac binary '%s'", getEXEName().c_str());
- } else {
- // The RIFX is located in the data fork of the executable
- _macBinary = new Common::MacResManager();
+ if (convertTagToUppercase(stream->readUint32BE()) != MKTAG('R', 'I', 'F', 'F'))
+ return false;
- if (!_macBinary->open(getEXEName()) || !_macBinary->hasDataFork())
- error("Failed to open Mac binary '%s'", getEXEName().c_str());
+ stream->readUint32LE(); // size
- Common::SeekableReadStream *dataFork = _macBinary->getDataFork();
- _mainArchive = new RIFXArchive();
+ if (convertTagToUppercase(stream->readUint32BE()) != MKTAG('R', 'M', 'M', 'P'))
+ return false;
- // First we need to detect PPC vs. 68k
+ if (convertTagToUppercase(stream->readUint32BE()) != MKTAG('C', 'F', 'T', 'C'))
+ return false;
- uint32 tag = dataFork->readUint32BE();
- uint32 startOffset;
+ uint32 cftcSize = stream->readUint32LE();
+ uint32 startPos = stream->pos();
+ stream->readUint32LE(); // unknown (always 0?)
- if (SWAP_BYTES_32(tag) == MKTAG('P', 'J', '9', '3') || tag == MKTAG('P', 'J', '9', '5') || tag == MKTAG('P', 'J', '0', '0')) {
- // PPC: The RIFX shares the data fork with the binary
- startOffset = dataFork->readUint32BE();
- } else {
- // 68k: The RIFX is the only thing in the data fork
- startOffset = 0;
+ while ((uint32)stream->pos() < startPos + cftcSize) {
+ uint32 tag = convertTagToUppercase(stream->readUint32BE());
+
+ uint32 size = stream->readUint32LE();
+ uint32 id = stream->readUint32LE();
+ uint32 offset = stream->readUint32LE();
+
+ if (tag == 0)
+ break;
+
+ uint16 startResPos = stream->pos();
+ stream->seek(offset + 12);
+
+ Common::String name = "";
+ byte nameSize = stream->readByte();
+
+ if (nameSize) {
+ for (uint8 i = 0; i < nameSize; i++) {
+ name += stream->readByte();
+ }
}
- if (!_mainArchive->openStream(dataFork, startOffset))
- error("Failed to load RIFX from Mac binary");
+ stream->seek(startResPos);
+
+ debug(3, "Found RIFF resource '%s' %d: %d @ 0x%08x", tag2str(tag), id, size, offset);
+
+ ResourceMap &resMap = _types[tag];
+ Resource &res = resMap[id];
+ res.offset = offset;
+ res.size = size;
+ res.name = name;
}
+
+ _stream = stream;
+ return true;
}
-void DirectorEngine::loadSharedCastsFrom(Common::String filename) {
- Archive *shardcst = createArchive();
+Common::SeekableSubReadStreamEndian *RIFFArchive::getResource(uint32 tag, uint16 id) {
+ if (!_types.contains(tag))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
+
+ const ResourceMap &resMap = _types[tag];
- debugC(1, kDebugLoading, "Loading Shared cast '%s'", filename.c_str());
+ if (!resMap.contains(id))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
- if (!shardcst->openFile(filename)) {
- warning("No shared cast %s", filename.c_str());
+ const Resource &res = resMap[id];
- return;
+ // Adjust to skip the resource header
+ uint32 offset = res.offset + 12;
+ uint32 size = res.size - 4;
+ // Skip the Pascal string
+ _stream->seek(offset);
+ byte stringSize = _stream->readByte(); // 1 for this byte
+
+ offset += stringSize + 1;
+ size -= stringSize + 1;
+
+ // Align to nearest word boundary
+ if (offset & 1) {
+ offset++;
+ size--;
}
- _sharedDIB = new Common::HashMap<int, Common::SeekableSubReadStreamEndian *>;
- _sharedSTXT = new Common::HashMap<int, Common::SeekableSubReadStreamEndian *>;
- _sharedSound = new Common::HashMap<int, Common::SeekableSubReadStreamEndian *>;
- _sharedBMP = new Common::HashMap<int, Common::SeekableSubReadStreamEndian *>;
+ return new Common::SeekableSubReadStreamEndian(_stream, offset, offset + size, true, DisposeAfterUse::NO);
+}
- Score *castScore = new Score(this, shardcst);
+// RIFX Archive code
- castScore->loadConfig(*shardcst->getResource(MKTAG('V','W','C','F'), 1024));
- castScore->loadCastData(*shardcst->getResource(MKTAG('V','W','C','R'), 1024));
+bool RIFXArchive::openStream(Common::SeekableReadStream *stream, uint32 startOffset) {
+ close();
- _sharedCasts = &castScore->_casts;
+ stream->seek(startOffset);
- Common::Array<uint16> dib = shardcst->getResourceIDList(MKTAG('D','I','B',' '));
- if (dib.size() != 0) {
- debugC(3, kDebugLoading, "Loading %d DIBs", dib.size());
+ uint32 headerTag = stream->readUint32BE();
- for (Common::Array<uint16>::iterator iterator = dib.begin(); iterator != dib.end(); ++iterator) {
- debugC(3, kDebugLoading, "Shared DIB %d", *iterator);
- _sharedDIB->setVal(*iterator, shardcst->getResource(MKTAG('D','I','B',' '), *iterator));
- }
+ if (headerTag == MKTAG('R', 'I', 'F', 'X'))
+ _isBigEndian = true;
+ else if (SWAP_BYTES_32(headerTag) == MKTAG('R', 'I', 'F', 'X'))
+ _isBigEndian = false;
+ else
+ return false;
+
+ Common::SeekableSubReadStreamEndian subStream(stream, startOffset + 4, stream->size(), _isBigEndian, DisposeAfterUse::NO);
+
+ subStream.readUint32(); // size
+
+ uint32 rifxType = subStream.readUint32();
+
+ if (rifxType != MKTAG('M', 'V', '9', '3') && rifxType != MKTAG('A', 'P', 'P', 'L'))
+ return false;
+
+ if (subStream.readUint32() != MKTAG('i', 'm', 'a', 'p'))
+ return false;
+
+ subStream.readUint32(); // imap length
+ subStream.readUint32(); // unknown
+ uint32 mmapOffset = subStream.readUint32() - startOffset - 4;
+
+ subStream.seek(mmapOffset);
+
+ if (subStream.readUint32() != MKTAG('m', 'm', 'a', 'p'))
+ return false;
+
+ subStream.readUint32(); // mmap length
+ subStream.readUint16(); // unknown
+ subStream.readUint16(); // unknown
+ subStream.readUint32(); // resCount + empty entries
+ uint32 resCount = subStream.readUint32();
+ subStream.skip(8); // all 0xFF
+ subStream.readUint32(); // unknown
+
+ Common::Array<Resource> resources;
+
+ // Need to look for these two resources
+ const Resource *keyRes = 0;
+ const Resource *casRes = 0;
+
+ for (uint32 i = 0; i < resCount; i++) {
+ uint32 tag = subStream.readUint32();
+ uint32 size = subStream.readUint32();
+ uint32 offset = subStream.readUint32();
+ /*uint16 flags = */ subStream.readUint16();
+ /*uint16 unk1 = */ subStream.readUint16();
+ /*uint32 unk2 = */ subStream.readUint32();
+
+ debug(3, "Found RIFX resource index %d: '%s', %d @ 0x%08x", i, tag2str(tag), size, offset);
+
+ Resource res;
+ res.offset = offset;
+ res.size = size;
+ resources.push_back(res);
+
+ // APPL is a special case; it has an embedded "normal" archive
+ if (rifxType == MKTAG('A', 'P', 'P', 'L') && tag == MKTAG('F', 'i', 'l', 'e'))
+ return openStream(stream, offset);
+
+ // Looking for two types here
+ if (tag == MKTAG('K', 'E', 'Y', '*'))
+ keyRes = &resources[resources.size() - 1];
+ else if (tag == MKTAG('C', 'A', 'S', '*'))
+ casRes = &resources[resources.size() - 1];
}
- Common::Array<uint16> stxt = shardcst->getResourceIDList(MKTAG('S','T','X','T'));
- if (stxt.size() != 0) {
- debugC(3, kDebugLoading, "Loading %d STXTs", stxt.size());
+ // We need to have found the 'File' resource already
+ if (rifxType == MKTAG('A', 'P', 'P', 'L')) {
+ warning("No 'File' resource present in APPL archive");
+ return false;
+ }
- for (Common::Array<uint16>::iterator iterator = stxt.begin(); iterator != stxt.end(); ++iterator) {
- debugC(3, kDebugLoading, "Shared STXT %d", *iterator);
- _sharedSTXT->setVal(*iterator, shardcst->getResource(MKTAG('S','T','X','T'), *iterator));
- }
+ // A KEY* must be present
+ if (!keyRes) {
+ warning("No 'KEY*' resource present");
+ return false;
}
- Common::Array<uint16> bmp = shardcst->getResourceIDList(MKTAG('B','I','T','D'));
- if (bmp.size() != 0) {
- debugC(3, kDebugLoading, "Loading %d BITDs", bmp.size());
- for (Common::Array<uint16>::iterator iterator = bmp.begin(); iterator != bmp.end(); ++iterator) {
- _sharedBMP->setVal(*iterator, shardcst->getResource(MKTAG('B','I','T','D'), *iterator));
- }
+ // Parse the CAS*, if present
+ Common::Array<uint32> casEntries;
+ if (casRes) {
+ Common::SeekableSubReadStreamEndian casStream(stream, casRes->offset + 8, casRes->offset + 8 + casRes->size, _isBigEndian, DisposeAfterUse::NO);
+ casEntries.resize(casRes->size / 4);
+
+ for (uint32 i = 0; i < casEntries.size(); i++)
+ casEntries[i] = casStream.readUint32();
}
- Common::Array<uint16> sound = shardcst->getResourceIDList(MKTAG('S','N','D',' '));
- if (stxt.size() != 0) {
- debugC(3, kDebugLoading, "Loading %d SNDs", sound.size());
- for (Common::Array<uint16>::iterator iterator = sound.begin(); iterator != sound.end(); ++iterator) {
- _sharedSound->setVal(*iterator, shardcst->getResource(MKTAG('S','N','D',' '), *iterator));
+ // Parse the KEY*
+ Common::SeekableSubReadStreamEndian keyStream(stream, keyRes->offset + 8, keyRes->offset + 8 + keyRes->size, _isBigEndian, DisposeAfterUse::NO);
+ /*uint16 unk1 = */ keyStream.readUint16();
+ /*uint16 unk2 = */ keyStream.readUint16();
+ /*uint32 unk3 = */ keyStream.readUint32();
+ uint32 keyCount = keyStream.readUint32();
+
+ for (uint32 i = 0; i < keyCount; i++) {
+ uint32 index = keyStream.readUint32();
+ uint32 id = keyStream.readUint32();
+ uint32 resTag = keyStream.readUint32();
+
+ // Handle CAS*/CASt nonsense
+ if (resTag == MKTAG('C', 'A', 'S', 't')) {
+ for (uint32 j = 0; j < casEntries.size(); j++) {
+ if (casEntries[j] == index) {
+ id += j + 1;
+ break;
+ }
+ }
}
+
+ const Resource &res = resources[index];
+ debug(3, "Found RIFX resource: '%s' 0x%04x, %d @ 0x%08x", tag2str(resTag), id, res.size, res.offset);
+ _types[resTag][id] = res;
}
+
+ _stream = stream;
+ return true;
}
} // End of namespace Director
diff --git a/engines/director/resource.h b/engines/director/archive.h
index 1265908cba..54d7086326 100644
--- a/engines/director/resource.h
+++ b/engines/director/archive.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef DIRECTOR_RESOURCE_H
-#define DIRECTOR_RESOURCE_H
+#ifndef DIRECTOR_ARCHIVE_H
+#define DIRECTOR_ARCHIVE_H
#include "common/file.h"
#include "common/substream.h"
diff --git a/engines/director/director.cpp b/engines/director/director.cpp
index 034c7c4afb..32358e4b6e 100644
--- a/engines/director/director.cpp
+++ b/engines/director/director.cpp
@@ -27,7 +27,7 @@
#include "graphics/macgui/macwindowmanager.h"
#include "director/director.h"
-#include "director/resource.h"
+#include "director/archive.h"
#include "director/sound.h"
#include "director/lingo/lingo.h"
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index 0ce7f2be9b..c00d8bd2b4 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -29,7 +29,7 @@
#include "director/director.h"
#include "director/frame.h"
#include "director/images.h"
-#include "director/resource.h"
+#include "director/archive.h"
#include "director/score.h"
#include "director/sprite.h"
diff --git a/engines/director/resource.cpp b/engines/director/resource.cpp
index 8efec141d1..a704918860 100644
--- a/engines/director/resource.cpp
+++ b/engines/director/resource.cpp
@@ -20,430 +20,233 @@
*
*/
-#include "director/resource.h"
-
-#include "common/debug.h"
#include "common/macresman.h"
-namespace Director {
-
-// Base Archive code
-
-Archive::Archive() {
- _stream = 0;
- _isBigEndian = true;
-}
-
-Archive::~Archive() {
- close();
-}
+#include "director/director.h"
+#include "director/archive.h"
+#include "director/lingo/lingo.h"
-bool Archive::openFile(const Common::String &fileName) {
- Common::File *file = new Common::File();
-
- if (!file->open(fileName)) {
- delete file;
- return false;
- }
+namespace Director {
- if (!openStream(file)) {
- close();
- return false;
+Archive *DirectorEngine::createArchive() {
+ if (getPlatform() == Common::kPlatformMacintosh) {
+ if (getVersion() < 4)
+ return new MacArchive();
+ else
+ return new RIFXArchive();
+ } else {
+ return new RIFFArchive();
}
-
- _fileName = fileName;
-
- return true;
}
-void Archive::close() {
- _types.clear();
-
- if (_stream)
- delete _stream;
-
- _stream = 0;
-}
-
-bool Archive::hasResource(uint32 tag, uint16 id) const {
- if (!_types.contains(tag))
- return false;
-
- return _types[tag].contains(id);
-}
-
-bool Archive::hasResource(uint32 tag, const Common::String &resName) const {
- if (!_types.contains(tag) || resName.empty())
- return false;
-
- const ResourceMap &resMap = _types[tag];
-
- for (ResourceMap::const_iterator it = resMap.begin(); it != resMap.end(); it++)
- if (it->_value.name.matchString(resName))
- return true;
-
- return false;
-}
-
-Common::SeekableSubReadStreamEndian *Archive::getResource(uint32 tag, uint16 id) {
- if (!_types.contains(tag))
- error("Archive does not contain '%s' %04x", tag2str(tag), id);
-
- const ResourceMap &resMap = _types[tag];
-
- if (!resMap.contains(id))
- error("Archive does not contain '%s' %04x", tag2str(tag), id);
-
- const Resource &res = resMap[id];
-
- return new Common::SeekableSubReadStreamEndian(_stream, res.offset, res.offset + res.size, _isBigEndian, DisposeAfterUse::NO);
-}
-
-uint32 Archive::getOffset(uint32 tag, uint16 id) const {
- if (!_types.contains(tag))
- error("Archive does not contain '%s' %04x", tag2str(tag), id);
-
- const ResourceMap &resMap = _types[tag];
-
- if (!resMap.contains(id))
- error("Archive does not contain '%s' %04x", tag2str(tag), id);
-
- return resMap[id].offset;
-}
-
-uint16 Archive::findResourceID(uint32 tag, const Common::String &resName) const {
- if (!_types.contains(tag) || resName.empty())
- return 0xFFFF;
-
- const ResourceMap &resMap = _types[tag];
-
- for (ResourceMap::const_iterator it = resMap.begin(); it != resMap.end(); it++)
- if (it->_value.name.matchString(resName))
- return it->_key;
-
- return 0xFFFF;
+void DirectorEngine::loadMainArchive() {
+ if (getPlatform() == Common::kPlatformWindows)
+ loadEXE();
+ else
+ loadMac();
+}
+
+void DirectorEngine::cleanupMainArchive() {
+ delete _mainArchive;
+ delete _macBinary;
+}
+
+void DirectorEngine::loadEXE() {
+ Common::SeekableReadStream *exeStream = SearchMan.createReadStreamForMember(getEXEName());
+ if (!exeStream)
+ error("Failed to open EXE '%s'", getEXEName().c_str());
+
+ _lingo->processEvent(kEventStart, 0);
+
+ exeStream->seek(-4, SEEK_END);
+ exeStream->seek(exeStream->readUint32LE());
+
+ switch (getVersion()) {
+ case 3:
+ loadEXEv3(exeStream);
+ break;
+ case 4:
+ loadEXEv4(exeStream);
+ break;
+ case 5:
+ loadEXEv5(exeStream);
+ break;
+ case 7:
+ loadEXEv7(exeStream);
+ break;
+ default:
+ error("Unhandled Windows EXE version %d", getVersion());
+ }
}
-Common::String Archive::getName(uint32 tag, uint16 id) const {
- if (!_types.contains(tag))
- error("Archive does not contain '%s' %04x", tag2str(tag), id);
+void DirectorEngine::loadEXEv3(Common::SeekableReadStream *stream) {
+ uint16 entryCount = stream->readUint16LE();
+ if (entryCount != 1)
+ error("Unhandled multiple entry v3 EXE");
- const ResourceMap &resMap = _types[tag];
+ stream->skip(5); // unknown
- if (!resMap.contains(id))
- error("Archive does not contain '%s' %04x", tag2str(tag), id);
+ stream->readUint32LE(); // Main MMM size
+ Common::String mmmFileName = readPascalString(*stream);
+ Common::String directoryName = readPascalString(*stream);
- return resMap[id].name;
-}
+ debugC(1, kDebugLoading, "Main MMM: '%s'", mmmFileName.c_str());
+ debugC(1, kDebugLoading, "Directory Name: '%s'", directoryName.c_str());
-Common::Array<uint32> Archive::getResourceTypeList() const {
- Common::Array<uint32> typeList;
+ _mainArchive = new RIFFArchive();
- for (TypeMap::const_iterator it = _types.begin(); it != _types.end(); it++)
- typeList.push_back(it->_key);
+ if (!_mainArchive->openFile(mmmFileName))
+ error("Could not open '%s'", mmmFileName.c_str());
- return typeList;
+ delete stream;
}
-Common::Array<uint16> Archive::getResourceIDList(uint32 type) const {
- Common::Array<uint16> idList;
-
- if (!_types.contains(type))
- return idList;
-
- const ResourceMap &resMap = _types[type];
+void DirectorEngine::loadEXEv4(Common::SeekableReadStream *stream) {
+ if (stream->readUint32BE() != MKTAG('P', 'J', '9', '3'))
+ error("Invalid projector tag found in v4 EXE");
- for (ResourceMap::const_iterator it = resMap.begin(); it != resMap.end(); it++)
- idList.push_back(it->_key);
+ uint32 rifxOffset = stream->readUint32LE();
+ /* uint32 fontMapOffset = */ stream->readUint32LE();
+ /* uint32 resourceForkOffset1 = */ stream->readUint32LE();
+ /* uint32 resourceForkOffset2 = */ stream->readUint32LE();
+ stream->readUint32LE(); // graphics DLL offset
+ stream->readUint32LE(); // sound DLL offset
+ /* uint32 rifxOffsetAlt = */ stream->readUint32LE(); // equivalent to rifxOffset
- return idList;
+ loadEXERIFX(stream, rifxOffset);
}
-uint32 Archive::convertTagToUppercase(uint32 tag) {
- uint32 newTag = toupper(tag >> 24) << 24;
- newTag |= toupper((tag >> 16) & 0xFF) << 16;
- newTag |= toupper((tag >> 8) & 0xFF) << 8;
+void DirectorEngine::loadEXEv5(Common::SeekableReadStream *stream) {
+ if (stream->readUint32LE() != MKTAG('P', 'J', '9', '5'))
+ error("Invalid projector tag found in v5 EXE");
- return newTag | toupper(tag & 0xFF);
-}
-
-// Mac Archive code
-
-MacArchive::MacArchive() : Archive(), _resFork(0) {
-}
-
-MacArchive::~MacArchive() {
- delete _resFork;
-}
+ uint32 rifxOffset = stream->readUint32LE();
+ stream->readUint32LE(); // unknown
+ stream->readUint32LE(); // unknown
+ stream->readUint32LE(); // unknown
+ /* uint16 screenWidth = */ stream->readUint16LE();
+ /* uint16 screenHeight = */ stream->readUint16LE();
+ stream->readUint32LE(); // unknown
+ stream->readUint32LE(); // unknown
+ /* uint32 fontMapOffset = */ stream->readUint32LE();
-void MacArchive::close() {
- Archive::close();
- delete _resFork;
- _resFork = 0;
+ loadEXERIFX(stream, rifxOffset);
}
-bool MacArchive::openFile(const Common::String &fileName) {
- close();
+void DirectorEngine::loadEXEv7(Common::SeekableReadStream *stream) {
+ if (stream->readUint32LE() != MKTAG('P', 'J', '0', '0'))
+ error("Invalid projector tag found in v7 EXE");
- _resFork = new Common::MacResManager();
+ uint32 rifxOffset = stream->readUint32LE();
+ stream->readUint32LE(); // unknown
+ stream->readUint32LE(); // unknown
+ stream->readUint32LE(); // unknown
+ stream->readUint32LE(); // unknown
+ stream->readUint32LE(); // some DLL offset
- if (!_resFork->open(fileName) || !_resFork->hasResFork()) {
- close();
- return false;
- }
-
- _fileName = _resFork->getBaseFileName();
- if (_fileName.hasSuffix(".bin")) {
- for (int i = 0; i < 4; i++)
- _fileName.deleteLastChar();
- }
-
- Common::MacResTagArray tagArray = _resFork->getResTagArray();
-
- for (uint32 i = 0; i < tagArray.size(); i++) {
- ResourceMap &resMap = _types[tagArray[i]];
- Common::MacResIDArray idArray = _resFork->getResIDArray(tagArray[i]);
-
- for (uint32 j = 0; j < idArray.size(); j++) {
- Resource &res = resMap[idArray[j]];
-
- res.offset = res.size = 0; // unused
- res.name = _resFork->getResName(tagArray[i], idArray[j]);
- debug(3, "Found MacArchive resource '%s' %d: %s", tag2str(tagArray[i]), idArray[j], res.name.c_str());
- }
- }
-
- return true;
+ loadEXERIFX(stream, rifxOffset);
}
-bool MacArchive::openStream(Common::SeekableReadStream *stream, uint32 startOffset) {
- // TODO: Add support for this (v4 Windows games)
- return false;
-}
+void DirectorEngine::loadEXERIFX(Common::SeekableReadStream *stream, uint32 offset) {
+ _mainArchive = new RIFXArchive();
-Common::SeekableSubReadStreamEndian *MacArchive::getResource(uint32 tag, uint16 id) {
- assert(_resFork);
- Common::SeekableReadStream *stream = _resFork->getResource(tag, id);
- return new Common::SeekableSubReadStreamEndian(stream, 0, stream->size(), true, DisposeAfterUse::NO);
+ if (!_mainArchive->openStream(stream, offset))
+ error("Failed to load RIFX from EXE");
}
-// RIFF Archive code
-
-bool RIFFArchive::openStream(Common::SeekableReadStream *stream, uint32 startOffset) {
- close();
-
- stream->seek(startOffset);
+void DirectorEngine::loadMac() {
+ if (getVersion() < 4) {
+ // The data is part of the resource fork of the executable
+ _mainArchive = new MacArchive();
- if (convertTagToUppercase(stream->readUint32BE()) != MKTAG('R', 'I', 'F', 'F'))
- return false;
+ if (!_mainArchive->openFile(getEXEName()))
+ error("Failed to open Mac binary '%s'", getEXEName().c_str());
+ } else {
+ // The RIFX is located in the data fork of the executable
+ _macBinary = new Common::MacResManager();
- stream->readUint32LE(); // size
+ if (!_macBinary->open(getEXEName()) || !_macBinary->hasDataFork())
+ error("Failed to open Mac binary '%s'", getEXEName().c_str());
- if (convertTagToUppercase(stream->readUint32BE()) != MKTAG('R', 'M', 'M', 'P'))
- return false;
+ Common::SeekableReadStream *dataFork = _macBinary->getDataFork();
+ _mainArchive = new RIFXArchive();
- if (convertTagToUppercase(stream->readUint32BE()) != MKTAG('C', 'F', 'T', 'C'))
- return false;
+ // First we need to detect PPC vs. 68k
- uint32 cftcSize = stream->readUint32LE();
- uint32 startPos = stream->pos();
- stream->readUint32LE(); // unknown (always 0?)
+ uint32 tag = dataFork->readUint32BE();
+ uint32 startOffset;
- while ((uint32)stream->pos() < startPos + cftcSize) {
- uint32 tag = convertTagToUppercase(stream->readUint32BE());
-
- uint32 size = stream->readUint32LE();
- uint32 id = stream->readUint32LE();
- uint32 offset = stream->readUint32LE();
-
- if (tag == 0)
- break;
-
- uint16 startResPos = stream->pos();
- stream->seek(offset + 12);
-
- Common::String name = "";
- byte nameSize = stream->readByte();
-
- if (nameSize) {
- for (uint8 i = 0; i < nameSize; i++) {
- name += stream->readByte();
- }
+ if (SWAP_BYTES_32(tag) == MKTAG('P', 'J', '9', '3') || tag == MKTAG('P', 'J', '9', '5') || tag == MKTAG('P', 'J', '0', '0')) {
+ // PPC: The RIFX shares the data fork with the binary
+ startOffset = dataFork->readUint32BE();
+ } else {
+ // 68k: The RIFX is the only thing in the data fork
+ startOffset = 0;
}
- stream->seek(startResPos);
-
- debug(3, "Found RIFF resource '%s' %d: %d @ 0x%08x", tag2str(tag), id, size, offset);
-
- ResourceMap &resMap = _types[tag];
- Resource &res = resMap[id];
- res.offset = offset;
- res.size = size;
- res.name = name;
+ if (!_mainArchive->openStream(dataFork, startOffset))
+ error("Failed to load RIFX from Mac binary");
}
-
- _stream = stream;
- return true;
}
-Common::SeekableSubReadStreamEndian *RIFFArchive::getResource(uint32 tag, uint16 id) {
- if (!_types.contains(tag))
- error("Archive does not contain '%s' %04x", tag2str(tag), id);
-
- const ResourceMap &resMap = _types[tag];
+void DirectorEngine::loadSharedCastsFrom(Common::String filename) {
+ Archive *shardcst = createArchive();
- if (!resMap.contains(id))
- error("Archive does not contain '%s' %04x", tag2str(tag), id);
+ debugC(1, kDebugLoading, "Loading Shared cast '%s'", filename.c_str());
- const Resource &res = resMap[id];
+ if (!shardcst->openFile(filename)) {
+ warning("No shared cast %s", filename.c_str());
- // Adjust to skip the resource header
- uint32 offset = res.offset + 12;
- uint32 size = res.size - 4;
- // Skip the Pascal string
- _stream->seek(offset);
- byte stringSize = _stream->readByte(); // 1 for this byte
-
- offset += stringSize + 1;
- size -= stringSize + 1;
-
- // Align to nearest word boundary
- if (offset & 1) {
- offset++;
- size--;
+ return;
}
- return new Common::SeekableSubReadStreamEndian(_stream, offset, offset + size, true, DisposeAfterUse::NO);
-}
+ _sharedDIB = new Common::HashMap<int, Common::SeekableSubReadStreamEndian *>;
+ _sharedSTXT = new Common::HashMap<int, Common::SeekableSubReadStreamEndian *>;
+ _sharedSound = new Common::HashMap<int, Common::SeekableSubReadStreamEndian *>;
+ _sharedBMP = new Common::HashMap<int, Common::SeekableSubReadStreamEndian *>;
-// RIFX Archive code
+ Score *castScore = new Score(this, shardcst);
-bool RIFXArchive::openStream(Common::SeekableReadStream *stream, uint32 startOffset) {
- close();
+ castScore->loadConfig(*shardcst->getResource(MKTAG('V','W','C','F'), 1024));
+ castScore->loadCastData(*shardcst->getResource(MKTAG('V','W','C','R'), 1024));
- stream->seek(startOffset);
+ _sharedCasts = &castScore->_casts;
- uint32 headerTag = stream->readUint32BE();
+ Common::Array<uint16> dib = shardcst->getResourceIDList(MKTAG('D','I','B',' '));
+ if (dib.size() != 0) {
+ debugC(3, kDebugLoading, "Loading %d DIBs", dib.size());
- if (headerTag == MKTAG('R', 'I', 'F', 'X'))
- _isBigEndian = true;
- else if (SWAP_BYTES_32(headerTag) == MKTAG('R', 'I', 'F', 'X'))
- _isBigEndian = false;
- else
- return false;
-
- Common::SeekableSubReadStreamEndian subStream(stream, startOffset + 4, stream->size(), _isBigEndian, DisposeAfterUse::NO);
-
- subStream.readUint32(); // size
-
- uint32 rifxType = subStream.readUint32();
-
- if (rifxType != MKTAG('M', 'V', '9', '3') && rifxType != MKTAG('A', 'P', 'P', 'L'))
- return false;
-
- if (subStream.readUint32() != MKTAG('i', 'm', 'a', 'p'))
- return false;
-
- subStream.readUint32(); // imap length
- subStream.readUint32(); // unknown
- uint32 mmapOffset = subStream.readUint32() - startOffset - 4;
-
- subStream.seek(mmapOffset);
-
- if (subStream.readUint32() != MKTAG('m', 'm', 'a', 'p'))
- return false;
-
- subStream.readUint32(); // mmap length
- subStream.readUint16(); // unknown
- subStream.readUint16(); // unknown
- subStream.readUint32(); // resCount + empty entries
- uint32 resCount = subStream.readUint32();
- subStream.skip(8); // all 0xFF
- subStream.readUint32(); // unknown
-
- Common::Array<Resource> resources;
-
- // Need to look for these two resources
- const Resource *keyRes = 0;
- const Resource *casRes = 0;
-
- for (uint32 i = 0; i < resCount; i++) {
- uint32 tag = subStream.readUint32();
- uint32 size = subStream.readUint32();
- uint32 offset = subStream.readUint32();
- /*uint16 flags = */ subStream.readUint16();
- /*uint16 unk1 = */ subStream.readUint16();
- /*uint32 unk2 = */ subStream.readUint32();
-
- debug(3, "Found RIFX resource index %d: '%s', %d @ 0x%08x", i, tag2str(tag), size, offset);
-
- Resource res;
- res.offset = offset;
- res.size = size;
- resources.push_back(res);
-
- // APPL is a special case; it has an embedded "normal" archive
- if (rifxType == MKTAG('A', 'P', 'P', 'L') && tag == MKTAG('F', 'i', 'l', 'e'))
- return openStream(stream, offset);
-
- // Looking for two types here
- if (tag == MKTAG('K', 'E', 'Y', '*'))
- keyRes = &resources[resources.size() - 1];
- else if (tag == MKTAG('C', 'A', 'S', '*'))
- casRes = &resources[resources.size() - 1];
+ for (Common::Array<uint16>::iterator iterator = dib.begin(); iterator != dib.end(); ++iterator) {
+ debugC(3, kDebugLoading, "Shared DIB %d", *iterator);
+ _sharedDIB->setVal(*iterator, shardcst->getResource(MKTAG('D','I','B',' '), *iterator));
+ }
}
- // We need to have found the 'File' resource already
- if (rifxType == MKTAG('A', 'P', 'P', 'L')) {
- warning("No 'File' resource present in APPL archive");
- return false;
- }
+ Common::Array<uint16> stxt = shardcst->getResourceIDList(MKTAG('S','T','X','T'));
+ if (stxt.size() != 0) {
+ debugC(3, kDebugLoading, "Loading %d STXTs", stxt.size());
- // A KEY* must be present
- if (!keyRes) {
- warning("No 'KEY*' resource present");
- return false;
+ for (Common::Array<uint16>::iterator iterator = stxt.begin(); iterator != stxt.end(); ++iterator) {
+ debugC(3, kDebugLoading, "Shared STXT %d", *iterator);
+ _sharedSTXT->setVal(*iterator, shardcst->getResource(MKTAG('S','T','X','T'), *iterator));
+ }
}
- // Parse the CAS*, if present
- Common::Array<uint32> casEntries;
- if (casRes) {
- Common::SeekableSubReadStreamEndian casStream(stream, casRes->offset + 8, casRes->offset + 8 + casRes->size, _isBigEndian, DisposeAfterUse::NO);
- casEntries.resize(casRes->size / 4);
-
- for (uint32 i = 0; i < casEntries.size(); i++)
- casEntries[i] = casStream.readUint32();
+ Common::Array<uint16> bmp = shardcst->getResourceIDList(MKTAG('B','I','T','D'));
+ if (bmp.size() != 0) {
+ debugC(3, kDebugLoading, "Loading %d BITDs", bmp.size());
+ for (Common::Array<uint16>::iterator iterator = bmp.begin(); iterator != bmp.end(); ++iterator) {
+ _sharedBMP->setVal(*iterator, shardcst->getResource(MKTAG('B','I','T','D'), *iterator));
+ }
}
- // Parse the KEY*
- Common::SeekableSubReadStreamEndian keyStream(stream, keyRes->offset + 8, keyRes->offset + 8 + keyRes->size, _isBigEndian, DisposeAfterUse::NO);
- /*uint16 unk1 = */ keyStream.readUint16();
- /*uint16 unk2 = */ keyStream.readUint16();
- /*uint32 unk3 = */ keyStream.readUint32();
- uint32 keyCount = keyStream.readUint32();
-
- for (uint32 i = 0; i < keyCount; i++) {
- uint32 index = keyStream.readUint32();
- uint32 id = keyStream.readUint32();
- uint32 resTag = keyStream.readUint32();
-
- // Handle CAS*/CASt nonsense
- if (resTag == MKTAG('C', 'A', 'S', 't')) {
- for (uint32 j = 0; j < casEntries.size(); j++) {
- if (casEntries[j] == index) {
- id += j + 1;
- break;
- }
- }
+ Common::Array<uint16> sound = shardcst->getResourceIDList(MKTAG('S','N','D',' '));
+ if (stxt.size() != 0) {
+ debugC(3, kDebugLoading, "Loading %d SNDs", sound.size());
+ for (Common::Array<uint16>::iterator iterator = sound.begin(); iterator != sound.end(); ++iterator) {
+ _sharedSound->setVal(*iterator, shardcst->getResource(MKTAG('S','N','D',' '), *iterator));
}
-
- const Resource &res = resources[index];
- debug(3, "Found RIFX resource: '%s' 0x%04x, %d @ 0x%08x", tag2str(resTag), id, res.size, res.offset);
- _types[resTag][id] = res;
}
-
- _stream = stream;
- return true;
}
} // End of namespace Director
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 5c594c20fc..7b03ca1a7d 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -32,7 +32,7 @@
#include "director/score.h"
#include "director/frame.h"
-#include "director/resource.h"
+#include "director/archive.h"
#include "director/sound.h"
#include "director/sprite.h"
#include "director/lingo/lingo.h"