/src/zlib-ng/deflate_stored.c
Line | Count | Source |
1 | | /* deflate_stored.c -- store data without compression using deflation algorithm |
2 | | * |
3 | | * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler |
4 | | * For conditions of distribution and use, see copyright notice in zlib.h |
5 | | */ |
6 | | |
7 | | #include "zbuild.h" |
8 | | #include "deflate.h" |
9 | | #include "deflate_p.h" |
10 | | #include "functable.h" |
11 | | |
12 | | /* =========================================================================== |
13 | | * Copy without compression as much as possible from the input stream, return |
14 | | * the current block state. |
15 | | * |
16 | | * In case deflateParams() is used to later switch to a non-zero compression |
17 | | * level, s->matches (otherwise unused when storing) keeps track of the number |
18 | | * of hash table slides to perform. If s->matches is 1, then one hash table |
19 | | * slide will be done when switching. If s->matches is 2, the maximum value |
20 | | * allowed here, then the hash table will be cleared, since two or more slides |
21 | | * is the same as a clear. |
22 | | * |
23 | | * deflate_stored() is written to minimize the number of times an input byte is |
24 | | * copied. It is most efficient with large input and output buffers, which |
25 | | * maximizes the opportunities to have a single copy from next_in to next_out. |
26 | | */ |
27 | 3.25k | Z_INTERNAL block_state deflate_stored(deflate_state *s, int flush) { |
28 | | /* Smallest worthy block size when not flushing or finishing. By default |
29 | | * this is 32K. This can be as small as 507 bytes for memLevel == 1. For |
30 | | * large input and output buffers, the stored block size will be larger. |
31 | | */ |
32 | 3.25k | unsigned int w_size = s->w_size; |
33 | 3.25k | unsigned min_block = MIN(s->pending_buf_size - 5, w_size); |
34 | | |
35 | | /* Copy as many min_block or larger stored blocks directly to next_out as |
36 | | * possible. If flushing, copy the remaining available input to next_out as |
37 | | * stored blocks, if there is enough space. |
38 | | */ |
39 | 3.25k | unsigned len, left, have, last = 0; |
40 | 3.25k | unsigned used = s->strm->avail_in; |
41 | 5.15k | do { |
42 | | /* Set len to the maximum size block that we can copy directly with the |
43 | | * available input data and output space. Set left to how much of that |
44 | | * would be copied from what's left in the window. |
45 | | */ |
46 | 5.15k | len = MAX_STORED; /* maximum deflate stored block length */ |
47 | 5.15k | have = (s->bi_valid + 42) >> 3; /* number of header bytes */ |
48 | 5.15k | if (s->strm->avail_out < have) /* need room for header */ |
49 | 207 | break; |
50 | | /* maximum stored block length that will fit in avail_out: */ |
51 | 4.94k | have = s->strm->avail_out - have; |
52 | 4.94k | left = (int)s->strstart - s->block_start; /* bytes left in window */ |
53 | 4.94k | if (len > (unsigned long)left + s->strm->avail_in) |
54 | 4.50k | len = left + s->strm->avail_in; /* limit len to the input */ |
55 | 4.94k | len = MIN(len, have); /* limit len to the output */ |
56 | | |
57 | | /* If the stored block would be less than min_block in length, or if |
58 | | * unable to copy all of the available input when flushing, then try |
59 | | * copying to the window and the pending buffer instead. Also don't |
60 | | * write an empty block when flushing -- deflate() does that. |
61 | | */ |
62 | 4.94k | if (len < min_block && ((len == 0 && flush != Z_FINISH) || flush == Z_NO_FLUSH || len != left + s->strm->avail_in)) |
63 | 2.91k | break; |
64 | | |
65 | | /* Make a dummy stored block in pending to get the header bytes, |
66 | | * including any pending bits. This also updates the debugging counts. |
67 | | */ |
68 | 2.03k | last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0; |
69 | 2.03k | zng_tr_stored_block(s, (char *)0, 0L, last); |
70 | | |
71 | | /* Replace the lengths in the dummy stored block with len. */ |
72 | 2.03k | s->pending -= 4; |
73 | 2.03k | put_short(s, (uint16_t)len); |
74 | 2.03k | put_short(s, (uint16_t)~len); |
75 | | |
76 | | /* Write the stored block header bytes. */ |
77 | 2.03k | PREFIX(flush_pending)(s->strm); |
78 | | |
79 | | /* Update debugging counts for the data about to be copied. */ |
80 | 2.03k | cmpr_bits_add(s, len << 3); |
81 | 2.03k | sent_bits_add(s, len << 3); |
82 | | |
83 | | /* Copy uncompressed bytes from the window to next_out. */ |
84 | 2.03k | if (left) { |
85 | 1.64k | left = MIN(left, len); |
86 | 1.64k | memcpy(s->strm->next_out, s->window + s->block_start, left); |
87 | 1.64k | s->strm->next_out += left; |
88 | 1.64k | s->strm->avail_out -= left; |
89 | 1.64k | s->strm->total_out += left; |
90 | 1.64k | s->block_start += (int)left; |
91 | 1.64k | len -= left; |
92 | 1.64k | } |
93 | | |
94 | | /* Copy uncompressed bytes directly from next_in to next_out, updating |
95 | | * the check value. |
96 | | */ |
97 | 2.03k | if (len) { |
98 | 574 | read_buf(s->strm, s->strm->next_out, len); |
99 | 574 | s->strm->next_out += len; |
100 | 574 | s->strm->avail_out -= len; |
101 | 574 | s->strm->total_out += len; |
102 | 574 | } |
103 | 2.03k | } while (last == 0); |
104 | | |
105 | | /* Update the sliding window with the last s->w_size bytes of the copied |
106 | | * data, or append all of the copied data to the existing window if less |
107 | | * than s->w_size bytes were copied. Also update the number of bytes to |
108 | | * insert in the hash tables, in the event that deflateParams() switches to |
109 | | * a non-zero compression level. |
110 | | */ |
111 | 3.25k | used -= s->strm->avail_in; /* number of input bytes directly copied */ |
112 | 3.25k | if (used) { |
113 | | /* If any input was used, then no unused input remains in the window, |
114 | | * therefore s->block_start == s->strstart. |
115 | | */ |
116 | 335 | if (used >= w_size) { /* supplant the previous history */ |
117 | 267 | s->matches = 2; /* clear hash */ |
118 | 267 | memcpy(s->window, s->strm->next_in - w_size, w_size); |
119 | 267 | s->strstart = w_size; |
120 | 267 | s->insert = s->strstart; |
121 | 267 | } else { |
122 | 68 | if (s->window_size - s->strstart <= used) { |
123 | | /* Slide the window down. */ |
124 | 3 | s->strstart -= w_size; |
125 | 3 | memcpy(s->window, s->window + w_size, s->strstart); |
126 | 3 | if (s->matches < 2) |
127 | 0 | s->matches++; /* add a pending slide_hash() */ |
128 | 3 | s->insert = MIN(s->insert, s->strstart); |
129 | 3 | } |
130 | 68 | memcpy(s->window + s->strstart, s->strm->next_in - used, used); |
131 | 68 | s->strstart += used; |
132 | 68 | s->insert += MIN(used, w_size - s->insert); |
133 | 68 | } |
134 | 335 | s->block_start = (int)s->strstart; |
135 | 335 | } |
136 | 3.25k | s->high_water = MAX(s->high_water, s->strstart); |
137 | | |
138 | | /* If the last block was written to next_out, then done. */ |
139 | 3.25k | if (last) |
140 | 128 | return finish_done; |
141 | | |
142 | | /* If flushing and all input has been consumed, then done. */ |
143 | 3.12k | if (flush != Z_NO_FLUSH && flush != Z_FINISH && s->strm->avail_in == 0 && (int)s->strstart == s->block_start) |
144 | 1.45k | return block_done; |
145 | | |
146 | | /* Fill the window with any remaining input. */ |
147 | 1.66k | have = s->window_size - s->strstart; |
148 | 1.66k | if (s->strm->avail_in > have && s->block_start >= (int)w_size) { |
149 | | /* Slide the window down. */ |
150 | 20 | s->block_start -= (int)w_size; |
151 | 20 | s->strstart -= w_size; |
152 | 20 | memcpy(s->window, s->window + w_size, s->strstart); |
153 | 20 | if (s->matches < 2) |
154 | 20 | s->matches++; /* add a pending slide_hash() */ |
155 | 20 | have += w_size; /* more space now */ |
156 | 20 | s->insert = MIN(s->insert, s->strstart); |
157 | 20 | } |
158 | | |
159 | 1.66k | have = MIN(have, s->strm->avail_in); |
160 | 1.66k | if (have) { |
161 | 1.66k | read_buf(s->strm, s->window + s->strstart, have); |
162 | 1.66k | s->strstart += have; |
163 | 1.66k | s->insert += MIN(have, w_size - s->insert); |
164 | 1.66k | } |
165 | 1.66k | s->high_water = MAX(s->high_water, s->strstart); |
166 | | |
167 | | /* There was not enough avail_out to write a complete worthy or flushed |
168 | | * stored block to next_out. Write a stored block to pending instead, if we |
169 | | * have enough input for a worthy block, or if flushing and there is enough |
170 | | * room for the remaining input as a stored block in the pending buffer. |
171 | | */ |
172 | 1.66k | have = (s->bi_valid + 42) >> 3; /* number of header bytes */ |
173 | | /* maximum stored block length that will fit in pending: */ |
174 | 1.66k | have = MIN(s->pending_buf_size - have, MAX_STORED); |
175 | 1.66k | min_block = MIN(have, w_size); |
176 | 1.66k | left = (int)s->strstart - s->block_start; |
177 | 1.66k | if (left >= min_block || ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH && s->strm->avail_in == 0 && left <= have)) { |
178 | 21 | len = MIN(left, have); |
179 | 21 | last = flush == Z_FINISH && s->strm->avail_in == 0 && len == left ? 1 : 0; |
180 | 21 | zng_tr_stored_block(s, (char *)s->window + s->block_start, len, last); |
181 | 21 | s->block_start += (int)len; |
182 | 21 | PREFIX(flush_pending)(s->strm); |
183 | 21 | } |
184 | | |
185 | | /* We've done all we can with the available input and output. */ |
186 | 1.66k | return last ? finish_started : need_more; |
187 | 3.12k | } |