From ae0b605ad4c2b69f1e47e0d98c5cf3a881267318 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Thu, 7 Feb 2008 23:13:13 +0000 Subject: Reworked Kyrandia resource loading code. svn-id: r30820 --- engines/kyra/kyra_v3.cpp | 8 +- engines/kyra/resource.cpp | 566 +++++++++++++++++++++++----------------------- engines/kyra/resource.h | 108 +++------ engines/kyra/script.cpp | 45 ++-- engines/kyra/script.h | 10 +- engines/kyra/sound.cpp | 12 +- engines/kyra/sound.h | 1 - 7 files changed, 350 insertions(+), 400 deletions(-) (limited to 'engines/kyra') 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 { - 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 filenames; + Common::List 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::iterator entry = entries.begin(); + Common::List::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(), 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(), 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(), 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 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::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(), 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(), 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(), 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::iterator PakIterator; - typedef Common::List::const_iterator ConstPakIterator; - Common::List _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 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::iterator FileIterator; - typedef Common::List::const_iterator ConstFileIterator; - Common::List _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::iterator ResIterator; - typedef Common::List::const_iterator ConstResIterator; + bool isAccessable(const Common::String &file) const; + + void detectFileTypes(); + + void initializeLoaders(); + const ResArchiveLoader *getLoader(ResFileEntry::kType type) const; + typedef Common::List::iterator LoaderIterator; + typedef Common::List::const_iterator CLoaderIterator; + Common::List _loaders; + ResFileMap _map; KyraEngine *_vm; - Common::List _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; -- cgit v1.2.3