Coverage Report

Created: 2026-02-14 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/minizip-ng/mz_strm_zlib.c
Line
Count
Source
1
/* mz_strm_zlib.c -- Stream for zlib inflate/deflate
2
   part of the minizip-ng project
3
4
   Copyright (C) Nathan Moinvaziri
5
      https://github.com/zlib-ng/minizip-ng
6
7
   This program is distributed under the terms of the same license as zlib.
8
   See the accompanying LICENSE file for the full text of the license.
9
*/
10
11
#include "mz.h"
12
#include "mz_strm.h"
13
#include "mz_strm_zlib.h"
14
15
#if !defined(ZLIB_COMPAT)
16
#  include "zlib-ng.h"
17
#else
18
#  include "zlib.h"
19
#endif
20
21
/***************************************************************************/
22
23
#if !defined(ZLIB_COMPAT)
24
#  define ZLIB_PREFIX(x) zng_##x
25
typedef zng_stream zlib_stream;
26
#else
27
2.73k
#  define ZLIB_PREFIX(x) x
28
typedef z_stream zlib_stream;
29
#endif
30
31
#if !defined(DEF_MEM_LEVEL)
32
#  if MAX_MEM_LEVEL >= 8
33
#    define DEF_MEM_LEVEL 8
34
#  else
35
#    define DEF_MEM_LEVEL MAX_MEM_LEVEL
36
#  endif
37
#endif
38
39
/***************************************************************************/
40
41
static mz_stream_vtbl mz_stream_zlib_vtbl = {
42
    mz_stream_zlib_open,   mz_stream_zlib_is_open, mz_stream_zlib_read,           mz_stream_zlib_write,
43
    mz_stream_zlib_tell,   mz_stream_zlib_seek,    mz_stream_zlib_close,          mz_stream_zlib_error,
44
    mz_stream_zlib_create, mz_stream_zlib_delete,  mz_stream_zlib_get_prop_int64, mz_stream_zlib_set_prop_int64};
45
46
/***************************************************************************/
47
48
typedef struct mz_stream_zlib_s {
49
    mz_stream stream;
50
    zlib_stream zstream;
51
    uint8_t buffer[INT16_MAX];
52
    int32_t buffer_len;
53
    int64_t total_in;
54
    int64_t total_out;
55
    int64_t max_total_in;
56
    int8_t initialized;
57
    int16_t level;
58
    int32_t window_bits;
59
    int32_t mode;
60
    int32_t error;
61
} mz_stream_zlib;
62
63
/***************************************************************************/
64
65
1.50k
int32_t mz_stream_zlib_open(void *stream, const char *path, int32_t mode) {
66
1.50k
    mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
67
68
1.50k
    MZ_UNUSED(path);
69
70
1.50k
    zlib->zstream.data_type = Z_BINARY;
71
1.50k
    zlib->zstream.zalloc = Z_NULL;
72
1.50k
    zlib->zstream.zfree = Z_NULL;
73
1.50k
    zlib->zstream.opaque = Z_NULL;
74
1.50k
    zlib->zstream.total_in = 0;
75
1.50k
    zlib->zstream.total_out = 0;
76
77
1.50k
    zlib->total_in = 0;
78
1.50k
    zlib->total_out = 0;
79
80
1.50k
    if (mode & MZ_OPEN_MODE_WRITE) {
81
#ifdef MZ_ZIP_NO_COMPRESSION
82
        return MZ_SUPPORT_ERROR;
83
#else
84
0
        zlib->zstream.next_out = zlib->buffer;
85
0
        zlib->zstream.avail_out = sizeof(zlib->buffer);
86
87
0
        zlib->error = ZLIB_PREFIX(deflateInit2)(&zlib->zstream, (int8_t)zlib->level, Z_DEFLATED, zlib->window_bits,
88
0
                                                DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
89
0
#endif
90
1.50k
    } else if (mode & MZ_OPEN_MODE_READ) {
91
#ifdef MZ_ZIP_NO_DECOMPRESSION
92
        return MZ_SUPPORT_ERROR;
93
#else
94
1.50k
        zlib->zstream.next_in = zlib->buffer;
95
1.50k
        zlib->zstream.avail_in = 0;
96
97
1.50k
        zlib->error = ZLIB_PREFIX(inflateInit2)(&zlib->zstream, zlib->window_bits);
98
1.50k
#endif
99
1.50k
    }
100
101
1.50k
    if (zlib->error != Z_OK)
102
0
        return MZ_OPEN_ERROR;
103
104
1.50k
    zlib->initialized = 1;
105
1.50k
    zlib->mode = mode;
106
1.50k
    return MZ_OK;
107
1.50k
}
108
109
2.72k
int32_t mz_stream_zlib_is_open(void *stream) {
110
2.72k
    mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
111
2.72k
    if (zlib->initialized != 1)
112
0
        return MZ_OPEN_ERROR;
113
2.72k
    return MZ_OK;
114
2.72k
}
115
116
1.22k
int32_t mz_stream_zlib_read(void *stream, void *buf, int32_t size) {
117
#ifdef MZ_ZIP_NO_DECOMPRESSION
118
    MZ_UNUSED(stream);
119
    MZ_UNUSED(buf);
120
    MZ_UNUSED(size);
121
    return MZ_SUPPORT_ERROR;
122
#else
123
1.22k
    mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
124
1.22k
    uint64_t total_in_before = 0;
125
1.22k
    uint64_t total_in_after = 0;
126
1.22k
    uint64_t total_out_before = 0;
127
1.22k
    uint64_t total_out_after = 0;
128
1.22k
    uint32_t total_in = 0;
129
1.22k
    uint32_t total_out = 0;
130
1.22k
    uint32_t in_bytes = 0;
131
1.22k
    uint32_t out_bytes = 0;
132
1.22k
    int32_t bytes_to_read = sizeof(zlib->buffer);
133
1.22k
    int32_t read = 0;
134
1.22k
    int32_t err = Z_OK;
135
136
1.22k
    zlib->zstream.next_out = (Bytef *)buf;
137
1.22k
    zlib->zstream.avail_out = (uInt)size;
138
139
1.23k
    do {
140
1.23k
        if (zlib->zstream.avail_in == 0) {
141
1.23k
            if (zlib->max_total_in > 0) {
142
991
                if ((int64_t)bytes_to_read > (zlib->max_total_in - zlib->total_in))
143
73
                    bytes_to_read = (int32_t)(zlib->max_total_in - zlib->total_in);
144
991
            }
145
146
1.23k
            read = mz_stream_read(zlib->stream.base, zlib->buffer, bytes_to_read);
147
148
1.23k
            if (read < 0)
149
0
                return read;
150
151
1.23k
            zlib->zstream.next_in = zlib->buffer;
152
1.23k
            zlib->zstream.avail_in = read;
153
1.23k
        }
154
155
1.23k
        total_in_before = zlib->zstream.avail_in;
156
1.23k
        total_out_before = zlib->zstream.total_out;
157
158
1.23k
        err = ZLIB_PREFIX(inflate)(&zlib->zstream, Z_SYNC_FLUSH);
159
1.23k
        if ((err >= Z_OK) && (zlib->zstream.msg)) {
160
0
            zlib->error = Z_DATA_ERROR;
161
0
            break;
162
0
        }
163
164
1.23k
        total_in_after = zlib->zstream.avail_in;
165
1.23k
        total_out_after = zlib->zstream.total_out;
166
167
1.23k
        in_bytes = (uint32_t)(total_in_before - total_in_after);
168
1.23k
        out_bytes = (uint32_t)(total_out_after - total_out_before);
169
170
1.23k
        total_in += in_bytes;
171
1.23k
        total_out += out_bytes;
172
173
1.23k
        zlib->total_in += in_bytes;
174
1.23k
        zlib->total_out += out_bytes;
175
176
1.23k
        if (err == Z_STREAM_END)
177
1.06k
            break;
178
167
        if (err != Z_OK) {
179
114
            zlib->error = err;
180
114
            break;
181
114
        }
182
167
    } while (zlib->zstream.avail_out > 0);
183
184
1.22k
    MZ_UNUSED(total_in);
185
186
1.22k
    if (zlib->error != 0) {
187
        /* Zlib errors are compatible with MZ */
188
114
        return zlib->error;
189
114
    }
190
191
1.11k
    return total_out;
192
1.22k
#endif
193
1.22k
}
194
195
#ifndef MZ_ZIP_NO_COMPRESSION
196
0
static int32_t mz_stream_zlib_flush(void *stream) {
197
0
    mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
198
0
    if (mz_stream_write(zlib->stream.base, zlib->buffer, zlib->buffer_len) != zlib->buffer_len)
199
0
        return MZ_WRITE_ERROR;
200
0
    return MZ_OK;
201
0
}
202
203
0
static int32_t mz_stream_zlib_deflate(void *stream, int flush) {
204
0
    mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
205
0
    uint64_t total_out_before = 0;
206
0
    uint64_t total_out_after = 0;
207
0
    int32_t out_bytes = 0;
208
0
    int32_t err = Z_OK;
209
210
0
    do {
211
0
        if (zlib->zstream.avail_out == 0) {
212
0
            err = mz_stream_zlib_flush(zlib);
213
0
            if (err != MZ_OK)
214
0
                return err;
215
216
0
            zlib->zstream.avail_out = sizeof(zlib->buffer);
217
0
            zlib->zstream.next_out = zlib->buffer;
218
219
0
            zlib->buffer_len = 0;
220
0
        }
221
222
0
        total_out_before = zlib->zstream.total_out;
223
0
        err = ZLIB_PREFIX(deflate)(&zlib->zstream, flush);
224
0
        total_out_after = zlib->zstream.total_out;
225
226
0
        out_bytes = (uint32_t)(total_out_after - total_out_before);
227
228
0
        zlib->buffer_len += out_bytes;
229
0
        zlib->total_out += out_bytes;
230
231
0
        if (err == Z_STREAM_END)
232
0
            break;
233
0
        if (err != Z_OK) {
234
0
            zlib->error = err;
235
0
            return MZ_DATA_ERROR;
236
0
        }
237
0
    } while ((zlib->zstream.avail_in > 0) || (flush == Z_FINISH && err == Z_OK));
238
239
0
    return MZ_OK;
240
0
}
241
#endif
242
243
0
int32_t mz_stream_zlib_write(void *stream, const void *buf, int32_t size) {
244
#ifdef MZ_ZIP_NO_COMPRESSION
245
    MZ_UNUSED(stream);
246
    MZ_UNUSED(buf);
247
    MZ_UNUSED(size);
248
    return MZ_SUPPORT_ERROR;
249
#else
250
0
    mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
251
0
    int32_t err = MZ_OK;
252
253
0
    zlib->zstream.next_in = (Bytef *)(intptr_t)buf;
254
0
    zlib->zstream.avail_in = (uInt)size;
255
256
0
    err = mz_stream_zlib_deflate(stream, Z_NO_FLUSH);
257
0
    if (err != MZ_OK) {
258
0
        return err;
259
0
    }
260
261
0
    zlib->total_in += size;
262
0
    return size;
263
0
#endif
264
0
}
265
266
0
int64_t mz_stream_zlib_tell(void *stream) {
267
0
    MZ_UNUSED(stream);
268
269
0
    return MZ_TELL_ERROR;
270
0
}
271
272
0
int32_t mz_stream_zlib_seek(void *stream, int64_t offset, int32_t origin) {
273
0
    MZ_UNUSED(stream);
274
0
    MZ_UNUSED(offset);
275
0
    MZ_UNUSED(origin);
276
277
0
    return MZ_SEEK_ERROR;
278
0
}
279
280
1.50k
int32_t mz_stream_zlib_close(void *stream) {
281
1.50k
    mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
282
283
1.50k
    if (zlib->mode & MZ_OPEN_MODE_WRITE) {
284
#ifdef MZ_ZIP_NO_COMPRESSION
285
        return MZ_SUPPORT_ERROR;
286
#else
287
0
        mz_stream_zlib_deflate(stream, Z_FINISH);
288
0
        mz_stream_zlib_flush(stream);
289
290
0
        ZLIB_PREFIX(deflateEnd)(&zlib->zstream);
291
0
#endif
292
1.50k
    } else if (zlib->mode & MZ_OPEN_MODE_READ) {
293
#ifdef MZ_ZIP_NO_DECOMPRESSION
294
        return MZ_SUPPORT_ERROR;
295
#else
296
1.50k
        ZLIB_PREFIX(inflateEnd)(&zlib->zstream);
297
1.50k
#endif
298
1.50k
    }
299
300
1.50k
    zlib->initialized = 0;
301
302
1.50k
    if (zlib->error != Z_OK)
303
114
        return MZ_CLOSE_ERROR;
304
1.38k
    return MZ_OK;
305
1.50k
}
306
307
0
int32_t mz_stream_zlib_error(void *stream) {
308
0
    mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
309
0
    return zlib->error;
310
0
}
311
312
1.50k
int32_t mz_stream_zlib_get_prop_int64(void *stream, int32_t prop, int64_t *value) {
313
1.50k
    mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
314
1.50k
    switch (prop) {
315
1.50k
    case MZ_STREAM_PROP_TOTAL_IN:
316
1.50k
        *value = zlib->total_in;
317
1.50k
        break;
318
0
    case MZ_STREAM_PROP_TOTAL_IN_MAX:
319
0
        *value = zlib->max_total_in;
320
0
        break;
321
0
    case MZ_STREAM_PROP_TOTAL_OUT:
322
0
        *value = zlib->total_out;
323
0
        break;
324
0
    case MZ_STREAM_PROP_HEADER_SIZE:
325
0
        *value = 0;
326
0
        break;
327
0
    case MZ_STREAM_PROP_COMPRESS_WINDOW:
328
0
        *value = zlib->window_bits;
329
0
        break;
330
0
    default:
331
0
        return MZ_EXIST_ERROR;
332
1.50k
    }
333
1.50k
    return MZ_OK;
334
1.50k
}
335
336
1.19k
int32_t mz_stream_zlib_set_prop_int64(void *stream, int32_t prop, int64_t value) {
337
1.19k
    mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
338
1.19k
    switch (prop) {
339
0
    case MZ_STREAM_PROP_COMPRESS_LEVEL:
340
0
        if (value == MZ_COMPRESS_LEVEL_DEFAULT)
341
0
            zlib->level = Z_DEFAULT_COMPRESSION;
342
0
        else
343
0
            zlib->level = (int16_t)value;
344
0
        break;
345
1.19k
    case MZ_STREAM_PROP_TOTAL_IN_MAX:
346
1.19k
        zlib->max_total_in = value;
347
1.19k
        break;
348
0
    case MZ_STREAM_PROP_COMPRESS_WINDOW:
349
0
        zlib->window_bits = (int32_t)value;
350
0
        break;
351
0
    default:
352
0
        return MZ_EXIST_ERROR;
353
1.19k
    }
354
1.19k
    return MZ_OK;
355
1.19k
}
356
357
1.50k
void *mz_stream_zlib_create(void) {
358
1.50k
    mz_stream_zlib *zlib = (mz_stream_zlib *)calloc(1, sizeof(mz_stream_zlib));
359
1.50k
    if (zlib) {
360
1.50k
        zlib->stream.vtbl = &mz_stream_zlib_vtbl;
361
1.50k
        zlib->level = Z_DEFAULT_COMPRESSION;
362
1.50k
        zlib->window_bits = -MAX_WBITS;
363
1.50k
    }
364
1.50k
    return zlib;
365
1.50k
}
366
367
1.50k
void mz_stream_zlib_delete(void **stream) {
368
1.50k
    mz_stream_zlib *zlib = NULL;
369
1.50k
    if (!stream)
370
0
        return;
371
1.50k
    zlib = (mz_stream_zlib *)*stream;
372
1.50k
    free(zlib);
373
1.50k
    *stream = NULL;
374
1.50k
}
375
376
0
void *mz_stream_zlib_get_interface(void) {
377
0
    return (void *)&mz_stream_zlib_vtbl;
378
0
}