Rev 3711 | Rev 3803 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1652 | terminx | 1 | //------------------------------------------------------------------------- |
2 | /* |
||
3 | Copyright (C) 2010 EDuke32 developers and contributors |
||
4 | |||
5 | This file is part of EDuke32. |
||
6 | |||
7 | EDuke32 is free software; you can redistribute it and/or |
||
8 | modify it under the terms of the GNU General Public License version 2 |
||
9 | as published by the Free Software Foundation. |
||
10 | |||
11 | This program is distributed in the hope that it will be useful, |
||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
||
14 | |||
15 | See the GNU General Public License for more details. |
||
16 | |||
17 | You should have received a copy of the GNU General Public License |
||
18 | along with this program; if not, write to the Free Software |
||
19 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||
20 | */ |
||
21 | //------------------------------------------------------------------------- |
||
22 | |||
241 | terminx | 23 | #include "compat.h" |
24 | #include "baselayer.h" |
||
25 | |||
26 | #include "scriptfile.h" |
||
27 | #include "cache1d.h" |
||
28 | #include "crc32.h" |
||
29 | |||
30 | #include "duke3d.h" |
||
2726 | hendricks2 | 31 | #include "common_game.h" |
241 | terminx | 32 | #include "grpscan.h" |
33 | |||
3708 | terminx | 34 | // custom GRP support for the startup window, file format reflects the structure below |
35 | #define GAMELISTFILE "games.list" |
||
36 | // name crc size flags dependency scriptname defname |
||
37 | struct grpfile internalgrpfiles[NUMGRPFILES] = |
||
559 | terminx | 38 | { |
3708 | terminx | 39 | { "Duke Nukem 3D", DUKE13_CRC, 26524524, GAMEFLAG_DUKE, 0, NULL, NULL, NULL }, |
40 | { "Duke Nukem 3D (South Korean Censored)", DUKEKR_CRC, 26385383, GAMEFLAG_DUKE, 0, NULL, NULL, NULL }, |
||
41 | { "Duke Nukem 3D: Atomic Edition", DUKE15_CRC, 44356548, GAMEFLAG_DUKE, 0, NULL, NULL, NULL }, |
||
42 | { "Duke Nukem 3D: Plutonium Pak", DUKEPP_CRC, 44348015, GAMEFLAG_DUKE, 0, NULL, NULL, NULL }, |
||
43 | { "Duke Nukem 3D Shareware", DUKESW_CRC, 11035779, GAMEFLAG_DUKE, 0, NULL, NULL, NULL }, |
||
44 | { "Duke Nukem 3D Mac Demo", DUKEMD_CRC, 10444391, GAMEFLAG_DUKE, 0, NULL, NULL, NULL }, |
||
45 | { "Duke it out in D.C.", DUKEDC_CRC, 8410183 , GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, NULL, NULL, NULL }, |
||
46 | { "Duke Caribbean: Life's a Beach", DUKECB_CRC, 22213819, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, NULL, NULL, NULL }, |
||
47 | { "Duke: Nuclear Winter", DUKENW_CRC, 16169365, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, "nwinter.con", NULL, NULL }, |
||
48 | { "NAM", NAM_CRC, 43448927, GAMEFLAG_NAM, 0, "nam.con", "nam.def", NULL }, |
||
49 | { "NAPALM", NAPALM_CRC, 44365728, GAMEFLAG_NAM|GAMEFLAG_NAPALM, 0, "napalm.con", "nam.def", NULL }, |
||
50 | { "WWII GI", WW2GI_CRC, 77939508, GAMEFLAG_WW2GI|GAMEFLAG_NAM, 0, "ww2gi.con", "ww2gi.def", NULL }, |
||
559 | terminx | 51 | }; |
241 | terminx | 52 | struct grpfile *foundgrps = NULL; |
3708 | terminx | 53 | struct grpfile *listgrps = NULL; |
241 | terminx | 54 | |
3708 | terminx | 55 | static void LoadList(const char * filename) |
56 | { |
||
57 | struct grpfile *fg; |
||
58 | |||
59 | char *grpend = NULL; |
||
60 | |||
61 | scriptfile *script = scriptfile_fromfile(filename); |
||
62 | |||
63 | if (!script) |
||
64 | return; |
||
65 | |||
66 | scriptfile_addsymbolvalue("GAMEFLAG_DUKE", GAMEFLAG_DUKE); |
||
67 | scriptfile_addsymbolvalue("GAMEFLAG_ADDON", GAMEFLAG_DUKE|GAMEFLAG_ADDON); |
||
68 | scriptfile_addsymbolvalue("DUKE15_CRC", DUKE15_CRC); |
||
69 | scriptfile_addsymbolvalue("DUKE13_CRC", DUKE13_CRC); |
||
70 | scriptfile_addsymbolvalue("DUKEDC_CRC", DUKEDC_CRC); |
||
71 | scriptfile_addsymbolvalue("DUKECB_CRC", DUKECB_CRC); |
||
72 | scriptfile_addsymbolvalue("DUKENW_CRC", DUKENW_CRC); |
||
73 | |||
3711 | helixhorne | 74 | while (!scriptfile_eof(script)) |
3708 | terminx | 75 | { |
3711 | helixhorne | 76 | enum |
77 | { |
||
78 | T_GRPINFO, |
||
79 | T_GAMENAME, |
||
80 | T_CRC, |
||
81 | T_SIZE, |
||
82 | T_DEPCRC, |
||
83 | T_SCRIPTNAME, |
||
84 | T_DEFNAME, |
||
85 | T_FLAGS, |
||
86 | }; |
||
3708 | terminx | 87 | |
3711 | helixhorne | 88 | static const tokenlist profiletokens[] = |
89 | { |
||
90 | { "grpinfo", T_GRPINFO }, |
||
91 | }; |
||
3708 | terminx | 92 | |
93 | int32_t token = getatoken(script,profiletokens,sizeof(profiletokens)/sizeof(tokenlist)); |
||
94 | switch (token) |
||
95 | { |
||
96 | case T_GRPINFO: |
||
3711 | helixhorne | 97 | { |
98 | int32_t gsize = 0, gcrcval = 0, gflags = GAMEFLAG_DUKE, gdepcrc = DUKE15_CRC; |
||
99 | char *gname = NULL, *gscript = NULL, *gdef = NULL; |
||
100 | |||
101 | static const tokenlist grpinfotokens[] = |
||
3708 | terminx | 102 | { |
3711 | helixhorne | 103 | { "name", T_GAMENAME }, |
104 | { "scriptname", T_SCRIPTNAME }, |
||
105 | { "defname", T_DEFNAME }, |
||
106 | { "crc", T_CRC }, |
||
107 | { "dependency", T_DEPCRC }, |
||
108 | { "size", T_SIZE }, |
||
109 | { "flags", T_FLAGS }, |
||
3708 | terminx | 110 | |
3711 | helixhorne | 111 | }; |
3708 | terminx | 112 | |
3711 | helixhorne | 113 | if (scriptfile_getbraces(script,&grpend)) break; |
3708 | terminx | 114 | |
3711 | helixhorne | 115 | while (script->textptr < grpend) |
116 | { |
||
117 | int32_t token = getatoken(script,grpinfotokens,sizeof(grpinfotokens)/sizeof(tokenlist)); |
||
3708 | terminx | 118 | |
3711 | helixhorne | 119 | switch (token) |
3708 | terminx | 120 | { |
3711 | helixhorne | 121 | case T_GAMENAME: |
122 | scriptfile_getstring(script,&gname); break; |
||
123 | case T_SCRIPTNAME: |
||
124 | scriptfile_getstring(script,&gscript); break; |
||
125 | case T_DEFNAME: |
||
126 | scriptfile_getstring(script,&gdef); break; |
||
3708 | terminx | 127 | |
3711 | helixhorne | 128 | case T_FLAGS: |
129 | scriptfile_getsymbol(script,&gflags); break; |
||
130 | case T_DEPCRC: |
||
131 | scriptfile_getsymbol(script,&gdepcrc); break; |
||
132 | case T_CRC: |
||
133 | scriptfile_getsymbol(script,&gcrcval); break; |
||
134 | case T_SIZE: |
||
135 | scriptfile_getnumber(script,&gsize); break; |
||
136 | default: |
||
137 | break; |
||
138 | } |
||
3708 | terminx | 139 | |
3711 | helixhorne | 140 | fg = (struct grpfile *)Bcalloc(1, sizeof(struct grpfile)); |
141 | fg->next = listgrps; |
||
142 | listgrps = fg; |
||
3708 | terminx | 143 | |
3711 | helixhorne | 144 | if (gname) |
145 | fg->name = Bstrdup(gname); |
||
3708 | terminx | 146 | |
3711 | helixhorne | 147 | fg->size = gsize; |
148 | fg->crcval = gcrcval; |
||
149 | fg->dependency = gdepcrc; |
||
150 | fg->game = gflags; |
||
3708 | terminx | 151 | |
3711 | helixhorne | 152 | if (gscript) |
153 | fg->scriptname = dup_filename(gscript); |
||
3708 | terminx | 154 | |
3711 | helixhorne | 155 | if (gdef) |
156 | fg->defname = dup_filename(gdef); |
||
3708 | terminx | 157 | } |
3711 | helixhorne | 158 | break; |
159 | } |
||
3708 | terminx | 160 | |
161 | default: |
||
162 | break; |
||
163 | } |
||
164 | } |
||
165 | |||
166 | scriptfile_close(script); |
||
167 | scriptfile_clearsymbols(); |
||
168 | } |
||
169 | |||
170 | static void LoadGameList(void) |
||
171 | { |
||
172 | struct grpfile *fg; |
||
173 | CACHE1D_FIND_REC *srch, *sidx; |
||
174 | |||
175 | int32_t i; |
||
176 | |||
177 | for (i = 0; i<NUMGRPFILES; i++) |
||
178 | { |
||
179 | fg = (struct grpfile *)Bcalloc(1, sizeof(struct grpfile)); |
||
180 | |||
181 | fg->name = Bstrdup(internalgrpfiles[i].name); |
||
182 | fg->crcval = internalgrpfiles[i].crcval; |
||
183 | fg->size = internalgrpfiles[i].size; |
||
184 | fg->game = internalgrpfiles[i].game; |
||
185 | fg->dependency = internalgrpfiles[i].dependency; |
||
186 | |||
187 | if (internalgrpfiles[i].scriptname) |
||
188 | fg->scriptname = dup_filename(internalgrpfiles[i].scriptname); |
||
189 | |||
190 | if (internalgrpfiles[i].defname) |
||
191 | fg->defname = dup_filename(internalgrpfiles[i].defname); |
||
192 | |||
193 | fg->next = listgrps; |
||
194 | listgrps = fg; |
||
195 | } |
||
196 | |||
197 | srch = klistpath("/", "*.grpinfo", CACHE1D_FIND_FILE); |
||
198 | |||
199 | for (sidx = srch; sidx; sidx = sidx->next) |
||
200 | LoadList(srch->name); |
||
201 | |||
202 | klistfree(srch); |
||
203 | } |
||
204 | |||
205 | static void FreeGameList(void) |
||
206 | { |
||
207 | struct grpfile *fg; |
||
208 | |||
209 | while (listgrps) |
||
210 | { |
||
211 | fg = listgrps->next; |
||
212 | Bfree(listgrps->name); |
||
213 | |||
214 | if (listgrps->scriptname) |
||
215 | Bfree(listgrps->scriptname); |
||
216 | |||
217 | if (listgrps->defname) |
||
218 | Bfree(listgrps->defname); |
||
219 | |||
220 | Bfree(listgrps); |
||
221 | listgrps = fg; |
||
222 | } |
||
223 | } |
||
224 | |||
225 | |||
241 | terminx | 226 | #define GRPCACHEFILE "grpfiles.cache" |
335 | terminx | 227 | static struct grpcache |
228 | { |
||
241 | terminx | 229 | struct grpcache *next; |
1205 | terminx | 230 | int32_t size; |
231 | int32_t mtime; |
||
232 | int32_t crcval; |
||
1457 | terminx | 233 | char name[BMAX_PATH]; |
335 | terminx | 234 | } |
235 | *grpcache = NULL, *usedgrpcache = NULL; |
||
241 | terminx | 236 | |
1205 | terminx | 237 | static int32_t LoadGroupsCache(void) |
241 | terminx | 238 | { |
239 | struct grpcache *fg; |
||
240 | |||
1205 | terminx | 241 | int32_t fsize, fmtime, fcrcval; |
241 | terminx | 242 | char *fname; |
243 | |||
244 | scriptfile *script; |
||
245 | |||
246 | script = scriptfile_fromfile(GRPCACHEFILE); |
||
247 | if (!script) return -1; |
||
248 | |||
335 | terminx | 249 | while (!scriptfile_eof(script)) |
250 | { |
||
2726 | hendricks2 | 251 | if (scriptfile_getstring(script, &fname)) break; // filename |
252 | if (scriptfile_getnumber(script, &fsize)) break; // filesize |
||
253 | if (scriptfile_getnumber(script, &fmtime)) break; // modification time |
||
254 | if (scriptfile_getnumber(script, &fcrcval)) break; // crc checksum |
||
241 | terminx | 255 | |
3176 | helixhorne | 256 | fg = (struct grpcache *)Bcalloc(1, sizeof(struct grpcache)); |
241 | terminx | 257 | fg->next = grpcache; |
258 | grpcache = fg; |
||
259 | |||
1221 | terminx | 260 | Bstrncpy(fg->name, fname, BMAX_PATH); |
241 | terminx | 261 | fg->size = fsize; |
262 | fg->mtime = fmtime; |
||
263 | fg->crcval = fcrcval; |
||
264 | } |
||
265 | |||
266 | scriptfile_close(script); |
||
267 | return 0; |
||
268 | } |
||
269 | |||
270 | static void FreeGroupsCache(void) |
||
271 | { |
||
272 | struct grpcache *fg; |
||
273 | |||
335 | terminx | 274 | while (grpcache) |
275 | { |
||
241 | terminx | 276 | fg = grpcache->next; |
1527 | terminx | 277 | Bfree(grpcache); |
241 | terminx | 278 | grpcache = fg; |
279 | } |
||
280 | } |
||
281 | |||
3654 | terminx | 282 | void RemoveGroup(int32_t crcval) |
283 | { |
||
3661 | terminx | 284 | struct grpfile *grp; |
3654 | terminx | 285 | |
286 | for (grp = foundgrps; grp; grp=grp->next) |
||
287 | { |
||
288 | if (grp->crcval == crcval) |
||
289 | { |
||
290 | if (grp == foundgrps) |
||
291 | foundgrps = grp->next; |
||
3661 | terminx | 292 | else |
293 | { |
||
294 | struct grpfile *fg; |
||
3654 | terminx | 295 | |
3661 | terminx | 296 | for (fg = foundgrps; fg; fg=fg->next) |
297 | { |
||
298 | if (fg->next == grp) |
||
299 | { |
||
300 | fg->next = grp->next; |
||
301 | break; |
||
302 | } |
||
303 | } |
||
304 | } |
||
305 | |||
3654 | terminx | 306 | Bfree((char *)grp->name); |
307 | Bfree(grp); |
||
308 | |||
3661 | terminx | 309 | RemoveGroup(crcval); |
310 | |||
3654 | terminx | 311 | break; |
312 | } |
||
313 | } |
||
314 | } |
||
315 | |||
316 | struct grpfile * FindGroup(int32_t crcval) |
||
317 | { |
||
318 | struct grpfile *grp; |
||
319 | |||
320 | for (grp = foundgrps; grp; grp=grp->next) |
||
321 | { |
||
322 | if (grp->crcval == crcval) |
||
323 | return grp; |
||
324 | } |
||
325 | |||
326 | return NULL; |
||
327 | } |
||
328 | |||
1205 | terminx | 329 | int32_t ScanGroups(void) |
241 | terminx | 330 | { |
331 | CACHE1D_FIND_REC *srch, *sidx; |
||
332 | struct grpcache *fg, *fgg; |
||
333 | struct grpfile *grp; |
||
334 | char *fn; |
||
335 | struct Bstat st; |
||
1430 | terminx | 336 | #define BUFFER_SIZE (1024 * 1024 * 8) |
3176 | helixhorne | 337 | uint8_t *buf = (uint8_t *)Bmalloc(BUFFER_SIZE); |
241 | terminx | 338 | |
1431 | terminx | 339 | if (!buf) |
1430 | terminx | 340 | { |
341 | initprintf("Error allocating %d byte buffer to scan GRPs!\n", BUFFER_SIZE); |
||
342 | return 0; |
||
343 | } |
||
344 | |||
1643 | terminx | 345 | initprintf("Searching for game data...\n"); |
241 | terminx | 346 | |
3708 | terminx | 347 | LoadGameList(); |
241 | terminx | 348 | LoadGroupsCache(); |
349 | |||
350 | srch = klistpath("/", "*.grp", CACHE1D_FIND_FILE); |
||
351 | |||
335 | terminx | 352 | for (sidx = srch; sidx; sidx = sidx->next) |
353 | { |
||
354 | for (fg = grpcache; fg; fg = fg->next) |
||
355 | { |
||
241 | terminx | 356 | if (!Bstrcmp(fg->name, sidx->name)) break; |
357 | } |
||
358 | |||
335 | terminx | 359 | if (fg) |
360 | { |
||
2726 | hendricks2 | 361 | if (findfrompath(sidx->name, &fn)) continue; // failed to resolve the filename |
335 | terminx | 362 | if (Bstat(fn, &st)) |
363 | { |
||
1527 | terminx | 364 | Bfree(fn); |
335 | terminx | 365 | continue; |
2726 | hendricks2 | 366 | } // failed to stat the file |
1527 | terminx | 367 | Bfree(fn); |
335 | terminx | 368 | if (fg->size == st.st_size && fg->mtime == st.st_mtime) |
369 | { |
||
808 | terminx | 370 | grp = (struct grpfile *)Bcalloc(1, sizeof(struct grpfile)); |
1527 | terminx | 371 | grp->name = Bstrdup(sidx->name); |
241 | terminx | 372 | grp->crcval = fg->crcval; |
373 | grp->size = fg->size; |
||
374 | grp->next = foundgrps; |
||
375 | foundgrps = grp; |
||
376 | |||
808 | terminx | 377 | fgg = (struct grpcache *)Bcalloc(1, sizeof(struct grpcache)); |
241 | terminx | 378 | strcpy(fgg->name, fg->name); |
379 | fgg->size = fg->size; |
||
380 | fgg->mtime = fg->mtime; |
||
381 | fgg->crcval = fg->crcval; |
||
382 | fgg->next = usedgrpcache; |
||
383 | usedgrpcache = fgg; |
||
384 | continue; |
||
385 | } |
||
386 | } |
||
387 | |||
388 | { |
||
1205 | terminx | 389 | int32_t b, fh; |
390 | int32_t crcval; |
||
241 | terminx | 391 | |
392 | fh = openfrompath(sidx->name, BO_RDONLY|BO_BINARY, BS_IREAD); |
||
393 | if (fh < 0) continue; |
||
3171 | helixhorne | 394 | if (Bfstat(fh, &st)) continue; |
241 | terminx | 395 | |
396 | initprintf(" Checksumming %s...", sidx->name); |
||
1205 | terminx | 397 | crc32init((uint32_t *)&crcval); |
335 | terminx | 398 | do |
399 | { |
||
1430 | terminx | 400 | b = read(fh, buf, BUFFER_SIZE); |
1205 | terminx | 401 | if (b > 0) crc32block((uint32_t *)&crcval, (uint8_t *)buf, b); |
335 | terminx | 402 | } |
1430 | terminx | 403 | while (b == BUFFER_SIZE); |
1205 | terminx | 404 | crc32finish((uint32_t *)&crcval); |
241 | terminx | 405 | close(fh); |
406 | initprintf(" Done\n"); |
||
407 | |||
808 | terminx | 408 | grp = (struct grpfile *)Bcalloc(1, sizeof(struct grpfile)); |
1527 | terminx | 409 | grp->name = Bstrdup(sidx->name); |
241 | terminx | 410 | grp->crcval = crcval; |
411 | grp->size = st.st_size; |
||
412 | grp->next = foundgrps; |
||
413 | foundgrps = grp; |
||
414 | |||
808 | terminx | 415 | fgg = (struct grpcache *)Bcalloc(1, sizeof(struct grpcache)); |
1221 | terminx | 416 | Bstrncpy(fgg->name, sidx->name, BMAX_PATH); |
241 | terminx | 417 | fgg->size = st.st_size; |
418 | fgg->mtime = st.st_mtime; |
||
419 | fgg->crcval = crcval; |
||
420 | fgg->next = usedgrpcache; |
||
421 | usedgrpcache = fgg; |
||
422 | } |
||
423 | } |
||
424 | |||
425 | klistfree(srch); |
||
426 | FreeGroupsCache(); |
||
427 | |||
3654 | terminx | 428 | for (grp = foundgrps; grp; /*grp=grp->next*/) |
429 | { |
||
3708 | terminx | 430 | struct grpfile *igrp; |
431 | for (igrp = listgrps; igrp; igrp=igrp->next) |
||
432 | if (grp->crcval == igrp->crcval) break; |
||
3654 | terminx | 433 | |
3708 | terminx | 434 | if (igrp == NULL) |
435 | { |
||
436 | grp = grp->next; |
||
437 | continue; |
||
438 | } |
||
3654 | terminx | 439 | |
3708 | terminx | 440 | if (igrp->dependency) |
3654 | terminx | 441 | { |
3723 | terminx | 442 | struct grpfile *depgrp; |
443 | |||
3654 | terminx | 444 | //initprintf("found grp with dep\n"); |
3723 | terminx | 445 | for (depgrp = foundgrps; depgrp; depgrp=depgrp->next) |
446 | if (depgrp->crcval == igrp->dependency) break; |
||
3654 | terminx | 447 | |
3723 | terminx | 448 | if (depgrp == NULL || depgrp->crcval != igrp->dependency) // couldn't find dependency |
3654 | terminx | 449 | { |
450 | //initprintf("removing %s\n", grp->name); |
||
3708 | terminx | 451 | RemoveGroup(igrp->crcval); |
3654 | terminx | 452 | grp = foundgrps; |
453 | continue; |
||
454 | } |
||
455 | } |
||
456 | |||
457 | grp=grp->next; |
||
458 | } |
||
459 | |||
335 | terminx | 460 | if (usedgrpcache) |
461 | { |
||
1205 | terminx | 462 | int32_t i = 0; |
241 | terminx | 463 | FILE *fp; |
464 | fp = fopen(GRPCACHEFILE, "wt"); |
||
335 | terminx | 465 | if (fp) |
466 | { |
||
467 | for (fg = usedgrpcache; fg; fg=fgg) |
||
468 | { |
||
241 | terminx | 469 | fgg = fg->next; |
470 | fprintf(fp, "\"%s\" %d %d %d\n", fg->name, fg->size, fg->mtime, fg->crcval); |
||
1527 | terminx | 471 | Bfree(fg); |
1000 | terminx | 472 | i++; |
241 | terminx | 473 | } |
474 | fclose(fp); |
||
475 | } |
||
1178 | terminx | 476 | // initprintf("Found %d recognized GRP %s.\n",i,i>1?"files":"file"); |
2978 | helixhorne | 477 | |
478 | Bfree(buf); |
||
1000 | terminx | 479 | return 0; |
241 | terminx | 480 | } |
1642 | terminx | 481 | |
482 | initprintf("Found no recognized game data!\n"); |
||
483 | |||
2978 | helixhorne | 484 | Bfree(buf); |
241 | terminx | 485 | return 0; |
486 | } |
||
487 | |||
3654 | terminx | 488 | |
241 | terminx | 489 | void FreeGroups(void) |
490 | { |
||
491 | struct grpfile *fg; |
||
492 | |||
335 | terminx | 493 | while (foundgrps) |
494 | { |
||
241 | terminx | 495 | fg = foundgrps->next; |
1677 | terminx | 496 | Bfree((char *)foundgrps->name); |
1527 | terminx | 497 | Bfree(foundgrps); |
241 | terminx | 498 | foundgrps = fg; |
499 | } |
||
3708 | terminx | 500 | |
501 | FreeGameList(); |
||
241 | terminx | 502 | } |
503 |