Exemple #1
0
/*
** try to save entry as BitMap .BMP
*/
static Bool XTRbmpSave(Int16 *pinsrX,Int16 *pinsrY,struct WADDIR  *entry,
		 PICTYPE type,const char *DataDir,const char *dir,struct
		 WADINFO *info,IMGTYPE Picture,Bool WSafe, cusage_t *cusage)
{  Bool res;
   Int32 start=entry->start;
   Int32 size =entry->size;
   char *name=entry->name;
   char  *buffer;
   char *extens=NULL;

   if(size<8L) return FALSE;
   switch(Picture)
   { case PICGIF: extens="GIF";break;
     case PICBMP: extens="BMP";break;
     case PICPPM: extens="PPM";break;
     case PICTGA: extens="TGA";break;
     default: Bug("EX47", "Invalid img type %d", (int) Picture);
   }
   res = MakeFileName(file,DataDir,dir,"",name,extens);
   if((WSafe==TRUE)&&(res==TRUE))
   { Warning("EX48", "Will not overwrite file %s",file);
     return TRUE;
   }
   buffer=(char  *)Malloc(size);
   WADRseek(info,start);
   WADRreadBytes(info,buffer,size);
   res = PICsaveInFile(file,type,buffer,size,pinsrX,pinsrY,Picture, name,
       cusage);
   if(res==TRUE)Detail("EX49", "Saved picture as %s", fname (file));
   Free(buffer);
   return res;
}
Exemple #2
0
/*
** determine image format of a lump within TX_START..TX_END.
** returns a PICXXX value, defaulting to PICNONE when no
** specific image format matches the lump data.
*/
static IMGTYPE XTRpicFormat(struct WADDIR *entry, struct WADINFO *info)
{
    int32_t start = entry->start;
    int32_t size = entry->size;

    unsigned char buf[16];

    memset(buf, 0, sizeof(buf));

    if (size > 16)
        size = 16;

    WADRseek(info, start);
    WADRreadBytes(info, buf, size);

    /* PNG? */
    if (buf[0] == 0x89 &&
        buf[1] == 'P' && buf[2] == 'N' && buf[3] == 'G' &&
        buf[4] == 0x0D && buf[5] == 0x0A && buf[6] == 0x1A) {
        return PICPNG;
    }

    /* JPEG? */
    if (buf[0] == 0xFF && buf[1] == 0xD8 &&
        buf[2] == 0xFF && buf[3] >= 0xE0 &&
        ((buf[6] == 'J' && buf[7] == 'F') ||
         (buf[6] == 'E' && buf[7] == 'x'))) {
        return PICJPEG;
    }

    return PICNONE;
}
Exemple #3
0
/*
** try to save entry
*/
static bool XTRbmpSave(int16_t * pinsrX, int16_t * pinsrY,
                       struct WADDIR *entry, PICTYPE type,
                       const char *DataDir, const char *dir, struct
                       WADINFO *info, IMGTYPE Picture, bool WSafe,
                       cusage_t * cusage)
{
    bool res;
    int32_t start = entry->start;
    int32_t size = entry->size;
    char *name = entry->name;
    char *buffer;
    char *extens = NULL;

    if (size < 8L)
        return false;
    switch (Picture) {
#ifdef HAVE_LIBPNG
    case PICPNG:
        extens = "PNG";
        break;
#endif
    case PICGIF:
        extens = "GIF";
        break;
    case PICBMP:
        extens = "BMP";
        break;
    case PICPPM:
        extens = "PPM";
        break;
    default:
        Bug("EX47", "Invalid img type %d", (int) Picture);
    }
    res = MakeFileName(file, DataDir, dir, "", name, extens);
    if (res && WSafe) {
        Warning("EX48", "Will not overwrite file %s", file);
        return true;
    }
    buffer = (char *) Malloc(size);
    WADRseek(info, start);
    WADRreadBytes(info, buffer, size);
    res =
        PICsaveInFile(file, type, buffer, size, pinsrX, pinsrY, Picture,
                      name, cusage);
    if (res)
        Detail("EX49", "Saved picture as %s", fname(file));
    free(buffer);
    return res;
}
Exemple #4
0
/*
**  Take some entries from a WAD
*/
static void HDRplunderWad(struct WADINFO *rwad,struct WADINFO *ewad)
{ char  *data;
  Int32 wsize,sz=0;
  Int32 ostart,osize;
  Int16 n;
  Int32 oldfilesz;
  /*
  ** calculate required size
  */
  oldfilesz=WADRposition(rwad); /*old file size*/
  /*
  ** copy entries from WAD
  */
  Phase("ME10", "Copying entries from wad (please wait)");
  data = (char  *)Malloc(MEMORYCACHE);
  for(n=0;n<(rwad->ntry);n++)
  {
    /*if((n&0x7F)==0) Phase("."); FIXME need /dev/tty output */
    ostart=rwad->dir[n].start;
    osize=rwad->dir[n].size;
    /*detect external entries */
    if(ostart&EXTERNAL)
    { /*update new directory*/
      WADRalign4(rwad);
      rwad->dir[n].start=WADRposition(rwad);
      /*get entry size*/
      if(osize>0)
      { /*copy old entry */
	WADRseek(ewad,ostart&(~EXTERNAL));
	for(wsize=0;wsize<osize;wsize+=sz)
	{ sz=(osize-wsize>MEMORYCACHE)? MEMORYCACHE:osize-wsize;
	  WADRreadBytes(ewad,data,sz);
	  if(WADRwriteBytes2(rwad,data,sz)<0)
	  { WADRchsize(rwad,oldfilesz);
	    ProgError("ME13", "Not enough disk space");
	    break;
	  }
	}
      }
    }
  }
  /*Phase("\n"); FIXME need /dev/tty output */
  Free(data);
}
Exemple #5
0
/*
** Copy a WAD, and link to it's entries
*/
static Int32 HDRinsertWad(struct WADINFO *rwad,struct WADINFO *ewad,Int32 *pesize)
{ char  *data;
  Int32 wsize,sz=0;
  Int32 estart,esize;
  Int16 n;
  Int32 oldfilesz;
  /*
  ** calculate required size
  */
  oldfilesz=WADRposition(rwad); /*old file size*/
  WADRalign4(rwad);
  estart=WADRposition(rwad);
  WADRseek(ewad,0);
  esize=ewad->maxpos;
  Phase("ME16", "Inserting wad file into wad");
  data = (char  *)Malloc(MEMORYCACHE);
  for(wsize=0;wsize<esize;wsize+=sz)
  { sz=(esize-wsize>MEMORYCACHE)? MEMORYCACHE:esize-wsize;
    WADRreadBytes(ewad,data,sz);
    if(WADRwriteBytes2(rwad,data,sz)<0)
    { WADRchsize(rwad,oldfilesz);
      ProgError("ME19", "Not enough disk space");
      break;
    }
    /*if((wsize&0xF000)==0) Phase("."); FIXME need /dev/tty output */
  }
  Free(data);
  for(n=0;n<(rwad->ntry);n++)
  { /*detect external entries */
    if((rwad->dir[n].start)&EXTERNAL)
    { /*update new directory*/
      rwad->dir[n].start &= (~EXTERNAL);
      rwad->dir[n].start += estart;
    }
  }
  /* Phase("\n"); FIXME need /dev/tty output */
  *pesize=  esize;
  return estart;
}
Exemple #6
0
/******************* WAD restoration **********************/
void HDRrestoreWAD(const char *wadres)
{ struct WADINFO rwad;
  Int32 dirpos,ntry,n;
  Int32 rwadstart=0,rwadsize=0;
  Int32 ewadstart=0,ewadsize=0;
  static char ewadname[8];
  static char ewadfile[40];
  char  *data;
  Int32      size=0,wsize=0,sz=0;
  Int32 time;
  FILE *fp;
  Bool Fail;
  Phase("ME22", "Attempting to restore wad %s", fname (wadres));
  /*open DOOM.WAD*/
  rwad.ok=0;
  WADRopenR(&rwad,wadres);

  /*get position of fake directory entry, reference to old dir*/
  dirpos = rwad.dirpos - HDRdirSz;
  WADRseek(&rwad,dirpos);
  WADRreadBytes(&rwad,(char  *)HDRdir,HDRdirSz);
  Fail=FALSE;
  if(peek_i32_le (&HDRdir[0].start) != 0x24061968L)  Fail=TRUE;
  if(peek_i32_le (&HDRdir[0].size)  != 666L)         Fail=TRUE;
  if(strncmp(HDRdir[0].name,"IZNOGOOD",8)!=0)       Fail=TRUE;
  if(Fail != FALSE)
  { if((n=WADRfindEntry(&rwad,"_DEUTEX_"))>=0)
      if(rwad.dir[n].size>=HDRdirSz)
	{ dirpos=rwad.dir[n].start;
	  WADRseek(&rwad,dirpos);
	  WADRreadBytes(&rwad,(char  *)HDRdir,HDRdirSz);
	  Fail=FALSE;
	  if(peek_i32_le (&HDRdir[0].start) != 0x24061968L)  Fail=TRUE;
	  if(peek_i32_le (&HDRdir[0].size)  != 666L)         Fail=TRUE;
	  if(strncmp(HDRdir[0].name,"IZNOGOOD",8)!=0) Fail=TRUE;
	}
  }
  if(Fail != FALSE) ProgError("ME25", "Not a modified WAD");
  Phase("ME28", "Restoration infos seem correct");
  dirpos = peek_i32_le (&HDRdir[1].start);
  ntry   = peek_i32_le (&HDRdir[1].size);
  rwadstart = peek_i32_le (&HDRdir[2].start);
  rwadsize  = peek_i32_le (&HDRdir[2].size);
  ewadstart = peek_i32_le (&HDRdir[3].start);
  ewadsize  = peek_i32_le (&HDRdir[3].size);
  Normalise(ewadname,HDRdir[3].name);   /*name of WAD inside*/
  /*original file time*/
  time   = peek_i32_le (&HDRdir[4].size);
  if(peek_i32_le (&HDRdir[4].start)!=FALSE)
  { /*extract the PWAD*/
    sprintf(ewadfile,"%.8s.WAD",ewadname);
#if DT_OS == 'd'
#elif DT_OS == 'o'
    ToLowerCase(ewadfile);
#else
    ToLowerCase(ewadfile);
#endif
    fp=fopen(ewadfile,FOPEN_RB);
    if(fp!=NULL)
    { fclose(fp);
      Info("ME31", "%s already exists, internal WAD discarded",
	  fname (ewadfile));
    }
    else
    { Phase("ME34", "Restoring internal wad %s", fname (ewadfile));
      if((fp=fopen(ewadfile,FOPEN_WB))!=NULL)
      { data = (char  *)Malloc( MEMORYCACHE);
	size = ewadsize;
	WADRseek(&rwad,ewadstart);
	fseek(fp,0,SEEK_SET);
	for(wsize=0;wsize<size;wsize+=sz)
	{ sz=(size-wsize>MEMORYCACHE)? MEMORYCACHE : size-wsize;
	  WADRreadBytes(&rwad,data,sz);
	  errno = 0;
	  if(fwrite(data,(size_t)sz,1,fp)!=1)
	  { Warning("ME37", "%s: %s",
	      fnameofs (ewadfile, (long) ewadstart),
	      errno == 0 ? "write error" : strerror (errno));
	    break;
	  }
	}
	Free(data);
	fclose(fp);
      }
      else
	Warning("ME40", "%s: %s", fname (ewadfile), strerror (errno));
    }
  }
  WADRopenA(&rwad,wadres);
  /*correct the directory reference of DOOM.WAD*/
  WADRsetDirRef(&rwad,ntry,dirpos);
  /*restore original size*/
  WADRchsize(&rwad,rwadstart+rwadsize);
  WADRclose(&rwad);
  SetFileTime(wadres,time);
  Output("Restoration of %s should be successful\n", fname (wadres));
}
Exemple #7
0
/*
** extract entries from a WAD
**
** Called with cusage == NULL, (-xtract) this function extracts
** everything in the wad to separate files.
**
** Called with cusage != NULL, (-usedidx) this function creates
** no files but print statistics about which colours are used
** in the wad.
*/
void XTRextractWAD(const char *doomwad, const char *DataDir, const char
    *wadin, const char *wadinfo, IMGTYPE Picture,SNDTYPE Sound,Bool
    fullSND,NTRYB select, char trnR, char trnG, char trnB,Bool WSafe,
    cusage_t *cusage)
{ static struct WADINFO pwad;
  static struct WADINFO iwad;
  static struct WADINFO lwad;
  struct WADDIR  *pdir;
  Int16 pnb;
  ENTRY  *piden;
  Int16 p;
  Int32 ostart,osize;
  char  *buffer;
  Bool res;
  Int16 insrX=0,insrY=0;
  Bool EntryFound;
  char *extens=NULL;
  /*text file to write*/
  static struct TXTFILE *TXT = NULL;
  Phase("EX00", "Extracting entries from wad %s", wadin);
  /*open iwad,get iwad directory*/
  iwad.ok=0;
  WADRopenR(&iwad,doomwad);

  /* If -usedidx, we're only interested in graphics. */
  if (cusage != NULL)
     select &= (BGRAPHIC | BSPRITE | BPATCH | BFLAT | BSNEAP | BSNEAT | BWALL);

  /*read WAD*/
  pwad.ok=0;
  WADRopenR(&pwad,wadin);
  pdir=pwad.dir;
  pnb=(Int16)pwad.ntry;

  /*find PNAMES*/
  { Int16 pnm=WADRfindEntry(&iwad,"PNAMES");
    char *Pnam=NULL;
    Int32 Pnamsz=0;
    if(pnm<0)
      Warning("EX01", "Iwad: no PNAMES lump");
    else
      Pnam=WADRreadEntry(&iwad,pnm,&Pnamsz);
    piden=IDENTentriesPWAD(&pwad, Pnam, Pnamsz);
    if(Pnam!=NULL)
      Free(Pnam);
  }

  /*
  ** prepare for graphics
  */

  /* Read PLAYPAL */
  {
    const char     *lumpname = palette_lump;
    struct WADINFO *wad;
    Int16           lumpnum;
    char           *lumpdata = NULL;
    Int32           lumpsz;

    wad = &pwad;
    lumpnum = WADRfindEntry (wad, lumpname);
    if (lumpnum >= 0)
      lumpdata = WADRreadEntry (wad, lumpnum, &lumpsz);
    else
    {
      wad = &iwad;
      lumpnum = WADRfindEntry (wad, lumpname);
      if (lumpnum >= 0)
	lumpdata = WADRreadEntry (wad, lumpnum, &lumpsz);
      else
      {
	long n;

	wad = NULL;
	lumpdata = Malloc (768);
	Warning ("EX02", "No %s lump found, making up a palette", lumpname);
	for (n = 0; n < 256; n++)
	{
	  lumpdata[3*n]   = n;
	  lumpdata[3*n+1] = (n & 0x7f) << 1;
	  lumpdata[3*n+2] = (n & 0x3f) << 2;
	}
      }
    }
    COLinit (trnR, trnG, trnB, lumpdata, (Int16) lumpsz,
	(wad == NULL) ? "(nofile)" : wad->filename, lumpname);
    Free (lumpdata);
  }

  /* If TITLEPAL exists, read the first 768 bytes of it. But
     don't prepare COLpal2 because we don't know yet whether we
     need it. Indeed, if there are no sneats to extract, we're
     not interested in seeing any TITLEPAL-related warnings. */
  {
    int n;
    char *titlepal_data = NULL;
    Int32 titlepal_size = 3 * NCOLOURS;

    n = WADRfindEntry (&pwad, "TITLEPAL");
    if (n >= 0)
      titlepal_data = WADRreadEntry2 (&pwad, n, &titlepal_size);
    else
    {
      n = WADRfindEntry (&iwad, "TITLEPAL");
      if (n >= 0)
	titlepal_data = WADRreadEntry2 (&iwad, n, &titlepal_size);
      else
      {
	titlepal_data = NULL;
	titlepal_size = 0;
      }
    }
    COLinitAlt (titlepal_data, titlepal_size);
  }

  /*
  ** read the PNAMES entry in PWAD
  ** or in DOOM.WAD if it does not exist elsewhere
  */
  do
  { Int16 pnm=WADRfindEntry(&pwad,"PNAMES");
    char *Pnam;
    Int32 lumpsz;
    if(pnm>=0)
      Pnam=WADRreadEntry(&pwad,pnm,&lumpsz);
    else
    { pnm=WADRfindEntry(&iwad,"PNAMES");
      if(pnm<0)
      { Warning("EX03", "Iwad: no PNAMES lump (2)");
	break;
      }
      Pnam=WADRreadEntry(&iwad,pnm,&lumpsz);
    }
    PNMinit(Pnam,lumpsz);
    Free(Pnam);
  }
  while (0);

  /*
  ** iwad not needed anymore
  */
  WADRclose(&iwad);

  /*
  ** output WAD creation directives
  ** and save entries depending on their type.
  ** If -usedidx, do _not_ create a directives file.
  */
  if (cusage != NULL)
     TXT = &TXTdummy;  /* Notional >/dev/null */ 
  else
  {
     /*check if file exists*/
     TXT=TXTopenW(wadinfo);
     {
       char comment[81];
       sprintf (comment, "DeuTex %.32s by Olivier Montanuy", deutex_version);
       TXTaddComment (TXT, comment);
     }
     TXTaddComment(TXT,"PWAD creation directives");
  }

  /*
  ** LEVELS
  */
  if(select&BLEVEL)
  { Phase("EX10", "Extracting levels...");
    for(EntryFound=FALSE,p=0;p<pnb;p++)
    { switch(piden[p]&EMASK)
      { case ELEVEL: case EMAP:
        if(EntryFound!=TRUE)
        {  MakeDir(file,DataDir,"LEVELS","");
           TXTaddEmptyLine (TXT);
           TXTaddComment(TXT,"List of levels");
           TXTaddSection(TXT,"levels");
           EntryFound=TRUE;
        }
        /* entries to save in WAD, named from Level name*/
	{
	  int pmax;
	  for (pmax = p; pmax < pnb && piden[pmax] == piden[p]; pmax++)
	    ;
	  res=MakeFileName(file,DataDir,"LEVELS","",pdir[p].name,"WAD");
	  if((WSafe==TRUE)&&(res==TRUE))
	    Warning("EX11", "Will not overwrite file %s",file);
	  else
	  { WADRopenW(&lwad,file,PWAD, 0);
	    ostart=WADRposition(&lwad);/*BC++ 4.5 bug*/
	    WADRdirAddEntry(&lwad,ostart,0L,pdir[p].name);
	    WADRwriteWADlevelParts (&lwad, &pwad, p, pmax - p);
	    WADRwriteDir(&lwad, 0);
	    WADRclose(&lwad);
	  }
	  TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,FALSE,FALSE);
	  p = pmax - 1;
	}
      }
    }
  }


  /*
  ** LUMPS
  */
  if(select&BLUMP)
  { Phase("EX15", "Extracting lumps...");
    ostart=0x80000000L;osize=0;
    for(EntryFound=FALSE,p=0;p<pnb;p++)
    { if((piden[p]&EMASK)==ELUMP)
      { if(EntryFound!=TRUE)
        { MakeDir(file,DataDir,"LUMPS","");
	  TXTaddEmptyLine (TXT);
          TXTaddComment(TXT,"List of data Lumps");
          TXTaddSection(TXT,"lumps");
          EntryFound=TRUE;
        }
        if((ostart==pwad.dir[p].start)&&(osize==pwad.dir[p].size))
        { TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,TRUE,FALSE);
        }
        else
        { ostart=pwad.dir[p].start; osize=pwad.dir[p].size;
          res=FALSE;
          if(osize==64000L)/*lumps that are pics*/
          { res=XTRbmpSave(&insrX,&insrY,&pdir[p],PLUMP,DataDir,"LUMPS",&pwad,
	      Picture,WSafe, cusage);
          }
          if(res!=TRUE)   /*normal lumps*/
          { res=MakeFileName(file,DataDir,"LUMPS","",pdir[p].name,"LMP");
            if((WSafe==TRUE)&&(res==TRUE))
            {  Warning("EX16", "Will not overwrite file %s",file);
            }
            else
            { WADRsaveEntry(&pwad,p,file);
              Detail("EX17", "Saved lump as   %s", fname (file));
            }
          }
          TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,FALSE,FALSE);
        }
      }
    }
  }

  /*
  ** TEXTURES
  */
  if(select&BTEXTUR)
  { EntryFound=FALSE;
    for(p=0;p<pnb;p++)
    { if(piden[p]==ETEXTUR+1)
      { if(EntryFound!=TRUE)
	{  MakeDir(file,DataDir,"TEXTURES","");
	   EntryFound=TRUE;
	}
	TXTaddEmptyLine (TXT);
	TXTaddComment(TXT,"List of definitions for TEXTURE1");
	TXTaddSection(TXT,"texture1");
	
	{
	   const char *name;
	   /* Always extract TEXTURES as texture1.txt ! -- AYM 1999-09-18 */
	   if (texture_lump == TL_TEXTURES)
	      name = "TEXTURE1";
	   else
	      name = pdir[p].name;
	   TXTaddEntry(TXT,name,NULL,INVALIDINT,INVALIDINT,FALSE,FALSE);
	   res=MakeFileName(file,DataDir,"TEXTURES","",name,"TXT");
	}
	if((WSafe==TRUE)&&(res==TRUE))
	{         Warning("EX21", "Will not overwrite file %s",file);
	}
	else
	{ buffer=(char  *)Malloc(pdir[p].size);
	  WADRseek(&pwad,pdir[p].start);
	  WADRreadBytes(&pwad,buffer,pdir[p].size);
	  TXUinit();
	  TXUreadTEXTURE(pdir[p].name, buffer, pdir[p].size, NULL, 0, TRUE);
	  Free(buffer);
	  TXUwriteTexFile(file);
	  TXUfree();
	}
      }
    }
    for(p=0;p<pnb;p++)
    { if(piden[p]==ETEXTUR+2)
      { if(EntryFound!=TRUE)
	{  MakeDir(file,DataDir,"TEXTURES","");
	   EntryFound=TRUE;
	}
	TXTaddEmptyLine (TXT);
	TXTaddComment(TXT,"List of definitions for TEXTURE2");
	TXTaddSection(TXT,"texture2");
	TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,FALSE,FALSE);
	res=MakeFileName(file,DataDir,"TEXTURES","",pdir[p].name,"TXT");
	if((WSafe==TRUE)&&(res==TRUE))
	{         Warning("EX22", "Will not overwrite file %s",file);
	}
	else
	{ buffer=(char  *)Malloc(pdir[p].size);
	  WADRseek(&pwad,pdir[p].start);
	  WADRreadBytes(&pwad,buffer,pdir[p].size);
	  TXUinit();
	  TXUreadTEXTURE(pdir[p].name, buffer, pdir[p].size, NULL, 0, TRUE);
	  Free(buffer);
	  TXUwriteTexFile(file);
	  TXUfree();
	}
      }
    }
  }


  /*
  ** SOUNDS
  */
  if(select&BSOUND)
  { Phase("EX25", "Extracting sounds...");
    ostart=0x80000000L;osize=0;
    for(EntryFound=FALSE,p=0;p<pnb;p++)
    { if((piden[p]&EMASK)==ESOUND)
      { if(EntryFound!=TRUE)
        { MakeDir(file,DataDir,"SOUNDS","");
          TXTaddEmptyLine (TXT);
          TXTaddComment(TXT,"List of Sounds");
          TXTaddSection(TXT,"sounds");
          EntryFound=TRUE;
        }
        if((ostart==pwad.dir[p].start)&&(osize==pwad.dir[p].size))
        { TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,TRUE,FALSE);
        }
        else
        { ostart=pwad.dir[p].start; osize=pwad.dir[p].size;
          switch(piden[p])
          { case ESNDPC:
              res=MakeFileName(file,DataDir,"SOUNDS","",pdir[p].name,"TXT");
              if((WSafe==TRUE)&&(res==TRUE))
              {  Warning("EX26", "Will not overwrite file %s",file);
              }
              else
              {
		char name[33];
		strcpy(name, lump_name(pdir[p].name));
		buffer=(char  *)Malloc(pdir[p].size);
                WADRseek(&pwad,pdir[p].start);
                WADRreadBytes(&pwad,buffer,pdir[p].size);
                SNDsavePCSound(name, file, buffer, pdir[p].size);
                Free(buffer);
                Detail("EX27", "Saved PC sound as   %s", fname (file));
              }
              TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,FALSE,
		  FALSE);
              break;
             case ESNDWAV:
              switch(Sound)
              { case SNDAU:  extens="AU";break;
                case SNDWAV: extens="WAV";break;
                case SNDVOC: extens="VOC";break;
                default: Bug("EX28", "Invalid snd type %d", Sound);
              }
              res=MakeFileName(file,DataDir,"SOUNDS","",pdir[p].name,extens);
              if((WSafe==TRUE)&&(res==TRUE))
              { Warning("EX29", "Will not overwrite file %s", fname (file));
              }
              else
              { buffer=(char  *)Malloc(pdir[p].size);
                WADRseek(&pwad,pdir[p].start);
                WADRreadBytes(&pwad,buffer,pdir[p].size);
                SNDsaveSound(file,buffer,pdir[p].size,Sound,fullSND,
		    pdir[p].name);
                Detail("EX30", "Saved sound as   %s", fname (file));
                Free(buffer);
              }
              TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,FALSE,
		  FALSE);
              break;
            default:
              Bug("EX31", "Invalid snd type %d", piden[p]);
          }
        }
      }
    }
  }

  /*
  ** MUSICS
  */
  if(select&BMUSIC)
  { Phase("EX32", "Extracting musics...");
    ostart=0x80000000L;osize=0;
    for(EntryFound=FALSE,p=0;p<pnb;p++)
    { if((piden[p]&EMASK)==EMUSIC)
      { if(EntryFound!=TRUE)
        {  MakeDir(file,DataDir,"MUSICS","");
           TXTaddEmptyLine (TXT);
           TXTaddComment(TXT,"List of Musics");
           TXTaddSection(TXT,"musics");
           EntryFound=TRUE;
        }
        if((ostart==pwad.dir[p].start)&&(osize==pwad.dir[p].size))
        { TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,TRUE,FALSE);
        }
        else
        { ostart=pwad.dir[p].start; osize=pwad.dir[p].size;
          res=MakeFileName(file,DataDir,"MUSICS","",pdir[p].name,"MUS");
          if((WSafe==TRUE)&&(res==TRUE))
          {  Warning("EX33", "Will not overwrite file %s", fname (file));
          }
          else
          {
	    Detail("EX34", "Saving music as %s", fname (file));
	    WADRsaveEntry(&pwad,p,file);
          }
          TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,FALSE,FALSE);
        }
      }
    }
  }

  /*
  ** GRAPHICS
  */
  if(select&BGRAPHIC)
  { Phase("EX35", "Extracting graphics...");
    ostart=0x80000000L;osize=0;
    for(EntryFound=FALSE,p=0;p<pnb;p++)
    { if((piden[p]&EMASK)==EGRAPHIC)
      { if(EntryFound!=TRUE && cusage == NULL)
        { MakeDir(file,DataDir,"GRAPHICS","");
        }
        if((ostart==pwad.dir[p].start)&&(osize==pwad.dir[p].size))
        { TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,TRUE,FALSE);
        }
        else
        { ostart=pwad.dir[p].start; osize=pwad.dir[p].size;
          if(XTRbmpSave(&insrX,&insrY,&pdir[p],PGRAPH,DataDir,"GRAPHICS",&pwad,
	      Picture,WSafe, cusage)==TRUE)
          { if(EntryFound!=TRUE)
            { 
              TXTaddEmptyLine (TXT);
	      TXTaddComment(TXT,"List of Pictures (with insertion point)");
              TXTaddSection(TXT,"graphics");
              EntryFound=TRUE;
            }
            TXTaddEntry(TXT,pdir[p].name,NULL,insrX,insrY,FALSE,TRUE);
          }
          else if(XTRbmpSave(&insrX,&insrY,&pdir[p],PFLAT,DataDir,"LUMPS",&pwad,
	      Picture,WSafe, cusage)==TRUE)
          { /*Was saved as graphic lump*/
	    char *name = Malloc (sizeof pdir[p].name + 1);
	    sprintf (name, "%.*s", (int) sizeof pdir[p].name, pdir[p].name);
	    TXTaddComment(TXT, name);
	    Free (name);
          }
          else if (cusage == NULL)
          { if(MakeFileName(file,DataDir,"LUMPS","",pdir[p].name,"LMP")==TRUE)
            {  Warning("EX36", "Will not overwrite file %s", fname (file));
            }
            else
            { WADRsaveEntry(&pwad,p,file);
              Detail("EX37", "Saved lump as   %s", fname (file));
            }
	    {
	      char *name = Malloc (sizeof pdir[p].name + 1);
	      sprintf (name, "%.*s", (int) sizeof pdir[p].name, pdir[p].name);
	      TXTaddComment(TXT, name);
	      Free (name);
	    }
          }
        }
      }
    }
  }

  /*
  ** SPRITES
  */
  if(select&BSPRITE)
  { Phase("EX40", "Extracting sprites...");
    ostart=0x80000000L;osize=0;
    for(EntryFound=FALSE,p=0;p<pnb;p++)
    { if((piden[p]&EMASK)==ESPRITE)
      { if(EntryFound!=TRUE)
        {  if (cusage == NULL)
	      MakeDir(file,DataDir,"SPRITES","");
           TXTaddEmptyLine (TXT);
           TXTaddComment(TXT,"List of Sprites");
           TXTaddSection(TXT,"sprites");
           EntryFound=TRUE;
        }
        if((ostart==pwad.dir[p].start)&&(osize==pwad.dir[p].size))
        { TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,TRUE,FALSE);
        }
        else
        { ostart=pwad.dir[p].start; osize=pwad.dir[p].size;
          if(XTRbmpSave(&insrX,&insrY,&pdir[p],PSPRIT,DataDir,"SPRITES",&pwad,
	      Picture,WSafe, cusage)!=TRUE)
          { Warning("EX41", "Failed to write sprite %s",
	      lump_name (pwad.dir[p].name));
          }
          else
          { TXTaddEntry(TXT,pdir[p].name,NULL,insrX,insrY,FALSE,TRUE);
          }
        }
      }
    }
  }

  /*
  ** PATCHES
  */
  if (select & BPATCH)
  { Phase("EX45", "Extracting patches...");
    for(EntryFound=FALSE,p=0;p<pnb;p++)
     { if((piden[p] & EMASK)==EPATCH)
       { if(EntryFound!=TRUE)
         { 
	   if (cusage == NULL)
	      MakeDir(file,DataDir,"PATCHES","");
           TXTaddEmptyLine (TXT);
           TXTaddComment(TXT,"List of patches");
           TXTaddSection(TXT,"patches");
           EntryFound=TRUE;
         }
         if(XTRbmpSave(&insrX,&insrY,&pdir[p],PPATCH,DataDir,"PATCHES",&pwad,
	     Picture,WSafe,cusage)==TRUE)
         { TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,FALSE,FALSE);
         }
         else
         { Warning("EX46", "Failed to write patch %s",
	     lump_name (pwad.dir[p].name));
         }
       }
     }
  }

  /*
  ** PNAMES not needed anymore
  */
  PNMfree();

  /*
  ** FLATS
  */
  if (select & BFLAT)
  { Phase("EX50", "Extracting flats...");
    ostart=0x80000000L;osize=0;
    for(EntryFound=FALSE,p=0;p<pnb;p++)
    { if((piden[p]&EMASK)==EFLAT)
      { if(EntryFound!=TRUE)
        {  if (cusage == NULL)
	      MakeDir(file,DataDir,"FLATS","");
           TXTaddEmptyLine (TXT);
           TXTaddComment(TXT,"List of Floors and Ceilings");
           TXTaddSection(TXT,"flats");
           EntryFound=TRUE;
        }
        if((ostart==pwad.dir[p].start)&&(osize==pwad.dir[p].size))
        { TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,TRUE,FALSE);
	}
        else
        { ostart=pwad.dir[p].start; osize=pwad.dir[p].size;
          if(XTRbmpSave(&insrX,&insrY,&pdir[p],PFLAT,DataDir,"FLATS",&pwad,
	      Picture,WSafe,cusage)!=TRUE)
          { if(strncmp(pwad.dir[p].name,"F_SKY1",6)!=0)
            Warning("EX51", "Failed to write flat %s",
		lump_name (pwad.dir[p].name));
          }
          else
            TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,FALSE,FALSE);
        }
      }
    }
  }

  /* Extract all sneaps */
  if (select & BSNEAP)
  {
    ENTRY type = ESNEAP;
    Phase ("EX55", "Extracting %s...", entry_type_plural (type));
    ostart = 0x80000000L;
    osize = 0;

    for(EntryFound=FALSE,p=0;p<pnb;p++)
    { if(piden[p] == type)
      { if(EntryFound!=TRUE)
	{
	   char comment[40];
	   if (cusage == NULL)
	      MakeDir(file,DataDir,entry_type_dir(type),"");
           TXTaddEmptyLine (TXT);
	   sprintf (comment, "List of %.20s", entry_type_plural (type));
	   TXTaddComment (TXT, comment);
	   TXTaddSection (TXT, entry_type_section (type));
	   EntryFound=TRUE;
	}
	if((ostart==pwad.dir[p].start)&&(osize==pwad.dir[p].size))
	{
	  TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,TRUE,FALSE);
	}
	else
	{ ostart=pwad.dir[p].start; osize=pwad.dir[p].size;
	  if(XTRbmpSave(&insrX,&insrY,&pdir[p],entry_type_pictype (type),
	      DataDir, entry_type_dir (type),&pwad, Picture, WSafe,
	      cusage) != TRUE)
	  {
	    Warning("EX56", "Failed to write %.20s %s",
		entry_type_name (type), lump_name (pwad.dir[p].name));
	  }
	  else
	  {
	    TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,FALSE,
		FALSE);
	  }
	}
      }
    }
  }

  /* Extract all sneats */
  if (select & BSNEAT)
  {
    ENTRY type = ESNEAT;
    Phase ("EX60", "Extracting %s...", entry_type_plural (type));
    ostart = 0x80000000L;
    osize = 0;

    for(EntryFound=FALSE,p=0;p<pnb;p++)
    { if(piden[p] == type)
      { if(EntryFound!=TRUE)
	{
	   char comment[40];
	   if (cusage == NULL)
	      MakeDir(file,DataDir,entry_type_dir(type),"");
           TXTaddEmptyLine (TXT);
	   sprintf (comment, "List of %.20s", entry_type_plural (type));
	   TXTaddComment (TXT, comment);
	   TXTaddSection (TXT, entry_type_section (type));
	   EntryFound=TRUE;
	}
	if((ostart==pwad.dir[p].start)&&(osize==pwad.dir[p].size))
	{
	  TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,TRUE,FALSE);
	}
	else
	{ ostart=pwad.dir[p].start; osize=pwad.dir[p].size;
	  if(XTRbmpSave(&insrX,&insrY,&pdir[p],entry_type_pictype (type),
	      DataDir, entry_type_dir (type),&pwad, Picture, WSafe,
	      cusage) != TRUE)
	  {
	    Warning("EX61", "Failed to write %.20s %s",
		entry_type_name (type), lump_name (pwad.dir[p].name));
	  }
	  else
	  {
	    TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,FALSE,
		FALSE);
	  }
	}
      }
    }
  }

  /* Extract all Strife scripts */
  if (select & BSCRIPT)
  {
    ENTRY type = ESSCRIPT;
    Phase ("EX65", "Extracting %s...", entry_type_plural (type));
    ostart = 0x80000000L;
    osize = 0;

    for(EntryFound=FALSE,p=0;p<pnb;p++)
    { if(piden[p] == type)
      { if(EntryFound!=TRUE)
	{
	   char comment[40];
	   if (cusage == NULL)
	      MakeDir(file,DataDir,entry_type_dir(type),"");
           TXTaddEmptyLine (TXT);
	   sprintf (comment, "List of %.20s", entry_type_plural (type));
	   TXTaddComment (TXT, comment);
	   TXTaddSection (TXT, entry_type_section (type));
	   EntryFound=TRUE;
	}
	if((ostart==pwad.dir[p].start)&&(osize==pwad.dir[p].size))
	{
	  TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,TRUE,FALSE);
	}
	else
	{ ostart=pwad.dir[p].start; osize=pwad.dir[p].size;
	  { res = MakeFileName (file, DataDir, entry_type_dir(type), "",
	      pdir[p].name, "txt");
            if (WSafe==TRUE && res==TRUE)
            {  Warning("EX66", "Will not overwrite file %s",file);
            }
            else
            { if (sscript_save (&pwad, p, file))
	      {
		Warning("EX67", "Failed to write %.20s %s",
		  entry_type_name (type), lump_name (pwad.dir[p].name));
	      }
	      else
	      {
		TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,FALSE,
		FALSE);
	      }
            }
          }
	}
      }
    }
  }

  /* Extract all ROTT walls. They're raw 64x64 bitmaps, between
     WALLSTRT and WALLSTOP. This is based on the regular Doom
     flats extraction code above. */
  if (ROTT && (select & BWALL))
  { Phase("EX70", "Extracting walls...");
    ostart=0x80000000L;osize=0;
    for(EntryFound=FALSE,p=0;p<pnb;p++)
    { if((piden[p]&EMASK)==EWALL)
      { if(EntryFound!=TRUE)
        {  if (cusage == NULL)
	      MakeDir(file,DataDir,"WALLS","");
           TXTaddEmptyLine (TXT);
           TXTaddComment(TXT,"List of walls");
           TXTaddSection(TXT,"walls");
           EntryFound=TRUE;
        }
        if((ostart==pwad.dir[p].start)&&(osize==pwad.dir[p].size))
        { TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,TRUE,FALSE);
	}
        else
        { ostart=pwad.dir[p].start; osize=pwad.dir[p].size;
          if(XTRbmpSave(&insrX,&insrY,&pdir[p],PWALL,DataDir,"WALLS",&pwad,
	      Picture,WSafe,cusage)!=TRUE)
	    Warning("EX71", "Failed to write wall %s",
		lump_name (pwad.dir[p].name));
          else
            TXTaddEntry(TXT,pdir[p].name,NULL,INVALIDINT,INVALIDINT,FALSE,FALSE);
        }
      }
    }
  }


  /* If -usedidx, print statistics */
  if (cusage != NULL)
  {
    int n;

    printf ("Npixels    Idx  Nlumps  First lump\n");
    printf ("---------  ---  ------  ----------\n");
    for (n = 0; n < NCOLOURS; n++)
      printf ("%9lu  %3d  %5lu   %s\n",
	  cusage->uses[n],
	  n,
	  cusage->nlumps[n],
	  (cusage->uses[n] == 0) ? "" : lump_name (cusage->where_first[n]));
    putchar ('\n');
  }

  /*
  ** exit graphics and end
  */
  COLfree();
  Free(piden);
  WADRclose(&pwad);
  TXTaddEmptyLine (TXT);
  TXTaddComment(TXT,"End of extraction");
  TXTcloseW(TXT);
  Phase("EX99", "End of extraction");
}