summaryrefslogtreecommitdiff
path: root/neozip/deflate_stored.c
diff options
context:
space:
mode:
Diffstat (limited to 'neozip/deflate_stored.c')
-rw-r--r--neozip/deflate_stored.c187
1 files changed, 187 insertions, 0 deletions
diff --git a/neozip/deflate_stored.c b/neozip/deflate_stored.c
new file mode 100644
index 0000000000..f912f631b2
--- /dev/null
+++ b/neozip/deflate_stored.c
@@ -0,0 +1,187 @@
+/* deflate_stored.c -- store data without compression using deflation algorithm
+ *
+ * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zbuild.h"
+#include "deflate.h"
+#include "deflate_p.h"
+#include "functable.h"
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ *
+ * In case deflateParams() is used to later switch to a non-zero compression
+ * level, s->matches (otherwise unused when storing) keeps track of the number
+ * of hash table slides to perform. If s->matches is 1, then one hash table
+ * slide will be done when switching. If s->matches is 2, the maximum value
+ * allowed here, then the hash table will be cleared, since two or more slides
+ * is the same as a clear.
+ *
+ * deflate_stored() is written to minimize the number of times an input byte is
+ * copied. It is most efficient with large input and output buffers, which
+ * maximizes the opportunities to have a single copy from next_in to next_out.
+ */
+Z_INTERNAL block_state deflate_stored(deflate_state *s, int flush) {
+ /* Smallest worthy block size when not flushing or finishing. By default
+ * this is 32K. This can be as small as 507 bytes for memLevel == 1. For
+ * large input and output buffers, the stored block size will be larger.
+ */
+ unsigned int w_size = s->w_size;
+ unsigned min_block = MIN(s->pending_buf_size - 5, w_size);
+
+ /* Copy as many min_block or larger stored blocks directly to next_out as
+ * possible. If flushing, copy the remaining available input to next_out as
+ * stored blocks, if there is enough space.
+ */
+ unsigned len, left, have, last = 0;
+ unsigned used = s->strm->avail_in;
+ do {
+ /* Set len to the maximum size block that we can copy directly with the
+ * available input data and output space. Set left to how much of that
+ * would be copied from what's left in the window.
+ */
+ len = MAX_STORED; /* maximum deflate stored block length */
+ have = (s->bi_valid + 42) >> 3; /* number of header bytes */
+ if (s->strm->avail_out < have) /* need room for header */
+ break;
+ /* maximum stored block length that will fit in avail_out: */
+ have = s->strm->avail_out - have;
+ left = (int)s->strstart - s->block_start; /* bytes left in window */
+ if (len > (unsigned long)left + s->strm->avail_in)
+ len = left + s->strm->avail_in; /* limit len to the input */
+ len = MIN(len, have); /* limit len to the output */
+
+ /* If the stored block would be less than min_block in length, or if
+ * unable to copy all of the available input when flushing, then try
+ * copying to the window and the pending buffer instead. Also don't
+ * write an empty block when flushing -- deflate() does that.
+ */
+ if (len < min_block && ((len == 0 && flush != Z_FINISH) || flush == Z_NO_FLUSH || len != left + s->strm->avail_in))
+ break;
+
+ /* Make a dummy stored block in pending to get the header bytes,
+ * including any pending bits. This also updates the debugging counts.
+ */
+ last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0;
+ zng_tr_stored_block(s, NULL, 0L, last);
+
+ /* Replace the lengths in the dummy stored block with len. */
+ s->pending -= 4;
+ put_short(s, (uint16_t)len);
+ put_short(s, (uint16_t)~len);
+
+ /* Write the stored block header bytes. */
+ PREFIX(flush_pending)(s->strm);
+
+ /* Update debugging counts for the data about to be copied. */
+ cmpr_bits_add(s, len << 3);
+ sent_bits_add(s, len << 3);
+
+ /* Copy uncompressed bytes from the window to next_out. */
+ if (left) {
+ left = MIN(left, len);
+ memcpy(s->strm->next_out, s->window + s->block_start, left);
+ s->strm->next_out += left;
+ s->strm->avail_out -= left;
+ s->strm->total_out += left;
+ s->block_start += (int)left;
+ len -= left;
+ }
+
+ /* Copy uncompressed bytes directly from next_in to next_out, updating
+ * the check value.
+ */
+ if (len) {
+ read_buf(s->strm, s->strm->next_out, len);
+ s->strm->next_out += len;
+ s->strm->avail_out -= len;
+ s->strm->total_out += len;
+ }
+ } while (last == 0);
+
+ /* Update the sliding window with the last s->w_size bytes of the copied
+ * data, or append all of the copied data to the existing window if less
+ * than s->w_size bytes were copied. Also update the number of bytes to
+ * insert in the hash tables, in the event that deflateParams() switches to
+ * a non-zero compression level.
+ */
+ used -= s->strm->avail_in; /* number of input bytes directly copied */
+ if (used) {
+ /* If any input was used, then no unused input remains in the window,
+ * therefore s->block_start == s->strstart.
+ */
+ if (used >= w_size) { /* supplant the previous history */
+ s->matches = 2; /* clear hash */
+ memcpy(s->window, s->strm->next_in - w_size, w_size);
+ s->strstart = w_size;
+ s->insert = s->strstart;
+ } else {
+ if (s->window_size - s->strstart <= used) {
+ /* Slide the window down. */
+ s->strstart -= w_size;
+ memcpy(s->window, s->window + w_size, s->strstart);
+ if (s->matches < 2)
+ s->matches++; /* add a pending slide_hash() */
+ s->insert = MIN(s->insert, s->strstart);
+ }
+ memcpy(s->window + s->strstart, s->strm->next_in - used, used);
+ s->strstart += used;
+ s->insert += MIN(used, w_size - s->insert);
+ }
+ s->block_start = (int)s->strstart;
+ }
+ s->high_water = MAX(s->high_water, s->strstart);
+
+ /* If the last block was written to next_out, then done. */
+ if (last)
+ return finish_done;
+
+ /* If flushing and all input has been consumed, then done. */
+ if (flush != Z_NO_FLUSH && flush != Z_FINISH && s->strm->avail_in == 0 && (int)s->strstart == s->block_start)
+ return block_done;
+
+ /* Fill the window with any remaining input. */
+ have = s->window_size - s->strstart;
+ if (s->strm->avail_in > have && s->block_start >= (int)w_size) {
+ /* Slide the window down. */
+ s->block_start -= (int)w_size;
+ s->strstart -= w_size;
+ memcpy(s->window, s->window + w_size, s->strstart);
+ if (s->matches < 2)
+ s->matches++; /* add a pending slide_hash() */
+ have += w_size; /* more space now */
+ s->insert = MIN(s->insert, s->strstart);
+ }
+
+ have = MIN(have, s->strm->avail_in);
+ if (have) {
+ read_buf(s->strm, s->window + s->strstart, have);
+ s->strstart += have;
+ s->insert += MIN(have, w_size - s->insert);
+ }
+ s->high_water = MAX(s->high_water, s->strstart);
+
+ /* There was not enough avail_out to write a complete worthy or flushed
+ * stored block to next_out. Write a stored block to pending instead, if we
+ * have enough input for a worthy block, or if flushing and there is enough
+ * room for the remaining input as a stored block in the pending buffer.
+ */
+ have = (s->bi_valid + 42) >> 3; /* number of header bytes */
+ /* maximum stored block length that will fit in pending: */
+ have = MIN(s->pending_buf_size - have, MAX_STORED);
+ min_block = MIN(have, w_size);
+ left = (int)s->strstart - s->block_start;
+ if (left >= min_block || ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH && s->strm->avail_in == 0 && left <= have)) {
+ len = MIN(left, have);
+ last = flush == Z_FINISH && s->strm->avail_in == 0 && len == left ? 1 : 0;
+ zng_tr_stored_block(s, s->window + s->block_start, len, last);
+ s->block_start += (int)len;
+ PREFIX(flush_pending)(s->strm);
+ }
+
+ /* We've done all we can with the available input and output. */
+ return last ? finish_started : need_more;
+}