Coverage Report

Created: 2026-03-07 06:05

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
4.53k
#  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
8.70k
local void gz_reset(gz_statep state) {
70
8.70k
    state->x.have = 0;              /* no output data available */
71
8.70k
    if (state->mode == GZ_READ) {   /* for reading ... */
72
3.88k
        state->eof = 0;             /* not at end of file */
73
3.88k
        state->past = 0;            /* have not read past end yet */
74
3.88k
        state->how = LOOK;          /* look for gzip header */
75
3.88k
        state->junk = -1;           /* mark first member */
76
3.88k
    }
77
4.81k
    else                            /* for writing ... */
78
4.81k
        state->reset = 0;           /* no deflateReset pending */
79
8.70k
    state->again = 0;               /* no stalled i/o yet */
80
8.70k
    state->skip = 0;                /* no seek request pending */
81
8.70k
    gz_error(state, Z_OK, NULL);    /* clear error */
82
8.70k
    state->x.pos = 0;               /* no uncompressed data yet */
83
8.70k
    state->strm.avail_in = 0;       /* no input data yet */
84
8.70k
}
85
86
/* Open a gzip file either by name or file descriptor. */
87
9.14k
local gzFile gz_open(const void *path, int fd, const char *mode) {
88
9.14k
    gz_statep state;
89
9.14k
    z_size_t len;
90
9.14k
    int oflag = 0;
91
9.14k
#ifdef O_EXCL
92
9.14k
    int exclusive = 0;
93
9.14k
#endif
94
95
    /* check input */
96
9.14k
    if (path == NULL || mode == NULL)
97
0
        return NULL;
98
99
    /* allocate gzFile structure to return */
100
9.14k
    state = (gz_statep)malloc(sizeof(gz_state));
101
9.14k
    if (state == NULL)
102
0
        return NULL;
103
9.14k
    state->size = 0;            /* no buffers allocated yet */
104
9.14k
    state->want = GZBUFSIZE;    /* requested buffer size */
105
9.14k
    state->err = Z_OK;          /* no error yet */
106
9.14k
    state->msg = NULL;          /* no error message yet */
107
108
    /* interpret mode */
109
9.14k
    state->mode = GZ_NONE;
110
9.14k
    state->level = Z_DEFAULT_COMPRESSION;
111
9.14k
    state->strategy = Z_DEFAULT_STRATEGY;
112
9.14k
    state->direct = 0;
113
42.2k
    while (*mode) {
114
33.0k
        if (*mode >= '0' && *mode <= '9')
115
699
            state->level = *mode - '0';
116
32.3k
        else
117
32.3k
            switch (*mode) {
118
3.93k
            case 'r':
119
3.93k
                state->mode = GZ_READ;
120
3.93k
                break;
121
0
#ifndef NO_GZCOMPRESS
122
4.29k
            case 'w':
123
4.29k
                state->mode = GZ_WRITE;
124
4.29k
                break;
125
935
            case 'a':
126
935
                state->mode = GZ_APPEND;
127
935
                break;
128
0
#endif
129
32
            case '+':       /* can't read and write at the same time */
130
32
                free(state);
131
32
                return NULL;
132
7.39k
            case 'b':       /* ignore -- will request binary anyway */
133
7.39k
                break;
134
0
#ifdef O_CLOEXEC
135
79
            case 'e':
136
79
                oflag |= O_CLOEXEC;
137
79
                break;
138
0
#endif
139
0
#ifdef O_EXCL
140
28
            case 'x':
141
28
                exclusive = 1;
142
28
                break;
143
0
#endif
144
771
            case 'f':
145
771
                state->strategy = Z_FILTERED;
146
771
                break;
147
980
            case 'h':
148
980
                state->strategy = Z_HUFFMAN_ONLY;
149
980
                break;
150
1.31k
            case 'R':
151
1.31k
                state->strategy = Z_RLE;
152
1.31k
                break;
153
42
            case 'F':
154
42
                state->strategy = Z_FIXED;
155
42
                break;
156
92
            case 'G':
157
92
                state->direct = -1;
158
92
                break;
159
0
#ifdef O_NONBLOCK
160
52
            case 'N':
161
52
                oflag |= O_NONBLOCK;
162
52
                break;
163
0
#endif
164
55
            case 'T':
165
55
                state->direct = 1;
166
55
                break;
167
12.3k
            default:        /* could consider as an error, but just ignore */
168
12.3k
                ;
169
32.3k
            }
170
33.0k
        mode++;
171
33.0k
    }
172
173
    /* must provide an "r", "w", or "a" */
174
9.11k
    if (state->mode == GZ_NONE) {
175
405
        free(state);
176
405
        return NULL;
177
405
    }
178
179
    /* direct is 0, 1 if "T", or -1 if "G" (last "G" or "T" wins) */
180
8.70k
    if (state->mode == GZ_READ) {
181
3.88k
        if (state->direct == 1) {
182
            /* can't force a transparent read */
183
7
            free(state);
184
7
            return NULL;
185
7
        }
186
3.87k
        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
3.83k
            state->direct = 1;
190
3.87k
    }
191
4.82k
    else if (state->direct == -1) {
192
        /* "G" has no meaning when writing -- disallow it */
193
2
        free(state);
194
2
        return NULL;
195
2
    }
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
8.69k
        len = strlen((const char *)path);
206
8.69k
    state->path = (char *)malloc(len + 1);
207
8.69k
    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
8.69k
    {
221
8.69k
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
222
8.69k
        (void)snprintf(state->path, len + 1, "%s", (const char *)path);
223
#else
224
        strcpy(state->path, path);
225
#endif
226
8.69k
    }
227
228
    /* compute the flags for open() */
229
8.69k
    oflag |=
230
8.69k
#ifdef O_LARGEFILE
231
8.69k
        O_LARGEFILE |
232
8.69k
#endif
233
#ifdef O_BINARY
234
        O_BINARY |
235
#endif
236
8.69k
        (state->mode == GZ_READ ?
237
8.69k
         O_RDONLY :
238
8.69k
         (O_WRONLY | O_CREAT |
239
4.81k
#ifdef O_EXCL
240
4.81k
          (exclusive ? O_EXCL : 0) |
241
4.81k
#endif
242
4.81k
          (state->mode == GZ_WRITE ?
243
4.81k
           O_TRUNC :
244
4.81k
           O_APPEND)));
245
246
    /* open the file with the appropriate flags (or just use fd) */
247
8.69k
    if (fd == -1)
248
8.69k
        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
8.69k
    if (state->fd == -1) {
265
2
        free(state->path);
266
2
        free(state);
267
2
        return NULL;
268
2
    }
269
8.69k
    if (state->mode == GZ_APPEND) {
270
639
        LSEEK(state->fd, 0, SEEK_END);  /* so gzoffset() is correct */
271
639
        state->mode = GZ_WRITE;         /* simplify later checks */
272
639
    }
273
274
    /* save the current position for rewinding (only if reading) */
275
8.69k
    if (state->mode == GZ_READ) {
276
3.87k
        state->start = LSEEK(state->fd, 0, SEEK_CUR);
277
3.87k
        if (state->start == -1) state->start = 0;
278
3.87k
    }
279
280
    /* initialize stream */
281
8.69k
    gz_reset(state);
282
283
    /* return stream */
284
8.69k
    return (gzFile)state;
285
8.69k
}
286
287
/* -- see zlib.h -- */
288
9.14k
gzFile ZEXPORT gzopen(const char *path, const char *mode) {
289
9.14k
    return gz_open(path, -1, mode);
290
9.14k
}
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
201
int ZEXPORT gzbuffer(gzFile file, unsigned size) {
323
201
    gz_statep state;
324
325
    /* get internal structure and check integrity */
326
201
    if (file == NULL)
327
8
        return -1;
328
193
    state = (gz_statep)file;
329
193
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
330
0
        return -1;
331
332
    /* make sure we haven't already allocated memory */
333
193
    if (state->size != 0)
334
1
        return -1;
335
336
    /* check and set requested size */
337
192
    if ((size << 1) < size)
338
0
        return -1;              /* need to be able to double it */
339
192
    if (size < 8)
340
39
        size = 8;               /* needed to behave well with flushing */
341
192
    state->want = size;
342
192
    return 0;
343
192
}
344
345
/* -- see zlib.h -- */
346
21
int ZEXPORT gzrewind(gzFile file) {
347
21
    gz_statep state;
348
349
    /* get internal structure */
350
21
    if (file == NULL)
351
7
        return -1;
352
14
    state = (gz_statep)file;
353
354
    /* check that we're reading and that there's no error */
355
14
    if (state->mode != GZ_READ ||
356
5
            (state->err != Z_OK && state->err != Z_BUF_ERROR))
357
9
        return -1;
358
359
    /* back up and start over */
360
5
    if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
361
0
        return -1;
362
5
    gz_reset(state);
363
5
    return 0;
364
5
}
365
366
/* -- see zlib.h -- */
367
323
z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
368
323
    unsigned n;
369
323
    z_off64_t ret;
370
323
    gz_statep state;
371
372
    /* get internal structure and check integrity */
373
323
    if (file == NULL)
374
25
        return -1;
375
298
    state = (gz_statep)file;
376
298
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
377
0
        return -1;
378
379
    /* check that there's no error */
380
298
    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
381
0
        return -1;
382
383
    /* can only seek from start or relative to current position */
384
298
    if (whence != SEEK_SET && whence != SEEK_CUR)
385
1
        return -1;
386
387
    /* normalize offset to a SEEK_CUR specification */
388
297
    if (whence == SEEK_SET)
389
211
        offset -= state->x.pos;
390
86
    else {
391
86
        offset += state->past ? 0 : state->skip;
392
86
        state->skip = 0;
393
86
    }
394
395
    /* if within raw area while reading, just go there */
396
297
    if (state->mode == GZ_READ && state->how == COPY &&
397
0
            state->x.pos + offset >= 0) {
398
0
        ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR);
399
0
        if (ret == -1)
400
0
            return -1;
401
0
        state->x.have = 0;
402
0
        state->eof = 0;
403
0
        state->past = 0;
404
0
        state->skip = 0;
405
0
        gz_error(state, Z_OK, NULL);
406
0
        state->strm.avail_in = 0;
407
0
        state->x.pos += offset;
408
0
        return state->x.pos;
409
0
    }
410
411
    /* calculate skip amount, rewinding if needed for back seek when reading */
412
297
    if (offset < 0) {
413
10
        if (state->mode != GZ_READ)         /* writing -- can't go backwards */
414
10
            return -1;
415
0
        offset += state->x.pos;
416
0
        if (offset < 0)                     /* before start of file! */
417
0
            return -1;
418
0
        if (gzrewind(file) == -1)           /* rewind, then skip to offset */
419
0
            return -1;
420
0
    }
421
422
    /* if reading, skip what's in output buffer (one less gzgetc() check) */
423
287
    if (state->mode == GZ_READ) {
424
26
        n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
425
26
            (unsigned)offset : state->x.have;
426
26
        state->x.have -= n;
427
26
        state->x.next += n;
428
26
        state->x.pos += n;
429
26
        offset -= n;
430
26
    }
431
432
    /* request skip (if not zero) */
433
287
    state->skip = offset;
434
287
    return state->x.pos + offset;
435
297
}
436
437
/* -- see zlib.h -- */
438
323
z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) {
439
323
    z_off64_t ret;
440
441
323
    ret = gzseek64(file, (z_off64_t)offset, whence);
442
323
    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
443
323
}
444
445
/* -- see zlib.h -- */
446
32
z_off64_t ZEXPORT gztell64(gzFile file) {
447
32
    gz_statep state;
448
449
    /* get internal structure and check integrity */
450
32
    if (file == NULL)
451
16
        return -1;
452
16
    state = (gz_statep)file;
453
16
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
454
0
        return -1;
455
456
    /* return position */
457
16
    return state->x.pos + (state->past ? 0 : state->skip);
458
16
}
459
460
/* -- see zlib.h -- */
461
32
z_off_t ZEXPORT gztell(gzFile file) {
462
32
    z_off64_t ret;
463
464
32
    ret = gztell64(file);
465
32
    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
466
32
}
467
468
/* -- see zlib.h -- */
469
18
z_off64_t ZEXPORT gzoffset64(gzFile file) {
470
18
    z_off64_t offset;
471
18
    gz_statep state;
472
473
    /* get internal structure and check integrity */
474
18
    if (file == NULL)
475
6
        return -1;
476
12
    state = (gz_statep)file;
477
12
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
478
0
        return -1;
479
480
    /* compute and return effective offset in file */
481
12
    offset = LSEEK(state->fd, 0, SEEK_CUR);
482
12
    if (offset == -1)
483
0
        return -1;
484
12
    if (state->mode == GZ_READ)             /* reading */
485
4
        offset -= state->strm.avail_in;     /* don't count buffered input */
486
12
    return offset;
487
12
}
488
489
/* -- see zlib.h -- */
490
18
z_off_t ZEXPORT gzoffset(gzFile file) {
491
18
    z_off64_t ret;
492
493
18
    ret = gzoffset64(file);
494
18
    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
495
18
}
496
497
/* -- see zlib.h -- */
498
16
int ZEXPORT gzeof(gzFile file) {
499
16
    gz_statep state;
500
501
    /* get internal structure and check integrity */
502
16
    if (file == NULL)
503
4
        return 0;
504
12
    state = (gz_statep)file;
505
12
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
506
0
        return 0;
507
508
    /* return end-of-file state */
509
12
    return state->mode == GZ_READ ? state->past : 0;
510
12
}
511
512
/* -- see zlib.h -- */
513
18
const char * ZEXPORT gzerror(gzFile file, int *errnum) {
514
18
    gz_statep state;
515
516
    /* get internal structure and check integrity */
517
18
    if (file == NULL)
518
8
        return NULL;
519
10
    state = (gz_statep)file;
520
10
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
521
0
        return NULL;
522
523
    /* return error information */
524
10
    if (errnum != NULL)
525
10
        *errnum = state->err;
526
10
    return state->err == Z_MEM_ERROR ? "out of memory" :
527
10
                                       (state->msg == NULL ? "" : state->msg);
528
10
}
529
530
/* -- see zlib.h -- */
531
21
void ZEXPORT gzclearerr(gzFile file) {
532
21
    gz_statep state;
533
534
    /* get internal structure and check integrity */
535
21
    if (file == NULL)
536
11
        return;
537
10
    state = (gz_statep)file;
538
10
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
539
0
        return;
540
541
    /* clear error and end-of-file */
542
10
    if (state->mode == GZ_READ) {
543
5
        state->eof = 0;
544
5
        state->past = 0;
545
5
    }
546
10
    gz_error(state, Z_OK, NULL);
547
10
}
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
46.1k
void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) {
556
    /* free previously allocated message and clear */
557
46.1k
    if (state->msg != NULL) {
558
73
        if (state->err != Z_MEM_ERROR)
559
73
            free(state->msg);
560
73
        state->msg = NULL;
561
73
    }
562
563
    /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
564
46.1k
    if (err != Z_OK && err != Z_BUF_ERROR && !state->again)
565
47
        state->x.have = 0;
566
567
    /* set error code, and if no message, then done */
568
46.1k
    state->err = err;
569
46.1k
    if (msg == NULL)
570
46.0k
        return;
571
572
    /* for an out of memory error, return literal string when requested */
573
120
    if (err == Z_MEM_ERROR)
574
47
        return;
575
576
    /* construct error message with path */
577
73
    if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
578
73
            NULL) {
579
0
        state->err = Z_MEM_ERROR;
580
0
        return;
581
0
    }
582
73
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
583
73
    (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
584
73
                   "%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
73
}
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
}