Hooked up the pathfinder so that it seems to work. Animation opcode 0x12.
[scummvm-innocent.git] / tools / md5table.c
blobf4aacb8e3128e96867adbcff0b60201b099da5d1
1 /* md5table - Convert a MD5 table to either PHP or C++ code
2 * Copyright (C) 2003-2006 The ScummVM Team
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * $URL$
19 * $Id$
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <time.h>
30 void error(const char *s, ...) {
31 char buf[1024];
32 va_list va;
34 va_start(va, s);
35 vsnprintf(buf, 1024, s, va);
36 va_end(va);
38 fprintf(stderr, "ERROR: %s!\n", buf);
40 exit(1);
43 void warning(const char *s, ...) {
44 char buf[1024];
45 va_list va;
47 va_start(va, s);
48 vsnprintf(buf, 1024, s, va);
49 va_end(va);
51 fprintf(stderr, "WARNING: %s!\n", buf);
54 typedef struct {
55 const char *key;
56 const char *value;
57 } StringMap;
59 typedef struct {
60 const char *md5;
61 const char *language;
62 const char *platform;
63 const char *variant;
64 const char *extra;
65 const char *size;
66 const char *desc;
67 const char *comments;
68 const char *infoSource;
69 } Entry;
71 /* Map MD5 table platform names to ScummVM constant names.
72 * Note: Currently not many constants are defined within ScummVM. However, more
73 * will probably be added eventually (see also commented out constants in
74 * common/util.h).
76 static const StringMap platformMap[] = {
77 { "3DO", "kPlatform3DO" },
78 { "Amiga", "kPlatformAmiga" },
79 { "Atari", "kPlatformAtariST" },
80 { "C64", "kPlatformC64" },
81 { "DOS", "kPlatformPC" },
82 { "FM-TOWNS", "kPlatformFMTowns" },
83 { "Mac", "kPlatformMacintosh" },
84 { "NES", "kPlatformNES" },
85 { "PC-Engine", "kPlatformPCEngine" },
86 { "SEGA", "kPlatformSegaCD" },
87 { "Windows", "kPlatformWindows" },
88 { "Wii", "kPlatformWii" },
90 { "All?", "kPlatformUnknown" },
91 { "All", "kPlatformUnknown" },
93 { 0, "kPlatformUnknown" }
96 static const StringMap langMap[] = {
97 { "en", "EN_ANY" },
98 { "us", "EN_USA" },
99 { "gb", "EN_GRB" },
100 { "de", "DE_DEU" },
101 { "fr", "FR_FRA" },
102 { "it", "IT_ITA" },
103 { "br", "PT_BRA" },
104 { "es", "ES_ESP" },
105 { "jp", "JA_JPN" },
106 { "zh", "ZH_TWN" },
107 { "ko", "KO_KOR" },
108 { "se", "SE_SWE" },
109 { "en", "EN_GRB" },
110 { "hb", "HB_ISR" },
111 { "ru", "RU_RUS" },
112 { "cz", "CZ_CZE" },
113 { "nl", "NL_NLD" },
114 { "nb", "NB_NOR" },
115 { "pl", "PL_POL" },
117 { "All", "UNK_LANG" },
118 { "All?", "UNK_LANG" },
120 { 0, "UNK_LANG" }
123 static const char *php_header =
124 "<!--\n"
125 " This file was generated by the md5table tool on %s"
126 " DO NOT EDIT MANUALLY!\n"
127 " -->\n"
128 "<?php\n"
129 "\n";
131 static const char *c_header =
132 "/*\n"
133 " This file was generated by the md5table tool on %s"
134 " DO NOT EDIT MANUALLY!\n"
135 " */\n"
136 "\n"
137 "struct MD5Table {\n"
138 " const char *md5;\n"
139 " const char *gameid;\n"
140 " const char *variant;\n"
141 " const char *extra;\n"
142 " int32 filesize;\n"
143 " Common::Language language;\n"
144 " Common::Platform platform;\n"
145 "};\n"
146 "\n"
147 "static const MD5Table md5table[] = {\n";
149 static const char *c_footer =
150 " { 0, 0, 0, 0, 0, Common::UNK_LANG, Common::kPlatformUnknown }\n"
151 "};\n";
153 static void parseEntry(Entry *entry, char *line) {
154 assert(entry);
155 assert(line);
157 /* Split at the tabs */
158 entry->md5 = strtok(line, "\t\n\r");
159 entry->size = strtok(NULL, "\t\n\r");
160 entry->language = strtok(NULL, "\t\n\r");
161 entry->platform = strtok(NULL, "\t\n\r");
162 entry->variant = strtok(NULL, "\t\n\r");
163 entry->extra = strtok(NULL, "\t\n\r");
164 entry->desc = strtok(NULL, "\t\n\r");
165 entry->infoSource = strtok(NULL, "\t\n\r");
168 static int isEmptyLine(const char *line) {
169 const char *whitespace = " \t\n\r";
170 while (*line) {
171 if (!strchr(whitespace, *line))
172 return 0;
173 line++;
175 return 1;
178 static const char *mapStr(const char *str, const StringMap *map) {
179 assert(str);
180 assert(map);
181 while (map->key) {
182 if (0 == strcmp(map->key, str))
183 return map->value;
184 map++;
186 warning("mapStr: unknown string '%s', defaulting to '%s'", str, map->value);
187 return map->value;
190 void showhelp(const char *exename)
192 printf("\nUsage: %s <params>\n", exename);
193 printf("\nParams:\n");
194 printf(" --c++ output C++ code for inclusion in ScummVM (default)\n");
195 printf(" --php output PHP code for the web site\n");
196 printf(" --txt output TXT file (should be identical to input file)\n");
197 exit(2);
200 /* needed to call from qsort */
201 int strcmp_wrapper(const void *s1, const void *s2)
203 return strcmp((const char *)s1, (const char *)s2);
206 int main(int argc, char *argv[])
208 FILE *inFile = stdin;
209 FILE *outFile = stdout;
210 char buffer[1024];
211 char section[256];
212 char gameid[32];
213 char *line;
214 int err;
215 int i;
216 time_t theTime;
217 const char *generationDate;
219 const int entrySize = 256;
220 int numEntries = 0, maxEntries = 1;
221 char *entriesBuffer = malloc(maxEntries * entrySize);
223 typedef enum {
224 kCPPOutput,
225 kPHPOutput,
226 kTXTOutput
227 } OutputMode;
229 OutputMode outputMode = kCPPOutput;
231 if (argc != 2)
232 showhelp(argv[0]);
233 if (strcmp(argv[1], "--c++") == 0) {
234 outputMode = kCPPOutput;
235 } else if (strcmp(argv[1], "--php") == 0) {
236 outputMode = kPHPOutput;
237 } else if (strcmp(argv[1], "--txt") == 0) {
238 outputMode = kTXTOutput;
239 } else {
240 showhelp(argv[0]);
243 time(&theTime);
244 generationDate = strdup(asctime(gmtime(&theTime)));
246 if (outputMode == kPHPOutput)
247 fprintf(outFile, php_header, generationDate);
249 section[0] = 0;
250 gameid[0] = 0;
251 while ((line = fgets(buffer, sizeof(buffer), inFile))) {
252 /* Parse line */
253 if (line[0] == '#' || isEmptyLine(line)) {
254 if (outputMode == kTXTOutput)
255 fprintf(outFile, "%s", line);
256 continue; /* Skip comments & empty lines */
258 if (line[0] == '\t') {
259 Entry entry;
260 assert(section[0]);
261 parseEntry(&entry, line+1);
262 if (outputMode == kPHPOutput) {
263 fprintf(outFile, "\taddEntry(");
265 // Print the description string
266 fprintf(outFile, "\"");
267 if (entry.extra && strcmp(entry.extra, "-")) {
268 fprintf(outFile, "%s", entry.extra);
269 if (entry.desc && strcmp(entry.desc, "-"))
270 fprintf(outFile, " (%s)", entry.desc);
272 fprintf(outFile, "\", ");
274 fprintf(outFile, "\"%s\", ", entry.platform);
275 fprintf(outFile, "\"%s\", ", entry.language);
276 fprintf(outFile, "\"%s\"", entry.md5);
277 if (entry.infoSource)
278 fprintf(outFile, ", \"%s\"", entry.infoSource);
279 fprintf(outFile, ");\n");
280 } else if (outputMode == kTXTOutput) {
281 fprintf(outFile, "\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
282 entry.md5,
283 entry.size,
284 entry.language,
285 entry.platform,
286 entry.variant,
287 entry.extra,
288 entry.desc,
289 entry.infoSource ? entry.infoSource : ""
291 } else if (entry.md5) {
292 if (numEntries >= maxEntries) {
293 maxEntries *= 2;
294 entriesBuffer = realloc(entriesBuffer, maxEntries * entrySize);
296 if (0 == strcmp(entry.variant, "-"))
297 entry.variant = "";
298 if (0 == strcmp(entry.extra, "-"))
299 entry.extra = "";
300 snprintf(entriesBuffer + numEntries * entrySize, entrySize,
301 "\t{ \"%s\", \"%s\", \"%s\", \"%s\", %s, Common::%s, Common::%s },\n",
302 entry.md5,
303 gameid,
304 entry.variant,
305 entry.extra,
306 entry.size,
307 mapStr(entry.language, langMap),
308 mapStr(entry.platform, platformMap));
309 numEntries++;
311 } else {
312 if (outputMode == kPHPOutput && gameid[0] != 0) {
313 // If there is an active section, close it now
314 fprintf(outFile, "endSection();\n");
316 // Read the gameid, followed by a tab
317 for (i = 0; *line && *line != '\t'; ++i)
318 gameid[i] = *line++;
319 assert(i > 0);
320 gameid[i] = 0;
321 assert(*line != 0);
322 line++;
324 // Read the section header (usually the full game name)
325 for (i = 0; *line && *line != '\n'; ++i)
326 section[i] = *line++;
327 assert(i > 0);
328 section[i] = 0;
330 // If in PHP or TXT mode, we write the output immediately
331 if (outputMode == kPHPOutput) {
332 fprintf(outFile, "beginSection(\"%s\", \"%s\");\n", section, gameid);
333 } else if (outputMode == kTXTOutput) {
334 fprintf(outFile, "%s\t%s\n", gameid, section);
339 err = ferror(inFile);
340 if (err)
341 error("Failed reading from input file, error %d", err);
343 if (outputMode == kPHPOutput) {
344 if (gameid[0] != 0) // If there is an active section, close it now
345 fprintf(outFile, "endSection();\n");
347 fprintf(outFile, "?>\n");
350 if (outputMode == kCPPOutput) {
351 /* Printf header */
352 fprintf(outFile, c_header, generationDate);
353 /* Now sort the MD5 table (this allows for binary searches) */
354 qsort(entriesBuffer, numEntries, entrySize, strcmp_wrapper);
355 /* Output the table and emit warnings if duplicate md5s are found */
356 buffer[0] = '\0';
357 for (i = 0; i < numEntries; ++i) {
358 const char *currentEntry = entriesBuffer + i * entrySize;
359 fprintf(outFile, "%s", currentEntry);
360 if (strncmp(currentEntry + 4, buffer, 32) == 0) {
361 warning("Duplicate MD5 found '%.32s'", buffer);
362 } else {
363 strncpy(buffer, currentEntry + 4, 32);
366 /* Finally, print the footer */
367 fprintf(outFile, "%s", c_footer);
370 free(entriesBuffer);
372 return 0;