summaryrefslogtreecommitdiffstats
path: root/src/isa-l/igzip/igzip.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/isa-l/igzip/igzip.c')
-rw-r--r--src/isa-l/igzip/igzip.c1180
1 files changed, 1180 insertions, 0 deletions
diff --git a/src/isa-l/igzip/igzip.c b/src/isa-l/igzip/igzip.c
new file mode 100644
index 00000000..6ac1c150
--- /dev/null
+++ b/src/isa-l/igzip/igzip.c
@@ -0,0 +1,1180 @@
+/**********************************************************************
+ Copyright(c) 2011-2016 Intel Corporation All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+
+#define ASM
+
+#include <assert.h>
+#include <string.h>
+#ifdef _WIN32
+# include <intrin.h>
+#endif
+
+#define MAX_WRITE_BITS_SIZE 8
+#define FORCE_FLUSH 64
+#define MIN_OBUF_SIZE 224
+#define NON_EMPTY_BLOCK_SIZE 6
+#define MAX_SYNC_FLUSH_SIZE NON_EMPTY_BLOCK_SIZE + MAX_WRITE_BITS_SIZE
+
+#define MAX_TOKENS (16 * 1024)
+
+#include "huffman.h"
+#include "bitbuf2.h"
+#include "igzip_lib.h"
+#include "repeated_char_result.h"
+#include "huff_codes.h"
+#include "encode_df.h"
+#include "igzip_level_buf_structs.h"
+
+extern const uint8_t gzip_hdr[];
+extern const uint32_t gzip_hdr_bytes;
+extern const uint32_t gzip_trl_bytes;
+extern const struct isal_hufftables hufftables_default;
+extern const struct isal_hufftables hufftables_static;
+
+extern uint32_t crc32_gzip(uint32_t init_crc, const unsigned char *buf, uint64_t len);
+
+static int write_stored_block_stateless(struct isal_zstream *stream, uint32_t stored_len,
+ uint32_t crc32);
+
+static int write_gzip_header_stateless(struct isal_zstream *stream);
+static void write_gzip_header(struct isal_zstream *stream);
+static int write_deflate_header_stateless(struct isal_zstream *stream);
+static int write_deflate_header_unaligned_stateless(struct isal_zstream *stream);
+
+unsigned int detect_repeated_char(uint8_t * buf, uint32_t size);
+
+#define STORED_BLK_HDR_BZ 5
+#define STORED_BLK_MAX_BZ 65535
+
+void isal_deflate_body(struct isal_zstream *stream);
+void isal_deflate_finish(struct isal_zstream *stream);
+
+void isal_deflate_icf_body(struct isal_zstream *stream);
+void isal_deflate_icf_finish(struct isal_zstream *stream);
+/*****************************************************************/
+
+/* Forward declarations */
+static inline void reset_match_history(struct isal_zstream *stream);
+void write_header(struct isal_zstream *stream, uint8_t * deflate_hdr,
+ uint32_t deflate_hdr_count, uint32_t extra_bits_count, uint32_t next_state,
+ uint32_t toggle_end_of_stream);
+void write_deflate_header(struct isal_zstream *stream);
+void write_trailer(struct isal_zstream *stream);
+
+struct slver {
+ uint16_t snum;
+ uint8_t ver;
+ uint8_t core;
+};
+
+/* Version info */
+struct slver isal_deflate_init_slver_01030081;
+struct slver isal_deflate_init_slver = { 0x0081, 0x03, 0x01 };
+
+struct slver isal_deflate_stateless_init_slver_00010084;
+struct slver isal_deflate_stateless_init_slver = { 0x0084, 0x01, 0x00 };
+
+struct slver isal_deflate_slver_01030082;
+struct slver isal_deflate_slver = { 0x0082, 0x03, 0x01 };
+
+struct slver isal_deflate_stateless_slver_01010083;
+struct slver isal_deflate_stateless_slver = { 0x0083, 0x01, 0x01 };
+
+struct slver isal_deflate_set_hufftables_slver_00_01_008b;
+struct slver isal_deflate_set_hufftables_slver = { 0x008b, 0x01, 0x00 };
+
+/*****************************************************************/
+static
+void sync_flush(struct isal_zstream *stream)
+{
+ struct isal_zstate *state = &stream->internal_state;
+ uint64_t bits_to_write = 0xFFFF0000, bits_len;
+ uint64_t bytes;
+ int flush_size;
+
+ if (stream->avail_out >= 8) {
+ set_buf(&state->bitbuf, stream->next_out, stream->avail_out);
+
+ flush_size = (-(state->bitbuf.m_bit_count + 3)) % 8;
+
+ bits_to_write <<= flush_size + 3;
+ bits_len = 32 + flush_size + 3;
+
+#ifdef USE_BITBUFB /* Write Bits Always */
+ state->state = ZSTATE_NEW_HDR;
+#else /* Not Write Bits Always */
+ state->state = ZSTATE_FLUSH_WRITE_BUFFER;
+#endif
+ state->has_eob = 0;
+
+ write_bits(&state->bitbuf, bits_to_write, bits_len);
+
+ bytes = buffer_used(&state->bitbuf);
+ stream->next_out = buffer_ptr(&state->bitbuf);
+ stream->avail_out -= bytes;
+ stream->total_out += bytes;
+
+ if (stream->flush == FULL_FLUSH) {
+ /* Clear match history so there are no cross
+ * block length distance pairs */
+ state->file_start -= state->b_bytes_processed;
+ state->b_bytes_valid -= state->b_bytes_processed;
+ state->b_bytes_processed = 0;
+ reset_match_history(stream);
+ }
+ }
+}
+
+static void flush_write_buffer(struct isal_zstream *stream)
+{
+ struct isal_zstate *state = &stream->internal_state;
+ int bytes = 0;
+ if (stream->avail_out >= 8) {
+ set_buf(&state->bitbuf, stream->next_out, stream->avail_out);
+ flush(&state->bitbuf);
+ stream->next_out = buffer_ptr(&state->bitbuf);
+ bytes = buffer_used(&state->bitbuf);
+ stream->avail_out -= bytes;
+ stream->total_out += bytes;
+ state->state = ZSTATE_NEW_HDR;
+ }
+}
+
+static void flush_icf_block(struct isal_zstream *stream)
+{
+ struct isal_zstate *state = &stream->internal_state;
+ struct level_2_buf *level_buf = (struct level_2_buf *)stream->level_buf;
+ struct BitBuf2 *write_buf = &state->bitbuf;
+ struct deflate_icf *icf_buf_encoded_next;
+
+ set_buf(write_buf, stream->next_out, stream->avail_out);
+
+#if defined (USE_BITBUF8) || (USE_BITBUF_ELSE)
+ if (!is_full(write_buf))
+ flush_bits(write_buf);
+#endif
+
+ icf_buf_encoded_next = encode_deflate_icf(level_buf->icf_buf_start + state->count,
+ level_buf->icf_buf_next, write_buf,
+ &level_buf->encode_tables);
+
+ state->count = icf_buf_encoded_next - level_buf->icf_buf_start;
+ stream->next_out = buffer_ptr(write_buf);
+ stream->total_out += buffer_used(write_buf);
+ stream->avail_out -= buffer_used(write_buf);
+
+ if (level_buf->icf_buf_next <= icf_buf_encoded_next) {
+ state->count = 0;
+ if (stream->avail_in == 0 && stream->end_of_stream)
+ state->state = ZSTATE_TRL;
+ else if (stream->avail_in == 0 && stream->flush != NO_FLUSH)
+ state->state = ZSTATE_SYNC_FLUSH;
+ else
+ state->state = ZSTATE_NEW_HDR;
+ }
+}
+
+static void init_new_icf_block(struct isal_zstream *stream)
+{
+ struct isal_zstate *state = &stream->internal_state;
+ struct level_2_buf *level_buf = (struct level_2_buf *)stream->level_buf;
+
+ if (stream->level_buf_size >=
+ sizeof(struct level_2_buf) + 100 * sizeof(struct deflate_icf)) {
+ level_buf->icf_buf_next = level_buf->icf_buf_start;
+ level_buf->icf_buf_avail_out =
+ stream->level_buf_size - sizeof(struct level_2_buf) -
+ sizeof(struct deflate_icf);
+ memset(&state->hist, 0, sizeof(struct isal_mod_hist));
+ state->state = ZSTATE_BODY;
+ }
+}
+
+static void create_icf_block_hdr(struct isal_zstream *stream)
+{
+ struct isal_zstate *state = &stream->internal_state;
+ struct level_2_buf *level_buf = (struct level_2_buf *)stream->level_buf;
+ struct BitBuf2 *write_buf = &state->bitbuf;
+ struct BitBuf2 write_buf_tmp;
+ uint32_t out_size = stream->avail_out;
+ uint8_t *end_out = stream->next_out + out_size;
+ /* Write EOB in icf_buf */
+ state->hist.ll_hist[256] = 1;
+ level_buf->icf_buf_next->lit_len = 0x100;
+ level_buf->icf_buf_next->lit_dist = NULL_DIST_SYM;
+ level_buf->icf_buf_next->dist_extra = 0;
+ level_buf->icf_buf_next++;
+
+ state->has_eob_hdr = stream->end_of_stream && !stream->avail_in;
+ if (end_out - stream->next_out >= ISAL_DEF_MAX_HDR_SIZE) {
+ /* Determine whether this is the final block */
+
+ if (stream->gzip_flag == IGZIP_GZIP)
+ write_gzip_header_stateless(stream);
+
+ set_buf(write_buf, stream->next_out, stream->avail_out);
+
+ create_hufftables_icf(write_buf, &level_buf->encode_tables, &state->hist,
+ state->has_eob_hdr);
+ state->state = ZSTATE_FLUSH_ICF_BUFFER;
+ stream->next_out = buffer_ptr(write_buf);
+ stream->total_out += buffer_used(write_buf);
+ stream->avail_out -= buffer_used(write_buf);
+ } else {
+ /* Start writing into temporary buffer */
+ write_buf_tmp.m_bits = write_buf->m_bits;
+ write_buf_tmp.m_bit_count = write_buf->m_bit_count;
+
+ write_buf->m_bits = 0;
+ write_buf->m_bit_count = 0;
+
+ set_buf(&write_buf_tmp, level_buf->deflate_hdr, ISAL_DEF_MAX_HDR_SIZE);
+
+ create_hufftables_icf(&write_buf_tmp, &level_buf->encode_tables,
+ &state->hist, state->has_eob_hdr);
+
+ level_buf->deflate_hdr_count = buffer_used(&write_buf_tmp);
+ level_buf->deflate_hdr_extra_bits = write_buf_tmp.m_bit_count;
+ flush(&write_buf_tmp);
+
+ state->state = ZSTATE_HDR;
+ }
+}
+
+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);
+}
+
+static void isal_deflate_int(struct isal_zstream *stream)
+{
+ struct isal_zstate *state = &stream->internal_state;
+ uint32_t size;
+
+ /* Move data from temporary output buffer to output buffer */
+ if (state->state >= ZSTATE_TMP_OFFSET) {
+ size = state->tmp_out_end - state->tmp_out_start;
+ if (size > stream->avail_out)
+ size = stream->avail_out;
+ memcpy(stream->next_out, state->tmp_out_buff + state->tmp_out_start, size);
+ stream->next_out += size;
+ stream->avail_out -= size;
+ stream->total_out += size;
+ state->tmp_out_start += size;
+
+ if (state->tmp_out_start == state->tmp_out_end)
+ state->state -= ZSTATE_TMP_OFFSET;
+
+ if (stream->avail_out == 0 || state->state == ZSTATE_END
+ // or do not write out empty blocks since the outbuffer was processed
+ || (state->state == ZSTATE_NEW_HDR && stream->avail_out == 0))
+ return;
+ }
+ assert(state->tmp_out_start == state->tmp_out_end);
+
+ if (stream->level == 0)
+ isal_deflate_pass(stream);
+ else
+ isal_deflate_icf_pass(stream);
+
+ /* Fill temporary output buffer then complete filling output buffer */
+ if (stream->avail_out > 0 && stream->avail_out < 8 && state->state != ZSTATE_NEW_HDR) {
+ uint8_t *next_out;
+ uint32_t avail_out;
+ uint32_t total_out;
+
+ next_out = stream->next_out;
+ avail_out = stream->avail_out;
+ total_out = stream->total_out;
+
+ stream->next_out = state->tmp_out_buff;
+ stream->avail_out = sizeof(state->tmp_out_buff);
+ stream->total_out = 0;
+
+ if (stream->level == 0)
+ isal_deflate_pass(stream);
+ else
+ isal_deflate_icf_pass(stream);
+
+ state->tmp_out_start = 0;
+ state->tmp_out_end = stream->total_out;
+
+ stream->next_out = next_out;
+ stream->avail_out = avail_out;
+ stream->total_out = total_out;
+ if (state->tmp_out_end) {
+ size = state->tmp_out_end;
+ if (size > stream->avail_out)
+ size = stream->avail_out;
+ memcpy(stream->next_out, state->tmp_out_buff, size);
+ stream->next_out += size;
+ stream->avail_out -= size;
+ stream->total_out += size;
+ state->tmp_out_start += size;
+ if (state->tmp_out_start != state->tmp_out_end)
+ state->state += ZSTATE_TMP_OFFSET;
+
+ }
+ }
+
+}
+
+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;
+}
+
+int detect_repeated_char_length(uint8_t * in, uint32_t length)
+{
+ /* This currently assumes the first 8 bytes are the same character.
+ * This won't work effectively if the input stream isn't aligned well. */
+ uint8_t *p_8, *end = in + length;
+ uint64_t *p_64 = (uint64_t *) in;
+ uint64_t w = *p_64;
+ uint8_t c = (uint8_t) w;
+
+ for (; (p_64 <= (uint64_t *) (end - 8)) && (w == *p_64); p_64++) ;
+
+ p_8 = (uint8_t *) p_64;
+
+ for (; (p_8 < end) && (c == *p_8); p_8++) ;
+
+ return p_8 - in;
+}
+
+static int isal_deflate_int_stateless(struct isal_zstream *stream)
+{
+ uint32_t repeat_length;
+ struct isal_zstate *state = &stream->internal_state;
+
+ if (stream->gzip_flag == IGZIP_GZIP)
+ if (write_gzip_header_stateless(stream))
+ return STATELESS_OVERFLOW;
+
+ if (stream->avail_in >= 8
+ && (*(uint64_t *) stream->next_in == 0
+ || *(uint64_t *) stream->next_in == ~(uint64_t) 0)) {
+ repeat_length = detect_repeated_char_length(stream->next_in, stream->avail_in);
+
+ if (stream->avail_in == repeat_length || repeat_length >= MIN_REPEAT_LEN)
+ write_constant_compressed_stateless(stream, repeat_length);
+ }
+
+ if (stream->level == 0) {
+ if (state->state == ZSTATE_NEW_HDR || state->state == ZSTATE_HDR) {
+ write_deflate_header_unaligned_stateless(stream);
+ if (state->state == ZSTATE_NEW_HDR || state->state == ZSTATE_HDR)
+ return STATELESS_OVERFLOW;
+
+ reset_match_history(stream);
+ }
+
+ state->file_start = stream->next_in - stream->total_in;
+ isal_deflate_pass(stream);
+
+ } else if (stream->level == 1) {
+ if (stream->level_buf == NULL || stream->level_buf_size < ISAL_DEF_LVL1_MIN) {
+ /* Default to internal buffer if invalid size is supplied */
+ stream->level_buf = state->buffer;
+ stream->level_buf_size = sizeof(state->buffer);
+ }
+
+ if (state->state == ZSTATE_NEW_HDR || state->state == ZSTATE_HDR)
+ reset_match_history(stream);
+
+ state->count = 0;
+ state->file_start = stream->next_in - stream->total_in;
+ isal_deflate_icf_pass(stream);
+
+ } else
+ return ISAL_INVALID_LEVEL;
+
+ if (state->state == ZSTATE_END
+ || (state->state == ZSTATE_NEW_HDR && stream->flush == FULL_FLUSH))
+ return COMP_OK;
+ else
+ return STATELESS_OVERFLOW;
+}
+
+static int write_stored_block_stateless(struct isal_zstream *stream,
+ uint32_t stored_len, uint32_t crc32)
+{
+ uint64_t stored_blk_hdr;
+ uint32_t copy_size;
+ uint32_t avail_in;
+ uint64_t gzip_trl;
+
+ if (stream->avail_out < stored_len)
+ return STATELESS_OVERFLOW;
+
+ stream->avail_out -= stored_len;
+ stream->total_out += stored_len;
+ avail_in = stream->avail_in;
+
+ if (stream->gzip_flag == IGZIP_GZIP) {
+ memcpy(stream->next_out, gzip_hdr, gzip_hdr_bytes);
+ stream->next_out += gzip_hdr_bytes;
+ stream->gzip_flag = IGZIP_GZIP_NO_HDR;
+ }
+
+ do {
+ if (avail_in >= STORED_BLK_MAX_BZ) {
+ stored_blk_hdr = 0xFFFF00;
+ copy_size = STORED_BLK_MAX_BZ;
+ } else {
+ stored_blk_hdr = ~avail_in;
+ stored_blk_hdr <<= 24;
+ stored_blk_hdr |= (avail_in & 0xFFFF) << 8;
+ copy_size = avail_in;
+ }
+
+ avail_in -= copy_size;
+
+ /* Handle BFINAL bit */
+ if (avail_in == 0) {
+ if (stream->flush == NO_FLUSH || stream->end_of_stream) {
+ stored_blk_hdr |= 0x1;
+ stream->internal_state.has_eob_hdr = 1;
+ }
+ }
+ memcpy(stream->next_out, &stored_blk_hdr, STORED_BLK_HDR_BZ);
+ stream->next_out += STORED_BLK_HDR_BZ;
+
+ memcpy(stream->next_out, stream->next_in, copy_size);
+ stream->next_out += copy_size;
+ stream->next_in += copy_size;
+ stream->total_in += copy_size;
+ } while (avail_in != 0);
+
+ if (stream->gzip_flag && stream->internal_state.has_eob_hdr) {
+ gzip_trl = stream->avail_in;
+ gzip_trl <<= 32;
+ gzip_trl |= crc32 & 0xFFFFFFFF;
+ memcpy(stream->next_out, &gzip_trl, gzip_trl_bytes);
+ stream->next_out += gzip_trl_bytes;
+ }
+
+ stream->avail_in = 0;
+ return COMP_OK;
+}
+
+static inline void reset_match_history(struct isal_zstream *stream)
+{
+ struct isal_zstate *state = &stream->internal_state;
+ uint16_t *head = stream->internal_state.head;
+ int i = 0;
+
+ state->has_hist = 0;
+
+ if (stream->total_in == 0)
+ memset(stream->internal_state.head, 0, sizeof(stream->internal_state.head));
+ else {
+ for (i = 0; i < sizeof(state->head) / 2; i++) {
+ head[i] = (uint16_t) (stream->total_in);
+ }
+ }
+}
+
+void isal_deflate_init(struct isal_zstream *stream)
+{
+ struct isal_zstate *state = &stream->internal_state;
+
+ stream->total_in = 0;
+ stream->total_out = 0;
+ stream->hufftables = (struct isal_hufftables *)&hufftables_default;
+ stream->level = 0;
+ stream->level_buf = NULL;
+ stream->level_buf_size = 0;
+ stream->end_of_stream = 0;
+ stream->flush = NO_FLUSH;
+ stream->gzip_flag = 0;
+
+ state->b_bytes_valid = 0;
+ state->b_bytes_processed = 0;
+ state->has_eob = 0;
+ state->has_eob_hdr = 0;
+ state->has_hist = 0;
+ state->state = ZSTATE_NEW_HDR;
+ state->count = 0;
+
+ state->tmp_out_start = 0;
+ state->tmp_out_end = 0;
+
+ state->file_start = stream->next_in;
+
+ init(&state->bitbuf);
+
+ state->crc = 0;
+
+ memset(state->head, 0, sizeof(state->head));
+
+ return;
+}
+
+int isal_deflate_set_hufftables(struct isal_zstream *stream,
+ struct isal_hufftables *hufftables, int type)
+{
+ if (stream->internal_state.state != ZSTATE_NEW_HDR)
+ return ISAL_INVALID_OPERATION;
+
+ switch (type) {
+ case IGZIP_HUFFTABLE_DEFAULT:
+ stream->hufftables = (struct isal_hufftables *)&hufftables_default;
+ break;
+ case IGZIP_HUFFTABLE_STATIC:
+ stream->hufftables = (struct isal_hufftables *)&hufftables_static;
+ break;
+ case IGZIP_HUFFTABLE_CUSTOM:
+ if (hufftables != NULL) {
+ stream->hufftables = hufftables;
+ break;
+ }
+ default:
+ return ISAL_INVALID_OPERATION;
+ }
+
+ return COMP_OK;
+}
+
+void isal_deflate_stateless_init(struct isal_zstream *stream)
+{
+ stream->total_in = 0;
+ stream->total_out = 0;
+ stream->hufftables = (struct isal_hufftables *)&hufftables_default;
+ stream->level = 0;
+ stream->level_buf = NULL;
+ stream->level_buf_size = 0;
+ stream->end_of_stream = 0;
+ stream->flush = NO_FLUSH;
+ stream->gzip_flag = 0;
+ stream->internal_state.state = ZSTATE_NEW_HDR;
+ return;
+}
+
+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);
+}
+
+int isal_deflate(struct isal_zstream *stream)
+{
+ struct isal_zstate *state = &stream->internal_state;
+ int ret = COMP_OK;
+ uint8_t *next_in;
+ uint32_t avail_in, avail_in_start;
+ uint32_t flush_type = stream->flush;
+ uint32_t end_of_stream = stream->end_of_stream;
+ int size = 0;
+ uint8_t *copy_down_src = NULL;
+ uint64_t copy_down_size = 0;
+ int32_t processed = -(state->b_bytes_valid - state->b_bytes_processed);
+
+ if (stream->flush >= 3)
+ return INVALID_FLUSH;
+
+ next_in = stream->next_in;
+ avail_in = stream->avail_in;
+ stream->total_in -= state->b_bytes_valid - state->b_bytes_processed;
+
+ do {
+ size = avail_in;
+ if (size > sizeof(state->buffer) - state->b_bytes_valid) {
+ size = sizeof(state->buffer) - state->b_bytes_valid;
+ stream->flush = NO_FLUSH;
+ stream->end_of_stream = 0;
+ }
+ memcpy(&state->buffer[state->b_bytes_valid], next_in, size);
+
+ next_in += size;
+ avail_in -= size;
+ state->b_bytes_valid += size;
+
+ stream->next_in = &state->buffer[state->b_bytes_processed];
+ stream->avail_in = state->b_bytes_valid - state->b_bytes_processed;
+ state->file_start = stream->next_in - stream->total_in;
+ processed += stream->avail_in;
+
+ if (stream->avail_in > IGZIP_HIST_SIZE
+ || stream->end_of_stream || stream->flush != NO_FLUSH) {
+ avail_in_start = stream->avail_in;
+ isal_deflate_int(stream);
+ state->b_bytes_processed += avail_in_start - stream->avail_in;
+
+ if (state->b_bytes_processed > IGZIP_HIST_SIZE) {
+ copy_down_src =
+ &state->buffer[state->b_bytes_processed - IGZIP_HIST_SIZE];
+ copy_down_size =
+ state->b_bytes_valid - state->b_bytes_processed +
+ IGZIP_HIST_SIZE;
+ memmove(state->buffer, copy_down_src, copy_down_size);
+
+ state->b_bytes_valid -= copy_down_src - state->buffer;
+ state->b_bytes_processed -= copy_down_src - state->buffer;
+ }
+
+ }
+
+ stream->flush = flush_type;
+ stream->end_of_stream = end_of_stream;
+ processed -= stream->avail_in;
+ } while (processed < IGZIP_HIST_SIZE + ISAL_LOOK_AHEAD && avail_in > 0
+ && stream->avail_out > 0);
+
+ if (processed >= IGZIP_HIST_SIZE + ISAL_LOOK_AHEAD) {
+ stream->next_in = next_in - stream->avail_in;
+ stream->avail_in = avail_in + stream->avail_in;
+
+ state->file_start = stream->next_in - stream->total_in;
+
+ if (stream->avail_in > 0 && stream->avail_out > 0)
+ isal_deflate_int(stream);
+
+ size = stream->avail_in;
+ if (stream->avail_in > IGZIP_HIST_SIZE)
+ size = 0;
+
+ memmove(state->buffer, stream->next_in - IGZIP_HIST_SIZE,
+ size + IGZIP_HIST_SIZE);
+ state->b_bytes_processed = IGZIP_HIST_SIZE;
+ state->b_bytes_valid = size + IGZIP_HIST_SIZE;
+
+ stream->next_in += size;
+ stream->avail_in -= size;
+ stream->total_in += size;
+
+ } else {
+ stream->total_in += state->b_bytes_valid - state->b_bytes_processed;
+ stream->next_in = next_in;
+ stream->avail_in = avail_in;
+ state->file_start = stream->next_in - stream->total_in;
+
+ }
+
+ return ret;
+}
+
+static int write_gzip_header_stateless(struct isal_zstream *stream)
+{
+ if (gzip_hdr_bytes >= stream->avail_out)
+ return STATELESS_OVERFLOW;
+
+ stream->avail_out -= gzip_hdr_bytes;
+ stream->total_out += gzip_hdr_bytes;
+
+ memcpy(stream->next_out, gzip_hdr, gzip_hdr_bytes);
+
+ stream->next_out += gzip_hdr_bytes;
+ stream->gzip_flag = IGZIP_GZIP_NO_HDR;
+
+ return COMP_OK;
+}
+
+static void write_gzip_header(struct isal_zstream *stream)
+{
+ struct isal_zstate *state = &stream->internal_state;
+ int bytes_to_write = gzip_hdr_bytes;
+
+ bytes_to_write -= state->count;
+
+ if (bytes_to_write > stream->avail_out)
+ bytes_to_write = stream->avail_out;
+
+ memcpy(stream->next_out, gzip_hdr + state->count, bytes_to_write);
+ state->count += bytes_to_write;
+
+ if (state->count == gzip_hdr_bytes) {
+ state->count = 0;
+ stream->gzip_flag = IGZIP_GZIP_NO_HDR;
+ }
+
+ stream->avail_out -= bytes_to_write;
+ stream->total_out += bytes_to_write;
+ stream->next_out += bytes_to_write;
+
+}
+
+static int write_deflate_header_stateless(struct isal_zstream *stream)
+{
+ struct isal_zstate *state = &stream->internal_state;
+ struct isal_hufftables *hufftables = stream->hufftables;
+ uint64_t hdr_extra_bits = hufftables->deflate_hdr[hufftables->deflate_hdr_count];
+ uint32_t count;
+
+ if (hufftables->deflate_hdr_count + 8 >= stream->avail_out)
+ return STATELESS_OVERFLOW;
+
+ memcpy(stream->next_out, hufftables->deflate_hdr, hufftables->deflate_hdr_count);
+
+ if (stream->end_of_stream == 0) {
+ if (hufftables->deflate_hdr_count > 0)
+ *stream->next_out -= 1;
+ else
+ hdr_extra_bits -= 1;
+ } else
+ state->has_eob_hdr = 1;
+
+ stream->avail_out -= hufftables->deflate_hdr_count;
+ stream->total_out += hufftables->deflate_hdr_count;
+ stream->next_out += hufftables->deflate_hdr_count;
+
+ set_buf(&state->bitbuf, stream->next_out, stream->avail_out);
+
+ write_bits(&state->bitbuf, hdr_extra_bits, hufftables->deflate_hdr_extra_bits);
+
+ count = buffer_used(&state->bitbuf);
+ stream->next_out = buffer_ptr(&state->bitbuf);
+ stream->avail_out -= count;
+ stream->total_out += count;
+
+ state->state = ZSTATE_BODY;
+
+ return COMP_OK;
+}
+
+static int write_deflate_header_unaligned_stateless(struct isal_zstream *stream)
+{
+ struct isal_zstate *state = &stream->internal_state;
+ struct isal_hufftables *hufftables = stream->hufftables;
+ unsigned int count;
+ uint64_t bit_count;
+ uint64_t *header_next;
+ uint64_t *header_end;
+ uint64_t header_bits;
+
+ if (state->bitbuf.m_bit_count == 0)
+ return write_deflate_header_stateless(stream);
+
+ if (hufftables->deflate_hdr_count + 16 >= stream->avail_out)
+ return STATELESS_OVERFLOW;
+
+ set_buf(&state->bitbuf, stream->next_out, stream->avail_out);
+
+ header_next = (uint64_t *) hufftables->deflate_hdr;
+ header_end = header_next + hufftables->deflate_hdr_count / 8;
+
+ header_bits = *header_next;
+
+ if (stream->end_of_stream == 0)
+ header_bits--;
+ else
+ state->has_eob_hdr = 1;
+
+ header_next++;
+
+ /* Write out Complete Header bits */
+ for (; header_next <= header_end; header_next++) {
+ write_bits(&state->bitbuf, header_bits, 32);
+ header_bits >>= 32;
+ write_bits(&state->bitbuf, header_bits, 32);
+ header_bits = *header_next;
+ }
+
+ bit_count =
+ (hufftables->deflate_hdr_count & 0x7) * 8 + hufftables->deflate_hdr_extra_bits;
+
+ if (bit_count > MAX_BITBUF_BIT_WRITE) {
+ write_bits(&state->bitbuf, header_bits, MAX_BITBUF_BIT_WRITE);
+ header_bits >>= MAX_BITBUF_BIT_WRITE;
+ bit_count -= MAX_BITBUF_BIT_WRITE;
+
+ }
+
+ write_bits(&state->bitbuf, header_bits, bit_count);
+
+ /* check_space flushes extra bytes in bitbuf. Required because
+ * write_bits_always fails when the next commit makes the buffer
+ * length exceed 64 bits */
+ check_space(&state->bitbuf, FORCE_FLUSH);
+
+ count = buffer_used(&state->bitbuf);
+ stream->next_out = buffer_ptr(&state->bitbuf);
+ stream->avail_out -= count;
+ stream->total_out += count;
+
+ state->state = ZSTATE_BODY;
+
+ return COMP_OK;
+}
+
+/* Toggle end of stream only works when deflate header is aligned */
+void write_header(struct isal_zstream *stream, uint8_t * deflate_hdr,
+ uint32_t deflate_hdr_count, uint32_t extra_bits_count, uint32_t next_state,
+ uint32_t toggle_end_of_stream)
+{
+ struct isal_zstate *state = &stream->internal_state;
+ uint32_t hdr_extra_bits = deflate_hdr[deflate_hdr_count];
+ uint32_t count;
+ state->state = ZSTATE_HDR;
+
+ if (state->bitbuf.m_bit_count != 0) {
+ if (stream->avail_out < 8)
+ return;
+ set_buf(&state->bitbuf, stream->next_out, stream->avail_out);
+ flush(&state->bitbuf);
+ count = buffer_used(&state->bitbuf);
+ stream->next_out = buffer_ptr(&state->bitbuf);
+ stream->avail_out -= count;
+ stream->total_out += count;
+ }
+
+ if (stream->gzip_flag == IGZIP_GZIP)
+ write_gzip_header(stream);
+
+ count = deflate_hdr_count - state->count;
+
+ if (count != 0) {
+ if (count > stream->avail_out)
+ count = stream->avail_out;
+
+ memcpy(stream->next_out, deflate_hdr + state->count, count);
+
+ if (toggle_end_of_stream && state->count == 0 && count > 0) {
+ /* Assumes the final block bit is the first bit */
+ *stream->next_out ^= 1;
+ state->has_eob_hdr = !state->has_eob_hdr;
+ }
+
+ stream->next_out += count;
+ stream->avail_out -= count;
+ stream->total_out += count;
+ state->count += count;
+
+ count = deflate_hdr_count - state->count;
+ } else if (toggle_end_of_stream && deflate_hdr_count == 0) {
+ /* Assumes the final block bit is the first bit */
+ hdr_extra_bits ^= 1;
+ state->has_eob_hdr = !state->has_eob_hdr;
+ }
+
+ if ((count == 0) && (stream->avail_out >= 8)) {
+
+ set_buf(&state->bitbuf, stream->next_out, stream->avail_out);
+
+ write_bits(&state->bitbuf, hdr_extra_bits, extra_bits_count);
+
+ state->state = next_state;
+ state->count = 0;
+
+ count = buffer_used(&state->bitbuf);
+ stream->next_out = buffer_ptr(&state->bitbuf);
+ stream->avail_out -= count;
+ stream->total_out += count;
+ }
+
+}
+
+void write_trailer(struct isal_zstream *stream)
+{
+ struct isal_zstate *state = &stream->internal_state;
+ unsigned int bytes;
+ uint32_t crc = state->crc;
+
+ if (stream->avail_out >= 8) {
+ set_buf(&state->bitbuf, stream->next_out, stream->avail_out);
+
+ /* the flush() will pad to the next byte and write up to 8 bytes
+ * to the output stream/buffer.
+ */
+ if (!state->has_eob_hdr) {
+ /* If the final header has not been written, write a
+ * final block. This block is a static huffman block
+ * which only contains the end of block symbol. The code
+ * that happens to do this is the fist 10 bits of
+ * 0x003 */
+ state->has_eob_hdr = 1;
+ write_bits(&state->bitbuf, 0x003, 10);
+ if (is_full(&state->bitbuf)) {
+ stream->next_out = buffer_ptr(&state->bitbuf);
+ bytes = buffer_used(&state->bitbuf);
+ stream->avail_out -= bytes;
+ stream->total_out += bytes;
+ return;
+ }
+ }
+
+ flush(&state->bitbuf);
+ stream->next_out = buffer_ptr(&state->bitbuf);
+ bytes = buffer_used(&state->bitbuf);
+
+ if (stream->gzip_flag) {
+ if (!is_full(&state->bitbuf)) {
+ *(uint64_t *) stream->next_out =
+ ((uint64_t) stream->total_in << 32) | crc;
+ stream->next_out += 8;
+ bytes += 8;
+ state->state = ZSTATE_END;
+ }
+ } else
+ state->state = ZSTATE_END;
+
+ stream->avail_out -= bytes;
+ stream->total_out += bytes;
+ }
+}