mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-12-01 00:21:43 +00:00
6cd1e2ce6a
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)
503 lines
12 KiB
C
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(¤ttime);
|
|
ltime = localtime(¤ttime);
|
|
// 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;
|
|
}
|