diff options
author | Matthew Hoops | 2012-11-13 21:18:56 -0500 |
---|---|---|
committer | Eugene Sandulenko | 2016-08-03 23:40:36 +0200 |
commit | 8c252aa830296fa138a892baf6fee121807c0797 (patch) | |
tree | 85ad88463530ac7426826d82df4e5098bc392f74 | |
parent | a243b5cb33b36b6cc0f3e92b76dad5714a87942e (diff) | |
download | scummvm-rg350-8c252aa830296fa138a892baf6fee121807c0797.tar.gz scummvm-rg350-8c252aa830296fa138a892baf6fee121807c0797.tar.bz2 scummvm-rg350-8c252aa830296fa138a892baf6fee121807c0797.zip |
DIRECTOR: Add basic resource code
-rw-r--r-- | engines/director/module.mk | 3 | ||||
-rw-r--r-- | engines/director/resource.cpp | 307 | ||||
-rw-r--r-- | engines/director/resource.h | 107 |
3 files changed, 416 insertions, 1 deletions
diff --git a/engines/director/module.mk b/engines/director/module.mk index 122ff6c7d8..ef47485578 100644 --- a/engines/director/module.mk +++ b/engines/director/module.mk @@ -2,7 +2,8 @@ MODULE := engines/director MODULE_OBJS = \ detection.o \ - director.o + director.o \ + resource.o # This module can be built as a plugin ifeq ($(ENABLE_DIRECTOR), DYNAMIC_PLUGIN) diff --git a/engines/director/resource.cpp b/engines/director/resource.cpp new file mode 100644 index 0000000000..da664a4f0e --- /dev/null +++ b/engines/director/resource.cpp @@ -0,0 +1,307 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "director/resource.h" + +#include "common/debug.h" +#include "common/macresman.h" +#include "common/substream.h" +#include "common/util.h" +#include "common/textconsole.h" + +namespace Director { + +// Base Archive code + +Archive::Archive() { + _stream = 0; +} + +Archive::~Archive() { + close(); +} + +bool Archive::openFile(const Common::String &fileName) { + Common::File *file = new Common::File(); + + if (!file->open(fileName)) { + delete file; + return false; + } + + if (!openStream(file)) { + close(); + return false; + } + + return true; +} + +void Archive::close() { + _types.clear(); + 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::SeekableReadStream *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::SeekableSubReadStream(_stream, res.offset, res.offset + res.size); +} + +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; +} + +Common::String Archive::getName(uint32 tag, uint16 id) const { + if (!_types.contains(tag)) + error("Archive does not contain '%s' %04x", tag2str(tag), id); + + const ResourceMap &resMap = _types[tag]; + + if (!resMap.contains(id)) + error("Archive does not contain '%s' %04x", tag2str(tag), id); + + return resMap[id].name; +} + +Common::Array<uint32> Archive::getResourceTypeList() const { + Common::Array<uint32> typeList; + + for (TypeMap::const_iterator it = _types.begin(); it != _types.end(); it++) + typeList.push_back(it->_key); + + return typeList; +} + +Common::Array<uint16> Archive::getResourceIDList(uint32 type) const { + Common::Array<uint16> idList; + + if (!_types.contains(type)) + return idList; + + const ResourceMap &resMap = _types[type]; + + for (ResourceMap::const_iterator it = resMap.begin(); it != resMap.end(); it++) + idList.push_back(it->_key); + + return idList; +} + +// Mac Archive code + +MacArchive::MacArchive() : Archive(), _resFork(0) { +} + +MacArchive::~MacArchive() { + delete _resFork; +} + +void MacArchive::close() { + Archive::close(); + delete _resFork; + _resFork = 0; +} + +bool MacArchive::openFile(const Common::String &fileName) { + close(); + + _resFork = new Common::MacResManager(); + + if (!_resFork->open(fileName) || !_resFork->hasResFork()) { + close(); + return false; + } + + 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]); + } + } + + + return true; +} + +bool MacArchive::openStream(Common::SeekableReadStream *stream) { + // TODO: Add support for this (v4 Windows games) + return false; +} + +Common::SeekableReadStream *MacArchive::getResource(uint32 tag, uint16 id) { + assert(_resFork); + return _resFork->getResource(tag, id); +} + +// RIFF Archive code + +bool RIFFArchive::openStream(Common::SeekableReadStream *stream) { + close(); + + if (stream->readUint32BE() != MKTAG('R', 'I', 'F', 'F')) + return false; + + stream->readUint32LE(); // size + + if (stream->readUint32BE() != MKTAG('R', 'M', 'M', 'P')) + return false; + + if (stream->readUint32BE() != MKTAG('C', 'F', 'T', 'C')) + return false; + + uint32 cftcSize = stream->readUint32LE(); + uint32 startPos = stream->pos(); + + while ((uint32)stream->pos() < startPos + cftcSize) { + uint32 offset = stream->readUint32LE(); + uint32 tag = stream->readUint32BE(); + uint32 size = stream->readUint32LE(); + uint32 id = stream->readUint32LE(); + + if (tag == 0) + break; + + ResourceMap &resMap = _types[tag]; + Resource &res = resMap[id]; + res.offset = offset; + res.size = size; + } + + _stream = stream; + return true; +} + + +// RIFX Archive code + +bool RIFXArchive::openStream(Common::SeekableReadStream *stream) { + close(); + + uint32 tag = stream->readUint32BE(); + bool isBigEndian; + + if (tag == MKTAG('R', 'I', 'F', 'X')) + isBigEndian = true; + else if (SWAP_BYTES_32(tag) == MKTAG('R', 'I', 'F', 'X')) + isBigEndian = false; + else + return false; + + Common::SeekableSubReadStreamEndian subStream(stream, 4, stream->size(), isBigEndian, DisposeAfterUse::NO); + + subStream.readUint32(); // size + + if (subStream.readUint32() != MKTAG('M', 'V', '9', '3')) + return false; + + if (subStream.readUint32() != MKTAG('i', 'm', 'a', 'p')) + return false; + + subStream.readUint32(); // imap length + subStream.readUint32(); // unknown + uint32 mmapOffset = subStream.readUint32() - 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 + + for (uint32 i = 0; i < resCount; i++) { + tag = subStream.readUint32(); + uint32 size = subStream.readUint32(); + uint32 offset = subStream.readUint32(); + subStream.skip(8); // always 0? + + ResourceMap &resMap = _types[tag]; + Resource &res = resMap[i]; // FIXME: What is the ID? Is this setup even viable? + res.offset = offset; + res.size = size; + } + + _stream = stream; + return true; +} + +} // End of namespace Director diff --git a/engines/director/resource.h b/engines/director/resource.h new file mode 100644 index 0000000000..f757c9c0ee --- /dev/null +++ b/engines/director/resource.h @@ -0,0 +1,107 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" +#include "common/endian.h" +#include "common/hashmap.h" +#include "common/file.h" +#include "common/str.h" + +#ifndef DIRECTOR_RESOURCE_H +#define DIRECTOR_RESOURCE_H + +namespace Common { +class MacResManager; +} + +namespace Director { + +// Completely ripped off of Mohawk's Archive code + +class Archive { +public: + Archive(); + virtual ~Archive(); + + virtual bool openFile(const Common::String &fileName); + virtual bool openStream(Common::SeekableReadStream *stream) = 0; + virtual void close(); + + bool isOpen() const { return _stream != 0; } + + bool hasResource(uint32 tag, uint16 id) const; + bool hasResource(uint32 tag, const Common::String &resName) const; + virtual 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; + + Common::Array<uint32> getResourceTypeList() const; + Common::Array<uint16> getResourceIDList(uint32 type) const; + +protected: + 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 MacArchive : public Archive { +public: + MacArchive(); + ~MacArchive(); + + void close(); + bool openFile(const Common::String &fileName); + bool openStream(Common::SeekableReadStream *stream); + Common::SeekableReadStream *getResource(uint32 tag, uint16 id); + +private: + Common::MacResManager *_resFork; +}; + +class RIFFArchive : public Archive { +public: + RIFFArchive() : Archive() {} + ~RIFFArchive() {} + + bool openStream(Common::SeekableReadStream *stream); +}; + +class RIFXArchive : public Archive { +public: + RIFXArchive() : Archive() {} + ~RIFXArchive() {} + + bool openStream(Common::SeekableReadStream *stream); +}; + +} // End of namespace Director + +#endif |