add "fast" compression mode
This commit is contained in:
parent
b19637c39a
commit
c9e004e18b
3 changed files with 44 additions and 29 deletions
33
compress.c
33
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;
|
||||
|
|
|
@ -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);
|
||||
|
|
36
inhal.c
36
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
|
||||
|
|
Loading…
Reference in a new issue