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; }
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 }