]> git.ipfire.org Git - thirdparty/linux.git/blob - lib/zlib_dfltcc/dfltcc_inflate.c
Merge tag 'timers-urgent-2020-02-09' of git://git.kernel.org/pub/scm/linux/kernel...
[thirdparty/linux.git] / lib / zlib_dfltcc / dfltcc_inflate.c
1 // SPDX-License-Identifier: Zlib
2
3 #include "../zlib_inflate/inflate.h"
4 #include "dfltcc_util.h"
5 #include "dfltcc.h"
6 #include <asm/setup.h>
7 #include <linux/zutil.h>
8
9 /*
10 * Expand.
11 */
12 int dfltcc_can_inflate(
13 z_streamp strm
14 )
15 {
16 struct inflate_state *state = (struct inflate_state *)strm->state;
17 struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
18
19 /* Check for kernel dfltcc command line parameter */
20 if (zlib_dfltcc_support == ZLIB_DFLTCC_DISABLED ||
21 zlib_dfltcc_support == ZLIB_DFLTCC_DEFLATE_ONLY)
22 return 0;
23
24 /* Unsupported compression settings */
25 if (state->wbits != HB_BITS)
26 return 0;
27
28 /* Unsupported hardware */
29 return is_bit_set(dfltcc_state->af.fns, DFLTCC_XPND) &&
30 is_bit_set(dfltcc_state->af.fmts, DFLTCC_FMT0);
31 }
32
33 static int dfltcc_was_inflate_used(
34 z_streamp strm
35 )
36 {
37 struct inflate_state *state = (struct inflate_state *)strm->state;
38 struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;
39
40 return !param->nt;
41 }
42
43 static int dfltcc_inflate_disable(
44 z_streamp strm
45 )
46 {
47 struct inflate_state *state = (struct inflate_state *)strm->state;
48 struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
49
50 if (!dfltcc_can_inflate(strm))
51 return 0;
52 if (dfltcc_was_inflate_used(strm))
53 /* DFLTCC has already decompressed some data. Since there is not
54 * enough information to resume decompression in software, the call
55 * must fail.
56 */
57 return 1;
58 /* DFLTCC was not used yet - decompress in software */
59 memset(&dfltcc_state->af, 0, sizeof(dfltcc_state->af));
60 return 0;
61 }
62
63 static dfltcc_cc dfltcc_xpnd(
64 z_streamp strm
65 )
66 {
67 struct inflate_state *state = (struct inflate_state *)strm->state;
68 struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;
69 size_t avail_in = strm->avail_in;
70 size_t avail_out = strm->avail_out;
71 dfltcc_cc cc;
72
73 cc = dfltcc(DFLTCC_XPND | HBT_CIRCULAR,
74 param, &strm->next_out, &avail_out,
75 &strm->next_in, &avail_in, state->window);
76 strm->avail_in = avail_in;
77 strm->avail_out = avail_out;
78 return cc;
79 }
80
81 dfltcc_inflate_action dfltcc_inflate(
82 z_streamp strm,
83 int flush,
84 int *ret
85 )
86 {
87 struct inflate_state *state = (struct inflate_state *)strm->state;
88 struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
89 struct dfltcc_param_v0 *param = &dfltcc_state->param;
90 dfltcc_cc cc;
91
92 if (flush == Z_BLOCK) {
93 /* DFLTCC does not support stopping on block boundaries */
94 if (dfltcc_inflate_disable(strm)) {
95 *ret = Z_STREAM_ERROR;
96 return DFLTCC_INFLATE_BREAK;
97 } else
98 return DFLTCC_INFLATE_SOFTWARE;
99 }
100
101 if (state->last) {
102 if (state->bits != 0) {
103 strm->next_in++;
104 strm->avail_in--;
105 state->bits = 0;
106 }
107 state->mode = CHECK;
108 return DFLTCC_INFLATE_CONTINUE;
109 }
110
111 if (strm->avail_in == 0 && !param->cf)
112 return DFLTCC_INFLATE_BREAK;
113
114 if (!state->window || state->wsize == 0) {
115 state->mode = MEM;
116 return DFLTCC_INFLATE_CONTINUE;
117 }
118
119 /* Translate stream to parameter block */
120 param->cvt = CVT_ADLER32;
121 param->sbb = state->bits;
122 param->hl = state->whave; /* Software and hardware history formats match */
123 param->ho = (state->write - state->whave) & ((1 << HB_BITS) - 1);
124 if (param->hl)
125 param->nt = 0; /* Honor history for the first block */
126 param->cv = state->flags ? REVERSE(state->check) : state->check;
127
128 /* Inflate */
129 do {
130 cc = dfltcc_xpnd(strm);
131 } while (cc == DFLTCC_CC_AGAIN);
132
133 /* Translate parameter block to stream */
134 strm->msg = oesc_msg(dfltcc_state->msg, param->oesc);
135 state->last = cc == DFLTCC_CC_OK;
136 state->bits = param->sbb;
137 state->whave = param->hl;
138 state->write = (param->ho + param->hl) & ((1 << HB_BITS) - 1);
139 state->check = state->flags ? REVERSE(param->cv) : param->cv;
140 if (cc == DFLTCC_CC_OP2_CORRUPT && param->oesc != 0) {
141 /* Report an error if stream is corrupted */
142 state->mode = BAD;
143 return DFLTCC_INFLATE_CONTINUE;
144 }
145 state->mode = TYPEDO;
146 /* Break if operands are exhausted, otherwise continue looping */
147 return (cc == DFLTCC_CC_OP1_TOO_SHORT || cc == DFLTCC_CC_OP2_TOO_SHORT) ?
148 DFLTCC_INFLATE_BREAK : DFLTCC_INFLATE_CONTINUE;
149 }