From 8c5c2a7e4b42788a50b2af3e01cde5a5f9f4215a Mon Sep 17 00:00:00 2001
From: James R <justsomejames2@gmail.com>
Date: Mon, 21 Oct 2019 12:42:04 -0700
Subject: [PATCH] Flatb

---
 tools/flatb/Makefile |   9 +
 tools/flatb/flatb.c  | 566 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 575 insertions(+)
 create mode 100644 tools/flatb/Makefile
 create mode 100644 tools/flatb/flatb.c

diff --git a/tools/flatb/Makefile b/tools/flatb/Makefile
new file mode 100644
index 0000000000..2134973e68
--- /dev/null
+++ b/tools/flatb/Makefile
@@ -0,0 +1,9 @@
+.PHONY : all clean
+
+all : flatb
+
+flatb.exe : flatb.c
+	i686-w64-mingw32-gcc $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ $<
+
+clean :
+	$(RM) flatb flatb.exe
diff --git a/tools/flatb/flatb.c b/tools/flatb/flatb.c
new file mode 100644
index 0000000000..edc0892324
--- /dev/null
+++ b/tools/flatb/flatb.c
@@ -0,0 +1,566 @@
+#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;
+}
-- 
GitLab