]> git.ipfire.org Git - thirdparty/zlib-ng.git/commitdiff
Implement switching between DFLTCC and software
authorIlya Leoshkevich <iii@linux.ibm.com>
Tue, 21 Jul 2020 11:27:47 +0000 (13:27 +0200)
committerHans Kristian Rosbach <hk-github@circlestorm.org>
Fri, 21 Aug 2020 19:54:12 +0000 (21:54 +0200)
arch/s390/dfltcc_deflate.c
arch/s390/dfltcc_deflate.h
deflate.c

index c2c5f1be1f9c9a0ceb21d0f8bcde9b4e112f3da3..a088a7315509b06504df21d9d15fc5fcb78f6901 100644 (file)
@@ -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;
 }
 
index 8775321b3a3fad6164bd9c729cf47c778b36f49c..d4c9143d71326cd1e2978670322ad390c191543f 100644 (file)
@@ -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))) \
index 37cb5675bc540e12db4636a2b3b1f38cf9f38f7c..4ff6e7b608b59193f20e6658c54153c9578d1e85 100644 (file)
--- 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) {