aboutsummaryrefslogtreecommitdiff
path: root/engines/zvision/file
diff options
context:
space:
mode:
authorFilippos Karapetis2014-12-16 01:14:37 +0200
committerFilippos Karapetis2014-12-16 01:58:56 +0200
commitd8a961244d99a87c1a01613a971173cc135c246a (patch)
tree0ef8ca6c14d1ad0ccf1a262edef8d2eb2fa674fd /engines/zvision/file
parent2463b4580436b41a46500e53b4868789c9c7b21e (diff)
downloadscummvm-rg350-d8a961244d99a87c1a01613a971173cc135c246a.tar.gz
scummvm-rg350-d8a961244d99a87c1a01613a971173cc135c246a.tar.bz2
scummvm-rg350-d8a961244d99a87c1a01613a971173cc135c246a.zip
ZVISION: Move all the file-related classes together
Diffstat (limited to 'engines/zvision/file')
-rw-r--r--engines/zvision/file/lzss_read_stream.cpp102
-rw-r--r--engines/zvision/file/lzss_read_stream.h71
-rw-r--r--engines/zvision/file/search_manager.cpp273
-rw-r--r--engines/zvision/file/search_manager.h73
-rw-r--r--engines/zvision/file/zfs_archive.cpp154
-rw-r--r--engines/zvision/file/zfs_archive.h125
6 files changed, 798 insertions, 0 deletions
diff --git a/engines/zvision/file/lzss_read_stream.cpp b/engines/zvision/file/lzss_read_stream.cpp
new file mode 100644
index 0000000000..6f27eaa765
--- /dev/null
+++ b/engines/zvision/file/lzss_read_stream.cpp
@@ -0,0 +1,102 @@
+/* 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 "zvision/file/lzss_read_stream.h"
+
+namespace ZVision {
+
+LzssReadStream::LzssReadStream(Common::SeekableReadStream *source)
+ : _source(source),
+ // It's convention to set the starting cursor position to blockSize - 16
+ _windowCursor(0x0FEE),
+ _eosFlag(false) {
+ // Clear the window to null
+ memset(_window, 0, BLOCK_SIZE);
+}
+
+uint32 LzssReadStream::decompressBytes(byte *destination, uint32 numberOfBytes) {
+ uint32 destinationCursor = 0;
+
+ while (destinationCursor < numberOfBytes) {
+ byte flagbyte = _source->readByte();
+ if (_source->eos())
+ break;
+ uint mask = 1;
+
+ for (int i = 0; i < 8; ++i) {
+ if ((flagbyte & mask) == mask) {
+ byte data = _source->readByte();
+ if (_source->eos()) {
+ return destinationCursor;
+ }
+
+ _window[_windowCursor] = data;
+ destination[destinationCursor++] = data;
+
+ // Increment and wrap the window cursor
+ _windowCursor = (_windowCursor + 1) & 0xFFF;
+ } else {
+ byte low = _source->readByte();
+ if (_source->eos()) {
+ return destinationCursor;
+ }
+
+ byte high = _source->readByte();
+ if (_source->eos()) {
+ return destinationCursor;
+ }
+
+ uint16 length = (high & 0xF) + 2;
+ uint16 offset = low | ((high & 0xF0) << 4);
+
+ for (int j = 0; j <= length; ++j) {
+ byte temp = _window[(offset + j) & 0xFFF];
+ _window[_windowCursor] = temp;
+ destination[destinationCursor++] = temp;
+ _windowCursor = (_windowCursor + 1) & 0xFFF;
+ }
+ }
+
+ mask = mask << 1;
+ }
+ }
+
+ return destinationCursor;
+}
+
+bool LzssReadStream::eos() const {
+ return _eosFlag;
+}
+
+uint32 LzssReadStream::read(void *dataPtr, uint32 dataSize) {
+ uint32 bytesRead = decompressBytes(static_cast<byte *>(dataPtr), dataSize);
+ if (bytesRead < dataSize) {
+ // Flag that we're at EOS
+ _eosFlag = true;
+ }
+
+ return dataSize;
+}
+
+} // End of namespace ZVision
diff --git a/engines/zvision/file/lzss_read_stream.h b/engines/zvision/file/lzss_read_stream.h
new file mode 100644
index 0000000000..1420621f13
--- /dev/null
+++ b/engines/zvision/file/lzss_read_stream.h
@@ -0,0 +1,71 @@
+/* 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.
+ *
+ */
+
+#ifndef ZVISION_LZSS_STREAM_H
+#define ZVISION_LZSS_STREAM_H
+
+#include "common/stream.h"
+#include "common/array.h"
+
+namespace Common {
+class SeekableReadStream;
+}
+
+namespace ZVision {
+
+class LzssReadStream : public Common::ReadStream {
+public:
+ /**
+ * A class that decompresses LZSS data and implements ReadStream for easy access
+ * to the decompiled data.
+ *
+ * @param source The source data
+ */
+ LzssReadStream(Common::SeekableReadStream *source);
+
+private:
+ enum {
+ BLOCK_SIZE = 0x1000
+ };
+
+private:
+ Common::SeekableReadStream *_source;
+ byte _window[BLOCK_SIZE];
+ uint _windowCursor;
+ bool _eosFlag;
+
+public:
+ bool eos() const;
+ uint32 read(void *dataPtr, uint32 dataSize);
+
+private:
+ /**
+ * Decompress the next <numberOfBytes> from the source stream. Or until EOS
+ *
+ * @param numberOfBytes How many bytes to decompress. This is a count of source bytes, not destination bytes
+ */
+ uint32 decompressBytes(byte *destination, uint32 numberOfBytes);
+};
+
+}
+
+#endif
diff --git a/engines/zvision/file/search_manager.cpp b/engines/zvision/file/search_manager.cpp
new file mode 100644
index 0000000000..752b52b01f
--- /dev/null
+++ b/engines/zvision/file/search_manager.cpp
@@ -0,0 +1,273 @@
+/* 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/debug.h"
+#include "common/fs.h"
+#include "common/stream.h"
+
+#include "zvision/file/search_manager.h"
+#include "zvision/file/zfs_archive.h"
+
+namespace ZVision {
+
+SearchManager::SearchManager(const Common::String &rootPath, int depth) {
+ _root = rootPath;
+ if (_root[_root.size() - 1] == '\\' || _root[_root.size() - 1] == '/')
+ _root.deleteLastChar();
+
+ Common::FSNode fsNode(_root);
+
+ listDirRecursive(_dirList, fsNode, depth);
+
+ for (Common::List<Common::String>::iterator it = _dirList.begin(); it != _dirList.end();)
+ if (it->size() == _root.size())
+ it = _dirList.erase(it);
+ else if (it->size() > _root.size()) {
+ *it = Common::String(it->c_str() + _root.size() + 1);
+ it++;
+ } else
+ it++;
+}
+
+SearchManager::~SearchManager() {
+ Common::List<Common::Archive *>::iterator it = _archList.begin();
+ while (it != _archList.end()) {
+ delete *it;
+ it++;
+ }
+
+ _archList.clear();
+}
+
+void SearchManager::addPatch(const Common::String &src, const Common::String &dst) {
+ Common::String lowerCaseName = dst;
+ lowerCaseName.toLowercase();
+
+ SearchManager::MatchList::iterator it = _files.find(lowerCaseName);
+
+ if (it != _files.end()) {
+ lowerCaseName = src;
+ lowerCaseName.toLowercase();
+ _files[lowerCaseName] = it->_value;
+ }
+}
+
+void SearchManager::addFile(const Common::String &name, Common::Archive *arch) {
+ bool addArch = true;
+ Common::List<Common::Archive *>::iterator it = _archList.begin();
+ while (it != _archList.end()) {
+ if (*it == arch) {
+ addArch = false;
+ break;
+ }
+ it++;
+ }
+ if (addArch)
+ _archList.push_back(arch);
+
+ Common::String lowerCaseName = name;
+ lowerCaseName.toLowercase();
+
+ SearchManager::Node nod;
+ nod.name = lowerCaseName;
+ nod.arch = arch;
+
+ SearchManager::MatchList::iterator fit = _files.find(lowerCaseName);
+
+ if (fit == _files.end()) {
+ _files[lowerCaseName] = nod;
+ } else {
+ Common::SeekableReadStream *stream = fit->_value.arch->createReadStreamForMember(fit->_value.name);
+ if (stream) {
+ if (stream->size() < 10)
+ fit->_value.arch = arch;
+ delete stream;
+ } else {
+ _files[lowerCaseName] = nod;
+ }
+ }
+}
+
+Common::File *SearchManager::openFile(const Common::String &name) {
+ Common::String lowerCaseName = name;
+ lowerCaseName.toLowercase();
+
+ SearchManager::MatchList::iterator fit = _files.find(lowerCaseName);
+
+ if (fit != _files.end()) {
+ Common::File *tmp = new Common::File();
+ tmp->open(fit->_value.name, *fit->_value.arch);
+ return tmp;
+ }
+ return NULL;
+}
+
+bool SearchManager::openFile(Common::File &file, const Common::String &name) {
+ Common::String lowerCaseName = name;
+ lowerCaseName.toLowercase();
+
+ SearchManager::MatchList::iterator fit = _files.find(lowerCaseName);
+
+ if (fit != _files.end())
+ return file.open(fit->_value.name, *fit->_value.arch);
+ return false;
+}
+
+bool SearchManager::hasFile(const Common::String &name) {
+ Common::String lowerCaseName = name;
+ lowerCaseName.toLowercase();
+
+ SearchManager::MatchList::iterator fit = _files.find(lowerCaseName);
+
+ if (fit != _files.end())
+ return true;
+ return false;
+}
+
+void SearchManager::loadZix(const Common::String &name) {
+ Common::File file;
+ file.open(name);
+
+ Common::String line;
+
+ while (!file.eos()) {
+ line = file.readLine();
+ if (line.matchString("----------*", true))
+ break;
+ }
+
+ if (file.eos())
+ return;
+
+ Common::Array<Common::Archive *> archives;
+
+ while (!file.eos()) {
+ line = file.readLine();
+ line.trim();
+ if (line.matchString("----------*", true))
+ break;
+ else if (line.matchString("DIR:*", true)) {
+ Common::String path(line.c_str() + 5);
+ Common::Archive *arc;
+ char tempPath[128];
+ strcpy(tempPath, path.c_str());
+ for (uint i = 0; i < path.size(); i++)
+ if (tempPath[i] == '\\')
+ tempPath[i] = '/';
+
+ path = Common::String(tempPath);
+ if (path.size() && path[0] == '.')
+ path.deleteChar(0);
+ if (path.size() && path[0] == '/')
+ path.deleteChar(0);
+
+ if (path.matchString("*.zfs", true))
+ arc = new ZfsArchive(path);
+ else {
+ if (path.size()) {
+ if (path[path.size() - 1] == '\\' || path[path.size() - 1] == '/')
+ path.deleteLastChar();
+ if (path.size())
+ for (Common::List<Common::String>::iterator it = _dirList.begin(); it != _dirList.end(); ++it)
+ if (path.equalsIgnoreCase(*it)) {
+ path = *it;
+ break;
+ }
+ }
+
+ path = Common::String::format("%s/%s", _root.c_str(), path.c_str());
+
+ arc = new Common::FSDirectory(path);
+ }
+ archives.push_back(arc);
+ }
+ }
+
+ if (file.eos())
+ return;
+
+ while (!file.eos()) {
+ line = file.readLine();
+ line.trim();
+ uint dr = 0;
+ char buf[32];
+ if (sscanf(line.c_str(), "%u %s", &dr, buf) == 2) {
+ if (dr <= archives.size() && dr > 0) {
+ addFile(Common::String(buf), archives[dr - 1]);
+ }
+ }
+ }
+}
+
+void SearchManager::addDir(const Common::String &name) {
+ Common::String path;
+ for (Common::List<Common::String>::iterator it = _dirList.begin(); it != _dirList.end(); ++it)
+ if (name.equalsIgnoreCase(*it)) {
+ path = *it;
+ break;
+ }
+
+ if (path.size() == 0)
+ return;
+
+ path = Common::String::format("%s/%s", _root.c_str(), path.c_str());
+
+ Common::FSDirectory *dir = new Common::FSDirectory(path);
+
+ Common::ArchiveMemberList list;
+ dir->listMatchingMembers(list, "*.zfs");
+
+ for (Common::ArchiveMemberList::iterator iter = list.begin(); iter != list.end(); ++iter) {
+ Common::String flname = (*iter)->getName();
+
+ ZfsArchive *zfs = new ZfsArchive(Common::String::format("%s/%s", name.c_str(), flname.c_str()));
+
+ Common::ArchiveMemberList zfslist;
+ zfs->listMembers(zfslist);
+
+ for (Common::ArchiveMemberList::iterator ziter = zfslist.begin(); ziter != zfslist.end(); ++ziter) {
+ Common::String zfsFileName = (*ziter)->getName();
+ addFile(zfsFileName, zfs);
+ }
+ }
+
+ list.clear();
+ dir->listMembers(list);
+
+ for (Common::ArchiveMemberList::iterator iter = list.begin(); iter != list.end(); ++iter) {
+ Common::String flname = (*iter)->getName();
+ addFile(flname, dir);
+ }
+}
+
+void SearchManager::listDirRecursive(Common::List<Common::String> &_list, const Common::FSNode &fsNode, int depth) {
+ Common::FSList fsList;
+ fsNode.getChildren(fsList);
+
+ _list.push_back(fsNode.getPath());
+
+ if (depth > 1)
+ for (Common::FSList::const_iterator it = fsList.begin(); it != fsList.end(); ++it)
+ listDirRecursive(_list, *it, depth - 1);
+}
+
+} // End of namespace ZVision
diff --git a/engines/zvision/file/search_manager.h b/engines/zvision/file/search_manager.h
new file mode 100644
index 0000000000..fdd70fd381
--- /dev/null
+++ b/engines/zvision/file/search_manager.h
@@ -0,0 +1,73 @@
+/* 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.
+ *
+ */
+
+#ifndef ZVISION_SEARCH_MANAGER_H
+#define ZVISION_SEARCH_MANAGER_H
+
+#include "common/str.h"
+#include "common/hash-str.h"
+#include "common/hashmap.h"
+#include "common/archive.h"
+#include "common/file.h"
+#include "common/list.h"
+
+namespace ZVision {
+
+class SearchManager {
+public:
+ SearchManager(const Common::String &rootPath, int depth);
+ ~SearchManager();
+
+ void addFile(const Common::String &name, Common::Archive *arch);
+ void addDir(const Common::String &name);
+ void addPatch(const Common::String &src, const Common::String &dst);
+
+ Common::File *openFile(const Common::String &name);
+ bool openFile(Common::File &file, const Common::String &name);
+ bool hasFile(const Common::String &name);
+
+ void loadZix(const Common::String &name);
+
+private:
+
+ void listDirRecursive(Common::List<Common::String> &dirList, const Common::FSNode &fsNode, int depth);
+
+ struct Node {
+ Common::String name;
+ Common::Archive *arch;
+ };
+
+ Common::List<Common::String> _dirList;
+
+ typedef Common::HashMap<Common::String, Node, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> MatchList;
+
+ Common::List<Common::Archive *> _archList;
+ MatchList _files;
+
+ Common::String _root;
+
+private:
+};
+
+}
+
+#endif // ZVISION_SEARCH_MANAGER_H
diff --git a/engines/zvision/file/zfs_archive.cpp b/engines/zvision/file/zfs_archive.cpp
new file mode 100644
index 0000000000..9b55a366ed
--- /dev/null
+++ b/engines/zvision/file/zfs_archive.cpp
@@ -0,0 +1,154 @@
+/* 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/memstream.h"
+#include "common/debug.h"
+#include "common/file.h"
+
+#include "zvision/file/zfs_archive.h"
+
+namespace ZVision {
+
+ZfsArchive::ZfsArchive(const Common::String &fileName) : _fileName(fileName) {
+ Common::File zfsFile;
+
+ if (!zfsFile.open(_fileName)) {
+ warning("ZFSArchive::ZFSArchive(): Could not find the archive file");
+ return;
+ }
+
+ readHeaders(&zfsFile);
+
+ debug(1, "ZfsArchive::ZfsArchive(%s): Located %d files", _fileName.c_str(), _entryHeaders.size());
+}
+
+ZfsArchive::ZfsArchive(const Common::String &fileName, Common::SeekableReadStream *stream) : _fileName(fileName) {
+ readHeaders(stream);
+
+ debug(1, "ZfsArchive::ZfsArchive(%s): Located %d files", _fileName.c_str(), _entryHeaders.size());
+}
+
+ZfsArchive::~ZfsArchive() {
+ debug(1, "ZfsArchive Destructor Called");
+ ZfsEntryHeaderMap::iterator it = _entryHeaders.begin();
+ for (; it != _entryHeaders.end(); ++it) {
+ delete it->_value;
+ }
+}
+
+void ZfsArchive::readHeaders(Common::SeekableReadStream *stream) {
+ // Don't do a straight struct cast since we can't guarantee endianness
+ _header.magic = stream->readUint32LE();
+ _header.unknown1 = stream->readUint32LE();
+ _header.maxNameLength = stream->readUint32LE();
+ _header.filesPerBlock = stream->readUint32LE();
+ _header.fileCount = stream->readUint32LE();
+ _header.xorKey[0] = stream->readByte();
+ _header.xorKey[1] = stream->readByte();
+ _header.xorKey[2] = stream->readByte();
+ _header.xorKey[3] = stream->readByte();
+ _header.fileSectionOffset = stream->readUint32LE();
+
+ uint32 nextOffset;
+
+ do {
+ // Read the offset to the next block
+ nextOffset = stream->readUint32LE();
+
+ // Read in each entry header
+ for (uint32 i = 0; i < _header.filesPerBlock; ++i) {
+ ZfsEntryHeader entryHeader;
+
+ entryHeader.name = readEntryName(stream);
+ entryHeader.offset = stream->readUint32LE();
+ entryHeader.id = stream->readUint32LE();
+ entryHeader.size = stream->readUint32LE();
+ entryHeader.time = stream->readUint32LE();
+ entryHeader.unknown = stream->readUint32LE();
+
+ if (entryHeader.size != 0)
+ _entryHeaders[entryHeader.name] = new ZfsEntryHeader(entryHeader);
+ }
+
+ // Seek to the next block of headers
+ stream->seek(nextOffset);
+ } while (nextOffset != 0);
+}
+
+Common::String ZfsArchive::readEntryName(Common::SeekableReadStream *stream) const {
+ // Entry Names are at most 16 bytes and are null padded
+ char buffer[16];
+ stream->read(buffer, 16);
+
+ return Common::String(buffer);
+}
+
+bool ZfsArchive::hasFile(const Common::String &name) const {
+ return _entryHeaders.contains(name);
+}
+
+int ZfsArchive::listMembers(Common::ArchiveMemberList &list) const {
+ int matches = 0;
+
+ for (ZfsEntryHeaderMap::const_iterator it = _entryHeaders.begin(); it != _entryHeaders.end(); ++it) {
+ list.push_back(Common::ArchiveMemberList::value_type(new Common::GenericArchiveMember(it->_value->name, this)));
+ matches++;
+ }
+
+ return matches;
+}
+
+const Common::ArchiveMemberPtr ZfsArchive::getMember(const Common::String &name) const {
+ if (!_entryHeaders.contains(name))
+ return Common::ArchiveMemberPtr();
+
+ return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this));
+}
+
+Common::SeekableReadStream *ZfsArchive::createReadStreamForMember(const Common::String &name) const {
+ if (!_entryHeaders.contains(name)) {
+ return 0;
+ }
+
+ ZfsEntryHeader *entryHeader = _entryHeaders[name];
+
+ Common::File zfsArchive;
+ zfsArchive.open(_fileName);
+ zfsArchive.seek(entryHeader->offset);
+
+ // This *HAS* to be malloc (not new[]) because MemoryReadStream uses free() to free the memory
+ byte *buffer = (byte *)malloc(entryHeader->size);
+ zfsArchive.read(buffer, entryHeader->size);
+ // Decrypt the data in place
+ if (_header.xorKey != 0)
+ unXor(buffer, entryHeader->size, _header.xorKey);
+
+ return new Common::MemoryReadStream(buffer, entryHeader->size, DisposeAfterUse::YES);
+}
+
+void ZfsArchive::unXor(byte *buffer, uint32 length, const byte *xorKey) const {
+ for (uint32 i = 0; i < length; ++i)
+ buffer[i] ^= xorKey[i % 4];
+}
+
+} // End of namespace ZVision
diff --git a/engines/zvision/file/zfs_archive.h b/engines/zvision/file/zfs_archive.h
new file mode 100644
index 0000000000..571591a6d1
--- /dev/null
+++ b/engines/zvision/file/zfs_archive.h
@@ -0,0 +1,125 @@
+/* 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.
+ *
+ */
+
+#ifndef ZVISION_ZFS_ARCHIVE_H
+#define ZVISION_ZFS_ARCHIVE_H
+
+#include "common/archive.h"
+#include "common/hashmap.h"
+#include "common/hash-str.h"
+
+namespace Common {
+class String;
+}
+
+namespace ZVision {
+
+struct ZfsHeader {
+ uint32 magic;
+ uint32 unknown1;
+ uint32 maxNameLength;
+ uint32 filesPerBlock;
+ uint32 fileCount;
+ byte xorKey[4];
+ uint32 fileSectionOffset;
+};
+
+struct ZfsEntryHeader {
+ Common::String name;
+ uint32 offset;
+ uint32 id;
+ uint32 size;
+ uint32 time;
+ uint32 unknown;
+};
+
+typedef Common::HashMap<Common::String, ZfsEntryHeader *, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> ZfsEntryHeaderMap;
+
+class ZfsArchive : public Common::Archive {
+public:
+ ZfsArchive(const Common::String &fileName);
+ ZfsArchive(const Common::String &fileName, Common::SeekableReadStream *stream);
+ ~ZfsArchive();
+
+ /**
+ * Check if a member with the given name is present in the Archive.
+ * Patterns are not allowed, as this is meant to be a quick File::exists()
+ * replacement.
+ */
+ bool hasFile(const Common::String &fileName) const;
+
+ /**
+ * Add all members of the Archive to list.
+ * Must only append to list, and not remove elements from it.
+ *
+ * @return The number of names added to list
+ */
+ int listMembers(Common::ArchiveMemberList &list) const;
+
+ /**
+ * Returns a ArchiveMember representation of the given file.
+ */
+ const Common::ArchiveMemberPtr getMember(const Common::String &name) const;
+
+ /**
+ * Create a stream bound to a member with the specified name in the
+ * archive. If no member with this name exists, 0 is returned.
+ *
+ * @return The newly created input stream
+ */
+ Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const;
+
+private:
+ const Common::String _fileName;
+ ZfsHeader _header;
+ ZfsEntryHeaderMap _entryHeaders;
+
+ /**
+ * Parses the zfs file into file entry headers that can be used later
+ * to get the entry data.
+ *
+ * @param stream The contents of the zfs file
+ */
+ void readHeaders(Common::SeekableReadStream *stream);
+
+ /**
+ * Entry names are contained within a 16 byte block. This reads the block
+ * and converts it the name to a Common::String
+ *
+ * @param stream The zfs file stream
+ * @return The entry file name
+ */
+ Common::String readEntryName(Common::SeekableReadStream *stream) const;
+
+ /**
+ * ZFS file entries can be encrypted using XOR encoding. This method
+ * decodes the buffer in place using the supplied xorKey.
+ *
+ * @param buffer The data to decode
+ * @param length Length of buffer
+ */
+ void unXor(byte *buffer, uint32 length, const byte *xorKey) const;
+};
+
+} // End of namespace ZVision
+
+#endif