--- a/contrib/s390/dfltcc.c +++ b/contrib/s390/dfltcc.c @@ -539,10 +539,6 @@ int ZLIB_INTERNAL dfltcc_can_inflate(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); @@ -606,8 +602,6 @@ dfltcc_inflate_action ZLIB_INTERNAL dfltcc_inflate(strm, flush, ret) /* 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; @@ -621,8 +615,6 @@ dfltcc_inflate_action ZLIB_INTERNAL dfltcc_inflate(strm, flush, ret) 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); 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 */ @@ -644,11 +636,52 @@ int ZLIB_INTERNAL dfltcc_was_inflate_used(strm) return !param->nt; } +/* + Rotates a circular buffer. + The implementation is based on https://cplusplus.com/reference/algorithm/rotate/ + */ +local void rotate OF((Bytef *start, Bytef *pivot, Bytef *end)); +local void rotate(start, pivot, end) + Bytef *start; + Bytef *pivot; + Bytef *end; +{ + Bytef *p = pivot; + Bytef tmp; + + while (p != start) { + tmp = *start; + *start = *p; + *p = tmp; + + start++; + p++; + + if (p == end) + p = pivot; + else if (start == pivot) + pivot = p; + } +} + +#define MIN(x, y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + _x < _y ? _x : _y; \ +}) + +#define MAX(x, y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + _x > _y ? _x : _y; \ +}) + 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); + struct dfltcc_param_v0 *param = &dfltcc_state->param; if (!dfltcc_can_inflate(strm)) return 0; @@ -660,6 +693,9 @@ int ZLIB_INTERNAL dfltcc_inflate_disable(strm) 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; } @@ -830,9 +866,9 @@ voidpf ZLIB_INTERNAL dfltcc_alloc_window(strm, items, size) voidpf p, w; /* To simplify freeing, we store the pointer to the allocated buffer right - * before the window. + * before the window. Note that DFLTCC always uses HB_SIZE bytes. */ - p = ZALLOC(strm, sizeof(voidpf) + items * size + PAGE_ALIGN, + p = ZALLOC(strm, sizeof(voidpf) + MAX(items * size, HB_SIZE) + PAGE_ALIGN, sizeof(unsigned char)); if (p == NULL) return NULL; @@ -841,6 +877,14 @@ voidpf ZLIB_INTERNAL dfltcc_alloc_window(strm, items, size) return w; } +void ZLIB_INTERNAL dfltcc_copy_window(dest, src, n) + void *dest; + const void *src; + size_t n; +{ + memcpy(dest, src, MAX(n, HB_SIZE)); +} + void ZLIB_INTERNAL dfltcc_free_window(strm, w) z_streamp strm; voidpf w; @@ -951,6 +995,24 @@ local void append_history(param, history, buf, count) } } +local void get_history OF((struct dfltcc_param_v0 FAR *param, + const Bytef *history, + Bytef *buf)); +local void get_history(param, history, buf) + struct dfltcc_param_v0 FAR *param; + const Bytef *history; + Bytef *buf; +{ + if (param->ho + param->hl <= HB_SIZE) + /* Circular history buffer does not wrap - copy one chunk */ + memcpy(buf, history + param->ho, param->hl); + else { + /* Circular history buffer wraps - copy two chunks */ + memcpy(buf, history + param->ho, HB_SIZE - param->ho); + memcpy(buf + HB_SIZE - param->ho, history, param->ho + param->hl - HB_SIZE); + } +} + int ZLIB_INTERNAL dfltcc_deflate_set_dictionary(strm, dictionary, dict_length) z_streamp strm; const Bytef *dictionary; @@ -975,20 +1037,43 @@ int ZLIB_INTERNAL dfltcc_deflate_get_dictionary(strm, dictionary, dict_length) 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 (dictionary) + get_history(param, state->window, dictionary); + if (dict_length) + *dict_length = param->hl; + return Z_OK; +} + +int ZLIB_INTERNAL dfltcc_inflate_set_dictionary(strm, dictionary, dict_length) + z_streamp strm; + const Bytef *dictionary; + uInt dict_length; +{ + 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; + + if (inflate_ensure_window(state)) { + state->mode = MEM; + return Z_MEM_ERROR; } + + append_history(param, state->window, dictionary, dict_length); + state->havedict = 1; + return Z_OK; +} + +int ZLIB_INTERNAL dfltcc_inflate_get_dictionary(strm, dictionary, dict_length) + z_streamp strm; + Bytef *dictionary; + uInt *dict_length; +{ + 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; + + if (dictionary && state->window) + get_history(param, state->window, dictionary); if (dict_length) *dict_length = param->hl; return Z_OK; --- a/contrib/s390/dfltcc.h +++ b/contrib/s390/dfltcc.h @@ -11,6 +11,8 @@ void ZLIB_INTERNAL dfltcc_copy_state OF((voidpf dst, const voidpf src, 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_copy_window OF((void *dest, const void *src, + size_t n)); void ZLIB_INTERNAL dfltcc_free_window OF((z_streamp strm, voidpf w)); #define DFLTCC_BLOCK_HEADER_BITS 3 #define DFLTCC_HLITS_COUNT_BITS 5 @@ -44,11 +46,18 @@ 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)); +int ZLIB_INTERNAL dfltcc_inflate_set_dictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dict_length)); +int ZLIB_INTERNAL dfltcc_inflate_get_dictionary OF((z_streamp strm, + Bytef *dictionary, + uInt* dict_length)); #define ZALLOC_STATE dfltcc_alloc_state #define ZFREE_STATE ZFREE #define ZCOPY_STATE dfltcc_copy_state #define ZALLOC_WINDOW dfltcc_alloc_window +#define ZCOPY_WINDOW dfltcc_copy_window #define ZFREE_WINDOW dfltcc_free_window #define TRY_FREE_WINDOW dfltcc_free_window #define INFLATE_RESET_KEEP_HOOK(strm) \ @@ -77,5 +86,15 @@ int ZLIB_INTERNAL dfltcc_inflate_disable OF((z_streamp strm)); do { \ if (dfltcc_was_inflate_used((strm))) return Z_STREAM_ERROR; \ } while (0) +#define INFLATE_SET_DICTIONARY_HOOK(strm, dict, dict_len) \ + do { \ + if (dfltcc_can_inflate(strm)) \ + return dfltcc_inflate_set_dictionary(strm, dict, dict_len); \ + } while (0) +#define INFLATE_GET_DICTIONARY_HOOK(strm, dict, dict_len) \ + do { \ + if (dfltcc_can_inflate(strm)) \ + return dfltcc_inflate_get_dictionary(strm, dict, dict_len); \ + } while (0) #endif \ No newline at end of file diff --git a/inflate.c b/inflate.c index 3750152..a0e2169 100644 --- a/inflate.c +++ b/inflate.c @@ -93,6 +93,7 @@ #define ZFREE_STATE ZFREE #define ZCOPY_STATE zmemcpy #define ZALLOC_WINDOW ZALLOC +#define ZCOPY_WINDOW zmemcpy #define ZFREE_WINDOW ZFREE #define INFLATE_RESET_KEEP_HOOK(strm) do {} while (0) #define INFLATE_PRIME_HOOK(strm, bits, value) do {} while (0) @@ -101,6 +102,8 @@ #define INFLATE_NEED_UPDATEWINDOW(strm) 1 #define INFLATE_MARK_HOOK(strm) do {} while (0) #define INFLATE_SYNC_POINT_HOOK(strm) do {} while (0) +#define INFLATE_SET_DICTIONARY_HOOK(strm, dict, dict_len) do {} while (0) +#define INFLATE_GET_DICTIONARY_HOOK(strm, dict, dict_len) do {} while (0) #endif #ifdef MAKEFIXED @@ -1330,6 +1333,8 @@ uInt *dictLength; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; + INFLATE_GET_DICTIONARY_HOOK(strm, dictionary, dictLength); + /* copy dictionary */ if (state->whave && dictionary != Z_NULL) { zmemcpy(dictionary, state->window + state->wnext, @@ -1365,6 +1370,8 @@ uInt dictLength; return Z_DATA_ERROR; } + INFLATE_SET_DICTIONARY_HOOK(strm, dictionary, dictLength); + /* copy dictionary to window using updatewindow(), which will amend the existing dictionary if appropriate */ ret = updatewindow(strm, dictionary + dictLength, dictLength); @@ -1529,8 +1536,7 @@ z_streamp source; } copy->next = copy->codes + (state->next - state->codes); if (window != Z_NULL) { - wsize = 1U << state->wbits; - zmemcpy(window, state->window, wsize); + ZCOPY_WINDOW(window, state->window, 1U << state->wbits); } copy->window = window; dest->state = (struct internal_state FAR *)copy;