199767f8919635c4928607450d9e0abb932109ceToomas Soome/* gzlib.c -- zlib functions common to reading and writing gzip files
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Copyright (C) 2004, 2010, 2011, 2012, 2013 Mark Adler
199767f8919635c4928607450d9e0abb932109ceToomas Soome * For conditions of distribution and use, see copyright notice in zlib.h
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* $FreeBSD$ */
199767f8919635c4928607450d9e0abb932109ceToomas Soome#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* Local functions */
199767f8919635c4928607450d9e0abb932109ceToomas Soomelocal gzFile gz_open OF((const void *, int, const char *));
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* Map the Windows error number in ERROR to a locale-dependent error message
199767f8919635c4928607450d9e0abb932109ceToomas Soome string and return a pointer to it. Typically, the values for ERROR come
199767f8919635c4928607450d9e0abb932109ceToomas Soome from GetLastError.
199767f8919635c4928607450d9e0abb932109ceToomas Soome The string pointed to shall not be modified by the application, but may be
199767f8919635c4928607450d9e0abb932109ceToomas Soome overwritten by a subsequent call to gz_strwinerror
199767f8919635c4928607450d9e0abb932109ceToomas Soome The gz_strwinerror function does not change the current setting of
199767f8919635c4928607450d9e0abb932109ceToomas Soome GetLastError. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
199767f8919635c4928607450d9e0abb932109ceToomas Soome 0, /* Default language */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* If there is an \r\n appended, zap it. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(buf, "unknown win32 error (%ld)", error);
199767f8919635c4928607450d9e0abb932109ceToomas Soome#endif /* UNDER_CE */
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* Reset gzip file state */
199767f8919635c4928607450d9e0abb932109ceToomas Soome state->x.have = 0; /* no output data available */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (state->mode == GZ_READ) { /* for reading ... */
199767f8919635c4928607450d9e0abb932109ceToomas Soome state->past = 0; /* have not read past end yet */
199767f8919635c4928607450d9e0abb932109ceToomas Soome state->x.pos = 0; /* no uncompressed data yet */
199767f8919635c4928607450d9e0abb932109ceToomas Soome state->strm.avail_in = 0; /* no input data yet */
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* Open a gzip file either by name or file descriptor. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome const void *path;
199767f8919635c4928607450d9e0abb932109ceToomas Soome const char *mode;
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* check input */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* allocate gzFile structure to return */
199767f8919635c4928607450d9e0abb932109ceToomas Soome state->size = 0; /* no buffers allocated yet */
199767f8919635c4928607450d9e0abb932109ceToomas Soome state->want = GZBUFSIZE; /* requested buffer size */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* interpret mode */
199767f8919635c4928607450d9e0abb932109ceToomas Soome case '+': /* can't read and write at the same time */
199767f8919635c4928607450d9e0abb932109ceToomas Soome case 'b': /* ignore -- will request binary anyway */
199767f8919635c4928607450d9e0abb932109ceToomas Soome default: /* could consider as an error, but just ignore */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* must provide an "r", "w", or "a" */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* can't force transparent read */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* save the path name for error messages */
199767f8919635c4928607450d9e0abb932109ceToomas Soome#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(state->path, len + 1, "%s", (const char *)path);
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* compute the flags for open() */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* open the file with the appropriate flags (or just use fd) */
199767f8919635c4928607450d9e0abb932109ceToomas Soome state->mode = GZ_WRITE; /* simplify later checks */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* save the current position for rewinding (only if reading) */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* initialize stream */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* return stream */
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* -- see zlib.h -- */
199767f8919635c4928607450d9e0abb932109ceToomas Soome const char *path;
199767f8919635c4928607450d9e0abb932109ceToomas Soome const char *mode;
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* -- see zlib.h -- */
199767f8919635c4928607450d9e0abb932109ceToomas Soome const char *path;
199767f8919635c4928607450d9e0abb932109ceToomas Soome const char *mode;
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* -- see zlib.h -- */
199767f8919635c4928607450d9e0abb932109ceToomas Soome const char *mode;
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *path; /* identifier for error messages */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd); /* for debugging */
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(path, "<fd:%d>", fd); /* for debugging */
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* -- see zlib.h -- */
199767f8919635c4928607450d9e0abb932109ceToomas Soome const char *mode;
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* -- see zlib.h -- */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* get internal structure and check integrity */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (state->mode != GZ_READ && state->mode != GZ_WRITE)
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* make sure we haven't already allocated memory */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* check and set requested size */
199767f8919635c4928607450d9e0abb932109ceToomas Soome size = 2; /* need two bytes to check magic header */
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* -- see zlib.h -- */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* get internal structure */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* check that we're reading and that there's no error */
199767f8919635c4928607450d9e0abb932109ceToomas Soome (state->err != Z_OK && state->err != Z_BUF_ERROR))
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* back up and start over */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* -- see zlib.h -- */
199767f8919635c4928607450d9e0abb932109ceToomas Soomez_off64_t ZEXPORT gzseek64(file, offset, whence)
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* get internal structure and check integrity */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (state->mode != GZ_READ && state->mode != GZ_WRITE)
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* check that there's no error */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (state->err != Z_OK && state->err != Z_BUF_ERROR)
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* can only seek from start or relative to current position */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* normalize offset to a SEEK_CUR specification */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* if within raw area while reading, just go there */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (state->mode == GZ_READ && state->how == COPY &&
199767f8919635c4928607450d9e0abb932109ceToomas Soome ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR);
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* calculate skip amount, rewinding if needed for back seek when reading */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (state->mode != GZ_READ) /* writing -- can't go backwards */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (gzrewind(file) == -1) /* rewind, then skip to offset */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* if reading, skip what's in output buffer (one less gzgetc() check) */
199767f8919635c4928607450d9e0abb932109ceToomas Soome n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* request skip (if not zero) */
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* -- see zlib.h -- */
199767f8919635c4928607450d9e0abb932109ceToomas Soome ret = gzseek64(file, (z_off64_t)offset, whence);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return ret == (z_off_t)ret ? (z_off_t)ret : -1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* -- see zlib.h -- */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* get internal structure and check integrity */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (state->mode != GZ_READ && state->mode != GZ_WRITE)
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* return position */
199767f8919635c4928607450d9e0abb932109ceToomas Soome return state->x.pos + (state->seek ? state->skip : 0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* -- see zlib.h -- */
199767f8919635c4928607450d9e0abb932109ceToomas Soome return ret == (z_off_t)ret ? (z_off_t)ret : -1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* -- see zlib.h -- */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* get internal structure and check integrity */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (state->mode != GZ_READ && state->mode != GZ_WRITE)
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* compute and return effective offset in file */
199767f8919635c4928607450d9e0abb932109ceToomas Soome offset -= state->strm.avail_in; /* don't count buffered input */
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* -- see zlib.h -- */
199767f8919635c4928607450d9e0abb932109ceToomas Soome return ret == (z_off_t)ret ? (z_off_t)ret : -1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* -- see zlib.h -- */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* get internal structure and check integrity */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (state->mode != GZ_READ && state->mode != GZ_WRITE)
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* return end-of-file state */
199767f8919635c4928607450d9e0abb932109ceToomas Soome return state->mode == GZ_READ ? state->past : 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* -- see zlib.h -- */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* get internal structure and check integrity */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (state->mode != GZ_READ && state->mode != GZ_WRITE)
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* return error information */
199767f8919635c4928607450d9e0abb932109ceToomas Soome return state->err == Z_MEM_ERROR ? "out of memory" :
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* -- see zlib.h -- */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* get internal structure and check integrity */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (state->mode != GZ_READ && state->mode != GZ_WRITE)
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* clear error and end-of-file */
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* Create an error message in allocated memory and set state->err and
199767f8919635c4928607450d9e0abb932109ceToomas Soome state->msg accordingly. Free any previous error message already there. Do
199767f8919635c4928607450d9e0abb932109ceToomas Soome not try to free or allocate space if the error is Z_MEM_ERROR (out of
199767f8919635c4928607450d9e0abb932109ceToomas Soome memory). Simply save the error message as a static string. If there is an
199767f8919635c4928607450d9e0abb932109ceToomas Soome allocation failure constructing the error message, then convert the error to
199767f8919635c4928607450d9e0abb932109ceToomas Soome out of memory. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome const char *msg;
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* free previously allocated message and clear */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* set error code, and if no message, then done */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* for an out of memory error, return literal string when requested */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* construct error message with path */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
199767f8919635c4928607450d9e0abb932109ceToomas Soome#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* portably return maximum value for an int (when limits.h presumed not
199767f8919635c4928607450d9e0abb932109ceToomas Soome available) -- we need to do this to cover cases where 2's complement not
199767f8919635c4928607450d9e0abb932109ceToomas Soome used, since C standard permits 1's complement and sign-bit representations,
199767f8919635c4928607450d9e0abb932109ceToomas Soome otherwise we could just use ((unsigned)-1) >> 1 */
199767f8919635c4928607450d9e0abb932109ceToomas Soome unsigned p, q;
199767f8919635c4928607450d9e0abb932109ceToomas Soome } while (p > q);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return q >> 1;