HSE_sink_res heatshrink_encoder_sink(heatshrink_encoder *hse,
        uint8_t *in_buf, size_t size, size_t *input_size) {
    if ((hse == NULL) || (in_buf == NULL) || (input_size == NULL)) {
        return HSER_SINK_ERROR_NULL;
    }

    /* Sinking more content after saying the content is done, tsk tsk */
    if (is_finishing(hse)) { return HSER_SINK_ERROR_MISUSE; }

    /* Sinking more content before processing is done */
    if (hse->state != HSES_NOT_FULL) { return HSER_SINK_ERROR_MISUSE; }

    uint16_t write_offset = get_input_offset(hse) + hse->input_size;
    uint16_t ibs = get_input_buffer_size(hse);
    uint16_t rem = ibs - hse->input_size;
    uint16_t cp_sz = rem < size ? rem : size;

    memcpy(&hse->buffer[write_offset], in_buf, cp_sz);
    *input_size = cp_sz;
    hse->input_size += cp_sz;

    LOG("-- sunk %u bytes (of %zu) into encoder at %d, input buffer now has %u\n",
        cp_sz, size, write_offset, hse->input_size);
    if (cp_sz == rem) {
        LOG("-- internal buffer is now full\n");
        hse->state = HSES_FILLED;
    }

    return HSER_SINK_OK;
}
Esempio n. 2
0
static HSE_state ICACHE_FLASH_ATTR st_step_search(heatshrink_encoder *hse) {
    uint16_t window_length = get_input_buffer_size(hse);
    uint16_t lookahead_sz = get_lookahead_size(hse);
    uint16_t msi = hse->match_scan_index;
    LOG("## step_search, scan @ +%d (%d/%d), input size %d\n",
        msi, hse->input_size + msi, 2*window_length, hse->input_size);

    bool fin = is_finishing(hse);
    if (msi >= hse->input_size - (fin ? 0 : lookahead_sz)) {
        /* Current search buffer is exhausted, copy it into the
         * backlog and await more input. */
        LOG("-- end of search @ %d, saving backlog\n", msi);
        return HSES_SAVE_BACKLOG;
    }

    uint16_t input_offset = get_input_offset(hse);
    uint16_t end = input_offset + msi;

    uint16_t start = 0;
    if (backlog_is_filled(hse)) { /* last WINDOW_LENGTH bytes */
        start = end - window_length + 1;
    } else if (backlog_is_partial(hse)) { /* clamp to available data */
        start = end - window_length + 1;
        if (start < lookahead_sz) { start = lookahead_sz; }
    } else {              /* only scan available input */
        start = input_offset;
    }

    uint16_t max_possible = lookahead_sz;
    if (hse->input_size - msi < lookahead_sz) {
        max_possible = hse->input_size - msi;
    }
    
    uint16_t match_length = 0;
    uint16_t match_pos = find_longest_match(hse,
        start, end, max_possible, &match_length);
    
    if (match_pos == MATCH_NOT_FOUND) {
        LOG("ss Match not found\n");
        hse->match_scan_index++;
        hse->flags |= FLAG_HAS_LITERAL;
        hse->match_length = 0;
        return HSES_YIELD_TAG_BIT;
    } else {
        LOG("ss Found match of %d bytes at %d\n", match_length, match_pos);
        hse->match_pos = match_pos;
        hse->match_length = match_length;
        ASSERT(match_pos < 1 << hse->window_sz2 /*window_length*/);

        return HSES_YIELD_TAG_BIT;
    }
}
static HSE_state st_step_search(heatshrink_encoder *hse) {
    uint16_t window_length = get_input_buffer_size(hse);
    uint16_t lookahead_sz = get_lookahead_size(hse);
    uint16_t msi = hse->match_scan_index;
    LOG("## step_search, scan @ +%d (%d/%d), input size %d\n",
        msi, hse->input_size + msi, 2*window_length, hse->input_size);

    bool fin = is_finishing(hse);
    if (msi > hse->input_size - (fin ? 1 : lookahead_sz)) {
        /* Current search buffer is exhausted, copy it into the
         * backlog and await more input. */
        LOG("-- end of search @ %d\n", msi);
        return fin ? HSES_FLUSH_BITS : HSES_SAVE_BACKLOG;
    }

    uint16_t input_offset = get_input_offset(hse);
    uint16_t end = input_offset + msi;
    uint16_t start = end - window_length;

    uint16_t max_possible = lookahead_sz;
    if (hse->input_size - msi < lookahead_sz) {
        max_possible = hse->input_size - msi;
    }
    
    uint16_t match_length = 0;
    uint16_t match_pos = find_longest_match(hse,
        start, end, max_possible, &match_length);
    
    if (match_pos == MATCH_NOT_FOUND) {
        LOG("ss Match not found\n");
        hse->match_scan_index++;
        hse->match_length = 0;
        return HSES_YIELD_TAG_BIT;
    } else {
        LOG("ss Found match of %d bytes at %d\n", match_length, match_pos);
        hse->match_pos = match_pos;
        hse->match_length = match_length;
        ASSERT(match_pos < 1 << HEATSHRINK_ENCODER_WINDOW_BITS(hse) /*window_length*/);

        return HSES_YIELD_TAG_BIT;
    }
}
static void do_indexing(heatshrink_encoder *hse) {
#if HEATSHRINK_USE_INDEX
    /* Build an index array I that contains flattened linked lists
     * for the previous instances of every byte in the buffer.
     * 
     * For example, if buf[200] == 'x', then index[200] will either
     * be an offset i such that buf[i] == 'x', or a negative offset
     * to indicate end-of-list. This significantly speeds up matching,
     * while only using sizeof(uint16_t)*sizeof(buffer) bytes of RAM.
     *
     * Future optimization options:
     * 1. Since any negative value represents end-of-list, the other
     *    15 bits could be used to improve the index dynamically.
     *    
     * 2. Likewise, the last lookahead_sz bytes of the index will
     *    not be usable, so temporary data could be stored there to
     *    dynamically improve the index.
     * */
    struct hs_index *hsi = HEATSHRINK_ENCODER_INDEX(hse);
    int16_t last[256];
    memset(last, 0xFF, sizeof(last));

    uint8_t * const data = hse->buffer;
    int16_t * const index = hsi->index;

    const uint16_t input_offset = get_input_offset(hse);
    const uint16_t end = input_offset + hse->input_size;

    for (uint16_t i=0; i<end; i++) {
        uint8_t v = data[i];
        int16_t lv = last[v];
        index[i] = lv;
        last[v] = i;
    }
#else
    (void)hse;
#endif
}