mirror of
https://github.com/scummvm/scummvm.git
synced 2025-04-02 10:52:32 -04:00
229 lines
6.9 KiB
C++
229 lines
6.9 KiB
C++
/* 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:
|
|
// 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
|