ZoneBuilder/Source/Plugins/vpo_dll/w_wad.cc

366 lines
6.7 KiB
C++

//-----------------------------------------------------------------------------
//
// 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.
//
// DESCRIPTION:
// Handles WAD file header, directory, lump I/O.
//
//-----------------------------------------------------------------------------
#include "vpo_local.h"
namespace vpo
{
typedef struct
{
// Should be "IWAD" or "PWAD".
char identification[4];
int numlumps;
int infotableofs;
} PACKEDATTR wadinfo_t;
typedef struct
{
int filepos;
int size;
char name[8];
} PACKEDATTR filelump_t;
//
// GLOBALS
//
// Location of each lump on disk.
lumpinfo_t *lumpinfo;
int numlumps = 0;
static char * wad_filename;
static wad_file_t * current_file;
//
// LUMP BASED ROUTINES.
//
// andrewj: added this to find level names
// returns 0 if not a level, 1 for DOOM, 2 for HEXEN format
static int CheckMapHeader(filelump_t *lumps, int num_after)
{
static const char *level_lumps[] =
{
"THINGS", "LINEDEFS", "SIDEDEFS", "VERTEXES",
"SEGS", "SSECTORS", "NODES", "SECTORS",
"REJECT", "BLOCKMAP"
};
if (num_after < 10)
return 0;
for (int i = 0 ; i < 10 ; i++)
{
const char *name = level_lumps[i];
// level lumps are never valid map header names
if (strncmp(lumps[0].name, name, 8) == 0)
return 0;
// require a one-to-one correspondence
// (anything else would crash DOOM)
if (strncmp(lumps[1 + i].name, name, 8) != 0)
return 0;
}
// hexen format is distinguished by a following BEHAVIOR lump
if (num_after >= 11 && strncmp(lumps[11].name, "BEHAVIOR", 8) == 0)
return 2;
return 1;
}
//
// 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.
bool W_AddFile (const char *filename)
{
wadinfo_t header;
lumpinfo_t *lump_p;
wad_file_t *wad_file;
int i;
int length;
int startlump;
filelump_t *fileinfo;
filelump_t *filerover;
// open the file and add to directory
wad_file = W_OpenFile(filename);
if (wad_file == NULL)
{
return false;
}
startlump = numlumps;
W_Read(wad_file, 0, &header, sizeof(header));
if (strncmp(header.identification,"IWAD",4) != 0)
{
// Homebrew levels?
if (strncmp(header.identification,"PWAD",4) != 0)
{
/// I_Error ("Wad file %s doesn't have IWAD "
/// "or PWAD id\n", filename);
W_CloseFile(wad_file);
return false;
}
}
header.numlumps = LONG(header.numlumps);
header.infotableofs = LONG(header.infotableofs);
length = header.numlumps * sizeof(filelump_t);
fileinfo = new filelump_t[header.numlumps];
W_Read(wad_file, header.infotableofs, fileinfo, length);
numlumps += header.numlumps;
// Fill in lumpinfo
lumpinfo = (lumpinfo_t *)realloc(lumpinfo, numlumps * sizeof(lumpinfo_t));
if (! lumpinfo)
I_Error ("Out of memory -- could not realloc lumpinfo");
lump_p = &lumpinfo[startlump];
filerover = fileinfo;
for (i=startlump; i < numlumps; ++i)
{
int map_header;
lump_p->position = LONG(filerover->filepos);
lump_p->size = LONG(filerover->size);
strncpy(lump_p->name, filerover->name, 8);
map_header = CheckMapHeader(filerover, numlumps - i - 1);
lump_p->is_map_header = (map_header >= 1);
lump_p->is_hexen = (map_header == 2);
++lump_p;
++filerover;
}
delete[] fileinfo;
// close the file now, we re-open it later to load the map
W_CloseFile(wad_file);
wad_filename = strdup(filename);
if (! wad_filename)
I_Error ("Out of memory -- could not strdup filename");
return true;
}
void W_RemoveFile(void)
{
if (wad_filename)
{
free(wad_filename);
wad_filename = NULL;
free(lumpinfo);
lumpinfo = NULL;
numlumps = 0;
}
}
//
// W_NumLumps
//
int W_NumLumps (void)
{
return numlumps;
}
//
// W_CheckNumForName
// Returns -1 if name not found.
//
int W_CheckNumForName (const char* name)
{
int i;
// scan backwards so patch lump files take precedence
for (i=numlumps-1; i >= 0; --i)
{
if (strncasecmp(lumpinfo[i].name, name, 8) == 0)
{
return i;
}
}
// TFB. Not found.
return -1;
}
//
// W_LumpLength
// Returns the buffer size needed to load the given lump.
//
int W_LumpLength (int lumpnum)
{
if (lumpnum >= numlumps)
{
I_Error ("W_LumpLength: %i >= numlumps", lumpnum);
}
return lumpinfo[lumpnum].size;
}
//
// W_ReadLump
// Loads the lump into the given buffer,
// which must be >= W_LumpLength().
//
static 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;
c = W_Read(current_file, l->position, dest, l->size);
if (c < l->size)
{
I_Error ("W_ReadLump: only read %i of %i on lump %i", c, l->size, lump);
}
}
//
// W_LoadLump
//
// Load a lump into memory and return a pointer to a buffer containing
// the lump data.
//
byte * W_LoadLump(int lumpnum)
{
byte *result;
if (lumpnum < 0 || lumpnum >= numlumps)
{
I_Error ("W_LoadLump: %i >= numlumps", lumpnum);
}
if (! current_file)
I_Error ("W_LoadLump: no current file (W_BeginRead not called)");
// load it now
result = new byte[W_LumpLength(lumpnum) + 1];
W_ReadLump (lumpnum, result);
return result;
}
void W_FreeLump(byte * data)
{
delete[] data;
}
void W_BeginRead(void)
{
// check API usage
if (! wad_filename)
I_Error("W_BeginRead called without any wad file!");
if (current_file)
I_Error("W_BeginRead called twice without W_EndRead.");
current_file = W_OpenFile(wad_filename);
// it should normally succeed, as it is unlikely the file suddenly
// disappears between reading the directory and loading a map.
if (! current_file)
I_Error("Could not re-open the wad file -- deleted?");
}
void W_EndRead()
{
if (! current_file)
I_Error("W_EndRead called without a previous W_BeginRead.");
W_CloseFile(current_file);
current_file = NULL;
}
} // namespace vpo
//--- editor settings ---
// vi:ts=4:sw=4:noexpandtab
// Emacs style mode select -*- C++ -*-