Coverage Report

Created: 2026-02-14 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/zlib/gzlib.c
Line
Count
Source
1
/* gzlib.c -- zlib functions common to reading and writing gzip files
2
 * Copyright (C) 2004-2025 Mark Adler
3
 * For conditions of distribution and use, see copyright notice in zlib.h
4
 */
5
6
#include "gzguts.h"
7
8
#if defined(__DJGPP__)
9
#  define LSEEK llseek
10
#elif defined(_WIN32) && !defined(__BORLANDC__) && !defined(UNDER_CE)
11
#  define LSEEK _lseeki64
12
#elif defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
13
99.6k
#  define LSEEK lseek64
14
#else
15
#  define LSEEK lseek
16
#endif
17
18
#if defined UNDER_CE
19
20
/* Map the Windows error number in ERROR to a locale-dependent error message
21
   string and return a pointer to it.  Typically, the values for ERROR come
22
   from GetLastError.
23
24
   The string pointed to shall not be modified by the application, but may be
25
   overwritten by a subsequent call to gz_strwinerror
26
27
   The gz_strwinerror function does not change the current setting of
28
   GetLastError. */
29
char ZLIB_INTERNAL *gz_strwinerror(DWORD error) {
30
    static char buf[1024];
31
32
    wchar_t *msgbuf;
33
    DWORD lasterr = GetLastError();
34
    DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
35
        | FORMAT_MESSAGE_ALLOCATE_BUFFER,
36
        NULL,
37
        error,
38
        0, /* Default language */
39
        (LPVOID)&msgbuf,
40
        0,
41
        NULL);
42
    if (chars != 0) {
43
        /* If there is an \r\n appended, zap it.  */
44
        if (chars >= 2
45
            && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
46
            chars -= 2;
47
            msgbuf[chars] = 0;
48
        }
49
50
        if (chars > sizeof (buf) - 1) {
51
            chars = sizeof (buf) - 1;
52
            msgbuf[chars] = 0;
53
        }
54
55
        wcstombs(buf, msgbuf, chars + 1);       /* assumes buf is big enough */
56
        LocalFree(msgbuf);
57
    }
58
    else {
59
        sprintf(buf, "unknown win32 error (%ld)", error);
60
    }
61
62
    SetLastError(lasterr);
63
    return buf;
64
}
65
66
#endif /* UNDER_CE */
67
68
/* Reset gzip file state */
69
99.4k
local void gz_reset(gz_statep state) {
70
99.4k
    state->x.have = 0;              /* no output data available */
71
99.4k
    if (state->mode == GZ_READ) {   /* for reading ... */
72
99.4k
        state->eof = 0;             /* not at end of file */
73
99.4k
        state->past = 0;            /* have not read past end yet */
74
99.4k
        state->how = LOOK;          /* look for gzip header */
75
99.4k
        state->junk = -1;           /* mark first member */
76
99.4k
    }
77
0
    else                            /* for writing ... */
78
0
        state->reset = 0;           /* no deflateReset pending */
79
99.4k
    state->again = 0;               /* no stalled i/o yet */
80
99.4k
    state->skip = 0;                /* no seek request pending */
81
99.4k
    gz_error(state, Z_OK, NULL);    /* clear error */
82
99.4k
    state->x.pos = 0;               /* no uncompressed data yet */
83
99.4k
    state->strm.avail_in = 0;       /* no input data yet */
84
99.4k
}
85
86
/* Open a gzip file either by name or file descriptor. */
87
96.0k
local gzFile gz_open(const void *path, int fd, const char *mode) {
88
96.0k
    gz_statep state;
89
96.0k
    z_size_t len;
90
96.0k
    int oflag = 0;
91
96.0k
#ifdef O_EXCL
92
96.0k
    int exclusive = 0;
93
96.0k
#endif
94
95
    /* check input */
96
96.0k
    if (path == NULL || mode == NULL)
97
0
        return NULL;
98
99
    /* allocate gzFile structure to return */
100
96.0k
    state = (gz_statep)malloc(sizeof(gz_state));
101
96.0k
    if (state == NULL)
102
0
        return NULL;
103
96.0k
    state->size = 0;            /* no buffers allocated yet */
104
96.0k
    state->want = GZBUFSIZE;    /* requested buffer size */
105
96.0k
    state->err = Z_OK;          /* no error yet */
106
96.0k
    state->msg = NULL;          /* no error message yet */
107
108
    /* interpret mode */
109
96.0k
    state->mode = GZ_NONE;
110
96.0k
    state->level = Z_DEFAULT_COMPRESSION;
111
96.0k
    state->strategy = Z_DEFAULT_STRATEGY;
112
96.0k
    state->direct = 0;
113
288k
    while (*mode) {
114
192k
        if (*mode >= '0' && *mode <= '9')
115
0
            state->level = *mode - '0';
116
192k
        else
117
192k
            switch (*mode) {
118
96.0k
            case 'r':
119
96.0k
                state->mode = GZ_READ;
120
96.0k
                break;
121
0
#ifndef NO_GZCOMPRESS
122
0
            case 'w':
123
0
                state->mode = GZ_WRITE;
124
0
                break;
125
0
            case 'a':
126
0
                state->mode = GZ_APPEND;
127
0
                break;
128
0
#endif
129
0
            case '+':       /* can't read and write at the same time */
130
0
                free(state);
131
0
                return NULL;
132
96.0k
            case 'b':       /* ignore -- will request binary anyway */
133
96.0k
                break;
134
0
#ifdef O_CLOEXEC
135
0
            case 'e':
136
0
                oflag |= O_CLOEXEC;
137
0
                break;
138
0
#endif
139
0
#ifdef O_EXCL
140
0
            case 'x':
141
0
                exclusive = 1;
142
0
                break;
143
0
#endif
144
0
            case 'f':
145
0
                state->strategy = Z_FILTERED;
146
0
                break;
147
0
            case 'h':
148
0
                state->strategy = Z_HUFFMAN_ONLY;
149
0
                break;
150
0
            case 'R':
151
0
                state->strategy = Z_RLE;
152
0
                break;
153
0
            case 'F':
154
0
                state->strategy = Z_FIXED;
155
0
                break;
156
0
            case 'G':
157
0
                state->direct = -1;
158
0
                break;
159
0
#ifdef O_NONBLOCK
160
0
            case 'N':
161
0
                oflag |= O_NONBLOCK;
162
0
                break;
163
0
#endif
164
0
            case 'T':
165
0
                state->direct = 1;
166
0
                break;
167
0
            default:        /* could consider as an error, but just ignore */
168
0
                ;
169
192k
            }
170
192k
        mode++;
171
192k
    }
172
173
    /* must provide an "r", "w", or "a" */
174
96.0k
    if (state->mode == GZ_NONE) {
175
0
        free(state);
176
0
        return NULL;
177
0
    }
178
179
    /* direct is 0, 1 if "T", or -1 if "G" (last "G" or "T" wins) */
180
96.0k
    if (state->mode == GZ_READ) {
181
96.0k
        if (state->direct == 1) {
182
            /* can't force a transparent read */
183
0
            free(state);
184
0
            return NULL;
185
0
        }
186
96.0k
        if (state->direct == 0)
187
            /* default when reading is auto-detect of gzip vs. transparent --
188
               start with a transparent assumption in case of an empty file */
189
96.0k
            state->direct = 1;
190
96.0k
    }
191
0
    else if (state->direct == -1) {
192
        /* "G" has no meaning when writing -- disallow it */
193
0
        free(state);
194
0
        return NULL;
195
0
    }
196
    /* if reading, direct == 1 for auto-detect, -1 for gzip only; if writing or
197
       appending, direct == 0 for gzip, 1 for transparent (copy in to out) */
198
199
    /* save the path name for error messages */
200
#ifdef WIDECHAR
201
    if (fd == -2)
202
        len = wcstombs(NULL, path, 0);
203
    else
204
#endif
205
96.0k
        len = strlen((const char *)path);
206
96.0k
    state->path = (char *)malloc(len + 1);
207
96.0k
    if (state->path == NULL) {
208
0
        free(state);
209
0
        return NULL;
210
0
    }
211
#ifdef WIDECHAR
212
    if (fd == -2) {
213
        if (len)
214
            wcstombs(state->path, path, len + 1);
215
        else
216
            *(state->path) = 0;
217
    }
218
    else
219
#endif
220
96.0k
    {
221
96.0k
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
222
96.0k
        (void)snprintf(state->path, len + 1, "%s", (const char *)path);
223
#else
224
        strcpy(state->path, path);
225
#endif
226
96.0k
    }
227
228
    /* compute the flags for open() */
229
96.0k
    oflag |=
230
96.0k
#ifdef O_LARGEFILE
231
96.0k
        O_LARGEFILE |
232
96.0k
#endif
233
#ifdef O_BINARY
234
        O_BINARY |
235
#endif
236
96.0k
        (state->mode == GZ_READ ?
237
96.0k
         O_RDONLY :
238
96.0k
         (O_WRONLY | O_CREAT |
239
0
#ifdef O_EXCL
240
0
          (exclusive ? O_EXCL : 0) |
241
0
#endif
242
0
          (state->mode == GZ_WRITE ?
243
0
           O_TRUNC :
244
0
           O_APPEND)));
245
246
    /* open the file with the appropriate flags (or just use fd) */
247
96.0k
    if (fd == -1)
248
96.0k
        state->fd = open((const char *)path, oflag, 0666);
249
#ifdef WIDECHAR
250
    else if (fd == -2)
251
        state->fd = _wopen(path, oflag, _S_IREAD | _S_IWRITE);
252
#endif
253
0
    else {
254
0
#ifdef O_NONBLOCK
255
0
        if (oflag & O_NONBLOCK)
256
0
            fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
257
0
#endif
258
0
#ifdef O_CLOEXEC
259
0
        if (oflag & O_CLOEXEC)
260
0
            fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | O_CLOEXEC);
261
0
#endif
262
0
        state->fd = fd;
263
0
    }
264
96.0k
    if (state->fd == -1) {
265
796
        free(state->path);
266
796
        free(state);
267
796
        return NULL;
268
796
    }
269
95.2k
    if (state->mode == GZ_APPEND) {
270
0
        LSEEK(state->fd, 0, SEEK_END);  /* so gzoffset() is correct */
271
0
        state->mode = GZ_WRITE;         /* simplify later checks */
272
0
    }
273
274
    /* save the current position for rewinding (only if reading) */
275
95.2k
    if (state->mode == GZ_READ) {
276
95.2k
        state->start = LSEEK(state->fd, 0, SEEK_CUR);
277
95.2k
        if (state->start == -1) state->start = 0;
278
95.2k
    }
279
280
    /* initialize stream */
281
95.2k
    gz_reset(state);
282
283
    /* return stream */
284
95.2k
    return (gzFile)state;
285
96.0k
}
286
287
/* -- see zlib.h -- */
288
96.0k
gzFile ZEXPORT gzopen(const char *path, const char *mode) {
289
96.0k
    return gz_open(path, -1, mode);
290
96.0k
}
291
292
/* -- see zlib.h -- */
293
0
gzFile ZEXPORT gzopen64(const char *path, const char *mode) {
294
0
    return gz_open(path, -1, mode);
295
0
}
296
297
/* -- see zlib.h -- */
298
0
gzFile ZEXPORT gzdopen(int fd, const char *mode) {
299
0
    char *path;         /* identifier for error messages */
300
0
    gzFile gz;
301
302
0
    if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
303
0
        return NULL;
304
0
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
305
0
    (void)snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd);
306
#else
307
    sprintf(path, "<fd:%d>", fd);   /* for debugging */
308
#endif
309
0
    gz = gz_open(path, fd, mode);
310
0
    free(path);
311
0
    return gz;
312
0
}
313
314
/* -- see zlib.h -- */
315
#ifdef WIDECHAR
316
gzFile ZEXPORT gzopen_w(const wchar_t *path, const char *mode) {
317
    return gz_open(path, -2, mode);
318
}
319
#endif
320
321
/* -- see zlib.h -- */
322
0
int ZEXPORT gzbuffer(gzFile file, unsigned size) {
323
0
    gz_statep state;
324
325
    /* get internal structure and check integrity */
326
0
    if (file == NULL)
327
0
        return -1;
328
0
    state = (gz_statep)file;
329
0
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
330
0
        return -1;
331
332
    /* make sure we haven't already allocated memory */
333
0
    if (state->size != 0)
334
0
        return -1;
335
336
    /* check and set requested size */
337
0
    if ((size << 1) < size)
338
0
        return -1;              /* need to be able to double it */
339
0
    if (size < 8)
340
0
        size = 8;               /* needed to behave well with flushing */
341
0
    state->want = size;
342
0
    return 0;
343
0
}
344
345
/* -- see zlib.h -- */
346
4.23k
int ZEXPORT gzrewind(gzFile file) {
347
4.23k
    gz_statep state;
348
349
    /* get internal structure */
350
4.23k
    if (file == NULL)
351
0
        return -1;
352
4.23k
    state = (gz_statep)file;
353
354
    /* check that we're reading and that there's no error */
355
4.23k
    if (state->mode != GZ_READ ||
356
4.23k
            (state->err != Z_OK && state->err != Z_BUF_ERROR))
357
0
        return -1;
358
359
    /* back up and start over */
360
4.23k
    if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
361
0
        return -1;
362
4.23k
    gz_reset(state);
363
4.23k
    return 0;
364
4.23k
}
365
366
/* -- see zlib.h -- */
367
54.3k
z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
368
54.3k
    unsigned n;
369
54.3k
    z_off64_t ret;
370
54.3k
    gz_statep state;
371
372
    /* get internal structure and check integrity */
373
54.3k
    if (file == NULL)
374
0
        return -1;
375
54.3k
    state = (gz_statep)file;
376
54.3k
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
377
0
        return -1;
378
379
    /* check that there's no error */
380
54.3k
    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
381
1.59k
        return -1;
382
383
    /* can only seek from start or relative to current position */
384
52.7k
    if (whence != SEEK_SET && whence != SEEK_CUR)
385
0
        return -1;
386
387
    /* normalize offset to a SEEK_CUR specification */
388
52.7k
    if (whence == SEEK_SET)
389
5.79k
        offset -= state->x.pos;
390
46.9k
    else {
391
46.9k
        offset += state->past ? 0 : state->skip;
392
46.9k
        state->skip = 0;
393
46.9k
    }
394
395
    /* if within raw area while reading, just go there */
396
52.7k
    if (state->mode == GZ_READ && state->how == COPY &&
397
166
            state->x.pos + offset >= 0) {
398
166
        ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR);
399
166
        if (ret == -1)
400
0
            return -1;
401
166
        state->x.have = 0;
402
166
        state->eof = 0;
403
166
        state->past = 0;
404
166
        state->skip = 0;
405
166
        gz_error(state, Z_OK, NULL);
406
166
        state->strm.avail_in = 0;
407
166
        state->x.pos += offset;
408
166
        return state->x.pos;
409
166
    }
410
411
    /* calculate skip amount, rewinding if needed for back seek when reading */
412
52.5k
    if (offset < 0) {
413
4.23k
        if (state->mode != GZ_READ)         /* writing -- can't go backwards */
414
0
            return -1;
415
4.23k
        offset += state->x.pos;
416
4.23k
        if (offset < 0)                     /* before start of file! */
417
0
            return -1;
418
4.23k
        if (gzrewind(file) == -1)           /* rewind, then skip to offset */
419
0
            return -1;
420
4.23k
    }
421
422
    /* if reading, skip what's in output buffer (one less gzgetc() check) */
423
52.5k
    if (state->mode == GZ_READ) {
424
52.5k
        n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
425
52.1k
            (unsigned)offset : state->x.have;
426
52.5k
        state->x.have -= n;
427
52.5k
        state->x.next += n;
428
52.5k
        state->x.pos += n;
429
52.5k
        offset -= n;
430
52.5k
    }
431
432
    /* request skip (if not zero) */
433
52.5k
    state->skip = offset;
434
52.5k
    return state->x.pos + offset;
435
52.5k
}
436
437
/* -- see zlib.h -- */
438
54.3k
z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) {
439
54.3k
    z_off64_t ret;
440
441
54.3k
    ret = gzseek64(file, (z_off64_t)offset, whence);
442
54.3k
    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
443
54.3k
}
444
445
/* -- see zlib.h -- */
446
7.98k
z_off64_t ZEXPORT gztell64(gzFile file) {
447
7.98k
    gz_statep state;
448
449
    /* get internal structure and check integrity */
450
7.98k
    if (file == NULL)
451
0
        return -1;
452
7.98k
    state = (gz_statep)file;
453
7.98k
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
454
0
        return -1;
455
456
    /* return position */
457
7.98k
    return state->x.pos + (state->past ? 0 : state->skip);
458
7.98k
}
459
460
/* -- see zlib.h -- */
461
7.98k
z_off_t ZEXPORT gztell(gzFile file) {
462
7.98k
    z_off64_t ret;
463
464
7.98k
    ret = gztell64(file);
465
7.98k
    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
466
7.98k
}
467
468
/* -- see zlib.h -- */
469
0
z_off64_t ZEXPORT gzoffset64(gzFile file) {
470
0
    z_off64_t offset;
471
0
    gz_statep state;
472
473
    /* get internal structure and check integrity */
474
0
    if (file == NULL)
475
0
        return -1;
476
0
    state = (gz_statep)file;
477
0
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
478
0
        return -1;
479
480
    /* compute and return effective offset in file */
481
0
    offset = LSEEK(state->fd, 0, SEEK_CUR);
482
0
    if (offset == -1)
483
0
        return -1;
484
0
    if (state->mode == GZ_READ)             /* reading */
485
0
        offset -= state->strm.avail_in;     /* don't count buffered input */
486
0
    return offset;
487
0
}
488
489
/* -- see zlib.h -- */
490
0
z_off_t ZEXPORT gzoffset(gzFile file) {
491
0
    z_off64_t ret;
492
493
0
    ret = gzoffset64(file);
494
0
    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
495
0
}
496
497
/* -- see zlib.h -- */
498
148M
int ZEXPORT gzeof(gzFile file) {
499
148M
    gz_statep state;
500
501
    /* get internal structure and check integrity */
502
148M
    if (file == NULL)
503
0
        return 0;
504
148M
    state = (gz_statep)file;
505
148M
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
506
0
        return 0;
507
508
    /* return end-of-file state */
509
148M
    return state->mode == GZ_READ ? state->past : 0;
510
148M
}
511
512
/* -- see zlib.h -- */
513
149M
const char * ZEXPORT gzerror(gzFile file, int *errnum) {
514
149M
    gz_statep state;
515
516
    /* get internal structure and check integrity */
517
149M
    if (file == NULL)
518
0
        return NULL;
519
149M
    state = (gz_statep)file;
520
149M
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
521
0
        return NULL;
522
523
    /* return error information */
524
149M
    if (errnum != NULL)
525
149M
        *errnum = state->err;
526
149M
    return state->err == Z_MEM_ERROR ? "out of memory" :
527
149M
                                       (state->msg == NULL ? "" : state->msg);
528
149M
}
529
530
/* -- see zlib.h -- */
531
0
void ZEXPORT gzclearerr(gzFile file) {
532
0
    gz_statep state;
533
534
    /* get internal structure and check integrity */
535
0
    if (file == NULL)
536
0
        return;
537
0
    state = (gz_statep)file;
538
0
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
539
0
        return;
540
541
    /* clear error and end-of-file */
542
0
    if (state->mode == GZ_READ) {
543
0
        state->eof = 0;
544
0
        state->past = 0;
545
0
    }
546
0
    gz_error(state, Z_OK, NULL);
547
0
}
548
549
/* Create an error message in allocated memory and set state->err and
550
   state->msg accordingly.  Free any previous error message already there.  Do
551
   not try to free or allocate space if the error is Z_MEM_ERROR (out of
552
   memory).  Simply save the error message as a static string.  If there is an
553
   allocation failure constructing the error message, then convert the error to
554
   out of memory. */
555
878k
void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) {
556
    /* free previously allocated message and clear */
557
878k
    if (state->msg != NULL) {
558
40.3k
        if (state->err != Z_MEM_ERROR)
559
40.3k
            free(state->msg);
560
40.3k
        state->msg = NULL;
561
40.3k
    }
562
563
    /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
564
878k
    if (err != Z_OK && err != Z_BUF_ERROR && !state->again)
565
7.00k
        state->x.have = 0;
566
567
    /* set error code, and if no message, then done */
568
878k
    state->err = err;
569
878k
    if (msg == NULL)
570
837k
        return;
571
572
    /* for an out of memory error, return literal string when requested */
573
40.3k
    if (err == Z_MEM_ERROR)
574
0
        return;
575
576
    /* construct error message with path */
577
40.3k
    if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
578
40.3k
            NULL) {
579
0
        state->err = Z_MEM_ERROR;
580
0
        return;
581
0
    }
582
40.3k
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
583
40.3k
    (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
584
40.3k
                   "%s%s%s", state->path, ": ", msg);
585
#else
586
    strcpy(state->msg, state->path);
587
    strcat(state->msg, ": ");
588
    strcat(state->msg, msg);
589
#endif
590
40.3k
}
591
592
/* portably return maximum value for an int (when limits.h presumed not
593
   available) -- we need to do this to cover cases where 2's complement not
594
   used, since C standard permits 1's complement and sign-bit representations,
595
   otherwise we could just use ((unsigned)-1) >> 1 */
596
0
unsigned ZLIB_INTERNAL gz_intmax(void) {
597
0
#ifdef INT_MAX
598
0
    return INT_MAX;
599
#else
600
    unsigned p = 1, q;
601
602
    do {
603
        q = p;
604
        p <<= 1;
605
        p++;
606
    } while (p > q);
607
    return q >> 1;
608
#endif
609
0
}