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() */
24 // MACROS ------------------------------------------------------------------
26 #if defined(NeXT) || defined(__linux) || defined(__FreeBSD__)
27 // NeXT doesn't need a binary flag in open call
29 #define strcmpi strcasecmp
32 // TYPES -------------------------------------------------------------------
36 char identification[4];
48 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
50 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
52 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
54 void W_MergeLumps(char *start, char *end);
56 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
58 // PUBLIC DATA DEFINITIONS -------------------------------------------------
64 // PRIVATE DATA DEFINITIONS ------------------------------------------------
66 static lumpinfo_t *PrimaryLumpInfo;
67 static int PrimaryNumLumps;
68 static void **PrimaryLumpCache;
69 static lumpinfo_t *AuxiliaryLumpInfo;
70 static int AuxiliaryNumLumps;
71 static void **AuxiliaryLumpCache;
72 static int AuxiliaryHandle = 0;
73 boolean AuxiliaryOpened = false;
75 // CODE --------------------------------------------------------------------
77 #if defined(NeXT) || defined(__linux) || defined(__FreeBSD__)
78 //==========================================================================
82 //==========================================================================
90 //==========================================================================
94 //==========================================================================
96 int filelength(int handle)
100 if(fstat(handle, &fileinfo) == -1)
102 I_Error("Error fstating");
104 return fileinfo.st_size;
108 //==========================================================================
112 // Files with a .wad extension are wadlink files with multiple lumps,
113 // other files are single lumps with the base filename for the lump name.
115 //==========================================================================
117 void W_AddFile(char *filename)
125 filelump_t *fileinfo, singleinfo;
126 filelump_t *freeFileInfo;
128 /* Add support for HHEXEN_DATA envirionment variable */
129 snprintf (path, 128, "%s/%s", getenv("HHEXEN_DATA"), filename);
130 if((handle = open(path, O_RDONLY|O_BINARY)) == -1)
133 if((handle = open(filename, O_RDONLY|O_BINARY)) == -1)
134 { // Didn't find file
138 startlump = numlumps;
139 if(strcmpi(filename+strlen(filename)-3, "wad"))
140 { // Single lump file
141 fileinfo = &singleinfo;
143 singleinfo.filepos = 0;
144 singleinfo.size = LONG(filelength(handle));
145 M_ExtractFileBase(filename, singleinfo.name);
150 read(handle, &header, sizeof(header));
151 if(strncmp(header.identification, "IWAD", 4))
153 if(strncmp(header.identification, "PWAD", 4))
155 I_Error("Wad file %s doesn't have IWAD or PWAD id\n",
159 header.numlumps = LONG(header.numlumps);
160 header.infotableofs = LONG(header.infotableofs);
161 length = header.numlumps*sizeof(filelump_t);
162 // fileinfo = alloca(length);
163 if(!(fileinfo = malloc(length)))
165 I_Error("W_AddFile: fileinfo malloc failed\n");
167 freeFileInfo = fileinfo;
168 lseek(handle, header.infotableofs, SEEK_SET);
169 read(handle, fileinfo, length);
170 numlumps += header.numlumps;
174 lumpinfo = realloc(lumpinfo, numlumps*sizeof(lumpinfo_t));
177 I_Error("Couldn't realloc lumpinfo");
179 lump_p = &lumpinfo[startlump];
180 for(i = startlump; i < numlumps; i++, lump_p++, fileinfo++)
182 lump_p->handle = handle;
183 lump_p->position = LONG(fileinfo->filepos);
184 lump_p->size = LONG(fileinfo->size);
185 strncpy(lump_p->name, fileinfo->name, 8);
193 //==========================================================================
195 // W_InitMultipleFiles
197 // Pass a null terminated list of files to use. All files are optional,
198 // but at least one file must be found. Lump names can appear multiple
199 // times. The name searcher looks backwards, so a later file can
200 // override an earlier one.
202 //==========================================================================
204 void W_InitMultipleFiles(char **filenames)
208 // Open all the files, load headers, and count lumps
210 lumpinfo = malloc(1); // Will be realloced as lumps are added
212 for(; *filenames; filenames++)
214 W_AddFile(*filenames);
218 I_Error("W_InitMultipleFiles: no files found");
221 // Merge lumps for flats and sprites
222 W_MergeLumps("S_START","S_END");
223 W_MergeLumps("F_START","F_END");
226 size = numlumps*sizeof(*lumpcache);
227 lumpcache = malloc(size);
230 I_Error("Couldn't allocate lumpcache");
232 memset(lumpcache, 0, size);
234 PrimaryLumpInfo = lumpinfo;
235 PrimaryLumpCache = lumpcache;
236 PrimaryNumLumps = numlumps;
239 //==========================================================================
243 // From BOOM/xdoom. Finds an S_START or SS_START marker
245 //==========================================================================
247 static int IsMarker(char *marker, char *name)
249 return !strncasecmp(name, marker, 8) ||
250 (*name == *marker && !strncasecmp(name+1,marker,7));
253 //==========================================================================
257 // From xdoom/BOOM again. Merges all sprite lumps into one big 'ol block
259 //==========================================================================
261 void W_MergeLumps(char *start, char *end)
263 lumpinfo_t *newlumpinfo;
264 int newlumps, oldlumps;
268 newlumpinfo = (lumpinfo_t *) malloc(numlumps * sizeof(lumpinfo_t));
269 oldlumps = newlumps = 0;
271 for(i=0;i < numlumps;i++)
273 //process lumps in global namespace
276 //check for start of block
277 if (IsMarker(start, lumpinfo[i].name))
283 memset(newlumpinfo[0].name,0,8);
284 strcpy(newlumpinfo[0].name, start);
285 newlumpinfo[0].handle = -1;
286 newlumpinfo[0].position = newlumpinfo[0].size = 0;
292 lumpinfo[oldlumps++] = lumpinfo[i];
295 // process lumps in sprites or flats namespace
298 // check for end of block
299 if (IsMarker(end, lumpinfo[i].name))
303 else if (i && lumpinfo[i].handle != lumpinfo[i-1].handle)
306 lumpinfo[oldlumps++] = lumpinfo[i];
310 newlumpinfo[newlumps++] = lumpinfo[i];
315 // now copy the merged lumps to the end of the old list
318 if (oldlumps + newlumps > numlumps)
319 lumpinfo = realloc(lumpinfo, (oldlumps + newlumps) *
321 memcpy(lumpinfo + oldlumps, newlumpinfo, sizeof(lumpinfo_t) * newlumps);
323 numlumps = oldlumps + newlumps;
325 memset(lumpinfo[numlumps].name, 0, 8);
326 strcpy(lumpinfo[numlumps].name, end);
327 lumpinfo[numlumps].handle = -1;
328 lumpinfo[numlumps].position = lumpinfo[numlumps].size = 0;
334 //==========================================================================
338 // Initialize the primary from a single file.
340 //==========================================================================
342 void W_InitFile(char *filename)
348 W_InitMultipleFiles(names);
351 //==========================================================================
355 //==========================================================================
357 void W_OpenAuxiliary(char *filename)
364 filelump_t *fileinfo;
365 filelump_t *sourceLump;
366 lumpinfo_t *destLump;
372 if((handle = open(filename, O_RDONLY|O_BINARY)) == -1)
374 I_Error("W_OpenAuxiliary: %s not found.", filename);
377 AuxiliaryHandle = handle;
378 read(handle, &header, sizeof(header));
379 if(strncmp(header.identification, "IWAD", 4))
381 if(strncmp(header.identification, "PWAD", 4))
383 I_Error("Wad file %s doesn't have IWAD or PWAD id\n",
387 header.numlumps = LONG(header.numlumps);
388 header.infotableofs = LONG(header.infotableofs);
389 length = header.numlumps*sizeof(filelump_t);
390 fileinfo = Z_Malloc(length, PU_STATIC, 0);
391 lseek(handle, header.infotableofs, SEEK_SET);
392 read(handle, fileinfo, length);
393 numlumps = header.numlumps;
395 // Init the auxiliary lumpinfo array
396 lumpinfo = Z_Malloc(numlumps*sizeof(lumpinfo_t), PU_STATIC, 0);
397 sourceLump = fileinfo;
399 for(i = 0; i < numlumps; i++, destLump++, sourceLump++)
401 destLump->handle = handle;
402 destLump->position = LONG(sourceLump->filepos);
403 destLump->size = LONG(sourceLump->size);
404 strncpy(destLump->name, sourceLump->name, 8);
408 // Allocate the auxiliary lumpcache array
409 size = numlumps*sizeof(*lumpcache);
410 lumpcache = Z_Malloc(size, PU_STATIC, 0);
411 memset(lumpcache, 0, size);
413 AuxiliaryLumpInfo = lumpinfo;
414 AuxiliaryLumpCache = lumpcache;
415 AuxiliaryNumLumps = numlumps;
416 AuxiliaryOpened = true;
419 //==========================================================================
423 //==========================================================================
425 void W_CloseAuxiliary(void)
432 for(i = 0; i < numlumps; i++)
436 Z_Free(lumpcache[i]);
439 Z_Free(AuxiliaryLumpInfo);
440 Z_Free(AuxiliaryLumpCache);
441 W_CloseAuxiliaryFile();
442 AuxiliaryOpened = false;
447 //==========================================================================
449 // W_CloseAuxiliaryFile
451 // WARNING: W_CloseAuxiliary() must be called before any further
452 // auxiliary lump processing.
454 //==========================================================================
456 void W_CloseAuxiliaryFile(void)
460 close(AuxiliaryHandle);
465 //==========================================================================
469 //==========================================================================
471 void W_UsePrimary(void)
473 lumpinfo = PrimaryLumpInfo;
474 numlumps = PrimaryNumLumps;
475 lumpcache = PrimaryLumpCache;
478 //==========================================================================
482 //==========================================================================
484 void W_UseAuxiliary(void)
486 if(AuxiliaryOpened == false)
488 I_Error("W_UseAuxiliary: WAD not opened.");
490 lumpinfo = AuxiliaryLumpInfo;
491 numlumps = AuxiliaryNumLumps;
492 lumpcache = AuxiliaryLumpCache;
495 //==========================================================================
499 //==========================================================================
506 //==========================================================================
510 // Returns -1 if name not found.
512 //==========================================================================
514 int W_CheckNumForName(char *name)
520 // Make the name into two integers for easy compares
521 strncpy(name8, name, 8);
522 name8[8] = 0; // in case the name was a full 8 chars
523 strupr(name8); // case insensitive
525 v2 = *(int *)&name8[4];
527 // Scan backwards so patch lump files take precedence
528 lump_p = lumpinfo+numlumps;
529 while(lump_p-- != lumpinfo)
531 if(*(int *)lump_p->name == v1 && *(int *)&lump_p->name[4] == v2)
533 return lump_p-lumpinfo;
539 //==========================================================================
543 // Calls W_CheckNumForName, but bombs out if not found.
545 //==========================================================================
547 int W_GetNumForName (char *name)
551 i = W_CheckNumForName(name);
557 printf("W_GetNumForName: %s not found! Assuming shareware wad.\n", name);
560 I_Error("W_GetNumForName: %s not found!", name);
565 //==========================================================================
569 // Returns the buffer size needed to load the given lump.
571 //==========================================================================
573 int W_LumpLength(int lump)
577 I_Error("W_LumpLength: %i >= numlumps", lump);
579 return lumpinfo[lump].size;
582 //==========================================================================
586 // Loads the lump into the given buffer, which must be >= W_LumpLength().
588 //==========================================================================
590 void W_ReadLump(int lump, void *dest)
597 I_Error("W_ReadLump: %i >= numlumps", lump);
601 lseek(l->handle, l->position, SEEK_SET);
602 c = read(l->handle, dest, l->size);
605 I_Error("W_ReadLump: only read %i of %i on lump %i",
611 //==========================================================================
615 //==========================================================================
617 void *W_CacheLumpNum(int lump, int tag)
621 if((unsigned)lump >= numlumps)
623 I_Error("W_CacheLumpNum: %i >= numlumps", lump);
626 { // Need to read the lump in
627 ptr = Z_Malloc(W_LumpLength(lump), tag, &lumpcache[lump]);
628 W_ReadLump(lump, lumpcache[lump]);
632 Z_ChangeTag(lumpcache[lump], tag);
634 return lumpcache[lump];
637 //==========================================================================
641 //==========================================================================
643 void *W_CacheLumpName(char *name, int tag)
645 return W_CacheLumpNum(W_GetNumForName(name), tag);
648 void W_CheckForOldFiles (void)
650 if(W_CheckNumForName("clus1msg") == -1)
652 ST_Message ("\nIt appears that you are using a Version 1.0 \'hexen.wad\' file. Running HHexen\n");
653 ST_Message ("without a Version 1.1 wadfile can cause many problems.\n");
654 ST_Message ("\nPress <ENTER> to continue.\n");
659 //==========================================================================
663 //==========================================================================
665 // Ripped out for Heretic
670 void W_Profile (void)
681 for (i=0 ; i<numlumps ; i++)
691 block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
692 if (block->tag < PU_PURGELEVEL)
697 info[i][profilecount] = ch;
701 f = fopen ("waddump.txt","w");
703 for (i=0 ; i<numlumps ; i++)
705 memcpy (name,lumpinfo[i].name,8);
706 for (j=0 ; j<8 ; j++)
711 fprintf (f,"%s ",name);
712 for (j=0 ; j<profilecount ; j++)
713 fprintf (f," %c",info[i][j]);