Coverage Report

Created: 2026-11-12 07:18

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
848
#  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
1.90k
local void gz_reset(gz_statep state) {
70
1.90k
    state->x.have = 0;              /* no output data available */
71
1.90k
    state->past = 0;                /* have not read past end yet */
72
1.90k
    if (state->mode == GZ_READ) {   /* for reading ... */
73
252
        state->eof = 0;             /* not at end of file */
74
252
        state->how = LOOK;          /* look for gzip header */
75
252
        state->junk = -1;           /* mark first member */
76
252
    }
77
1.64k
    else                            /* for writing ... */
78
1.64k
        state->reset = 0;           /* no deflateReset pending */
79
1.90k
    state->again = 0;               /* no stalled i/o yet */
80
1.90k
    state->skip = 0;                /* no seek request pending */
81
1.90k
    gz_error(state, Z_OK, NULL);    /* clear error */
82
1.90k
    state->x.pos = 0;               /* no uncompressed data yet */
83
1.90k
    state->strm.avail_in = 0;       /* no input data yet */
84
1.90k
}
85
86
/* Open a gzip file either by name or file descriptor. */
87
2.21k
local gzFile gz_open(const void *path, int fd, const char *mode) {
88
2.21k
    gz_statep state;
89
2.21k
    z_size_t len;
90
2.21k
    int oflag = 0;
91
2.21k
    int exclusive = 0;
92
93
    /* check input */
94
2.21k
    if (path == NULL || mode == NULL)
95
0
        return NULL;
96
97
    /* allocate gzFile structure to return */
98
2.21k
    state = (gz_statep)malloc(sizeof(gz_state));
99
2.21k
    if (state == NULL)
100
0
        return NULL;
101
2.21k
    state->size = 0;            /* no buffers allocated yet */
102
2.21k
    state->want = GZBUFSIZE;    /* requested buffer size */
103
2.21k
    state->err = Z_OK;          /* no error yet */
104
2.21k
    state->msg = NULL;          /* no error message yet */
105
106
    /* interpret mode */
107
2.21k
    state->mode = GZ_NONE;
108
2.21k
    state->level = Z_DEFAULT_COMPRESSION;
109
2.21k
    state->strategy = Z_DEFAULT_STRATEGY;
110
2.21k
    state->direct = 0;
111
18.4k
    while (*mode) {
112
16.2k
        if (*mode >= '0' && *mode <= '9')
113
762
            state->level = *mode - '0';
114
15.4k
        else
115
15.4k
            switch (*mode) {
116
283
            case 'r':
117
283
                state->mode = GZ_READ;
118
283
                break;
119
0
#ifndef NO_GZCOMPRESS
120
1.19k
            case 'w':
121
1.19k
                state->mode = GZ_WRITE;
122
1.19k
                break;
123
821
            case 'a':
124
821
                state->mode = GZ_APPEND;
125
821
                break;
126
0
#endif
127
6
            case '+':       /* can't read and write at the same time */
128
6
                free(state);
129
6
                return NULL;
130
5
            case 'b':       /* ignore -- will request binary anyway */
131
5
                break;
132
0
#ifdef O_CLOEXEC
133
43
            case 'e':
134
43
                oflag |= O_CLOEXEC;
135
43
                break;
136
0
#endif
137
26
            case 'x':
138
26
                exclusive = 1;
139
26
                break;
140
51
            case 'f':
141
51
                state->strategy = Z_FILTERED;
142
51
                break;
143
242
            case 'h':
144
242
                state->strategy = Z_HUFFMAN_ONLY;
145
242
                break;
146
364
            case 'R':
147
364
                state->strategy = Z_RLE;
148
364
                break;
149
34
            case 'F':
150
34
                state->strategy = Z_FIXED;
151
34
                break;
152
111
            case 'G':
153
111
                state->direct = -1;
154
111
                break;
155
0
#ifdef O_NONBLOCK
156
68
            case 'N':
157
68
                oflag |= O_NONBLOCK;
158
68
                break;
159
0
#endif
160
52
            case 'T':
161
52
                state->direct = 1;
162
52
                break;
163
12.1k
            default:        /* could consider as an error, but just ignore */
164
12.1k
                ;
165
15.4k
            }
166
16.2k
        mode++;
167
16.2k
    }
168
169
    /* must provide an "r", "w", or "a" */
170
2.20k
    if (state->mode == GZ_NONE) {
171
305
        free(state);
172
305
        return NULL;
173
305
    }
174
175
    /* direct is 0, 1 if "T", or -1 if "G" (last "G" or "T" wins) */
176
1.90k
    if (state->mode == GZ_READ) {
177
249
        if (state->direct == 1) {
178
            /* can't force a transparent read */
179
1
            free(state);
180
1
            return NULL;
181
1
        }
182
248
        if (state->direct == 0)
183
            /* default when reading is auto-detect of gzip vs. transparent --
184
               start with a transparent assumption in case of an empty file */
185
181
            state->direct = 1;
186
248
    }
187
1.65k
    else if (state->direct == -1) {
188
        /* "G" has no meaning when writing -- disallow it */
189
2
        free(state);
190
2
        return NULL;
191
2
    }
192
    /* if reading, direct == 1 for auto-detect, -1 for gzip only; if writing or
193
       appending, direct == 0 for gzip, 1 for transparent (copy in to out) */
194
195
#ifndef O_EXCL
196
    if (exclusive && state->mode != GZ_READ && fd < 0) {
197
        /* exclusive creation request can't be honored -- fail out */
198
        free(state);
199
        return NULL;
200
    }
201
#endif
202
203
    /* save the path name for error messages */
204
#ifdef WIDECHAR
205
    if (fd == -2) {
206
        len = wcstombs(NULL, path, 0);
207
        if (len == (z_size_t)-1)
208
            len = 0;            /* not representable in the current locale */
209
    }
210
    else
211
#endif
212
1.89k
        len = strlen((const char *)path);
213
1.89k
    state->path = (char *)malloc(len + 1);
214
1.89k
    if (state->path == NULL) {
215
0
        free(state);
216
0
        return NULL;
217
0
    }
218
#ifdef WIDECHAR
219
    if (fd == -2) {
220
        if (len == 0 || wcstombs(state->path, path, len + 1) != len)
221
            *(state->path) = 0;
222
    }
223
    else
224
#endif
225
1.89k
    {
226
1.89k
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
227
1.89k
        (void)snprintf(state->path, len + 1, "%s", (const char *)path);
228
#else
229
        strcpy(state->path, (const char *)path);
230
#endif
231
1.89k
    }
232
233
    /* compute the flags for open() */
234
1.89k
    oflag |=
235
1.89k
#ifdef O_LARGEFILE
236
1.89k
        O_LARGEFILE |
237
1.89k
#endif
238
#ifdef O_BINARY
239
        O_BINARY |
240
#endif
241
1.89k
        (state->mode == GZ_READ ?
242
1.89k
         O_RDONLY :
243
1.89k
         (O_WRONLY | O_CREAT |
244
1.65k
#ifdef O_EXCL
245
1.65k
          (exclusive ? O_EXCL : 0) |
246
1.65k
#endif
247
1.65k
          (state->mode == GZ_WRITE ?
248
1.65k
           O_TRUNC :
249
1.65k
           O_APPEND)));
250
251
    /* open the file with the appropriate flags (or just use fd) */
252
1.89k
    if (fd == -1)
253
1.89k
        state->fd = open((const char *)path, oflag, 0666);
254
#ifdef WIDECHAR
255
    else if (fd == -2)
256
        state->fd = _wopen(path, oflag, _S_IREAD | _S_IWRITE);
257
#endif
258
0
    else {
259
0
#ifdef O_NONBLOCK
260
0
        if (oflag & O_NONBLOCK)
261
0
            fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
262
0
#endif
263
0
#if defined(O_CLOEXEC) && defined(FD_CLOEXEC)
264
0
        if (oflag & O_CLOEXEC)
265
0
            fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
266
0
#endif
267
0
        state->fd = fd;
268
0
    }
269
1.89k
    if (state->fd == -1) {
270
2
        free(state->path);
271
2
        free(state);
272
2
        return NULL;
273
2
    }
274
1.89k
    if (state->mode == GZ_APPEND) {
275
576
        LSEEK(state->fd, 0, SEEK_END);  /* so gzoffset() is correct */
276
576
        state->mode = GZ_WRITE;         /* simplify later checks */
277
576
    }
278
279
    /* save the current position for rewinding (only if reading) */
280
1.89k
    if (state->mode == GZ_READ) {
281
248
        state->start = LSEEK(state->fd, 0, SEEK_CUR);
282
248
        if (state->start == -1) state->start = 0;
283
248
    }
284
285
    /* initialize stream */
286
1.89k
    gz_reset(state);
287
288
    /* return stream */
289
1.89k
    return (gzFile)state;
290
1.89k
}
291
292
/* -- see zlib.h -- */
293
2.21k
gzFile ZEXPORT gzopen(const char *path, const char *mode) {
294
2.21k
    return gz_open(path, -1, mode);
295
2.21k
}
296
297
/* -- see zlib.h -- */
298
0
gzFile ZEXPORT gzopen64(const char *path, const char *mode) {
299
0
    return gz_open(path, -1, mode);
300
0
}
301
302
/* -- see zlib.h -- */
303
0
gzFile ZEXPORT gzdopen(int fd, const char *mode) {
304
0
    char *path;         /* identifier for error messages */
305
0
    gzFile gz;
306
307
0
    if (fd < 0 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
308
0
        return NULL;
309
0
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
310
0
    (void)snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd);
311
#else
312
    sprintf(path, "<fd:%d>", fd);   /* for debugging */
313
#endif
314
0
    gz = gz_open(path, fd, mode);
315
0
    free(path);
316
0
    return gz;
317
0
}
318
319
/* -- see zlib.h -- */
320
#ifdef WIDECHAR
321
gzFile ZEXPORT gzopen_w(const wchar_t *path, const char *mode) {
322
    return gz_open(path, -2, mode);
323
}
324
#endif
325
326
/* -- see zlib.h -- */
327
264
int ZEXPORT gzbuffer(gzFile file, unsigned size) {
328
264
    gz_statep state;
329
330
    /* get internal structure and check integrity */
331
264
    if (file == NULL)
332
9
        return -1;
333
255
    state = (gz_statep)file;
334
255
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
335
0
        return -1;
336
337
    /* make sure we haven't already allocated memory */
338
255
    if (state->size != 0)
339
1
        return -1;
340
341
    /* check and set requested size */
342
254
    if ((size << 1) < size)
343
0
        return -1;              /* need to be able to double it */
344
254
    if (size < 8)
345
39
        size = 8;               /* needed to behave well with flushing */
346
254
    state->want = size;
347
254
    return 0;
348
254
}
349
350
/* -- see zlib.h -- */
351
17
int ZEXPORT gzrewind(gzFile file) {
352
17
    gz_statep state;
353
354
    /* get internal structure */
355
17
    if (file == NULL)
356
7
        return -1;
357
10
    state = (gz_statep)file;
358
359
    /* check that we're reading and that there's no error */
360
10
    if (state->mode != GZ_READ ||
361
4
            (state->err != Z_OK && state->err != Z_BUF_ERROR))
362
6
        return -1;
363
364
    /* back up and start over */
365
4
    if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
366
0
        return -1;
367
4
    gz_reset(state);
368
4
    return 0;
369
4
}
370
371
/* -- see zlib.h -- */
372
337
z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
373
337
    unsigned n;
374
337
    z_off64_t ret, pos;
375
337
    gz_statep state;
376
377
    /* get internal structure and check integrity */
378
337
    if (file == NULL)
379
12
        return -1;
380
325
    state = (gz_statep)file;
381
325
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
382
0
        return -1;
383
384
    /* check that there's no error */
385
325
    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
386
0
        return -1;
387
388
    /* can only seek from start or relative to current position */
389
325
    if (whence != SEEK_SET && whence != SEEK_CUR)
390
2
        return -1;
391
392
    /* compute the absolute position */
393
323
    pos = whence == SEEK_SET ? 0 :
394
323
          state->x.pos + (state->past ? 0 : state->skip);
395
323
    if (offset > GZ_OFF_MAX - pos)
396
2
        return -1;                          /* would overflow z_off64_t */
397
321
    if (offset < -pos)
398
0
        return -1;                          /* before start of file */
399
321
    pos += offset;
400
401
    /* if within raw area while reading, just go there */
402
321
    if (state->mode == GZ_READ && state->how == COPY) {
403
0
        ret = LSEEK(state->fd, pos - state->x.pos - (z_off64_t)state->x.have,
404
0
                    SEEK_CUR);
405
0
        if (ret == -1)
406
0
            return -1;
407
0
        state->x.have = 0;
408
0
        state->eof = 0;
409
0
        state->past = 0;
410
0
        state->skip = 0;
411
0
        gz_error(state, Z_OK, NULL);
412
0
        state->strm.avail_in = 0;
413
0
        state->x.pos = pos;
414
0
        return pos;
415
0
    }
416
417
    /* rewind if needed for back seek when reading */
418
321
    if (pos < state->x.pos) {
419
2
        if (state->mode != GZ_READ)         /* writing -- can't go backwards */
420
2
            return -1;
421
0
        if (gzrewind(file) == -1)           /* rewind, then skip to pos */
422
0
            return -1;
423
0
    }
424
319
    offset = pos - state->x.pos;
425
426
    /* if reading, skip what's in output buffer (one less gzgetc() check) */
427
319
    if (state->mode == GZ_READ) {
428
51
        n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
429
51
            (unsigned)offset : state->x.have;
430
51
        state->x.have -= n;
431
51
        state->x.next += n;
432
51
        state->x.pos += n;
433
51
        offset -= n;
434
51
    }
435
436
    /* request skip (if not zero) */
437
319
    state->skip = offset;
438
319
    return pos;
439
321
}
440
441
/* -- see zlib.h -- */
442
337
z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) {
443
337
    z_off64_t ret;
444
445
337
    ret = gzseek64(file, (z_off64_t)offset, whence);
446
337
    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
447
337
}
448
449
/* -- see zlib.h -- */
450
21
z_off64_t ZEXPORT gztell64(gzFile file) {
451
21
    gz_statep state;
452
453
    /* get internal structure and check integrity */
454
21
    if (file == NULL)
455
5
        return -1;
456
16
    state = (gz_statep)file;
457
16
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
458
0
        return -1;
459
460
    /* return position */
461
16
    return state->x.pos + (state->past ? 0 : state->skip);
462
16
}
463
464
/* -- see zlib.h -- */
465
21
z_off_t ZEXPORT gztell(gzFile file) {
466
21
    z_off64_t ret;
467
468
21
    ret = gztell64(file);
469
21
    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
470
21
}
471
472
/* -- see zlib.h -- */
473
23
z_off64_t ZEXPORT gzoffset64(gzFile file) {
474
23
    z_off64_t offset;
475
23
    gz_statep state;
476
477
    /* get internal structure and check integrity */
478
23
    if (file == NULL)
479
3
        return -1;
480
20
    state = (gz_statep)file;
481
20
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
482
0
        return -1;
483
484
    /* compute and return effective offset in file */
485
20
    offset = LSEEK(state->fd, 0, SEEK_CUR);
486
20
    if (offset == -1)
487
0
        return -1;
488
20
    if (state->mode == GZ_READ)             /* reading */
489
5
        offset -= state->strm.avail_in;     /* don't count buffered input */
490
20
    return offset;
491
20
}
492
493
/* -- see zlib.h -- */
494
23
z_off_t ZEXPORT gzoffset(gzFile file) {
495
23
    z_off64_t ret;
496
497
23
    ret = gzoffset64(file);
498
23
    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
499
23
}
500
501
/* -- see zlib.h -- */
502
21
int ZEXPORT gzeof(gzFile file) {
503
21
    gz_statep state;
504
505
    /* get internal structure and check integrity */
506
21
    if (file == NULL)
507
8
        return 0;
508
13
    state = (gz_statep)file;
509
13
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
510
0
        return 0;
511
512
    /* return end-of-file state */
513
13
    return state->mode == GZ_READ ? state->past : 0;
514
13
}
515
516
/* -- see zlib.h -- */
517
15
const char * ZEXPORT gzerror(gzFile file, int *errnum) {
518
15
    gz_statep state;
519
520
    /* get internal structure and check integrity */
521
15
    if (file == NULL)
522
7
        return NULL;
523
8
    state = (gz_statep)file;
524
8
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
525
0
        return NULL;
526
527
    /* return error information */
528
8
    if (errnum != NULL)
529
8
        *errnum = state->err;
530
8
    return state->err == Z_MEM_ERROR ? "out of memory" :
531
8
                                       (state->msg == NULL ? "" : state->msg);
532
8
}
533
534
/* -- see zlib.h -- */
535
27
void ZEXPORT gzclearerr(gzFile file) {
536
27
    gz_statep state;
537
538
    /* get internal structure and check integrity */
539
27
    if (file == NULL)
540
18
        return;
541
9
    state = (gz_statep)file;
542
9
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
543
0
        return;
544
545
    /* clear error and end-of-file */
546
9
    if (state->mode == GZ_READ) {
547
5
        state->eof = 0;
548
5
        state->past = 0;
549
5
    }
550
9
    gz_error(state, Z_OK, NULL);
551
9
}
552
553
/* Create an error message in allocated memory and set state->err and
554
   state->msg accordingly.  Free any previous error message already there.  Do
555
   not try to free or allocate space if the error is Z_MEM_ERROR (out of
556
   memory).  Simply save the error message as a static string.  If there is an
557
   allocation failure constructing the error message, then convert the error to
558
   out of memory. */
559
6.13k
void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) {
560
    /* free previously allocated message and clear */
561
6.13k
    if (state->msg != NULL) {
562
62
        if (state->err != Z_MEM_ERROR)
563
62
            free(state->msg);
564
62
        state->msg = NULL;
565
62
    }
566
567
    /* set error code, and if no message, then done */
568
6.13k
    state->err = err;
569
6.13k
    if (msg == NULL)
570
5.98k
        return;
571
572
    /* for an out of memory error, return literal string when requested */
573
150
    if (err == Z_MEM_ERROR)
574
88
        return;
575
576
    /* construct error message with path */
577
62
    if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
578
62
            NULL) {
579
0
        state->err = Z_MEM_ERROR;
580
0
        return;
581
0
    }
582
62
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
583
62
    (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
584
62
                   "%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
62
}
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
}