diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Darwin.mk | 2 | ||||
-rw-r--r-- | Makefile | 60 | ||||
-rw-r--r-- | image.c | 47 | ||||
-rw-r--r-- | png.h | 108 |
5 files changed, 148 insertions, 70 deletions
diff --git a/.gitignore b/.gitignore index f9ac67d..714260a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.o chroot.tar client +config.mk image merge meta diff --git a/Darwin.mk b/Darwin.mk new file mode 100644 index 0000000..6a2f53f --- /dev/null +++ b/Darwin.mk @@ -0,0 +1,2 @@ +LDFLAGS = +LDLIBS = -lcurses diff --git a/Makefile b/Makefile index ec80687..91ab927 100644 --- a/Makefile +++ b/Makefile @@ -1,55 +1,57 @@ CHROOT_USER = torus CHROOT_GROUP = $(CHROOT_USER) -CFLAGS += -Wall -Wextra -Wpedantic -LDFLAGS += -static -LDLIBS = -lcursesw -lutil -lz -BINS = server client image meta merge +CFLAGS += -std=c11 -Wall -Wextra -Wpedantic +LDFLAGS = -static +LDLIBS = -lcursesw -lutil + +-include config.mk + +BINS = client image merge meta server OBJS = $(BINS:%=%.o) all: tags $(BINS) -.o: - $(CC) $(LDFLAGS) $< $(LDLIBS) -o $@ - $(OBJS): torus.h client.o: help.h -help.h: - head -c 4096 torus.dat \ - | file2c -s -x 'static const uint8_t HelpData[] = {' '};' \ - > help.h - echo 'static const struct Tile *Help = (const struct Tile *)HelpData;' \ - >> help.h +image.o: png.h + +.o: + $(CC) $(LDFLAGS) $< $(LDLIBS) -o $@ tags: *.h *.c ctags -w *.h *.c -chroot.tar: server client - mkdir -p root +chroot.tar: client server install -d -o root -g wheel \ + root \ root/bin \ root/home \ - root/usr \ - root/usr/share \ root/usr/share/misc \ - root/var \ root/var/run install -d -o $(CHROOT_USER) -g $(CHROOT_GROUP) root/home/$(CHROOT_USER) install -d -o $(CHROOT_USER) -g $(CHROOT_GROUP) root/var/run/torus - cp -a -f /usr/share/locale root/usr/share - cp -p -f /usr/share/misc/termcap.db root/usr/share/misc - cp -p -f /rescue/sh root/bin - install -o root -g wheel -m 555 server client root/bin - tar -c -f chroot.tar -C root bin home usr var + cp -af /usr/share/locale root/usr/share + cp -fp /usr/share/misc/termcap.db root/usr/share/misc + cp -fp /rescue/sh root/bin + install client server root/bin + tar -cf chroot.tar -C root bin home usr var + +install: chroot.tar rc.torus + tar -xf chroot.tar -C /home/$(CHROOT_USER) + install rc.torus /usr/local/etc/rc.d/torus clean: - rm -f tags $(OBJS) $(BINS) chroot.tar + rm -f $(OBJS) $(BINS) tags root chroot.tar -README: torus.1 - mandoc torus.1 | col -b -x > README +help.h: + head -c 4096 torus.dat \ + | file2c -sx 'static const uint8_t HelpData[] = {' '};' \ + > help.h + echo 'static const struct Tile *Help = (const struct Tile *)HelpData;' \ + >> help.h -install: chroot.tar rc.torus - tar -x -f chroot.tar -C /home/$(CHROOT_USER) - install rc.torus /usr/local/etc/rc.d/torus +README: torus.1 + mandoc torus.1 | col -bx > README diff --git a/image.c b/image.c index d67706f..670dae7 100644 --- a/image.c +++ b/image.c @@ -14,7 +14,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <arpa/inet.h> #include <err.h> #include <fcntl.h> #include <stdint.h> @@ -25,8 +24,8 @@ #include <sys/stat.h> #include <sysexits.h> #include <unistd.h> -#include <zlib.h> +#include "png.h" #include "torus.h" static const uint8_t Palette[16][3] = { @@ -106,40 +105,15 @@ static void tilesMap(const char *path) { if (error) err(EX_OSERR, "madvise"); } -static uint32_t crc; -static void pngWrite(const void *ptr, size_t size) { - fwrite(ptr, size, 1, stdout); - if (ferror(stdout)) err(EX_IOERR, "(stdout)"); - crc = crc32(crc, ptr, size); -} -static void pngInt(uint32_t host) { - uint32_t net = htonl(host); - pngWrite(&net, 4); -} -static void pngChunk(char type[static 4], uint32_t size) { - pngInt(size); - crc = crc32(0, Z_NULL, 0); - pngWrite(type, 4); -} - static void render(uint32_t tileX, uint32_t tileY) { uint32_t width = CellCols * font.glyph.width; uint32_t height = CellRows * font.glyph.height; - pngWrite("\x89PNG\r\n\x1A\n", 8); - - pngChunk("IHDR", 13); - pngInt(width); - pngInt(height); - pngWrite("\x08\x03\x00\x00\x00", 5); - pngInt(crc); - - pngChunk("PLTE", sizeof(Palette)); - pngWrite(Palette, sizeof(Palette)); - pngInt(crc); + pngHead(stdout, width, height, 8, PNGIndexed); + pngPalette(stdout, (uint8_t *)Palette, sizeof(Palette)); uint8_t data[height][1 + width]; - memset(data, 0, sizeof(data)); + memset(data, PNGNone, sizeof(data)); uint32_t widthBytes = (font.glyph.width + 7) / 8; uint8_t (*bits)[font.glyph.len][font.glyph.height][widthBytes]; @@ -163,17 +137,8 @@ static void render(uint32_t tileX, uint32_t tileY) { } } - uLong size = compressBound(sizeof(data)); - uint8_t deflate[size]; - int error = compress(deflate, &size, (Byte *)data, sizeof(data)); - if (error != Z_OK) errx(EX_SOFTWARE, "compress: %d", error); - - pngChunk("IDAT", size); - pngWrite(deflate, size); - pngInt(crc); - - pngChunk("IEND", 0); - pngInt(crc); + pngData(stdout, (uint8_t *)data, sizeof(data)); + pngTail(stdout); } int main(int argc, char *argv[]) { diff --git a/png.h b/png.h new file mode 100644 index 0000000..0df4699 --- /dev/null +++ b/png.h @@ -0,0 +1,108 @@ +/* Copyright (C) 2018 June McEnroe <june@causal.agency> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <err.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <sysexits.h> + +static inline uint32_t pngCRCTable(uint8_t n) { + static uint32_t table[256]; + if (table[1]) return table[n]; + for (int i = 0; i < 256; ++i) { + table[i] = i; + for (int j = 0; j < 8; ++j) { + table[i] = (table[i] >> 1) ^ (table[i] & 1 ? 0xEDB88320 : 0); + } + } + return table[n]; +} + +static uint32_t pngCRC; + +static inline void pngWrite(FILE *file, const uint8_t *ptr, uint32_t len) { + if (!fwrite(ptr, len, 1, file)) err(EX_IOERR, "pngWrite"); + for (uint32_t i = 0; i < len; ++i) { + pngCRC = pngCRCTable(pngCRC ^ ptr[i]) ^ (pngCRC >> 8); + } +} +static inline void pngInt32(FILE *file, uint32_t n) { + pngWrite(file, (uint8_t []) { n >> 24, n >> 16, n >> 8, n }, 4); +} +static inline void pngChunk(FILE *file, char type[static 4], uint32_t len) { + pngInt32(file, len); + pngCRC = ~0; + pngWrite(file, (uint8_t *)type, 4); +} + +enum { + PNGGrayscale, + PNGTruecolor = 2, + PNGIndexed, + PNGAlpha, +}; + +static inline void pngHead( + FILE *file, uint32_t width, uint32_t height, uint8_t depth, uint8_t color +) { + pngWrite(file, (uint8_t *)"\x89PNG\r\n\x1A\n", 8); + pngChunk(file, "IHDR", 13); + pngInt32(file, width); + pngInt32(file, height); + pngWrite(file, &depth, 1); + pngWrite(file, &color, 1); + pngWrite(file, (uint8_t []) { 0, 0, 0 }, 3); + pngInt32(file, ~pngCRC); +} + +static inline void pngPalette(FILE *file, const uint8_t *pal, uint32_t len) { + pngChunk(file, "PLTE", len); + pngWrite(file, pal, len); + pngInt32(file, ~pngCRC); +} + +enum { + PNGNone, + PNGSub, + PNGUp, + PNGAverage, + PNGPaeth, +}; + +static inline void pngData(FILE *file, const uint8_t *data, uint32_t len) { + uint32_t adler1 = 1, adler2 = 0; + for (uint32_t i = 0; i < len; ++i) { + adler1 = (adler1 + data[i]) % 65521; + adler2 = (adler1 + adler2) % 65521; + } + uint32_t zlen = 2 + 5 * ((len + 0xFFFE) / 0xFFFF) + len + 4; + pngChunk(file, "IDAT", zlen); + pngWrite(file, (uint8_t []) { 0x08, 0x1D }, 2); + for (; len > 0xFFFF; data += 0xFFFF, len -= 0xFFFF) { + pngWrite(file, (uint8_t []) { 0x00, 0xFF, 0xFF, 0x00, 0x00 }, 5); + pngWrite(file, data, 0xFFFF); + } + pngWrite(file, (uint8_t []) { 0x01, len, len >> 8, ~len, ~len >> 8 }, 5); + pngWrite(file, data, len); + pngInt32(file, adler2 << 16 | adler1); + pngInt32(file, ~pngCRC); +} + +static inline void pngTail(FILE *file) { + pngChunk(file, "IEND", 0); + pngInt32(file, ~pngCRC); +} |