ref: 21f6a1501d32f541673f8226d4b2292aef920c2b
dir: /w_wad.c/
//**************************************************************************
//**
//** w_wad.c : Heretic 2 : Raven Software, Corp.
//**
//** $Revision: 586 $
//** $Date: 2012-08-31 21:51:13 +0300 (Fri, 31 Aug 2012) $
//**
//**************************************************************************
// HEADER FILES ------------------------------------------------------------
#include "h2stdinc.h"
#include "h2def.h"
// MACROS ------------------------------------------------------------------
/* Old (beta) PC demo from hexen.zip, "Released October 2nd, 1995" */
#define OLDDEMO_LUMPS 2762
#define OLDDEMO_WADSIZE 10615976
/* PC Shareware from hexndemo.zip, "Re-released October 18th, 1995" */
#define PCDEMO_LUMPS 2856
#define PCDEMO_WADSIZE 10644136
/* Mac Shareware: */
#define MACDEMO_LUMPS 3500
#define MACDEMO_WADSIZE 13596228
/* PC Retail, original: */
#define RETAIL10_LUMPS 4249
#define RETAIL10_SIZE 20128392
/* PC Retail, patched : */
#define RETAIL11_LUMPS 4270
#define RETAIL11_SIZE 20083672
/* Macintosh, retail : */
#define MACRETAIL_LUMPS 4567
#define MACRETAIL_SIZE 21078584
/* DeathKings, original: */
#define DKINGS10_LUMPS 325
#define DKINGS10_SIZE 4429700
/* DeathKings, patched : */
#define DKINGS11_LUMPS 326
#define DKINGS11_SIZE 4440584
// 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 ---------------------------------------------
static void W_MergeLumps(const char *start, const char *end);
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
// PUBLIC DATA DEFINITIONS -------------------------------------------------
const char *waddir;
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 --------------------------------------------------------------------
boolean W_IsWadPresent(const char *filename)
{
char path[MAX_OSPATH];
int handle = -1;
/* try the directory from the command line or
* from the shared data environment variable.
*/
if (waddir && *waddir)
{
snprintf (path, sizeof(path), "%s/%s", waddir, filename);
handle = open(path, OREAD);
}
#if !defined(_NO_USERDIRS)
if (handle == -1) /* Try UserDIR */
{
snprintf (path, sizeof(path), "%s%s", basePath, filename);
handle = open(path, OREAD);
}
#endif /* !_NO_USERDIRS */
if (handle == -1) /* Now try CWD */
{
handle = open(filename, OREAD);
}
if (handle == -1)
return false; /* Didn't find the file. */
close(handle);
return true;
}
//==========================================================================
//
// 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(const char *filename)
{
wadinfo_t header;
lumpinfo_t *lump_p;
char path[MAX_OSPATH];
int handle, length, flength;
int startlump;
filelump_t *fileinfo, singleinfo;
filelump_t *freeFileInfo;
int i, j;
byte *c;
handle = -1;
/* try the directory from the command line or
* from the shared data environment variable.
*/
if (waddir && *waddir)
{
snprintf (path, sizeof(path), "%s/%s", waddir, filename);
handle = open(path, OREAD);
}
#if !defined(_NO_USERDIRS)
if (handle == -1) /* Try UserDIR */
{
snprintf (path, sizeof(path), "%s%s", basePath, filename);
handle = open(path, OREAD);
}
#endif /* !_NO_USERDIRS */
if (handle == -1) /* Now try CWD */
{
handle = open(filename, OREAD);
}
if (handle == -1)
return; /* Didn't find the file. */
flength = filelength(handle);
startlump = numlumps;
if (strcmp(filename + strlen(filename) - 3, "wad") != 0)
{ // Single lump file
fileinfo = &singleinfo;
freeFileInfo = NULL;
singleinfo.filepos = 0;
singleinfo.size = LONG(flength);
M_ExtractFileBase(filename, singleinfo.name);
numlumps++;
}
else
{ // WAD file
read(handle, &header, sizeof(header));
if (strncmp(header.identification, "IWAD", 4) != 0)
{
if (strncmp(header.identification, "PWAD", 4) != 0)
{ // 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);
if (strncmp(header.identification, "IWAD", 4) == 0 &&
header.numlumps == PCDEMO_LUMPS && flength == PCDEMO_WADSIZE)
{
shareware = true;
ST_Message("Shareware WAD detected (4 level 1.0 PC version).\n");
}
else if (strncmp(header.identification, "IWAD", 4) == 0 &&
header.numlumps == MACDEMO_LUMPS && flength == MACDEMO_WADSIZE)
{
shareware = true;
ST_Message("Shareware WAD detected (4 level 1.1 Mac version).\n");
}
else if (strncmp(header.identification, "IWAD", 4) == 0 &&
header.numlumps == OLDDEMO_LUMPS && flength == OLDDEMO_WADSIZE)
{
shareware = true;
/* This old beta version is not supported: it is missing
* at least the FONTAY_S, chess and orb lumps. Its demos
* do not play correctly, either. Just reject it. */
I_Error("Beta Shareware WAD from 2 Oct. 1995 not supported.");
}
fileinfo = (filelump_t *) malloc(length);
if (!fileinfo)
{
I_Error("W_AddFile: fileinfo malloc failed\n");
}
freeFileInfo = fileinfo;
seek(handle, header.infotableofs, 0);
read(handle, fileinfo, length);
numlumps += header.numlumps;
}
// Fill in lumpinfo
lumpinfo = (lumpinfo_t *) 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++)
{
memset(lump_p->name, 0, 8);
lump_p->handle = handle;
lump_p->position = LONG(fileinfo->filepos);
lump_p->size = LONG(fileinfo->size);
strncpy(lump_p->name, fileinfo->name, 8);
/* In the Mac demo wad, many (1784) of the lump names
* have their first character with the high bit (0x80)
* set. I don't know the reason for that.. We must
* clear the high bits for such Mac wad files to work
* in this engine. This shouldn't break other wads. */
c = (byte *)lump_p->name;
for (j = 0; j < 8; c++, j++)
*c &= 0x7f;
}
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(const char **filenames)
{
int size;
// Open all the files, load headers, and count lumps
numlumps = 0;
lumpinfo = (lumpinfo_t *) malloc(1); // Will be realloced as lumps are added
for ( ; *filenames; filenames++)
{
W_AddFile(*filenames);
}
if (!numlumps)
{
I_Error("W_InitMultipleFiles: no files found");
}
// Merge lumps for flats and sprites
W_MergeLumps("S_START","S_END");
W_MergeLumps("F_START","F_END");
// Set up caching
size = numlumps * sizeof(*lumpcache);
lumpcache = (void **) malloc(size);
if (!lumpcache)
{
I_Error("Couldn't allocate lumpcache");
}
memset(lumpcache, 0, size);
PrimaryLumpInfo = lumpinfo;
PrimaryLumpCache = lumpcache;
PrimaryNumLumps = numlumps;
}
//==========================================================================
//
// IsMarker
//
// From BOOM/xdoom. Finds an S_START or SS_START marker
//
//==========================================================================
static int IsMarker(const char *marker, const char *name)
{
return !cistrncmp(name, marker, 8) ||
(*name == *marker && !cistrncmp(name + 1, marker, 7));
}
//==========================================================================
//
// W_MergeLumps
//
// From xdoom/BOOM again. Merges all sprite lumps into one big 'ol block
//
//==========================================================================
static void W_MergeLumps(const char *start, const char *end)
{
lumpinfo_t *newlumpinfo;
int newlumps, oldlumps;
int in_block = 0;
int i;
oldlumps = newlumps = 0;
newlumpinfo = (lumpinfo_t *) malloc(numlumps * sizeof(lumpinfo_t));
if (!newlumpinfo)
{
I_Error("W_MergeLumps: newlumpinfo malloc failed");
}
for (i = 0; i < numlumps; i++)
{
//process lumps in global namespace
if (!in_block)
{
//check for start of block
if (IsMarker(start, lumpinfo[i].name))
{
in_block = 1;
if (!newlumps)
{
newlumps++;
memset(newlumpinfo[0].name, 0, 8);
strcpy(newlumpinfo[0].name, start);
newlumpinfo[0].handle = -1;
newlumpinfo[0].position = newlumpinfo[0].size = 0;
}
}
// else copy it
else
{
lumpinfo[oldlumps++] = lumpinfo[i];
}
}
// process lumps in sprites or flats namespace
else
{
// check for end of block
if (IsMarker(end, lumpinfo[i].name))
{
in_block = 0;
}
else if (i && lumpinfo[i].handle != lumpinfo[i-1].handle)
{
in_block = 0;
lumpinfo[oldlumps++] = lumpinfo[i];
}
else
{
newlumpinfo[newlumps++] = lumpinfo[i];
}
}
}
// now copy the merged lumps to the end of the old list
if (newlumps)
{
if (oldlumps + newlumps > numlumps)
lumpinfo = (lumpinfo_t *) realloc(lumpinfo, (oldlumps + newlumps) * sizeof(lumpinfo_t));
memcpy(lumpinfo + oldlumps, newlumpinfo, sizeof(lumpinfo_t) * newlumps);
numlumps = oldlumps + newlumps;
memset(lumpinfo[numlumps].name, 0, 8);
strcpy(lumpinfo[numlumps].name, end);
lumpinfo[numlumps].handle = -1;
lumpinfo[numlumps].position = lumpinfo[numlumps].size = 0;
numlumps++;
}
free (newlumpinfo);
}
//==========================================================================
//
// W_InitFile
//
// Initialize the primary from a single file.
//
//==========================================================================
void W_InitFile(const char *filename)
{
const char *names[2];
names[0] = filename;
names[1] = NULL;
W_InitMultipleFiles(names);
}
//==========================================================================
//
// W_OpenAuxiliary
//
//==========================================================================
void W_OpenAuxiliary(const 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, OREAD)) == -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 = (filelump_t *) Z_Malloc(length, PU_STATIC, NULL);
seek(handle, header.infotableofs, 0);
read(handle, fileinfo, length);
numlumps = header.numlumps;
// Init the auxiliary lumpinfo array
lumpinfo = (lumpinfo_t *) Z_Malloc(numlumps*sizeof(lumpinfo_t), PU_STATIC, NULL);
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 = (void **) Z_Malloc(size, PU_STATIC, NULL);
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(const char *name)
{
char name8[9];
lumpinfo_t *lump_p;
// Make the name into two integers for easy compares
memset(name8, 0, sizeof(name8));
strncpy(name8, name, 8);
strupr(name8); // case insensitive
// Scan backwards so patch lump files take precedence
lump_p = lumpinfo + numlumps;
while (lump_p-- != lumpinfo)
{
if (memcmp(lump_p->name, name8, 8) == 0)
{
return (int)(lump_p - lumpinfo);
}
}
return -1;
}
//==========================================================================
//
// W_GetNumForName
//
// Calls W_CheckNumForName, but bombs out if not found.
//
//==========================================================================
int W_GetNumForName (const 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();
seek(l->handle, l->position, 0);
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)
{
if ((unsigned)lump >= numlumps)
{
I_Error("W_CacheLumpNum: %i >= numlumps", lump);
}
if (!lumpcache[lump])
{ // Need to read the lump in
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(const char *name, int tag)
{
return W_CacheLumpNum(W_GetNumForName(name), tag);
}
void W_CheckWADFiles (void)
{
char lumpmsg[10];
int i;
if (W_CheckNumForName("PRSGCRED") != -1)
mac_hexen = true; /* credits page lump for Mac port by Presage is present. */
strcpy (lumpmsg, "CLUS1MSG");
for (i = 1; i <= 4 && oldwad_10 != true; i++)
{
lumpmsg[4] = '0' + i;
if (W_CheckNumForName(lumpmsg) == -1)
oldwad_10 = true;
}
strcpy (lumpmsg, "WIN1MSG");
for (i = 1; i <= 3 && oldwad_10 != true; i++)
{
lumpmsg[3] = '0' + i;
if (W_CheckNumForName(lumpmsg) == -1)
oldwad_10 = true;
}
#if 0
if (shareware)
{
ST_Message ("\n========================================================================\n");
ST_Message (" Hexen: Beyond Heretic\n\n");
ST_Message (" 4 Level Demo Version\n");
ST_Message (" Press any key to continue.\n");
ST_Message ("========================================================================\n\n");
getchar();
}
#endif
#if defined(DEMO_VERSION)
if (shareware != true)
I_Error ("\nShareware WAD not detected.\nThis exe is configured only for the DEMO version of Hexen!\n");
#endif /* Shareware-only */
#if defined(VERSION10_WAD)
if (oldwad_10 != true)
I_Error ("\nThis exe is configured only for Hexen 1.0 (4-player-only) wad files!\n");
ST_Message ("Running with 4-player-only Version 1.0 hexen.wad files.\n");
#else
if (oldwad_10 == true)
{
ST_Message ("\nIt appears that you are using a 4-player-only Version 1.0 hexen.wad.\n");
ST_Message ("Running HHexen without a Version 1.1 wadfile can cause many problems.\n");
ST_Message ("\nPress <ENTER> to continue.\n");
USED(getchar());
}
#endif
}
//==========================================================================
//
// W_Profile
//
//==========================================================================
// Ripped out for Heretic
/*
static int info[2500][10];
static 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);
}
*/