/* 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 #endif #ifdef HAVE_STRINGS_H # include #endif #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #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[17]; int i; for (i = 0; i < 16; i++) name[i] = tolower (((lumpinfo_t *) l)->name[i]); name[16] = 0; return Hash_String (name); } static int wad_compare (void *la, 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); }