summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--gfx/gfx.mk12
-rw-r--r--tools/scan_includes.c2
-rw-r--r--tools/tools.mk9
-rw-r--r--tools/xor_compress.c115
-rw-r--r--tools/xor_compress.py12
6 files changed, 137 insertions, 14 deletions
diff --git a/.gitignore b/.gitignore
index aac1c0f..e48f237 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,3 +12,4 @@ __pycache__
/coverage.png
/picross.png
tools/scan_includes
+tools/xor_compress
diff --git a/gfx/gfx.mk b/gfx/gfx.mk
index 2299205..377df8f 100644
--- a/gfx/gfx.mk
+++ b/gfx/gfx.mk
@@ -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: