Coverage Report

Created: 2026-09-28 06:47

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-2026 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
45.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
45.6k
local void gz_reset(gz_statep state) {
70
45.6k
    state->x.have = 0;              /* no output data available */
71
45.6k
    state->past = 0;                /* have not read past end yet */
72
45.6k
    if (state->mode == GZ_READ) {   /* for reading ... */
73
45.6k
        state->eof = 0;             /* not at end of file */
74
45.6k
        state->how = LOOK;          /* look for gzip header */
75
45.6k
        state->junk = -1;           /* mark first member */
76
45.6k
    }
77
0
    else                            /* for writing ... */
78
0
        state->reset = 0;           /* no deflateReset pending */
79
45.6k
    state->again = 0;               /* no stalled i/o yet */
80
45.6k
    state->skip = 0;                /* no seek request pending */
81
45.6k
    gz_error(state, Z_OK, NULL);    /* clear error */
82
45.6k
    state->x.pos = 0;               /* no uncompressed data yet */
83
45.6k
    state->strm.avail_in = 0;       /* no input data yet */
84
45.6k
}
85
86
/* Open a gzip file either by name or file descriptor. */
87
46.1k
local gzFile gz_open(const void *path, int fd, const char *mode) {
88
46.1k
    gz_statep state;
89
46.1k
    z_size_t len;
90
46.1k
    int oflag = 0;
91
46.1k
#ifdef O_EXCL
92
46.1k
    int exclusive = 0;
93
46.1k
#endif
94
95
    /* check input */
96
46.1k
    if (path == NULL || mode == NULL)
97
0
        return NULL;
98
99
    /* allocate gzFile structure to return */
100
46.1k
    state = (gz_statep)malloc(sizeof(gz_state));
101
46.1k
    if (state == NULL)
102
0
        return NULL;
103
46.1k
    state->size = 0;            /* no buffers allocated yet */
104
46.1k
    state->want = GZBUFSIZE;    /* requested buffer size */
105
46.1k
    state->err = Z_OK;          /* no error yet */
106
46.1k
    state->msg = NULL;          /* no error message yet */
107
108
    /* interpret mode */
109
46.1k
    state->mode = GZ_NONE;
110
46.1k
    state->level = Z_DEFAULT_COMPRESSION;
111
46.1k
    state->strategy = Z_DEFAULT_STRATEGY;
112
46.1k
    state->direct = 0;
113
138k
    while (*mode) {
114
92.2k
        if (*mode >= '0' && *mode <= '9')
115
0
            state->level = *mode - '0';
116
92.2k
        else
117
92.2k
            switch (*mode) {
118
46.1k
            case 'r':
119
46.1k
                state->mode = GZ_READ;
120
46.1k
                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
46.1k
            case 'b':       /* ignore -- will request binary anyway */
133
46.1k
                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
92.2k
            }
170
92.2k
        mode++;
171
92.2k
    }
172
173
    /* must provide an "r", "w", or "a" */
174
46.1k
    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
46.1k
    if (state->mode == GZ_READ) {
181
46.1k
        if (state->direct == 1) {
182
            /* can't force a transparent read */
183
0
            free(state);
184
0
            return NULL;
185
0
        }
186
46.1k
        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
46.1k
            state->direct = 1;
190
46.1k
    }
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
46.1k
        len = strlen((const char *)path);
206
46.1k
    state->path = (char *)malloc(len + 1);
207
46.1k
    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
46.1k
    {
221
46.1k
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
222
46.1k
        (void)snprintf(state->path, len + 1, "%s", (const char *)path);
223
#else
224
        strcpy(state->path, path);
225
#endif
226
46.1k
    }
227
228
    /* compute the flags for open() */
229
46.1k
    oflag |=
230
46.1k
#ifdef O_LARGEFILE
231
46.1k
        O_LARGEFILE |
232
46.1k
#endif
233
#ifdef O_BINARY
234
        O_BINARY |
235
#endif
236
46.1k
        (state->mode == GZ_READ ?
237
46.1k
         O_RDONLY :
238
46.1k
         (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
46.1k
    if (fd == -1)
248
46.1k
        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
46.1k
    if (state->fd == -1) {
265
952
        free(state->path);
266
952
        free(state);
267
952
        return NULL;
268
952
    }
269
45.1k
    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
45.1k
    if (state->mode == GZ_READ) {
276
45.1k
        state->start = LSEEK(state->fd, 0, SEEK_CUR);
277
45.1k
        if (state->start == -1) state->start = 0;
278
45.1k
    }
279
280
    /* initialize stream */
281
45.1k
    gz_reset(state);
282
283
    /* return stream */
284
45.1k
    return (gzFile)state;
285
46.1k
}
286
287
/* -- see zlib.h -- */
288
46.1k
gzFile ZEXPORT gzopen(const char *path, const char *mode) {
289
46.1k
    return gz_open(path, -1, mode);
290
46.1k
}
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
449
int ZEXPORT gzrewind(gzFile file) {
347
449
    gz_statep state;
348
349
    /* get internal structure */
350
449
    if (file == NULL)
351
0
        return -1;
352
449
    state = (gz_statep)file;
353
354
    /* check that we're reading and that there's no error */
355
449
    if (state->mode != GZ_READ ||
356
449
            (state->err != Z_OK && state->err != Z_BUF_ERROR))
357
0
        return -1;
358
359
    /* back up and start over */
360
449
    if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
361
0
        return -1;
362
449
    gz_reset(state);
363
449
    return 0;
364
449
}
365
366
/* -- see zlib.h -- */
367
22.8k
z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
368
22.8k
    unsigned n;
369
22.8k
    z_off64_t ret, pos;
370
22.8k
    gz_statep state;
371
372
    /* get internal structure and check integrity */
373
22.8k
    if (file == NULL)
374
0
        return -1;
375
22.8k
    state = (gz_statep)file;
376
22.8k
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
377
0
        return -1;
378
379
    /* check that there's no error */
380
22.8k
    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
381
129
        return -1;
382
383
    /* can only seek from start or relative to current position */
384
22.7k
    if (whence != SEEK_SET && whence != SEEK_CUR)
385
0
        return -1;
386
387
    /* compute the absolute position */
388
22.7k
    pos = whence == SEEK_SET ? 0 :
389
22.7k
          state->x.pos + (state->past ? 0 : state->skip);
390
22.7k
    if (offset > GZ_OFF_MAX - pos)
391
0
        return -1;                          /* would overflow z_off64_t */
392
22.7k
    if (offset < -pos)
393
0
        return -1;                          /* before start of file */
394
22.7k
    pos += offset;
395
396
    /* if within raw area while reading, just go there */
397
22.7k
    if (state->mode == GZ_READ && state->how == COPY) {
398
9
        ret = LSEEK(state->fd, pos - state->x.pos - (z_off64_t)state->x.have,
399
9
                    SEEK_CUR);
400
9
        if (ret == -1)
401
0
            return -1;
402
9
        state->x.have = 0;
403
9
        state->eof = 0;
404
9
        state->past = 0;
405
9
        state->skip = 0;
406
9
        gz_error(state, Z_OK, NULL);
407
9
        state->strm.avail_in = 0;
408
9
        state->x.pos = pos;
409
9
        return pos;
410
9
    }
411
412
    /* rewind if needed for back seek when reading */
413
22.7k
    if (pos < state->x.pos) {
414
449
        if (state->mode != GZ_READ)         /* writing -- can't go backwards */
415
0
            return -1;
416
449
        if (gzrewind(file) == -1)           /* rewind, then skip to pos */
417
0
            return -1;
418
449
    }
419
22.7k
    offset = pos - state->x.pos;
420
421
    /* if reading, skip what's in output buffer (one less gzgetc() check) */
422
22.7k
    if (state->mode == GZ_READ) {
423
22.7k
        n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
424
22.6k
            (unsigned)offset : state->x.have;
425
22.7k
        state->x.have -= n;
426
22.7k
        state->x.next += n;
427
22.7k
        state->x.pos += n;
428
22.7k
        offset -= n;
429
22.7k
    }
430
431
    /* request skip (if not zero) */
432
22.7k
    state->skip = offset;
433
22.7k
    return pos;
434
22.7k
}
435
436
/* -- see zlib.h -- */
437
22.8k
z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) {
438
22.8k
    z_off64_t ret;
439
440
22.8k
    ret = gzseek64(file, (z_off64_t)offset, whence);
441
22.8k
    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
442
22.8k
}
443
444
/* -- see zlib.h -- */
445
1.03k
z_off64_t ZEXPORT gztell64(gzFile file) {
446
1.03k
    gz_statep state;
447
448
    /* get internal structure and check integrity */
449
1.03k
    if (file == NULL)
450
0
        return -1;
451
1.03k
    state = (gz_statep)file;
452
1.03k
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
453
0
        return -1;
454
455
    /* return position */
456
1.03k
    return state->x.pos + (state->past ? 0 : state->skip);
457
1.03k
}
458
459
/* -- see zlib.h -- */
460
1.03k
z_off_t ZEXPORT gztell(gzFile file) {
461
1.03k
    z_off64_t ret;
462
463
1.03k
    ret = gztell64(file);
464
1.03k
    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
465
1.03k
}
466
467
/* -- see zlib.h -- */
468
0
z_off64_t ZEXPORT gzoffset64(gzFile file) {
469
0
    z_off64_t offset;
470
0
    gz_statep state;
471
472
    /* get internal structure and check integrity */
473
0
    if (file == NULL)
474
0
        return -1;
475
0
    state = (gz_statep)file;
476
0
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
477
0
        return -1;
478
479
    /* compute and return effective offset in file */
480
0
    offset = LSEEK(state->fd, 0, SEEK_CUR);
481
0
    if (offset == -1)
482
0
        return -1;
483
0
    if (state->mode == GZ_READ)             /* reading */
484
0
        offset -= state->strm.avail_in;     /* don't count buffered input */
485
0
    return offset;
486
0
}
487
488
/* -- see zlib.h -- */
489
0
z_off_t ZEXPORT gzoffset(gzFile file) {
490
0
    z_off64_t ret;
491
492
0
    ret = gzoffset64(file);
493
0
    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
494
0
}
495
496
/* -- see zlib.h -- */
497
77.9M
int ZEXPORT gzeof(gzFile file) {
498
77.9M
    gz_statep state;
499
500
    /* get internal structure and check integrity */
501
77.9M
    if (file == NULL)
502
0
        return 0;
503
77.9M
    state = (gz_statep)file;
504
77.9M
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
505
0
        return 0;
506
507
    /* return end-of-file state */
508
77.9M
    return state->mode == GZ_READ ? state->past : 0;
509
77.9M
}
510
511
/* -- see zlib.h -- */
512
77.9M
const char * ZEXPORT gzerror(gzFile file, int *errnum) {
513
77.9M
    gz_statep state;
514
515
    /* get internal structure and check integrity */
516
77.9M
    if (file == NULL)
517
0
        return NULL;
518
77.9M
    state = (gz_statep)file;
519
77.9M
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
520
0
        return NULL;
521
522
    /* return error information */
523
77.9M
    if (errnum != NULL)
524
77.9M
        *errnum = state->err;
525
77.9M
    return state->err == Z_MEM_ERROR ? "out of memory" :
526
77.9M
                                       (state->msg == NULL ? "" : state->msg);
527
77.9M
}
528
529
/* -- see zlib.h -- */
530
0
void ZEXPORT gzclearerr(gzFile file) {
531
0
    gz_statep state;
532
533
    /* get internal structure and check integrity */
534
0
    if (file == NULL)
535
0
        return;
536
0
    state = (gz_statep)file;
537
0
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
538
0
        return;
539
540
    /* clear error and end-of-file */
541
0
    if (state->mode == GZ_READ) {
542
0
        state->eof = 0;
543
0
        state->past = 0;
544
0
    }
545
0
    gz_error(state, Z_OK, NULL);
546
0
}
547
548
/* Create an error message in allocated memory and set state->err and
549
   state->msg accordingly.  Free any previous error message already there.  Do
550
   not try to free or allocate space if the error is Z_MEM_ERROR (out of
551
   memory).  Simply save the error message as a static string.  If there is an
552
   allocation failure constructing the error message, then convert the error to
553
   out of memory. */
554
110k
void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) {
555
    /* free previously allocated message and clear */
556
110k
    if (state->msg != NULL) {
557
19.3k
        if (state->err != Z_MEM_ERROR)
558
19.3k
            free(state->msg);
559
19.3k
        state->msg = NULL;
560
19.3k
    }
561
562
    /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
563
110k
    if (err != Z_OK && err != Z_BUF_ERROR && !state->again)
564
4.50k
        state->x.have = 0;
565
566
    /* set error code, and if no message, then done */
567
110k
    state->err = err;
568
110k
    if (msg == NULL)
569
90.7k
        return;
570
571
    /* for an out of memory error, return literal string when requested */
572
19.3k
    if (err == Z_MEM_ERROR)
573
0
        return;
574
575
    /* construct error message with path */
576
19.3k
    if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
577
19.3k
            NULL) {
578
0
        state->err = Z_MEM_ERROR;
579
0
        return;
580
0
    }
581
19.3k
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
582
19.3k
    (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
583
19.3k
                   "%s%s%s", state->path, ": ", msg);
584
#else
585
    strcpy(state->msg, state->path);
586
    strcat(state->msg, ": ");
587
    strcat(state->msg, msg);
588
#endif
589
19.3k
}
590
591
/* portably return maximum value for an int (when limits.h presumed not
592
   available) -- we need to do this to cover cases where 2's complement not
593
   used, since C standard permits 1's complement and sign-bit representations,
594
   otherwise we could just use ((unsigned)-1) >> 1 */
595
0
unsigned ZLIB_INTERNAL gz_intmax(void) {
596
0
#ifdef INT_MAX
597
0
    return INT_MAX;
598
#else
599
    unsigned p = 1, q;
600
601
    do {
602
        q = p;
603
        p <<= 1;
604
        p++;
605
    } while (p > q);
606
    return q >> 1;
607
#endif
608
0
}