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