| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- /* dfltcc_inflate.c - IBM Z DEFLATE CONVERSION CALL decompression support. */
- /*
- Use the following commands to build zlib-ng with DFLTCC decompression support:
- $ ./configure --with-dfltcc-inflate
- or
- $ cmake -DWITH_DFLTCC_INFLATE=1 .
- and then
- $ make
- */
- #include "zbuild.h"
- #include "zutil.h"
- #include "inftrees.h"
- #include "inflate.h"
- #include "dfltcc_inflate.h"
- #include "dfltcc_detail.h"
- void Z_INTERNAL PREFIX(dfltcc_reset_inflate_state)(PREFIX3(streamp) strm) {
- struct inflate_state *state = (struct inflate_state *)strm->state;
- dfltcc_reset_state(&state->arch.common);
- }
- int Z_INTERNAL PREFIX(dfltcc_can_inflate)(PREFIX3(streamp) strm) {
- struct inflate_state *state = (struct inflate_state *)strm->state;
- struct dfltcc_state *dfltcc_state = &state->arch.common;
- /* Unsupported hardware */
- return is_bit_set(dfltcc_state->af.fns, DFLTCC_XPND) && is_bit_set(dfltcc_state->af.fmts, DFLTCC_FMT0);
- }
- static inline dfltcc_cc dfltcc_xpnd(PREFIX3(streamp) strm) {
- struct inflate_state *state = (struct inflate_state *)strm->state;
- struct dfltcc_param_v0 *param = &state->arch.common.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 Z_INTERNAL PREFIX(dfltcc_inflate)(PREFIX3(streamp) strm, int flush, int *ret) {
- struct inflate_state *state = (struct inflate_state *)strm->state;
- struct dfltcc_state *dfltcc_state = &state->arch.common;
- struct dfltcc_param_v0 *param = &dfltcc_state->param;
- dfltcc_cc cc;
- if (flush == Z_BLOCK || flush == Z_TREES) {
- /* DFLTCC does not support stopping on block boundaries */
- if (PREFIX(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 window not in use yet, initialize */
- if (state->wsize == 0)
- state->wsize = 1U << state->wbits;
- /* Translate stream to parameter block */
- param->cvt = ((state->wrap & 4) && state->flags) ? CVT_CRC32 : CVT_ADLER32;
- param->sbb = state->bits;
- if (param->hl)
- param->nt = 0; /* Honor history for the first block */
- if (state->wrap & 4)
- param->cv = state->flags ? ZSWAP32(state->check) : 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;
- if (state->wrap & 4)
- strm->adler = state->check = state->flags ? ZSWAP32(param->cv) : 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;
- }
- int Z_INTERNAL PREFIX(dfltcc_was_inflate_used)(PREFIX3(streamp) strm) {
- struct inflate_state *state = (struct inflate_state *)strm->state;
- return !state->arch.common.param.nt;
- }
- /*
- Rotates a circular buffer.
- The implementation is based on https://cplusplus.com/reference/algorithm/rotate/
- */
- static void rotate(unsigned char *start, unsigned char *pivot, unsigned char *end) {
- unsigned char *p = pivot;
- unsigned char tmp;
- while (p != start) {
- tmp = *start;
- *start = *p;
- *p = tmp;
- start++;
- p++;
- if (p == end)
- p = pivot;
- else if (start == pivot)
- pivot = p;
- }
- }
- int Z_INTERNAL PREFIX(dfltcc_inflate_disable)(PREFIX3(streamp) strm) {
- struct inflate_state *state = (struct inflate_state *)strm->state;
- struct dfltcc_state *dfltcc_state = &state->arch.common;
- struct dfltcc_param_v0 *param = &dfltcc_state->param;
- if (!PREFIX(dfltcc_can_inflate)(strm))
- return 0;
- if (PREFIX(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));
- /* Convert the window from the hardware to the software format */
- rotate(state->window, state->window + param->ho, state->window + HB_SIZE);
- state->whave = state->wnext = MIN(param->hl, state->wsize);
- return 0;
- }
- /*
- Preloading history.
- */
- int Z_INTERNAL PREFIX(dfltcc_inflate_set_dictionary)(PREFIX3(streamp) strm,
- const unsigned char *dictionary, uInt dict_length) {
- struct inflate_state *state = (struct inflate_state *)strm->state;
- struct dfltcc_param_v0 *param = &state->arch.common.param;
- /* if window not in use yet, initialize */
- if (state->wsize == 0)
- state->wsize = 1U << state->wbits;
- append_history(param, state->window, dictionary, dict_length);
- state->havedict = 1;
- return Z_OK;
- }
- int Z_INTERNAL PREFIX(dfltcc_inflate_get_dictionary)(PREFIX3(streamp) strm,
- unsigned char *dictionary, uInt *dict_length) {
- struct inflate_state *state = (struct inflate_state *)strm->state;
- struct dfltcc_param_v0 *param = &state->arch.common.param;
- if (dictionary && state->window)
- get_history(param, state->window, dictionary);
- if (dict_length)
- *dict_length = param->hl;
- return Z_OK;
- }
|