Coverage Report

Created: 2026-04-12 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libzip/lib/zip_algorithm_deflate.c
Line
Count
Source
1
/*
2
  zip_algorithm_deflate.c -- deflate (de)compression routines
3
  Copyright (C) 2017-2025 Dieter Baron and Thomas Klausner
4
5
  This file is part of libzip, a library to manipulate ZIP archives.
6
  The authors can be contacted at <info@libzip.org>
7
8
  Redistribution and use in source and binary forms, with or without
9
  modification, are permitted provided that the following conditions
10
  are met:
11
  1. Redistributions of source code must retain the above copyright
12
     notice, this list of conditions and the following disclaimer.
13
  2. Redistributions in binary form must reproduce the above copyright
14
     notice, this list of conditions and the following disclaimer in
15
     the documentation and/or other materials provided with the
16
     distribution.
17
  3. The names of the authors may not be used to endorse or promote
18
     products derived from this software without specific prior
19
     written permission.
20
21
  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
22
  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27
  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29
  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30
  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31
  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
*/
33
34
#include "zipint.h"
35
36
#include <limits.h>
37
#include <stdlib.h>
38
#include <zlib.h>
39
40
struct ctx {
41
    zip_error_t *error;
42
    bool compress;
43
    int level;
44
    int mem_level;
45
    bool end_of_input;
46
    z_stream zstr;
47
};
48
49
50
1.03k
static zip_uint64_t maximum_compressed_size(zip_uint64_t uncompressed_size) {
51
    /* max deflate size increase: size + ceil(size/16k)*5+6 */
52
53
1.03k
    zip_uint64_t compressed_size = uncompressed_size + (uncompressed_size + 16383) / 16384 * 5 + 6;
54
55
1.03k
    if (compressed_size < uncompressed_size) {
56
0
        return ZIP_UINT64_MAX;
57
0
    }
58
1.03k
    return compressed_size;
59
1.03k
}
60
61
62
19.5k
static void *allocate(bool compress, zip_uint32_t compression_flags, zip_error_t *error) {
63
19.5k
    struct ctx *ctx;
64
65
19.5k
    if ((ctx = (struct ctx *)malloc(sizeof(*ctx))) == NULL) {
66
0
        zip_error_set(error, ZIP_ET_SYS, errno);
67
0
        return NULL;
68
0
    }
69
70
19.5k
    ctx->error = error;
71
19.5k
    ctx->compress = compress;
72
19.5k
    if (compression_flags >= 1 && compression_flags <= 9) {
73
0
        ctx->level = (int)compression_flags;
74
0
    }
75
19.5k
    else {
76
19.5k
        ctx->level = Z_BEST_COMPRESSION;
77
19.5k
    }
78
19.5k
    ctx->mem_level = compression_flags == TORRENTZIP_COMPRESSION_FLAGS ? TORRENTZIP_MEM_LEVEL : MAX_MEM_LEVEL;
79
19.5k
    ctx->end_of_input = false;
80
81
19.5k
    ctx->zstr.zalloc = Z_NULL;
82
19.5k
    ctx->zstr.zfree = Z_NULL;
83
19.5k
    ctx->zstr.opaque = NULL;
84
85
19.5k
    return ctx;
86
19.5k
}
87
88
89
1.03k
static void *compress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) {
90
1.03k
    (void)method;
91
1.03k
    return allocate(true, compression_flags, error);
92
1.03k
}
93
94
95
18.4k
static void *decompress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) {
96
18.4k
    (void)method;
97
18.4k
    return allocate(false, compression_flags, error);
98
18.4k
}
99
100
101
19.5k
static void deallocate(void *ud) {
102
19.5k
    struct ctx *ctx = (struct ctx *)ud;
103
104
19.5k
    free(ctx);
105
19.5k
}
106
107
108
1.77k
static zip_uint16_t general_purpose_bit_flags(void *ud) {
109
1.77k
    struct ctx *ctx = (struct ctx *)ud;
110
111
1.77k
    if (!ctx->compress) {
112
0
        return 0;
113
0
    }
114
115
1.77k
    if (ctx->level < 3) {
116
0
        return 2 << 1;
117
0
    }
118
1.77k
    else if (ctx->level > 7) {
119
1.77k
        return 1 << 1;
120
1.77k
    }
121
0
    return 0;
122
1.77k
}
123
124
125
16.7k
static bool start(void *ud, zip_stat_t *st, zip_file_attributes_t *attributes) {
126
16.7k
    struct ctx *ctx = (struct ctx *)ud;
127
16.7k
    int ret;
128
129
16.7k
    (void)st;
130
16.7k
    (void)attributes;
131
132
16.7k
    ctx->zstr.avail_in = 0;
133
16.7k
    ctx->zstr.next_in = NULL;
134
16.7k
    ctx->zstr.avail_out = 0;
135
16.7k
    ctx->zstr.next_out = NULL;
136
137
16.7k
    if (ctx->compress) {
138
        /* negative value to tell zlib not to write a header */
139
1.03k
        ret = deflateInit2(&ctx->zstr, ctx->level, Z_DEFLATED, -MAX_WBITS, ctx->mem_level, Z_DEFAULT_STRATEGY);
140
1.03k
    }
141
15.7k
    else {
142
15.7k
        ret = inflateInit2(&ctx->zstr, -MAX_WBITS);
143
15.7k
    }
144
145
16.7k
    if (ret != Z_OK) {
146
0
        zip_error_set(ctx->error, ZIP_ER_ZLIB, ret);
147
0
        return false;
148
0
    }
149
150
151
16.7k
    return true;
152
16.7k
}
153
154
155
16.7k
static bool end(void *ud) {
156
16.7k
    struct ctx *ctx = (struct ctx *)ud;
157
16.7k
    int err;
158
159
16.7k
    if (ctx->compress) {
160
1.03k
        err = deflateEnd(&ctx->zstr);
161
1.03k
    }
162
15.7k
    else {
163
15.7k
        err = inflateEnd(&ctx->zstr);
164
15.7k
    }
165
166
16.7k
    if (err != Z_OK) {
167
0
        zip_error_set(ctx->error, ZIP_ER_ZLIB, err);
168
0
        return false;
169
0
    }
170
171
16.7k
    return true;
172
16.7k
}
173
174
175
39.5k
static bool input(void *ud, zip_uint8_t *data, zip_uint64_t length) {
176
39.5k
    struct ctx *ctx = (struct ctx *)ud;
177
178
39.5k
    if (length > UINT_MAX || ctx->zstr.avail_in > 0) {
179
0
        zip_error_set(ctx->error, ZIP_ER_INVAL, 0);
180
0
        return false;
181
0
    }
182
183
39.5k
    ctx->zstr.avail_in = (uInt)length;
184
39.5k
    ctx->zstr.next_in = (Bytef *)data;
185
186
39.5k
    return true;
187
39.5k
}
188
189
190
5.48k
static bool end_of_input(void *ud) {
191
5.48k
    struct ctx *ctx = (struct ctx *)ud;
192
193
5.48k
    ctx->end_of_input = true;
194
5.48k
    return ctx->zstr.avail_in != 0;
195
5.48k
}
196
197
198
108k
static zip_compression_status_t process(void *ud, zip_uint8_t *data, zip_uint64_t *length) {
199
108k
    struct ctx *ctx = (struct ctx *)ud;
200
108k
    uInt avail_out;
201
202
108k
    int ret;
203
204
108k
    avail_out = (uInt)ZIP_MIN(UINT_MAX, *length);
205
108k
    ctx->zstr.avail_out = avail_out;
206
108k
    ctx->zstr.next_out = (Bytef *)data;
207
208
108k
    if (ctx->compress) {
209
73.4k
        ret = deflate(&ctx->zstr, ctx->end_of_input ? Z_FINISH : 0);
210
73.4k
    }
211
35.1k
    else {
212
35.1k
        ret = inflate(&ctx->zstr, Z_SYNC_FLUSH);
213
35.1k
    }
214
215
108k
    *length = avail_out - ctx->zstr.avail_out;
216
217
108k
    switch (ret) {
218
48.4k
    case Z_OK:
219
48.4k
        return ZIP_COMPRESSION_OK;
220
221
4.45k
    case Z_STREAM_END:
222
4.45k
        return ZIP_COMPRESSION_END;
223
224
46.6k
    case Z_BUF_ERROR:
225
46.6k
        if (ctx->zstr.avail_in == 0) {
226
46.6k
            return ZIP_COMPRESSION_NEED_DATA;
227
46.6k
        }
228
229
        /* fallthrough */
230
231
9.11k
    default:
232
9.11k
        zip_error_set(ctx->error, ZIP_ER_ZLIB, ret);
233
9.11k
        return ZIP_COMPRESSION_ERROR;
234
108k
    }
235
108k
}
236
237
/* clang-format off */
238
239
zip_compression_algorithm_t zip_algorithm_deflate_compress = {
240
    maximum_compressed_size,
241
    compress_allocate,
242
    deallocate,
243
    general_purpose_bit_flags,
244
    20,
245
    start,
246
    end,
247
    input,
248
    end_of_input,
249
    process
250
};
251
252
253
zip_compression_algorithm_t zip_algorithm_deflate_decompress = {
254
    maximum_compressed_size,
255
    decompress_allocate,
256
    deallocate,
257
    general_purpose_bit_flags,
258
    20,
259
    start,
260
    end,
261
    input,
262
    end_of_input,
263
    process
264
};
265
266
/* clang-format on */