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