From: Ilya Leoshkevich Date: Tue, 21 Jul 2020 11:27:47 +0000 (+0200) Subject: Implement switching between DFLTCC and software X-Git-Tag: 1.9.9-b1~85 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fc0427546be80670fd60402a079f8e6a5f488f83;p=thirdparty%2Fzlib-ng.git Implement switching between DFLTCC and software --- diff --git a/arch/s390/dfltcc_deflate.c b/arch/s390/dfltcc_deflate.c index c2c5f1be1..a088a7315 100644 --- a/arch/s390/dfltcc_deflate.c +++ b/arch/s390/dfltcc_deflate.c @@ -105,30 +105,36 @@ int ZLIB_INTERNAL dfltcc_deflate(PREFIX3(streamp) strm, int flush, block_state * int soft_bcc; int no_flush; - if (!dfltcc_can_deflate(strm)) + if (!dfltcc_can_deflate(strm)) { + /* Clear history. */ + if (flush == Z_FULL_FLUSH) + param->hl = 0; return 0; + } again: masked_avail_in = 0; soft_bcc = 0; no_flush = flush == Z_NO_FLUSH; - /* Trailing empty block. Switch to software, except when Continuation Flag - * is set, which means that DFLTCC has buffered some output in the - * parameter block and needs to be called again in order to flush it. + /* No input data. Return, except when Continuation Flag is set, which means + * that DFLTCC has buffered some output in the parameter block and needs to + * be called again in order to flush it. */ - if (flush == Z_FINISH && strm->avail_in == 0 && !param->cf) { - if (param->bcf) { - /* A block is still open, and the hardware does not support closing - * blocks without adding data. Thus, close it manually. - */ + if (strm->avail_in == 0 && !param->cf) { + /* A block is still open, and the hardware does not support closing + * blocks without adding data. Thus, close it manually. + */ + if (!no_flush && param->bcf) { send_eobs(strm, param); param->bcf = 0; } - return 0; - } - - if (strm->avail_in == 0 && !param->cf) { + /* Let one of deflate_* functions write a trailing empty block. */ + if (flush == Z_FINISH) + return 0; + /* Clear history. */ + if (flush == Z_FULL_FLUSH) + param->hl = 0; *result = need_more; return 1; } @@ -181,7 +187,7 @@ again: param->cvt = state->wrap == 2 ? CVT_CRC32 : CVT_ADLER32; if (!no_flush) /* We need to close a block. Always do this in software - when there is - * no input data, the hardware will not nohor BCC. */ + * no input data, the hardware will not honor BCC. */ soft_bcc = 1; if (flush == Z_FINISH && !param->bcf) /* We are about to open a BFINAL block, set Block Header Final bit @@ -196,8 +202,8 @@ again: param->sbb = (unsigned int)state->bi_valid; if (param->sbb > 0) *strm->next_out = (unsigned char)state->bi_buf; - if (param->hl) - param->nt = 0; /* Honor history */ + /* Honor history and check value */ + param->nt = 0; param->cv = state->wrap == 2 ? ZSWAP32(strm->adler) : strm->adler; /* When opening a block, choose a Huffman-Table Type */ @@ -285,7 +291,7 @@ static int dfltcc_was_deflate_used(PREFIX3(streamp) strm) { return strm->total_in > 0 || param->nt == 0 || param->hl > 0; } -int ZLIB_INTERNAL dfltcc_deflate_params(PREFIX3(streamp) strm, int level, int strategy) { +int ZLIB_INTERNAL dfltcc_deflate_params(PREFIX3(streamp) strm, int level, int strategy, int *flush) { deflate_state *state = (deflate_state *)strm->state; int could_deflate = dfltcc_can_deflate(strm); int can_deflate = dfltcc_can_deflate_with_params(strm, level, state->w_bits, strategy, state->reproducible); @@ -298,8 +304,28 @@ int ZLIB_INTERNAL dfltcc_deflate_params(PREFIX3(streamp) strm, int level, int st /* DFLTCC was not used yet - no changes needed */ return Z_OK; - /* Switching between hardware and software is not implemented */ - return Z_STREAM_ERROR; + /* For now, do not convert between window formats - simply get rid of the old data instead */ + *flush = Z_FULL_FLUSH; + return Z_OK; +} + +int ZLIB_INTERNAL dfltcc_deflate_done(PREFIX3(streamp) strm, int flush) { + deflate_state *state = (deflate_state *)strm->state; + struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state); + struct dfltcc_param_v0 *param = &dfltcc_state->param; + + /* When deflate(Z_FULL_FLUSH) is called with small avail_out, it might + * close the block without resetting the compression state. Detect this + * situation and return that deflation is not done. + */ + if (flush == Z_FULL_FLUSH && strm->avail_out == 0) + return 0; + + /* Return that deflation is not done if DFLTCC is used and either it + * buffered some data (Continuation Flag is set), or has not written EOBS + * yet (Block-Continuation Flag is set). + */ + return !dfltcc_can_deflate(strm) || (!param->cf && !param->bcf); } int ZLIB_INTERNAL dfltcc_can_set_reproducible(PREFIX3(streamp) strm, int reproducible) { @@ -349,6 +375,7 @@ int ZLIB_INTERNAL dfltcc_deflate_set_dictionary(PREFIX3(streamp) strm, append_history(param, state->window, dictionary, dict_length); state->strstart = 1; /* Add FDICT to zlib header */ + state->block_start = state->strstart; /* Make deflate_stored happy */ return Z_OK; } diff --git a/arch/s390/dfltcc_deflate.h b/arch/s390/dfltcc_deflate.h index 8775321b3..d4c9143d7 100644 --- a/arch/s390/dfltcc_deflate.h +++ b/arch/s390/dfltcc_deflate.h @@ -5,7 +5,8 @@ int ZLIB_INTERNAL dfltcc_can_deflate(PREFIX3(streamp) strm); int ZLIB_INTERNAL dfltcc_deflate(PREFIX3(streamp) strm, int flush, block_state *result); -int ZLIB_INTERNAL dfltcc_deflate_params(PREFIX3(streamp) strm, int level, int strategy); +int ZLIB_INTERNAL dfltcc_deflate_params(PREFIX3(streamp) strm, int level, int strategy, int *flush); +int ZLIB_INTERNAL dfltcc_deflate_done(PREFIX3(streamp) strm, int flush); int ZLIB_INTERNAL dfltcc_can_set_reproducible(PREFIX3(streamp) strm, int reproducible); int ZLIB_INTERNAL dfltcc_deflate_set_dictionary(PREFIX3(streamp) strm, const unsigned char *dictionary, uInt dict_length); @@ -26,15 +27,17 @@ int ZLIB_INTERNAL dfltcc_deflate_get_dictionary(PREFIX3(streamp) strm, unsigned #define DEFLATE_RESET_KEEP_HOOK(strm) \ dfltcc_reset((strm), sizeof(deflate_state)) -#define DEFLATE_PARAMS_HOOK(strm, level, strategy) \ +#define DEFLATE_PARAMS_HOOK(strm, level, strategy, hook_flush) \ do { \ int err; \ \ - err = dfltcc_deflate_params((strm), (level), (strategy)); \ + err = dfltcc_deflate_params((strm), (level), (strategy), (hook_flush)); \ if (err == Z_STREAM_ERROR) \ return err; \ } while (0) +#define DEFLATE_DONE dfltcc_deflate_done + #define DEFLATE_BOUND_ADJUST_COMPLEN(strm, complen, source_len) \ do { \ if (dfltcc_can_deflate((strm))) \ diff --git a/deflate.c b/deflate.c index 37cb5675b..4ff6e7b60 100644 --- a/deflate.c +++ b/deflate.c @@ -80,7 +80,9 @@ const char PREFIX(deflate_copyright)[] = " deflate 1.2.12.f Copyright 1995-2016 /* Invoked at the end of deflateResetKeep(). Useful for initializing arch-specific extension blocks. */ # define DEFLATE_RESET_KEEP_HOOK(strm) do {} while (0) /* Invoked at the beginning of deflateParams(). Useful for updating arch-specific compression parameters. */ -# define DEFLATE_PARAMS_HOOK(strm, level, strategy) do {} while (0) +# define DEFLATE_PARAMS_HOOK(strm, level, strategy, hook_flush) do {} while (0) +/* Returns whether the last deflate(flush) operation did everything it's supposed to do. */ +# define DEFLATE_DONE(strm, flush) 1 /* Adjusts the upper bound on compressed data length based on compression parameters and uncompressed data length. * Useful when arch-specific deflation code behaves differently than regular zlib-ng algorithms. */ # define DEFLATE_BOUND_ADJUST_COMPLEN(strm, complen, sourceLen) do {} while (0) @@ -610,6 +612,7 @@ int32_t ZEXPORT PREFIX(deflatePrime)(PREFIX3(stream) *strm, int32_t bits, int32_ int32_t ZEXPORT PREFIX(deflateParams)(PREFIX3(stream) *strm, int32_t level, int32_t strategy) { deflate_state *s; compress_func func; + int hook_flush = Z_NO_FLUSH; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -620,16 +623,17 @@ int32_t ZEXPORT PREFIX(deflateParams)(PREFIX3(stream) *strm, int32_t level, int3 if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } - DEFLATE_PARAMS_HOOK(strm, level, strategy); /* hook for IBM Z DFLTCC */ + DEFLATE_PARAMS_HOOK(strm, level, strategy, &hook_flush); /* hook for IBM Z DFLTCC */ func = configuration_table[s->level].func; - if ((strategy != s->strategy || func != configuration_table[level].func) && - s->last_flush != -2) { - /* Flush the last buffer: */ - int err = PREFIX(deflate)(strm, Z_BLOCK); + if (((strategy != s->strategy || func != configuration_table[level].func) && s->last_flush != -2) || + hook_flush != Z_NO_FLUSH) { + /* Flush the last buffer. Use Z_BLOCK mode, unless the hook requests a "stronger" one. */ + int flush = RANK(hook_flush) > RANK(Z_BLOCK) ? hook_flush : Z_BLOCK; + int err = PREFIX(deflate)(strm, flush); if (err == Z_STREAM_ERROR) return err; - if (strm->avail_in || (s->strstart - s->block_start) + s->lookahead) + if (strm->avail_in || (s->strstart - s->block_start) + s->lookahead || !DEFLATE_DONE(strm, flush)) return Z_BUF_ERROR; } if (s->level != level) {