• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* dfltcc_inflate.c - IBM Z DEFLATE CONVERSION CALL decompression support. */
2 
3 /*
4    Use the following commands to build zlib-ng with DFLTCC decompression support:
5 
6         $ ./configure --with-dfltcc-inflate
7    or
8 
9         $ cmake -DWITH_DFLTCC_INFLATE=1 .
10 
11    and then
12 
13         $ make
14 */
15 
16 #include "../../zbuild.h"
17 #include "../../zutil.h"
18 #include "../../inftrees.h"
19 #include "../../inflate.h"
20 #include "dfltcc_inflate.h"
21 #include "dfltcc_detail.h"
22 
dfltcc_can_inflate(PREFIX3 (streamp)strm)23 int Z_INTERNAL dfltcc_can_inflate(PREFIX3(streamp) strm) {
24     struct inflate_state *state = (struct inflate_state *)strm->state;
25     struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
26 
27     /* Unsupported compression settings */
28     if (state->wbits != HB_BITS)
29         return 0;
30 
31     /* Unsupported hardware */
32     return is_bit_set(dfltcc_state->af.fns, DFLTCC_XPND) && is_bit_set(dfltcc_state->af.fmts, DFLTCC_FMT0);
33 }
34 
dfltcc_xpnd(PREFIX3 (streamp)strm)35 static inline dfltcc_cc dfltcc_xpnd(PREFIX3(streamp) strm) {
36     struct inflate_state *state = (struct inflate_state *)strm->state;
37     struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;
38     size_t avail_in = strm->avail_in;
39     size_t avail_out = strm->avail_out;
40     dfltcc_cc cc;
41 
42     cc = dfltcc(DFLTCC_XPND | HBT_CIRCULAR,
43                 param, &strm->next_out, &avail_out,
44                 &strm->next_in, &avail_in, state->window);
45     strm->avail_in = avail_in;
46     strm->avail_out = avail_out;
47     return cc;
48 }
49 
dfltcc_inflate(PREFIX3 (streamp)strm,int flush,int * ret)50 dfltcc_inflate_action Z_INTERNAL dfltcc_inflate(PREFIX3(streamp) strm, int flush, int *ret) {
51     struct inflate_state *state = (struct inflate_state *)strm->state;
52     struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
53     struct dfltcc_param_v0 *param = &dfltcc_state->param;
54     dfltcc_cc cc;
55 
56     if (flush == Z_BLOCK || flush == Z_TREES) {
57         /* DFLTCC does not support stopping on block boundaries */
58         if (dfltcc_inflate_disable(strm)) {
59             *ret = Z_STREAM_ERROR;
60             return DFLTCC_INFLATE_BREAK;
61         } else
62             return DFLTCC_INFLATE_SOFTWARE;
63     }
64 
65     if (state->last) {
66         if (state->bits != 0) {
67             strm->next_in++;
68             strm->avail_in--;
69             state->bits = 0;
70         }
71         state->mode = CHECK;
72         return DFLTCC_INFLATE_CONTINUE;
73     }
74 
75     if (strm->avail_in == 0 && !param->cf)
76         return DFLTCC_INFLATE_BREAK;
77 
78     if (inflate_ensure_window(state)) {
79         state->mode = MEM;
80         return DFLTCC_INFLATE_CONTINUE;
81     }
82 
83     /* Translate stream to parameter block */
84     param->cvt = state->flags ? CVT_CRC32 : CVT_ADLER32;
85     param->sbb = state->bits;
86     param->hl = state->whave; /* Software and hardware history formats match */
87     param->ho = (state->wnext - state->whave) & ((1 << HB_BITS) - 1);
88     if (param->hl)
89         param->nt = 0; /* Honor history for the first block */
90     param->cv = state->flags ? ZSWAP32(state->check) : state->check;
91 
92     /* Inflate */
93     do {
94         cc = dfltcc_xpnd(strm);
95     } while (cc == DFLTCC_CC_AGAIN);
96 
97     /* Translate parameter block to stream */
98     strm->msg = oesc_msg(dfltcc_state->msg, param->oesc);
99     state->last = cc == DFLTCC_CC_OK;
100     state->bits = param->sbb;
101     state->whave = param->hl;
102     state->wnext = (param->ho + param->hl) & ((1 << HB_BITS) - 1);
103     state->check = state->flags ? ZSWAP32(param->cv) : param->cv;
104     if (cc == DFLTCC_CC_OP2_CORRUPT && param->oesc != 0) {
105         /* Report an error if stream is corrupted */
106         state->mode = BAD;
107         return DFLTCC_INFLATE_CONTINUE;
108     }
109     state->mode = TYPEDO;
110     /* Break if operands are exhausted, otherwise continue looping */
111     return (cc == DFLTCC_CC_OP1_TOO_SHORT || cc == DFLTCC_CC_OP2_TOO_SHORT) ?
112         DFLTCC_INFLATE_BREAK : DFLTCC_INFLATE_CONTINUE;
113 }
114 
dfltcc_was_inflate_used(PREFIX3 (streamp)strm)115 int Z_INTERNAL dfltcc_was_inflate_used(PREFIX3(streamp) strm) {
116     struct inflate_state *state = (struct inflate_state *)strm->state;
117     struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;
118 
119     return !param->nt;
120 }
121 
dfltcc_inflate_disable(PREFIX3 (streamp)strm)122 int Z_INTERNAL dfltcc_inflate_disable(PREFIX3(streamp) strm) {
123     struct inflate_state *state = (struct inflate_state *)strm->state;
124     struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
125 
126     if (!dfltcc_can_inflate(strm))
127         return 0;
128     if (dfltcc_was_inflate_used(strm))
129         /* DFLTCC has already decompressed some data. Since there is not
130          * enough information to resume decompression in software, the call
131          * must fail.
132          */
133         return 1;
134     /* DFLTCC was not used yet - decompress in software */
135     memset(&dfltcc_state->af, 0, sizeof(dfltcc_state->af));
136     return 0;
137 }
138