Coverage Report

Created: 2026-08-31 06:47

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