mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-05 20:50:43 +00:00
330 lines
7 KiB
C
330 lines
7 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
|
|
|
|
static __attribute__ ((used)) const char rcsid[] =
|
|
"$Id$";
|
|
|
|
#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 (void *l, void *unused)
|
|
{
|
|
char name[16];
|
|
int i;
|
|
|
|
for (i = 0; i < 16; i++)
|
|
name[i] = tolower (((lumpinfo_t *) l)->name[i]);
|
|
return Hash_String (name);
|
|
}
|
|
|
|
static int
|
|
wad_compare (void *la, void *lb, void *unused)
|
|
{
|
|
return strcasecmp (((lumpinfo_t *) la)->name,
|
|
((lumpinfo_t *) lb)->name) == 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);
|
|
}
|