mirror of
				https://github.com/KartKrewDev/RingRacers.git
				synced 2025-10-30 08:01:28 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			566 lines
		
	
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			566 lines
		
	
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#define HELP \
 | 
						|
"Usage: flatb WAD-file list-file"                                         "\n"\
 | 
						|
"Replace flats and textures by name in a DOOM WAD."                       "\n"\
 | 
						|
"\n"\
 | 
						|
"list-file may have the following format:"                                "\n"\
 | 
						|
"\n"\
 | 
						|
"GFZFLR01 GFZFLR02"                                                       "\n"\
 | 
						|
"# Comment"                                                               "\n"\
 | 
						|
"GFZROCK GFZBLOCK"                                                        "\n"\
 | 
						|
"\n"\
 | 
						|
"The first name and second name may be delimited by any whitespace."       "\n"\
 | 
						|
"\n"\
 | 
						|
"Copyright 2019 James R."                                                 "\n"\
 | 
						|
"All rights reserved."                                                    "\n"
 | 
						|
 | 
						|
/*
 | 
						|
Copyright 2019 James R.
 | 
						|
All rights reserved.
 | 
						|
 | 
						|
Redistribution and use in source and binary forms, with or without
 | 
						|
modification, are permitted provided that the following conditions are met:
 | 
						|
 | 
						|
1. Redistributions of source code must retain the above copyright notice, this
 | 
						|
   list of conditions and the following disclaimer.
 | 
						|
2. Redistributions in binary form must reproduce the above copyright notice.
 | 
						|
 | 
						|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 | 
						|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
						|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
						|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 | 
						|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 | 
						|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 | 
						|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 | 
						|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
						|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
						|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
*/
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <stdint.h>
 | 
						|
#include <stdarg.h>
 | 
						|
#include <string.h>
 | 
						|
#include <ctype.h>
 | 
						|
 | 
						|
#define cchar const char
 | 
						|
#define cvoid const void
 | 
						|
 | 
						|
#define LONG int32_t
 | 
						|
 | 
						|
#define va_inline( __ap,__last, ... )\
 | 
						|
(\
 | 
						|
		va_start (__ap,__last),\
 | 
						|
		__VA_ARGS__,\
 | 
						|
		va_end   (__ap)\
 | 
						|
)
 | 
						|
 | 
						|
#define DELIM "\t\n\r "
 | 
						|
 | 
						|
typedef struct
 | 
						|
{
 | 
						|
	FILE  *       fp;
 | 
						|
	cchar * filename;
 | 
						|
}
 | 
						|
File;
 | 
						|
 | 
						|
int (*le32)(cvoid *);
 | 
						|
 | 
						|
void
 | 
						|
Pexit (int c, cchar *s, ...)
 | 
						|
{
 | 
						|
	va_list ap;
 | 
						|
	va_inline (ap, s,
 | 
						|
 | 
						|
			vfprintf(stderr, s, ap)
 | 
						|
 | 
						|
	);
 | 
						|
	exit(c);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
Prexit (cchar *pr, ...)
 | 
						|
{
 | 
						|
	va_list ap;
 | 
						|
	va_inline (ap, pr,
 | 
						|
 | 
						|
			vfprintf(stderr, pr, ap)
 | 
						|
 | 
						|
	);
 | 
						|
	perror("");
 | 
						|
	exit(-1);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
Fopen (File *f, cchar *filename, const char *mode)
 | 
						|
{
 | 
						|
	FILE *fp;
 | 
						|
	if (!( fp = fopen(filename, mode) ))
 | 
						|
		Prexit("%s", filename);
 | 
						|
	f->filename = filename;
 | 
						|
	f->fp = fp;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
Ferr (File *f)
 | 
						|
{
 | 
						|
	if (ferror(f->fp))
 | 
						|
		Prexit("%s", f->filename);
 | 
						|
}
 | 
						|
 | 
						|
char *
 | 
						|
Fgets (File *f, int b, char *p)
 | 
						|
{
 | 
						|
	if (!( p = fgets(p, b, f->fp) ))
 | 
						|
		Ferr(f);
 | 
						|
	return p;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
Fread (File *f, int b, void *p)
 | 
						|
{
 | 
						|
	if (fread(p, 1, b, f->fp) < b)
 | 
						|
		Ferr(f);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
Fwrite (File *f, int b, cvoid *s)
 | 
						|
{
 | 
						|
	if (fwrite(s, 1, b, f->fp) < b)
 | 
						|
		Ferr(f);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
Fseek (File *f, long o)
 | 
						|
{
 | 
						|
	if (fseek(f->fp, o, SEEK_SET) == -1)
 | 
						|
		Prexit("%s", f->filename);
 | 
						|
}
 | 
						|
 | 
						|
void *
 | 
						|
Malloc (int b)
 | 
						|
{
 | 
						|
	void *p;
 | 
						|
	if (!( p = malloc(b) ))
 | 
						|
		Prexit("%d", b);
 | 
						|
	return p;
 | 
						|
}
 | 
						|
 | 
						|
void *
 | 
						|
Calloc (int c, int b)
 | 
						|
{
 | 
						|
	void *p;
 | 
						|
	if (!( p = calloc(c, b) ))
 | 
						|
		Prexit("(%d)%d", c, b);
 | 
						|
	return p;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
Reallocp (void *pp, int b)
 | 
						|
{
 | 
						|
	void *p;
 | 
						|
	if (!( p = realloc((*(void **)pp), b) ))
 | 
						|
		Prexit("%d", b);
 | 
						|
	(*(void **)pp) = p;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
strucpy (char *p, cchar *s, int n)
 | 
						|
{
 | 
						|
	int c;
 | 
						|
	int i;
 | 
						|
	for (i = 0; i < n && ( c = s[i] ); ++i)
 | 
						|
		p[i] = toupper(c);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
e32 (cvoid *s)
 | 
						|
{
 | 
						|
	unsigned int c;
 | 
						|
	c = *(LONG *)s;
 | 
						|
	return (
 | 
						|
			 ( c >> 24 )            |
 | 
						|
			(( c >>  8 )& 0x00FF00 )|
 | 
						|
			(( c <<  8 )& 0xFF0000 )|
 | 
						|
			 ( c << 24 )
 | 
						|
	);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
n32 (cvoid *s)
 | 
						|
{
 | 
						|
	return *(LONG *)s;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
Ie ()
 | 
						|
{
 | 
						|
	int c;
 | 
						|
	c = 1;
 | 
						|
	if (*(char *)&c == 1)
 | 
						|
		le32 = n32;
 | 
						|
	else
 | 
						|
		le32 = e32;
 | 
						|
}
 | 
						|
 | 
						|
File         wad_file;
 | 
						|
File        list_file;
 | 
						|
 | 
						|
int         list_c;
 | 
						|
char ***    list_v;
 | 
						|
 | 
						|
char   * directory;
 | 
						|
char   *  lump;
 | 
						|
int       lumpsize;
 | 
						|
 | 
						|
char   * sectors;
 | 
						|
int      sectors_c;
 | 
						|
 | 
						|
char   *   sides;
 | 
						|
int        sides_c;
 | 
						|
 | 
						|
int      st_floors;
 | 
						|
int      st_ceilings;
 | 
						|
int      st_sectors;
 | 
						|
 | 
						|
int      st_sides;
 | 
						|
int      st_uppers;
 | 
						|
int      st_mids;
 | 
						|
int      st_lowers;
 | 
						|
 | 
						|
/* this is horseshit */
 | 
						|
char   * old;
 | 
						|
char   * new;
 | 
						|
int      did;
 | 
						|
 | 
						|
void
 | 
						|
Itable ()
 | 
						|
{
 | 
						|
	char a[1024];
 | 
						|
 | 
						|
	char ***ttt;
 | 
						|
	char ***ppp;
 | 
						|
 | 
						|
	char  **pp;
 | 
						|
 | 
						|
	int c;
 | 
						|
 | 
						|
	while (Fgets(&list_file, sizeof a, a))
 | 
						|
	{
 | 
						|
		c = a[0];
 | 
						|
		if (!(
 | 
						|
					c == '\n' ||
 | 
						|
					c == '#'
 | 
						|
		))
 | 
						|
		{
 | 
						|
			list_c++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	rewind(list_file.fp);
 | 
						|
 | 
						|
	list_v = Calloc(list_c, sizeof (char **));
 | 
						|
	for (
 | 
						|
			ttt = ( ppp = list_v ) + list_c;
 | 
						|
			ppp < ttt;
 | 
						|
			++ppp
 | 
						|
	)
 | 
						|
	{
 | 
						|
		(*ppp) = pp = Calloc(2, sizeof (char *));
 | 
						|
		pp[0] = Malloc(9);
 | 
						|
		pp[1] = Malloc(9);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
Iwad ()
 | 
						|
{
 | 
						|
	char  buf[12];
 | 
						|
 | 
						|
	char *  t;
 | 
						|
	char *  p;
 | 
						|
	int   map;
 | 
						|
 | 
						|
	char *sector_p;
 | 
						|
	char *  side_p;
 | 
						|
 | 
						|
	int n;
 | 
						|
	int h;
 | 
						|
 | 
						|
	Fread(&wad_file, 12, buf);
 | 
						|
	if (
 | 
						|
			memcmp(buf, "IWAD", 4) != 0 &&
 | 
						|
			memcmp(buf, "PWAD", 4) != 0
 | 
						|
	)
 | 
						|
	{
 | 
						|
		Pexit(-1,"%s: Not a WAD\n", wad_file.filename);
 | 
						|
	}
 | 
						|
 | 
						|
	Fseek(&wad_file, (*le32)(&buf[8]));
 | 
						|
 | 
						|
	n         = (*le32)(&buf[4]) * 8;
 | 
						|
	h         = n / 9;
 | 
						|
	n        *= 2;
 | 
						|
	directory = Malloc(n);
 | 
						|
	/* minimum number of lumps for a map */
 | 
						|
	sectors   = Malloc(h);
 | 
						|
	sides     = Malloc(h);
 | 
						|
 | 
						|
	Fread(&wad_file, n, directory);
 | 
						|
 | 
						|
	sector_p = sectors;
 | 
						|
	side_p   = sides;
 | 
						|
	map = 3;
 | 
						|
	for (t = ( p = directory ) + n; p < t; p += 16)
 | 
						|
	{
 | 
						|
		/* looking for SECTORS? Hopefully order doesn't matter in real world. */
 | 
						|
		/* also search for fucking SIDES MY SIDES AAAAAAAAAA */
 | 
						|
		switch (map)
 | 
						|
		{
 | 
						|
			case 0:
 | 
						|
			case 2:
 | 
						|
				if (strncmp(&p[8], "SECTORS", 8) == 0)
 | 
						|
				{
 | 
						|
					/* copy file offset and size */
 | 
						|
					memcpy(sector_p, p, 8);
 | 
						|
					sector_p += 8;
 | 
						|
					sectors_c++;
 | 
						|
					map |= 1;
 | 
						|
				}
 | 
						|
			case 1:
 | 
						|
				if (strncmp(&p[8], "SIDEDEFS", 8) == 0)
 | 
						|
				{
 | 
						|
					memcpy(side_p, p, 8);
 | 
						|
					side_p += 8;
 | 
						|
					sides_c++;
 | 
						|
					map |= 2;
 | 
						|
				}
 | 
						|
		}
 | 
						|
		if (map == 3)
 | 
						|
		{
 | 
						|
			/* MAP marker */
 | 
						|
			if (p[13] == '\0' && strncmp(&p[8], "MAP", 3) == 0)
 | 
						|
				map = 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
Fuckyou (char *p, int f, int *st)
 | 
						|
{
 | 
						|
	if (strncmp(p, old, 8) == 0)
 | 
						|
	{
 | 
						|
		strncpy(p, new, 8);
 | 
						|
		(*st)++;
 | 
						|
		did |= f;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
Epic (char *p, char *t)
 | 
						|
{
 | 
						|
	char *top;
 | 
						|
	char *bot;
 | 
						|
	int i;
 | 
						|
	/* oh hi magic number! */
 | 
						|
	for (; p < t; p += 26)
 | 
						|
	{
 | 
						|
		bot = &p [4];
 | 
						|
		top = &p[12];
 | 
						|
		did = 0;
 | 
						|
		for (i = 0; i < list_c; ++i)
 | 
						|
		{
 | 
						|
			old = list_v[i][0];
 | 
						|
			new = list_v[i][1];
 | 
						|
			switch (did)
 | 
						|
			{
 | 
						|
				case 0:
 | 
						|
				case 2:
 | 
						|
					Fuckyou(bot, 1, &st_floors);
 | 
						|
				case 1:
 | 
						|
					Fuckyou(top, 2, &st_ceilings);
 | 
						|
			}
 | 
						|
			if (did == 3)
 | 
						|
				break;
 | 
						|
		}
 | 
						|
		if (did)
 | 
						|
			st_sectors++;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
Epic2 (char *p, char *t)
 | 
						|
{
 | 
						|
	char *top;
 | 
						|
	char *mid;
 | 
						|
	char *bot;
 | 
						|
	int i;
 | 
						|
	for (; p < t; p += 30)
 | 
						|
	{
 | 
						|
		top = &p [4];
 | 
						|
		bot = &p[12];
 | 
						|
		mid = &p[20];
 | 
						|
		did = 0;
 | 
						|
		for (i = 0; i < list_c; ++i)
 | 
						|
		{
 | 
						|
			old = list_v[i][0];
 | 
						|
			new = list_v[i][1];
 | 
						|
			switch (did)
 | 
						|
			{
 | 
						|
				case 0:
 | 
						|
				case 2:
 | 
						|
				case 4:
 | 
						|
				case 6:
 | 
						|
					Fuckyou(top, 1, &st_uppers);
 | 
						|
				case 1:
 | 
						|
				case 5:
 | 
						|
					Fuckyou(mid, 2, &st_mids);
 | 
						|
				case 3:
 | 
						|
					Fuckyou(bot, 4, &st_lowers);
 | 
						|
			}
 | 
						|
			if (did == 7)
 | 
						|
				break;
 | 
						|
		}
 | 
						|
		if (did)
 | 
						|
			st_sides++;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
Fuck (char *p, int c, void (*fn)(char *,char *))
 | 
						|
{
 | 
						|
	char *t;
 | 
						|
	int offs;
 | 
						|
	int size;
 | 
						|
	for (t = p + c * 8; p < t; p += 8)
 | 
						|
	{
 | 
						|
		offs = (*le32)(p);
 | 
						|
		size = (*le32)(p + 4);
 | 
						|
		if (lumpsize < size)
 | 
						|
		{
 | 
						|
			Reallocp(&lump, size);
 | 
						|
			lumpsize = size;
 | 
						|
		}
 | 
						|
		Fseek(&wad_file, offs);
 | 
						|
		Fread(&wad_file, size, lump);
 | 
						|
		(*fn)(lump, lump + size);
 | 
						|
		Fseek(&wad_file, offs);
 | 
						|
		Fwrite(&wad_file, size, lump);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
Awad ()
 | 
						|
{
 | 
						|
	Fuck (sectors, sectors_c, Epic);
 | 
						|
	Fuck   (sides,   sides_c, Epic2);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
Readtable ()
 | 
						|
{
 | 
						|
	char    a[1024];
 | 
						|
 | 
						|
	int     s;
 | 
						|
	char *old;
 | 
						|
	char *new;
 | 
						|
 | 
						|
	int c;
 | 
						|
 | 
						|
	s = 0;
 | 
						|
 | 
						|
	while (Fgets(&list_file, sizeof a, a))
 | 
						|
	{
 | 
						|
		c = a[0];
 | 
						|
		if (!(
 | 
						|
				c == '\n' ||
 | 
						|
				c == '#'
 | 
						|
		))
 | 
						|
		{
 | 
						|
			if (
 | 
						|
					( old = strtok(a, DELIM) ) &&
 | 
						|
					( new = strtok(0, DELIM) )
 | 
						|
			)
 | 
						|
			{
 | 
						|
				strucpy(list_v[s][0], old, 8);
 | 
						|
				strucpy(list_v[s][1], new, 8);
 | 
						|
				++s;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
Cleanup ()
 | 
						|
{
 | 
						|
	char ***ttt;
 | 
						|
	char ***ppp;
 | 
						|
 | 
						|
	char  **pp;
 | 
						|
 | 
						|
	free(lump);
 | 
						|
	free(sides);
 | 
						|
	free(sectors);
 | 
						|
	free(directory);
 | 
						|
 | 
						|
	if (list_v)
 | 
						|
	{
 | 
						|
		for (
 | 
						|
				ttt = ( ppp = list_v ) + list_c;
 | 
						|
				ppp < ttt && ( pp = (*ppp) );
 | 
						|
				++ppp
 | 
						|
		)
 | 
						|
		{
 | 
						|
			free(pp[0]);
 | 
						|
			free(pp[1]);
 | 
						|
			free(pp);
 | 
						|
		}
 | 
						|
		free(list_v);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
main (int ac, char **av)
 | 
						|
{
 | 
						|
	int n;
 | 
						|
 | 
						|
	if (ac < 3)
 | 
						|
		Pexit(0,HELP);
 | 
						|
 | 
						|
	Fopen (& wad_file, av[1], "rb+");
 | 
						|
	Fopen (&list_file, av[2], "r");
 | 
						|
 | 
						|
	if (atexit(Cleanup) != 0)
 | 
						|
		Pexit(-1,"Failed to register cleanup function.\n");
 | 
						|
 | 
						|
	Itable();
 | 
						|
	Readtable();
 | 
						|
 | 
						|
	Ie();
 | 
						|
 | 
						|
	Iwad();
 | 
						|
	Awad();
 | 
						|
 | 
						|
	printf(
 | 
						|
			"%5d sectors changed.\n"
 | 
						|
			"%5d floors.\n"
 | 
						|
			"%5d ceilings.\n"
 | 
						|
			"\n"
 | 
						|
			"%5d sides.\n"
 | 
						|
			"%5d upper textures.\n"
 | 
						|
			"%5d mid textures.\n"
 | 
						|
			"%5d lower textures.\n",
 | 
						|
 | 
						|
			st_sectors,
 | 
						|
 | 
						|
			st_floors,
 | 
						|
			st_ceilings,
 | 
						|
 | 
						|
			st_sides,
 | 
						|
 | 
						|
			st_uppers,
 | 
						|
			st_mids,
 | 
						|
			st_lowers);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 |