65fa5e
From 608b71008c16ce6fbf2305145c5ffb69cd88ef59 Mon Sep 17 00:00:00 2001
65fa5e
From: Ondrej Dubaj <odubaj@redhat.com>
65fa5e
Date: Fri, 7 Aug 2020 07:12:50 +0200
65fa5e
Subject: [PATCH] Fix for Z hardware-accelerated deflate for s390x
65fa5e
65fa5e
---
65fa5e
 configure                     |   7 +
65fa5e
 contrib/s390/dfltcc.c         | 244 +++++++++++++++++++++-------------
65fa5e
 contrib/s390/dfltcc_deflate.h |  10 +-
65fa5e
 deflate.c                     |  21 +--
65fa5e
 4 files changed, 177 insertions(+), 105 deletions(-)
65fa5e
65fa5e
diff --git a/configure b/configure
65fa5e
index 66caece..bfe4386 100755
65fa5e
--- a/configure
65fa5e
+++ b/configure
65fa5e
@@ -114,6 +114,7 @@ case "$1" in
65fa5e
       echo '  configure [--const] [--zprefix] [--prefix=PREFIX]  [--eprefix=EXPREFIX]' | tee -a configure.log
65fa5e
       echo '    [--static] [--64] [--libdir=LIBDIR] [--sharedlibdir=LIBDIR]' | tee -a configure.log
65fa5e
       echo '    [--includedir=INCLUDEDIR] [--archs="-arch i386 -arch x86_64"]' | tee -a configure.log
65fa5e
+      echo '    [--dfltcc]' | tee -a configure.log
65fa5e
         exit 0 ;;
65fa5e
     -p*=* | --prefix=*) prefix=`echo $1 | sed 's/.*=//'`; shift ;;
65fa5e
     -e*=* | --eprefix=*) exec_prefix=`echo $1 | sed 's/.*=//'`; shift ;;
65fa5e
@@ -137,6 +138,12 @@ case "$1" in
65fa5e
     -c* | --const) zconst=1; shift ;;
65fa5e
     -w* | --warn) warn=1; shift ;;
65fa5e
     -d* | --debug) debug=1; shift ;;
65fa5e
+    --dfltcc)
65fa5e
+	    CFLAGS="$CFLAGS -DDFLTCC"
65fa5e
+      OBJC="$OBJC dfltcc.o"
65fa5e
+	    PIC_OBJC="$PIC_OBJC dfltcc.lo"
65fa5e
+      shift
65fa5e
+      ;; 
65fa5e
     *)
65fa5e
       echo "unknown option: $1" | tee -a configure.log
65fa5e
       echo "$0 --help for help" | tee -a configure.log
65fa5e
diff --git a/contrib/s390/dfltcc.c b/contrib/s390/dfltcc.c
65fa5e
index d187796..d88a0d6 100644
65fa5e
--- a/contrib/s390/dfltcc.c
65fa5e
+++ b/contrib/s390/dfltcc.c
65fa5e
@@ -2,12 +2,13 @@
65fa5e
 
65fa5e
 /*
65fa5e
    Use the following commands to build zlib with DFLTCC support:
65fa5e
-        $ CFLAGS=-DDFLTCC ./configure
65fa5e
-        $ make OBJA=dfltcc.o PIC_OBJA=dfltcc.lo
65fa5e
+        $ ./configure --dfltcc
65fa5e
+        $ make 
65fa5e
 */
65fa5e
 
65fa5e
 #define _GNU_SOURCE
65fa5e
 #include <ctype.h>
65fa5e
+#include <errno.h>
65fa5e
 #include <inttypes.h>
65fa5e
 #include <stddef.h>
65fa5e
 #include <stdio.h>
65fa5e
@@ -230,31 +231,28 @@ struct dfltcc_state {
65fa5e
 /*
65fa5e
    Compress.
65fa5e
  */
65fa5e
-local inline int dfltcc_are_params_ok(int level,
65fa5e
-                                      uInt window_bits,
65fa5e
-                                      int strategy,
65fa5e
-                                      uLong level_mask);
65fa5e
-local inline int dfltcc_are_params_ok(level, window_bits, strategy, level_mask)
65fa5e
+local inline int dfltcc_can_deflate_with_params(z_streamp strm,
65fa5e
+                                                 int level,
65fa5e
+                                                 uInt window_bits,
65fa5e
+                                                 int strategy);
65fa5e
+local inline int dfltcc_can_deflate_with_params(strm,
65fa5e
+                                                 level,
65fa5e
+                                                 window_bits,
65fa5e
+                                                 strategy)
65fa5e
+    z_streamp strm; 
65fa5e
     int level;
65fa5e
     uInt window_bits;
65fa5e
     int strategy;
65fa5e
-    uLong level_mask;
65fa5e
-{
65fa5e
-    return (level_mask & (1 << level)) != 0 &&
65fa5e
-        (window_bits == HB_BITS) &&
65fa5e
-        (strategy == Z_FIXED || strategy == Z_DEFAULT_STRATEGY);
65fa5e
-}
65fa5e
-
65fa5e
-
65fa5e
-int ZLIB_INTERNAL dfltcc_can_deflate(strm)
65fa5e
-    z_streamp strm;
65fa5e
 {
65fa5e
     deflate_state FAR *state = (deflate_state FAR *)strm->state;
65fa5e
     struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state);
65fa5e
 
65fa5e
     /* Unsupported compression settings */
65fa5e
-    if (!dfltcc_are_params_ok(state->level, state->w_bits, state->strategy,
65fa5e
-                              dfltcc_state->level_mask))
65fa5e
+    if ((dfltcc_state->level_mask & (1 << level)) == 0)
65fa5e
+        return 0;
65fa5e
+    if (window_bits != HB_BITS)
65fa5e
+        return 0;
65fa5e
+    if (strategy != Z_FIXED && strategy != Z_DEFAULT_STRATEGY) 
65fa5e
         return 0;
65fa5e
 
65fa5e
     /* Unsupported hardware */
65fa5e
@@ -266,6 +264,17 @@ int ZLIB_INTERNAL dfltcc_can_deflate(strm)
65fa5e
     return 1;
65fa5e
 }
65fa5e
 
65fa5e
+int ZLIB_INTERNAL dfltcc_can_deflate(strm)
65fa5e
+    z_streamp strm;
65fa5e
+{
65fa5e
+    deflate_state FAR *state = (deflate_state FAR *)strm->state;
65fa5e
+
65fa5e
+    return dfltcc_can_deflate_with_params(strm,
65fa5e
+                                          state->level,
65fa5e
+                                          state->w_bits,
65fa5e
+                                          state->strategy);
65fa5e
+} 
65fa5e
+
65fa5e
 local void dfltcc_gdht OF((z_streamp strm));
65fa5e
 local void dfltcc_gdht(strm)
65fa5e
     z_streamp strm;
65fa5e
@@ -349,22 +358,24 @@ again:
65fa5e
     soft_bcc = 0;
65fa5e
     no_flush = flush == Z_NO_FLUSH;
65fa5e
 
65fa5e
-    /* Trailing empty block. Switch to software, except when Continuation Flag
65fa5e
-     * is set, which means that DFLTCC has buffered some output in the
65fa5e
-     * parameter block and needs to be called again in order to flush it.
65fa5e
+    /* No input data. Return, except when Continuation Flag is set, which means
65fa5e
+     * that DFLTCC has buffered some output in the parameter block and needs to
65fa5e
+     * be called again in order to flush it. 
65fa5e
      */
65fa5e
-    if (flush == Z_FINISH && strm->avail_in == 0 && !param->cf) {
65fa5e
-        if (param->bcf) {
65fa5e
-            /* A block is still open, and the hardware does not support closing
65fa5e
-             * blocks without adding data. Thus, close it manually.
65fa5e
-             */
65fa5e
+    if (strm->avail_in == 0 && !param->cf) {
65fa5e
+        /* A block is still open, and the hardware does not support closing
65fa5e
+         * blocks without adding data. Thus, close it manually.
65fa5e
+         */
65fa5e
+        if (!no_flush && param->bcf) { 
65fa5e
             send_eobs(strm, param);
65fa5e
             param->bcf = 0;
65fa5e
         }
65fa5e
-        return 0;
65fa5e
-    }
65fa5e
-
65fa5e
-    if (strm->avail_in == 0 && !param->cf) {
65fa5e
+        /* Let one of deflate_* functions write a trailing empty block. */
65fa5e
+        if (flush == Z_FINISH)
65fa5e
+            return 0;
65fa5e
+        /* Clear history. */
65fa5e
+        if (flush == Z_FULL_FLUSH)
65fa5e
+            param->hl = 0; 
65fa5e
         *result = need_more;
65fa5e
         return 1;
65fa5e
     }
65fa5e
@@ -418,7 +429,7 @@ again:
65fa5e
     param->cvt = state->wrap == 2 ? CVT_CRC32 : CVT_ADLER32;
65fa5e
     if (!no_flush)
65fa5e
         /* We need to close a block. Always do this in software - when there is
65fa5e
-         * no input data, the hardware will not nohor BCC. */
65fa5e
+         * no input data, the hardware will not honor BCC. */
65fa5e
         soft_bcc = 1;
65fa5e
     if (flush == Z_FINISH && !param->bcf)
65fa5e
         /* We are about to open a BFINAL block, set Block Header Final bit
65fa5e
@@ -433,8 +444,8 @@ again:
65fa5e
     param->sbb = (unsigned int)state->bi_valid;
65fa5e
     if (param->sbb > 0)
65fa5e
         *strm->next_out = (Bytef)state->bi_buf;
65fa5e
-    if (param->hl)
65fa5e
-        param->nt = 0; /* Honor history */
65fa5e
+    /* Honor history and check value */
65fa5e
+    param->nt = 0; 
65fa5e
     param->cv = state->wrap == 2 ? ZSWAP32(strm->adler) : strm->adler;
65fa5e
 
65fa5e
     /* When opening a block, choose a Huffman-Table Type */
65fa5e
@@ -642,27 +653,86 @@ int ZLIB_INTERNAL dfltcc_inflate_disable(strm)
65fa5e
     return 0;
65fa5e
 }
65fa5e
 
65fa5e
-/*
65fa5e
-   Memory management.
65fa5e
-   DFLTCC requires parameter blocks and window to be aligned. zlib allows
65fa5e
-   users to specify their own allocation functions, so using e.g.
65fa5e
-   `posix_memalign' is not an option. Thus, we overallocate and take the
65fa5e
-   aligned portion of the buffer.
65fa5e
-*/
65fa5e
+local int env_dfltcc_disabled;
65fa5e
+local int env_source_date_epoch;
65fa5e
+local unsigned long env_level_mask;
65fa5e
+local unsigned long env_block_size;
65fa5e
+local unsigned long env_block_threshold;
65fa5e
+local unsigned long env_dht_threshold;
65fa5e
+local unsigned long env_ribm;
65fa5e
+local uint64_t cpu_facilities[(DFLTCC_FACILITY / 64) + 1];
65fa5e
+local struct dfltcc_qaf_param cpu_af __attribute__((aligned(8))); 
65fa5e
+
65fa5e
 local inline int is_dfltcc_enabled OF((void));
65fa5e
 local inline int is_dfltcc_enabled(void)
65fa5e
+{
65fa5e
+    if (env_dfltcc_disabled)
65fa5e
+      /* User has explicitly disabled DFLTCC. */
65fa5e
+      return 0;
65fa5e
+
65fa5e
+    return is_bit_set((const char *)cpu_facilities, DFLTCC_FACILITY);
65fa5e
+}
65fa5e
+
65fa5e
+local unsigned long xstrtoul OF((const char *s, unsigned long _default));
65fa5e
+local unsigned long xstrtoul(s, _default)
65fa5e
+    const char *s;
65fa5e
+    unsigned long _default;
65fa5e
+{
65fa5e
+    char *endptr;
65fa5e
+    unsigned long result;
65fa5e
+
65fa5e
+    if (!(s && *s))
65fa5e
+        return _default;
65fa5e
+    errno = 0;
65fa5e
+    result = strtoul(s, &endptr, 0);
65fa5e
+    return (errno || *endptr) ? _default : result;
65fa5e
+}
65fa5e
+
65fa5e
+__attribute__((constructor)) local void init_globals OF((void));
65fa5e
+__attribute__((constructor)) local void init_globals(void)
65fa5e
 {
65fa5e
     const char *env;
65fa5e
-    uint64_t facilities[(DFLTCC_FACILITY / 64) + 1];
65fa5e
     register char r0 __asm__("r0");
65fa5e
 
65fa5e
     env = secure_getenv("DFLTCC");
65fa5e
-    if (env && !strcmp(env, "0"))
65fa5e
-      /* User has explicitly disabled DFLTCC. */
65fa5e
-      return 0;
65fa5e
+    
65fa5e
+
65fa5e
+    env_dfltcc_disabled = env && !strcmp(env, "0");
65fa5e
+
65fa5e
+    env = secure_getenv("SOURCE_DATE_EPOCH");
65fa5e
+    env_source_date_epoch = !!env;
65fa5e
+
65fa5e
+#ifndef DFLTCC_LEVEL_MASK
65fa5e
+#define DFLTCC_LEVEL_MASK 0x2
65fa5e
+#endif
65fa5e
+    env_level_mask = xstrtoul(secure_getenv("DFLTCC_LEVEL_MASK"),
65fa5e
+                              DFLTCC_LEVEL_MASK);
65fa5e
+
65fa5e
+#ifndef DFLTCC_BLOCK_SIZE
65fa5e
+#define DFLTCC_BLOCK_SIZE 1048576
65fa5e
+#endif
65fa5e
+    env_block_size = xstrtoul(secure_getenv("DFLTCC_BLOCK_SIZE"),
65fa5e
+                              DFLTCC_BLOCK_SIZE);
65fa5e
 
65fa5e
-    memset(facilities, 0, sizeof(facilities));
65fa5e
-    r0 = sizeof(facilities) / sizeof(facilities[0]) - 1;
65fa5e
+#ifndef DFLTCC_FIRST_FHT_BLOCK_SIZE
65fa5e
+#define DFLTCC_FIRST_FHT_BLOCK_SIZE 4096
65fa5e
+#endif
65fa5e
+    env_block_threshold = xstrtoul(secure_getenv("DFLTCC_FIRST_FHT_BLOCK_SIZE"),
65fa5e
+                                   DFLTCC_FIRST_FHT_BLOCK_SIZE);
65fa5e
+
65fa5e
+#ifndef DFLTCC_DHT_MIN_SAMPLE_SIZE
65fa5e
+#define DFLTCC_DHT_MIN_SAMPLE_SIZE 4096
65fa5e
+#endif
65fa5e
+    env_dht_threshold = xstrtoul(secure_getenv("DFLTCC_DHT_MIN_SAMPLE_SIZE"),
65fa5e
+                                  DFLTCC_DHT_MIN_SAMPLE_SIZE);
65fa5e
+
65fa5e
+#ifndef DFLTCC_RIBM
65fa5e
+#define DFLTCC_RIBM 0
65fa5e
+#endif
65fa5e
+    env_ribm = xstrtoul(secure_getenv("DFLTCC_RIBM"), DFLTCC_RIBM);
65fa5e
+
65fa5e
+    memset(cpu_facilities, 0, sizeof(cpu_facilities));
65fa5e
+    r0 = sizeof(cpu_facilities) / sizeof(cpu_facilities[0]) - 1;
65fa5e
     /* STFLE is supported since z9-109 and only in z/Architecture mode. When
65fa5e
      * compiling with -m31, gcc defaults to ESA mode, however, since the kernel
65fa5e
      * is 64-bit, it's always z/Architecture mode at runtime.
65fa5e
@@ -671,31 +741,35 @@ local inline int is_dfltcc_enabled(void)
65fa5e
                      ".machinemode zarch\n"
65fa5e
                      "stfle %[facilities]\n"
65fa5e
                      ".machinemode pop\n"
65fa5e
-                     : [facilities] "=Q" (facilities)
65fa5e
+                     : [facilities] "=Q" (cpu_facilities)
65fa5e
                      , [r0] "+r" (r0)
65fa5e
                      :
65fa5e
                      : "cc");
65fa5e
-    return is_bit_set((const char *)facilities, DFLTCC_FACILITY);
65fa5e
+    /* Initialize available functions */
65fa5e
+    if (is_dfltcc_enabled())
65fa5e
+        dfltcc(DFLTCC_QAF, &cpu_af, NULL, NULL, NULL, NULL, NULL);
65fa5e
+    else
65fa5e
+        memset(&cpu_af, 0, sizeof(cpu_af)); 
65fa5e
 }
65fa5e
 
65fa5e
+/*
65fa5e
+   Memory management.
65fa5e
+
65fa5e
+   DFLTCC requires parameter blocks and window to be aligned. zlib allows
65fa5e
+   users to specify their own allocation functions, so using e.g.
65fa5e
+   `posix_memalign' is not an option. Thus, we overallocate and take the
65fa5e
+   aligned portion of the buffer.
65fa5e
+*/ 
65fa5e
 void ZLIB_INTERNAL dfltcc_reset(strm, size)
65fa5e
     z_streamp strm;
65fa5e
     uInt size;
65fa5e
 {
65fa5e
     struct dfltcc_state *dfltcc_state =
65fa5e
         (struct dfltcc_state *)((char FAR *)strm->state + ALIGN_UP(size, 8));
65fa5e
-    struct dfltcc_qaf_param *param =
65fa5e
-        (struct dfltcc_qaf_param *)&dfltcc_state->param;
65fa5e
-    const char *s;
65fa5e
 
65fa5e
-    /* Initialize available functions */
65fa5e
-    if (is_dfltcc_enabled()) {
65fa5e
-        dfltcc(DFLTCC_QAF, param, NULL, NULL, NULL, NULL, NULL);
65fa5e
-        memmove(&dfltcc_state->af, param, sizeof(dfltcc_state->af));
65fa5e
-    } else
65fa5e
-        memset(&dfltcc_state->af, 0, sizeof(dfltcc_state->af));
65fa5e
+    memcpy(&dfltcc_state->af, &cpu_af, sizeof(dfltcc_state->af));
65fa5e
 
65fa5e
-    if (secure_getenv("SOURCE_DATE_EPOCH"))
65fa5e
+    if (env_source_date_epoch)
65fa5e
         /* User needs reproducible results, but the output of DFLTCC_CMPR
65fa5e
          * depends on buffers' page offsets.
65fa5e
          */
65fa5e
@@ -706,36 +780,11 @@ void ZLIB_INTERNAL dfltcc_reset(strm, size)
65fa5e
     dfltcc_state->param.nt = 1;
65fa5e
 
65fa5e
     /* Initialize tuning parameters */
65fa5e
-#ifndef DFLTCC_LEVEL_MASK
65fa5e
-#define DFLTCC_LEVEL_MASK 0x2
65fa5e
-#endif
65fa5e
-    s = secure_getenv("DFLTCC_LEVEL_MASK");
65fa5e
-    dfltcc_state->level_mask = (s && *s) ? strtoul(s, NULL, 0) :
65fa5e
-                                           DFLTCC_LEVEL_MASK;
65fa5e
-#ifndef DFLTCC_BLOCK_SIZE
65fa5e
-#define DFLTCC_BLOCK_SIZE 1048576
65fa5e
-#endif
65fa5e
-    s = secure_getenv("DFLTCC_BLOCK_SIZE");
65fa5e
-    dfltcc_state->block_size = (s && *s) ? strtoul(s, NULL, 0) :
65fa5e
-                                           DFLTCC_BLOCK_SIZE;
65fa5e
-#ifndef DFLTCC_FIRST_FHT_BLOCK_SIZE
65fa5e
-#define DFLTCC_FIRST_FHT_BLOCK_SIZE 4096
65fa5e
-#endif
65fa5e
-    s = secure_getenv("DFLTCC_FIRST_FHT_BLOCK_SIZE");
65fa5e
-    dfltcc_state->block_threshold = (s && *s) ? strtoul(s, NULL, 0) :
65fa5e
-                                                DFLTCC_FIRST_FHT_BLOCK_SIZE;
65fa5e
-#ifndef DFLTCC_DHT_MIN_SAMPLE_SIZE
65fa5e
-#define DFLTCC_DHT_MIN_SAMPLE_SIZE 4096
65fa5e
-#endif
65fa5e
-    s = secure_getenv("DFLTCC_DHT_MIN_SAMPLE_SIZE");
65fa5e
-    dfltcc_state->dht_threshold = (s && *s) ? strtoul(s, NULL, 0) :
65fa5e
-                                              DFLTCC_DHT_MIN_SAMPLE_SIZE;
65fa5e
-#ifndef DFLTCC_RIBM
65fa5e
-#define DFLTCC_RIBM 0
65fa5e
-#endif
65fa5e
-    s = secure_getenv("DFLTCC_RIBM");
65fa5e
-    dfltcc_state->param.ribm = (s && *s) ? strtoul(s, NULL, 0) :
65fa5e
-                                           DFLTCC_RIBM;
65fa5e
+    dfltcc_state->level_mask = env_level_mask;
65fa5e
+    dfltcc_state->block_size = env_block_size;
65fa5e
+    dfltcc_state->block_threshold = env_block_threshold;
65fa5e
+    dfltcc_state->dht_threshold = env_dht_threshold;
65fa5e
+    dfltcc_state->param.ribm = env_ribm;
65fa5e
 }
65fa5e
 
65fa5e
 voidpf ZLIB_INTERNAL dfltcc_alloc_state(strm, items, size)
65fa5e
@@ -787,22 +836,26 @@ void ZLIB_INTERNAL dfltcc_free_window(strm, w)
65fa5e
 
65fa5e
 /*
65fa5e
    Switching between hardware and software compression.
65fa5e
+
65fa5e
    DFLTCC does not support all zlib settings, e.g. generation of non-compressed
65fa5e
    blocks or alternative window sizes. When such settings are applied on the
65fa5e
    fly with deflateParams, we need to convert between hardware and software
65fa5e
    window formats.
65fa5e
 */
65fa5e
-int ZLIB_INTERNAL dfltcc_deflate_params(strm, level, strategy)
65fa5e
+int ZLIB_INTERNAL dfltcc_deflate_params(strm, level, strategy, flush)
65fa5e
     z_streamp strm;
65fa5e
     int level;
65fa5e
     int strategy;
65fa5e
+    int *flush;
65fa5e
 {
65fa5e
     deflate_state FAR *state = (deflate_state FAR *)strm->state;
65fa5e
     struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state);
65fa5e
     struct dfltcc_param_v0 FAR *param = &dfltcc_state->param;
65fa5e
     int could_deflate = dfltcc_can_deflate(strm);
65fa5e
-    int can_deflate = dfltcc_are_params_ok(level, state->w_bits, strategy,
65fa5e
-                                           dfltcc_state->level_mask);
65fa5e
+    int can_deflate = dfltcc_can_deflate_with_params(strm,
65fa5e
+                                                     level,
65fa5e
+                                                     state->w_bits,
65fa5e
+                                                     strategy); 
65fa5e
 
65fa5e
     if (can_deflate == could_deflate)
65fa5e
         /* We continue to work in the same mode - no changes needed */
65fa5e
@@ -812,8 +865,11 @@ int ZLIB_INTERNAL dfltcc_deflate_params(strm, level, strategy)
65fa5e
         /* DFLTCC was not used yet - no changes needed */
65fa5e
         return Z_OK;
65fa5e
 
65fa5e
-    /* Switching between hardware and software is not implemented */
65fa5e
-    return Z_STREAM_ERROR;
65fa5e
+    /* For now, do not convert between window formats - simply get rid of the
65fa5e
+     * old data instead.
65fa5e
+     */
65fa5e
+    *flush = Z_FULL_FLUSH;
65fa5e
+    return Z_OK; 
65fa5e
 }
65fa5e
 
65fa5e
 /*
65fa5e
diff --git a/contrib/s390/dfltcc_deflate.h b/contrib/s390/dfltcc_deflate.h
65fa5e
index a129a91..de36784 100644
65fa5e
--- a/contrib/s390/dfltcc_deflate.h
65fa5e
+++ b/contrib/s390/dfltcc_deflate.h
65fa5e
@@ -9,7 +9,8 @@ int ZLIB_INTERNAL dfltcc_deflate OF((z_streamp strm,
65fa5e
                                      block_state *result));
65fa5e
 int ZLIB_INTERNAL dfltcc_deflate_params OF((z_streamp strm,
65fa5e
                                             int level,
65fa5e
-                                            int strategy));
65fa5e
+                                            int strategy,
65fa5e
+                                            int *flush)); 
65fa5e
 int ZLIB_INTERNAL dfltcc_deflate_set_dictionary OF((z_streamp strm,
65fa5e
                                                     const Bytef *dictionary,
65fa5e
                                                     uInt dict_length));
65fa5e
@@ -29,11 +30,14 @@ int ZLIB_INTERNAL dfltcc_deflate_get_dictionary OF((z_streamp strm,
65fa5e
     } while (0)
65fa5e
 #define DEFLATE_RESET_KEEP_HOOK(strm) \
65fa5e
     dfltcc_reset((strm), sizeof(deflate_state))
65fa5e
-#define DEFLATE_PARAMS_HOOK(strm, level, strategy) \
65fa5e
+#define DEFLATE_PARAMS_HOOK(strm, level, strategy, hook_flush) \
65fa5e
     do { \
65fa5e
         int err; \
65fa5e
 \
65fa5e
-        err = dfltcc_deflate_params((strm), (level), (strategy)); \
65fa5e
+        err = dfltcc_deflate_params((strm), \
65fa5e
+                                    (level), \
65fa5e
+                                    (strategy), \
65fa5e
+                                    (hook_flush)); \
65fa5e
         if (err == Z_STREAM_ERROR) \
65fa5e
             return err; \
65fa5e
     } while (0)
65fa5e
diff --git a/deflate.c b/deflate.c
65fa5e
index b17a7dd..a80bd3e 100644
65fa5e
--- a/deflate.c
65fa5e
+++ b/deflate.c
65fa5e
@@ -74,7 +74,7 @@ const char deflate_copyright[] =
65fa5e
 #define DEFLATE_SET_DICTIONARY_HOOK(strm, dict, dict_len) do {} while (0)
65fa5e
 #define DEFLATE_GET_DICTIONARY_HOOK(strm, dict, dict_len) do {} while (0)
65fa5e
 #define DEFLATE_RESET_KEEP_HOOK(strm) do {} while (0)
65fa5e
-#define DEFLATE_PARAMS_HOOK(strm, level, strategy) do {} while (0)
65fa5e
+#define DEFLATE_PARAMS_HOOK(strm, level, strategy, hook_flush) do {} while (0)
65fa5e
 #define DEFLATE_BOUND_ADJUST_COMPLEN(strm, complen, sourceLen) do {} while (0)
65fa5e
 #define DEFLATE_NEED_CONSERVATIVE_BOUND(strm) 0
65fa5e
 #define DEFLATE_HOOK(strm, flush, bstate) 0
65fa5e
@@ -589,6 +589,7 @@ int ZEXPORT deflateParams(strm, level, strategy)
65fa5e
 {
65fa5e
     deflate_state *s;
65fa5e
     compress_func func;
65fa5e
+    int hook_flush = Z_NO_FLUSH;
65fa5e
 
65fa5e
     if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
65fa5e
     s = strm->state;
65fa5e
@@ -601,13 +602,14 @@ int ZEXPORT deflateParams(strm, level, strategy)
65fa5e
     if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
65fa5e
         return Z_STREAM_ERROR;
65fa5e
     }
65fa5e
-    DEFLATE_PARAMS_HOOK(strm, level, strategy);
65fa5e
+    DEFLATE_PARAMS_HOOK(strm, level, strategy, &hook_flush);
65fa5e
     func = configuration_table[s->level].func;
65fa5e
 
65fa5e
-    if ((strategy != s->strategy || func != configuration_table[level].func) &&
65fa5e
-        s->high_water) {
65fa5e
+    if ((strategy != s->strategy || func != configuration_table[level].func ||
65fa5e
+        hook_flush != Z_NO_FLUSH) && s->high_water) {
65fa5e
         /* Flush the last buffer: */
65fa5e
-        int err = deflate(strm, Z_BLOCK);
65fa5e
+        int err = deflate(strm, RANK(hook_flush) > RANK(Z_BLOCK) ?
65fa5e
+                          hook_flush : Z_BLOCK); 
65fa5e
         if (err == Z_STREAM_ERROR)
65fa5e
             return err;
65fa5e
         if (strm->avail_out == 0)
65fa5e
@@ -1065,7 +1067,6 @@ int ZEXPORT deflate (strm, flush)
65fa5e
     }
65fa5e
 
65fa5e
     if (flush != Z_FINISH) return Z_OK;
65fa5e
-    if (s->wrap <= 0) return Z_STREAM_END;
65fa5e
 
65fa5e
     /* Write the trailer */
65fa5e
 #ifdef GZIP
65fa5e
@@ -1081,7 +1082,7 @@ int ZEXPORT deflate (strm, flush)
65fa5e
     }
65fa5e
     else
65fa5e
 #endif
65fa5e
-    {
65fa5e
+    if (s->wrap == 1) {
65fa5e
         putShortMSB(s, (uInt)(strm->adler >> 16));
65fa5e
         putShortMSB(s, (uInt)(strm->adler & 0xffff));
65fa5e
     }
65fa5e
@@ -1090,7 +1091,11 @@ int ZEXPORT deflate (strm, flush)
65fa5e
      * to flush the rest.
65fa5e
      */
65fa5e
     if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
65fa5e
-    return s->pending != 0 ? Z_OK : Z_STREAM_END;
65fa5e
+    if (s->pending == 0) {
65fa5e
+        Assert(s->bi_valid == 0, "bi_buf not flushed");
65fa5e
+        return Z_STREAM_END;
65fa5e
+    }
65fa5e
+    return Z_OK; 
65fa5e
 }
65fa5e
 
65fa5e
 /* ========================================================================= */
65fa5e
-- 
65fa5e
2.26.0
65fa5e