diff --git a/Makefile.in b/Makefile.in index 3413266aed..6c28f1f7f4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -143,6 +143,14 @@ match.lo: match.S mv _match.o match.lo rm -f _match.s +dfltcc.o: $(SRCDIR)contrib/s390/dfltcc.c $(SRCDIR)zlib.h zconf.h + $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)contrib/s390/dfltcc.c + +dfltcc.lo: $(SRCDIR)contrib/s390/dfltcc.c $(SRCDIR)zlib.h zconf.h + -@mkdir objs 2>/dev/null || test -d objs + $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/dfltcc.o $(SRCDIR)contrib/s390/dfltcc.c + -@mv objs/dfltcc.o $@ + example.o: $(SRCDIR)test/example.c $(SRCDIR)zlib.h zconf.h $(CC) $(CFLAGS) $(ZINCOUT) -c -o $@ $(SRCDIR)test/example.c diff --git a/contrib/s390/dfltcc.c b/contrib/s390/dfltcc.c new file mode 100644 index 0000000000..78b30c1dfb --- /dev/null +++ b/contrib/s390/dfltcc.c @@ -0,0 +1,897 @@ +/* dfltcc.c - SystemZ DEFLATE CONVERSION CALL support. */ + +/* + Use the following commands to build zlib with DFLTCC support: + + $ CFLAGS=-DDFLTCC ./configure + $ make OBJA=dfltcc.o PIC_OBJA=dfltcc.lo +*/ + +#include +#include +#include +#include +#include +#include +#include "../../zutil.h" +#include "../../deflate.h" +#include "../../inftrees.h" +#include "../../inflate.h" +#include "dfltcc.h" +#include "dfltcc_deflate.h" +#ifdef DFLTCC_USDT +#include +#endif + +/* + C wrapper for the DEFLATE CONVERSION CALL instruction. + */ +typedef enum { + DFLTCC_CC_OK = 0, + DFLTCC_CC_OP1_TOO_SHORT = 1, + DFLTCC_CC_OP2_TOO_SHORT = 2, + DFLTCC_CC_OP2_CORRUPT = 2, + DFLTCC_CC_AGAIN = 3, +} dfltcc_cc; + +#define DFLTCC_QAF 0 +#define DFLTCC_GDHT 1 +#define DFLTCC_CMPR 2 +#define DFLTCC_XPND 4 +#define HBT_CIRCULAR (1 << 7) +#define HB_BITS 15 +#define HB_SIZE (1 << HB_BITS) +#define DFLTCC_FACILITY 151 + +local inline dfltcc_cc dfltcc OF((int fn, void *param, + Bytef **op1, size_t *len1, + z_const Bytef **op2, size_t *len2, + void *hist)); +local inline dfltcc_cc dfltcc(fn, param, op1, len1, op2, len2, hist) + int fn; + void *param; + Bytef **op1; + size_t *len1; + z_const Bytef **op2; + size_t *len2; + void *hist; +{ + Bytef *t2 = op1 ? *op1 : NULL; + size_t t3 = len1 ? *len1 : 0; + z_const Bytef *t4 = op2 ? *op2 : NULL; + size_t t5 = len2 ? *len2 : 0; + register int r0 __asm__("r0") = fn; + register void *r1 __asm__("r1") = param; + register Bytef *r2 __asm__("r2") = t2; + register size_t r3 __asm__("r3") = t3; + register z_const Bytef *r4 __asm__("r4") = t4; + register size_t r5 __asm__("r5") = t5; + int cc; + + __asm__ volatile( +#ifdef DFLTCC_USDT + STAP_PROBE_ASM(zlib, dfltcc_entry, + STAP_PROBE_ASM_TEMPLATE(5)) +#endif + ".insn rrf,0xb9390000,%[r2],%[r4],%[hist],0\n" +#ifdef DFLTCC_USDT + STAP_PROBE_ASM(zlib, dfltcc_exit, + STAP_PROBE_ASM_TEMPLATE(5)) +#endif + "ipm %[cc]\n" + : [r2] "+r" (r2) + , [r3] "+r" (r3) + , [r4] "+r" (r4) + , [r5] "+r" (r5) + , [cc] "=r" (cc) + : [r0] "r" (r0) + , [r1] "r" (r1) + , [hist] "r" (hist) +#ifdef DFLTCC_USDT + , STAP_PROBE_ASM_OPERANDS(5, r2, r3, r4, r5, hist) +#endif + : "cc", "memory"); + t2 = r2; t3 = r3; t4 = r4; t5 = r5; + + if (op1) + *op1 = t2; + if (len1) + *len1 = t3; + if (op2) + *op2 = t4; + if (len2) + *len2 = t5; + return (cc >> 28) & 3; +} + +/* + Parameter Block for Query Available Functions. + */ +#define static_assert(c, msg) \ + __attribute__((unused)) \ + static char static_assert_failed_ ## msg[c ? 1 : -1] + +struct dfltcc_qaf_param { + char fns[16]; + char reserved1[8]; + char fmts[2]; + char reserved2[6]; +}; + +static_assert(sizeof(struct dfltcc_qaf_param) == 32, + sizeof_struct_dfltcc_qaf_param_is_32); + +local inline int is_bit_set OF((const char *bits, int n)); +local inline int is_bit_set(bits, n) + const char *bits; + int n; +{ + return bits[n / 8] & (1 << (7 - (n % 8))); +} + +local inline void clear_bit OF((char *bits, int n)); +local inline void clear_bit(bits, n) + char *bits; + int n; +{ + bits[n / 8] &= ~(1 << (7 - (n % 8))); +} + +#define DFLTCC_FMT0 0 + +/* + Parameter Block for Generate Dynamic-Huffman Table, Compress and Expand. + */ +#define CVT_CRC32 0 +#define CVT_ADLER32 1 +#define HTT_FIXED 0 +#define HTT_DYNAMIC 1 + +struct dfltcc_param_v0 { + uint16_t pbvn; /* Parameter-Block-Version Number */ + uint8_t mvn; /* Model-Version Number */ + uint8_t ribm; /* Reserved for IBM use */ + unsigned reserved32 : 31; + unsigned cf : 1; /* Continuation Flag */ + uint8_t reserved64[8]; + unsigned nt : 1; /* New Task */ + unsigned reserved129 : 1; + unsigned cvt : 1; /* Check Value Type */ + unsigned reserved131 : 1; + unsigned htt : 1; /* Huffman-Table Type */ + unsigned bcf : 1; /* Block-Continuation Flag */ + unsigned bcc : 1; /* Block Closing Control */ + unsigned bhf : 1; /* Block Header Final */ + unsigned reserved136 : 1; + unsigned reserved137 : 1; + unsigned dhtgc : 1; /* DHT Generation Control */ + unsigned reserved139 : 5; + unsigned reserved144 : 5; + unsigned sbb : 3; /* Sub-Byte Boundary */ + uint8_t oesc; /* Operation-Ending-Supplemental Code */ + unsigned reserved160 : 12; + unsigned ifs : 4; /* Incomplete-Function Status */ + uint16_t ifl; /* Incomplete-Function Length */ + uint8_t reserved192[8]; + uint8_t reserved256[8]; + uint8_t reserved320[4]; + uint16_t hl; /* History Length */ + unsigned reserved368 : 1; + uint16_t ho : 15; /* History Offset */ + uint32_t cv; /* Check Value */ + unsigned eobs : 15; /* End-of-block Symbol */ + unsigned reserved431: 1; + uint8_t eobl : 4; /* End-of-block Length */ + unsigned reserved436 : 12; + unsigned reserved448 : 4; + uint16_t cdhtl : 12; /* Compressed-Dynamic-Huffman Table + Length */ + uint8_t reserved464[6]; + uint8_t cdht[288]; + uint8_t reserved[32]; + uint8_t csb[1152]; +}; + +static_assert(sizeof(struct dfltcc_param_v0) == 1536, + sizeof_struct_dfltcc_param_v0_is_1536); + +local z_const char *oesc_msg OF((char *buf, int oesc)); +local z_const char *oesc_msg(buf, oesc) + char *buf; + int oesc; +{ + if (oesc == 0x00) + return NULL; /* Successful completion */ + else { + sprintf(buf, "Operation-Ending-Supplemental Code is 0x%.2X", oesc); + return buf; + } +} + +/* + Extension of inflate_state and deflate_state. Must be doubleword-aligned. +*/ +struct dfltcc_state { + struct dfltcc_param_v0 param; /* Parameter block. */ + struct dfltcc_qaf_param af; /* Available functions. */ + uLong level_mask; /* Levels on which to use DFLTCC */ + uLong block_size; /* New block each X bytes */ + uLong block_threshold; /* New block after total_in > X */ + uLong dht_threshold; /* New block only if avail_in >= X */ + char msg[64]; /* Buffer for strm->msg */ +}; + +#define GET_DFLTCC_STATE(state) ((struct dfltcc_state FAR *)((state) + 1)) + +/* + Compress. + */ +local inline int dfltcc_are_params_ok(int level, + uInt window_bits, + int strategy, + uLong level_mask); +local inline int dfltcc_are_params_ok(level, window_bits, strategy, level_mask) + int level; + uInt window_bits; + int strategy; + uLong level_mask; +{ + return (level_mask & (1 << level)) != 0 && + (window_bits == HB_BITS) && + (strategy == Z_FIXED || strategy == Z_DEFAULT_STRATEGY); +} + + +int ZLIB_INTERNAL dfltcc_can_deflate(strm) + z_streamp strm; +{ + deflate_state FAR *state = (deflate_state FAR *)strm->state; + struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state); + + /* Unsupported compression settings */ + if (!dfltcc_are_params_ok(state->level, state->w_bits, state->strategy, + dfltcc_state->level_mask)) + return 0; + + /* Unsupported hardware */ + if (!is_bit_set(dfltcc_state->af.fns, DFLTCC_GDHT) || + !is_bit_set(dfltcc_state->af.fns, DFLTCC_CMPR) || + !is_bit_set(dfltcc_state->af.fmts, DFLTCC_FMT0)) + return 0; + + return 1; +} + +local void dfltcc_gdht OF((z_streamp strm)); +local void dfltcc_gdht(strm) + z_streamp strm; +{ + deflate_state FAR *state = (deflate_state FAR *)strm->state; + struct dfltcc_param_v0 FAR *param = &GET_DFLTCC_STATE(state)->param; + size_t avail_in = avail_in = strm->avail_in; + + dfltcc(DFLTCC_GDHT, + param, NULL, NULL, + &strm->next_in, &avail_in, NULL); +} + +local dfltcc_cc dfltcc_cmpr OF((z_streamp strm)); +local dfltcc_cc dfltcc_cmpr(strm) + z_streamp strm; +{ + deflate_state FAR *state = (deflate_state FAR *)strm->state; + struct dfltcc_param_v0 FAR *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_CMPR | HBT_CIRCULAR, + param, &strm->next_out, &avail_out, + &strm->next_in, &avail_in, state->window); + strm->total_in += (strm->avail_in - avail_in); + strm->total_out += (strm->avail_out - avail_out); + strm->avail_in = avail_in; + strm->avail_out = avail_out; + return cc; +} + +local void send_eobs OF((z_streamp strm, + z_const struct dfltcc_param_v0 FAR *param)); +local void send_eobs(strm, param) + z_streamp strm; + z_const struct dfltcc_param_v0 FAR *param; +{ + deflate_state FAR *state = (deflate_state FAR *)strm->state; + + _tr_send_bits( + state, + bi_reverse(param->eobs >> (15 - param->eobl), param->eobl), + param->eobl); + flush_pending(strm); +#ifdef ZLIB_DEBUG + state->compressed_len += param->eobl; +#endif +} + +int ZLIB_INTERNAL dfltcc_deflate(strm, flush, result) + z_streamp strm; + int flush; + block_state *result; +{ + deflate_state FAR *state = (deflate_state FAR *)strm->state; + struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state); + struct dfltcc_param_v0 FAR *param = &dfltcc_state->param; + uInt masked_avail_in; + dfltcc_cc cc; + int need_empty_block; + int soft_bcc; + int no_flush; + + if (!dfltcc_can_deflate(strm)) + return 0; + +again: + masked_avail_in = 0; + soft_bcc = 0; + no_flush = flush == Z_NO_FLUSH; + + /* Trailing empty block. Switch to software, except when Continuation Flag + * is set, which means that DFLTCC has buffered some output in the + * parameter block and needs to be called again in order to flush it. + */ + if (flush == Z_FINISH && strm->avail_in == 0 && !param->cf) { + if (param->bcf) { + /* A block is still open, and the hardware does not support closing + * blocks without adding data. Thus, close it manually. + */ + send_eobs(strm, param); + param->bcf = 0; + param->bcc = 0; + } + return 0; + } + + if (strm->avail_in == 0 && !param->cf) { + *result = need_more; + return 1; + } + + /* There is an open non-BFINAL block, we are not going to close it just + * yet, we have compressed more than DFLTCC_BLOCK_SIZE bytes and we see + * more than DFLTCC_DHT_MIN_SAMPLE_SIZE bytes. Open a new block with a new + * DHT in order to adapt to a possibly changed input data distribution. + */ + if (param->bcf && no_flush && + strm->total_in > dfltcc_state->block_threshold && + strm->avail_in >= dfltcc_state->dht_threshold) { + if (param->cf) { + /* We need to flush the DFLTCC buffer before writing the + * End-of-block Symbol. Mask the input data and proceed as usual. + */ + masked_avail_in += strm->avail_in; + strm->avail_in = 0; + no_flush = 0; + } else { + /* DFLTCC buffer is empty, so we can manually write the + * End-of-block Symbol right away. + */ + send_eobs(strm, param); + param->bcf = 0; + param->bcc = 0; + dfltcc_state->block_threshold = + strm->total_in + dfltcc_state->block_size; + if (strm->avail_out == 0) { + *result = need_more; + return 1; + } + } + } + + /* The caller gave us too much data. Pass only one block worth of + * uncompressed data to DFLTCC and mask the rest, so that on the next + * iteration we start a new block. + */ + if (no_flush && strm->avail_in > dfltcc_state->block_size) { + masked_avail_in += (strm->avail_in - dfltcc_state->block_size); + strm->avail_in = dfltcc_state->block_size; + } + + /* When we have an open non-BFINAL deflate block and caller indicates that + * the stream is ending, we need to close an open deflate block and open a + * BFINAL one. + */ + need_empty_block = flush == Z_FINISH && param->bcf && !param->bhf; + + /* Translate stream to parameter block */ + param->cvt = state->wrap == 2 ? CVT_CRC32 : CVT_ADLER32; + if (!no_flush) { + /* We need to close a block */ + if (param->bcc) { + /* We have already asked the hardware to do this */ + } else if (strm->avail_in == 0) + /* There is no input data, so the hardware will not nohor our + * request. Close the block manually. + */ + soft_bcc = 1; + else + /* The hardware will honor our request. Set Block Closing Control + * until the block ends. + */ + param->bcc = 1; + } + if (flush == Z_FINISH && !param->bcf) + /* We are about to open a BFINAL block, set Block Header Final bit + * until the stream ends. + */ + param->bhf = 1; + /* DFLTCC-CMPR will write to next_out, so make sure that buffers with + * higher precedence are empty. + */ + Assert(state->pending == 0, "There must be no pending bytes"); + Assert(state->bi_valid < 8, "There must be less than 8 pending bits"); + param->sbb = (unsigned int)state->bi_valid; + if (param->sbb > 0) + *strm->next_out = (Bytef)state->bi_buf; + if (param->hl) + param->nt = 0; /* Honor history */ + param->cv = state->wrap == 2 ? ZSWAP32(strm->adler) : strm->adler; + + /* When opening a block, choose a Huffman-Table Type */ + if (!param->bcf) { + if (state->strategy == Z_FIXED || + (strm->total_in == 0 && dfltcc_state->block_threshold > 0)) + param->htt = HTT_FIXED; + else { + param->htt = HTT_DYNAMIC; + dfltcc_gdht(strm); + } + } + + /* Deflate */ + do { + cc = dfltcc_cmpr(strm); + if (strm->avail_in < 4096 && masked_avail_in > 0) + /* We are about to call DFLTCC with a small input buffer, which is + * inefficient. Since there is masked data, there will be at least + * one more DFLTCC call, so skip the current one and make the next + * one handle more data. + */ + break; + } while (cc == DFLTCC_CC_AGAIN); + + /* Translate parameter block to stream */ + strm->msg = oesc_msg(dfltcc_state->msg, param->oesc); + state->bi_valid = param->sbb; + if (state->bi_valid == 0) + state->bi_buf = 0; /* Avoid accessing next_out */ + else + state->bi_buf = *strm->next_out & ((1 << state->bi_valid) - 1); + strm->adler = state->wrap == 2 ? ZSWAP32(param->cv) : param->cv; + + /* Unmask the input data */ + strm->avail_in += masked_avail_in; + masked_avail_in = 0; + + /* If we encounter an error, it means there is a bug in DFLTCC call */ + Assert(cc != DFLTCC_CC_OP2_CORRUPT || param->oesc == 0, "BUG"); + + /* Update Block-Continuation Flag. It will be used to check whether to call + * GDHT the next time. + */ + if (cc == DFLTCC_CC_OK) { + if (soft_bcc) + send_eobs(strm, param); + if (param->bcc || soft_bcc) { + param->bcf = 0; + dfltcc_state->block_threshold = + strm->total_in + dfltcc_state->block_size; + } else + param->bcf = 1; + param->bcc = 0; + if (flush == Z_FINISH) { + if (need_empty_block) + /* Make the current deflate() call also close the stream */ + return 0; + else { + bi_windup(state); + *result = finish_done; + } + } else { + if (flush == Z_FULL_FLUSH) + param->hl = 0; /* Clear history */ + *result = flush == Z_NO_FLUSH ? need_more : block_done; + } + } else { + param->bcf = 1; + *result = need_more; + } + if (strm->avail_in != 0 && strm->avail_out != 0) + goto again; /* deflate() must use all input or all output */ + return 1; +} + +/* + Expand. + */ +int ZLIB_INTERNAL dfltcc_can_inflate(strm) + z_streamp strm; +{ + struct inflate_state FAR *state = (struct inflate_state FAR *)strm->state; + struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state); + + /* 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); +} + +local dfltcc_cc dfltcc_xpnd OF((z_streamp strm)); +local dfltcc_cc dfltcc_xpnd(strm) + z_streamp strm; +{ + struct inflate_state FAR *state = (struct inflate_state FAR *)strm->state; + struct dfltcc_param_v0 FAR *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 ZLIB_INTERNAL dfltcc_inflate(strm, flush, ret) + z_streamp strm; + int flush; + int *ret; +{ + struct inflate_state FAR *state = (struct inflate_state FAR *)strm->state; + struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state); + struct dfltcc_param_v0 FAR *param = &dfltcc_state->param; + dfltcc_cc cc; + + if (flush == Z_BLOCK || flush == Z_TREES) { + /* 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 (inflate_ensure_window(state)) { + state->mode = MEM; + return DFLTCC_INFLATE_CONTINUE; + } + + /* Translate stream to parameter block */ + param->cvt = state->flags ? CVT_CRC32 : CVT_ADLER32; + param->sbb = state->bits; + param->hl = state->whave; /* Software and hardware history formats match */ + param->ho = (state->wnext - state->whave) & ((1 << HB_BITS) - 1); + if (param->hl) + param->nt = 0; /* Honor history for the first block */ + 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; + state->whave = param->hl; + state->wnext = (param->ho + param->hl) & ((1 << HB_BITS) - 1); + 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 ZLIB_INTERNAL dfltcc_was_inflate_used(strm) + z_streamp strm; +{ + struct inflate_state FAR *state = (struct inflate_state FAR *)strm->state; + struct dfltcc_param_v0 FAR *param = &GET_DFLTCC_STATE(state)->param; + + return !param->nt; +} + +int ZLIB_INTERNAL dfltcc_inflate_disable(strm) + z_streamp strm; +{ + struct inflate_state FAR *state = (struct inflate_state FAR *)strm->state; + struct dfltcc_state FAR *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; +} + +/* + Memory management. + + DFLTCC requires parameter blocks and window to be aligned. zlib allows + users to specify their own allocation functions, so using e.g. + `posix_memalign' is not an option. Thus, we overallocate and take the + aligned portion of the buffer. +*/ +local inline int is_dfltcc_enabled OF((void)); +local inline int is_dfltcc_enabled(void) +{ + const char *env; + uint64_t facilities[(DFLTCC_FACILITY / 64) + 1]; + register int r0 __asm__("r0"); + + env = getenv("DFLTCC"); + if (env && !strcmp(env, "0")) + /* User has explicitly disabled DFLTCC. */ + return 0; + + r0 = sizeof(facilities) / sizeof(facilities[0]); + __asm__ volatile("stfle %[facilities]\n" + : [facilities] "=Q" (facilities) + : [r0] "r" (r0) + : "cc", "memory"); + return is_bit_set((const char *)facilities, DFLTCC_FACILITY); +} + +void ZLIB_INTERNAL dfltcc_reset(strm, size) + z_streamp strm; + uInt size; +{ + struct dfltcc_state *dfltcc_state = + (struct dfltcc_state *)((char FAR *)strm->state + size); + struct dfltcc_qaf_param *param = + (struct dfltcc_qaf_param *)&dfltcc_state->param; + const char *s; + + /* Initialize available functions */ + if (is_dfltcc_enabled()) { + dfltcc(DFLTCC_QAF, param, NULL, NULL, NULL, NULL, NULL); + memmove(&dfltcc_state->af, param, sizeof(dfltcc_state->af)); + } else + memset(&dfltcc_state->af, 0, sizeof(dfltcc_state->af)); + + if (getenv("SOURCE_DATE_EPOCH")) + /* User needs reproducible results, but the output of DFLTCC_CMPR + * depends on buffers' page offsets. + */ + clear_bit(dfltcc_state->af.fns, DFLTCC_CMPR); + + /* Initialize parameter block */ + memset(&dfltcc_state->param, 0, sizeof(dfltcc_state->param)); + dfltcc_state->param.nt = 1; + + /* Initialize tuning parameters */ +#ifndef DFLTCC_LEVEL_MASK +#define DFLTCC_LEVEL_MASK 0x2 +#endif + s = getenv("DFLTCC_LEVEL_MASK"); + dfltcc_state->level_mask = (s && *s) ? strtoul(s, NULL, 0) : + DFLTCC_LEVEL_MASK; +#ifndef DFLTCC_BLOCK_SIZE +#define DFLTCC_BLOCK_SIZE 1048576 +#endif + s = getenv("DFLTCC_BLOCK_SIZE"); + dfltcc_state->block_size = (s && *s) ? strtoul(s, NULL, 0) : + DFLTCC_BLOCK_SIZE; +#ifndef DFLTCC_FIRST_FHT_BLOCK_SIZE +#define DFLTCC_FIRST_FHT_BLOCK_SIZE 4096 +#endif + s = getenv("DFLTCC_FIRST_FHT_BLOCK_SIZE"); + dfltcc_state->block_threshold = (s && *s) ? strtoul(s, NULL, 0) : + DFLTCC_FIRST_FHT_BLOCK_SIZE; +#ifndef DFLTCC_DHT_MIN_SAMPLE_SIZE +#define DFLTCC_DHT_MIN_SAMPLE_SIZE 4096 +#endif + s = getenv("DFLTCC_DHT_MIN_SAMPLE_SIZE"); + dfltcc_state->dht_threshold = (s && *s) ? strtoul(s, NULL, 0) : + DFLTCC_DHT_MIN_SAMPLE_SIZE; +#ifndef DFLTCC_RIBM +#define DFLTCC_RIBM 0 +#endif + s = getenv("DFLTCC_RIBM"); + dfltcc_state->param.ribm = (s && *s) ? strtoul(s, NULL, 0) : + DFLTCC_RIBM; +} + +voidpf ZLIB_INTERNAL dfltcc_alloc_state(strm, items, size) + z_streamp strm; + uInt items; + uInt size; +{ + Assert((items * size) % 8 == 0, + "The size of zlib state must be a multiple of 8"); + return ZALLOC(strm, + items * size + sizeof(struct dfltcc_state), + sizeof(unsigned char)); +} + +void ZLIB_INTERNAL dfltcc_copy_state(dst, src, size) + voidpf dst; + const voidpf src; + uInt size; +{ + zmemcpy(dst, src, size + sizeof(struct dfltcc_state)); +} + +static const int PAGE_ALIGN = 0x1000; + +#define ALIGN_UP(p, size) \ + (__typeof__(p))(((uintptr_t)(p) + ((size) - 1)) & ~((size) - 1)) + +voidpf ZLIB_INTERNAL dfltcc_alloc_window(strm, items, size) + z_streamp strm; + uInt items; + uInt size; +{ + voidpf p, w; + + /* To simplify freeing, we store the pointer to the allocated buffer right + * before the window. + */ + p = ZALLOC(strm, sizeof(voidpf) + items * size + PAGE_ALIGN, + sizeof(unsigned char)); + if (p == NULL) + return NULL; + w = ALIGN_UP((char FAR *)p + sizeof(voidpf), PAGE_ALIGN); + *(voidpf *)((char FAR *)w - sizeof(voidpf)) = p; + return w; +} + +void ZLIB_INTERNAL dfltcc_free_window(strm, w) + z_streamp strm; + voidpf w; +{ + if (w) + ZFREE(strm, *(voidpf *)((unsigned char FAR *)w - sizeof(voidpf))); +} + +/* + Switching between hardware and software compression. + + DFLTCC does not support all zlib settings, e.g. generation of non-compressed + blocks or alternative window sizes. When such settings are applied on the + fly with deflateParams, we need to convert between hardware and software + window formats. +*/ +int ZLIB_INTERNAL dfltcc_deflate_params(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state FAR *state = (deflate_state FAR *)strm->state; + struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state); + struct dfltcc_param_v0 FAR *param = &dfltcc_state->param; + int could_deflate = dfltcc_can_deflate(strm); + int can_deflate = dfltcc_are_params_ok(level, state->w_bits, strategy, + dfltcc_state->level_mask); + + if (can_deflate == could_deflate) + /* We continue to work in the same mode - no changes needed */ + return Z_OK; + + if (strm->total_in == 0 && param->nt == 1 && param->hl == 0) + /* DFLTCC was not used yet - no changes needed */ + return Z_OK; + + /* Switching between hardware and software is not implemented */ + return Z_STREAM_ERROR; +} + +/* + Preloading history. +*/ +local void append_history OF((struct dfltcc_param_v0 FAR *param, + Bytef *history, + const Bytef *buf, + uInt count)); +local void append_history(param, history, buf, count) + struct dfltcc_param_v0 FAR *param; + Bytef *history; + const Bytef *buf; + uInt count; +{ + size_t offset; + size_t n; + + /* Do not use more than 32K */ + if (count > HB_SIZE) { + buf += count - HB_SIZE; + count = HB_SIZE; + } + offset = (param->ho + param->hl) % HB_SIZE; + if (offset + count <= HB_SIZE) + /* Circular history buffer does not wrap - copy one chunk */ + zmemcpy(history + offset, buf, count); + else { + /* Circular history buffer wraps - copy two chunks */ + n = HB_SIZE - offset; + zmemcpy(history + offset, buf, n); + zmemcpy(history, buf + n, count - n); + } + n = param->hl + count; + if (n <= HB_SIZE) + /* All history fits into buffer - no need to discard anything */ + param->hl = n; + else { + /* History does not fit into buffer - discard extra bytes */ + param->ho = (param->ho + (n - HB_SIZE)) % HB_SIZE; + param->hl = HB_SIZE; + } +} + +int ZLIB_INTERNAL dfltcc_deflate_set_dictionary(strm, dictionary, dict_length) + z_streamp strm; + const Bytef *dictionary; + uInt dict_length; +{ + deflate_state FAR *state = (deflate_state FAR *)strm->state; + struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state); + struct dfltcc_param_v0 FAR *param = &dfltcc_state->param; + + append_history(param, state->window, dictionary, dict_length); + state->strstart = 1; /* Add FDICT to zlib header */ + return Z_OK; +} + +int ZLIB_INTERNAL dfltcc_deflate_get_dictionary(strm, dictionary, dict_length) + z_streamp strm; + Bytef *dictionary; + uInt *dict_length; +{ + deflate_state FAR *state = (deflate_state FAR *)strm->state; + struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state); + struct dfltcc_param_v0 FAR *param = &dfltcc_state->param; + + if (dictionary) { + if (param->ho + param->hl <= HB_SIZE) + /* Circular history buffer does not wrap - copy one chunk */ + zmemcpy(dictionary, state->window + param->ho, param->hl); + else + /* Circular history buffer wraps - copy two chunks */ + zmemcpy(dictionary, state->window + param->ho, HB_SIZE - param->ho); + zmemcpy(dictionary + HB_SIZE - param->ho, + state->window, + param->ho + param->hl - HB_SIZE); + } + if (dict_length) + *dict_length = param->hl; + return Z_OK; +} diff --git a/contrib/s390/dfltcc.h b/contrib/s390/dfltcc.h new file mode 100644 index 0000000000..344e89802e --- /dev/null +++ b/contrib/s390/dfltcc.h @@ -0,0 +1,78 @@ +#ifndef DFLTCC_H +#define DFLTCC_H + +#include "../../zlib.h" +#include "../../zutil.h" + +voidpf ZLIB_INTERNAL dfltcc_alloc_state OF((z_streamp strm, uInt items, + uInt size)); +void ZLIB_INTERNAL dfltcc_copy_state OF((voidpf dst, const voidpf src, + uInt size)); +void ZLIB_INTERNAL dfltcc_reset OF((z_streamp strm, uInt size)); +voidpf ZLIB_INTERNAL dfltcc_alloc_window OF((z_streamp strm, uInt items, + uInt size)); +void ZLIB_INTERNAL dfltcc_free_window OF((z_streamp strm, voidpf w)); +int ZLIB_INTERNAL dfltcc_can_inflate OF((z_streamp strm)); +typedef enum { + DFLTCC_INFLATE_CONTINUE, + DFLTCC_INFLATE_BREAK, + DFLTCC_INFLATE_SOFTWARE, +} dfltcc_inflate_action; +dfltcc_inflate_action ZLIB_INTERNAL dfltcc_inflate OF((z_streamp strm, + int flush, int *ret)); +int ZLIB_INTERNAL dfltcc_was_inflate_used OF((z_streamp strm)); +int ZLIB_INTERNAL dfltcc_inflate_disable OF((z_streamp strm)); + +#undef ZALLOC_STATE +#define ZALLOC_STATE dfltcc_alloc_state + +#undef ZFREE_STATE +#define ZFREE_STATE ZFREE + +#undef ZCOPY_STATE +#define ZCOPY_STATE dfltcc_copy_state + +#undef ZALLOC_WINDOW +#define ZALLOC_WINDOW dfltcc_alloc_window + +#undef ZFREE_WINDOW +#define ZFREE_WINDOW dfltcc_free_window + +#undef TRY_FREE_WINDOW +#define TRY_FREE_WINDOW dfltcc_free_window + +#undef INFLATE_RESET_KEEP_HOOK +#define INFLATE_RESET_KEEP_HOOK(strm) \ + dfltcc_reset((strm), sizeof(struct inflate_state)) + +#undef INFLATE_PRIME_HOOK +#define INFLATE_PRIME_HOOK(strm, bits, value) \ + do { if (dfltcc_inflate_disable((strm))) return Z_STREAM_ERROR; } while (0) + +#undef INFLATE_TYPEDO_HOOK +#define INFLATE_TYPEDO_HOOK(strm, flush) \ + if (dfltcc_can_inflate((strm))) { \ + dfltcc_inflate_action action; \ +\ + RESTORE(); \ + action = dfltcc_inflate((strm), (flush), &ret); \ + LOAD(); \ + if (action == DFLTCC_INFLATE_CONTINUE) \ + break; \ + else if (action == DFLTCC_INFLATE_BREAK) \ + goto inf_leave; \ + } + +#undef INFLATE_NEED_CHECKSUM +#define INFLATE_NEED_CHECKSUM(strm) (!dfltcc_can_inflate((strm))) + +#undef INFLATE_NEED_UPDATEWINDOW +#define INFLATE_NEED_UPDATEWINDOW(strm) (!dfltcc_can_inflate((strm))) + +#undef INFLATE_MARK_HOOK +#define INFLATE_MARK_HOOK(strm) \ + do { \ + if (dfltcc_was_inflate_used((strm))) return -(1L << 16); \ + } while (0) + +#endif diff --git a/contrib/s390/dfltcc_deflate.h b/contrib/s390/dfltcc_deflate.h new file mode 100644 index 0000000000..37dd87a684 --- /dev/null +++ b/contrib/s390/dfltcc_deflate.h @@ -0,0 +1,65 @@ +#ifndef DFLTCC_DEFLATE_H +#define DFLTCC_DEFLATE_H + +#include "dfltcc.h" + +int ZLIB_INTERNAL dfltcc_can_deflate OF((z_streamp strm)); +int ZLIB_INTERNAL dfltcc_deflate OF((z_streamp strm, + int flush, + block_state *result)); +int ZLIB_INTERNAL dfltcc_deflate_params OF((z_streamp strm, + int level, + int strategy)); +int ZLIB_INTERNAL dfltcc_deflate_set_dictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dict_length)); +int ZLIB_INTERNAL dfltcc_deflate_get_dictionary OF((z_streamp strm, + Bytef *dictionary, + uInt* dict_length)); + +#undef DEFLATE_SET_DICTIONARY_HOOK +#define DEFLATE_SET_DICTIONARY_HOOK(strm, dict, dict_len) \ + do { \ + if (dfltcc_can_deflate((strm))) \ + return dfltcc_deflate_set_dictionary((strm), (dict), (dict_len)); \ + } while (0) + +#undef DEFLATE_GET_DICTIONARY_HOOK +#define DEFLATE_GET_DICTIONARY_HOOK(strm, dict, dict_len) \ + do { \ + if (dfltcc_can_deflate((strm))) \ + return dfltcc_deflate_get_dictionary((strm), (dict), (dict_len)); \ + } while (0) + +#undef DEFLATE_RESET_KEEP_HOOK +#define DEFLATE_RESET_KEEP_HOOK(strm) \ + dfltcc_reset((strm), sizeof(deflate_state)) + +#undef DEFLATE_PARAMS_HOOK +#define DEFLATE_PARAMS_HOOK(strm, level, strategy) \ + do { \ + int err; \ +\ + err = dfltcc_deflate_params((strm), (level), (strategy)); \ + if (err == Z_STREAM_ERROR) \ + return err; \ + } while (0) + +#undef DEFLATE_BOUND_ADJUST_COMPLEN +#define DEFLATE_BOUND_ADJUST_COMPLEN(strm, complen, source_len) \ + do { \ + if (dfltcc_can_deflate((strm))) \ + (complen) = (3 + 5 + 5 + 4 + 19 * 3 + (286 + 30) * 7 + \ + (source_len) * 16 + 15 + 7) >> 3; \ + } while (0) + +#undef DEFLATE_NEED_CONSERVATIVE_BOUND +#define DEFLATE_NEED_CONSERVATIVE_BOUND(strm) (dfltcc_can_deflate((strm))) + +#undef DEFLATE_HOOK +#define DEFLATE_HOOK dfltcc_deflate + +#undef DEFLATE_NEED_CHECKSUM +#define DEFLATE_NEED_CHECKSUM(strm) (!dfltcc_can_deflate((strm))) + +#endif diff --git a/deflate.c b/deflate.c index 23aef18788..16024abf5f 100644 --- a/deflate.c +++ b/deflate.c @@ -61,15 +61,29 @@ const char deflate_copyright[] = */ /* =========================================================================== - * Function prototypes. + * Architecture-specific bits. */ -typedef enum { - need_more, /* block not completed, need more input or more output */ - block_done, /* block flush performed */ - finish_started, /* finish started, need only more output at next deflate */ - finish_done /* finish done, accept no more input or output */ -} block_state; +#define ZALLOC_STATE ZALLOC +#define ZFREE_STATE ZFREE +#define ZCOPY_STATE zmemcpy +#define ZALLOC_WINDOW ZALLOC +#define TRY_FREE_WINDOW TRY_FREE +#define DEFLATE_SET_DICTIONARY_HOOK(strm, dict, dict_len) do {} while (0) +#define DEFLATE_GET_DICTIONARY_HOOK(strm, dict, dict_len) do {} while (0) +#define DEFLATE_RESET_KEEP_HOOK(strm) do {} while (0) +#define DEFLATE_PARAMS_HOOK(strm, level, strategy) do {} while (0) +#define DEFLATE_BOUND_ADJUST_COMPLEN(strm, complen, sourceLen) do {} while (0) +#define DEFLATE_NEED_CONSERVATIVE_BOUND(strm) 0 +#define DEFLATE_HOOK(strm, flush, bstate) 0 +#define DEFLATE_NEED_CHECKSUM(strm) 1 + +#ifdef DFLTCC +# include "contrib/s390/dfltcc_deflate.h" +#endif +/* =========================================================================== + * Function prototypes. + */ typedef block_state (*compress_func) OF((deflate_state *s, int flush)); /* Compression function. Returns the block state after the call. */ @@ -85,7 +99,6 @@ local block_state deflate_rle OF((deflate_state *s, int flush)); local block_state deflate_huff OF((deflate_state *s, int flush)); local void lm_init OF((deflate_state *s)); local void putShortMSB OF((deflate_state *s, uInt b)); -local void flush_pending OF((z_streamp strm)); local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); #ifdef ASMV # pragma message("Assembler code may have bugs -- use at your own risk") @@ -299,7 +312,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, return Z_STREAM_ERROR; } if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ - s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + s = (deflate_state *) ZALLOC_STATE(strm, 1, sizeof(deflate_state)); if (s == Z_NULL) return Z_MEM_ERROR; strm->state = (struct internal_state FAR *)s; s->strm = strm; @@ -316,7 +329,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, s->hash_mask = s->hash_size - 1; s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); - s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->window = (Bytef *) ZALLOC_WINDOW(strm, s->w_size, 2*sizeof(Byte)); s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); @@ -434,6 +447,7 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) /* when using zlib wrappers, compute Adler-32 for provided dictionary */ if (wrap == 1) strm->adler = adler32(strm->adler, dictionary, dictLength); + DEFLATE_SET_DICTIONARY_HOOK(strm, dictionary, dictLength); s->wrap = 0; /* avoid computing Adler-32 in read_buf */ /* if dictionary would fill window, just replace the history */ @@ -492,6 +506,7 @@ int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength) if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + DEFLATE_GET_DICTIONARY_HOOK(strm, dictionary, dictLength); s = strm->state; len = s->strstart + s->lookahead; if (len > s->w_size) @@ -538,6 +553,8 @@ int ZEXPORT deflateResetKeep (strm) _tr_init(s); + DEFLATE_RESET_KEEP_HOOK(strm); + return Z_OK; } @@ -625,6 +642,7 @@ int ZEXPORT deflateParams(strm, level, strategy) if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } + DEFLATE_PARAMS_HOOK(strm, level, strategy); func = configuration_table[s->level].func; if ((strategy != s->strategy || func != configuration_table[level].func) && @@ -700,6 +718,7 @@ uLong ZEXPORT deflateBound(strm, sourceLen) /* conservative upper bound for compressed data */ complen = sourceLen + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; + DEFLATE_BOUND_ADJUST_COMPLEN(strm, complen, sourceLen); /* if can't get parameters, return conservative bound plus zlib wrapper */ if (deflateStateCheck(strm)) @@ -741,7 +760,8 @@ uLong ZEXPORT deflateBound(strm, sourceLen) } /* if not default parameters, return conservative bound */ - if (s->w_bits != 15 || s->hash_bits != 8 + 7) + if (DEFLATE_NEED_CONSERVATIVE_BOUND(strm) || + s->w_bits != 15 || s->hash_bits != 8 + 7) return complen + wraplen; /* default settings: return tight bound for that case */ @@ -768,7 +788,7 @@ local void putShortMSB (s, b) * applications may wish to modify it to avoid allocating a large * strm->next_out buffer and copying into it. (See also read_buf()). */ -local void flush_pending(strm) +void ZLIB_INTERNAL flush_pending(strm) z_streamp strm; { unsigned len; @@ -1040,7 +1060,8 @@ int ZEXPORT deflate (strm, flush) (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { block_state bstate; - bstate = s->level == 0 ? deflate_stored(s, flush) : + bstate = DEFLATE_HOOK(strm, flush, &bstate) ? bstate : + s->level == 0 ? deflate_stored(s, flush) : s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : s->strategy == Z_RLE ? deflate_rle(s, flush) : (*(configuration_table[s->level].func))(s, flush); @@ -1129,9 +1150,9 @@ int ZEXPORT deflateEnd (strm) TRY_FREE(strm, strm->state->pending_buf); TRY_FREE(strm, strm->state->head); TRY_FREE(strm, strm->state->prev); - TRY_FREE(strm, strm->state->window); + TRY_FREE_WINDOW(strm, strm->state->window); - ZFREE(strm, strm->state); + ZFREE_STATE(strm, strm->state); strm->state = Z_NULL; return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; @@ -1161,13 +1182,13 @@ int ZEXPORT deflateCopy (dest, source) zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); - ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + ds = (deflate_state *) ZALLOC_STATE(dest, 1, sizeof(deflate_state)); if (ds == Z_NULL) return Z_MEM_ERROR; dest->state = (struct internal_state FAR *) ds; - zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); + ZCOPY_STATE((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); ds->strm = dest; - ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->window = (Bytef *) ZALLOC_WINDOW(dest, ds->w_size, 2*sizeof(Byte)); ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, 4); @@ -1214,7 +1235,8 @@ local unsigned read_buf(strm, buf, size) strm->avail_in -= len; zmemcpy(buf, strm->next_in, len); - if (strm->state->wrap == 1) { + if (!DEFLATE_NEED_CHECKSUM(strm)) {} + else if (strm->state->wrap == 1) { strm->adler = adler32(strm->adler, buf, len); } #ifdef GZIP diff --git a/deflate.h b/deflate.h index d4cf1a98be..79c2057e27 100644 --- a/deflate.h +++ b/deflate.h @@ -299,6 +299,7 @@ void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, int last)); +void ZLIB_INTERNAL _tr_send_bits OF((deflate_state *s, int value, int length)); #define d_code(dist) \ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) @@ -343,4 +344,15 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, flush = _tr_tally(s, distance, length) #endif +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +unsigned ZLIB_INTERNAL bi_reverse OF((unsigned code, int len)); +void ZLIB_INTERNAL bi_windup OF((deflate_state *s)); +void ZLIB_INTERNAL flush_pending OF((z_streamp strm)); + #endif /* DEFLATE_H */ diff --git a/gzguts.h b/gzguts.h index 6378d468a2..7a3ac462da 100644 --- a/gzguts.h +++ b/gzguts.h @@ -153,7 +153,11 @@ /* default i/o buffer size -- double this for output when reading (this and twice this must be able to fit in an unsigned type) */ +#ifdef DFLTCC +#define GZBUFSIZE 131072 +#else #define GZBUFSIZE 8192 +#endif /* gzip modes, also provide a little integrity check on the passed structure */ #define GZ_NONE 0 diff --git a/inflate.c b/inflate.c index 2c1b17f16a..9ee6c52342 100644 --- a/inflate.c +++ b/inflate.c @@ -85,6 +85,23 @@ #include "inflate.h" #include "inffast.h" +/* architecture-specific bits */ +#define ZALLOC_STATE ZALLOC +#define ZFREE_STATE ZFREE +#define ZCOPY_STATE zmemcpy +#define ZALLOC_WINDOW ZALLOC +#define ZFREE_WINDOW ZFREE +#define INFLATE_RESET_KEEP_HOOK(strm) do {} while (0) +#define INFLATE_PRIME_HOOK(strm, bits, value) do {} while (0) +#define INFLATE_TYPEDO_HOOK(strm, flush) do {} while (0) +#define INFLATE_NEED_CHECKSUM(strm) 1 +#define INFLATE_NEED_UPDATEWINDOW(strm) 1 +#define INFLATE_MARK_HOOK(strm) do {} while (0) + +#ifdef DFLTCC +# include "contrib/s390/dfltcc.h" +#endif + #ifdef MAKEFIXED # ifndef BUILDFIXED # define BUILDFIXED @@ -138,6 +155,7 @@ z_streamp strm; state->lencode = state->distcode = state->next = state->codes; state->sane = 1; state->back = -1; + INFLATE_RESET_KEEP_HOOK(strm); Tracev((stderr, "inflate: reset\n")); return Z_OK; } @@ -183,7 +201,7 @@ int windowBits; if (windowBits && (windowBits < 8 || windowBits > 15)) return Z_STREAM_ERROR; if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { - ZFREE(strm, state->window); + ZFREE_WINDOW(strm, state->window); state->window = Z_NULL; } @@ -222,7 +240,7 @@ int stream_size; strm->zfree = zcfree; #endif state = (struct inflate_state FAR *) - ZALLOC(strm, 1, sizeof(struct inflate_state)); + ZALLOC_STATE(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); strm->state = (struct internal_state FAR *)state; @@ -231,7 +249,7 @@ int stream_size; state->mode = HEAD; /* to pass state test in inflateReset2() */ ret = inflateReset2(strm, windowBits); if (ret != Z_OK) { - ZFREE(strm, state); + ZFREE_STATE(strm, state); strm->state = Z_NULL; } return ret; @@ -253,6 +271,7 @@ int value; struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + INFLATE_PRIME_HOOK(strm, bits, value); state = (struct inflate_state FAR *)strm->state; if (bits < 0) { state->hold = 0; @@ -380,6 +399,27 @@ void makefixed() } #endif /* MAKEFIXED */ +int ZLIB_INTERNAL inflate_ensure_window(state) + struct inflate_state *state; +{ + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC_WINDOW(state->strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->wnext = 0; + state->whave = 0; + } + + return 0; +} + /* Update the window with the last wsize (normally 32K) bytes written before returning. If window does not exist yet, create it. This is only called @@ -404,20 +444,7 @@ unsigned copy; state = (struct inflate_state FAR *)strm->state; - /* if it hasn't been done already, allocate space for the window */ - if (state->window == Z_NULL) { - state->window = (unsigned char FAR *) - ZALLOC(strm, 1U << state->wbits, - sizeof(unsigned char)); - if (state->window == Z_NULL) return 1; - } - - /* if window not in use yet, initialize */ - if (state->wsize == 0) { - state->wsize = 1U << state->wbits; - state->wnext = 0; - state->whave = 0; - } + if (inflate_ensure_window(state)) return 1; /* copy state->wsize or less output bytes into the circular window */ if (copy >= state->wsize) { @@ -850,6 +877,7 @@ int flush; case TYPE: if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; case TYPEDO: + INFLATE_TYPEDO_HOOK(strm, flush); if (state->last) { BYTEBITS(); state->mode = CHECK; @@ -1201,7 +1229,7 @@ int flush; out -= left; strm->total_out += out; state->total += out; - if ((state->wrap & 4) && out) + if (INFLATE_NEED_CHECKSUM(strm) && (state->wrap & 4) && out) strm->adler = state->check = UPDATE(state->check, put - out, out); out = left; @@ -1253,8 +1281,9 @@ int flush; */ inf_leave: RESTORE(); - if (state->wsize || (out != strm->avail_out && state->mode < BAD && - (state->mode < CHECK || flush != Z_FINISH))) + if (INFLATE_NEED_UPDATEWINDOW(strm) && + (state->wsize || (out != strm->avail_out && state->mode < BAD && + (state->mode < CHECK || flush != Z_FINISH)))) if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { state->mode = MEM; return Z_MEM_ERROR; @@ -1264,7 +1293,7 @@ int flush; strm->total_in += in; strm->total_out += out; state->total += out; - if ((state->wrap & 4) && out) + if (INFLATE_NEED_CHECKSUM(strm) && (state->wrap & 4) && out) strm->adler = state->check = UPDATE(state->check, strm->next_out - out, out); strm->data_type = (int)state->bits + (state->last ? 64 : 0) + @@ -1282,8 +1311,8 @@ z_streamp strm; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; - if (state->window != Z_NULL) ZFREE(strm, state->window); - ZFREE(strm, strm->state); + if (state->window != Z_NULL) ZFREE_WINDOW(strm, state->window); + ZFREE_STATE(strm, strm->state); strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; @@ -1482,21 +1511,22 @@ z_streamp source; /* allocate space */ copy = (struct inflate_state FAR *) - ZALLOC(source, 1, sizeof(struct inflate_state)); + ZALLOC_STATE(source, 1, sizeof(struct inflate_state)); if (copy == Z_NULL) return Z_MEM_ERROR; window = Z_NULL; if (state->window != Z_NULL) { window = (unsigned char FAR *) - ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + ZALLOC_WINDOW(source, 1U << state->wbits, + sizeof(unsigned char)); if (window == Z_NULL) { - ZFREE(source, copy); + ZFREE_STATE(source, copy); return Z_MEM_ERROR; } } /* copy state */ zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); - zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); + ZCOPY_STATE((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); copy->strm = dest; if (state->lencode >= state->codes && state->lencode <= state->codes + ENOUGH - 1) { @@ -1553,6 +1583,7 @@ z_streamp strm; if (inflateStateCheck(strm)) return -(1L << 16); + INFLATE_MARK_HOOK(strm); state = (struct inflate_state FAR *)strm->state; return (long)(((unsigned long)((long)state->back)) << 16) + (state->mode == COPY ? state->length : diff --git a/inflate.h b/inflate.h index 98679fa9bc..b14e56dd05 100644 --- a/inflate.h +++ b/inflate.h @@ -124,3 +124,5 @@ struct inflate_state { int back; /* bits back of last unprocessed length/lit */ unsigned was; /* initial length of match */ }; + +int ZLIB_INTERNAL inflate_ensure_window OF((struct inflate_state *state)); diff --git a/test/infcover.c b/test/infcover.c index 2be01646ce..a34cd17a69 100644 --- a/test/infcover.c +++ b/test/infcover.c @@ -444,7 +444,7 @@ local void cover_wrap(void) } /* input and output functions for inflateBack() */ -local unsigned pull(void *desc, unsigned char **buf) +local unsigned pull(void *desc, z_const unsigned char **buf) { static unsigned int next = 0; static unsigned char dat[] = {0x63, 0, 2, 0}; diff --git a/test/minigzip.c b/test/minigzip.c index e22fb08c0a..4b5f4efed4 100644 --- a/test/minigzip.c +++ b/test/minigzip.c @@ -132,7 +132,11 @@ static void pwinerror (s) #endif #define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) +#ifdef DFLTCC +#define BUFLEN 262144 +#else #define BUFLEN 16384 +#endif #define MAX_NAME_LEN 1024 #ifdef MAXSEG_64K diff --git a/trees.c b/trees.c index decaeb7c3c..3f749d8306 100644 --- a/trees.c +++ b/trees.c @@ -149,8 +149,6 @@ local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, local void compress_block OF((deflate_state *s, const ct_data *ltree, const ct_data *dtree)); local int detect_data_type OF((deflate_state *s)); -local unsigned bi_reverse OF((unsigned code, int len)); -local void bi_windup OF((deflate_state *s)); local void bi_flush OF((deflate_state *s)); #ifdef GEN_TREES_H @@ -223,6 +221,13 @@ local void send_bits(s, value, length) } #endif /* ZLIB_DEBUG */ +void ZLIB_INTERNAL _tr_send_bits(s, value, length) + deflate_state *s; + int value; + int length; +{ + send_bits(s, value, length); +} /* the arguments must not have side effects */ @@ -1134,7 +1139,7 @@ local int detect_data_type(s) * method would use a table) * IN assertion: 1 <= len <= 15 */ -local unsigned bi_reverse(code, len) +unsigned ZLIB_INTERNAL bi_reverse(code, len) unsigned code; /* the value to invert */ int len; /* its bit length */ { @@ -1166,7 +1171,7 @@ local void bi_flush(s) /* =========================================================================== * Flush the bit buffer and align the output on a byte boundary */ -local void bi_windup(s) +void ZLIB_INTERNAL bi_windup(s) deflate_state *s; { if (s->bi_valid > 8) {