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