aboutsummaryrefslogtreecommitdiff
path: root/engines/mohawk
diff options
context:
space:
mode:
Diffstat (limited to 'engines/mohawk')
-rw-r--r--engines/mohawk/cstime.cpp2
-rw-r--r--engines/mohawk/cursors.cpp2
-rw-r--r--engines/mohawk/livingbooks.cpp21
-rw-r--r--engines/mohawk/livingbooks.h10
-rw-r--r--engines/mohawk/mohawk.h4
-rw-r--r--engines/mohawk/myst.cpp4
-rw-r--r--engines/mohawk/resource.cpp592
-rw-r--r--engines/mohawk/resource.h143
-rw-r--r--engines/mohawk/riven.cpp4
-rw-r--r--engines/mohawk/riven_saveload.cpp2
10 files changed, 322 insertions, 462 deletions
diff --git a/engines/mohawk/cstime.cpp b/engines/mohawk/cstime.cpp
index 59bc5ad661..3f9827581b 100644
--- a/engines/mohawk/cstime.cpp
+++ b/engines/mohawk/cstime.cpp
@@ -217,7 +217,7 @@ void MohawkEngine_CSTime::nextScene() {
void MohawkEngine_CSTime::loadResourceFile(Common::String name) {
MohawkArchive *archive = new MohawkArchive();
- if (!archive->open(name + ".mhk"))
+ if (!archive->openFile(name + ".mhk"))
error("failed to open %s.mhk", name.c_str());
_mhk.push_back(archive);
}
diff --git a/engines/mohawk/cursors.cpp b/engines/mohawk/cursors.cpp
index a797e4e127..3284a3228f 100644
--- a/engines/mohawk/cursors.cpp
+++ b/engines/mohawk/cursors.cpp
@@ -234,7 +234,7 @@ LivingBooksCursorManager_v2::LivingBooksCursorManager_v2() {
// Try to open the system archive if we have it
_sysArchive = new MohawkArchive();
- if (!_sysArchive->open("system.mhk")) {
+ if (!_sysArchive->openFile("system.mhk")) {
delete _sysArchive;
_sysArchive = 0;
}
diff --git a/engines/mohawk/livingbooks.cpp b/engines/mohawk/livingbooks.cpp
index 248a9e607a..8df5db720c 100644
--- a/engines/mohawk/livingbooks.cpp
+++ b/engines/mohawk/livingbooks.cpp
@@ -82,7 +82,7 @@ LBPage::LBPage(MohawkEngine_LivingBooks *vm) : _vm(vm) {
_cascade = false;
}
-void LBPage::open(MohawkArchive *mhk, uint16 baseId) {
+void LBPage::open(Archive *mhk, uint16 baseId) {
_mhk = mhk;
_baseId = baseId;
@@ -385,8 +385,8 @@ bool MohawkEngine_LivingBooks::loadPage(LBMode mode, uint page, uint subpage) {
warning("ignoring 'killgag' for filename '%s'", filename.c_str());
}
- MohawkArchive *pageArchive = createMohawkArchive();
- if (!filename.empty() && pageArchive->open(filename)) {
+ Archive *pageArchive = createArchive();
+ if (!filename.empty() && pageArchive->openFile(filename)) {
_page = new LBPage(this);
_page->open(pageArchive, 1000);
} else {
@@ -590,11 +590,11 @@ void MohawkEngine_LivingBooks::updatePage() {
}
}
-void MohawkEngine_LivingBooks::addArchive(MohawkArchive *archive) {
+void MohawkEngine_LivingBooks::addArchive(Archive *archive) {
_mhk.push_back(archive);
}
-void MohawkEngine_LivingBooks::removeArchive(MohawkArchive *archive) {
+void MohawkEngine_LivingBooks::removeArchive(Archive *archive) {
for (uint i = 0; i < _mhk.size(); i++) {
if (archive != _mhk[i])
continue;
@@ -863,8 +863,11 @@ Common::String MohawkEngine_LivingBooks::convertWinFileName(const Common::String
return filename;
}
-MohawkArchive *MohawkEngine_LivingBooks::createMohawkArchive() const {
- return isPreMohawk() ? new LivingBooksArchive_v1() : new MohawkArchive();
+Archive *MohawkEngine_LivingBooks::createArchive() const {
+ if (isPreMohawk())
+ return new LivingBooksArchive_v1();
+
+ return new MohawkArchive();
}
bool MohawkEngine_LivingBooks::isPreMohawk() const {
@@ -3855,8 +3858,8 @@ void LBProxyItem::init() {
}
debug(1, "LBProxyItem loading archive '%s' with id %d", filename.c_str(), baseId);
- MohawkArchive *pageArchive = _vm->createMohawkArchive();
- if (!pageArchive->open(filename))
+ Archive *pageArchive = _vm->createArchive();
+ if (!pageArchive->openFile(filename))
error("failed to open archive '%s' (for proxy '%s')", filename.c_str(), _desc.c_str());
_page = new LBPage(_vm);
_page->open(pageArchive, baseId);
diff --git a/engines/mohawk/livingbooks.h b/engines/mohawk/livingbooks.h
index 02cf6c3f64..ed198a60c1 100644
--- a/engines/mohawk/livingbooks.h
+++ b/engines/mohawk/livingbooks.h
@@ -628,7 +628,7 @@ public:
LBPage(MohawkEngine_LivingBooks *vm);
~LBPage();
- void open(MohawkArchive *mhk, uint16 baseId);
+ void open(Archive *mhk, uint16 baseId);
uint16 getResourceVersion();
void itemDestroyed(LBItem *item);
@@ -638,7 +638,7 @@ public:
protected:
MohawkEngine_LivingBooks *_vm;
- MohawkArchive *_mhk;
+ Archive *_mhk;
Common::Array<LBItem *> _items;
uint16 _baseId;
@@ -667,8 +667,8 @@ public:
Common::Rect readRect(Common::ReadStreamEndian *stream);
GUI::Debugger *getDebugger() { return _console; }
- void addArchive(MohawkArchive *archive);
- void removeArchive(MohawkArchive *Archive);
+ void addArchive(Archive *archive);
+ void removeArchive(Archive *Archive);
void addItem(LBItem *item);
void removeItems(const Common::Array<LBItem *> &items);
@@ -697,7 +697,7 @@ public:
// helper functions, also used by LBProxyItem
Common::String getFileNameFromConfig(const Common::String &section, const Common::String &key, Common::String &leftover);
- MohawkArchive *createMohawkArchive() const;
+ Archive *createArchive() const;
private:
LivingBooksConsole *_console;
diff --git a/engines/mohawk/mohawk.h b/engines/mohawk/mohawk.h
index f0618f7374..2f0e570d56 100644
--- a/engines/mohawk/mohawk.h
+++ b/engines/mohawk/mohawk.h
@@ -77,7 +77,7 @@ enum MohawkGameFeatures {
struct MohawkGameDescription;
class Sound;
class PauseDialog;
-class MohawkArchive;
+class Archive;
class CursorManager;
class MohawkEngine : public ::Engine {
@@ -123,7 +123,7 @@ private:
protected:
// An array holding the main Mohawk archives require by the games
- Common::Array<MohawkArchive *> _mhk;
+ Common::Array<Archive *> _mhk;
};
} // End of namespace Mohawk
diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp
index b60f8bd1ee..6bdf163a91 100644
--- a/engines/mohawk/myst.cpp
+++ b/engines/mohawk/myst.cpp
@@ -281,7 +281,7 @@ Common::Error MohawkEngine_Myst::run() {
// Load Help System (Masterpiece Edition Only)
if (getFeatures() & GF_ME) {
MohawkArchive *mhk = new MohawkArchive();
- if (!mhk->open("help.dat"))
+ if (!mhk->openFile("help.dat"))
error("Could not load help.dat");
_mhk.push_back(mhk);
}
@@ -488,7 +488,7 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS
_mhk[0] = new MohawkArchive();
}
- if (!_mhk[0]->open(mystFiles[_curStack]))
+ if (!_mhk[0]->openFile(mystFiles[_curStack]))
error("Could not open %s", mystFiles[_curStack]);
if (getPlatform() == Common::kPlatformMacintosh)
diff --git a/engines/mohawk/resource.cpp b/engines/mohawk/resource.cpp
index 37fc73de67..2dc6d2252a 100644
--- a/engines/mohawk/resource.cpp
+++ b/engines/mohawk/resource.cpp
@@ -29,23 +29,25 @@
namespace Mohawk {
-MohawkArchive::MohawkArchive() {
- _mhk = NULL;
- _types = NULL;
- _fileTable = NULL;
+// Base Archive code
+
+Archive::Archive() {
+ _stream = 0;
+}
+
+Archive::~Archive() {
+ close();
}
-bool MohawkArchive::open(const Common::String &filename) {
+bool Archive::openFile(const Common::String &fileName) {
Common::File *file = new Common::File();
- if (!file->open(filename)) {
+ if (!file->open(fileName)) {
delete file;
return false;
}
- _curFile = filename;
-
- if (!open(file)) {
+ if (!openStream(file)) {
close();
return false;
}
@@ -53,431 +55,349 @@ bool MohawkArchive::open(const Common::String &filename) {
return true;
}
-void MohawkArchive::close() {
- delete _mhk; _mhk = NULL;
- delete[] _types; _types = NULL;
- delete[] _fileTable; _fileTable = NULL;
-
- _curFile.clear();
+void Archive::close() {
+ _types.clear();
+ delete _stream; _stream = 0;
}
-bool MohawkArchive::open(Common::SeekableReadStream *stream) {
- // Make sure no other file is open...
- close();
- _mhk = stream;
-
- if (_mhk->readUint32BE() != ID_MHWK) {
- warning("Could not find tag 'MHWK'");
- return false;
- }
-
- /* uint32 fileSize = */ _mhk->readUint32BE();
-
- if (_mhk->readUint32BE() != ID_RSRC) {
- warning("Could not find tag \'RSRC\'");
+bool Archive::hasResource(uint32 tag, uint16 id) const {
+ if (!_types.contains(tag))
return false;
- }
- _rsrc.version = _mhk->readUint16BE();
+ return _types[tag].contains(id);
+}
- if (_rsrc.version != 0x100) {
- warning("Unsupported Mohawk resource version %d.%d", (_rsrc.version >> 8) & 0xff, _rsrc.version & 0xff);
+bool Archive::hasResource(uint32 tag, const Common::String &resName) const {
+ if (!_types.contains(tag) || resName.empty())
return false;
- }
- _rsrc.compaction = _mhk->readUint16BE(); // Only used in creation, not in reading
- _rsrc.filesize = _mhk->readUint32BE();
- _rsrc.abs_offset = _mhk->readUint32BE();
- _rsrc.file_table_offset = _mhk->readUint16BE();
- _rsrc.file_table_size = _mhk->readUint16BE();
+ const ResourceMap &resMap = _types[tag];
- debug (3, "Absolute Offset = %08x", _rsrc.abs_offset);
+ for (ResourceMap::const_iterator it = resMap.begin(); it != resMap.end(); it++)
+ if (it->_value.name.equalsIgnoreCase(resName))
+ return true;
- /////////////////////////////////
- //Resource Dir
- /////////////////////////////////
+ return false;
+}
- // Type Table
- _mhk->seek(_rsrc.abs_offset);
- _typeTable.name_offset = _mhk->readUint16BE();
- _typeTable.resource_types = _mhk->readUint16BE();
+Common::SeekableReadStream *Archive::getResource(uint32 tag, uint16 id) {
+ if (!_types.contains(tag))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
- debug (0, "Name List Offset = %04x Number of Resource Types = %04x", _typeTable.name_offset, _typeTable.resource_types);
+ const ResourceMap &resMap = _types[tag];
- _types = new Type[_typeTable.resource_types];
+ if (!resMap.contains(id))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
- for (uint16 i = 0; i < _typeTable.resource_types; i++) {
- _types[i].tag = _mhk->readUint32BE();
- _types[i].resource_table_offset = _mhk->readUint16BE();
- _types[i].name_table_offset = _mhk->readUint16BE();
+ const Resource &res = resMap[id];
- // HACK: Zoombini's SND resource starts will a NULL.
- if (_types[i].tag == ID_SND)
- debug (3, "Type[%02d]: Tag = \'SND\' ResTable Offset = %04x NameTable Offset = %04x", i, _types[i].resource_table_offset, _types[i].name_table_offset);
- else
- debug (3, "Type[%02d]: Tag = \'%s\' ResTable Offset = %04x NameTable Offset = %04x", i, tag2str(_types[i].tag), _types[i].resource_table_offset, _types[i].name_table_offset);
+ return new Common::SeekableSubReadStream(_stream, res.offset, res.offset + res.size);
+}
- // Resource Table
- _mhk->seek(_rsrc.abs_offset + _types[i].resource_table_offset);
- _types[i].resTable.resources = _mhk->readUint16BE();
+uint32 Archive::getOffset(uint32 tag, uint16 id) const {
+ if (!_types.contains(tag))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
- debug (3, "Resources = %04x", _types[i].resTable.resources);
+ const ResourceMap &resMap = _types[tag];
- _types[i].resTable.entries = new Type::ResourceTable::Entries[_types[i].resTable.resources];
+ if (!resMap.contains(id))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
- for (uint16 j = 0; j < _types[i].resTable.resources; j++) {
- _types[i].resTable.entries[j].id = _mhk->readUint16BE();
- _types[i].resTable.entries[j].index = _mhk->readUint16BE();
+ return resMap[id].offset;
+}
- debug (4, "Entry[%02x]: ID = %04x (%d) Index = %04x", j, _types[i].resTable.entries[j].id, _types[i].resTable.entries[j].id, _types[i].resTable.entries[j].index);
- }
+uint16 Archive::findResourceID(uint32 tag, const Common::String &resName) const {
+ if (!_types.contains(tag) || resName.empty())
+ return 0xFFFF;
- // Name Table
- _mhk->seek(_rsrc.abs_offset + _types[i].name_table_offset);
- _types[i].nameTable.num = _mhk->readUint16BE();
+ const ResourceMap &resMap = _types[tag];
- debug (3, "Names = %04x", _types[i].nameTable.num);
+ for (ResourceMap::const_iterator it = resMap.begin(); it != resMap.end(); it++)
+ if (it->_value.name.equalsIgnoreCase(resName))
+ return it->_key;
- _types[i].nameTable.entries = new Type::NameTable::Entries[_types[i].nameTable.num];
+ return 0xFFFF;
+}
- for (uint16 j = 0; j < _types[i].nameTable.num; j++) {
- _types[i].nameTable.entries[j].offset = _mhk->readUint16BE();
- _types[i].nameTable.entries[j].index = _mhk->readUint16BE();
+Common::String Archive::getName(uint32 tag, uint16 id) const {
+ if (!_types.contains(tag))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
- debug (4, "Entry[%02x]: Name List Offset = %04x Index = %04x", j, _types[i].nameTable.entries[j].offset, _types[i].nameTable.entries[j].index);
+ const ResourceMap &resMap = _types[tag];
- // Name List
- uint32 pos = _mhk->pos();
- _mhk->seek(_rsrc.abs_offset + _typeTable.name_offset + _types[i].nameTable.entries[j].offset);
- char c = (char)_mhk->readByte();
- while (c != 0) {
- _types[i].nameTable.entries[j].name += c;
- c = (char)_mhk->readByte();
- }
+ if (!resMap.contains(id))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
- debug (3, "Name = \'%s\'", _types[i].nameTable.entries[j].name.c_str());
-
- // Get back to next entry
- _mhk->seek(pos);
- }
+ return resMap[id].name;
+}
- // Return to next TypeTable entry
- _mhk->seek(_rsrc.abs_offset + (i + 1) * 8 + 4);
- debug (3, "\n");
- }
+// Mohawk Archive code
- _mhk->seek(_rsrc.abs_offset + _rsrc.file_table_offset);
- _fileTableAmount = _mhk->readUint32BE();
- _fileTable = new FileTable[_fileTableAmount];
+struct FileTableEntry {
+ uint32 offset;
+ uint32 size;
+ byte flags;
+ uint16 unknown;
+};
- for (uint32 i = 0; i < _fileTableAmount; i++) {
- _fileTable[i].offset = _mhk->readUint32BE();
- _fileTable[i].dataSize = _mhk->readUint16BE();
- _fileTable[i].dataSize += _mhk->readByte() << 16; // Get bits 15-24 of dataSize too
- _fileTable[i].flags = _mhk->readByte();
- _fileTable[i].unk = _mhk->readUint16BE();
+struct NameTableEntry {
+ uint16 index;
+ Common::String name;
+};
- // Add in another 3 bits for file size from the flags.
- // The flags are useless to us except for doing this ;)
- _fileTable[i].dataSize += (_fileTable[i].flags & 7) << 24;
+bool MohawkArchive::openStream(Common::SeekableReadStream *stream) {
+ // Make sure no other file is open...
+ close();
- debug (4, "File[%02x]: Offset = %08x DataSize = %07x Flags = %02x Unk = %04x", i, _fileTable[i].offset, _fileTable[i].dataSize, _fileTable[i].flags, _fileTable[i].unk);
+ if (stream->readUint32BE() != ID_MHWK) {
+ warning("Could not find tag 'MHWK'");
+ return false;
}
- return true;
-}
-
-int MohawkArchive::getTypeIndex(uint32 tag) {
- for (uint16 i = 0; i < _typeTable.resource_types; i++)
- if (_types[i].tag == tag)
- return i;
- return -1; // not found
-}
-
-int MohawkArchive::getIDIndex(int typeIndex, uint16 id) {
- for (uint16 i = 0; i < _types[typeIndex].resTable.resources; i++)
- if (_types[typeIndex].resTable.entries[i].id == id)
- return i;
- return -1; // not found
-}
-
-int MohawkArchive::getIDIndex(int typeIndex, const Common::String &resName) {
- int index = -1;
+ /* uint32 fileSize = */ stream->readUint32BE();
- for (uint16 i = 0; i < _types[typeIndex].nameTable.num; i++)
- if (_types[typeIndex].nameTable.entries[i].name.matchString(resName)) {
- index = _types[typeIndex].nameTable.entries[i].index;
- break;
- }
-
- if (index < 0)
- return -1; // Not found
+ if (stream->readUint32BE() != ID_RSRC) {
+ warning("Could not find tag \'RSRC\'");
+ return false;
+ }
- for (uint16 i = 0; i < _types[typeIndex].resTable.resources; i++)
- if (_types[typeIndex].resTable.entries[i].index == index)
- return i;
+ uint16 version = stream->readUint16BE();
- return -1; // Not found
-}
+ if (version != 0x100) {
+ warning("Unsupported Mohawk resource version %d.%d", (version >> 8) & 0xff, version & 0xff);
+ return false;
+ }
-uint16 MohawkArchive::findResourceID(uint32 type, const Common::String &resName) {
- int typeIndex = getTypeIndex(type);
+ /* uint16 compaction = */ stream->readUint16BE(); // Only used in creation, not in reading
+ /* uint32 rsrcSize = */ stream->readUint32BE();
+ uint32 absOffset = stream->readUint32BE();
+ uint16 fileTableOffset = stream->readUint16BE();
+ /* uint16 fileTableSize = */ stream->readUint16BE();
- if (typeIndex < 0)
- return 0xFFFF;
+ // First, read in the file table
+ stream->seek(absOffset + fileTableOffset);
+ Common::Array<FileTableEntry> fileTable;
+ fileTable.resize(stream->readUint32BE());
- int idIndex = getIDIndex(typeIndex, resName);
+ debug(4, "Reading file table with %d entries", fileTable.size());
- if (idIndex < 0)
- return 0xFFFF;
+ for (uint32 i = 0; i < fileTable.size(); i++) {
+ fileTable[i].offset = stream->readUint32BE();
+ fileTable[i].size = stream->readUint16BE();
+ fileTable[i].size += stream->readByte() << 16; // Get bits 15-24 of size too
+ fileTable[i].flags = stream->readByte();
+ fileTable[i].unknown = stream->readUint16BE();
- return _types[typeIndex].resTable.entries[idIndex].id;
-}
-
-bool MohawkArchive::hasResource(uint32 tag, uint16 id) {
- if (!_mhk)
- return false;
+ // Add in another 3 bits for file size from the flags.
+ // The flags are useless to us except for doing this ;)
+ fileTable[i].size += (fileTable[i].flags & 7) << 24;
- int16 typeIndex = getTypeIndex(tag);
+ debug(4, "File[%02x]: Offset = %08x Size = %07x Flags = %02x Unknown = %04x", i, fileTable[i].offset, fileTable[i].size, fileTable[i].flags, fileTable[i].unknown);
+ }
- if (typeIndex < 0)
- return false;
+ // Now go in an read in each of the types
+ stream->seek(absOffset);
+ uint16 stringTableOffset = stream->readUint16BE();
+ uint16 typeCount = stream->readUint16BE();
- return getIDIndex(typeIndex, id) >= 0;
-}
+ debug(0, "Name List Offset = %04x Number of Resource Types = %04x", stringTableOffset, typeCount);
-bool MohawkArchive::hasResource(uint32 tag, const Common::String &resName) {
- if (!_mhk)
- return false;
+ for (uint16 i = 0; i < typeCount; i++) {
+ uint32 tag = stream->readUint32BE();
+ uint16 resourceTableOffset = stream->readUint16BE();
+ uint16 nameTableOffset = stream->readUint16BE();
- int16 typeIndex = getTypeIndex(tag);
+ // HACK: Zoombini's SND resource starts will a NULL.
+ if (tag == ID_SND)
+ debug(3, "Type[%02d]: Tag = \'SND\' ResTable Offset = %04x NameTable Offset = %04x", i, resourceTableOffset, nameTableOffset);
+ else
+ debug(3, "Type[%02d]: Tag = \'%s\' ResTable Offset = %04x NameTable Offset = %04x", i, tag2str(tag), resourceTableOffset, nameTableOffset);
- if (typeIndex < 0)
- return false;
+ // Name Table
+ stream->seek(absOffset + nameTableOffset);
+ Common::Array<NameTableEntry> nameTable;
+ nameTable.resize(stream->readUint16BE());
- return getIDIndex(typeIndex, resName) >= 0;
-}
+ debug(3, "Names = %04x", nameTable.size());
-Common::String MohawkArchive::getName(uint32 tag, uint16 id) {
- if (!_mhk)
- return 0;
+ for (uint16 j = 0; j < nameTable.size(); j++) {
+ uint16 offset = stream->readUint16BE();
+ nameTable[j].index = stream->readUint16BE();
- int16 typeIndex = getTypeIndex(tag);
+ debug(4, "Entry[%02x]: Name List Offset = %04x Index = %04x", j, offset, nameTable[j].index);
- if (typeIndex < 0)
- return 0;
+ // Name List
+ uint32 pos = stream->pos();
+ stream->seek(absOffset + stringTableOffset + offset);
+ char c = (char)stream->readByte();
+ while (c != 0) {
+ nameTable[j].name += c;
+ c = (char)stream->readByte();
+ }
- int16 idIndex = -1;
+ debug(3, "Name = \'%s\'", nameTable[j].name.c_str());
- for (uint16 i = 0; i < _types[typeIndex].resTable.resources; i++)
- if (_types[typeIndex].resTable.entries[i].id == id) {
- idIndex = _types[typeIndex].resTable.entries[i].index;
- break;
+ // Get back to next entry
+ stream->seek(pos);
}
- assert(idIndex >= 0);
-
- for (uint16 i = 0; i < _types[typeIndex].nameTable.num; i++)
- if (_types[typeIndex].nameTable.entries[i].index == idIndex)
- return _types[typeIndex].nameTable.entries[i].name;
-
- return 0; // not found
-}
-
-uint32 MohawkArchive::getOffset(uint32 tag, uint16 id) {
- assert(_mhk);
+ // Resource Table
+ stream->seek(absOffset + resourceTableOffset);
+ uint16 resourceCount = stream->readUint16BE();
- int16 typeIndex = getTypeIndex(tag);
- assert(typeIndex >= 0);
+ debug(3, "Resource count = %04x", resourceCount);
- int16 idIndex = getIDIndex(typeIndex, id);
- assert(idIndex >= 0);
+ ResourceMap &resMap = _types[tag];
- return _fileTable[_types[typeIndex].resTable.entries[idIndex].index - 1].offset;
-}
+ for (uint16 j = 0; j < resourceCount; j++) {
+ uint16 id = stream->readUint16BE();
+ uint16 index = stream->readUint16BE();
-Common::SeekableReadStream *MohawkArchive::getResource(uint32 tag, uint16 id) {
- if (!_mhk)
- error("MohawkArchive::getResource(): No File in Use");
+ Resource &res = resMap[id];
- int16 typeIndex = getTypeIndex(tag);
-
- if (typeIndex < 0)
- error("Could not find a tag of '%s' in file '%s'", tag2str(tag), _curFile.c_str());
+ // Pull out the name from the name table
+ for (uint32 k = 0; k < nameTable.size(); k++) {
+ if (nameTable[k].index == index) {
+ res.name = nameTable[k].name;
+ break;
+ }
+ }
- int16 idIndex = getIDIndex(typeIndex, id);
+ // Pull out our offset/size too
+ res.offset = fileTable[index - 1].offset;
+
+ // WORKAROUND: tMOV resources pretty much ignore the size part of the file table,
+ // as the original just passed the full Mohawk file to QuickTime and the offset.
+ // We need to do this because of the way Mohawk is set up (this is much more "proper"
+ // than passing _stream at the right offset). We may want to do that in the future, though.
+ if (tag == ID_TMOV) {
+ if (index == fileTable.size() - 1)
+ res.size = stream->size() - fileTable[index - 1].offset;
+ else
+ res.size = fileTable[index].offset - fileTable[index - 1].offset;
+ } else
+ res.size = fileTable[index - 1].size;
+
+ debug(4, "Entry[%02x]: ID = %04x (%d) Index = %04x", j, id, id, index);
+ }
- if (idIndex < 0)
- error("Could not find '%s' %04x in file '%s'", tag2str(tag), id, _curFile.c_str());
- // Note: the fileTableIndex is based off 1, not 0. So, subtract 1
- uint16 fileTableIndex = _types[typeIndex].resTable.entries[idIndex].index - 1;
+ // Return to next TypeTable entry
+ stream->seek(absOffset + (i + 1) * 8 + 4);
- // WORKAROUND: tMOV resources pretty much ignore the size part of the file table,
- // as the original just passed the full Mohawk file to QuickTime and the offset.
- // We need to do this because of the way Mohawk is set up (this is much more "proper"
- // than passing _mhk at the right offset). We may want to do that in the future, though.
- if (_types[typeIndex].tag == ID_TMOV) {
- if (fileTableIndex == _fileTableAmount - 1)
- return new Common::SeekableSubReadStream(_mhk, _fileTable[fileTableIndex].offset, _mhk->size());
- else
- return new Common::SeekableSubReadStream(_mhk, _fileTable[fileTableIndex].offset, _fileTable[fileTableIndex + 1].offset);
+ debug(3, "\n");
}
- return new Common::SeekableSubReadStream(_mhk, _fileTable[fileTableIndex].offset, _fileTable[fileTableIndex].offset + _fileTable[fileTableIndex].dataSize);
+ _stream = stream;
+ return true;
}
-bool LivingBooksArchive_v1::open(Common::SeekableReadStream *stream) {
+// Living Books Archive code
+
+bool LivingBooksArchive_v1::openStream(Common::SeekableReadStream *stream) {
close();
- _mhk = stream;
// This is for the "old" Mohawk resource format used in some older
// Living Books. It is very similar, just missing the MHWK tag and
// some other minor differences, especially with the file table
// being merged into the resource table.
- uint32 headerSize = _mhk->readUint32BE();
+ uint32 headerSize = stream->readUint32BE();
// NOTE: There are differences besides endianness! (Subtle changes,
// but different).
if (headerSize == 6) { // We're in Big Endian mode (Macintosh)
- _mhk->readUint16BE(); // Resource Table Size
- _typeTable.resource_types = _mhk->readUint16BE();
- _types = new OldType[_typeTable.resource_types];
+ stream->readUint16BE(); // Resource Table Size
+ uint16 typeCount = stream->readUint16BE();
- debug (0, "Old Mohawk File (Macintosh): Number of Resource Types = %04x", _typeTable.resource_types);
+ debug(0, "Old Mohawk File (Macintosh): Number of Resource Types = %04x", typeCount);
- for (uint16 i = 0; i < _typeTable.resource_types; i++) {
- _types[i].tag = _mhk->readUint32BE();
- _types[i].resource_table_offset = (uint16)_mhk->readUint32BE() + 6;
- _mhk->readUint32BE(); // Unknown (always 0?)
+ for (uint16 i = 0; i < typeCount; i++) {
+ uint32 tag = stream->readUint32BE();
+ uint32 resourceTableOffset = stream->readUint32BE() + 6;
+ stream->readUint32BE(); // Unknown (always 0?)
- debug (3, "Type[%02d]: Tag = \'%s\' ResTable Offset = %04x", i, tag2str(_types[i].tag), _types[i].resource_table_offset);
+ debug(3, "Type[%02d]: Tag = \'%s\' ResTable Offset = %04x", i, tag2str(tag), resourceTableOffset);
- uint32 oldPos = _mhk->pos();
+ uint32 oldPos = stream->pos();
// Resource Table/File Table
- _mhk->seek(_types[i].resource_table_offset);
- _types[i].resTable.resources = _mhk->readUint16BE();
- _types[i].resTable.entries = new OldType::ResourceTable::Entries[_types[i].resTable.resources];
-
- for (uint16 j = 0; j < _types[i].resTable.resources; j++) {
- _types[i].resTable.entries[j].id = _mhk->readUint16BE();
- _types[i].resTable.entries[j].offset = _mhk->readUint32BE();
- _types[i].resTable.entries[j].size = _mhk->readByte() << 16;
- _types[i].resTable.entries[j].size += _mhk->readUint16BE();
- _mhk->skip(5); // Unknown (always 0?)
-
- debug (4, "Entry[%02x]: ID = %04x (%d)\tOffset = %08x, Size = %08x", j, _types[i].resTable.entries[j].id, _types[i].resTable.entries[j].id, _types[i].resTable.entries[j].offset, _types[i].resTable.entries[j].size);
- }
-
- _mhk->seek(oldPos);
- debug (3, "\n");
- }
- } else if (SWAP_BYTES_32(headerSize) == 6) { // We're in Little Endian mode (Windows)
- _mhk->readUint16LE(); // Resource Table Size
- _typeTable.resource_types = _mhk->readUint16LE();
- _types = new OldType[_typeTable.resource_types];
+ stream->seek(resourceTableOffset);
+ uint16 resourceCount = stream->readUint16BE();
- debug (0, "Old Mohawk File (Windows): Number of Resource Types = %04x", _typeTable.resource_types);
+ ResourceMap &resMap = _types[tag];
- for (uint16 i = 0; i < _typeTable.resource_types; i++) {
- _types[i].tag = _mhk->readUint32LE();
- _types[i].resource_table_offset = _mhk->readUint16LE() + 6;
- _mhk->readUint16LE(); // Unknown (always 0?)
+ for (uint16 j = 0; j < resourceCount; j++) {
+ uint16 id = stream->readUint16BE();
- debug (3, "Type[%02d]: Tag = \'%s\' ResTable Offset = %04x", i, tag2str(_types[i].tag), _types[i].resource_table_offset);
+ Resource &res = resMap[id];
- uint32 oldPos = _mhk->pos();
+ res.offset = stream->readUint32BE();
+ res.size = stream->readByte() << 16;
+ res.size |= stream->readUint16BE();
+ stream->skip(5); // Unknown (always 0?)
- // Resource Table/File Table
- _mhk->seek(_types[i].resource_table_offset);
- _types[i].resTable.resources = _mhk->readUint16LE();
- _types[i].resTable.entries = new OldType::ResourceTable::Entries[_types[i].resTable.resources];
-
- for (uint16 j = 0; j < _types[i].resTable.resources; j++) {
- _types[i].resTable.entries[j].id = _mhk->readUint16LE();
- _types[i].resTable.entries[j].offset = _mhk->readUint32LE();
- _types[i].resTable.entries[j].size = _mhk->readUint32LE();
- _mhk->readUint16LE(); // Unknown (always 0?)
-
- debug (4, "Entry[%02x]: ID = %04x (%d)\tOffset = %08x, Size = %08x", j, _types[i].resTable.entries[j].id, _types[i].resTable.entries[j].id, _types[i].resTable.entries[j].offset, _types[i].resTable.entries[j].size);
+ debug(4, "Entry[%02x]: ID = %04x (%d)\tOffset = %08x, Size = %08x", j, id, id, res.offset, res.size);
}
- _mhk->seek(oldPos);
- debug (3, "\n");
+ stream->seek(oldPos);
+ debug(3, "\n");
}
- } else {
- warning("Could not determine type of Old Mohawk resource");
- return false;
- }
-
- return true;
-}
-
-uint32 LivingBooksArchive_v1::getOffset(uint32 tag, uint16 id) {
- assert(_mhk);
-
- int16 typeIndex = getTypeIndex(tag);
- assert(typeIndex >= 0);
+ } else if (SWAP_BYTES_32(headerSize) == 6) { // We're in Little Endian mode (Windows)
+ stream->readUint16LE(); // Resource Table Size
+ uint16 typeCount = stream->readUint16LE();
- int16 idIndex = getIDIndex(typeIndex, id);
- assert(idIndex >= 0);
+ debug(0, "Old Mohawk File (Windows): Number of Resource Types = %04x", typeCount);
- return _types[typeIndex].resTable.entries[idIndex].offset;
-}
+ for (uint16 i = 0; i < typeCount; i++) {
+ uint32 tag = stream->readUint32LE();
+ uint16 resourceTableOffset = stream->readUint16LE() + 6;
+ stream->readUint16LE(); // Unknown (always 0?)
-Common::SeekableReadStream *LivingBooksArchive_v1::getResource(uint32 tag, uint16 id) {
- if (!_mhk)
- error("LivingBooksArchive_v1::getResource(): No File in Use");
+ debug(3, "Type[%02d]: Tag = \'%s\' ResTable Offset = %04x", i, tag2str(tag), resourceTableOffset);
- int16 typeIndex = getTypeIndex(tag);
+ uint32 oldPos = stream->pos();
- if (typeIndex < 0)
- error("Could not find a tag of \'%s\' in file \'%s\'", tag2str(tag), _curFile.c_str());
+ // Resource Table/File Table
+ stream->seek(resourceTableOffset);
+ uint16 resourceCount = stream->readUint16LE();
- int16 idIndex = getIDIndex(typeIndex, id);
+ ResourceMap &resMap = _types[tag];
- if (idIndex < 0)
- error("Could not find \'%s\' %04x in file \'%s\'", tag2str(tag), id, _curFile.c_str());
+ for (uint16 j = 0; j < resourceCount; j++) {
+ uint16 id = stream->readUint16LE();
- return new Common::SeekableSubReadStream(_mhk, _types[typeIndex].resTable.entries[idIndex].offset, _types[typeIndex].resTable.entries[idIndex].offset + _types[typeIndex].resTable.entries[idIndex].size);
-}
+ Resource &res = resMap[id];
-bool LivingBooksArchive_v1::hasResource(uint32 tag, uint16 id) {
- if (!_mhk)
- return false;
+ res.offset = stream->readUint32LE();
+ res.size = stream->readUint32LE();
+ stream->readUint16LE(); // Unknown (always 0?)
- int16 typeIndex = getTypeIndex(tag);
+ debug(4, "Entry[%02x]: ID = %04x (%d)\tOffset = %08x, Size = %08x", j, id, id, res.offset, res.size);
+ }
- if (typeIndex < 0)
+ stream->seek(oldPos);
+ debug(3, "\n");
+ }
+ } else {
+ // Not a valid Living Books Archive
return false;
+ }
- return getIDIndex(typeIndex, id) >= 0;
+ _stream = stream;
+ return true;
}
-int LivingBooksArchive_v1::getTypeIndex(uint32 tag) {
- for (uint16 i = 0; i < _typeTable.resource_types; i++)
- if (_types[i].tag == tag)
- return i;
- return -1; // not found
-}
-
-int LivingBooksArchive_v1::getIDIndex(int typeIndex, uint16 id) {
- for (uint16 i = 0; i < _types[typeIndex].resTable.resources; i++)
- if (_types[typeIndex].resTable.entries[i].id == id)
- return i;
- return -1; // not found
-}
+// DOS Archive (v2) code
// Partially based on the Prince of Persia Format Specifications
// See http://sdfg.com.ar/git/?p=fp-git.git;a=blob;f=FP/doc/FormatSpecifications
// However, I'm keeping with the terminology we've been using with the
// later archive formats.
-bool DOSArchive_v2::open(Common::SeekableReadStream *stream) {
+bool DOSArchive_v2::openStream(Common::SeekableReadStream *stream) {
close();
uint32 typeTableOffset = stream->readUint32LE();
@@ -488,36 +408,38 @@ bool DOSArchive_v2::open(Common::SeekableReadStream *stream) {
stream->seek(typeTableOffset);
- _typeTable.resource_types = stream->readUint16LE();
- _types = new OldType[_typeTable.resource_types];
+ uint16 typeCount = stream->readUint16LE();
- for (uint16 i = 0; i < _typeTable.resource_types; i++) {
- _types[i].tag = stream->readUint32LE();
- _types[i].resource_table_offset = stream->readUint16LE();
+ for (uint16 i = 0; i < typeCount; i++) {
+ uint32 tag = stream->readUint32LE();
+ uint16 resourceTableOffset = stream->readUint16LE();
- debug(3, "Type[%02d]: Tag = \'%s\' ResTable Offset = %04x", i, tag2str(_types[i].tag), _types[i].resource_table_offset);
+ debug(3, "Type[%02d]: Tag = \'%s\' ResTable Offset = %04x", i, tag2str(tag), resourceTableOffset);
uint32 oldPos = stream->pos();
// Resource Table/File Table
- stream->seek(_types[i].resource_table_offset + typeTableOffset);
- _types[i].resTable.resources = stream->readUint16LE();
- _types[i].resTable.entries = new OldType::ResourceTable::Entries[_types[i].resTable.resources];
+ stream->seek(resourceTableOffset + typeTableOffset);
+ uint16 resourceCount = stream->readUint16LE();
+
+ ResourceMap &resMap = _types[tag];
+
+ for (uint16 j = 0; j < resourceCount; j++) {
+ uint16 id = stream->readUint16LE();
- for (uint16 j = 0; j < _types[i].resTable.resources; j++) {
- _types[i].resTable.entries[j].id = stream->readUint16LE();
- _types[i].resTable.entries[j].offset = stream->readUint32LE() + 1; // Need to add one to the offset to skip the checksum byte
- _types[i].resTable.entries[j].size = stream->readUint16LE();
- stream->skip(3); // Skip the useless flags
+ Resource &res = resMap[id];
+ res.offset = stream->readUint32LE() + 1; // Need to add one to the offset to skip the checksum byte
+ res.size = stream->readUint16LE();
+ stream->skip(3); // Skip (useless) flags
- debug (4, "Entry[%02x]: ID = %04x (%d)\tOffset = %08x, Size = %08x", j, _types[i].resTable.entries[j].id, _types[i].resTable.entries[j].id, _types[i].resTable.entries[j].offset, _types[i].resTable.entries[j].size);
+ debug(4, "Entry[%02x]: ID = %04x (%d)\tOffset = %08x, Size = %08x", j, id, id, res.offset, res.size);
}
stream->seek(oldPos);
- debug (3, "\n");
+ debug(3, "\n");
}
- _mhk = stream;
+ _stream = stream;
return true;
}
diff --git a/engines/mohawk/resource.h b/engines/mohawk/resource.h
index cabce04e38..d4e91e0ec4 100644
--- a/engines/mohawk/resource.h
+++ b/engines/mohawk/resource.h
@@ -22,6 +22,7 @@
#include "common/scummsys.h"
#include "common/endian.h"
+#include "common/hashmap.h"
#include "common/file.h"
#include "common/str.h"
@@ -128,127 +129,61 @@ namespace Mohawk {
#define ID_BBOX MKTAG('B','B','O','X') // Boxes? (CSWorld, CSAmtrak)
#define ID_SYSX MKTAG('S','Y','S','X') // MIDI Sysex
-struct FileTable {
- uint32 offset;
- uint32 dataSize; // Really 27 bits
- byte flags; // Mostly useless except for the bottom 3 bits which are part of the size
- uint16 unk; // Always 0
-};
-
-struct Type {
- Type() { resTable.entries = NULL; nameTable.entries = NULL; }
- ~Type() { delete[] resTable.entries; delete[] nameTable.entries; }
-
- //Type Table
- uint32 tag;
- uint16 resource_table_offset;
- uint16 name_table_offset;
-
- struct ResourceTable {
- uint16 resources;
- struct Entries {
- uint16 id;
- uint16 index;
- } *entries;
- } resTable;
-
- struct NameTable {
- uint16 num;
- struct Entries {
- uint16 offset;
- uint16 index;
- // Name List
- Common::String name;
- } *entries;
- } nameTable;
-};
-
-struct TypeTable {
- uint16 name_offset;
- uint16 resource_types;
-};
-struct RSRC_Header {
- uint16 version;
- uint16 compaction;
- uint32 filesize;
- uint32 abs_offset;
- uint16 file_table_offset;
- uint16 file_table_size;
-};
-
-class MohawkArchive {
+class Archive {
public:
- MohawkArchive();
- virtual ~MohawkArchive() { close(); }
+ Archive();
+ virtual ~Archive();
- bool open(const Common::String &filename);
- virtual bool open(Common::SeekableReadStream *stream);
+ bool openFile(const Common::String &fileName);
+ virtual bool openStream(Common::SeekableReadStream *stream) = 0;
void close();
- virtual bool hasResource(uint32 tag, uint16 id);
- virtual bool hasResource(uint32 tag, const Common::String &resName);
- virtual Common::SeekableReadStream *getResource(uint32 tag, uint16 id);
- virtual uint32 getOffset(uint32 tag, uint16 id);
- virtual uint16 findResourceID(uint32 type, const Common::String &resName);
- Common::String getName(uint32 tag, uint16 id);
+ bool isOpen() const { return _stream != 0; }
+
+ bool hasResource(uint32 tag, uint16 id) const;
+ bool hasResource(uint32 tag, const Common::String &resName) const;
+ Common::SeekableReadStream *getResource(uint32 tag, uint16 id);
+ uint32 getOffset(uint32 tag, uint16 id) const;
+ uint16 findResourceID(uint32 tag, const Common::String &resName) const;
+ Common::String getName(uint32 tag, uint16 id) const;
protected:
- Common::SeekableReadStream *_mhk;
- TypeTable _typeTable;
- Common::String _curFile;
-
-private:
- RSRC_Header _rsrc;
- Type *_types;
- FileTable *_fileTable;
- uint16 _nameTableAmount;
- uint16 _resourceTableAmount;
- uint16 _fileTableAmount;
-
- int getTypeIndex(uint32 tag);
- int getIDIndex(int typeIndex, uint16 id);
- int getIDIndex(int typeIndex, const Common::String &resName);
+ Common::SeekableReadStream *_stream;
+
+ struct Resource {
+ uint32 offset;
+ uint32 size;
+ Common::String name;
+ };
+
+ typedef Common::HashMap<uint16, Resource> ResourceMap;
+ typedef Common::HashMap<uint32, ResourceMap> TypeMap;
+ TypeMap _types;
};
-class LivingBooksArchive_v1 : public MohawkArchive {
+class MohawkArchive : public Archive {
public:
- LivingBooksArchive_v1() : MohawkArchive() {}
- ~LivingBooksArchive_v1() {}
+ MohawkArchive() : Archive() {}
+ ~MohawkArchive() {}
- bool hasResource(uint32 tag, uint16 id);
- bool hasResource(uint32 tag, const Common::String &resName) { return false; }
- virtual bool open(Common::SeekableReadStream *stream);
- Common::SeekableReadStream *getResource(uint32 tag, uint16 id);
- Common::SeekableReadStream *getResource(uint32 tag, const Common::String &resName) { return 0; }
- uint32 getOffset(uint32 tag, uint16 id);
- uint16 findResourceID(uint32 type, const Common::String &resName) { return 0xFFFF; }
+ bool openStream(Common::SeekableReadStream *stream);
+};
-protected:
- struct OldType {
- uint32 tag;
- uint16 resource_table_offset;
- struct ResourceTable {
- uint16 resources;
- struct Entries {
- uint16 id;
- uint32 offset;
- uint32 size;
- } *entries;
- } resTable;
- } *_types;
-
-private:
- int getTypeIndex(uint32 tag);
- int getIDIndex(int typeIndex, uint16 id);
+class LivingBooksArchive_v1 : public Archive {
+public:
+ LivingBooksArchive_v1() : Archive() {}
+ ~LivingBooksArchive_v1() {}
+
+ bool openStream(Common::SeekableReadStream *stream);
};
-class DOSArchive_v2 : public LivingBooksArchive_v1 {
+class DOSArchive_v2 : public Archive {
public:
- DOSArchive_v2() : LivingBooksArchive_v1() {}
+ DOSArchive_v2() : Archive() {}
~DOSArchive_v2() {}
- virtual bool open(Common::SeekableReadStream *stream);
+ bool openStream(Common::SeekableReadStream *stream);
};
} // End of namespace Mohawk
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp
index 8f8bc15990..612b8b3685 100644
--- a/engines/mohawk/riven.cpp
+++ b/engines/mohawk/riven.cpp
@@ -143,7 +143,7 @@ Common::Error MohawkEngine_Riven::run() {
_extrasFile = new MohawkArchive();
// We need extras.mhk for inventory images, marble images, and credits images
- if (!_extrasFile->open("extras.mhk")) {
+ if (!_extrasFile->openFile("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());
@@ -317,7 +317,7 @@ void MohawkEngine_Riven::changeToStack(uint16 n) {
Common::String filename = Common::String(prefix) + endings[i];
MohawkArchive *mhk = new MohawkArchive();
- if (mhk->open(filename))
+ if (mhk->openFile(filename))
_mhk.push_back(mhk);
else
delete mhk;
diff --git a/engines/mohawk/riven_saveload.cpp b/engines/mohawk/riven_saveload.cpp
index 35d82d4aa0..f1ce2447a5 100644
--- a/engines/mohawk/riven_saveload.cpp
+++ b/engines/mohawk/riven_saveload.cpp
@@ -100,7 +100,7 @@ bool RivenSaveLoad::loadGame(Common::String filename) {
MohawkArchive *mhk = new MohawkArchive();
- if (!mhk->open(loadFile)) {
+ if (!mhk->openStream(loadFile)) {
warning("Save file is not a Mohawk archive");
delete mhk;
return false;