1 /* W_wad.c */
2
3 #ifdef NeXT
4 #include <libc.h>
5 #include <ctype.h>
6
7 /* next doesn't need a binary flag in open call */
8 #define O_BINARY 0
9
10 #else
11
12 #ifdef UNIX
13 #include <ctype.h>
14 #include <sys/types.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <stdlib.h>
18 #include <assert.h>
19 #include <fcntl.h>
20 #include <sys/stat.h>
21
22 #ifdef HAVE_ALLOCA_H
23 #include <alloca.h>
24 #endif /* HAVE_ALLOCA_H */
25
26 #define O_BINARY 0
27 #endif /* UNIX */
28
29 #ifdef __GLIBC__
30 /* kludge for broken asm-sparc/io.h on linux 2.2.14.? */
31 #ifdef __sparc__
32 #define __KERNEL__
33 #endif
34 #include <asm/system.h>
35 #include <asm/types.h>
36 /* kludge ends */
37 #include <sys/io.h>
38 #else
39 #include <sys/uio.h>
40 #endif /* __GLIBC__ */
41
42 #include <fcntl.h>
43 #include <sys/stat.h>
44 #endif /* NeXT */
45
46 #include "doomdef.h"
47
48
49 #ifndef HOMEDIR
50 #define HOMEDIR "/.heretic"
51 #endif /* HOMEDIR */
52
53
54 /* ===============
55 * TYPES
56 * ===============
57 */
58
59
60 typedef struct
61 {
62 char identification[4]; /* should be IWAD */
63 int numlumps __PACKED__ ;
64 int infotableofs __PACKED__ ;
65 } __PACKED__ wadinfo_t;
66
67
68 typedef struct
69 {
70 int filepos;
71 int size;
72 char name[8];
73 } __PACKED__ filelump_t;
74
75
76 /* =============
77 * GLOBALS
78 * =============
79 */
80
81 lumpinfo_t *lumpinfo; /* location of each lump on disk */
82 int numlumps;
83
84 void **lumpcache;
85
86
87 /* =================== */
88
89 #ifdef UNIX
90
91 #define strcmpi strcasecmp
92
93 /* first character is missing with *s++ ,so this is changed */
strupr(char * s)94 void strupr (char *s)
95 {
96 #if 0
97 while (*s)
98 *s++ = toupper(*s);
99 #endif
100 while (*s) {
101 *s = toupper(*s);
102 s++;
103 }
104 }
105
106 /*
107 ================
108 =
109 = filelength
110 =
111 ================
112 */
113
filelength(int handle)114 int filelength (int handle)
115 {
116 struct stat fileinfo;
117
118 if (fstat (handle,&fileinfo) == -1)
119 I_Error ("Error fstating");
120
121 return fileinfo.st_size;
122 }
123
124 #endif /* UNIX */
125
126
ExtractFileBase(char * path,char * dest)127 void ExtractFileBase (char *path, char *dest)
128 {
129 char *src;
130 int length;
131
132 src = path + strlen(path) - 1;
133
134 /* back up until a \ or the start */
135 while (src != path
136 && *(src-1) != '\\'
137 && *(src-1) != '/')
138 src--;
139
140 /* copy up to eight characters */
141
142 memset (dest,0,8);
143 length = 0;
144
145 while (*src && *src != '.')
146 {
147 if (++length == 9)
148 I_Error ("Filename base of %s >8 chars",path);
149 *dest++ = toupper((int)*src++);
150 }
151 }
152
153
154 /* Helper function */
155
wadopen(const char * fileName)156 int wadopen(const char* fileName)
157 {
158 int fd = -1;
159 char* fn;
160 char* envhome;
161
162
163 fn = (char*) malloc(strlen("./")+strlen(fileName)+1);
164 assert(fn);
165 sprintf(fn, "./%s", fileName);
166 if (!access(fn, R_OK))
167 {
168 fd = open(fn, O_RDONLY | O_BINARY);
169 free(fn);
170 return fd;
171 }
172
173 if ((envhome = getenv("HERETICHOME")) != NULL)
174 {
175 fn = (char*) malloc(strlen(envhome)+strlen("/")+strlen(fileName)+1);
176 assert(fn);
177 sprintf(fn, "%s/%s", envhome, fileName);
178 fd = open(fn, O_RDONLY | O_BINARY);
179 free(fn);
180 }
181
182 if ((fd < 0) && ((envhome = getenv("HOME")) != NULL))
183 {
184 fn = (char*) malloc(strlen(envhome)+strlen(HOMEDIR"/")
185 +strlen(fileName)+1);
186 assert(fn);
187 sprintf(fn, "%s"HOMEDIR"/%s", envhome, fileName);
188 fd = open(fn, O_RDONLY | O_BINARY);
189 free(fn);
190 }
191
192 if ((fd < 0) && (envhome = getenv("PATH")))
193 {
194 char *path = strdup(envhome), *curentry;
195 assert(path);
196 while (strlen(path) && (fd < 0))
197 {
198 if (!(curentry = strrchr(path, ':')))
199 curentry = path;
200 else
201 *curentry++ = 0;
202 fn = (char*) malloc(strlen(curentry)+19+strlen(fileName)); /* Add space for /, ../share/heretic/ */
203 assert(fn);
204 sprintf(fn, "%s/%s", curentry, fileName);
205 fd = open(fn, O_RDONLY | O_BINARY);
206 /* check ../share/heretic */
207 if (fd < 0)
208 {
209 sprintf(fn, "%s/../share/heretic/%s", curentry, fileName);
210 fd = open(fn, O_RDONLY | O_BINARY);
211 }
212 free(fn);
213 *curentry = 0;
214 }
215 free(path);
216 }
217
218 if (fd < 0)
219 fd = open(fileName, O_RDONLY | O_BINARY);
220
221 return fd;
222 }
223
224
225
226 /*
227 ============================================================================
228
229 LUMP BASED ROUTINES
230
231 ============================================================================
232 */
233
234 /*
235 ====================
236 =
237 = W_AddFile
238 =
239 = All files are optional, but at least one file must be found
240 = Files with a .wad extension are wadlink files with multiple lumps
241 = Other files are single lumps with the base filename for the lump name
242 =
243 ====================
244 */
245
W_AddFile(char * filename)246 void W_AddFile (char *filename)
247 {
248 wadinfo_t header;
249 lumpinfo_t *lump_p;
250 unsigned i;
251 int handle;
252 size_t length;
253 int startlump;
254 filelump_t *fileinfo, singleinfo;
255
256 /*
257 * open the file and add to directory
258 */
259
260
261 if ( (handle = wadopen (filename)) == -1)
262 {
263 printf (" couldn't open %s\n",filename);
264 return;
265 }
266
267 printf (" adding %s\n", filename);
268 startlump = numlumps;
269
270 if (strcmpi (filename+strlen(filename)-3 , "wad" ) )
271 {
272 /* single lump file */
273 fileinfo = &singleinfo;
274 singleinfo.filepos = 0;
275 singleinfo.size = LONG(filelength(handle));
276 ExtractFileBase (filename, singleinfo.name);
277 numlumps++;
278 }
279 else
280 {
281 /* WAD file */
282 read (handle, &header, sizeof(header));
283 if (strncmp(header.identification,"IWAD",4))
284 {
285 if (strncmp(header.identification,"PWAD",4))
286 I_Error ("Wad file %s doesn't have IWAD or PWAD id\n"
287 ,filename);
288 }
289 header.numlumps = LONG(header.numlumps);
290 header.infotableofs = LONG(header.infotableofs);
291 length = header.numlumps*sizeof(filelump_t);
292 fileinfo = alloca (length);
293 lseek (handle, header.infotableofs, SEEK_SET);
294 read (handle, fileinfo, length);
295 numlumps += header.numlumps;
296 }
297
298 /* Fill in lumpinfo */
299 lumpinfo = realloc (lumpinfo, numlumps*sizeof(lumpinfo_t));
300 if (!lumpinfo)
301 I_Error ("Couldn't realloc lumpinfo");
302 lump_p = &lumpinfo[startlump];
303
304 for (i=startlump ; i<numlumps ; i++,lump_p++, fileinfo++)
305 {
306 lump_p->handle = handle;
307 lump_p->position = LONG(fileinfo->filepos);
308 lump_p->size = LONG(fileinfo->size);
309 strncpy (lump_p->name, fileinfo->name, 8);
310 }
311 }
312
313
314 /*
315 ====================
316 =
317 = W_InitMultipleFiles
318 =
319 = Pass a null terminated list of files to use.
320 =
321 = All files are optional, but at least one file must be found
322 =
323 = Files with a .wad extension are idlink files with multiple lumps
324 =
325 = Other files are single lumps with the base filename for the lump name
326 =
327 = Lump names can appear multiple times. The name searcher looks backwards,
328 = so a later file can override an earlier one.
329 =
330 ====================
331 */
332
W_InitMultipleFiles(char ** filenames)333 void W_InitMultipleFiles (char **filenames)
334 {
335 int size;
336
337 /* open all the files, load headers, and count lumps */
338 numlumps = 0;
339 lumpinfo = malloc(1); /* will be realloced as lumps are added */
340
341 for ( ; *filenames ; filenames++)
342 W_AddFile (*filenames);
343
344 if (!numlumps)
345 I_Error ("W_InitFiles: no files found");
346
347 /* set up caching */
348 size = numlumps * sizeof(*lumpcache);
349 lumpcache = malloc (size);
350 assert(lumpcache);
351 if (!lumpcache)
352 I_Error ("Couldn't allocate lumpcache");
353 memset (lumpcache,0, size);
354 }
355
356
357 /*
358 ====================
359 =
360 = W_InitFile
361 =
362 = Just initialize from a single file
363 =
364 ====================
365 */
366
W_InitFile(char * filename)367 void W_InitFile (char *filename)
368 {
369 char *names[2];
370
371 names[0] = filename;
372 names[1] = NULL;
373 W_InitMultipleFiles (names);
374 }
375
376
377 /*
378 ====================
379 =
380 = W_NumLumps
381 =
382 ====================
383 */
384
W_NumLumps(void)385 int W_NumLumps (void)
386 {
387 return numlumps;
388 }
389
390
391 /*
392 ====================
393 =
394 = W_CheckNumForName
395 =
396 = Returns -1 if name not found
397 =
398 ====================
399 */
400
W_CheckNumForName(char * name)401 int W_CheckNumForName (char *name)
402 {
403 char name8[9];
404 int v1,v2;
405 lumpinfo_t *lump_p;
406
407 /* make the name into two integers for easy compares */
408
409 strncpy (name8,name,8);
410 name8[8] = 0; /* in case the name was a fill 8 chars */
411 strupr (name8); /* case insensitive */
412
413 v1 = *(int *)name8;
414 v2 = *(int *)&name8[4];
415
416
417 /* scan backwards so patch lump files take precedence */
418
419 lump_p = lumpinfo + numlumps;
420
421 while (lump_p-- != lumpinfo)
422 if ( *(int *)lump_p->name == v1
423 && *(int *)&lump_p->name[4] == v2)
424 return lump_p - lumpinfo;
425
426 return -1;
427 }
428
429
430 /*
431 ====================
432 =
433 = W_GetNumForName
434 =
435 = Calls W_CheckNumForName, but bombs out if not found
436 =
437 ====================
438 */
439
W_GetNumForName(char * name)440 int W_GetNumForName (char *name)
441 {
442 int i;
443
444 i = W_CheckNumForName (name);
445 if (i != -1)
446 return i;
447
448 I_Error ("W_GetNumForName: %s not found!",name);
449 return -1;
450 }
451
452
453 /*
454 ====================
455 =
456 = W_LumpLength
457 =
458 = Returns the buffer size needed to load the given lump
459 =
460 ====================
461 */
462
W_LumpLength(int lump)463 int W_LumpLength (int lump)
464 {
465 if (lump >= numlumps)
466 I_Error ("W_LumpLength: %i >= numlumps",lump);
467 return lumpinfo[lump].size;
468 }
469
470
471 /*
472 ====================
473 =
474 = W_ReadLump
475 =
476 = Loads the lump into the given buffer, which must be >= W_LumpLength()
477 =
478 ====================
479 */
480
W_ReadLump(int lump,void * dest)481 void W_ReadLump (int lump, void *dest)
482 {
483 int c;
484 lumpinfo_t *l;
485
486 if (lump >= numlumps)
487 I_Error ("W_ReadLump: %i >= numlumps",lump);
488 l = lumpinfo+lump;
489
490 /* I_BeginRead (); - for use with DiskIconFlashing... */
491
492 lseek (l->handle, l->position, SEEK_SET);
493 c = read (l->handle, dest, l->size);
494
495 if (c < l->size)
496 I_Error ("W_ReadLump: only read %i of %i on lump %i",c,l->size,lump);
497 /* I_EndRead (); - for use with DiskIconFlashing... */
498 }
499
500
501
502 /*
503 ====================
504 =
505 = W_CacheLumpNum
506 =
507 ====================
508 */
509
W_CacheLumpNum(int lump,int tag)510 void *W_CacheLumpNum (int lump, int tag)
511 {
512 byte *ptr;
513
514 if ((unsigned)lump >= numlumps)
515 I_Error ("W_CacheLumpNum: %i >= numlumps",lump);
516
517 if (!lumpcache[lump])
518 { /* read the lump in */
519 /* printf ("cache miss on lump %i\n",lump); */
520 ptr = Z_Malloc (W_LumpLength (lump), tag, &lumpcache[lump]);
521 W_ReadLump (lump, lumpcache[lump]);
522 }
523 else
524 {
525 /* printf ("cache hit on lump %i\n",lump); */
526 Z_ChangeTag (lumpcache[lump],tag);
527 }
528
529 return lumpcache[lump];
530 }
531
532
533 /*
534 ====================
535 =
536 = W_CacheLumpName
537 =
538 ====================
539 */
540
W_CacheLumpName(char * name,int tag)541 void *W_CacheLumpName (char *name, int tag)
542 {
543 return W_CacheLumpNum (W_GetNumForName(name), tag);
544 }
545
546
547
548 /*
549 ====================
550 =
551 = W_Profile
552 =
553 ====================
554 */
555
556 // Ripped out for Heretic
557 /*
558 int info[2500][10];
559 int profilecount;
560
561 void W_Profile (void)
562 {
563 int i;
564 memblock_t *block;
565 void *ptr;
566 char ch;
567 FILE *f;
568 int j;
569 char name[9];
570
571
572 for (i=0 ; i<numlumps ; i++)
573 {
574 ptr = lumpcache[i];
575 if (!ptr)
576 {
577 ch = ' ';
578 continue;
579 }
580 else
581 {
582 block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
583 if (block->tag < PU_PURGELEVEL)
584 ch = 'S';
585 else
586 ch = 'P';
587 }
588 info[i][profilecount] = ch;
589 }
590 profilecount++;
591
592 f = fopen ("waddump.txt","w");
593 name[8] = 0;
594 for (i=0 ; i<numlumps ; i++)
595 {
596 memcpy (name,lumpinfo[i].name,8);
597 for (j=0 ; j<8 ; j++)
598 if (!name[j])
599 break;
600 for ( ; j<8 ; j++)
601 name[j] = ' ';
602 fprintf (f,"%s ",name);
603 for (j=0 ; j<profilecount ; j++)
604 fprintf (f," %c",info[i][j]);
605 fprintf (f,"\n");
606 }
607 fclose (f);
608 }
609 */
610