From c771a718b75b01148fc1a24c5a1098de3176e947 Mon Sep 17 00:00:00 2001 From: Connor Olding Date: Sun, 12 Aug 2018 13:25:13 +0200 Subject: [PATCH] greatly simplify compressor loop thanks byuu! --- compressor.c | 150 +++++++++++++++------------------------------------ 1 file changed, 44 insertions(+), 106 deletions(-) diff --git a/compressor.c b/compressor.c index 651233d..0dae6d8 100644 --- a/compressor.c +++ b/compressor.c @@ -1,15 +1,9 @@ -//#include #include #include #include #include typedef unsigned char u8; -typedef unsigned int u32; - -#define MIN(a, b) ((a) <= (b) ? (a) : (b)) -#define MAX(a, b) ((a) >= (b) ? (a) : (b)) -#define PMOD(a, b) (((a) + (b)) % (b)) #ifdef _WIN32 #define FMT_SIZE "%Iu" @@ -31,108 +25,52 @@ typedef unsigned int u32; #define MAX_LEN 66 #define BUF_START 0x3BE -#ifndef RW_OVERLAP -#define RW_OVERLAP 1 -#endif - -long compress(const u8 *bufi, long size, u8 *bufo) { - // this function cannot fail. - // just ensure bufo points to enough memory to hold the compressed data. - u8 buf[BUF_LEN] = {0}; - int buf_i = BUF_START; - - int shift = 0; - int shifted = 0; - int last_shift_i = -1; - long written = 0; - +int compress(const u8 *bufi, int size, u8 *bufo) { int i = 0; + int written = 0; while (i < size) { - const u8 *sub = bufi + i; - int sub_len = MIN(MAX_LEN, size - i); - int best_i = -1; - int best_len = -1; + int flag_i = written; + int flags = 0x00; + bufo[written++] = 0; - if (sub_len >= MIN_LEN) { - for (int j = 0; j < BUF_LEN; j++) { - int match_i = PMOD(buf_i - j, BUF_LEN); - int match_len = 0; -#if RW_OVERLAP - int overlap = 0; -#endif - for (;;) { - int buf_off = (match_i + match_len) % BUF_LEN; -#if RW_OVERLAP - if (overlap > 0 || (buf_off == buf_i && j != 0)) { - if (sub[overlap % j] != sub[match_len]) break; - overlap++; - } else { - if (buf[buf_off] != sub[match_len]) break; - } -#else - if (buf_off == buf_i && j != 0) break; - if (buf[buf_off] != sub[match_len]) break; -#endif - match_len++; - if (match_len == MAX_LEN) break; - if (match_len == sub_len) break; - } + for (int j = 0; j < 8; j++) { + if (i == size) break; + int best_match = 0; + int best_len = 0; - if (match_len < MIN_LEN) continue; - if (match_len > best_len) { - best_i = match_i; - best_len = match_len; + for (int match = BUF_LEN; match > 0; match--) { + int len = 0; + int left = i - match; + int right = i; + while (bufi[left++] == bufi[right++]) { + if (left == i) left -= match; + len++; + if (right >= size) break; + if (len >= MAX_LEN) break; } + if (len > best_len) { + best_len = len; + best_match = match; + if (len == MAX_LEN) break; + } + } + + if (best_len < MIN_LEN) { + flags |= 1 << j; + bufo[written++] = bufi[i++]; + } else { + int buf_match = (i + BUF_START - best_match) & 0x3FF; + //lament("$%03X:%i\n", buf_match, best_len); + int a = buf_match & 0xFF; + int b = ((buf_match & 0x300) >> 2) | (best_len - 3); + bufo[written++] = a; + bufo[written++] = b; + i += best_len; } } - if (last_shift_i < 0) { - last_shift_i = written; - bufo[written++] = 0; - shift = 0; - shifted = 0; - } - - if (best_i < 0 || best_len < 0) { - shift >>= 1; - shift |= 0x80; - shifted++; - - bufo[written++] = sub[0]; - buf[buf_i] = sub[0]; - buf_i = (buf_i + 1) % BUF_LEN; - i++; - } else { - shift >>= 1; - shifted++; - - u8 a = best_i & 0xFF; - u8 b = ((best_i & 0x300) >> 2) | (best_len - 3); - bufo[written++] = a; - bufo[written++] = b; - - for (int j = 0; j < best_len; j++) { - buf[buf_i] = sub[j]; - buf_i = (buf_i + 1) % BUF_LEN; - } - i += best_len; - } - - if (shifted >= 8) { - //assert(last_shift_i != -1); - bufo[last_shift_i] = shift; - shift = 0; - shifted = 0; - last_shift_i = -1; - } + bufo[flag_i] = flags; } - - if (last_shift_i >= 0) { - bufo[last_shift_i] = shift >> (8 - shifted); - } - - //assert(i == size); - return written; } @@ -155,9 +93,10 @@ int compress_file(const char *fp) { error_when(fseek(f, 0, SEEK_SET) != 0, "Error seeking in file: %s", fp); if (size > 0) { - bufi = (u8 *)malloc(size); - error_when(bufi == NULL, "Error allocating %li bytes", size); - error_when(fread(bufi, 1, size, f) != (size_t)size, "Error reading %li bytes from file: %s", size, fp); + bufi = (u8 *)malloc(size + BUF_LEN); + for (int i = 0; i < BUF_LEN; i++) bufi[i] = 0; + error_when(bufi == NULL, "Error allocating %li bytes", size + BUF_LEN); + error_when(fread(bufi + BUF_LEN, 1, size, f) != (size_t)size, "Error reading %li bytes from file: %s", size, fp); } error_when(fclose(f) != 0, "Error closing file: %s", fp); @@ -167,9 +106,7 @@ int compress_file(const char *fp) { size_t bufo_size = size * 9 / 8 + 8; bufo = (u8 *)malloc(bufo_size); error_when(bufo == NULL, "Error allocating " FMT_SIZE " bytes", bufo_size); - - new_size = compress(bufi, size, bufo); - //assert(new_size > 0 && (size_t)new_size < bufo_size); + new_size = compress(bufi + BUF_LEN, size, bufo); } f = fopen(fp, "wb"); @@ -204,7 +141,8 @@ int main(int argc, char *argv[]) { } const char *name = argv[0]; if (argc == 1) { - lament("compressor: compress files in-place for Bomberman 64.\n"); + lament("compressor: compress files in-place with LZSS\n"); + lament("compatible with Bomberman 64 and Mario Party 1\n"); lament("usage: %s {file}\n", name); return 1; } else if (argc == 2) {