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 "zbuild.h" |
7 | | #include "zutil.h" |
8 | | #include "zutil_p.h" |
9 | | #include "gzguts.h" |
10 | | |
11 | | #if defined(_WIN32) |
12 | | # define LSEEK _lseeki64 |
13 | | #else |
14 | | #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 |
15 | 11.7k | # define LSEEK lseek64 |
16 | | #else |
17 | | # define LSEEK lseek |
18 | | #endif |
19 | | #endif |
20 | | |
21 | | /* Local functions */ |
22 | | static gzFile gz_state_init(void); |
23 | | static void gz_reset(gz_state *); |
24 | | static gzFile gz_open(const void *, int, const char *); |
25 | | |
26 | | /* Initialize struct for gzFile state */ |
27 | 23.4k | static gzFile gz_state_init(void) { |
28 | | /* allocate gzFile structure to return */ |
29 | 23.4k | gz_state *state = (gz_state *)zng_alloc(sizeof(gz_state)); |
30 | 23.4k | if (state == NULL) |
31 | 0 | return NULL; |
32 | | |
33 | 23.4k | state->strm.zalloc = NULL; |
34 | 23.4k | state->strm.zfree = NULL; |
35 | 23.4k | state->strm.opaque = NULL; |
36 | 23.4k | state->strm.next_in = NULL; |
37 | | |
38 | 23.4k | state->size = 0; |
39 | 23.4k | state->want = GZBUFSIZE; |
40 | 23.4k | state->in = NULL; |
41 | 23.4k | state->out = NULL; |
42 | 23.4k | state->direct = 0; |
43 | 23.4k | state->mode = GZ_NONE; |
44 | 23.4k | state->level = Z_DEFAULT_COMPRESSION; |
45 | 23.4k | state->strategy = Z_DEFAULT_STRATEGY; |
46 | 23.4k | state->msg = NULL; |
47 | | |
48 | 23.4k | state->past = 0; |
49 | 23.4k | state->skip = 0; |
50 | | |
51 | 23.4k | return (gzFile)state; |
52 | 23.4k | } |
53 | | |
54 | 11.7k | void Z_INTERNAL gz_state_free(gz_state *state) { |
55 | 11.7k | zng_free(state); |
56 | 11.7k | } |
57 | | |
58 | | /* Reset gzip file state */ |
59 | 23.4k | static void gz_reset(gz_state *state) { |
60 | 23.4k | state->x.have = 0; /* no output data available */ |
61 | 23.4k | if (state->mode == GZ_READ) { /* for reading ... */ |
62 | 11.7k | state->eof = 0; /* not at end of file */ |
63 | 11.7k | state->past = 0; /* have not read past end yet */ |
64 | 11.7k | state->how = LOOK; /* look for gzip header */ |
65 | 11.7k | } |
66 | 11.7k | else /* for writing ... */ |
67 | 11.7k | state->reset = 0; /* no deflateReset pending */ |
68 | 23.4k | state->skip = 0; /* no seek request pending */ |
69 | 23.4k | PREFIX(gz_error)(state, Z_OK, NULL); /* clear error */ |
70 | 23.4k | state->x.pos = 0; /* no uncompressed data yet */ |
71 | 23.4k | state->strm.avail_in = 0; /* no input data yet */ |
72 | 23.4k | } |
73 | | |
74 | | /* Allocate in/out buffers for gzFile */ |
75 | 23.4k | int Z_INTERNAL gz_buffer_alloc(gz_state *state) { |
76 | 23.4k | unsigned want = state->want; |
77 | 23.4k | unsigned in_size = want, out_size = want; |
78 | | |
79 | 23.4k | if (state->mode == GZ_WRITE) { |
80 | 11.7k | in_size = want * 2; // double input buffer for compression (ref: gzprintf) |
81 | 11.7k | if (state->direct) |
82 | 11 | out_size = 0; // output buffer not needed in write + direct mode |
83 | 11.7k | } else if (state->mode == GZ_READ) { |
84 | 11.7k | out_size = want * 2; // double output buffer for decompression |
85 | 11.7k | } |
86 | | |
87 | 23.4k | state->buffers = (unsigned char *)zng_alloc_aligned((in_size + out_size), 64); |
88 | 23.4k | state->in = state->buffers; |
89 | 23.4k | if (out_size) { |
90 | 23.4k | state->out = state->buffers + (in_size); // Outbuffer goes after inbuffer |
91 | 23.4k | } |
92 | | |
93 | | /* Return error if memory allocation failed */ |
94 | 23.4k | if (state->in == NULL || (out_size && state->out == NULL)) { |
95 | 0 | gz_buffer_free(state); |
96 | 0 | PREFIX(gz_error)(state, Z_MEM_ERROR, "out of memory"); |
97 | 0 | return -1; |
98 | 0 | } |
99 | | |
100 | 23.4k | state->size = want; // mark state as initialized |
101 | 23.4k | return 0; |
102 | 23.4k | } |
103 | | |
104 | 23.4k | void Z_INTERNAL gz_buffer_free(gz_state *state) { |
105 | 23.4k | zng_free_aligned(state->buffers); |
106 | 23.4k | state->buffers = NULL; |
107 | 23.4k | state->out = NULL; |
108 | 23.4k | state->in = NULL; |
109 | 23.4k | state->size = 0; |
110 | 23.4k | } |
111 | | |
112 | | /* Open a gzip file either by name or file descriptor. */ |
113 | 23.4k | static gzFile gz_open(const void *path, int fd, const char *mode) { |
114 | 23.4k | gz_state *state; |
115 | 23.4k | size_t len; |
116 | 23.4k | int oflag; |
117 | 23.4k | #ifdef O_CLOEXEC |
118 | 23.4k | int cloexec = 0; |
119 | 23.4k | #endif |
120 | 23.4k | #ifdef O_EXCL |
121 | 23.4k | int exclusive = 0; |
122 | 23.4k | #endif |
123 | | |
124 | | /* check input */ |
125 | 23.4k | if (path == NULL || mode == NULL) |
126 | 0 | return NULL; |
127 | | |
128 | | /* Initialize gzFile state */ |
129 | 23.4k | state = (gz_state *)gz_state_init(); |
130 | 23.4k | if (state == NULL) |
131 | 0 | return NULL; |
132 | | |
133 | | /* interpret mode */ |
134 | 90.4k | while (*mode) { |
135 | 66.9k | if (*mode >= '0' && *mode <= '9') { |
136 | 11.7k | state->level = *mode - '0'; |
137 | 55.2k | } else { |
138 | 55.2k | switch (*mode) { |
139 | 11.7k | case 'r': |
140 | 11.7k | state->mode = GZ_READ; |
141 | 11.7k | break; |
142 | 0 | #ifndef NO_GZCOMPRESS |
143 | 11.7k | case 'w': |
144 | 11.7k | state->mode = GZ_WRITE; |
145 | 11.7k | break; |
146 | 0 | case 'a': |
147 | 0 | state->mode = GZ_APPEND; |
148 | 0 | break; |
149 | 0 | #endif |
150 | 0 | case '+': /* can't read and write at the same time */ |
151 | 0 | gz_state_free(state); |
152 | 0 | return NULL; |
153 | 23.4k | case 'b': /* ignore -- will request binary anyway */ |
154 | 23.4k | break; |
155 | 0 | #ifdef O_CLOEXEC |
156 | 0 | case 'e': |
157 | 0 | cloexec = 1; |
158 | 0 | break; |
159 | 0 | #endif |
160 | 0 | #ifdef O_EXCL |
161 | 0 | case 'x': |
162 | 0 | exclusive = 1; |
163 | 0 | break; |
164 | 0 | #endif |
165 | 2.16k | case 'f': |
166 | 2.16k | state->strategy = Z_FILTERED; |
167 | 2.16k | break; |
168 | 864 | case 'h': |
169 | 864 | state->strategy = Z_HUFFMAN_ONLY; |
170 | 864 | break; |
171 | 4.04k | case 'R': |
172 | 4.04k | state->strategy = Z_RLE; |
173 | 4.04k | break; |
174 | 1.17k | case 'F': |
175 | 1.17k | state->strategy = Z_FIXED; |
176 | 1.17k | break; |
177 | 0 | case 'G': |
178 | 0 | state->direct = -1; |
179 | 0 | break; |
180 | 11 | case 'T': |
181 | 11 | state->direct = 1; |
182 | 11 | break; |
183 | 0 | default: /* could consider as an error, but just ignore */ |
184 | 0 | {} |
185 | 55.2k | } |
186 | 55.2k | } |
187 | 66.9k | mode++; |
188 | 66.9k | } |
189 | | |
190 | | /* must provide an "r", "w", or "a" */ |
191 | 23.4k | if (state->mode == GZ_NONE) { |
192 | 0 | gz_state_free(state); |
193 | 0 | return NULL; |
194 | 0 | } |
195 | | |
196 | | /* direct is 0, 1 if "T", or -1 if "G" (last "G" or "T" wins) */ |
197 | 23.4k | if (state->mode == GZ_READ) { |
198 | 11.7k | if (state->direct == 1) { |
199 | | /* can't force a transparent read */ |
200 | 0 | gz_state_free(state); |
201 | 0 | return NULL; |
202 | 0 | } |
203 | 11.7k | if (state->direct == 0) |
204 | | /* default when reading is auto-detect of gzip vs. transparent -- |
205 | | start with a transparent assumption in case of an empty file */ |
206 | 11.7k | state->direct = 1; |
207 | 11.7k | } |
208 | 11.7k | else if (state->direct == -1) { |
209 | | /* "G" has no meaning when writing -- disallow it */ |
210 | 0 | gz_state_free(state); |
211 | 0 | return NULL; |
212 | 0 | } |
213 | | /* if reading, direct == 1 for auto-detect, -1 for gzip only; if writing or |
214 | | appending, direct == 0 for gzip, 1 for transparent (copy in to out) */ |
215 | | |
216 | | /* save the path name for error messages */ |
217 | | #ifdef WIDECHAR |
218 | | if (fd == -2) { |
219 | | len = wcstombs(NULL, (const wchar_t *)path, 0); |
220 | | if (len == (size_t)-1) |
221 | | len = 0; |
222 | | } else |
223 | | #endif |
224 | 23.4k | len = strlen((const char *)path); |
225 | 23.4k | state->path = malloc(len + 1); |
226 | 23.4k | if (state->path == NULL) { |
227 | 0 | gz_state_free(state); |
228 | 0 | return NULL; |
229 | 0 | } |
230 | | #ifdef WIDECHAR |
231 | | if (fd == -2) |
232 | | if (len) { |
233 | | wcstombs(state->path, (const wchar_t *)path, len + 1); |
234 | | } else { |
235 | | *(state->path) = 0; |
236 | | } |
237 | | else |
238 | | #endif |
239 | 23.4k | (void)snprintf(state->path, len + 1, "%s", (const char *)path); |
240 | | |
241 | | /* compute the flags for open() */ |
242 | 23.4k | oflag = |
243 | 23.4k | #ifdef O_LARGEFILE |
244 | 23.4k | O_LARGEFILE | |
245 | 23.4k | #endif |
246 | | #ifdef O_BINARY |
247 | | O_BINARY | |
248 | | #endif |
249 | 23.4k | #ifdef O_CLOEXEC |
250 | 23.4k | (cloexec ? O_CLOEXEC : 0) | |
251 | 23.4k | #endif |
252 | 23.4k | (state->mode == GZ_READ ? |
253 | 23.4k | O_RDONLY : |
254 | 23.4k | (O_WRONLY | O_CREAT | |
255 | 11.7k | #ifdef O_EXCL |
256 | 11.7k | (exclusive ? O_EXCL : 0) | |
257 | 11.7k | #endif |
258 | 11.7k | (state->mode == GZ_WRITE ? |
259 | 11.7k | O_TRUNC : |
260 | 11.7k | O_APPEND))); |
261 | | |
262 | | /* open the file with the appropriate flags (or just use fd) */ |
263 | 23.4k | state->fd = fd > -1 ? fd : ( |
264 | | #if defined(_WIN32) |
265 | | fd == -2 ? _wopen((const wchar_t *)path, oflag, 0666) : |
266 | | #elif defined(__CYGWIN__) |
267 | | fd == -2 ? open(state->path, oflag, 0666) : |
268 | | #endif |
269 | 23.4k | open((const char *)path, oflag, 0666)); |
270 | 23.4k | if (state->fd == -1) { |
271 | 0 | free(state->path); |
272 | 0 | gz_state_free(state); |
273 | 0 | return NULL; |
274 | 0 | } |
275 | 23.4k | if (state->mode == GZ_APPEND) { |
276 | 0 | LSEEK(state->fd, 0, SEEK_END); /* so gzoffset() is correct */ |
277 | 0 | state->mode = GZ_WRITE; /* simplify later checks */ |
278 | 0 | } |
279 | | |
280 | | /* save the current position for rewinding (only if reading) */ |
281 | 23.4k | if (state->mode == GZ_READ) { |
282 | 11.7k | state->start = LSEEK(state->fd, 0, SEEK_CUR); |
283 | 11.7k | if (state->start == -1) state->start = 0; |
284 | 11.7k | } |
285 | | |
286 | | /* initialize stream */ |
287 | 23.4k | gz_reset(state); |
288 | | |
289 | | /* return stream */ |
290 | 23.4k | return (gzFile)state; |
291 | 23.4k | } |
292 | | |
293 | | /* -- see zlib.h -- */ |
294 | 23.4k | gzFile Z_EXPORT PREFIX(gzopen)(const char *path, const char *mode) { |
295 | 23.4k | return gz_open(path, -1, mode); |
296 | 23.4k | } |
297 | | |
298 | | #ifdef ZLIB_COMPAT |
299 | | gzFile Z_EXPORT PREFIX4(gzopen)(const char *path, const char *mode) { |
300 | | return gz_open(path, -1, mode); |
301 | | } |
302 | | #endif |
303 | | |
304 | | /* -- see zlib.h -- */ |
305 | 0 | gzFile Z_EXPORT PREFIX(gzdopen)(int fd, const char *mode) { |
306 | 0 | gzFile gz; |
307 | 0 | char path[32]; /* identifier for error messages */ |
308 | |
|
309 | 0 | if (fd == -1) |
310 | 0 | return NULL; |
311 | 0 | (void)snprintf(path, 32, "<fd:%d>", fd); /* for debugging */ |
312 | 0 | gz = gz_open(path, fd, mode); |
313 | 0 | return gz; |
314 | 0 | } |
315 | | |
316 | | /* -- see zlib.h -- */ |
317 | | #ifdef WIDECHAR |
318 | | gzFile Z_EXPORT PREFIX(gzopen_w)(const wchar_t *path, const char *mode) { |
319 | | return gz_open(path, -2, mode); |
320 | | } |
321 | | #endif |
322 | | |
323 | 23.4k | z_int32_t Z_EXPORT PREFIX(gzclose)(gzFile file) { |
324 | 23.4k | #ifndef NO_GZCOMPRESS |
325 | 23.4k | gz_state *state; |
326 | | |
327 | 23.4k | if (file == NULL) |
328 | 0 | return Z_STREAM_ERROR; |
329 | 23.4k | state = (gz_state *)file; |
330 | | |
331 | 23.4k | return state->mode == GZ_READ ? PREFIX(gzclose_r)(file) : PREFIX(gzclose_w)(file); |
332 | | #else |
333 | | return PREFIX(gzclose_r)(file); |
334 | | #endif |
335 | 23.4k | } |
336 | | |
337 | | /* -- see zlib.h -- */ |
338 | 0 | z_int32_t Z_EXPORT PREFIX(gzbuffer)(gzFile file, z_uint32_t size) { |
339 | 0 | gz_state *state; |
340 | | |
341 | | /* get internal structure and check integrity */ |
342 | 0 | if (file == NULL) |
343 | 0 | return -1; |
344 | 0 | state = (gz_state *)file; |
345 | 0 | if (state->mode != GZ_READ && state->mode != GZ_WRITE) |
346 | 0 | return -1; |
347 | | |
348 | | /* make sure we haven't already allocated memory */ |
349 | 0 | if (state->size != 0) |
350 | 0 | return -1; |
351 | | |
352 | | /* check and set requested size */ |
353 | 0 | if (size > GZBUFSIZE_MAX) { |
354 | | #ifdef ZLIB_COMPAT |
355 | | size = GZBUFSIZE_MAX; /* silently clamp to stay compatible with zlib */ |
356 | | #else |
357 | 0 | PREFIX(gz_error)(state, Z_MEM_ERROR, "out of memory"); |
358 | 0 | return -1; /* too large */ |
359 | 0 | #endif |
360 | 0 | } |
361 | 0 | if (size < 8) |
362 | 0 | size = 8; /* needed to behave well with flushing */ |
363 | 0 | state->want = size; |
364 | 0 | return 0; |
365 | 0 | } |
366 | | |
367 | | /* -- see zlib.h -- */ |
368 | 0 | z_int32_t Z_EXPORT PREFIX(gzrewind)(gzFile file) { |
369 | 0 | gz_state *state; |
370 | | |
371 | | /* get internal structure */ |
372 | 0 | if (file == NULL) |
373 | 0 | return -1; |
374 | 0 | state = (gz_state *)file; |
375 | | |
376 | | /* check that we're reading and that there's no error */ |
377 | 0 | if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) |
378 | 0 | return -1; |
379 | | |
380 | | /* back up and start over */ |
381 | 0 | if (LSEEK(state->fd, state->start, SEEK_SET) == -1) |
382 | 0 | return -1; |
383 | 0 | gz_reset(state); |
384 | 0 | return 0; |
385 | 0 | } |
386 | | |
387 | | /* -- see zlib.h -- */ |
388 | 0 | z_off64_t Z_EXPORT PREFIX4(gzseek)(gzFile file, z_off64_t offset, int whence) { |
389 | 0 | unsigned n; |
390 | 0 | z_off64_t ret; |
391 | 0 | gz_state *state; |
392 | | |
393 | | /* get internal structure and check integrity */ |
394 | 0 | if (file == NULL) |
395 | 0 | return -1; |
396 | 0 | state = (gz_state *)file; |
397 | 0 | if (state->mode != GZ_READ && state->mode != GZ_WRITE) |
398 | 0 | return -1; |
399 | | |
400 | | /* check that there's no error */ |
401 | 0 | if (state->err != Z_OK && state->err != Z_BUF_ERROR) |
402 | 0 | return -1; |
403 | | |
404 | | /* can only seek from start or relative to current position */ |
405 | 0 | if (whence != SEEK_SET && whence != SEEK_CUR) |
406 | 0 | return -1; |
407 | | |
408 | | /* normalize offset to a SEEK_CUR specification */ |
409 | 0 | if (whence == SEEK_SET) |
410 | 0 | offset -= state->x.pos; |
411 | 0 | else { |
412 | 0 | offset += state->past ? 0 : state->skip; |
413 | 0 | state->skip = 0; |
414 | 0 | } |
415 | | |
416 | | /* if within raw area while reading, just go there */ |
417 | 0 | if (state->mode == GZ_READ && state->how == COPY && state->x.pos + offset >= 0) { |
418 | 0 | ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR); |
419 | 0 | if (ret == -1) |
420 | 0 | return -1; |
421 | 0 | state->x.have = 0; |
422 | 0 | state->eof = 0; |
423 | 0 | state->past = 0; |
424 | 0 | state->skip = 0; |
425 | 0 | PREFIX(gz_error)(state, Z_OK, NULL); |
426 | 0 | state->strm.avail_in = 0; |
427 | 0 | state->x.pos += offset; |
428 | 0 | return state->x.pos; |
429 | 0 | } |
430 | | |
431 | | /* calculate skip amount, rewinding if needed for back seek when reading */ |
432 | 0 | if (offset < 0) { |
433 | 0 | if (state->mode != GZ_READ) /* writing -- can't go backwards */ |
434 | 0 | return -1; |
435 | 0 | offset += state->x.pos; |
436 | 0 | if (offset < 0) /* before start of file! */ |
437 | 0 | return -1; |
438 | 0 | if (PREFIX(gzrewind)(file) == -1) /* rewind, then skip to offset */ |
439 | 0 | return -1; |
440 | 0 | } |
441 | | |
442 | | /* if reading, skip what's in output buffer (one less gzgetc() check) */ |
443 | 0 | if (state->mode == GZ_READ) { |
444 | 0 | n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? (unsigned)offset : state->x.have; |
445 | 0 | state->x.have -= n; |
446 | 0 | state->x.next += n; |
447 | 0 | state->x.pos += n; |
448 | 0 | offset -= n; |
449 | 0 | } |
450 | | |
451 | | /* request skip (if not zero) */ |
452 | 0 | state->skip = offset; |
453 | 0 | return state->x.pos + offset; |
454 | 0 | } |
455 | | |
456 | | /* -- see zlib.h -- */ |
457 | | #ifdef ZLIB_COMPAT |
458 | | z_off_t Z_EXPORT PREFIX(gzseek)(gzFile file, z_off_t offset, int whence) { |
459 | | z_off64_t ret; |
460 | | |
461 | | ret = PREFIX4(gzseek)(file, (z_off64_t)offset, whence); |
462 | | return ret == (z_off_t)ret ? (z_off_t)ret : -1; |
463 | | } |
464 | | #endif |
465 | | |
466 | | /* -- see zlib.h -- */ |
467 | 0 | z_off64_t Z_EXPORT PREFIX4(gztell)(gzFile file) { |
468 | 0 | gz_state *state; |
469 | | |
470 | | /* get internal structure and check integrity */ |
471 | 0 | if (file == NULL) |
472 | 0 | return -1; |
473 | 0 | state = (gz_state *)file; |
474 | 0 | if (state->mode != GZ_READ && state->mode != GZ_WRITE) |
475 | 0 | return -1; |
476 | | |
477 | | /* return position */ |
478 | 0 | return state->x.pos + (state->past ? 0 : state->skip); |
479 | 0 | } |
480 | | |
481 | | /* -- see zlib.h -- */ |
482 | | #ifdef ZLIB_COMPAT |
483 | | z_off_t Z_EXPORT PREFIX(gztell)(gzFile file) { |
484 | | |
485 | | z_off64_t ret; |
486 | | |
487 | | ret = PREFIX4(gztell)(file); |
488 | | return ret == (z_off_t)ret ? (z_off_t)ret : -1; |
489 | | } |
490 | | #endif |
491 | | |
492 | | /* -- see zlib.h -- */ |
493 | 0 | z_off64_t Z_EXPORT PREFIX4(gzoffset)(gzFile file) { |
494 | 0 | z_off64_t offset; |
495 | 0 | gz_state *state; |
496 | | |
497 | | /* get internal structure and check integrity */ |
498 | 0 | if (file == NULL) |
499 | 0 | return -1; |
500 | 0 | state = (gz_state *)file; |
501 | 0 | if (state->mode != GZ_READ && state->mode != GZ_WRITE) |
502 | 0 | return -1; |
503 | | |
504 | | /* compute and return effective offset in file */ |
505 | 0 | offset = LSEEK(state->fd, 0, SEEK_CUR); |
506 | 0 | if (offset == -1) |
507 | 0 | return -1; |
508 | 0 | if (state->mode == GZ_READ) /* reading */ |
509 | 0 | offset -= state->strm.avail_in; /* don't count buffered input */ |
510 | 0 | return offset; |
511 | 0 | } |
512 | | |
513 | | /* -- see zlib.h -- */ |
514 | | #ifdef ZLIB_COMPAT |
515 | | z_off_t Z_EXPORT PREFIX(gzoffset)(gzFile file) { |
516 | | z_off64_t ret; |
517 | | |
518 | | ret = PREFIX4(gzoffset)(file); |
519 | | return ret == (z_off_t)ret ? (z_off_t)ret : -1; |
520 | | } |
521 | | #endif |
522 | | |
523 | | /* -- see zlib.h -- */ |
524 | 0 | z_int32_t Z_EXPORT PREFIX(gzeof)(gzFile file) { |
525 | 0 | gz_state *state; |
526 | | |
527 | | /* get internal structure and check integrity */ |
528 | 0 | if (file == NULL) |
529 | 0 | return 0; |
530 | 0 | state = (gz_state *)file; |
531 | 0 | if (state->mode != GZ_READ && state->mode != GZ_WRITE) |
532 | 0 | return 0; |
533 | | |
534 | | /* return end-of-file state */ |
535 | 0 | return state->mode == GZ_READ ? state->past : 0; |
536 | 0 | } |
537 | | |
538 | | /* -- see zlib.h -- */ |
539 | 0 | const char * Z_EXPORT PREFIX(gzerror)(gzFile file, z_int32_t *errnum) { |
540 | 0 | gz_state *state; |
541 | | |
542 | | /* get internal structure and check integrity */ |
543 | 0 | if (file == NULL) |
544 | 0 | return NULL; |
545 | 0 | state = (gz_state *)file; |
546 | 0 | if (state->mode != GZ_READ && state->mode != GZ_WRITE) |
547 | 0 | return NULL; |
548 | | |
549 | | /* return error information */ |
550 | 0 | if (errnum != NULL) |
551 | 0 | *errnum = state->err; |
552 | 0 | return state->err == Z_MEM_ERROR ? "out of memory" : (state->msg == NULL ? "" : state->msg); |
553 | 0 | } |
554 | | |
555 | | /* -- see zlib.h -- */ |
556 | 0 | void Z_EXPORT PREFIX(gzclearerr)(gzFile file) { |
557 | 0 | gz_state *state; |
558 | | |
559 | | /* get internal structure and check integrity */ |
560 | 0 | if (file == NULL) |
561 | 0 | return; |
562 | 0 | state = (gz_state *)file; |
563 | 0 | if (state->mode != GZ_READ && state->mode != GZ_WRITE) |
564 | 0 | return; |
565 | | |
566 | | /* clear error and end-of-file */ |
567 | 0 | if (state->mode == GZ_READ) { |
568 | 0 | state->eof = 0; |
569 | 0 | state->past = 0; |
570 | 0 | } |
571 | 0 | PREFIX(gz_error)(state, Z_OK, NULL); |
572 | 0 | } |
573 | | |
574 | | /* Create an error message in allocated memory and set state->err and |
575 | | state->msg accordingly. Free any previous error message already there. Do |
576 | | not try to free or allocate space if the error is Z_MEM_ERROR (out of |
577 | | memory). Simply save the error message as a static string. If there is an |
578 | | allocation failure constructing the error message, then convert the error to |
579 | | out of memory. */ |
580 | 46.9k | void Z_INTERNAL PREFIX(gz_error)(gz_state *state, int err, const char *msg) { |
581 | | /* free previously allocated message and clear */ |
582 | 46.9k | if (state->msg != NULL) { |
583 | 0 | if (state->err != Z_MEM_ERROR) |
584 | 0 | free(state->msg); |
585 | 0 | state->msg = NULL; |
586 | 0 | } |
587 | | |
588 | | /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */ |
589 | 46.9k | if (err != Z_OK && err != Z_BUF_ERROR) |
590 | 0 | state->x.have = 0; |
591 | | |
592 | | /* set error code, and if no message, then done */ |
593 | 46.9k | state->err = err; |
594 | 46.9k | if (msg == NULL) |
595 | 46.9k | return; |
596 | | |
597 | | /* for an out of memory error, return literal string when requested */ |
598 | 0 | if (err == Z_MEM_ERROR) |
599 | 0 | return; |
600 | | |
601 | | /* construct error message with path */ |
602 | 0 | if ((state->msg = malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) { |
603 | 0 | state->err = Z_MEM_ERROR; |
604 | 0 | return; |
605 | 0 | } |
606 | 0 | (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, "%s%s%s", state->path, ": ", msg); |
607 | 0 | } |
608 | | |
609 | | #ifdef ZLIB_COMPAT |
610 | | unsigned Z_INTERNAL gz_intmax(void) { |
611 | | return INT_MAX; |
612 | | } |
613 | | #endif |