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) {
// load just the pak files needed for ingame
_res->loadPakFile(StaticResource::staticDataFilename());
_staticres->loadStaticResourceFile();
if (_flags.platform == Common::kPlatformPC && _flags.isTalkie) {
if (!_res->loadFileList("FILEDATA.FDT"))
error("couldn't load 'FILEDATA.FDT'");

View File

@ -62,12 +62,6 @@ bool Resource::reset() {
if (!dir.exists() || !dir.isDirectory())
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) {
// We only need kyra.dat for the demo.
if (_vm->gameFlags().isDemo)
@ -276,16 +270,27 @@ Common::ArchivePtr Resource::loadArchive(const Common::String &file) {
if (cachedArchive != _archiveCache.end())
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)
return Common::ArchivePtr();
Common::ArchivePtr archive;
for (LoaderList::const_iterator i = _loaders.begin(); i != _loaders.end(); ++i) {
if ((*i)->checkFilename(file)) {
if ((*i)->isLoadable(file, *stream)) {
if ((*i)->checkFilename(name)) {
if ((*i)->isLoadable(name, *stream)) {
stream->seek(0, SEEK_SET);
archive = Common::ArchivePtr((*i)->load(this, file, *stream));
archive = Common::ArchivePtr((*i)->load(member, *stream));
break;
} else {
stream->seek(0, SEEK_SET);
@ -298,7 +303,7 @@ Common::ArchivePtr Resource::loadArchive(const Common::String &file) {
if (!archive)
return Common::ArchivePtr();
_archiveCache[file] = archive;
_archiveCache[name] = archive;
return archive;
}

View File

@ -40,6 +40,10 @@
#include "kyra/kyra_v1.h"
#include "kyra/kyra_hof.h"
namespace Common {
class ArchiveMember;
} // end of namespace Common
namespace Kyra {
class Resource;
@ -47,6 +51,7 @@ class Resource;
class ResArchiveLoader;
class Resource {
friend class StaticResource;
public:
Resource(KyraEngine_v1 *vm);
~Resource();
@ -77,6 +82,7 @@ protected:
Common::SharedPtr<Common::SearchSet> _protectedFiles;
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);
void initializeLoaders();
@ -207,12 +213,12 @@ struct Room;
class StaticResource {
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() { deinit(); }
static bool checkKyraDat(Resource *res);
bool loadStaticResourceFile();
bool init();
void deinit();
@ -233,7 +239,7 @@ public:
bool prefetchId(int id);
void unloadId(int id);
private:
void outputError(const Common::String &error);
bool tryKyraDatLoad();
KyraEngine_v1 *_vm;

View File

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

View File

@ -47,7 +47,7 @@ public:
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);
int listMembers(Common::ArchiveMemberList &list);
@ -60,8 +60,7 @@ private:
typedef Common::HashMap<Common::String, Entry, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileMap;
Resource *_owner;
Common::String _filename;
Common::SharedPtr<Common::ArchiveMember> _file;
FileMap _files;
};
@ -98,28 +97,28 @@ public:
virtual ~ResArchiveLoader() {}
virtual bool checkFilename(Common::String filename) 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 {
public:
bool checkFilename(Common::String filename) 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 {
public:
bool checkFilename(Common::String filename) 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 {
public:
bool checkFilename(Common::String filename) 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 {

View File

@ -45,20 +45,20 @@ namespace Kyra {
#define RESFILE_VERSION 32
bool StaticResource::checkKyraDat(Resource *res) {
Common::SharedPtr<Common::SeekableReadStream> kyraDat(res->getFileStream(StaticResource::staticDataFilename()));
if (!kyraDat)
namespace {
bool checkKyraDat(Common::SeekableReadStream *file) {
if (!file)
return false;
uint32 size = kyraDat->size() - 16;
uint32 size = file->size() - 16;
uint8 digest[16];
kyraDat->seek(size, SEEK_SET);
if (kyraDat->read(digest, 16) != 16)
file->seek(size, SEEK_SET);
if (file->read(digest, 16) != 16)
return false;
uint8 digestCalc[16];
kyraDat->seek(0, SEEK_SET);
if (!Common::md5_file(*kyraDat, digestCalc, size))
file->seek(0, SEEK_SET);
if (!Common::md5_file(*file, digestCalc, size))
return false;
for (int i = 0; i < 16; ++i)
@ -66,6 +66,7 @@ bool StaticResource::checkKyraDat(Resource *res) {
return false;
return true;
}
} // end of anonymous namespace
// used for the KYRA.DAT file which still uses
// the old flag system, we just convert it, which
@ -132,6 +133,81 @@ static const LanguageTypes languages[] = {
{ 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() {
#define proc(x) &StaticResource::x
static const FileType fileTypeTable[] = {
@ -307,65 +383,14 @@ bool StaticResource::init() {
error("StaticResource: Unknown game ID");
}
char errorBuffer[100];
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;
return loadStaticResourceFile();
}
void StaticResource::deinit() {
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);
if (temp)
return temp;