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