|
|
@ -4,16 +4,16 @@ |
|
|
|
#include "heatshrink_encoder.h" |
|
|
|
#include "heatshrink_encoder.h" |
|
|
|
|
|
|
|
|
|
|
|
typedef enum { |
|
|
|
typedef enum { |
|
|
|
HSES_NOT_FULL, /* input buffer not full enough */ |
|
|
|
HSES_NOT_FULL, /* input buffer not full enough */ |
|
|
|
HSES_FILLED, /* buffer is full */ |
|
|
|
HSES_FILLED, /* buffer is full */ |
|
|
|
HSES_SEARCH, /* searching for patterns */ |
|
|
|
HSES_SEARCH, /* searching for patterns */ |
|
|
|
HSES_YIELD_TAG_BIT, /* yield tag bit */ |
|
|
|
HSES_YIELD_TAG_BIT, /* yield tag bit */ |
|
|
|
HSES_YIELD_LITERAL, /* emit literal byte */ |
|
|
|
HSES_YIELD_LITERAL, /* emit literal byte */ |
|
|
|
HSES_YIELD_BR_INDEX, /* yielding backref index */ |
|
|
|
HSES_YIELD_BR_INDEX, /* yielding backref index */ |
|
|
|
HSES_YIELD_BR_LENGTH, /* yielding backref length */ |
|
|
|
HSES_YIELD_BR_LENGTH, /* yielding backref length */ |
|
|
|
HSES_SAVE_BACKLOG, /* copying buffer to backlog */ |
|
|
|
HSES_SAVE_BACKLOG, /* copying buffer to backlog */ |
|
|
|
HSES_FLUSH_BITS, /* flush bit buffer */ |
|
|
|
HSES_FLUSH_BITS, /* flush bit buffer */ |
|
|
|
HSES_DONE, /* done */ |
|
|
|
HSES_DONE, /* done */ |
|
|
|
} HSE_state; |
|
|
|
} HSE_state; |
|
|
|
|
|
|
|
|
|
|
|
#if HEATSHRINK_DEBUGGING_LOGS |
|
|
|
#if HEATSHRINK_DEBUGGING_LOGS |
|
|
@ -41,34 +41,44 @@ static const char *state_names[] = { |
|
|
|
|
|
|
|
|
|
|
|
// Encoder flags
|
|
|
|
// Encoder flags
|
|
|
|
enum { |
|
|
|
enum { |
|
|
|
FLAG_IS_FINISHING = 0x01, |
|
|
|
FLAG_IS_FINISHING = 0x01, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
typedef struct { |
|
|
|
uint8_t *buf; /* output buffer */ |
|
|
|
uint8_t *buf; /* output buffer */ |
|
|
|
size_t buf_size; /* buffer size */ |
|
|
|
size_t buf_size; /* buffer size */ |
|
|
|
size_t *output_size; /* bytes pushed to buffer, so far */ |
|
|
|
size_t *output_size; /* bytes pushed to buffer, so far */ |
|
|
|
} output_info; |
|
|
|
} output_info; |
|
|
|
|
|
|
|
|
|
|
|
#define MATCH_NOT_FOUND ((uint16_t)-1) |
|
|
|
#define MATCH_NOT_FOUND ((uint16_t)-1) |
|
|
|
|
|
|
|
|
|
|
|
static uint16_t get_input_offset(heatshrink_encoder *hse); |
|
|
|
static uint16_t get_input_offset(heatshrink_encoder *hse); |
|
|
|
|
|
|
|
|
|
|
|
static uint16_t get_input_buffer_size(heatshrink_encoder *hse); |
|
|
|
static uint16_t get_input_buffer_size(heatshrink_encoder *hse); |
|
|
|
|
|
|
|
|
|
|
|
static uint16_t get_lookahead_size(heatshrink_encoder *hse); |
|
|
|
static uint16_t get_lookahead_size(heatshrink_encoder *hse); |
|
|
|
|
|
|
|
|
|
|
|
static void add_tag_bit(heatshrink_encoder *hse, output_info *oi, uint8_t tag); |
|
|
|
static void add_tag_bit(heatshrink_encoder *hse, output_info *oi, uint8_t tag); |
|
|
|
|
|
|
|
|
|
|
|
static int can_take_byte(output_info *oi); |
|
|
|
static int can_take_byte(output_info *oi); |
|
|
|
|
|
|
|
|
|
|
|
static int is_finishing(heatshrink_encoder *hse); |
|
|
|
static int is_finishing(heatshrink_encoder *hse); |
|
|
|
|
|
|
|
|
|
|
|
static void save_backlog(heatshrink_encoder *hse); |
|
|
|
static void save_backlog(heatshrink_encoder *hse); |
|
|
|
|
|
|
|
|
|
|
|
/* Push COUNT (max 8) bits to the output buffer, which has room. */ |
|
|
|
/* Push COUNT (max 8) bits to the output buffer, which has room. */ |
|
|
|
static void push_bits(heatshrink_encoder *hse, uint8_t count, uint8_t bits, |
|
|
|
static void push_bits(heatshrink_encoder *hse, uint8_t count, uint8_t bits, |
|
|
|
output_info *oi); |
|
|
|
output_info *oi); |
|
|
|
|
|
|
|
|
|
|
|
static uint8_t push_outgoing_bits(heatshrink_encoder *hse, output_info *oi); |
|
|
|
static uint8_t push_outgoing_bits(heatshrink_encoder *hse, output_info *oi); |
|
|
|
|
|
|
|
|
|
|
|
static void push_literal_byte(heatshrink_encoder *hse, output_info *oi); |
|
|
|
static void push_literal_byte(heatshrink_encoder *hse, output_info *oi); |
|
|
|
|
|
|
|
|
|
|
|
#if HEATSHRINK_DYNAMIC_ALLOC |
|
|
|
#if HEATSHRINK_DYNAMIC_ALLOC |
|
|
|
|
|
|
|
|
|
|
|
heatshrink_encoder *heatshrink_encoder_alloc(uint8_t window_sz2, |
|
|
|
heatshrink_encoder *heatshrink_encoder_alloc(uint8_t window_sz2, |
|
|
|
uint8_t lookahead_sz2) { |
|
|
|
uint8_t lookahead_sz2) |
|
|
|
|
|
|
|
{ |
|
|
|
if ((window_sz2 < HEATSHRINK_MIN_WINDOW_BITS) || |
|
|
|
if ((window_sz2 < HEATSHRINK_MIN_WINDOW_BITS) || |
|
|
|
(window_sz2 > HEATSHRINK_MAX_WINDOW_BITS) || |
|
|
|
(window_sz2 > HEATSHRINK_MAX_WINDOW_BITS) || |
|
|
|
(lookahead_sz2 < HEATSHRINK_MIN_LOOKAHEAD_BITS) || |
|
|
|
(lookahead_sz2 < HEATSHRINK_MIN_LOOKAHEAD_BITS) || |
|
|
@ -89,13 +99,13 @@ heatshrink_encoder *heatshrink_encoder_alloc(uint8_t window_sz2, |
|
|
|
heatshrink_encoder_reset(hse); |
|
|
|
heatshrink_encoder_reset(hse); |
|
|
|
|
|
|
|
|
|
|
|
#if HEATSHRINK_USE_INDEX |
|
|
|
#if HEATSHRINK_USE_INDEX |
|
|
|
size_t index_sz = buf_sz*sizeof(uint16_t); |
|
|
|
size_t index_sz = buf_sz * sizeof(uint16_t); |
|
|
|
hse->search_index = HEATSHRINK_MALLOC(index_sz + sizeof(struct hs_index)); |
|
|
|
hse->search_index = HEATSHRINK_MALLOC(index_sz + sizeof(struct hs_index)); |
|
|
|
if (hse->search_index == NULL) { |
|
|
|
if (hse->search_index == NULL) { |
|
|
|
HEATSHRINK_FREE(hse, sizeof(*hse) + buf_sz); |
|
|
|
HEATSHRINK_FREE(hse, sizeof(*hse) + buf_sz); |
|
|
|
return NULL; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
hse->search_index->size = (uint16_t)index_sz; |
|
|
|
hse->search_index->size = (uint16_t) index_sz; |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
LOG("-- allocated encoder with buffer size of %zu (%u byte input size)\n", |
|
|
|
LOG("-- allocated encoder with buffer size of %zu (%u byte input size)\n", |
|
|
@ -103,19 +113,22 @@ heatshrink_encoder *heatshrink_encoder_alloc(uint8_t window_sz2, |
|
|
|
return hse; |
|
|
|
return hse; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void heatshrink_encoder_free(heatshrink_encoder *hse) { |
|
|
|
void heatshrink_encoder_free(heatshrink_encoder *hse) |
|
|
|
|
|
|
|
{ |
|
|
|
size_t buf_sz = (2U << HEATSHRINK_ENCODER_WINDOW_BITS(hse)); |
|
|
|
size_t buf_sz = (2U << HEATSHRINK_ENCODER_WINDOW_BITS(hse)); |
|
|
|
#if HEATSHRINK_USE_INDEX |
|
|
|
#if HEATSHRINK_USE_INDEX |
|
|
|
size_t index_sz = sizeof(struct hs_index) + hse->search_index->size; |
|
|
|
size_t index_sz = sizeof(struct hs_index) + hse->search_index->size; |
|
|
|
HEATSHRINK_FREE(hse->search_index, index_sz); |
|
|
|
HEATSHRINK_FREE(hse->search_index, index_sz); |
|
|
|
(void)index_sz; |
|
|
|
(void) index_sz; |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
HEATSHRINK_FREE(hse, sizeof(heatshrink_encoder) + buf_sz); |
|
|
|
HEATSHRINK_FREE(hse, sizeof(heatshrink_encoder) + buf_sz); |
|
|
|
(void)buf_sz; |
|
|
|
(void) buf_sz; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
void heatshrink_encoder_reset(heatshrink_encoder *hse) { |
|
|
|
void heatshrink_encoder_reset(heatshrink_encoder *hse) |
|
|
|
|
|
|
|
{ |
|
|
|
size_t buf_sz = (2U << HEATSHRINK_ENCODER_WINDOW_BITS(hse)); |
|
|
|
size_t buf_sz = (2U << HEATSHRINK_ENCODER_WINDOW_BITS(hse)); |
|
|
|
memset(hse->buffer, 0, buf_sz); |
|
|
|
memset(hse->buffer, 0, buf_sz); |
|
|
|
hse->input_size = 0; |
|
|
|
hse->input_size = 0; |
|
|
@ -129,13 +142,14 @@ void heatshrink_encoder_reset(heatshrink_encoder *hse) { |
|
|
|
hse->outgoing_bits = 0x0000; |
|
|
|
hse->outgoing_bits = 0x0000; |
|
|
|
hse->outgoing_bits_count = 0; |
|
|
|
hse->outgoing_bits_count = 0; |
|
|
|
|
|
|
|
|
|
|
|
#ifdef LOOP_DETECT |
|
|
|
#ifdef LOOP_DETECT |
|
|
|
hse->loop_detect = (uint32_t)-1; |
|
|
|
hse->loop_detect = (uint32_t)-1; |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
HSE_sink_res heatshrink_encoder_sink(heatshrink_encoder *hse, |
|
|
|
HSE_sink_res heatshrink_encoder_sink(heatshrink_encoder *hse, |
|
|
|
const uint8_t *in_buf, size_t size, size_t *input_size) { |
|
|
|
const uint8_t *in_buf, size_t size, size_t *input_size) |
|
|
|
|
|
|
|
{ |
|
|
|
if ((hse == NULL) || (in_buf == NULL) || (input_size == NULL)) { |
|
|
|
if ((hse == NULL) || (in_buf == NULL) || (input_size == NULL)) { |
|
|
|
return HSER_SINK_ERROR_NULL; |
|
|
|
return HSER_SINK_ERROR_NULL; |
|
|
|
} |
|
|
|
} |
|
|
@ -149,7 +163,7 @@ HSE_sink_res heatshrink_encoder_sink(heatshrink_encoder *hse, |
|
|
|
uint16_t write_offset = get_input_offset(hse) + hse->input_size; |
|
|
|
uint16_t write_offset = get_input_offset(hse) + hse->input_size; |
|
|
|
uint16_t ibs = get_input_buffer_size(hse); |
|
|
|
uint16_t ibs = get_input_buffer_size(hse); |
|
|
|
uint16_t rem = ibs - hse->input_size; |
|
|
|
uint16_t rem = ibs - hse->input_size; |
|
|
|
uint16_t cp_sz = rem < size ? rem : (uint16_t)size; |
|
|
|
uint16_t cp_sz = rem < size ? rem : (uint16_t) size; |
|
|
|
|
|
|
|
|
|
|
|
memcpy(&hse->buffer[write_offset], in_buf, cp_sz); |
|
|
|
memcpy(&hse->buffer[write_offset], in_buf, cp_sz); |
|
|
|
*input_size = cp_sz; |
|
|
|
*input_size = cp_sz; |
|
|
@ -171,24 +185,32 @@ HSE_sink_res heatshrink_encoder_sink(heatshrink_encoder *hse, |
|
|
|
***************/ |
|
|
|
***************/ |
|
|
|
|
|
|
|
|
|
|
|
static uint16_t find_longest_match(heatshrink_encoder *hse, uint16_t start, |
|
|
|
static uint16_t find_longest_match(heatshrink_encoder *hse, uint16_t start, |
|
|
|
uint16_t end, const uint16_t maxlen, uint16_t *match_length); |
|
|
|
uint16_t end, const uint16_t maxlen, uint16_t *match_length); |
|
|
|
|
|
|
|
|
|
|
|
static void do_indexing(heatshrink_encoder *hse); |
|
|
|
static void do_indexing(heatshrink_encoder *hse); |
|
|
|
|
|
|
|
|
|
|
|
static HSE_state st_step_search(heatshrink_encoder *hse); |
|
|
|
static HSE_state st_step_search(heatshrink_encoder *hse); |
|
|
|
|
|
|
|
|
|
|
|
static HSE_state st_yield_tag_bit(heatshrink_encoder *hse, |
|
|
|
static HSE_state st_yield_tag_bit(heatshrink_encoder *hse, |
|
|
|
output_info *oi); |
|
|
|
output_info *oi); |
|
|
|
|
|
|
|
|
|
|
|
static HSE_state st_yield_literal(heatshrink_encoder *hse, |
|
|
|
static HSE_state st_yield_literal(heatshrink_encoder *hse, |
|
|
|
output_info *oi); |
|
|
|
output_info *oi); |
|
|
|
|
|
|
|
|
|
|
|
static HSE_state st_yield_br_index(heatshrink_encoder *hse, |
|
|
|
static HSE_state st_yield_br_index(heatshrink_encoder *hse, |
|
|
|
output_info *oi); |
|
|
|
output_info *oi); |
|
|
|
|
|
|
|
|
|
|
|
static HSE_state st_yield_br_length(heatshrink_encoder *hse, |
|
|
|
static HSE_state st_yield_br_length(heatshrink_encoder *hse, |
|
|
|
output_info *oi); |
|
|
|
output_info *oi); |
|
|
|
|
|
|
|
|
|
|
|
static HSE_state st_save_backlog(heatshrink_encoder *hse); |
|
|
|
static HSE_state st_save_backlog(heatshrink_encoder *hse); |
|
|
|
|
|
|
|
|
|
|
|
static HSE_state st_flush_bit_buffer(heatshrink_encoder *hse, |
|
|
|
static HSE_state st_flush_bit_buffer(heatshrink_encoder *hse, |
|
|
|
output_info *oi); |
|
|
|
output_info *oi); |
|
|
|
|
|
|
|
|
|
|
|
HSE_poll_res heatshrink_encoder_poll(heatshrink_encoder *hse, |
|
|
|
HSE_poll_res heatshrink_encoder_poll(heatshrink_encoder *hse, |
|
|
|
uint8_t *out_buf, size_t out_buf_size, size_t *output_size) { |
|
|
|
uint8_t *out_buf, size_t out_buf_size, size_t *output_size) |
|
|
|
|
|
|
|
{ |
|
|
|
if ((hse == NULL) || (out_buf == NULL) || (output_size == NULL)) { |
|
|
|
if ((hse == NULL) || (out_buf == NULL) || (output_size == NULL)) { |
|
|
|
return HSER_POLL_ERROR_NULL; |
|
|
|
return HSER_POLL_ERROR_NULL; |
|
|
|
} |
|
|
|
} |
|
|
@ -211,49 +233,50 @@ HSE_poll_res heatshrink_encoder_poll(heatshrink_encoder *hse, |
|
|
|
HSE_state next_state; |
|
|
|
HSE_state next_state; |
|
|
|
|
|
|
|
|
|
|
|
switch (in_state) { |
|
|
|
switch (in_state) { |
|
|
|
case HSES_NOT_FULL: |
|
|
|
case HSES_NOT_FULL: |
|
|
|
return HSER_POLL_EMPTY; |
|
|
|
return HSER_POLL_EMPTY; |
|
|
|
case HSES_FILLED: |
|
|
|
case HSES_FILLED: |
|
|
|
do_indexing(hse); |
|
|
|
do_indexing(hse); |
|
|
|
next_state = HSES_SEARCH; |
|
|
|
next_state = HSES_SEARCH; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case HSES_SEARCH: |
|
|
|
case HSES_SEARCH: |
|
|
|
next_state = st_step_search(hse); |
|
|
|
next_state = st_step_search(hse); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case HSES_YIELD_TAG_BIT: |
|
|
|
case HSES_YIELD_TAG_BIT: |
|
|
|
next_state = st_yield_tag_bit(hse, &oi); |
|
|
|
next_state = st_yield_tag_bit(hse, &oi); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case HSES_YIELD_LITERAL: |
|
|
|
case HSES_YIELD_LITERAL: |
|
|
|
next_state = st_yield_literal(hse, &oi); |
|
|
|
next_state = st_yield_literal(hse, &oi); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case HSES_YIELD_BR_INDEX: |
|
|
|
case HSES_YIELD_BR_INDEX: |
|
|
|
next_state = st_yield_br_index(hse, &oi); |
|
|
|
next_state = st_yield_br_index(hse, &oi); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case HSES_YIELD_BR_LENGTH: |
|
|
|
case HSES_YIELD_BR_LENGTH: |
|
|
|
next_state = st_yield_br_length(hse, &oi); |
|
|
|
next_state = st_yield_br_length(hse, &oi); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case HSES_SAVE_BACKLOG: |
|
|
|
case HSES_SAVE_BACKLOG: |
|
|
|
next_state = st_save_backlog(hse); |
|
|
|
next_state = st_save_backlog(hse); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case HSES_FLUSH_BITS: |
|
|
|
case HSES_FLUSH_BITS: |
|
|
|
hse->state = (uint8_t)st_flush_bit_buffer(hse, &oi); |
|
|
|
hse->state = (uint8_t) st_flush_bit_buffer(hse, &oi); |
|
|
|
return HSER_POLL_EMPTY; |
|
|
|
return HSER_POLL_EMPTY; |
|
|
|
case HSES_DONE: |
|
|
|
case HSES_DONE: |
|
|
|
return HSER_POLL_EMPTY; |
|
|
|
return HSER_POLL_EMPTY; |
|
|
|
default: |
|
|
|
default: |
|
|
|
LOG("-- bad state %s\n", state_names[hse->state]); |
|
|
|
LOG("-- bad state %s\n", state_names[hse->state]); |
|
|
|
return HSER_POLL_ERROR_MISUSE; |
|
|
|
return HSER_POLL_ERROR_MISUSE; |
|
|
|
} |
|
|
|
} |
|
|
|
hse->state = (uint8_t)next_state; |
|
|
|
hse->state = (uint8_t) next_state; |
|
|
|
|
|
|
|
|
|
|
|
if (hse->state == in_state) { |
|
|
|
if (hse->state == in_state) { |
|
|
|
/* Check if output buffer is exhausted. */ |
|
|
|
/* Check if output buffer is exhausted. */ |
|
|
|
if (*output_size == out_buf_size) return HSER_POLL_MORE; |
|
|
|
if (*output_size == out_buf_size) { return HSER_POLL_MORE; } |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
HSE_finish_res heatshrink_encoder_finish(heatshrink_encoder *hse) { |
|
|
|
HSE_finish_res heatshrink_encoder_finish(heatshrink_encoder *hse) |
|
|
|
|
|
|
|
{ |
|
|
|
if (hse == NULL) { return HSER_FINISH_ERROR_NULL; } |
|
|
|
if (hse == NULL) { return HSER_FINISH_ERROR_NULL; } |
|
|
|
LOG("-- setting is_finishing flag\n"); |
|
|
|
LOG("-- setting is_finishing flag\n"); |
|
|
|
hse->flags |= FLAG_IS_FINISHING; |
|
|
|
hse->flags |= FLAG_IS_FINISHING; |
|
|
@ -261,12 +284,13 @@ HSE_finish_res heatshrink_encoder_finish(heatshrink_encoder *hse) { |
|
|
|
return hse->state == HSES_DONE ? HSER_FINISH_DONE : HSER_FINISH_MORE; |
|
|
|
return hse->state == HSES_DONE ? HSER_FINISH_DONE : HSER_FINISH_MORE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static HSE_state st_step_search(heatshrink_encoder *hse) { |
|
|
|
static HSE_state st_step_search(heatshrink_encoder *hse) |
|
|
|
|
|
|
|
{ |
|
|
|
uint16_t window_length = get_input_buffer_size(hse); |
|
|
|
uint16_t window_length = get_input_buffer_size(hse); |
|
|
|
uint16_t lookahead_sz = get_lookahead_size(hse); |
|
|
|
uint16_t lookahead_sz = get_lookahead_size(hse); |
|
|
|
uint16_t msi = hse->match_scan_index; |
|
|
|
uint16_t msi = hse->match_scan_index; |
|
|
|
LOG("## step_search, scan @ +%d (%d/%d), input size %d\n", |
|
|
|
LOG("## step_search, scan @ +%d (%d/%d), input size %d\n", |
|
|
|
msi, hse->input_size + msi, 2*window_length, hse->input_size); |
|
|
|
msi, hse->input_size + msi, 2 * window_length, hse->input_size); |
|
|
|
|
|
|
|
|
|
|
|
bool fin = is_finishing(hse); |
|
|
|
bool fin = is_finishing(hse); |
|
|
|
if (msi > hse->input_size - (fin ? 1 : lookahead_sz)) { |
|
|
|
if (msi > hse->input_size - (fin ? 1 : lookahead_sz)) { |
|
|
@ -287,7 +311,7 @@ static HSE_state st_step_search(heatshrink_encoder *hse) { |
|
|
|
|
|
|
|
|
|
|
|
uint16_t match_length = 0; |
|
|
|
uint16_t match_length = 0; |
|
|
|
uint16_t match_pos = find_longest_match(hse, |
|
|
|
uint16_t match_pos = find_longest_match(hse, |
|
|
|
start, end, max_possible, &match_length); |
|
|
|
start, end, max_possible, &match_length); |
|
|
|
|
|
|
|
|
|
|
|
if (match_pos == MATCH_NOT_FOUND) { |
|
|
|
if (match_pos == MATCH_NOT_FOUND) { |
|
|
|
LOG("ss Match not found\n"); |
|
|
|
LOG("ss Match not found\n"); |
|
|
@ -305,7 +329,8 @@ static HSE_state st_step_search(heatshrink_encoder *hse) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static HSE_state st_yield_tag_bit(heatshrink_encoder *hse, |
|
|
|
static HSE_state st_yield_tag_bit(heatshrink_encoder *hse, |
|
|
|
output_info *oi) { |
|
|
|
output_info *oi) |
|
|
|
|
|
|
|
{ |
|
|
|
if (can_take_byte(oi)) { |
|
|
|
if (can_take_byte(oi)) { |
|
|
|
if (hse->match_length == 0) { |
|
|
|
if (hse->match_length == 0) { |
|
|
|
add_tag_bit(hse, oi, HEATSHRINK_LITERAL_MARKER); |
|
|
|
add_tag_bit(hse, oi, HEATSHRINK_LITERAL_MARKER); |
|
|
@ -322,7 +347,8 @@ static HSE_state st_yield_tag_bit(heatshrink_encoder *hse, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static HSE_state st_yield_literal(heatshrink_encoder *hse, |
|
|
|
static HSE_state st_yield_literal(heatshrink_encoder *hse, |
|
|
|
output_info *oi) { |
|
|
|
output_info *oi) |
|
|
|
|
|
|
|
{ |
|
|
|
if (can_take_byte(oi)) { |
|
|
|
if (can_take_byte(oi)) { |
|
|
|
push_literal_byte(hse, oi); |
|
|
|
push_literal_byte(hse, oi); |
|
|
|
return HSES_SEARCH; |
|
|
|
return HSES_SEARCH; |
|
|
@ -332,7 +358,8 @@ static HSE_state st_yield_literal(heatshrink_encoder *hse, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static HSE_state st_yield_br_index(heatshrink_encoder *hse, |
|
|
|
static HSE_state st_yield_br_index(heatshrink_encoder *hse, |
|
|
|
output_info *oi) { |
|
|
|
output_info *oi) |
|
|
|
|
|
|
|
{ |
|
|
|
if (can_take_byte(oi)) { |
|
|
|
if (can_take_byte(oi)) { |
|
|
|
LOG("-- yielding backref index %u\n", hse->match_pos); |
|
|
|
LOG("-- yielding backref index %u\n", hse->match_pos); |
|
|
|
if (push_outgoing_bits(hse, oi) > 0) { |
|
|
|
if (push_outgoing_bits(hse, oi) > 0) { |
|
|
@ -348,7 +375,8 @@ static HSE_state st_yield_br_index(heatshrink_encoder *hse, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static HSE_state st_yield_br_length(heatshrink_encoder *hse, |
|
|
|
static HSE_state st_yield_br_length(heatshrink_encoder *hse, |
|
|
|
output_info *oi) { |
|
|
|
output_info *oi) |
|
|
|
|
|
|
|
{ |
|
|
|
if (can_take_byte(oi)) { |
|
|
|
if (can_take_byte(oi)) { |
|
|
|
LOG("-- yielding backref length %u\n", hse->match_length); |
|
|
|
LOG("-- yielding backref length %u\n", hse->match_length); |
|
|
|
if (push_outgoing_bits(hse, oi) > 0) { |
|
|
|
if (push_outgoing_bits(hse, oi) > 0) { |
|
|
@ -363,14 +391,16 @@ static HSE_state st_yield_br_length(heatshrink_encoder *hse, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static HSE_state st_save_backlog(heatshrink_encoder *hse) { |
|
|
|
static HSE_state st_save_backlog(heatshrink_encoder *hse) |
|
|
|
|
|
|
|
{ |
|
|
|
LOG("-- saving backlog\n"); |
|
|
|
LOG("-- saving backlog\n"); |
|
|
|
save_backlog(hse); |
|
|
|
save_backlog(hse); |
|
|
|
return HSES_NOT_FULL; |
|
|
|
return HSES_NOT_FULL; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static HSE_state st_flush_bit_buffer(heatshrink_encoder *hse, |
|
|
|
static HSE_state st_flush_bit_buffer(heatshrink_encoder *hse, |
|
|
|
output_info *oi) { |
|
|
|
output_info *oi) |
|
|
|
|
|
|
|
{ |
|
|
|
if (hse->bit_index == 0x80) { |
|
|
|
if (hse->bit_index == 0x80) { |
|
|
|
LOG("-- done!\n"); |
|
|
|
LOG("-- done!\n"); |
|
|
|
return HSES_DONE; |
|
|
|
return HSES_DONE; |
|
|
@ -384,26 +414,31 @@ static HSE_state st_flush_bit_buffer(heatshrink_encoder *hse, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void add_tag_bit(heatshrink_encoder *hse, output_info *oi, uint8_t tag) { |
|
|
|
static void add_tag_bit(heatshrink_encoder *hse, output_info *oi, uint8_t tag) |
|
|
|
|
|
|
|
{ |
|
|
|
LOG("-- adding tag bit: %d\n", tag); |
|
|
|
LOG("-- adding tag bit: %d\n", tag); |
|
|
|
push_bits(hse, 1, tag, oi); |
|
|
|
push_bits(hse, 1, tag, oi); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static uint16_t get_input_offset(heatshrink_encoder *hse) { |
|
|
|
static uint16_t get_input_offset(heatshrink_encoder *hse) |
|
|
|
|
|
|
|
{ |
|
|
|
return get_input_buffer_size(hse); |
|
|
|
return get_input_buffer_size(hse); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static uint16_t get_input_buffer_size(heatshrink_encoder *hse) { |
|
|
|
static uint16_t get_input_buffer_size(heatshrink_encoder *hse) |
|
|
|
(void)hse; |
|
|
|
{ |
|
|
|
return (uint16_t)(1U << HEATSHRINK_ENCODER_WINDOW_BITS(hse)); |
|
|
|
(void) hse; |
|
|
|
|
|
|
|
return (uint16_t) (1U << HEATSHRINK_ENCODER_WINDOW_BITS(hse)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static uint16_t get_lookahead_size(heatshrink_encoder *hse) { |
|
|
|
static uint16_t get_lookahead_size(heatshrink_encoder *hse) |
|
|
|
(void)hse; |
|
|
|
{ |
|
|
|
return (uint16_t)(1U << HEATSHRINK_ENCODER_LOOKAHEAD_BITS(hse)); |
|
|
|
(void) hse; |
|
|
|
|
|
|
|
return (uint16_t) (1U << HEATSHRINK_ENCODER_LOOKAHEAD_BITS(hse)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void do_indexing(heatshrink_encoder *hse) { |
|
|
|
static void do_indexing(heatshrink_encoder *hse) |
|
|
|
|
|
|
|
{ |
|
|
|
#if HEATSHRINK_USE_INDEX |
|
|
|
#if HEATSHRINK_USE_INDEX |
|
|
|
/* Build an index array I that contains flattened linked lists
|
|
|
|
/* Build an index array I that contains flattened linked lists
|
|
|
|
* for the previous instances of every byte in the buffer. |
|
|
|
* for the previous instances of every byte in the buffer. |
|
|
@ -425,8 +460,8 @@ static void do_indexing(heatshrink_encoder *hse) { |
|
|
|
int16_t last[256]; |
|
|
|
int16_t last[256]; |
|
|
|
memset(last, 0xFF, sizeof(last)); |
|
|
|
memset(last, 0xFF, sizeof(last)); |
|
|
|
|
|
|
|
|
|
|
|
uint8_t * const data = hse->buffer; |
|
|
|
uint8_t *const data = hse->buffer; |
|
|
|
int16_t * const index = hsi->index; |
|
|
|
int16_t *const index = hsi->index; |
|
|
|
|
|
|
|
|
|
|
|
const uint16_t input_offset = get_input_offset(hse); |
|
|
|
const uint16_t input_offset = get_input_offset(hse); |
|
|
|
const uint16_t end = input_offset + hse->input_size; |
|
|
|
const uint16_t end = input_offset + hse->input_size; |
|
|
@ -442,18 +477,21 @@ static void do_indexing(heatshrink_encoder *hse) { |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int is_finishing(heatshrink_encoder *hse) { |
|
|
|
static int is_finishing(heatshrink_encoder *hse) |
|
|
|
|
|
|
|
{ |
|
|
|
return hse->flags & FLAG_IS_FINISHING; |
|
|
|
return hse->flags & FLAG_IS_FINISHING; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int can_take_byte(output_info *oi) { |
|
|
|
static int can_take_byte(output_info *oi) |
|
|
|
|
|
|
|
{ |
|
|
|
return *oi->output_size < oi->buf_size; |
|
|
|
return *oi->output_size < oi->buf_size; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Return the longest match for the bytes at buf[end:end+maxlen] between
|
|
|
|
/* Return the longest match for the bytes at buf[end:end+maxlen] between
|
|
|
|
* buf[start] and buf[end-1]. If no match is found, return -1. */ |
|
|
|
* buf[start] and buf[end-1]. If no match is found, return -1. */ |
|
|
|
static uint16_t find_longest_match(heatshrink_encoder *hse, uint16_t start, |
|
|
|
static uint16_t find_longest_match(heatshrink_encoder *hse, uint16_t start, |
|
|
|
uint16_t end, const uint16_t maxlen, uint16_t *match_length) { |
|
|
|
uint16_t end, const uint16_t maxlen, uint16_t *match_length) |
|
|
|
|
|
|
|
{ |
|
|
|
LOG("-- scanning for match of buf[%u:%u] between buf[%u:%u] (max %u bytes)\n", |
|
|
|
LOG("-- scanning for match of buf[%u:%u] between buf[%u:%u] (max %u bytes)\n", |
|
|
|
end, end + maxlen, start, end + maxlen - 1, maxlen); |
|
|
|
end, end + maxlen, start, end + maxlen - 1, maxlen); |
|
|
|
uint8_t *buf = hse->buffer; |
|
|
|
uint8_t *buf = hse->buffer; |
|
|
@ -462,13 +500,13 @@ static uint16_t find_longest_match(heatshrink_encoder *hse, uint16_t start, |
|
|
|
uint16_t match_index = MATCH_NOT_FOUND; |
|
|
|
uint16_t match_index = MATCH_NOT_FOUND; |
|
|
|
|
|
|
|
|
|
|
|
uint16_t len = 0; |
|
|
|
uint16_t len = 0; |
|
|
|
uint8_t * const needlepoint = &buf[end]; |
|
|
|
uint8_t *const needlepoint = &buf[end]; |
|
|
|
#if HEATSHRINK_USE_INDEX |
|
|
|
#if HEATSHRINK_USE_INDEX |
|
|
|
struct hs_index *hsi = HEATSHRINK_ENCODER_INDEX(hse); |
|
|
|
struct hs_index *hsi = HEATSHRINK_ENCODER_INDEX(hse); |
|
|
|
int16_t pos = hsi->index[end]; |
|
|
|
int16_t pos = hsi->index[end]; |
|
|
|
|
|
|
|
|
|
|
|
while (pos - (int16_t)start >= 0) { |
|
|
|
while (pos - (int16_t) start >= 0) { |
|
|
|
uint8_t * const pospoint = &buf[pos]; |
|
|
|
uint8_t *const pospoint = &buf[pos]; |
|
|
|
|
|
|
|
|
|
|
|
/* Only check matches that will potentially beat the current maxlen.
|
|
|
|
/* Only check matches that will potentially beat the current maxlen.
|
|
|
|
* This is redundant with the index if match_maxlen is 0, but the |
|
|
|
* This is redundant with the index if match_maxlen is 0, but the |
|
|
@ -479,12 +517,12 @@ static uint16_t find_longest_match(heatshrink_encoder *hse, uint16_t start, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (len = 1; len < maxlen; len++) { |
|
|
|
for (len = 1; len < maxlen; len++) { |
|
|
|
if (pospoint[len] != needlepoint[len]) break; |
|
|
|
if (pospoint[len] != needlepoint[len]) { break; } |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (len > match_maxlen) { |
|
|
|
if (len > match_maxlen) { |
|
|
|
match_maxlen = len; |
|
|
|
match_maxlen = len; |
|
|
|
match_index = (uint16_t)pos; |
|
|
|
match_index = (uint16_t) pos; |
|
|
|
if (len == maxlen) { break; } /* won't find better */ |
|
|
|
if (len == maxlen) { break; } /* won't find better */ |
|
|
|
} |
|
|
|
} |
|
|
|
pos = hsi->index[pos]; |
|
|
|
pos = hsi->index[pos]; |
|
|
@ -510,9 +548,8 @@ static uint16_t find_longest_match(heatshrink_encoder *hse, uint16_t start, |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
const size_t break_even_point = |
|
|
|
const size_t break_even_point = (size_t) (1 + HEATSHRINK_ENCODER_WINDOW_BITS(hse) |
|
|
|
(1 + HEATSHRINK_ENCODER_WINDOW_BITS(hse) + |
|
|
|
+ HEATSHRINK_ENCODER_LOOKAHEAD_BITS(hse)); |
|
|
|
HEATSHRINK_ENCODER_LOOKAHEAD_BITS(hse)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Instead of comparing break_even_point against 8*match_maxlen,
|
|
|
|
/* Instead of comparing break_even_point against 8*match_maxlen,
|
|
|
|
* compare match_maxlen against break_even_point/8 to avoid |
|
|
|
* compare match_maxlen against break_even_point/8 to avoid |
|
|
@ -528,15 +565,16 @@ static uint16_t find_longest_match(heatshrink_encoder *hse, uint16_t start, |
|
|
|
return MATCH_NOT_FOUND; |
|
|
|
return MATCH_NOT_FOUND; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static uint8_t push_outgoing_bits(heatshrink_encoder *hse, output_info *oi) { |
|
|
|
static uint8_t push_outgoing_bits(heatshrink_encoder *hse, output_info *oi) |
|
|
|
|
|
|
|
{ |
|
|
|
uint8_t count = 0; |
|
|
|
uint8_t count = 0; |
|
|
|
uint8_t bits = 0; |
|
|
|
uint8_t bits = 0; |
|
|
|
if (hse->outgoing_bits_count > 8) { |
|
|
|
if (hse->outgoing_bits_count > 8) { |
|
|
|
count = 8; |
|
|
|
count = 8; |
|
|
|
bits = (uint8_t)(hse->outgoing_bits >> (hse->outgoing_bits_count - 8)); |
|
|
|
bits = (uint8_t) (hse->outgoing_bits >> (hse->outgoing_bits_count - 8)); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
count = hse->outgoing_bits_count; |
|
|
|
count = hse->outgoing_bits_count; |
|
|
|
bits = (uint8_t)hse->outgoing_bits; |
|
|
|
bits = (uint8_t) hse->outgoing_bits; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (count > 0) { |
|
|
|
if (count > 0) { |
|
|
@ -550,7 +588,8 @@ static uint8_t push_outgoing_bits(heatshrink_encoder *hse, output_info *oi) { |
|
|
|
/* Push COUNT (max 8) bits to the output buffer, which has room.
|
|
|
|
/* Push COUNT (max 8) bits to the output buffer, which has room.
|
|
|
|
* Bytes are set from the lowest bits, up. */ |
|
|
|
* Bytes are set from the lowest bits, up. */ |
|
|
|
static void push_bits(heatshrink_encoder *hse, uint8_t count, uint8_t bits, |
|
|
|
static void push_bits(heatshrink_encoder *hse, uint8_t count, uint8_t bits, |
|
|
|
output_info *oi) { |
|
|
|
output_info *oi) |
|
|
|
|
|
|
|
{ |
|
|
|
ASSERT(count <= 8); |
|
|
|
ASSERT(count <= 8); |
|
|
|
LOG("++ push_bits: %d bits, input of 0x%02x\n", count, bits); |
|
|
|
LOG("++ push_bits: %d bits, input of 0x%02x\n", count, bits); |
|
|
|
|
|
|
|
|
|
|
@ -559,7 +598,7 @@ static void push_bits(heatshrink_encoder *hse, uint8_t count, uint8_t bits, |
|
|
|
if (count == 8 && hse->bit_index == 0x80) { |
|
|
|
if (count == 8 && hse->bit_index == 0x80) { |
|
|
|
oi->buf[(*oi->output_size)++] = bits; |
|
|
|
oi->buf[(*oi->output_size)++] = bits; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
for (int i=count - 1; i>=0; i--) { |
|
|
|
for (int i = count - 1; i >= 0; i--) { |
|
|
|
bool bit = bits & (1 << i); |
|
|
|
bool bit = bits & (1 << i); |
|
|
|
if (bit) { hse->current_byte |= hse->bit_index; } |
|
|
|
if (bit) { hse->current_byte |= hse->bit_index; } |
|
|
|
if (0) { |
|
|
|
if (0) { |
|
|
@ -577,7 +616,8 @@ static void push_bits(heatshrink_encoder *hse, uint8_t count, uint8_t bits, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void push_literal_byte(heatshrink_encoder *hse, output_info *oi) { |
|
|
|
static void push_literal_byte(heatshrink_encoder *hse, output_info *oi) |
|
|
|
|
|
|
|
{ |
|
|
|
uint16_t processed_offset = hse->match_scan_index - 1; |
|
|
|
uint16_t processed_offset = hse->match_scan_index - 1; |
|
|
|
uint16_t input_offset = get_input_offset(hse) + processed_offset; |
|
|
|
uint16_t input_offset = get_input_offset(hse) + processed_offset; |
|
|
|
uint8_t c = hse->buffer[input_offset]; |
|
|
|
uint8_t c = hse->buffer[input_offset]; |
|
|
@ -586,7 +626,8 @@ static void push_literal_byte(heatshrink_encoder *hse, output_info *oi) { |
|
|
|
push_bits(hse, 8, c, oi); |
|
|
|
push_bits(hse, 8, c, oi); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void save_backlog(heatshrink_encoder *hse) { |
|
|
|
static void save_backlog(heatshrink_encoder *hse) |
|
|
|
|
|
|
|
{ |
|
|
|
size_t input_buf_sz = get_input_buffer_size(hse); |
|
|
|
size_t input_buf_sz = get_input_buffer_size(hse); |
|
|
|
|
|
|
|
|
|
|
|
uint16_t msi = hse->match_scan_index; |
|
|
|
uint16_t msi = hse->match_scan_index; |
|
|
@ -595,13 +636,13 @@ static void save_backlog(heatshrink_encoder *hse) { |
|
|
|
* used for future matches. Don't bother checking whether the |
|
|
|
* used for future matches. Don't bother checking whether the |
|
|
|
* input is less than the maximum size, because if it isn't, |
|
|
|
* input is less than the maximum size, because if it isn't, |
|
|
|
* we're done anyway. */ |
|
|
|
* we're done anyway. */ |
|
|
|
uint16_t rem = (uint16_t)input_buf_sz - msi; // unprocessed bytes
|
|
|
|
uint16_t rem = (uint16_t) input_buf_sz - msi; // unprocessed bytes
|
|
|
|
uint16_t shift_sz = (uint16_t)input_buf_sz + rem; |
|
|
|
uint16_t shift_sz = (uint16_t) input_buf_sz + rem; |
|
|
|
|
|
|
|
|
|
|
|
memmove(&hse->buffer[0], |
|
|
|
memmove(&hse->buffer[0], |
|
|
|
&hse->buffer[input_buf_sz - rem], |
|
|
|
&hse->buffer[input_buf_sz - rem], |
|
|
|
shift_sz); |
|
|
|
shift_sz); |
|
|
|
|
|
|
|
|
|
|
|
hse->match_scan_index = 0; |
|
|
|
hse->match_scan_index = 0; |
|
|
|
hse->input_size -= (uint16_t)input_buf_sz - rem; |
|
|
|
hse->input_size -= (uint16_t) (input_buf_sz - rem); |
|
|
|
} |
|
|
|
} |
|
|
|