1 /* gzlib.c -- zlib functions common to reading and writing gzip files 2 * Copyright (C) 2004-2024 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(__DJGPP__) 9 # define LSEEK llseek 10 #elif defined(_WIN32) && !defined(__BORLANDC__) && !defined(UNDER_CE) 11 # define LSEEK _lseeki64 12 #elif defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 13 # define LSEEK lseek64 14 #else 15 # define LSEEK lseek 16 #endif 17 18 #if defined UNDER_CE 19 20 /* Map the Windows error number in ERROR to a locale-dependent error message 21 string and return a pointer to it. Typically, the values for ERROR come 22 from GetLastError. 23 24 The string pointed to shall not be modified by the application, but may be 25 overwritten by a subsequent call to gz_strwinerror 26 27 The gz_strwinerror function does not change the current setting of 28 GetLastError. */ 29 char ZLIB_INTERNAL *gz_strwinerror(DWORD error) { 30 static char buf[1024]; 31 32 wchar_t *msgbuf; 33 DWORD lasterr = GetLastError(); 34 DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM 35 | FORMAT_MESSAGE_ALLOCATE_BUFFER, 36 NULL, 37 error, 38 0, /* Default language */ 39 (LPVOID)&msgbuf, 40 0, 41 NULL); 42 if (chars != 0) { 43 /* If there is an \r\n appended, zap it. */ 44 if (chars >= 2 45 && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { 46 chars -= 2; 47 msgbuf[chars] = 0; 48 } 49 50 if (chars > sizeof (buf) - 1) { 51 chars = sizeof (buf) - 1; 52 msgbuf[chars] = 0; 53 } 54 55 wcstombs(buf, msgbuf, chars + 1); // assumes buf is big enough 56 LocalFree(msgbuf); 57 } 58 else { 59 sprintf(buf, "unknown win32 error (%ld)", error); 60 } 61 62 SetLastError(lasterr); 63 return buf; 64 } 65 66 #endif /* UNDER_CE */ 67 68 /* Reset gzip file state */ 69 local void gz_reset(gz_statep state) { 70 state->x.have = 0; /* no output data available */ 71 if (state->mode == GZ_READ) { /* for reading ... */ 72 state->eof = 0; /* not at end of file */ 73 state->past = 0; /* have not read past end yet */ 74 state->how = LOOK; /* look for gzip header */ 75 } 76 else /* for writing ... */ 77 state->reset = 0; /* no deflateReset pending */ 78 state->seek = 0; /* no seek request pending */ 79 gz_error(state, Z_OK, NULL); /* clear error */ 80 state->x.pos = 0; /* no uncompressed data yet */ 81 state->strm.avail_in = 0; /* no input data yet */ 82 } 83 84 /* Open a gzip file either by name or file descriptor. */ 85 local gzFile gz_open(const void *path, int fd, const char *mode) { 86 gz_statep state; 87 z_size_t len; 88 int oflag; 89 #ifdef O_CLOEXEC 90 int cloexec = 0; 91 #endif 92 #ifdef O_EXCL 93 int exclusive = 0; 94 #endif 95 96 /* check input */ 97 if (path == NULL) 98 return NULL; 99 100 /* allocate gzFile structure to return */ 101 state = (gz_statep)malloc(sizeof(gz_state)); 102 if (state == NULL) 103 return NULL; 104 state->size = 0; /* no buffers allocated yet */ 105 state->want = GZBUFSIZE; /* requested buffer size */ 106 state->msg = NULL; /* no error message yet */ 107 108 /* interpret mode */ 109 state->mode = GZ_NONE; 110 state->level = Z_DEFAULT_COMPRESSION; 111 state->strategy = Z_DEFAULT_STRATEGY; 112 state->direct = 0; 113 while (*mode) { 114 if (*mode >= '0' && *mode <= '9') 115 state->level = *mode - '0'; 116 else 117 switch (*mode) { 118 case 'r': 119 state->mode = GZ_READ; 120 break; 121 #ifndef NO_GZCOMPRESS 122 case 'w': 123 state->mode = GZ_WRITE; 124 break; 125 case 'a': 126 state->mode = GZ_APPEND; 127 break; 128 #endif 129 case '+': /* can't read and write at the same time */ 130 free(state); 131 return NULL; 132 case 'b': /* ignore -- will request binary anyway */ 133 break; 134 #ifdef O_CLOEXEC 135 case 'e': 136 cloexec = 1; 137 break; 138 #endif 139 #ifdef O_EXCL 140 case 'x': 141 exclusive = 1; 142 break; 143 #endif 144 case 'f': 145 state->strategy = Z_FILTERED; 146 break; 147 case 'h': 148 state->strategy = Z_HUFFMAN_ONLY; 149 break; 150 case 'R': 151 state->strategy = Z_RLE; 152 break; 153 case 'F': 154 state->strategy = Z_FIXED; 155 break; 156 case 'T': 157 state->direct = 1; 158 break; 159 default: /* could consider as an error, but just ignore */ 160 ; 161 } 162 mode++; 163 } 164 165 /* must provide an "r", "w", or "a" */ 166 if (state->mode == GZ_NONE) { 167 free(state); 168 return NULL; 169 } 170 171 /* can't force transparent read */ 172 if (state->mode == GZ_READ) { 173 if (state->direct) { 174 free(state); 175 return NULL; 176 } 177 state->direct = 1; /* for empty file */ 178 } 179 180 /* save the path name for error messages */ 181 #ifdef WIDECHAR 182 if (fd == -2) 183 len = wcstombs(NULL, path, 0); 184 else 185 #endif 186 len = strlen((const char *)path); 187 state->path = (char *)malloc(len + 1); 188 if (state->path == NULL) { 189 free(state); 190 return NULL; 191 } 192 #ifdef WIDECHAR 193 if (fd == -2) { 194 if (len) 195 wcstombs(state->path, path, len + 1); 196 else 197 *(state->path) = 0; 198 } 199 else 200 #endif 201 { 202 #if !defined(NO_snprintf) && !defined(NO_vsnprintf) 203 (void)snprintf(state->path, len + 1, "%s", (const char *)path); 204 #else 205 strcpy(state->path, path); 206 #endif 207 } 208 209 /* compute the flags for open() */ 210 oflag = 211 #ifdef O_LARGEFILE 212 O_LARGEFILE | 213 #endif 214 #ifdef O_BINARY 215 O_BINARY | 216 #endif 217 #ifdef O_CLOEXEC 218 (cloexec ? O_CLOEXEC : 0) | 219 #endif 220 (state->mode == GZ_READ ? 221 O_RDONLY : 222 (O_WRONLY | O_CREAT | 223 #ifdef O_EXCL 224 (exclusive ? O_EXCL : 0) | 225 #endif 226 (state->mode == GZ_WRITE ? 227 O_TRUNC : 228 O_APPEND))); 229 230 /* open the file with the appropriate flags (or just use fd) */ 231 if (fd == -1) 232 state->fd = open((const char *)path, oflag, 0666); 233 #ifdef WIDECHAR 234 else if (fd == -2) 235 state->fd = _wopen(path, oflag, _S_IREAD | _S_IWRITE); 236 #endif 237 else 238 state->fd = fd; 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 -- */ 263 gzFile ZEXPORT gzopen(const char *path, const char *mode) { 264 return gz_open(path, -1, mode); 265 } 266 267 /* -- see zlib.h -- */ 268 gzFile ZEXPORT gzopen64(const char *path, const char *mode) { 269 return gz_open(path, -1, mode); 270 } 271 272 /* -- see zlib.h -- */ 273 gzFile 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 291 gzFile 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 -- */ 297 int 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 -- */ 321 int 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 -- */ 342 z_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 -- */ 415 z_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 -- */ 423 z_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 -- */ 438 z_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 -- */ 446 z_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 -- */ 467 z_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 -- */ 475 int 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 -- */ 490 const 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 -- */ 508 void 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. */ 532 void 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 /* portably return maximum value for an int (when limits.h presumed not 570 available) -- we need to do this to cover cases where 2's complement not 571 used, since C standard permits 1's complement and sign-bit representations, 572 otherwise we could just use ((unsigned)-1) >> 1 */ 573 unsigned ZLIB_INTERNAL gz_intmax(void) { 574 #ifdef INT_MAX 575 return INT_MAX; 576 #else 577 unsigned p = 1, q; 578 do { 579 q = p; 580 p <<= 1; 581 p++; 582 } while (p > q); 583 return q >> 1; 584 #endif 585 } 586