/******************************************************************************
	MODULE:		WADIO.C
	WRITTEN BY:	Robert Fenske, Jr. (rfenske@swri.edu)
				Southwest Research Institute
				Electromagnetics Division
				6220 Culebra
				San Antonio, Texas 78238-5166
	CREATED:	May  1994
	DESCRIPTION:	This module contains routines to read and write DOOM-
			related IWAD, PWAD, and VERDA patch files.

			There is a number of byte swapping calls used in the
			SunOS case; these calls are ugly, but necessary since
			the WAD files store data in little-endian order.

			DOOM is a trademark of id Software, Inc.
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "dmglobal.i"

#if defined(sun) && !defined(BSWAP)		/* anything big-endian (like */
#define BSWAP		1			/* Suns) needs bytes swapped */
#endif

#if defined(BSWAP)
#define bswapw(v)	((unsigned short)((((v)>>8)&0xFF) | ((v)<<8)))
#define bswapl(v)	((unsigned long)((((v)>>24)&0x000000FFL) | \
			                 (((v)>> 8)&0x0000FF00L) | \
			                 (((v)<< 8)&0x00FF0000L) | \
			                 ( (v)<<24)))
#else
#define bswapw(v)	(v)
#define bswapl(v)	(v)
#endif

#define is_type(n,t)	(strncmp((n),mapresrc[t],sizeof(n)) == 0)

local char mapresrc[][9] = {			/* resource name in dir */
	"", "THINGS", "LINEDEFS", "SIDEDEFS", "VERTEXES", "SEGS",
	"SSECTORS", "NODES", "SECTORS", "REJECT", "BLOCKMAP"
};
local int mapresiz[] = {			/* item size in resource */
	1, sizeof(DOOM_THING), sizeof(DOOM_LINE),
	sizeof(DOOM_SIDE), sizeof(DOOM_VERT),
	sizeof(DOOM_SEGS), sizeof(DOOM_SSECTOR),
	sizeof(DOOM_NODE), sizeof(DOOM_SECTOR),
	sizeof(DOOM_REJECT), sizeof(DOOM_BLOCKMAP)
};


/******************************************************************************
	ROUTINE:	wad_bswap(winfo,resource)
	WRITTEN BY:	Robert Fenske, Jr.
	CREATED:	May  1994
	DESCRIPTION:	This routine swaps the bytes in the short integer
			fields of the various resources.  This is necessary
			since the data files store integers in Intel little-
			endian order, while all real systems use big-endian
			order.
******************************************************************************/
#if defined(BSWAP)
#if defined(ANSI_C)
local void wad_bswap(register WAD_INFO *winfo, int resource)
#else
local void wad_bswap(winfo,resource)
register WAD_INFO *winfo;
int resource;
#endif
{
  short *data = (short *)winfo->data[resource];	/* where data is */
  DOOM_SIDE *sides = (DOOM_SIDE *)data;
  DOOM_SECTOR *sects = (DOOM_SECTOR *)data;
  int cnt = resource_count(&winfo->dir[resource]);
  int type;
  register int d, w;

  if (data != NULL) {
    for (type = 0; type < numelm(mapresrc); type++)
      if (is_type(winfo->dir[resource].name,type)) break;
    switch (type) {
       case THINGS:
       case LINES:
       case VERTS:
       case SEGS:
       case SSECTS:
       case NODES:
       case BLKMAPS:
        for (d = 0; d < cnt; d++)
          for (w = 0; w < mapresiz[type]/2; w++)
            data[d*mapresiz[type]/2+w] = bswapw(data[d*mapresiz[type]/2+w]);
      bcase SIDES:				/* only swap integer fields */
        for (d = 0; d < cnt; d++) {
          sides[d].image_xoff = bswapw(sides[d].image_xoff);
          sides[d].image_yoff = bswapw(sides[d].image_yoff);
          sides[d].sectndx = bswapw(sides[d].sectndx);
        }
      bcase SECTS:				/* only swap integer fields */
        for (d = 0; d < cnt; d++) {
          sects[d].floor_ht = bswapw(sects[d].floor_ht);
          sects[d].ceil_ht = bswapw(sects[d].ceil_ht);
          sects[d].light_lvl = bswapw(sects[d].light_lvl);
          sects[d].property = bswapw(sects[d].property);
          sects[d].line_tag = bswapw(sects[d].line_tag);
        }
      bcase REJECTS:				/* don't have to swap this */
        ;
      bdefault:					/* something else--no swap */
        ;
    }
  }
}
#endif


/******************************************************************************
	ROUTINE:	resource_update(winfo,entry,data,count)
	WRITTEN BY:	Robert Fenske, Jr.
	CREATED:	June 1994
	DESCRIPTION:	This routine assigns the input data to the specified
			entry.  If the entry already has data, it is freed
			first.  The changed flag is set to TRUE.
******************************************************************************/
#if defined(ANSI_C)
void resource_update(register WAD_INFO *winfo, int entry, void *data,
                     long count)
#else
void resource_update(winfo,entry,data,count)
register WAD_INFO *winfo;
int entry;
void *data;
long count;
#endif
{
  register int type;

  if ((char *)data != winfo->data[entry]) blockfree(winfo->data[entry]);
  winfo->data[entry] = (char *)data;
  for (type = 0; type < numelm(mapresrc); type++)
    if (is_type(winfo->dir[entry].name,type)) break;
  if (type < numelm(mapresrc)) winfo->dir[entry].nbytes = count*mapresiz[type];
  else                         winfo->dir[entry].nbytes = count;
  winfo->count[entry] = count;
  winfo->changed[entry] = TRUE;
}


/******************************************************************************
	ROUTINE:	resource_count(entry)
	WRITTEN BY:	Robert Fenske, Jr.
	CREATED:	June 1994
	DESCRIPTION:	This routine gets the count of the number of items in
			the input directory entry (resource).  If the entry
			is not associated with map level data, the number of
			items is simply the byte count.
******************************************************************************/
#if defined(ANSI_C)
int resource_count(register DIR_ENTRY *entry)
#else
int resource_count(entry)
register DIR_ENTRY *entry;
#endif
{
  int count = 0;
  register int type;

  if (entry != NULL) {
    for (type = 0; type < numelm(mapresrc); type++)
      if (is_type(entry->name,type)) break;
    if (type < numelm(mapresrc)) count = entry->nbytes/mapresiz[type];
    else                         count = entry->nbytes;
  }
  return count;
}


/******************************************************************************
	ROUTINE:	patch_read(winfo,entry,resources_needed)
	WRITTEN BY:	Robert Fenske, Jr.
	CREATED:	May  1994
	DESCRIPTION:	This routine reads a VERDA patch file.  It reads the
			file twice; the first time is to obtain the sizes of
			each of the resources.  The input resources_needed is
			ignored--everything in the patch file is read.  Also,
			only one level's data is stored in a patch file.
******************************************************************************/
#if defined(ANSI_C)
boolean patch_read(register WAD_INFO *winfo, int entry, long resources_needed)
#else
boolean patch_read(winfo,entry,resources_needed)
register WAD_INFO *winfo;
int entry;
long resources_needed;
#endif
{
  char str[256];
  int type;
  DOOM_THING *things;
  DOOM_LINE *lines;
  DOOM_SIDE *sides;
  DOOM_VERT *verts;
  DOOM_SEGS *segs;
  DOOM_SSECTOR *ssecs;
  DOOM_NODE *nodes;
  DOOM_SECTOR *sects;
  register int k;

  if (winfo->head.count <= entry)		/* can't read beyond count */
    return FALSE;
  for (k = 0; k < ALL; k++)
    winfo->count[k] = 0;
  rewind(winfo->fp);
  for (k = 0; fgets(str,sizeof str,winfo->fp) != NULL; ) {/* get counts */
    if (str[0] == ';' || str[0] == '#')		/* skip any comments */
      continue;
    if (k == 0) {
      k = sscanf(str," %d %d %d %lf",&winfo->ep,&winfo->mp,&type,&winfo->ver);
      continue;
    }
    k = str[0] != '%';
    if (k) winfo->count[type]++;
  }
  for (k = 0; k < ALL; k++)
    if ((resources_needed & (1L<<k)) && winfo->count[k] > 0) {
      blockfree(winfo->data[k]);
      winfo->dir[k].nbytes = winfo->count[k]*mapresiz[k];
      winfo->data[k] = blockmem(char,winfo->dir[k].nbytes);
    }
  things = (DOOM_THING *)winfo->data[THINGS];
  lines  = (DOOM_LINE *)winfo->data[LINES];
  sides  = (DOOM_SIDE *)winfo->data[SIDES];
  verts  = (DOOM_VERT *)winfo->data[VERTS];
  segs   = (DOOM_SEGS *)winfo->data[SEGS];
  ssecs  = (DOOM_SSECTOR *)winfo->data[SSECTS];
  nodes  = (DOOM_NODE *)winfo->data[NODES];
  sects  = (DOOM_SECTOR *)winfo->data[SECTS];
  rewind(winfo->fp);
  for (k = 0; fgets(str,sizeof str,winfo->fp) != NULL; ) {
    if (str[0] == ';' || str[0] == '#')		/* skip any comments */
      continue;
    if (k == 0) {
      k = sscanf(str," %d %d %d %lf",&winfo->ep,&winfo->mp,&type,&winfo->ver);
      continue;
    }
    if (!(resources_needed & (1L << type)))
      continue;
    switch (type) {
      case THINGS:				/* THINGS */
	sscanf(str,"%*d %4hx %4hx %3hd %4hx %4hx",
               &things->x,&things->y,&things->angle,&things->item,
               &things->flag);
        things++;
      bcase LINES:				/* LINES */
	sscanf(str,"%*d %4hx %4hx %4hx %4hx %4hx %4hx %4hx",
               &lines->fndx,&lines->tndx,&lines->flag,&lines->action_flag,
               &lines->sect_tag,&lines->rsidndx,&lines->lsidndx);
        lines++;
      bcase SIDES:				/* SIDES */
	sscanf(str,"%*d %4hx %4hx %8c %8c %8c %4hx",
               &sides->image_xoff,&sides->image_yoff,
               sides->lwall,sides->uwall,sides->nwall,&sides->sectndx);
        while (sides->lwall[min(8,strlen(sides->lwall))-1] == ' ')
          sides->lwall[min(8,strlen(sides->lwall))-1] = '\0';
        while (sides->uwall[min(8,strlen(sides->uwall))-1] == ' ')
          sides->uwall[min(8,strlen(sides->uwall))-1] = '\0';
        while (sides->nwall[min(8,strlen(sides->nwall))-1] == ' ')
          sides->nwall[min(8,strlen(sides->nwall))-1] = '\0';
        sides++;
      bcase VERTS:				/* VERTEXES */
	sscanf(str,"%*d %4hx %4hx",&verts->x,&verts->y);
        verts++;
      bcase SEGS:				/* SEGS */
        sscanf(str,"%*d %4hx %4hx %4hx %4hx %4hx %4hx",
               &segs->fndx,&segs->tndx,&segs->angle,&segs->lndx,&segs->sndx,
               &segs->loffset);
        segs++;
      bcase SSECTS:				/* SSECTORS */
        sscanf(str,"%*d %4hx %4hx",&ssecs->count,&ssecs->sndx);
        ssecs++;
      bcase NODES:				/* NODES */
        sscanf(str,"%*d \
%4hx %4hx %4hx %4hx %4hx %4hx %4hx %4hx %4hx %4hx %4hx %4hx %4hx %4hx",
               &nodes->x,&nodes->y,&nodes->xdel,&nodes->ydel,
               &nodes->rymax,&nodes->rymin,&nodes->rxmin,&nodes->rxmax,
               &nodes->lymax,&nodes->lymin,&nodes->lxmin,&nodes->lxmax,
               &nodes->nndx[0],&nodes->nndx[1]);
        nodes++;
      bcase SECTS:				/* SECTORS */
	sscanf(str,"%*d %4hx %4hx %8c %8c %4hx %4hx %4hx",
               &sects->floor_ht,&sects->ceil_ht,sects->floor_desc,
               sects->ceil_desc,&sects->light_lvl,&sects->property,
               &sects->line_tag);
        while (sects->floor_desc[min(8,strlen(sects->floor_desc))-1] == ' ')
          sects->floor_desc[min(8,strlen(sects->floor_desc))-1] = '\0';
        while (sects->ceil_desc[min(8,strlen(sects->ceil_desc))-1] == ' ')
          sects->ceil_desc[min(8,strlen(sects->ceil_desc))-1] = '\0';
        sects++;
    }
    k = str[0] != '%';
  }
  winfo->ep++; winfo->mp++;
  return TRUE;
}


/******************************************************************************
	ROUTINE:	patch_write(oinfo,winfo)
	WRITTEN BY:	Robert Fenske, Jr.
	CREATED:	May  1994
	DESCRIPTION:	This routine writes a VERDA patch file.  Only one
			level's data is stored in a patch file.
******************************************************************************/
#if defined(ANSI_C)
boolean patch_write(register WAD_INFO *oinfo, register WAD_INFO *winfo)
#else
boolean patch_write(oinfo,winfo)
register WAD_INFO *oinfo, *winfo;
#endif
{
  DOOM_THING *things = (DOOM_THING *)winfo->data[THINGS];
  DOOM_LINE *lines = (DOOM_LINE *)winfo->data[LINES];
  DOOM_SIDE *sides = (DOOM_SIDE *)winfo->data[SIDES];
  DOOM_VERT *verts = (DOOM_VERT *)winfo->data[VERTS];
  DOOM_SEGS *segs = (DOOM_SEGS *)winfo->data[SEGS];
  DOOM_SSECTOR *ssecs = (DOOM_SSECTOR *)winfo->data[SSECTS];
  DOOM_NODE *nodes = (DOOM_NODE *)winfo->data[NODES];
  DOOM_SECTOR *sects = (DOOM_SECTOR *)winfo->data[SECTS];
  register int k;

  fprintf(oinfo->fp,"%d %d %d %4.2f\r\n",
          --winfo->ep,--winfo->mp,THINGS,winfo->ver);
  for (k = 0; k < winfo->count[THINGS]; k++)
    fprintf(oinfo->fp,"%03d %04x %04x %03d %04x %02x\r\n",k,
            (ushort)things[k].x,(ushort)things[k].y,things[k].angle,
            things[k].item,things[k].flag);
  fprintf(oinfo->fp,"%%\r\n%d %d %d %4.2f\r\n",
          winfo->ep,winfo->mp,LINES,winfo->ver);
  for (k = 0; k < winfo->count[LINES]; k++)
    fprintf(oinfo->fp,"%03d %04x %04x %04x %04x %04x %04x %04x\r\n",k,
            lines[k].fndx,lines[k].tndx,
            (ushort)lines[k].flag,(ushort)lines[k].action_flag,
            (ushort)lines[k].sect_tag,
            (ushort)lines[k].rsidndx,(ushort)lines[k].lsidndx);
  fprintf(oinfo->fp,"%%\r\n%d %d %d %4.2f\r\n",
          winfo->ep,winfo->mp,SIDES,winfo->ver);
  for (k = 0; k < winfo->count[SIDES]; k++)
    fprintf(oinfo->fp,"%03d %04x %04x %-8.8s %-8.8s %-8.8s %03x\r\n",k,
            (ushort)sides[k].image_xoff,(ushort)sides[k].image_yoff,
            sides[k].lwall,sides[k].uwall,sides[k].nwall,sides[k].sectndx);
  fprintf(oinfo->fp,"%%\r\n%d %d %d %4.2f\r\n",
          winfo->ep,winfo->mp,VERTS,winfo->ver);
  for (k = 0; k < winfo->count[VERTS]; k++)
    fprintf(oinfo->fp,"%03d %04x %04x\r\n",k,
            (ushort)verts[k].x,(ushort)verts[k].y);
  fprintf(oinfo->fp,"%%\r\n%d %d %d %4.2f\r\n",
          winfo->ep,winfo->mp,SEGS,winfo->ver);
  for (k = 0; k < winfo->count[SEGS]; k++)
    fprintf(oinfo->fp,"%03d %04x %04x %04x %04x %04x %04x\r\n",k,
            segs[k].fndx,segs[k].tndx,(ushort)segs[k].angle,
            segs[k].lndx,segs[k].sndx,segs[k].loffset);
  fprintf(oinfo->fp,"%%\r\n%d %d %d %4.2f\r\n",
          winfo->ep,winfo->mp,SSECTS,winfo->ver);
  for (k = 0; k < winfo->count[SSECTS]; k++)
    fprintf(oinfo->fp,"%03d %04x %04x\r\n",k,
            ssecs[k].count,ssecs[k].sndx);
  fprintf(oinfo->fp,"%%\r\n%d %d %d %4.2f\r\n",
          winfo->ep,winfo->mp,NODES,winfo->ver);
  for (k = 0; k < winfo->count[NODES]; k++)
    fprintf(oinfo->fp,"%03d \
%04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x\r\n",k,
            (ushort)nodes[k].x,(ushort)nodes[k].y,
            (ushort)nodes[k].xdel,(ushort)nodes[k].ydel,
            (ushort)nodes[k].rymax,(ushort)nodes[k].rymin,
            (ushort)nodes[k].rxmin,(ushort)nodes[k].rxmax,
            (ushort)nodes[k].lymax,(ushort)nodes[k].lymin,
            (ushort)nodes[k].lxmin,(ushort)nodes[k].lxmax,
            (ushort)nodes[k].nndx[0],(ushort)nodes[k].nndx[1]);
  fprintf(oinfo->fp,"%%\r\n%d %d %d %4.2f\r\n",
          winfo->ep,winfo->mp,SECTS,winfo->ver);
  for (k = 0; k < winfo->count[SECTS]; k++)
    fprintf(oinfo->fp,"%03d %04x %04x %-8.8s %-8.8s %04x %04x %04x\r\n",k,
 	   (ushort)sects[k].floor_ht,(ushort)sects[k].ceil_ht,
            sects[k].floor_desc,sects[k].ceil_desc,
            sects[k].light_lvl,sects[k].property,(ushort)sects[k].line_tag);
  return TRUE;
}


/******************************************************************************
	ROUTINE:	wad_open(file,input,rewrite)
	WRITTEN BY:	Robert Fenske, Jr.
	CREATED:	June 1994
	DESCRIPTION:	This routine opens the specified file.  The file is
			created if input and rewrite are FALSE.  If the open
			fails for any reason a NULL is returned, otherwise an
			information block is allocated for the file.  The file
			is identified as either a (P/I)WAD file or a VERDA
			patch file.  If the file is a (P/I)WAD file, then the
			directory is read.  The resource directory is held in
			two locations--one for modification and one to preserve
			the original directory.  The address of the information
			block is returned.
******************************************************************************/
#if defined(ANSI_C)
WAD_INFO *wad_open(char *file, boolean input, boolean rewrite)
#else
WAD_INFO *wad_open(file,input,rewrite)
char *file;
boolean input, rewrite;
#endif
{
  register FILE *fp;
  register WAD_INFO *winfo;
  register int e;

  fp = fopen(file,input?"rb":rewrite?"r+b":"wb");
  if (fp == NULL)				/* oops */
    return NULL;
  winfo = blockmem(WAD_INFO,1);
  if (input || rewrite) {
    rewind(fp);
    fread((char *)&winfo->head,sizeof winfo->head,1,fp);
    if (strncmp(winfo->head.ident,"PWAD",4) == 0 ||
        strncmp(winfo->head.ident,"IWAD",4) == 0) {
      winfo->type = 1;				/* it's a (I/P)WAD */
      winfo->head.count = bswapl(winfo->head.count);
      winfo->head.offset = bswapl(winfo->head.offset);
    }else {
      rewind(fp);
      if (3 == fscanf(fp," %d %d %*d %lf",&winfo->ep,&winfo->mp,&winfo->ver)) {
        winfo->type = 2;			/* it's a patch file */
        winfo->head.count = ALL;
      }else					/* it's illegal */
        memset(&winfo->head,0,sizeof(winfo->head));
    }
    winfo->origdir = blockmem(DIR_ENTRY,winfo->head.count);
    winfo->dir = blockmem(DIR_ENTRY,winfo->head.count);
    winfo->data = blockmem(char *,winfo->head.count);
    winfo->changed = blockmem(boolean,winfo->head.count);
    winfo->count = blockmem(long,winfo->head.count);
    if (winfo->type == 1) {			/* it's a WAD file */
      rewind(fp);
      fseek(fp,winfo->head.offset,0);		/* read directory */
      fread((char *)winfo->origdir,sizeof(*winfo->origdir),
            (int)winfo->head.count,fp);
    }else if (winfo->type == 2) {		/* it's a patch file */
      if (++winfo->ep != 4)
        sprintf(winfo->origdir[MAINS].name,"E%dM%d",winfo->ep,++winfo->mp);
      else
        sprintf(winfo->origdir[MAINS].name,"MAP%02d",++winfo->mp);
      for (e = 1; e < ALL; e++)
        blockcopy(winfo->origdir[e].name,mapresrc[e],
                  sizeof winfo->origdir[e].name);
    }
    for (e = 0; e < winfo->head.count; e++) {
      winfo->dir[e] = winfo->origdir[e];
      winfo->dir[e].offset =
      winfo->origdir[e].offset = bswapl(winfo->origdir[e].offset);
      winfo->dir[e].nbytes =
      winfo->origdir[e].nbytes = bswapl(winfo->origdir[e].nbytes);
    }
  }
  winfo->fp = fp;
  return winfo;
}


/******************************************************************************
	ROUTINE:	wad_read(winfo,entry,resources_needed)
	WRITTEN BY:	Robert Fenske, Jr.
	CREATED:	May  1994
	DESCRIPTION:	This routine reads a WAD file. resources_needed governs
			which resources from the level are actually read.
******************************************************************************/
#if defined(ANSI_C)
boolean wad_read(register WAD_INFO *winfo, int entry, long resources_needed)
#else
boolean wad_read(winfo,entry,resources_needed)
register WAD_INFO *winfo;
int entry;
long resources_needed;
#endif
{
  register int i;

  if (winfo == NULL ||
      winfo->fp == NULL) return FALSE;		/* can't do if invalid */
  if (winfo->type == 2)
    return patch_read(winfo,entry,resources_needed);/* do patch file */
  if (winfo->head.count <= entry)		/* can't read beyond count */
    return FALSE;
  for (i = 0; i < sizeof(resources_needed)*8; i++) {
    if (resources_needed & (1L<<i)) {		/* get requested resources */
      blockfree(winfo->data[entry+i]);
      winfo->data[entry+i] = blockmem(char,winfo->origdir[entry+i].nbytes);
      fseek(winfo->fp,winfo->origdir[entry+i].offset,0);
      fread(winfo->data[entry+i],1,(int)winfo->origdir[entry+i].nbytes,
            winfo->fp);
#if defined(BSWAP)
      wad_bswap(winfo,entry+i);
#endif
      winfo->count[entry+i] = resource_count(&winfo->origdir[entry+i]);
    }
  }
  return TRUE;
}


/******************************************************************************
	ROUTINE:	wad_write(oinfo,winfo)
	WRITTEN BY:	Robert Fenske, Jr.
	CREATED:	May  1994
	DESCRIPTION:	This routine writes a WAD file.  If oinfo has a
			directory then the input file is being rewritten with
			the new data; otherwise, a new file is written.  The
			resources are written out in reverse order; this easily
			handles the case where the input file is being
			rewritten and some of the resources have grown in size.
			Also in the rewrite case, if a resource is smaller than
			before, it is marked with the new smaller size but the
			following resources are not "shifted down".  Thus there
			will be some parts of the file that will be unused.
******************************************************************************/
#if defined(ANSI_C)
boolean wad_write(register WAD_INFO *oinfo,register WAD_INFO *winfo)
#else
boolean wad_write(oinfo,winfo)
register WAD_INFO *oinfo, *winfo;
#endif
{
  long dir_offset;				/* new directory offset */
  char *buf;					/* temporary data buffer */
  register int e;

  if (oinfo == NULL ||
      oinfo->fp == NULL) return FALSE;		/* can't do if invalid */
  if (oinfo->type == 2)
    return patch_write(oinfo,winfo);		/* do patch file */
  winfo->dir[0].offset = sizeof winfo->head;
  for (e = 1; e < winfo->head.count; e++) {	/* compute new directory */
    if (oinfo->dir == NULL || winfo->origdir[e-1].offset == 0)
      winfo->dir[e].offset = winfo->dir[e-1].offset + winfo->dir[e-1].nbytes;
    else
      winfo->dir[e].offset = winfo->dir[e-1].offset +
                             max(winfo->dir[e-1].nbytes,
                                 winfo->origdir[e].offset-
                                 winfo->origdir[e-1].offset);
  }
  for (e = winfo->head.count-1; e >= 0; e--) {	/* write resources */
    if (winfo->changed[e] || winfo->type == 2) {/* write new data */
      if (winfo->data[e] != NULL) {
#if defined(BSWAP)
        wad_bswap(winfo,e);
#endif
        fseek(oinfo->fp,winfo->dir[e].offset,0);
        fwrite(winfo->data[e],1,(int)winfo->dir[e].nbytes,oinfo->fp);
        blockfree(winfo->data[e]);
        winfo->data[e] = NULL;
      }
    }else if (oinfo->dir == NULL ||
              winfo->origdir[e].offset != winfo->dir[e].offset) {
      buf = blockmem(char,winfo->origdir[e].nbytes);
      fseek(winfo->fp,winfo->origdir[e].offset,0);
      fread(buf,sizeof(*buf),(int)winfo->origdir[e].nbytes,winfo->fp);
      fseek(oinfo->fp,winfo->dir[e].offset,0);
      fwrite(buf,sizeof(*buf),(int)winfo->origdir[e].nbytes,oinfo->fp);
      blockfree(buf);
    }
  }
  dir_offset = winfo->dir[winfo->head.count-1].offset +
               winfo->dir[winfo->head.count-1].nbytes;
  for (e = 0; e < winfo->head.count; e++) {
    winfo->dir[e].offset = bswapl(winfo->dir[e].offset);
    winfo->dir[e].nbytes = bswapl(winfo->dir[e].nbytes);
  }
  fseek(oinfo->fp,dir_offset,0);		/* write new directory */
  fwrite((char *)winfo->dir,sizeof(*winfo->dir),(int)winfo->head.count,
         oinfo->fp);
  for (e = 0; e < winfo->head.count; e++) {
    winfo->dir[e].offset = bswapl(winfo->dir[e].offset);
    winfo->dir[e].nbytes = bswapl(winfo->dir[e].nbytes);
  }
  if (oinfo->dir != NULL)
    blockcopy((char *)winfo->origdir,(char *)winfo->dir,/* this is now       */
              winfo->head.count*sizeof(winfo->dir[0]));/* original directory */
  if (winfo->type == 2) blockcopy(winfo->head.ident,"PWAD",4);
  winfo->head.offset = bswapl(dir_offset);
  winfo->head.count = bswapl(winfo->head.count);
  fseek(oinfo->fp,0L,0);			 /* write new header */
  fwrite((char *)&winfo->head,sizeof(winfo->head),1,oinfo->fp);
  winfo->head.offset = bswapl(dir_offset);
  winfo->head.count = bswapl(winfo->head.count);
  return TRUE;
}


/******************************************************************************
	ROUTINE:	wad_close(winfo)
	WRITTEN BY:	Robert Fenske, Jr.
	CREATED:	June 1994
	DESCRIPTION:	This routine closes the specified file and it frees
			the associated memory.
******************************************************************************/
#if defined(ANSI_C)
void wad_close(register WAD_INFO *winfo)
#else
void wad_close(winfo)
register WAD_INFO *winfo;
#endif
{
  if (winfo != NULL) {
    if (winfo->fp != NULL) (void)fclose(winfo->fp);
    blockfree(winfo->dir);			/* done with these */
    blockfree(winfo->origdir);
    blockfree(winfo->data);
    blockfree(winfo->changed);
    blockfree(winfo->count);
    blockfree(winfo);
  }
}
