Match LZ compressed files (#724)
Replace lzcomp with new version and match all LZ compressed files
This commit is contained in:
63
tools/lz/repcomp.c
Normal file
63
tools/lz/repcomp.c
Normal file
@@ -0,0 +1,63 @@
|
||||
#include "proto.h"
|
||||
|
||||
/*
|
||||
Repetitions compressor: compresses the data only using a subset of the available repetition commands.
|
||||
Methods defined: 6
|
||||
Flags values: the value plus one is taken as a bitfield indicating which kinds of repetition commands are used
|
||||
(lowest bit to highest: repeat single byte (1), repeat two bytes (2), repeat zeros (3)).
|
||||
*/
|
||||
|
||||
struct command * try_compress_repetitions (const unsigned char * data, __attribute__((unused)) const unsigned char * bitflipped, unsigned short * size, unsigned flags) {
|
||||
unsigned short pos = 0, skipped = 0;
|
||||
struct command * result = malloc(*size * sizeof(struct command));
|
||||
struct command * current = result;
|
||||
struct command candidate;
|
||||
flags = (flags + 1) << 1;
|
||||
while (pos < *size) {
|
||||
candidate = find_repetition_at_position(data, pos, *size);
|
||||
if ((candidate.command == 3) && !(flags & 8)) {
|
||||
candidate.command = 1;
|
||||
candidate.value = 0;
|
||||
}
|
||||
if ((candidate.command == 1) && !(flags & 2)) {
|
||||
candidate.command = 2;
|
||||
candidate.value |= candidate.value << 8;
|
||||
}
|
||||
if ((flags & (1 << candidate.command)) && (command_size(candidate) <= candidate.count)) {
|
||||
if (skipped) *(current ++) = (struct command) {.command = 0, .count = skipped, .value = pos - skipped};
|
||||
skipped = 0;
|
||||
*(current ++) = candidate;
|
||||
pos += candidate.count;
|
||||
} else {
|
||||
pos ++;
|
||||
if ((++ skipped) == MAX_COMMAND_COUNT) {
|
||||
*(current ++) = (struct command) {.command = 0, .count = MAX_COMMAND_COUNT, .value = pos - MAX_COMMAND_COUNT};
|
||||
skipped = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (skipped) *(current ++) = (struct command) {.command = 0, .count = skipped, .value = pos - skipped};
|
||||
*size = current - result;
|
||||
result = realloc(result, *size * sizeof(struct command));
|
||||
return result;
|
||||
}
|
||||
|
||||
struct command find_repetition_at_position (const unsigned char * data, unsigned short position, unsigned short length) {
|
||||
if ((position + 1) >= length) return data[position] ? ((struct command) {.command = 7}) : ((struct command) {.command = 3, .count = 1});
|
||||
unsigned char value[2] = {data[position], data[position + 1]};
|
||||
unsigned repcount, limit = length - position;
|
||||
if (limit > MAX_COMMAND_COUNT) limit = MAX_COMMAND_COUNT;
|
||||
for (repcount = 2; (repcount < limit) && (data[position + repcount] == value[repcount & 1]); repcount ++);
|
||||
struct command result;
|
||||
result.count = repcount;
|
||||
if (*value != value[1]) {
|
||||
if (!*value && (repcount < 3)) return (struct command) {.command = 3, .count = 1};
|
||||
result.command = 2;
|
||||
result.value = ((unsigned) (*value)) | (((unsigned) (value[1])) << 8);
|
||||
} else if (*value) {
|
||||
result.command = 1;
|
||||
result.value = *value;
|
||||
} else
|
||||
result.command = 3;
|
||||
return result;
|
||||
}
|
Reference in New Issue
Block a user