Coverage Report

Created: 2026-09-04 06:47

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
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, &current_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
}
deflate_medium
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, &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
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
}
deflate_medium_fizzle
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, &current_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
}