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