1 // SPDX-License-Identifier: Zlib
3 #include "../zlib_inflate/inflate.h"
4 #include "dfltcc_util.h"
7 #include <linux/zutil.h>
12 int dfltcc_can_inflate(
16 struct inflate_state
*state
= (struct inflate_state
*)strm
->state
;
17 struct dfltcc_state
*dfltcc_state
= GET_DFLTCC_STATE(state
);
19 /* Check for kernel dfltcc command line parameter */
20 if (zlib_dfltcc_support
== ZLIB_DFLTCC_DISABLED
||
21 zlib_dfltcc_support
== ZLIB_DFLTCC_DEFLATE_ONLY
)
24 /* Unsupported compression settings */
25 if (state
->wbits
!= HB_BITS
)
28 /* Unsupported hardware */
29 return is_bit_set(dfltcc_state
->af
.fns
, DFLTCC_XPND
) &&
30 is_bit_set(dfltcc_state
->af
.fmts
, DFLTCC_FMT0
);
33 static int dfltcc_was_inflate_used(
37 struct inflate_state
*state
= (struct inflate_state
*)strm
->state
;
38 struct dfltcc_param_v0
*param
= &GET_DFLTCC_STATE(state
)->param
;
43 static int dfltcc_inflate_disable(
47 struct inflate_state
*state
= (struct inflate_state
*)strm
->state
;
48 struct dfltcc_state
*dfltcc_state
= GET_DFLTCC_STATE(state
);
50 if (!dfltcc_can_inflate(strm
))
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
58 /* DFLTCC was not used yet - decompress in software */
59 memset(&dfltcc_state
->af
, 0, sizeof(dfltcc_state
->af
));
63 static dfltcc_cc
dfltcc_xpnd(
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
;
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
;
81 dfltcc_inflate_action
dfltcc_inflate(
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
;
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
;
98 return DFLTCC_INFLATE_SOFTWARE
;
102 if (state
->bits
!= 0) {
108 return DFLTCC_INFLATE_CONTINUE
;
111 if (strm
->avail_in
== 0 && !param
->cf
)
112 return DFLTCC_INFLATE_BREAK
;
114 if (!state
->window
|| state
->wsize
== 0) {
116 return DFLTCC_INFLATE_CONTINUE
;
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);
125 param
->nt
= 0; /* Honor history for the first block */
126 param
->cv
= state
->flags
? REVERSE(state
->check
) : state
->check
;
130 cc
= dfltcc_xpnd(strm
);
131 } while (cc
== DFLTCC_CC_AGAIN
);
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 */
143 return DFLTCC_INFLATE_CONTINUE
;
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
;