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;
}
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
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 */
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);
/* 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) {
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;
}
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);
#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))) \
/* 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)
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;
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) {