1/* gzio.c -- IO on .gz files 2 * Copyright (C) 1995-2005 Jean-loup Gailly. 3 * For conditions of distribution and use, see copyright notice in zlib.h 4 * 5 * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. 6 */ 7 8/* @(#) $Id$ */ 9 10#include <stdio.h> 11 12#include "zutil.h" 13#include <errno.h> 14 15#ifdef NO_DEFLATE /* for compatibility with old definition */ 16# define NO_GZCOMPRESS 17#endif 18 19#ifndef NO_DUMMY_DECL 20struct internal_state {int dummy;}; /* for buggy compilers */ 21#endif 22 23#ifndef Z_BUFSIZE 24# ifdef MAXSEG_64K 25# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ 26# else 27# define Z_BUFSIZE 16384 28# endif 29#endif 30#ifndef Z_PRINTF_BUFSIZE 31# define Z_PRINTF_BUFSIZE 4096 32#endif 33 34#ifdef __MVS__ 35# pragma map (fdopen , "\174\174FDOPEN") 36 FILE *fdopen(int, const char *); 37#endif 38 39#ifndef STDC 40extern voidp malloc OF((uInt size)); 41extern void free OF((voidpf ptr)); 42#endif 43 44#define ALLOC(size) malloc(size) 45#define TRYFREE(p) {if (p) free(p);} 46 47static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ 48 49/* gzip flag byte */ 50#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ 51#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ 52#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ 53#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ 54#define COMMENT 0x10 /* bit 4 set: file comment present */ 55#define RESERVED 0xE0 /* bits 5..7: reserved */ 56 57typedef struct gz_stream { 58 z_stream stream; 59 int z_err; /* error code for last stream operation */ 60 int z_eof; /* set if end of input file */ 61 FILE *file; /* .gz file */ 62 Byte *inbuf; /* input buffer */ 63 Byte *outbuf; /* output buffer */ 64 uLong crc; /* crc32 of uncompressed data */ 65 char *msg; /* error message */ 66 char *path; /* path name for debugging only */ 67 int transparent; /* 1 if input file is not a .gz file */ 68 char mode; /* 'w' or 'r' */ 69 z_off_t start; /* start of compressed data in file (header skipped) */ 70 z_off_t in; /* bytes into deflate or inflate */ 71 z_off_t out; /* bytes out of deflate or inflate */ 72 int back; /* one character push-back */ 73 int last; /* true if push-back is last character */ 74} gz_stream; 75 76 77local gzFile gz_open OF((const char *path, const char *mode, int fd)); 78local int do_flush OF((gzFile file, int flush)); 79local int get_byte OF((gz_stream *s)); 80local void check_header OF((gz_stream *s)); 81local int destroy OF((gz_stream *s)); 82local void putLong OF((FILE *file, uLong x)); 83local uLong getLong OF((gz_stream *s)); 84 85/* =========================================================================== 86 Opens a gzip (.gz) file for reading or writing. The mode parameter 87 is as in fopen ("rb" or "wb"). The file is given either by file descriptor 88 or path name (if fd == -1). 89 gz_open returns NULL if the file could not be opened or if there was 90 insufficient memory to allocate the (de)compression state; errno 91 can be checked to distinguish the two cases (if errno is zero, the 92 zlib error is Z_MEM_ERROR). 93*/ 94local gzFile gz_open (path, mode, fd) 95 const char *path; 96 const char *mode; 97 int fd; 98{ 99 int err; 100 int level = Z_DEFAULT_COMPRESSION; /* compression level */ 101 int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ 102 char *p = (char*)mode; 103 gz_stream *s; 104 char fmode[80]; /* copy of mode, without the compression level */ 105 char *m = fmode; 106 107 if (!path || !mode) return Z_NULL; 108 109 s = (gz_stream *)ALLOC(sizeof(gz_stream)); 110 if (!s) return Z_NULL; 111 112 s->stream.zalloc = (alloc_func)0; 113 s->stream.zfree = (free_func)0; 114 s->stream.opaque = (voidpf)0; 115 s->stream.next_in = s->inbuf = Z_NULL; 116 s->stream.next_out = s->outbuf = Z_NULL; 117 s->stream.avail_in = s->stream.avail_out = 0; 118 s->file = NULL; 119 s->z_err = Z_OK; 120 s->z_eof = 0; 121 s->in = 0; 122 s->out = 0; 123 s->back = EOF; 124 s->crc = crc32(0L, Z_NULL, 0); 125 s->msg = NULL; 126 s->transparent = 0; 127 128 s->path = (char*)ALLOC(strlen(path)+1); 129 if (s->path == NULL) { 130 return destroy(s), (gzFile)Z_NULL; 131 } 132 strcpy(s->path, path); /* do this early for debugging */ 133 134 s->mode = '\0'; 135 do { 136 if (*p == 'r') s->mode = 'r'; 137 if (*p == 'w' || *p == 'a') s->mode = 'w'; 138 if (*p >= '0' && *p <= '9') { 139 level = *p - '0'; 140 } else if (*p == 'f') { 141 strategy = Z_FILTERED; 142 } else if (*p == 'h') { 143 strategy = Z_HUFFMAN_ONLY; 144 } else if (*p == 'R') { 145 strategy = Z_RLE; 146 } else { 147 *m++ = *p; /* copy the mode */ 148 } 149 } while (*p++ && m != fmode + sizeof(fmode)); 150 if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; 151 152 if (s->mode == 'w') { 153#ifdef NO_GZCOMPRESS 154 err = Z_STREAM_ERROR; 155#else 156 err = deflateInit2(&(s->stream), level, 157 Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); 158 /* windowBits is passed < 0 to suppress zlib header */ 159 160 s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); 161#endif 162 if (err != Z_OK || s->outbuf == Z_NULL) { 163 return destroy(s), (gzFile)Z_NULL; 164 } 165 } else { 166 s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); 167 168 err = inflateInit2(&(s->stream), -MAX_WBITS); 169 /* windowBits is passed < 0 to tell that there is no zlib header. 170 * Note that in this case inflate *requires* an extra "dummy" byte 171 * after the compressed stream in order to complete decompression and 172 * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are 173 * present after the compressed stream. 174 */ 175 if (err != Z_OK || s->inbuf == Z_NULL) { 176 return destroy(s), (gzFile)Z_NULL; 177 } 178 } 179 s->stream.avail_out = Z_BUFSIZE; 180 181 errno = 0; 182 s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); 183 184 if (s->file == NULL) { 185 return destroy(s), (gzFile)Z_NULL; 186 } 187 if (s->mode == 'w') { 188 /* Write a very simple .gz header: 189 */ 190 fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], 191 Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); 192 s->start = 10L; 193 /* We use 10L instead of ftell(s->file) to because ftell causes an 194 * fflush on some systems. This version of the library doesn't use 195 * start anyway in write mode, so this initialization is not 196 * necessary. 197 */ 198 } else { 199 check_header(s); /* skip the .gz header */ 200 s->start = ftell(s->file) - s->stream.avail_in; 201 } 202 203 return (gzFile)s; 204} 205 206/* =========================================================================== 207 Opens a gzip (.gz) file for reading or writing. 208*/ 209gzFile ZEXPORT gzopen (path, mode) 210 const char *path; 211 const char *mode; 212{ 213 return gz_open (path, mode, -1); 214} 215 216/* =========================================================================== 217 Associate a gzFile with the file descriptor fd. fd is not dup'ed here 218 to mimic the behavio(u)r of fdopen. 219*/ 220gzFile ZEXPORT gzdopen (fd, mode) 221 int fd; 222 const char *mode; 223{ 224 char name[46]; /* allow for up to 128-bit integers */ 225 226 if (fd < 0) return (gzFile)Z_NULL; 227 sprintf(name, "<fd:%d>", fd); /* for debugging */ 228 229 return gz_open (name, mode, fd); 230} 231 232/* =========================================================================== 233 * Update the compression level and strategy 234 */ 235int ZEXPORT gzsetparams (file, level, strategy) 236 gzFile file; 237 int level; 238 int strategy; 239{ 240 gz_stream *s = (gz_stream*)file; 241 242 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; 243 244 /* Make room to allow flushing */ 245 if (s->stream.avail_out == 0) { 246 247 s->stream.next_out = s->outbuf; 248 if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { 249 s->z_err = Z_ERRNO; 250 } 251 s->stream.avail_out = Z_BUFSIZE; 252 } 253 254 return deflateParams (&(s->stream), level, strategy); 255} 256 257/* =========================================================================== 258 Read a byte from a gz_stream; update next_in and avail_in. Return EOF 259 for end of file. 260 IN assertion: the stream s has been sucessfully opened for reading. 261*/ 262local int get_byte(s) 263 gz_stream *s; 264{ 265 if (s->z_eof) return EOF; 266 if (s->stream.avail_in == 0) { 267 errno = 0; 268 s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); 269 if (s->stream.avail_in == 0) { 270 s->z_eof = 1; 271 if (ferror(s->file)) s->z_err = Z_ERRNO; 272 return EOF; 273 } 274 s->stream.next_in = s->inbuf; 275 } 276 s->stream.avail_in--; 277 return *(s->stream.next_in)++; 278} 279 280/* =========================================================================== 281 Check the gzip header of a gz_stream opened for reading. Set the stream 282 mode to transparent if the gzip magic header is not present; set s->err 283 to Z_DATA_ERROR if the magic header is present but the rest of the header 284 is incorrect. 285 IN assertion: the stream s has already been created sucessfully; 286 s->stream.avail_in is zero for the first time, but may be non-zero 287 for concatenated .gz files. 288*/ 289local void check_header(s) 290 gz_stream *s; 291{ 292 int method; /* method byte */ 293 int flags; /* flags byte */ 294 uInt len; 295 int c; 296 297 /* Assure two bytes in the buffer so we can peek ahead -- handle case 298 where first byte of header is at the end of the buffer after the last 299 gzip segment */ 300 len = s->stream.avail_in; 301 if (len < 2) { 302 if (len) s->inbuf[0] = s->stream.next_in[0]; 303 errno = 0; 304 len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); 305 if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; 306 s->stream.avail_in += len; 307 s->stream.next_in = s->inbuf; 308 if (s->stream.avail_in < 2) { 309 s->transparent = s->stream.avail_in; 310 return; 311 } 312 } 313 314 /* Peek ahead to check the gzip magic header */ 315 if (s->stream.next_in[0] != gz_magic[0] || 316 s->stream.next_in[1] != gz_magic[1]) { 317 s->transparent = 1; 318 return; 319 } 320 s->stream.avail_in -= 2; 321 s->stream.next_in += 2; 322 323 /* Check the rest of the gzip header */ 324 method = get_byte(s); 325 flags = get_byte(s); 326 if (method != Z_DEFLATED || (flags & RESERVED) != 0) { 327 s->z_err = Z_DATA_ERROR; 328 return; 329 } 330 331 /* Discard time, xflags and OS code: */ 332 for (len = 0; len < 6; len++) (void)get_byte(s); 333 334 if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ 335 len = (uInt)get_byte(s); 336 len += ((uInt)get_byte(s))<<8; 337 /* len is garbage if EOF but the loop below will quit anyway */ 338 while (len-- != 0 && get_byte(s) != EOF) ; 339 } 340 if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ 341 while ((c = get_byte(s)) != 0 && c != EOF) ; 342 } 343 if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ 344 while ((c = get_byte(s)) != 0 && c != EOF) ; 345 } 346 if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ 347 for (len = 0; len < 2; len++) (void)get_byte(s); 348 } 349 s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; 350} 351 352 /* =========================================================================== 353 * Cleanup then free the given gz_stream. Return a zlib error code. 354 Try freeing in the reverse order of allocations. 355 */ 356local int destroy (s) 357 gz_stream *s; 358{ 359 int err = Z_OK; 360 361 if (!s) return Z_STREAM_ERROR; 362 363 TRYFREE(s->msg); 364 365 if (s->stream.state != NULL) { 366 if (s->mode == 'w') { 367#ifdef NO_GZCOMPRESS 368 err = Z_STREAM_ERROR; 369#else 370 err = deflateEnd(&(s->stream)); 371#endif 372 } else if (s->mode == 'r') { 373 err = inflateEnd(&(s->stream)); 374 } 375 } 376 if (s->file != NULL && fclose(s->file)) { 377#ifdef ESPIPE 378 if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ 379#endif 380 err = Z_ERRNO; 381 } 382 if (s->z_err < 0) err = s->z_err; 383 384 TRYFREE(s->inbuf); 385 TRYFREE(s->outbuf); 386 TRYFREE(s->path); 387 TRYFREE(s); 388 return err; 389} 390 391/* =========================================================================== 392 Reads the given number of uncompressed bytes from the compressed file. 393 gzread returns the number of bytes actually read (0 for end of file). 394*/ 395int ZEXPORT gzread (file, buf, len) 396 gzFile file; 397 voidp buf; 398 unsigned len; 399{ 400 gz_stream *s = (gz_stream*)file; 401 Bytef *start = (Bytef*)buf; /* starting point for crc computation */ 402 Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ 403 404 if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; 405 406 if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; 407 if (s->z_err == Z_STREAM_END) return 0; /* EOF */ 408 409 next_out = (Byte*)buf; 410 s->stream.next_out = (Bytef*)buf; 411 s->stream.avail_out = len; 412 413 if (s->stream.avail_out && s->back != EOF) { 414 *next_out++ = s->back; 415 s->stream.next_out++; 416 s->stream.avail_out--; 417 s->back = EOF; 418 s->out++; 419 start++; 420 if (s->last) { 421 s->z_err = Z_STREAM_END; 422 return 1; 423 } 424 } 425 426 while (s->stream.avail_out != 0) { 427 428 if (s->transparent) { 429 /* Copy first the lookahead bytes: */ 430 uInt n = s->stream.avail_in; 431 if (n > s->stream.avail_out) n = s->stream.avail_out; 432 if (n > 0) { 433 zmemcpy(s->stream.next_out, s->stream.next_in, n); 434 next_out += n; 435 s->stream.next_out = next_out; 436 s->stream.next_in += n; 437 s->stream.avail_out -= n; 438 s->stream.avail_in -= n; 439 } 440 if (s->stream.avail_out > 0) { 441 s->stream.avail_out -= 442 (uInt)fread(next_out, 1, s->stream.avail_out, s->file); 443 } 444 len -= s->stream.avail_out; 445 s->in += len; 446 s->out += len; 447 if (len == 0) s->z_eof = 1; 448 return (int)len; 449 } 450 if (s->stream.avail_in == 0 && !s->z_eof) { 451 452 errno = 0; 453 s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); 454 if (s->stream.avail_in == 0) { 455 s->z_eof = 1; 456 if (ferror(s->file)) { 457 s->z_err = Z_ERRNO; 458 break; 459 } 460 } 461 s->stream.next_in = s->inbuf; 462 } 463 s->in += s->stream.avail_in; 464 s->out += s->stream.avail_out; 465 s->z_err = inflate(&(s->stream), Z_NO_FLUSH); 466 s->in -= s->stream.avail_in; 467 s->out -= s->stream.avail_out; 468 469 if (s->z_err == Z_STREAM_END) { 470 /* Check CRC and original size */ 471 s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); 472 start = s->stream.next_out; 473 474 if (getLong(s) != s->crc) { 475 s->z_err = Z_DATA_ERROR; 476 } else { 477 (void)getLong(s); 478 /* The uncompressed length returned by above getlong() may be 479 * different from s->out in case of concatenated .gz files. 480 * Check for such files: 481 */ 482 check_header(s); 483 if (s->z_err == Z_OK) { 484 inflateReset(&(s->stream)); 485 s->crc = crc32(0L, Z_NULL, 0); 486 } 487 } 488 } 489 if (s->z_err != Z_OK || s->z_eof) break; 490 } 491 s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); 492 493 if (len == s->stream.avail_out && 494 (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) 495 return -1; 496 return (int)(len - s->stream.avail_out); 497} 498 499 500/* =========================================================================== 501 Reads one byte from the compressed file. gzgetc returns this byte 502 or -1 in case of end of file or error. 503*/ 504int ZEXPORT gzgetc(file) 505 gzFile file; 506{ 507 unsigned char c; 508 509 return gzread(file, &c, 1) == 1 ? c : -1; 510} 511 512 513/* =========================================================================== 514 Push one byte back onto the stream. 515*/ 516int ZEXPORT gzungetc(c, file) 517 int c; 518 gzFile file; 519{ 520 gz_stream *s = (gz_stream*)file; 521 522 if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; 523 s->back = c; 524 s->out--; 525 s->last = (s->z_err == Z_STREAM_END); 526 if (s->last) s->z_err = Z_OK; 527 s->z_eof = 0; 528 return c; 529} 530 531 532/* =========================================================================== 533 Reads bytes from the compressed file until len-1 characters are 534 read, or a newline character is read and transferred to buf, or an 535 end-of-file condition is encountered. The string is then terminated 536 with a null character. 537 gzgets returns buf, or Z_NULL in case of error. 538 539 The current implementation is not optimized at all. 540*/ 541char * ZEXPORT gzgets(file, buf, len) 542 gzFile file; 543 char *buf; 544 int len; 545{ 546 char *b = buf; 547 if (buf == Z_NULL || len <= 0) return Z_NULL; 548 549 while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; 550 *buf = '\0'; 551 return b == buf && len > 0 ? Z_NULL : b; 552} 553 554 555#ifndef NO_GZCOMPRESS 556/* =========================================================================== 557 Writes the given number of uncompressed bytes into the compressed file. 558 gzwrite returns the number of bytes actually written (0 in case of error). 559*/ 560int ZEXPORT gzwrite (file, buf, len) 561 gzFile file; 562 voidpc buf; 563 unsigned len; 564{ 565 gz_stream *s = (gz_stream*)file; 566 567 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; 568 569 s->stream.next_in = (Bytef*)buf; 570 s->stream.avail_in = len; 571 572 while (s->stream.avail_in != 0) { 573 574 if (s->stream.avail_out == 0) { 575 576 s->stream.next_out = s->outbuf; 577 if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { 578 s->z_err = Z_ERRNO; 579 break; 580 } 581 s->stream.avail_out = Z_BUFSIZE; 582 } 583 s->in += s->stream.avail_in; 584 s->out += s->stream.avail_out; 585 s->z_err = deflate(&(s->stream), Z_NO_FLUSH); 586 s->in -= s->stream.avail_in; 587 s->out -= s->stream.avail_out; 588 if (s->z_err != Z_OK) break; 589 } 590 s->crc = crc32(s->crc, (const Bytef *)buf, len); 591 592 return (int)(len - s->stream.avail_in); 593} 594 595 596/* =========================================================================== 597 Converts, formats, and writes the args to the compressed file under 598 control of the format string, as in fprintf. gzprintf returns the number of 599 uncompressed bytes actually written (0 in case of error). 600*/ 601#ifdef STDC 602#include <stdarg.h> 603 604int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) 605{ 606 char buf[Z_PRINTF_BUFSIZE]; 607 va_list va; 608 int len; 609 610 buf[sizeof(buf) - 1] = 0; 611 va_start(va, format); 612#ifdef NO_vsnprintf 613# ifdef HAS_vsprintf_void 614 (void)vsprintf(buf, format, va); 615 va_end(va); 616 for (len = 0; len < sizeof(buf); len++) 617 if (buf[len] == 0) break; 618# else 619 len = vsprintf(buf, format, va); 620 va_end(va); 621# endif 622#else 623# ifdef HAS_vsnprintf_void 624 (void)vsnprintf(buf, sizeof(buf), format, va); 625 va_end(va); 626 len = strlen(buf); 627# else 628 len = vsnprintf(buf, sizeof(buf), format, va); 629 va_end(va); 630# endif 631#endif 632 if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) 633 return 0; 634 return gzwrite(file, buf, (unsigned)len); 635} 636#else /* not ANSI C */ 637 638int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, 639 a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) 640 gzFile file; 641 const char *format; 642 int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, 643 a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; 644{ 645 char buf[Z_PRINTF_BUFSIZE]; 646 int len; 647 648 buf[sizeof(buf) - 1] = 0; 649#ifdef NO_snprintf 650# ifdef HAS_sprintf_void 651 sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, 652 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); 653 for (len = 0; len < sizeof(buf); len++) 654 if (buf[len] == 0) break; 655# else 656 len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, 657 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); 658# endif 659#else 660# ifdef HAS_snprintf_void 661 snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, 662 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); 663 len = strlen(buf); 664# else 665 len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, 666 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); 667# endif 668#endif 669 if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) 670 return 0; 671 return gzwrite(file, buf, len); 672} 673#endif 674 675/* =========================================================================== 676 Writes c, converted to an unsigned char, into the compressed file. 677 gzputc returns the value that was written, or -1 in case of error. 678*/ 679int ZEXPORT gzputc(file, c) 680 gzFile file; 681 int c; 682{ 683 unsigned char cc = (unsigned char) c; /* required for big endian systems */ 684 685 return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; 686} 687 688 689/* =========================================================================== 690 Writes the given null-terminated string to the compressed file, excluding 691 the terminating null character. 692 gzputs returns the number of characters written, or -1 in case of error. 693*/ 694int ZEXPORT gzputs(file, s) 695 gzFile file; 696 const char *s; 697{ 698 return gzwrite(file, (char*)s, (unsigned)strlen(s)); 699} 700 701 702/* =========================================================================== 703 Flushes all pending output into the compressed file. The parameter 704 flush is as in the deflate() function. 705*/ 706local int do_flush (file, flush) 707 gzFile file; 708 int flush; 709{ 710 uInt len; 711 int done = 0; 712 gz_stream *s = (gz_stream*)file; 713 714 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; 715 716 s->stream.avail_in = 0; /* should be zero already anyway */ 717 718 for (;;) { 719 len = Z_BUFSIZE - s->stream.avail_out; 720 721 if (len != 0) { 722 if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { 723 s->z_err = Z_ERRNO; 724 return Z_ERRNO; 725 } 726 s->stream.next_out = s->outbuf; 727 s->stream.avail_out = Z_BUFSIZE; 728 } 729 if (done) break; 730 s->out += s->stream.avail_out; 731 s->z_err = deflate(&(s->stream), flush); 732 s->out -= s->stream.avail_out; 733 734 /* Ignore the second of two consecutive flushes: */ 735 if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; 736 737 /* deflate has finished flushing only when it hasn't used up 738 * all the available space in the output buffer: 739 */ 740 done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); 741 742 if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; 743 } 744 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; 745} 746 747int ZEXPORT gzflush (file, flush) 748 gzFile file; 749 int flush; 750{ 751 gz_stream *s = (gz_stream*)file; 752 int err = do_flush (file, flush); 753 754 if (err) return err; 755 fflush(s->file); 756 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; 757} 758#endif /* NO_GZCOMPRESS */ 759 760/* =========================================================================== 761 Sets the starting position for the next gzread or gzwrite on the given 762 compressed file. The offset represents a number of bytes in the 763 gzseek returns the resulting offset location as measured in bytes from 764 the beginning of the uncompressed stream, or -1 in case of error. 765 SEEK_END is not implemented, returns error. 766 In this version of the library, gzseek can be extremely slow. 767*/ 768z_off_t ZEXPORT gzseek (file, offset, whence) 769 gzFile file; 770 z_off_t offset; 771 int whence; 772{ 773 gz_stream *s = (gz_stream*)file; 774 775 if (s == NULL || whence == SEEK_END || 776 s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { 777 return -1L; 778 } 779 780 if (s->mode == 'w') { 781#ifdef NO_GZCOMPRESS 782 return -1L; 783#else 784 if (whence == SEEK_SET) { 785 offset -= s->in; 786 } 787 if (offset < 0) return -1L; 788 789 /* At this point, offset is the number of zero bytes to write. */ 790 if (s->inbuf == Z_NULL) { 791 s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ 792 if (s->inbuf == Z_NULL) return -1L; 793 zmemzero(s->inbuf, Z_BUFSIZE); 794 } 795 while (offset > 0) { 796 uInt size = Z_BUFSIZE; 797 if (offset < Z_BUFSIZE) size = (uInt)offset; 798 799 size = gzwrite(file, s->inbuf, size); 800 if (size == 0) return -1L; 801 802 offset -= size; 803 } 804 return s->in; 805#endif 806 } 807 /* Rest of function is for reading only */ 808 809 /* compute absolute position */ 810 if (whence == SEEK_CUR) { 811 offset += s->out; 812 } 813 if (offset < 0) return -1L; 814 815 if (s->transparent) { 816 /* map to fseek */ 817 s->back = EOF; 818 s->stream.avail_in = 0; 819 s->stream.next_in = s->inbuf; 820 if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; 821 822 s->in = s->out = offset; 823 return offset; 824 } 825 826 /* For a negative seek, rewind and use positive seek */ 827 if (offset >= s->out) { 828 offset -= s->out; 829 } else if (gzrewind(file) < 0) { 830 return -1L; 831 } 832 /* offset is now the number of bytes to skip. */ 833 834 if (offset != 0 && s->outbuf == Z_NULL) { 835 s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); 836 if (s->outbuf == Z_NULL) return -1L; 837 } 838 if (offset && s->back != EOF) { 839 s->back = EOF; 840 s->out++; 841 offset--; 842 if (s->last) s->z_err = Z_STREAM_END; 843 } 844 while (offset > 0) { 845 int size = Z_BUFSIZE; 846 if (offset < Z_BUFSIZE) size = (int)offset; 847 848 size = gzread(file, s->outbuf, (uInt)size); 849 if (size <= 0) return -1L; 850 offset -= size; 851 } 852 return s->out; 853} 854 855/* =========================================================================== 856 Rewinds input file. 857*/ 858int ZEXPORT gzrewind (file) 859 gzFile file; 860{ 861 gz_stream *s = (gz_stream*)file; 862 863 if (s == NULL || s->mode != 'r') return -1; 864 865 s->z_err = Z_OK; 866 s->z_eof = 0; 867 s->back = EOF; 868 s->stream.avail_in = 0; 869 s->stream.next_in = s->inbuf; 870 s->crc = crc32(0L, Z_NULL, 0); 871 if (!s->transparent) (void)inflateReset(&s->stream); 872 s->in = 0; 873 s->out = 0; 874 return fseek(s->file, s->start, SEEK_SET); 875} 876 877/* =========================================================================== 878 Returns the starting position for the next gzread or gzwrite on the 879 given compressed file. This position represents a number of bytes in the 880 uncompressed data stream. 881*/ 882z_off_t ZEXPORT gztell (file) 883 gzFile file; 884{ 885 return gzseek(file, 0L, SEEK_CUR); 886} 887 888/* =========================================================================== 889 Returns 1 when EOF has previously been detected reading the given 890 input stream, otherwise zero. 891*/ 892int ZEXPORT gzeof (file) 893 gzFile file; 894{ 895 gz_stream *s = (gz_stream*)file; 896 897 /* With concatenated compressed files that can have embedded 898 * crc trailers, z_eof is no longer the only/best indicator of EOF 899 * on a gz_stream. Handle end-of-stream error explicitly here. 900 */ 901 if (s == NULL || s->mode != 'r') return 0; 902 if (s->z_eof) return 1; 903 return s->z_err == Z_STREAM_END; 904} 905 906/* =========================================================================== 907 Returns 1 if reading and doing so transparently, otherwise zero. 908*/ 909int ZEXPORT gzdirect (file) 910 gzFile file; 911{ 912 gz_stream *s = (gz_stream*)file; 913 914 if (s == NULL || s->mode != 'r') return 0; 915 return s->transparent; 916} 917 918/* =========================================================================== 919 Outputs a long in LSB order to the given file 920*/ 921local void putLong (file, x) 922 FILE *file; 923 uLong x; 924{ 925 int n; 926 for (n = 0; n < 4; n++) { 927 fputc((int)(x & 0xff), file); 928 x >>= 8; 929 } 930} 931 932/* =========================================================================== 933 Reads a long in LSB order from the given gz_stream. Sets z_err in case 934 of error. 935*/ 936local uLong getLong (s) 937 gz_stream *s; 938{ 939 uLong x = (uLong)get_byte(s); 940 int c; 941 942 x += ((uLong)get_byte(s))<<8; 943 x += ((uLong)get_byte(s))<<16; 944 c = get_byte(s); 945 if (c == EOF) s->z_err = Z_DATA_ERROR; 946 x += ((uLong)c)<<24; 947 return x; 948} 949 950/* =========================================================================== 951 Flushes all pending output if necessary, closes the compressed file 952 and deallocates all the (de)compression state. 953*/ 954int ZEXPORT gzclose (file) 955 gzFile file; 956{ 957 gz_stream *s = (gz_stream*)file; 958 959 if (s == NULL) return Z_STREAM_ERROR; 960 961 if (s->mode == 'w') { 962#ifdef NO_GZCOMPRESS 963 return Z_STREAM_ERROR; 964#else 965 if (do_flush (file, Z_FINISH) != Z_OK) 966 return destroy((gz_stream*)file); 967 968 putLong (s->file, s->crc); 969 putLong (s->file, (uLong)(s->in & 0xffffffff)); 970#endif 971 } 972 return destroy((gz_stream*)file); 973} 974 975#ifdef STDC 976# define zstrerror(errnum) strerror(errnum) 977#else 978# define zstrerror(errnum) "" 979#endif 980 981/* =========================================================================== 982 Returns the error message for the last error which occurred on the 983 given compressed file. errnum is set to zlib error number. If an 984 error occurred in the file system and not in the compression library, 985 errnum is set to Z_ERRNO and the application may consult errno 986 to get the exact error code. 987*/ 988const char * ZEXPORT gzerror (file, errnum) 989 gzFile file; 990 int *errnum; 991{ 992 char *m; 993 gz_stream *s = (gz_stream*)file; 994 995 if (s == NULL) { 996 *errnum = Z_STREAM_ERROR; 997 return (const char*)ERR_MSG(Z_STREAM_ERROR); 998 } 999 *errnum = s->z_err; 1000 if (*errnum == Z_OK) return (const char*)""; 1001 1002 m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); 1003 1004 if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); 1005 1006 TRYFREE(s->msg); 1007 s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); 1008 if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); 1009 strcpy(s->msg, s->path); 1010 strcat(s->msg, ": "); 1011 strcat(s->msg, m); 1012 return (const char*)s->msg; 1013} 1014 1015/* =========================================================================== 1016 Clear the error and end-of-file flags, and do the same for the real file. 1017*/ 1018void ZEXPORT gzclearerr (file) 1019 gzFile file; 1020{ 1021 gz_stream *s = (gz_stream*)file; 1022 1023 if (s == NULL) return; 1024 if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; 1025 s->z_eof = 0; 1026 clearerr(s->file); 1027} 1028