diff options
-rw-r--r-- | dists/engine-data/kyra.dat | bin | 336898 -> 336508 bytes | |||
-rw-r--r-- | engines/kyra/staticres.cpp | 186 | ||||
-rw-r--r-- | tools/create_kyradat/create_kyradat.cpp | 234 |
3 files changed, 232 insertions, 188 deletions
diff --git a/dists/engine-data/kyra.dat b/dists/engine-data/kyra.dat Binary files differindex ed6cad0e9e..aacf17ee23 100644 --- a/dists/engine-data/kyra.dat +++ b/dists/engine-data/kyra.dat diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index 22cc60c003..d5ebd07dd1 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -45,7 +45,7 @@ namespace Kyra { -#define RESFILE_VERSION 64 +#define RESFILE_VERSION 65 namespace { bool checkKyraDat(Common::SeekableReadStream *file) { @@ -68,75 +68,86 @@ bool checkKyraDat(Common::SeekableReadStream *file) { 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 -// is less work than to change KYRA.DAT again -enum { - GF_FLOPPY = 1 << 0, - GF_TALKIE = 1 << 1, - GF_FMTOWNS = 1 << 2, - GF_DEMO = 1 << 3, - GF_ENGLISH = 1 << 4, - GF_FRENCH = 1 << 5, - GF_GERMAN = 1 << 6, - GF_SPANISH = 1 << 7, - GF_ITALIAN = 1 << 8, - GF_JAPANESE = 1 << 9, - // other languages here - GF_LNGUNK = 1 << 16, // also used for multi language in kyra3 - GF_AMIGA = 1 << 17 -}; - -#define GAME_FLAGS (GF_FLOPPY | GF_TALKIE | GF_DEMO | GF_FMTOWNS | GF_AMIGA) -#define LANGUAGE_FLAGS (GF_ENGLISH | GF_FRENCH | GF_GERMAN | GF_SPANISH | GF_ITALIAN | GF_JAPANESE | GF_LNGUNK) - -uint32 createFeatures(const GameFlags &flags) { - if (flags.isTalkie && flags.isDemo) - return GF_TALKIE | GF_DEMO; - if (flags.isTalkie) - return GF_TALKIE; - if (flags.isDemo) - return GF_DEMO; - if (flags.platform == Common::kPlatformFMTowns || flags.platform == Common::kPlatformPC98) - return GF_FMTOWNS; - if (flags.platform == Common::kPlatformAmiga) - return GF_AMIGA; - return GF_FLOPPY; -} - -uint32 createLanguage(const GameFlags &flags) { - if (flags.lang == Common::EN_ANY) - return GF_ENGLISH; - if (flags.lang == Common::DE_DEU) - return GF_GERMAN; - if (flags.lang == Common::FR_FRA) - return GF_FRENCH; - if (flags.lang == Common::ES_ESP) - return GF_SPANISH; - if (flags.lang == Common::IT_ITA) - return GF_ITALIAN; - if (flags.lang == Common::JA_JPN) - return GF_JAPANESE; - return GF_LNGUNK; -} struct LanguageTypes { - uint32 flags; + Common::Language lang; const char *ext; }; -static const LanguageTypes languages[] = { - { GF_ENGLISH, "ENG" }, // this is the default language - { GF_FRENCH, "FRE" }, - { GF_GERMAN, "GER" }, - { GF_SPANISH, "SPA" }, - { GF_ITALIAN, "ITA" }, - { GF_JAPANESE, "JPN" }, - { 0, 0 } +const LanguageTypes languages[] = { + { Common::EN_ANY, "ENG" }, + { Common::FR_FRA, "FRE" }, + { Common::DE_DEU, "GER" }, + { Common::ES_ESP, "SPA" }, + { Common::IT_ITA, "ITA" }, + { Common::JA_JPN, "JPN" }, + { Common::UNK_LANG, 0 } }; +struct IndexTable { + int type; + int value; + + bool operator==(int t) const { + return (type == t); + } +}; + +const IndexTable iGameTable[] = { + { GI_KYRA1, 0 }, + { GI_KYRA2, 1 }, + { GI_KYRA3, 2 }, + { GI_LOL, 3 }, + { -1, -1 } +}; + +byte getGameID(const GameFlags &flags) { + return Common::find(iGameTable, iGameTable + ARRAYSIZE(iGameTable) - 1, flags.gameID)->value; +} + +/*const IndexTable iLanguageTable[] = { + { Common::EN_ANY, 0 }, + { Common::FR_FRA, 1 }, + { Common::DE_DEU, 2 }, + { Common::ES_ESP, 3 }, + { Common::IT_ITA, 4 }, + { Common::JA_JPN, 5 }, + { -1, -1 } +}; + +byte getLanguageID(const GameFlags &flags) { + return Common::find(iLanguageTable, iLanguageTable + ARRAYSIZE(iLanguageTable) - 1, flags.lang)->value; +}*/ + +const IndexTable iPlatformTable[] = { + { Common::kPlatformPC, 0 }, + { Common::kPlatformAmiga, 1 }, + { Common::kPlatformFMTowns, 2 }, + { Common::kPlatformPC98, 3 }, + { Common::kPlatformMacintosh, 0 }, // HACK: Should be type "4", but as long as we can't extract Macintosh data, we need to use DOS data. + { -1, -1 } +}; + +byte getPlatformID(const GameFlags &flags) { + // HACK: Gross hack to support Kyra2 PC98, till there's data for it in kyra.dat + if (flags.gameID == GI_KYRA2 && flags.platform == Common::kPlatformPC98) + return 3; + return Common::find(iPlatformTable, iPlatformTable + ARRAYSIZE(iPlatformTable) - 1, flags.platform)->value; +} + +byte getSpecialID(const GameFlags &flags) { + if (flags.isDemo && flags.isTalkie) + return 3; + else if (flags.isDemo) + return 2; + else if (flags.isTalkie) + return 1; + else + return 0; +} + +} // end of anonymous namespace + bool StaticResource::loadStaticResourceFile() { Resource *res = _vm->resource(); @@ -178,30 +189,40 @@ bool StaticResource::loadStaticResourceFile() { } bool StaticResource::tryKyraDatLoad() { - Common::SeekableReadStream *index = getFile("INDEX"); + Common::SeekableReadStream *index = _vm->resource()->createReadStream("INDEX"); if (!index) return false; - if (index->size() != 3*4) { + const uint32 version = index->readUint32BE(); + + if (version != RESFILE_VERSION) { delete index; return false; } - uint32 version = index->readUint32BE(); - uint32 gameID = index->readUint32BE(); - uint32 featuresValue = index->readUint32BE(); + const uint32 includedGames = index->readUint32BE(); - delete index; - index = 0; - - if (version != RESFILE_VERSION) + if (includedGames * 2 + 8 != (uint32)index->size()) { + delete index; return false; + } - if (gameID != _vm->game()) - return false; + const uint16 gameDef = ((getGameID(_vm->gameFlags()) & 0xF) << 12) | + ((getPlatformID(_vm->gameFlags()) & 0xF) << 8) | + ((getSpecialID(_vm->gameFlags()) & 0xF) << 4); - uint32 gameFeatures = createFeatures(_vm->gameFlags()); - if ((featuresValue & GAME_FLAGS) != gameFeatures) + bool found = false; + for (uint32 i = 0; i < includedGames; ++i) { + if (index->readUint16BE() == gameDef) { + found = true; + break; + } + } + + delete index; + index = 0; + + if (!found) return false; // load all tables for now @@ -705,7 +726,7 @@ const void *StaticResource::getData(int id, int requesttype, int &size) { bool StaticResource::loadLanguageTable(const char *filename, void *&ptr, int &size) { static Common::String file; for (int i = 0; languages[i].ext; ++i) { - if (languages[i].flags != createLanguage(_vm->gameFlags())) + if (languages[i].lang != _vm->gameFlags().lang) continue; file = filename; @@ -714,17 +735,6 @@ bool StaticResource::loadLanguageTable(const char *filename, void *&ptr, int &si return true; } - file = filename; - file += languages[0].ext; - if (loadStringTable(file.c_str(), ptr, size)) { - static bool warned = false; - if (!warned) { - warned = true; - warning("couldn't find specific language table for your version, using English now"); - } - return true; - } - return false; } diff --git a/tools/create_kyradat/create_kyradat.cpp b/tools/create_kyradat/create_kyradat.cpp index b49472eedc..dbeadb51f0 100644 --- a/tools/create_kyradat/create_kyradat.cpp +++ b/tools/create_kyradat/create_kyradat.cpp @@ -38,10 +38,10 @@ #include <string> #include <map> +#include <algorithm> enum { - kKyraDatVersion = 64, - kIndexSize = 12 + kKyraDatVersion = 65 }; const ExtractFilename extractFilenames[] = { @@ -353,126 +353,160 @@ const PlatformExtension platformTable[] = { // index generation -enum { - GF_FLOPPY = 1 << 0, - GF_TALKIE = 1 << 1, - GF_FMTOWNS = 1 << 2, - GF_DEMO = 1 << 3, - GF_ENGLISH = 1 << 4, - GF_FRENCH = 1 << 5, - GF_GERMAN = 1 << 6, - GF_SPANISH = 1 << 7, - GF_ITALIAN = 1 << 8, - GF_JAPANESE = 1 << 9, - // ... - GF_LNGUNK = 1 << 16, - GF_AMIGA = 1 << 17 +struct IndexTable { + int type; + int value; + + bool operator==(int t) const { + return (type == t); + } }; -uint32 getFeatures(const Game *g) { - uint32 features = 0; - - if (g->special == kTalkieVersion) - features |= GF_TALKIE; - else if (g->special == kDemoVersion) - features |= GF_DEMO; - else if (g->special == kTalkieDemoVersion) - features |= (GF_DEMO | GF_TALKIE); - else if (g->platform == kPlatformFMTowns || g->platform == kPlatformPC98) // HACK - features |= GF_FMTOWNS; - else if (g->platform == kPlatformAmiga) - features |= GF_AMIGA; - else - features |= GF_FLOPPY; - - if (g->lang == EN_ANY) - features |= GF_ENGLISH; - else if (g->lang == DE_DEU) - features |= GF_GERMAN; - else if (g->lang == FR_FRA) - features |= GF_FRENCH; - else if (g->lang == ES_ESP) - features |= GF_SPANISH; - else if (g->lang == IT_ITA) - features |= GF_ITALIAN; - else if (g->lang == JA_JPN) - features |= GF_JAPANESE; - else - features |= GF_LNGUNK; - - return features; +const IndexTable iGameTable[] = { + { kKyra1, 0 }, + { kKyra2, 1 }, + { kKyra3, 2 }, + { kLol, 3 }, + { -1, -1 } +}; + +byte getGameID(int game) { + return std::find(iGameTable, iGameTable + ARRAYSIZE(iGameTable) - 1, game)->value; } -bool updateIndex(byte *dst, const int dstSize, const Game *g) { - if ((size_t)dstSize < kIndexSize) - return false; +/*const IndexTable iLanguageTable[] = { + { EN_ANY, 0 }, + { FR_FRA, 1 }, + { DE_DEU, 2 }, + { ES_ESP, 3 }, + { IT_ITA, 4 }, + { JA_JPN, 5 }, + { -1, -1 } +}; - WRITE_BE_UINT32(dst, kKyraDatVersion); dst += 4; - WRITE_BE_UINT32(dst, g->game); dst += 4; - uint32 features = READ_BE_UINT32(dst); - features |= getFeatures(g); - WRITE_BE_UINT32(dst, features); dst += 4; +byte getLanguageID(int lang) { + return std::find(iLanguageTable, iLanguageTable + ARRAYSIZE(iLanguageTable) - 1, lang)->value; +}*/ + +const IndexTable iPlatformTable[] = { + { kPlatformPC, 0 }, + { kPlatformAmiga, 1 }, + { kPlatformFMTowns, 2 }, + { kPlatformPC98, 3 }, + { kPlatformMacintosh, 4 }, + { -1, -1 } +}; - return true; +byte getPlatformID(int platform) { + return std::find(iPlatformTable, iPlatformTable + ARRAYSIZE(iPlatformTable) - 1, platform)->value; } -bool checkIndex(const byte *s, const int srcSize) { - if ((size_t)srcSize < sizeof(uint32)) - return false; - uint32 version = READ_BE_UINT32(s); - return (version == kKyraDatVersion); +const IndexTable iSpecialTable[] = { + { kNoSpecial, 0 }, + { kTalkieVersion, 1 }, + { kDemoVersion, 2 }, + { kTalkieDemoVersion, 3 }, + { -1, -1 } +}; + +byte getSpecialID(int special) { + return std::find(iSpecialTable, iSpecialTable + ARRAYSIZE(iSpecialTable) - 1, special)->value; } -bool updateIndex(PAKFile &out, const Game *g) { - char filename[32]; - ExtractInformation extractInfo; - extractInfo.game = g->game; - extractInfo.lang = -1; - extractInfo.platform = g->platform; - extractInfo.special = g->special; +typedef uint16 GameDef; - createFilename(filename, &extractInfo, "INDEX"); +GameDef createGameDef(const Game *g) { + return ((getGameID(g->game) & 0xF) << 12) | + ((getPlatformID(g->platform) & 0xF) << 8) | + ((getSpecialID(g->special) & 0xF) << 4); +} - byte *index = new byte[kIndexSize]; - assert(index); - memset(index, 0, kIndexSize); +struct Index { + Index() : version(0), includedGames(0), gameList() {} + + uint32 version; + uint32 includedGames; + + typedef std::list<GameDef> GameList; + GameList gameList; +}; +Index parseIndex(const uint8 *data, uint32 size) { + Index result; + + if (size < 8) + return result; + + result.version = READ_BE_UINT32(data); data += 4; + result.includedGames = READ_BE_UINT32(data); data += 4; + + if (result.includedGames * 2 + 8 != size) { + result.version = result.includedGames = 0; + return result; + } + + for (uint32 i = 0; i < result.includedGames; ++i) { + GameDef game = READ_BE_UINT16(data); data += 2; + result.gameList.push_back(game); + } + + return result; +} + +bool updateIndex(PAKFile &out, const Game *g) { uint32 size = 0; - const uint8 *data = out.getFileData(filename, &size); + const uint8 *data = out.getFileData("INDEX", &size); + + Index index; if (data) - memcpy(index, data, size); + index = parseIndex(data, size); - if (!updateIndex(index, kIndexSize, g)) { - delete[] index; - return false; + GameDef gameDef = createGameDef(g); + if (index.version == kKyraDatVersion) { + if (std::find(index.gameList.begin(), index.gameList.end(), gameDef) == index.gameList.end()) { + ++index.includedGames; + index.gameList.push_back(gameDef); + } + } else { + index.version = kKyraDatVersion; + index.includedGames = 1; + index.gameList.push_back(gameDef); + } + + const uint32 indexBufferSize = 8 + index.includedGames * 2; + uint8 *indexBuffer = new uint8[indexBufferSize]; + assert(indexBuffer); + uint8 *dst = indexBuffer; + WRITE_BE_UINT32(dst, index.version); dst += 4; + WRITE_BE_UINT32(dst, index.includedGames); dst += 4; + for (Index::GameList::const_iterator i = index.gameList.begin(); i != index.gameList.end(); ++i) { + WRITE_BE_UINT16(dst, *i); dst += 2; } - out.removeFile(filename); - if (!out.addFile(filename, index, kIndexSize)) { - fprintf(stderr, "ERROR: couldn't update %s file\n", filename); - delete[] index; + out.removeFile("INDEX"); + if (!out.addFile("INDEX", indexBuffer, indexBufferSize)) { + fprintf(stderr, "ERROR: couldn't update kyra.dat INDEX\n"); + delete[] indexBuffer; return false; } return true; } -bool checkIndex(PAKFile &out, const Game *g) { - char filename[32]; - ExtractInformation extractInfo; - extractInfo.game = g->game; - extractInfo.lang = -1; - extractInfo.platform = g->platform; - extractInfo.special = g->special; - - createFilename(filename, &extractInfo, "INDEX"); - +bool checkIndex(PAKFile &file) { uint32 size = 0; - const uint8 *data = out.getFileData(filename, &size); + const uint8 *data = file.getFileData("INDEX", &size); if (!data) - return true; + return false; - return checkIndex(data, size); + Index index = parseIndex(data, size); + + if (index.version != kKyraDatVersion) + return false; + if (index.includedGames * 2 + 8 != size) + return false; + + return true; } // main processing @@ -548,6 +582,11 @@ int main(int argc, char *argv[]) { PAKFile out; out.loadFile(argv[1], false); + // When the output file is no valid kyra.dat file, we will delete + // all the output. + if (!checkIndex(out)) + out.clearFile(); + MD5Map inputFiles = createMD5Sums(argc - 2, &argv[2]); GameMap games = createGameMap(inputFiles); @@ -1134,11 +1173,6 @@ bool process(PAKFile &out, const Game *g, const byte *data, const uint32 size) { extractInfo.platform = g->platform; extractInfo.special = g->special; - if (!checkIndex(out, g)) { - fprintf(stderr, "ERROR: corrupted INDEX file\n"); - return false; - } - Search search(data, size); IdMap ids; |