diff --git a/compress.c b/compress.c index 5d322dc..4e77bb8 100644 --- a/compress.c +++ b/compress.c @@ -16,8 +16,8 @@ #endif uint8_t rotate (uint8_t); -rle_t rle_check (uint8_t*, uint8_t*, uint32_t); -backref_t ref_search (uint8_t*, uint8_t*, uint32_t); +rle_t rle_check (uint8_t*, uint8_t*, uint32_t, int); +backref_t ref_search (uint8_t*, uint8_t*, uint32_t, int); uint16_t write_backref (uint8_t*, uint16_t, backref_t); uint16_t write_rle (uint8_t*, uint16_t, rle_t); uint16_t write_raw (uint8_t*, uint16_t, uint8_t*, uint16_t); @@ -26,7 +26,7 @@ uint16_t write_raw (uint8_t*, uint16_t, uint8_t*, uint16_t); // unpacked/packed are 65536 byte buffers to read/from write to, // inputsize is the length of the uncompressed data. // Returns the size of the compressed data in bytes. -size_t pack(uint8_t *unpacked, uint32_t inputsize, uint8_t *packed) { +size_t pack(uint8_t *unpacked, uint32_t inputsize, uint8_t *packed, int fast) { // current input/output positions uint32_t inpos = 0; uint32_t outpos = 0; @@ -43,9 +43,9 @@ size_t pack(uint8_t *unpacked, uint32_t inputsize, uint8_t *packed) { while (inpos < inputsize) { // check for a potential back reference - backref = ref_search(unpacked, unpacked + inpos, inputsize); + backref = ref_search(unpacked, unpacked + inpos, inputsize, fast); // and for a potential RLE - rle = rle_check(unpacked, unpacked + inpos, inputsize); + rle = rle_check(unpacked, unpacked + inpos, inputsize, fast); // if the backref is a better candidate, use it if (backref.size > 3 && backref.size > rle.size) { @@ -183,11 +183,6 @@ size_t unpack(uint8_t *packed, uint8_t *unpacked) { unpacked[outpos++] = unpacked[offset - i]; inpos += 2; - break; - - default: - printf("Error: Unsupported method %i near 0x%06x\n", command, inpos); - exit(-1); } // keep track of how many times each compression method is used @@ -235,10 +230,9 @@ uint8_t rotate (uint8_t i) { } // Searches for possible RLE compressed data. -// Currently only does 8-bit RLE and sequence RLE (since 16-bit can be handled decently -// using the LZ77-like backrefs.) -// start and current are positions within the uncompressed input stream -rle_t rle_check (uint8_t *start, uint8_t *current, uint32_t insize) { +// start and current are positions within the uncompressed input stream. +// fast enables faster compression by ignoring sequence RLE. +rle_t rle_check (uint8_t *start, uint8_t *current, uint32_t insize, int fast) { rle_t candidate = { 0, 0, 0 }; int size; @@ -275,6 +269,9 @@ rle_t rle_check (uint8_t *start, uint8_t *current, uint32_t insize) { debug("\trle_check: found new candidate (size = %d, method = %d)\n", candidate.size, candidate.method); } + // fast mode: don't use sequence RLE + if (fast) return candidate; + // check for possible sequence RLE for (size = 0; current + size < start + insize; size++) if (current[size] != (current[0] + size)) break; @@ -294,8 +291,9 @@ rle_t rle_check (uint8_t *start, uint8_t *current, uint32_t insize) { } // Searches for the best possible back reference. -// start and current are positions within the uncompressed input stream -backref_t ref_search (uint8_t *start, uint8_t *current, uint32_t insize) { +// start and current are positions within the uncompressed input stream. +// fast enables fast mode which only uses regular forward references +backref_t ref_search (uint8_t *start, uint8_t *current, uint32_t insize, int fast) { backref_t candidate = { 0, 0, 0 }; uint16_t size; @@ -316,6 +314,9 @@ backref_t ref_search (uint8_t *start, uint8_t *current, uint32_t insize) { debug("\tref_search: found new candidate (offset: %4x, size: %d, method = %d)\n", candidate.offset, candidate.size, candidate.method); } + // fast mode: forward references only + if (fast) continue; + // now repeat the check with the bit rotation method for (size = 0; size <= LONG_RUN_SIZE && current + size < start + insize; size++) if (pos[size] != rotate(current[size])) break; diff --git a/compress.h b/compress.h index f8201dc..874fd4e 100644 --- a/compress.h +++ b/compress.h @@ -23,7 +23,7 @@ typedef enum { rle_16 = 1, rle_seq = 2, - lz_norm = 0, + lz_norm = 0, lz_rot = 1, lz_rev = 2 } method_e; @@ -40,7 +40,7 @@ typedef struct { method_e method; } rle_t; -size_t pack (uint8_t *unpacked, size_t inputsize, uint8_t *packed); +size_t pack (uint8_t *unpacked, size_t inputsize, uint8_t *packed, int fast); size_t unpack (uint8_t *packed, uint8_t *unpacked); size_t unpack_from_file (FILE *file, unsigned int offset, uint8_t *unpacked); diff --git a/inhal.c b/inhal.c index ec4dcc9..fc7dacb 100644 --- a/inhal.c +++ b/inhal.c @@ -17,14 +17,16 @@ int main (int argc, char **argv) { printf("inhal - %s %s\nby Devin Acker (Revenant)\n\n", __DATE__, __TIME__); - if (argc != 4) { + if (argc < 4) { printf("To insert compressed data into a ROM:\n"); - printf("%s infile romfile offset\n", argv[0]); + printf("%s [-fast] infile romfile offset\n", argv[0]); printf("To write compressed data to a new file:\n"); - printf("%s -n infile outfile\n", argv[0]); + printf("%s [-fast] -n infile outfile\n\n", argv[0]); - printf("\nExample:\n%s test.chr kirbybowl.sfc 0x70000\n", argv[0]); + printf("Running with the -fast switch increases compression speed at the expense of size.\n"); + + printf("\nExample:\n%s -fast test.chr kirbybowl.sfc 0x70000\n", argv[0]); printf("%s -n test.chr test-packed.bin\n\n", argv[0]); printf("offset can be in either decimal or hex.\n"); exit(-1); @@ -32,16 +34,28 @@ int main (int argc, char **argv) { FILE *infile, *outfile; int fileoffset; + int newfile = 0; + int fast = 0; + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-n")) + newfile = 1; + else if (!strcmp(argv[i], "-fast")) + fast = 1; + } + + if (fast) + printf("Fast compression enabled.\n"); + // check for -n switch - if (!strcmp(argv[1], "-n")) { + if (newfile) { fileoffset = 0; - infile = fopen(argv[2], "rb"); - outfile = fopen(argv[3], "wb"); + infile = fopen(argv[argc - 2], "rb"); + outfile = fopen(argv[argc - 1], "wb"); } else { - fileoffset = strtol(argv[3], NULL, 0); - infile = fopen(argv[1], "rb"); - outfile = fopen(argv[2], "r+b"); + fileoffset = strtol(argv[argc - 1], NULL, 0); + infile = fopen(argv[argc - 3], "rb"); + outfile = fopen(argv[argc - 2], "r+b"); } if (!infile) { @@ -74,7 +88,7 @@ int main (int argc, char **argv) { // compress the file clock_t time = clock(); - outputsize = pack(unpacked, inputsize, packed); + outputsize = pack(unpacked, inputsize, packed, fast); time = clock() - time; // write the compressed data to the file