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