Initial commit
This commit is contained in:
156
engines/zvision/file/zfs_archive.cpp
Normal file
156
engines/zvision/file/zfs_archive.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/file.h"
|
||||
#include "common/memstream.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "zvision/detection.h"
|
||||
#include "zvision/file/zfs_archive.h"
|
||||
|
||||
namespace ZVision {
|
||||
|
||||
ZfsArchive::ZfsArchive(const Common::Path &fileName) : _fileName(fileName) {
|
||||
Common::File zfsFile;
|
||||
memset(&_header, 0, sizeof(_header));
|
||||
|
||||
if (!zfsFile.open(_fileName)) {
|
||||
warning("ZFSArchive::ZFSArchive(): Could not find the archive file");
|
||||
return;
|
||||
}
|
||||
|
||||
readHeaders(&zfsFile);
|
||||
|
||||
debugC(1, kDebugFile, "ZfsArchive::ZfsArchive(%s): Located %d files", _fileName.toString(Common::Path::kNativeSeparator).c_str(), _entryHeaders.size());
|
||||
}
|
||||
|
||||
ZfsArchive::ZfsArchive(const Common::Path &fileName, Common::SeekableReadStream *stream) : _fileName(fileName) {
|
||||
readHeaders(stream);
|
||||
|
||||
debugC(1, kDebugFile, "ZfsArchive::ZfsArchive(%s): Located %d files", _fileName.toString(Common::Path::kNativeSeparator).c_str(), _entryHeaders.size());
|
||||
}
|
||||
|
||||
ZfsArchive::~ZfsArchive() {
|
||||
debugC(1, kDebugFile, "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::Path &path) const {
|
||||
Common::String name = path.toString();
|
||||
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::Path &path) const {
|
||||
if (!hasFile(path))
|
||||
return Common::ArchiveMemberPtr();
|
||||
|
||||
return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(path, *this));
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *ZfsArchive::createReadStreamForMember(const Common::Path &path) const {
|
||||
Common::String name = path.toString();
|
||||
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] + _header.xorKey[1] + _header.xorKey[2] + _header.xorKey[3] != 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
|
||||
Reference in New Issue
Block a user