grpscan.cpp 23.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//-------------------------------------------------------------------------
/*
Copyright (C) 2010 EDuke32 developers and contributors

This file is part of EDuke32.

EDuke32 is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.

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
19
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20
21
22
*/
//-------------------------------------------------------------------------

Richard Gobeille's avatar
Richard Gobeille committed
23
24
#include "baselayer.h"
#include "cache1d.h"
Richard Gobeille's avatar
Richard Gobeille committed
25
26
#include "common_game.h"
#include "compat.h"
Richard Gobeille's avatar
Richard Gobeille committed
27
#include "crc32.h"
Richard Gobeille's avatar
Richard Gobeille committed
28
29
#include "duke3d.h"
#include "grpscan.h"
Richard Gobeille's avatar
Richard Gobeille committed
30
#include "scriptfile.h"
Richard Gobeille's avatar
Richard Gobeille committed
31

32
33
#include "vfs.h"

34
#ifndef EDUKE32_STANDALONE
35
36
static void process_vaca13(int32_t crcval);
static void process_vacapp15(int32_t crcval);
37

38
39
// custom GRP support for the startup window, file format reflects the structure below
#define GAMELISTFILE "games.list"
40
41
//    name                                     crc          size      flags                         dependency  scriptname     postprocessing
static internalgrpinfo_t const internalgrpfiles[] =
Richard Gobeille's avatar
   
Richard Gobeille committed
42
{
43
44
45
    { "Duke Nukem 3D",                         DUKE13_CRC,  26524524, GAMEFLAG_DUKE,                         0, NULL, NULL},
    { "Duke Nukem 3D (South Korean Censored)", DUKEKR_CRC,  26385383, GAMEFLAG_DUKE,                         0, NULL, NULL},
    { "Duke Nukem 3D: Atomic Edition",         DUKE15_CRC,  44356548, GAMEFLAG_DUKE,                         0, NULL, NULL},
46
    { "Duke Nukem 3D: Atomic Edition (WT)",    DUKEWT_CRC,  44356548, GAMEFLAG_DUKE,                         0, NULL, NULL},
47
48
49
50
51
52
    { "Duke Nukem 3D: Plutonium Pak",          DUKEPP_CRC,  44348015, GAMEFLAG_DUKE,                         0, NULL, NULL},
    { "Duke Nukem 3D Shareware 0.99",          DUKE099_CRC, 9690241,  GAMEFLAG_DUKE|GAMEFLAG_DUKEBETA,       0, NULL, NULL},
    { "Duke Nukem 3D Shareware 1.0",           DUKE10_CRC,  10429258, GAMEFLAG_DUKE|GAMEFLAG_SHAREWARE,      0, NULL, NULL},
    { "Duke Nukem 3D Shareware 1.1",           DUKE11_CRC,  10442980, GAMEFLAG_DUKE|GAMEFLAG_SHAREWARE,      0, NULL, NULL},
    { "Duke Nukem 3D Shareware 1.3D",          DUKESW_CRC,  11035779, GAMEFLAG_DUKE|GAMEFLAG_SHAREWARE,      0, NULL, NULL},
    { "Duke Nukem 3D Mac Demo",                DUKEMD_CRC,  10444391, GAMEFLAG_DUKE|GAMEFLAG_SHAREWARE,      0, NULL, NULL},
53
    { "Duke Nukem 3D MacUser Demo",            DUKEMD2_CRC, 10628573, GAMEFLAG_DUKE|GAMEFLAG_SHAREWARE,      0, NULL, NULL },
54
55
56
57
58
59
60
61
62
63
    { "Duke it out in D.C. (1.3D)",            DUKEDC13_CRC, 7926624, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE13_CRC, NULL, NULL},
    { "Duke it out in D.C.",                   DUKEDCPP_CRC, 8225517, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, NULL, NULL},
    { "Duke it out in D.C.",                   DUKEDC_CRC,  8410183,  GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, NULL, NULL},
    { "Duke it out in D.C.",                   (int32_t) 0x39A692BF,  8410187, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, "DUKEDC.CON", NULL},
    { "Duke Caribbean: Life's a Beach (1.3D)", VACA13_CRC,  23559381, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE13_CRC, NULL, process_vaca13},
    { "Duke Caribbean: Life's a Beach (PPak)", VACAPP_CRC,  22551333, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKEPP_CRC, NULL, process_vacapp15},
    { "Duke Caribbean: Life's a Beach",        VACA15_CRC,  22521880, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, NULL, process_vacapp15},
    { "Duke Caribbean: Life's a Beach",        DUKECB_CRC,  22213819, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, NULL, NULL},
    { "Duke Caribbean: Life's a Beach",        (int32_t) 0x65B5F690, 22397273, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, "VACATION.CON", NULL},
    { "Duke: Nuclear Winter",                  DUKENW_CRC,  16169365, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, "NWINTER.CON", NULL},
64
    { "Duke: Nuclear Winter Demo",             (int32_t) 0xC7EFBFA9,  10965909, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, "NWINTER.CON", NULL},
65
66
67
68
69
70
    { "Duke!ZONE II (1.3D)",                   DZ2_13_CRC,  26135388, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE13_CRC, "DZ-GAME.CON", NULL},
    { "Duke!ZONE II",                          DZ2_PP_CRC,  44100411, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, "DZ-GAME.CON", NULL},
    { "Duke!ZONE II",                          (int32_t) 0x1E9516F1,  3186656, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, "DZ-GAME.CON", NULL},
    { "NAM",                                   NAM_CRC,     43448927, GAMEFLAG_NAM,                          0, NULL, NULL},
    { "NAPALM",                                NAPALM_CRC,  44365728, GAMEFLAG_NAM|GAMEFLAG_NAPALM,          0, NULL, NULL},
    { "WWII GI",                               WW2GI_CRC,   77939508, GAMEFLAG_WW2GI,                        0, NULL, NULL},
71
    { "Platoon Leader",                        PLATOONL_CRC, 37852572, GAMEFLAG_WW2GI|GAMEFLAG_ADDON,        WW2GI_CRC, "PLATOONL.DEF", NULL},
Richard Gobeille's avatar
   
Richard Gobeille committed
72
};
73
#endif
Evan Ramos's avatar
Evan Ramos committed
74

75
76
struct grpfile_t *foundgrps = NULL;
struct grpinfo_t *listgrps = NULL;
77
78
79
80
81
82
83
84

static void LoadList(const char * filename)
{
    scriptfile *script = scriptfile_fromfile(filename);

    if (!script)
        return;

85
#ifndef EDUKE32_STANDALONE
86
87
    scriptfile_addsymbolvalue("GAMEFLAG_DUKE", GAMEFLAG_DUKE);
    scriptfile_addsymbolvalue("GAMEFLAG_ADDON", GAMEFLAG_DUKE|GAMEFLAG_ADDON);
88
89
90
    scriptfile_addsymbolvalue("GAMEFLAG_NAM", GAMEFLAG_NAM);
    scriptfile_addsymbolvalue("GAMEFLAG_NAPALM", GAMEFLAG_NAM|GAMEFLAG_NAPALM);
    scriptfile_addsymbolvalue("GAMEFLAG_WW2GI", GAMEFLAG_NAM|GAMEFLAG_WW2GI);
91
    scriptfile_addsymbolvalue("DUKE15_CRC", DUKE15_CRC);
92
    scriptfile_addsymbolvalue("DUKEPP_CRC", DUKEPP_CRC);
93
    scriptfile_addsymbolvalue("DUKE13_CRC", DUKE13_CRC);
94
95
    scriptfile_addsymbolvalue("DUKEDC13_CRC", DUKEDC13_CRC);
    scriptfile_addsymbolvalue("DUKEDCPP_CRC", DUKEDCPP_CRC);
96
    scriptfile_addsymbolvalue("DUKEDC_CRC", DUKEDC_CRC);
97
98
99
    scriptfile_addsymbolvalue("VACA13_CRC", VACA13_CRC);
    scriptfile_addsymbolvalue("VACAPP_CRC", VACAPP_CRC);
    scriptfile_addsymbolvalue("VACA15_CRC", VACA15_CRC);
100
101
    scriptfile_addsymbolvalue("DUKECB_CRC", DUKECB_CRC);
    scriptfile_addsymbolvalue("DUKENW_CRC", DUKENW_CRC);
102
103
    scriptfile_addsymbolvalue("DZ2_13_CRC", DZ2_13_CRC);
    scriptfile_addsymbolvalue("DZ2_PP_CRC", DZ2_PP_CRC);
104
105
106
    scriptfile_addsymbolvalue("NAM_CRC", NAM_CRC);
    scriptfile_addsymbolvalue("NAPALM_CRC", NAPALM_CRC);
    scriptfile_addsymbolvalue("WW2GI_CRC", WW2GI_CRC);
107
#endif
108
109
110

    while (!scriptfile_eof(script))
    {
111
112
113
114
115
116
117
118
119
120
        enum
        {
            T_GRPINFO,
            T_GAMENAME,
            T_CRC,
            T_SIZE,
            T_DEPCRC,
            T_SCRIPTNAME,
            T_DEFNAME,
            T_FLAGS,
121
            T_RTSNAME,
122
123
124
125
126
127
128
        };

        static const tokenlist profiletokens[] =
        {
            { "grpinfo",            T_GRPINFO },
        };

129
        int32_t token = getatoken(script,profiletokens,ARRAY_SIZE(profiletokens));
130
131
132
        switch (token)
        {
        case T_GRPINFO:
133
134
135
        {
            int32_t gsize = 0, gcrcval = 0, gflags = GAMEFLAG_DUKE, gdepcrc = DUKE15_CRC;
            char *gname = NULL, *gscript = NULL, *gdef = NULL;
136
            char *grts = NULL;
137
            char *grpend = NULL;
138
139

            static const tokenlist grpinfotokens[] =
140
            {
141
142
143
                { "name",           T_GAMENAME },
                { "scriptname",     T_SCRIPTNAME },
                { "defname",        T_DEFNAME },
144
                { "rtsname",        T_RTSNAME },
145
146
147
148
                { "crc",            T_CRC },
                { "dependency",     T_DEPCRC },
                { "size",           T_SIZE },
                { "flags",          T_FLAGS },
149

150
            };
151

152
            if (scriptfile_getbraces(script,&grpend)) break;
153

154
155
            while (script->textptr < grpend)
            {
156
                int32_t token = getatoken(script,grpinfotokens,ARRAY_SIZE(grpinfotokens));
157

158
                switch (token)
159
                {
160
161
162
163
164
165
                case T_GAMENAME:
                    scriptfile_getstring(script,&gname); break;
                case T_SCRIPTNAME:
                    scriptfile_getstring(script,&gscript); break;
                case T_DEFNAME:
                    scriptfile_getstring(script,&gdef); break;
166
167
                case T_RTSNAME:
                    scriptfile_getstring(script,&grts); break;
168
169

                case T_FLAGS:
170
                    scriptfile_getsymbol(script,&gflags); gflags &= GAMEFLAGMASK; break;
171
172
173
174
175
176
177
178
                case T_DEPCRC:
                    scriptfile_getsymbol(script,&gdepcrc); break;
                case T_CRC:
                    scriptfile_getsymbol(script,&gcrcval); break;
                case T_SIZE:
                    scriptfile_getnumber(script,&gsize); break;
                default:
                    break;
179
180
                }

181
                grpinfo_t * const fg = (grpinfo_t *)Xcalloc(1, sizeof(grpinfo_t));
182
183
184
185
                fg->next = listgrps;
                listgrps = fg;

                if (gname)
186
                    fg->name = Xstrdup(gname);
187
188
189
190
191
192
193
194
195
196
197

                fg->size = gsize;
                fg->crcval = gcrcval;
                fg->dependency = gdepcrc;
                fg->game = gflags;

                if (gscript)
                    fg->scriptname = dup_filename(gscript);

                if (gdef)
                    fg->defname = dup_filename(gdef);
198
199
200

                if (grts)
                    fg->rtsname = dup_filename(grts);
201
            }
202
            break;
203
204
        }

205
206
207
208
209
210
211
212
213
214
215
        default:
            break;
        }
    }

    scriptfile_close(script);
    scriptfile_clearsymbols();
}

static void LoadGameList(void)
{
216
#ifndef EDUKE32_STANDALONE
217
    for (size_t i = 0; i < ARRAY_SIZE(internalgrpfiles); i++)
218
    {
219
        grpinfo_t * const fg = (grpinfo_t *)Xcalloc(1, sizeof(grpinfo_t));
220

221
        fg->name = Xstrdup(internalgrpfiles[i].name);
222
223
224
225
226
227
228
229
        fg->crcval = internalgrpfiles[i].crcval;
        fg->size = internalgrpfiles[i].size;
        fg->game = internalgrpfiles[i].game;
        fg->dependency = internalgrpfiles[i].dependency;

        if (internalgrpfiles[i].scriptname)
            fg->scriptname = dup_filename(internalgrpfiles[i].scriptname);

230
231
        fg->postprocessing = internalgrpfiles[i].postprocessing;

232
233
234
        fg->next = listgrps;
        listgrps = fg;
    }
235
#endif
236

237
238
239
240
241
#ifdef USE_PHYSFS
    auto const base = PHYSFS_getBaseDir();
#else
    static char const base[] = "/";
#endif
242
    BUILDVFS_FIND_REC * const srch = klistpath(base, "*.grpinfo", BUILDVFS_FIND_FILE);
243

244
    for (BUILDVFS_FIND_REC *sidx = srch; sidx; sidx = sidx->next)
245
        LoadList(sidx->name);
246
247
248
249
250
251
252
253

    klistfree(srch);
}

static void FreeGameList(void)
{
    while (listgrps)
    {
254
255
256
257
        Xfree(listgrps->name);
        Xfree(listgrps->scriptname);
        Xfree(listgrps->defname);
        Xfree(listgrps->rtsname);
258

259
        grpinfo_t * const fg = listgrps->next;
260
        Xfree(listgrps);
261
262
263
264
        listgrps = fg;
    }
}

Richard Gobeille's avatar
Richard Gobeille committed
265
266

#define GRPCACHEFILE "grpfiles.cache"
267
268
static struct grpcache
{
Richard Gobeille's avatar
Richard Gobeille committed
269
    struct grpcache *next;
Richard Gobeille's avatar
Richard Gobeille committed
270
271
272
    int32_t size;
    int32_t mtime;
    int32_t crcval;
273
    char name[BMAX_PATH];
274
275
}
*grpcache = NULL, *usedgrpcache = NULL;
Richard Gobeille's avatar
Richard Gobeille committed
276

Richard Gobeille's avatar
Richard Gobeille committed
277
static int32_t LoadGroupsCache(void)
Richard Gobeille's avatar
Richard Gobeille committed
278
279
280
{
    struct grpcache *fg;

Richard Gobeille's avatar
Richard Gobeille committed
281
    int32_t fsize, fmtime, fcrcval;
Richard Gobeille's avatar
Richard Gobeille committed
282
283
284
285
286
287
288
    char *fname;

    scriptfile *script;

    script = scriptfile_fromfile(GRPCACHEFILE);
    if (!script) return -1;

289
290
    while (!scriptfile_eof(script))
    {
291
292
293
294
        if (scriptfile_getstring(script, &fname)) break;    // filename
        if (scriptfile_getnumber(script, &fsize)) break;    // filesize
        if (scriptfile_getnumber(script, &fmtime)) break;   // modification time
        if (scriptfile_getnumber(script, &fcrcval)) break;  // crc checksum
Richard Gobeille's avatar
Richard Gobeille committed
295

296
        fg = (struct grpcache *)Xcalloc(1, sizeof(struct grpcache));
Richard Gobeille's avatar
Richard Gobeille committed
297
298
299
        fg->next = grpcache;
        grpcache = fg;

Richard Gobeille's avatar
   
Richard Gobeille committed
300
        Bstrncpy(fg->name, fname, BMAX_PATH);
Richard Gobeille's avatar
Richard Gobeille committed
301
302
303
304
305
306
307
308
309
310
311
        fg->size = fsize;
        fg->mtime = fmtime;
        fg->crcval = fcrcval;
    }

    scriptfile_close(script);
    return 0;
}

static void FreeGroupsCache(void)
{
312
313
    while (grpcache)
    {
314
        struct grpcache * const fg = grpcache->next;
315
        Xfree(grpcache);
Richard Gobeille's avatar
Richard Gobeille committed
316
317
318
319
        grpcache = fg;
    }
}

320
static void RemoveGroup(grpfile_t *igrp)
321
{
322
    for (grpfile_t *prev = NULL, *grp = foundgrps; grp; grp=grp->next)
323
    {
324
        if (grp == igrp)
325
326
327
        {
            if (grp == foundgrps)
                foundgrps = grp->next;
328
            else
329
                prev->next = grp->next;
330

331
332
            Xfree((char *)grp->filename);
            Xfree(grp);
333

334
            return;
335
        }
336
337

        prev = grp;
338
339
340
    }
}

341
grpfile_t * FindGroup(int32_t crcval)
342
{
343
    grpfile_t *grp;
344
345
346

    for (grp = foundgrps; grp; grp=grp->next)
    {
347
        if (grp->type->crcval == crcval)
348
349
350
351
352
353
            return grp;
    }

    return NULL;
}

354
#ifndef USE_PHYSFS
355
356
357
358
359
360
361
362
363
364
365
366
367
static grpinfo_t const * FindGrpInfo(int32_t crcval, int32_t size)
{
    grpinfo_t *grpinfo;

    for (grpinfo = listgrps; grpinfo; grpinfo=grpinfo->next)
    {
        if (grpinfo->crcval == crcval && grpinfo->size == size)
            return grpinfo;
    }

    return NULL;
}

368
static void ProcessGroups(BUILDVFS_FIND_REC *srch, native_t maxsize)
Richard Gobeille's avatar
Richard Gobeille committed
369
{
370
    BUILDVFS_FIND_REC *sidx;
Richard Gobeille's avatar
Richard Gobeille committed
371
372
373
    struct grpcache *fg, *fgg;
    char *fn;
    struct Bstat st;
374

375
376
    static constexpr int ReadSize = 65536;

377
    auto buf = (uint8_t *)Xmalloc(ReadSize);
Richard Gobeille's avatar
Richard Gobeille committed
378

379
380
381
382
    for (sidx = srch; sidx; sidx = sidx->next)
    {
        for (fg = grpcache; fg; fg = fg->next)
        {
Richard Gobeille's avatar
Richard Gobeille committed
383
384
385
            if (!Bstrcmp(fg->name, sidx->name)) break;
        }

386
387
        if (fg)
        {
388
            if (findfrompath(sidx->name, &fn)) continue; // failed to resolve the filename
389
390
            if (Bstat(fn, &st))
            {
391
                Xfree(fn);
392
                continue;
393
            } // failed to stat the file
394
            Xfree(fn);
395
            if (fg->size == (int32_t)st.st_size && fg->mtime == (int32_t)st.st_mtime)
396
            {
397
398
399
400
401
402
403
404
405
                grpinfo_t const * const grptype = FindGrpInfo(fg->crcval, fg->size);
                if (grptype)
                {
                    grpfile_t * const grp = (grpfile_t *)Xcalloc(1, sizeof(grpfile_t));
                    grp->filename = Xstrdup(sidx->name);
                    grp->type = grptype;
                    grp->next = foundgrps;
                    foundgrps = grp;
                }
Richard Gobeille's avatar
Richard Gobeille committed
406

407
                fgg = (struct grpcache *)Xcalloc(1, sizeof(struct grpcache));
Richard Gobeille's avatar
Richard Gobeille committed
408
409
410
411
412
413
414
415
416
417
418
                strcpy(fgg->name, fg->name);
                fgg->size = fg->size;
                fgg->mtime = fg->mtime;
                fgg->crcval = fg->crcval;
                fgg->next = usedgrpcache;
                usedgrpcache = fgg;
                continue;
            }
        }

        {
Richard Gobeille's avatar
Richard Gobeille committed
419
            int32_t b, fh;
420
            int32_t crcval = 0;
Richard Gobeille's avatar
Richard Gobeille committed
421
422
423

            fh = openfrompath(sidx->name, BO_RDONLY|BO_BINARY, BS_IREAD);
            if (fh < 0) continue;
424
            if (Bfstat(fh, &st)) continue;
425
            if (st.st_size > maxsize) continue;
Richard Gobeille's avatar
Richard Gobeille committed
426
427

            initprintf(" Checksumming %s...", sidx->name);
428
429
            do
            {
430
                b = read(fh, buf, ReadSize);
431
                if (b > 0) crcval = Bcrc32((uint8_t *)buf, b, crcval);
432
            }
433
            while (b == ReadSize);
Richard Gobeille's avatar
Richard Gobeille committed
434
435
436
            close(fh);
            initprintf(" Done\n");

437
438
439
440
441
442
443
444
445
            grpinfo_t const * const grptype = FindGrpInfo(crcval, st.st_size);
            if (grptype)
            {
                grpfile_t * const grp = (grpfile_t *)Xcalloc(1, sizeof(grpfile_t));
                grp->filename = Xstrdup(sidx->name);
                grp->type = grptype;
                grp->next = foundgrps;
                foundgrps = grp;
            }
Richard Gobeille's avatar
Richard Gobeille committed
446

447
            fgg = (struct grpcache *)Xcalloc(1, sizeof(struct grpcache));
Richard Gobeille's avatar
   
Richard Gobeille committed
448
            Bstrncpy(fgg->name, sidx->name, BMAX_PATH);
Richard Gobeille's avatar
Richard Gobeille committed
449
450
451
452
453
454
455
456
            fgg->size = st.st_size;
            fgg->mtime = st.st_mtime;
            fgg->crcval = crcval;
            fgg->next = usedgrpcache;
            usedgrpcache = fgg;
        }
    }

457
    Xfree(buf);
458
}
459
#endif
460
461
462

int32_t ScanGroups(void)
{
463
#ifndef USE_PHYSFS
464
465
466
467
468
469
470
    struct grpcache *fg, *fgg;

    initprintf("Searching for game data...\n");

    LoadGameList();
    LoadGroupsCache();

471
472
473
474
475
476
477
    native_t maxsize = 0;
    for (grpinfo_t * grpinfo = listgrps; grpinfo; grpinfo = grpinfo->next)
    {
        if (maxsize < grpinfo->size)
            maxsize = grpinfo->size;
    }

478
479
480
481
482
    static char const *extensions[] =
    {
        "*.grp",
        "*.ssi",
        "*.dat",
483
        "*.zip",
484
    };
485

486
487
    for (char const *extension : extensions)
    {
488
        BUILDVFS_FIND_REC *srch = klistpath("/", extension, BUILDVFS_FIND_FILE);
489
        ProcessGroups(srch, maxsize);
490
491
        klistfree(srch);
    }
492

Richard Gobeille's avatar
Richard Gobeille committed
493
494
    FreeGroupsCache();

495
    for (grpfile_t *grp = foundgrps; grp; grp=grp->next)
496
    {
497
        if (grp->type->dependency)
498
        {
499
            if (FindGroup(grp->type->dependency) == NULL) // couldn't find dependency
500
501
            {
                //initprintf("removing %s\n", grp->name);
502
                RemoveGroup(grp);
503
                grp = foundgrps;
504
                // start from the beginning so we can remove anything that depended on this grp
505
506
507
508
509
                continue;
            }
        }
    }

510
511
    if (usedgrpcache)
    {
Richard Gobeille's avatar
Richard Gobeille committed
512
        int32_t i = 0;
513
        buildvfs_FILE fp = buildvfs_fopen_write(GRPCACHEFILE);
514
515
516
517
        if (fp)
        {
            for (fg = usedgrpcache; fg; fg=fgg)
            {
Richard Gobeille's avatar
Richard Gobeille committed
518
519
                fgg = fg->next;
                fprintf(fp, "\"%s\" %d %d %d\n", fg->name, fg->size, fg->mtime, fg->crcval);
520
                Xfree(fg);
521
                i++;
Richard Gobeille's avatar
Richard Gobeille committed
522
            }
523
            buildvfs_fclose(fp);
Richard Gobeille's avatar
Richard Gobeille committed
524
        }
Richard Gobeille's avatar
   
Richard Gobeille committed
525
//        initprintf("Found %d recognized GRP %s.\n",i,i>1?"files":"file");
526

527
        return 0;
Richard Gobeille's avatar
Richard Gobeille committed
528
    }
529
530

    initprintf("Found no recognized game data!\n");
531
#endif
532

Richard Gobeille's avatar
Richard Gobeille committed
533
534
535
    return 0;
}

536

Richard Gobeille's avatar
Richard Gobeille committed
537
538
void FreeGroups(void)
{
539
540
    while (foundgrps)
    {
541
        Xfree((char *)foundgrps->filename);
542
        grpfile_t * const fg = foundgrps->next;
543
        Xfree(foundgrps);
Richard Gobeille's avatar
Richard Gobeille committed
544
545
        foundgrps = fg;
    }
546
547

    FreeGameList();
Richard Gobeille's avatar
Richard Gobeille committed
548
549
}

550
#ifndef EDUKE32_STANDALONE
551
static void process_vaca13(int32_t crcval)
552
{
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
    krename(crcval, 0, "ADDREE.VOC");
    krename(crcval, 1, "BALLBOOM.VOC");
    krename(crcval, 2, "BARMUSIC.VOC");
    krename(crcval, 3, "BCHBALL.VOC");
    krename(crcval, 4, "BOING.VOC");
    krename(crcval, 5, "CHACHA.VOC");
    krename(crcval, 6, "CHAINDRV.VOC");
    krename(crcval, 7, "CHEAP01.VOC");
    krename(crcval, 8, "CHEER.VOC");
    krename(crcval, 9, "CHNSQRT.VOC");
    krename(crcval, 10, "COCOANUT.VOC");
    krename(crcval, 11, "CRUSH2.VOC");
    krename(crcval, 12, "DEFLATE2.VOC");
    krename(crcval, 13, "DRAGHURT.VOC");
    krename(crcval, 14, "DRAGROAM.VOC");
    krename(crcval, 15, "DRAGSHOT.VOC");
    krename(crcval, 16, "DUKE01.VOC");
    krename(crcval, 17, "ELEV1.VOC");
    krename(crcval, 18, "GMEOVR05.VOC");
    krename(crcval, 19, "GULLDIE.VOC");
    krename(crcval, 20, "GULLHURT.VOC");
    krename(crcval, 21, "GULLROAM.VOC");
    krename(crcval, 22, "GULLSHIT.VOC");
    krename(crcval, 23, "HELP04.VOC");
    krename(crcval, 24, "ICECONCH.VOC");
    krename(crcval, 25, "IDLEBOAT.VOC");
    krename(crcval, 26, "KICKHEAD.VOC");
    krename(crcval, 27, "LANI05.VOC");
    krename(crcval, 28, "LANI08.VOC");
    krename(crcval, 29, "LANIDUK2.VOC");
    krename(crcval, 30, "MUSCLE01.VOC");
    krename(crcval, 31, "MUSCLE04.VOC");
    krename(crcval, 32, "MUZAK.VOC");
    krename(crcval, 33, "PINEFALL.VOC");
    krename(crcval, 34, "POINT07.VOC");
    krename(crcval, 35, "POINT08.VOC");
    krename(crcval, 36, "RADIO.VOC");
    krename(crcval, 37, "RUIN01.VOC");
    krename(crcval, 38, "SCREAM.VOC");
    krename(crcval, 39, "SCREAM04.VOC");
    krename(crcval, 40, "SCREAM9.VOC");
    krename(crcval, 41, "SHIPHORN.VOC");
    krename(crcval, 42, "SNGLGULL.VOC");
    krename(crcval, 43, "SQRT4.VOC");
    krename(crcval, 44, "SQUIRT1.VOC");
    krename(crcval, 45, "SSCOOL1.VOC");
    krename(crcval, 46, "SSCOOL2.VOC");
    krename(crcval, 47, "SSCOOL3.VOC");
    krename(crcval, 48, "SSDIE1.VOC");
    krename(crcval, 49, "SSDIE2.VOC");
    krename(crcval, 50, "SSNORM01.VOC");
    krename(crcval, 51, "SSNORM02.VOC");
    krename(crcval, 52, "SSNORM03.VOC");
    krename(crcval, 53, "SSNORM04.VOC");
    krename(crcval, 54, "SSNORM05.VOC");
    krename(crcval, 55, "SSNORM06.VOC");
    krename(crcval, 56, "SSNORM07.VOC");
    krename(crcval, 57, "SSNORM08.VOC");
    krename(crcval, 58, "SSNORM10.VOC");
    krename(crcval, 59, "SSNORM11.VOC");
    krename(crcval, 60, "SSNORM12.VOC");
    krename(crcval, 61, "SSNORM13.VOC");
    krename(crcval, 62, "SSNORM14.VOC");
    krename(crcval, 63, "SSNORM15.VOC");
    krename(crcval, 64, "SSNORM16.VOC");
    krename(crcval, 65, "SSNORM17.VOC");
    krename(crcval, 66, "SSNORM18.VOC");
    krename(crcval, 67, "SSNORM19.VOC");
    krename(crcval, 68, "SSNORM20.VOC");
    krename(crcval, 69, "SSTAUNT1.VOC");
    krename(crcval, 70, "SSTAUNT2.VOC");
    krename(crcval, 71, "SSTAUNT3.VOC");
    krename(crcval, 72, "SSTAUNT4.VOC");
    krename(crcval, 73, "SSTAUNT5.VOC");
    krename(crcval, 74, "SSTAUNT6.VOC");
    krename(crcval, 75, "SSTAUNT7.VOC");
    krename(crcval, 76, "SSTAUNT8.VOC");
    krename(crcval, 77, "SURF.VOC");
    krename(crcval, 78, "TAN01.VOC");
    krename(crcval, 79, "TAN04.VOC");
    krename(crcval, 80, "VINESNAP.VOC");
    krename(crcval, 81, "VOODRUMS.VOC");
    krename(crcval, 82, "WIND54.VOC");
    krename(crcval, 83, "DOOMSDAY.MID");
    krename(crcval, 84, "DUKE-O.MID");
    krename(crcval, 85, "IRIEPRTY.MID");
    krename(crcval, 86, "JUNGVEIN.MID");
    krename(crcval, 87, "PRTYCRUZ.MID");
    krename(crcval, 88, "SOL-MAN1.MID");
    krename(crcval, 90, "CINEOV3.ANM");
    krename(crcval, 91, "DUKETEAM.ANM");
    krename(crcval, 92, "BEACHBAB.CON");
    krename(crcval, 93, "BEACHBAL.CON");
    krename(crcval, 94, "BEACHBTH.CON");
    krename(crcval, 95, "DEFS.CON");
    krename(crcval, 96, "DRAGON.CON");
    krename(crcval, 97, "GAME.CON");
    krename(crcval, 98, "SEAGULL.CON");
    krename(crcval, 99, "SOUNDS.CON");
    krename(crcval, 100, "USER.CON");
    krename(crcval, 101, "DEMO1.DMO");
    krename(crcval, 102, "DEMO2.DMO");
    krename(crcval, 103, "DEMO3.DMO");
    krename(crcval, 104, "VACA1.MAP");
    krename(crcval, 105, "VACA2.MAP");
    krename(crcval, 106, "VACA3.MAP");
    krename(crcval, 107, "VACA4.MAP");
    krename(crcval, 108, "VACA5.MAP");
    krename(crcval, 109, "VACA6.MAP");
    krename(crcval, 110, "VACA7.MAP");
    krename(crcval, 111, "VACADM1.MAP");
    krename(crcval, 112, "VACADM2.MAP");
    krename(crcval, 113, "VACADM3.MAP");
    krename(crcval, 114, "VACADM4.MAP");
    krename(crcval, 115, "VACASL.MAP");
    krename(crcval, 120, "TILES000.ART");
    krename(crcval, 121, "TILES001.ART");
    krename(crcval, 122, "TILES003.ART");
    krename(crcval, 123, "TILES005.ART");
    krename(crcval, 124, "TILES006.ART");
    krename(crcval, 125, "TILES007.ART");
    krename(crcval, 126, "TILES008.ART");
    krename(crcval, 127, "TILES009.ART");
    krename(crcval, 128, "TILES010.ART");
    krename(crcval, 129, "TILES012.ART");
    krename(crcval, 130, "TILES014.ART");
679
680
}

681
static void process_vacapp15(int32_t crcval)
682
{
683
684
685
686
687
688
    krename(crcval, 5, "DEFS.CON");
    krename(crcval, 6, "GAME.CON");
    krename(crcval, 7, "USER.CON");
    krename(crcval, 8, "DEMO1.DMO");
    krename(crcval, 9, "DEMO2.DMO");
    krename(crcval, 10, "DEMO3.DMO");
689
690
691

    initgroupfile("VACATION.PRG");
}
692
#endif