heretic/Heretic Source/W_WAD.C

496 lines
7.8 KiB
C

// W_wad.c
#ifdef NeXT
#include <libc.h>
#include <ctype.h>
// next doesn't need a binary flag in open call
#define O_BINARY 0
#else
#include <malloc.h>
#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#endif
#include "DoomDef.h"
//===============
// TYPES
//===============
typedef struct
{
char identification[4]; // should be IWAD
int numlumps;
int infotableofs;
} wadinfo_t;
typedef struct
{
int filepos;
int size;
char name[8];
} filelump_t;
//=============
// GLOBALS
//=============
lumpinfo_t *lumpinfo; // location of each lump on disk
int numlumps;
void **lumpcache;
//===================
#ifdef NeXT
#define strcmpi strcasecmp
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
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
= 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;
//
// open the file and add to directory
//
if ( (handle = open (filename,O_RDONLY | O_BINARY)) == -1)
return;
startlump = numlumps;
if (strcmpi (filename+strlen(filename)-3 , "wad" ) )
{
// single lump file
fileinfo = &singleinfo;
singleinfo.filepos = 0;
singleinfo.size = LONG(filelength(handle));
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))
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);
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);
}
}
/*
====================
=
= 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 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_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)
{
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 fill 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])
{ // 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
=
====================
*/
// 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);
}
*/