2 //**************************************************************************
4 //** w_wad.c : Heretic 2 : Raven Software, Corp.
11 //**************************************************************************
13 // HEADER FILES ------------------------------------------------------------
19 #include <unistd.h> /* jim open() etc. */
20 #include <ctype.h> /* jim toupper() */
35 // MACROS ------------------------------------------------------------------
37 #if defined(NeXT) || defined(__linux)
38 // NeXT doesn't need a binary flag in open call
40 #define strcmpi strcasecmp
43 // TYPES -------------------------------------------------------------------
47 char identification[4];
59 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
61 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
63 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
65 void W_MergeLumps(char *start, char *end);
67 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
69 // PUBLIC DATA DEFINITIONS -------------------------------------------------
75 // PRIVATE DATA DEFINITIONS ------------------------------------------------
77 static lumpinfo_t *PrimaryLumpInfo;
78 static int PrimaryNumLumps;
79 static void **PrimaryLumpCache;
80 static lumpinfo_t *AuxiliaryLumpInfo;
81 static int AuxiliaryNumLumps;
82 static void **AuxiliaryLumpCache;
83 static int AuxiliaryHandle = 0;
84 boolean AuxiliaryOpened = false;
86 // CODE --------------------------------------------------------------------
88 #if defined(NeXT) || defined(__linux)
89 //==========================================================================
93 //==========================================================================
101 //==========================================================================
105 //==========================================================================
107 int filelength(int handle)
109 struct stat fileinfo;
111 if(fstat(handle, &fileinfo) == -1)
113 I_Error("Error fstating");
115 return fileinfo.st_size;
119 //==========================================================================
123 // Files with a .wad extension are wadlink files with multiple lumps,
124 // other files are single lumps with the base filename for the lump name.
126 //==========================================================================
128 void W_AddFile(char *filename)
136 filelump_t *fileinfo, singleinfo;
137 filelump_t *freeFileInfo;
139 /* Add support for HHEXEN_DATA envirionment variable */
140 snprintf (path, 128, "%s/%s", getenv("HHEXEN_DATA"), filename);
141 if((handle = open(path, O_RDONLY|O_BINARY)) == -1)
144 if((handle = open(filename, O_RDONLY|O_BINARY)) == -1)
145 { // Didn't find file
149 startlump = numlumps;
150 if(strcmpi(filename+strlen(filename)-3, "wad"))
151 { // Single lump file
152 fileinfo = &singleinfo;
154 singleinfo.filepos = 0;
155 singleinfo.size = LONG(filelength(handle));
156 M_ExtractFileBase(filename, singleinfo.name);
161 read(handle, &header, sizeof(header));
162 if(strncmp(header.identification, "IWAD", 4))
164 if(strncmp(header.identification, "PWAD", 4))
166 I_Error("Wad file %s doesn't have IWAD or PWAD id\n",
170 header.numlumps = LONG(header.numlumps);
171 header.infotableofs = LONG(header.infotableofs);
172 length = header.numlumps*sizeof(filelump_t);
173 // fileinfo = alloca(length);
174 if(!(fileinfo = malloc(length)))
176 I_Error("W_AddFile: fileinfo malloc failed\n");
178 freeFileInfo = fileinfo;
179 lseek(handle, header.infotableofs, SEEK_SET);
180 read(handle, fileinfo, length);
181 numlumps += header.numlumps;
185 lumpinfo = realloc(lumpinfo, numlumps*sizeof(lumpinfo_t));
188 I_Error("Couldn't realloc lumpinfo");
190 lump_p = &lumpinfo[startlump];
191 for(i = startlump; i < numlumps; i++, lump_p++, fileinfo++)
193 lump_p->handle = handle;
194 lump_p->position = LONG(fileinfo->filepos);
195 lump_p->size = LONG(fileinfo->size);
196 strncpy(lump_p->name, fileinfo->name, 8);
204 //==========================================================================
206 // W_InitMultipleFiles
208 // Pass a null terminated list of files to use. All files are optional,
209 // but at least one file must be found. Lump names can appear multiple
210 // times. The name searcher looks backwards, so a later file can
211 // override an earlier one.
213 //==========================================================================
215 void W_InitMultipleFiles(char **filenames)
219 // Open all the files, load headers, and count lumps
221 lumpinfo = malloc(1); // Will be realloced as lumps are added
223 for(; *filenames; filenames++)
225 W_AddFile(*filenames);
229 I_Error("W_InitMultipleFiles: no files found");
232 // Merge lumps for flats and sprites
233 W_MergeLumps("S_START","S_END");
234 W_MergeLumps("F_START","F_END");
237 size = numlumps*sizeof(*lumpcache);
238 lumpcache = malloc(size);
241 I_Error("Couldn't allocate lumpcache");
243 memset(lumpcache, 0, size);
245 PrimaryLumpInfo = lumpinfo;
246 PrimaryLumpCache = lumpcache;
247 PrimaryNumLumps = numlumps;
250 //==========================================================================
254 // From BOOM/xdoom. Finds an S_START or SS_START marker
256 //==========================================================================
258 static int IsMarker(char *marker, char *name)
260 return !strncasecmp(name, marker, 8) ||
261 (*name == *marker && !strncasecmp(name+1,marker,7));
264 //==========================================================================
268 // From xdoom/BOOM again. Merges all sprite lumps into one big 'ol block
270 //==========================================================================
272 void W_MergeLumps(char *start, char *end)
274 lumpinfo_t *newlumpinfo;
275 int newlumps, oldlumps;
279 newlumpinfo = (lumpinfo_t *) alloca(numlumps * sizeof(lumpinfo_t));
280 oldlumps = newlumps = 0;
282 for(i=0;i < numlumps;i++)
284 //process lumps in global namespace
287 //check for start of block
288 if (IsMarker(start, lumpinfo[i].name))
294 memset(newlumpinfo[0].name,0,8);
295 strcpy(newlumpinfo[0].name, start);
296 newlumpinfo[0].handle = -1;
297 newlumpinfo[0].position = newlumpinfo[0].size = 0;
303 lumpinfo[oldlumps++] = lumpinfo[i];
306 // process lumps in sprites or flats namespace
309 // check for end of block
310 if (IsMarker(end, lumpinfo[i].name))
314 else if (i && lumpinfo[i].handle != lumpinfo[i-1].handle)
317 lumpinfo[oldlumps++] = lumpinfo[i];
321 newlumpinfo[newlumps++] = lumpinfo[i];
326 // now copy the merged lumps to the end of the old list
329 if (oldlumps + newlumps > numlumps)
330 lumpinfo = realloc(lumpinfo, (oldlumps + newlumps) *
332 memcpy(lumpinfo + oldlumps, newlumpinfo, sizeof(lumpinfo_t) * newlumps);
334 numlumps = oldlumps + newlumps;
336 memset(lumpinfo[numlumps].name, 0, 8);
337 strcpy(lumpinfo[numlumps].name, end);
338 lumpinfo[numlumps].handle = -1;
339 lumpinfo[numlumps].position = lumpinfo[numlumps].size = 0;
344 //==========================================================================
348 // Initialize the primary from a single file.
350 //==========================================================================
352 void W_InitFile(char *filename)
358 W_InitMultipleFiles(names);
361 //==========================================================================
365 //==========================================================================
367 void W_OpenAuxiliary(char *filename)
374 filelump_t *fileinfo;
375 filelump_t *sourceLump;
376 lumpinfo_t *destLump;
382 if((handle = open(filename, O_RDONLY|O_BINARY)) == -1)
384 I_Error("W_OpenAuxiliary: %s not found.", filename);
387 AuxiliaryHandle = handle;
388 read(handle, &header, sizeof(header));
389 if(strncmp(header.identification, "IWAD", 4))
391 if(strncmp(header.identification, "PWAD", 4))
393 I_Error("Wad file %s doesn't have IWAD or PWAD id\n",
397 header.numlumps = LONG(header.numlumps);
398 header.infotableofs = LONG(header.infotableofs);
399 length = header.numlumps*sizeof(filelump_t);
400 fileinfo = Z_Malloc(length, PU_STATIC, 0);
401 lseek(handle, header.infotableofs, SEEK_SET);
402 read(handle, fileinfo, length);
403 numlumps = header.numlumps;
405 // Init the auxiliary lumpinfo array
406 lumpinfo = Z_Malloc(numlumps*sizeof(lumpinfo_t), PU_STATIC, 0);
407 sourceLump = fileinfo;
409 for(i = 0; i < numlumps; i++, destLump++, sourceLump++)
411 destLump->handle = handle;
412 destLump->position = LONG(sourceLump->filepos);
413 destLump->size = LONG(sourceLump->size);
414 strncpy(destLump->name, sourceLump->name, 8);
418 // Allocate the auxiliary lumpcache array
419 size = numlumps*sizeof(*lumpcache);
420 lumpcache = Z_Malloc(size, PU_STATIC, 0);
421 memset(lumpcache, 0, size);
423 AuxiliaryLumpInfo = lumpinfo;
424 AuxiliaryLumpCache = lumpcache;
425 AuxiliaryNumLumps = numlumps;
426 AuxiliaryOpened = true;
429 //==========================================================================
433 //==========================================================================
435 void W_CloseAuxiliary(void)
442 for(i = 0; i < numlumps; i++)
446 Z_Free(lumpcache[i]);
449 Z_Free(AuxiliaryLumpInfo);
450 Z_Free(AuxiliaryLumpCache);
451 W_CloseAuxiliaryFile();
452 AuxiliaryOpened = false;
457 //==========================================================================
459 // W_CloseAuxiliaryFile
461 // WARNING: W_CloseAuxiliary() must be called before any further
462 // auxiliary lump processing.
464 //==========================================================================
466 void W_CloseAuxiliaryFile(void)
470 close(AuxiliaryHandle);
475 //==========================================================================
479 //==========================================================================
481 void W_UsePrimary(void)
483 lumpinfo = PrimaryLumpInfo;
484 numlumps = PrimaryNumLumps;
485 lumpcache = PrimaryLumpCache;
488 //==========================================================================
492 //==========================================================================
494 void W_UseAuxiliary(void)
496 if(AuxiliaryOpened == false)
498 I_Error("W_UseAuxiliary: WAD not opened.");
500 lumpinfo = AuxiliaryLumpInfo;
501 numlumps = AuxiliaryNumLumps;
502 lumpcache = AuxiliaryLumpCache;
505 //==========================================================================
509 //==========================================================================
516 //==========================================================================
520 // Returns -1 if name not found.
522 //==========================================================================
524 int W_CheckNumForName(char *name)
530 // Make the name into two integers for easy compares
531 strncpy(name8, name, 8);
532 name8[8] = 0; // in case the name was a full 8 chars
533 strupr(name8); // case insensitive
535 v2 = *(int *)&name8[4];
537 // Scan backwards so patch lump files take precedence
538 lump_p = lumpinfo+numlumps;
539 while(lump_p-- != lumpinfo)
541 if(*(int *)lump_p->name == v1 && *(int *)&lump_p->name[4] == v2)
543 return lump_p-lumpinfo;
549 //==========================================================================
553 // Calls W_CheckNumForName, but bombs out if not found.
555 //==========================================================================
557 int W_GetNumForName (char *name)
561 i = W_CheckNumForName(name);
567 printf("W_GetNumForName: %s not found! Assuming shareware wad.\n", name);
570 I_Error("W_GetNumForName: %s not found!", name);
575 //==========================================================================
579 // Returns the buffer size needed to load the given lump.
581 //==========================================================================
583 int W_LumpLength(int lump)
587 I_Error("W_LumpLength: %i >= numlumps", lump);
589 return lumpinfo[lump].size;
592 //==========================================================================
596 // Loads the lump into the given buffer, which must be >= W_LumpLength().
598 //==========================================================================
600 void W_ReadLump(int lump, void *dest)
607 I_Error("W_ReadLump: %i >= numlumps", lump);
611 lseek(l->handle, l->position, SEEK_SET);
612 c = read(l->handle, dest, l->size);
615 I_Error("W_ReadLump: only read %i of %i on lump %i",
621 //==========================================================================
625 //==========================================================================
627 void *W_CacheLumpNum(int lump, int tag)
631 if((unsigned)lump >= numlumps)
633 I_Error("W_CacheLumpNum: %i >= numlumps", lump);
636 { // Need to read the lump in
637 ptr = Z_Malloc(W_LumpLength(lump), tag, &lumpcache[lump]);
638 W_ReadLump(lump, lumpcache[lump]);
642 Z_ChangeTag(lumpcache[lump], tag);
644 return lumpcache[lump];
647 //==========================================================================
651 //==========================================================================
653 void *W_CacheLumpName(char *name, int tag)
655 return W_CacheLumpNum(W_GetNumForName(name), tag);
658 //==========================================================================
662 //==========================================================================
664 // Ripped out for Heretic
669 void W_Profile (void)
680 for (i=0 ; i<numlumps ; i++)
690 block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
691 if (block->tag < PU_PURGELEVEL)
696 info[i][profilecount] = ch;
700 f = fopen ("waddump.txt","w");
702 for (i=0 ; i<numlumps ; i++)
704 memcpy (name,lumpinfo[i].name,8);
705 for (j=0 ; j<8 ; j++)
710 fprintf (f,"%s ",name);
711 for (j=0 ; j<profilecount ; j++)
712 fprintf (f," %c",info[i][j]);