Coverage Report

Created: 2026-11-12 07:35

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