]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/doom/w_wad.c
games/doom:
[plan9front.git] / sys / src / games / doom / w_wad.c
1 // Emacs style mode select   -*- C++ -*- 
2 //-----------------------------------------------------------------------------
3 //
4 // $Id:$
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 //
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
11 //
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15 // for more details.
16 //
17 // $Log:$
18 //
19 // DESCRIPTION:
20 //      Handles WAD file header, directory, lump I/O.
21 //
22 //-----------------------------------------------------------------------------
23
24
25 static const char
26 rcsid[] = "$Id: w_wad.c,v 1.5 1997/02/03 16:47:57 b1 Exp $";
27
28
29 #ifdef NORMALUNIX
30 #include <ctype.h>
31 #include <sys/types.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <malloc.h>
35 #include <fcntl.h>
36 #include <sys/stat.h>
37 #include <alloca.h>
38 #define O_BINARY                0
39 #endif
40
41 #include "doomtype.h"
42 #include "m_swap.h"
43 #include "i_system.h"
44 #include "z_zone.h"
45
46 #include "w_wad.h"
47
48
49 //
50 // GLOBALS
51 //
52
53 // Location of each lump on disk.
54 lumpinfo_t*             lumpinfo;               
55 int                     numlumps;
56
57 void**                  lumpcache;
58
59
60 #define strcmpi strcasecmp
61
62 void strupr (char* s)
63 {
64     while (*s) { *s = toupper(*s); s++; }
65 }
66
67 int filelength (int handle) 
68 {
69         USED(handle);
70         I_Error ("PORTME w_wad.c filelength");
71         return -1;
72 /*
73     struct stat fileinfo;
74     
75     if (fstat (handle,&fileinfo) == -1)
76         I_Error ("Error fstating");
77
78     return fileinfo.st_size;
79 */
80 }
81
82
83 void
84 ExtractFileBase
85 ( char*         path,
86   char*         dest )
87 {
88     char*       src;
89     int         length;
90
91     src = path + strlen(path) - 1;
92     
93     // back up until a \ or the start
94     while (src != path
95            && *(src-1) != '\\'
96            && *(src-1) != '/')
97     {
98         src--;
99     }
100     
101     // copy up to eight characters
102     memset (dest,0,8);
103     length = 0;
104     
105     while (*src && *src != '.')
106     {
107         if (++length == 9)
108             I_Error ("Filename base of %s >8 chars",path);
109
110         *dest++ = toupper((int)*src++);
111     }
112 }
113
114
115
116
117
118 //
119 // LUMP BASED ROUTINES.
120 //
121
122 //
123 // W_AddFile
124 // All files are optional, but at least one file must be
125 //  found (PWAD, if all required lumps are present).
126 // Files with a .wad extension are wadlink files
127 //  with multiple lumps.
128 // Other files are single lumps with the base filename
129 //  for the lump name.
130 //
131 // If filename starts with a tilde, the file is handled
132 //  specially to allow map reloads.
133 // But: the reload feature is a fragile hack...
134
135 int                     reloadlump;
136 char*                   reloadname;
137
138
139 void W_AddFile (char *filename)
140 {
141     wadinfo_t           header;
142     lumpinfo_t*         lump_p;
143     unsigned            i;
144     int                 handle;
145     int                 length;
146     int                 startlump;
147     filelump_t*         fileinfo;
148     filelump_t          singleinfo;
149     int                 storehandle;
150     void                *freefileinfo = nil;
151     
152     // open the file and add to directory
153
154     // handle reload indicator.
155     if (filename[0] == '~')
156     {
157         filename++;
158         reloadname = filename;
159         reloadlump = numlumps;
160     }
161
162     if ( (handle = I_Open(filename)) == -1 )            
163     {
164         printf (" couldn't open %s\n",filename);
165         return;
166     }
167
168     printf (" adding %s\n",filename);
169     startlump = numlumps;
170         
171     if (cistrcmp (filename+strlen(filename)-3 , "wad" ) )
172     {
173         // single lump file
174         fileinfo = &singleinfo;
175         singleinfo.filepos = 0;
176         singleinfo.size = LONG(filelength(handle));
177         ExtractFileBase (filename, singleinfo.name);
178         numlumps++;
179     }
180     else 
181     {
182         // WAD file
183         I_Read (handle, &header, sizeof(header));
184         if (strncmp(header.identification,"IWAD",4))
185         {
186             // Homebrew levels?
187             if (strncmp(header.identification,"PWAD",4))
188             {
189                 I_Error ("Wad file %s doesn't have IWAD "
190                          "or PWAD id\n", filename);
191             }
192             
193             // ???modifiedgame = true;          
194         }
195         header.numlumps = LONG(header.numlumps);
196         header.infotableofs = LONG(header.infotableofs);
197         length = header.numlumps*sizeof(filelump_t);
198         fileinfo = malloc (length); freefileinfo=fileinfo;
199         I_Seek (handle, header.infotableofs);
200         I_Read (handle, fileinfo, length);
201         numlumps += header.numlumps;
202     }
203
204     
205     // Fill in lumpinfo
206     lumpinfo = realloc (lumpinfo, numlumps*sizeof(lumpinfo_t));
207
208     if (!lumpinfo)
209         I_Error ("Couldn't realloc lumpinfo");
210
211     lump_p = &lumpinfo[startlump];
212         
213     storehandle = reloadname ? -1 : handle;
214         
215     for (i=startlump ; i<numlumps ; i++,lump_p++, fileinfo++)
216     {
217         lump_p->handle = storehandle;
218         lump_p->position = LONG(fileinfo->filepos);
219         lump_p->size = LONG(fileinfo->size);
220         strncpy (lump_p->name, fileinfo->name, 8);
221     }
222         
223     if (reloadname)
224         I_Close (handle);
225
226     if (freefileinfo)
227         free(freefileinfo);
228 }
229
230
231
232
233 //
234 // W_Reload
235 // Flushes any of the reloadable lumps in memory
236 //  and reloads the directory.
237 //
238 void W_Reload (void)
239 {
240     wadinfo_t           header;
241     int                 lumpcount;
242     lumpinfo_t*         lump_p;
243     unsigned            i;
244     int                 handle;
245     int                 length;
246     filelump_t*         fileinfo;
247         
248     if (!reloadname)
249         return;
250                 
251     if ( (handle = I_Open (reloadname)) == -1)
252         I_Error ("W_Reload: couldn't open %s",reloadname);
253
254     I_Read (handle, &header, sizeof(header));
255     lumpcount = LONG(header.numlumps);
256     header.infotableofs = LONG(header.infotableofs);
257     length = lumpcount*sizeof(filelump_t);
258     fileinfo = malloc (length);
259     I_Seek (handle, header.infotableofs);
260     I_Read (handle, fileinfo, length);
261     
262     // Fill in lumpinfo
263     lump_p = &lumpinfo[reloadlump];
264         
265     for (i=reloadlump ;
266          i<reloadlump+lumpcount ;
267          i++,lump_p++, fileinfo++)
268     {
269         if (lumpcache[i])
270             Z_Free (lumpcache[i]);
271
272         lump_p->position = LONG(fileinfo->filepos);
273         lump_p->size = LONG(fileinfo->size);
274     }
275         
276     I_Close (handle);
277     free(fileinfo);
278 }
279
280
281
282 //
283 // W_InitMultipleFiles
284 // Pass a null terminated list of files to use.
285 // All files are optional, but at least one file
286 //  must be found.
287 // Files with a .wad extension are idlink files
288 //  with multiple lumps.
289 // Other files are single lumps with the base filename
290 //  for the lump name.
291 // Lump names can appear multiple times.
292 // The name searcher looks backwards, so a later file
293 //  does override all earlier ones.
294 //
295 void W_InitMultipleFiles (char** filenames)
296 {       
297     int         size;
298     
299     // open all the files, load headers, and count lumps
300     numlumps = 0;
301
302     // will be realloced as lumps are added
303     lumpinfo = malloc(1);       
304
305     for ( ; *filenames ; filenames++)
306         W_AddFile (*filenames);
307
308     if (!numlumps)
309         I_Error ("W_InitFiles: no files found");
310     
311     // set up caching
312     size = numlumps * sizeof(*lumpcache);
313     lumpcache = malloc (size);
314     
315     if (!lumpcache)
316         I_Error ("Couldn't allocate lumpcache");
317
318     memset (lumpcache,0, size);
319 }
320
321
322
323
324 //
325 // W_InitFile
326 // Just initialize from a single file.
327 //
328 void W_InitFile (char* filename)
329 {
330     char*       names[2];
331
332     names[0] = filename;
333     names[1] = NULL;
334     W_InitMultipleFiles (names);
335 }
336
337
338
339 //
340 // W_NumLumps
341 //
342 int W_NumLumps (void)
343 {
344     return numlumps;
345 }
346
347
348
349 //
350 // W_CheckNumForName
351 // Returns -1 if name not found.
352 //
353
354 int W_CheckNumForName (char* name)
355 {
356     union {
357         char    s[9];
358         int     x[2];
359         
360     } name8;
361     
362     int         v1;
363     int         v2;
364     lumpinfo_t* lump_p;
365
366     // make the name into two integers for easy compares
367     strncpy (name8.s,name,8);
368
369     // in case the name was a fill 8 chars
370     name8.s[8] = 0;
371
372     // case insensitive
373     strupr (name8.s);           
374
375     v1 = name8.x[0];
376     v2 = name8.x[1];
377
378
379     // scan backwards so patch lump files take precedence
380     lump_p = lumpinfo + numlumps;
381
382     while (lump_p-- != lumpinfo)
383     {
384         if ( *(int *)lump_p->name == v1
385              && *(int *)&lump_p->name[4] == v2)
386         {
387             return lump_p - lumpinfo;
388         }
389     }
390
391     // TFB. Not found.
392     return -1;
393 }
394
395
396
397
398 //
399 // W_GetNumForName
400 // Calls W_CheckNumForName, but bombs out if not found.
401 //
402 int W_GetNumForName (char* name)
403 {
404     int i;
405
406     i = W_CheckNumForName (name);
407     
408     if (i == -1)
409       I_Error ("W_GetNumForName: %s not found!", name);
410       
411     return i;
412 }
413
414
415 //
416 // W_LumpLength
417 // Returns the buffer size needed to load the given lump.
418 //
419 int W_LumpLength (int lump)
420 {
421     if (lump >= numlumps)
422         I_Error ("W_LumpLength: %i >= numlumps",lump);
423
424     return lumpinfo[lump].size;
425 }
426
427
428
429 //
430 // W_ReadLump
431 // Loads the lump into the given buffer,
432 //  which must be >= W_LumpLength().
433 //
434 void
435 W_ReadLump
436 ( int           lump,
437   void*         dest )
438 {
439     int         c;
440     lumpinfo_t* l;
441     int         handle;
442         
443     if (lump >= numlumps)
444         I_Error ("W_ReadLump: %i >= numlumps",lump);
445
446     l = lumpinfo+lump;
447         
448     // ??? I_BeginRead ();
449         
450     if (l->handle == -1)
451     {
452         // reloadable file, so use open / read / close
453         if ( (handle = I_Open (reloadname)) == -1)
454             I_Error ("W_ReadLump: couldn't open %s",reloadname);
455     }
456     else
457         handle = l->handle;
458                 
459     I_Seek (handle, l->position);
460     c = I_Read (handle, dest, l->size);
461
462     if (c < l->size)
463         I_Error ("W_ReadLump: only read %i of %i on lump %i",
464                  c,l->size,lump);       
465
466     if (l->handle == -1)
467         I_Close (handle);
468
469     // ??? I_EndRead ();
470 }
471
472
473
474
475 //
476 // W_CacheLumpNum
477 //
478 void*
479 W_CacheLumpNum
480 ( int           lump,
481   int           tag )
482 {
483     if ((unsigned)lump >= numlumps)
484         I_Error ("W_CacheLumpNum: %i >= numlumps",lump);
485                 
486     if (!lumpcache[lump])
487     {
488         // read the lump in
489         
490         //printf ("cache miss on lump %i\n",lump);
491         Z_Malloc (W_LumpLength (lump), tag, &lumpcache[lump]);
492         W_ReadLump (lump, lumpcache[lump]);
493     }
494     else
495     {
496         //printf ("cache hit on lump %i\n",lump);
497         Z_ChangeTag (lumpcache[lump],tag);
498     }
499         
500     return lumpcache[lump];
501 }
502
503
504
505 //
506 // W_CacheLumpName
507 //
508 void*
509 W_CacheLumpName
510 ( char*         name,
511   int           tag )
512 {
513     return W_CacheLumpNum (W_GetNumForName(name), tag);
514 }
515
516
517 //
518 // W_Profile
519 //
520 int             info[2500][10];
521 int             profilecount;
522
523 void W_Profile (void)
524 {
525     int         i;
526     memblock_t* block;
527     void*       ptr;
528     char        ch;
529     FILE*       f;
530     int         j;
531     char        name[9];
532         
533         
534     for (i=0 ; i<numlumps ; i++)
535     {   
536         ptr = lumpcache[i];
537         if (!ptr)
538         {
539             continue;
540         }
541         else
542         {
543             block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
544             if (block->tag < PU_PURGELEVEL)
545                 ch = 'S';
546             else
547                 ch = 'P';
548         }
549         info[i][profilecount] = ch;
550     }
551     profilecount++;
552         
553     f = fopen ("waddump.txt","w");
554     name[8] = 0;
555
556     for (i=0 ; i<numlumps ; i++)
557     {
558         memcpy (name,lumpinfo[i].name,8);
559
560         for (j=0 ; j<8 ; j++)
561             if (!name[j])
562                 break;
563
564         for ( ; j<8 ; j++)
565             name[j] = ' ';
566
567         fprintf (f,"%s ",name);
568
569         for (j=0 ; j<profilecount ; j++)
570             fprintf (f,"    %c",info[i][j]);
571
572         fprintf (f,"\n");
573     }
574     fclose (f);
575 }
576
577