greatly simplify compressor loop
thanks byuu!
This commit is contained in:
parent
155682e209
commit
c771a718b7
1 changed files with 44 additions and 106 deletions
150
compressor.c
150
compressor.c
|
@ -1,15 +1,9 @@
|
|||
//#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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) {
|
||||
|
|
Loading…
Reference in a new issue