21b10c
From 4e65ca20fc242e4a03471558a357d7809adeb9c4 Mon Sep 17 00:00:00 2001
21b10c
From: IBM developers
21b10c
Date: Thu, 1 Aug 2019 09:02:01 +0200
21b10c
Subject: [PATCH] Add support for IBM Z hardware-accelerated deflate
21b10c
21b10c
Future versions of IBM Z mainframes will provide DFLTCC instruction,
21b10c
which implements deflate algorithm in hardware with estimated
21b10c
compression and decompression performance orders of magnitude faster
21b10c
than the current zlib and ratio comparable with that of level 1.
21b10c
21b10c
This patch adds DFLTCC support to zlib. In order to enable it, the
21b10c
following build commands should be used:
21b10c
21b10c
    $ CFLAGS=-DDFLTCC ./configure
21b10c
    $ make OBJA=dfltcc.o PIC_OBJA=dfltcc.lo
21b10c
21b10c
When built like this, zlib would compress in hardware on level 1, and in
21b10c
software on all other levels. Decompression will always happen in
21b10c
hardware. In order to enable DFLTCC compression for levels 1-6 (i.e. to
21b10c
make it used by default) one could either add -DDFLTCC_LEVEL_MASK=0x7e
21b10c
at compile time, or set the environment variable DFLTCC_LEVEL_MASK to
21b10c
0x7e at run time.
21b10c
21b10c
Two DFLTCC compression calls produce the same results only when they
21b10c
both are made on machines of the same generation, and when the
21b10c
respective buffers have the same offset relative to the start of the
21b10c
page. Therefore care should be taken when using hardware compression
21b10c
when reproducible results are desired. One such use case - reproducible
21b10c
software builds - is handled explicitly: when SOURCE_DATE_EPOCH
21b10c
environment variable is set, the hardware compression is disabled.
21b10c
21b10c
DFLTCC does not support every single zlib feature, in particular:
21b10c
21b10c
    * inflate(Z_BLOCK) and inflate(Z_TREES)
21b10c
    * inflateMark()
21b10c
    * inflatePrime()
21b10c
    * deflateParams() after the first deflate() call
21b10c
21b10c
When used, these functions will either switch to software, or, in case
21b10c
this is not possible, gracefully fail.
21b10c
21b10c
This patch tries to add DFLTCC support in a least intrusive way.
21b10c
All SystemZ-specific code was placed into a separate file, but
21b10c
unfortunately there is still a noticeable amount of changes in the
21b10c
main zlib code. Below is the summary of those changes.
21b10c
21b10c
DFLTCC takes as arguments a parameter block, an input buffer, an output
21b10c
buffer and a window. Since DFLTCC requires parameter block to be
21b10c
doubleword-aligned, and it's reasonable to allocate it alongside
21b10c
deflate and inflate states, ZALLOC_STATE, ZFREE_STATE and ZCOPY_STATE
21b10c
macros were introduced in order to encapsulate the allocation details.
21b10c
The same is true for window, for which ZALLOC_WINDOW and
21b10c
TRY_FREE_WINDOW macros were introduced.
21b10c
21b10c
While for inflate software and hardware window formats match, this is
21b10c
not the case for deflate. Therefore, deflateSetDictionary and
21b10c
deflateGetDictionary need special handling, which is triggered using the
21b10c
new DEFLATE_SET_DICTIONARY_HOOK and DEFLATE_GET_DICTIONARY_HOOK macros.
21b10c
21b10c
deflateResetKeep() and inflateResetKeep() now update the DFLTCC
21b10c
parameter block, which is allocated alongside zlib state, using
21b10c
the new DEFLATE_RESET_KEEP_HOOK and INFLATE_RESET_KEEP_HOOK macros.
21b10c
21b10c
In order to make unsupported deflateParams(), inflatePrime() and
21b10c
inflateMark() calls to fail gracefully, the new DEFLATE_PARAMS_HOOK,
21b10c
INFLATE_PRIME_HOOK and INFLATE_MARK_HOOK macros were introduced.
21b10c
21b10c
The algorithm implemented in hardware has different compression ratio
21b10c
than the one implemented in software. In order for deflateBound() to
21b10c
return the correct results for the hardware implementation, the new
21b10c
DEFLATE_BOUND_ADJUST_COMPLEN and DEFLATE_NEED_CONSERVATIVE_BOUND macros
21b10c
were introduced.
21b10c
21b10c
Actual compression and decompression are handled by the new DEFLATE_HOOK
21b10c
and INFLATE_TYPEDO_HOOK macros. Since inflation with DFLTCC manages the
21b10c
window on its own, calling updatewindow() is suppressed using the new
21b10c
INFLATE_NEED_UPDATEWINDOW() macro.
21b10c
21b10c
In addition to compression, DFLTCC computes CRC-32 and Adler-32
21b10c
checksums, therefore, whenever it's used, software checksumming needs to
21b10c
be suppressed using the new DEFLATE_NEED_CHECKSUM and
21b10c
INFLATE_NEED_CHECKSUM macros.
21b10c
21b10c
DFLTCC will refuse to write an End-of-block Symbol if there is no input
21b10c
data, thus in some cases it is necessary to do this manually. In order
21b10c
to achieve this, send_bits, bi_reverse, bi_windup and flush_pending
21b10c
were promoted from local to ZLIB_INTERNAL. Furthermore, since block and
21b10c
stream termination must be handled in software as well, block_state enum
21b10c
was moved to deflate.h.
21b10c
21b10c
Since the first call to dfltcc_inflate already needs the window, and it
21b10c
might be not allocated yet, inflate_ensure_window was factored out of
21b10c
updatewindow and made ZLIB_INTERNAL.
21b10c
---
21b10c
 Makefile.in                   |   8 +
21b10c
 configure                     |  13 +
21b10c
 contrib/README.contrib        |   4 +
21b10c
 contrib/s390/dfltcc.c         | 901 ++++++++++++++++++++++++++++++++++
21b10c
 contrib/s390/dfltcc.h         |  55 +++
21b10c
 contrib/s390/dfltcc_deflate.h |  50 ++
21b10c
 deflate.c                     |  60 ++-
21b10c
 deflate.h                     |  12 +
21b10c
 gzguts.h                      |   4 +
21b10c
 inflate.c                     |  84 +++-
21b10c
 inflate.h                     |   2 +
21b10c
 test/infcover.c               |   2 +-
21b10c
 test/minigzip.c               |   4 +
21b10c
 trees.c                       |  13 +-
21b10c
 14 files changed, 1161 insertions(+), 51 deletions(-)
21b10c
 create mode 100644 contrib/s390/dfltcc.c
21b10c
 create mode 100644 contrib/s390/dfltcc.h
21b10c
 create mode 100644 contrib/s390/dfltcc_deflate.h
21b10c
21b10c
diff --git a/Makefile.in b/Makefile.in
21b10c
index 5a77949..e756e2f 100644
21b10c
--- a/Makefile.in
21b10c
+++ b/Makefile.in
21b10c
@@ -143,6 +143,14 @@ match.lo: match.S
21b10c
 	mv _match.o match.lo
21b10c
 	rm -f _match.s
21b10c
 
21b10c
+dfltcc.o: $(SRCDIR)contrib/s390/dfltcc.c $(SRCDIR)zlib.h zconf.h
21b10c
+	$(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)contrib/s390/dfltcc.c
21b10c
+
21b10c
+dfltcc.lo: $(SRCDIR)contrib/s390/dfltcc.c $(SRCDIR)zlib.h zconf.h
21b10c
+	-@mkdir objs 2>/dev/null || test -d objs
21b10c
+	$(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/dfltcc.o $(SRCDIR)contrib/s390/dfltcc.c
21b10c
+	-@mv objs/dfltcc.o $@
21b10c
+
21b10c
 example.o: $(SRCDIR)test/example.c $(SRCDIR)zlib.h zconf.h
21b10c
 	$(CC) $(CFLAGS) $(ZINCOUT) -c -o $@ $(SRCDIR)test/example.c
21b10c
 
21b10c
diff --git a/configure b/configure
21b10c
index e974d1f..8fab355 100755
21b10c
--- a/configure
21b10c
+++ b/configure
21b10c
@@ -826,6 +826,19 @@ EOF
21b10c
   fi
21b10c
 fi
21b10c
 
21b10c
+# Check whether sys/sdt.h is available
21b10c
+cat > $test.c << EOF
21b10c
+#include <sys/sdt.h>
21b10c
+int main() { return 0; }
21b10c
+EOF
21b10c
+if try ${CC} ${CFLAGS} $test.c; then
21b10c
+    echo "Checking for sys/sdt.h ... Yes." | tee -a configure.log
21b10c
+    CFLAGS="$CFLAGS -DHAVE_SYS_SDT_H"
21b10c
+    SFLAGS="$SFLAGS -DHAVE_SYS_SDT_H"
21b10c
+else
21b10c
+    echo "Checking for sys/sdt.h ... No." | tee -a configure.log
21b10c
+fi
21b10c
+
21b10c
 # show the results in the log
21b10c
 echo >> configure.log
21b10c
 echo ALL = $ALL >> configure.log
21b10c
diff --git a/contrib/README.contrib b/contrib/README.contrib
21b10c
index a411d5c..b4d3b18 100644
21b10c
--- a/contrib/README.contrib
21b10c
+++ b/contrib/README.contrib
21b10c
@@ -67,6 +67,10 @@ puff/       by Mark Adler <madler@alumni.caltech.edu>
21b10c
         Small, low memory usage inflate.  Also serves to provide an
21b10c
         unambiguous description of the deflate format.
21b10c
 
21b10c
+s390/       by Ilya Leoshkevich <iii@linux.ibm.com>
21b10c
+        Hardware-accelerated deflate on IBM Z with DEFLATE CONVERSION CALL
21b10c
+        instruction.
21b10c
+
21b10c
 testzlib/   by Gilles Vollant <info@winimage.com>
21b10c
         Example of the use of zlib
21b10c
 
21b10c
diff --git a/contrib/s390/dfltcc.c b/contrib/s390/dfltcc.c
21b10c
new file mode 100644
21b10c
index 0000000..d187796
21b10c
--- /dev/null
21b10c
+++ b/contrib/s390/dfltcc.c
21b10c
@@ -0,0 +1,901 @@
21b10c
+/* dfltcc.c - SystemZ DEFLATE CONVERSION CALL support. */
21b10c
+
21b10c
+/*
21b10c
+   Use the following commands to build zlib with DFLTCC support:
21b10c
+        $ CFLAGS=-DDFLTCC ./configure
21b10c
+        $ make OBJA=dfltcc.o PIC_OBJA=dfltcc.lo
21b10c
+*/
21b10c
+
21b10c
+#define _GNU_SOURCE
21b10c
+#include <ctype.h>
21b10c
+#include <inttypes.h>
21b10c
+#include <stddef.h>
21b10c
+#include <stdio.h>
21b10c
+#include <stdint.h>
21b10c
+#include <stdlib.h>
21b10c
+#include "../../zutil.h"
21b10c
+#include "../../deflate.h"
21b10c
+#include "../../inftrees.h"
21b10c
+#include "../../inflate.h"
21b10c
+#include "dfltcc.h"
21b10c
+#include "dfltcc_deflate.h"
21b10c
+#ifdef HAVE_SYS_SDT_H
21b10c
+#include <sys/sdt.h>
21b10c
+#endif
21b10c
+
21b10c
+/*
21b10c
+   C wrapper for the DEFLATE CONVERSION CALL instruction.
21b10c
+ */
21b10c
+typedef enum {
21b10c
+    DFLTCC_CC_OK = 0,
21b10c
+    DFLTCC_CC_OP1_TOO_SHORT = 1,
21b10c
+    DFLTCC_CC_OP2_TOO_SHORT = 2,
21b10c
+    DFLTCC_CC_OP2_CORRUPT = 2,
21b10c
+    DFLTCC_CC_AGAIN = 3,
21b10c
+} dfltcc_cc;
21b10c
+
21b10c
+#define DFLTCC_QAF 0
21b10c
+#define DFLTCC_GDHT 1
21b10c
+#define DFLTCC_CMPR 2
21b10c
+#define DFLTCC_XPND 4
21b10c
+#define HBT_CIRCULAR (1 << 7)
21b10c
+#define HB_BITS 15
21b10c
+#define HB_SIZE (1 << HB_BITS)
21b10c
+#define DFLTCC_FACILITY 151
21b10c
+
21b10c
+local inline dfltcc_cc dfltcc OF((int fn, void *param,
21b10c
+                                  Bytef **op1, size_t *len1,
21b10c
+                                  z_const Bytef **op2, size_t *len2,
21b10c
+                                  void *hist));
21b10c
+local inline dfltcc_cc dfltcc(fn, param, op1, len1, op2, len2, hist)
21b10c
+    int fn;
21b10c
+    void *param;
21b10c
+    Bytef **op1;
21b10c
+    size_t *len1;
21b10c
+    z_const Bytef **op2;
21b10c
+    size_t *len2;
21b10c
+    void *hist;
21b10c
+{
21b10c
+    Bytef *t2 = op1 ? *op1 : NULL;
21b10c
+    size_t t3 = len1 ? *len1 : 0;
21b10c
+    z_const Bytef *t4 = op2 ? *op2 : NULL;
21b10c
+    size_t t5 = len2 ? *len2 : 0;
21b10c
+    register int r0 __asm__("r0") = fn;
21b10c
+    register void *r1 __asm__("r1") = param;
21b10c
+    register Bytef *r2 __asm__("r2") = t2;
21b10c
+    register size_t r3 __asm__("r3") = t3;
21b10c
+    register z_const Bytef *r4 __asm__("r4") = t4;
21b10c
+    register size_t r5 __asm__("r5") = t5;
21b10c
+    int cc;
21b10c
+
21b10c
+    __asm__ volatile(
21b10c
+#ifdef HAVE_SYS_SDT_H
21b10c
+                     STAP_PROBE_ASM(zlib, dfltcc_entry,
21b10c
+                                    STAP_PROBE_ASM_TEMPLATE(5))
21b10c
+#endif
21b10c
+                     ".insn rrf,0xb9390000,%[r2],%[r4],%[hist],0\n"
21b10c
+#ifdef HAVE_SYS_SDT_H
21b10c
+                     STAP_PROBE_ASM(zlib, dfltcc_exit,
21b10c
+                                    STAP_PROBE_ASM_TEMPLATE(5))
21b10c
+#endif
21b10c
+                     "ipm %[cc]\n"
21b10c
+                     : [r2] "+r" (r2)
21b10c
+                     , [r3] "+r" (r3)
21b10c
+                     , [r4] "+r" (r4)
21b10c
+                     , [r5] "+r" (r5)
21b10c
+                     , [cc] "=r" (cc)
21b10c
+                     : [r0] "r" (r0)
21b10c
+                     , [r1] "r" (r1)
21b10c
+                     , [hist] "r" (hist)
21b10c
+#ifdef HAVE_SYS_SDT_H
21b10c
+                     , STAP_PROBE_ASM_OPERANDS(5, r2, r3, r4, r5, hist)
21b10c
+#endif
21b10c
+                     : "cc", "memory");
21b10c
+    t2 = r2; t3 = r3; t4 = r4; t5 = r5;
21b10c
+
21b10c
+    if (op1)
21b10c
+        *op1 = t2;
21b10c
+    if (len1)
21b10c
+        *len1 = t3;
21b10c
+    if (op2)
21b10c
+        *op2 = t4;
21b10c
+    if (len2)
21b10c
+        *len2 = t5;
21b10c
+    return (cc >> 28) & 3;
21b10c
+}
21b10c
+
21b10c
+/*
21b10c
+   Parameter Block for Query Available Functions.
21b10c
+ */
21b10c
+#define static_assert(c, msg) \
21b10c
+        __attribute__((unused)) \
21b10c
+        static char static_assert_failed_ ## msg[c ? 1 : -1]
21b10c
+
21b10c
+struct dfltcc_qaf_param {
21b10c
+    char fns[16];
21b10c
+    char reserved1[8];
21b10c
+    char fmts[2];
21b10c
+    char reserved2[6];
21b10c
+};
21b10c
+
21b10c
+static_assert(sizeof(struct dfltcc_qaf_param) == 32,
21b10c
+              sizeof_struct_dfltcc_qaf_param_is_32);
21b10c
+
21b10c
+local inline int is_bit_set OF((const char *bits, int n));
21b10c
+local inline int is_bit_set(bits, n)
21b10c
+    const char *bits;
21b10c
+    int n;
21b10c
+{
21b10c
+    return bits[n / 8] & (1 << (7 - (n % 8)));
21b10c
+}
21b10c
+
21b10c
+local inline void clear_bit OF((char *bits, int n));
21b10c
+local inline void clear_bit(bits, n)
21b10c
+    char *bits;
21b10c
+    int n;
21b10c
+{
21b10c
+    bits[n / 8] &= ~(1 << (7 - (n % 8)));
21b10c
+}
21b10c
+
21b10c
+#define DFLTCC_FMT0 0
21b10c
+
21b10c
+/*
21b10c
+   Parameter Block for Generate Dynamic-Huffman Table, Compress and Expand.
21b10c
+ */
21b10c
+#define CVT_CRC32 0
21b10c
+#define CVT_ADLER32 1
21b10c
+#define HTT_FIXED 0
21b10c
+#define HTT_DYNAMIC 1
21b10c
+
21b10c
+struct dfltcc_param_v0 {
21b10c
+    uint16_t pbvn;                     /* Parameter-Block-Version Number */
21b10c
+    uint8_t mvn;                       /* Model-Version Number */
21b10c
+    uint8_t ribm;                      /* Reserved for IBM use */
21b10c
+    unsigned reserved32 : 31;
21b10c
+    unsigned cf : 1;                   /* Continuation Flag */
21b10c
+    uint8_t reserved64[8];
21b10c
+    unsigned nt : 1;                   /* New Task */
21b10c
+    unsigned reserved129 : 1;
21b10c
+    unsigned cvt : 1;                  /* Check Value Type */
21b10c
+    unsigned reserved131 : 1;
21b10c
+    unsigned htt : 1;                  /* Huffman-Table Type */
21b10c
+    unsigned bcf : 1;                  /* Block-Continuation Flag */
21b10c
+    unsigned bcc : 1;                  /* Block Closing Control */
21b10c
+    unsigned bhf : 1;                  /* Block Header Final */
21b10c
+    unsigned reserved136 : 1;
21b10c
+    unsigned reserved137 : 1;
21b10c
+    unsigned dhtgc : 1;                /* DHT Generation Control */
21b10c
+    unsigned reserved139 : 5;
21b10c
+    unsigned reserved144 : 5;
21b10c
+    unsigned sbb : 3;                  /* Sub-Byte Boundary */
21b10c
+    uint8_t oesc;                      /* Operation-Ending-Supplemental Code */
21b10c
+    unsigned reserved160 : 12;
21b10c
+    unsigned ifs : 4;                  /* Incomplete-Function Status */
21b10c
+    uint16_t ifl;                      /* Incomplete-Function Length */
21b10c
+    uint8_t reserved192[8];
21b10c
+    uint8_t reserved256[8];
21b10c
+    uint8_t reserved320[4];
21b10c
+    uint16_t hl;                       /* History Length */
21b10c
+    unsigned reserved368 : 1;
21b10c
+    uint16_t ho : 15;                  /* History Offset */
21b10c
+    uint32_t cv;                       /* Check Value */
21b10c
+    unsigned eobs : 15;                /* End-of-block Symbol */
21b10c
+    unsigned reserved431: 1;
21b10c
+    uint8_t eobl : 4;                  /* End-of-block Length */
21b10c
+    unsigned reserved436 : 12;
21b10c
+    unsigned reserved448 : 4;
21b10c
+    uint16_t cdhtl : 12;               /* Compressed-Dynamic-Huffman Table
21b10c
+                                          Length */
21b10c
+    uint8_t reserved464[6];
21b10c
+    uint8_t cdht[288];
21b10c
+    uint8_t reserved[32];
21b10c
+    uint8_t csb[1152];
21b10c
+};
21b10c
+
21b10c
+static_assert(sizeof(struct dfltcc_param_v0) == 1536,
21b10c
+              sizeof_struct_dfltcc_param_v0_is_1536);
21b10c
+
21b10c
+local z_const char *oesc_msg OF((char *buf, int oesc));
21b10c
+local z_const char *oesc_msg(buf, oesc)
21b10c
+    char *buf;
21b10c
+    int oesc;
21b10c
+{
21b10c
+    if (oesc == 0x00)
21b10c
+        return NULL; /* Successful completion */
21b10c
+    else {
21b10c
+        sprintf(buf, "Operation-Ending-Supplemental Code is 0x%.2X", oesc);
21b10c
+        return buf;
21b10c
+    }
21b10c
+}
21b10c
+
21b10c
+/*
21b10c
+   Extension of inflate_state and deflate_state. Must be doubleword-aligned.
21b10c
+*/
21b10c
+struct dfltcc_state {
21b10c
+    struct dfltcc_param_v0 param;      /* Parameter block. */
21b10c
+    struct dfltcc_qaf_param af;        /* Available functions. */
21b10c
+    uLong level_mask;                  /* Levels on which to use DFLTCC */
21b10c
+    uLong block_size;                  /* New block each X bytes */
21b10c
+    uLong block_threshold;             /* New block after total_in > X */
21b10c
+    uLong dht_threshold;               /* New block only if avail_in >= X */
21b10c
+    char msg[64];                      /* Buffer for strm->msg */
21b10c
+};
21b10c
+
21b10c
+#define ALIGN_UP(p, size) \
21b10c
+        (__typeof__(p))(((uintptr_t)(p) + ((size) - 1)) & ~((size) - 1))
21b10c
+
21b10c
+#define GET_DFLTCC_STATE(state) ((struct dfltcc_state FAR *)( \
21b10c
+        (char FAR *)(state) + ALIGN_UP(sizeof(*state), 8)))
21b10c
+
21b10c
+/*
21b10c
+   Compress.
21b10c
+ */
21b10c
+local inline int dfltcc_are_params_ok(int level,
21b10c
+                                      uInt window_bits,
21b10c
+                                      int strategy,
21b10c
+                                      uLong level_mask);
21b10c
+local inline int dfltcc_are_params_ok(level, window_bits, strategy, level_mask)
21b10c
+    int level;
21b10c
+    uInt window_bits;
21b10c
+    int strategy;
21b10c
+    uLong level_mask;
21b10c
+{
21b10c
+    return (level_mask & (1 << level)) != 0 &&
21b10c
+        (window_bits == HB_BITS) &&
21b10c
+        (strategy == Z_FIXED || strategy == Z_DEFAULT_STRATEGY);
21b10c
+}
21b10c
+
21b10c
+
21b10c
+int ZLIB_INTERNAL dfltcc_can_deflate(strm)
21b10c
+    z_streamp strm;
21b10c
+{
21b10c
+    deflate_state FAR *state = (deflate_state FAR *)strm->state;
21b10c
+    struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state);
21b10c
+
21b10c
+    /* Unsupported compression settings */
21b10c
+    if (!dfltcc_are_params_ok(state->level, state->w_bits, state->strategy,
21b10c
+                              dfltcc_state->level_mask))
21b10c
+        return 0;
21b10c
+
21b10c
+    /* Unsupported hardware */
21b10c
+    if (!is_bit_set(dfltcc_state->af.fns, DFLTCC_GDHT) ||
21b10c
+            !is_bit_set(dfltcc_state->af.fns, DFLTCC_CMPR) ||
21b10c
+            !is_bit_set(dfltcc_state->af.fmts, DFLTCC_FMT0))
21b10c
+        return 0;
21b10c
+
21b10c
+    return 1;
21b10c
+}
21b10c
+
21b10c
+local void dfltcc_gdht OF((z_streamp strm));
21b10c
+local void dfltcc_gdht(strm)
21b10c
+    z_streamp strm;
21b10c
+{
21b10c
+    deflate_state FAR *state = (deflate_state FAR *)strm->state;
21b10c
+    struct dfltcc_param_v0 FAR *param = &GET_DFLTCC_STATE(state)->param;
21b10c
+    size_t avail_in = avail_in = strm->avail_in;
21b10c
+
21b10c
+    dfltcc(DFLTCC_GDHT,
21b10c
+           param, NULL, NULL,
21b10c
+           &strm->next_in, &avail_in, NULL);
21b10c
+}
21b10c
+
21b10c
+local dfltcc_cc dfltcc_cmpr OF((z_streamp strm));
21b10c
+local dfltcc_cc dfltcc_cmpr(strm)
21b10c
+    z_streamp strm;
21b10c
+{
21b10c
+    deflate_state FAR *state = (deflate_state FAR *)strm->state;
21b10c
+    struct dfltcc_param_v0 FAR *param = &GET_DFLTCC_STATE(state)->param;
21b10c
+    size_t avail_in = strm->avail_in;
21b10c
+    size_t avail_out = strm->avail_out;
21b10c
+    dfltcc_cc cc;
21b10c
+
21b10c
+    cc = dfltcc(DFLTCC_CMPR | HBT_CIRCULAR,
21b10c
+                param, &strm->next_out, &avail_out,
21b10c
+                &strm->next_in, &avail_in, state->window);
21b10c
+    strm->total_in += (strm->avail_in - avail_in);
21b10c
+    strm->total_out += (strm->avail_out - avail_out);
21b10c
+    strm->avail_in = avail_in;
21b10c
+    strm->avail_out = avail_out;
21b10c
+    return cc;
21b10c
+}
21b10c
+
21b10c
+local void send_eobs OF((z_streamp strm,
21b10c
+                         z_const struct dfltcc_param_v0 FAR *param));
21b10c
+local void send_eobs(strm, param)
21b10c
+    z_streamp strm;
21b10c
+    z_const struct dfltcc_param_v0 FAR *param;
21b10c
+{
21b10c
+    deflate_state FAR *state = (deflate_state FAR *)strm->state;
21b10c
+
21b10c
+    _tr_send_bits(
21b10c
+          state,
21b10c
+          bi_reverse(param->eobs >> (15 - param->eobl), param->eobl),
21b10c
+          param->eobl);
21b10c
+    flush_pending(strm);
21b10c
+    if (state->pending != 0) {
21b10c
+        /* The remaining data is located in pending_out[0:pending]. If someone
21b10c
+         * calls put_byte() - this might happen in deflate() - the byte will be
21b10c
+         * placed into pending_buf[pending], which is incorrect. Move the
21b10c
+         * remaining data to the beginning of pending_buf so that put_byte() is
21b10c
+         * usable again.
21b10c
+         */
21b10c
+        memmove(state->pending_buf, state->pending_out, state->pending);
21b10c
+        state->pending_out = state->pending_buf;
21b10c
+    }
21b10c
+#ifdef ZLIB_DEBUG
21b10c
+    state->compressed_len += param->eobl;
21b10c
+#endif
21b10c
+}
21b10c
+
21b10c
+int ZLIB_INTERNAL dfltcc_deflate(strm, flush, result)
21b10c
+    z_streamp strm;
21b10c
+    int flush;
21b10c
+    block_state *result;
21b10c
+{
21b10c
+    deflate_state FAR *state = (deflate_state FAR *)strm->state;
21b10c
+    struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state);
21b10c
+    struct dfltcc_param_v0 FAR *param = &dfltcc_state->param;
21b10c
+    uInt masked_avail_in;
21b10c
+    dfltcc_cc cc;
21b10c
+    int need_empty_block;
21b10c
+    int soft_bcc;
21b10c
+    int no_flush;
21b10c
+
21b10c
+    if (!dfltcc_can_deflate(strm))
21b10c
+        return 0;
21b10c
+
21b10c
+again:
21b10c
+    masked_avail_in = 0;
21b10c
+    soft_bcc = 0;
21b10c
+    no_flush = flush == Z_NO_FLUSH;
21b10c
+
21b10c
+    /* Trailing empty block. Switch to software, except when Continuation Flag
21b10c
+     * is set, which means that DFLTCC has buffered some output in the
21b10c
+     * parameter block and needs to be called again in order to flush it.
21b10c
+     */
21b10c
+    if (flush == Z_FINISH && strm->avail_in == 0 && !param->cf) {
21b10c
+        if (param->bcf) {
21b10c
+            /* A block is still open, and the hardware does not support closing
21b10c
+             * blocks without adding data. Thus, close it manually.
21b10c
+             */
21b10c
+            send_eobs(strm, param);
21b10c
+            param->bcf = 0;
21b10c
+        }
21b10c
+        return 0;
21b10c
+    }
21b10c
+
21b10c
+    if (strm->avail_in == 0 && !param->cf) {
21b10c
+        *result = need_more;
21b10c
+        return 1;
21b10c
+    }
21b10c
+
21b10c
+    /* There is an open non-BFINAL block, we are not going to close it just
21b10c
+     * yet, we have compressed more than DFLTCC_BLOCK_SIZE bytes and we see
21b10c
+     * more than DFLTCC_DHT_MIN_SAMPLE_SIZE bytes. Open a new block with a new
21b10c
+     * DHT in order to adapt to a possibly changed input data distribution.
21b10c
+     */
21b10c
+    if (param->bcf && no_flush &&
21b10c
+            strm->total_in > dfltcc_state->block_threshold &&
21b10c
+            strm->avail_in >= dfltcc_state->dht_threshold) {
21b10c
+        if (param->cf) {
21b10c
+            /* We need to flush the DFLTCC buffer before writing the
21b10c
+             * End-of-block Symbol. Mask the input data and proceed as usual.
21b10c
+             */
21b10c
+            masked_avail_in += strm->avail_in;
21b10c
+            strm->avail_in = 0;
21b10c
+            no_flush = 0;
21b10c
+        } else {
21b10c
+            /* DFLTCC buffer is empty, so we can manually write the
21b10c
+             * End-of-block Symbol right away.
21b10c
+             */
21b10c
+            send_eobs(strm, param);
21b10c
+            param->bcf = 0;
21b10c
+            dfltcc_state->block_threshold =
21b10c
+                strm->total_in + dfltcc_state->block_size;
21b10c
+            if (strm->avail_out == 0) {
21b10c
+                *result = need_more;
21b10c
+                return 1;
21b10c
+            }
21b10c
+        }
21b10c
+    }
21b10c
+
21b10c
+    /* The caller gave us too much data. Pass only one block worth of
21b10c
+     * uncompressed data to DFLTCC and mask the rest, so that on the next
21b10c
+     * iteration we start a new block.
21b10c
+     */
21b10c
+    if (no_flush && strm->avail_in > dfltcc_state->block_size) {
21b10c
+        masked_avail_in += (strm->avail_in - dfltcc_state->block_size);
21b10c
+        strm->avail_in = dfltcc_state->block_size;
21b10c
+    }
21b10c
+
21b10c
+    /* When we have an open non-BFINAL deflate block and caller indicates that
21b10c
+     * the stream is ending, we need to close an open deflate block and open a
21b10c
+     * BFINAL one.
21b10c
+     */
21b10c
+    need_empty_block = flush == Z_FINISH && param->bcf && !param->bhf;
21b10c
+
21b10c
+    /* Translate stream to parameter block */
21b10c
+    param->cvt = state->wrap == 2 ? CVT_CRC32 : CVT_ADLER32;
21b10c
+    if (!no_flush)
21b10c
+        /* We need to close a block. Always do this in software - when there is
21b10c
+         * no input data, the hardware will not nohor BCC. */
21b10c
+        soft_bcc = 1;
21b10c
+    if (flush == Z_FINISH && !param->bcf)
21b10c
+        /* We are about to open a BFINAL block, set Block Header Final bit
21b10c
+         * until the stream ends.
21b10c
+         */
21b10c
+        param->bhf = 1;
21b10c
+    /* DFLTCC-CMPR will write to next_out, so make sure that buffers with
21b10c
+     * higher precedence are empty.
21b10c
+     */
21b10c
+    Assert(state->pending == 0, "There must be no pending bytes");
21b10c
+    Assert(state->bi_valid < 8, "There must be less than 8 pending bits");
21b10c
+    param->sbb = (unsigned int)state->bi_valid;
21b10c
+    if (param->sbb > 0)
21b10c
+        *strm->next_out = (Bytef)state->bi_buf;
21b10c
+    if (param->hl)
21b10c
+        param->nt = 0; /* Honor history */
21b10c
+    param->cv = state->wrap == 2 ? ZSWAP32(strm->adler) : strm->adler;
21b10c
+
21b10c
+    /* When opening a block, choose a Huffman-Table Type */
21b10c
+    if (!param->bcf) {
21b10c
+        if (state->strategy == Z_FIXED ||
21b10c
+                (strm->total_in == 0 && dfltcc_state->block_threshold > 0))
21b10c
+            param->htt = HTT_FIXED;
21b10c
+        else {
21b10c
+            param->htt = HTT_DYNAMIC;
21b10c
+            dfltcc_gdht(strm);
21b10c
+        }
21b10c
+    }
21b10c
+
21b10c
+    /* Deflate */
21b10c
+    do {
21b10c
+        cc = dfltcc_cmpr(strm);
21b10c
+        if (strm->avail_in < 4096 && masked_avail_in > 0)
21b10c
+            /* We are about to call DFLTCC with a small input buffer, which is
21b10c
+             * inefficient. Since there is masked data, there will be at least
21b10c
+             * one more DFLTCC call, so skip the current one and make the next
21b10c
+             * one handle more data.
21b10c
+             */
21b10c
+            break;
21b10c
+    } while (cc == DFLTCC_CC_AGAIN);
21b10c
+
21b10c
+    /* Translate parameter block to stream */
21b10c
+    strm->msg = oesc_msg(dfltcc_state->msg, param->oesc);
21b10c
+    state->bi_valid = param->sbb;
21b10c
+    if (state->bi_valid == 0)
21b10c
+        state->bi_buf = 0; /* Avoid accessing next_out */
21b10c
+    else
21b10c
+        state->bi_buf = *strm->next_out & ((1 << state->bi_valid) - 1);
21b10c
+    strm->adler = state->wrap == 2 ? ZSWAP32(param->cv) : param->cv;
21b10c
+
21b10c
+    /* Unmask the input data */
21b10c
+    strm->avail_in += masked_avail_in;
21b10c
+    masked_avail_in = 0;
21b10c
+
21b10c
+    /* If we encounter an error, it means there is a bug in DFLTCC call */
21b10c
+    Assert(cc != DFLTCC_CC_OP2_CORRUPT || param->oesc == 0, "BUG");
21b10c
+
21b10c
+    /* Update Block-Continuation Flag. It will be used to check whether to call
21b10c
+     * GDHT the next time.
21b10c
+     */
21b10c
+    if (cc == DFLTCC_CC_OK) {
21b10c
+        if (soft_bcc) {
21b10c
+            send_eobs(strm, param);
21b10c
+            param->bcf = 0;
21b10c
+            dfltcc_state->block_threshold =
21b10c
+                strm->total_in + dfltcc_state->block_size;
21b10c
+        } else
21b10c
+            param->bcf = 1;
21b10c
+        if (flush == Z_FINISH) {
21b10c
+            if (need_empty_block)
21b10c
+                /* Make the current deflate() call also close the stream */
21b10c
+                return 0;
21b10c
+            else {
21b10c
+                bi_windup(state);
21b10c
+                *result = finish_done;
21b10c
+            }
21b10c
+        } else {
21b10c
+            if (flush == Z_FULL_FLUSH)
21b10c
+                param->hl = 0; /* Clear history */
21b10c
+            *result = flush == Z_NO_FLUSH ? need_more : block_done;
21b10c
+        }
21b10c
+    } else {
21b10c
+        param->bcf = 1;
21b10c
+        *result = need_more;
21b10c
+    }
21b10c
+    if (strm->avail_in != 0 && strm->avail_out != 0)
21b10c
+        goto again; /* deflate() must use all input or all output */
21b10c
+    return 1;
21b10c
+}
21b10c
+
21b10c
+/*
21b10c
+   Expand.
21b10c
+ */
21b10c
+int ZLIB_INTERNAL dfltcc_can_inflate(strm)
21b10c
+    z_streamp strm;
21b10c
+{
21b10c
+    struct inflate_state FAR *state = (struct inflate_state FAR *)strm->state;
21b10c
+    struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state);
21b10c
+
21b10c
+    /* Unsupported compression settings */
21b10c
+    if (state->wbits != HB_BITS)
21b10c
+        return 0;
21b10c
+
21b10c
+    /* Unsupported hardware */
21b10c
+    return is_bit_set(dfltcc_state->af.fns, DFLTCC_XPND) &&
21b10c
+               is_bit_set(dfltcc_state->af.fmts, DFLTCC_FMT0);
21b10c
+}
21b10c
+
21b10c
+local dfltcc_cc dfltcc_xpnd OF((z_streamp strm));
21b10c
+local dfltcc_cc dfltcc_xpnd(strm)
21b10c
+    z_streamp strm;
21b10c
+{
21b10c
+    struct inflate_state FAR *state = (struct inflate_state FAR *)strm->state;
21b10c
+    struct dfltcc_param_v0 FAR *param = &GET_DFLTCC_STATE(state)->param;
21b10c
+    size_t avail_in = strm->avail_in;
21b10c
+    size_t avail_out = strm->avail_out;
21b10c
+    dfltcc_cc cc;
21b10c
+
21b10c
+    cc = dfltcc(DFLTCC_XPND | HBT_CIRCULAR,
21b10c
+                param, &strm->next_out, &avail_out,
21b10c
+                &strm->next_in, &avail_in, state->window);
21b10c
+    strm->avail_in = avail_in;
21b10c
+    strm->avail_out = avail_out;
21b10c
+    return cc;
21b10c
+}
21b10c
+
21b10c
+dfltcc_inflate_action ZLIB_INTERNAL dfltcc_inflate(strm, flush, ret)
21b10c
+    z_streamp strm;
21b10c
+    int flush;
21b10c
+    int *ret;
21b10c
+{
21b10c
+    struct inflate_state FAR *state = (struct inflate_state FAR *)strm->state;
21b10c
+    struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state);
21b10c
+    struct dfltcc_param_v0 FAR *param = &dfltcc_state->param;
21b10c
+    dfltcc_cc cc;
21b10c
+
21b10c
+    if (flush == Z_BLOCK || flush == Z_TREES) {
21b10c
+        /* DFLTCC does not support stopping on block boundaries */
21b10c
+        if (dfltcc_inflate_disable(strm)) {
21b10c
+            *ret = Z_STREAM_ERROR;
21b10c
+            return DFLTCC_INFLATE_BREAK;
21b10c
+        } else
21b10c
+            return DFLTCC_INFLATE_SOFTWARE;
21b10c
+    }
21b10c
+
21b10c
+    if (state->last) {
21b10c
+        if (state->bits != 0) {
21b10c
+            strm->next_in++;
21b10c
+            strm->avail_in--;
21b10c
+            state->bits = 0;
21b10c
+        }
21b10c
+        state->mode = CHECK;
21b10c
+        return DFLTCC_INFLATE_CONTINUE;
21b10c
+    }
21b10c
+
21b10c
+    if (strm->avail_in == 0 && !param->cf)
21b10c
+        return DFLTCC_INFLATE_BREAK;
21b10c
+
21b10c
+    if (inflate_ensure_window(state)) {
21b10c
+        state->mode = MEM;
21b10c
+        return DFLTCC_INFLATE_CONTINUE;
21b10c
+    }
21b10c
+
21b10c
+    /* Translate stream to parameter block */
21b10c
+    param->cvt = state->flags ? CVT_CRC32 : CVT_ADLER32;
21b10c
+    param->sbb = state->bits;
21b10c
+    param->hl = state->whave; /* Software and hardware history formats match */
21b10c
+    param->ho = (state->wnext - state->whave) & ((1 << HB_BITS) - 1);
21b10c
+    if (param->hl)
21b10c
+        param->nt = 0; /* Honor history for the first block */
21b10c
+    param->cv = state->flags ? ZSWAP32(state->check) : state->check;
21b10c
+
21b10c
+    /* Inflate */
21b10c
+    do {
21b10c
+        cc = dfltcc_xpnd(strm);
21b10c
+    } while (cc == DFLTCC_CC_AGAIN);
21b10c
+
21b10c
+    /* Translate parameter block to stream */
21b10c
+    strm->msg = oesc_msg(dfltcc_state->msg, param->oesc);
21b10c
+    state->last = cc == DFLTCC_CC_OK;
21b10c
+    state->bits = param->sbb;
21b10c
+    state->whave = param->hl;
21b10c
+    state->wnext = (param->ho + param->hl) & ((1 << HB_BITS) - 1);
21b10c
+    state->check = state->flags ? ZSWAP32(param->cv) : param->cv;
21b10c
+    if (cc == DFLTCC_CC_OP2_CORRUPT && param->oesc != 0) {
21b10c
+        /* Report an error if stream is corrupted */
21b10c
+        state->mode = BAD;
21b10c
+        return DFLTCC_INFLATE_CONTINUE;
21b10c
+    }
21b10c
+    state->mode = TYPEDO;
21b10c
+    /* Break if operands are exhausted, otherwise continue looping */
21b10c
+    return (cc == DFLTCC_CC_OP1_TOO_SHORT || cc == DFLTCC_CC_OP2_TOO_SHORT) ?
21b10c
+        DFLTCC_INFLATE_BREAK : DFLTCC_INFLATE_CONTINUE;
21b10c
+}
21b10c
+
21b10c
+int ZLIB_INTERNAL dfltcc_was_inflate_used(strm)
21b10c
+    z_streamp strm;
21b10c
+{
21b10c
+    struct inflate_state FAR *state = (struct inflate_state FAR *)strm->state;
21b10c
+    struct dfltcc_param_v0 FAR *param = &GET_DFLTCC_STATE(state)->param;
21b10c
+
21b10c
+    return !param->nt;
21b10c
+}
21b10c
+
21b10c
+int ZLIB_INTERNAL dfltcc_inflate_disable(strm)
21b10c
+    z_streamp strm;
21b10c
+{
21b10c
+    struct inflate_state FAR *state = (struct inflate_state FAR *)strm->state;
21b10c
+    struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state);
21b10c
+
21b10c
+    if (!dfltcc_can_inflate(strm))
21b10c
+        return 0;
21b10c
+    if (dfltcc_was_inflate_used(strm))
21b10c
+        /* DFLTCC has already decompressed some data. Since there is not
21b10c
+         * enough information to resume decompression in software, the call
21b10c
+         * must fail.
21b10c
+         */
21b10c
+        return 1;
21b10c
+    /* DFLTCC was not used yet - decompress in software */
21b10c
+    memset(&dfltcc_state->af, 0, sizeof(dfltcc_state->af));
21b10c
+    return 0;
21b10c
+}
21b10c
+
21b10c
+/*
21b10c
+   Memory management.
21b10c
+   DFLTCC requires parameter blocks and window to be aligned. zlib allows
21b10c
+   users to specify their own allocation functions, so using e.g.
21b10c
+   `posix_memalign' is not an option. Thus, we overallocate and take the
21b10c
+   aligned portion of the buffer.
21b10c
+*/
21b10c
+local inline int is_dfltcc_enabled OF((void));
21b10c
+local inline int is_dfltcc_enabled(void)
21b10c
+{
21b10c
+    const char *env;
21b10c
+    uint64_t facilities[(DFLTCC_FACILITY / 64) + 1];
21b10c
+    register char r0 __asm__("r0");
21b10c
+
21b10c
+    env = secure_getenv("DFLTCC");
21b10c
+    if (env && !strcmp(env, "0"))
21b10c
+      /* User has explicitly disabled DFLTCC. */
21b10c
+      return 0;
21b10c
+
21b10c
+    memset(facilities, 0, sizeof(facilities));
21b10c
+    r0 = sizeof(facilities) / sizeof(facilities[0]) - 1;
21b10c
+    /* STFLE is supported since z9-109 and only in z/Architecture mode. When
21b10c
+     * compiling with -m31, gcc defaults to ESA mode, however, since the kernel
21b10c
+     * is 64-bit, it's always z/Architecture mode at runtime.
21b10c
+     */
21b10c
+    __asm__ volatile(".machinemode push\n"
21b10c
+                     ".machinemode zarch\n"
21b10c
+                     "stfle %[facilities]\n"
21b10c
+                     ".machinemode pop\n"
21b10c
+                     : [facilities] "=Q" (facilities)
21b10c
+                     , [r0] "+r" (r0)
21b10c
+                     :
21b10c
+                     : "cc");
21b10c
+    return is_bit_set((const char *)facilities, DFLTCC_FACILITY);
21b10c
+}
21b10c
+
21b10c
+void ZLIB_INTERNAL dfltcc_reset(strm, size)
21b10c
+    z_streamp strm;
21b10c
+    uInt size;
21b10c
+{
21b10c
+    struct dfltcc_state *dfltcc_state =
21b10c
+        (struct dfltcc_state *)((char FAR *)strm->state + ALIGN_UP(size, 8));
21b10c
+    struct dfltcc_qaf_param *param =
21b10c
+        (struct dfltcc_qaf_param *)&dfltcc_state->param;
21b10c
+    const char *s;
21b10c
+
21b10c
+    /* Initialize available functions */
21b10c
+    if (is_dfltcc_enabled()) {
21b10c
+        dfltcc(DFLTCC_QAF, param, NULL, NULL, NULL, NULL, NULL);
21b10c
+        memmove(&dfltcc_state->af, param, sizeof(dfltcc_state->af));
21b10c
+    } else
21b10c
+        memset(&dfltcc_state->af, 0, sizeof(dfltcc_state->af));
21b10c
+
21b10c
+    if (secure_getenv("SOURCE_DATE_EPOCH"))
21b10c
+        /* User needs reproducible results, but the output of DFLTCC_CMPR
21b10c
+         * depends on buffers' page offsets.
21b10c
+         */
21b10c
+        clear_bit(dfltcc_state->af.fns, DFLTCC_CMPR);
21b10c
+
21b10c
+    /* Initialize parameter block */
21b10c
+    memset(&dfltcc_state->param, 0, sizeof(dfltcc_state->param));
21b10c
+    dfltcc_state->param.nt = 1;
21b10c
+
21b10c
+    /* Initialize tuning parameters */
21b10c
+#ifndef DFLTCC_LEVEL_MASK
21b10c
+#define DFLTCC_LEVEL_MASK 0x2
21b10c
+#endif
21b10c
+    s = secure_getenv("DFLTCC_LEVEL_MASK");
21b10c
+    dfltcc_state->level_mask = (s && *s) ? strtoul(s, NULL, 0) :
21b10c
+                                           DFLTCC_LEVEL_MASK;
21b10c
+#ifndef DFLTCC_BLOCK_SIZE
21b10c
+#define DFLTCC_BLOCK_SIZE 1048576
21b10c
+#endif
21b10c
+    s = secure_getenv("DFLTCC_BLOCK_SIZE");
21b10c
+    dfltcc_state->block_size = (s && *s) ? strtoul(s, NULL, 0) :
21b10c
+                                           DFLTCC_BLOCK_SIZE;
21b10c
+#ifndef DFLTCC_FIRST_FHT_BLOCK_SIZE
21b10c
+#define DFLTCC_FIRST_FHT_BLOCK_SIZE 4096
21b10c
+#endif
21b10c
+    s = secure_getenv("DFLTCC_FIRST_FHT_BLOCK_SIZE");
21b10c
+    dfltcc_state->block_threshold = (s && *s) ? strtoul(s, NULL, 0) :
21b10c
+                                                DFLTCC_FIRST_FHT_BLOCK_SIZE;
21b10c
+#ifndef DFLTCC_DHT_MIN_SAMPLE_SIZE
21b10c
+#define DFLTCC_DHT_MIN_SAMPLE_SIZE 4096
21b10c
+#endif
21b10c
+    s = secure_getenv("DFLTCC_DHT_MIN_SAMPLE_SIZE");
21b10c
+    dfltcc_state->dht_threshold = (s && *s) ? strtoul(s, NULL, 0) :
21b10c
+                                              DFLTCC_DHT_MIN_SAMPLE_SIZE;
21b10c
+#ifndef DFLTCC_RIBM
21b10c
+#define DFLTCC_RIBM 0
21b10c
+#endif
21b10c
+    s = secure_getenv("DFLTCC_RIBM");
21b10c
+    dfltcc_state->param.ribm = (s && *s) ? strtoul(s, NULL, 0) :
21b10c
+                                           DFLTCC_RIBM;
21b10c
+}
21b10c
+
21b10c
+voidpf ZLIB_INTERNAL dfltcc_alloc_state(strm, items, size)
21b10c
+    z_streamp strm;
21b10c
+    uInt items;
21b10c
+    uInt size;
21b10c
+{
21b10c
+    return ZALLOC(strm,
21b10c
+                  ALIGN_UP(items * size, 8) + sizeof(struct dfltcc_state),
21b10c
+                  sizeof(unsigned char));
21b10c
+}
21b10c
+
21b10c
+void ZLIB_INTERNAL dfltcc_copy_state(dst, src, size)
21b10c
+    voidpf dst;
21b10c
+    const voidpf src;
21b10c
+    uInt size;
21b10c
+{
21b10c
+    zmemcpy(dst, src, ALIGN_UP(size, 8) + sizeof(struct dfltcc_state));
21b10c
+}
21b10c
+
21b10c
+static const int PAGE_ALIGN = 0x1000;
21b10c
+
21b10c
+voidpf ZLIB_INTERNAL dfltcc_alloc_window(strm, items, size)
21b10c
+    z_streamp strm;
21b10c
+    uInt items;
21b10c
+    uInt size;
21b10c
+{
21b10c
+    voidpf p, w;
21b10c
+
21b10c
+    /* To simplify freeing, we store the pointer to the allocated buffer right
21b10c
+     * before the window.
21b10c
+     */
21b10c
+    p = ZALLOC(strm, sizeof(voidpf) + items * size + PAGE_ALIGN,
21b10c
+               sizeof(unsigned char));
21b10c
+    if (p == NULL)
21b10c
+        return NULL;
21b10c
+    w = ALIGN_UP((char FAR *)p + sizeof(voidpf), PAGE_ALIGN);
21b10c
+    *(voidpf *)((char FAR *)w - sizeof(voidpf)) = p;
21b10c
+    return w;
21b10c
+}
21b10c
+
21b10c
+void ZLIB_INTERNAL dfltcc_free_window(strm, w)
21b10c
+    z_streamp strm;
21b10c
+    voidpf w;
21b10c
+{
21b10c
+    if (w)
21b10c
+        ZFREE(strm, *(voidpf *)((unsigned char FAR *)w - sizeof(voidpf)));
21b10c
+}
21b10c
+
21b10c
+/*
21b10c
+   Switching between hardware and software compression.
21b10c
+   DFLTCC does not support all zlib settings, e.g. generation of non-compressed
21b10c
+   blocks or alternative window sizes. When such settings are applied on the
21b10c
+   fly with deflateParams, we need to convert between hardware and software
21b10c
+   window formats.
21b10c
+*/
21b10c
+int ZLIB_INTERNAL dfltcc_deflate_params(strm, level, strategy)
21b10c
+    z_streamp strm;
21b10c
+    int level;
21b10c
+    int strategy;
21b10c
+{
21b10c
+    deflate_state FAR *state = (deflate_state FAR *)strm->state;
21b10c
+    struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state);
21b10c
+    struct dfltcc_param_v0 FAR *param = &dfltcc_state->param;
21b10c
+    int could_deflate = dfltcc_can_deflate(strm);
21b10c
+    int can_deflate = dfltcc_are_params_ok(level, state->w_bits, strategy,
21b10c
+                                           dfltcc_state->level_mask);
21b10c
+
21b10c
+    if (can_deflate == could_deflate)
21b10c
+        /* We continue to work in the same mode - no changes needed */
21b10c
+        return Z_OK;
21b10c
+
21b10c
+    if (strm->total_in == 0 && param->nt == 1 && param->hl == 0)
21b10c
+        /* DFLTCC was not used yet - no changes needed */
21b10c
+        return Z_OK;
21b10c
+
21b10c
+    /* Switching between hardware and software is not implemented */
21b10c
+    return Z_STREAM_ERROR;
21b10c
+}
21b10c
+
21b10c
+/*
21b10c
+   Preloading history.
21b10c
+*/
21b10c
+local void append_history OF((struct dfltcc_param_v0 FAR *param,
21b10c
+                              Bytef *history,
21b10c
+                              const Bytef *buf,
21b10c
+                              uInt count));
21b10c
+local void append_history(param, history, buf, count)
21b10c
+    struct dfltcc_param_v0 FAR *param;
21b10c
+    Bytef *history;
21b10c
+    const Bytef *buf;
21b10c
+    uInt count;
21b10c
+{
21b10c
+    size_t offset;
21b10c
+    size_t n;
21b10c
+
21b10c
+    /* Do not use more than 32K */
21b10c
+    if (count > HB_SIZE) {
21b10c
+        buf += count - HB_SIZE;
21b10c
+        count = HB_SIZE;
21b10c
+    }
21b10c
+    offset = (param->ho + param->hl) % HB_SIZE;
21b10c
+    if (offset + count <= HB_SIZE)
21b10c
+        /* Circular history buffer does not wrap - copy one chunk */
21b10c
+        zmemcpy(history + offset, buf, count);
21b10c
+    else {
21b10c
+        /* Circular history buffer wraps - copy two chunks */
21b10c
+        n = HB_SIZE - offset;
21b10c
+        zmemcpy(history + offset, buf, n);
21b10c
+        zmemcpy(history, buf + n, count - n);
21b10c
+    }
21b10c
+    n = param->hl + count;
21b10c
+    if (n <= HB_SIZE)
21b10c
+        /* All history fits into buffer - no need to discard anything */
21b10c
+        param->hl = n;
21b10c
+    else {
21b10c
+        /* History does not fit into buffer - discard extra bytes */
21b10c
+        param->ho = (param->ho + (n - HB_SIZE)) % HB_SIZE;
21b10c
+        param->hl = HB_SIZE;
21b10c
+    }
21b10c
+}
21b10c
+
21b10c
+int ZLIB_INTERNAL dfltcc_deflate_set_dictionary(strm, dictionary, dict_length)
21b10c
+    z_streamp strm;
21b10c
+    const Bytef *dictionary;
21b10c
+    uInt dict_length;
21b10c
+{
21b10c
+    deflate_state FAR *state = (deflate_state FAR *)strm->state;
21b10c
+    struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state);
21b10c
+    struct dfltcc_param_v0 FAR *param = &dfltcc_state->param;
21b10c
+
21b10c
+    append_history(param, state->window, dictionary, dict_length);
21b10c
+    state->strstart = 1; /* Add FDICT to zlib header */
21b10c
+    return Z_OK;
21b10c
+}
21b10c
+
21b10c
+int ZLIB_INTERNAL dfltcc_deflate_get_dictionary(strm, dictionary, dict_length)
21b10c
+    z_streamp strm;
21b10c
+    Bytef *dictionary;
21b10c
+    uInt *dict_length;
21b10c
+{
21b10c
+    deflate_state FAR *state = (deflate_state FAR *)strm->state;
21b10c
+    struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state);
21b10c
+    struct dfltcc_param_v0 FAR *param = &dfltcc_state->param;
21b10c
+
21b10c
+    if (dictionary) {
21b10c
+        if (param->ho + param->hl <= HB_SIZE)
21b10c
+            /* Circular history buffer does not wrap - copy one chunk */
21b10c
+            zmemcpy(dictionary, state->window + param->ho, param->hl);
21b10c
+        else {
21b10c
+            /* Circular history buffer wraps - copy two chunks */
21b10c
+            zmemcpy(dictionary,
21b10c
+                    state->window + param->ho,
21b10c
+                    HB_SIZE - param->ho);
21b10c
+            zmemcpy(dictionary + HB_SIZE - param->ho,
21b10c
+                    state->window,
21b10c
+                    param->ho + param->hl - HB_SIZE);
21b10c
+        }
21b10c
+    }
21b10c
+    if (dict_length)
21b10c
+        *dict_length = param->hl;
21b10c
+    return Z_OK;
21b10c
+}
21b10c
\ No newline at end of file
21b10c
diff --git a/contrib/s390/dfltcc.h b/contrib/s390/dfltcc.h
21b10c
new file mode 100644
21b10c
index 0000000..574e84c
21b10c
--- /dev/null
21b10c
+++ b/contrib/s390/dfltcc.h
21b10c
@@ -0,0 +1,55 @@
21b10c
+#ifndef DFLTCC_H
21b10c
+#define DFLTCC_H
21b10c
+
21b10c
+#include "../../zlib.h"
21b10c
+#include "../../zutil.h"
21b10c
+
21b10c
+voidpf ZLIB_INTERNAL dfltcc_alloc_state OF((z_streamp strm, uInt items,
21b10c
+                                            uInt size));
21b10c
+void ZLIB_INTERNAL dfltcc_copy_state OF((voidpf dst, const voidpf src,
21b10c
+                                         uInt size));
21b10c
+void ZLIB_INTERNAL dfltcc_reset OF((z_streamp strm, uInt size));
21b10c
+voidpf ZLIB_INTERNAL dfltcc_alloc_window OF((z_streamp strm, uInt items,
21b10c
+                                             uInt size));
21b10c
+void ZLIB_INTERNAL dfltcc_free_window OF((z_streamp strm, voidpf w));
21b10c
+int ZLIB_INTERNAL dfltcc_can_inflate OF((z_streamp strm));
21b10c
+typedef enum {
21b10c
+    DFLTCC_INFLATE_CONTINUE,
21b10c
+    DFLTCC_INFLATE_BREAK,
21b10c
+    DFLTCC_INFLATE_SOFTWARE,
21b10c
+} dfltcc_inflate_action;
21b10c
+dfltcc_inflate_action ZLIB_INTERNAL dfltcc_inflate OF((z_streamp strm,
21b10c
+                                                       int flush, int *ret));
21b10c
+int ZLIB_INTERNAL dfltcc_was_inflate_used OF((z_streamp strm));
21b10c
+int ZLIB_INTERNAL dfltcc_inflate_disable OF((z_streamp strm));
21b10c
+
21b10c
+#define ZALLOC_STATE dfltcc_alloc_state
21b10c
+#define ZFREE_STATE ZFREE
21b10c
+#define ZCOPY_STATE dfltcc_copy_state
21b10c
+#define ZALLOC_WINDOW dfltcc_alloc_window
21b10c
+#define ZFREE_WINDOW dfltcc_free_window
21b10c
+#define TRY_FREE_WINDOW dfltcc_free_window
21b10c
+#define INFLATE_RESET_KEEP_HOOK(strm) \
21b10c
+    dfltcc_reset((strm), sizeof(struct inflate_state))
21b10c
+#define INFLATE_PRIME_HOOK(strm, bits, value) \
21b10c
+    do { if (dfltcc_inflate_disable((strm))) return Z_STREAM_ERROR; } while (0)
21b10c
+#define INFLATE_TYPEDO_HOOK(strm, flush) \
21b10c
+    if (dfltcc_can_inflate((strm))) { \
21b10c
+        dfltcc_inflate_action action; \
21b10c
+\
21b10c
+        RESTORE(); \
21b10c
+        action = dfltcc_inflate((strm), (flush), &ret;; \
21b10c
+        LOAD(); \
21b10c
+        if (action == DFLTCC_INFLATE_CONTINUE) \
21b10c
+            break; \
21b10c
+        else if (action == DFLTCC_INFLATE_BREAK) \
21b10c
+            goto inf_leave; \
21b10c
+    }
21b10c
+#define INFLATE_NEED_CHECKSUM(strm) (!dfltcc_can_inflate((strm)))
21b10c
+#define INFLATE_NEED_UPDATEWINDOW(strm) (!dfltcc_can_inflate((strm)))
21b10c
+#define INFLATE_MARK_HOOK(strm) \
21b10c
+    do { \
21b10c
+        if (dfltcc_was_inflate_used((strm))) return -(1L << 16); \
21b10c
+    } while (0)
21b10c
+
21b10c
+#endif
21b10c
\ No newline at end of file
21b10c
diff --git a/contrib/s390/dfltcc_deflate.h b/contrib/s390/dfltcc_deflate.h
21b10c
new file mode 100644
21b10c
index 0000000..a129a91
21b10c
--- /dev/null
21b10c
+++ b/contrib/s390/dfltcc_deflate.h
21b10c
@@ -0,0 +1,50 @@
21b10c
+#ifndef DFLTCC_DEFLATE_H
21b10c
+#define DFLTCC_DEFLATE_H
21b10c
+
21b10c
+#include "dfltcc.h"
21b10c
+
21b10c
+int ZLIB_INTERNAL dfltcc_can_deflate OF((z_streamp strm));
21b10c
+int ZLIB_INTERNAL dfltcc_deflate OF((z_streamp strm,
21b10c
+                                     int flush,
21b10c
+                                     block_state *result));
21b10c
+int ZLIB_INTERNAL dfltcc_deflate_params OF((z_streamp strm,
21b10c
+                                            int level,
21b10c
+                                            int strategy));
21b10c
+int ZLIB_INTERNAL dfltcc_deflate_set_dictionary OF((z_streamp strm,
21b10c
+                                                    const Bytef *dictionary,
21b10c
+                                                    uInt dict_length));
21b10c
+int ZLIB_INTERNAL dfltcc_deflate_get_dictionary OF((z_streamp strm,
21b10c
+                                                    Bytef *dictionary,
21b10c
+                                                    uInt* dict_length));
21b10c
+
21b10c
+#define DEFLATE_SET_DICTIONARY_HOOK(strm, dict, dict_len) \
21b10c
+    do { \
21b10c
+        if (dfltcc_can_deflate((strm))) \
21b10c
+            return dfltcc_deflate_set_dictionary((strm), (dict), (dict_len)); \
21b10c
+    } while (0)
21b10c
+#define DEFLATE_GET_DICTIONARY_HOOK(strm, dict, dict_len) \
21b10c
+    do { \
21b10c
+        if (dfltcc_can_deflate((strm))) \
21b10c
+            return dfltcc_deflate_get_dictionary((strm), (dict), (dict_len)); \
21b10c
+    } while (0)
21b10c
+#define DEFLATE_RESET_KEEP_HOOK(strm) \
21b10c
+    dfltcc_reset((strm), sizeof(deflate_state))
21b10c
+#define DEFLATE_PARAMS_HOOK(strm, level, strategy) \
21b10c
+    do { \
21b10c
+        int err; \
21b10c
+\
21b10c
+        err = dfltcc_deflate_params((strm), (level), (strategy)); \
21b10c
+        if (err == Z_STREAM_ERROR) \
21b10c
+            return err; \
21b10c
+    } while (0)
21b10c
+#define DEFLATE_BOUND_ADJUST_COMPLEN(strm, complen, source_len) \
21b10c
+    do { \
21b10c
+        if (dfltcc_can_deflate((strm))) \
21b10c
+            (complen) = (3 + 5 + 5 + 4 + 19 * 3 + (286 + 30) * 7 + \
21b10c
+                         (source_len) * 16 + 15 + 7) >> 3; \
21b10c
+    } while (0)
21b10c
+#define DEFLATE_NEED_CONSERVATIVE_BOUND(strm) (dfltcc_can_deflate((strm)))
21b10c
+#define DEFLATE_HOOK dfltcc_deflate
21b10c
+#define DEFLATE_NEED_CHECKSUM(strm) (!dfltcc_can_deflate((strm)))
21b10c
+
21b10c
+#endif
21b10c
\ No newline at end of file
21b10c
diff --git a/deflate.c b/deflate.c
21b10c
index 1ec7614..089285a 100644
21b10c
--- a/deflate.c
21b10c
+++ b/deflate.c
21b10c
@@ -61,15 +61,29 @@ const char deflate_copyright[] =
21b10c
  */
21b10c
 
21b10c
 /* ===========================================================================
21b10c
- *  Function prototypes.
21b10c
+ *  Architecture-specific bits.
21b10c
  */
21b10c
-typedef enum {
21b10c
-    need_more,      /* block not completed, need more input or more output */
21b10c
-    block_done,     /* block flush performed */
21b10c
-    finish_started, /* finish started, need only more output at next deflate */
21b10c
-    finish_done     /* finish done, accept no more input or output */
21b10c
-} block_state;
21b10c
+#ifdef DFLTCC
21b10c
+#  include "contrib/s390/dfltcc_deflate.h"
21b10c
+#else
21b10c
+#define ZALLOC_STATE ZALLOC
21b10c
+#define ZFREE_STATE ZFREE
21b10c
+#define ZCOPY_STATE zmemcpy
21b10c
+#define ZALLOC_WINDOW ZALLOC
21b10c
+#define TRY_FREE_WINDOW TRY_FREE
21b10c
+#define DEFLATE_SET_DICTIONARY_HOOK(strm, dict, dict_len) do {} while (0)
21b10c
+#define DEFLATE_GET_DICTIONARY_HOOK(strm, dict, dict_len) do {} while (0)
21b10c
+#define DEFLATE_RESET_KEEP_HOOK(strm) do {} while (0)
21b10c
+#define DEFLATE_PARAMS_HOOK(strm, level, strategy) do {} while (0)
21b10c
+#define DEFLATE_BOUND_ADJUST_COMPLEN(strm, complen, sourceLen) do {} while (0)
21b10c
+#define DEFLATE_NEED_CONSERVATIVE_BOUND(strm) 0
21b10c
+#define DEFLATE_HOOK(strm, flush, bstate) 0
21b10c
+#define DEFLATE_NEED_CHECKSUM(strm) 1
21b10c
+#endif
21b10c
 
21b10c
+/* ===========================================================================
21b10c
+ *  Function prototypes.
21b10c
+ */
21b10c
 typedef block_state (*compress_func) OF((deflate_state *s, int flush));
21b10c
 /* Compression function. Returns the block state after the call. */
21b10c
 
21b10c
@@ -85,7 +99,6 @@ local block_state deflate_rle    OF((deflate_state *s, int flush));
21b10c
 local block_state deflate_huff   OF((deflate_state *s, int flush));
21b10c
 local void lm_init        OF((deflate_state *s));
21b10c
 local void putShortMSB    OF((deflate_state *s, uInt b));
21b10c
-local void flush_pending  OF((z_streamp strm));
21b10c
 local unsigned read_buf   OF((z_streamp strm, Bytef *buf, unsigned size));
21b10c
 #ifdef ASMV
21b10c
 #  pragma message("Assembler code may have bugs -- use at your own risk")
21b10c
@@ -301,7 +314,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
21b10c
         return Z_STREAM_ERROR;
21b10c
     }
21b10c
     if (windowBits == 8) windowBits = 9;  /* until 256-byte window bug fixed */
21b10c
-    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
21b10c
+    s = (deflate_state *) ZALLOC_STATE(strm, 1, sizeof(deflate_state));
21b10c
     if (s == Z_NULL) return Z_MEM_ERROR;
21b10c
     strm->state = (struct internal_state FAR *)s;
21b10c
     s->strm = strm;
21b10c
@@ -318,7 +331,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
21b10c
     s->hash_mask = s->hash_size - 1;
21b10c
     s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
21b10c
 
21b10c
-    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
21b10c
+    s->window = (Bytef *) ZALLOC_WINDOW(strm, s->w_size, 2*sizeof(Byte));
21b10c
     s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
21b10c
     s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
21b10c
 
21b10c
@@ -394,6 +407,7 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
21b10c
     /* when using zlib wrappers, compute Adler-32 for provided dictionary */
21b10c
     if (wrap == 1)
21b10c
         strm->adler = adler32(strm->adler, dictionary, dictLength);
21b10c
+    DEFLATE_SET_DICTIONARY_HOOK(strm, dictionary, dictLength);
21b10c
     s->wrap = 0;                    /* avoid computing Adler-32 in read_buf */
21b10c
 
21b10c
     /* if dictionary would fill window, just replace the history */
21b10c
@@ -452,6 +466,7 @@ int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength)
21b10c
 
21b10c
     if (deflateStateCheck(strm))
21b10c
         return Z_STREAM_ERROR;
21b10c
+    DEFLATE_GET_DICTIONARY_HOOK(strm, dictionary, dictLength);
21b10c
     s = strm->state;
21b10c
     len = s->strstart + s->lookahead;
21b10c
     if (len > s->w_size)
21b10c
@@ -498,6 +513,8 @@ int ZEXPORT deflateResetKeep (strm)
21b10c
 
21b10c
     _tr_init(s);
21b10c
 
21b10c
+    DEFLATE_RESET_KEEP_HOOK(strm);
21b10c
+
21b10c
     return Z_OK;
21b10c
 }
21b10c
 
21b10c
@@ -584,6 +601,7 @@ int ZEXPORT deflateParams(strm, level, strategy)
21b10c
     if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
21b10c
         return Z_STREAM_ERROR;
21b10c
     }
21b10c
+    DEFLATE_PARAMS_HOOK(strm, level, strategy);
21b10c
     func = configuration_table[s->level].func;
21b10c
 
21b10c
     if ((strategy != s->strategy || func != configuration_table[level].func) &&
21b10c
@@ -659,6 +677,7 @@ uLong ZEXPORT deflateBound(strm, sourceLen)
21b10c
     /* conservative upper bound for compressed data */
21b10c
     complen = sourceLen +
21b10c
               ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5;
21b10c
+    DEFLATE_BOUND_ADJUST_COMPLEN(strm, complen, sourceLen);
21b10c
 
21b10c
     /* if can't get parameters, return conservative bound plus zlib wrapper */
21b10c
     if (deflateStateCheck(strm))
21b10c
@@ -700,7 +719,8 @@ uLong ZEXPORT deflateBound(strm, sourceLen)
21b10c
     }
21b10c
 
21b10c
     /* if not default parameters, return conservative bound */
21b10c
-    if (s->w_bits != 15 || s->hash_bits != 8 + 7)
21b10c
+    if (DEFLATE_NEED_CONSERVATIVE_BOUND(strm) ||
21b10c
+            s->w_bits != 15 || s->hash_bits != 8 + 7)
21b10c
         return complen + wraplen;
21b10c
 
21b10c
     /* default settings: return tight bound for that case */
21b10c
@@ -727,7 +747,7 @@ local void putShortMSB (s, b)
21b10c
  * applications may wish to modify it to avoid allocating a large
21b10c
  * strm->next_out buffer and copying into it. (See also read_buf()).
21b10c
  */
21b10c
-local void flush_pending(strm)
21b10c
+void ZLIB_INTERNAL flush_pending(strm)
21b10c
     z_streamp strm;
21b10c
 {
21b10c
     unsigned len;
21b10c
@@ -997,7 +1017,8 @@ int ZEXPORT deflate (strm, flush)
21b10c
         (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
21b10c
         block_state bstate;
21b10c
 
21b10c
-        bstate = s->level == 0 ? deflate_stored(s, flush) :
21b10c
+        bstate = DEFLATE_HOOK(strm, flush, &bstate) ? bstate :
21b10c
+                 s->level == 0 ? deflate_stored(s, flush) :
21b10c
                  s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :
21b10c
                  s->strategy == Z_RLE ? deflate_rle(s, flush) :
21b10c
                  (*(configuration_table[s->level].func))(s, flush);
21b10c
@@ -1086,9 +1107,9 @@ int ZEXPORT deflateEnd (strm)
21b10c
     TRY_FREE(strm, strm->state->pending_buf);
21b10c
     TRY_FREE(strm, strm->state->head);
21b10c
     TRY_FREE(strm, strm->state->prev);
21b10c
-    TRY_FREE(strm, strm->state->window);
21b10c
+    TRY_FREE_WINDOW(strm, strm->state->window);
21b10c
 
21b10c
-    ZFREE(strm, strm->state);
21b10c
+    ZFREE_STATE(strm, strm->state);
21b10c
     strm->state = Z_NULL;
21b10c
 
21b10c
     return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
21b10c
@@ -1119,13 +1140,13 @@ int ZEXPORT deflateCopy (dest, source)
21b10c
 
21b10c
     zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));
21b10c
 
21b10c
-    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
21b10c
+    ds = (deflate_state *) ZALLOC_STATE(dest, 1, sizeof(deflate_state));
21b10c
     if (ds == Z_NULL) return Z_MEM_ERROR;
21b10c
     dest->state = (struct internal_state FAR *) ds;
21b10c
-    zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state));
21b10c
+    ZCOPY_STATE((voidpf)ds, (voidpf)ss, sizeof(deflate_state));
21b10c
     ds->strm = dest;
21b10c
 
21b10c
-    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
21b10c
+    ds->window = (Bytef *) ZALLOC_WINDOW(dest, ds->w_size, 2*sizeof(Byte));
21b10c
     ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
21b10c
     ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
21b10c
     overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
21b10c
@@ -1174,7 +1195,8 @@ local unsigned read_buf(strm, buf, size)
21b10c
     strm->avail_in  -= len;
21b10c
 
21b10c
     zmemcpy(buf, strm->next_in, len);
21b10c
-    if (strm->state->wrap == 1) {
21b10c
+        if (!DEFLATE_NEED_CHECKSUM(strm)) {}
21b10c
+    else if (strm->state->wrap == 1) {
21b10c
         strm->adler = adler32(strm->adler, buf, len);
21b10c
     }
21b10c
 #ifdef GZIP
21b10c
diff --git a/deflate.h b/deflate.h
21b10c
index 23ecdd3..821a4b9 100644
21b10c
--- a/deflate.h
21b10c
+++ b/deflate.h
21b10c
@@ -304,6 +304,7 @@ void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s));
21b10c
 void ZLIB_INTERNAL _tr_align OF((deflate_state *s));
21b10c
 void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
21b10c
                         ulg stored_len, int last));
21b10c
+void ZLIB_INTERNAL _tr_send_bits OF((deflate_state *s, int value, int length));
21b10c
 
21b10c
 #define d_code(dist) \
21b10c
    ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
21b10c
@@ -346,4 +347,15 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
21b10c
               flush = _tr_tally(s, distance, length)
21b10c
 #endif
21b10c
 
21b10c
+typedef enum {
21b10c
+    need_more,      /* block not completed, need more input or more output */
21b10c
+    block_done,     /* block flush performed */
21b10c
+    finish_started, /* finish started, need only more output at next deflate */
21b10c
+    finish_done     /* finish done, accept no more input or output */
21b10c
+} block_state;
21b10c
+
21b10c
+unsigned ZLIB_INTERNAL bi_reverse OF((unsigned code, int len));
21b10c
+void ZLIB_INTERNAL bi_windup OF((deflate_state *s));
21b10c
+void ZLIB_INTERNAL flush_pending OF((z_streamp strm));
21b10c
+
21b10c
 #endif /* DEFLATE_H */
21b10c
diff --git a/gzguts.h b/gzguts.h
21b10c
index 990a4d2..3218395 100644
21b10c
--- a/gzguts.h
21b10c
+++ b/gzguts.h
21b10c
@@ -153,7 +153,11 @@
21b10c
 
21b10c
 /* default i/o buffer size -- double this for output when reading (this and
21b10c
    twice this must be able to fit in an unsigned type) */
21b10c
+#ifdef DFLTCC
21b10c
+#define GZBUFSIZE 131072
21b10c
+#else
21b10c
 #define GZBUFSIZE 8192
21b10c
+#endif
21b10c
 
21b10c
 /* gzip modes, also provide a little integrity check on the passed structure */
21b10c
 #define GZ_NONE 0
21b10c
diff --git a/inflate.c b/inflate.c
21b10c
index ac333e8..f77c2ae 100644
21b10c
--- a/inflate.c
21b10c
+++ b/inflate.c
21b10c
@@ -85,6 +85,23 @@
21b10c
 #include "inflate.h"
21b10c
 #include "inffast.h"
21b10c
 
21b10c
+/* architecture-specific bits */
21b10c
+#ifdef DFLTCC
21b10c
+#  include "contrib/s390/dfltcc.h"
21b10c
+#else
21b10c
+#define ZALLOC_STATE ZALLOC
21b10c
+#define ZFREE_STATE ZFREE
21b10c
+#define ZCOPY_STATE zmemcpy
21b10c
+#define ZALLOC_WINDOW ZALLOC
21b10c
+#define ZFREE_WINDOW ZFREE
21b10c
+#define INFLATE_RESET_KEEP_HOOK(strm) do {} while (0)
21b10c
+#define INFLATE_PRIME_HOOK(strm, bits, value) do {} while (0)
21b10c
+#define INFLATE_TYPEDO_HOOK(strm, flush) do {} while (0)
21b10c
+#define INFLATE_NEED_CHECKSUM(strm) 1
21b10c
+#define INFLATE_NEED_UPDATEWINDOW(strm) 1
21b10c
+#define INFLATE_MARK_HOOK(strm) do {} while (0)
21b10c
+#endif
21b10c
+
21b10c
 #ifdef MAKEFIXED
21b10c
 #  ifndef BUILDFIXED
21b10c
 #    define BUILDFIXED
21b10c
@@ -137,6 +154,7 @@ z_streamp strm;
21b10c
     state->lencode = state->distcode = state->next = state->codes;
21b10c
     state->sane = 1;
21b10c
     state->back = -1;
21b10c
+    INFLATE_RESET_KEEP_HOOK(strm);
21b10c
     Tracev((stderr, "inflate: reset\n"));
21b10c
     return Z_OK;
21b10c
 }
21b10c
@@ -182,7 +200,7 @@ int windowBits;
21b10c
     if (windowBits && (windowBits < 8 || windowBits > 15))
21b10c
         return Z_STREAM_ERROR;
21b10c
     if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) {
21b10c
-        ZFREE(strm, state->window);
21b10c
+        ZFREE_WINDOW(strm, state->window);
21b10c
         state->window = Z_NULL;
21b10c
     }
21b10c
 
21b10c
@@ -221,7 +239,7 @@ int stream_size;
21b10c
         strm->zfree = zcfree;
21b10c
 #endif
21b10c
     state = (struct inflate_state FAR *)
21b10c
-            ZALLOC(strm, 1, sizeof(struct inflate_state));
21b10c
+            ZALLOC_STATE(strm, 1, sizeof(struct inflate_state));
21b10c
     if (state == Z_NULL) return Z_MEM_ERROR;
21b10c
     Tracev((stderr, "inflate: allocated\n"));
21b10c
     strm->state = (struct internal_state FAR *)state;
21b10c
@@ -230,7 +248,7 @@ int stream_size;
21b10c
     state->mode = HEAD;     /* to pass state test in inflateReset2() */
21b10c
     ret = inflateReset2(strm, windowBits);
21b10c
     if (ret != Z_OK) {
21b10c
-        ZFREE(strm, state);
21b10c
+        ZFREE_STATE(strm, state);
21b10c
         strm->state = Z_NULL;
21b10c
     }
21b10c
     return ret;
21b10c
@@ -252,6 +270,7 @@ int value;
21b10c
     struct inflate_state FAR *state;
21b10c
 
21b10c
     if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
21b10c
+    INFLATE_PRIME_HOOK(strm, bits, value);
21b10c
     state = (struct inflate_state FAR *)strm->state;
21b10c
     if (bits < 0) {
21b10c
         state->hold = 0;
21b10c
@@ -379,6 +398,27 @@ void makefixed()
21b10c
 }
21b10c
 #endif /* MAKEFIXED */
21b10c
 
21b10c
+int ZLIB_INTERNAL inflate_ensure_window(state)
21b10c
+    struct inflate_state *state;
21b10c
+{
21b10c
+    /* if it hasn't been done already, allocate space for the window */
21b10c
+    if (state->window == Z_NULL) {
21b10c
+        state->window = (unsigned char FAR *)
21b10c
+                        ZALLOC_WINDOW(state->strm, 1U << state->wbits,
21b10c
+                                      sizeof(unsigned char));
21b10c
+        if (state->window == Z_NULL) return 1;
21b10c
+    }
21b10c
+
21b10c
+    /* if window not in use yet, initialize */
21b10c
+    if (state->wsize == 0) {
21b10c
+        state->wsize = 1U << state->wbits;
21b10c
+        state->wnext = 0;
21b10c
+        state->whave = 0;
21b10c
+    }
21b10c
+
21b10c
+    return 0;
21b10c
+}
21b10c
+
21b10c
 /*
21b10c
    Update the window with the last wsize (normally 32K) bytes written before
21b10c
    returning.  If window does not exist yet, create it.  This is only called
21b10c
@@ -403,20 +443,7 @@ unsigned copy;
21b10c
 
21b10c
     state = (struct inflate_state FAR *)strm->state;
21b10c
 
21b10c
-    /* if it hasn't been done already, allocate space for the window */
21b10c
-    if (state->window == Z_NULL) {
21b10c
-        state->window = (unsigned char FAR *)
21b10c
-                        ZALLOC(strm, 1U << state->wbits,
21b10c
-                               sizeof(unsigned char));
21b10c
-        if (state->window == Z_NULL) return 1;
21b10c
-    }
21b10c
-
21b10c
-    /* if window not in use yet, initialize */
21b10c
-    if (state->wsize == 0) {
21b10c
-        state->wsize = 1U << state->wbits;
21b10c
-        state->wnext = 0;
21b10c
-        state->whave = 0;
21b10c
-    }
21b10c
+    if (inflate_ensure_window(state)) return 1;
21b10c
 
21b10c
     /* copy state->wsize or less output bytes into the circular window */
21b10c
     if (copy >= state->wsize) {
21b10c
@@ -849,6 +876,7 @@ int flush;
21b10c
         case TYPE:
21b10c
             if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
21b10c
         case TYPEDO:
21b10c
+            INFLATE_TYPEDO_HOOK(strm, flush);
21b10c
             if (state->last) {
21b10c
                 BYTEBITS();
21b10c
                 state->mode = CHECK;
21b10c
@@ -1200,7 +1228,7 @@ int flush;
21b10c
                 out -= left;
21b10c
                 strm->total_out += out;
21b10c
                 state->total += out;
21b10c
-                if ((state->wrap & 4) && out)
21b10c
+                if (INFLATE_NEED_CHECKSUM(strm) && (state->wrap & 4) && out)
21b10c
                     strm->adler = state->check =
21b10c
                         UPDATE(state->check, put - out, out);
21b10c
                 out = left;
21b10c
@@ -1252,8 +1280,9 @@ int flush;
21b10c
      */
21b10c
   inf_leave:
21b10c
     RESTORE();
21b10c
-    if (state->wsize || (out != strm->avail_out && state->mode < BAD &&
21b10c
-            (state->mode < CHECK || flush != Z_FINISH)))
21b10c
+    if (INFLATE_NEED_UPDATEWINDOW(strm) &&
21b10c
+        (state->wsize || (out != strm->avail_out && state->mode < BAD &&
21b10c
+                (state->mode < CHECK || flush != Z_FINISH))))
21b10c
         if (updatewindow(strm, strm->next_out, out - strm->avail_out)) {
21b10c
             state->mode = MEM;
21b10c
             return Z_MEM_ERROR;
21b10c
@@ -1263,7 +1292,7 @@ int flush;
21b10c
     strm->total_in += in;
21b10c
     strm->total_out += out;
21b10c
     state->total += out;
21b10c
-    if ((state->wrap & 4) && out)
21b10c
+    if (INFLATE_NEED_CHECKSUM(strm) && (state->wrap & 4) && out)
21b10c
         strm->adler = state->check =
21b10c
             UPDATE(state->check, strm->next_out - out, out);
21b10c
     strm->data_type = (int)state->bits + (state->last ? 64 : 0) +
21b10c
@@ -1281,8 +1310,8 @@ z_streamp strm;
21b10c
     if (inflateStateCheck(strm))
21b10c
         return Z_STREAM_ERROR;
21b10c
     state = (struct inflate_state FAR *)strm->state;
21b10c
-    if (state->window != Z_NULL) ZFREE(strm, state->window);
21b10c
-    ZFREE(strm, strm->state);
21b10c
+    if (state->window != Z_NULL) ZFREE_WINDOW(strm, state->window);
21b10c
+    ZFREE_STATE(strm, strm->state);
21b10c
     strm->state = Z_NULL;
21b10c
     Tracev((stderr, "inflate: end\n"));
21b10c
     return Z_OK;
21b10c
@@ -1474,21 +1503,21 @@ z_streamp source;
21b10c
 
21b10c
     /* allocate space */
21b10c
     copy = (struct inflate_state FAR *)
21b10c
-           ZALLOC(source, 1, sizeof(struct inflate_state));
21b10c
+           ZALLOC_STATE(source, 1, sizeof(struct inflate_state));
21b10c
     if (copy == Z_NULL) return Z_MEM_ERROR;
21b10c
     window = Z_NULL;
21b10c
     if (state->window != Z_NULL) {
21b10c
         window = (unsigned char FAR *)
21b10c
-                 ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
21b10c
+                 ZALLOC_WINDOW(source, 1U << state->wbits, sizeof(unsigned char));
21b10c
         if (window == Z_NULL) {
21b10c
-            ZFREE(source, copy);
21b10c
+            ZFREE_STATE(source, copy);
21b10c
             return Z_MEM_ERROR;
21b10c
         }
21b10c
     }
21b10c
 
21b10c
     /* copy state */
21b10c
     zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));
21b10c
-    zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state));
21b10c
+    ZCOPY_STATE((voidpf)copy, (voidpf)state, sizeof(struct inflate_state));
21b10c
     copy->strm = dest;
21b10c
     if (state->lencode >= state->codes &&
21b10c
         state->lencode <= state->codes + ENOUGH - 1) {
21b10c
@@ -1545,6 +1574,7 @@ z_streamp strm;
21b10c
 
21b10c
     if (inflateStateCheck(strm))
21b10c
         return -(1L << 16);
21b10c
+    INFLATE_MARK_HOOK(strm);
21b10c
     state = (struct inflate_state FAR *)strm->state;
21b10c
     return (long)(((unsigned long)((long)state->back)) << 16) +
21b10c
         (state->mode == COPY ? state->length :
21b10c
diff --git a/inflate.h b/inflate.h
21b10c
index a46cce6..7b19617 100644
21b10c
--- a/inflate.h
21b10c
+++ b/inflate.h
21b10c
@@ -123,3 +123,5 @@ struct inflate_state {
21b10c
     int back;                   /* bits back of last unprocessed length/lit */
21b10c
     unsigned was;               /* initial length of match */
21b10c
 };
21b10c
+
21b10c
+int ZLIB_INTERNAL inflate_ensure_window OF((struct inflate_state *state));
21b10c
diff --git a/test/infcover.c b/test/infcover.c
21b10c
index 2be0164..a34cd17 100644
21b10c
--- a/test/infcover.c
21b10c
+++ b/test/infcover.c
21b10c
@@ -444,7 +444,7 @@ local void cover_wrap(void)
21b10c
 }
21b10c
 
21b10c
 /* input and output functions for inflateBack() */
21b10c
-local unsigned pull(void *desc, unsigned char **buf)
21b10c
+local unsigned pull(void *desc, z_const unsigned char **buf)
21b10c
 {
21b10c
     static unsigned int next = 0;
21b10c
     static unsigned char dat[] = {0x63, 0, 2, 0};
21b10c
diff --git a/test/minigzip.c b/test/minigzip.c
21b10c
index e22fb08..4b5f4ef 100644
21b10c
--- a/test/minigzip.c
21b10c
+++ b/test/minigzip.c
21b10c
@@ -132,7 +132,11 @@ static void pwinerror (s)
21b10c
 #endif
21b10c
 #define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1)
21b10c
 
21b10c
+#ifdef DFLTCC
21b10c
+#define BUFLEN      262144
21b10c
+#else
21b10c
 #define BUFLEN      16384
21b10c
+#endif
21b10c
 #define MAX_NAME_LEN 1024
21b10c
 
21b10c
 #ifdef MAXSEG_64K
21b10c
diff --git a/trees.c b/trees.c
21b10c
index 50cf4b4..ad51207 100644
21b10c
--- a/trees.c
21b10c
+++ b/trees.c
21b10c
@@ -149,8 +149,6 @@ local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
21b10c
 local void compress_block OF((deflate_state *s, const ct_data *ltree,
21b10c
                               const ct_data *dtree));
21b10c
 local int  detect_data_type OF((deflate_state *s));
21b10c
-local unsigned bi_reverse OF((unsigned value, int length));
21b10c
-local void bi_windup      OF((deflate_state *s));
21b10c
 local void bi_flush       OF((deflate_state *s));
21b10c
 
21b10c
 #ifdef GEN_TREES_H
21b10c
@@ -223,6 +221,13 @@ local void send_bits(s, value, length)
21b10c
 }
21b10c
 #endif /* ZLIB_DEBUG */
21b10c
 
21b10c
+void ZLIB_INTERNAL _tr_send_bits(s, value, length)
21b10c
+    deflate_state *s;
21b10c
+    int value;
21b10c
+    int length;
21b10c
+{
21b10c
+    send_bits(s, value, length);
21b10c
+}
21b10c
 
21b10c
 /* the arguments must not have side effects */
21b10c
 
21b10c
@@ -1155,7 +1160,7 @@ local int detect_data_type(s)
21b10c
  * method would use a table)
21b10c
  * IN assertion: 1 <= len <= 15
21b10c
  */
21b10c
-local unsigned bi_reverse(code, len)
21b10c
+unsigned ZLIB_INTERNAL bi_reverse(code, len)
21b10c
     unsigned code; /* the value to invert */
21b10c
     int len;       /* its bit length */
21b10c
 {
21b10c
@@ -1187,7 +1192,7 @@ local void bi_flush(s)
21b10c
 /* ===========================================================================
21b10c
  * Flush the bit buffer and align the output on a byte boundary
21b10c
  */
21b10c
-local void bi_windup(s)
21b10c
+void ZLIB_INTERNAL bi_windup(s)
21b10c
     deflate_state *s;
21b10c
 {
21b10c
     if (s->bi_valid > 8) {
21b10c
-- 
21b10c
2.19.1
21b10c