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 //==========================================================================
93 //==========================================================================
97 //==========================================================================
99 int filelength(int handle)
101 struct stat fileinfo;
103 if(fstat(handle, &fileinfo) == -1)
105 I_Error("Error fstating");
107 return fileinfo.st_size;
111 //==========================================================================
115 // Files with a .wad extension are wadlink files with multiple lumps,
116 // other files are single lumps with the base filename for the lump name.
118 //==========================================================================
120 void W_AddFile(char *filename)
128 filelump_t *fileinfo, singleinfo;
129 filelump_t *freeFileInfo;
131 /* Add support for HHEXEN_DATA envirionment variable */
132 snprintf (path, 128, "%s/%s", getenv("HHEXEN_DATA"), filename);
133 if((handle = open(path, O_RDONLY|O_BINARY)) == -1)
136 if((handle = open(filename, O_RDONLY|O_BINARY)) == -1)
137 { // Didn't find file
141 startlump = numlumps;
142 if(strcmpi(filename+strlen(filename)-3, "wad"))
143 { // Single lump file
144 fileinfo = &singleinfo;
146 singleinfo.filepos = 0;
147 singleinfo.size = LONG(filelength(handle));
148 M_ExtractFileBase(filename, singleinfo.name);
153 read(handle, &header, sizeof(header));
154 if(strncmp(header.identification, "IWAD", 4))
156 if(strncmp(header.identification, "PWAD", 4))
158 I_Error("Wad file %s doesn't have IWAD or PWAD id\n",
162 header.numlumps = LONG(header.numlumps);
163 header.infotableofs = LONG(header.infotableofs);
164 length = header.numlumps*sizeof(filelump_t);
165 // fileinfo = alloca(length);
166 if(!(fileinfo = malloc(length)))
168 I_Error("W_AddFile: fileinfo malloc failed\n");
170 freeFileInfo = fileinfo;
171 lseek(handle, header.infotableofs, SEEK_SET);
172 read(handle, fileinfo, length);
173 numlumps += header.numlumps;
177 lumpinfo = realloc(lumpinfo, numlumps*sizeof(lumpinfo_t));
180 I_Error("Couldn't realloc lumpinfo");
182 lump_p = &lumpinfo[startlump];
183 for(i = startlump; i < numlumps; i++, lump_p++, fileinfo++)
185 lump_p->handle = handle;
186 lump_p->position = LONG(fileinfo->filepos);
187 lump_p->size = LONG(fileinfo->size);
188 strncpy(lump_p->name, fileinfo->name, 8);
196 //==========================================================================
198 // W_InitMultipleFiles
200 // Pass a null terminated list of files to use. All files are optional,
201 // but at least one file must be found. Lump names can appear multiple
202 // times. The name searcher looks backwards, so a later file can
203 // override an earlier one.
205 //==========================================================================
207 void W_InitMultipleFiles(char **filenames)
211 // Open all the files, load headers, and count lumps
213 lumpinfo = malloc(1); // Will be realloced as lumps are added
215 for(; *filenames; filenames++)
217 W_AddFile(*filenames);
221 I_Error("W_InitMultipleFiles: no files found");
224 // Merge lumps for flats and sprites
225 W_MergeLumps("S_START","S_END");
226 W_MergeLumps("F_START","F_END");
229 size = numlumps*sizeof(*lumpcache);
230 lumpcache = malloc(size);
233 I_Error("Couldn't allocate lumpcache");
235 memset(lumpcache, 0, size);
237 PrimaryLumpInfo = lumpinfo;
238 PrimaryLumpCache = lumpcache;
239 PrimaryNumLumps = numlumps;
242 //==========================================================================
246 // From BOOM/xdoom. Finds an S_START or SS_START marker
248 //==========================================================================
250 static int IsMarker(char *marker, char *name)
252 return !strncasecmp(name, marker, 8) ||
253 (*name == *marker && !strncasecmp(name+1,marker,7));
256 //==========================================================================
260 // From xdoom/BOOM again. Merges all sprite lumps into one big 'ol block
262 //==========================================================================
264 void W_MergeLumps(char *start, char *end)
266 lumpinfo_t *newlumpinfo;
267 int newlumps, oldlumps;
271 newlumpinfo = (lumpinfo_t *) malloc(numlumps * sizeof(lumpinfo_t));
272 oldlumps = newlumps = 0;
274 for(i=0;i < numlumps;i++)
276 //process lumps in global namespace
279 //check for start of block
280 if (IsMarker(start, lumpinfo[i].name))
286 memset(newlumpinfo[0].name,0,8);
287 strcpy(newlumpinfo[0].name, start);
288 newlumpinfo[0].handle = -1;
289 newlumpinfo[0].position = newlumpinfo[0].size = 0;
295 lumpinfo[oldlumps++] = lumpinfo[i];
298 // process lumps in sprites or flats namespace
301 // check for end of block
302 if (IsMarker(end, lumpinfo[i].name))
306 else if (i && lumpinfo[i].handle != lumpinfo[i-1].handle)
309 lumpinfo[oldlumps++] = lumpinfo[i];
313 newlumpinfo[newlumps++] = lumpinfo[i];
318 // now copy the merged lumps to the end of the old list
321 if (oldlumps + newlumps > numlumps)
322 lumpinfo = realloc(lumpinfo, (oldlumps + newlumps) *
324 memcpy(lumpinfo + oldlumps, newlumpinfo, sizeof(lumpinfo_t) * newlumps);
326 numlumps = oldlumps + newlumps;
328 memset(lumpinfo[numlumps].name, 0, 8);
329 strcpy(lumpinfo[numlumps].name, end);
330 lumpinfo[numlumps].handle = -1;
331 lumpinfo[numlumps].position = lumpinfo[numlumps].size = 0;
337 //==========================================================================
341 // Initialize the primary from a single file.
343 //==========================================================================
345 void W_InitFile(char *filename)
351 W_InitMultipleFiles(names);
354 //==========================================================================
358 //==========================================================================
360 void W_OpenAuxiliary(char *filename)
367 filelump_t *fileinfo;
368 filelump_t *sourceLump;
369 lumpinfo_t *destLump;
375 if((handle = open(filename, O_RDONLY|O_BINARY)) == -1)
377 I_Error("W_OpenAuxiliary: %s not found.", filename);
380 AuxiliaryHandle = handle;
381 read(handle, &header, sizeof(header));
382 if(strncmp(header.identification, "IWAD", 4))
384 if(strncmp(header.identification, "PWAD", 4))
386 I_Error("Wad file %s doesn't have IWAD or PWAD id\n",
390 header.numlumps = LONG(header.numlumps);
391 header.infotableofs = LONG(header.infotableofs);
392 length = header.numlumps*sizeof(filelump_t);
393 fileinfo = Z_Malloc(length, PU_STATIC, 0);
394 lseek(handle, header.infotableofs, SEEK_SET);
395 read(handle, fileinfo, length);
396 numlumps = header.numlumps;
398 // Init the auxiliary lumpinfo array
399 lumpinfo = Z_Malloc(numlumps*sizeof(lumpinfo_t), PU_STATIC, 0);
400 sourceLump = fileinfo;
402 for(i = 0; i < numlumps; i++, destLump++, sourceLump++)
404 destLump->handle = handle;
405 destLump->position = LONG(sourceLump->filepos);
406 destLump->size = LONG(sourceLump->size);
407 strncpy(destLump->name, sourceLump->name, 8);
411 // Allocate the auxiliary lumpcache array
412 size = numlumps*sizeof(*lumpcache);
413 lumpcache = Z_Malloc(size, PU_STATIC, 0);
414 memset(lumpcache, 0, size);
416 AuxiliaryLumpInfo = lumpinfo;
417 AuxiliaryLumpCache = lumpcache;
418 AuxiliaryNumLumps = numlumps;
419 AuxiliaryOpened = true;
422 //==========================================================================
426 //==========================================================================
428 void W_CloseAuxiliary(void)
435 for(i = 0; i < numlumps; i++)
439 Z_Free(lumpcache[i]);
442 Z_Free(AuxiliaryLumpInfo);
443 Z_Free(AuxiliaryLumpCache);
444 W_CloseAuxiliaryFile();
445 AuxiliaryOpened = false;
450 //==========================================================================
452 // W_CloseAuxiliaryFile
454 // WARNING: W_CloseAuxiliary() must be called before any further
455 // auxiliary lump processing.
457 //==========================================================================
459 void W_CloseAuxiliaryFile(void)
463 close(AuxiliaryHandle);
468 //==========================================================================
472 //==========================================================================
474 void W_UsePrimary(void)
476 lumpinfo = PrimaryLumpInfo;
477 numlumps = PrimaryNumLumps;
478 lumpcache = PrimaryLumpCache;
481 //==========================================================================
485 //==========================================================================
487 void W_UseAuxiliary(void)
489 if(AuxiliaryOpened == false)
491 I_Error("W_UseAuxiliary: WAD not opened.");
493 lumpinfo = AuxiliaryLumpInfo;
494 numlumps = AuxiliaryNumLumps;
495 lumpcache = AuxiliaryLumpCache;
498 //==========================================================================
502 //==========================================================================
509 //==========================================================================
513 // Returns -1 if name not found.
515 //==========================================================================
517 int W_CheckNumForName(char *name)
523 // Make the name into two integers for easy compares
524 strncpy(name8, name, 8);
525 name8[8] = 0; // in case the name was a full 8 chars
526 strupr(name8); // case insensitive
528 v2 = *(int *)&name8[4];
530 // Scan backwards so patch lump files take precedence
531 lump_p = lumpinfo+numlumps;
532 while(lump_p-- != lumpinfo)
534 if(*(int *)lump_p->name == v1 && *(int *)&lump_p->name[4] == v2)
536 return lump_p-lumpinfo;
542 //==========================================================================
546 // Calls W_CheckNumForName, but bombs out if not found.
548 //==========================================================================
550 int W_GetNumForName (char *name)
554 i = W_CheckNumForName(name);
560 printf("W_GetNumForName: %s not found! Assuming shareware wad.\n", name);
563 I_Error("W_GetNumForName: %s not found!", name);
568 //==========================================================================
572 // Returns the buffer size needed to load the given lump.
574 //==========================================================================
576 int W_LumpLength(int lump)
580 I_Error("W_LumpLength: %i >= numlumps", lump);
582 return lumpinfo[lump].size;
585 //==========================================================================
589 // Loads the lump into the given buffer, which must be >= W_LumpLength().
591 //==========================================================================
593 void W_ReadLump(int lump, void *dest)
600 I_Error("W_ReadLump: %i >= numlumps", lump);
604 lseek(l->handle, l->position, SEEK_SET);
605 c = read(l->handle, dest, l->size);
608 I_Error("W_ReadLump: only read %i of %i on lump %i",
614 //==========================================================================
618 //==========================================================================
620 void *W_CacheLumpNum(int lump, int tag)
624 if((unsigned)lump >= numlumps)
626 I_Error("W_CacheLumpNum: %i >= numlumps", lump);
629 { // Need to read the lump in
630 ptr = Z_Malloc(W_LumpLength(lump), tag, &lumpcache[lump]);
631 W_ReadLump(lump, lumpcache[lump]);
635 Z_ChangeTag(lumpcache[lump], tag);
637 return lumpcache[lump];
640 //==========================================================================
644 //==========================================================================
646 void *W_CacheLumpName(char *name, int tag)
648 return W_CacheLumpNum(W_GetNumForName(name), tag);
651 void W_CheckForOldFiles (void)
653 if(W_CheckNumForName("clus1msg") == -1)
655 ST_Message ("\nIt appears that you are using a Version 1.0 \'hexen.wad\' file. Running HHexen\n");
656 ST_Message ("without a Version 1.1 wadfile can cause many problems.\n");
657 ST_Message ("\nPress <ENTER> to continue.\n");
662 //==========================================================================
666 //==========================================================================
668 // Ripped out for Heretic
673 void W_Profile (void)
684 for (i=0 ; i<numlumps ; i++)
694 block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
695 if (block->tag < PU_PURGELEVEL)
700 info[i][profilecount] = ch;
704 f = fopen ("waddump.txt","w");
706 for (i=0 ; i<numlumps ; i++)
708 memcpy (name,lumpinfo[i].name,8);
709 for (j=0 ; j<8 ; j++)
714 fprintf (f,"%s ",name);
715 for (j=0 ; j<profilecount ; j++)
716 fprintf (f," %c",info[i][j]);