File indexing completed on 2024-04-21 03:48:30

0001 /* gzlib.c -- zlib functions common to reading and writing gzip files
0002  * Copyright (C) 2004, 2010, 2011, 2012, 2013 Mark Adler
0003  * For conditions of distribution and use, see copyright notice in zlib.h
0004  */
0005 
0006 #include "gzguts.h"
0007 
0008 #if defined(_WIN32) && !defined(__BORLANDC__)
0009 #  define LSEEK _lseeki64
0010 #else
0011 #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
0012 #  define LSEEK lseek64
0013 #else
0014 #  define LSEEK lseek
0015 #endif
0016 #endif
0017 
0018 /* Local functions */
0019 local void gz_reset OF((gz_statep));
0020 local gzFile gz_open OF((const void *, int, const char *));
0021 
0022 #if defined UNDER_CE
0023 
0024 /* Map the Windows error number in ERROR to a locale-dependent error message
0025    string and return a pointer to it.  Typically, the values for ERROR come
0026    from GetLastError.
0027 
0028    The string pointed to shall not be modified by the application, but may be
0029    overwritten by a subsequent call to gz_strwinerror
0030 
0031    The gz_strwinerror function does not change the current setting of
0032    GetLastError. */
0033 char ZLIB_INTERNAL *gz_strwinerror (error)
0034      DWORD error;
0035 {
0036     static char buf[1024];
0037 
0038     wchar_t *msgbuf;
0039     DWORD lasterr = GetLastError();
0040     DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
0041         | FORMAT_MESSAGE_ALLOCATE_BUFFER,
0042         NULL,
0043         error,
0044         0, /* Default language */
0045         (LPVOID)&msgbuf,
0046         0,
0047         NULL);
0048     if (chars != 0) {
0049         /* If there is an \r\n appended, zap it.  */
0050         if (chars >= 2
0051             && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
0052             chars -= 2;
0053             msgbuf[chars] = 0;
0054         }
0055 
0056         if (chars > sizeof (buf) - 1) {
0057             chars = sizeof (buf) - 1;
0058             msgbuf[chars] = 0;
0059         }
0060 
0061         wcstombs(buf, msgbuf, chars + 1);
0062         LocalFree(msgbuf);
0063     }
0064     else {
0065         sprintf(buf, "unknown win32 error (%ld)", error);
0066     }
0067 
0068     SetLastError(lasterr);
0069     return buf;
0070 }
0071 
0072 #endif /* UNDER_CE */
0073 
0074 /* Reset gzip file state */
0075 local void gz_reset(state)
0076     gz_statep state;
0077 {
0078     state->x.have = 0;              /* no output data available */
0079     if (state->mode == GZ_READ) {   /* for reading ... */
0080         state->eof = 0;             /* not at end of file */
0081         state->past = 0;            /* have not read past end yet */
0082         state->how = LOOK;          /* look for gzip header */
0083     }
0084     state->seek = 0;                /* no seek request pending */
0085     gz_error(state, Z_OK, NULL);    /* clear error */
0086     state->x.pos = 0;               /* no uncompressed data yet */
0087     state->strm.avail_in = 0;       /* no input data yet */
0088 }
0089 
0090 /* Open a gzip file either by name or file descriptor. */
0091 local gzFile gz_open(path, fd, mode)
0092     const void *path;
0093     int fd;
0094     const char *mode;
0095 {
0096     gz_statep state;
0097     size_t len;
0098     int oflag;
0099 #ifdef O_CLOEXEC
0100     int cloexec = 0;
0101 #endif
0102 #ifdef O_EXCL
0103     int exclusive = 0;
0104 #endif
0105 
0106     /* check input */
0107     if (path == NULL)
0108         return NULL;
0109 
0110     /* allocate gzFile structure to return */
0111     state = (gz_statep)malloc(sizeof(gz_state));
0112     if (state == NULL)
0113         return NULL;
0114     state->size = 0;            /* no buffers allocated yet */
0115     state->want = GZBUFSIZE;    /* requested buffer size */
0116     state->msg = NULL;          /* no error message yet */
0117 
0118     /* interpret mode */
0119     state->mode = GZ_NONE;
0120     state->level = Z_DEFAULT_COMPRESSION;
0121     state->strategy = Z_DEFAULT_STRATEGY;
0122     state->direct = 0;
0123     while (*mode) {
0124         if (*mode >= '0' && *mode <= '9')
0125             state->level = *mode - '0';
0126         else
0127             switch (*mode) {
0128             case 'r':
0129                 state->mode = GZ_READ;
0130                 break;
0131 #ifndef NO_GZCOMPRESS
0132             case 'w':
0133                 state->mode = GZ_WRITE;
0134                 break;
0135             case 'a':
0136                 state->mode = GZ_APPEND;
0137                 break;
0138 #endif
0139             case '+':       /* can't read and write at the same time */
0140                 free(state);
0141                 return NULL;
0142             case 'b':       /* ignore -- will request binary anyway */
0143                 break;
0144 #ifdef O_CLOEXEC
0145             case 'e':
0146                 cloexec = 1;
0147                 break;
0148 #endif
0149 #ifdef O_EXCL
0150             case 'x':
0151                 exclusive = 1;
0152                 break;
0153 #endif
0154             case 'f':
0155                 state->strategy = Z_FILTERED;
0156                 break;
0157             case 'h':
0158                 state->strategy = Z_HUFFMAN_ONLY;
0159                 break;
0160             case 'R':
0161                 state->strategy = Z_RLE;
0162                 break;
0163             case 'F':
0164                 state->strategy = Z_FIXED;
0165                 break;
0166             case 'T':
0167                 state->direct = 1;
0168                 break;
0169             default:        /* could consider as an error, but just ignore */
0170                 ;
0171             }
0172         mode++;
0173     }
0174 
0175     /* must provide an "r", "w", or "a" */
0176     if (state->mode == GZ_NONE) {
0177         free(state);
0178         return NULL;
0179     }
0180 
0181     /* can't force transparent read */
0182     if (state->mode == GZ_READ) {
0183         if (state->direct) {
0184             free(state);
0185             return NULL;
0186         }
0187         state->direct = 1;      /* for empty file */
0188     }
0189 
0190     /* save the path name for error messages */
0191 #ifdef _WIN32
0192     if (fd == -2) {
0193         len = wcstombs(NULL, path, 0);
0194         if (len == (size_t)-1)
0195             len = 0;
0196     }
0197     else
0198 #endif
0199         len = strlen((const char *)path);
0200     state->path = (char *)malloc(len + 1);
0201     if (state->path == NULL) {
0202         free(state);
0203         return NULL;
0204     }
0205 #ifdef _WIN32
0206     if (fd == -2)
0207         if (len)
0208             wcstombs(state->path, path, len + 1);
0209         else
0210             *(state->path) = 0;
0211     else
0212 #endif
0213 #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
0214         snprintf(state->path, len + 1, "%s", (const char *)path);
0215 #else
0216         strcpy(state->path, path);
0217 #endif
0218 
0219     /* compute the flags for open() */
0220     oflag =
0221 #ifdef O_LARGEFILE
0222         O_LARGEFILE |
0223 #endif
0224 #ifdef O_BINARY
0225         O_BINARY |
0226 #endif
0227 #ifdef O_CLOEXEC
0228         (cloexec ? O_CLOEXEC : 0) |
0229 #endif
0230         (state->mode == GZ_READ ?
0231          O_RDONLY :
0232          (O_WRONLY | O_CREAT |
0233 #ifdef O_EXCL
0234           (exclusive ? O_EXCL : 0) |
0235 #endif
0236           (state->mode == GZ_WRITE ?
0237            O_TRUNC :
0238            O_APPEND)));
0239 
0240     /* open the file with the appropriate flags (or just use fd) */
0241     state->fd = fd > -1 ? fd : (
0242 #ifdef _WIN32
0243         fd == -2 ? _wopen(path, oflag, 0666) :
0244 #endif
0245         open((const char *)path, oflag, 0666));
0246     if (state->fd == -1) {
0247         free(state->path);
0248         free(state);
0249         return NULL;
0250     }
0251     if (state->mode == GZ_APPEND)
0252         state->mode = GZ_WRITE;         /* simplify later checks */
0253 
0254     /* save the current position for rewinding (only if reading) */
0255     if (state->mode == GZ_READ) {
0256         state->start = LSEEK(state->fd, 0, SEEK_CUR);
0257         if (state->start == -1) state->start = 0;
0258     }
0259 
0260     /* initialize stream */
0261     gz_reset(state);
0262 
0263     /* return stream */
0264     return (gzFile)state;
0265 }
0266 
0267 /* -- see zlib.h -- */
0268 gzFile ZEXPORT gzopen(path, mode)
0269     const char *path;
0270     const char *mode;
0271 {
0272     return gz_open(path, -1, mode);
0273 }
0274 
0275 /* -- see zlib.h -- */
0276 gzFile ZEXPORT gzopen64(path, mode)
0277     const char *path;
0278     const char *mode;
0279 {
0280     return gz_open(path, -1, mode);
0281 }
0282 
0283 /* -- see zlib.h -- */
0284 gzFile ZEXPORT gzdopen(fd, mode)
0285     int fd;
0286     const char *mode;
0287 {
0288     char *path;         /* identifier for error messages */
0289     gzFile gz;
0290 
0291     if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
0292         return NULL;
0293 #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
0294     snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd); /* for debugging */
0295 #else
0296     sprintf(path, "<fd:%d>", fd);   /* for debugging */
0297 #endif
0298     gz = gz_open(path, fd, mode);
0299     free(path);
0300     return gz;
0301 }
0302 
0303 /* -- see zlib.h -- */
0304 #ifdef _WIN32
0305 gzFile ZEXPORT gzopen_w(path, mode)
0306     const wchar_t *path;
0307     const char *mode;
0308 {
0309     return gz_open(path, -2, mode);
0310 }
0311 #endif
0312 
0313 /* -- see zlib.h -- */
0314 int ZEXPORT gzbuffer(file, size)
0315     gzFile file;
0316     unsigned size;
0317 {
0318     gz_statep state;
0319 
0320     /* get internal structure and check integrity */
0321     if (file == NULL)
0322         return -1;
0323     state = (gz_statep)file;
0324     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
0325         return -1;
0326 
0327     /* make sure we haven't already allocated memory */
0328     if (state->size != 0)
0329         return -1;
0330 
0331     /* check and set requested size */
0332     if (size < 2)
0333         size = 2;               /* need two bytes to check magic header */
0334     state->want = size;
0335     return 0;
0336 }
0337 
0338 /* -- see zlib.h -- */
0339 int ZEXPORT gzrewind(file)
0340     gzFile file;
0341 {
0342     gz_statep state;
0343 
0344     /* get internal structure */
0345     if (file == NULL)
0346         return -1;
0347     state = (gz_statep)file;
0348 
0349     /* check that we're reading and that there's no error */
0350     if (state->mode != GZ_READ ||
0351             (state->err != Z_OK && state->err != Z_BUF_ERROR))
0352         return -1;
0353 
0354     /* back up and start over */
0355     if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
0356         return -1;
0357     gz_reset(state);
0358     return 0;
0359 }
0360 
0361 /* -- see zlib.h -- */
0362 z_off64_t ZEXPORT gzseek64(file, offset, whence)
0363     gzFile file;
0364     z_off64_t offset;
0365     int whence;
0366 {
0367     unsigned n;
0368     z_off64_t ret;
0369     gz_statep state;
0370 
0371     /* get internal structure and check integrity */
0372     if (file == NULL)
0373         return -1;
0374     state = (gz_statep)file;
0375     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
0376         return -1;
0377 
0378     /* check that there's no error */
0379     if (state->err != Z_OK && state->err != Z_BUF_ERROR)
0380         return -1;
0381 
0382     /* can only seek from start or relative to current position */
0383     if (whence != SEEK_SET && whence != SEEK_CUR)
0384         return -1;
0385 
0386     /* normalize offset to a SEEK_CUR specification */
0387     if (whence == SEEK_SET)
0388         offset -= state->x.pos;
0389     else if (state->seek)
0390         offset += state->skip;
0391     state->seek = 0;
0392 
0393     /* if within raw area while reading, just go there */
0394     if (state->mode == GZ_READ && state->how == COPY &&
0395             state->x.pos + offset >= 0) {
0396         ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR);
0397         if (ret == -1)
0398             return -1;
0399         state->x.have = 0;
0400         state->eof = 0;
0401         state->past = 0;
0402         state->seek = 0;
0403         gz_error(state, Z_OK, NULL);
0404         state->strm.avail_in = 0;
0405         state->x.pos += offset;
0406         return state->x.pos;
0407     }
0408 
0409     /* calculate skip amount, rewinding if needed for back seek when reading */
0410     if (offset < 0) {
0411         if (state->mode != GZ_READ)         /* writing -- can't go backwards */
0412             return -1;
0413         offset += state->x.pos;
0414         if (offset < 0)                     /* before start of file! */
0415             return -1;
0416         if (gzrewind(file) == -1)           /* rewind, then skip to offset */
0417             return -1;
0418     }
0419 
0420     /* if reading, skip what's in output buffer (one less gzgetc() check) */
0421     if (state->mode == GZ_READ) {
0422         n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
0423             (unsigned)offset : state->x.have;
0424         state->x.have -= n;
0425         state->x.next += n;
0426         state->x.pos += n;
0427         offset -= n;
0428     }
0429 
0430     /* request skip (if not zero) */
0431     if (offset) {
0432         state->seek = 1;
0433         state->skip = offset;
0434     }
0435     return state->x.pos + offset;
0436 }
0437 
0438 /* -- see zlib.h -- */
0439 z_off_t ZEXPORT gzseek(file, offset, whence)
0440     gzFile file;
0441     z_off_t offset;
0442     int whence;
0443 {
0444     z_off64_t ret;
0445 
0446     ret = gzseek64(file, (z_off64_t)offset, whence);
0447     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
0448 }
0449 
0450 /* -- see zlib.h -- */
0451 z_off64_t ZEXPORT gztell64(file)
0452     gzFile file;
0453 {
0454     gz_statep state;
0455 
0456     /* get internal structure and check integrity */
0457     if (file == NULL)
0458         return -1;
0459     state = (gz_statep)file;
0460     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
0461         return -1;
0462 
0463     /* return position */
0464     return state->x.pos + (state->seek ? state->skip : 0);
0465 }
0466 
0467 /* -- see zlib.h -- */
0468 z_off_t ZEXPORT gztell(file)
0469     gzFile file;
0470 {
0471     z_off64_t ret;
0472 
0473     ret = gztell64(file);
0474     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
0475 }
0476 
0477 /* -- see zlib.h -- */
0478 z_off64_t ZEXPORT gzoffset64(file)
0479     gzFile file;
0480 {
0481     z_off64_t offset;
0482     gz_statep state;
0483 
0484     /* get internal structure and check integrity */
0485     if (file == NULL)
0486         return -1;
0487     state = (gz_statep)file;
0488     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
0489         return -1;
0490 
0491     /* compute and return effective offset in file */
0492     offset = LSEEK(state->fd, 0, SEEK_CUR);
0493     if (offset == -1)
0494         return -1;
0495     if (state->mode == GZ_READ)             /* reading */
0496         offset -= state->strm.avail_in;     /* don't count buffered input */
0497     return offset;
0498 }
0499 
0500 /* -- see zlib.h -- */
0501 z_off_t ZEXPORT gzoffset(file)
0502     gzFile file;
0503 {
0504     z_off64_t ret;
0505 
0506     ret = gzoffset64(file);
0507     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
0508 }
0509 
0510 /* -- see zlib.h -- */
0511 int ZEXPORT gzeof(file)
0512     gzFile file;
0513 {
0514     gz_statep state;
0515 
0516     /* get internal structure and check integrity */
0517     if (file == NULL)
0518         return 0;
0519     state = (gz_statep)file;
0520     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
0521         return 0;
0522 
0523     /* return end-of-file state */
0524     return state->mode == GZ_READ ? state->past : 0;
0525 }
0526 
0527 /* -- see zlib.h -- */
0528 const char * ZEXPORT gzerror(file, errnum)
0529     gzFile file;
0530     int *errnum;
0531 {
0532     gz_statep state;
0533 
0534     /* get internal structure and check integrity */
0535     if (file == NULL)
0536         return NULL;
0537     state = (gz_statep)file;
0538     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
0539         return NULL;
0540 
0541     /* return error information */
0542     if (errnum != NULL)
0543         *errnum = state->err;
0544     return state->err == Z_MEM_ERROR ? "out of memory" :
0545                                        (state->msg == NULL ? "" : state->msg);
0546 }
0547 
0548 /* -- see zlib.h -- */
0549 void ZEXPORT gzclearerr(file)
0550     gzFile file;
0551 {
0552     gz_statep state;
0553 
0554     /* get internal structure and check integrity */
0555     if (file == NULL)
0556         return;
0557     state = (gz_statep)file;
0558     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
0559         return;
0560 
0561     /* clear error and end-of-file */
0562     if (state->mode == GZ_READ) {
0563         state->eof = 0;
0564         state->past = 0;
0565     }
0566     gz_error(state, Z_OK, NULL);
0567 }
0568 
0569 /* Create an error message in allocated memory and set state->err and
0570    state->msg accordingly.  Free any previous error message already there.  Do
0571    not try to free or allocate space if the error is Z_MEM_ERROR (out of
0572    memory).  Simply save the error message as a static string.  If there is an
0573    allocation failure constructing the error message, then convert the error to
0574    out of memory. */
0575 void ZLIB_INTERNAL gz_error(state, err, msg)
0576     gz_statep state;
0577     int err;
0578     const char *msg;
0579 {
0580     /* free previously allocated message and clear */
0581     if (state->msg != NULL) {
0582         if (state->err != Z_MEM_ERROR)
0583             free(state->msg);
0584         state->msg = NULL;
0585     }
0586 
0587     /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
0588     if (err != Z_OK && err != Z_BUF_ERROR)
0589         state->x.have = 0;
0590 
0591     /* set error code, and if no message, then done */
0592     state->err = err;
0593     if (msg == NULL)
0594         return;
0595 
0596     /* for an out of memory error, return literal string when requested */
0597     if (err == Z_MEM_ERROR)
0598         return;
0599 
0600     /* construct error message with path */
0601     if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
0602             NULL) {
0603         state->err = Z_MEM_ERROR;
0604         return;
0605     }
0606 #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
0607     snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
0608              "%s%s%s", state->path, ": ", msg);
0609 #else
0610     strcpy(state->msg, state->path);
0611     strcat(state->msg, ": ");
0612     strcat(state->msg, msg);
0613 #endif
0614     return;
0615 }
0616 
0617 #ifndef INT_MAX
0618 /* portably return maximum value for an int (when limits.h presumed not
0619    available) -- we need to do this to cover cases where 2's complement not
0620    used, since C standard permits 1's complement and sign-bit representations,
0621    otherwise we could just use ((unsigned)-1) >> 1 */
0622 unsigned ZLIB_INTERNAL gz_intmax()
0623 {
0624     unsigned p, q;
0625 
0626     p = 1;
0627     do {
0628         q = p;
0629         p <<= 1;
0630         p++;
0631     } while (p > q);
0632     return q >> 1;
0633 }
0634 #endif