Coverage Report

Created: 2025-11-14 07:32

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