aboutsummaryrefslogtreecommitdiff
path: root/engines/director/resource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/director/resource.cpp')
-rw-r--r--engines/director/resource.cpp527
1 files changed, 170 insertions, 357 deletions
diff --git a/engines/director/resource.cpp b/engines/director/resource.cpp
index 8efec141d1..54ab2198e1 100644
--- a/engines/director/resource.cpp
+++ b/engines/director/resource.cpp
@@ -20,430 +20,243 @@
*
*/
-#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();
-}
-
-bool Archive::openFile(const Common::String &fileName) {
- Common::File *file = new Common::File();
+#include "director/director.h"
+#include "director/archive.h"
+#include "director/lingo/lingo.h"
- 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();
}
-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;
+void DirectorEngine::cleanupMainArchive() {
+ delete _mainArchive;
+ delete _macBinary;
}
-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;
+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::Array<uint16> Archive::getResourceIDList(uint32 type) const {
- Common::Array<uint16> idList;
+void DirectorEngine::loadEXEv3(Common::SeekableReadStream *stream) {
+ uint16 entryCount = stream->readUint16LE();
+ if (entryCount != 1)
+ error("Unhandled multiple entry v3 EXE");
- if (!_types.contains(type))
- return idList;
+ stream->skip(5); // unknown
- const ResourceMap &resMap = _types[type];
+ stream->readUint32LE(); // Main MMM size
+ Common::String mmmFileName = readPascalString(*stream);
+ Common::String directoryName = readPascalString(*stream);
- for (ResourceMap::const_iterator it = resMap.begin(); it != resMap.end(); it++)
- idList.push_back(it->_key);
+ debugC(1, kDebugLoading, "Main MMM: '%s'", mmmFileName.c_str());
+ debugC(1, kDebugLoading, "Directory Name: '%s'", directoryName.c_str());
- return idList;
-}
+ _mainArchive = new RIFFArchive();
-uint32 Archive::convertTagToUppercase(uint32 tag) {
- uint32 newTag = toupper(tag >> 24) << 24;
- newTag |= toupper((tag >> 16) & 0xFF) << 16;
- newTag |= toupper((tag >> 8) & 0xFF) << 8;
+ if (!_mainArchive->openFile(mmmFileName))
+ error("Could not open '%s'", mmmFileName.c_str());
- return newTag | toupper(tag & 0xFF);
+ delete stream;
}
-// Mac Archive code
+void DirectorEngine::loadEXEv4(Common::SeekableReadStream *stream) {
+ if (stream->readUint32BE() != MKTAG('P', 'J', '9', '3'))
+ error("Invalid projector tag found in v4 EXE");
-MacArchive::MacArchive() : Archive(), _resFork(0) {
-}
+ 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
-MacArchive::~MacArchive() {
- delete _resFork;
+ loadEXERIFX(stream, rifxOffset);
}
-void MacArchive::close() {
- Archive::close();
- delete _resFork;
- _resFork = 0;
+void DirectorEngine::loadEXEv5(Common::SeekableReadStream *stream) {
+ if (stream->readUint32LE() != MKTAG('P', 'J', '9', '5'))
+ error("Invalid projector tag found in v5 EXE");
+
+ 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();
+
+ 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();
+void DirectorEngine::loadMac() {
+ if (getVersion() < 4) {
+ // The data is part of the resource fork of the executable
+ _mainArchive = new MacArchive();
- 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?)
-
- 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);
+void DirectorEngine::loadSharedCastsFrom(Common::String filename) {
+ Archive *shardcst = createArchive();
- 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];
+ _sharedCasts = new Common::HashMap<int, Cast *>;
- // 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));
- stream->seek(startOffset);
+ if (getVersion() < 4)
+ castScore->loadCastDataVWCR(*shardcst->getResource(MKTAG('V','W','C','R'), 1024));
- uint32 headerTag = stream->readUint32BE();
-
- 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);
+ Common::Array<uint16> cast = shardcst->getResourceIDList(MKTAG('C','A','S','t'));
+ if (cast.size() > 0) {
+ for (Common::Array<uint16>::iterator iterator = cast.begin(); iterator != cast.end(); ++iterator)
+ castScore->loadCastData(*shardcst->getResource(MKTAG('C','A','S','t'), *iterator), *iterator);
+ }
- Resource res;
- res.offset = offset;
- res.size = size;
- resources.push_back(res);
+ _sharedCasts = &castScore->_casts;
- // 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);
+ Common::Array<uint16> dib = shardcst->getResourceIDList(MKTAG('D','I','B',' '));
+ if (dib.size() != 0) {
+ debugC(3, kDebugLoading, "Loading %d DIBs", dib.size());
- // 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