Initial commit
This commit is contained in:
229
engines/stark/formats/xarc.cpp
Normal file
229
engines/stark/formats/xarc.cpp
Normal file
@@ -0,0 +1,229 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// Based on the Xentax Wiki documentation:
|
||||
// https://web.archive.org/web/20090621212912/http://wiki.xentax.com/index.php?title=The_Longest_Journey_XARC
|
||||
|
||||
#include "engines/stark/formats/xarc.h"
|
||||
#include "engines/stark/debug.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/file.h"
|
||||
#include "common/substream.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Formats {
|
||||
|
||||
// ARCHIVE MEMBER
|
||||
|
||||
class XARCMember : public Common::ArchiveMember {
|
||||
public:
|
||||
XARCMember(const XARCArchive *xarc, Common::ReadStream &stream, uint32 offset);
|
||||
|
||||
Common::SeekableReadStream *createReadStream() const override;
|
||||
Common::SeekableReadStream *createReadStreamForAltStream(Common::AltStreamType altStreamType) const override;
|
||||
Common::String getName() const override { return _name.baseName(); }
|
||||
Common::Path getPathInArchive() const override { return _name; }
|
||||
Common::String getFileName() const override { return _name.baseName(); }
|
||||
uint32 getLength() const { return _length; }
|
||||
uint32 getOffset() const { return _offset; }
|
||||
|
||||
private:
|
||||
const XARCArchive *_xarc;
|
||||
Common::Path _name;
|
||||
uint32 _offset;
|
||||
uint32 _length;
|
||||
|
||||
// Helper function
|
||||
Common::String readString(Common::ReadStream &stream);
|
||||
};
|
||||
|
||||
XARCMember::XARCMember(const XARCArchive *xarc, Common::ReadStream &stream, uint32 offset) {
|
||||
_xarc = xarc;
|
||||
|
||||
// Read the information about this archive member
|
||||
_name = Common::Path(readString(stream));
|
||||
_offset = offset;
|
||||
_length = stream.readUint32LE();
|
||||
debugC(20, kDebugArchive, "Stark::XARC Member: \"%s\" starts at offset=%d and has length=%d", _name.toString().c_str(), _offset, _length);
|
||||
|
||||
// Unknown value. English: 0, others: 1
|
||||
uint32 unknown = stream.readUint32LE();
|
||||
debugC(kDebugUnknown, "Stark::XARC Member: \"%s\" has unknown=%d", _name.toString().c_str(), unknown);
|
||||
if (unknown != 0 && unknown != 1) {
|
||||
warning("Stark::XARC Member: \"%s\" has unknown=%d with unknown meaning", _name.toString().c_str(), unknown);
|
||||
}
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *XARCMember::createReadStream() const {
|
||||
return _xarc->createReadStreamForMember(this);
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *XARCMember::createReadStreamForAltStream(Common::AltStreamType altStreamType) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Common::String XARCMember::readString(Common::ReadStream &stream) {
|
||||
Common::String str;
|
||||
|
||||
// Read until we find a 0
|
||||
char c = 1;
|
||||
while (c != 0) {
|
||||
c = stream.readByte();
|
||||
if (stream.eos()) {
|
||||
c = 0;
|
||||
}
|
||||
if (c != 0) {
|
||||
str += c;
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
// ARCHIVE
|
||||
|
||||
bool XARCArchive::open(const Common::Path &filename) {
|
||||
Common::File stream;
|
||||
if (!stream.open(filename)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_filename = filename;
|
||||
|
||||
// Unknown: always 1? version?
|
||||
uint32 unknown = stream.readUint32LE();
|
||||
debugC(kDebugUnknown, "Stark::XARC: \"%s\" has unknown=%d", _filename.toString(Common::Path::kNativeSeparator).c_str(), unknown);
|
||||
if (unknown != 1) {
|
||||
warning("Stark::XARC: \"%s\" has unknown=%d with unknown meaning", _filename.toString(Common::Path::kNativeSeparator).c_str(), unknown);
|
||||
}
|
||||
|
||||
// Read the number of contained files
|
||||
uint32 numFiles = stream.readUint32LE();
|
||||
debugC(20, kDebugArchive, "Stark::XARC: \"%s\" contains %d files", _filename.toString(Common::Path::kNativeSeparator).c_str(), numFiles);
|
||||
|
||||
// Read the offset to the contents of the first file
|
||||
uint32 offset = stream.readUint32LE();
|
||||
debugC(20, kDebugArchive, "Stark::XARC: \"%s\"'s first file has offset=%d", _filename.toString(Common::Path::kNativeSeparator).c_str(), offset);
|
||||
|
||||
for (uint32 i = 0; i < numFiles; i++) {
|
||||
XARCMember *member = new XARCMember(this, stream, offset);
|
||||
_members.push_back(Common::ArchiveMemberPtr(member));
|
||||
|
||||
// Set the offset to the next member
|
||||
offset += member->getLength();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::Path XARCArchive::getFilename() const {
|
||||
return _filename;
|
||||
}
|
||||
|
||||
bool XARCArchive::hasFile(const Common::Path &path) const {
|
||||
Common::String name = path.toString();
|
||||
for (Common::ArchiveMemberList::const_iterator it = _members.begin(); it != _members.end(); ++it) {
|
||||
if ((*it)->getName() == name) {
|
||||
// Found it
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Not found
|
||||
return false;
|
||||
}
|
||||
|
||||
int XARCArchive::listMatchingMembers(Common::ArchiveMemberList &list, const Common::Path &pattern, bool matchPathComponents) const {
|
||||
Common::String patternString = pattern.toString();
|
||||
int matches = 0;
|
||||
for (Common::ArchiveMemberList::const_iterator it = _members.begin(); it != _members.end(); ++it) {
|
||||
if ((*it)->getName().matchString(patternString)) {
|
||||
// This file matches, add it
|
||||
list.push_back(*it);
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
int XARCArchive::listMembers(Common::ArchiveMemberList &list) const {
|
||||
int files = 0;
|
||||
for (Common::ArchiveMemberList::const_iterator it = _members.begin(); it != _members.end(); ++it) {
|
||||
// Add all the members to the list
|
||||
list.push_back(*it);
|
||||
files++;
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
const Common::ArchiveMemberPtr XARCArchive::getMember(const Common::Path &path) const {
|
||||
Common::String name = path.toString();
|
||||
for (Common::ArchiveMemberList::const_iterator it = _members.begin(); it != _members.end(); ++it) {
|
||||
if ((*it)->getName() == name) {
|
||||
// Found it
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
|
||||
// Not found, return an empty ptr
|
||||
return Common::ArchiveMemberPtr();
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *XARCArchive::createReadStreamForMember(const Common::Path &path) const {
|
||||
Common::String name = path.toString();
|
||||
for (Common::ArchiveMemberList::const_iterator it = _members.begin(); it != _members.end(); ++it) {
|
||||
if ((*it)->getName() == name) {
|
||||
// Found it
|
||||
return createReadStreamForMember((const XARCMember *)it->get());
|
||||
}
|
||||
}
|
||||
|
||||
// Not found
|
||||
return 0;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *XARCArchive::createReadStreamForMember(const XARCMember *member) const {
|
||||
// Open the xarc file
|
||||
Common::File *f = new Common::File;
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
if (!f->open(_filename)) {
|
||||
delete f;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Return the substream that contains the archive member
|
||||
uint32 offset = member->getOffset();
|
||||
uint32 length = member->getLength();
|
||||
return new Common::SeekableSubReadStream(f, offset, offset + length, DisposeAfterUse::YES);
|
||||
|
||||
// Different approach: keep the archive open and read full resources to memory
|
||||
//f.seek(member->getOffset());
|
||||
//return f.readStream(member->getLength());
|
||||
}
|
||||
|
||||
} // End of namespace Formats
|
||||
} // End of namespace Stark
|
||||
Reference in New Issue
Block a user