Coverage Report

Created: 2025-10-10 06:41

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
4.24k
#  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.19k
local void gz_reset(gz_statep state) {
70
8.19k
    state->x.have = 0;              /* no output data available */
71
8.19k
    if (state->mode == GZ_READ) {   /* for reading ... */
72
3.79k
        state->eof = 0;             /* not at end of file */
73
3.79k
        state->past = 0;            /* have not read past end yet */
74
3.79k
        state->how = LOOK;          /* look for gzip header */
75
3.79k
    }
76
4.40k
    else                            /* for writing ... */
77
4.40k
        state->reset = 0;           /* no deflateReset pending */
78
8.19k
    state->seek = 0;                /* no seek request pending */
79
8.19k
    gz_error(state, Z_OK, NULL);    /* clear error */
80
8.19k
    state->x.pos = 0;               /* no uncompressed data yet */
81
8.19k
    state->strm.avail_in = 0;       /* no input data yet */
82
8.19k
}
83
84
/* Open a gzip file either by name or file descriptor. */
85
8.61k
local gzFile gz_open(const void *path, int fd, const char *mode) {
86
8.61k
    gz_statep state;
87
8.61k
    z_size_t len;
88
8.61k
    int oflag;
89
8.61k
#ifdef O_CLOEXEC
90
8.61k
    int cloexec = 0;
91
8.61k
#endif
92
8.61k
#ifdef O_EXCL
93
8.61k
    int exclusive = 0;
94
8.61k
#endif
95
96
    /* check input */
97
8.61k
    if (path == NULL)
98
0
        return NULL;
99
100
    /* allocate gzFile structure to return */
101
8.61k
    state = (gz_statep)malloc(sizeof(gz_state));
102
8.61k
    if (state == NULL)
103
0
        return NULL;
104
8.61k
    state->size = 0;            /* no buffers allocated yet */
105
8.61k
    state->want = GZBUFSIZE;    /* requested buffer size */
106
8.61k
    state->msg = NULL;          /* no error message yet */
107
108
    /* interpret mode */
109
8.61k
    state->mode = GZ_NONE;
110
8.61k
    state->level = Z_DEFAULT_COMPRESSION;
111
8.61k
    state->strategy = Z_DEFAULT_STRATEGY;
112
8.61k
    state->direct = 0;
113
37.1k
    while (*mode) {
114
28.5k
        if (*mode >= '0' && *mode <= '9')
115
369
            state->level = *mode - '0';
116
28.2k
        else
117
28.2k
            switch (*mode) {
118
3.82k
            case 'r':
119
3.82k
                state->mode = GZ_READ;
120
3.82k
                break;
121
0
#ifndef NO_GZCOMPRESS
122
4.01k
            case 'w':
123
4.01k
                state->mode = GZ_WRITE;
124
4.01k
                break;
125
1.03k
            case 'a':
126
1.03k
                state->mode = GZ_APPEND;
127
1.03k
                break;
128
0
#endif
129
20
            case '+':       /* can't read and write at the same time */
130
20
                free(state);
131
20
                return NULL;
132
7.35k
            case 'b':       /* ignore -- will request binary anyway */
133
7.35k
                break;
134
0
#ifdef O_CLOEXEC
135
81
            case 'e':
136
81
                cloexec = 1;
137
81
                break;
138
0
#endif
139
0
#ifdef O_EXCL
140
35
            case 'x':
141
35
                exclusive = 1;
142
35
                break;
143
0
#endif
144
772
            case 'f':
145
772
                state->strategy = Z_FILTERED;
146
772
                break;
147
950
            case 'h':
148
950
                state->strategy = Z_HUFFMAN_ONLY;
149
950
                break;
150
1.18k
            case 'R':
151
1.18k
                state->strategy = Z_RLE;
152
1.18k
                break;
153
34
            case 'F':
154
34
                state->strategy = Z_FIXED;
155
34
                break;
156
50
            case 'T':
157
50
                state->direct = 1;
158
50
                break;
159
8.86k
            default:        /* could consider as an error, but just ignore */
160
8.86k
                ;
161
28.2k
            }
162
28.5k
        mode++;
163
28.5k
    }
164
165
    /* must provide an "r", "w", or "a" */
166
8.59k
    if (state->mode == GZ_NONE) {
167
393
        free(state);
168
393
        return NULL;
169
393
    }
170
171
    /* can't force transparent read */
172
8.20k
    if (state->mode == GZ_READ) {
173
3.79k
        if (state->direct) {
174
2
            free(state);
175
2
            return NULL;
176
2
        }
177
3.78k
        state->direct = 1;      /* for empty file */
178
3.78k
    }
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
8.19k
        len = strlen((const char *)path);
187
8.19k
    state->path = (char *)malloc(len + 1);
188
8.19k
    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
8.19k
    {
202
8.19k
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
203
8.19k
        (void)snprintf(state->path, len + 1, "%s", (const char *)path);
204
#else
205
        strcpy(state->path, path);
206
#endif
207
8.19k
    }
208
209
    /* compute the flags for open() */
210
8.19k
    oflag =
211
8.19k
#ifdef O_LARGEFILE
212
8.19k
        O_LARGEFILE |
213
8.19k
#endif
214
#ifdef O_BINARY
215
        O_BINARY |
216
#endif
217
8.19k
#ifdef O_CLOEXEC
218
8.19k
        (cloexec ? O_CLOEXEC : 0) |
219
8.19k
#endif
220
8.19k
        (state->mode == GZ_READ ?
221
8.19k
         O_RDONLY :
222
8.19k
         (O_WRONLY | O_CREAT |
223
4.41k
#ifdef O_EXCL
224
4.41k
          (exclusive ? O_EXCL : 0) |
225
4.41k
#endif
226
4.41k
          (state->mode == GZ_WRITE ?
227
4.41k
           O_TRUNC :
228
4.41k
           O_APPEND)));
229
230
    /* open the file with the appropriate flags (or just use fd) */
231
8.19k
    if (fd == -1)
232
8.19k
        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
8.19k
    if (state->fd == -1) {
240
3
        free(state->path);
241
3
        free(state);
242
3
        return NULL;
243
3
    }
244
8.19k
    if (state->mode == GZ_APPEND) {
245
443
        LSEEK(state->fd, 0, SEEK_END);  /* so gzoffset() is correct */
246
443
        state->mode = GZ_WRITE;         /* simplify later checks */
247
443
    }
248
249
    /* save the current position for rewinding (only if reading) */
250
8.19k
    if (state->mode == GZ_READ) {
251
3.78k
        state->start = LSEEK(state->fd, 0, SEEK_CUR);
252
3.78k
        if (state->start == -1) state->start = 0;
253
3.78k
    }
254
255
    /* initialize stream */
256
8.19k
    gz_reset(state);
257
258
    /* return stream */
259
8.19k
    return (gzFile)state;
260
8.19k
}
261
262
/* -- see zlib.h -- */
263
8.61k
gzFile ZEXPORT gzopen(const char *path, const char *mode) {
264
8.61k
    return gz_open(path, -1, mode);
265
8.61k
}
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
131
int ZEXPORT gzbuffer(gzFile file, unsigned size) {
298
131
    gz_statep state;
299
300
    /* get internal structure and check integrity */
301
131
    if (file == NULL)
302
12
        return -1;
303
119
    state = (gz_statep)file;
304
119
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
305
0
        return -1;
306
307
    /* make sure we haven't already allocated memory */
308
119
    if (state->size != 0)
309
4
        return -1;
310
311
    /* check and set requested size */
312
115
    if ((size << 1) < size)
313
0
        return -1;              /* need to be able to double it */
314
115
    if (size < 8)
315
0
        size = 8;               /* needed to behave well with flushing */
316
115
    state->want = size;
317
115
    return 0;
318
115
}
319
320
/* -- see zlib.h -- */
321
9
int ZEXPORT gzrewind(gzFile file) {
322
9
    gz_statep state;
323
324
    /* get internal structure */
325
9
    if (file == NULL)
326
3
        return -1;
327
6
    state = (gz_statep)file;
328
329
    /* check that we're reading and that there's no error */
330
6
    if (state->mode != GZ_READ ||
331
3
            (state->err != Z_OK && state->err != Z_BUF_ERROR))
332
3
        return -1;
333
334
    /* back up and start over */
335
3
    if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
336
0
        return -1;
337
3
    gz_reset(state);
338
3
    return 0;
339
3
}
340
341
/* -- see zlib.h -- */
342
214
z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
343
214
    unsigned n;
344
214
    z_off64_t ret;
345
214
    gz_statep state;
346
347
    /* get internal structure and check integrity */
348
214
    if (file == NULL)
349
29
        return -1;
350
185
    state = (gz_statep)file;
351
185
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
352
0
        return -1;
353
354
    /* check that there's no error */
355
185
    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
356
0
        return -1;
357
358
    /* can only seek from start or relative to current position */
359
185
    if (whence != SEEK_SET && whence != SEEK_CUR)
360
1
        return -1;
361
362
    /* normalize offset to a SEEK_CUR specification */
363
184
    if (whence == SEEK_SET)
364
99
        offset -= state->x.pos;
365
85
    else if (state->seek)
366
3
        offset += state->skip;
367
184
    state->seek = 0;
368
369
    /* if within raw area while reading, just go there */
370
184
    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
184
    if (offset < 0) {
387
12
        if (state->mode != GZ_READ)         /* writing -- can't go backwards */
388
12
            return -1;
389
0
        offset += state->x.pos;
390
0
        if (offset < 0)                     /* before start of file! */
391
0
            return -1;
392
0
        if (gzrewind(file) == -1)           /* rewind, then skip to offset */
393
0
            return -1;
394
0
    }
395
396
    /* if reading, skip what's in output buffer (one less gzgetc() check) */
397
172
    if (state->mode == GZ_READ) {
398
24
        n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
399
24
            (unsigned)offset : state->x.have;
400
24
        state->x.have -= n;
401
24
        state->x.next += n;
402
24
        state->x.pos += n;
403
24
        offset -= n;
404
24
    }
405
406
    /* request skip (if not zero) */
407
172
    if (offset) {
408
170
        state->seek = 1;
409
170
        state->skip = offset;
410
170
    }
411
172
    return state->x.pos + offset;
412
184
}
413
414
/* -- see zlib.h -- */
415
214
z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) {
416
214
    z_off64_t ret;
417
418
214
    ret = gzseek64(file, (z_off64_t)offset, whence);
419
214
    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
420
214
}
421
422
/* -- see zlib.h -- */
423
32
z_off64_t ZEXPORT gztell64(gzFile file) {
424
32
    gz_statep state;
425
426
    /* get internal structure and check integrity */
427
32
    if (file == NULL)
428
17
        return -1;
429
15
    state = (gz_statep)file;
430
15
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
431
0
        return -1;
432
433
    /* return position */
434
15
    return state->x.pos + (state->seek ? state->skip : 0);
435
15
}
436
437
/* -- see zlib.h -- */
438
32
z_off_t ZEXPORT gztell(gzFile file) {
439
32
    z_off64_t ret;
440
441
32
    ret = gztell64(file);
442
32
    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
443
32
}
444
445
/* -- see zlib.h -- */
446
15
z_off64_t ZEXPORT gzoffset64(gzFile file) {
447
15
    z_off64_t offset;
448
15
    gz_statep state;
449
450
    /* get internal structure and check integrity */
451
15
    if (file == NULL)
452
7
        return -1;
453
8
    state = (gz_statep)file;
454
8
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
455
0
        return -1;
456
457
    /* compute and return effective offset in file */
458
8
    offset = LSEEK(state->fd, 0, SEEK_CUR);
459
8
    if (offset == -1)
460
0
        return -1;
461
8
    if (state->mode == GZ_READ)             /* reading */
462
3
        offset -= state->strm.avail_in;     /* don't count buffered input */
463
8
    return offset;
464
8
}
465
466
/* -- see zlib.h -- */
467
15
z_off_t ZEXPORT gzoffset(gzFile file) {
468
15
    z_off64_t ret;
469
470
15
    ret = gzoffset64(file);
471
15
    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
472
15
}
473
474
/* -- see zlib.h -- */
475
18
int ZEXPORT gzeof(gzFile file) {
476
18
    gz_statep state;
477
478
    /* get internal structure and check integrity */
479
18
    if (file == NULL)
480
8
        return 0;
481
10
    state = (gz_statep)file;
482
10
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
483
0
        return 0;
484
485
    /* return end-of-file state */
486
10
    return state->mode == GZ_READ ? state->past : 0;
487
10
}
488
489
/* -- see zlib.h -- */
490
13
const char * ZEXPORT gzerror(gzFile file, int *errnum) {
491
13
    gz_statep state;
492
493
    /* get internal structure and check integrity */
494
13
    if (file == NULL)
495
4
        return NULL;
496
9
    state = (gz_statep)file;
497
9
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
498
0
        return NULL;
499
500
    /* return error information */
501
9
    if (errnum != NULL)
502
9
        *errnum = state->err;
503
9
    return state->err == Z_MEM_ERROR ? "out of memory" :
504
9
                                       (state->msg == NULL ? "" : state->msg);
505
9
}
506
507
/* -- see zlib.h -- */
508
24
void ZEXPORT gzclearerr(gzFile file) {
509
24
    gz_statep state;
510
511
    /* get internal structure and check integrity */
512
24
    if (file == NULL)
513
14
        return;
514
10
    state = (gz_statep)file;
515
10
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
516
0
        return;
517
518
    /* clear error and end-of-file */
519
10
    if (state->mode == GZ_READ) {
520
3
        state->eof = 0;
521
3
        state->past = 0;
522
3
    }
523
10
    gz_error(state, Z_OK, NULL);
524
10
}
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
16.4k
void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) {
533
    /* free previously allocated message and clear */
534
16.4k
    if (state->msg != NULL) {
535
0
        if (state->err != Z_MEM_ERROR)
536
0
            free(state->msg);
537
0
        state->msg = NULL;
538
0
    }
539
540
    /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
541
16.4k
    if (err != Z_OK && err != Z_BUF_ERROR)
542
41
        state->x.have = 0;
543
544
    /* set error code, and if no message, then done */
545
16.4k
    state->err = err;
546
16.4k
    if (msg == NULL)
547
16.4k
        return;
548
549
    /* for an out of memory error, return literal string when requested */
550
41
    if (err == Z_MEM_ERROR)
551
41
        return;
552
553
    /* construct error message with path */
554
0
    if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
555
0
            NULL) {
556
0
        state->err = Z_MEM_ERROR;
557
0
        return;
558
0
    }
559
0
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
560
0
    (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
561
0
                   "%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
0
}
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
}