igzip: Implement stateful inflate.

Signed-off-by: Roy Oursler <roy.j.oursler@intel.com>
Reviewed-by: Greg Tucker <greg.b.tucker@intel.com>
This commit is contained in:
Roy Oursler 2016-07-21 10:33:30 -07:00 committed by Greg Tucker
parent 6b2bedfe28
commit 340e0f99df
9 changed files with 759 additions and 142 deletions

View File

@ -348,7 +348,12 @@ int inflate_check(uint8_t * z_buf, int z_size, uint8_t * in_buf, int in_size)
z_size -= gzip_hdr_bytes;
#endif
isal_inflate_init(&gstream, z_buf, z_size, test_buf, test_size);
isal_inflate_init(&gstream);
gstream.next_in = z_buf;
gstream.avail_in = z_size;
gstream.next_out = test_buf;
gstream.avail_out = test_size;
ret = isal_inflate_stateless(&gstream);
if (test_buf != NULL)

View File

@ -79,7 +79,9 @@ extern rfc1951_lookup_table
%define rfc_lookup r15
start_out_mem_offset equ 0
stack_size equ 8
read_in_mem_offset equ 8
read_in_length_mem_offset equ 16
stack_size equ 4 * 8 + 8
%define _dist_extra_bit_count 264
%define _dist_start _dist_extra_bit_count + 1*32
@ -280,6 +282,9 @@ decode_huffman_code_block_stateless_ %+ ARCH %+ :
mov end_in %+ d, dword [state + _avail_in]
add end_in, next_in
mov dword [state + _copy_overflow_len], 0
mov dword [state + _copy_overflow_dist], 0
mov tmp3 %+ d, dword [state + _total_out]
sub tmp3, next_out
neg tmp3
@ -292,8 +297,12 @@ decode_huffman_code_block_stateless_ %+ ARCH %+ :
cmp next_in, end_in
jg end_loop_block_pre
cmp read_in_length, 64
je skip_load
inflate_in_load next_in, end_in, read_in, read_in_length, tmp1, tmp2
skip_load:
mov tmp3, read_in
and tmp3, (1 << DECODE_LOOKUP_SIZE_LARGE) - 1
movzx next_sym, word [state + _lit_huff_code + 2 * tmp3]
@ -395,7 +404,7 @@ decode_len_dist:
sub copy_start, repeat_length
sub copy_start, look_back_dist2
;; ;; Check if a valid look back distances was decoded
;; ;; ;; Check if a valid look back distances was decoded
cmp copy_start, [rsp + start_out_mem_offset]
jl invalid_look_back_distance
MOVDQU xmm1, [copy_start]
@ -443,9 +452,13 @@ end_loop_block_pre:
;; Fix up in buffer and out buffer to reflect the actual buffer end
add end_out, OUT_BUFFER_SLOP
add end_in, IN_BUFFER_SLOP
end_loop_block:
;; Load read in buffer and decode next lit/len symbol
inflate_in_small_load next_in, end_in, read_in, read_in_length, tmp1, tmp2
mov [rsp + read_in_mem_offset], read_in
mov [rsp + read_in_length_mem_offset], read_in_length
decode_next state, DECODE_LOOKUP_SIZE_LARGE, _lit_huff_code, read_in, read_in_length, next_sym, tmp1, tmp2
;; Check that enough input was available to decode symbol
@ -457,7 +470,6 @@ end_loop_block:
je end_symbol
decode_len_dist_2:
;; Load length exta bits
mov next_bits, read_in
@ -484,8 +496,8 @@ decode_len_dist_2:
;; Calculate the look back distance and check for enough input
BZHI next_bits, next_bits, rcx, tmp1
SHRX read_in, read_in, rcx
sub read_in_length, rcx
add look_back_dist, next_bits
sub read_in_length, rcx
jl end_of_input
;; Setup code for byte copy using rep movsb
@ -494,32 +506,53 @@ decode_len_dist_2:
mov rcx, repeat_length
sub rsi, look_back_dist
;; Check for out buffer overflow
add next_out, repeat_length
cmp next_out, end_out
jg out_buffer_overflow
;; Check if a valid look back distance was decoded
cmp rsi, [rsp + start_out_mem_offset]
jl invalid_look_back_distance
;; Check for out buffer overflow
add repeat_length, next_out
cmp repeat_length, end_out
jg out_buffer_overflow_repeat
mov next_out, repeat_length
rep movsb
jmp end_loop_block
decode_literal:
;; Store literal decoded from the input stream
add next_out, 1
cmp next_out, end_out
jg out_buffer_overflow
jge out_buffer_overflow_lit
add next_out, 1
mov byte [next_out - 1], next_sym %+ b
jmp end_loop_block
;; Set exit codes
end_of_input:
mov read_in, [rsp + read_in_mem_offset]
mov read_in_length, [rsp + read_in_length_mem_offset]
mov rax, END_OF_INPUT
jmp end
out_buffer_overflow:
out_buffer_overflow_repeat:
mov rcx, end_out
sub rcx, next_out
sub repeat_length, rcx
sub repeat_length, next_out
rep movsb
mov [state + _copy_overflow_len], repeat_length %+ d
mov [state + _copy_overflow_dist], look_back_dist %+ d
mov next_out, end_out
mov rax, OUT_BUFFER_OVERFLOW
jmp end
out_buffer_overflow_lit:
mov read_in, [rsp + read_in_mem_offset]
mov read_in_length, [rsp + read_in_length_mem_offset]
mov rax, OUT_BUFFER_OVERFLOW
jmp end
@ -533,7 +566,7 @@ end_symbol_pre:
add end_in, IN_BUFFER_SLOP
end_symbol:
;; Set flag identifying a new block is required
mov byte [state + _new_block], 1
mov byte [state + _block_state], ISAL_BLOCK_NEW_HDR
xor rax, rax
end:
;; Save current buffer states

View File

@ -83,15 +83,15 @@ int isal_inflate_hist(struct inflate_state *state, struct isal_huff_histogram *h
uint32_t tmp;
memset(histogram, 0, sizeof(struct isal_huff_histogram));
while (state->new_block == 0 || state->bfinal == 0) {
if (state->new_block != 0) {
while (state->block_state != ISAL_BLOCK_INPUT_DONE) {
if (state->block_state == ISAL_BLOCK_NEW_HDR) {
tmp = read_header(state);
if (tmp)
return tmp;
}
if (state->btype == 0) {
if (state->block_state == ISAL_BLOCK_TYPE0) {
/* If the block is uncompressed, update state data accordingly */
if (state->avail_in < 4)
return END_OF_INPUT;
@ -108,18 +108,18 @@ int isal_inflate_hist(struct inflate_state *state, struct isal_huff_histogram *h
if (state->avail_in < len)
len = state->avail_in;
else
state->new_block = 1;
state->block_state = ISAL_BLOCK_NEW_HDR;
state->total_out += len;
state->next_in += len;
state->avail_in -= len + 4;
if (state->avail_in == 0 && state->new_block == 0)
if (state->avail_in == 0 && state->block_state == 0)
return END_OF_INPUT;
} else {
/* Else decode a huffman encoded block */
while (state->new_block == 0) {
while (state->block_state == ISAL_BLOCK_CODED) {
/* While not at the end of block, decode the next
* symbol */
next_lit = decode_next_large(state, &state->lit_huff_code);
@ -135,7 +135,7 @@ int isal_inflate_hist(struct inflate_state *state, struct isal_huff_histogram *h
else if (next_lit == 256)
/* Next symbol is end of block */
state->new_block = 1;
state->block_state = ISAL_BLOCK_NEW_HDR;
else if (next_lit < 286) {
/* Next symbol is a repeat length followed by a
@ -168,6 +168,9 @@ int isal_inflate_hist(struct inflate_state *state, struct isal_huff_histogram *h
return INVALID_SYMBOL;
}
}
if (state->bfinal != 0 && state->block_state == ISAL_BLOCK_NEW_HDR)
state->block_state = ISAL_BLOCK_INPUT_DONE;
}
state->next_in -= state->read_in_length / 8;
state->avail_in += state->read_in_length / 8;
@ -340,7 +343,9 @@ int main(int argc, char *argv[])
stream.hufftables = &hufftables_custom;
isal_deflate_stateless(&stream);
isal_inflate_init(&gstream, outbuf, stream.total_out, NULL, 0);
isal_inflate_init(&gstream);
gstream.next_in = outbuf;
gstream.avail_in = outbuf_size;
isal_inflate_hist(&gstream, &histogram2);
printf("Histogram Error \n");

View File

@ -72,6 +72,9 @@ void inline inflate_in_load(struct inflate_state *state, int min_required)
uint64_t temp = 0;
uint8_t new_bytes;
if (state->read_in_length >= 64)
return;
if (state->avail_in >= 8) {
/* If there is enough space to load a 64 bits, load the data and use
* that to fill read_in */
@ -94,7 +97,6 @@ void inline inflate_in_load(struct inflate_state *state, int min_required)
}
}
}
/* Returns the next bit_count bits from the in stream and shifts the stream over
@ -443,6 +445,8 @@ int inline setup_static_header(struct inflate_state *state)
make_inflate_huff_code_small(&state->dist_huff_code, dist_code, DIST_LEN + 2,
dist_count);
state->block_state = ISAL_BLOCK_CODED;
return 0;
}
@ -686,6 +690,8 @@ int inline setup_dynamic_header(struct inflate_state *state)
make_inflate_huff_code_small(&state->dist_huff_code, &lit_and_dist_huff[LIT_LEN],
DIST_LEN, dist_count);
state->block_state = ISAL_BLOCK_CODED;
return 0;
}
@ -694,61 +700,133 @@ int inline setup_dynamic_header(struct inflate_state *state)
int read_header(struct inflate_state *state)
{
uint8_t bytes;
state->new_block = 0;
uint32_t btype;
uint16_t len, nlen;
int ret = 0;
/* btype and bfinal are defined in RFC 1951, bfinal represents whether
* the current block is the end of block, and btype represents the
* encoding method on the current block. */
state->bfinal = inflate_in_read_bits(state, 1);
state->btype = inflate_in_read_bits(state, 2);
btype = inflate_in_read_bits(state, 2);
if (state->read_in_length < 0)
return END_OF_INPUT;
ret = END_OF_INPUT;
else if (btype == 0) {
inflate_in_load(state, 40);
bytes = state->read_in_length / 8;
if (bytes < 4)
return END_OF_INPUT;
state->read_in >>= state->read_in_length % 8;
state->read_in_length = bytes * 8;
len = state->read_in & 0xFFFF;
state->read_in >>= 16;
nlen = state->read_in & 0xFFFF;
state->read_in >>= 16;
state->read_in_length -= 32;
if (state->btype == 0) {
bytes = state->read_in_length / 8;
state->read_in = 0;
state->read_in_length = 0;
state->next_in -= bytes;
state->avail_in += bytes;
return 0;
state->read_in = 0;
state->read_in_length = 0;
} else if (state->btype == 1)
return setup_static_header(state);
/* Check if len and nlen match */
if (len != (~nlen & 0xffff))
return INVALID_NON_COMPRESSED_BLOCK_LENGTH;
else if (state->btype == 2)
return setup_dynamic_header(state);
state->type0_block_len = len;
state->block_state = ISAL_BLOCK_TYPE0;
ret = 0;
} else if (btype == 1)
ret = setup_static_header(state);
else if (btype == 2)
ret = setup_dynamic_header(state);
else
ret = INVALID_BLOCK_HEADER;
return ret;
}
/* Reads in the header pointed to by in_stream and sets up state to reflect that
* header information*/
int read_header_stateful(struct inflate_state *state)
{
uint64_t read_in_start = state->read_in;
int32_t read_in_length_start = state->read_in_length;
uint8_t *next_in_start = state->next_in;
uint32_t avail_in_start = state->avail_in;
int block_state_start = state->block_state;
int ret;
int copy_size;
int bytes_read;
if (block_state_start == ISAL_BLOCK_HDR) {
/* Setup so read_header decodes data in tmp_in_buffer */
copy_size = ISAL_INFLATE_MAX_HDR_SIZE - state->tmp_in_size;
if (copy_size > state->avail_in)
copy_size = state->avail_in;
memcpy(&state->tmp_in_buffer[state->tmp_in_size], state->next_in, copy_size);
state->next_in = state->tmp_in_buffer;
state->avail_in = state->tmp_in_size + copy_size;
}
ret = read_header(state);
if (block_state_start == ISAL_BLOCK_HDR) {
/* Setup so state is restored to a valid state */
bytes_read = state->next_in - state->tmp_in_buffer - state->tmp_in_size;
if (bytes_read < 0)
bytes_read = 0;
state->next_in = next_in_start + bytes_read;
state->avail_in = avail_in_start - bytes_read;
}
if (ret == END_OF_INPUT) {
/* Save off data so header can be decoded again with more data */
state->read_in = read_in_start;
state->read_in_length = read_in_length_start;
memcpy(&state->tmp_in_buffer[state->tmp_in_size], next_in_start,
avail_in_start);
state->tmp_in_size += avail_in_start;
state->avail_in = 0;
state->next_in = next_in_start + avail_in_start;
state->block_state = ISAL_BLOCK_HDR;
} else
state->tmp_in_size = 0;
return ret;
return INVALID_BLOCK_HEADER;
}
int inline decode_literal_block(struct inflate_state *state)
{
uint16_t len, nlen;
uint32_t len = state->type0_block_len;
/* If the block is uncompressed, perform a memcopy while
* updating state data */
if (state->avail_in < 4)
return END_OF_INPUT;
len = *(uint16_t *) state->next_in;
state->next_in += 2;
nlen = *(uint16_t *) state->next_in;
state->next_in += 2;
state->block_state = ISAL_BLOCK_NEW_HDR;
/* Check if len and nlen match */
if (len != (~nlen & 0xffff))
return INVALID_NON_COMPRESSED_BLOCK_LENGTH;
if (state->avail_out < len) {
len = state->avail_out;
state->block_state = ISAL_BLOCK_TYPE0;
}
if (state->avail_out < len)
return OUT_BUFFER_OVERFLOW;
if (state->avail_in < len)
if (state->avail_in < len) {
len = state->avail_in;
else
state->new_block = 1;
state->block_state = ISAL_BLOCK_TYPE0;
}
memcpy(state->next_out, state->next_in, len);
@ -756,11 +834,15 @@ int inline decode_literal_block(struct inflate_state *state)
state->avail_out -= len;
state->total_out += len;
state->next_in += len;
state->avail_in -= len + 4;
state->avail_in -= len;
state->type0_block_len -= len;
if (state->avail_in == 0 && state->new_block == 0)
if (state->avail_in == 0 && state->block_state != ISAL_BLOCK_NEW_HDR)
return END_OF_INPUT;
if (state->avail_out == 0 && state->type0_block_len > 0)
return OUT_BUFFER_OVERFLOW;
return 0;
}
@ -772,22 +854,45 @@ int decode_huffman_code_block_stateless_base(struct inflate_state *state)
uint8_t next_dist;
uint32_t repeat_length;
uint32_t look_back_dist;
uint64_t read_in_tmp;
int32_t read_in_length_tmp;
uint8_t *next_in_tmp;
uint32_t avail_in_tmp;
while (state->new_block == 0) {
state->copy_overflow_length = 0;
state->copy_overflow_distance = 0;
while (state->block_state == ISAL_BLOCK_CODED) {
/* While not at the end of block, decode the next
* symbol */
inflate_in_load(state, 0);
read_in_tmp = state->read_in;
read_in_length_tmp = state->read_in_length;
next_in_tmp = state->next_in;
avail_in_tmp = state->avail_in;
next_lit = decode_next_large(state, &state->lit_huff_code);
if (state->read_in_length < 0)
if (state->read_in_length < 0) {
state->read_in = read_in_tmp;
state->read_in_length = read_in_length_tmp;
state->next_in = next_in_tmp;
state->avail_in = avail_in_tmp;
return END_OF_INPUT;
}
if (next_lit < 256) {
/* If the next symbol is a literal,
* write out the symbol and update state
* data accordingly. */
if (state->avail_out < 1)
if (state->avail_out < 1) {
state->read_in = read_in_tmp;
state->read_in_length = read_in_length_tmp;
state->next_in = next_in_tmp;
state->avail_in = avail_in_tmp;
return OUT_BUFFER_OVERFLOW;
}
*state->next_out = next_lit;
state->next_out++;
@ -798,7 +903,7 @@ int decode_huffman_code_block_stateless_base(struct inflate_state *state)
/* If the next symbol is the end of
* block, update the state data
* accordingly */
state->new_block = 1;
state->block_state = ISAL_BLOCK_NEW_HDR;
} else if (next_lit < 286) {
/* Else if the next symbol is a repeat
@ -812,10 +917,6 @@ int decode_huffman_code_block_stateless_base(struct inflate_state *state)
inflate_in_read_bits(state,
rfc_lookup_table.len_extra_bit_count[next_lit
- 257]);
if (state->avail_out < repeat_length)
return OUT_BUFFER_OVERFLOW;
next_dist = decode_next_small(state, &state->dist_huff_code);
look_back_dist = rfc_lookup_table.dist_start[next_dist] +
@ -823,12 +924,23 @@ int decode_huffman_code_block_stateless_base(struct inflate_state *state)
rfc_lookup_table.dist_extra_bit_count
[next_dist]);
if (state->read_in_length < 0)
if (state->read_in_length < 0) {
state->read_in = read_in_tmp;
state->read_in_length = read_in_length_tmp;
state->next_in = next_in_tmp;
state->avail_in = avail_in_tmp;
return END_OF_INPUT;
}
if (look_back_dist > state->total_out)
return INVALID_LOOK_BACK_DISTANCE;
if (state->avail_out < repeat_length) {
state->copy_overflow_length = repeat_length - state->avail_out;
state->copy_overflow_distance = look_back_dist;
repeat_length = state->avail_out;
}
if (look_back_dist > repeat_length)
memcpy(state->next_out,
state->next_out - look_back_dist, repeat_length);
@ -838,6 +950,9 @@ int decode_huffman_code_block_stateless_base(struct inflate_state *state)
state->next_out += repeat_length;
state->avail_out -= repeat_length;
state->total_out += repeat_length;
if (state->copy_overflow_length > 0)
return OUT_BUFFER_OVERFLOW;
} else
/* Else the read in bits do not
* correspond to any valid symbol */
@ -846,45 +961,206 @@ int decode_huffman_code_block_stateless_base(struct inflate_state *state)
return 0;
}
void isal_inflate_init(struct inflate_state *state, uint8_t * in_stream, uint32_t in_size,
uint8_t * out_stream, uint64_t out_size)
void isal_inflate_init(struct inflate_state *state)
{
state->read_in = 0;
state->read_in_length = 0;
state->next_in = in_stream;
state->avail_in = in_size;
state->next_out = out_stream;
state->avail_out = out_size;
state->next_in = NULL;
state->avail_in = 0;
state->next_out = NULL;
state->avail_out = 0;
state->total_out = 0;
state->new_block = 1;
state->block_state = ISAL_BLOCK_NEW_HDR;
state->bfinal = 0;
state->type0_block_len = 0;
state->copy_overflow_length = 0;
state->copy_overflow_distance = 0;
state->tmp_in_size = 0;
state->tmp_out_processed = 0;
state->tmp_out_valid = 0;
}
int isal_inflate_stateless(struct inflate_state *state)
{
uint32_t ret;
uint32_t ret = 0;
while (state->new_block == 0 || state->bfinal == 0) {
if (state->new_block != 0) {
state->read_in = 0;
state->read_in_length = 0;
state->block_state = ISAL_BLOCK_NEW_HDR;
state->bfinal = 0;
state->total_out = 0;
while (state->block_state != ISAL_BLOCK_INPUT_DONE) {
if (state->block_state == ISAL_BLOCK_NEW_HDR) {
ret = read_header(state);
if (ret)
return ret;
break;
}
if (state->btype == 0)
if (state->block_state == ISAL_BLOCK_TYPE0)
ret = decode_literal_block(state);
else
ret = decode_huffman_code_block_stateless(state);
if (ret)
return ret;
break;
if (state->bfinal != 0 && state->block_state == ISAL_BLOCK_NEW_HDR)
state->block_state = ISAL_BLOCK_INPUT_DONE;
}
/* Undo count stuff of bytes read into the read buffer */
state->next_in -= state->read_in_length / 8;
state->avail_in += state->read_in_length / 8;
return ret;
}
int isal_inflate(struct inflate_state *state)
{
uint8_t *next_out = state->next_out;
uint32_t avail_out = state->avail_out;
uint32_t copy_size = 0;
int32_t shift_size = 0;
int ret = 0;
if (state->block_state != ISAL_BLOCK_FINISH) {
/* If space in tmp_out buffer, decompress into the tmp_out_buffer */
if (state->tmp_out_valid < 2 * ISAL_INFLATE_HIST_SIZE) {
/* Setup to start decoding into temp buffer */
state->next_out = &state->tmp_out_buffer[state->tmp_out_valid];
state->avail_out =
sizeof(state->tmp_out_buffer) - ISAL_INFLATE_SLOP -
state->tmp_out_valid;
if ((int32_t) state->avail_out < 0)
state->avail_out = 0;
/* Decode into internal buffer until exit */
while (state->block_state != ISAL_BLOCK_INPUT_DONE) {
if (state->block_state == ISAL_BLOCK_NEW_HDR
|| state->block_state == ISAL_BLOCK_HDR) {
ret = read_header_stateful(state);
if (ret)
break;
}
if (state->block_state == ISAL_BLOCK_TYPE0) {
ret = decode_literal_block(state);
} else
ret = decode_huffman_code_block_stateless(state);
if (ret)
break;
if (state->bfinal != 0
&& state->block_state == ISAL_BLOCK_NEW_HDR)
state->block_state = ISAL_BLOCK_INPUT_DONE;
}
/* Copy valid data from internal buffer into out_buffer */
if (state->copy_overflow_length != 0) {
byte_copy(state->next_out, state->copy_overflow_distance,
state->copy_overflow_length);
state->tmp_out_valid += state->copy_overflow_length;
state->next_out += state->copy_overflow_length;
state->total_out += state->copy_overflow_length;
state->copy_overflow_distance = 0;
state->copy_overflow_length = 0;
}
state->tmp_out_valid = state->next_out - state->tmp_out_buffer;
/* Setup state for decompressing into out_buffer */
state->next_out = next_out;
state->avail_out = avail_out;
}
/* Copy data from tmp_out buffer into out_buffer */
copy_size = state->tmp_out_valid - state->tmp_out_processed;
if (copy_size > avail_out)
copy_size = avail_out;
memcpy(state->next_out,
&state->tmp_out_buffer[state->tmp_out_processed], copy_size);
state->tmp_out_processed += copy_size;
state->avail_out -= copy_size;
state->next_out += copy_size;
if (ret == INVALID_LOOK_BACK_DISTANCE || ret == INVALID_BLOCK_HEADER
|| ret == INVALID_NON_COMPRESSED_BLOCK_LENGTH) {
/* Set total_out to not count data in tmp_out_buffer */
state->total_out -= state->tmp_out_valid - state->tmp_out_processed;
return ret;
}
/* If all data from tmp_out buffer has been processed, start
* decompressing into the out buffer */
if (state->tmp_out_processed == state->tmp_out_valid) {
while (state->block_state != ISAL_BLOCK_INPUT_DONE) {
if (state->block_state == ISAL_BLOCK_NEW_HDR
|| state->block_state == ISAL_BLOCK_HDR) {
ret = read_header_stateful(state);
if (ret)
break;
}
if (state->block_state == ISAL_BLOCK_TYPE0)
ret = decode_literal_block(state);
else
ret = decode_huffman_code_block_stateless(state);
if (ret)
break;
if (state->bfinal != 0
&& state->block_state == ISAL_BLOCK_NEW_HDR)
state->block_state = ISAL_BLOCK_INPUT_DONE;
}
}
if (state->block_state != ISAL_BLOCK_INPUT_DONE) {
/* Save decompression history in tmp_out buffer */
if (state->tmp_out_valid == state->tmp_out_processed
&& avail_out - state->avail_out >= ISAL_INFLATE_HIST_SIZE) {
memcpy(state->tmp_out_buffer,
state->next_out - ISAL_INFLATE_HIST_SIZE,
ISAL_INFLATE_HIST_SIZE);
state->tmp_out_valid = ISAL_INFLATE_HIST_SIZE;
state->tmp_out_processed = ISAL_INFLATE_HIST_SIZE;
} else if (state->tmp_out_processed >= ISAL_INFLATE_HIST_SIZE) {
shift_size = state->tmp_out_valid - ISAL_INFLATE_HIST_SIZE;
if (shift_size > state->tmp_out_processed)
shift_size = state->tmp_out_processed;
memmove(state->tmp_out_buffer,
&state->tmp_out_buffer[shift_size],
state->tmp_out_valid - shift_size);
state->tmp_out_valid -= shift_size;
state->tmp_out_processed -= shift_size;
}
if (state->copy_overflow_length != 0) {
byte_copy(&state->tmp_out_buffer[state->tmp_out_valid],
state->copy_overflow_distance,
state->copy_overflow_length);
state->tmp_out_valid += state->copy_overflow_length;
state->total_out += state->copy_overflow_length;
state->copy_overflow_distance = 0;
state->copy_overflow_length = 0;
}
if (ret == INVALID_LOOK_BACK_DISTANCE
|| ret == INVALID_BLOCK_HEADER
|| ret == INVALID_NON_COMPRESSED_BLOCK_LENGTH)
return ret;
} else if (state->tmp_out_valid == state->tmp_out_processed)
state->block_state = ISAL_BLOCK_FINISH;
}
return DECOMPRESSION_FINISHED;
}

View File

@ -208,9 +208,13 @@ int main(int argc, char *argv[])
perf_start(&start);
for (i = 0; i < iterations; i++) {
isal_inflate_init(&state, inbuf, inbuf_size, outbuf, outbuf_size);
isal_inflate_init(&state);
state.next_in = inbuf;
state.avail_in = inbuf_size;
state.next_out = outbuf;
state.avail_out = outbuf_size;
check = isal_inflate_stateless(&state);
check = isal_inflate(&state);
if (check) {
printf("Error in decompression with error %d\n", check);
break;

View File

@ -37,24 +37,129 @@
* are done in a stateless manner. */
#define MAX_INPUT_FILE_SIZE 2L*1024L*1024L*1024L
int test(uint8_t * compressed_stream, uint64_t * compressed_length,
uint8_t * uncompressed_stream, int uncompressed_length,
uint8_t * uncompressed_test_stream, int uncompressed_test_stream_length)
int inflate_multi_pass(uint8_t * compress_buf, uint64_t compress_len,
uint8_t * uncompress_buf, uint32_t * uncompress_len)
{
struct inflate_state *state = NULL;
int ret = 0;
uint8_t *comp_tmp = NULL, *uncomp_tmp = NULL;
uint32_t comp_tmp_size = 0, uncomp_tmp_size = 0;
uint32_t comp_processed = 0, uncomp_processed = 0;
state = malloc(sizeof(struct inflate_state));
if (state == NULL) {
printf("Failed to allocate memory\n");
exit(0);
}
isal_inflate_init(state);
state->next_in = NULL;
state->next_out = NULL;
state->avail_in = 0;
state->avail_out = 0;
while (1) {
if (state->avail_in == 0) {
comp_tmp_size = rand() % (compress_len + 1);
if (comp_tmp_size >= compress_len - comp_processed)
comp_tmp_size = compress_len - comp_processed;
if (comp_tmp_size != 0) {
if (comp_tmp != NULL) {
free(comp_tmp);
comp_tmp = NULL;
}
comp_tmp = malloc(comp_tmp_size);
if (comp_tmp == NULL) {
printf("Failed to allocate memory\n");
exit(0);
}
memcpy(comp_tmp, compress_buf + comp_processed, comp_tmp_size);
comp_processed += comp_tmp_size;
state->next_in = comp_tmp;
state->avail_in = comp_tmp_size;
}
}
if (state->avail_out == 0) {
/* Save uncompressed data into uncompress_buf */
if (uncomp_tmp != NULL) {
memcpy(uncompress_buf + uncomp_processed, uncomp_tmp,
uncomp_tmp_size);
uncomp_processed += uncomp_tmp_size;
}
uncomp_tmp_size = rand() % (*uncompress_len + 1);
/* Limit size of buffer to be smaller than maximum */
if (uncomp_tmp_size > *uncompress_len - uncomp_processed)
uncomp_tmp_size = *uncompress_len - uncomp_processed;
if (uncomp_tmp_size != 0) {
if (uncomp_tmp != NULL) {
fflush(0);
free(uncomp_tmp);
uncomp_tmp = NULL;
}
uncomp_tmp = malloc(uncomp_tmp_size);
if (uncomp_tmp == NULL) {
printf("Failed to allocate memory\n");
exit(0);
}
state->avail_out = uncomp_tmp_size;
state->next_out = uncomp_tmp;
}
}
ret = isal_inflate(state);
if (state->block_state == ISAL_BLOCK_FINISH || ret != 0) {
memcpy(uncompress_buf + uncomp_processed, uncomp_tmp, uncomp_tmp_size);
*uncompress_len = state->total_out;
break;
}
}
if (comp_tmp != NULL) {
free(comp_tmp);
comp_tmp = NULL;
}
if (uncomp_tmp != NULL) {
free(uncomp_tmp);
uncomp_tmp = NULL;
}
free(state);
return ret;
}
int test(uint8_t * compressed_stream,
uint64_t * compressed_length,
uint8_t * uncompressed_stream, uint32_t uncompressed_length,
uint8_t * uncompressed_test_stream, uint32_t uncompressed_test_stream_length)
{
struct inflate_state state;
int ret;
ret =
compress2(compressed_stream, compressed_length, uncompressed_stream,
uncompressed_length, 6);
compress2(compressed_stream, compressed_length,
uncompressed_stream, uncompressed_length, 6);
if (ret) {
printf("Failed compressing input with exit code %d", ret);
return ret;
}
isal_inflate_init(&state, compressed_stream + 2, *compressed_length - 2,
uncompressed_test_stream, uncompressed_test_stream_length);
ret = isal_inflate_stateless(&state);
ret =
inflate_multi_pass(compressed_stream + 2,
*compressed_length - 2 - 4,
uncompressed_test_stream, &uncompressed_test_stream_length);
switch (ret) {
case 0:
break;
@ -88,10 +193,10 @@ int test(uint8_t * compressed_stream, uint64_t * compressed_length,
break;
}
if (state.total_out != uncompressed_length) {
if (uncompressed_test_stream_length != uncompressed_length) {
printf("incorrect amount of data was decompressed from compressed data\n");
printf("%d decompressed of %d compressed", state.total_out,
uncompressed_length);
printf("%d decompressed of %d compressed",
uncompressed_test_stream_length, uncompressed_length);
return -1;
}
if (memcmp(uncompressed_stream, uncompressed_test_stream, uncompressed_length)) {
@ -105,6 +210,7 @@ int test(uint8_t * compressed_stream, uint64_t * compressed_length,
printf(" decompressed data is not the same as the compressed data\n");
return -1;
}
return 0;
}
@ -120,7 +226,6 @@ int main(int argc, char **argv)
if (argc == 1)
printf("Error, no input file\n");
for (i = 1; i < argc; i++) {
file = fopen(argv[i], "r");
if (file == NULL) {
@ -128,7 +233,7 @@ int main(int argc, char **argv)
return 1;
} else
printf("Starting file %s", argv[i]);
fflush(0);
fseek(file, 0, SEEK_END);
file_length = ftell(file);
fseek(file, 0, SEEK_SET);
@ -145,7 +250,6 @@ int main(int argc, char **argv)
uncompressed_test_stream = malloc(file_length);
}
compressed_stream = malloc(compressed_length);
if (uncompressed_stream == NULL && file_length != 0) {
printf("Failed to allocate memory\n");
exit(0);
@ -163,7 +267,6 @@ int main(int argc, char **argv)
uncompressed_length = fread(uncompressed_stream, 1, file_length, file);
uncompressed_test_stream_length = uncompressed_length;
ret =
test(compressed_stream, &compressed_length, uncompressed_stream,
uncompressed_length, uncompressed_test_stream,
@ -175,10 +278,8 @@ int main(int argc, char **argv)
else
printf(" ");
printf("0x%02x,", compressed_stream[j]);
}
printf("\n");
}
fflush(0);
@ -188,13 +289,11 @@ int main(int argc, char **argv)
free(uncompressed_stream);
if (uncompressed_test_stream != NULL)
free(uncompressed_test_stream);
if (ret) {
printf(" ... Fail with exit code %d\n", ret);
return ret;
} else
printf(" ... Pass\n");
fin_ret |= ret;
}
return fin_ret;

View File

@ -113,6 +113,8 @@ const int gzip_extra_bytes = 0;
#endif
int inflate_type = 0;
struct isal_hufftables *hufftables = NULL;
#define HISTORY_SIZE 32*1024
@ -306,29 +308,192 @@ uint32_t check_gzip_header(uint8_t * z_buf)
return ret;
}
uint32_t check_gzip_trl(struct inflate_state * gstream)
uint32_t check_gzip_trl(uint64_t gzip_crc, uint8_t * uncompress_buf, uint32_t uncompress_len)
{
uint8_t *index = NULL;
uint32_t crc, ret = 0;
uint64_t crc, ret = 0;
index = gstream->next_out - gstream->total_out;
crc = find_crc(index, gstream->total_out);
crc = find_crc(uncompress_buf, uncompress_len);
if (gstream->total_out != *(uint32_t *) (gstream->next_in + 4) ||
crc != *(uint32_t *) gstream->next_in)
crc = ((uint64_t) uncompress_len << 32) | crc;
if (crc != gzip_crc)
ret = INCORRECT_GZIP_TRAILER;
return ret;
}
#endif
int inflate_stateless_pass(uint8_t * compress_buf, uint64_t compress_len,
uint8_t * uncompress_buf, uint32_t * uncompress_len)
{
struct inflate_state state;
int ret = 0;
state.next_in = compress_buf;
state.avail_in = compress_len;
state.next_out = uncompress_buf;
state.avail_out = *uncompress_len;
ret = isal_inflate_stateless(&state);
*uncompress_len = state.total_out;
#ifndef DEFLATE
if (!ret)
ret =
check_gzip_trl(*(uint64_t *) state.next_in, uncompress_buf,
*uncompress_len);
state.avail_in -= 8;
#endif
if (ret == 0 && state.avail_in != 0)
ret = INFLATE_LEFTOVER_INPUT;
return ret;
}
int inflate_multi_pass(uint8_t * compress_buf, uint64_t compress_len,
uint8_t * uncompress_buf, uint32_t * uncompress_len)
{
struct inflate_state *state = NULL;
int ret = 0;
uint8_t *comp_tmp = NULL, *uncomp_tmp = NULL;
uint32_t comp_tmp_size = 0, uncomp_tmp_size = 0;
uint32_t comp_processed = 0, uncomp_processed = 0;
int32_t read_in_old = 0;
state = malloc(sizeof(struct inflate_state));
if (state == NULL) {
printf("Failed to allocate memory\n");
exit(0);
}
isal_inflate_init(state);
state->next_in = NULL;
state->next_out = NULL;
state->avail_in = 0;
state->avail_out = 0;
#ifndef DEFLATE
compress_len -= 8;
#endif
while (1) {
if (state->avail_in == 0) {
comp_tmp_size = rand() % (compress_len + 1);
if (comp_tmp_size >= compress_len - comp_processed)
comp_tmp_size = compress_len - comp_processed;
if (comp_tmp_size != 0) {
if (comp_tmp != NULL) {
free(comp_tmp);
comp_tmp = NULL;
}
comp_tmp = malloc(comp_tmp_size);
if (comp_tmp == NULL) {
printf("Failed to allocate memory\n");
return MALLOC_FAILED;
}
memcpy(comp_tmp, compress_buf + comp_processed, comp_tmp_size);
comp_processed += comp_tmp_size;
state->next_in = comp_tmp;
state->avail_in = comp_tmp_size;
}
}
if (state->avail_out == 0) {
/* Save uncompressed data into uncompress_buf */
if (uncomp_tmp != NULL) {
memcpy(uncompress_buf + uncomp_processed, uncomp_tmp,
uncomp_tmp_size);
uncomp_processed += uncomp_tmp_size;
}
uncomp_tmp_size = rand() % (*uncompress_len + 1);
/* Limit size of buffer to be smaller than maximum */
if (uncomp_tmp_size > *uncompress_len - uncomp_processed)
uncomp_tmp_size = *uncompress_len - uncomp_processed;
if (uncomp_tmp_size != 0) {
if (uncomp_tmp != NULL) {
fflush(0);
free(uncomp_tmp);
uncomp_tmp = NULL;
}
uncomp_tmp = malloc(uncomp_tmp_size);
if (uncomp_tmp == NULL) {
printf("Failed to allocate memory\n");
return MALLOC_FAILED;
}
state->avail_out = uncomp_tmp_size;
state->next_out = uncomp_tmp;
}
}
ret = isal_inflate(state);
if (state->block_state == ISAL_BLOCK_FINISH || ret != 0) {
memcpy(uncompress_buf + uncomp_processed, uncomp_tmp, uncomp_tmp_size);
*uncompress_len = state->total_out;
break;
}
if (*uncompress_len - uncomp_processed == 0 && state->avail_out == 0
&& state->tmp_out_valid - state->tmp_out_processed > 0) {
ret = INFLATE_OUT_BUFFER_OVERFLOW;
break;
}
if (compress_len - comp_processed == 0 && state->avail_in == 0
&& (state->block_state != ISAL_BLOCK_INPUT_DONE)
&& state->tmp_out_valid - state->tmp_out_processed == 0) {
if (state->read_in_length == read_in_old) {
ret = INFLATE_END_OF_INPUT;
break;
}
read_in_old = state->read_in_length;
}
}
#ifndef DEFLATE
if (!ret)
ret =
check_gzip_trl(*(uint64_t *) & compress_buf[compress_len],
uncompress_buf, *uncompress_len);
#endif
if (ret == 0 && state->avail_in != 0)
ret = INFLATE_LEFTOVER_INPUT;
if (comp_tmp != NULL) {
free(comp_tmp);
comp_tmp = NULL;
}
if (uncomp_tmp != NULL) {
free(uncomp_tmp);
uncomp_tmp = NULL;
}
free(state);
return ret;
}
/* Inflate the compressed data and check that the decompressed data agrees with the input data */
int inflate_check(uint8_t * z_buf, int z_size, uint8_t * in_buf, int in_size)
{
/* Test inflate with reference inflate */
int ret = 0;
struct inflate_state gstream;
uint32_t test_size = in_size;
uint8_t *test_buf = NULL;
int mem_result = 0;
@ -336,23 +501,27 @@ int inflate_check(uint8_t * z_buf, int z_size, uint8_t * in_buf, int in_size)
if (in_size > 0) {
assert(in_buf != NULL);
test_buf = malloc(test_size);
if (test_buf == NULL)
return MALLOC_FAILED;
}
if (test_buf != NULL)
memset(test_buf, 0xff, test_size);
#ifndef DEFLATE
int gzip_hdr_result, gzip_trl_result;
int gzip_hdr_result = 0, gzip_trl_result = 0;
gzip_hdr_result = check_gzip_header(z_buf);
z_buf += gzip_hdr_bytes;
z_size -= gzip_hdr_bytes;
#endif
isal_inflate_init(&gstream, z_buf, z_size, test_buf, test_size);
ret = isal_inflate_stateless(&gstream);
if (inflate_type == 0) {
ret = inflate_stateless_pass(z_buf, z_size, test_buf, &test_size);
inflate_type = 1;
} else {
ret = inflate_multi_pass(z_buf, z_size, test_buf, &test_size);
inflate_type = 0;
}
if (test_buf != NULL)
mem_result = memcmp(in_buf, test_buf, in_size);
@ -362,22 +531,16 @@ int inflate_check(uint8_t * z_buf, int z_size, uint8_t * in_buf, int in_size)
if (mem_result)
for (i = 0; i < in_size; i++) {
if (in_buf[i] != test_buf[i]) {
printf("First incorrect data at 0x%x of 0x%x, 0x%x != 0x%x\n",
i, in_size, in_buf[i], test_buf[i]);
printf
("First incorrect data at 0x%x of 0x%x, 0x%x != 0x%x\n",
i, in_size, in_buf[i], test_buf[i]);
break;
}
}
#endif
#ifndef DEFLATE
gzip_trl_result = check_gzip_trl(&gstream);
gstream.avail_in -= gzip_trl_bytes;
gstream.next_in += gzip_trl_bytes;
#endif
if (test_buf != NULL)
free(test_buf);
switch (ret) {
case 0:
break;
@ -399,17 +562,22 @@ int inflate_check(uint8_t * z_buf, int z_size, uint8_t * in_buf, int in_size)
case INVALID_LOOK_BACK_DISTANCE:
return INFLATE_INVALID_LOOK_BACK_DISTANCE;
break;
case INFLATE_LEFTOVER_INPUT:
return INFLATE_LEFTOVER_INPUT;
break;
#ifndef DEFLATE
case INCORRECT_GZIP_TRAILER:
gzip_trl_result = INCORRECT_GZIP_TRAILER;
break;
#endif
default:
return INFLATE_GENERAL_ERROR;
break;
}
if (gstream.avail_in != 0) {
printf("leftover = %d\n", gstream.avail_in);
return INFLATE_LEFTOVER_INPUT;
}
if (gstream.total_out != in_size)
if (test_size != in_size)
return INFLATE_INCORRECT_OUTPUT_SIZE;
if (mem_result)

View File

@ -61,9 +61,11 @@ FIELD _avail_in, 4, 4
FIELD _read_in_length,4, 4
FIELD _lit_huff_code, _inflate_huff_code_large_size, _inflate_huff_code_large_align
FIELD _dist_huff_code,_inflate_huff_code_small_size, _inflate_huff_code_small_align
FIELD _new_block, 1, 1
FIELD _bfinal, 1, 1
FIELD _btype, 1, 1
FIELD _block_state, 4, 4
FIELD _bfinal, 4, 4
FIELD _type0_block_len, 4, 4
FIELD _copy_overflow_len, 4, 4
FIELD _copy_overflow_dist, 4, 4
%assign _inflate_state_size _FIELD_OFFSET
%assign _inflate_state_align _STRUCT_ALIGN
@ -74,7 +76,12 @@ _lit_huff_code_long_code_lookup equ _lit_huff_code+_long_code_lookup_large
_dist_huff_code_small_code_lookup equ _dist_huff_code+_small_code_lookup_small
_dist_huff_code_long_code_lookup equ _dist_huff_code+_long_code_lookup_small
ISAL_BLOCK_NEW_HDR equ 0
ISAL_BLOCK_HDR equ 1
ISAL_BLOCK_TYPE0 equ 2
ISAL_BLOCK_CODED equ 3
ISAL_BLOCK_END equ 4
ISAL_BLOCK_FINISH equ 5
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@ -16,6 +16,18 @@
#define DECODE_LOOKUP_SIZE_LARGE 13
#define DECODE_LOOKUP_SIZE_SMALL 10
#define ISAL_INFLATE_HIST_SIZE (32*1024)
#define ISAL_INFLATE_SLOP 17*16
#define ISAL_INFLATE_MAX_HDR_SIZE 360
enum isal_block_state {
ISAL_BLOCK_NEW_HDR, /* Just starting a new block */
ISAL_BLOCK_HDR, /* In the middle of reading in a block header */
ISAL_BLOCK_TYPE0, /* Decoding a type 0 block */
ISAL_BLOCK_CODED, /* Decoding a huffman coded block */
ISAL_BLOCK_INPUT_DONE, /* Decompression of input is completed */
ISAL_BLOCK_FINISH /* Decompression of input is completed and all data has been flushed to output */
};
/*
* Data structure used to store a Huffman code for fast lookup. It works by
* performing a lookup in small_code_lookup that hopefully yields the correct
@ -62,14 +74,13 @@
* code length and code value forces the maximum offset to be less than 288.
*/
struct inflate_huff_code_large{
uint16_t short_code_lookup[ 1 << (DECODE_LOOKUP_SIZE_LARGE)];
struct inflate_huff_code_large {
uint16_t short_code_lookup[1 << (DECODE_LOOKUP_SIZE_LARGE)];
uint16_t long_code_lookup[288 + (1 << (15 - DECODE_LOOKUP_SIZE_LARGE))];
};
struct inflate_huff_code_small{
uint16_t short_code_lookup[ 1 << (DECODE_LOOKUP_SIZE_SMALL)];
struct inflate_huff_code_small {
uint16_t short_code_lookup[1 << (DECODE_LOOKUP_SIZE_SMALL)];
uint16_t long_code_lookup[32 + (1 << (15 - DECODE_LOOKUP_SIZE_SMALL))];
};
@ -84,18 +95,27 @@ struct inflate_state {
int32_t read_in_length;
struct inflate_huff_code_large lit_huff_code;
struct inflate_huff_code_small dist_huff_code;
uint8_t new_block;
uint8_t bfinal;
uint8_t btype;
enum isal_block_state block_state;
uint32_t bfinal;
int32_t type0_block_len;
int32_t copy_overflow_length;
int32_t copy_overflow_distance;
int32_t tmp_in_size;
int32_t tmp_out_valid;
int32_t tmp_out_processed;
uint8_t tmp_in_buffer[ISAL_INFLATE_MAX_HDR_SIZE];
uint8_t tmp_out_buffer[2 * ISAL_INFLATE_HIST_SIZE + ISAL_INFLATE_SLOP];
};
/* Initialize a struct inflate_state for deflate compressed input data at in_stream and to output
* data into out_stream */
void isal_inflate_init(struct inflate_state *state, uint8_t *in_stream, uint32_t in_size,
uint8_t *out_stream, uint64_t out_size);
void isal_inflate_init(struct inflate_state *state);
/* Decompress a deflate data. This function assumes a call to igzip_inflate_init
* has been made to set up the state structure to allow for decompression.*/
int isal_inflate_stateless(struct inflate_state *state);
/* Decompress a deflate data. This function assumes a call to igzip_inflate_init
* has been made to set up the state structure to allow for decompression.*/
int isal_inflate(struct inflate_state *state);
#endif