Skip to content
Browse files

Initial commit

  • Loading branch information...
1 parent 5a94823 commit fe3aa926c64e327b3c3aa25b372bb74ae3a06471 @icefox committed Jun 1, 2005
Showing with 2,341 additions and 0 deletions.
  1. +10 −0 wad/SConscript
  2. +119 −0 wad/compat.h
  3. +495 −0 wad/hash.c
  4. +155 −0 wad/hash.h
  5. +128 −0 wad/quakefs.h
  6. +530 −0 wad/quakeio.c
  7. +56 −0 wad/quakeio.h
  8. +108 −0 wad/sys.h
  9. +224 −0 wad/wad.c
  10. +52 −0 wad/wad.h
  11. +362 −0 wad/wadfile.c
  12. +102 −0 wad/wadfile.h
View
10 wad/SConscript
@@ -0,0 +1,10 @@
+Import( 'env installPath' )
+myenv=env.Copy()
+
+myenv['CPPPATH'] = Split('../common')
+myenv['LIBS'] = Split('qutils m c')
+myenv['LIBPATH'] = '../common'
+
+wad = myenv.Program('wad', Split('wad.c wadfile.c hash.c quakeio.c'))
+
+myenv.Install(installPath, wad)
View
119 wad/compat.h
@@ -0,0 +1,119 @@
+/*
+ compat.h
+
+ Miscellaneous compability stuff
+
+ Copyright (C) 1996-1997 Id Software, Inc.
+
+ 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
+
+ $Id: compat.h,v 1.14 2002/06/26 22:20:11 despair Exp $
+*/
+
+#ifndef __compat_h
+#define __compat_h
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#ifdef HAVE_STDARG_H
+# include <stdarg.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#include <stdlib.h>
+
+
+#ifndef max
+# define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+#ifndef min
+# define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef bound
+# define bound(a,b,c) (max(a, min(b, c)))
+#endif
+/* This fixes warnings when compiling with -pedantic */
+#if defined(__GNUC__) && !defined(inline)
+# define inline __inline__
+#endif
+
+/* These may be underscored... */
+#if defined(HAVE__SNPRINTF) && !defined(HAVE_SNPRINTF)
+# undef snprintf
+# define snprintf Q_snprintfz
+# define need_qstring_h
+#endif
+#if defined(HAVE__VSNPRINTF) && !defined(HAVE_VSNPRINTF)
+# undef vsnprintf
+# define vsnprintf Q_vsnprintfz
+# define need_qstring_h
+#endif
+#if defined(_WIN32) && !defined(__BORLANDC__)
+# define kbhit _kbhit
+#endif
+
+/* If we don't have them in the C-library we declare them to avoid warnings */
+#if ! (defined(HAVE_SNPRINTF) || defined(HAVE__SNPRINTF))
+extern int snprintf(char * s, size_t maxlen, const char *format, ...);
+#endif
+#if ! (defined(HAVE_VSNPRINTF) || defined(HAVE__VSNPRINTF))
+extern int vsnprintf(char *s, size_t maxlen, const char *format, va_list arg);
+#endif
+
+/* String utility functions */
+#if !defined(strequal)
+# define strequal(a,b) (strcmp (a, b) == 0)
+#endif
+#if !defined(strcaseequal)
+# define strcaseequal(a,b) (strcasecmp (a, b) == 0)
+#endif
+#if !defined(strnequal)
+# define strnequal(a,b,c) (strncmp (a, b, c) == 0)
+#endif
+#if !defined(strncaseequal)
+# define strncaseequal(a,b,c) (strncasecmp (a, b, c) == 0)
+#endif
+#ifdef HAVE_STRCASESTR
+# ifndef HAVE_STRCASESTR_PROTO
+extern char *strcasestr (const char *__haystack, const char *__needle);
+# endif
+#else
+# define strcasestr Q_strcasestr
+# define need_qstring_h
+#endif
+#ifdef HAVE_STRNLEN
+# ifndef HAVE_STRNLEN_PROTO
+size_t strnlen (const char *str, size_t len);
+# endif
+#else
+# define strnlen Q_strnlen
+# define need_qstring_h
+#endif
+
+#ifdef need_qstring_h
+//# include "qstring.h"
+#endif
+
+#undef field_offset
+#define field_offset(type,field) ((size_t)&(((type *)0)->field))
+
+#endif // __compat_h
View
495 wad/hash.c
@@ -0,0 +1,495 @@
+/*
+ hash.c
+
+ hash tables
+
+ Copyright (C) 2000 Bill Currie <bill@taniwha.org>
+
+ 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__ ((unused)) const char rcsid[] =
+ "$Id: hash.c,v 1.28 2004/02/07 07:47:23 taniwha Exp $";
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+
+#include <math.h>
+#include <stdlib.h> // should be sys/types.h, but bc is stupid
+
+#include "hash.h"
+#include "sys.h"
+#include "compat.h"
+
+typedef struct hashlink_s {
+ struct hashlink_s *next;
+ struct hashlink_s **prev;
+ void *data;
+} hashlink_t;
+
+struct hashtab_s {
+ size_t tab_size;
+ unsigned int size_bits;
+ size_t num_ele;
+ void *user_data;
+ int (*compare)(void*,void*,void*);
+ unsigned long (*get_hash)(void*,void*);
+ const char *(*get_key)(void*,void*);
+ void (*free_ele)(void*,void*);
+ hashlink_t *tab[1]; // variable size
+};
+
+#define Sys_Printf printf
+
+static hashlink_t *free_hashlinks;
+
+static hashlink_t *
+new_hashlink (void)
+{
+ hashlink_t *link;
+
+ if (!free_hashlinks) {
+ int i;
+
+ if (!(free_hashlinks = calloc (1024, sizeof (hashlink_t))))
+ return 0;
+ for (i = 0, link = free_hashlinks; i < 1023; i++, link++)
+ link->next = link + 1;
+ link->next = 0;
+ }
+ link = free_hashlinks;
+ free_hashlinks = link->next;
+ link->next = 0;
+ return link;
+}
+
+static void
+free_hashlink (hashlink_t *link)
+{
+ link->next = free_hashlinks;
+ free_hashlinks = link;
+}
+
+unsigned long
+Hash_String (const char *str)
+{
+#if 0
+ unsigned long h = 0;
+ while (*str) {
+ h = (h << 4) + (unsigned char)*str++;
+ if (h&0xf0000000)
+ h = (h ^ (h >> 24)) & 0xfffffff;
+ }
+ return h;
+#else
+ // dx_hack_hash
+ // shamelessly stolen from Daniel Phillips <phillips@innominate.de>
+ // from his post to lkml
+ unsigned long hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
+ while (*str) {
+ unsigned long hash = hash1 + (hash0 ^ ((unsigned char)*str++ * 71523));
+ if (hash < 0) hash -= 0x7fffffff;
+ hash1 = hash0;
+ hash0 = hash;
+ }
+ return hash0;
+#endif
+}
+
+unsigned long
+Hash_Buffer (const void *_buf, int len)
+{
+ const unsigned char *buf = _buf;
+#if 0
+ unsigned long h = 0;
+ while (len-- > 0) {
+ h = (h << 4) + (unsigned char)*buf++;
+ if (h&0xf0000000)
+ h = (h ^ (h >> 24)) & 0xfffffff;
+ }
+ return h;
+#else
+ // dx_hack_hash
+ // shamelessly stolen from Daniel Phillips <phillips@innominate.de>
+ // from his post to lkml
+ unsigned long hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
+ while (len-- > 0) {
+ unsigned long hash = hash1 + (hash0 ^ ((unsigned char)*buf++ * 71523));
+ if (hash < 0) hash -= 0x7fffffff;
+ hash1 = hash0;
+ hash0 = hash;
+ }
+ return hash0;
+#endif
+}
+
+static unsigned long
+get_hash (void *ele, void *data)
+{
+ return (unsigned long)ele;
+}
+
+static int
+compare (void *a, void *b, void *data)
+{
+ return a == b;
+}
+
+static inline int
+get_index (unsigned long hash, size_t size, size_t bits)
+{
+#if 0
+ unsigned long mask = ~0UL << bits;
+ unsigned long extract;
+
+ size -= 1;
+ for (extract = (hash & mask) >> bits;
+ extract;
+ extract = (hash & mask) >> bits) {
+ hash &= ~mask;
+ hash ^= extract;
+ } while (extract);
+ if (hash > size) {
+ extract = hash - size;
+ hash = size - (extract >> 1);
+ }
+ return hash;
+#else
+ return hash % size;
+#endif
+}
+
+hashtab_t *
+Hash_NewTable (int tsize, const char *(*gk)(void*,void*),
+ void (*f)(void*,void*), void *ud)
+{
+ hashtab_t *tab = calloc (1, field_offset (hashtab_t, tab[tsize]));
+ if (!tab)
+ return 0;
+ tab->tab_size = tsize;
+ tab->user_data = ud;
+ tab->get_key = gk;
+ tab->free_ele = f;
+
+ while (tsize) {
+ tab->size_bits++;
+ tsize = ((unsigned int) tsize) >> 1;
+ }
+
+ tab->get_hash = get_hash;
+ tab->compare = compare;
+ return tab;
+}
+
+void
+Hash_SetHashCompare (hashtab_t *tab, unsigned long (*gh)(void*,void*),
+ int (*cmp)(void*,void*,void*))
+{
+ tab->get_hash = gh;
+ tab->compare = cmp;
+}
+
+void
+Hash_DelTable (hashtab_t *tab)
+{
+ Hash_FlushTable (tab);
+ free (tab);
+}
+
+void
+Hash_FlushTable (hashtab_t *tab)
+{
+ size_t i;
+
+ for (i = 0; i < tab->tab_size; i++) {
+ while (tab->tab[i]) {
+ hashlink_t *t = tab->tab[i]->next;
+ void *data = tab->tab[i]->data;
+
+ free_hashlink (tab->tab[i]);
+ tab->tab[i] = t;
+ if (tab->free_ele)
+ tab->free_ele (data, tab->user_data);
+ }
+ }
+ tab->num_ele = 0;
+}
+
+int
+Hash_Add (hashtab_t *tab, void *ele)
+{
+ unsigned long h = Hash_String (tab->get_key(ele, tab->user_data));
+ size_t ind = get_index (h, tab->tab_size, tab->size_bits);
+ hashlink_t *lnk = new_hashlink ();
+
+ if (!lnk)
+ return -1;
+ if (tab->tab[ind])
+ tab->tab[ind]->prev = &lnk->next;
+ lnk->next = tab->tab[ind];
+ lnk->prev = &tab->tab[ind];
+ lnk->data = ele;
+ tab->tab[ind] = lnk;
+ tab->num_ele++;
+ return 0;
+}
+
+int
+Hash_AddElement (hashtab_t *tab, void *ele)
+{
+ unsigned long h = tab->get_hash (ele, tab->user_data);
+ size_t ind = get_index (h, tab->tab_size, tab->size_bits);
+ hashlink_t *lnk = new_hashlink ();
+
+ if (!lnk)
+ return -1;
+ if (tab->tab[ind])
+ tab->tab[ind]->prev = &lnk->next;
+ lnk->next = tab->tab[ind];
+ lnk->prev = &tab->tab[ind];
+ lnk->data = ele;
+ tab->tab[ind] = lnk;
+ tab->num_ele++;
+ return 0;
+}
+
+void *
+Hash_Find (hashtab_t *tab, const char *key)
+{
+ unsigned long h = Hash_String (key);
+ size_t ind = get_index (h, tab->tab_size, tab->size_bits);
+ hashlink_t *lnk = tab->tab[ind];
+
+ while (lnk) {
+ if (strequal (key, tab->get_key (lnk->data, tab->user_data)))
+ return lnk->data;
+ lnk = lnk->next;
+ }
+ return 0;
+}
+
+void *
+Hash_FindElement (hashtab_t *tab, void *ele)
+{
+ unsigned long h = tab->get_hash (ele, tab->user_data);
+ size_t ind = get_index (h, tab->tab_size, tab->size_bits);
+ hashlink_t *lnk = tab->tab[ind];
+
+ while (lnk) {
+ if (tab->compare (lnk->data, ele, tab->user_data))
+ return lnk->data;
+ lnk = lnk->next;
+ }
+ return 0;
+}
+
+void **
+Hash_FindList (hashtab_t *tab, const char *key)
+{
+ unsigned long h = Hash_String (key);
+ size_t ind = get_index (h, tab->tab_size, tab->size_bits);
+ hashlink_t *lnk = tab->tab[ind], *start = 0;
+ int count = 0;
+ void **list;
+
+ while (lnk) {
+ if (strequal (key, tab->get_key (lnk->data, tab->user_data))) {
+ count++;
+ if (!start)
+ start = lnk;
+ }
+ lnk = lnk->next;
+ }
+ if (!count)
+ return 0;
+ list = malloc ((count + 1) * sizeof (void *));
+ for (count = 0, lnk = start; lnk; lnk = lnk->next) {
+ if (strequal (key, tab->get_key (lnk->data, tab->user_data)))
+ list[count++] = lnk->data;
+ }
+ list[count] = 0;
+ return list;
+}
+
+void **
+Hash_FindElementList (hashtab_t *tab, void *ele)
+{
+ unsigned long h = tab->get_hash (ele, tab->user_data);
+ size_t ind = get_index (h, tab->tab_size, tab->size_bits);
+ hashlink_t *lnk = tab->tab[ind], *start = 0;
+ int count = 0;
+ void **list;
+
+ while (lnk) {
+ if (tab->compare (lnk->data, ele, tab->user_data)) {
+ count++;
+ if (!start)
+ start = lnk;
+ }
+ lnk = lnk->next;
+ }
+ if (!count)
+ return 0;
+ list = malloc ((count + 1) * sizeof (void *));
+ for (count = 0, lnk = start; lnk; lnk = lnk->next) {
+ if (tab->compare (lnk->data, ele, tab->user_data))
+ list[count++] = lnk->data;
+ }
+ list[count] = 0;
+ return list;
+}
+
+void *
+Hash_Del (hashtab_t *tab, const char *key)
+{
+ unsigned long h = Hash_String (key);
+ size_t ind = get_index (h, tab->tab_size, tab->size_bits);
+ hashlink_t *lnk = tab->tab[ind];
+ void *data;
+
+ while (lnk) {
+ if (strequal (key, tab->get_key (lnk->data, tab->user_data))) {
+ data = lnk->data;
+ if (lnk->next)
+ lnk->next->prev = lnk->prev;
+ *lnk->prev = lnk->next;
+ free_hashlink (lnk);
+ tab->num_ele--;
+ return data;
+ }
+ lnk = lnk->next;
+ }
+ return 0;
+}
+
+void *
+Hash_DelElement (hashtab_t *tab, void *ele)
+{
+ unsigned long h = tab->get_hash (ele, tab->user_data);
+ size_t ind = get_index (h, tab->tab_size, tab->size_bits);
+ hashlink_t *lnk = tab->tab[ind];
+ void *data;
+
+ while (lnk) {
+ if (tab->compare (lnk->data, ele, tab->user_data)) {
+ data = lnk->data;
+ if (lnk->next)
+ lnk->next->prev = lnk->prev;
+ *lnk->prev = lnk->next;
+ free_hashlink (lnk);
+ tab->num_ele--;
+ return data;
+ }
+ lnk = lnk->next;
+ }
+ return 0;
+}
+
+void
+Hash_Free (hashtab_t *tab, void *ele)
+{
+ if (ele && tab->free_ele)
+ tab->free_ele (ele, tab->user_data);
+}
+
+size_t
+Hash_NumElements (hashtab_t *tab)
+{
+ return tab->num_ele;
+}
+
+void **
+Hash_GetList (hashtab_t *tab)
+{
+ void **list;
+ void **l;
+ size_t ind;
+
+ l = list = malloc ((tab->num_ele + 1) * sizeof (void *));
+ if (!list)
+ return 0;
+ for (ind = 0; ind < tab->tab_size; ind++) {
+ hashlink_t *lnk;
+
+ for (lnk = tab->tab[ind]; lnk; lnk = lnk->next) {
+ *l++ = lnk->data;
+ }
+ }
+ *l++ = 0;
+ return list;
+}
+
+static inline double
+sqr (double x)
+{
+ return x * x;
+}
+
+void
+Hash_Stats (hashtab_t *tab)
+{
+ int *lengths = calloc (tab->tab_size, sizeof (int));
+ int chains = 0;
+ size_t i;
+ int min_length = tab->num_ele;
+ int max_length = 0;
+
+ if (!lengths) {
+ Sys_Printf ("Hash_Stats: memory alloc error\n");
+ return;
+ }
+
+ for (i = 0; i < tab->tab_size; i++) {
+ hashlink_t *lnk = tab->tab[i];
+
+ while (lnk) {
+ lengths[i]++;
+ lnk = lnk->next;
+ }
+ if (lengths[i]) {
+ min_length = min (min_length, lengths[i]);
+ max_length = max (max_length, lengths[i]);
+ chains++;
+ }
+ }
+ Sys_Printf ("%d elements\n", (int)tab->num_ele);
+ Sys_Printf ("%d / %d chains\n", chains, (int)tab->tab_size);
+ if (chains) {
+ double average = (double) tab->num_ele / chains;
+ double variance = 0;
+ Sys_Printf ("%d minium chain length\n", min_length);
+ Sys_Printf ("%d maximum chain length\n", max_length);
+ Sys_Printf ("%.3g average chain length\n", average);
+ for (i = 0; i < tab->tab_size; i++) {
+ if (lengths[i])
+ variance += sqr (lengths[i] - average);
+ }
+ variance /= chains;
+ Sys_Printf ("%.3g variance, %.3g standard deviation\n",
+ variance, sqrt (variance));
+ }
+}
View
155 wad/hash.h
@@ -0,0 +1,155 @@
+/*
+ hash.h
+
+ hash tables
+
+ Copyright (C) 2000 Bill Currie <bill@taniwha.org>
+
+ 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
+
+ $Id: hash.h,v 1.17 2004/02/07 07:47:22 taniwha Exp $
+*/
+
+#ifndef __hash_h
+#define __hash_h
+
+typedef struct hashtab_s hashtab_t;
+
+/** create a new hash table:
+ tsize: table size. larger values will give better distribution, but
+ use more memory.
+ gk: a function that returns a string to be used as the key for
+ inserting or finding the element. First parameter is a pointer
+ to the element from which to extract the key, the second is
+ the user data pointer.
+ f: a function to free the element. Only ever called from
+ Hash_FlushTable and Hash_DelTable. The first parameter is the
+ element to be freed and the second is the user data pointer.
+ ud: user data pointer. set to whatever you want, it will be passed
+ to the get key and free functions as the second parameter.
+ returns a pointer to the hash table (to be passed to the other functions)
+ or 0 on error.
+
+ Hash_Add, Hash_Find, Hash_FindList and Hash_Del use gk and strcmp.
+
+ multiple inserions of the same key are fine; later insertions override
+ previous ones until the later one is removed (Hash_Del).
+*/
+hashtab_t *Hash_NewTable (int tsize, const char *(*gk)(void*,void*),
+ void (*f)(void*,void*), void *ud);
+
+/** change the hash and compare functions used by the Hash_*Element functions.
+ the default hash function just returns the address of the element, and the
+ default compare just compares the addresses. compare is to return 0 for not
+ equal and non-0 otherwise.
+
+ With suitably crafted gh and cmp functions, Hash_*Element functions can
+ be mixed with the non-element functions, but by default the results will
+ be undefined.
+
+ gh takes the same parameters as gk above
+ cmp is element 1, element 2, userdata
+*/
+void Hash_SetHashCompare (hashtab_t *tab, unsigned long (*gh)(void*,void*),
+ int (*cmp)(void*,void*,void*));
+
+
+/** delete a hash table:
+ tab: the table to be deleted
+*/
+void Hash_DelTable (hashtab_t *tab);
+
+/** clean out all the entries from a hash table, starting over again:
+ tab: the table to be cleared
+*/
+void Hash_FlushTable (hashtab_t *tab);
+
+//@{
+/** add an entry to a hash table:
+ tab: the table to be added to
+ ele: the element to add to the table
+ returns 0 for success, -1 for error.
+*/
+int Hash_Add (hashtab_t *tab, void *ele);
+int Hash_AddElement (hashtab_t *tab, void *ele);
+//@}
+
+//@{
+/** find an element within a hash table:
+ tab: the table to search
+ key: the key string identifying the element being searched for
+ returns a pointer to the element if found, otherwise 0.
+*/
+void *Hash_Find (hashtab_t *tab, const char *key);
+void *Hash_FindElement (hashtab_t *tab, void *ele);
+//@}
+
+//@{
+/** find a list of elements within a hash table:
+ tab: the table to search
+ key: the key string identifying the elements being searched for
+ returns a null terminated list of element pointers if at least one found,
+ otherwise 0.
+*/
+void **Hash_FindList (hashtab_t *tab, const char *key);
+void **Hash_FindElementList (hashtab_t *tab, void *ele);
+//@}
+
+//@{
+/** delete an element from a hash table:
+ tab: the table to remove the element from
+ key: the key string identifying the element to be deleted
+ returns a pointer to the element on success, 0 if the element could not
+ be found.
+ Does /NOT/ call the free element function. That is the caller's
+ responsibility.
+*/
+void *Hash_Del (hashtab_t *tab, const char *key);
+void *Hash_DelElement (hashtab_t *tab, void *ele);
+//@}
+
+/** calls the free element function for the supplied ele
+ eg:
+ Hash_Free (tab, Hash_Del (tab, key));
+*/
+void Hash_Free (hashtab_t *tab, void *ele);
+
+/** returh the hash value of a string. this is the same function as used
+ internally.
+*/
+unsigned long Hash_String (const char *str);
+
+/** returh the hash value of a buffer.
+*/
+unsigned long Hash_Buffer (const void *buf, int len);
+
+/** return the number of elements in the table.
+*/
+size_t Hash_NumElements (hashtab_t *tab);
+
+/** return a list of all elements in the table. it is the caller's
+ responsibilty to free() the array. Null terminated.
+*/
+void **Hash_GetList (hashtab_t *tab);
+
+/** dump statistics about the hash table
+*/
+void Hash_Stats (hashtab_t *tab);
+
+#endif // __hash_h
View
128 wad/quakefs.h
@@ -0,0 +1,128 @@
+/*
+ quakefs.h
+
+ quake virtual filesystem definitions
+
+ Copyright (C) 1996-1997 Id Software, Inc.
+ Copyright (C) 1999,2000 contributors of the QuakeForge project
+ Please see the file "AUTHORS" for a list of contributors
+
+ 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
+
+ $Id: quakefs.h,v 1.23 2004/04/23 22:53:38 taniwha Exp $
+*/
+
+#ifndef __quakefs_h
+#define __quakefs_h
+
+#include "cmdlib.h"
+#include "quakeio.h"
+
+//============================================================================
+
+#define MAX_OSPATH 128 // max length of a filesystem pathname
+
+#define MAX_GAMEDIR_CALLBACKS 128 // most QFS_GamedirCallback calls.
+
+typedef struct filelist_s {
+ char **list;
+ int count;
+ int size;
+} filelist_t;
+
+typedef struct searchpath_s {
+ char filename[MAX_OSPATH];
+ struct pack_s *pack; // only one of filename / pack will be used
+ struct searchpath_s *next;
+} searchpath_t;
+
+typedef struct gamedir_s {
+ const char *name;
+ const char *gamedir;
+ const char *path;
+ const char *gamecode;
+ struct {
+ const char *def;
+ const char *skins;
+ const char *progs;
+ const char *sound;
+ const char *maps;
+ } dir;
+} gamedir_t;
+
+typedef void gamedir_callback_t (void);
+
+extern searchpath_t *qfs_searchpaths;
+extern gamedir_t *qfs_gamedir;
+
+extern struct cvar_s *fs_sharepath;
+extern struct cvar_s *fs_userpath;
+
+extern const char *qfs_userpath;
+
+extern int file_from_pak;
+extern int qfs_filesize;
+
+struct cache_user_s;
+struct dstring_s;
+
+void QFS_Init (const char *game);
+
+void QFS_Gamedir (const char *dir);
+
+QFile *QFS_Open (const char *path, const char *mode);
+QFile *QFS_WOpen (const char *path, int zip);
+void QFS_WriteFile (const char *filename, const void *data, int len);
+void QFS_WriteBuffers (const char *filename, int count, ...);
+
+int _QFS_FOpenFile (const char *filename, QFile **gzfile,
+ struct dstring_s *foundname, int zip);
+int QFS_FOpenFile (const char *filename, QFile **gzfile);
+byte *QFS_LoadFile (const char *path, int usehunk);
+byte *QFS_LoadStackFile (const char *path, void *buffer, int bufsize);
+byte *QFS_LoadTempFile (const char *path);
+byte *QFS_LoadHunkFile (const char *path);
+void QFS_LoadCacheFile (const char *path, struct cache_user_s *cu);
+
+void QFS_CreatePath (const char *path);
+int QFS_Rename (const char *old, const char *new);
+int QFS_Remove (const char *path);
+int QFS_NextFilename (struct dstring_s *filename, const char *prefix,
+ const char *ext);
+
+char *QFS_FileBase (const char *in);
+void QFS_DefaultExtension (char *path, const char *extension);
+void QFS_StripExtension (const char *in, char *out);
+char *QFS_CompressPath (const char *pth);
+const char *QFS_SkipPath (const char *pathname);
+const char *QFS_FileExtension (const char *in);
+
+void QFS_GamedirCallback (gamedir_callback_t *);
+
+filelist_t *QFS_FilelistNew (void);
+void QFS_FilelistAdd (filelist_t *filelist, const char *fname,
+ const char *ext);
+void QFS_FilelistFill (filelist_t *list, const char *path, const char *ext,
+ int strip);
+void QFS_FilelistFree (filelist_t *list);
+
+// FIXME: This is here temporarily until fs_usercfg gets sorted out
+char *expand_squiggle (const char *path);
+
+#endif // __quakefs_h
View
530 wad/quakeio.c
@@ -0,0 +1,530 @@
+/*
+ quakeio.c
+
+ (description)
+
+ Copyright (C) 1996-1997 Id Software, Inc.
+ Copyright (C) 1999,2000 contributors of the QuakeForge project
+ Please see the file "AUTHORS" for a list of contributors
+
+ 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__ ((unused)) const char rcsid[] =
+ "$Id: quakeio.c,v 1.29 2004/02/29 07:12:05 taniwha Exp $";
+
+#ifdef HAVE_ZLIB
+# include <zlib.h>
+#endif
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifdef _MSC_VER
+# define _POSIX_
+#endif
+
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <errno.h>
+
+//#include "dstring.h"
+//#include "qendian.h"
+#include "quakefs.h"
+#include "quakeio.h"
+
+#ifdef _WIN32
+# ifndef __BORLANDC__
+# define setmode _setmode
+# define O_BINARY _O_BINARY
+# endif
+#endif
+
+struct QFile_s {
+ FILE *file;
+#ifdef HAVE_ZLIB
+ gzFile *gzfile;
+#endif
+ off_t size;
+ off_t start;
+ int c;
+};
+
+
+int
+Qrename (const char *old, const char *new)
+{
+ return rename (old, new);
+}
+
+int
+Qremove (const char *path)
+{
+ return remove (path);
+}
+
+int
+Qfilesize (QFile *file)
+{
+ return file->size;
+}
+
+static int
+check_file (int fd, int offs, int len, int *zip)
+{
+ unsigned char id[2], len_bytes[4];
+
+ if (offs < 0 || len < 0) {
+ // normal file
+ offs = 0;
+ len = lseek (fd, 0, SEEK_END);
+ lseek (fd, 0, SEEK_SET);
+ }
+ if (*zip) {
+ int r;
+
+ lseek (fd, offs, SEEK_SET);
+ r = read (fd, id, 2);
+ if (r == 2 && id[0] == 0x1f && id[1] == 0x8b && len >= 6) {
+ lseek (fd, offs + len - 4, SEEK_SET);
+ read (fd, len_bytes, 4);
+ len = ((len_bytes[3] << 24)
+ | (len_bytes[2] << 16)
+ | (len_bytes[1] << 8)
+ | (len_bytes[0]));
+ } else {
+ *zip = 0;
+ }
+ }
+ lseek (fd, offs, SEEK_SET);
+ return len;
+}
+
+QFile *
+Qopen (const char *path, const char *mode)
+{
+ QFile *file;
+ char *m, *p;
+ int reading = 0;
+ int zip = 0;
+ int size = -1;
+
+ m = alloca (strlen (mode) + 1);
+ for (p = m; *mode && p - m < ((int) sizeof (m) - 1); mode++) {
+ if (*mode == 'z') {
+ zip = 1;
+ continue;
+ }
+ if (*mode == 'r') {
+ reading = 1;
+ }
+#ifndef HAVE_ZLIB
+ if (strchr ("0123456789fh", *mode)) {
+ continue;
+ }
+#endif
+ *p++ = *mode;
+ }
+ *p = 0;
+
+ if (reading) {
+ int fd = open (path, O_RDONLY);
+ if (fd != -1) {
+ size = check_file (fd, -1, -1, &zip);
+ close (fd);
+ }
+ }
+
+ file = calloc (sizeof (*file), 1);
+ if (!file)
+ return 0;
+ file->size = size;
+#ifdef HAVE_ZLIB
+ if (zip) {
+ file->gzfile = gzopen (path, m);
+ if (!file->gzfile) {
+ free (file);
+ return 0;
+ }
+ } else
+#endif
+ {
+ file->file = fopen (path, m);
+ if (!file->file) {
+ free (file);
+ return 0;
+ }
+ }
+ file->c = -1;
+ return file;
+}
+
+QFile *
+Qdopen (int fd, const char *mode)
+{
+ QFile *file;
+ char *m, *p;
+ int zip = 0;
+
+ m = alloca (strlen (mode) + 1);
+#ifdef _WIN32
+ setmode (fd, O_BINARY);
+#endif
+ for (p = m; *mode && p - m < ((int) sizeof (m) - 1); mode++) {
+ if (*mode == 'z') {
+ zip = 1;
+ continue;
+ }
+ *p++ = *mode;
+ }
+
+ *p = 0;
+
+ file = calloc (sizeof (*file), 1);
+ if (!file)
+ return 0;
+#ifdef HAVE_ZLIB
+ if (zip) {
+ file->gzfile = gzdopen (fd, m);
+ if (!file->gzfile) {
+ free (file);
+ return 0;
+ }
+ } else
+#endif
+ {
+ file->file = fdopen (fd, m);
+ if (!file->file) {
+ free (file);
+ return 0;
+ }
+ }
+ file->c = -1;
+ return file;
+}
+
+QFile *
+Qsubopen (const char *path, int offs, int len, int zip)
+{
+ int fd = open (path, O_RDONLY);
+ QFile *file;
+
+ if (fd == -1)
+ return 0;
+#ifdef _WIN32
+ setmode (fd, O_BINARY);
+#endif
+
+ len = check_file (fd, offs, len, &zip);
+ file = Qdopen (fd, zip ? "rbz" : "rb");
+ file->size = len;
+ file->start = offs;
+ return file;
+}
+
+void
+Qclose (QFile *file)
+{
+ if (file->file)
+ fclose (file->file);
+#ifdef HAVE_ZLIB
+ else
+ gzclose (file->gzfile);
+#endif
+ free (file);
+}
+
+int
+Qread (QFile *file, void *buf, int count)
+{
+ int offs = 0;
+ int ret;
+
+ if (file->c != -1) {
+ char *b = buf;
+ *b++ = file->c;
+ buf = b;
+ offs = 1;
+ file->c = -1;
+ count--;
+ }
+ if (file->file)
+ ret = fread (buf, 1, count, file->file);
+ else
+#ifdef HAVE_ZLIB
+ ret = gzread (file->gzfile, buf, count);
+#else
+ return -1;
+#endif
+ return ret == -1 ? ret : ret + offs;
+}
+
+int
+Qwrite (QFile *file, const void *buf, int count)
+{
+ if (file->file)
+ return fwrite (buf, 1, count, file->file);
+#ifdef HAVE_ZLIB
+ else
+ return gzwrite (file->gzfile, (const voidp)buf, count);
+#else
+ return -1;
+#endif
+}
+
+int
+Qprintf (QFile *file, const char *fmt, ...)
+{
+ va_list args;
+ int ret = -1;
+
+ va_start (args, fmt);
+ if (file->file)
+ ret = vfprintf (file->file, fmt, args);
+#ifdef HAVE_ZLIB
+ else {
+ static dstring_t *buf;
+
+ if (!buf)
+ buf = dstring_new ();
+
+ va_start (args, fmt);
+ dvsprintf (buf, fmt, args);
+ va_end (args);
+ ret = strlen (buf->str);
+ if (ret > 0)
+ ret = gzwrite (file->gzfile, buf, (unsigned) ret);
+ }
+#endif
+ va_end (args);
+ return ret;
+}
+
+int
+Qputs (QFile *file, const char *buf)
+{
+ if (file->file)
+ return fputs (buf, file->file);
+#ifdef HAVE_ZLIB
+ else
+ return gzputs (file->gzfile, buf);
+#else
+ return 0;
+#endif
+}
+
+char *
+Qgets (QFile *file, char *buf, int count)
+{
+ char *ret = buf;
+
+ if (file->c != -1) {
+ *buf++ = file->c;
+ count--;
+ file->c = -1;
+ if (!count)
+ return ret;
+ }
+ if (file->file)
+ buf = fgets (buf, count, file->file);
+ else {
+#ifdef HAVE_ZLIB
+ buf = gzgets (file->gzfile, buf, count);
+#else
+ return 0;
+#endif
+ }
+ return buf ? ret : 0;
+}
+
+int
+Qgetc (QFile *file)
+{
+ if (file->c != -1) {
+ int c = file->c;
+ file->c = -1;
+ return c;
+ }
+ if (file->file)
+ return fgetc (file->file);
+#ifdef HAVE_ZLIB
+ else
+ return gzgetc (file->gzfile);
+#else
+ return -1;
+#endif
+}
+
+int
+Qputc (QFile *file, int c)
+{
+ if (file->file)
+ return fputc (c, file->file);
+#ifdef HAVE_ZLIB
+ else
+ return gzputc (file->gzfile, c);
+#else
+ return -1;
+#endif
+}
+
+int
+Qungetc (QFile *file, int c)
+{
+ if (file->c == -1)
+ file->c = (byte) c;
+ return c;
+}
+
+int
+Qseek (QFile *file, long offset, int whence)
+{
+ file->c = -1;
+ if (file->file) {
+ int res;
+ switch (whence) {
+ case SEEK_SET:
+ res = fseek (file->file, file->start + offset, whence);
+ break;
+ case SEEK_CUR:
+ res = fseek (file->file, offset, whence);
+ break;
+ case SEEK_END:
+ if (file->size == -1) {
+ // we don't know the size (due to writing) so punt and
+ // pass on the request as-is
+ res = fseek (file->file, offset, SEEK_END);
+ } else {
+ res = fseek (file->file,
+ file->start + file->size - offset, SEEK_SET);
+ }
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ if (res != -1)
+ res = ftell (file->file) - file->start;
+ return res;
+ }
+#ifdef HAVE_ZLIB
+ else {
+ // libz seems to keep track of the true start position itself
+ // doesn't support SEEK_END, though
+ return gzseek (file->gzfile, offset, whence);
+ }
+#else
+ return -1;
+#endif
+}
+
+long
+Qtell (QFile *file)
+{
+ int offs;
+ int ret;
+
+ offs = (file->c != -1) ? 1 : 0;
+ if (file->file)
+ ret = ftell (file->file) - file->start;
+ else
+#ifdef HAVE_ZLIB
+ ret = gztell (file->gzfile); //FIXME does gztell do the right thing?
+#else
+ return -1;
+#endif
+ return ret == -1 ? ret : ret - offs;
+}
+
+int
+Qflush (QFile *file)
+{
+ if (file->file)
+ return fflush (file->file);
+#ifdef HAVE_ZLIB
+ else
+ return gzflush (file->gzfile, Z_SYNC_FLUSH);
+#else
+ return -1;
+#endif
+}
+
+int
+Qeof (QFile *file)
+{
+ if (file->c != -1)
+ return 0;
+ if (file->file)
+ return feof (file->file);
+#ifdef HAVE_ZLIB
+ else
+ return gzeof (file->gzfile);
+#else
+ return -1;
+#endif
+}
+
+/*
+ Qgetline
+
+ Dynamic length version of Qgets. DO NOT free the buffer.
+*/
+const char *
+Qgetline (QFile *file)
+{
+ static int size = 256;
+ static char *buf = 0;
+ int len;
+
+ if (!buf) {
+ buf = malloc (size);
+ if (!buf)
+ return 0;
+ }
+
+ if (!Qgets (file, buf, size))
+ return 0;
+
+ len = strlen (buf);
+ while (len && buf[len - 1] != '\n') {
+ char *t = realloc (buf, size + 256);
+
+ if (!t)
+ return 0;
+ buf = t;
+ size += 256;
+ if (!Qgets (file, buf + len, size - len))
+ break;
+ len = strlen (buf);
+ }
+ return buf;
+}
View
56 wad/quakeio.h
@@ -0,0 +1,56 @@
+/*
+ quakeio.h
+
+ (description)
+
+ Copyright (C) 1996-1997 Id Software, Inc.
+ Copyright (C) 1999,2000 contributors of the QuakeForge project
+ Please see the file "AUTHORS" for a list of contributors
+
+ 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
+
+ $Id: quakeio.h,v 1.11 2003/05/23 17:16:59 taniwha Exp $
+*/
+#ifndef __quakeio_h
+#define __quakeio_h
+
+typedef struct QFile_s QFile;
+
+int Qrename(const char *old, const char *new);
+int Qremove(const char *path);
+int Qfilesize (QFile *file);
+QFile *Qopen(const char *path, const char *mode);
+QFile *Qdopen(int fd, const char *mode);
+QFile *Qsubopen (const char *path, int offs, int len, int zip);
+void Qclose(QFile *file);
+int Qread(QFile *file, void *buf, int count);
+int Qwrite(QFile *file, const void *buf, int count);
+int Qprintf(QFile *file, const char *fmt, ...) __attribute__((format(printf,2,3)));
+int Qputs(QFile *file, const char *buf);
+char *Qgets(QFile *file, char *buf, int count);
+int Qgetc(QFile *file);
+int Qputc(QFile *file, int c);
+int Qungetc (QFile *file, int c);
+int Qseek(QFile *file, long offset, int whence);
+long Qtell(QFile *file);
+int Qflush(QFile *file);
+int Qeof(QFile *file);
+const char *Qgetline(QFile *file);
+
+#endif /*__quakeio_h*/
View
108 wad/sys.h
@@ -0,0 +1,108 @@
+/*
+ sys.h
+
+ non-portable functions
+
+ Copyright (C) 1996-1997 Id Software, Inc.
+
+ 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
+
+ $Id: sys.h,v 1.32 2004/01/13 21:30:12 taniwha Exp $
+*/
+
+#ifndef __sys_h
+#define __sys_h
+
+#include <stdio.h>
+#include <stdarg.h>
+
+extern struct cvar_s *sys_nostdout;
+extern struct cvar_s *sys_extrasleep;
+extern struct cvar_s *sys_dead_sleep;
+extern struct cvar_s *sys_sleep;
+
+extern struct cvar_s *developer;
+
+
+extern const char sys_char_map[256];
+
+typedef struct date_s {
+ int sec;
+ int min;
+ int hour;
+ int day;
+ int mon;
+ int year;
+ char str[128];
+} date_t;
+
+int Sys_FileTime (const char *path);
+void Sys_mkdir (const char *path);
+
+typedef void (*sys_printf_t) (const char *fmt, va_list args);
+
+void Sys_SetStdPrintf (sys_printf_t func);
+void Sys_SetErrPrintf (sys_printf_t func);
+
+void Sys_Print (FILE *stream, const char *fmt, va_list args);
+void Sys_Printf (const char *fmt, ...) __attribute__((format(printf,1,2)));
+void Sys_DPrintf (const char *fmt, ...) __attribute__((format(printf,1,2)));
+void Sys_Error (const char *error, ...) __attribute__((format(printf,1,2), noreturn));
+void Sys_Quit (void) __attribute__((noreturn));
+void Sys_Shutdown (void);
+void Sys_RegisterShutdown (void (*func) (void));
+double Sys_DoubleTime (void);
+void Sys_TimeOfDay(date_t *date);
+
+int Sys_CheckInput (int idle, int net_socket);
+const char *Sys_ConsoleInput (void);
+
+void Sys_Sleep (void);
+
+int Sys_TimeID (void);
+// called to yield for a little bit so as
+// not to hog cpu when paused or debugging
+
+void Sys_MaskFPUExceptions (void);
+void Sys_PushSignalHook (int (*hook)(int, void*), void *data);
+void Sys_PopSignalHook (void);
+
+// send text to the console
+
+void Sys_Init (void);
+void Sys_Init_Cvars (void);
+
+//
+// memory protection
+//
+void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length);
+void Sys_PageIn (void *ptr, int size);
+
+//
+// system IO
+//
+void Sys_DebugLog(const char *file, const char *fmt, ...) __attribute__((format(printf,2,3)));
+
+#define SYS_CHECKMEM(x) \
+ do { \
+ if (!(x)) \
+ Sys_Error ("%s: Failed to allocate memory.", __FUNCTION__); \
+ } while (0)
+
+#endif // __sys_h
View
224 wad/wad.c
@@ -0,0 +1,224 @@
+/*
+ wad.c
+
+ wadfile tool
+
+ Copyright (C) 1996-1997 Id Software, Inc.
+ Copyright (C) 2002 Bill Currie <bill@taniwha.org>
+ Copyright (C) 2002 Jeff Teunissen <deek@quakeforge.net>
+
+ 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
+*/
+
+#include <getopt.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "wad.h"
+#include "cmdlib.h"
+
+#define VERSION "1.0"
+
+const char *this_program;
+options_t options;
+
+static const struct option long_options[] = {
+ {"create", no_argument, 0, 'c'},
+ {"test", no_argument, 0, 't'},
+ {"extract", no_argument, 0, 'x'},
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'V'},
+ {"pad", no_argument, 0, 'p'},
+ {"quiet", no_argument, 0, 'q'},
+ {"verbose", no_argument, 0, 'v'},
+ {NULL, 0, NULL, 0},
+};
+
+static void
+usage (int status)
+{
+ printf ("%s - QuakeForge Packfile tool\n", this_program);
+ printf ("Usage: %s <command> [options] ARCHIVE [FILE...]\n",
+ this_program);
+
+ printf ("Commands:\n"
+ " -c, --create Create archive\n"
+ " -t, --test Test archive\n"
+ " -x, --extract Extract archive contents\n"
+ " -h, --help Display this help and exit\n"
+ " -V, --version Output version information and exit\n\n");
+
+ printf ("Options:\n"
+ " -f, --file ARCHIVE Use ARCHIVE for archive filename\n"
+ " -p, --pad Pad file space to a 32-bit boundary\n"
+ " -q, --quiet Inhibit usual output\n"
+ " -v, --verbose Display more output than usual\n");
+ exit (status);
+}
+
+static int
+decode_args (int argc, char **argv)
+{
+ int c;
+
+ options.mode = mo_none;
+ options.pad = false;
+ options.wadfile = NULL;
+ options.verbosity = 0;
+
+ while ((c = getopt_long (argc, argv, "c" // create archive
+ "t" // test archive
+ "x" // extract archive contents
+ "h" // show help
+ "V" // show version
+ "f:" // filename
+ "p" // pad
+ "q" // quiet
+ "v" // verbose
+ , long_options, (int *) 0)) != EOF) {
+ switch (c) {
+ case 'h': // help
+ usage (0);
+ break;
+ case 'V': // version
+ printf ("wad version %s\n", VERSION);
+ exit (0);
+ break;
+ case 'c': // create
+ options.mode = mo_create;
+ break;
+ case 't': // test
+ options.mode = mo_test;
+ break;
+ case 'x': // extract
+ options.mode = mo_extract;
+ break;
+ case 'f': // set filename
+ options.wadfile = strdup (optarg);
+ break;
+ case 'q': // lower verbosity
+ options.verbosity--;
+ break;
+ case 'p': // pad
+ options.pad = true;
+ break;
+ case 'v': // increase verbosity
+ options.verbosity++;
+ break;
+ default:
+ usage (1);
+ }
+ }
+
+ if ((!options.wadfile) && argv[optind] && *(argv[optind]))
+ options.wadfile = strdup (argv[optind++]);
+
+ return optind;
+}
+
+int
+main (int argc, char **argv)
+{
+ wad_t *wad;
+ int i;//, j, rehash = 0;
+ lumpinfo_t *pf;
+
+ this_program = argv[0];
+
+ decode_args (argc, argv);
+
+ if (!options.wadfile) {
+ fprintf (stderr, "%s: no archive file specified.\n",
+ this_program);
+ usage (1);
+ }
+
+ switch (options.mode) {
+ case mo_extract:
+ if (!(wad = wad_open (options.wadfile))) {
+ fprintf (stderr, "%s: error opening %s: %s\n", this_program,
+ options.wadfile,
+ strerror (errno));
+ return 1;
+ }
+ for (i = 0; i < wad->numlumps; i++) {
+ pf = &wad->lumps[i];
+ if (optind == argc) {
+ if (options.verbosity > 0)
+ printf ("%s\n", pf->name);
+ wad_extract (wad, pf);
+ }
+ }
+ if (optind < argc) {
+ while (optind < argc) {
+ pf = wad_find_lump (wad, argv[optind]);
+ if (!pf) {
+ fprintf (stderr, "could not find %s\n", argv[optind]);
+ continue;
+ }
+ if (options.verbosity > 0)
+ printf ("%s\n", pf->name);
+ wad_extract (wad, pf);
+ optind++;
+ }
+ }
+ wad_close (wad);
+ break;
+ case mo_test:
+ if (!(wad = wad_open (options.wadfile))) {
+ fprintf (stderr, "%s: error opening %s: %s\n", this_program,
+ options.wadfile,
+ strerror (errno));
+ return 1;
+ }
+ for (i = 0; i < wad->numlumps; i++) {
+ if (options.verbosity >= 1)
+ printf ("%6d ", wad->lumps[i].size);
+ if (options.verbosity >= 0)
+ printf ("%3d %s\n", wad->lumps[i].type,
+ wad->lumps[i].name);
+ }
+ wad_close (wad);
+ break;
+ case mo_create:
+ /*
+ wad = wad_create (options.wadfile);
+ if (!wad) {
+ fprintf (stderr, "%s: error creating %s: %s\n", this_program,
+ options.wadfile,
+ strerror (errno));
+ return 1;
+ }
+ wad->pad = options.pad;
+ while (optind < argc) {
+ if (options.verbosity > 0)
+ printf ("%s\n", argv[optind]);
+ wad_add (wad, argv[optind++]);
+ }
+ wad_close (wad);
+ */
+ break;
+ default:
+ fprintf (stderr, "%s: No command given.\n",
+ this_program);
+ usage (1);
+ }
+ return 0;
+}
View
52 wad/wad.h
@@ -0,0 +1,52 @@
+/*
+ wad.h
+
+ wadfile tool (definitions)
+
+ Copyright (C) 1996-1997 Id Software, Inc.
+ Copyright (C) 2002 Bill Currie <bill@taniwha.org>
+ Copyright (C) 2002 Jeff Teunissen <deek@quakeforge.net>
+
+ 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
+
+ $Id: wad.h,v 1.1 2004/01/10 08:05:25 taniwha Exp $
+*/
+
+#ifndef __wad_h
+#define __wad_h
+
+#include "cmdlib.h"
+#include "wadfile.h"
+
+typedef enum {
+ mo_none,
+ mo_test,
+ mo_create,
+ mo_extract,
+} wadmode_t;
+
+typedef struct {
+ wadmode_t mode; // see above
+ int verbosity; // 0=silent
+ qboolean compress; // for the future
+ qboolean pad; // pad area of files to 4-byte boundary
+ char *wadfile; // wad file to read/write/test
+} options_t;
+
+#endif // __wad_h
View
362 wad/wadfile.c
@@ -0,0 +1,362 @@
+/*
+ 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
+
+*/
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+
+//#include "QF/hash.h"
+//#include "QF/qendian.h"
+#include "wad.h"
+
+// case insensitive hash and compare
+static unsigned long
+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;
+}
+
+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;
+}
+
+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);
+}
+
+void
+wad_rehash (wad_t *wad)
+{
+ int i;
+
+ for (i = 0; i < wad->numlumps; i++) {
+ Hash_AddElement (wad->lump_hash, &wad->lumps[i]);
+ }
+}
+
+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;
+}
+
+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;
+}
+
+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);
+}
+
+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));
+ }
+ Hash_AddElement (wad->lump_hash, pf);
+ return 0;
+}
+
+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));
+ }
+ Hash_AddElement (wad->lump_hash, pf);
+ return 0;
+}
+
+static int
+make_parents (const char *_path)
+{
+ char *path;
+ char *d, *p, t;
+
+ path = (char *) alloca (strlen (_path) + 1);
+ strcpy (path, _path);
+ for (p = path; *p && (d = strchr (p, '/')); p = d + 1) {
+ t = *d;
+ *d = 0;
+#ifdef _WIN32
+ if (mkdir (path) < 0)
+#else
+ if (mkdir (path, 0777) < 0)
+#endif
+ if (errno != EEXIST)
+ return -1;
+ *d = t;
+ }
+ return 0;
+}
+
+int
+wad_extract (wad_t *wad, lumpinfo_t *pf)
+{
+ const char *name = pf->name;
+ size_t count;
+ int len;
+ QFile *file;
+ char buffer[16384];
+
+ if (make_parents (name) == -1)
+ return -1;
+ if (!(file = Qopen (name, "wb")))
+ return -1;
+ Qseek (wad->handle, pf->filepos, SEEK_SET);
+ len = pf->size;
+ while (len) {
+ count = len;
+ if (count > sizeof (buffer))
+ count = sizeof (buffer);
+ count = Qread (wad->handle, buffer, count);
+ Qwrite (file, buffer, count);
+ len -= count;
+ }
+ Qclose (file);
+ return 0;
+}
+
+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);
+}
View
102 wad/wadfile.h
@@ -0,0 +1,102 @@
+/*
+ wadfile.h
+
+ (description)
+
+ Copyright (C) 1996-1997 Id Software, Inc.
+
+ 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
+
+ $Id: wadfile.h,v 1.2 2004/01/15 07:16:42 taniwha Exp $
+*/
+// wadfile.h
+
+#ifndef __QF_wadfile_h
+#define __QF_wadfile_h
+
+#include "quakeio.h"
+#include "cmdlib.h"
+
+//===============
+// TYPES
+//===============
+
+#define CMP_NONE 0
+#define CMP_LZSS 1
+
+#define TYP_NONE 0
+#define TYP_LABEL 1
+
+#define TYP_LUMPY 64 // 64 + grab command number
+#define TYP_PALETTE 64
+#define TYP_QTEX 65
+#define TYP_QPIC 66
+#define TYP_SOUND 67
+#define TYP_MIPTEX 68
+
+typedef struct qpic_s {
+ int width, height;
+ byte data[4]; // variably sized
+} qpic_t;
+
+typedef struct wadinfo_s {
+ char id[4]; // should be WAD2 or 2DAW
+ int numlumps;
+ int infotableofs;
+} wadinfo_t;
+
+typedef struct lumpinfo_s {
+ int filepos;
+ int disksize;
+ int size; // uncompressed
+ byte type;
+ byte compression;
+ byte pad1, pad2;
+ char name[16]; // must be null terminated
+} lumpinfo_t;
+
+typedef struct wad_s {
+ char *filename;
+ QFile *handle;
+ int numlumps;
+ int lumps_size;
+ lumpinfo_t *lumps;
+ struct hashtab_s *lump_hash;
+
+ wadinfo_t header;
+
+ int modified;
+ int old_numlumps;
+ int pad;
+} wad_t;
+
+wad_t *wad_new (const char *name);
+void wad_del (wad_t *wad);
+void wad_rehash (wad_t *wad);
+wad_t *wad_open (const char *name);
+void wad_close (wad_t *wad);
+wad_t *wad_create (const char *name);
+int wad_add (wad_t *wad, const char *filename, const char *lumpname,
+ byte type);
+int wad_add_data (wad_t *wad, const char *lumpname, byte type,
+ const void *data, int bytes);
+int wad_extract (wad_t *wad, lumpinfo_t *pf);
+lumpinfo_t *wad_find_lump (wad_t *wad, const char *filename);
+
+#endif//__QF_wadfile_h

0 comments on commit fe3aa92

Please sign in to comment.
Something went wrong with that request. Please try again.