diff options
author | Matthew Hoops | 2011-06-28 11:58:52 -0400 |
---|---|---|
committer | Matthew Hoops | 2011-06-28 12:10:28 -0400 |
commit | 71c4329d86566aa6281a4790b08fe8e77d057f10 (patch) | |
tree | ffca295074195c60c04984a623b5e641b4e044db /engines/mohawk | |
parent | ede71596ba43c777d13201757c974aa22fd0e8ec (diff) | |
download | scummvm-rg350-71c4329d86566aa6281a4790b08fe8e77d057f10.tar.gz scummvm-rg350-71c4329d86566aa6281a4790b08fe8e77d057f10.tar.bz2 scummvm-rg350-71c4329d86566aa6281a4790b08fe8e77d057f10.zip |
MOHAWK: Rework archive handling
A new base class has been introduced (aptly named "Archive"), which is much cleaner than inheriting from MohawkArchive. In addition, the underlying resource retrieving code has been merged to reduce dupliplication.
Diffstat (limited to 'engines/mohawk')
-rw-r--r-- | engines/mohawk/cstime.cpp | 2 | ||||
-rw-r--r-- | engines/mohawk/cursors.cpp | 2 | ||||
-rw-r--r-- | engines/mohawk/livingbooks.cpp | 21 | ||||
-rw-r--r-- | engines/mohawk/livingbooks.h | 10 | ||||
-rw-r--r-- | engines/mohawk/mohawk.h | 4 | ||||
-rw-r--r-- | engines/mohawk/myst.cpp | 4 | ||||
-rw-r--r-- | engines/mohawk/resource.cpp | 592 | ||||
-rw-r--r-- | engines/mohawk/resource.h | 143 | ||||
-rw-r--r-- | engines/mohawk/riven.cpp | 4 | ||||
-rw-r--r-- | engines/mohawk/riven_saveload.cpp | 2 |
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 §ion, 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; |