git subrepo pull (merge) --force deps/libchdr
[pcsx_rearmed.git] / deps / libchdr / deps / zlib-1.3.1 / gzlib.c
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 }