Rev 1 | Blame | Compare with Previous | Last modification | View Log | RSS feed
/* gzlib.c -- zlib functions common to reading and writing gzip files* Copyright (C) 2004, 2010 Mark Adler* For conditions of distribution and use, see copyright notice in zlib.h*/#include "gzguts.h"#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0# define LSEEK lseek64#else# define LSEEK _lseek#endif/* Local functions */local void gz_reset OF((gz_statep));local gzFile gz_open OF((const char *, int, const char *));#if defined UNDER_CE/* Map the Windows error number in ERROR to a locale-dependent error messagestring and return a pointer to it. Typically, the values for ERROR comefrom GetLastError.The string pointed to shall not be modified by the application, but may beoverwritten by a subsequent call to gz_strwinerrorThe gz_strwinerror function does not change the current setting ofGetLastError. */char ZLIB_INTERNAL *gz_strwinerror (error)DWORD error;{static char buf[1024];wchar_t *msgbuf;DWORD lasterr = GetLastError();DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM| FORMAT_MESSAGE_ALLOCATE_BUFFER,NULL,error,0, /* Default language */(LPVOID)&msgbuf,0,NULL);if (chars != 0) {/* If there is an \r\n appended, zap it. */if (chars >= 2&& msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {chars -= 2;msgbuf[chars] = 0;}if (chars > sizeof (buf) - 1) {chars = sizeof (buf) - 1;msgbuf[chars] = 0;}wcstombs(buf, msgbuf, chars + 1);LocalFree(msgbuf);}else {sprintf(buf, "unknown win32 error (%ld)", error);}SetLastError(lasterr);return buf;}#endif /* UNDER_CE *//* Reset gzip file state */local void gz_reset(state)gz_statep state;{if (state->mode == GZ_READ) { /* for reading ... */state->have = 0; /* no output data available */state->eof = 0; /* not at end of file */state->how = LOOK; /* look for gzip header */state->direct = 1; /* default for empty file */}state->seek = 0; /* no seek request pending */gz_error(state, Z_OK, NULL); /* clear error */state->pos = 0; /* no uncompressed data yet */state->strm.avail_in = 0; /* no input data yet */}/* Open a gzip file either by name or file descriptor. */local gzFile gz_open(path, fd, mode)const char *path;int fd;const char *mode;{gz_statep state;/* allocate gzFile structure to return */state = malloc(sizeof(gz_state));if (state == NULL)return NULL;state->size = 0; /* no buffers allocated yet */state->want = GZBUFSIZE; /* requested buffer size */state->msg = NULL; /* no error message yet *//* interpret mode */state->mode = GZ_NONE;state->level = Z_DEFAULT_COMPRESSION;state->strategy = Z_DEFAULT_STRATEGY;while (*mode) {if (*mode >= '0' && *mode <= '9')state->level = *mode - '0';elseswitch (*mode) {case 'r':state->mode = GZ_READ;break;#ifndef NO_GZCOMPRESScase 'w':state->mode = GZ_WRITE;break;case 'a':state->mode = GZ_APPEND;break;#endifcase '+': /* can't read and write at the same time */free(state);return NULL;case 'b': /* ignore -- will request binary anyway */break;case 'f':state->strategy = Z_FILTERED;break;case 'h':state->strategy = Z_HUFFMAN_ONLY;break;case 'R':state->strategy = Z_RLE;break;case 'F':state->strategy = Z_FIXED;default: /* could consider as an error, but just ignore */;}mode++;}/* must provide an "r", "w", or "a" */if (state->mode == GZ_NONE) {free(state);return NULL;}/* save the path name for error messages */state->path = malloc(strlen(path) + 1);if (state->path == NULL) {free(state);return NULL;}strcpy(state->path, path);/* open the file with the appropriate mode (or just use fd) */state->fd = fd != -1 ? fd :_open(path,#ifdef O_LARGEFILEO_LARGEFILE |#endif#ifdef O_BINARYO_BINARY |#endif(state->mode == GZ_READ ?O_RDONLY :(O_WRONLY | O_CREAT | (state->mode == GZ_WRITE ?O_TRUNC :O_APPEND))),0666);if (state->fd == -1) {free(state->path);free(state);return NULL;}if (state->mode == GZ_APPEND)state->mode = GZ_WRITE; /* simplify later checks *//* save the current position for rewinding (only if reading) */if (state->mode == GZ_READ) {state->start = LSEEK(state->fd, 0, SEEK_CUR);if (state->start == -1) state->start = 0;}/* initialize stream */gz_reset(state);/* return stream */return (gzFile)state;}/* -- see zlib.h -- */gzFile ZEXPORT gzopen(path, mode)const char *path;const char *mode;{return gz_open(path, -1, mode);}/* -- see zlib.h -- */gzFile ZEXPORT gzopen64(path, mode)const char *path;const char *mode;{return gz_open(path, -1, mode);}/* -- see zlib.h -- */gzFile ZEXPORT gzdopen(fd, mode)int fd;const char *mode;{char *path; /* identifier for error messages */gzFile gz;if (fd == -1 || (path = malloc(7 + 3 * sizeof(int))) == NULL)return NULL;sprintf(path, "<fd:%d>", fd); /* for debugging */gz = gz_open(path, fd, mode);free(path);return gz;}/* -- see zlib.h -- */int ZEXPORT gzbuffer(file, size)gzFile file;unsigned size;{gz_statep state;/* get internal structure and check integrity */if (file == NULL)return -1;state = (gz_statep)file;if (state->mode != GZ_READ && state->mode != GZ_WRITE)return -1;/* make sure we haven't already allocated memory */if (state->size != 0)return -1;/* check and set requested size */if (size == 0)return -1;state->want = size;return 0;}/* -- see zlib.h -- */int ZEXPORT gzrewind(file)gzFile file;{gz_statep state;/* get internal structure */if (file == NULL)return -1;state = (gz_statep)file;/* check that we're reading and that there's no error */if (state->mode != GZ_READ || state->err != Z_OK)return -1;/* back up and start over */if (LSEEK(state->fd, state->start, SEEK_SET) == -1)return -1;gz_reset(state);return 0;}/* -- see zlib.h -- */z_off64_t ZEXPORT gzseek64(file, offset, whence)gzFile file;z_off64_t offset;int whence;{unsigned n;z_off64_t ret;gz_statep state;/* get internal structure and check integrity */if (file == NULL)return -1;state = (gz_statep)file;if (state->mode != GZ_READ && state->mode != GZ_WRITE)return -1;/* check that there's no error */if (state->err != Z_OK)return -1;/* can only seek from start or relative to current position */if (whence != SEEK_SET && whence != SEEK_CUR)return -1;/* normalize offset to a SEEK_CUR specification */if (whence == SEEK_SET)offset -= state->pos;else if (state->seek)offset += state->skip;state->seek = 0;/* if within raw area while reading, just go there */if (state->mode == GZ_READ && state->how == COPY &&state->pos + offset >= state->raw) {ret = LSEEK(state->fd, offset - state->have, SEEK_CUR);if (ret == -1)return -1;state->have = 0;state->eof = 0;state->seek = 0;gz_error(state, Z_OK, NULL);state->strm.avail_in = 0;state->pos += offset;return state->pos;}/* calculate skip amount, rewinding if needed for back seek when reading */if (offset < 0) {if (state->mode != GZ_READ) /* writing -- can't go backwards */return -1;offset += state->pos;if (offset < 0) /* before start of file! */return -1;if (gzrewind(file) == -1) /* rewind, then skip to offset */return -1;}/* if reading, skip what's in output buffer (one less gzgetc() check) */if (state->mode == GZ_READ) {n = GT_OFF(state->have) || (z_off64_t)state->have > offset ?(unsigned)offset : state->have;state->have -= n;state->next += n;state->pos += n;offset -= n;}/* request skip (if not zero) */if (offset) {state->seek = 1;state->skip = offset;}return state->pos + offset;}/* -- see zlib.h -- */z_off_t ZEXPORT gzseek(file, offset, whence)gzFile file;z_off_t offset;int whence;{z_off64_t ret;ret = gzseek64(file, (z_off64_t)offset, whence);return ret == (z_off_t)ret ? (z_off_t)ret : -1;}/* -- see zlib.h -- */z_off64_t ZEXPORT gztell64(file)gzFile file;{gz_statep state;/* get internal structure and check integrity */if (file == NULL)return -1;state = (gz_statep)file;if (state->mode != GZ_READ && state->mode != GZ_WRITE)return -1;/* return position */return state->pos + (state->seek ? state->skip : 0);}/* -- see zlib.h -- */z_off_t ZEXPORT gztell(file)gzFile file;{z_off64_t ret;ret = gztell64(file);return ret == (z_off_t)ret ? (z_off_t)ret : -1;}/* -- see zlib.h -- */z_off64_t ZEXPORT gzoffset64(file)gzFile file;{z_off64_t offset;gz_statep state;/* get internal structure and check integrity */if (file == NULL)return -1;state = (gz_statep)file;if (state->mode != GZ_READ && state->mode != GZ_WRITE)return -1;/* compute and return effective offset in file */offset = LSEEK(state->fd, 0, SEEK_CUR);if (offset == -1)return -1;if (state->mode == GZ_READ) /* reading */offset -= state->strm.avail_in; /* don't count buffered input */return offset;}/* -- see zlib.h -- */z_off_t ZEXPORT gzoffset(file)gzFile file;{z_off64_t ret;ret = gzoffset64(file);return ret == (z_off_t)ret ? (z_off_t)ret : -1;}/* -- see zlib.h -- */int ZEXPORT gzeof(file)gzFile file;{gz_statep state;/* get internal structure and check integrity */if (file == NULL)return 0;state = (gz_statep)file;if (state->mode != GZ_READ && state->mode != GZ_WRITE)return 0;/* return end-of-file state */return state->mode == GZ_READ ?(state->eof && state->strm.avail_in == 0 && state->have == 0) : 0;}/* -- see zlib.h -- */const char * ZEXPORT gzerror(file, errnum)gzFile file;int *errnum;{gz_statep state;/* get internal structure and check integrity */if (file == NULL)return NULL;state = (gz_statep)file;if (state->mode != GZ_READ && state->mode != GZ_WRITE)return NULL;/* return error information */if (errnum != NULL)*errnum = state->err;return state->msg == NULL ? "" : state->msg;}/* -- see zlib.h -- */void ZEXPORT gzclearerr(file)gzFile file;{gz_statep state;/* get internal structure and check integrity */if (file == NULL)return;state = (gz_statep)file;if (state->mode != GZ_READ && state->mode != GZ_WRITE)return;/* clear error and end-of-file */if (state->mode == GZ_READ)state->eof = 0;gz_error(state, Z_OK, NULL);}/* Create an error message in allocated memory and set state->err andstate->msg accordingly. Free any previous error message already there. Donot try to free or allocate space if the error is Z_MEM_ERROR (out ofmemory). Simply save the error message as a static string. If there is anallocation failure constructing the error message, then convert the error toout of memory. */void ZLIB_INTERNAL gz_error(state, err, msg)gz_statep state;int err;const char *msg;{/* free previously allocated message and clear */if (state->msg != NULL) {if (state->err != Z_MEM_ERROR)free(state->msg);state->msg = NULL;}/* set error code, and if no message, then done */state->err = err;if (msg == NULL)return;/* for an out of memory error, save as static string */if (err == Z_MEM_ERROR) {state->msg = (char *)msg;return;}/* construct error message with path */if ((state->msg = malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) {state->err = Z_MEM_ERROR;state->msg = (char *)"out of memory";return;}strcpy(state->msg, state->path);strcat(state->msg, ": ");strcat(state->msg, msg);return;}#ifndef INT_MAX/* portably return maximum value for an int (when limits.h presumed notavailable) -- we need to do this to cover cases where 2's complement notused, since C standard permits 1's complement and sign-bit representations,otherwise we could just use ((unsigned)-1) >> 1 */unsigned ZLIB_INTERNAL gz_intmax(){unsigned p, q;p = 1;do {q = p;p <<= 1;p++;} while (p > q);return q >> 1;}#endif