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