2 //**************************************************************************
4 //** w_wad.c : Heretic 2 : Raven Software, Corp.
11 //**************************************************************************
13 // HEADER FILES ------------------------------------------------------------
18 #include <unistd.h> /* jim open() etc. */
19 #include <ctype.h> /* jim toupper() */
27 // MACROS ------------------------------------------------------------------
29 #if defined(NeXT) || defined(__linux) || defined(__FreeBSD__)
30 // NeXT doesn't need a binary flag in open call
32 #define strcmpi strcasecmp
35 // TYPES -------------------------------------------------------------------
39 char identification[4];
51 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
53 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
55 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
57 void W_MergeLumps(char *start, char *end);
59 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
61 // PUBLIC DATA DEFINITIONS -------------------------------------------------
67 // PRIVATE DATA DEFINITIONS ------------------------------------------------
69 static lumpinfo_t *PrimaryLumpInfo;
70 static int PrimaryNumLumps;
71 static void **PrimaryLumpCache;
72 static lumpinfo_t *AuxiliaryLumpInfo;
73 static int AuxiliaryNumLumps;
74 static void **AuxiliaryLumpCache;
75 static int AuxiliaryHandle = 0;
76 boolean AuxiliaryOpened = false;
78 // CODE --------------------------------------------------------------------
80 #if defined(NeXT) || defined(__linux) || defined(__FreeBSD__)
81 //==========================================================================
85 //==========================================================================
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 *) alloca(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;
336 //==========================================================================
340 // Initialize the primary from a single file.
342 //==========================================================================
344 void W_InitFile(char *filename)
350 W_InitMultipleFiles(names);
353 //==========================================================================
357 //==========================================================================
359 void W_OpenAuxiliary(char *filename)
366 filelump_t *fileinfo;
367 filelump_t *sourceLump;
368 lumpinfo_t *destLump;
374 if((handle = open(filename, O_RDONLY|O_BINARY)) == -1)
376 I_Error("W_OpenAuxiliary: %s not found.", filename);
379 AuxiliaryHandle = handle;
380 read(handle, &header, sizeof(header));
381 if(strncmp(header.identification, "IWAD", 4))
383 if(strncmp(header.identification, "PWAD", 4))
385 I_Error("Wad file %s doesn't have IWAD or PWAD id\n",
389 header.numlumps = LONG(header.numlumps);
390 header.infotableofs = LONG(header.infotableofs);
391 length = header.numlumps*sizeof(filelump_t);
392 fileinfo = Z_Malloc(length, PU_STATIC, 0);
393 lseek(handle, header.infotableofs, SEEK_SET);
394 read(handle, fileinfo, length);
395 numlumps = header.numlumps;
397 // Init the auxiliary lumpinfo array
398 lumpinfo = Z_Malloc(numlumps*sizeof(lumpinfo_t), PU_STATIC, 0);
399 sourceLump = fileinfo;
401 for(i = 0; i < numlumps; i++, destLump++, sourceLump++)
403 destLump->handle = handle;
404 destLump->position = LONG(sourceLump->filepos);
405 destLump->size = LONG(sourceLump->size);
406 strncpy(destLump->name, sourceLump->name, 8);
410 // Allocate the auxiliary lumpcache array
411 size = numlumps*sizeof(*lumpcache);
412 lumpcache = Z_Malloc(size, PU_STATIC, 0);
413 memset(lumpcache, 0, size);
415 AuxiliaryLumpInfo = lumpinfo;
416 AuxiliaryLumpCache = lumpcache;
417 AuxiliaryNumLumps = numlumps;
418 AuxiliaryOpened = true;
421 //==========================================================================
425 //==========================================================================
427 void W_CloseAuxiliary(void)
434 for(i = 0; i < numlumps; i++)
438 Z_Free(lumpcache[i]);
441 Z_Free(AuxiliaryLumpInfo);
442 Z_Free(AuxiliaryLumpCache);
443 W_CloseAuxiliaryFile();
444 AuxiliaryOpened = false;
449 //==========================================================================
451 // W_CloseAuxiliaryFile
453 // WARNING: W_CloseAuxiliary() must be called before any further
454 // auxiliary lump processing.
456 //==========================================================================
458 void W_CloseAuxiliaryFile(void)
462 close(AuxiliaryHandle);
467 //==========================================================================
471 //==========================================================================
473 void W_UsePrimary(void)
475 lumpinfo = PrimaryLumpInfo;
476 numlumps = PrimaryNumLumps;
477 lumpcache = PrimaryLumpCache;
480 //==========================================================================
484 //==========================================================================
486 void W_UseAuxiliary(void)
488 if(AuxiliaryOpened == false)
490 I_Error("W_UseAuxiliary: WAD not opened.");
492 lumpinfo = AuxiliaryLumpInfo;
493 numlumps = AuxiliaryNumLumps;
494 lumpcache = AuxiliaryLumpCache;
497 //==========================================================================
501 //==========================================================================
508 //==========================================================================
512 // Returns -1 if name not found.
514 //==========================================================================
516 int W_CheckNumForName(char *name)
522 // Make the name into two integers for easy compares
523 strncpy(name8, name, 8);
524 name8[8] = 0; // in case the name was a full 8 chars
525 strupr(name8); // case insensitive
527 v2 = *(int *)&name8[4];
529 // Scan backwards so patch lump files take precedence
530 lump_p = lumpinfo+numlumps;
531 while(lump_p-- != lumpinfo)
533 if(*(int *)lump_p->name == v1 && *(int *)&lump_p->name[4] == v2)
535 return lump_p-lumpinfo;
541 //==========================================================================
545 // Calls W_CheckNumForName, but bombs out if not found.
547 //==========================================================================
549 int W_GetNumForName (char *name)
553 i = W_CheckNumForName(name);
559 printf("W_GetNumForName: %s not found! Assuming shareware wad.\n", name);
562 I_Error("W_GetNumForName: %s not found!", name);
567 //==========================================================================
571 // Returns the buffer size needed to load the given lump.
573 //==========================================================================
575 int W_LumpLength(int lump)
579 I_Error("W_LumpLength: %i >= numlumps", lump);
581 return lumpinfo[lump].size;
584 //==========================================================================
588 // Loads the lump into the given buffer, which must be >= W_LumpLength().
590 //==========================================================================
592 void W_ReadLump(int lump, void *dest)
599 I_Error("W_ReadLump: %i >= numlumps", lump);
603 lseek(l->handle, l->position, SEEK_SET);
604 c = read(l->handle, dest, l->size);
607 I_Error("W_ReadLump: only read %i of %i on lump %i",
613 //==========================================================================
617 //==========================================================================
619 void *W_CacheLumpNum(int lump, int tag)
623 if((unsigned)lump >= numlumps)
625 I_Error("W_CacheLumpNum: %i >= numlumps", lump);
628 { // Need to read the lump in
629 ptr = Z_Malloc(W_LumpLength(lump), tag, &lumpcache[lump]);
630 W_ReadLump(lump, lumpcache[lump]);
634 Z_ChangeTag(lumpcache[lump], tag);
636 return lumpcache[lump];
639 //==========================================================================
643 //==========================================================================
645 void *W_CacheLumpName(char *name, int tag)
647 return W_CacheLumpNum(W_GetNumForName(name), tag);
650 //==========================================================================
654 //==========================================================================
656 // Ripped out for Heretic
661 void W_Profile (void)
672 for (i=0 ; i<numlumps ; i++)
682 block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
683 if (block->tag < PU_PURGELEVEL)
688 info[i][profilecount] = ch;
692 f = fopen ("waddump.txt","w");
694 for (i=0 ; i<numlumps ; i++)
696 memcpy (name,lumpinfo[i].name,8);
697 for (j=0 ; j<8 ; j++)
702 fprintf (f,"%s ",name);
703 for (j=0 ; j<profilecount ; j++)
704 fprintf (f," %c",info[i][j]);