TEST encoder_alloc_should_reject_invalid_arguments() {
    ASSERT_EQ(NULL, heatshrink_encoder_alloc(
            HEATSHRINK_MIN_WINDOW_BITS - 1, 8));
    ASSERT_EQ(NULL, heatshrink_encoder_alloc(
            HEATSHRINK_MAX_WINDOW_BITS + 1, 8));
    ASSERT_EQ(NULL, heatshrink_encoder_alloc(8, HEATSHRINK_MIN_LOOKAHEAD_BITS - 1));
    ASSERT_EQ(NULL, heatshrink_encoder_alloc(8, 9));
    PASS();
}
Ejemplo n.º 2
0
static int encode(config *cfg) {
    uint8_t window_sz2 = cfg->window_sz2;
    size_t window_sz = 1 << window_sz2; 
    heatshrink_encoder *hse = heatshrink_encoder_alloc(window_sz2, cfg->lookahead_sz2);
    if (hse == NULL) { die("failed to init encoder: bad settings"); }
    ssize_t read_sz = 0;
    io_handle *in = cfg->in;

    /* Process input until end of stream */
    while (1) {
        uint8_t *input = NULL;
        read_sz = handle_read(in, window_sz, &input);
        if (input == NULL) {
            printf("handle read failure\n");
            die("read");
        }
        if (read_sz < 0) { die("read"); }

        /* Pass read to encoder and check if input is fully processed. */
        if (encoder_sink_read(cfg, hse, input, read_sz)) break;

        if (handle_drop(in, read_sz) < 0) { die("drop"); }
    };

    if (read_sz == -1) { err(1, "read"); }

    heatshrink_encoder_free(hse);
    close_and_report(cfg);
    return 0;
}
TEST gen() {
    heatshrink_encoder *hse = heatshrink_encoder_alloc(8, 7);
    uint8_t input[] = {'a', 'a', 'a', 'a', 'a'};
    uint8_t output[1024];
    uint16_t copied = 0;
    memset(output, 0, 1024);
    HSE_sink_res sres = heatshrink_encoder_sink(hse,
        input, sizeof(input), &copied);
    ASSERT_EQ(HSER_SINK_OK, sres);
    ASSERT_EQ(sizeof(input), copied);

    HSE_finish_res fres = heatshrink_encoder_finish(hse);
    ASSERT_EQ(HSER_FINISH_MORE, fres);

    ASSERT_EQ(HSER_POLL_EMPTY, heatshrink_encoder_poll(hse, output, 1024, &copied));
    fres = heatshrink_encoder_finish(hse);
    ASSERT_EQ(HSER_FINISH_DONE, fres);
    if (0) {
        printf("{");
        for (int i=0; i<copied; i++) printf("0x%02x, ", output[i]);
        printf("}\n");
    }
    heatshrink_encoder_free(hse);
    PASS();
}
TEST encoder_poll_should_detect_repeated_substring_and_preserve_trailing_literal() {
    heatshrink_encoder *hse = heatshrink_encoder_alloc(8, 3);
    uint8_t input[] = {'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'e'};
    uint8_t output[1024];
    uint8_t expected[] = {0xb0, 0xd8, 0xac, 0x76, 0x40, 0x1b, 0xb2, 0x80 };
    uint16_t copied = 0;
    memset(output, 0, 1024);
    HSE_sink_res sres = heatshrink_encoder_sink(hse,
        input, sizeof(input), &copied);
    ASSERT_EQ(HSER_SINK_OK, sres);
    ASSERT_EQ(sizeof(input), copied);

    HSE_finish_res fres = heatshrink_encoder_finish(hse);
    ASSERT_EQ(HSER_FINISH_MORE, fres);

    ASSERT_EQ(HSER_POLL_EMPTY, heatshrink_encoder_poll(hse, output, 1024, &copied));
    fres = heatshrink_encoder_finish(hse);
    ASSERT_EQ(HSER_FINISH_DONE, fres);

    if (0) dump_buf("output", output, copied);
    ASSERT_EQ(sizeof(expected), copied);
    for (int i=0; i<sizeof(expected); i++) ASSERT_EQ(expected[i], output[i]);
    heatshrink_encoder_free(hse);
    PASS();
}
TEST encoder_should_emit_series_of_same_byte_as_literal_then_backref() {
    heatshrink_encoder *hse = heatshrink_encoder_alloc(8, 7);
    ASSERT(hse);
    uint8_t input[5];
    uint8_t output[1024];
    uint16_t copied = 0;
    uint8_t expected[] = {0xb0, 0x80, 0x01, 0x80};

    for (int i=0; i<5; i++) { input[i] = 'a'; } /* "aaaaa" */
    memset(output, 0, 1024);
    ASSERT_EQ(HSER_SINK_OK, heatshrink_encoder_sink(hse, input, 5, &copied));
    ASSERT_EQ(5, copied);
    
    /* Should get no output yet, since encoder doesn't know input is complete. */
    copied = 0;
    HSE_poll_res pres = heatshrink_encoder_poll(hse, output, 1024, &copied);
    ASSERT_EQ(HSER_POLL_EMPTY, pres);
    ASSERT_EQ(0, copied);

    /* Mark input stream as done, to force small input to be processed. */
    HSE_finish_res fres = heatshrink_encoder_finish(hse);
    ASSERT_EQ(HSER_FINISH_MORE, fres);

    pres = heatshrink_encoder_poll(hse, output, 1024, &copied);
    ASSERT_EQ(HSER_POLL_EMPTY, pres);
    ASSERT_EQ(4, copied);
    if (0) dump_buf("output", output, copied);
    for (int i=0; i<copied; i++) ASSERT_EQ(expected[i], output[i]);

    ASSERT_EQ(HSER_FINISH_DONE, heatshrink_encoder_finish(hse));
    
    heatshrink_encoder_free(hse);
    PASS();
}
TEST encoder_should_emit_data_without_repetitions_as_literal_sequence() {
    heatshrink_encoder *hse = heatshrink_encoder_alloc(8, 7);
    ASSERT(hse);
    uint8_t input[5];
    uint8_t output[1024];
    uint16_t copied = 0;
    uint8_t expected[] = { 0x80, 0x40, 0x60, 0x50, 0x38, 0x20 };

    for (int i=0; i<5; i++) { input[i] = i; }
    memset(output, 0, 1024);
    ASSERT_EQ(HSER_SINK_OK, heatshrink_encoder_sink(hse, input, 5, &copied));
    ASSERT_EQ(5, copied);
    
    /* Should get no output yet, since encoder doesn't know input is complete. */
    copied = 0;
    HSE_poll_res pres = heatshrink_encoder_poll(hse, output, 1024, &copied);
    ASSERT_EQ(HSER_POLL_EMPTY, pres);
    ASSERT_EQ(0, copied);

    /* Mark input stream as done, to force small input to be processed. */
    HSE_finish_res fres = heatshrink_encoder_finish(hse);
    ASSERT_EQ(HSER_FINISH_MORE, fres);

    pres = heatshrink_encoder_poll(hse, output, 1024, &copied);
    ASSERT_EQ(HSER_POLL_EMPTY, pres);

    for (int i=0; i<sizeof(expected); i++) {
        ASSERT_EQ(expected[i], output[i]);
    }

    ASSERT_EQ(HSER_FINISH_DONE, heatshrink_encoder_finish(hse));
    
    heatshrink_encoder_free(hse);
    PASS();
}
TEST encoder_poll_should_indicate_when_no_input_is_provided() {
    heatshrink_encoder *hse = heatshrink_encoder_alloc(8, 7);
    uint8_t output[512];
    uint16_t output_size = 0;

    HSE_poll_res res = heatshrink_encoder_poll(hse,
        output, 512, &output_size);
    ASSERT_EQ(HSER_POLL_EMPTY, res);
    heatshrink_encoder_free(hse);
    PASS();
}
TEST encoder_sink_should_reject_nulls() {
    heatshrink_encoder *hse = heatshrink_encoder_alloc(8, 7);
    uint8_t input[] = {'f', 'o', 'o'};
    uint16_t input_size = 0;
    ASSERT(hse);
    ASSERT_EQ(HSER_SINK_ERROR_NULL, heatshrink_encoder_sink(NULL, input, 3, &input_size));
    ASSERT_EQ(HSER_SINK_ERROR_NULL, heatshrink_encoder_sink(hse, NULL, 3, &input_size));
    ASSERT_EQ(HSER_SINK_ERROR_NULL, heatshrink_encoder_sink(hse, input, 3, NULL));
    heatshrink_encoder_free(hse);
    PASS();
}
TEST encoder_sink_should_accept_partial_input_when_some_will_fit() {
    heatshrink_encoder *hse = heatshrink_encoder_alloc(8, 7);
    ASSERT(hse);
    uint8_t input[512];
    uint16_t bytes_copied = 0;
    memset(input, '*', 512);
    ASSERT_EQ(HSER_SINK_OK, heatshrink_encoder_sink(hse,
            input, 512, &bytes_copied));
    ASSERT_EQ(256, bytes_copied);

    heatshrink_encoder_free(hse);
    PASS();
}
Ejemplo n.º 10
0
TEST encoder_sink_should_accept_input_when_it_will_fit(void) {
    heatshrink_encoder *hse = heatshrink_encoder_alloc(8, 7);
    ASSERT(hse);
    uint8_t input[256];
    size_t bytes_copied = 0;
    memset(input, '*', 256);
    ASSERT_EQ(HSER_SINK_OK, heatshrink_encoder_sink(hse,
            input, 256, &bytes_copied));
    ASSERT_EQ(256, bytes_copied);

    heatshrink_encoder_free(hse);
    PASS();
}
TEST encoder_poll_should_reject_nulls() {
    heatshrink_encoder *hse = heatshrink_encoder_alloc(8, 7);
    uint8_t output[256];
    uint16_t output_size = 0;
    ASSERT_EQ(HSER_POLL_ERROR_NULL, heatshrink_encoder_poll(NULL,
            output, 256, &output_size));
    ASSERT_EQ(HSER_POLL_ERROR_NULL, heatshrink_encoder_poll(hse,
            NULL, 256, &output_size));
    ASSERT_EQ(HSER_POLL_ERROR_NULL, heatshrink_encoder_poll(hse,
            output, 256, NULL));

    heatshrink_encoder_free(hse);
    PASS();
}
Ejemplo n.º 12
0
size_t compressHeatshrink(char *in, int insize, char *out, int outsize, int level) {
	char *inp=in;
	char *outp=out;
	size_t len;
	int ws[]={5, 6, 8, 11, 13};
	int ls[]={3, 3, 4, 4, 4};
	HSE_poll_res pres;
	HSE_sink_res sres;
	size_t r;
	if (level==-1) level=8;
	level=(level-1)/2; //level is now 0, 1, 2, 3, 4
	heatshrink_encoder *enc=heatshrink_encoder_alloc(ws[level], ls[level]);
	if (enc==NULL) {
		perror("allocating mem for heatshrink");
		exit(1);
	}
	//Save encoder parms as first byte
	*outp=(ws[level]<<4)|ls[level];
	outp++; outsize--;

	r=1;
	do {
		if (insize>0) {
			sres=heatshrink_encoder_sink(enc, inp, insize, &len);
			if (sres!=HSER_SINK_OK) break;
			inp+=len; insize-=len;
			if (insize==0) heatshrink_encoder_finish(enc);
		}
		do {
			pres=heatshrink_encoder_poll(enc, outp, outsize, &len);
			if (pres!=HSER_POLL_MORE && pres!=HSER_POLL_EMPTY) break;
			outp+=len; outsize-=len;
			r+=len;
		} while (pres==HSER_POLL_MORE);
	} while (insize!=0);

	if (insize!=0) {
		fprintf(stderr, "Heatshrink: Bug? insize is still %d. sres=%d pres=%d\n", insize, sres, pres);
		exit(1);
	}

	heatshrink_encoder_free(enc);
	return r;
}
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();
}
Ejemplo n.º 14
0
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();
}
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();
}
Ejemplo n.º 16
0
/* PHP */
static ZEND_FUNCTION(hs_compress)
{
    zval *data;
    size_t data_len;
    size_t sink_sz = 0;
    size_t poll_sz = 0;
    HSE_sink_res sres;
    HSE_poll_res pres;
    HSE_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_compress : expects parameter to be string.");
        RETURN_FALSE;
    }

    //Allocate encoder
    heatshrink_encoder *hse = heatshrink_encoder_alloc(window, lookahead);
    if (hse == NULL) {
        zend_error(E_WARNING, "hs_compress : heatshrink_encoder_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+1;
    unsigned char *outbuff = (unsigned char *) emalloc(outbuff_len);

    size_t sunk = 0;
    do {
        sres = heatshrink_encoder_sink(hse, (unsigned char *) &(Z_STRVAL_P(data)[sunk]), data_len - sunk, &sink_sz);
        if (sres < 0) {
            zend_error(E_WARNING, "hs_compress : heatshrink_encoder_sink error");
            efree(outbuff);
            heatshrink_encoder_free(hse);
            RETURN_FALSE;
        }
        sunk += sink_sz;
        
        do {
            do {
                pres = heatshrink_encoder_poll(hse, &outbuff[poll_sz], outbuff_len - poll_sz, &sink_sz);

                if (pres < 0) {
                    zend_error(E_WARNING, "hs_compress : heatshrink_encoder_poll error");
                    efree(outbuff);
                    heatshrink_encoder_free(hse);
                    RETURN_FALSE;
                }
                poll_sz += sink_sz;
                if (poll_sz == outbuff_len && pres == HSER_POLL_MORE) {
                    //TODO: think of bettery way to compute buffer reallocation size
                    outbuff_len += data_len/2;
                    outbuff = erealloc(outbuff, outbuff_len);
                }

            } while (pres == HSER_POLL_MORE);
            
            if (sunk == data_len) {
                fres = heatshrink_encoder_finish(hse);
                if (fres < 0) {
                    zend_error(E_WARNING, "hs_compress : heatshrink_encoder_finish error");
                    efree(outbuff);
                    heatshrink_encoder_free(hse);
                    RETURN_FALSE;
                }
                if (fres == HSER_FINISH_DONE) {
                    RETVAL_STRINGL((char *) outbuff, poll_sz, 1);
                    efree(outbuff);
                    heatshrink_encoder_free(hse);
                    return;
                }
            }
        } while (fres == HSER_FINISH_MORE);
    } while (sunk < data_len);

    zend_error(E_WARNING, "hs_compress : general error");
    efree(outbuff);
    heatshrink_encoder_free(hse);
    RETURN_FALSE;
}