bool createIDMap(PAKFile &out, const ExtractInformation *eI, const int *needList) { int dataEntries = 0; // Count entries in the need list for (const int *n = needList; *n != -1; ++n) ++dataEntries; const int mapSize = 2 + dataEntries * (2 + 1 + 4); uint8 *map = new uint8[mapSize]; uint8 *dst = map; WRITE_BE_UINT16(dst, dataEntries); dst += 2; for (const int *id = needList; *id != -1; ++id) { WRITE_BE_UINT16(dst, *id); dst += 2; const ExtractFilename *fDesc = getFilenameDesc(*id); if (!fDesc) return false; *dst++ = getTypeID(fDesc->type); WRITE_BE_UINT32(dst, getFilename(eI, *id)); dst += 4; } char filename[12]; if (!getFilename(filename, eI, 0)) { fprintf(stderr, "ERROR: Could not create ID map for game\n"); return false; } out.removeFile(filename); if (!out.addFile(filename, map, mapSize)) { fprintf(stderr, "ERROR: Could not add ID map \"%s\" to kyra.dat\n", filename); return false; } return true; }
void ExtractKyra::execute() { Common::Filename inputpath(_inputPaths[0].path); Extractor *extract = 0; if (isHoFInstaller) { extract = new HoFInstaller(inputpath.getFullPath().c_str()); } else { PAKFile *myfile = new PAKFile; if (!myfile->loadFile(inputpath.getFullPath().c_str(), isAmiga)) { delete myfile; error("Couldn't load file '%s'", inputpath.getFullPath().c_str()); } extract = myfile; } // Everything has been decided, do the actual extraction if (extractAll) { extract->outputAllFiles(&_outputPath); } else if (extractOne) { inputpath.setFullName(singleFilename); extract->outputFileAs(singleFilename.c_str(), inputpath.getFullPath().c_str()); } else { extract->drawFileList(); } delete extract; }
bool createIDMap(PAKFile &out, const Game *g, const int *needList) { int dataEntries = 0; // Count entries in the need list and check whether the resources are // present for (const int *n = needList; *n != -1; ++n) { char filename[12]; if (!getFilename(filename, g, *n) || !out.getFileList()->findEntry(filename)) { fprintf(stderr, "ERROR: Could not find need %d for game %04X", *n, createGameDef(g)); return false; } ++dataEntries; } const int mapSize = 2 + dataEntries * (2 + 1 + 4); uint8 *map = new uint8[mapSize]; uint8 *dst = map; WRITE_BE_UINT16(dst, dataEntries); dst += 2; for (const int *id = needList; *id != -1; ++id) { WRITE_BE_UINT16(dst, *id); dst += 2; const ExtractFilename *fDesc = getFilenameDesc(*id); if (!fDesc) { delete[] map; return false; } *dst++ = fDesc->type; WRITE_BE_UINT32(dst, getFilename(g, *id)); dst += 4; } char filename[12]; if (!getFilename(filename, g, 0)) { fprintf(stderr, "ERROR: Could not create ID map for game\n"); delete[] map; return false; } if (!out.addFile(filename, map, mapSize)) { fprintf(stderr, "ERROR: Could not add ID map \"%s\" to kyra.dat\n", filename); delete[] map; return false; } return true; }
int main(int argc, char *argv[]) { if (argc != 2) { printHelp(argv[0]); return -1; } PAKFile out; // First step: Write out all resources. outputAllResources(out); // Second step: Write all game version information std::vector<GameDef> games; outputAllGames(out, games); // Third step: Write index file byte *const indexBuffer = new byte[8 + 2 * games.size()]; byte *dst = indexBuffer; WRITE_BE_UINT32(dst, kKyraDatVersion); dst += 4; WRITE_BE_UINT32(dst, games.size()); dst += 4; for (std::vector<GameDef>::const_iterator i = games.begin(), end = games.end(); i != end; ++i) { WRITE_BE_UINT16(dst, *i); dst += 2; } if (!out.addFile("INDEX", indexBuffer, 8 + 2 * games.size())) { error("couldn't write INDEX file"); } if (!out.saveFile(argv[1])) { error("couldn't save changes to '%s'", argv[1]); } uint8 digest[16]; if (!md5_file(argv[1], digest, 0)) error("couldn't calc. md5 for file '%s'", argv[1]); FILE *f = fopen(argv[1], "ab"); if (!f) error("couldn't open file '%s'", argv[1]); if (fwrite(digest, 1, 16, f) != 16) error("couldn't write md5sum to file '%s'", argv[1]); fclose(f); return 0; }
bool updateIndex(PAKFile &out, const ExtractInformation *eI) { uint32 size = 0; const uint8 *data = out.getFileData("INDEX", &size); Index index; if (data) index = parseIndex(data, size); GameDef gameDef = createGameDef(eI); 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 { // Already included in the game list, thus we do not need any further processing here. return true; } } 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("INDEX"); if (!out.addFile("INDEX", indexBuffer, indexBufferSize)) { fprintf(stderr, "ERROR: couldn't update kyra.dat INDEX\n"); delete[] indexBuffer; return false; } return true; }
void build_tree( void ) { clear_tree( ); GtkTree* tree = GTK_TREE( context.tree ); PAKFile* pak = context.pak; PAKTree& pak_tree = pak->getTree( ); PAKTreeNode& root = pak_tree.getRoot( ); // Construct the special root node. // GtkWidget* item = gtk_tree_item_new_with_label( const_cast<char*>( pak->getPakName( ) ) ); GtkWidget* item = gtk_tree_item_new_with_label( context.pak_filename ); gtk_signal_connect( GTK_OBJECT( item ), "select", GTK_SIGNAL_FUNC( tree_item_selected ), NULL ); gtk_tree_append( tree, item ); gtk_widget_show( item ); GtkWidget* root_tree = gtk_tree_new( ); gtk_tree_item_set_subtree( GTK_TREE_ITEM( item ), root_tree ); add_children_to_tree( GTK_TREE( root_tree ), root ); }
bool checkIndex(PAKFile &file) { uint32 size = 0; const uint8 *data = file.getFileData("INDEX", &size); if (!data) return false; Index index = parseIndex(data, size); if (index.version != kKyraDatVersion) return false; if (index.includedGames * 2 + 8 != size) return false; return true; }
int main(int argc, char *argv[]) { if (argc < 3) { printHelp(argv[0]); return -1; } // Special case for developer mode of this tool: // With "--create filename offset size" the tool will output // a search entry for the specifed data in the specified file. if (!strcmp(argv[1], "--create")) { if (argc < 5) { printf("Developer usage: %s --create input_file hex_offset hex_size\n", argv[0]); return -1; } uint32 offset, size; sscanf(argv[3], "%x", &offset); sscanf(argv[4], "%x", &size); FILE *input = fopen(argv[2], "rb"); if (!input) error("Couldn't open file '%s'", argv[2]); byte *buffer = new byte[size]; fseek(input, offset, SEEK_SET); if (fread(buffer, 1, size, input) != size) { delete[] buffer; error("Couldn't read from file '%s'", argv[2]); } fclose(input); SearchData d = SearchCreator::create(buffer, size); delete[] buffer; printf("{ 0x%.08X, 0x%.08X, { {", d.size, d.byteSum); for (int j = 0; j < 16; ++j) { printf(" 0x%.2X", d.hash.digest[j]); if (j != 15) printf(","); else printf(" } } }\n"); } return 0; } 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); // Check for unused input files MD5Map unusedFiles = inputFiles; for (GameMap::const_iterator i = games.begin(); i != games.end(); ++i) { unusedFiles.erase(i->first->md5[0]); if (i->first->md5[1]) unusedFiles.erase(i->first->md5[1]); } for (MD5Map::const_iterator i = unusedFiles.begin(); i != unusedFiles.end(); ++i) printf("Input file '%s' with md5 sum '%s' is not known.\n", i->second.c_str(), i->first.c_str()); unusedFiles.clear(); // Short circuit, in case no games are found. if (games.empty()) { printf("No games found. Exiting prematurely\n"); return -1; } // Process all games found for (GameMap::const_iterator i = games.begin(); i != games.end(); ++i) { MD5Map::const_iterator f1 = inputFiles.find(i->first->md5[0]); MD5Map::const_iterator f2 = inputFiles.end(); if (i->first->md5[1]) f2 = inputFiles.find(i->first->md5[1]); if (f2 != inputFiles.end()) printf("Processing files '%s' and '%s'...\n", f1->second.c_str(), f2->second.c_str()); else printf("Processing file '%s'...\n", f1->second.c_str()); if (!process(out, i->first, i->second.data, i->second.size)) printf("FAILED\n"); else printf("OK\n"); } // Free up memory for (GameMap::iterator i = games.begin(); i != games.end(); ++i) delete[] i->second.data; games.clear(); inputFiles.clear(); if (!out.saveFile(argv[1])) error("couldn't save changes to '%s'", argv[1]); uint8 digest[16]; if (!md5_file(argv[1], digest, 0)) error("couldn't calc. md5 for file '%s'", argv[1]); FILE *f = fopen(argv[1], "ab"); if (!f) error("couldn't open file '%s'", argv[1]); if (fwrite(digest, 1, 16, f) != 16) error("couldn't write md5sum to file '%s'", argv[1]); fclose(f); return 0; }
bool process(PAKFile &out, const Game *g, const byte *data, const uint32 size) { char filename[128]; Search search(data, size); ExtractMap ids; if (!getExtractionData(g, search, ids)) return false; const int *needList = getNeedList(g); if (!needList) { fprintf(stderr, "ERROR: No entry need list available\n"); return false; } ExtractInformation extractInfo; extractInfo.game = g->game; extractInfo.platform = g->platform; extractInfo.special = g->special; for (ExtractMap::const_iterator i = ids.begin(); i != ids.end(); ++i) { const int id = i->first; extractInfo.lang = i->second.desc.lang; const ExtractFilename *fDesc = getFilenameDesc(id); if (!fDesc) { fprintf(stderr, "ERROR: couldn't find file description for id %d/%s\n", id, getIdString(id)); return false; } filename[0] = 0; if (!getFilename(filename, &extractInfo, id)) { fprintf(stderr, "ERROR: couldn't get filename for id %d/%s\n", id, getIdString(id)); return false; } const ExtractType *tDesc = findExtractType(fDesc->type); if (!tDesc) { fprintf(stderr, "ERROR: couldn't find type description for id %d/%s (%d)\n", id, getIdString(id), fDesc->type); return false; } PAKFile::cFileList *list = out.getFileList(); if (list && list->findEntry(filename) != 0) continue; if (!tDesc->extract(out, &extractInfo, data + i->second.offset, i->second.desc.hint.size, filename, id)) { fprintf(stderr, "ERROR: couldn't extract id %d/%s\n", id, getIdString(id)); return false; } } for (int i = 0; i < 3; ++i) { if (g->lang[i] == -1) continue; extractInfo.lang = g->lang[i]; if (!createIDMap(out, &extractInfo, needList)) return false; if (!updateIndex(out, &extractInfo)) { error("couldn't update INDEX file, stop processing of all files"); return false; } } return true; }