aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Hoops2012-11-13 21:18:56 -0500
committerEugene Sandulenko2016-08-03 23:40:36 +0200
commit8c252aa830296fa138a892baf6fee121807c0797 (patch)
tree85ad88463530ac7426826d82df4e5098bc392f74
parenta243b5cb33b36b6cc0f3e92b76dad5714a87942e (diff)
downloadscummvm-rg350-8c252aa830296fa138a892baf6fee121807c0797.tar.gz
scummvm-rg350-8c252aa830296fa138a892baf6fee121807c0797.tar.bz2
scummvm-rg350-8c252aa830296fa138a892baf6fee121807c0797.zip
DIRECTOR: Add basic resource code
-rw-r--r--engines/director/module.mk3
-rw-r--r--engines/director/resource.cpp307
-rw-r--r--engines/director/resource.h107
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