summaryrefslogtreecommitdiff
path: root/wad.c
diff options
context:
space:
mode:
authorIan C <ianc@noddybox.co.uk>2011-06-09 13:57:32 +0000
committerIan C <ianc@noddybox.co.uk>2011-06-09 13:57:32 +0000
commit0f12083fdb14ae813e419500918b95cb83070586 (patch)
tree93f855836faede895a4c37d12dcc46a8c5fbb835 /wad.c
Added copies of old numbered releases.0.01
Diffstat (limited to 'wad.c')
-rw-r--r--wad.c806
1 files changed, 806 insertions, 0 deletions
diff --git a/wad.c b/wad.c
new file mode 100644
index 0000000..ca7f28a
--- /dev/null
+++ b/wad.c
@@ -0,0 +1,806 @@
+/*
+
+ viDOOM - level editor for DOOM
+
+ Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ WAD file definitions and readers
+
+*/
+static const char rcs_id[]="$Id$";
+
+#include "config.h"
+#include "globals.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "wad.h"
+#include "gfx.h"
+#include "mem.h"
+#include "file.h"
+
+/* ---------------------------------------- TYPES
+*/
+
+typedef struct WadEnt
+ {
+ DirName name;
+ Long off;
+ Long size;
+ } WadEnt;
+
+typedef struct WadDirTable
+ {
+ int no;
+ WadEnt *ent;
+ } WadDirTable;
+
+typedef struct WadFile
+ {
+ FILE *fp;
+ char path[PATH_MAX+1];
+ } WadFile;
+
+
+/* ---------------------------------------- VARS
+*/
+
+#define IGNORE_LUMP 0
+#define THING_LUMP 1
+#define VERTEX_LUMP 2
+#define LINEDEF_LUMP 3
+#define SIDEDEF_LUMP 4
+#define SECTOR_LUMP 5
+
+#define ERR(e,r) do {wad_err=e;return(r);} while(0)
+static const char *wad_errstr[WAD_NOERROR]=
+ {
+ "no error",
+ "File not found",
+ "File not an IWAD or PWAD",
+ "File not an IWAD",
+ "File not a PWAD",
+ "Map not found",
+ "Lump not found",
+ "Could not create file",
+ __FILE__ " - ??? BROKEN ???",
+ };
+
+static int wad_err=WAD_OK;
+
+static List waddir=NULL;
+static List wadlist=NULL;
+
+
+/* ---------------------------------------- MACROS
+*/
+#define ERR(e,r) do {wad_err=e;return(r);} while(0)
+
+
+/* ---------------------------------------- PREDICATE FUNCTIONS
+*/
+static int FindDirEnt(void *a,void *b)
+{
+ WadDir *aa;
+
+ aa=(WadDir *)a;
+
+ return(STREQ(aa->name,b));
+}
+
+
+static int FindWAD(void *a,void *b)
+{
+ WadFile *aa;
+
+ aa=a;
+
+ return(FilenamesEqual(aa->path,b));
+}
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static Word GetShort(FILE *fp)
+{
+ return ((Short)fgetc(fp)|((Short)fgetc(fp))<<8);
+}
+
+
+static Long GetLong(FILE *fp)
+{
+ return ((Long)fgetc(fp)|
+ ((Long)fgetc(fp))<<8|
+ ((Long)fgetc(fp))<<16|
+ ((Long)fgetc(fp))<<24);
+}
+
+
+static char *GetName(FILE *fp)
+{
+ static DirName d;
+
+ fread(d,1,8,fp);
+ d[sizeof(d)-1]=0;
+ return(d);
+}
+
+
+static void PutShort(FILE *fp,Short s)
+{
+ fputc(s&0xff,fp);
+ fputc((s>>8)&0xff,fp);
+}
+
+
+static void PutLong(FILE *fp,Long l)
+{
+ fputc(l&0xff,fp);
+ fputc((l>>8)&0xff,fp);
+ fputc((l>>16)&0xff,fp);
+ fputc((l>>24)&0xff,fp);
+}
+
+
+static void PutName(FILE *fp,char *p)
+{
+ int f;
+
+ f=0;
+ while(f<8)
+ {
+ fputc(*p,fp);
+
+ if (*p)
+ p++;
+
+ f++;
+ }
+}
+
+
+static void PutDirEnt(FILE *fp,Long off,Long size,char *p)
+{
+ PutLong(fp,off);
+ PutLong(fp,size);
+ PutName(fp,p);
+}
+
+
+static int IsMapLump(char *n)
+{
+ return(STREQ("THINGS",n)||
+ STREQ("LINEDEFS",n)||
+ STREQ("SIDEDEFS",n)||
+ STREQ("VERTEXES",n)||
+ STREQ("SEGS",n)||
+ STREQ("SSECTORS",n)||
+ STREQ("NODES",n)||
+ STREQ("SECTORS",n)||
+ STREQ("REJECT",n)||
+ STREQ("BLOCKMAP",n));
+}
+
+static int HandledMapLump(char *n)
+{
+ static struct
+ {
+ char *name;
+ int lump;
+ } lump[]= {
+ {"THINGS",THING_LUMP},
+ {"VERTEXES",VERTEX_LUMP},
+ {"SIDEDEFS",SIDEDEF_LUMP},
+ {"LINEDEFS",LINEDEF_LUMP},
+ {"SECTORS",SECTOR_LUMP},
+ {NULL,IGNORE_LUMP},
+ };
+
+ int f;
+
+ f=0;
+ while(lump[f].name)
+ {
+ if (STREQ(lump[f].name,n))
+ return(lump[f].lump);
+
+ f++;
+ }
+
+ return(IGNORE_LUMP);
+}
+
+
+static WadDir *GetDir(char *name)
+{
+ Iterator i;
+ WadDir *w;
+
+ if (!(i=ListFindElem(waddir,FindDirEnt,name)))
+ return(NULL);
+
+ w=IteratorData(i);
+ IteratorClear(i);
+
+ return(w);
+}
+
+
+static WadFile *GetWADFile(char *name)
+{
+ Iterator i;
+ WadFile *w;
+
+ if (!(i=ListFindElem(wadlist,FindWAD,name)))
+ return(NULL);
+
+ w=IteratorData(i);
+ IteratorClear(i);
+
+ return(w);
+}
+
+
+static void *LoadDirEnt(WadDir *d,Long *size)
+{
+ void *ret;
+ WadFile *wf;
+
+ if (!(wf=GetWADFile(d->wad)))
+ return(NULL);
+
+ ret=Grab(d->size);
+ fseek(wf->fp,(long)d->off,SEEK_SET);
+ fread(ret,1,d->size,wf->fp);
+
+ if (size)
+ *size=d->size;
+
+ return(ret);
+}
+
+
+static WadDirTable *ReadDir(char *wad, char *expect)
+{
+ char type[4];
+ WadDirTable *d;
+ int f;
+ FILE *fp;
+
+ if (!(fp=fopen(wad,"rb")))
+ ERR(WAD_FILE_NOT_FOUND,NULL);
+
+ fread(type,1,4,fp);
+
+ if (STRNEQ("IWAD",expect)&&(!STRNEQ("IWAD",type)))
+ ERR(WAD_NOT_IWAD,NULL);
+ else if (STRNEQ("PWAD",expect)&&(!STRNEQ("PWAD",type)))
+ ERR(WAD_NOT_PWAD,NULL);
+
+ d=Grab(sizeof(WadDirTable));
+ d->no=GetLong(fp);
+
+ d->ent=Grab(sizeof(WadEnt)*d->no);
+
+ fseek(fp,(long)GetLong(fp),SEEK_SET);
+
+ for(f=0;f<d->no;f++)
+ {
+ d->ent[f].off=GetLong(fp);
+ d->ent[f].size=GetLong(fp);
+ strcpy(d->ent[f].name,GetName(fp));
+ }
+
+ return(d);
+}
+
+
+static int AddWAD(char *wad,char *type)
+{
+ Iterator i;
+ WadDirTable *d;
+ WadDir w;
+ int f;
+ char *wadname;
+ WadFile *wf;
+ int check;
+ int e2m1;
+ int map01;
+
+ /* Read in the directory from the WAD
+ */
+ if (!waddir)
+ {
+ waddir=ListNew(sizeof(WadDir));
+ wadlist=ListNew(sizeof(WadFile));
+ }
+
+ if (!(d=ReadDir(wad,type)))
+ return(wad_err);
+
+ /* Find the WAD name in the WAD list
+ */
+ if ((i=ListFindElem(wadlist,FindWAD,wad)))
+ {
+ wadname=((WadFile *)IteratorData(i))->path;
+ IteratorClear(i);
+ }
+ else
+ {
+ wf=Grab(sizeof(WadFile));
+
+ if (!(wf->fp=fopen(wad,"rb")))
+ GFX_exit(EXIT_FAILURE,"BIZARRE: WAD opening failed after "
+ "first open succeeded on\nt%s\n",wad);
+
+ strcpy(wf->path,wad);
+ wadname=wf->path;
+ ListInsert(wadlist,wf);
+ }
+
+ /* Add the directory entries to the global dir
+ */
+ e2m1=FALSE;
+ map01=FALSE;
+ check=STRNEQ("IWAD",type);
+
+ for(f=d->no-1;f>=0;f--)
+ {
+ w.wad=wadname;
+ w.off=d->ent[f].off;
+ w.size=d->ent[f].size;
+ strcpy(w.name,d->ent[f].name);
+
+ if (check)
+ {
+ if (STREQ("E2M1",d->ent[f].name))
+ e2m1=TRUE;
+
+ if (STREQ("MAP01",d->ent[f].name))
+ map01=TRUE;
+ }
+
+ ListInsert(waddir,&w);
+ }
+
+ /* Shareware checks fo IWAD files
+ */
+ if (check)
+ switch(level_style)
+ {
+ case DOOM_LEVELS:
+ case ULTIMATE_DOOM_LEVELS:
+ if (e2m1)
+ break;
+ case DOOM_2_LEVELS:
+ if (map01)
+ break;
+ default:
+ GFX_exit(EXIT_FAILURE,
+ "You MUST have an IWAD from the registered "
+ "version of\nDOOM, ULTIMATE DOOM, DOOM II "
+ "or FINAL DOOM\n");
+ break;
+ }
+
+ Release(d->ent);
+ Release(d);
+
+ ERR(WAD_OK,WAD_OK);
+}
+
+
+/* ---------------------------------------- EXPORTED FUNCTIONS
+*/
+
+int AddIWAD(char *wad)
+{
+ return (AddWAD(wad,"IWAD"));
+}
+
+
+int AddPWAD(char *wad)
+{
+ return (AddWAD(wad,"PWAD"));
+}
+
+
+int CloseWad(char *wad)
+{
+ WadDir *w;
+ Iterator i;
+
+ if (!(i=ListFindElem(wadlist,FindWAD,wad)))
+ ERR(WAD_FILE_NOT_FOUND,WAD_FILE_NOT_FOUND);
+
+ i=IteratorDelete(i);
+ IteratorClear(i);
+
+ i=ListIterator(waddir);
+
+ while(i)
+ {
+ w=IteratorData(i);
+
+ if (strcmp(w->wad,wad)==0)
+ i=IteratorDelete(i);
+ else
+ i=IteratorNext(i);
+ }
+
+ IteratorClear(i);
+
+ ERR(WAD_OK,WAD_OK);
+}
+
+
+char *OpenWads(void)
+{
+ Iterator i;
+ WadFile *w;
+ char *ret;
+
+ if (!(i=ListIterator(wadlist)))
+ ret=Strdup("");
+ else
+ {
+ w=IteratorData(i);
+ ret=Grab(PATH_MAX+1);
+ strcpy(ret,w->path);
+ i=IteratorNext(i);
+
+ while(i)
+ {
+ strcat(ret,"|");
+ w=IteratorData(i);
+ ret=ReGrab(ret,strlen(ret)+PATH_MAX+1);
+ strcat(ret,w->path);
+ i=IteratorNext(i);
+ }
+ }
+
+ return(ret);
+}
+
+
+Iterator GetWadDir(void)
+{
+ return(ListIterator(waddir));
+}
+
+
+int GetWadDirSize(void)
+{
+ return(ListSize(waddir));
+}
+
+
+void *GetLump(char *name, Long *size)
+{
+ WadDir *d;
+ void *ret;
+
+ if (size)
+ *size=0;
+
+ if (!(d=GetDir(name)))
+ ERR(WAD_LUMP_NOT_FOUND,NULL);
+
+ if ((ret=LoadDirEnt(d,size)))
+ ERR(WAD_OK,ret);
+ else
+ ERR(WAD_FILE_NOT_FOUND,NULL);
+}
+
+
+WadMap *LoadMap(char *name)
+{
+ Iterator i;
+ WadMap *map;
+ WadDir *dir;
+ WadFile *wf;
+ Thing thing;
+ Vertex vertex;
+ Sidedef sidedef;
+ Linedef linedef;
+ Sector sector;
+ int f;
+
+ if (!(i=ListFindElem(waddir,FindDirEnt,name)))
+ ERR(WAD_MAP_NOT_FOUND,NULL);
+
+ dir=IteratorData(i);
+ if (!(wf=GetWADFile(dir->wad)))
+ ERR(WAD_FILE_NOT_FOUND,NULL);
+
+ map=Grab(sizeof(WadMap));
+ map->thing=MapNew(sizeof(Thing));
+ map->vertex=MapNew(sizeof(Vertex));
+ map->sidedef=MapNew(sizeof(Sidedef));
+ map->linedef=MapNew(sizeof(Linedef));
+ map->sector=MapNew(sizeof(Sector));
+
+ /* Step through the items following the map in the dir to load the
+ lumps for the level in.
+ */
+ while(TRUE)
+ {
+ i=IteratorNext(i);
+ dir=IteratorData(i);
+
+ if (!IsMapLump(dir->name))
+ ERR(WAD_OK,map);
+
+ switch (HandledMapLump(dir->name))
+ {
+ case THING_LUMP:
+ fseek(wf->fp,(long)dir->off,SEEK_SET);
+
+ for(f=0;f<dir->size/THING_SIZE;f++)
+ {
+ thing.x=GetShort(wf->fp);
+ thing.y=GetShort(wf->fp);
+ thing.ang=GetShort(wf->fp);
+ thing.type=GetShort(wf->fp);
+ thing.opt=GetShort(wf->fp);
+
+ MapAdd(map->thing,f,&thing);
+ }
+ break;
+
+ case VERTEX_LUMP:
+ fseek(wf->fp,(long)dir->off,SEEK_SET);
+
+ for(f=0;f<dir->size/VERTEX_SIZE;f++)
+ {
+ vertex.x=GetShort(wf->fp);
+ vertex.y=GetShort(wf->fp);
+ MapAdd(map->vertex,f,&vertex);
+ }
+ break;
+
+ case SIDEDEF_LUMP:
+ fseek(wf->fp,(long)dir->off,SEEK_SET);
+
+ for(f=0;f<dir->size/SIDEDEF_SIZE;f++)
+ {
+ sidedef.x=GetShort(wf->fp);
+ sidedef.y=GetShort(wf->fp);
+ strcpy(sidedef.upper,GetName(wf->fp));
+ strcpy(sidedef.lower,GetName(wf->fp));
+ strcpy(sidedef.middle,GetName(wf->fp));
+ sidedef.sector=GetShort(wf->fp);
+ MapAdd(map->sidedef,f,&sidedef);
+ }
+ break;
+
+ case LINEDEF_LUMP:
+ fseek(wf->fp,(long)dir->off,SEEK_SET);
+
+ for(f=0;f<dir->size/LINEDEF_SIZE;f++)
+ {
+ linedef.from=GetShort(wf->fp);
+ linedef.to=GetShort(wf->fp);
+ linedef.flags=GetShort(wf->fp);
+ linedef.type=GetShort(wf->fp);
+ linedef.tag=GetShort(wf->fp);
+ linedef.right=GetShort(wf->fp);
+ linedef.left=GetShort(wf->fp);
+ MapAdd(map->linedef,f,&linedef);
+ }
+ break;
+
+ case SECTOR_LUMP:
+ fseek(wf->fp,(long)dir->off,SEEK_SET);
+
+ for(f=0;f<dir->size/SECTOR_SIZE;f++)
+ {
+ sector.floor=GetShort(wf->fp);
+ sector.ceiling=GetShort(wf->fp);
+ strcpy(sector.floor_t,GetName(wf->fp));
+ strcpy(sector.ceiling_t,GetName(wf->fp));
+ sector.light=GetShort(wf->fp);
+ sector.special=GetShort(wf->fp);
+ sector.tag=GetShort(wf->fp);
+ MapAdd(map->sector,f,&sector);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ ERR(WAD_OK,map);
+}
+
+
+WadMap *NewMap(void)
+{
+ WadMap *map;
+
+ map=Grab(sizeof(WadMap));
+ map->thing=MapNew(sizeof(Thing));
+ map->vertex=MapNew(sizeof(Vertex));
+ map->sidedef=MapNew(sizeof(Sidedef));
+ map->linedef=MapNew(sizeof(Linedef));
+ map->sector=MapNew(sizeof(Sector));
+
+ return(map);
+}
+
+
+WadMap *ClearMap(WadMap *map)
+{
+ MapClear(map->thing);
+ MapClear(map->vertex);
+ MapClear(map->sidedef);
+ MapClear(map->linedef);
+ MapClear(map->sector);
+ Release(map);
+ return(NULL);
+}
+
+
+int SaveMap(WadMap *map, char *name, char *wad)
+{
+ FILE *fp;
+ Long off;
+ int f;
+
+ if (!(fp=fopen(wad,"wb")))
+ ERR(WAD_COULD_NOT_CREATE,WAD_COULD_NOT_CREATE);
+
+ off=MapSize(map->vertex)*VERTEX_SIZE+
+ MapSize(map->sidedef)*SIDEDEF_SIZE+
+ MapSize(map->linedef)*LINEDEF_SIZE+
+ MapSize(map->sector)*SECTOR_SIZE+
+ MapSize(map->thing)*THING_SIZE+12;
+
+ /* Put PWAD header
+ */
+ fputs("PWAD",fp);
+ PutLong(fp,10);
+ PutLong(fp,off);
+
+ /* Put THINGS
+ */
+ for(f=0;f<MapSize(map->thing);f++)
+ {
+ Thing *t;
+
+ t=MapElem(map->thing,f);
+ PutShort(fp,t->x);
+ PutShort(fp,t->y);
+ PutShort(fp,t->ang);
+ PutShort(fp,t->type);
+ PutShort(fp,t->opt);
+ }
+
+ /* Put LINEDEFS
+ */
+ for(f=0;f<MapSize(map->linedef);f++)
+ {
+ Linedef *l;
+
+ l=MapElem(map->linedef,f);
+ PutShort(fp,l->from);
+ PutShort(fp,l->to);
+ PutShort(fp,l->flags);
+ PutShort(fp,l->type);
+ PutShort(fp,l->tag);
+ PutShort(fp,l->right);
+ PutShort(fp,l->left);
+ }
+
+ /* Put SIDEDEFS
+ */
+ for(f=0;f<MapSize(map->sidedef);f++)
+ {
+ Sidedef *s;
+
+ s=MapElem(map->sidedef,f);
+ PutShort(fp,s->x);
+ PutShort(fp,s->y);
+ PutName(fp,s->upper);
+ PutName(fp,s->lower);
+ PutName(fp,s->middle);
+ PutShort(fp,s->sector);
+ }
+
+ /* Put VERTEXES
+ */
+ for(f=0;f<MapSize(map->vertex);f++)
+ {
+ Vertex *v;
+
+ v=MapElem(map->vertex,f);
+ PutShort(fp,v->x);
+ PutShort(fp,v->y);
+ }
+
+ /* Skip SEGS, SSECTORS, NODE
+ */
+
+ /* Put SECTORS
+ */
+ for(f=0;f<MapSize(map->sector);f++)
+ {
+ Sector *s;
+
+ s=MapElem(map->sector,f);
+ PutShort(fp,s->floor);
+ PutShort(fp,s->ceiling);
+ PutName(fp,s->floor_t);
+ PutName(fp,s->ceiling_t);
+ PutShort(fp,s->light);
+ PutShort(fp,s->special);
+ PutShort(fp,s->tag);
+ }
+
+ /* Skip REJECT, BLOCKMAP
+ */
+
+ /* Create directory
+ */
+ off=12;
+
+ PutDirEnt(fp,off,0,name);
+
+ PutDirEnt(fp,off,MapSize(map->thing)*THING_SIZE,"THINGS");
+ off+=MapSize(map->thing)*THING_SIZE;
+
+ PutDirEnt(fp,off,MapSize(map->linedef)*LINEDEF_SIZE,"LINEDEFS");
+ off+=MapSize(map->linedef)*LINEDEF_SIZE;
+
+ PutDirEnt(fp,off,MapSize(map->sidedef)*SIDEDEF_SIZE,"SIDEDEFS");
+ off+=MapSize(map->sidedef)*SIDEDEF_SIZE;
+
+ PutDirEnt(fp,off,MapSize(map->vertex)*VERTEX_SIZE,"VERTEXES");
+ off+=MapSize(map->vertex)*VERTEX_SIZE;
+
+ PutDirEnt(fp,off,0,"SEGS");
+ PutDirEnt(fp,off,0,"SSECTORS");
+ PutDirEnt(fp,off,0,"NODES");
+
+ PutDirEnt(fp,off,MapSize(map->sector)*SECTOR_SIZE,"SECTORS");
+ off+=MapSize(map->sector)*SECTOR_SIZE;
+
+ PutDirEnt(fp,off,0,"REJECT");
+ PutDirEnt(fp,off,0,"BLOCKMAP");
+
+ fclose(fp);
+
+ ERR(WAD_OK,WAD_OK);
+}
+
+
+int WadError(void)
+{
+ return(wad_err);
+}
+
+
+const char *WadErrorString(void)
+{
+ return(wad_errstr[wad_err]);
+}
+
+/* END OF FILE */