diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | gfx/gfx.mk | 12 | ||||
-rw-r--r-- | tools/scan_includes.c | 2 | ||||
-rw-r--r-- | tools/tools.mk | 9 | ||||
-rw-r--r-- | tools/xor_compress.c | 115 | ||||
-rw-r--r-- | tools/xor_compress.py | 12 |
6 files changed, 137 insertions, 14 deletions
@@ -12,3 +12,4 @@ __pycache__ /coverage.png /picross.png tools/scan_includes +tools/xor_compress @@ -9,10 +9,10 @@ $(dir_build)/gfx/data_select/data_select.2bpp: gfx/data_select/data_select.png | $(RGBGFX) $(RGBGFXFLAGS) -o $@ $< printf 3 >> $@ -$(dir_build)/%.xor: $(dir_build)/% | $$(dir $$@) - tools/xor_compress.py $< > $@ -$(dir_build)/%.xor: % | $$(dir $$@) - tools/xor_compress.py $< > $@ +$(dir_build)/%.xor: $(dir_build)/% | $$(dir $$@) tools/xor_compress + tools/xor_compress $< > $@ +$(dir_build)/%.xor: % | $$(dir $$@) tools/xor_compress + tools/xor_compress $< > $@ -$(dir_build)/%.tilemap_attrmap.xor: %.tilemap %.attrmap | $$(dir $$@) - tools/xor_compress.py $^ > $@ +$(dir_build)/%.tilemap_attrmap.xor: %.tilemap %.attrmap | $$(dir $$@) tools/xor_compress + tools/xor_compress $^ > $@ diff --git a/tools/scan_includes.c b/tools/scan_includes.c index 52d0612..adef2b2 100644 --- a/tools/scan_includes.c +++ b/tools/scan_includes.c @@ -260,7 +260,7 @@ int main(int argc, char* argv[]) { } if (Options.target) { - fprintf(f, "%s:", Options.target, includes, incbins); + fprintf(f, "%s:", Options.target); } if (includes) fprintf(f, " %s", includes); if (incbins) fprintf(f, " %s", incbins); diff --git a/tools/tools.mk b/tools/tools.mk index 0321462..0857fcb 100644 --- a/tools/tools.mk +++ b/tools/tools.mk @@ -1,2 +1,9 @@ tools := \ -tools/scan_includes +tools/scan_includes \ +tools/xor_compress + +CC := gcc +CFLAGS := -O3 -std=c99 -Wall -Wextra -pedantic + +tools/%: tools/%.c + $(CC) $(CFLAGS) -o $@ $< diff --git a/tools/xor_compress.c b/tools/xor_compress.c new file mode 100644 index 0000000..03ea451 --- /dev/null +++ b/tools/xor_compress.c @@ -0,0 +1,115 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#define PROGRAM_NAME "xor_compress" + +extern int errno; + +size_t file_size(FILE *f, int *err) { + int check = fseek(f, 0, SEEK_END); + if (check == -1) goto failure; + + long f_size = ftell(f); + if (f_size == -1) goto failure; + + check = fseek(f, 0, SEEK_SET); + if (check == -1) goto failure; + + *err = 0; + return (size_t)f_size; + +failure: + *err = errno; + return 0; +} + +unsigned char *read_files(char *filenames[], int num_files, size_t *buf_size, int *err) { + *buf_size = 0; + unsigned char *buffer = NULL; + + const char *filename = NULL; + for (int i = 0; i < num_files; i++) { + filename = filenames[i]; + + FILE *f = fopen(filename, "rb"); + if (!f) goto failure; + + size_t f_size = file_size(f, err); + if (*err > 0) goto failure; + if (f_size == 0) continue; + + *buf_size += f_size; + buffer = realloc(buffer, *buf_size); + if (!buffer) goto failure; + + unsigned char *buf_end = buffer + (*buf_size - f_size); + size_t read_size = fread(buf_end, 1, f_size, f); + if (read_size != f_size) { + // fread does not set errno + fprintf(stderr, PROGRAM_NAME ": %s: Read error\n", filename); + *err = 1; + return buffer; + } + } + + *err = 0; + return buffer; + +failure: + fprintf(stderr, PROGRAM_NAME ": %s: %s\n", filename, strerror(errno)); + *err = errno; + return buffer; +} + +int compress_files(char *filenames[], int num_files) { + int err = 0; + size_t n = 0; + unsigned char *data = read_files(filenames, num_files, &n, &err); + if (err > 0) { + if (data) free(data); + return err; + } + + unsigned char v = 0x00; + for (size_t i = 0; i < n;) { + unsigned char byte = data[i++]; + unsigned char size = 0; + if (data[i] == v) { + // Alternating (>= 0x80) + // Run stops at 0x80 bytes or when the values stop alternating + for (; i < n && size < 0x80 && data[i] == (size % 2 ? byte : v); size++, i++); + putchar(size + 0x7f); + putchar(v ^ byte); + if (size % 2 == 0) v = byte; + } else { + // Sequential (< 0x80) + // Run stops at 0x80 bytes or when the value two ahead is equal to v + unsigned char buffer[256] = {0}; + buffer[size++] = v ^ byte; + for (; i < n; i++) { + v = byte; + if (size > 0x7f || (i + 1 < n && data[i + 1] == v)) break; + byte = data[i]; + buffer[size++] = v ^ byte; + } + putchar(size - 1); + fwrite(buffer, 1, size, stdout); + } + } + + fflush(stdout); + free(data); + return 0; +} + +int main(int argc, char *argv[]) { + if (argc < 2) { + fputs("Usage: " PROGRAM_NAME " file... > files.xor\n", stderr); + exit(1); + } + argv++; + argc--; + return compress_files(argv, argc); +} diff --git a/tools/xor_compress.py b/tools/xor_compress.py index 6deb2aa..b3bf317 100644 --- a/tools/xor_compress.py +++ b/tools/xor_compress.py @@ -9,7 +9,7 @@ for filename in sys.argv[1:]: with open(filename, 'rb') as f: data.extend(f.read()) -n = len(data) +n = len(data) output = bytearray() v = 0x00 i = 0 @@ -20,14 +20,14 @@ while i < n: if data[i] == v: # Alternating (>= 0x80) - # Run stops at 0x81 bytes or when the values stop alternating - size = 1 - while i < n and size < 0x81 and data[i] == (v if size % 2 else byte): + # Run stops at 0x80 bytes or when the values stop alternating + size = 0 + while i < n and size < 0x80 and data[i] == (byte if size % 2 else v): size += 1 i += 1 - output.append(size + 0x7e) + output.append(size + 0x7f) output.append(v ^ byte) - if size % 2: + if not size % 2: v = byte else: |