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