gzdoom-gles/tools/makewad/makewad.c
Randy Heit 6cd1e2ce6a - Fixed: CopyPlayer() in p_saveg.cpp should use normal assignment, not
memcpy to copy the player structures.
- Fixed compilation with MinGW again and removed most of the new warnings.

And following is the log that I forgot to paste in for the previous commit:

- Changed the memory management for FString. Instead of using a garbage
  collected heap, it now uses normal heap calls and reference counting to
  implement lazy copying. You may now use bitwise operators to move
  (but not copy!) FStrings around in memory. This means that the
  CopyForTArray template function is gone, since TArrays can now freely
  move their contents around without bothering with their specifics.
  
  There is one important caveat, however. It is not acceptable to blindly 0
  an FString's contents. This necessitated the creation of a proper
  constructor for player_s so that it can be reset without using memset. I
  did a quick scan of all memsets in the source and didn't see anything else
  with a similar problem, but it's possible I missed something.
- Fixed: Build tiles were never deallocated.
- Fixed: Using Build's palette.dat only got half the palette right.


SVN r117 (trunk)
2006-05-16 04:19:20 +00:00

503 lines
12 KiB
C

// makewad.c
//
// Reads a wad specification from stdin.
// Produces a wad file -or- writes a Makefile to stdout.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#include "zip.h"
#define MAX_LUMPS 4096
typedef struct
{
char magic[4];
unsigned int numlumps;
int infotableofs;
} wadinfo_t;
typedef struct
{
int filepos;
unsigned int size;
char name[8];
} filelump_t;
/*
// appendlump(wadfile, filename):
//
// open the file by filename, write all of its contents to the wadfile
//
// returns: 0 = success, 1 = error
*/
int appendlump (FILE *wadfile, char *filename)
{
char readbuf[64*1024];
FILE *lumpfile;
size_t readlen;
int ret = 0;
lumpfile = fopen (filename, "rb");
if (lumpfile == NULL)
{
fprintf (stderr, "Could not open %s: %s\n", filename, strerror(errno));
return 1;
}
while (lumpfile != NULL)
{
// try to read a chunk of data
readlen = fread (readbuf, 1, sizeof(readbuf), lumpfile);
// if we reached the end, or hit an error
if (readlen < sizeof(readbuf))
{
// if it's an error,
if (ferror (lumpfile))
{
// diagnose
fprintf (stderr, "Error reading %s: %s\n", filename, strerror(errno));
// set return code to error
ret |= 1;
}
// in any case, close the lump file to break the loop
fclose (lumpfile);
lumpfile = NULL;
}
// write whatever data we have in the buffer
// if we hit an error (less bytes written than given)
if (fwrite (readbuf, 1, readlen, wadfile) < readlen)
{
// diagnose
fprintf (stderr, "Error writing to wad: %s\n", strerror(errno));
// close the lump file to break the loop
fclose (lumpfile);
lumpfile = NULL;
// set return code to error
ret |= 1;
}
// if the lump file got closed, the loop exits
}
return ret;
}
/*
// appendtozip(zipFile, zipname, filename):
//
// write a given lump file (filename) to the zipFile as zipname
//
// zipFile: zip object to be written to
//
// zipname: name of the file inside the zip
// filename: file to read data from
//
// returns: 0 = success, 1 = error
*/
int appendtozip (zipFile zipfile, const char * zipname, const char *filename)
{
char *readbuf;
FILE *lumpfile;
size_t readlen;
size_t len;
zip_fileinfo zip_inf;
time_t currenttime;
struct tm * ltime;
// clear zip_inf structure
memset(&zip_inf, 0, sizeof(zip_inf));
// try to determine local time
time(&currenttime);
ltime = localtime(&currenttime);
// if succeeded,
if (ltime != NULL)
{
// put it into the zip_inf structure
zip_inf.tmz_date.tm_sec = ltime->tm_sec;
zip_inf.tmz_date.tm_min = ltime->tm_min;
zip_inf.tmz_date.tm_hour = ltime->tm_hour;
zip_inf.tmz_date.tm_mday = ltime->tm_mday;
zip_inf.tmz_date.tm_mon = ltime->tm_mon;
zip_inf.tmz_date.tm_year = ltime->tm_year;
}
// lumpfile = source file
lumpfile = fopen (filename, "rb");
if (lumpfile == NULL)
{
fprintf (stderr, "Could not open %s: %s\n", filename, strerror(errno));
return 1;
}
// len = source size
fseek (lumpfile, 0, SEEK_END);
len = ftell(lumpfile);
fseek (lumpfile, 0, SEEK_SET);
// allocate a buffer for the whole source file
readbuf = (char*)malloc(len);
if (readbuf == NULL)
{
fclose(lumpfile);
fprintf (stderr, "Could not allocate %d bytes\n", len);
return 1;
}
// read the whole source file into buffer
readlen = fread (readbuf, 1, len, lumpfile);
fclose(lumpfile);
// if read less bytes than expected,
if (readlen != len)
{
// diagnose and return error
free (readbuf);
fprintf (stderr, "Unable to read %s\n", filename);
return 1;
}
// file loaded
// create zip entry, giving entry name and zip_inf data
if (Z_OK != zipOpenNewFileInZip(zipfile, zipname, &zip_inf, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_BEST_COMPRESSION))
{
free (readbuf);
fprintf (stderr, "Unable to open zip for writing %s\n", filename);
return 1;
}
// write data into zipfile (zipfile remembers the state)
if (Z_OK != zipWriteInFileInZip(zipfile, readbuf, (unsigned)len))
{
free (readbuf);
fprintf (stderr, "Unable to write %s to zip\n", filename);
return 1;
}
// done writing data
free (readbuf);
// close the zip entry
if (Z_OK != zipCloseFileInZip(zipfile))
{
fprintf (stderr, "Unable to close %s in zip\n", filename);
return 1;
}
// all done
return 0;
}
/*
// buildwad(listfile, listfilename, makecmd, makefile)
//
// go through the listfile, either:
// writing dependencies (listfile + lumps with files) into a makefile,
// -or-
// writing lumps into a wad/zip file
//
// listfile: already opened source file
// listfilename: filename, if any - only for the makefile
// makecmd: given as argv[0] - only for the makefile
// makefile: output filename for makefile. determines mode:
// - if specified, we're writing deps into a makefile
// - otherwise, we're writing lumps into a wad/zip
//
*/
int buildwad (FILE *listfile, char *listfilename, char *makecmd, char *makefile)
{
// destination we're writing output into -
// one of these:
zipFile zipfile = NULL;
FILE *wadfile = NULL;
wadinfo_t header;
filelump_t directory[MAX_LUMPS];
char str[256]; // buffer for reading listfile line by line
char *pt;
char *lumpname, *filename;
int lineno = 0;
int ret = 0;
int i;
// prepare PWAD data
strncpy (header.magic, "PWAD", 4);
header.infotableofs = 0;
header.numlumps = 0;
memset (directory, 0, sizeof(directory));
// read the listfile line by line
while (fgets (str, sizeof(str), listfile))
{
lineno++; // counting lines for diagnostic purposes
// Strip comments
pt = strchr (str, '#');
if (pt) *pt = 0;
// Strip trailing whitespace
pt = str + strlen (str) - 1;
while (pt >= str && isspace(*pt)) pt--;
if (pt < str) continue;
pt[1] = 0;
// Skip leading whitespace
pt = str;
while (isspace(*pt)) pt++;
if (*pt == '@')
{ // Rest of line is wadfile to create
if (wadfile != NULL || zipfile != NULL)
{
fprintf (stderr, "Line %d: Tried to reopen wadfile as %s.\n", lineno, pt + 1);
if (wadfile != NULL) fclose (wadfile);
if (zipfile != NULL) zipClose (zipfile, NULL);
return 1;
}
if (!makefile) // if it's not a makefile,
{
int ln = (int)strlen(pt+1);
filename = pt+1;
if (ln >= 4)
{
// If the output file has an extension '.zip' or '.pk3' it will be in Zip format.
if (!stricmp(filename+ln-3, "ZIP") || !stricmp(filename+ln-3, "PK3"))
{
zipfile = zipOpen(filename, APPEND_STATUS_CREATE);
if (zipfile == NULL)
{
fprintf (stderr, "Line %d: Could not open %s: %s\n", lineno, filename, strerror(errno));
return 1;
}
}
}
}
else filename = makefile;
if (!zipfile) // if we didn't end up opening zip, it's a regular file
{
// open wadfile
wadfile = fopen (filename, makefile ? "w" : "wb");
if (wadfile == NULL)
{
fprintf (stderr, "Line %d: Could not open %s: %s\n", lineno, filename, strerror(errno));
return 1;
}
if (makefile)
{ // Write out the only rule the makefile has
fprintf (wadfile, "%s: %s", pt+1, listfilename);
}
else
{
// The correct header will be written once the wad is complete
fwrite (&header, sizeof(header), 1, wadfile);
}
}
continue;
} // @
// Everything up to the next whitespace is the lump name
lumpname = pt;
filename = NULL;
while (*pt && !isspace(*pt)) pt++;
// If there is more, skip whitespace and use the remainder of the line
// as the file to insert into the lump. If no filename is given, then
// a 0-length marker lump is inserted.
if (*pt)
{
*pt = 0;
filename = pt + 1;
while (*filename && isspace(*filename)) filename++;
if (*filename == 0) filename = NULL;
}
// must have output selected
if (wadfile == NULL && zipfile == NULL)
{
fprintf (stderr, "Line %d: No wad specified before lumps.\n", lineno);
return 1;
}
// if we're writing a makefile,
if (makefile)
{
// and the lump has a filename,
if (filename != NULL)
{
// add it as a dependency (with quotes, if needed)
if (strchr (filename, ' '))
{
fprintf (wadfile, " \\\n\t\"%s\"", filename);
}
else
{
fprintf (wadfile, " \\\n\t%s", filename);
}
}
}
else // not writing a makefile
{
if (zipfile == NULL) // must be a wadfile
{
// convert lumpname to uppercase
for (i = 0; lumpname[i]; ++i)
{
lumpname[i] = toupper(lumpname[i]);
}
// put name into directory entry
strncpy (directory[header.numlumps].name, lumpname, 8);
// put filepos into directory entry
directory[header.numlumps].filepos = ftell (wadfile);
// if filename given,
if (filename != NULL)
{
// append data to the wadfile
ret |= appendlump (wadfile, filename);
}
// put size into directory entry (how many bytes were just written)
directory[header.numlumps].size = ftell (wadfile) - directory[header.numlumps].filepos;
}
else if (filename != NULL) // writing a zip, and filename is non-null
{
// convert lumpname to lowercase
for (i = 0; lumpname[i]; ++i)
{
lumpname[i] = tolower(lumpname[i]);
}
// add lump data to the zip
ret |= appendtozip(zipfile, lumpname, filename);
}
// count all lumps
header.numlumps++;
}
} // end of line-by-line reading
// the finishing touches:
// - makefile: terminate the line, and write the action line
// - unzipped wad: write the directory at the end,
// and update the header with directory's position
// - zipped wad: just close it
// if we were writing a plain file,
if (wadfile != NULL)
{
// if it's makefile,
if (makefile)
{
// terminate the dependencies line,
// and write the action command
fprintf (wadfile, "\n\t%s %s\n", makecmd, listfilename);
}
else // otherwise, it's plain wad
{
// the directory of lumps will be written at the end,
// starting at the current position - put it into the header
header.infotableofs = ftell (wadfile);
// swap endianness, if needed
#ifdef WORDS_BIGENDIAN
#define SWAP(x) ((((x)>>24)|(((x)>>8) & 0xff00)|(((x)<<8) & 0xff0000)|((x)<<24)))
for (i = 0; i < header.numlumps; ++i)
{
directory[i].filepos = SWAP(directory[i].filepos);
directory[i].size = SWAP(directory[i].size);
}
#endif
// write the whole directory of lumps
if (fwrite (directory, sizeof(directory[0]), header.numlumps, wadfile) != header.numlumps)
{
// failed to write the whole directory
fprintf (stderr, "Error writing to wad: %s\n", strerror(errno));
ret |= 1;
}
else // success - seek to 0 and rewrite the header, now with offset
{
// endianness
#ifdef WORDS_BIGENDIAN
SWAP(header.infotableofs);
SWAP(header.numlumps);
#endif
// seek to 0
fseek (wadfile, 0, SEEK_SET);
// rewrite the header
if (fwrite (&header, sizeof(header), 1, wadfile) != 1)
{
fprintf (stderr, "Error writing to wad: %s\n", strerror(errno));
ret |= 1;
}
}
} // plain wad
fclose (wadfile);
} // wadfile!=NULL - wad or makefile
else if (zipfile != NULL)
{
// zip - just close it
zipClose(zipfile, NULL);
}
return ret;
}
int __cdecl main (int argc, char **argv)
{
FILE *listfile = NULL;
char *listfilename = NULL;
char *makefile = NULL;
int ret;
int i;
for (i = 1; i < argc; ++i)
{
if (strcmp (argv[i], "-make") == 0)
{
if (i >= argc-1)
{
goto baduse;
}
makefile = argv[++i];
}
else if (listfile == NULL)
{
listfilename = argv[i];
listfile = fopen (listfilename, "r");
if (listfile == NULL)
{
fprintf (stderr, "Can't open %s: %s\n", listfilename, strerror(errno));
return 1;
}
}
else
{
fclose (listfile);
goto baduse;
}
}
if (makefile != NULL && listfile == NULL)
{
fprintf (stderr, "You must specify a listfile if you want a makefile\n");
return 1;
}
ret = buildwad (listfile ? listfile : stdin, listfilename, argv[0], makefile);
if (listfile != NULL)
{
fclose (listfile);
}
return ret;
baduse:
fprintf (stderr, "Usage: makewad [-make makefile] [listfile]\n");
return 1;
}