mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
152 lines
4.4 KiB
152 lines
4.4 KiB
// SPDX-License-Identifier: Zlib |
|
|
|
#include "../zlib_inflate/inflate.h" |
|
#include "dfltcc_util.h" |
|
#include "dfltcc.h" |
|
#include <asm/setup.h> |
|
#include <linux/export.h> |
|
#include <linux/zutil.h> |
|
|
|
/* |
|
* Expand. |
|
*/ |
|
int dfltcc_can_inflate( |
|
z_streamp strm |
|
) |
|
{ |
|
struct inflate_state *state = (struct inflate_state *)strm->state; |
|
struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state); |
|
|
|
/* Check for kernel dfltcc command line parameter */ |
|
if (zlib_dfltcc_support == ZLIB_DFLTCC_DISABLED || |
|
zlib_dfltcc_support == ZLIB_DFLTCC_DEFLATE_ONLY) |
|
return 0; |
|
|
|
/* Unsupported compression settings */ |
|
if (state->wbits != HB_BITS) |
|
return 0; |
|
|
|
/* Unsupported hardware */ |
|
return is_bit_set(dfltcc_state->af.fns, DFLTCC_XPND) && |
|
is_bit_set(dfltcc_state->af.fmts, DFLTCC_FMT0); |
|
} |
|
EXPORT_SYMBOL(dfltcc_can_inflate); |
|
|
|
static int dfltcc_was_inflate_used( |
|
z_streamp strm |
|
) |
|
{ |
|
struct inflate_state *state = (struct inflate_state *)strm->state; |
|
struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param; |
|
|
|
return !param->nt; |
|
} |
|
|
|
static int dfltcc_inflate_disable( |
|
z_streamp strm |
|
) |
|
{ |
|
struct inflate_state *state = (struct inflate_state *)strm->state; |
|
struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state); |
|
|
|
if (!dfltcc_can_inflate(strm)) |
|
return 0; |
|
if (dfltcc_was_inflate_used(strm)) |
|
/* DFLTCC has already decompressed some data. Since there is not |
|
* enough information to resume decompression in software, the call |
|
* must fail. |
|
*/ |
|
return 1; |
|
/* DFLTCC was not used yet - decompress in software */ |
|
memset(&dfltcc_state->af, 0, sizeof(dfltcc_state->af)); |
|
return 0; |
|
} |
|
|
|
static dfltcc_cc dfltcc_xpnd( |
|
z_streamp strm |
|
) |
|
{ |
|
struct inflate_state *state = (struct inflate_state *)strm->state; |
|
struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param; |
|
size_t avail_in = strm->avail_in; |
|
size_t avail_out = strm->avail_out; |
|
dfltcc_cc cc; |
|
|
|
cc = dfltcc(DFLTCC_XPND | HBT_CIRCULAR, |
|
param, &strm->next_out, &avail_out, |
|
&strm->next_in, &avail_in, state->window); |
|
strm->avail_in = avail_in; |
|
strm->avail_out = avail_out; |
|
return cc; |
|
} |
|
|
|
dfltcc_inflate_action dfltcc_inflate( |
|
z_streamp strm, |
|
int flush, |
|
int *ret |
|
) |
|
{ |
|
struct inflate_state *state = (struct inflate_state *)strm->state; |
|
struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state); |
|
struct dfltcc_param_v0 *param = &dfltcc_state->param; |
|
dfltcc_cc cc; |
|
|
|
if (flush == Z_BLOCK) { |
|
/* DFLTCC does not support stopping on block boundaries */ |
|
if (dfltcc_inflate_disable(strm)) { |
|
*ret = Z_STREAM_ERROR; |
|
return DFLTCC_INFLATE_BREAK; |
|
} else |
|
return DFLTCC_INFLATE_SOFTWARE; |
|
} |
|
|
|
if (state->last) { |
|
if (state->bits != 0) { |
|
strm->next_in++; |
|
strm->avail_in--; |
|
state->bits = 0; |
|
} |
|
state->mode = CHECK; |
|
return DFLTCC_INFLATE_CONTINUE; |
|
} |
|
|
|
if (strm->avail_in == 0 && !param->cf) |
|
return DFLTCC_INFLATE_BREAK; |
|
|
|
if (!state->window || state->wsize == 0) { |
|
state->mode = MEM; |
|
return DFLTCC_INFLATE_CONTINUE; |
|
} |
|
|
|
/* Translate stream to parameter block */ |
|
param->cvt = CVT_ADLER32; |
|
param->sbb = state->bits; |
|
param->hl = state->whave; /* Software and hardware history formats match */ |
|
param->ho = (state->write - state->whave) & ((1 << HB_BITS) - 1); |
|
if (param->hl) |
|
param->nt = 0; /* Honor history for the first block */ |
|
param->cv = state->check; |
|
|
|
/* Inflate */ |
|
do { |
|
cc = dfltcc_xpnd(strm); |
|
} while (cc == DFLTCC_CC_AGAIN); |
|
|
|
/* Translate parameter block to stream */ |
|
strm->msg = oesc_msg(dfltcc_state->msg, param->oesc); |
|
state->last = cc == DFLTCC_CC_OK; |
|
state->bits = param->sbb; |
|
state->whave = param->hl; |
|
state->write = (param->ho + param->hl) & ((1 << HB_BITS) - 1); |
|
state->check = param->cv; |
|
if (cc == DFLTCC_CC_OP2_CORRUPT && param->oesc != 0) { |
|
/* Report an error if stream is corrupted */ |
|
state->mode = BAD; |
|
return DFLTCC_INFLATE_CONTINUE; |
|
} |
|
state->mode = TYPEDO; |
|
/* Break if operands are exhausted, otherwise continue looping */ |
|
return (cc == DFLTCC_CC_OP1_TOO_SHORT || cc == DFLTCC_CC_OP2_TOO_SHORT) ? |
|
DFLTCC_INFLATE_BREAK : DFLTCC_INFLATE_CONTINUE; |
|
} |
|
EXPORT_SYMBOL(dfltcc_inflate);
|
|
|