quakeforge/libs/util/wadfile.c
Bill Currie ec42bde527 Make hash tables more const correct.
And clean up the resulting mess :/
2012-10-27 11:44:31 +09:00

328 lines
6.9 KiB
C

/*
wadfile.c
wad file support
Copyright (C) 2003 #AUTHOR#
Author: #AUTHOR#
Date: #DATE#
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:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <sys/stat.h>
#include <sys/types.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include "QF/hash.h"
#include "QF/qendian.h"
#include "QF/wad.h"
// case insensitive hash and compare
static uintptr_t
wad_get_hash (const void *l, void *unused)
{
char name[17];
int i;
for (i = 0; i < 16; i++)
name[i] = tolower ((byte) ((lumpinfo_t *) l)->name[i]);
name[16] = 0;
return Hash_String (name);
}
static int
wad_compare (const void *la, const void *lb, void *unused)
{
return strncasecmp (((lumpinfo_t *) la)->name,
((lumpinfo_t *) lb)->name, 16) == 0;
}
VISIBLE wad_t *
wad_new (const char *name)
{
wad_t *wad = calloc (sizeof (*wad), 1);
if (!wad)
return 0;
wad->filename = strdup (name);
if (!wad->filename) {
free (wad);
return 0;
}
wad->lump_hash = Hash_NewTable (1021, 0, 0, 0);
if (!wad->lump_hash) {
free (wad->filename);
free (wad);
return 0;
}
Hash_SetHashCompare (wad->lump_hash, wad_get_hash, wad_compare);
return wad;
}
VISIBLE void
wad_del (wad_t *wad)
{
if (wad->lumps)
free (wad->lumps);
if (wad->handle)
Qclose (wad->handle);
if (wad->filename)
free (wad->filename);
if (wad->lump_hash)
free (wad->lump_hash);
free (wad);
}
VISIBLE void
wad_rehash (wad_t *wad)
{
int i;
for (i = 0; i < wad->numlumps; i++) {
Hash_AddElement (wad->lump_hash, &wad->lumps[i]);
}
}
VISIBLE wad_t *
wad_open (const char *name)
{
wad_t *wad = wad_new (name);
int i;
if (!wad)
return 0;
wad->handle = Qopen (name, "rbz");
if (!wad->handle) {
goto error;
}
if (Qread (wad->handle, &wad->header, sizeof (wad->header))
!= sizeof (wad->header)) {
fprintf (stderr, "%s: not a wad file\n", name);
errno = 0;
goto error;
}
if (strncmp (wad->header.id, "WAD2", 4)) {
fprintf (stderr, "%s: not a wad file\n", name);
errno = 0;
goto error;
}
wad->header.infotableofs = LittleLong (wad->header.infotableofs);
wad->header.numlumps = LittleLong (wad->header.numlumps);
wad->numlumps = wad->header.numlumps;
wad->old_numlumps = wad->lumps_size = wad->numlumps;
wad->lumps = malloc (wad->lumps_size * sizeof (lumpinfo_t));
if (!wad->lumps) {
//fprintf (stderr, "out of memory\n");
goto error;
}
Qseek (wad->handle, wad->header.infotableofs, SEEK_SET);
Qread (wad->handle, wad->lumps, wad->numlumps * sizeof (wad->lumps[0]));
for (i = 0; i < wad->numlumps; i++) {
wad->lumps[i].filepos = LittleLong (wad->lumps[i].filepos);
wad->lumps[i].size = LittleLong (wad->lumps[i].size);
Hash_AddElement (wad->lump_hash, &wad->lumps[i]);
}
return wad;
error:
wad_del (wad);
return 0;
}
VISIBLE wad_t *
wad_create (const char *name)
{
wad_t *wad = wad_new (name);
if (!wad)
return 0;
wad->handle = Qopen (name, "wb");
if (!wad->handle) {
wad_del (wad);
return 0;
}
strncpy (wad->header.id, "WAD2", sizeof (wad->header.id));
Qwrite (wad->handle, &wad->header, sizeof (wad->header));
return wad;
}
VISIBLE void
wad_close (wad_t *wad)
{
int i;
if (wad->modified) {
if (wad->numlumps > wad->old_numlumps) {
Qseek (wad->handle, 0, SEEK_END);
wad->header.infotableofs = Qtell (wad->handle);
}
for (i = 0; i < wad->numlumps; i++) {
wad->lumps[i].filepos = LittleLong (wad->lumps[i].filepos);
wad->lumps[i].size = LittleLong (wad->lumps[i].size);
}
Qseek (wad->handle, wad->header.infotableofs, SEEK_SET);
Qwrite (wad->handle, wad->lumps,
wad->numlumps * sizeof (wad->lumps[0]));
wad->header.infotableofs = LittleLong (wad->header.infotableofs);
wad->header.numlumps = LittleLong (wad->numlumps);
Qseek (wad->handle, 0, SEEK_SET);
Qwrite (wad->handle, &wad->header, sizeof (wad->header));
Qseek (wad->handle, 0, SEEK_END);
}
wad_del (wad);
}
VISIBLE int
wad_add (wad_t *wad, const char *filename, const char *lumpname, byte type)
{
lumpinfo_t *pf;
lumpinfo_t dummy;
QFile *file;
char buffer[16384];
int bytes;
strncpy (dummy.name, lumpname, 16);
dummy.name[15] = 0;
pf = Hash_FindElement (wad->lump_hash, &dummy);
if (pf)
return -1;
if (wad->numlumps == wad->lumps_size) {
lumpinfo_t *f;
wad->lumps_size += 64;
f = realloc (wad->lumps, wad->lumps_size * sizeof (lumpinfo_t));
if (!f)
return -1;
wad->lumps = f;
}
file = Qopen (filename, "rb");
if (!file)
return -1;
wad->modified = 1;
pf = &wad->lumps[wad->numlumps++];
strncpy (pf->name, lumpname, sizeof (pf->name));
pf->name[sizeof (pf->name) - 1] = 0;
Qseek (wad->handle, 0, SEEK_END);
pf->filepos = Qtell (wad->handle);
pf->type = type;
pf->size = 0;
while ((bytes = Qread (file, buffer, sizeof (buffer)))) {
Qwrite (wad->handle, buffer, bytes);
pf->size += bytes;
}
Qclose (file);
if (wad->pad && pf->size & 3) {
static char buf[4];
Qwrite (wad->handle, buf, 4 - (pf->size & 3));
}
pf->disksize = pf->size;
Hash_AddElement (wad->lump_hash, pf);
return 0;
}
VISIBLE int
wad_add_data (wad_t *wad, const char *lumpname, byte type, const void *data,
int bytes)
{
lumpinfo_t *pf;
lumpinfo_t dummy;
strncpy (dummy.name, lumpname, 16);
dummy.name[15] = 0;
pf = Hash_FindElement (wad->lump_hash, &dummy);
if (pf)
return -1;
if (wad->numlumps == wad->lumps_size) {
lumpinfo_t *f;
wad->lumps_size += 64;
f = realloc (wad->lumps, wad->lumps_size * sizeof (lumpinfo_t));
if (!f)
return -1;
wad->lumps = f;
}
wad->modified = 1;
pf = &wad->lumps[wad->numlumps++];
strncpy (pf->name, lumpname, sizeof (pf->name));
pf->name[sizeof (pf->name) - 1] = 0;
Qseek (wad->handle, 0, SEEK_END);
pf->filepos = Qtell (wad->handle);
pf->type = type;
pf->size = bytes;
Qwrite (wad->handle, data, bytes);
if (wad->pad && pf->size & 3) {
static char buf[4];
Qwrite (wad->handle, buf, 4 - (pf->size & 3));
}
pf->disksize = pf->size;
Hash_AddElement (wad->lump_hash, pf);
return 0;
}
VISIBLE lumpinfo_t *
wad_find_lump (wad_t *wad, const char *lumpname)
{
lumpinfo_t dummy;
strncpy (dummy.name, lumpname, 16);
dummy.name[15] = 0;
return Hash_FindElement (wad->lump_hash, &dummy);
}