ref: d7f9fa826e8483d66de33131f471b2f8aa28a81c
dir: /src/w_wad.c/
// Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // // $Id: w_wad.c 58 2005-08-30 22:15:11Z fraggle $ // // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005 Simon Howard // // 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. // // $Log$ // Revision 1.7 2005/08/30 22:15:11 fraggle // More Windows fixes // // Revision 1.6 2005/08/30 22:11:10 fraggle // Windows fixes // // Revision 1.5 2005/08/04 18:42:15 fraggle // Silence compiler warnings // // Revision 1.4 2005/08/04 01:13:46 fraggle // Loading disk // // Revision 1.3 2005/07/23 18:50:34 fraggle // Use standard C file functions for WAD code // // Revision 1.2 2005/07/23 16:44:57 fraggle // Update copyright to GNU GPL // // Revision 1.1.1.1 2005/07/23 16:20:39 fraggle // Initial import // // // DESCRIPTION: // Handles WAD file header, directory, lump I/O. // //----------------------------------------------------------------------------- static const char rcsid[] = "$Id: w_wad.c 58 2005-08-30 22:15:11Z fraggle $"; #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "doomtype.h" #include "m_swap.h" #include "i_system.h" #include "i_video.h" #include "z_zone.h" #include "w_wad.h" // // GLOBALS // // Location of each lump on disk. lumpinfo_t* lumpinfo; int numlumps; void** lumpcache; #define strcmpi strcasecmp void string_to_upper (char* s) { while (*s) { *s = toupper(*s); s++; } } int filelength (FILE *handle) { long savedpos; long length; // save the current position in the file savedpos = ftell(handle); // jump to the end and find the length fseek(handle, 0, SEEK_END); length = ftell(handle); // go back to the old location fseek(handle, savedpos, SEEK_SET); return length; } void ExtractFileBase ( char* path, char* dest ) { char* src; int length; src = path + strlen(path) - 1; // back up until a \ or the start while (src != path && *(src-1) != '\\' && *(src-1) != '/') { src--; } // copy up to eight characters memset (dest,0,8); length = 0; while (*src && *src != '.') { if (++length == 9) I_Error ("Filename base of %s >8 chars",path); *dest++ = toupper((int)*src++); } } // // LUMP BASED ROUTINES. // // // W_AddFile // All files are optional, but at least one file must be // found (PWAD, if all required lumps are present). // Files with a .wad extension are wadlink files // with multiple lumps. // Other files are single lumps with the base filename // for the lump name. // // If filename starts with a tilde, the file is handled // specially to allow map reloads. // But: the reload feature is a fragile hack... int reloadlump; char* reloadname; void W_AddFile (char *filename) { wadinfo_t header; lumpinfo_t* lump_p; unsigned i; FILE *handle; int length; int startlump; filelump_t* fileinfo; filelump_t* filerover; FILE *storehandle; // open the file and add to directory // handle reload indicator. if (filename[0] == '~') { filename++; reloadname = filename; reloadlump = numlumps; } if ( (handle = fopen(filename,"rb")) == NULL) { printf (" couldn't open %s\n",filename); return; } printf (" adding %s\n",filename); startlump = numlumps; if (strcmpi (filename+strlen(filename)-3 , "wad" ) ) { // single lump file fileinfo = Z_Malloc(sizeof(filelump_t), PU_STATIC, 0); fileinfo->filepos = 0; fileinfo->size = LONG(filelength(handle)); ExtractFileBase (filename, fileinfo->name); numlumps++; } else { // WAD file fread (&header, sizeof(header), 1, handle); if (strncmp(header.identification,"IWAD",4)) { // Homebrew levels? if (strncmp(header.identification,"PWAD",4)) { I_Error ("Wad file %s doesn't have IWAD " "or PWAD id\n", filename); } // ???modifiedgame = true; } header.numlumps = LONG(header.numlumps); header.infotableofs = LONG(header.infotableofs); length = header.numlumps*sizeof(filelump_t); fileinfo = Z_Malloc(length, PU_STATIC, 0); fseek(handle, header.infotableofs, SEEK_SET); fread(fileinfo, length, 1, handle); 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]; storehandle = reloadname ? NULL : handle; for (i=startlump,filerover=fileinfo ; i<numlumps ; i++,lump_p++, filerover++) { lump_p->handle = storehandle; lump_p->position = LONG(filerover->filepos); lump_p->size = LONG(filerover->size); strncpy (lump_p->name, filerover->name, 8); } if (reloadname) fclose (handle); Z_Free(fileinfo); } // // W_Reload // Flushes any of the reloadable lumps in memory // and reloads the directory. // void W_Reload (void) { wadinfo_t header; int lumpcount; lumpinfo_t* lump_p; unsigned i; FILE *handle; int length; filelump_t* fileinfo; if (!reloadname) return; if ( (handle = fopen(reloadname,"rb")) == NULL) I_Error ("W_Reload: couldn't open %s",reloadname); fread(&header, sizeof(header), 1, handle); lumpcount = LONG(header.numlumps); header.infotableofs = LONG(header.infotableofs); length = lumpcount*sizeof(filelump_t); fileinfo = Z_Malloc(length, PU_STATIC, 0); fseek(handle, header.infotableofs, SEEK_SET); fread(fileinfo, length, 1, handle); // Fill in lumpinfo lump_p = &lumpinfo[reloadlump]; for (i=reloadlump ; i<reloadlump+lumpcount ; i++,lump_p++, fileinfo++) { if (lumpcache[i]) Z_Free (lumpcache[i]); lump_p->position = LONG(fileinfo->filepos); lump_p->size = LONG(fileinfo->size); } fclose(handle); Z_Free(fileinfo); } // // W_InitMultipleFiles // Pass a null terminated list of files to use. // All files are optional, but at least one file // must be found. // Files with a .wad extension are idlink files // with multiple lumps. // Other files are single lumps with the base filename // for the lump name. // Lump names can appear multiple times. // The name searcher looks backwards, so a later file // does override all earlier ones. // void W_InitMultipleFiles (char** filenames) { int size; // open all the files, load headers, and count lumps numlumps = 0; // will be realloced as lumps are added lumpinfo = malloc(1); for ( ; *filenames ; filenames++) W_AddFile (*filenames); if (!numlumps) I_Error ("W_InitFiles: 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); } // // W_InitFile // Just initialize from a single file. // void W_InitFile (char* filename) { char* names[2]; names[0] = filename; names[1] = NULL; W_InitMultipleFiles (names); } // // W_NumLumps // int W_NumLumps (void) { return numlumps; } // // W_CheckNumForName // Returns -1 if name not found. // int W_CheckNumForName (char* name) { union { char s[9]; int x[2]; } name8; int v1; int v2; lumpinfo_t* lump_p; // make the name into two integers for easy compares strncpy (name8.s,name,8); // in case the name was a fill 8 chars name8.s[8] = 0; // case insensitive string_to_upper (name8.s); v1 = name8.x[0]; v2 = name8.x[1]; // 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; } } // TFB. Not found. 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) I_Error ("W_GetNumForName: %s not found!", name); return i; } // // 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; FILE *handle; if (lump >= numlumps) I_Error ("W_ReadLump: %i >= numlumps",lump); l = lumpinfo+lump; I_BeginRead (); if (l->handle == NULL) { // reloadable file, so use open / read / close if ( (handle = fopen(reloadname,"rb")) == NULL) I_Error ("W_ReadLump: couldn't open %s",reloadname); } else handle = l->handle; fseek(handle, l->position, SEEK_SET); c = fread (dest, 1, l->size, handle); if (c < l->size) I_Error ("W_ReadLump: only read %i of %i on lump %i", c,l->size,lump); if (l->handle == NULL) fclose (handle); 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]) { // read the lump in //printf ("cache miss on lump %i\n",lump); ptr = Z_Malloc (W_LumpLength (lump), tag, &lumpcache[lump]); W_ReadLump (lump, lumpcache[lump]); } else { //printf ("cache hit on lump %i\n",lump); 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 // 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); }