Skip to content
Snippets Groups Projects
Commit 86699925 authored by Vadim Vygonets's avatar Vadim Vygonets Committed by Scott Vokes
Browse files

Process tag bit sooner in decoder

Fix the bug where last 7 bits are not processed.

Test case:
$ echo -n aaaa | ./heatshrink -w4 -l2 | ./heatshrink -dw4 -l2 | hexdump -C

expected output:
00000000  61 61 61 61                                       |aaaa|
00000004

bug:
00000000  61                                                |a|
00000001

Conflicts:
	heatshrink_decoder.c
parent 9bef9df5
No related branches found
No related tags found
No related merge requests found
digraph {
graph [label="Decoder state machine", labelloc="t"]
Start [style="invis", shape="point"]
empty
input_available
tag_bit
yield_literal
backref_index_msb
backref_index_lsb
backref_count_msb
backref_count_lsb
yield_backref
check_for_more_input
done [peripheries=2]
empty->input_available [label="sink()", color="blue", weight=10]
Start->empty
tag_bit->tag_bit [label="sink()", color="blue", weight=10]
Start->tag_bit
input_available->yield_literal [label="pop 1-bit"]
input_available->backref_index_msb [label="pop 0-bit", weight=10]
input_available->backref_index_lsb [label="pop 0-bit, index <8 bits", weight=10]
tag_bit->yield_literal [label="pop 1-bit"]
tag_bit->backref_index_msb [label="pop 0-bit", weight=10]
tag_bit->backref_index_lsb [label="pop 0-bit, index <8 bits", weight=10]
yield_literal->yield_literal [label="sink()", color="blue"]
yield_literal->yield_literal [label="poll()", color="red"]
yield_literal->check_for_more_input [label="poll(), done", color="red"]
yield_literal->tag_bit [label="poll(), done", color="red"]
backref_index_msb->backref_index_msb [label="sink()", color="blue"]
backref_index_msb->backref_index_lsb [label="pop index, upper bits", weight=10]
......@@ -42,11 +40,8 @@ digraph {
yield_backref->yield_backref [label="sink()", color="blue"]
yield_backref->yield_backref [label="poll()", color="red"]
yield_backref->check_for_more_input [label="poll(), done",
yield_backref->tag_bit [label="poll(), done",
color="red", weight=10]
check_for_more_input->empty [label="no"]
check_for_more_input->input_available [label="yes"]
empty->done [label="finish()", color="blue"]
tag_bit->done [label="finish()", color="blue"]
}
......@@ -4,15 +4,13 @@
/* States for the polling state machine. */
typedef enum {
HSDS_EMPTY, /* no input to process */
HSDS_INPUT_AVAILABLE, /* new input, completely unprocessed */
HSDS_TAG_BIT, /* tag bit */
HSDS_YIELD_LITERAL, /* ready to yield literal byte */
HSDS_BACKREF_INDEX_MSB, /* most significant byte of index */
HSDS_BACKREF_INDEX_LSB, /* least significant byte of index */
HSDS_BACKREF_COUNT_MSB, /* most significant byte of count */
HSDS_BACKREF_COUNT_LSB, /* least significant byte of count */
HSDS_YIELD_BACKREF, /* ready to yield back-reference */
HSDS_CHECK_FOR_MORE_INPUT, /* check if input is exhausted */
} HSD_state;
#if HEATSHRINK_DEBUGGING_LOGS
......@@ -22,15 +20,13 @@ typedef enum {
#define LOG(...) fprintf(stderr, __VA_ARGS__)
#define ASSERT(X) assert(X)
static const char *state_names[] = {
"empty",
"input_available",
"tag_bit",
"yield_literal",
"backref_index_msb",
"backref_index_lsb",
"backref_count_msb",
"backref_count_lsb",
"yield_backref",
"check_for_more_input",
};
#else
#define LOG(...) /* no-op */
......@@ -85,7 +81,7 @@ void heatshrink_decoder_reset(heatshrink_decoder *hsd) {
size_t buf_sz = 1 << HEATSHRINK_DECODER_WINDOW_BITS(hsd);
size_t input_sz = HEATSHRINK_DECODER_INPUT_BUFFER_SIZE(hsd);
memset(hsd->buffers, 0, buf_sz + input_sz);
hsd->state = HSDS_EMPTY;
hsd->state = HSDS_TAG_BIT;
hsd->input_size = 0;
hsd->input_index = 0;
hsd->bit_index = 0x00;
......@@ -113,10 +109,6 @@ HSD_sink_res heatshrink_decoder_sink(heatshrink_decoder *hsd,
/* copy into input buffer (at head of buffers) */
memcpy(&hsd->buffers[hsd->input_size], in_buf, size);
hsd->input_size += size;
if (hsd->state == HSDS_EMPTY) {
hsd->state = HSDS_INPUT_AVAILABLE;
hsd->input_index = 0;
}
*input_size = size;
return HSDR_SINK_OK;
}
......@@ -130,7 +122,7 @@ HSD_sink_res heatshrink_decoder_sink(heatshrink_decoder *hsd,
#define BACKREF_INDEX_BITS(HSD) (HEATSHRINK_DECODER_WINDOW_BITS(HSD))
// States
static HSD_state st_input_available(heatshrink_decoder *hsd);
static HSD_state st_tag_bit(heatshrink_decoder *hsd);
static HSD_state st_yield_literal(heatshrink_decoder *hsd,
output_info *oi);
static HSD_state st_backref_index_msb(heatshrink_decoder *hsd);
......@@ -139,7 +131,6 @@ static HSD_state st_backref_count_msb(heatshrink_decoder *hsd);
static HSD_state st_backref_count_lsb(heatshrink_decoder *hsd);
static HSD_state st_yield_backref(heatshrink_decoder *hsd,
output_info *oi);
static HSD_state st_check_for_input(heatshrink_decoder *hsd);
HSD_poll_res heatshrink_decoder_poll(heatshrink_decoder *hsd,
uint8_t *out_buf, size_t out_buf_size, size_t *output_size) {
......@@ -158,10 +149,8 @@ HSD_poll_res heatshrink_decoder_poll(heatshrink_decoder *hsd,
hsd->state, state_names[hsd->state], hsd->input_size);
uint8_t in_state = hsd->state;
switch (in_state) {
case HSDS_EMPTY:
return HSDR_POLL_EMPTY;
case HSDS_INPUT_AVAILABLE:
hsd->state = st_input_available(hsd);
case HSDS_TAG_BIT:
hsd->state = st_tag_bit(hsd);
break;
case HSDS_YIELD_LITERAL:
hsd->state = st_yield_literal(hsd, &oi);
......@@ -181,9 +170,6 @@ HSD_poll_res heatshrink_decoder_poll(heatshrink_decoder *hsd,
case HSDS_YIELD_BACKREF:
hsd->state = st_yield_backref(hsd, &oi);
break;
case HSDS_CHECK_FOR_MORE_INPUT:
hsd->state = st_check_for_input(hsd);
break;
default:
return HSDR_POLL_ERROR_UNKNOWN;
}
......@@ -197,9 +183,11 @@ HSD_poll_res heatshrink_decoder_poll(heatshrink_decoder *hsd,
}
}
static HSD_state st_input_available(heatshrink_decoder *hsd) {
uint16_t bits = get_bits(hsd, 1); // get tag bit
if (bits) {
static HSD_state st_tag_bit(heatshrink_decoder *hsd) {
uint32_t bits = get_bits(hsd, 1); // get tag bit
if (bits == NO_BITS) {
return HSDS_TAG_BIT;
} else if (bits) {
return HSDS_YIELD_LITERAL;
} else if (HEATSHRINK_DECODER_WINDOW_BITS(hsd) > 8) {
return HSDS_BACKREF_INDEX_MSB;
......@@ -223,7 +211,7 @@ static HSD_state st_yield_literal(heatshrink_decoder *hsd,
LOG("-- emitting literal byte 0x%02x ('%c')\n", c, isprint(c) ? c : '.');
buf[hsd->head_index++ & mask] = c;
push_byte(hsd, oi, c);
return HSDS_CHECK_FOR_MORE_INPUT;
return HSDS_TAG_BIT;
} else {
return HSDS_YIELD_LITERAL;
}
......@@ -292,15 +280,11 @@ static HSD_state st_yield_backref(heatshrink_decoder *hsd,
LOG(" -- ++ 0x%02x\n", c);
}
hsd->output_count -= count;
if (hsd->output_count == 0) { return HSDS_CHECK_FOR_MORE_INPUT; }
if (hsd->output_count == 0) { return HSDS_TAG_BIT; }
}
return HSDS_YIELD_BACKREF;
}
static HSD_state st_check_for_input(heatshrink_decoder *hsd) {
return (hsd->input_size == 0) ? HSDS_EMPTY : HSDS_INPUT_AVAILABLE;
}
/* Get the next COUNT bits from the input buffer, saving incremental progress.
* Returns NO_BITS on end of input, or if more than 15 bits are requested. */
static uint16_t get_bits(heatshrink_decoder *hsd, uint8_t count) {
......@@ -353,8 +337,8 @@ static uint16_t get_bits(heatshrink_decoder *hsd, uint8_t count) {
HSD_finish_res heatshrink_decoder_finish(heatshrink_decoder *hsd) {
if (hsd == NULL) { return HSDR_FINISH_ERROR_NULL; }
switch (hsd->state) {
case HSDS_EMPTY:
return HSDR_FINISH_DONE;
case HSDS_TAG_BIT:
return hsd->input_size == 0 ? HSDR_FINISH_DONE : HSDR_FINISH_MORE;
/* If we want to finish with no input, but are in these states, it's
* because the 0-bit padding to the last byte looks like a backref
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment