Coverage Report

Created: 2026-10-17 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
9.71M
static void SUFFIX(insert_match)(deflate_state *s, unsigned char *Z_RESTRICT window, struct match match, const uint32_t max_len) {
17
9.71M
    uint32_t start;
18
9.71M
    uint32_t match_len = match.match_length;
19
9.71M
    uint32_t strstart = match.strstart + 1; // string at strstart already in table
20
9.71M
    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
9.71M
    if (UNLIKELY(match_len > max_len)) {
26
        // For too long matches, insert only the tail position.
27
574k
        start = end - 1;
28
9.14M
    } else {
29
9.14M
        start = strstart;
30
9.14M
    }
31
32
#ifdef USE_FIZZLE
33
4.56M
    if (UNLIKELY(start < match.orgstart))
34
77.9k
        start = match.orgstart;
35
#endif
36
37
9.71M
    insert_knuth_batch(s, window, start, end - start);
38
9.71M
}
deflate_medium.c:insert_match
Line
Count
Source
16
5.15M
static void SUFFIX(insert_match)(deflate_state *s, unsigned char *Z_RESTRICT window, struct match match, const uint32_t max_len) {
17
5.15M
    uint32_t start;
18
5.15M
    uint32_t match_len = match.match_length;
19
5.15M
    uint32_t strstart = match.strstart + 1; // string at strstart already in table
20
5.15M
    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
5.15M
    if (UNLIKELY(match_len > max_len)) {
26
        // For too long matches, insert only the tail position.
27
324k
        start = end - 1;
28
4.83M
    } else {
29
4.83M
        start = strstart;
30
4.83M
    }
31
32
#ifdef USE_FIZZLE
33
    if (UNLIKELY(start < match.orgstart))
34
        start = match.orgstart;
35
#endif
36
37
5.15M
    insert_knuth_batch(s, window, start, end - start);
38
5.15M
}
deflate_medium.c:insert_match_fizzle
Line
Count
Source
16
4.56M
static void SUFFIX(insert_match)(deflate_state *s, unsigned char *Z_RESTRICT window, struct match match, const uint32_t max_len) {
17
4.56M
    uint32_t start;
18
4.56M
    uint32_t match_len = match.match_length;
19
4.56M
    uint32_t strstart = match.strstart + 1; // string at strstart already in table
20
4.56M
    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
4.56M
    if (UNLIKELY(match_len > max_len)) {
26
        // For too long matches, insert only the tail position.
27
249k
        start = end - 1;
28
4.31M
    } else {
29
4.31M
        start = strstart;
30
4.31M
    }
31
32
4.56M
#ifdef USE_FIZZLE
33
4.56M
    if (UNLIKELY(start < match.orgstart))
34
77.9k
        start = match.orgstart;
35
4.56M
#endif
36
37
4.56M
    insert_knuth_batch(s, window, start, end - start);
38
4.56M
}
39
40
267M
Z_FORCEINLINE static struct match SUFFIX(find_best_match)(deflate_state *s, uint32_t hash_head, int32_t max_dist) {
41
267M
    struct match m;
42
267M
    int32_t dist;
43
44
267M
    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
267M
    dist = (int32_t)s->strstart - (int32_t)hash_head;
52
267M
    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
91.1M
        m.match_length = FUNCTABLE_CALL(longest_match)(s, hash_head);
58
91.1M
        m.match_start = s->match_start;
59
91.1M
        if (UNLIKELY(m.match_length < WANT_MIN_MATCH))
60
81.4M
            m.match_length = 1;
61
91.1M
        if (UNLIKELY(m.match_start >= m.strstart)) {
62
            /* this can happen due to some restarts */
63
0
            m.match_length = 1;
64
0
        }
65
176M
    } else {
66
        /* Set up the match to be a 1 byte literal */
67
176M
        m.match_start = 0;
68
176M
        m.match_length = 1;
69
176M
    }
70
71
267M
    return m;
72
267M
}
deflate_medium.c:find_best_match
Line
Count
Source
40
134M
Z_FORCEINLINE static struct match SUFFIX(find_best_match)(deflate_state *s, uint32_t hash_head, int32_t max_dist) {
41
134M
    struct match m;
42
134M
    int32_t dist;
43
44
134M
    m.strstart = s->strstart;
45
#ifdef USE_FIZZLE
46
    m.orgstart = m.strstart;
47
#else
48
134M
    m.orgstart = 0; // For sanitizer
49
134M
#endif
50
51
134M
    dist = (int32_t)s->strstart - (int32_t)hash_head;
52
134M
    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
45.8M
        m.match_length = FUNCTABLE_CALL(longest_match)(s, hash_head);
58
45.8M
        m.match_start = s->match_start;
59
45.8M
        if (UNLIKELY(m.match_length < WANT_MIN_MATCH))
60
40.6M
            m.match_length = 1;
61
45.8M
        if (UNLIKELY(m.match_start >= m.strstart)) {
62
            /* this can happen due to some restarts */
63
0
            m.match_length = 1;
64
0
        }
65
88.5M
    } else {
66
        /* Set up the match to be a 1 byte literal */
67
88.5M
        m.match_start = 0;
68
88.5M
        m.match_length = 1;
69
88.5M
    }
70
71
134M
    return m;
72
134M
}
deflate_medium.c:find_best_match_fizzle
Line
Count
Source
40
133M
Z_FORCEINLINE static struct match SUFFIX(find_best_match)(deflate_state *s, uint32_t hash_head, int32_t max_dist) {
41
133M
    struct match m;
42
133M
    int32_t dist;
43
44
133M
    m.strstart = s->strstart;
45
133M
#ifdef USE_FIZZLE
46
133M
    m.orgstart = m.strstart;
47
#else
48
    m.orgstart = 0; // For sanitizer
49
#endif
50
51
133M
    dist = (int32_t)s->strstart - (int32_t)hash_head;
52
133M
    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
45.3M
        m.match_length = FUNCTABLE_CALL(longest_match)(s, hash_head);
58
45.3M
        m.match_start = s->match_start;
59
45.3M
        if (UNLIKELY(m.match_length < WANT_MIN_MATCH))
60
40.7M
            m.match_length = 1;
61
45.3M
        if (UNLIKELY(m.match_start >= m.strstart)) {
62
            /* this can happen due to some restarts */
63
0
            m.match_length = 1;
64
0
        }
65
88.0M
    } else {
66
        /* Set up the match to be a 1 byte literal */
67
88.0M
        m.match_start = 0;
68
88.0M
        m.match_length = 1;
69
88.0M
    }
70
71
133M
    return m;
72
133M
}
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
2.64M
                           struct match *Z_RESTRICT next, int32_t max_dist) {
92
2.64M
    unsigned char *match = window + next->match_start + 1 - current->match_length;
93
2.64M
    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
2.64M
    if (LIKELY(*match != *orig))
97
1.13M
        return;
98
99
1.51M
    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
1.51M
    uint32_t need = current->match_length - 1;
103
104
    // Protect next->strstart from moving past maximum distance
105
1.51M
    int32_t max_steps_to_limit = (int32_t)next->strstart - limit;
106
107
    // Protect next->match_length from exceeding 256
108
1.51M
    int32_t max_growth_allowed = 256 - (int32_t)next->match_length;
109
110
    // Protect next->match_start from going too far back
111
1.51M
    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
1.51M
    int32_t steps1 = MIN((int32_t)current->match_length, max_steps_to_limit);
115
1.51M
    int32_t steps2 = MIN(max_growth_allowed, max_steps_to_history);
116
1.51M
    int32_t steps = MIN(steps1, steps2);
117
118
    // If we can't possibly fizzle the current match out, return early
119
1.51M
    if (LIKELY(steps < (int32_t)need))
120
254k
        return;
121
122
    // The quick exit above already checked the first byte of that range.
123
    // Compare the whole range here.
124
1.25M
    if (LIKELY(memcmp(match, orig, (size_t)need) != 0))
125
1.18M
        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
77.9k
    int extra_byte_ok = (steps == (int32_t)current->match_length);
130
131
    // Update variables, reduces current->match_length to 1.
132
77.9k
    next->match_start  = next->match_start - need;
133
77.9k
    next->strstart     = next->strstart - need;
134
77.9k
    next->match_length = next->match_length + need;
135
77.9k
    next->orgstart++;
136
77.9k
    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
77.9k
    if (extra_byte_ok) {
141
77.3k
        match = window + next->match_start - 1;
142
77.3k
        orig  = window + next->strstart - 1;
143
144
77.3k
        if (*match == *orig) {
145
11.5k
            next->match_start--;
146
11.5k
            next->strstart--;
147
11.5k
            next->match_length++;
148
11.5k
            current->match_length = 0;
149
11.5k
        }
150
77.3k
    }
151
77.9k
}
152
#endif
153
154
13.9k
Z_INTERNAL block_state SUFFIX(deflate_medium)(deflate_state *s, int flush) {
155
13.9k
    ALIGNED_(16) struct match current_match = {0};
156
#ifdef USE_FIZZLE
157
                 struct match next_match = {0};
158
6.96k
    uint32_t window_end = s->window_size - MIN_LOOKAHEAD;
159
#endif
160
13.9k
    uint32_t max_len = (16 * s->max_insert_length);
161
13.9k
    unsigned char *window = s->window;
162
13.9k
    int32_t max_dist = MAX_DIST(s);
163
164
267M
    for (;;) {
165
267M
        int bflush = 0;       /* set if current block must be flushed */
166
267M
        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
267M
        if (UNLIKELY(s->lookahead < MIN_LOOKAHEAD)) {
174
834k
            PREFIX(fill_window)(s);
175
834k
            if (UNLIKELY(s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH)) {
176
0
                return need_more;
177
0
            }
178
834k
            if (UNLIKELY(s->lookahead == 0))
179
13.9k
                break; /* flush the current block */
180
#ifdef USE_FIZZLE
181
408k
            next_match.match_length = 0;
182
408k
#endif
183
408k
        }
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
133M
        if (next_match.match_length > 0) {
192
132M
            current_match = next_match;
193
132M
            next_match.match_length = 0;
194
132M
        } else {
195
411k
            uint32_t hash_head = 0;   /* head of the hash chain */
196
411k
            if (LIKELY(s->lookahead >= WANT_MIN_MATCH)) {
197
398k
                hash_head = insert_knuth(s, window, s->strstart);
198
398k
            }
199
200
411k
            current_match = SUFFIX(find_best_match)(s, hash_head, max_dist);
201
411k
        }
202
        curr_match_len = current_match.match_length;
203
204
133M
        if (curr_match_len >= WANT_MIN_MATCH && s->lookahead > (unsigned int)(curr_match_len + WANT_MIN_MATCH )) {
205
4.56M
            SUFFIX(insert_match)(s, window, current_match, max_len);
206
4.56M
        }
207
208
        /* now, look ahead one */
209
133M
        if (LIKELY(s->lookahead > MIN_LOOKAHEAD && (current_match.strstart + curr_match_len) < window_end)) {
210
132M
            s->strstart = current_match.strstart + curr_match_len;
211
132M
            uint32_t hash_head = insert_knuth(s, window, s->strstart);
212
213
132M
            next_match = SUFFIX(find_best_match)(s, hash_head, max_dist);
214
215
132M
            uint32_t tmp_cmatch_len_sub = curr_match_len - 1;
216
132M
            if (tmp_cmatch_len_sub
217
4.53M
                     && next_match.match_length >= WANT_MIN_MATCH
218
2.64M
                     && tmp_cmatch_len_sub <= next_match.match_start) {
219
2.64M
                fizzle_matches(window, &current_match, &next_match, max_dist);
220
2.64M
                curr_match_len = current_match.match_length;
221
2.64M
            }
222
223
132M
            s->strstart = current_match.strstart;
224
132M
            if (curr_match_len == 0) {
225
                /* If current match fizzled out, jump to next loop iteration */
226
11.5k
                continue;
227
11.5k
            }
228
132M
        } else {
229
410k
            next_match.match_length = 0;
230
410k
        }
231
#else
232
        // WITHOUT_FIZZLE: We don't look for future matches, so code is much simplified
233
134M
        uint32_t hash_head = 0;   /* head of the hash chain */
234
134M
        if (LIKELY(s->lookahead >= WANT_MIN_MATCH)) {
235
134M
            hash_head = insert_knuth(s, window, s->strstart);
236
134M
        }
237
238
134M
        current_match = SUFFIX(find_best_match)(s, hash_head, max_dist);
239
        curr_match_len = current_match.match_length;
240
241
134M
        if (curr_match_len >= WANT_MIN_MATCH && s->lookahead > (unsigned int)(curr_match_len + WANT_MIN_MATCH )) {
242
5.15M
            SUFFIX(insert_match)(s, window, current_match, max_len);
243
5.15M
        }
244
134M
#endif
245
246
        /* now emit the current match */
247
133M
        s->lookahead -= curr_match_len;
248
267M
        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
258M
            bflush = zng_tr_tally_lit(s, window[current_match.strstart]);
251
258M
        } else {
252
9.64M
            check_match(s, current_match.strstart, current_match.match_start, curr_match_len);
253
9.64M
            bflush = zng_tr_tally_dist(s, current_match.strstart - current_match.match_start, curr_match_len - STD_MIN_MATCH);
254
9.64M
        }
255
256
        /* move the "cursor" forward */
257
133M
        s->strstart += curr_match_len;
258
259
267M
        if (UNLIKELY(bflush))
260
267M
            FLUSH_BLOCK(s, window, 0);
261
267M
    }
262
263
13.9k
    s->insert = s->strstart < (STD_MIN_MATCH - 1) ? s->strstart : (STD_MIN_MATCH - 1);
264
13.9k
    if (flush == Z_FINISH) {
265
13.9k
        FLUSH_BLOCK(s, window, 1);
266
13.9k
        return finish_done;
267
13.9k
    }
268
0
    if (UNLIKELY(s->sym_next))
269
0
        FLUSH_BLOCK(s, window, 0);
270
271
0
    return block_done;
272
0
}
deflate_medium
Line
Count
Source
154
6.96k
Z_INTERNAL block_state SUFFIX(deflate_medium)(deflate_state *s, int flush) {
155
6.96k
    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
6.96k
    uint32_t max_len = (16 * s->max_insert_length);
161
6.96k
    unsigned char *window = s->window;
162
6.96k
    int32_t max_dist = MAX_DIST(s);
163
164
134M
    for (;;) {
165
134M
        int bflush = 0;       /* set if current block must be flushed */
166
134M
        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
134M
        if (UNLIKELY(s->lookahead < MIN_LOOKAHEAD)) {
174
419k
            PREFIX(fill_window)(s);
175
419k
            if (UNLIKELY(s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH)) {
176
0
                return need_more;
177
0
            }
178
419k
            if (UNLIKELY(s->lookahead == 0))
179
6.96k
                break; /* flush the current block */
180
#ifdef USE_FIZZLE
181
            next_match.match_length = 0;
182
#endif
183
419k
        }
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, &current_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
134M
        uint32_t hash_head = 0;   /* head of the hash chain */
234
134M
        if (LIKELY(s->lookahead >= WANT_MIN_MATCH)) {
235
134M
            hash_head = insert_knuth(s, window, s->strstart);
236
134M
        }
237
238
134M
        current_match = SUFFIX(find_best_match)(s, hash_head, max_dist);
239
134M
        curr_match_len = current_match.match_length;
240
241
134M
        if (curr_match_len >= WANT_MIN_MATCH && s->lookahead > (unsigned int)(curr_match_len + WANT_MIN_MATCH )) {
242
5.15M
            SUFFIX(insert_match)(s, window, current_match, max_len);
243
5.15M
        }
244
134M
#endif
245
246
        /* now emit the current match */
247
134M
        s->lookahead -= curr_match_len;
248
134M
        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
129M
            bflush = zng_tr_tally_lit(s, window[current_match.strstart]);
251
129M
        } else {
252
5.16M
            check_match(s, current_match.strstart, current_match.match_start, curr_match_len);
253
5.16M
            bflush = zng_tr_tally_dist(s, current_match.strstart - current_match.match_start, curr_match_len - STD_MIN_MATCH);
254
5.16M
        }
255
256
        /* move the "cursor" forward */
257
134M
        s->strstart += curr_match_len;
258
259
134M
        if (UNLIKELY(bflush))
260
134M
            FLUSH_BLOCK(s, window, 0);
261
134M
    }
262
263
6.96k
    s->insert = s->strstart < (STD_MIN_MATCH - 1) ? s->strstart : (STD_MIN_MATCH - 1);
264
6.96k
    if (flush == Z_FINISH) {
265
6.96k
        FLUSH_BLOCK(s, window, 1);
266
6.96k
        return finish_done;
267
6.96k
    }
268
0
    if (UNLIKELY(s->sym_next))
269
0
        FLUSH_BLOCK(s, window, 0);
270
271
0
    return block_done;
272
0
}
deflate_medium_fizzle
Line
Count
Source
154
6.96k
Z_INTERNAL block_state SUFFIX(deflate_medium)(deflate_state *s, int flush) {
155
6.96k
    ALIGNED_(16) struct match current_match = {0};
156
6.96k
#ifdef USE_FIZZLE
157
6.96k
                 struct match next_match = {0};
158
6.96k
    uint32_t window_end = s->window_size - MIN_LOOKAHEAD;
159
6.96k
#endif
160
6.96k
    uint32_t max_len = (16 * s->max_insert_length);
161
6.96k
    unsigned char *window = s->window;
162
6.96k
    int32_t max_dist = MAX_DIST(s);
163
164
133M
    for (;;) {
165
133M
        int bflush = 0;       /* set if current block must be flushed */
166
133M
        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
133M
        if (UNLIKELY(s->lookahead < MIN_LOOKAHEAD)) {
174
415k
            PREFIX(fill_window)(s);
175
415k
            if (UNLIKELY(s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH)) {
176
0
                return need_more;
177
0
            }
178
415k
            if (UNLIKELY(s->lookahead == 0))
179
6.96k
                break; /* flush the current block */
180
408k
#ifdef USE_FIZZLE
181
408k
            next_match.match_length = 0;
182
408k
#endif
183
408k
        }
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
133M
#ifdef USE_FIZZLE
190
        /* If we already have a future match from a previous round, just use that */
191
133M
        if (next_match.match_length > 0) {
192
132M
            current_match = next_match;
193
132M
            next_match.match_length = 0;
194
132M
        } else {
195
411k
            uint32_t hash_head = 0;   /* head of the hash chain */
196
411k
            if (LIKELY(s->lookahead >= WANT_MIN_MATCH)) {
197
398k
                hash_head = insert_knuth(s, window, s->strstart);
198
398k
            }
199
200
411k
            current_match = SUFFIX(find_best_match)(s, hash_head, max_dist);
201
411k
        }
202
133M
        curr_match_len = current_match.match_length;
203
204
133M
        if (curr_match_len >= WANT_MIN_MATCH && s->lookahead > (unsigned int)(curr_match_len + WANT_MIN_MATCH )) {
205
4.56M
            SUFFIX(insert_match)(s, window, current_match, max_len);
206
4.56M
        }
207
208
        /* now, look ahead one */
209
133M
        if (LIKELY(s->lookahead > MIN_LOOKAHEAD && (current_match.strstart + curr_match_len) < window_end)) {
210
132M
            s->strstart = current_match.strstart + curr_match_len;
211
132M
            uint32_t hash_head = insert_knuth(s, window, s->strstart);
212
213
132M
            next_match = SUFFIX(find_best_match)(s, hash_head, max_dist);
214
215
132M
            uint32_t tmp_cmatch_len_sub = curr_match_len - 1;
216
132M
            if (tmp_cmatch_len_sub
217
4.53M
                     && next_match.match_length >= WANT_MIN_MATCH
218
2.64M
                     && tmp_cmatch_len_sub <= next_match.match_start) {
219
2.64M
                fizzle_matches(window, &current_match, &next_match, max_dist);
220
2.64M
                curr_match_len = current_match.match_length;
221
2.64M
            }
222
223
132M
            s->strstart = current_match.strstart;
224
132M
            if (curr_match_len == 0) {
225
                /* If current match fizzled out, jump to next loop iteration */
226
11.5k
                continue;
227
11.5k
            }
228
132M
        } else {
229
410k
            next_match.match_length = 0;
230
410k
        }
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
133M
        s->lookahead -= curr_match_len;
248
133M
        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
128M
            bflush = zng_tr_tally_lit(s, window[current_match.strstart]);
251
128M
        } else {
252
4.48M
            check_match(s, current_match.strstart, current_match.match_start, curr_match_len);
253
4.48M
            bflush = zng_tr_tally_dist(s, current_match.strstart - current_match.match_start, curr_match_len - STD_MIN_MATCH);
254
4.48M
        }
255
256
        /* move the "cursor" forward */
257
133M
        s->strstart += curr_match_len;
258
259
133M
        if (UNLIKELY(bflush))
260
133M
            FLUSH_BLOCK(s, window, 0);
261
133M
    }
262
263
6.96k
    s->insert = s->strstart < (STD_MIN_MATCH - 1) ? s->strstart : (STD_MIN_MATCH - 1);
264
6.96k
    if (flush == Z_FINISH) {
265
6.96k
        FLUSH_BLOCK(s, window, 1);
266
6.96k
        return finish_done;
267
6.96k
    }
268
0
    if (UNLIKELY(s->sym_next))
269
0
        FLUSH_BLOCK(s, window, 0);
270
271
0
    return block_done;
272
0
}