ref: e3f638419404fe03e5af0cf9607d550b55fe6c0c
dir: /src/hexen/w_wad.c/
// Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. // //----------------------------------------------------------------------------- // HEADER FILES ------------------------------------------------------------ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <fcntl.h> #include "h2def.h" // MACROS ------------------------------------------------------------------ #ifndef O_BINARY #define O_BINARY 0 #endif // TYPES ------------------------------------------------------------------- typedef struct { char identification[4]; int numlumps; int infotableofs; } wadinfo_t; typedef struct { int filepos; int size; char name[8]; } filelump_t; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- // EXTERNAL DATA DECLARATIONS ---------------------------------------------- // PUBLIC DATA DEFINITIONS ------------------------------------------------- lumpinfo_t *lumpinfo; int numlumps; void **lumpcache; // PRIVATE DATA DEFINITIONS ------------------------------------------------ static lumpinfo_t *PrimaryLumpInfo; static int PrimaryNumLumps; static void **PrimaryLumpCache; static lumpinfo_t *AuxiliaryLumpInfo; static int AuxiliaryNumLumps; static void **AuxiliaryLumpCache; static int AuxiliaryHandle = 0; boolean AuxiliaryOpened = false; // CODE -------------------------------------------------------------------- #ifdef NeXT //========================================================================== // // strupr // //========================================================================== void strupr(char *s) { while (*s) *s++ = toupper(*s); } //========================================================================== // // filelength // //========================================================================== int filelength(int handle) { struct stat fileinfo; if (fstat(handle, &fileinfo) == -1) { I_Error("Error fstating"); } return fileinfo.st_size; } #endif //========================================================================== // // W_AddFile // // Files with a .wad extension are wadlink files with multiple lumps, // other files are single lumps with the base filename for the lump name. // //========================================================================== void W_AddFile(char *filename) { wadinfo_t header; lumpinfo_t *lump_p; unsigned i; int handle, length; int startlump; filelump_t *fileinfo, singleinfo; filelump_t *freeFileInfo; if ((handle = open(filename, O_RDONLY | O_BINARY)) == -1) { // Didn't find file return; } startlump = numlumps; if (strcmpi(filename + strlen(filename) - 3, "wad")) { // Single lump file fileinfo = &singleinfo; freeFileInfo = NULL; singleinfo.filepos = 0; singleinfo.size = LONG(filelength(handle)); M_ExtractFileBase(filename, singleinfo.name); numlumps++; } else { // WAD file read(handle, &header, sizeof(header)); if (strncmp(header.identification, "IWAD", 4)) { if (strncmp(header.identification, "PWAD", 4)) { // Bad file id I_Error("Wad file %s doesn't have IWAD or PWAD id\n", filename); } } header.numlumps = LONG(header.numlumps); header.infotableofs = LONG(header.infotableofs); length = header.numlumps * sizeof(filelump_t); // fileinfo = alloca(length); if (!(fileinfo = malloc(length))) { I_Error("W_AddFile: fileinfo malloc failed\n"); } freeFileInfo = fileinfo; lseek(handle, header.infotableofs, SEEK_SET); read(handle, fileinfo, length); numlumps += header.numlumps; } // Fill in lumpinfo lumpinfo = realloc(lumpinfo, numlumps * sizeof(lumpinfo_t)); if (!lumpinfo) { I_Error("Couldn't realloc lumpinfo"); } lump_p = &lumpinfo[startlump]; for (i = startlump; i < numlumps; i++, lump_p++, fileinfo++) { lump_p->handle = handle; lump_p->position = LONG(fileinfo->filepos); lump_p->size = LONG(fileinfo->size); strncpy(lump_p->name, fileinfo->name, 8); } if (freeFileInfo) { free(freeFileInfo); } } //========================================================================== // // W_InitMultipleFiles // // Pass a null terminated list of files to use. All files are optional, // but at least one file must be found. Lump names can appear multiple // times. The name searcher looks backwards, so a later file can // override an earlier one. // //========================================================================== void W_InitMultipleFiles(char **filenames) { int size; // Open all the files, load headers, and count lumps numlumps = 0; lumpinfo = malloc(1); // Will be realloced as lumps are added for (; *filenames; filenames++) { W_AddFile(*filenames); } if (!numlumps) { I_Error("W_InitMultipleFiles: no files found"); } // Set up caching size = numlumps * sizeof(*lumpcache); lumpcache = malloc(size); if (!lumpcache) { I_Error("Couldn't allocate lumpcache"); } memset(lumpcache, 0, size); PrimaryLumpInfo = lumpinfo; PrimaryLumpCache = lumpcache; PrimaryNumLumps = numlumps; } //========================================================================== // // W_InitFile // // Initialize the primary from a single file. // //========================================================================== void W_InitFile(char *filename) { char *names[2]; names[0] = filename; names[1] = NULL; W_InitMultipleFiles(names); } //========================================================================== // // W_OpenAuxiliary // //========================================================================== void W_OpenAuxiliary(char *filename) { int i; int size; wadinfo_t header; int handle; int length; filelump_t *fileinfo; filelump_t *sourceLump; lumpinfo_t *destLump; if (AuxiliaryOpened) { W_CloseAuxiliary(); } if ((handle = open(filename, O_RDONLY | O_BINARY)) == -1) { I_Error("W_OpenAuxiliary: %s not found.", filename); return; } AuxiliaryHandle = handle; read(handle, &header, sizeof(header)); if (strncmp(header.identification, "IWAD", 4)) { if (strncmp(header.identification, "PWAD", 4)) { // Bad file id I_Error("Wad file %s doesn't have IWAD or PWAD id\n", filename); } } header.numlumps = LONG(header.numlumps); header.infotableofs = LONG(header.infotableofs); length = header.numlumps * sizeof(filelump_t); fileinfo = Z_Malloc(length, PU_STATIC, 0); lseek(handle, header.infotableofs, SEEK_SET); read(handle, fileinfo, length); numlumps = header.numlumps; // Init the auxiliary lumpinfo array lumpinfo = Z_Malloc(numlumps * sizeof(lumpinfo_t), PU_STATIC, 0); sourceLump = fileinfo; destLump = lumpinfo; for (i = 0; i < numlumps; i++, destLump++, sourceLump++) { destLump->handle = handle; destLump->position = LONG(sourceLump->filepos); destLump->size = LONG(sourceLump->size); strncpy(destLump->name, sourceLump->name, 8); } Z_Free(fileinfo); // Allocate the auxiliary lumpcache array size = numlumps * sizeof(*lumpcache); lumpcache = Z_Malloc(size, PU_STATIC, 0); memset(lumpcache, 0, size); AuxiliaryLumpInfo = lumpinfo; AuxiliaryLumpCache = lumpcache; AuxiliaryNumLumps = numlumps; AuxiliaryOpened = true; } //========================================================================== // // W_CloseAuxiliary // //========================================================================== void W_CloseAuxiliary(void) { int i; if (AuxiliaryOpened) { W_UseAuxiliary(); for (i = 0; i < numlumps; i++) { if (lumpcache[i]) { Z_Free(lumpcache[i]); } } Z_Free(AuxiliaryLumpInfo); Z_Free(AuxiliaryLumpCache); W_CloseAuxiliaryFile(); AuxiliaryOpened = false; } W_UsePrimary(); } //========================================================================== // // W_CloseAuxiliaryFile // // WARNING: W_CloseAuxiliary() must be called before any further // auxiliary lump processing. // //========================================================================== void W_CloseAuxiliaryFile(void) { if (AuxiliaryHandle) { close(AuxiliaryHandle); AuxiliaryHandle = 0; } } //========================================================================== // // W_UsePrimary // //========================================================================== void W_UsePrimary(void) { lumpinfo = PrimaryLumpInfo; numlumps = PrimaryNumLumps; lumpcache = PrimaryLumpCache; } //========================================================================== // // W_UseAuxiliary // //========================================================================== void W_UseAuxiliary(void) { if (AuxiliaryOpened == false) { I_Error("W_UseAuxiliary: WAD not opened."); } lumpinfo = AuxiliaryLumpInfo; numlumps = AuxiliaryNumLumps; lumpcache = AuxiliaryLumpCache; } //========================================================================== // // W_NumLumps // //========================================================================== int W_NumLumps(void) { return numlumps; } //========================================================================== // // W_CheckNumForName // // Returns -1 if name not found. // //========================================================================== int W_CheckNumForName(char *name) { char name8[9]; int v1, v2; lumpinfo_t *lump_p; // Make the name into two integers for easy compares strncpy(name8, name, 8); name8[8] = 0; // in case the name was a full 8 chars strupr(name8); // case insensitive v1 = *(int *) name8; v2 = *(int *) &name8[4]; // Scan backwards so patch lump files take precedence lump_p = lumpinfo + numlumps; while (lump_p-- != lumpinfo) { if (*(int *) lump_p->name == v1 && *(int *) &lump_p->name[4] == v2) { return lump_p - lumpinfo; } } return -1; } //========================================================================== // // W_GetNumForName // // Calls W_CheckNumForName, but bombs out if not found. // //========================================================================== int W_GetNumForName(char *name) { int i; i = W_CheckNumForName(name); if (i != -1) { return i; } I_Error("W_GetNumForName: %s not found!", name); return -1; } //========================================================================== // // W_LumpLength // // Returns the buffer size needed to load the given lump. // //========================================================================== int W_LumpLength(int lump) { if (lump >= numlumps) { I_Error("W_LumpLength: %i >= numlumps", lump); } return lumpinfo[lump].size; } //========================================================================== // // W_ReadLump // // Loads the lump into the given buffer, which must be >= W_LumpLength(). // //========================================================================== void W_ReadLump(int lump, void *dest) { int c; lumpinfo_t *l; if (lump >= numlumps) { I_Error("W_ReadLump: %i >= numlumps", lump); } l = lumpinfo + lump; //I_BeginRead(); lseek(l->handle, l->position, SEEK_SET); c = read(l->handle, dest, l->size); if (c < l->size) { I_Error("W_ReadLump: only read %i of %i on lump %i", c, l->size, lump); } //I_EndRead(); } //========================================================================== // // W_CacheLumpNum // //========================================================================== void *W_CacheLumpNum(int lump, int tag) { byte *ptr; if ((unsigned) lump >= numlumps) { I_Error("W_CacheLumpNum: %i >= numlumps", lump); } if (!lumpcache[lump]) { // Need to read the lump in ptr = Z_Malloc(W_LumpLength(lump), tag, &lumpcache[lump]); W_ReadLump(lump, lumpcache[lump]); } else { Z_ChangeTag(lumpcache[lump], tag); } return lumpcache[lump]; } //========================================================================== // // W_CacheLumpName // //========================================================================== void *W_CacheLumpName(char *name, int tag) { return W_CacheLumpNum(W_GetNumForName(name), tag); } //========================================================================== // // W_Profile // //========================================================================== // Ripped out for Heretic /* int info[2500][10]; int profilecount; void W_Profile (void) { int i; memblock_t *block; void *ptr; char ch; FILE *f; int j; char name[9]; for (i=0 ; i<numlumps ; i++) { ptr = lumpcache[i]; if (!ptr) { ch = ' '; continue; } else { block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t)); if (block->tag < PU_PURGELEVEL) ch = 'S'; else ch = 'P'; } info[i][profilecount] = ch; } profilecount++; f = fopen ("waddump.txt","w"); name[8] = 0; for (i=0 ; i<numlumps ; i++) { memcpy (name,lumpinfo[i].name,8); for (j=0 ; j<8 ; j++) if (!name[j]) break; for ( ; j<8 ; j++) name[j] = ' '; fprintf (f,"%s ",name); for (j=0 ; j<profilecount ; j++) fprintf (f," %c",info[i][j]); fprintf (f,"\n"); } fclose (f); } */