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
PREFIX(dfltcc_alloc_inflate_state)23 struct inflate_state Z_INTERNAL *PREFIX(dfltcc_alloc_inflate_state)(PREFIX3(streamp) strm) {
24 return (struct inflate_state *)dfltcc_alloc_state(strm, sizeof(struct inflate_state), sizeof(struct dfltcc_state));
25 }
26
PREFIX(dfltcc_reset_inflate_state)27 void Z_INTERNAL PREFIX(dfltcc_reset_inflate_state)(PREFIX3(streamp) strm) {
28 struct inflate_state *state = (struct inflate_state *)strm->state;
29 struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
30
31 dfltcc_reset_state(dfltcc_state);
32 }
33
PREFIX(dfltcc_copy_inflate_state)34 void Z_INTERNAL PREFIX(dfltcc_copy_inflate_state)(struct inflate_state *dst, const struct inflate_state *src) {
35 dfltcc_copy_state(dst, src, sizeof(struct inflate_state), sizeof(struct dfltcc_state));
36 }
37
PREFIX(dfltcc_can_inflate)38 int Z_INTERNAL PREFIX(dfltcc_can_inflate)(PREFIX3(streamp) strm) {
39 struct inflate_state *state = (struct inflate_state *)strm->state;
40 struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
41
42 /* Unsupported compression settings */
43 if (state->wbits != HB_BITS)
44 return 0;
45
46 /* Unsupported hardware */
47 return is_bit_set(dfltcc_state->af.fns, DFLTCC_XPND) && is_bit_set(dfltcc_state->af.fmts, DFLTCC_FMT0);
48 }
49
dfltcc_xpnd(PREFIX3 (streamp)strm)50 static inline dfltcc_cc dfltcc_xpnd(PREFIX3(streamp) strm) {
51 struct inflate_state *state = (struct inflate_state *)strm->state;
52 struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;
53 size_t avail_in = strm->avail_in;
54 size_t avail_out = strm->avail_out;
55 dfltcc_cc cc;
56
57 cc = dfltcc(DFLTCC_XPND | HBT_CIRCULAR,
58 param, &strm->next_out, &avail_out,
59 &strm->next_in, &avail_in, state->window);
60 strm->avail_in = avail_in;
61 strm->avail_out = avail_out;
62 return cc;
63 }
64
PREFIX(dfltcc_inflate)65 dfltcc_inflate_action Z_INTERNAL PREFIX(dfltcc_inflate)(PREFIX3(streamp) strm, int flush, int *ret) {
66 struct inflate_state *state = (struct inflate_state *)strm->state;
67 struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
68 struct dfltcc_param_v0 *param = &dfltcc_state->param;
69 dfltcc_cc cc;
70
71 if (flush == Z_BLOCK || flush == Z_TREES) {
72 /* DFLTCC does not support stopping on block boundaries */
73 if (PREFIX(dfltcc_inflate_disable)(strm)) {
74 *ret = Z_STREAM_ERROR;
75 return DFLTCC_INFLATE_BREAK;
76 } else
77 return DFLTCC_INFLATE_SOFTWARE;
78 }
79
80 if (state->last) {
81 if (state->bits != 0) {
82 strm->next_in++;
83 strm->avail_in--;
84 state->bits = 0;
85 }
86 state->mode = CHECK;
87 return DFLTCC_INFLATE_CONTINUE;
88 }
89
90 if (strm->avail_in == 0 && !param->cf)
91 return DFLTCC_INFLATE_BREAK;
92
93 if (PREFIX(inflate_ensure_window)(state)) {
94 state->mode = MEM;
95 return DFLTCC_INFLATE_CONTINUE;
96 }
97
98 /* Translate stream to parameter block */
99 param->cvt = state->flags ? CVT_CRC32 : CVT_ADLER32;
100 param->sbb = state->bits;
101 param->hl = state->whave; /* Software and hardware history formats match */
102 param->ho = (state->wnext - state->whave) & ((1 << HB_BITS) - 1);
103 if (param->hl)
104 param->nt = 0; /* Honor history for the first block */
105 param->cv = state->flags ? ZSWAP32(state->check) : state->check;
106
107 /* Inflate */
108 do {
109 cc = dfltcc_xpnd(strm);
110 } while (cc == DFLTCC_CC_AGAIN);
111
112 /* Translate parameter block to stream */
113 strm->msg = oesc_msg(dfltcc_state->msg, param->oesc);
114 state->last = cc == DFLTCC_CC_OK;
115 state->bits = param->sbb;
116 state->whave = param->hl;
117 state->wnext = (param->ho + param->hl) & ((1 << HB_BITS) - 1);
118 state->check = state->flags ? ZSWAP32(param->cv) : param->cv;
119 if (cc == DFLTCC_CC_OP2_CORRUPT && param->oesc != 0) {
120 /* Report an error if stream is corrupted */
121 state->mode = BAD;
122 return DFLTCC_INFLATE_CONTINUE;
123 }
124 state->mode = TYPEDO;
125 /* Break if operands are exhausted, otherwise continue looping */
126 return (cc == DFLTCC_CC_OP1_TOO_SHORT || cc == DFLTCC_CC_OP2_TOO_SHORT) ?
127 DFLTCC_INFLATE_BREAK : DFLTCC_INFLATE_CONTINUE;
128 }
129
PREFIX(dfltcc_was_inflate_used)130 int Z_INTERNAL PREFIX(dfltcc_was_inflate_used)(PREFIX3(streamp) strm) {
131 struct inflate_state *state = (struct inflate_state *)strm->state;
132 struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;
133
134 return !param->nt;
135 }
136
PREFIX(dfltcc_inflate_disable)137 int Z_INTERNAL PREFIX(dfltcc_inflate_disable)(PREFIX3(streamp) strm) {
138 struct inflate_state *state = (struct inflate_state *)strm->state;
139 struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
140
141 if (!PREFIX(dfltcc_can_inflate)(strm))
142 return 0;
143 if (PREFIX(dfltcc_was_inflate_used)(strm))
144 /* DFLTCC has already decompressed some data. Since there is not
145 * enough information to resume decompression in software, the call
146 * must fail.
147 */
148 return 1;
149 /* DFLTCC was not used yet - decompress in software */
150 memset(&dfltcc_state->af, 0, sizeof(dfltcc_state->af));
151 return 0;
152 }
153