#include #include "igzip_lib.h" #include "huffman.h" #include "huff_codes.h" #include "bitbuf2.h" extern const struct isal_hufftables hufftables_default; static inline void update_state(struct isal_zstream *stream, uint8_t * start_in, uint8_t * next_in, uint8_t * end_in) { struct isal_zstate *state = &stream->internal_state; uint32_t bytes_written; if (next_in - start_in > 0) state->has_hist = IGZIP_HIST; stream->next_in = next_in; stream->total_in += next_in - start_in; stream->avail_in = end_in - next_in; bytes_written = buffer_used(&state->bitbuf); stream->total_out += bytes_written; stream->next_out += bytes_written; stream->avail_out -= bytes_written; } void isal_deflate_body_base(struct isal_zstream *stream) { uint32_t literal, hash; uint8_t *start_in, *next_in, *end_in, *end, *next_hash; uint16_t match_length; uint32_t dist; uint64_t code, code_len, code2, code_len2; struct isal_zstate *state = &stream->internal_state; uint16_t *last_seen = state->head; uint8_t *file_start = (uint8_t *) ((uintptr_t) stream->next_in - stream->total_in); uint32_t hist_size = state->dist_mask; uint32_t hash_mask = state->hash_mask; if (stream->avail_in == 0) { if (stream->end_of_stream || stream->flush != NO_FLUSH) state->state = ZSTATE_FLUSH_READ_BUFFER; return; } set_buf(&state->bitbuf, stream->next_out, stream->avail_out); start_in = stream->next_in; end_in = start_in + stream->avail_in; next_in = start_in; while (next_in + ISAL_LOOK_AHEAD < end_in) { if (is_full(&state->bitbuf)) { update_state(stream, start_in, next_in, end_in); return; } literal = load_le_u32(next_in); hash = compute_hash(literal) & hash_mask; dist = (next_in - file_start - last_seen[hash]) & 0xFFFF; last_seen[hash] = (uint64_t) (next_in - file_start); /* The -1 are to handle the case when dist = 0 */ if (dist - 1 < hist_size) { assert(dist != 0); match_length = compare258(next_in - dist, next_in, 258); if (match_length >= SHORTEST_MATCH) { next_hash = next_in; #ifdef ISAL_LIMIT_HASH_UPDATE end = next_hash + 3; #else end = next_hash + match_length; #endif next_hash++; for (; next_hash < end; next_hash++) { literal = load_le_u32(next_hash); hash = compute_hash(literal) & hash_mask; last_seen[hash] = (uint64_t) (next_hash - file_start); } get_len_code(stream->hufftables, match_length, &code, &code_len); get_dist_code(stream->hufftables, dist, &code2, &code_len2); code |= code2 << code_len; code_len += code_len2; write_bits(&state->bitbuf, code, code_len); next_in += match_length; continue; } } get_lit_code(stream->hufftables, literal & 0xFF, &code, &code_len); write_bits(&state->bitbuf, code, code_len); next_in++; } update_state(stream, start_in, next_in, end_in); assert(stream->avail_in <= ISAL_LOOK_AHEAD); if (stream->end_of_stream || stream->flush != NO_FLUSH) state->state = ZSTATE_FLUSH_READ_BUFFER; return; } void isal_deflate_finish_base(struct isal_zstream *stream) { uint32_t literal = 0, hash; uint8_t *start_in, *next_in, *end_in, *end, *next_hash; uint16_t match_length; uint32_t dist; uint64_t code, code_len, code2, code_len2; struct isal_zstate *state = &stream->internal_state; uint16_t *last_seen = state->head; uint8_t *file_start = (uint8_t *) ((uintptr_t) stream->next_in - stream->total_in); uint32_t hist_size = state->dist_mask; uint32_t hash_mask = state->hash_mask; set_buf(&state->bitbuf, stream->next_out, stream->avail_out); start_in = stream->next_in; end_in = start_in + stream->avail_in; next_in = start_in; if (stream->avail_in != 0) { while (next_in + 3 < end_in) { if (is_full(&state->bitbuf)) { update_state(stream, start_in, next_in, end_in); return; } literal = load_le_u32(next_in); hash = compute_hash(literal) & hash_mask; dist = (next_in - file_start - last_seen[hash]) & 0xFFFF; last_seen[hash] = (uint64_t) (next_in - file_start); if (dist - 1 < hist_size) { /* The -1 are to handle the case when dist = 0 */ match_length = compare258(next_in - dist, next_in, end_in - next_in); if (match_length >= SHORTEST_MATCH) { next_hash = next_in; #ifdef ISAL_LIMIT_HASH_UPDATE end = next_hash + 3; #else end = next_hash + match_length; #endif next_hash++; for (; next_hash < end - 3; next_hash++) { literal = load_le_u32(next_hash); hash = compute_hash(literal) & hash_mask; last_seen[hash] = (uint64_t) (next_hash - file_start); } get_len_code(stream->hufftables, match_length, &code, &code_len); get_dist_code(stream->hufftables, dist, &code2, &code_len2); code |= code2 << code_len; code_len += code_len2; write_bits(&state->bitbuf, code, code_len); next_in += match_length; continue; } } get_lit_code(stream->hufftables, literal & 0xFF, &code, &code_len); write_bits(&state->bitbuf, code, code_len); next_in++; } while (next_in < end_in) { if (is_full(&state->bitbuf)) { update_state(stream, start_in, next_in, end_in); return; } literal = *next_in; get_lit_code(stream->hufftables, literal & 0xFF, &code, &code_len); write_bits(&state->bitbuf, code, code_len); next_in++; } } if (!is_full(&state->bitbuf)) { get_lit_code(stream->hufftables, 256, &code, &code_len); write_bits(&state->bitbuf, code, code_len); state->has_eob = 1; if (stream->end_of_stream == 1) state->state = ZSTATE_TRL; else state->state = ZSTATE_SYNC_FLUSH; } update_state(stream, start_in, next_in, end_in); return; } void isal_deflate_hash_base(uint16_t * hash_table, uint32_t hash_mask, uint32_t current_index, uint8_t * dict, uint32_t dict_len) { uint8_t *next_in = dict; uint8_t *end_in = dict + dict_len - SHORTEST_MATCH; uint32_t literal; uint32_t hash; uint16_t index = current_index - dict_len; while (next_in <= end_in) { literal = load_le_u32(next_in); hash = compute_hash(literal) & hash_mask; hash_table[hash] = index; index++; next_in++; } }