Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:11

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