home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1996 by Raphael Quinet. All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation. If more than a few
- * lines of this code are used in a program which displays a copyright
- * notice or credit notice, the following acknowledgment must also be
- * displayed on the same screen: "This product includes software
- * developed by Raphael Quinet for use in the Quake Editing Utilities
- * project." THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR
- * IMPLIED WARRANTY.
- *
- * More information about the QEU project can be found on the WWW:
- * "http://www.montefiore.ulg.ac.be/~quinet/games/editing.html" or by
- * mail: Raphael Quinet, 9 rue des Martyrs, B-4550 Nandrin, Belgium.
- */
-
- /*
- * F_WAD.C - Read and write Doom/Heretic/Hexen WAD files.
- */
-
- #include "qeu.h"
- #include "q_misc.h"
- #include "q_files.h"
- #include "f_wad.h"
-
- /*
- * Read the WAD directory into memory. The optional offset to the
- * start of the WAD file is given in "offset". The number of entries in
- * the directory is returned in *dirsize_r.
- */
- WADDirPtr ReadWADDirectory(FILE *wadfile, UInt32 offset, UInt16 *dirsize_r)
- {
- WADDirPtr dir;
- UInt32 pos, size;
- UInt16 max, i;
- int ftype;
-
- *dirsize_r = 0;
- if (wadfile == NULL)
- return NULL;
- if ((fseek(wadfile, offset, SEEK_SET) < 0)
- || ((ftype = ReadMagic(wadfile)) != FTYPE_PWAD && ftype != FTYPE_IWAD)
- || (ReadInt32(wadfile, &size) == FALSE)
- || (ReadInt32(wadfile, &pos) == FALSE)
- || (size == 0L)
- || (size > 65535L)
- || (fseek(wadfile, pos, SEEK_SET) < 0))
- return NULL;
- dir = (WADDirPtr)QMalloc(size * sizeof(struct WADDirectory));
- max = (UInt16)size;
- for (i = 0; i < max; i++)
- {
- if (ReadBytes(wadfile, &dir[i], sizeof(struct WADDirectory)) == FALSE)
- {
- QFree(dir);
- return NULL;
- }
- dir[i].offset = SwapInt32(dir[i].offset);
- dir[i].size = SwapInt32(dir[i].size);
- }
- *dirsize_r = max;
- return dir;
- }
-
-
- /*
- * Return the index number of the first entry matching "entryname".
- * A number greater or equal to dirsize is returned if no match is found.
- */
- UInt16 FindWADEntry(WADDirPtr dir, UInt16 dirsize, char *entryname)
- {
- UInt16 i;
-
- if (dir == NULL)
- ProgError("BUG: Cannot find entry in NULL directory");
- for (i = 0; i < dirsize; i++)
- if (!strnicmp(dir[i].name, entryname, 8))
- return i;
- return i;
- }
-
-
- /*
- * Print the contents of the WAD directory in "outf".
- */
- void DumpWADDirectory(FILE *outf, WADDirPtr dir, UInt16 dirsize)
- {
- UInt16 i;
- UInt32 sum;
- char buf[9];
-
- if (outf == NULL || dir == NULL || dirsize == 0)
- return;
- fprintf(outf, " num offset size entry name\n");
- fprintf(outf, " (hex) (dec)\n");
- sum = 0L;
- for (i = 0; i < dirsize; i++)
- {
- strncpy(buf, dir[i].name, 8);
- buf[8] = '\0';
- fprintf(outf, "%4u 0x%08lx %6ld %s\n",
- i, dir[i].offset, dir[i].size, buf);
- sum += dir[i].size;
- }
- fprintf(outf, "\nTotal size for %4u entries: %7lu bytes.\n", dirsize, sum);
- fprintf(outf, "Size of the WAD directory: %7lu bytes.\n",
- (UInt32)dirsize * (UInt32)sizeof(struct WADDirectory));
- fprintf(outf, "Total (header + data + dir): %7lu bytes.\n",
- 12L + sum + (UInt32)dirsize * (UInt32)sizeof(struct WADDirectory));
- }
-
-
- /*
- * If "entrynum" is smaller than dirsize, extract the corresponding
- * entry from a WAD file. Otherwise, extract all entries and save
- * them in separate files. The files will be saved in the directory
- * "prefixpath". If "outf" is not null, progress information will be
- * printed in it.
- */
- Bool UnWADFile(FILE *outf, FILE *wadfile, UInt32 offset, WADDirPtr dir,
- UInt16 dirsize, UInt16 entrynum, char *prefixpath)
- {
- char *newname;
- char *p, *q;
- FILE *newfile;
- FILE *indexfile;
- UInt16 i, n;
- UInt32 sum;
- Bool inmap = FALSE;
- int indir = 0;
-
- if (wadfile == NULL || dir == NULL || dirsize == 0)
- return FALSE;
- if (prefixpath == NULL)
- prefixpath = ".";
- newname = (char *)QMalloc(strlen(prefixpath) + 2 * 9 + 8 + 4 + 2);
- strcpy(newname, prefixpath);
- p = &newname[strlen(newname) - 1];
- #ifdef QEU_DOS
- if (*p != '\\')
- {
- p++;
- *p = '\\';
- }
- #else
- if (*p != '/')
- {
- p++;
- *p = '/';
- }
- #endif
- p++;
- q = p;
- strcpy(p, QEU_INDEX_FILE);
- if (outf != NULL)
- fprintf(outf, "Creating index file %s\n", newname);
- CreatePathToFile(newname);
- indexfile = fopen(newname, "a");
- fprintf(indexfile, "BEGIN WAD\n");
- sum = 0L;
- n = 0;
- for (i = 0; i < dirsize; i++)
- {
- if ((inmap == TRUE)
- && strnicmp(dir[i].name, "THINGS", 6)
- && strnicmp(dir[i].name, "LINEDEFS", 8)
- && strnicmp(dir[i].name, "SIDEDEFS", 8)
- && strnicmp(dir[i].name, "VERTEXES", 8)
- && strnicmp(dir[i].name, "SEGS", 4)
- && strnicmp(dir[i].name, "SSECTORS", 8)
- && strnicmp(dir[i].name, "NODES", 5)
- && strnicmp(dir[i].name, "SECTORS", 7)
- && strnicmp(dir[i].name, "REJECT", 6)
- && strnicmp(dir[i].name, "BLOCKMAP", 8))
- {
- inmap = FALSE;
- p--;
- #ifdef QEU_DOS
- while (*(p - 1) != '\\')
- p--;
- #else
- while (*(p - 1) != '/')
- p--;
- #endif
- }
- if (!strncmp(dir[i].name + 1, "_START", 7)
- || !strncmp(dir[i].name + 2, "_START", 6))
- {
- indir++;
- if (indir > 2)
- {
- fclose(indexfile);
- QFree(newname);
- return FALSE;
- }
- *p++ = dir[i].name[0];
- if (dir[i].name[1] != '_')
- *p++ = dir[i].name[1];
- #ifdef QEU_DOS
- *p++ = '\\';
- #else
- *p++ = '/';
- #endif
- if (dir[i].size == 0)
- {
- fprintf(indexfile, "+ %s *\n", dir[i].name);
- continue;
- }
- }
- if (!strncmp(dir[i].name + 1, "_END", 5)
- || !strncmp(dir[i].name + 2, "_END", 5))
- {
- indir--;
- if (indir < 0)
- {
- fclose(indexfile);
- QFree(newname);
- return FALSE;
- }
- p--;
- #ifdef QEU_DOS
- while (*(p - 1) != '\\')
- p--;
- #else
- while (*(p - 1) != '/')
- p--;
- #endif
- if (dir[i].size == 0)
- {
- fprintf(indexfile, "+ %s *\n", dir[i].name);
- continue;
- }
- continue;
- }
- strcpy(p, dir[i].name);
- if ((dir[i].name[0] == 'E' && dir[i].name[2] == 'M'
- && dir[i].name[4] == '\0')
- || (dir[i].name[0] == 'M' && dir[i].name[1] == 'A'
- && dir[i].name[2] == 'P' && dir[i].name[5] == '\0'))
- {
- inmap = TRUE;
- while (*p)
- p++;
- #ifdef QEU_DOS
- *p++ = '\\';
- #else
- *p++ = '/';
- #endif
- if (dir[i].size > 0)
- strcpy(p, dir[i].name);
- else
- {
- fprintf(indexfile, "+ %s *\n", dir[i].name);
- continue;
- }
- }
- if (entrynum < dirsize && i != entrynum)
- continue; /* horrible trick... */
- strcat(p, ".lmp");
- if (outf != NULL)
- fprintf(outf, "Saving %6ld bytes to %s\n", dir[i].size, newname);
- CreatePathToFile(newname);
- newfile = fopen(newname, "wb");
- if (newfile == NULL)
- {
- fclose(indexfile);
- QFree(newname);
- return FALSE;
- }
- fprintf(indexfile, "+ %s = %s\n", dir[i].name, q);
- if ((fseek(wadfile, offset + dir[i].offset, SEEK_SET) < 0)
- || (CopyBytes(newfile, wadfile, dir[i].size) == FALSE))
- {
- fclose(newfile);
- QFree(newname);
- return FALSE;
- }
- fclose(newfile);
- sum += dir[i].size;
- n++;
- }
- if (outf != NULL && entrynum >= dirsize)
- fprintf(outf, "Saved %lu bytes in %u files.\n", sum, n);
- QFree(newname);
- return TRUE;
- }
-
-
- /* ----------------------------------------------------------------------------
- * NOTE: How to save a wad file:
- *
- * UInt32 count; - used by the saving routines
- * WADDirPtr dir; - WAD directory structure (created step by step)
- * UInt16 n; - number of entries in WAD directory (idem)
- *
- * WriteWADHeader(f, &count, &dir, &n, TRUE); - write the header
- * size = WriteSomething(f, ...); - save one entry
- * AddWADEntry(f, &count, &dir, &n, name, size); - add entry to dir.
- * size = WriteSomethingElse(f, ...); - save another entry
- * AddWADEntry(f, &count, &dir, &n, othername, size); - add to dir. too
- * totalsize = WriteWADDirectory(f, &count, dir, n); - write the directory
- */
-
- /*
- * Write the WAD header to the file. The header will be modified later,
- * when the directory is written to the file.
- * If "patch" is TRUE, the file will be saved as a PWAD. If "patch" is
- * FALSE, it will be saved as an IWAD.
- */
- Bool WriteWADHeader(FILE *wadfile, UInt32 *count_r, WADDirPtr *dir_r,
- UInt16 *dirsize_r, Bool patch)
- {
- char buf[100];
-
- sprintf(buf, "PWAD********\r\nQEU %s\r\n", QEU_VERSION);
- if (patch == FALSE)
- buf[0] = 'I';
- if ((wadfile == NULL)
- || (WriteBytes(wadfile, buf, (UInt32)strlen(buf)) == FALSE))
- return FALSE;
- *dir_r = NULL;
- *count_r = (UInt32)strlen(buf);
- *dirsize_r = 0;
- return TRUE;
- }
-
-
- /*
- * Add a new entry to the WAD directory. This entry should have been
- * saved previously and be "entrysize" bytes long. It will be stored
- * in the WAD directory under the name "entryname".
- * All object saving routines in this package return the number of bytes
- * written, so that number can be passed directly to this routine.
- */
- Bool AddWADEntry(FILE *wadfile, UInt32 *count_r, WADDirPtr *dir_r,
- UInt16 *dirsize_r, char *entryname, UInt32 entrysize)
- {
- UInt16 n;
- char buf[9];
-
- if (wadfile == NULL || *count_r == 0L)
- return FALSE;
- n = *dirsize_r;
- if (n == 0)
- *dir_r = (WADDirPtr)QMalloc((UInt32)sizeof(struct WADDirectory));
- else
- *dir_r = (WADDirPtr)QRealloc(*dir_r, (UInt32)(n + 1)
- * (UInt32)sizeof(struct WADDirectory));
- strncpy(buf, entryname, 8);
- buf[8] = '\0';
- QStrNCpy((*dir_r)[n].name, strupr(buf), 8);
- (*dir_r)[n].offset = *count_r;
- (*dir_r)[n].size = entrysize;
- *count_r = *count_r + entrysize;
- *dirsize_r = n + 1;
- return TRUE;
- }
-
-
- /*
- * Write the WAD directory to the file. This should only be done
- * after all entries have been saved (using the appropriate
- * Write... routine) and registered (using AddWADEntry). The WAD
- * header is updated so that it points to the directory.
- *
- * This routine returns the total number of bytes taken by the WAD
- * file (header + all entries + directory). It is thus possible to
- * include a WAD file in another WAD file or in a PACK file.
- */
- UInt32 WriteWADDirectory(FILE *wadfile, UInt32 *count_r, WADDirPtr dir,
- UInt16 dirsize)
- {
- UInt32 size, pos;
- UInt16 i;
-
- pos = *count_r;
- if (wadfile == NULL || pos == 0L)
- return 0L;
- *count_r = 0L; /* invalidate the counter */
- size = (UInt32)dirsize;
- if ((fseek(wadfile, 4L - (Int32)(pos), SEEK_CUR) < 0)
- || (WriteInt32(wadfile, &size) == FALSE)
- || (WriteInt32(wadfile, &pos) == FALSE)
- || (fseek(wadfile, (Int32)(pos) - 12L, SEEK_CUR) < 0))
- return 0L;
- for (i = 0; i < dirsize; i++)
- if ((WriteInt32(wadfile, &(dir[i].offset)) == FALSE)
- || (WriteInt32(wadfile, &(dir[i].size)) == FALSE)
- || (WriteBytes(wadfile, &(dir[i].name), 8L) == FALSE))
- return 0L;
- return size * (UInt32)sizeof(struct WADDirectory) + pos;
- }
-
- /* end of file */
-