git subrepo pull (merge) --force deps/libchdr
[pcsx_rearmed.git] / deps / libchdr / deps / zlib-1.3.1 / gzlib.c
CommitLineData
b24e7fce 1/* gzlib.c -- zlib functions common to reading and writing gzip files
648db22b 2 * Copyright (C) 2004-2024 Mark Adler
b24e7fce 3 * For conditions of distribution and use, see copyright notice in zlib.h
4 */
5
6#include "gzguts.h"
7
9e052883 8#if defined(_WIN32) && !defined(__BORLANDC__)
b24e7fce 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
b24e7fce 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. */
648db22b 29char ZLIB_INTERNAL *gz_strwinerror(DWORD error) {
b24e7fce 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 */
648db22b 69local void gz_reset(gz_statep state) {
b24e7fce 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 }
9e052883 76 else /* for writing ... */
77 state->reset = 0; /* no deflateReset pending */
b24e7fce 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. */
648db22b 85local gzFile gz_open(const void *path, int fd, const char *mode) {
b24e7fce 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 -- */
648db22b 260gzFile ZEXPORT gzopen(const char *path, const char *mode) {
b24e7fce 261 return gz_open(path, -1, mode);
262}
263
264/* -- see zlib.h -- */
648db22b 265gzFile ZEXPORT gzopen64(const char *path, const char *mode) {
b24e7fce 266 return gz_open(path, -1, mode);
267}
268
269/* -- see zlib.h -- */
648db22b 270gzFile ZEXPORT gzdopen(int fd, const char *mode) {
b24e7fce 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
648db22b 288gzFile ZEXPORT gzopen_w(const wchar_t *path, const char *mode) {
b24e7fce 289 return gz_open(path, -2, mode);
290}
291#endif
292
293/* -- see zlib.h -- */
648db22b 294int ZEXPORT gzbuffer(gzFile file, unsigned size) {
b24e7fce 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 */
648db22b 311 if (size < 8)
312 size = 8; /* needed to behave well with flushing */
b24e7fce 313 state->want = size;
314 return 0;
315}
316
317/* -- see zlib.h -- */
648db22b 318int ZEXPORT gzrewind(gzFile file) {
b24e7fce 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 -- */
648db22b 339z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
b24e7fce 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) {
9e052883 369 ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR);
b24e7fce 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 -- */
648db22b 412z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) {
b24e7fce 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 -- */
648db22b 420z_off64_t ZEXPORT gztell64(gzFile file) {
b24e7fce 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 -- */
648db22b 435z_off_t ZEXPORT gztell(gzFile file) {
b24e7fce 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 -- */
648db22b 443z_off64_t ZEXPORT gzoffset64(gzFile file) {
b24e7fce 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 -- */
648db22b 464z_off_t ZEXPORT gzoffset(gzFile file) {
b24e7fce 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 -- */
648db22b 472int ZEXPORT gzeof(gzFile file) {
b24e7fce 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 -- */
648db22b 487const char * ZEXPORT gzerror(gzFile file, int *errnum) {
b24e7fce 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 -- */
648db22b 505void ZEXPORT gzclearerr(gzFile file) {
b24e7fce 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. */
648db22b 529void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) {
b24e7fce 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
b24e7fce 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 */
648db22b 570unsigned ZLIB_INTERNAL gz_intmax(void) {
571#ifdef INT_MAX
572 return INT_MAX;
573#else
574 unsigned p = 1, q;
b24e7fce 575 do {
576 q = p;
577 p <<= 1;
578 p++;
579 } while (p > q);
580 return q >> 1;
b24e7fce 581#endif
648db22b 582}