/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 | | * deflate_stored() is written to minimize the number of times an input byte is |
17 | | * copied. It is most efficient with large input and output buffers, which |
18 | | * maximizes the opportunities to have a single copy from next_in to next_out. |
19 | | */ |
20 | 3.04k | Z_INTERNAL block_state deflate_stored(deflate_state *s, int flush) { |
21 | 3.04k | unsigned char *window = s->window; |
22 | | /* Smallest worthy block size when not flushing or finishing. By default |
23 | | * this is 32K. This can be as small as 507 bytes for memLevel == 1. For |
24 | | * large input and output buffers, the stored block size will be larger. |
25 | | */ |
26 | 3.04k | unsigned int w_size = s->w_size; |
27 | 3.04k | unsigned min_block = MIN(s->pending_buf_size - 5, w_size); |
28 | | |
29 | | /* Copy as many min_block or larger stored blocks directly to next_out as |
30 | | * possible. If flushing, copy the remaining available input to next_out as |
31 | | * stored blocks, if there is enough space. |
32 | | */ |
33 | 3.04k | unsigned len, left, have, last = 0; |
34 | 3.04k | unsigned used = s->strm->avail_in; |
35 | 4.56k | do { |
36 | | /* Set len to the maximum size block that we can copy directly with the |
37 | | * available input data and output space. Set left to how much of that |
38 | | * would be copied from what's left in the window. |
39 | | */ |
40 | 4.56k | len = MAX_STORED; /* maximum deflate stored block length */ |
41 | 4.56k | have = (s->bi_valid + 42) >> 3; /* number of header bytes */ |
42 | 4.56k | if (s->strm->avail_out < have) /* need room for header */ |
43 | 0 | break; |
44 | | /* maximum stored block length that will fit in avail_out: */ |
45 | 4.56k | have = s->strm->avail_out - have; |
46 | 4.56k | left = (int)s->strstart - s->block_start; /* bytes left in window */ |
47 | 4.56k | if (len > (unsigned long)left + s->strm->avail_in) |
48 | 4.56k | len = left + s->strm->avail_in; /* limit len to the input */ |
49 | 4.56k | len = MIN(len, have); /* limit len to the output */ |
50 | | |
51 | | /* If the stored block would be less than min_block in length, or if |
52 | | * unable to copy all of the available input when flushing, then try |
53 | | * copying to the window and the pending buffer instead. Also don't |
54 | | * write an empty block when flushing -- deflate() does that. |
55 | | */ |
56 | 4.56k | if (len < min_block && ((len == 0 && flush != Z_FINISH) || flush == Z_NO_FLUSH || len != left + s->strm->avail_in)) |
57 | 3.04k | break; |
58 | | |
59 | | /* Make a dummy stored block in pending to get the header bytes, |
60 | | * including any pending bits. This also updates the debugging counts. |
61 | | */ |
62 | 1.52k | last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0; |
63 | 1.52k | zng_tr_stored_block(s, NULL, 0L, last); |
64 | | |
65 | | /* Replace the lengths in the dummy stored block with len. */ |
66 | 1.52k | s->pending -= 4; |
67 | 1.52k | put_short(s, (uint16_t)len); |
68 | 1.52k | put_short(s, (uint16_t)~len); |
69 | | |
70 | | /* Write the stored block header bytes. */ |
71 | 1.52k | PREFIX(flush_pending)(s->strm); |
72 | | |
73 | | /* Update debugging counts for the data about to be copied. */ |
74 | 1.52k | cmpr_bits_add(s, len << 3); |
75 | 1.52k | sent_bits_add(s, len << 3); |
76 | | |
77 | | /* Copy uncompressed bytes from the window to next_out. */ |
78 | 1.52k | if (left) { |
79 | 1.52k | left = MIN(left, len); |
80 | 1.52k | memcpy(s->strm->next_out, window + s->block_start, left); |
81 | 1.52k | s->strm->next_out += left; |
82 | 1.52k | s->strm->avail_out -= left; |
83 | 1.52k | s->strm->total_out += left; |
84 | 1.52k | s->block_start += (int)left; |
85 | 1.52k | len -= left; |
86 | 1.52k | } |
87 | | |
88 | | /* Copy uncompressed bytes directly from next_in to next_out, updating |
89 | | * the check value. |
90 | | */ |
91 | 1.52k | if (len) { |
92 | 0 | read_buf(s->strm, s->strm->next_out, len); |
93 | 0 | s->strm->next_out += len; |
94 | 0 | s->strm->avail_out -= len; |
95 | 0 | s->strm->total_out += len; |
96 | 0 | } |
97 | 1.52k | } while (last == 0); |
98 | | |
99 | | /* Update the sliding window with the last s->w_size bytes of the copied |
100 | | * data, or append all of the copied data to the existing window if less |
101 | | * than s->w_size bytes were copied. Also update the number of bytes to |
102 | | * insert in the hash tables, in the event that deflateParams() switches to |
103 | | * a non-zero compression level. |
104 | | */ |
105 | 3.04k | used -= s->strm->avail_in; /* number of input bytes directly copied */ |
106 | 3.04k | if (used) { |
107 | | /* If any input was used, then no unused input remains in the window, |
108 | | * therefore s->block_start == s->strstart. |
109 | | */ |
110 | 0 | if (used >= w_size) { /* supplant the previous history */ |
111 | 0 | memcpy(window, s->strm->next_in - w_size, w_size); |
112 | 0 | s->strstart = w_size; |
113 | 0 | s->insert = s->strstart; |
114 | 0 | } else { |
115 | 0 | if (s->window_size - s->strstart <= used) { |
116 | | /* Slide the window down. */ |
117 | 0 | s->strstart -= w_size; |
118 | 0 | memcpy(window, window + w_size, s->strstart); |
119 | 0 | s->insert = MIN(s->insert, s->strstart); |
120 | 0 | } |
121 | 0 | memcpy(window + s->strstart, s->strm->next_in - used, used); |
122 | 0 | s->strstart += used; |
123 | 0 | s->insert += MIN(used, w_size - s->insert); |
124 | 0 | } |
125 | 0 | s->block_start = (int)s->strstart; |
126 | 0 | } |
127 | 3.04k | s->high_water = MAX(s->high_water, s->strstart); |
128 | | |
129 | | /* If the last block was written to next_out, then done. */ |
130 | 3.04k | if (last) |
131 | 0 | return finish_done; |
132 | | |
133 | | /* If flushing and all input has been consumed, then done. */ |
134 | 3.04k | if (flush != Z_NO_FLUSH && flush != Z_FINISH && s->strm->avail_in == 0 && (int)s->strstart == s->block_start) |
135 | 1.52k | return block_done; |
136 | | |
137 | | /* Fill the window with any remaining input. */ |
138 | 1.52k | have = s->window_size - s->strstart; |
139 | 1.52k | if (s->strm->avail_in > have && s->block_start >= (int)w_size) { |
140 | | /* Slide the window down. */ |
141 | 31 | s->block_start -= (int)w_size; |
142 | 31 | s->strstart -= w_size; |
143 | 31 | memcpy(window, window + w_size, s->strstart); |
144 | 31 | have += w_size; /* more space now */ |
145 | 31 | s->insert = MIN(s->insert, s->strstart); |
146 | 31 | } |
147 | | |
148 | 1.52k | have = MIN(have, s->strm->avail_in); |
149 | 1.52k | if (have) { |
150 | 1.52k | read_buf(s->strm, window + s->strstart, have); |
151 | 1.52k | s->strstart += have; |
152 | 1.52k | s->insert += MIN(have, w_size - s->insert); |
153 | 1.52k | } |
154 | 1.52k | s->high_water = MAX(s->high_water, s->strstart); |
155 | | |
156 | | /* There was not enough avail_out to write a complete worthy or flushed |
157 | | * stored block to next_out. Write a stored block to pending instead, if we |
158 | | * have enough input for a worthy block, or if flushing and there is enough |
159 | | * room for the remaining input as a stored block in the pending buffer. |
160 | | */ |
161 | 1.52k | have = (s->bi_valid + 42) >> 3; /* number of header bytes */ |
162 | | /* maximum stored block length that will fit in pending: */ |
163 | 1.52k | have = MIN(s->pending_buf_size - have, MAX_STORED); |
164 | 1.52k | min_block = MIN(have, w_size); |
165 | 1.52k | left = (int)s->strstart - s->block_start; |
166 | 1.52k | if (left >= min_block || ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH && s->strm->avail_in == 0 && left <= have)) { |
167 | 0 | len = MIN(left, have); |
168 | 0 | last = flush == Z_FINISH && s->strm->avail_in == 0 && len == left ? 1 : 0; |
169 | 0 | zng_tr_stored_block(s, window + s->block_start, len, last); |
170 | 0 | s->block_start += (int)len; |
171 | 0 | PREFIX(flush_pending)(s->strm); |
172 | 0 | } |
173 | | |
174 | | /* We've done all we can with the available input and output. */ |
175 | 1.52k | return last ? finish_started : need_more; |
176 | 3.04k | } |