OLD | NEW |
(Empty) | |
| 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 */ |
| 17 local void gz_reset OF((gz_statep)); |
| 18 local 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. */ |
| 31 char 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 */ |
| 73 local 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. */ |
| 89 local 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 -- */ |
| 198 gzFile 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 -- */ |
| 206 gzFile 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 -- */ |
| 214 gzFile 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 -- */ |
| 230 int 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 -- */ |
| 255 int 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 -- */ |
| 277 z_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 -- */ |
| 353 z_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 -- */ |
| 365 z_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 -- */ |
| 382 z_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 -- */ |
| 392 z_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 -- */ |
| 415 z_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 -- */ |
| 425 int 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 -- */ |
| 443 const 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 -- */ |
| 463 void 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. */ |
| 487 void 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 */ |
| 527 unsigned 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 |
OLD | NEW |