brintos

brintos / linux-shallow public Read only

0
0
Text · 10.4 KiB · b732b6d Raw
314 lines · c
1// SPDX-License-Identifier: Zlib2 3#include "../zlib_deflate/defutil.h"4#include "dfltcc_util.h"5#include "dfltcc_deflate.h"6#include <asm/setup.h>7#include <linux/export.h>8#include <linux/zutil.h>9 10#define GET_DFLTCC_DEFLATE_STATE(state) ((struct dfltcc_deflate_state *)GET_DFLTCC_STATE(state))11 12/*13 * Compress.14 */15int dfltcc_can_deflate(16    z_streamp strm17)18{19    deflate_state *state = (deflate_state *)strm->state;20    struct dfltcc_deflate_state *dfltcc_state = GET_DFLTCC_DEFLATE_STATE(state);21 22    /* Check for kernel dfltcc command line parameter */23    if (zlib_dfltcc_support == ZLIB_DFLTCC_DISABLED ||24            zlib_dfltcc_support == ZLIB_DFLTCC_INFLATE_ONLY)25        return 0;26 27    /* Unsupported compression settings */28    if (!dfltcc_are_params_ok(state->level, state->w_bits, state->strategy,29                              dfltcc_state->level_mask))30        return 0;31 32    /* Unsupported hardware */33    if (!is_bit_set(dfltcc_state->common.af.fns, DFLTCC_GDHT) ||34            !is_bit_set(dfltcc_state->common.af.fns, DFLTCC_CMPR) ||35            !is_bit_set(dfltcc_state->common.af.fmts, DFLTCC_FMT0))36        return 0;37 38    return 1;39}40EXPORT_SYMBOL(dfltcc_can_deflate);41 42void dfltcc_reset_deflate_state(z_streamp strm) {43    deflate_state *state = (deflate_state *)strm->state;44    struct dfltcc_deflate_state *dfltcc_state = GET_DFLTCC_DEFLATE_STATE(state);45 46    dfltcc_reset_state(&dfltcc_state->common);47 48    /* Initialize tuning parameters */49    if (zlib_dfltcc_support == ZLIB_DFLTCC_FULL_DEBUG)50        dfltcc_state->level_mask = DFLTCC_LEVEL_MASK_DEBUG;51    else52        dfltcc_state->level_mask = DFLTCC_LEVEL_MASK;53    dfltcc_state->block_size = DFLTCC_BLOCK_SIZE;54    dfltcc_state->block_threshold = DFLTCC_FIRST_FHT_BLOCK_SIZE;55    dfltcc_state->dht_threshold = DFLTCC_DHT_MIN_SAMPLE_SIZE;56}57EXPORT_SYMBOL(dfltcc_reset_deflate_state);58 59static void dfltcc_gdht(60    z_streamp strm61)62{63    deflate_state *state = (deflate_state *)strm->state;64    struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;65    size_t avail_in = strm->avail_in;66 67    dfltcc(DFLTCC_GDHT,68           param, NULL, NULL,69           &strm->next_in, &avail_in, NULL);70}71 72static dfltcc_cc dfltcc_cmpr(73    z_streamp strm74)75{76    deflate_state *state = (deflate_state *)strm->state;77    struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;78    size_t avail_in = strm->avail_in;79    size_t avail_out = strm->avail_out;80    dfltcc_cc cc;81 82    cc = dfltcc(DFLTCC_CMPR | HBT_CIRCULAR,83                param, &strm->next_out, &avail_out,84                &strm->next_in, &avail_in, state->window);85    strm->total_in += (strm->avail_in - avail_in);86    strm->total_out += (strm->avail_out - avail_out);87    strm->avail_in = avail_in;88    strm->avail_out = avail_out;89    return cc;90}91 92static void send_eobs(93    z_streamp strm,94    const struct dfltcc_param_v0 *param95)96{97    deflate_state *state = (deflate_state *)strm->state;98 99    zlib_tr_send_bits(100          state,101          bi_reverse(param->eobs >> (15 - param->eobl), param->eobl),102          param->eobl);103    flush_pending(strm);104    if (state->pending != 0) {105        /* The remaining data is located in pending_out[0:pending]. If someone106         * calls put_byte() - this might happen in deflate() - the byte will be107         * placed into pending_buf[pending], which is incorrect. Move the108         * remaining data to the beginning of pending_buf so that put_byte() is109         * usable again.110         */111        memmove(state->pending_buf, state->pending_out, state->pending);112        state->pending_out = state->pending_buf;113    }114#ifdef ZLIB_DEBUG115    state->compressed_len += param->eobl;116#endif117}118 119int dfltcc_deflate(120    z_streamp strm,121    int flush,122    block_state *result123)124{125    deflate_state *state = (deflate_state *)strm->state;126    struct dfltcc_deflate_state *dfltcc_state = GET_DFLTCC_DEFLATE_STATE(state);127    struct dfltcc_param_v0 *param = &dfltcc_state->common.param;128    uInt masked_avail_in;129    dfltcc_cc cc;130    int need_empty_block;131    int soft_bcc;132    int no_flush;133 134    if (!dfltcc_can_deflate(strm)) {135        /* Clear history. */136        if (flush == Z_FULL_FLUSH)137            param->hl = 0;138        return 0;139    }140 141again:142    masked_avail_in = 0;143    soft_bcc = 0;144    no_flush = flush == Z_NO_FLUSH;145 146    /* No input data. Return, except when Continuation Flag is set, which means147     * that DFLTCC has buffered some output in the parameter block and needs to148     * be called again in order to flush it.149     */150    if (strm->avail_in == 0 && !param->cf) {151        /* A block is still open, and the hardware does not support closing152         * blocks without adding data. Thus, close it manually.153         */154        if (!no_flush && param->bcf) {155            send_eobs(strm, param);156            param->bcf = 0;157        }158        /* Let one of deflate_* functions write a trailing empty block. */159        if (flush == Z_FINISH)160            return 0;161        /* Clear history. */162        if (flush == Z_FULL_FLUSH)163            param->hl = 0;164        /* Trigger block post-processing if necessary. */165        *result = no_flush ? need_more : block_done;166        return 1;167    }168 169    /* There is an open non-BFINAL block, we are not going to close it just170     * yet, we have compressed more than DFLTCC_BLOCK_SIZE bytes and we see171     * more than DFLTCC_DHT_MIN_SAMPLE_SIZE bytes. Open a new block with a new172     * DHT in order to adapt to a possibly changed input data distribution.173     */174    if (param->bcf && no_flush &&175            strm->total_in > dfltcc_state->block_threshold &&176            strm->avail_in >= dfltcc_state->dht_threshold) {177        if (param->cf) {178            /* We need to flush the DFLTCC buffer before writing the179             * End-of-block Symbol. Mask the input data and proceed as usual.180             */181            masked_avail_in += strm->avail_in;182            strm->avail_in = 0;183            no_flush = 0;184        } else {185            /* DFLTCC buffer is empty, so we can manually write the186             * End-of-block Symbol right away.187             */188            send_eobs(strm, param);189            param->bcf = 0;190            dfltcc_state->block_threshold =191                strm->total_in + dfltcc_state->block_size;192        }193    }194 195    /* No space for compressed data. If we proceed, dfltcc_cmpr() will return196     * DFLTCC_CC_OP1_TOO_SHORT without buffering header bits, but we will still197     * set BCF=1, which is wrong. Avoid complications and return early.198     */199    if (strm->avail_out == 0) {200        *result = need_more;201        return 1;202    }203 204    /* The caller gave us too much data. Pass only one block worth of205     * uncompressed data to DFLTCC and mask the rest, so that on the next206     * iteration we start a new block.207     */208    if (no_flush && strm->avail_in > dfltcc_state->block_size) {209        masked_avail_in += (strm->avail_in - dfltcc_state->block_size);210        strm->avail_in = dfltcc_state->block_size;211    }212 213    /* When we have an open non-BFINAL deflate block and caller indicates that214     * the stream is ending, we need to close an open deflate block and open a215     * BFINAL one.216     */217    need_empty_block = flush == Z_FINISH && param->bcf && !param->bhf;218 219    /* Translate stream to parameter block */220    param->cvt = CVT_ADLER32;221    if (!no_flush)222        /* We need to close a block. Always do this in software - when there is223         * no input data, the hardware will not hohor BCC. */224        soft_bcc = 1;225    if (flush == Z_FINISH && !param->bcf)226        /* We are about to open a BFINAL block, set Block Header Final bit227         * until the stream ends.228         */229        param->bhf = 1;230    /* DFLTCC-CMPR will write to next_out, so make sure that buffers with231     * higher precedence are empty.232     */233    Assert(state->pending == 0, "There must be no pending bytes");234    Assert(state->bi_valid < 8, "There must be less than 8 pending bits");235    param->sbb = (unsigned int)state->bi_valid;236    if (param->sbb > 0)237        *strm->next_out = (Byte)state->bi_buf;238    /* Honor history and check value */239    param->nt = 0;240    param->cv = strm->adler;241 242    /* When opening a block, choose a Huffman-Table Type */243    if (!param->bcf) {244        if (strm->total_in == 0 && dfltcc_state->block_threshold > 0) {245            param->htt = HTT_FIXED;246        }247        else {248            param->htt = HTT_DYNAMIC;249            dfltcc_gdht(strm);250        }251    }252 253    /* Deflate */254    do {255        cc = dfltcc_cmpr(strm);256        if (strm->avail_in < 4096 && masked_avail_in > 0)257            /* We are about to call DFLTCC with a small input buffer, which is258             * inefficient. Since there is masked data, there will be at least259             * one more DFLTCC call, so skip the current one and make the next260             * one handle more data.261             */262            break;263    } while (cc == DFLTCC_CC_AGAIN);264 265    /* Translate parameter block to stream */266    strm->msg = oesc_msg(dfltcc_state->common.msg, param->oesc);267    state->bi_valid = param->sbb;268    if (state->bi_valid == 0)269        state->bi_buf = 0; /* Avoid accessing next_out */270    else271        state->bi_buf = *strm->next_out & ((1 << state->bi_valid) - 1);272    strm->adler = param->cv;273 274    /* Unmask the input data */275    strm->avail_in += masked_avail_in;276    masked_avail_in = 0;277 278    /* If we encounter an error, it means there is a bug in DFLTCC call */279    Assert(cc != DFLTCC_CC_OP2_CORRUPT || param->oesc == 0, "BUG");280 281    /* Update Block-Continuation Flag. It will be used to check whether to call282     * GDHT the next time.283     */284    if (cc == DFLTCC_CC_OK) {285        if (soft_bcc) {286            send_eobs(strm, param);287            param->bcf = 0;288            dfltcc_state->block_threshold =289                strm->total_in + dfltcc_state->block_size;290        } else291            param->bcf = 1;292        if (flush == Z_FINISH) {293            if (need_empty_block)294                /* Make the current deflate() call also close the stream */295                return 0;296            else {297                bi_windup(state);298                *result = finish_done;299            }300        } else {301            if (flush == Z_FULL_FLUSH)302                param->hl = 0; /* Clear history */303            *result = flush == Z_NO_FLUSH ? need_more : block_done;304        }305    } else {306        param->bcf = 1;307        *result = need_more;308    }309    if (strm->avail_in != 0 && strm->avail_out != 0)310        goto again; /* deflate() must use all input or all output */311    return 1;312}313EXPORT_SYMBOL(dfltcc_deflate);314