1 // SPDX-License-Identifier: Zlib
3 #include "../zlib_inflate/inflate.h"
4 #include "dfltcc_util.h"
6 #include <linux/zutil.h>
11 int dfltcc_can_inflate(
15 struct inflate_state *state = (struct inflate_state *)strm->state;
16 struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
18 /* Unsupported compression settings */
19 if (state->wbits != HB_BITS)
22 /* Unsupported hardware */
23 return is_bit_set(dfltcc_state->af.fns, DFLTCC_XPND) &&
24 is_bit_set(dfltcc_state->af.fmts, DFLTCC_FMT0);
27 static int dfltcc_was_inflate_used(
31 struct inflate_state *state = (struct inflate_state *)strm->state;
32 struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;
37 static int dfltcc_inflate_disable(
41 struct inflate_state *state = (struct inflate_state *)strm->state;
42 struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
44 if (!dfltcc_can_inflate(strm))
46 if (dfltcc_was_inflate_used(strm))
47 /* DFLTCC has already decompressed some data. Since there is not
48 * enough information to resume decompression in software, the call
52 /* DFLTCC was not used yet - decompress in software */
53 memset(&dfltcc_state->af, 0, sizeof(dfltcc_state->af));
57 static dfltcc_cc dfltcc_xpnd(
61 struct inflate_state *state = (struct inflate_state *)strm->state;
62 struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;
63 size_t avail_in = strm->avail_in;
64 size_t avail_out = strm->avail_out;
67 cc = dfltcc(DFLTCC_XPND | HBT_CIRCULAR,
68 param, &strm->next_out, &avail_out,
69 &strm->next_in, &avail_in, state->window);
70 strm->avail_in = avail_in;
71 strm->avail_out = avail_out;
75 dfltcc_inflate_action dfltcc_inflate(
81 struct inflate_state *state = (struct inflate_state *)strm->state;
82 struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
83 struct dfltcc_param_v0 *param = &dfltcc_state->param;
86 if (flush == Z_BLOCK) {
87 /* DFLTCC does not support stopping on block boundaries */
88 if (dfltcc_inflate_disable(strm)) {
89 *ret = Z_STREAM_ERROR;
90 return DFLTCC_INFLATE_BREAK;
92 return DFLTCC_INFLATE_SOFTWARE;
96 if (state->bits != 0) {
102 return DFLTCC_INFLATE_CONTINUE;
105 if (strm->avail_in == 0 && !param->cf)
106 return DFLTCC_INFLATE_BREAK;
108 if (!state->window || state->wsize == 0) {
110 return DFLTCC_INFLATE_CONTINUE;
113 /* Translate stream to parameter block */
114 param->cvt = CVT_ADLER32;
115 param->sbb = state->bits;
116 param->hl = state->whave; /* Software and hardware history formats match */
117 param->ho = (state->write - state->whave) & ((1 << HB_BITS) - 1);
119 param->nt = 0; /* Honor history for the first block */
120 param->cv = state->flags ? REVERSE(state->check) : state->check;
124 cc = dfltcc_xpnd(strm);
125 } while (cc == DFLTCC_CC_AGAIN);
127 /* Translate parameter block to stream */
128 strm->msg = oesc_msg(dfltcc_state->msg, param->oesc);
129 state->last = cc == DFLTCC_CC_OK;
130 state->bits = param->sbb;
131 state->whave = param->hl;
132 state->write = (param->ho + param->hl) & ((1 << HB_BITS) - 1);
133 state->check = state->flags ? REVERSE(param->cv) : param->cv;
134 if (cc == DFLTCC_CC_OP2_CORRUPT && param->oesc != 0) {
135 /* Report an error if stream is corrupted */
137 return DFLTCC_INFLATE_CONTINUE;
139 state->mode = TYPEDO;
140 /* Break if operands are exhausted, otherwise continue looping */
141 return (cc == DFLTCC_CC_OP1_TOO_SHORT || cc == DFLTCC_CC_OP2_TOO_SHORT) ?
142 DFLTCC_INFLATE_BREAK : DFLTCC_INFLATE_CONTINUE;