]>
Commit | Line | Data |
---|---|---|
12619610 MZ |
1 | // SPDX-License-Identifier: Zlib |
2 | ||
3 | #include "../zlib_inflate/inflate.h" | |
4 | #include "dfltcc_util.h" | |
5 | #include "dfltcc.h" | |
c65e6815 | 6 | #include <asm/setup.h> |
12619610 MZ |
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 | ||
c65e6815 MZ |
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 | ||
12619610 MZ |
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 | } |