static int isal_deflate_int_stateless(struct isal_zstream *stream, uint8_t * next_in, const uint32_t avail_in) { uint32_t crc32 = 0; uint32_t repeated_char_length; #ifndef DEFLATE if (write_gzip_header_stateless(stream)) return STATELESS_OVERFLOW; #endif if (avail_in >= 8 && (*(uint64_t *) stream->next_in == 0 || *(uint64_t *) stream->next_in == ~(uint64_t) 0)) repeated_char_length = detect_repeated_char_length(stream->next_in, stream->avail_in); else repeated_char_length = 0; if (stream->avail_in == repeated_char_length) { if (write_constant_compressed_stateless(stream, stream->next_in[0], repeated_char_length, 1) != COMP_OK) return STATELESS_OVERFLOW; #ifndef DEFLATE crc32 = crc32_gzip(0x0, next_in, avail_in); #endif /* write_trailer_stateless is required because if flushes out the last of the output */ if (write_trailer_stateless(stream, avail_in, crc32) != COMP_OK) return STATELESS_OVERFLOW; return COMP_OK; } else if (repeated_char_length >= MIN_REPEAT_LEN) { if (write_constant_compressed_stateless (stream, stream->next_in[0], repeated_char_length, 0) != COMP_OK) return STATELESS_OVERFLOW; } if (write_deflate_header_unaligned_stateless(stream) != COMP_OK) return STATELESS_OVERFLOW; if (stream->avail_out < 8) return STATELESS_OVERFLOW; isal_deflate_body_stateless(stream); if (!stream->internal_state.has_eob) return STATELESS_OVERFLOW; #ifndef DEFLATE crc32 = crc32_gzip(0x0, next_in, avail_in); #endif if (write_trailer_stateless(stream, avail_in, crc32) != COMP_OK) return STATELESS_OVERFLOW; return COMP_OK; }
static void isal_deflate_pass(struct isal_zstream *stream) { struct isal_zstate *state = &stream->internal_state; struct isal_hufftables *hufftables = stream->hufftables; uint8_t *start_in = stream->next_in; if (state->state == ZSTATE_NEW_HDR || state->state == ZSTATE_HDR) { if (state->count == 0) /* Assume the final header is being written since the header * stored in hufftables is the final header. */ state->has_eob_hdr = 1; write_header(stream, hufftables->deflate_hdr, hufftables->deflate_hdr_count, hufftables->deflate_hdr_extra_bits, ZSTATE_BODY, !stream->end_of_stream); } if (state->state == ZSTATE_BODY) isal_deflate_body(stream); if (state->state == ZSTATE_FLUSH_READ_BUFFER) isal_deflate_finish(stream); if (state->state == ZSTATE_SYNC_FLUSH) sync_flush(stream); if (state->state == ZSTATE_FLUSH_WRITE_BUFFER) flush_write_buffer(stream); if (stream->gzip_flag) state->crc = crc32_gzip(state->crc, start_in, stream->next_in - start_in); if (state->state == ZSTATE_TRL) write_trailer(stream); }
static void isal_deflate_icf_pass(struct isal_zstream *stream) { uint8_t *start_in = stream->next_in; struct isal_zstate *state = &stream->internal_state; struct level_2_buf *level_buf = (struct level_2_buf *)stream->level_buf; do { if (state->state == ZSTATE_NEW_HDR) init_new_icf_block(stream); if (state->state == ZSTATE_BODY) isal_deflate_icf_body(stream); if (state->state == ZSTATE_FLUSH_READ_BUFFER) isal_deflate_icf_finish(stream); if (state->state == ZSTATE_CREATE_HDR) create_icf_block_hdr(stream); if (state->state == ZSTATE_HDR) /* Note that the header may be prepended by the * remaining bits in the previous block, as such the * toggle header flag cannot be used */ write_header(stream, level_buf->deflate_hdr, level_buf->deflate_hdr_count, level_buf->deflate_hdr_extra_bits, ZSTATE_FLUSH_ICF_BUFFER, 0); if (state->state == ZSTATE_FLUSH_ICF_BUFFER) flush_icf_block(stream); } while (state->state == ZSTATE_NEW_HDR); if (state->state == ZSTATE_SYNC_FLUSH) sync_flush(stream); if (state->state == ZSTATE_FLUSH_WRITE_BUFFER) flush_write_buffer(stream); if (stream->gzip_flag) state->crc = crc32_gzip(state->crc, start_in, stream->next_in - start_in); if (state->state == ZSTATE_TRL) write_trailer(stream); }
int isal_deflate_stateless(struct isal_zstream *stream) { uint8_t *next_in = stream->next_in; const uint32_t avail_in = stream->avail_in; const uint32_t total_in = stream->total_in; uint8_t *next_out = stream->next_out; const uint32_t avail_out = stream->avail_out; const uint32_t total_out = stream->total_out; const uint32_t gzip_flag = stream->gzip_flag; uint32_t crc32 = 0; uint32_t stored_len; /* Final block has already been written */ stream->internal_state.has_eob_hdr = 0; init(&stream->internal_state.bitbuf); stream->internal_state.state = ZSTATE_NEW_HDR; stream->internal_state.crc = 0; if (stream->flush == NO_FLUSH) stream->end_of_stream = 1; if (stream->flush != NO_FLUSH && stream->flush != FULL_FLUSH) return INVALID_FLUSH; if (stream->level != 0 && stream->level != 1) return ISAL_INVALID_LEVEL; if (avail_in == 0) stored_len = STORED_BLK_HDR_BZ; else stored_len = STORED_BLK_HDR_BZ * ((avail_in + STORED_BLK_MAX_BZ - 1) / STORED_BLK_MAX_BZ) + avail_in; /* at least 1 byte compressed data in the case of empty dynamic block which only contains the EOB */ if (stream->gzip_flag == IGZIP_GZIP) stored_len += gzip_hdr_bytes + gzip_trl_bytes; else if (stream->gzip_flag == IGZIP_GZIP_NO_HDR) stored_len += gzip_trl_bytes; /* the output buffer should be no less than 8 bytes while empty stored deflate block is 5 bytes only */ if (stream->avail_out < 8) return STATELESS_OVERFLOW; if (isal_deflate_int_stateless(stream) == COMP_OK) return COMP_OK; else { if (stream->flush == FULL_FLUSH) { stream->internal_state.file_start = (uint8_t *) & stream->internal_state.buffer; reset_match_history(stream); } stream->internal_state.has_eob_hdr = 0; } if (avail_out < stored_len) return STATELESS_OVERFLOW; stream->next_in = next_in; stream->avail_in = avail_in; stream->total_in = total_in; stream->next_out = next_out; stream->avail_out = avail_out; stream->total_out = total_out; stream->gzip_flag = gzip_flag; if (stream->gzip_flag) crc32 = crc32_gzip(0x0, next_in, avail_in); return write_stored_block_stateless(stream, stored_len, crc32); }
static void write_constant_compressed_stateless(struct isal_zstream *stream, uint32_t repeated_length) { /* Assumes repeated_length is at least 1. * Assumes the input end_of_stream is either 0 or 1. */ struct isal_zstate *state = &stream->internal_state; uint32_t rep_bits = ((repeated_length - 1) / 258) * 2; uint32_t rep_bytes = rep_bits / 8; uint32_t rep_extra = (repeated_length - 1) % 258; uint32_t bytes; uint32_t repeated_char = *stream->next_in; uint8_t *start_in = stream->next_in; /* Guarantee there is enough space for the header even in the worst case */ if (stream->avail_out < HEADER_LENGTH + MAX_FIXUP_CODE_LENGTH + rep_bytes + 8) return; /* Assumes the repeated char is either 0 or 0xFF. */ memcpy(stream->next_out, repeated_char_header[repeated_char & 1], HEADER_LENGTH); if (stream->avail_in == repeated_length && stream->end_of_stream > 0) { stream->next_out[0] |= 1; state->has_eob_hdr = 1; state->has_eob = 1; state->state = ZSTATE_TRL; } else { state->state = ZSTATE_NEW_HDR; } memset(stream->next_out + HEADER_LENGTH, 0, rep_bytes); stream->avail_out -= HEADER_LENGTH + rep_bytes; stream->next_out += HEADER_LENGTH + rep_bytes; stream->total_out += HEADER_LENGTH + rep_bytes; set_buf(&state->bitbuf, stream->next_out, stream->avail_out); /* These two lines are basically a modified version of init. */ state->bitbuf.m_bits = 0; state->bitbuf.m_bit_count = rep_bits % 8; /* Add smaller repeat codes as necessary. Code280 can describe repeat * lengths of 115-130 bits. Code10 can describe repeat lengths of 10 * bits. If more than 230 bits, fill code with two code280s. Else if * more than 115 repeates, fill with code10s until one code280 can * finish the rest of the repeats. Else, fill with code10s and * literals */ if (rep_extra > 115) { while (rep_extra > 130 && rep_extra < 230) { write_bits(&state->bitbuf, CODE_10, CODE_10_LENGTH); rep_extra -= 10; } if (rep_extra >= 230) { write_bits(&state->bitbuf, CODE_280 | ((rep_extra / 2 - 115) << CODE_280_LENGTH), CODE_280_TOTAL_LENGTH); rep_extra -= rep_extra / 2; } write_bits(&state->bitbuf, CODE_280 | ((rep_extra - 115) << CODE_280_LENGTH), CODE_280_TOTAL_LENGTH); } else { while (rep_extra >= 10) { write_bits(&state->bitbuf, CODE_10, CODE_10_LENGTH); rep_extra -= 10; } for (; rep_extra > 0; rep_extra--) write_bits(&state->bitbuf, CODE_LIT, CODE_LIT_LENGTH); } write_bits(&state->bitbuf, END_OF_BLOCK, END_OF_BLOCK_LEN); stream->next_in += repeated_length; stream->avail_in -= repeated_length; stream->total_in += repeated_length; bytes = buffer_used(&state->bitbuf); stream->next_out = buffer_ptr(&state->bitbuf); stream->avail_out -= bytes; stream->total_out += bytes; if (stream->gzip_flag) state->crc = crc32_gzip(state->crc, start_in, stream->next_in - start_in); return; }
LIBEXPORT enum decompress_result gzip_decompress(struct deflate_decompressor *d, const void *in, size_t in_nbytes, void *out, size_t out_nbytes_avail, size_t *actual_out_nbytes_ret) { const u8 *in_next = in; const u8 * const in_end = in_next + in_nbytes; u8 flg; size_t actual_out_nbytes; enum decompress_result result; if (in_nbytes < GZIP_MIN_OVERHEAD) return DECOMPRESS_BAD_DATA; /* ID1 */ if (*in_next++ != GZIP_ID1) return DECOMPRESS_BAD_DATA; /* ID2 */ if (*in_next++ != GZIP_ID2) return DECOMPRESS_BAD_DATA; /* CM */ if (*in_next++ != GZIP_CM_DEFLATE) return DECOMPRESS_BAD_DATA; flg = *in_next++; /* MTIME */ in_next += 4; /* XFL */ in_next += 1; /* OS */ in_next += 1; if (flg & GZIP_FRESERVED) return DECOMPRESS_BAD_DATA; /* Extra field */ if (flg & GZIP_FEXTRA) { u16 xlen = get_unaligned_le16(in_next); in_next += 2; if (in_end - in_next < (u32)xlen + GZIP_FOOTER_SIZE) return DECOMPRESS_BAD_DATA; in_next += xlen; } /* Original file name (zero terminated) */ if (flg & GZIP_FNAME) { while (*in_next++ != 0 && in_next != in_end) ; if (in_end - in_next < GZIP_FOOTER_SIZE) return DECOMPRESS_BAD_DATA; } /* File comment (zero terminated) */ if (flg & GZIP_FCOMMENT) { while (*in_next++ != 0 && in_next != in_end) ; if (in_end - in_next < GZIP_FOOTER_SIZE) return DECOMPRESS_BAD_DATA; } /* CRC16 for gzip header */ if (flg & GZIP_FHCRC) { in_next += 2; if (in_end - in_next < GZIP_FOOTER_SIZE) return DECOMPRESS_BAD_DATA; } /* Compressed data */ result = deflate_decompress(d, in_next, in_end - GZIP_FOOTER_SIZE - in_next, out, out_nbytes_avail, actual_out_nbytes_ret); if (result != DECOMPRESS_SUCCESS) return result; if (actual_out_nbytes_ret) actual_out_nbytes = *actual_out_nbytes_ret; else actual_out_nbytes = out_nbytes_avail; in_next = in_end - GZIP_FOOTER_SIZE; /* CRC32 */ if (crc32_gzip(out, actual_out_nbytes) != get_unaligned_le32(in_next)) return DECOMPRESS_BAD_DATA; in_next += 4; /* ISIZE */ if ((u32)actual_out_nbytes != get_unaligned_le32(in_next)) return DECOMPRESS_BAD_DATA; return DECOMPRESS_SUCCESS; }
int isal_deflate_stateless(struct isal_zstream *stream) { uint8_t *next_in = stream->next_in; const uint32_t avail_in = stream->avail_in; uint8_t *next_out = stream->next_out; const uint32_t avail_out = stream->avail_out; uint32_t crc32 = 0; uint32_t stored_len; uint32_t dyn_min_len; uint32_t min_len; uint32_t select_stored_blk = 0; if (avail_in == 0) stored_len = STORED_BLK_HDR_BZ; else stored_len = STORED_BLK_HDR_BZ * ((avail_in + STORED_BLK_MAX_BZ - 1) / STORED_BLK_MAX_BZ) + avail_in; /* at least 1 byte compressed data in the case of empty dynamic block which only contains the EOB */ dyn_min_len = stream->hufftables->deflate_hdr_count + 1; #ifndef DEFLATE dyn_min_len += gzip_hdr_bytes + gzip_trl_bytes + 1; stored_len += gzip_hdr_bytes + gzip_trl_bytes; #endif min_len = dyn_min_len; if (stored_len < dyn_min_len) { min_len = stored_len; select_stored_blk = 1; } /* the output buffer should be no less than 8 bytes while empty stored deflate block is 5 bytes only */ if (avail_out < min_len || stream->avail_out < 8) return STATELESS_OVERFLOW; if (!select_stored_blk) { if (isal_deflate_int_stateless(stream, next_in, avail_in) == COMP_OK) return COMP_OK; } if (avail_out < stored_len) return STATELESS_OVERFLOW; isal_deflate_init(stream); stream->next_in = next_in; stream->avail_in = avail_in; stream->total_in = 0; stream->next_out = next_out; stream->avail_out = avail_out; stream->total_out = 0; #ifndef DEFLATE crc32 = crc32_gzip(0x0, next_in, avail_in); #endif return write_stored_block_stateless(stream, stored_len, crc32); }