TEST decoder_poll_should_expand_short_literal_and_backref() { uint8_t input[] = {0xb3, 0x5b, 0xed, 0xe0, 0x40, 0x80}; //"foofoo" uint8_t output[6]; heatshrink_decoder *hsd = heatshrink_decoder_alloc(256, 7, 7); memset(output, 0, sizeof(*output)); uint16_t count = 0; HSD_sink_res sres = heatshrink_decoder_sink(hsd, input, sizeof(input), &count); ASSERT_EQ(HSDR_SINK_OK, sres); uint16_t out_sz = 0; (void)heatshrink_decoder_poll(hsd, output, 6, &out_sz); if (0) dump_buf("output", output, out_sz); ASSERT_EQ(6, out_sz); ASSERT_EQ('f', output[0]); ASSERT_EQ('o', output[1]); ASSERT_EQ('o', output[2]); ASSERT_EQ('f', output[3]); ASSERT_EQ('o', output[4]); ASSERT_EQ('o', output[5]); heatshrink_decoder_free(hsd); PASS(); }
void decompress(uint8_t *input, uint32_t compressed_size) { printf("Decompressing data...\n"); heatshrink_decoder_reset(&hsd); size_t decomp_sz = 2048; /* Maximum buffer size before compression */ uint8_t *decomp = malloc(decomp_sz); memset(decomp, 0, decomp_sz); size_t count; uint32_t sunk = 0; uint32_t polled = 0; while (sunk < compressed_size) { heatshrink_decoder_sink(&hsd, &input[sunk], compressed_size - sunk, &count); sunk += count; if (sunk == compressed_size) { heatshrink_decoder_finish(&hsd); } HSD_poll_res pres; do { pres = heatshrink_decoder_poll(&hsd, &decomp[polled], decomp_sz - polled, &count); polled += count; } while (pres == HSDR_POLL_MORE); if (sunk == compressed_size) { heatshrink_decoder_finish(&hsd); } } printf("Size after decompression: %d\n", polled); csv = fopen("data.csv", "a"); for (int i = 0; i < polled; ++i) { fprintf(csv, "%hhu\n", decomp[i]); } fclose(csv); free(decomp); }
TEST decoder_poll_should_expand_short_literal_and_backref_when_fed_input_byte_by_byte() { uint8_t input[] = {0xb3, 0x5b, 0xed, 0xe0, 0x40, 0x80}; //"foofoo" uint8_t output[7]; heatshrink_decoder *hsd = heatshrink_decoder_alloc(256, 7, 7); memset(output, 0, sizeof(*output)); uint16_t count = 0; HSD_sink_res sres; for (int i=0; i<6; i++) { sres = heatshrink_decoder_sink(hsd, &input[i], 1, &count); ASSERT_EQ(HSDR_SINK_OK, sres); } heatshrink_decoder_finish(hsd); uint16_t out_sz = 0; HSD_poll_res pres = heatshrink_decoder_poll(hsd, output, 7, &out_sz); ASSERT_EQ(6, out_sz); ASSERT_EQ(HSDR_POLL_EMPTY, pres); ASSERT_EQ('f', output[0]); ASSERT_EQ('o', output[1]); ASSERT_EQ('o', output[2]); ASSERT_EQ('f', output[3]); ASSERT_EQ('o', output[4]); ASSERT_EQ('o', output[5]); heatshrink_decoder_free(hsd); PASS(); }
int decode_data (uint8_t * data, int sz) { size_t count = 0; size_t desz = sz + sz / 2 + 4; int sunk = 0; int polled = 0; uint8_t *decomp = malloc(desz); while (sunk < sz) { heatshrink_decoder_sink(&hsd, &data[sunk], sz - sunk, &count); sunk += count; HSD_poll_res pres; do { pres = heatshrink_decoder_poll(&hsd, &decomp[polled], desz - polled, &count); polled += count; } while (pres == HSDR_POLL_MORE); if (sunk == sz) { HSD_finish_res fres = heatshrink_decoder_finish(&hsd); } } fprintf(stdout, "%s", (char *) decomp); free(decomp); }
TEST decoder_poll_should_reject_null_hsd() { uint8_t output[256]; uint16_t out_sz = 0; HSD_poll_res res = heatshrink_decoder_poll(NULL, output, 256, &out_sz); ASSERT_EQ(HSDR_POLL_ERROR_NULL, res); PASS(); }
TEST decoder_finish_should_note_when_done() { uint8_t input[] = {0xb3, 0x5b, 0xed, 0xe0, 0x40, 0x80}; //"foofoo" uint8_t output[7]; heatshrink_decoder *hsd = heatshrink_decoder_alloc(256, 7, 7); memset(output, 0, sizeof(*output)); uint16_t count = 0; HSD_sink_res sres = heatshrink_decoder_sink(hsd, input, sizeof(input), &count); ASSERT_EQ(HSDR_SINK_OK, sres); uint16_t out_sz = 0; HSD_poll_res pres = heatshrink_decoder_poll(hsd, output, sizeof(output), &out_sz); ASSERT_EQ(HSDR_POLL_EMPTY, pres); ASSERT_EQ(6, out_sz); ASSERT_EQ('f', output[0]); ASSERT_EQ('o', output[1]); ASSERT_EQ('o', output[2]); ASSERT_EQ('f', output[3]); ASSERT_EQ('o', output[4]); ASSERT_EQ('o', output[5]); HSD_finish_res fres = heatshrink_decoder_finish(hsd); ASSERT_EQ(HSDR_FINISH_DONE, fres); heatshrink_decoder_free(hsd); PASS(); }
TEST decoder_poll_should_reject_null_output_buffer() { uint16_t out_sz = 0; heatshrink_decoder *hsd = heatshrink_decoder_alloc(256, HEATSHRINK_MIN_WINDOW_BITS, 4); HSD_poll_res res = heatshrink_decoder_poll(hsd, NULL, 256, &out_sz); ASSERT_EQ(HSDR_POLL_ERROR_NULL, res); heatshrink_decoder_free(hsd); PASS(); }
TEST decoder_poll_should_reject_null_output_size_pointer() { uint8_t output[256]; heatshrink_decoder *hsd = heatshrink_decoder_alloc(256, HEATSHRINK_MIN_WINDOW_BITS, 4); HSD_poll_res res = heatshrink_decoder_poll(hsd, output, 256, NULL); ASSERT_EQ(HSDR_POLL_ERROR_NULL, res); heatshrink_decoder_free(hsd); PASS(); }
TEST decoder_poll_should_return_empty_if_empty() { uint8_t output[256]; uint16_t out_sz = 0; heatshrink_decoder *hsd = heatshrink_decoder_alloc(256, HEATSHRINK_MIN_WINDOW_BITS, 4); HSD_poll_res res = heatshrink_decoder_poll(hsd, output, 256, &out_sz); ASSERT_EQ(HSDR_POLL_EMPTY, res); heatshrink_decoder_free(hsd); PASS(); }
/** gets data from callback, writes it into array if nonzero. Returns total length */ uint32_t heatshrink_decode(int (*callback)(uint32_t *cbdata), uint32_t *cbdata, unsigned char *data) { heatshrink_decoder hsd; uint8_t inBuf[BUFFERSIZE]; uint8_t outBuf[BUFFERSIZE]; heatshrink_decoder_reset(&hsd); size_t count = 0; size_t sunk = 0; size_t polled = 0; int lastByte = 0; size_t inBufCount = 0; while (lastByte >= 0 || inBufCount>0) { // Read data from flash while (inBufCount<BUFFERSIZE && lastByte>=0) { lastByte = callback(cbdata); if (lastByte >= 0) inBuf[inBufCount++] = (uint8_t)lastByte; } // decode bool ok = heatshrink_decoder_sink(&hsd, inBuf, inBufCount, &count) >= 0; // if not all the data was read, shift what's left to the start of our buffer if (count < inBufCount) { size_t i; for (i=count;i<inBufCount;i++) inBuf[i-count] = inBuf[i]; } inBufCount -= count; assert(ok);NOT_USED(ok); sunk += count; if (lastByte < 0) { heatshrink_decoder_finish(&hsd); } HSE_poll_res pres; do { pres = heatshrink_decoder_poll(&hsd, outBuf, sizeof(outBuf), &count); assert(pres >= 0); if (data) memcpy(&data[polled], outBuf, count); polled += count; } while (pres == HSER_POLL_MORE); assert(pres == HSER_POLL_EMPTY); if (lastByte < 0) { heatshrink_decoder_finish(&hsd); } } return (uint32_t)polled; }
TEST decoder_poll_should_suspend_if_out_of_space_in_output_buffer_during_literal_expansion() { uint8_t input[] = {0xb3, 0x5b, 0xed, 0xe0, 0x40, 0x80}; uint8_t output[1]; heatshrink_decoder *hsd = heatshrink_decoder_alloc(256, 7, 7); uint16_t count = 0; HSD_sink_res sres = heatshrink_decoder_sink(hsd, input, sizeof(input), &count); ASSERT_EQ(HSDR_SINK_OK, sres); uint16_t out_sz = 0; HSD_poll_res pres = heatshrink_decoder_poll(hsd, output, 1, &out_sz); ASSERT_EQ(HSDR_POLL_MORE, pres); ASSERT_EQ(1, out_sz); ASSERT_EQ('f', output[0]); heatshrink_decoder_free(hsd); PASS(); }
TEST decoder_poll_should_expand_short_literal() { uint8_t input[] = {0xb3, 0x5b, 0xed, 0xe0 }; //"foo" uint8_t output[4]; heatshrink_decoder *hsd = heatshrink_decoder_alloc(256, 7, 3); uint16_t count = 0; HSD_sink_res sres = heatshrink_decoder_sink(hsd, input, sizeof(input), &count); ASSERT_EQ(HSDR_SINK_OK, sres); uint16_t out_sz = 0; HSD_poll_res pres = heatshrink_decoder_poll(hsd, output, 4, &out_sz); ASSERT_EQ(HSDR_POLL_EMPTY, pres); ASSERT_EQ(3, out_sz); ASSERT_EQ('f', output[0]); ASSERT_EQ('o', output[1]); ASSERT_EQ('o', output[2]); heatshrink_decoder_free(hsd); PASS(); }
TEST data_with_simple_repetition_should_match_with_absurdly_tiny_buffers() { heatshrink_encoder *hse = heatshrink_encoder_alloc(8, 3); heatshrink_decoder *hsd = heatshrink_decoder_alloc(256, 8, 3); uint8_t input[] = {'a', 'b', 'c', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'e', 'a', 'b', 'c', 'd', 'e', 'f', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}; uint8_t comp[60]; uint8_t decomp[60]; uint16_t count = 0; int log = 0; if (log) dump_buf("input", input, sizeof(input)); for (int i=0; i<sizeof(input); i++) { ASSERT(heatshrink_encoder_sink(hse, &input[i], 1, &count) >= 0); } ASSERT_EQ(HSER_FINISH_MORE, heatshrink_encoder_finish(hse)); uint16_t packed_count = 0; do { ASSERT(heatshrink_encoder_poll(hse, &comp[packed_count], 1, &count) >= 0); packed_count += count; } while (heatshrink_encoder_finish(hse) == HSER_FINISH_MORE); if (log) dump_buf("comp", comp, packed_count); for (int i=0; i<packed_count; i++) { HSD_sink_res sres = heatshrink_decoder_sink(hsd, &comp[i], 1, &count); //printf("sres is %d\n", sres); ASSERT(sres >= 0); } for (int i=0; i<sizeof(input); i++) { ASSERT(heatshrink_decoder_poll(hsd, &decomp[i], 1, &count) >= 0); } if (log) dump_buf("decomp", decomp, sizeof(input)); for (int i=0; i<sizeof(input); i++) ASSERT_EQ(input[i], decomp[i]); heatshrink_encoder_free(hse); heatshrink_decoder_free(hsd); PASS(); }
TEST decoder_poll_should_expand_short_self_overlapping_backref() { /* "aaaaa" == (literal, 1), ('a'), (backref, 1 back, 4 bytes) */ uint8_t input[] = {0xb0, 0x80, 0x01, 0x80}; uint8_t output[6]; uint8_t expected[] = {'a', 'a', 'a', 'a', 'a'}; heatshrink_decoder *hsd = heatshrink_decoder_alloc(256, 8, 7); uint16_t count = 0; HSD_sink_res sres = heatshrink_decoder_sink(hsd, input, sizeof(input), &count); ASSERT_EQ(HSDR_SINK_OK, sres); uint16_t out_sz = 0; (void)heatshrink_decoder_poll(hsd, output, sizeof(output), &out_sz); if (0) dump_buf("output", output, out_sz); ASSERT_EQ(sizeof(expected), out_sz); for (int i=0; i<sizeof(expected); i++) ASSERT_EQ(expected[i], output[i]); heatshrink_decoder_free(hsd); PASS(); }
TEST data_without_duplication_should_match_with_absurdly_tiny_buffers(void) { heatshrink_encoder *hse = heatshrink_encoder_alloc(8, 3); heatshrink_decoder *hsd = heatshrink_decoder_alloc(256, 8, 3); uint8_t input[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}; uint8_t comp[60]; uint8_t decomp[60]; size_t count = 0; int log = 0; if (log) dump_buf("input", input, sizeof(input)); for (uint32_t i=0; i<sizeof(input); i++) { ASSERT(heatshrink_encoder_sink(hse, &input[i], 1, &count) >= 0); } ASSERT_EQ(HSER_FINISH_MORE, heatshrink_encoder_finish(hse)); size_t packed_count = 0; do { ASSERT(heatshrink_encoder_poll(hse, &comp[packed_count], 1, &count) >= 0); packed_count += count; } while (heatshrink_encoder_finish(hse) == HSER_FINISH_MORE); if (log) dump_buf("comp", comp, packed_count); for (uint32_t i=0; i<packed_count; i++) { HSD_sink_res sres = heatshrink_decoder_sink(hsd, &comp[i], 1, &count); //printf("sres is %d\n", sres); ASSERT(sres >= 0); } for (uint32_t i=0; i<sizeof(input); i++) { ASSERT(heatshrink_decoder_poll(hsd, &decomp[i], 1, &count) >= 0); } if (log) dump_buf("decomp", decomp, sizeof(input)); for (uint32_t i=0; i<sizeof(input); i++) ASSERT_EQ(input[i], decomp[i]); heatshrink_encoder_free(hse); heatshrink_decoder_free(hsd); PASS(); }
int main(int argc, char *argv[]) { int data_size = atoi(argv[argc - 1]); uint8_t data[data_size]; for (int i = 0; i < data_size; ++i) { data[i] = (uint8_t) argv[1][i]; } size_t count = 0; size_t decomp_sz = data_size + (data_size / 2) + 4; int sunk = 0; int polled = 0; uint8_t *decomp = malloc(decomp_sz); while (sunk < data_size) { heatshrink_decoder_sink(&hsd, &data[sunk], data_size - sunk, &count); sunk += count; HSD_poll_res pres; do { pres = heatshrink_decoder_poll(&hsd, &decomp[polled], decomp_sz - polled, &count); printf("%zu\n", count); polled += count; } while (pres == HSDR_POLL_MORE); if (sunk == data_size) { HSD_finish_res fres = heatshrink_decoder_finish(&hsd); } } uint8_t buf[polled]; for (int i = 0; i < polled; ++i) { buf[i] = decomp[i]; printf("%c", buf[i]); } buf[polled] = '\0'; printf("%s", buf); free(decomp); return 0; }
TEST decoder_poll_should_suspend_if_out_of_space_in_output_buffer_during_backref_expansion() { uint8_t input[] = {0xb3, 0x5b, 0xed, 0xe0, 0x40, 0x80}; //"foofoo" uint8_t output[4]; heatshrink_decoder *hsd = heatshrink_decoder_alloc(256, 7, 7); memset(output, 0, sizeof(*output)); uint16_t count = 0; HSD_sink_res sres = heatshrink_decoder_sink(hsd, input, 6, &count); ASSERT_EQ(HSDR_SINK_OK, sres); uint16_t out_sz = 0; HSD_poll_res pres = heatshrink_decoder_poll(hsd, output, 4, &out_sz); ASSERT_EQ(HSDR_POLL_MORE, pres); ASSERT_EQ(4, out_sz); ASSERT_EQ('f', output[0]); ASSERT_EQ('o', output[1]); ASSERT_EQ('o', output[2]); ASSERT_EQ('f', output[3]); heatshrink_decoder_free(hsd); PASS(); }
TEST decoder_should_not_get_stuck_with_finish_yielding_MORE_but_0_bytes_output_from_poll(void) { uint8_t input[512]; memset(input, 0xff, 256); uint8_t output[1024]; heatshrink_decoder *hsd = heatshrink_decoder_alloc(256, 8, 4); ASSERT(hsd); /* Confirm that no byte of trailing context can lead to * heatshrink_decoder_finish erroneously returning HSDR_FINISH_MORE * when heatshrink_decoder_poll will yield 0 bytes. * * Before 0.3.1, a final byte of 0xFF could potentially cause * this to happen, if at exactly the byte boundary. */ for (uint16_t byte = 0; byte < 256; byte++) { for (int i = 1; i < 512; i++) { input[i] = byte; heatshrink_decoder_reset(hsd); memset(output, 0, sizeof(*output)); size_t count = 0; HSD_sink_res sres = heatshrink_decoder_sink(hsd, input, i, &count); ASSERT_EQ(HSDR_SINK_OK, sres); size_t out_sz = 0; HSD_poll_res pres = heatshrink_decoder_poll(hsd, output, sizeof(output), &out_sz); ASSERT_EQ(HSDR_POLL_EMPTY, pres); HSD_finish_res fres = heatshrink_decoder_finish(hsd); ASSERT_EQ(HSDR_FINISH_DONE, fres); input[i] = 0xff; } } heatshrink_decoder_free(hsd); PASS(); }
static int decoder_sink_read(config *cfg, heatshrink_decoder *hsd, uint8_t *data, size_t data_sz) { io_handle *out = cfg->out; size_t sink_sz = 0; size_t poll_sz = 0; size_t out_sz = 4096; uint8_t out_buf[out_sz]; memset(out_buf, 0, out_sz); HSD_sink_res sres; HSD_poll_res pres; HSD_finish_res fres; size_t sunk = 0; do { if (data_sz > 0) { sres = heatshrink_decoder_sink(hsd, &data[sunk], data_sz - sunk, &sink_sz); if (sres < 0) { die("sink"); } sunk += sink_sz; } do { pres = heatshrink_decoder_poll(hsd, out_buf, out_sz, &poll_sz); if (pres < 0) { die("poll"); } if (handle_sink(out, poll_sz, out_buf) < 0) die("handle_sink"); } while (pres == HSDR_POLL_MORE); if (data_sz == 0 && poll_sz == 0) { fres = heatshrink_decoder_finish(hsd); if (fres < 0) { die("finish"); } if (fres == HSDR_FINISH_DONE) { return 1; } } } while (sunk < data_sz); return 0; }
static ZEND_FUNCTION(hs_decompress) { zval *data; size_t data_len; size_t sink_sz = 0; size_t poll_sz = 0; HSD_sink_res sres; HSD_poll_res pres; HSD_finish_res fres; //Default window_sz2 and lookahead_sz2 values uint8_t window = DEF_WINDOW_SZ2; uint8_t lookahead = DEF_LOOKAHEAD_SZ2; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", &data, &window, &lookahead) == FAILURE) { RETURN_FALSE; } if (Z_TYPE_P(data) != IS_STRING) { zend_error(E_WARNING, "hs_decompress : expects parameter to be string."); RETURN_FALSE; } //Allocate decoder //TODO: How we calculate input buffer size? heatshrink_decoder *hsd = heatshrink_decoder_alloc(DEF_DECODER_INPUT_BUFFER_SIZE, window, lookahead); if (hsd == NULL) { zend_error(E_WARNING, "hs_decompress : heatshrink_decoder_alloc error. Check window and lookahead values."); RETURN_FALSE; } data_len = Z_STRLEN_P(data); //TODO: think of better way to compute outbuff size size_t outbuff_len = data_len*2; unsigned char *outbuff = (unsigned char *) emalloc(outbuff_len); size_t sunk = 0; do { sres = heatshrink_decoder_sink(hsd, (unsigned char *) &(Z_STRVAL_P(data)[sunk]), data_len - sunk, &sink_sz); if (sres < 0) { zend_error(E_WARNING, "hs_decompress : heatshrink_decoder_sink error"); efree(outbuff); heatshrink_decoder_free(hsd); RETURN_FALSE; } sunk += sink_sz; do { do { pres = heatshrink_decoder_poll(hsd, &outbuff[poll_sz], outbuff_len - poll_sz, &sink_sz); if (pres < 0) { zend_error(E_WARNING, "hs_compress : heatshrink_decoder_poll error"); efree(outbuff); heatshrink_decoder_free(hsd); RETURN_FALSE; } poll_sz += sink_sz; if (poll_sz == outbuff_len && pres == HSDR_POLL_MORE) { //TODO: think of bettery way to compute buffer reallocation size outbuff_len += data_len/2; outbuff = erealloc(outbuff, outbuff_len); } } while (pres == HSDR_POLL_MORE); if (sunk == data_len) { fres = heatshrink_decoder_finish(hsd); if (fres < 0) { zend_error(E_WARNING, "hs_decompress : heatshrink_decoder_finish error"); efree(outbuff); heatshrink_decoder_free(hsd); RETURN_FALSE; } if (fres == HSDR_FINISH_DONE) { RETVAL_STRINGL((char *) outbuff, poll_sz, 1); efree(outbuff); heatshrink_decoder_free(hsd); return; } } } while (fres == HSDR_FINISH_MORE); } while (sunk < data_len); zend_error(E_WARNING, "hs_decompress : general error"); efree(outbuff); heatshrink_decoder_free(hsd); RETURN_FALSE; }
static int compress_and_expand_and_check(uint8_t *input, uint32_t input_size, cfg_info *cfg) { heatshrink_encoder *hse = heatshrink_encoder_alloc(cfg->window_sz2, cfg->lookahead_sz2); heatshrink_decoder *hsd = heatshrink_decoder_alloc(cfg->decoder_input_buffer_size, cfg->window_sz2, cfg->lookahead_sz2); size_t comp_sz = input_size + (input_size/2) + 4; size_t decomp_sz = input_size + (input_size/2) + 4; uint8_t *comp = malloc(comp_sz); uint8_t *decomp = malloc(decomp_sz); if (comp == NULL) FAILm("malloc fail"); if (decomp == NULL) FAILm("malloc fail"); memset(comp, 0, comp_sz); memset(decomp, 0, decomp_sz); uint16_t count = 0; if (cfg->log_lvl > 1) { printf("\n^^ COMPRESSING\n"); dump_buf("input", input, input_size); } uint32_t sunk = 0; uint32_t polled = 0; while (sunk < input_size) { ASSERT(heatshrink_encoder_sink(hse, &input[sunk], input_size - sunk, &count) >= 0); sunk += count; if (cfg->log_lvl > 1) printf("^^ sunk %d\n", count); if (sunk == input_size) { ASSERT_EQ(HSER_FINISH_MORE, heatshrink_encoder_finish(hse)); } HSE_poll_res pres; do { /* "turn the crank" */ pres = heatshrink_encoder_poll(hse, &comp[polled], comp_sz - polled, &count); ASSERT(pres >= 0); polled += count; if (cfg->log_lvl > 1) printf("^^ polled %d\n", count); } while (pres == HSER_POLL_MORE); ASSERT_EQ(HSER_POLL_EMPTY, pres); if (polled >= comp_sz) FAILm("compression should never expand that much"); if (sunk == input_size) { ASSERT_EQ(HSER_FINISH_DONE, heatshrink_encoder_finish(hse)); } } if (cfg->log_lvl > 0) printf("in: %u compressed: %u ", input_size, polled); uint32_t compressed_size = polled; sunk = 0; polled = 0; if (cfg->log_lvl > 1) { printf("\n^^ DECOMPRESSING\n"); dump_buf("comp", comp, compressed_size); } while (sunk < compressed_size) { ASSERT(heatshrink_decoder_sink(hsd, &comp[sunk], compressed_size - sunk, &count) >= 0); sunk += count; if (cfg->log_lvl > 1) printf("^^ sunk %d\n", count); if (sunk == compressed_size) { ASSERT_EQ(HSDR_FINISH_MORE, heatshrink_decoder_finish(hsd)); } HSD_poll_res pres; do { pres = heatshrink_decoder_poll(hsd, &decomp[polled], decomp_sz - polled, &count); ASSERT(pres >= 0); ASSERT(count > 0); polled += count; if (cfg->log_lvl > 1) printf("^^ polled %d\n", count); } while (pres == HSDR_POLL_MORE); ASSERT_EQ(HSDR_POLL_EMPTY, pres); if (sunk == compressed_size) { HSD_finish_res fres = heatshrink_decoder_finish(hsd); ASSERT_EQ(HSDR_FINISH_DONE, fres); } if (polled > input_size) { printf("\nExpected %d, got %d\n", input_size, polled); FAILm("Decompressed data is larger than original input"); } } if (cfg->log_lvl > 0) printf("decompressed: %u\n", polled); if (polled != input_size) { FAILm("Decompressed length does not match original input length"); } if (cfg->log_lvl > 1) dump_buf("decomp", decomp, polled); for (int i=0; i<input_size; i++) { if (input[i] != decomp[i]) { printf("*** mismatch at %d\n", i); if (0) { for (int j=0; j<=/*i*/ input_size; j++) { printf("in[%d] == 0x%02x ('%c') => out[%d] == 0x%02x ('%c') %c\n", j, input[j], isprint(input[j]) ? input[j] : '.', j, decomp[j], isprint(decomp[j]) ? decomp[j] : '.', input[j] == decomp[j] ? ' ' : 'X'); } } } ASSERT_EQ(input[i], decomp[i]); } free(comp); free(decomp); heatshrink_encoder_free(hse); heatshrink_decoder_free(hsd); PASS(); }