aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra
diff options
context:
space:
mode:
authorJohannes Schickel2008-02-07 23:13:13 +0000
committerJohannes Schickel2008-02-07 23:13:13 +0000
commitae0b605ad4c2b69f1e47e0d98c5cf3a881267318 (patch)
treebe84bc96837b8b2c8cd58be918ca25a13564df4f /engines/kyra
parent356ae3b9ce8b28b50e1f3df8c45bddeb861cd45a (diff)
downloadscummvm-rg350-ae0b605ad4c2b69f1e47e0d98c5cf3a881267318.tar.gz
scummvm-rg350-ae0b605ad4c2b69f1e47e0d98c5cf3a881267318.tar.bz2
scummvm-rg350-ae0b605ad4c2b69f1e47e0d98c5cf3a881267318.zip
Reworked Kyrandia resource loading code.
svn-id: r30820
Diffstat (limited to 'engines/kyra')
-rw-r--r--engines/kyra/kyra_v3.cpp8
-rw-r--r--engines/kyra/resource.cpp566
-rw-r--r--engines/kyra/resource.h108
-rw-r--r--engines/kyra/script.cpp45
-rw-r--r--engines/kyra/script.h10
-rw-r--r--engines/kyra/sound.cpp12
-rw-r--r--engines/kyra/sound.h1
7 files changed, 350 insertions, 400 deletions
diff --git a/engines/kyra/kyra_v3.cpp b/engines/kyra/kyra_v3.cpp
index ce0f1a8cd2..971f96c7ff 100644
--- a/engines/kyra/kyra_v3.cpp
+++ b/engines/kyra/kyra_v3.cpp
@@ -244,13 +244,13 @@ void KyraEngine_v3::playMenuAudioFile() {
if (_soundDigital->isPlaying(_musicSoundChannel))
return;
- Common::File *handle = new Common::File();
+ /*Common::File *handle = new Common::File();
uint32 temp = 0;
_res->getFileHandle(_menuAudioFile, &temp, *handle);
if (handle->isOpen())
_musicSoundChannel = _soundDigital->playSound(handle, true);
else
- delete handle;
+ delete handle;*/
}
void KyraEngine_v3::playMusicTrack(int track, int force) {
@@ -271,13 +271,13 @@ void KyraEngine_v3::playMusicTrack(int track, int force) {
if (_musicSoundChannel == -1) {
assert(track < _soundListSize && track >= 0);
- Common::File *handle = new Common::File();
+ /*Common::File *handle = new Common::File();
uint32 temp = 0;
_res->getFileHandle(_soundList[track], &temp, *handle);
if (handle->isOpen())
_musicSoundChannel = _soundDigital->playSound(handle);
else
- delete handle;
+ delete handle;*/
}
_musicSoundChannel = track;
diff --git a/engines/kyra/resource.cpp b/engines/kyra/resource.cpp
index b6d3bfe57a..9077a1291a 100644
--- a/engines/kyra/resource.cpp
+++ b/engines/kyra/resource.cpp
@@ -28,31 +28,17 @@
#include "common/endian.h"
#include "common/file.h"
#include "common/fs.h"
-#include "common/hash-str.h"
#include "common/func.h"
#include "common/algorithm.h"
#include "gui/message.h"
#include "kyra/resource.h"
-#include "kyra/script.h"
-#include "kyra/wsamovie.h"
-#include "kyra/screen.h"
namespace Kyra {
-namespace {
-struct ResFilenameEqual : public Common::UnaryFunction<ResourceFile*, bool> {
- uint _filename;
- ResFilenameEqual(uint file) : _filename(file) {}
-
- bool operator()(const ResourceFile *f) {
- return f->filename() == _filename;
- }
-};
-} // end of anonymous namespace
-
-Resource::Resource(KyraEngine *vm) : _vm(vm) {
+Resource::Resource(KyraEngine *vm) : _loaders(), _map(), _vm(vm) {
+ initializeLoaders();
}
Resource::~Resource() {
@@ -95,12 +81,7 @@ bool Resource::reset() {
return true;
} else if (_vm->game() == GI_KYRA3) {
- // load the installation package file for kyra3
- INSFile *insFile = new INSFile("WESTWOOD.001");
- assert(insFile);
- if (!insFile->isValid())
- error("'WESTWOOD.001' file not found or corrupt");
- _pakfiles.push_back(insFile);
+ loadPakFile("WESTWOOD.001");
}
FSList fslist;
@@ -115,7 +96,6 @@ bool Resource::reset() {
};
Common::for_each(list, list + ARRAYSIZE(list), Common::bind1st(Common::mem_fun(&Resource::loadPakFile), this));
- Common::for_each(_pakfiles.begin(), _pakfiles.end(), Common::bind2nd(Common::mem_fun(&ResourceFile::protect), true));
} else {
for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
Common::String filename = file->getName();
@@ -125,55 +105,48 @@ bool Resource::reset() {
if (filename == "TWMUSIC.PAK")
continue;
- if (filename.hasSuffix("PAK") || filename.hasSuffix("APK")) {
+ if (filename == ((_vm->gameFlags().lang == Common::EN_ANY) ? "JMC.PAK" : "EMC.PAK"))
+ continue;
+
+ if (filename.hasSuffix(".PAK") || filename.hasSuffix(".APK")) {
if (!loadPakFile(file->getName()))
error("couldn't open pakfile '%s'", file->getName().c_str());
}
}
-
- if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98) {
- uint unloadHash = (_vm->gameFlags().lang == Common::EN_ANY) ? Common::hashit_lower("JMC.PAK") : Common::hashit_lower("EMC.PAK");
-
- ResIterator file = Common::find_if(_pakfiles.begin(), _pakfiles.end(), ResFilenameEqual(unloadHash));
- if (file != _pakfiles.end()) {
- delete *file;
- _pakfiles.erase(file);
- }
- }
}
return true;
}
bool Resource::loadPakFile(const Common::String &filename) {
- ResIterator listFile = Common::find_if(_pakfiles.begin(), _pakfiles.end(), ResFilenameEqual(Common::hashit_lower(filename)));
- if (listFile != _pakfiles.end()) {
- (*listFile)->open();
- return true;
- }
+ ResFileMap::iterator iter = _map.find(filename);
+ if (iter == _map.end())
+ return false;
- const bool isKyraDat = filename.equalsIgnoreCase(StaticResource::staticDataFilename());
- uint32 size = 0;
+ iter->_value.loadable = true;
- Common::File handle;
- if (!getFileHandle(filename.c_str(), &size, handle)) {
- (!isKyraDat ? error : warning)("couldn't load file: '%s'", filename.c_str());
+ if (!isAccessable(filename))
return false;
- }
- PAKFile *file = new PAKFile(filename.c_str(), handle.name(), handle, (_vm->gameFlags().platform == Common::kPlatformAmiga) && !isKyraDat);
- handle.close();
+ if (iter->_value.preload)
+ return true;
- if (!file)
- return false;
+ Common::SeekableReadStream *stream = getFileStream(filename);
+ assert(stream);
+
+ const ResArchiveLoader *loader = getLoader(iter->_value.type);
+ assert(loader);
+
+ loader->loadFile(filename, *stream, _map);
+ delete stream;
+ stream = 0;
- if (!file->isValid()) {
- error("'%s' is no valid pak file", filename.c_str());
- delete file;
+ iter = _map.find(filename);
+ if (iter == _map.end())
return false;
- }
+ iter->_value.preload = true;
+ detectFileTypes();
- _pakfiles.push_back(file);
return true;
}
@@ -221,205 +194,252 @@ bool Resource::loadFileList(const char * const *filelist, uint32 numFiles) {
}
void Resource::unloadPakFile(const Common::String &filename) {
- ResIterator pak = Common::find_if(_pakfiles.begin(), _pakfiles.end(), ResFilenameEqual(Common::hashit_lower(filename)));
- if (pak != _pakfiles.end())
- (*pak)->close();
+ ResFileMap::iterator iter = _map.find(filename);
+ if (iter != _map.end()) {
+ if (!iter->_value.prot)
+ iter->_value.loadable = false;
+ }
}
bool Resource::isInPakList(const Common::String &filename) const {
- return (Common::find_if(_pakfiles.begin(), _pakfiles.end(), ResFilenameEqual(Common::hashit_lower(filename))) != _pakfiles.end());
+ return isAccessable(filename);
}
void Resource::unloadAllPakFiles() {
- for (ResIterator start = _pakfiles.begin(); start != _pakfiles.end(); ++start) {
- delete *start;
- *start = 0;
+ FilesystemNode dir(ConfMan.get("path"));
+
+ if (!dir.exists() || !dir.isDirectory())
+ error("invalid game path '%s'", dir.getPath().c_str());
+
+ FSList fslist;
+ if (!dir.getChildren(fslist, FilesystemNode::kListFilesOnly))
+ error("can't list files inside game path '%s'", dir.getPath().c_str());
+
+ // remove all entries
+ _map.clear();
+
+ Common::File temp;
+ if (temp.open("kyra.dat")) {
+ ResFileEntry entry;
+ entry.parent = "";
+ entry.size = temp.size();
+ entry.loadable = true;
+ entry.preload = false;
+ entry.prot = false;
+ entry.type = ResFileEntry::kPak;
+ entry.offset = 0;
+ _map["kyra.dat"] = entry;
+ temp.close();
+ }
+
+ for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
+ ResFileEntry entry;
+ entry.parent = "";
+ if (!temp.open(file->getPath()))
+ error("couldn't open file '%s'", file->getName().c_str());
+ entry.size = temp.size();
+ entry.offset = 0;
+ entry.loadable = true;
+ entry.preload = false;
+ entry.prot = false;
+ entry.type = ResFileEntry::kAutoDetect;
+ _map[file->getName()] = entry;
+ temp.close();
}
- _pakfiles.clear();
+
+ detectFileTypes();
}
uint8 *Resource::fileData(const char *file, uint32 *size) const {
- Common::File fileHandle;
+ Common::SeekableReadStream *stream = getFileStream(file);
+ if (!stream)
+ return 0;
+ uint32 bufferSize = stream->size();
+ uint8 *buffer = new uint8[bufferSize];
+ assert(buffer);
if (size)
- *size = 0;
-
- // test to open it in the main dir
- if (fileHandle.open(file)) {
- uint32 fileSize = fileHandle.size();
- uint8 *buffer = new uint8[fileSize];
- assert(buffer);
-
- fileHandle.read(buffer, fileSize);
-
- if (size)
- *size = fileSize;
+ *size = bufferSize;
+ stream->read(buffer, bufferSize);
+ delete stream;
+ return buffer;
+}
- return buffer;
- } else {
- // opens the file inside a PAK File
- uint fileHash = Common::hashit_lower(file);
- for (ConstResIterator cur = _pakfiles.begin(); cur != _pakfiles.end(); ++cur) {
- if (!(*cur)->isOpen())
- continue;
+uint32 Resource::getFileSize(const char *file) const {
+ if (!isAccessable(file))
+ return 0;
+ ResFileMap::const_iterator iter = _map.find(file);
+ if (iter != _map.end())
+ return iter->_value.size;
+ return 0;
+}
- uint8* result = (*cur)->getFile(fileHash);
+bool Resource::loadFileToBuf(const char *file, void *buf, uint32 maxSize) {
+ Common::SeekableReadStream *stream = getFileStream(file);
+ if (!stream)
+ return false;
- if (result) {
- uint32 fileSize = (*cur)->getFileSize(fileHash);
+ if (maxSize < stream->size()) {
+ delete stream;
+ return false;
+ }
+ memset(buf, 0, maxSize);
+ stream->read(buf, stream->size());
+ delete stream;
+ return true;
+}
- if (!fileSize)
- continue;
+Common::SeekableReadStream *Resource::getFileStream(const Common::String &file) const {
+ if (!isAccessable(file))
+ return 0;
- if (size)
- *size = fileSize;
+ ResFileMap::const_iterator iter = _map.find(file);
+ if (iter == _map.end())
+ return 0;
- return result;
- }
+ if (!iter->_value.parent.empty()) {
+ Common::SeekableReadStream *parent = getFileStream(iter->_value.parent);
+ assert(parent);
+ ResFileMap::const_iterator parentIter = _map.find(iter->_value.parent);
+ const ResArchiveLoader *loader = getLoader(parentIter->_value.type);
+ assert(loader);
+ return loader->loadFileFromArchive(file, parent, _map);
+ } else {
+ Common::File *stream = new Common::File();
+ if (!stream->open(file.c_str())) {
+ warning("Couldn't open file '%s'", file.c_str());
+ return 0;
}
+ return stream;
}
return 0;
}
-bool Resource::getFileHandle(const char *file, uint32 *size, Common::File &filehandle) {
- filehandle.close();
-
- if (filehandle.open(file)) {
- if (size)
- *size = filehandle.size();
- return true;
- }
-
- uint fileHash = Common::hashit_lower(file);
- for (ResIterator start = _pakfiles.begin() ;start != _pakfiles.end(); ++start) {
- if (!(*start)->isOpen())
- continue;
-
- if ((*start)->getFileHandle(fileHash, filehandle)) {
- uint32 tSize = (*start)->getFileSize(fileHash);
-
- if (!tSize)
- continue;
+bool Resource::isAccessable(const Common::String &file) const {
+ ResFileMap::const_iterator iter = _map.find(file);
+ while (true) {
+ if (iter == _map.end())
+ break;
- if (size)
- *size = tSize;
+ if (!iter->_value.loadable)
+ return false;
- return true;
- }
+ if (!iter->_value.parent.empty())
+ iter = _map.find(iter->_value.parent);
+ else
+ return iter->_value.loadable;
}
-
return false;
}
-uint32 Resource::getFileSize(const char *file) const {
- Common::File temp;
- if (temp.open(file))
- return temp.size();
-
- uint fileHash = Common::hashit_lower(file);
- for (ConstResIterator start = _pakfiles.begin() ;start != _pakfiles.end(); ++start) {
- if (!(*start)->isOpen())
+void Resource::detectFileTypes() {
+ for (ResFileMap::iterator i = _map.begin(); i != _map.end(); ++i) {
+ if (!isAccessable(i->_key))
continue;
- uint32 size = (*start)->getFileSize(fileHash);
+ if (i->_value.type == ResFileEntry::kAutoDetect) {
+ for (LoaderIterator l = _loaders.begin(); l != _loaders.end(); ++l) {
+ Common::SeekableReadStream *stream = getFileStream(i->_key);
+ if ((*l)->isLoadable(i->_key, *stream)) {
+ i->_value.type = (*l)->getType();
+ i->_value.loadable = false;
+ i->_value.preload = false;
+ break;
+ }
+ delete stream;
+ stream = 0;
+ }
- if (size)
- return size;
+ if (i->_value.type == ResFileEntry::kAutoDetect) {
+ i->_value.type = ResFileEntry::kRaw;
+ i->_value.loadable = true;
+ }
+ }
}
-
- return 0;
}
-bool Resource::loadFileToBuf(const char *file, void *buf, uint32 maxSize) {
- Common::File tempHandle;
- uint32 size = 0;
-
- if (!getFileHandle(file, &size, tempHandle))
- return false;
+#pragma mark -
+#pragma mark - ResFileLodaer
+#pragma mark -
- if (size > maxSize)
- return false;
+class ResLoaderPak : public ResArchiveLoader {
+public:
+ bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const;
+ bool loadFile(const Common::String &filename, Common::SeekableReadStream &stream, ResFileMap &map) const;
+ Common::SeekableReadStream *loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileMap &map) const;
- memset(buf, 0, maxSize);
- tempHandle.read(buf, size);
+ ResFileEntry::kType getType() const {
+ return ResFileEntry::kPak;
+ }
+};
- return true;
+bool ResLoaderPak::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const {
+ // TODO improve check:
+ Common::String file = filename;
+ file.toUppercase();
+ return ((file.hasSuffix(".PAK") && file != "TWMUSIC.PAK") || file.hasSuffix(".APK") || file.hasSuffix(".VRM") || file.hasSuffix(".TLK"));
}
-///////////////////////////////////////////
-// Pak file manager
-PAKFile::PAKFile(const char *file, const char *physfile, Common::File &pakfile, bool isAmiga) : ResourceFile() {
- _open = false;
-
- if (!pakfile.isOpen()) {
- debug(3, "couldn't open pakfile '%s'\n", file);
- return;
- }
-
- uint32 off = pakfile.pos();
- uint32 filesize = pakfile.size();
+bool ResLoaderPak::loadFile(const Common::String &filename, Common::SeekableReadStream &stream, ResFileMap &map) const {
+ uint32 filesize = stream.size();
+
+ Common::List<Common::String> filenames;
+ Common::List<ResFileEntry> entries;
uint32 pos = 0, startoffset = 0, endoffset = 0;
+ bool switchEndian = false;
- if (isAmiga)
- startoffset = pakfile.readUint32BE();
- else
- startoffset = pakfile.readUint32LE();
-
+ startoffset = stream.readUint32LE(); pos += 4;
if (startoffset > filesize) {
- warning("PAK file '%s' is corrupted", file);
- return;
+ switchEndian = true;
+ startoffset = SWAP_BYTES_32(startoffset);
}
- pos += 4;
-
while (pos < filesize) {
- PakChunk chunk;
uint8 buffer[64];
uint32 nameLength;
// Move to the position of the next file entry
- pakfile.seek(pos);
+ stream.seek(pos);
// Read in the header
- if (pakfile.read(&buffer, 64) < 5) {
- warning("PAK file '%s' is corrupted", file);
- return;
+ if (stream.read(&buffer, 64) < 5) {
+ warning("PAK file '%s' is corrupted", filename.c_str());
+ return false;
}
// Quit now if we encounter an empty string
if (!(*((const char*)buffer)))
break;
- chunk._name = Common::hashit_lower((const char*)buffer);
nameLength = strlen((const char*)buffer) + 1;
if (nameLength > 60) {
- warning("PAK file '%s' is corrupted", file);
- return;
+ warning("PAK file '%s' is corrupted", filename.c_str());
+ return false;
}
- if (isAmiga)
- endoffset = READ_BE_UINT32(buffer + nameLength);
- else
- endoffset = READ_LE_UINT32(buffer + nameLength);
+ endoffset = (switchEndian ? READ_BE_UINT32 : READ_LE_UINT32)(buffer + nameLength);
- if (!endoffset) {
+ if (!endoffset)
endoffset = filesize;
- } else if (endoffset > filesize || startoffset > endoffset) {
- warning("PAK file '%s' is corrupted", file);
- return;
- }
if (startoffset != endoffset) {
- chunk._start = startoffset;
- chunk._size = endoffset - startoffset;
-
- _files.push_back(chunk);
+ ResFileEntry entry;
+ entry.size = endoffset - startoffset;
+ entry.offset = startoffset;
+ entry.parent = filename;
+ entry.type = ResFileEntry::kAutoDetect;
+ entry.loadable = true;
+ entry.prot = false;
+ entry.preload = false;
+
+ filenames.push_back(Common::String((const char*)buffer));
+ entries.push_back(entry);
}
if (endoffset == filesize)
@@ -429,161 +449,129 @@ PAKFile::PAKFile(const char *file, const char *physfile, Common::File &pakfile,
pos += nameLength + 4;
}
- _open = true;
- _filename = Common::hashit_lower(file);
- _physfile = physfile;
- _physOffset = off;
-}
+ assert(filenames.size() == entries.size());
+ Common::List<ResFileEntry>::iterator entry = entries.begin();
+ Common::List<Common::String>::iterator file = filenames.begin();
-PAKFile::~PAKFile() {
- _physfile.clear();
- _open = false;
+ for (; entry != entries.end(); ++entry, ++file) {
+ map.erase(*file);
+ map[*file] = *entry;
+ }
- _files.clear();
+ return true;
}
-uint8 *PAKFile::getFile(uint hash) const {
- ConstPakIterator file = Common::find_if(_files.begin(), _files.end(), Common::bind2nd(Common::EqualTo<uint>(), hash));
- if (file == _files.end())
- return 0;
+Common::SeekableReadStream *ResLoaderPak::loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileMap &map) const {
+ assert(archive);
- Common::File pakfile;
- if (!openFile(pakfile))
- return false;
+ ResFileMap::const_iterator entry = map.find(file);
+ if (entry == map.end())
+ return 0;
- pakfile.seek(file->_start, SEEK_CUR);
- uint8 *buffer = new uint8[file->_size];
- assert(buffer);
- pakfile.read(buffer, file->_size);
- return buffer;
+ archive->seek(entry->_value.offset, SEEK_SET);
+ Common::SeekableSubReadStream *stream = new Common::SeekableSubReadStream(archive, entry->_value.offset, entry->_value.offset + entry->_value.size, true);
+ assert(stream);
+ return stream;
}
-bool PAKFile::getFileHandle(uint hash, Common::File &filehandle) const {
- filehandle.close();
+class ResLoaderIns : public ResArchiveLoader {
+public:
+ bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const;
+ bool loadFile(const Common::String &filename, Common::SeekableReadStream &stream, ResFileMap &map) const;
+ Common::SeekableReadStream *loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileMap &map) const;
- ConstPakIterator file = Common::find_if(_files.begin(), _files.end(), Common::bind2nd(Common::EqualTo<uint>(), hash));
- if (file == _files.end())
- return false;
-
- if (!openFile(filehandle))
- return false;
-
- filehandle.seek(file->_start, SEEK_CUR);
- return true;
-}
-
-uint32 PAKFile::getFileSize(uint hash) const {
- ConstPakIterator file = Common::find_if(_files.begin(), _files.end(), Common::bind2nd(Common::EqualTo<uint>(), hash));
- return (file != _files.end()) ? file->_size : 0;
-}
+ ResFileEntry::kType getType() const {
+ return ResFileEntry::kIns;
+ }
+};
-bool PAKFile::openFile(Common::File &filehandle) const {
- filehandle.close();
+bool ResLoaderIns::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const {
+ stream.seek(3);
+ uint32 size = stream.readUint32LE();
- if (!filehandle.open(_physfile))
+ if (size > stream.size())
return false;
- filehandle.seek(_physOffset, SEEK_CUR);
- return true;
-}
+ stream.seek(size+1, SEEK_SET);
+ uint8 buffer[2];
+ stream.read(&buffer, 2);
-///////////////////////////////////////////
-// Ins file manager
-INSFile::INSFile(const char *file) : ResourceFile(), _files() {
- Common::File pakfile;
- _open = false;
+ return (buffer[0] == 0x0D && buffer[1] == 0x0A);
+}
- if (!pakfile.open(file)) {
- debug(3, "couldn't open insfile '%s'\n", file);
- return;
- }
+bool ResLoaderIns::loadFile(const Common::String &filename, Common::SeekableReadStream &stream, ResFileMap &map) const {
+ Common::List<Common::String> filenames;
// thanks to eriktorbjorn for this code (a bit modified though)
-
- // skip first three bytes
- pakfile.seek(3);
+ stream.seek(3, SEEK_SET);
// first file is the index table
- uint32 filesize = pakfile.readUint32LE();
-
+ uint32 size = stream.readUint32LE();
Common::String temp = "";
- for (uint i = 0; i < filesize; ++i) {
- byte c = pakfile.readByte();
+ for (uint32 i = 0; i < size; ++i) {
+ byte c = stream.readByte();
if (c == '\\') {
temp = "";
} else if (c == 0x0D) {
// line endings are CRLF
- c = pakfile.readByte();
+ c = stream.readByte();
assert(c == 0x0A);
++i;
- FileEntry newEntry;
- newEntry._name = Common::hashit_lower(temp.c_str());
- newEntry._start = 0;
- newEntry._size = 0;
- _files.push_back(newEntry);
-
- temp = "";
+ filenames.push_back(temp);
} else {
temp += (char)c;
}
}
- pakfile.seek(3);
+ stream.seek(3, SEEK_SET);
- for (FileIterator start = _files.begin(); start != _files.end(); ++start) {
- filesize = pakfile.readUint32LE();
- start->_size = filesize;
- start->_start = pakfile.pos();
- pakfile.seek(filesize, SEEK_CUR);
- }
+ for (Common::List<Common::String>::iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ map.erase(*file);
- _filename = Common::hashit_lower(file);
- _physfile = file;
- _open = true;
-}
+ ResFileEntry entry;
+ entry.parent = filename;
+ entry.type = ResFileEntry::kAutoDetect;
+ entry.loadable = true;
+ entry.preload = false;
+ entry.prot = false;
+ entry.size = stream.readUint32LE();
+ entry.offset = stream.pos();
+ stream.seek(entry.size, SEEK_CUR);
-INSFile::~INSFile() {
- _open = false;
+ map[*file] = entry;
+ }
- _files.clear();
+ return true;
}
-uint8 *INSFile::getFile(uint hash) const {
- ConstFileIterator file = Common::find_if(_files.begin(), _files.end(), Common::bind2nd(Common::EqualTo<uint>(), hash));
- if (file == _files.end())
- return 0;
+Common::SeekableReadStream *ResLoaderIns::loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileMap &map) const {
+ assert(archive);
- Common::File pakfile;
- if (!pakfile.open(_physfile))
- return false;
+ ResFileMap::const_iterator entry = map.find(file);
+ if (entry == map.end())
+ return 0;
- pakfile.seek(file->_start);
- uint8 *buffer = new uint8[file->_size];
- assert(buffer);
- pakfile.read(buffer, file->_size);
- return buffer;
+ archive->seek(entry->_value.offset, SEEK_SET);
+ Common::SeekableSubReadStream *stream = new Common::SeekableSubReadStream(archive, entry->_value.offset, entry->_value.offset + entry->_value.size, true);
+ assert(stream);
+ return stream;
}
-bool INSFile::getFileHandle(uint hash, Common::File &filehandle) const {
- ConstFileIterator file = Common::find_if(_files.begin(), _files.end(), Common::bind2nd(Common::EqualTo<uint>(), hash));
-
- if (file == _files.end())
- return false;
-
- if (!filehandle.open(_physfile))
- return false;
-
- filehandle.seek(file->_start, SEEK_CUR);
- return true;
+void Resource::initializeLoaders() {
+ _loaders.push_back(new ResLoaderPak());
+ _loaders.push_back(new ResLoaderIns());
}
-uint32 INSFile::getFileSize(uint hash) const {
- ConstFileIterator file = Common::find_if(_files.begin(), _files.end(), Common::bind2nd(Common::EqualTo<uint>(), hash));
- return (file != _files.end()) ? file->_size : 0;
+const ResArchiveLoader *Resource::getLoader(ResFileEntry::kType type) const {
+ for (CLoaderIterator i = _loaders.begin(); i != _loaders.end(); ++i) {
+ if ((*i)->getType() == type)
+ return *i;
+ }
+ return 0;
}
} // end of namespace Kyra
diff --git a/engines/kyra/resource.h b/engines/kyra/resource.h
index c237051703..344e40fe68 100644
--- a/engines/kyra/resource.h
+++ b/engines/kyra/resource.h
@@ -31,84 +31,46 @@
#include "common/str.h"
#include "common/file.h"
#include "common/list.h"
+#include "common/hash-str.h"
+#include "common/hashmap.h"
+#include "common/stream.h"
#include "kyra/kyra.h"
namespace Kyra {
-class ResourceFile {
-public:
- ResourceFile() : _open(false), _protected(false), _filename() {}
- virtual ~ResourceFile() {}
-
- virtual uint8 *getFile(uint file) const = 0;
- virtual bool getFileHandle(uint file, Common::File &filehandle) const = 0;
- virtual uint32 getFileSize(uint file) const = 0;
-
- uint filename() const { return _filename; }
-
- virtual bool isValid(void) const { return (_filename != 0); }
- bool isOpen(void) const { return _open; }
-
- virtual void close() { if (!_protected) _open = false; }
- virtual void protect(const bool prot = true) { _protected = prot; }
- virtual void open() { _open = true; }
-protected:
- bool _open;
- bool _protected;
- uint _filename;
-};
+struct ResFileEntry {
+ Common::String parent;
+ uint32 size;
-// standard Package format for Kyrandia games
-class PAKFile : public ResourceFile {
- struct PakChunk {
- uint _name;
- uint32 _start;
- uint32 _size;
+ bool preload;
+ bool loadable;
+ bool prot;
- operator uint() const { return _name; }
+ enum kType {
+ kRaw = 0,
+ kPak = 1,
+ kIns = 2,
+ kAutoDetect
};
-
-public:
- PAKFile(const char *file, const char *physfile, Common::File &pakfile, bool isAmiga = false);
- ~PAKFile();
-
- uint8 *getFile(uint file) const;
- bool getFileHandle(uint file, Common::File &filehandle) const;
- uint32 getFileSize(uint file) const;
-private:
- bool openFile(Common::File &filehandle) const;
-
- Common::String _physfile;
- uint32 _physOffset;
-
- typedef Common::List<PakChunk>::iterator PakIterator;
- typedef Common::List<PakChunk>::const_iterator ConstPakIterator;
- Common::List<PakChunk> _files; // the entries
+ kType type;
+ uint32 offset;
};
-// installation file packages for (Kyra2/)Kyra3
-class INSFile : public ResourceFile {
- struct FileEntry {
- uint _name;
- uint32 _start;
- uint32 _size;
+typedef Common::HashMap<Common::String, ResFileEntry, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> ResFileMap;
+class Resource;
- operator uint() const { return _name; }
- };
+class ResArchiveLoader {
public:
- INSFile(const char *file);
- ~INSFile();
+ virtual ~ResArchiveLoader() {}
- uint8 *getFile(uint file) const;
- bool getFileHandle(uint file, Common::File &filehandle) const;
- uint32 getFileSize(uint file) const;
-protected:
- typedef Common::List<FileEntry>::iterator FileIterator;
- typedef Common::List<FileEntry>::const_iterator ConstFileIterator;
- Common::List<FileEntry> _files; // the entries
+ virtual bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const = 0;
+ virtual bool loadFile(const Common::String &filename, Common::SeekableReadStream &stream, ResFileMap &map) const = 0;
+ // parameter 'archive' can be deleted by this method and it may not be deleted from the caller
+ virtual Common::SeekableReadStream *loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileMap &map) const = 0;
- Common::String _physfile;
+ virtual ResFileEntry::kType getType() const = 0;
+protected:
};
class Resource {
@@ -129,18 +91,22 @@ public:
uint32 getFileSize(const char *file) const;
uint8* fileData(const char *file, uint32 *size) const;
- // gives back a file handle
- // it is possible that the needed file is embedded in the returned handle
- bool getFileHandle(const char *file, uint32 *size, Common::File &filehandle);
+ Common::SeekableReadStream *getFileStream(const Common::String &file) const;
bool loadFileToBuf(const char *file, void *buf, uint32 maxSize);
-
protected:
- typedef Common::List<ResourceFile*>::iterator ResIterator;
- typedef Common::List<ResourceFile*>::const_iterator ConstResIterator;
+ bool isAccessable(const Common::String &file) const;
+
+ void detectFileTypes();
+
+ void initializeLoaders();
+ const ResArchiveLoader *getLoader(ResFileEntry::kType type) const;
+ typedef Common::List<ResArchiveLoader*>::iterator LoaderIterator;
+ typedef Common::List<ResArchiveLoader*>::const_iterator CLoaderIterator;
+ Common::List<ResArchiveLoader*> _loaders;
+ ResFileMap _map;
KyraEngine *_vm;
- Common::List<ResourceFile*> _pakfiles;
};
// TODO?: maybe prefix all things here with 'kKyra1' instead of 'k'
diff --git a/engines/kyra/script.cpp b/engines/kyra/script.cpp
index 47c6391231..9f241c3d00 100644
--- a/engines/kyra/script.cpp
+++ b/engines/kyra/script.cpp
@@ -217,43 +217,44 @@ bool ScriptHelper::runScript(ScriptState *script) {
void ScriptFileParser::setFile(const char *filename, Resource *res) {
destroy();
- if (!res->getFileHandle(filename, &_endOffset, _scriptFile))
- return;
- _startOffset = _scriptFile.pos();
- _endOffset += _startOffset;
+ _stream = res->getFileStream(filename);
+ assert(_stream);
+ _startOffset = 0;
+ _endOffset = _stream->size();
}
void ScriptFileParser::destroy() {
- _scriptFile.close();
+ delete _stream;
+ _stream = 0;
_startOffset = _endOffset = 0;
}
uint32 ScriptFileParser::getFORMBlockSize() {
- uint32 oldOffset = _scriptFile.pos();
+ uint32 oldOffset = _stream->pos();
- uint32 data = _scriptFile.readUint32LE();
+ uint32 data = _stream->readUint32LE();
if (data != FORM_CHUNK) {
- _scriptFile.seek(oldOffset);
+ _stream->seek(oldOffset);
return (uint32)-1;
}
- data = _scriptFile.readUint32BE();
+ data = _stream->readUint32BE();
return data;
}
uint32 ScriptFileParser::getIFFBlockSize(const uint32 chunkName) {
uint32 size = (uint32)-1;
- _scriptFile.seek(_startOffset + 0x0C);
+ _stream->seek(_startOffset + 0x0C);
- while (_scriptFile.pos() < _endOffset) {
- uint32 chunk = _scriptFile.readUint32LE();
- uint32 size_temp = _scriptFile.readUint32BE();
+ while (_stream->pos() < _endOffset) {
+ uint32 chunk = _stream->readUint32LE();
+ uint32 size_temp = _stream->readUint32BE();
if (chunk != chunkName) {
- _scriptFile.seek((size_temp + 1) & (~1), SEEK_CUR);
- assert(_scriptFile.pos() <= _endOffset);
+ _stream->seek((size_temp + 1) & (~1), SEEK_CUR);
+ assert(_stream->pos() <= _endOffset);
} else {
size = size_temp;
break;
@@ -264,20 +265,20 @@ uint32 ScriptFileParser::getIFFBlockSize(const uint32 chunkName) {
}
bool ScriptFileParser::loadIFFBlock(const uint32 chunkName, void *loadTo, uint32 ptrSize) {
- _scriptFile.seek(_startOffset + 0x0C);
+ _stream->seek(_startOffset + 0x0C);
- while (_scriptFile.pos() < _endOffset) {
- uint32 chunk = _scriptFile.readUint32LE();
- uint32 chunkSize = _scriptFile.readUint32BE();
+ while (_stream->pos() < _endOffset) {
+ uint32 chunk = _stream->readUint32LE();
+ uint32 chunkSize = _stream->readUint32BE();
if (chunk != chunkName) {
- _scriptFile.seek((chunkSize + 1) & (~1), SEEK_CUR);
- assert(_scriptFile.pos() <= _endOffset);
+ _stream->seek((chunkSize + 1) & (~1), SEEK_CUR);
+ assert(_stream->pos() <= _endOffset);
} else {
uint32 loadSize = 0;
loadSize = MIN(ptrSize, chunkSize);
- _scriptFile.read(loadTo, loadSize);
+ _stream->read(loadTo, loadSize);
return true;
}
}
diff --git a/engines/kyra/script.h b/engines/kyra/script.h
index ce59d8ee29..47390e69bb 100644
--- a/engines/kyra/script.h
+++ b/engines/kyra/script.h
@@ -29,7 +29,7 @@
#include "kyra/kyra.h"
#include "kyra/util.h"
-#include "common/file.h"
+#include "common/stream.h"
namespace Kyra {
@@ -63,14 +63,14 @@ struct ScriptState {
class ScriptFileParser {
public:
- ScriptFileParser() : _scriptFile(), _startOffset(0), _endOffset(0) {}
- ScriptFileParser(const char *filename, Resource *res) : _scriptFile(), _startOffset(0), _endOffset(0) { setFile(filename, res); }
+ ScriptFileParser() : _stream(0), _startOffset(0), _endOffset(0) {}
+ ScriptFileParser(const char *filename, Resource *res) : _stream(0), _startOffset(0), _endOffset(0) { setFile(filename, res); }
~ScriptFileParser() { destroy(); }
// 'script' must be allocated with new!
void setFile(const char *filename, Resource *res);
- operator bool() const { return (_startOffset != _endOffset) && _scriptFile.isOpen(); }
+ operator bool() const { return (_startOffset != _endOffset) && _stream; }
uint32 getFORMBlockSize();
uint32 getIFFBlockSize(const uint32 chunk);
@@ -78,7 +78,7 @@ public:
private:
void destroy();
- Common::File _scriptFile;
+ Common::SeekableReadStream *_stream;
uint32 _startOffset;
uint32 _endOffset;
};
diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp
index c2ec98c904..a93a9ed66a 100644
--- a/engines/kyra/sound.cpp
+++ b/engines/kyra/sound.cpp
@@ -39,7 +39,7 @@
namespace Kyra {
Sound::Sound(KyraEngine *vm, Audio::Mixer *mixer)
- : _vm(vm), _mixer(mixer), _currentVocFile(0), _vocHandle(), _compressHandle(),
+ : _vm(vm), _mixer(mixer), _currentVocFile(0), _vocHandle(),
_musicEnabled(1), _sfxEnabled(true), _soundDataList(0) {
}
@@ -56,14 +56,10 @@ void Sound::voicePlay(const char *file) {
strcpy(filenamebuffer, file);
strcat(filenamebuffer, _supportedCodes[i].fileext);
- _compressHandle.close();
- _vm->resource()->getFileHandle(filenamebuffer, &fileSize, _compressHandle);
- if (!_compressHandle.isOpen())
+ Common::SeekableReadStream *stream = _vm->resource()->getFileStream(filenamebuffer);
+ if (!stream)
continue;
-
- Common::MemoryReadStream *tmp = _compressHandle.readStream(fileSize);
- assert(tmp);
- _currentVocFile = _supportedCodes[i].streamFunc(tmp, true, 0, 0, 1);
+ _currentVocFile = _supportedCodes[i].streamFunc(stream, true, 0, 0, 1);
found = true;
break;
}
diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h
index e8049a2e15..ea1eb738b3 100644
--- a/engines/kyra/sound.h
+++ b/engines/kyra/sound.h
@@ -192,7 +192,6 @@ private:
const AudioDataStruct *_soundDataList;
Audio::AudioStream *_currentVocFile;
Audio::SoundHandle _vocHandle;
- Common::File _compressHandle;
struct SpeechCodecs {
const char *fileext;