dfltcc_inflate.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /* dfltcc_inflate.c - IBM Z DEFLATE CONVERSION CALL decompression support. */
  2. /*
  3. Use the following commands to build zlib-ng with DFLTCC decompression support:
  4. $ ./configure --with-dfltcc-inflate
  5. or
  6. $ cmake -DWITH_DFLTCC_INFLATE=1 .
  7. and then
  8. $ make
  9. */
  10. #include "zbuild.h"
  11. #include "zutil.h"
  12. #include "inftrees.h"
  13. #include "inflate.h"
  14. #include "dfltcc_inflate.h"
  15. #include "dfltcc_detail.h"
  16. void Z_INTERNAL PREFIX(dfltcc_reset_inflate_state)(PREFIX3(streamp) strm) {
  17. struct inflate_state *state = (struct inflate_state *)strm->state;
  18. dfltcc_reset_state(&state->arch.common);
  19. }
  20. int Z_INTERNAL PREFIX(dfltcc_can_inflate)(PREFIX3(streamp) strm) {
  21. struct inflate_state *state = (struct inflate_state *)strm->state;
  22. struct dfltcc_state *dfltcc_state = &state->arch.common;
  23. /* Unsupported hardware */
  24. return is_bit_set(dfltcc_state->af.fns, DFLTCC_XPND) && is_bit_set(dfltcc_state->af.fmts, DFLTCC_FMT0);
  25. }
  26. static inline dfltcc_cc dfltcc_xpnd(PREFIX3(streamp) strm) {
  27. struct inflate_state *state = (struct inflate_state *)strm->state;
  28. struct dfltcc_param_v0 *param = &state->arch.common.param;
  29. size_t avail_in = strm->avail_in;
  30. size_t avail_out = strm->avail_out;
  31. dfltcc_cc cc;
  32. cc = dfltcc(DFLTCC_XPND | HBT_CIRCULAR,
  33. param, &strm->next_out, &avail_out,
  34. &strm->next_in, &avail_in, state->window);
  35. strm->avail_in = avail_in;
  36. strm->avail_out = avail_out;
  37. return cc;
  38. }
  39. dfltcc_inflate_action Z_INTERNAL PREFIX(dfltcc_inflate)(PREFIX3(streamp) strm, int flush, int *ret) {
  40. struct inflate_state *state = (struct inflate_state *)strm->state;
  41. struct dfltcc_state *dfltcc_state = &state->arch.common;
  42. struct dfltcc_param_v0 *param = &dfltcc_state->param;
  43. dfltcc_cc cc;
  44. if (flush == Z_BLOCK || flush == Z_TREES) {
  45. /* DFLTCC does not support stopping on block boundaries */
  46. if (PREFIX(dfltcc_inflate_disable)(strm)) {
  47. *ret = Z_STREAM_ERROR;
  48. return DFLTCC_INFLATE_BREAK;
  49. } else
  50. return DFLTCC_INFLATE_SOFTWARE;
  51. }
  52. if (state->last) {
  53. if (state->bits != 0) {
  54. strm->next_in++;
  55. strm->avail_in--;
  56. state->bits = 0;
  57. }
  58. state->mode = CHECK;
  59. return DFLTCC_INFLATE_CONTINUE;
  60. }
  61. if (strm->avail_in == 0 && !param->cf)
  62. return DFLTCC_INFLATE_BREAK;
  63. /* if window not in use yet, initialize */
  64. if (state->wsize == 0)
  65. state->wsize = 1U << state->wbits;
  66. /* Translate stream to parameter block */
  67. param->cvt = ((state->wrap & 4) && state->flags) ? CVT_CRC32 : CVT_ADLER32;
  68. param->sbb = state->bits;
  69. if (param->hl)
  70. param->nt = 0; /* Honor history for the first block */
  71. if (state->wrap & 4)
  72. param->cv = state->flags ? ZSWAP32(state->check) : state->check;
  73. /* Inflate */
  74. do {
  75. cc = dfltcc_xpnd(strm);
  76. } while (cc == DFLTCC_CC_AGAIN);
  77. /* Translate parameter block to stream */
  78. strm->msg = oesc_msg(dfltcc_state->msg, param->oesc);
  79. state->last = cc == DFLTCC_CC_OK;
  80. state->bits = param->sbb;
  81. if (state->wrap & 4)
  82. strm->adler = state->check = state->flags ? ZSWAP32(param->cv) : param->cv;
  83. if (cc == DFLTCC_CC_OP2_CORRUPT && param->oesc != 0) {
  84. /* Report an error if stream is corrupted */
  85. state->mode = BAD;
  86. return DFLTCC_INFLATE_CONTINUE;
  87. }
  88. state->mode = TYPEDO;
  89. /* Break if operands are exhausted, otherwise continue looping */
  90. return (cc == DFLTCC_CC_OP1_TOO_SHORT || cc == DFLTCC_CC_OP2_TOO_SHORT) ?
  91. DFLTCC_INFLATE_BREAK : DFLTCC_INFLATE_CONTINUE;
  92. }
  93. int Z_INTERNAL PREFIX(dfltcc_was_inflate_used)(PREFIX3(streamp) strm) {
  94. struct inflate_state *state = (struct inflate_state *)strm->state;
  95. return !state->arch.common.param.nt;
  96. }
  97. /*
  98. Rotates a circular buffer.
  99. The implementation is based on https://cplusplus.com/reference/algorithm/rotate/
  100. */
  101. static void rotate(unsigned char *start, unsigned char *pivot, unsigned char *end) {
  102. unsigned char *p = pivot;
  103. unsigned char tmp;
  104. while (p != start) {
  105. tmp = *start;
  106. *start = *p;
  107. *p = tmp;
  108. start++;
  109. p++;
  110. if (p == end)
  111. p = pivot;
  112. else if (start == pivot)
  113. pivot = p;
  114. }
  115. }
  116. int Z_INTERNAL PREFIX(dfltcc_inflate_disable)(PREFIX3(streamp) strm) {
  117. struct inflate_state *state = (struct inflate_state *)strm->state;
  118. struct dfltcc_state *dfltcc_state = &state->arch.common;
  119. struct dfltcc_param_v0 *param = &dfltcc_state->param;
  120. if (!PREFIX(dfltcc_can_inflate)(strm))
  121. return 0;
  122. if (PREFIX(dfltcc_was_inflate_used)(strm))
  123. /* DFLTCC has already decompressed some data. Since there is not
  124. * enough information to resume decompression in software, the call
  125. * must fail.
  126. */
  127. return 1;
  128. /* DFLTCC was not used yet - decompress in software */
  129. memset(&dfltcc_state->af, 0, sizeof(dfltcc_state->af));
  130. /* Convert the window from the hardware to the software format */
  131. rotate(state->window, state->window + param->ho, state->window + HB_SIZE);
  132. state->whave = state->wnext = MIN(param->hl, state->wsize);
  133. return 0;
  134. }
  135. /*
  136. Preloading history.
  137. */
  138. int Z_INTERNAL PREFIX(dfltcc_inflate_set_dictionary)(PREFIX3(streamp) strm,
  139. const unsigned char *dictionary, uInt dict_length) {
  140. struct inflate_state *state = (struct inflate_state *)strm->state;
  141. struct dfltcc_param_v0 *param = &state->arch.common.param;
  142. /* if window not in use yet, initialize */
  143. if (state->wsize == 0)
  144. state->wsize = 1U << state->wbits;
  145. append_history(param, state->window, dictionary, dict_length);
  146. state->havedict = 1;
  147. return Z_OK;
  148. }
  149. int Z_INTERNAL PREFIX(dfltcc_inflate_get_dictionary)(PREFIX3(streamp) strm,
  150. unsigned char *dictionary, uInt *dict_length) {
  151. struct inflate_state *state = (struct inflate_state *)strm->state;
  152. struct dfltcc_param_v0 *param = &state->arch.common.param;
  153. if (dictionary && state->window)
  154. get_history(param, state->window, dictionary);
  155. if (dict_length)
  156. *dict_length = param->hl;
  157. return Z_OK;
  158. }