Check all 'kyra.dat' files in setup paths instead of only the first one found.

svn-id: r34735
This commit is contained in:
Johannes Schickel 2008-10-03 18:18:42 +00:00
parent e417471177
commit f3469eae94
6 changed files with 131 additions and 95 deletions

View file

@ -298,7 +298,8 @@ int KyraEngine_HoF::go() {
if (_menuChoice != 4) { if (_menuChoice != 4) {
// load just the pak files needed for ingame // load just the pak files needed for ingame
_res->loadPakFile(StaticResource::staticDataFilename()); _staticres->loadStaticResourceFile();
if (_flags.platform == Common::kPlatformPC && _flags.isTalkie) { if (_flags.platform == Common::kPlatformPC && _flags.isTalkie) {
if (!_res->loadFileList("FILEDATA.FDT")) if (!_res->loadFileList("FILEDATA.FDT"))
error("couldn't load 'FILEDATA.FDT'"); error("couldn't load 'FILEDATA.FDT'");

View file

@ -62,12 +62,6 @@ bool Resource::reset() {
if (!dir.exists() || !dir.isDirectory()) if (!dir.exists() || !dir.isDirectory())
error("invalid game path '%s'", dir.getPath().c_str()); error("invalid game path '%s'", dir.getPath().c_str());
if (!loadPakFile(StaticResource::staticDataFilename()) || !StaticResource::checkKyraDat(this)) {
Common::String errorMessage = "You're missing the '" + StaticResource::staticDataFilename() + "' file or it got corrupted, (re)get it from the ScummVM website";
GUIErrorMessage(errorMessage);
error(errorMessage.c_str());
}
if (_vm->game() == GI_KYRA1) { if (_vm->game() == GI_KYRA1) {
// We only need kyra.dat for the demo. // We only need kyra.dat for the demo.
if (_vm->gameFlags().isDemo) if (_vm->gameFlags().isDemo)
@ -276,16 +270,27 @@ Common::ArchivePtr Resource::loadArchive(const Common::String &file) {
if (cachedArchive != _archiveCache.end()) if (cachedArchive != _archiveCache.end())
return cachedArchive->_value; return cachedArchive->_value;
Common::SeekableReadStream *stream = getFileStream(file); Common::ArchiveMemberList list;
_files.listMatchingMembers(list, file);
if (list.empty())
return Common::ArchivePtr();
return loadArchive(file, *list.begin());
}
Common::ArchivePtr Resource::loadArchive(const Common::String &name, Common::SharedPtr<Common::ArchiveMember> member) {
Common::SeekableReadStream *stream = member->open();
if (!stream) if (!stream)
return Common::ArchivePtr(); return Common::ArchivePtr();
Common::ArchivePtr archive; Common::ArchivePtr archive;
for (LoaderList::const_iterator i = _loaders.begin(); i != _loaders.end(); ++i) { for (LoaderList::const_iterator i = _loaders.begin(); i != _loaders.end(); ++i) {
if ((*i)->checkFilename(file)) { if ((*i)->checkFilename(name)) {
if ((*i)->isLoadable(file, *stream)) { if ((*i)->isLoadable(name, *stream)) {
stream->seek(0, SEEK_SET); stream->seek(0, SEEK_SET);
archive = Common::ArchivePtr((*i)->load(this, file, *stream)); archive = Common::ArchivePtr((*i)->load(member, *stream));
break; break;
} else { } else {
stream->seek(0, SEEK_SET); stream->seek(0, SEEK_SET);
@ -298,7 +303,7 @@ Common::ArchivePtr Resource::loadArchive(const Common::String &file) {
if (!archive) if (!archive)
return Common::ArchivePtr(); return Common::ArchivePtr();
_archiveCache[file] = archive; _archiveCache[name] = archive;
return archive; return archive;
} }

View file

@ -40,6 +40,10 @@
#include "kyra/kyra_v1.h" #include "kyra/kyra_v1.h"
#include "kyra/kyra_hof.h" #include "kyra/kyra_hof.h"
namespace Common {
class ArchiveMember;
} // end of namespace Common
namespace Kyra { namespace Kyra {
class Resource; class Resource;
@ -47,6 +51,7 @@ class Resource;
class ResArchiveLoader; class ResArchiveLoader;
class Resource { class Resource {
friend class StaticResource;
public: public:
Resource(KyraEngine_v1 *vm); Resource(KyraEngine_v1 *vm);
~Resource(); ~Resource();
@ -77,6 +82,7 @@ protected:
Common::SharedPtr<Common::SearchSet> _protectedFiles; Common::SharedPtr<Common::SearchSet> _protectedFiles;
Common::ArchivePtr loadArchive(const Common::String &file); Common::ArchivePtr loadArchive(const Common::String &file);
Common::ArchivePtr loadArchive(const Common::String &name, Common::SharedPtr<Common::ArchiveMember> member);
Common::ArchivePtr loadInstallerArchive(const Common::String &file, const Common::String &ext, const uint8 offset); Common::ArchivePtr loadInstallerArchive(const Common::String &file, const Common::String &ext, const uint8 offset);
void initializeLoaders(); void initializeLoaders();
@ -207,12 +213,12 @@ struct Room;
class StaticResource { class StaticResource {
public: public:
static const Common::String staticDataFilename() { return "kyra.dat"; } static const Common::String staticDataFilename() { return "KYRA.DAT"; }
StaticResource(KyraEngine_v1 *vm) : _vm(vm), _resList(), _fileLoader(0), _builtIn(0), _filenameTable(0) {} StaticResource(KyraEngine_v1 *vm) : _vm(vm), _resList(), _fileLoader(0), _builtIn(0), _filenameTable(0) {}
~StaticResource() { deinit(); } ~StaticResource() { deinit(); }
static bool checkKyraDat(Resource *res); bool loadStaticResourceFile();
bool init(); bool init();
void deinit(); void deinit();
@ -233,7 +239,7 @@ public:
bool prefetchId(int id); bool prefetchId(int id);
void unloadId(int id); void unloadId(int id);
private: private:
void outputError(const Common::String &error); bool tryKyraDatLoad();
KyraEngine_v1 *_vm; KyraEngine_v1 *_vm;

View file

@ -35,8 +35,8 @@ namespace Kyra {
// -> PlainArchive implementation // -> PlainArchive implementation
PlainArchive::PlainArchive(Resource *owner, const Common::String &filename, const FileInputList &files) PlainArchive::PlainArchive(Common::SharedPtr<Common::ArchiveMember> file, const FileInputList &files)
: _owner(owner), _filename(filename), _files() { : _file(file), _files() {
for (FileInputList::iterator i = files.begin(); i != files.end(); ++i) { for (FileInputList::iterator i = files.begin(); i != files.end(); ++i) {
Entry entry; Entry entry;
@ -67,7 +67,7 @@ Common::SeekableReadStream *PlainArchive::openFile(const Common::String &name) {
if (fDesc == _files.end()) if (fDesc == _files.end())
return 0; return 0;
Common::SeekableReadStream *parent = _owner->getFileStream(_filename); Common::SeekableReadStream *parent = _file->open();
if (!parent) if (!parent)
return 0; return 0;
@ -195,7 +195,7 @@ struct PlainArchiveListSearch {
} // end of anonymous namespace } // end of anonymous namespace
Common::Archive *ResLoaderPak::load(Resource *owner, const Common::String &filename, Common::SeekableReadStream &stream) const { Common::Archive *ResLoaderPak::load(Common::SharedPtr<Common::ArchiveMember> memberFile, Common::SeekableReadStream &stream) const {
int32 filesize = stream.size(); int32 filesize = stream.size();
int32 startoffset = 0, endoffset = 0; int32 startoffset = 0, endoffset = 0;
@ -214,7 +214,7 @@ Common::Archive *ResLoaderPak::load(Resource *owner, const Common::String &filen
while (!stream.eos()) { while (!stream.eos()) {
// The start offset of a file should never be in the filelist // The start offset of a file should never be in the filelist
if (startoffset < stream.pos() || startoffset > filesize) { if (startoffset < stream.pos() || startoffset > filesize) {
warning("PAK file '%s' is corrupted", filename.c_str()); warning("PAK file '%s' is corrupted", memberFile->getName().c_str());
return false; return false;
} }
@ -225,14 +225,14 @@ Common::Archive *ResLoaderPak::load(Resource *owner, const Common::String &filen
file += c; file += c;
if (stream.eos()) { if (stream.eos()) {
warning("PAK file '%s' is corrupted", filename.c_str()); warning("PAK file '%s' is corrupted", memberFile->getName().c_str());
return false; return false;
} }
// Quit now if we encounter an empty string // Quit now if we encounter an empty string
if (file.empty()) { if (file.empty()) {
if (firstFile) { if (firstFile) {
warning("PAK file '%s' is corrupted", filename.c_str()); warning("PAK file '%s' is corrupted", memberFile->getName().c_str());
return false; return false;
} else { } else {
break; break;
@ -287,7 +287,7 @@ Common::Archive *ResLoaderPak::load(Resource *owner, const Common::String &filen
} }
} }
return new PlainArchive(owner, filename, files); return new PlainArchive(memberFile, files);
} }
// -> ResLoaderInsMalcolm implementation // -> ResLoaderInsMalcolm implementation
@ -313,7 +313,7 @@ bool ResLoaderInsMalcolm::isLoadable(const Common::String &filename, Common::See
return (buffer[0] == 0x0D && buffer[1] == 0x0A); return (buffer[0] == 0x0D && buffer[1] == 0x0A);
} }
Common::Archive *ResLoaderInsMalcolm::load(Resource *owner, const Common::String &filename, Common::SeekableReadStream &stream) const { Common::Archive *ResLoaderInsMalcolm::load(Common::SharedPtr<Common::ArchiveMember> memberFile, Common::SeekableReadStream &stream) const {
Common::List<Common::String> filenames; Common::List<Common::String> filenames;
PlainArchive::FileInputList files; PlainArchive::FileInputList files;
@ -353,7 +353,7 @@ Common::Archive *ResLoaderInsMalcolm::load(Resource *owner, const Common::String
files.push_back(entry); files.push_back(entry);
} }
return new PlainArchive(owner, filename, files); return new PlainArchive(memberFile, files);
} }
bool ResLoaderTlk::checkFilename(Common::String filename) const { bool ResLoaderTlk::checkFilename(Common::String filename) const {
@ -381,7 +381,7 @@ bool ResLoaderTlk::isLoadable(const Common::String &filename, Common::SeekableRe
return true; return true;
} }
Common::Archive *ResLoaderTlk::load(Resource *owner, const Common::String &filename, Common::SeekableReadStream &stream) const { Common::Archive *ResLoaderTlk::load(Common::SharedPtr<Common::ArchiveMember> file, Common::SeekableReadStream &stream) const {
uint16 entries = stream.readUint16LE(); uint16 entries = stream.readUint16LE();
PlainArchive::FileInputList files; PlainArchive::FileInputList files;
@ -405,7 +405,7 @@ Common::Archive *ResLoaderTlk::load(Resource *owner, const Common::String &filen
files.push_back(entry); files.push_back(entry);
} }
return new PlainArchive(owner, filename, files); return new PlainArchive(file, files);
} }
// InstallerLoader implementation // InstallerLoader implementation

View file

@ -47,7 +47,7 @@ public:
typedef Common::List<InputEntry> FileInputList; typedef Common::List<InputEntry> FileInputList;
PlainArchive(Resource *owner, const Common::String &filename, const FileInputList &files); PlainArchive(Common::SharedPtr<Common::ArchiveMember> file, const FileInputList &files);
bool hasFile(const Common::String &name); bool hasFile(const Common::String &name);
int listMembers(Common::ArchiveMemberList &list); int listMembers(Common::ArchiveMemberList &list);
@ -60,8 +60,7 @@ private:
typedef Common::HashMap<Common::String, Entry, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileMap; typedef Common::HashMap<Common::String, Entry, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileMap;
Resource *_owner; Common::SharedPtr<Common::ArchiveMember> _file;
Common::String _filename;
FileMap _files; FileMap _files;
}; };
@ -98,28 +97,28 @@ public:
virtual ~ResArchiveLoader() {} virtual ~ResArchiveLoader() {}
virtual bool checkFilename(Common::String filename) const = 0; virtual bool checkFilename(Common::String filename) const = 0;
virtual bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const = 0; virtual bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const = 0;
virtual Common::Archive *load(Resource *owner, const Common::String &filename, Common::SeekableReadStream &stream) const = 0; virtual Common::Archive *load(Common::SharedPtr<Common::ArchiveMember> file, Common::SeekableReadStream &stream) const = 0;
}; };
class ResLoaderPak : public ResArchiveLoader { class ResLoaderPak : public ResArchiveLoader {
public: public:
bool checkFilename(Common::String filename) const; bool checkFilename(Common::String filename) const;
bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const; bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const;
Common::Archive *load(Resource *owner, const Common::String &filename, Common::SeekableReadStream &stream) const; Common::Archive *load(Common::SharedPtr<Common::ArchiveMember> file, Common::SeekableReadStream &stream) const;
}; };
class ResLoaderInsMalcolm : public ResArchiveLoader { class ResLoaderInsMalcolm : public ResArchiveLoader {
public: public:
bool checkFilename(Common::String filename) const; bool checkFilename(Common::String filename) const;
bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const; bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const;
Common::Archive *load(Resource *owner, const Common::String &filename, Common::SeekableReadStream &stream) const; Common::Archive *load(Common::SharedPtr<Common::ArchiveMember> file, Common::SeekableReadStream &stream) const;
}; };
class ResLoaderTlk : public ResArchiveLoader { class ResLoaderTlk : public ResArchiveLoader {
public: public:
bool checkFilename(Common::String filename) const; bool checkFilename(Common::String filename) const;
bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const; bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const;
Common::Archive *load(Resource *owner, const Common::String &filename, Common::SeekableReadStream &stream) const; Common::Archive *load(Common::SharedPtr<Common::ArchiveMember> file, Common::SeekableReadStream &stream) const;
}; };
class InstallerLoader { class InstallerLoader {

View file

@ -45,20 +45,20 @@ namespace Kyra {
#define RESFILE_VERSION 32 #define RESFILE_VERSION 32
bool StaticResource::checkKyraDat(Resource *res) { namespace {
Common::SharedPtr<Common::SeekableReadStream> kyraDat(res->getFileStream(StaticResource::staticDataFilename())); bool checkKyraDat(Common::SeekableReadStream *file) {
if (!kyraDat) if (!file)
return false; return false;
uint32 size = kyraDat->size() - 16; uint32 size = file->size() - 16;
uint8 digest[16]; uint8 digest[16];
kyraDat->seek(size, SEEK_SET); file->seek(size, SEEK_SET);
if (kyraDat->read(digest, 16) != 16) if (file->read(digest, 16) != 16)
return false; return false;
uint8 digestCalc[16]; uint8 digestCalc[16];
kyraDat->seek(0, SEEK_SET); file->seek(0, SEEK_SET);
if (!Common::md5_file(*kyraDat, digestCalc, size)) if (!Common::md5_file(*file, digestCalc, size))
return false; return false;
for (int i = 0; i < 16; ++i) for (int i = 0; i < 16; ++i)
@ -66,6 +66,7 @@ bool StaticResource::checkKyraDat(Resource *res) {
return false; return false;
return true; return true;
} }
} // end of anonymous namespace
// used for the KYRA.DAT file which still uses // used for the KYRA.DAT file which still uses
// the old flag system, we just convert it, which // the old flag system, we just convert it, which
@ -132,6 +133,81 @@ static const LanguageTypes languages[] = {
{ 0, 0 } { 0, 0 }
}; };
bool StaticResource::loadStaticResourceFile() {
Resource *res = _vm->resource();
if (res->_archiveCache.find(staticDataFilename()) != res->_archiveCache.end())
return true;
Common::ArchiveMemberList kyraDatFiles;
res->_files.listMatchingMembers(kyraDatFiles, staticDataFilename());
bool foundWorkingKyraDat = false;
for (Common::ArchiveMemberList::iterator i = kyraDatFiles.begin(); i != kyraDatFiles.end(); ++i) {
Common::SeekableReadStream *file = (*i)->open();
if (checkKyraDat(file)) {
file->seek(0, SEEK_SET);
Common::ArchivePtr archive = res->loadArchive(staticDataFilename(), *i);
if (archive) {
res->_archiveFiles->add(staticDataFilename(), archive, 0);
foundWorkingKyraDat = tryKyraDatLoad();
}
}
delete file;
if (foundWorkingKyraDat)
break;
res->_archiveCache.erase(staticDataFilename());
res->_archiveFiles->remove(staticDataFilename());
unloadId(-1);
}
if (!foundWorkingKyraDat) {
Common::String errorMessage = "You're missing the '" + StaticResource::staticDataFilename() + "' file or it got corrupted, (re)get it from the ScummVM website";
GUIErrorMessage(errorMessage);
error(errorMessage.c_str());
}
return true;
}
bool StaticResource::tryKyraDatLoad() {
Common::SeekableReadStream *index = getFile("INDEX");
if (!index)
return false;
if (index->size() != 3*4) {
delete index;
return false;
}
uint32 version = index->readUint32BE();
uint32 gameID = index->readUint32BE();
uint32 featuresValue = index->readUint32BE();
delete index;
index = 0;
if (version != RESFILE_VERSION)
return false;
if (gameID != _vm->game())
return false;
uint32 gameFeatures = createFeatures(_vm->gameFlags());
if ((featuresValue & GAME_FLAGS) != gameFeatures)
return false;
// load all tables for now
if (!prefetchId(-1))
return false;
return true;
}
bool StaticResource::init() { bool StaticResource::init() {
#define proc(x) &StaticResource::x #define proc(x) &StaticResource::x
static const FileType fileTypeTable[] = { static const FileType fileTypeTable[] = {
@ -307,64 +383,13 @@ bool StaticResource::init() {
error("StaticResource: Unknown game ID"); error("StaticResource: Unknown game ID");
} }
char errorBuffer[100]; return loadStaticResourceFile();
Common::SeekableReadStream *index = getFile("INDEX");
if (!index) {
snprintf(errorBuffer, sizeof(errorBuffer), "is missing an '%s' entry", getFilename("INDEX"));
outputError(errorBuffer);
return false;
}
if (index->size() != 3*4) {
delete index;
snprintf(errorBuffer, sizeof(errorBuffer), "has incorrect header size for entry '%s'", getFilename("INDEX"));
outputError(errorBuffer);
return false;
}
uint32 version = index->readUint32BE();
uint32 gameID = index->readUint32BE();
uint32 featuresValue = index->readUint32BE();
delete index;
index = 0;
if (version != RESFILE_VERSION) {
snprintf(errorBuffer, sizeof(errorBuffer), "has invalid version %d required, you got %d", RESFILE_VERSION, version);
outputError(errorBuffer);
return false;
}
if (gameID != _vm->game()) {
outputError("does not include support for your game");
return false;
}
uint32 gameFeatures = createFeatures(_vm->gameFlags());
if ((featuresValue & GAME_FLAGS) != gameFeatures) {
outputError("does not include support for your game version");
return false;
}
// load all tables for now
if (!prefetchId(-1)) {
outputError("is lacking entries for your game version");
return false;
}
return true;
} }
void StaticResource::deinit() { void StaticResource::deinit() {
unloadId(-1); unloadId(-1);
} }
void StaticResource::outputError(const Common::String &error) {
Common::String errorMessage = "Your '" + StaticResource::staticDataFilename() + "' file " + error + ", reget a correct version from the ScummVM website";
GUIErrorMessage(errorMessage);
::error(errorMessage.c_str());
}
const char * const *StaticResource::loadStrings(int id, int &strings) { const char * const *StaticResource::loadStrings(int id, int &strings) {
const char * const*temp = (const char* const*)getData(id, kStringList, strings); const char * const*temp = (const char* const*)getData(id, kStringList, strings);
if (temp) if (temp)