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