/* md5table - Convert a MD5 table to either PHP or C++ code * Copyright (C) 2003-2006 The ScummVM Team * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * $URL$ * $Id$ * */ #include #include #include #include #include #include void error(const char *s, ...) { char buf[1024]; va_list va; va_start(va, s); vsnprintf(buf, 1024, s, va); va_end(va); fprintf(stderr, "ERROR: %s!\n", buf); exit(1); } void warning(const char *s, ...) { char buf[1024]; va_list va; va_start(va, s); vsnprintf(buf, 1024, s, va); va_end(va); fprintf(stderr, "WARNING: %s!\n", buf); } typedef struct { const char *key; const char *value; } StringMap; typedef struct { const char *desc; const char *platform; const char *language; const char *md5; const char *gameid; const char *infoSource; } Entry; /* Map MD5 table platform names to ScummVM constant names. * Note: Currently not many constants are defined within ScummVM. However, more * will probably be added eventually (see also commented out constants in * common/util.h). */ static const StringMap platformMap[] = { { "3DO", "kPlatformUnknown" }, { "Amiga", "kPlatformAmiga" }, { "Atari", "kPlatformAtariST" }, { "C64", "kPlatformC64" }, { "DOS", "kPlatformPC" }, { "FM-TOWNS", "kPlatformFMTowns" }, { "Mac", "kPlatformMacintosh" }, { "NES", "kPlatformNES" }, { "SEGA", "kPlatformSegaCD" }, { "Windows", "kPlatformWindows" }, { "All?", "kPlatformUnknown" }, { "All", "kPlatformUnknown" }, { 0, "kPlatformUnknown" } }; static const StringMap langMap[] = { { "en", "EN_USA" }, { "de", "DE_DEU" }, { "fr", "FR_FRA" }, { "it", "IT_ITA" }, { "pt", "PT_BRA" }, { "es", "ES_ESP" }, { "jp", "JA_JPN" }, { "zh", "ZH_TWN" }, { "ko", "KO_KOR" }, { "se", "SE_SWE" }, { "en", "EN_GRB" }, { "hb", "HB_ISR" }, { "ru", "RU_RUS" }, { "cz", "CZ_CZE" }, { "nl", "NL_NLD" }, { "nb", "NB_NOR" }, { "pl", "PL_POL" }, { "All", "UNK_LANG" }, { "All?", "UNK_LANG" }, { 0, "UNK_LANG" } }; static const char *php_header = "\n" "\n"; static const char *c_header = "/*\n" " This file was generated by the md5table tool on %s" " DO NOT EDIT MANUALLY!\n" " */\n" "\n" "struct MD5Table {\n" " const char *md5;\n" " const char *gameid;\n" " Common::Language language;\n" " Common::Platform platform;\n" "};\n" "\n" "static const MD5Table md5table[] = {\n"; static const char *c_footer = " { 0, 0, Common::UNK_LANG, Common::kPlatformUnknown }\n" "};\n"; static void parseEntry(Entry *entry, char *line) { assert(entry); assert(line); /* Split at the tabs */ entry->desc = strtok(line, "\t\n\r"); entry->platform = strtok(NULL, "\t\n\r"); entry->language = strtok(NULL, "\t\n\r"); entry->md5 = strtok(NULL, "\t\n\r"); entry->gameid = strtok(NULL, "\t\n\r"); entry->infoSource = strtok(NULL, "\t\n\r"); } static int isEmptyLine(const char *line) { const char *whitespace = " \t\n\r"; while (*line) { if (!strchr(whitespace, *line)) return 0; line++; } return 1; } static const char *mapStr(const char *str, const StringMap *map) { assert(str); assert(map); while (map->key) { if (0 == strcmp(map->key, str)) return map->value; map++; } warning("mapStr: unknown string '%s', defaulting to '%s'", str, map->value); return map->value; } void showhelp(const char *exename) { printf("\nUsage: %s \n", exename); printf("\nParams:\n"); printf(" --c++ output C++ code for inclusion in ScummVM (default)\n"); printf(" --php output PHP code for the web site\n"); exit(2); } /* needed to call from qsort */ int strcmp_wrapper(const void *s1, const void *s2) { return strcmp((const char *)s1, (const char *)s2); } int main(int argc, char *argv[]) { FILE *inFile = stdin; FILE *outFile = stdout; char buffer[1024]; char section[1024]; char *line; int err; int i; time_t theTime; const char *generationDate; const int entrySize = 256; int numEntries = 0, maxEntries = 1; char *entriesBuffer = malloc(maxEntries * entrySize); int phpOutput = 0; if (argc != 2) showhelp(argv[0]); if (strcmp(argv[1], "--c++") == 0) { phpOutput = 0; } else if (strcmp(argv[1], "--php") == 0) { phpOutput = 1; } else { showhelp(argv[0]); } time(&theTime); generationDate = strdup(asctime(gmtime(&theTime))); if (phpOutput) fprintf(outFile, php_header, generationDate); while ((line = fgets(buffer, sizeof(buffer), inFile))) { /* Parse line */ if (line[0] == '#' || isEmptyLine(line)) continue; /* Skip comments & empty lines */ if (line[0] == '\t') { Entry entry; assert(section[0]); parseEntry(&entry, line+1); if (phpOutput) { fprintf(outFile, "\t\t\n"); } else if (entry.md5) { if (numEntries >= maxEntries) { maxEntries *= 2; entriesBuffer = realloc(entriesBuffer, maxEntries * entrySize); } snprintf(entriesBuffer + numEntries * entrySize, entrySize, "\t{ \"%s\", \"%s\", Common::%s, Common::%s },\n", entry.md5, entry.gameid, mapStr(entry.language, langMap), mapStr(entry.platform, platformMap)); numEntries++; } } else { for (i = 0; buffer[i] && buffer[i] != '\n'; ++i) section[i] = buffer[i]; section[i] = 0; if (phpOutput) { fprintf(outFile, "\t%s\n", section); } } } err = ferror(inFile); if (err) error("Failed reading from input file, error %d", err); if (!phpOutput) { /* Printf header */ fprintf(outFile, c_header, generationDate); /* Now sort the MD5 table (this allows for binary searches) */ qsort(entriesBuffer, numEntries, entrySize, strcmp_wrapper); /* Output the table and emit warnings if duplicate md5s are found */ buffer[0] = '\0'; for (i = 0; i < numEntries; ++i) { const char *currentEntry = entriesBuffer + i * entrySize; fprintf(outFile, currentEntry); if (strncmp(currentEntry + 4, buffer, 32) == 0) { warning("Duplicate MD5 found '%.32s'", buffer); } else { strncpy(buffer, currentEntry + 4, 32); } } /* Finally, print the footer */ fprintf(outFile, c_footer); } free(entriesBuffer); return 0; }