opencv
1/* gzlib.c -- zlib functions common to reading and writing gzip files
2* Copyright (C) 2004-2019 Mark Adler
3* For conditions of distribution and use, see copyright notice in zlib.h
4*/
5
6#include "zbuild.h"7#include "zutil_p.h"8#include "gzguts.h"9
10#if defined(_WIN32)11# define LSEEK _lseeki6412#else13#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-014# define LSEEK lseek6415#else16# define LSEEK lseek17#endif18#endif19
20/* Local functions */
21static void gz_reset(gz_state *);22static gzFile gz_open(const void *, int, const char *);23
24/* Reset gzip file state */
25static void gz_reset(gz_state *state) {26state->x.have = 0; /* no output data available */27if (state->mode == GZ_READ) { /* for reading ... */28state->eof = 0; /* not at end of file */29state->past = 0; /* have not read past end yet */30state->how = LOOK; /* look for gzip header */31}32else /* for writing ... */33state->reset = 0; /* no deflateReset pending */34state->seek = 0; /* no seek request pending */35gz_error(state, Z_OK, NULL); /* clear error */36state->x.pos = 0; /* no uncompressed data yet */37state->strm.avail_in = 0; /* no input data yet */38}
39
40/* Open a gzip file either by name or file descriptor. */
41static gzFile gz_open(const void *path, int fd, const char *mode) {42gz_state *state;43size_t len;44int oflag;45#ifdef O_CLOEXEC46int cloexec = 0;47#endif48#ifdef O_EXCL49int exclusive = 0;50#endif51
52/* check input */53if (path == NULL)54return NULL;55
56/* allocate gzFile structure to return */57state = (gz_state *)zng_alloc(sizeof(gz_state));58if (state == NULL)59return NULL;60state->size = 0; /* no buffers allocated yet */61state->want = GZBUFSIZE; /* requested buffer size */62state->msg = NULL; /* no error message yet */63
64/* interpret mode */65state->mode = GZ_NONE;66state->level = Z_DEFAULT_COMPRESSION;67state->strategy = Z_DEFAULT_STRATEGY;68state->direct = 0;69while (*mode) {70if (*mode >= '0' && *mode <= '9') {71state->level = *mode - '0';72} else {73switch (*mode) {74case 'r':75state->mode = GZ_READ;76break;77#ifndef NO_GZCOMPRESS78case 'w':79state->mode = GZ_WRITE;80break;81case 'a':82state->mode = GZ_APPEND;83break;84#endif85case '+': /* can't read and write at the same time */86zng_free(state);87return NULL;88case 'b': /* ignore -- will request binary anyway */89break;90#ifdef O_CLOEXEC91case 'e':92cloexec = 1;93break;94#endif95#ifdef O_EXCL96case 'x':97exclusive = 1;98break;99#endif100case 'f':101state->strategy = Z_FILTERED;102break;103case 'h':104state->strategy = Z_HUFFMAN_ONLY;105break;106case 'R':107state->strategy = Z_RLE;108break;109case 'F':110state->strategy = Z_FIXED;111break;112case 'T':113state->direct = 1;114break;115default: /* could consider as an error, but just ignore */116{}117}118}119mode++;120}121
122/* must provide an "r", "w", or "a" */123if (state->mode == GZ_NONE) {124zng_free(state);125return NULL;126}127
128/* can't force transparent read */129if (state->mode == GZ_READ) {130if (state->direct) {131zng_free(state);132return NULL;133}134state->direct = 1; /* for empty file */135}136
137/* save the path name for error messages */138#ifdef WIDECHAR139if (fd == -2) {140len = wcstombs(NULL, (const wchar_t *)path, 0);141if (len == (size_t)-1)142len = 0;143} else144#endif145len = strlen((const char *)path);146state->path = (char *)malloc(len + 1);147if (state->path == NULL) {148zng_free(state);149return NULL;150}151#ifdef WIDECHAR152if (fd == -2)153if (len) {154wcstombs(state->path, (const wchar_t *)path, len + 1);155} else {156*(state->path) = 0;157}158else159#endif160(void)snprintf(state->path, len + 1, "%s", (const char *)path);161
162/* compute the flags for open() */163oflag =164#ifdef O_LARGEFILE165O_LARGEFILE |166#endif167#ifdef O_BINARY168O_BINARY |169#endif170#ifdef O_CLOEXEC171(cloexec ? O_CLOEXEC : 0) |172#endif173(state->mode == GZ_READ ?174O_RDONLY :175(O_WRONLY | O_CREAT |176#ifdef O_EXCL177(exclusive ? O_EXCL : 0) |178#endif179(state->mode == GZ_WRITE ?180O_TRUNC :181O_APPEND)));182
183/* open the file with the appropriate flags (or just use fd) */184state->fd = fd > -1 ? fd : (185#if defined(_WIN32)186fd == -2 ? _wopen((const wchar_t *)path, oflag, 0666) :187#elif __CYGWIN__188fd == -2 ? open(state->path, oflag, 0666) :189#endif190open((const char *)path, oflag, 0666));191if (state->fd == -1) {192free(state->path);193zng_free(state);194return NULL;195}196if (state->mode == GZ_APPEND) {197LSEEK(state->fd, 0, SEEK_END); /* so gzoffset() is correct */198state->mode = GZ_WRITE; /* simplify later checks */199}200
201/* save the current position for rewinding (only if reading) */202if (state->mode == GZ_READ) {203state->start = LSEEK(state->fd, 0, SEEK_CUR);204if (state->start == -1) state->start = 0;205}206
207/* initialize stream */208gz_reset(state);209
210/* return stream */211return (gzFile)state;212}
213
214/* -- see zlib.h -- */
215gzFile Z_EXPORT PREFIX(gzopen)(const char *path, const char *mode) {216return gz_open(path, -1, mode);217}
218
219#ifdef ZLIB_COMPAT220gzFile Z_EXPORT PREFIX4(gzopen)(const char *path, const char *mode) {221return gz_open(path, -1, mode);222}
223#endif224
225/* -- see zlib.h -- */
226gzFile Z_EXPORT PREFIX(gzdopen)(int fd, const char *mode) {227char *path; /* identifier for error messages */228gzFile gz;229
230if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)231return NULL;232(void)snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd); /* for debugging */233gz = gz_open(path, fd, mode);234free(path);235return gz;236}
237
238/* -- see zlib.h -- */
239#ifdef WIDECHAR240gzFile Z_EXPORT PREFIX(gzopen_w)(const wchar_t *path, const char *mode) {241return gz_open(path, -2, mode);242}
243#endif244
245int Z_EXPORT PREFIX(gzclose)(gzFile file) {246#ifndef NO_GZCOMPRESS247gz_state *state;248
249if (file == NULL)250return Z_STREAM_ERROR;251state = (gz_state *)file;252
253return state->mode == GZ_READ ? PREFIX(gzclose_r)(file) : PREFIX(gzclose_w)(file);254#else255return PREFIX(gzclose_r)(file);256#endif257}
258
259/* -- see zlib.h -- */
260int Z_EXPORT PREFIX(gzbuffer)(gzFile file, unsigned size) {261gz_state *state;262
263/* get internal structure and check integrity */264if (file == NULL)265return -1;266state = (gz_state *)file;267if (state->mode != GZ_READ && state->mode != GZ_WRITE)268return -1;269
270/* make sure we haven't already allocated memory */271if (state->size != 0)272return -1;273
274/* check and set requested size */275if ((size << 1) < size)276return -1; /* need to be able to double it */277if (size < 8)278size = 8; /* needed to behave well with flushing */279state->want = size;280return 0;281}
282
283/* -- see zlib.h -- */
284int Z_EXPORT PREFIX(gzrewind)(gzFile file) {285gz_state *state;286
287/* get internal structure */288if (file == NULL)289return -1;290state = (gz_state *)file;291
292/* check that we're reading and that there's no error */293if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR))294return -1;295
296/* back up and start over */297if (LSEEK(state->fd, state->start, SEEK_SET) == -1)298return -1;299gz_reset(state);300return 0;301}
302
303/* -- see zlib.h -- */
304z_off64_t Z_EXPORT PREFIX4(gzseek)(gzFile file, z_off64_t offset, int whence) {305unsigned n;306z_off64_t ret;307gz_state *state;308
309/* get internal structure and check integrity */310if (file == NULL)311return -1;312state = (gz_state *)file;313if (state->mode != GZ_READ && state->mode != GZ_WRITE)314return -1;315
316/* check that there's no error */317if (state->err != Z_OK && state->err != Z_BUF_ERROR)318return -1;319
320/* can only seek from start or relative to current position */321if (whence != SEEK_SET && whence != SEEK_CUR)322return -1;323
324/* normalize offset to a SEEK_CUR specification */325if (whence == SEEK_SET)326offset -= state->x.pos;327else if (state->seek)328offset += state->skip;329state->seek = 0;330
331/* if within raw area while reading, just go there */332if (state->mode == GZ_READ && state->how == COPY && state->x.pos + offset >= 0) {333ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR);334if (ret == -1)335return -1;336state->x.have = 0;337state->eof = 0;338state->past = 0;339state->seek = 0;340gz_error(state, Z_OK, NULL);341state->strm.avail_in = 0;342state->x.pos += offset;343return state->x.pos;344}345
346/* calculate skip amount, rewinding if needed for back seek when reading */347if (offset < 0) {348if (state->mode != GZ_READ) /* writing -- can't go backwards */349return -1;350offset += state->x.pos;351if (offset < 0) /* before start of file! */352return -1;353if (PREFIX(gzrewind)(file) == -1) /* rewind, then skip to offset */354return -1;355}356
357/* if reading, skip what's in output buffer (one less gzgetc() check) */358if (state->mode == GZ_READ) {359n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? (unsigned)offset : state->x.have;360state->x.have -= n;361state->x.next += n;362state->x.pos += n;363offset -= n;364}365
366/* request skip (if not zero) */367if (offset) {368state->seek = 1;369state->skip = offset;370}371return state->x.pos + offset;372}
373
374/* -- see zlib.h -- */
375#ifdef ZLIB_COMPAT376z_off_t Z_EXPORT PREFIX(gzseek)(gzFile file, z_off_t offset, int whence) {377z_off64_t ret;378
379ret = PREFIX4(gzseek)(file, (z_off64_t)offset, whence);380return ret == (z_off_t)ret ? (z_off_t)ret : -1;381}
382#endif383
384/* -- see zlib.h -- */
385z_off64_t Z_EXPORT PREFIX4(gztell)(gzFile file) {386gz_state *state;387
388/* get internal structure and check integrity */389if (file == NULL)390return -1;391state = (gz_state *)file;392if (state->mode != GZ_READ && state->mode != GZ_WRITE)393return -1;394
395/* return position */396return state->x.pos + (state->seek ? state->skip : 0);397}
398
399/* -- see zlib.h -- */
400#ifdef ZLIB_COMPAT401z_off_t Z_EXPORT PREFIX(gztell)(gzFile file) {402
403z_off64_t ret;404
405ret = PREFIX4(gztell)(file);406return ret == (z_off_t)ret ? (z_off_t)ret : -1;407}
408#endif409
410/* -- see zlib.h -- */
411z_off64_t Z_EXPORT PREFIX4(gzoffset)(gzFile file) {412z_off64_t offset;413gz_state *state;414
415/* get internal structure and check integrity */416if (file == NULL)417return -1;418state = (gz_state *)file;419if (state->mode != GZ_READ && state->mode != GZ_WRITE)420return -1;421
422/* compute and return effective offset in file */423offset = LSEEK(state->fd, 0, SEEK_CUR);424if (offset == -1)425return -1;426if (state->mode == GZ_READ) /* reading */427offset -= state->strm.avail_in; /* don't count buffered input */428return offset;429}
430
431/* -- see zlib.h -- */
432#ifdef ZLIB_COMPAT433z_off_t Z_EXPORT PREFIX(gzoffset)(gzFile file) {434z_off64_t ret;435
436ret = PREFIX4(gzoffset)(file);437return ret == (z_off_t)ret ? (z_off_t)ret : -1;438}
439#endif440
441/* -- see zlib.h -- */
442int Z_EXPORT PREFIX(gzeof)(gzFile file) {443gz_state *state;444
445/* get internal structure and check integrity */446if (file == NULL)447return 0;448state = (gz_state *)file;449if (state->mode != GZ_READ && state->mode != GZ_WRITE)450return 0;451
452/* return end-of-file state */453return state->mode == GZ_READ ? state->past : 0;454}
455
456/* -- see zlib.h -- */
457const char * Z_EXPORT PREFIX(gzerror)(gzFile file, int *errnum) {458gz_state *state;459
460/* get internal structure and check integrity */461if (file == NULL)462return NULL;463state = (gz_state *)file;464if (state->mode != GZ_READ && state->mode != GZ_WRITE)465return NULL;466
467/* return error information */468if (errnum != NULL)469*errnum = state->err;470return state->err == Z_MEM_ERROR ? "out of memory" : (state->msg == NULL ? "" : state->msg);471}
472
473/* -- see zlib.h -- */
474void Z_EXPORT PREFIX(gzclearerr)(gzFile file) {475gz_state *state;476
477/* get internal structure and check integrity */478if (file == NULL)479return;480state = (gz_state *)file;481if (state->mode != GZ_READ && state->mode != GZ_WRITE)482return;483
484/* clear error and end-of-file */485if (state->mode == GZ_READ) {486state->eof = 0;487state->past = 0;488}489gz_error(state, Z_OK, NULL);490}
491
492/* Create an error message in allocated memory and set state->err and
493state->msg accordingly. Free any previous error message already there. Do
494not try to free or allocate space if the error is Z_MEM_ERROR (out of
495memory). Simply save the error message as a static string. If there is an
496allocation failure constructing the error message, then convert the error to
497out of memory. */
498void Z_INTERNAL gz_error(gz_state *state, int err, const char *msg) {499/* free previously allocated message and clear */500if (state->msg != NULL) {501if (state->err != Z_MEM_ERROR)502free(state->msg);503state->msg = NULL;504}505
506/* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */507if (err != Z_OK && err != Z_BUF_ERROR)508state->x.have = 0;509
510/* set error code, and if no message, then done */511state->err = err;512if (msg == NULL)513return;514
515/* for an out of memory error, return literal string when requested */516if (err == Z_MEM_ERROR)517return;518
519/* construct error message with path */520if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) {521state->err = Z_MEM_ERROR;522return;523}524(void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, "%s%s%s", state->path, ": ", msg);525}
526