/src/zlib-ng/deflate_medium_tpl.h
Line | Count | Source |
1 | | /* deflate_medium_tpl.h -- The deflate_medium deflate strategy |
2 | | * |
3 | | * Copyright (C) 2013 Intel Corporation. All rights reserved. |
4 | | * Authors: |
5 | | * Arjan van de Ven <arjan@linux.intel.com> |
6 | | * |
7 | | * Copyright (C) 2026 Hans Kristian Rosbach |
8 | | * |
9 | | * For conditions of distribution and use, see copyright notice in zlib.h |
10 | | */ |
11 | | |
12 | | /* insert_match assumes: |
13 | | * - s->lookahead > match.match_length + WANT_MIN_MATCH |
14 | | * - match_len >= WANT_MIN_MATCH |
15 | | */ |
16 | 209k | static void SUFFIX(insert_match)(deflate_state *s, unsigned char *Z_RESTRICT window, struct match match, const uint32_t max_len) { |
17 | 209k | uint32_t start; |
18 | 209k | uint32_t match_len = match.match_length; |
19 | 209k | uint32_t strstart = match.strstart + 1; // string at strstart already in table |
20 | 209k | uint32_t end = strstart + match_len - 1; |
21 | | |
22 | | /* Insert new strings in the hash table only if the match length |
23 | | * is not too large. This saves time but degrades compression. |
24 | | */ |
25 | 209k | if (UNLIKELY(match_len > max_len)) { |
26 | | // For too long matches, insert only the tail position. |
27 | 8.95k | start = end - 1; |
28 | 200k | } else { |
29 | 200k | start = strstart; |
30 | 200k | } |
31 | | |
32 | | #ifdef USE_FIZZLE |
33 | 112k | if (UNLIKELY(start < match.orgstart)) |
34 | 7.33k | start = match.orgstart; |
35 | | #endif |
36 | | |
37 | 209k | insert_knuth_batch(s, window, start, end - start); |
38 | 209k | } deflate_medium.c:insert_match Line | Count | Source | 16 | 96.8k | static void SUFFIX(insert_match)(deflate_state *s, unsigned char *Z_RESTRICT window, struct match match, const uint32_t max_len) { | 17 | 96.8k | uint32_t start; | 18 | 96.8k | uint32_t match_len = match.match_length; | 19 | 96.8k | uint32_t strstart = match.strstart + 1; // string at strstart already in table | 20 | 96.8k | uint32_t end = strstart + match_len - 1; | 21 | | | 22 | | /* Insert new strings in the hash table only if the match length | 23 | | * is not too large. This saves time but degrades compression. | 24 | | */ | 25 | 96.8k | if (UNLIKELY(match_len > max_len)) { | 26 | | // For too long matches, insert only the tail position. | 27 | 4.14k | start = end - 1; | 28 | 92.7k | } else { | 29 | 92.7k | start = strstart; | 30 | 92.7k | } | 31 | | | 32 | | #ifdef USE_FIZZLE | 33 | | if (UNLIKELY(start < match.orgstart)) | 34 | | start = match.orgstart; | 35 | | #endif | 36 | | | 37 | 96.8k | insert_knuth_batch(s, window, start, end - start); | 38 | 96.8k | } |
deflate_medium.c:insert_match_fizzle Line | Count | Source | 16 | 112k | static void SUFFIX(insert_match)(deflate_state *s, unsigned char *Z_RESTRICT window, struct match match, const uint32_t max_len) { | 17 | 112k | uint32_t start; | 18 | 112k | uint32_t match_len = match.match_length; | 19 | 112k | uint32_t strstart = match.strstart + 1; // string at strstart already in table | 20 | 112k | uint32_t end = strstart + match_len - 1; | 21 | | | 22 | | /* Insert new strings in the hash table only if the match length | 23 | | * is not too large. This saves time but degrades compression. | 24 | | */ | 25 | 112k | if (UNLIKELY(match_len > max_len)) { | 26 | | // For too long matches, insert only the tail position. | 27 | 4.80k | start = end - 1; | 28 | 107k | } else { | 29 | 107k | start = strstart; | 30 | 107k | } | 31 | | | 32 | 112k | #ifdef USE_FIZZLE | 33 | 112k | if (UNLIKELY(start < match.orgstart)) | 34 | 7.33k | start = match.orgstart; | 35 | 112k | #endif | 36 | | | 37 | 112k | insert_knuth_batch(s, window, start, end - start); | 38 | 112k | } |
|
39 | | |
40 | 2.79M | Z_FORCEINLINE static struct match SUFFIX(find_best_match)(deflate_state *s, uint32_t hash_head, int32_t max_dist) { |
41 | 2.79M | struct match m; |
42 | 2.79M | int32_t dist; |
43 | | |
44 | 2.79M | m.strstart = s->strstart; |
45 | | #ifdef USE_FIZZLE |
46 | | m.orgstart = m.strstart; |
47 | | #else |
48 | | m.orgstart = 0; // For sanitizer |
49 | | #endif |
50 | | |
51 | 2.79M | dist = (int32_t)s->strstart - (int32_t)hash_head; |
52 | 2.79M | if (dist <= max_dist && dist > 0 && hash_head != 0) { |
53 | | /* To simplify the code, we prevent matches with the string |
54 | | * of window index 0 (in particular we have to avoid a match |
55 | | * of the string with itself at the start of the input file). |
56 | | */ |
57 | 243k | m.match_length = FUNCTABLE_CALL(longest_match)(s, hash_head); |
58 | 243k | m.match_start = s->match_start; |
59 | 243k | if (UNLIKELY(m.match_length < WANT_MIN_MATCH)) |
60 | 32.5k | m.match_length = 1; |
61 | 243k | if (UNLIKELY(m.match_start >= m.strstart)) { |
62 | | /* this can happen due to some restarts */ |
63 | 0 | m.match_length = 1; |
64 | 0 | } |
65 | 2.54M | } else { |
66 | | /* Set up the match to be a 1 byte literal */ |
67 | 2.54M | m.match_start = 0; |
68 | 2.54M | m.match_length = 1; |
69 | 2.54M | } |
70 | | |
71 | 2.79M | return m; |
72 | 2.79M | } deflate_medium.c:find_best_match Line | Count | Source | 40 | 1.06M | Z_FORCEINLINE static struct match SUFFIX(find_best_match)(deflate_state *s, uint32_t hash_head, int32_t max_dist) { | 41 | 1.06M | struct match m; | 42 | 1.06M | int32_t dist; | 43 | | | 44 | 1.06M | m.strstart = s->strstart; | 45 | | #ifdef USE_FIZZLE | 46 | | m.orgstart = m.strstart; | 47 | | #else | 48 | 1.06M | m.orgstart = 0; // For sanitizer | 49 | 1.06M | #endif | 50 | | | 51 | 1.06M | dist = (int32_t)s->strstart - (int32_t)hash_head; | 52 | 1.06M | if (dist <= max_dist && dist > 0 && hash_head != 0) { | 53 | | /* To simplify the code, we prevent matches with the string | 54 | | * of window index 0 (in particular we have to avoid a match | 55 | | * of the string with itself at the start of the input file). | 56 | | */ | 57 | 108k | m.match_length = FUNCTABLE_CALL(longest_match)(s, hash_head); | 58 | 108k | m.match_start = s->match_start; | 59 | 108k | if (UNLIKELY(m.match_length < WANT_MIN_MATCH)) | 60 | 10.6k | m.match_length = 1; | 61 | 108k | if (UNLIKELY(m.match_start >= m.strstart)) { | 62 | | /* this can happen due to some restarts */ | 63 | 0 | m.match_length = 1; | 64 | 0 | } | 65 | 958k | } else { | 66 | | /* Set up the match to be a 1 byte literal */ | 67 | 958k | m.match_start = 0; | 68 | 958k | m.match_length = 1; | 69 | 958k | } | 70 | | | 71 | 1.06M | return m; | 72 | 1.06M | } |
deflate_medium.c:find_best_match_fizzle Line | Count | Source | 40 | 1.72M | Z_FORCEINLINE static struct match SUFFIX(find_best_match)(deflate_state *s, uint32_t hash_head, int32_t max_dist) { | 41 | 1.72M | struct match m; | 42 | 1.72M | int32_t dist; | 43 | | | 44 | 1.72M | m.strstart = s->strstart; | 45 | 1.72M | #ifdef USE_FIZZLE | 46 | 1.72M | m.orgstart = m.strstart; | 47 | | #else | 48 | | m.orgstart = 0; // For sanitizer | 49 | | #endif | 50 | | | 51 | 1.72M | dist = (int32_t)s->strstart - (int32_t)hash_head; | 52 | 1.72M | if (dist <= max_dist && dist > 0 && hash_head != 0) { | 53 | | /* To simplify the code, we prevent matches with the string | 54 | | * of window index 0 (in particular we have to avoid a match | 55 | | * of the string with itself at the start of the input file). | 56 | | */ | 57 | 135k | m.match_length = FUNCTABLE_CALL(longest_match)(s, hash_head); | 58 | 135k | m.match_start = s->match_start; | 59 | 135k | if (UNLIKELY(m.match_length < WANT_MIN_MATCH)) | 60 | 21.8k | m.match_length = 1; | 61 | 135k | if (UNLIKELY(m.match_start >= m.strstart)) { | 62 | | /* this can happen due to some restarts */ | 63 | 0 | m.match_length = 1; | 64 | 0 | } | 65 | 1.59M | } else { | 66 | | /* Set up the match to be a 1 byte literal */ | 67 | 1.59M | m.match_start = 0; | 68 | 1.59M | m.match_length = 1; | 69 | 1.59M | } | 70 | | | 71 | 1.72M | return m; | 72 | 1.72M | } |
|
73 | | |
74 | | /* fizzle_matches investigates whether next_match (which starts after current_match) can grow backwards |
75 | | * to absorb current_match entirely, or reduce it to a single literal. |
76 | | * This occurs because next_match points to a different historical dictionary position, allowing it to discover |
77 | | * a better matching alignment that current_match bypassed due to the medium-strategy skipping positions. |
78 | | * |
79 | | * fizzle_matches assumes: |
80 | | * - current_match.match_length > 1 |
81 | | * - current_match.match_length - 1 <= next->match_start |
82 | | * - current_match.match_length - 1 <= next->strstart |
83 | | * - next_match.match_length >= WANT_MIN_MATCH |
84 | | * |
85 | | * fizzle_matches returns: |
86 | | * - If successful, current and next are returned modified. |
87 | | * - current_match.match_length is then either 0, 1 |
88 | | */ |
89 | | #ifdef USE_FIZZLE |
90 | | static void fizzle_matches(unsigned char *Z_RESTRICT window, struct match *Z_RESTRICT current, |
91 | 53.5k | struct match *Z_RESTRICT next, int32_t max_dist) { |
92 | 53.5k | unsigned char *match = window + next->match_start + 1 - current->match_length; |
93 | 53.5k | unsigned char *orig = window + next->strstart + 1 - current->match_length; |
94 | | |
95 | | /* quick exit check.. if this fails then don't bother with anything else */ |
96 | 53.5k | if (LIKELY(*match != *orig)) |
97 | 29.7k | return; |
98 | | |
99 | 23.7k | int32_t limit = (int32_t)next->strstart > max_dist ? (int32_t)next->strstart - max_dist : 0; |
100 | | |
101 | | // Steps needed to successfully fizzle match |
102 | 23.7k | uint32_t need = current->match_length - 1; |
103 | | |
104 | | // Protect next->strstart from moving past maximum distance |
105 | 23.7k | int32_t max_steps_to_limit = (int32_t)next->strstart - limit; |
106 | | |
107 | | // Protect next->match_length from exceeding 256 |
108 | 23.7k | int32_t max_growth_allowed = 256 - (int32_t)next->match_length; |
109 | | |
110 | | // Protect next->match_start from going too far back |
111 | 23.7k | int32_t max_steps_to_history = (int32_t)next->match_start - 1; |
112 | | |
113 | | // steps is the max number of backward steps allowed for each limitation |
114 | 23.7k | int32_t steps1 = MIN((int32_t)current->match_length, max_steps_to_limit); |
115 | 23.7k | int32_t steps2 = MIN(max_growth_allowed, max_steps_to_history); |
116 | 23.7k | int32_t steps = MIN(steps1, steps2); |
117 | | |
118 | | // If we can't possibly fizzle the current match out, return early |
119 | 23.7k | if (LIKELY(steps < (int32_t)need)) |
120 | 5.31k | return; |
121 | | |
122 | | // The quick exit above already checked the first byte of that range. |
123 | | // Compare the whole range here. |
124 | 18.4k | if (LIKELY(memcmp(match, orig, (size_t)need) != 0)) |
125 | 11.0k | return; |
126 | | |
127 | | // Check whether the final extra backward byte is also possible. |
128 | | // This decides whether the current match becomes length 1 or 0. |
129 | 7.33k | int extra_byte_ok = (steps == (int32_t)current->match_length); |
130 | | |
131 | | // Update variables, reduces current->match_length to 1. |
132 | 7.33k | next->match_start = next->match_start - need; |
133 | 7.33k | next->strstart = next->strstart - need; |
134 | 7.33k | next->match_length = next->match_length + need; |
135 | 7.33k | next->orgstart++; |
136 | 7.33k | current->match_length = 1; |
137 | | |
138 | | // If every constraint allowed one more backward byte, test it. |
139 | | // If it matches, the current match is fully absorbed and becomes length 0. |
140 | 7.33k | if (extra_byte_ok) { |
141 | 6.80k | match = window + next->match_start - 1; |
142 | 6.80k | orig = window + next->strstart - 1; |
143 | | |
144 | 6.80k | if (*match == *orig) { |
145 | 1.53k | next->match_start--; |
146 | 1.53k | next->strstart--; |
147 | 1.53k | next->match_length++; |
148 | 1.53k | current->match_length = 0; |
149 | 1.53k | } |
150 | 6.80k | } |
151 | 7.33k | } |
152 | | #endif |
153 | | |
154 | 2.03k | Z_INTERNAL block_state SUFFIX(deflate_medium)(deflate_state *s, int flush) { |
155 | 2.03k | ALIGNED_(16) struct match current_match = {0}; |
156 | | #ifdef USE_FIZZLE |
157 | | struct match next_match = {0}; |
158 | 1.44k | uint32_t window_end = s->window_size - MIN_LOOKAHEAD; |
159 | | #endif |
160 | 2.03k | uint32_t max_len = (16 * s->max_insert_length); |
161 | 2.03k | unsigned char *window = s->window; |
162 | 2.03k | int32_t max_dist = MAX_DIST(s); |
163 | | |
164 | 2.79M | for (;;) { |
165 | 2.79M | int bflush = 0; /* set if current block must be flushed */ |
166 | 2.79M | uint32_t curr_match_len; |
167 | | |
168 | | /* Make sure that we always have enough lookahead, except |
169 | | * at the end of the input file. We need STD_MAX_MATCH bytes |
170 | | * for the next match, plus WANT_MIN_MATCH bytes to insert the |
171 | | * string following the next current_match. |
172 | | */ |
173 | 2.79M | if (UNLIKELY(s->lookahead < MIN_LOOKAHEAD)) { |
174 | 112k | PREFIX(fill_window)(s); |
175 | 112k | if (UNLIKELY(s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH)) { |
176 | 0 | return need_more; |
177 | 0 | } |
178 | 112k | if (UNLIKELY(s->lookahead == 0)) |
179 | 2.03k | break; /* flush the current block */ |
180 | | #ifdef USE_FIZZLE |
181 | 72.0k | next_match.match_length = 0; |
182 | 72.0k | #endif |
183 | 72.0k | } |
184 | | |
185 | | /* Insert the string window[strstart .. strstart+2] in the |
186 | | * dictionary, and set hash_head to the head of the hash chain: |
187 | | */ |
188 | | |
189 | | #ifdef USE_FIZZLE |
190 | | /* If we already have a future match from a previous round, just use that */ |
191 | 1.72M | if (next_match.match_length > 0) { |
192 | 1.65M | current_match = next_match; |
193 | 1.65M | next_match.match_length = 0; |
194 | 1.65M | } else { |
195 | 74.5k | uint32_t hash_head = 0; /* head of the hash chain */ |
196 | 74.5k | if (LIKELY(s->lookahead >= WANT_MIN_MATCH)) { |
197 | 72.5k | hash_head = insert_knuth(s, window, s->strstart); |
198 | 72.5k | } |
199 | | |
200 | 74.5k | current_match = SUFFIX(find_best_match)(s, hash_head, max_dist); |
201 | 74.5k | } |
202 | | curr_match_len = current_match.match_length; |
203 | | |
204 | 1.72M | if (curr_match_len >= WANT_MIN_MATCH && s->lookahead > (unsigned int)(curr_match_len + WANT_MIN_MATCH )) { |
205 | 112k | SUFFIX(insert_match)(s, window, current_match, max_len); |
206 | 112k | } |
207 | | |
208 | | /* now, look ahead one */ |
209 | 1.72M | if (LIKELY(s->lookahead > MIN_LOOKAHEAD && (current_match.strstart + curr_match_len) < window_end)) { |
210 | 1.65M | s->strstart = current_match.strstart + curr_match_len; |
211 | 1.65M | uint32_t hash_head = insert_knuth(s, window, s->strstart); |
212 | | |
213 | 1.65M | next_match = SUFFIX(find_best_match)(s, hash_head, max_dist); |
214 | | |
215 | 1.65M | uint32_t tmp_cmatch_len_sub = curr_match_len - 1; |
216 | 1.65M | if (tmp_cmatch_len_sub |
217 | 102k | && next_match.match_length >= WANT_MIN_MATCH |
218 | 53.7k | && tmp_cmatch_len_sub <= next_match.match_start) { |
219 | 53.5k | fizzle_matches(window, ¤t_match, &next_match, max_dist); |
220 | 53.5k | curr_match_len = current_match.match_length; |
221 | 53.5k | } |
222 | | |
223 | 1.65M | s->strstart = current_match.strstart; |
224 | 1.65M | if (curr_match_len == 0) { |
225 | | /* If current match fizzled out, jump to next loop iteration */ |
226 | 1.53k | continue; |
227 | 1.53k | } |
228 | 1.65M | } else { |
229 | 74.0k | next_match.match_length = 0; |
230 | 74.0k | } |
231 | | #else |
232 | | // WITHOUT_FIZZLE: We don't look for future matches, so code is much simplified |
233 | 1.06M | uint32_t hash_head = 0; /* head of the hash chain */ |
234 | 1.06M | if (LIKELY(s->lookahead >= WANT_MIN_MATCH)) { |
235 | 1.06M | hash_head = insert_knuth(s, window, s->strstart); |
236 | 1.06M | } |
237 | | |
238 | 1.06M | current_match = SUFFIX(find_best_match)(s, hash_head, max_dist); |
239 | | curr_match_len = current_match.match_length; |
240 | | |
241 | 1.06M | if (curr_match_len >= WANT_MIN_MATCH && s->lookahead > (unsigned int)(curr_match_len + WANT_MIN_MATCH )) { |
242 | 96.8k | SUFFIX(insert_match)(s, window, current_match, max_len); |
243 | 96.8k | } |
244 | 1.06M | #endif |
245 | | |
246 | | /* now emit the current match */ |
247 | 1.72M | s->lookahead -= curr_match_len; |
248 | 2.79M | if (LIKELY(curr_match_len == 1)) { |
249 | | /* matches shorter than WANT_MIN_MATCH are set to 1, we need to emit these as literals */ |
250 | 2.58M | bflush = zng_tr_tally_lit(s, window[current_match.strstart]); |
251 | 2.58M | } else { |
252 | 203k | check_match(s, current_match.strstart, current_match.match_start, curr_match_len); |
253 | 203k | bflush = zng_tr_tally_dist(s, current_match.strstart - current_match.match_start, curr_match_len - STD_MIN_MATCH); |
254 | 203k | } |
255 | | |
256 | | /* move the "cursor" forward */ |
257 | 1.72M | s->strstart += curr_match_len; |
258 | | |
259 | 2.79M | if (UNLIKELY(bflush)) |
260 | 2.79M | FLUSH_BLOCK(s, window, 0); |
261 | 2.79M | } |
262 | | |
263 | 2.03k | s->insert = s->strstart < (STD_MIN_MATCH - 1) ? s->strstart : (STD_MIN_MATCH - 1); |
264 | 2.03k | if (flush == Z_FINISH) { |
265 | 2.03k | FLUSH_BLOCK(s, window, 1); |
266 | 2.03k | return finish_done; |
267 | 2.03k | } |
268 | 0 | if (UNLIKELY(s->sym_next)) |
269 | 0 | FLUSH_BLOCK(s, window, 0); |
270 | |
|
271 | 0 | return block_done; |
272 | 0 | } Line | Count | Source | 154 | 586 | Z_INTERNAL block_state SUFFIX(deflate_medium)(deflate_state *s, int flush) { | 155 | 586 | ALIGNED_(16) struct match current_match = {0}; | 156 | | #ifdef USE_FIZZLE | 157 | | struct match next_match = {0}; | 158 | | uint32_t window_end = s->window_size - MIN_LOOKAHEAD; | 159 | | #endif | 160 | 586 | uint32_t max_len = (16 * s->max_insert_length); | 161 | 586 | unsigned char *window = s->window; | 162 | 586 | int32_t max_dist = MAX_DIST(s); | 163 | | | 164 | 1.06M | for (;;) { | 165 | 1.06M | int bflush = 0; /* set if current block must be flushed */ | 166 | 1.06M | uint32_t curr_match_len; | 167 | | | 168 | | /* Make sure that we always have enough lookahead, except | 169 | | * at the end of the input file. We need STD_MAX_MATCH bytes | 170 | | * for the next match, plus WANT_MIN_MATCH bytes to insert the | 171 | | * string following the next current_match. | 172 | | */ | 173 | 1.06M | if (UNLIKELY(s->lookahead < MIN_LOOKAHEAD)) { | 174 | 38.9k | PREFIX(fill_window)(s); | 175 | 38.9k | if (UNLIKELY(s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH)) { | 176 | 0 | return need_more; | 177 | 0 | } | 178 | 38.9k | if (UNLIKELY(s->lookahead == 0)) | 179 | 586 | break; /* flush the current block */ | 180 | | #ifdef USE_FIZZLE | 181 | | next_match.match_length = 0; | 182 | | #endif | 183 | 38.9k | } | 184 | | | 185 | | /* Insert the string window[strstart .. strstart+2] in the | 186 | | * dictionary, and set hash_head to the head of the hash chain: | 187 | | */ | 188 | | | 189 | | #ifdef USE_FIZZLE | 190 | | /* If we already have a future match from a previous round, just use that */ | 191 | | if (next_match.match_length > 0) { | 192 | | current_match = next_match; | 193 | | next_match.match_length = 0; | 194 | | } else { | 195 | | uint32_t hash_head = 0; /* head of the hash chain */ | 196 | | if (LIKELY(s->lookahead >= WANT_MIN_MATCH)) { | 197 | | hash_head = insert_knuth(s, window, s->strstart); | 198 | | } | 199 | | | 200 | | current_match = SUFFIX(find_best_match)(s, hash_head, max_dist); | 201 | | } | 202 | | curr_match_len = current_match.match_length; | 203 | | | 204 | | if (curr_match_len >= WANT_MIN_MATCH && s->lookahead > (unsigned int)(curr_match_len + WANT_MIN_MATCH )) { | 205 | | SUFFIX(insert_match)(s, window, current_match, max_len); | 206 | | } | 207 | | | 208 | | /* now, look ahead one */ | 209 | | if (LIKELY(s->lookahead > MIN_LOOKAHEAD && (current_match.strstart + curr_match_len) < window_end)) { | 210 | | s->strstart = current_match.strstart + curr_match_len; | 211 | | uint32_t hash_head = insert_knuth(s, window, s->strstart); | 212 | | | 213 | | next_match = SUFFIX(find_best_match)(s, hash_head, max_dist); | 214 | | | 215 | | uint32_t tmp_cmatch_len_sub = curr_match_len - 1; | 216 | | if (tmp_cmatch_len_sub | 217 | | && next_match.match_length >= WANT_MIN_MATCH | 218 | | && tmp_cmatch_len_sub <= next_match.match_start) { | 219 | | fizzle_matches(window, ¤t_match, &next_match, max_dist); | 220 | | curr_match_len = current_match.match_length; | 221 | | } | 222 | | | 223 | | s->strstart = current_match.strstart; | 224 | | if (curr_match_len == 0) { | 225 | | /* If current match fizzled out, jump to next loop iteration */ | 226 | | continue; | 227 | | } | 228 | | } else { | 229 | | next_match.match_length = 0; | 230 | | } | 231 | | #else | 232 | | // WITHOUT_FIZZLE: We don't look for future matches, so code is much simplified | 233 | 1.06M | uint32_t hash_head = 0; /* head of the hash chain */ | 234 | 1.06M | if (LIKELY(s->lookahead >= WANT_MIN_MATCH)) { | 235 | 1.06M | hash_head = insert_knuth(s, window, s->strstart); | 236 | 1.06M | } | 237 | | | 238 | 1.06M | current_match = SUFFIX(find_best_match)(s, hash_head, max_dist); | 239 | 1.06M | curr_match_len = current_match.match_length; | 240 | | | 241 | 1.06M | if (curr_match_len >= WANT_MIN_MATCH && s->lookahead > (unsigned int)(curr_match_len + WANT_MIN_MATCH )) { | 242 | 96.8k | SUFFIX(insert_match)(s, window, current_match, max_len); | 243 | 96.8k | } | 244 | 1.06M | #endif | 245 | | | 246 | | /* now emit the current match */ | 247 | 1.06M | s->lookahead -= curr_match_len; | 248 | 1.06M | if (LIKELY(curr_match_len == 1)) { | 249 | | /* matches shorter than WANT_MIN_MATCH are set to 1, we need to emit these as literals */ | 250 | 969k | bflush = zng_tr_tally_lit(s, window[current_match.strstart]); | 251 | 969k | } else { | 252 | 97.4k | check_match(s, current_match.strstart, current_match.match_start, curr_match_len); | 253 | 97.4k | bflush = zng_tr_tally_dist(s, current_match.strstart - current_match.match_start, curr_match_len - STD_MIN_MATCH); | 254 | 97.4k | } | 255 | | | 256 | | /* move the "cursor" forward */ | 257 | 1.06M | s->strstart += curr_match_len; | 258 | | | 259 | 1.06M | if (UNLIKELY(bflush)) | 260 | 1.06M | FLUSH_BLOCK(s, window, 0); | 261 | 1.06M | } | 262 | | | 263 | 586 | s->insert = s->strstart < (STD_MIN_MATCH - 1) ? s->strstart : (STD_MIN_MATCH - 1); | 264 | 586 | if (flush == Z_FINISH) { | 265 | 586 | FLUSH_BLOCK(s, window, 1); | 266 | 586 | return finish_done; | 267 | 586 | } | 268 | 0 | if (UNLIKELY(s->sym_next)) | 269 | 0 | FLUSH_BLOCK(s, window, 0); | 270 | |
| 271 | 0 | return block_done; | 272 | 0 | } |
Line | Count | Source | 154 | 1.44k | Z_INTERNAL block_state SUFFIX(deflate_medium)(deflate_state *s, int flush) { | 155 | 1.44k | ALIGNED_(16) struct match current_match = {0}; | 156 | 1.44k | #ifdef USE_FIZZLE | 157 | 1.44k | struct match next_match = {0}; | 158 | 1.44k | uint32_t window_end = s->window_size - MIN_LOOKAHEAD; | 159 | 1.44k | #endif | 160 | 1.44k | uint32_t max_len = (16 * s->max_insert_length); | 161 | 1.44k | unsigned char *window = s->window; | 162 | 1.44k | int32_t max_dist = MAX_DIST(s); | 163 | | | 164 | 1.72M | for (;;) { | 165 | 1.72M | int bflush = 0; /* set if current block must be flushed */ | 166 | 1.72M | uint32_t curr_match_len; | 167 | | | 168 | | /* Make sure that we always have enough lookahead, except | 169 | | * at the end of the input file. We need STD_MAX_MATCH bytes | 170 | | * for the next match, plus WANT_MIN_MATCH bytes to insert the | 171 | | * string following the next current_match. | 172 | | */ | 173 | 1.72M | if (UNLIKELY(s->lookahead < MIN_LOOKAHEAD)) { | 174 | 73.5k | PREFIX(fill_window)(s); | 175 | 73.5k | if (UNLIKELY(s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH)) { | 176 | 0 | return need_more; | 177 | 0 | } | 178 | 73.5k | if (UNLIKELY(s->lookahead == 0)) | 179 | 1.44k | break; /* flush the current block */ | 180 | 72.0k | #ifdef USE_FIZZLE | 181 | 72.0k | next_match.match_length = 0; | 182 | 72.0k | #endif | 183 | 72.0k | } | 184 | | | 185 | | /* Insert the string window[strstart .. strstart+2] in the | 186 | | * dictionary, and set hash_head to the head of the hash chain: | 187 | | */ | 188 | | | 189 | 1.72M | #ifdef USE_FIZZLE | 190 | | /* If we already have a future match from a previous round, just use that */ | 191 | 1.72M | if (next_match.match_length > 0) { | 192 | 1.65M | current_match = next_match; | 193 | 1.65M | next_match.match_length = 0; | 194 | 1.65M | } else { | 195 | 74.5k | uint32_t hash_head = 0; /* head of the hash chain */ | 196 | 74.5k | if (LIKELY(s->lookahead >= WANT_MIN_MATCH)) { | 197 | 72.5k | hash_head = insert_knuth(s, window, s->strstart); | 198 | 72.5k | } | 199 | | | 200 | 74.5k | current_match = SUFFIX(find_best_match)(s, hash_head, max_dist); | 201 | 74.5k | } | 202 | 1.72M | curr_match_len = current_match.match_length; | 203 | | | 204 | 1.72M | if (curr_match_len >= WANT_MIN_MATCH && s->lookahead > (unsigned int)(curr_match_len + WANT_MIN_MATCH )) { | 205 | 112k | SUFFIX(insert_match)(s, window, current_match, max_len); | 206 | 112k | } | 207 | | | 208 | | /* now, look ahead one */ | 209 | 1.72M | if (LIKELY(s->lookahead > MIN_LOOKAHEAD && (current_match.strstart + curr_match_len) < window_end)) { | 210 | 1.65M | s->strstart = current_match.strstart + curr_match_len; | 211 | 1.65M | uint32_t hash_head = insert_knuth(s, window, s->strstart); | 212 | | | 213 | 1.65M | next_match = SUFFIX(find_best_match)(s, hash_head, max_dist); | 214 | | | 215 | 1.65M | uint32_t tmp_cmatch_len_sub = curr_match_len - 1; | 216 | 1.65M | if (tmp_cmatch_len_sub | 217 | 102k | && next_match.match_length >= WANT_MIN_MATCH | 218 | 53.7k | && tmp_cmatch_len_sub <= next_match.match_start) { | 219 | 53.5k | fizzle_matches(window, ¤t_match, &next_match, max_dist); | 220 | 53.5k | curr_match_len = current_match.match_length; | 221 | 53.5k | } | 222 | | | 223 | 1.65M | s->strstart = current_match.strstart; | 224 | 1.65M | if (curr_match_len == 0) { | 225 | | /* If current match fizzled out, jump to next loop iteration */ | 226 | 1.53k | continue; | 227 | 1.53k | } | 228 | 1.65M | } else { | 229 | 74.0k | next_match.match_length = 0; | 230 | 74.0k | } | 231 | | #else | 232 | | // WITHOUT_FIZZLE: We don't look for future matches, so code is much simplified | 233 | | uint32_t hash_head = 0; /* head of the hash chain */ | 234 | | if (LIKELY(s->lookahead >= WANT_MIN_MATCH)) { | 235 | | hash_head = insert_knuth(s, window, s->strstart); | 236 | | } | 237 | | | 238 | | current_match = SUFFIX(find_best_match)(s, hash_head, max_dist); | 239 | | curr_match_len = current_match.match_length; | 240 | | | 241 | | if (curr_match_len >= WANT_MIN_MATCH && s->lookahead > (unsigned int)(curr_match_len + WANT_MIN_MATCH )) { | 242 | | SUFFIX(insert_match)(s, window, current_match, max_len); | 243 | | } | 244 | | #endif | 245 | | | 246 | | /* now emit the current match */ | 247 | 1.72M | s->lookahead -= curr_match_len; | 248 | 1.72M | if (LIKELY(curr_match_len == 1)) { | 249 | | /* matches shorter than WANT_MIN_MATCH are set to 1, we need to emit these as literals */ | 250 | 1.61M | bflush = zng_tr_tally_lit(s, window[current_match.strstart]); | 251 | 1.61M | } else { | 252 | 106k | check_match(s, current_match.strstart, current_match.match_start, curr_match_len); | 253 | 106k | bflush = zng_tr_tally_dist(s, current_match.strstart - current_match.match_start, curr_match_len - STD_MIN_MATCH); | 254 | 106k | } | 255 | | | 256 | | /* move the "cursor" forward */ | 257 | 1.72M | s->strstart += curr_match_len; | 258 | | | 259 | 1.72M | if (UNLIKELY(bflush)) | 260 | 1.72M | FLUSH_BLOCK(s, window, 0); | 261 | 1.72M | } | 262 | | | 263 | 1.44k | s->insert = s->strstart < (STD_MIN_MATCH - 1) ? s->strstart : (STD_MIN_MATCH - 1); | 264 | 1.44k | if (flush == Z_FINISH) { | 265 | 1.44k | FLUSH_BLOCK(s, window, 1); | 266 | 1.44k | return finish_done; | 267 | 1.44k | } | 268 | 0 | if (UNLIKELY(s->sym_next)) | 269 | 0 | FLUSH_BLOCK(s, window, 0); | 270 | |
| 271 | 0 | return block_done; | 272 | 0 | } |
|