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)
135 filelump_t *fileinfo, singleinfo;
136 filelump_t *freeFileInfo;
138 if((handle = open(filename, O_RDONLY|O_BINARY)) == -1)
139 { // Didn't find file
142 startlump = numlumps;
143 if(strcmpi(filename+strlen(filename)-3, "wad"))
144 { // Single lump file
145 fileinfo = &singleinfo;
147 singleinfo.filepos = 0;
148 singleinfo.size = LONG(filelength(handle));
149 M_ExtractFileBase(filename, singleinfo.name);
154 read(handle, &header, sizeof(header));
155 if(strncmp(header.identification, "IWAD", 4))
157 if(strncmp(header.identification, "PWAD", 4))
159 I_Error("Wad file %s doesn't have IWAD or PWAD id\n",
163 header.numlumps = LONG(header.numlumps);
164 header.infotableofs = LONG(header.infotableofs);
165 length = header.numlumps*sizeof(filelump_t);
166 // fileinfo = alloca(length);
167 if(!(fileinfo = malloc(length)))
169 I_Error("W_AddFile: fileinfo malloc failed\n");
171 freeFileInfo = fileinfo;
172 lseek(handle, header.infotableofs, SEEK_SET);
173 read(handle, fileinfo, length);
174 numlumps += header.numlumps;
178 lumpinfo = realloc(lumpinfo, numlumps*sizeof(lumpinfo_t));
181 I_Error("Couldn't realloc lumpinfo");
183 lump_p = &lumpinfo[startlump];
184 for(i = startlump; i < numlumps; i++, lump_p++, fileinfo++)
186 lump_p->handle = handle;
187 lump_p->position = LONG(fileinfo->filepos);
188 lump_p->size = LONG(fileinfo->size);
189 strncpy(lump_p->name, fileinfo->name, 8);
197 //==========================================================================
199 // W_InitMultipleFiles
201 // Pass a null terminated list of files to use. All files are optional,
202 // but at least one file must be found. Lump names can appear multiple
203 // times. The name searcher looks backwards, so a later file can
204 // override an earlier one.
206 //==========================================================================
208 void W_InitMultipleFiles(char **filenames)
212 // Open all the files, load headers, and count lumps
214 lumpinfo = malloc(1); // Will be realloced as lumps are added
216 for(; *filenames; filenames++)
218 W_AddFile(*filenames);
222 I_Error("W_InitMultipleFiles: no files found");
225 // Merge lumps for flats and sprites
226 W_MergeLumps("S_START","S_END");
227 W_MergeLumps("F_START","F_END");
230 size = numlumps*sizeof(*lumpcache);
231 lumpcache = malloc(size);
234 I_Error("Couldn't allocate lumpcache");
236 memset(lumpcache, 0, size);
238 PrimaryLumpInfo = lumpinfo;
239 PrimaryLumpCache = lumpcache;
240 PrimaryNumLumps = numlumps;
243 //==========================================================================
247 // From BOOM/xdoom. Finds an S_START or SS_START marker
249 //==========================================================================
251 static int IsMarker(char *marker, char *name)
253 return !strncasecmp(name, marker, 8) ||
254 (*name == *marker && !strncasecmp(name+1,marker,7));
257 //==========================================================================
261 // From xdoom/BOOM again. Merges all sprite lumps into one big 'ol block
263 //==========================================================================
265 void W_MergeLumps(char *start, char *end)
267 lumpinfo_t *newlumpinfo;
268 int newlumps, oldlumps;
272 newlumpinfo = (lumpinfo_t *) alloca(numlumps * sizeof(lumpinfo_t));
273 oldlumps = newlumps = 0;
275 for(i=0;i < numlumps;i++)
277 //process lumps in global namespace
280 //check for start of block
281 if (IsMarker(start, lumpinfo[i].name))
287 memset(newlumpinfo[0].name,0,8);
288 strcpy(newlumpinfo[0].name, start);
289 newlumpinfo[0].handle = -1;
290 newlumpinfo[0].position = newlumpinfo[0].size = 0;
296 lumpinfo[oldlumps++] = lumpinfo[i];
299 // process lumps in sprites or flats namespace
302 // check for end of block
303 if (IsMarker(end, lumpinfo[i].name))
307 else if (i && lumpinfo[i].handle != lumpinfo[i-1].handle)
310 lumpinfo[oldlumps++] = lumpinfo[i];
314 newlumpinfo[newlumps++] = lumpinfo[i];
319 // now copy the merged lumps to the end of the old list
322 if (oldlumps + newlumps > numlumps)
323 lumpinfo = realloc(lumpinfo, (oldlumps + newlumps) *
325 memcpy(lumpinfo + oldlumps, newlumpinfo, sizeof(lumpinfo_t) * newlumps);
327 numlumps = oldlumps + newlumps;
329 memset(lumpinfo[numlumps].name, 0, 8);
330 strcpy(lumpinfo[numlumps].name, end);
331 lumpinfo[numlumps].handle = -1;
332 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 //==========================================================================
655 //==========================================================================
657 // Ripped out for Heretic
662 void W_Profile (void)
673 for (i=0 ; i<numlumps ; i++)
683 block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
684 if (block->tag < PU_PURGELEVEL)
689 info[i][profilecount] = ch;
693 f = fopen ("waddump.txt","w");
695 for (i=0 ; i<numlumps ; i++)
697 memcpy (name,lumpinfo[i].name,8);
698 for (j=0 ; j<8 ; j++)
703 fprintf (f,"%s ",name);
704 for (j=0 ; j<profilecount ; j++)
705 fprintf (f," %c",info[i][j]);