gzio_symb.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  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. /* @(#) $Id$ */
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <errno.h>
  12. //#include "zutil.h"
  13. #include <EZlib.h>
  14. #include "gzio_symb.h"
  15. #ifndef Z_BUFSIZE
  16. # ifdef MAXSEG_64K
  17. # define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
  18. # else
  19. # define Z_BUFSIZE 16384
  20. # endif
  21. #endif
  22. #ifndef local
  23. # define local static
  24. #endif
  25. #ifndef OS_CODE
  26. # define OS_CODE 0x03 /* assume Unix */
  27. #endif
  28. #ifndef F_OPEN
  29. # define F_OPEN(name, mode) fopen((name), (mode))
  30. #endif
  31. #if MAX_MEM_LEVEL >= 8
  32. # define DEF_MEM_LEVEL 8
  33. #else
  34. # define DEF_MEM_LEVEL MAX_MEM_LEVEL
  35. #endif
  36. #define ALLOC(size) malloc(size)
  37. #define TRYFREE(p) {if (p) free(p);}
  38. #define zmemcpy memcpy
  39. static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
  40. /* gzip flag byte */
  41. #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
  42. #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
  43. #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
  44. #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
  45. #define COMMENT 0x10 /* bit 4 set: file comment present */
  46. #define RESERVED 0xE0 /* bits 5..7: reserved */
  47. typedef struct gz_stream {
  48. z_stream stream;
  49. int z_err; /* error code for last stream operation */
  50. int z_eof; /* set if end of input file */
  51. FILE *file; /* .gz file */
  52. Byte *inbuf; /* input buffer */
  53. Byte *outbuf; /* output buffer */
  54. uLong crc; /* crc32 of uncompressed data */
  55. char *msg; /* error message */
  56. char *path; /* path name for debugging only */
  57. int transparent; /* 1 if input file is not a .gz file */
  58. char mode; /* 'w' or 'r' */
  59. z_off_t start; /* start of compressed data in file (header skipped) */
  60. z_off_t in; /* bytes into deflate or inflate */
  61. z_off_t out; /* bytes out of deflate or inflate */
  62. int back; /* one character push-back */
  63. int last; /* true if push-back is last character */
  64. } gz_stream;
  65. local gzFile gz_open OF((const char *path, const char *mode, int fd));
  66. local int do_flush OF((gzFile file, int flush));
  67. local int get_byte OF((gz_stream *s));
  68. local void check_header OF((gz_stream *s));
  69. local int destroy OF((gz_stream *s));
  70. local void putLong OF((FILE *file, uLong x));
  71. local uLong getLong OF((gz_stream *s));
  72. /* ===========================================================================
  73. Opens a gzip (.gz) file for reading or writing. The mode parameter
  74. is as in fopen ("rb" or "wb"). The file is given either by file descriptor
  75. or path name (if fd == -1).
  76. gz_open returns NULL if the file could not be opened or if there was
  77. insufficient memory to allocate the (de)compression state; errno
  78. can be checked to distinguish the two cases (if errno is zero, the
  79. zlib error is Z_MEM_ERROR).
  80. */
  81. local gzFile gz_open (path, mode, fd)
  82. const char *path;
  83. const char *mode;
  84. int fd;
  85. {
  86. int err;
  87. int level = Z_DEFAULT_COMPRESSION; /* compression level */
  88. int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
  89. char *p = (char*)mode;
  90. gz_stream *s;
  91. char fmode[80]; /* copy of mode, without the compression level */
  92. char *m = fmode;
  93. if (!path || !mode) return Z_NULL;
  94. s = (gz_stream *)ALLOC(sizeof(gz_stream));
  95. if (!s) return Z_NULL;
  96. s->stream.zalloc = (alloc_func)0;
  97. s->stream.zfree = (free_func)0;
  98. s->stream.opaque = (voidpf)0;
  99. s->stream.next_in = s->inbuf = Z_NULL;
  100. s->stream.next_out = s->outbuf = Z_NULL;
  101. s->stream.avail_in = s->stream.avail_out = 0;
  102. s->file = NULL;
  103. s->z_err = Z_OK;
  104. s->z_eof = 0;
  105. s->in = 0;
  106. s->out = 0;
  107. s->back = EOF;
  108. s->crc = crc32(0L, Z_NULL, 0);
  109. s->msg = NULL;
  110. s->transparent = 0;
  111. s->path = (char*)ALLOC(strlen(path)+1);
  112. if (s->path == NULL) {
  113. return destroy(s), (gzFile)Z_NULL;
  114. }
  115. strcpy(s->path, path); /* do this early for debugging */
  116. s->mode = '\0';
  117. do {
  118. if (*p == 'r') s->mode = 'r';
  119. if (*p == 'w' || *p == 'a') s->mode = 'w';
  120. if (*p >= '0' && *p <= '9') {
  121. level = *p - '0';
  122. } else if (*p == 'f') {
  123. strategy = Z_FILTERED;
  124. } else if (*p == 'h') {
  125. strategy = Z_HUFFMAN_ONLY;
  126. } else if (*p == 'R') {
  127. strategy = Z_RLE;
  128. } else {
  129. *m++ = *p; /* copy the mode */
  130. }
  131. } while (*p++ && m != fmode + sizeof(fmode));
  132. if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
  133. if (s->mode == 'w') {
  134. #ifdef NO_GZCOMPRESS
  135. err = Z_STREAM_ERROR;
  136. #else
  137. err = deflateInit2(&(s->stream), level,
  138. Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
  139. /* windowBits is passed < 0 to suppress zlib header */
  140. s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
  141. #endif
  142. if (err != Z_OK || s->outbuf == Z_NULL) {
  143. return destroy(s), (gzFile)Z_NULL;
  144. }
  145. } else {
  146. s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
  147. err = inflateInit2(&(s->stream), -MAX_WBITS);
  148. /* windowBits is passed < 0 to tell that there is no zlib header.
  149. * Note that in this case inflate *requires* an extra "dummy" byte
  150. * after the compressed stream in order to complete decompression and
  151. * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
  152. * present after the compressed stream.
  153. */
  154. if (err != Z_OK || s->inbuf == Z_NULL) {
  155. return destroy(s), (gzFile)Z_NULL;
  156. }
  157. }
  158. s->stream.avail_out = Z_BUFSIZE;
  159. errno = 0;
  160. s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
  161. if (s->file == NULL) {
  162. return destroy(s), (gzFile)Z_NULL;
  163. }
  164. if (s->mode == 'w') {
  165. /* Write a very simple .gz header:
  166. */
  167. fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
  168. Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
  169. s->start = 10L;
  170. /* We use 10L instead of ftell(s->file) to because ftell causes an
  171. * fflush on some systems. This version of the library doesn't use
  172. * start anyway in write mode, so this initialization is not
  173. * necessary.
  174. */
  175. } else {
  176. check_header(s); /* skip the .gz header */
  177. s->start = ftell(s->file) - s->stream.avail_in;
  178. }
  179. return (gzFile)s;
  180. }
  181. /* ===========================================================================
  182. Opens a gzip (.gz) file for reading or writing.
  183. */
  184. gzFile ZEXPORT gzopen (path, mode)
  185. const char *path;
  186. const char *mode;
  187. {
  188. return gz_open (path, mode, -1);
  189. }
  190. /* ===========================================================================
  191. * Update the compression level and strategy
  192. */
  193. int ZEXPORT gzsetparams (file, level, strategy)
  194. gzFile file;
  195. int level;
  196. int strategy;
  197. {
  198. gz_stream *s = (gz_stream*)file;
  199. if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
  200. /* Make room to allow flushing */
  201. if (s->stream.avail_out == 0) {
  202. s->stream.next_out = s->outbuf;
  203. if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
  204. s->z_err = Z_ERRNO;
  205. }
  206. s->stream.avail_out = Z_BUFSIZE;
  207. }
  208. return deflateParams (&(s->stream), level, strategy);
  209. }
  210. /* ===========================================================================
  211. Read a byte from a gz_stream; update next_in and avail_in. Return EOF
  212. for end of file.
  213. IN assertion: the stream s has been sucessfully opened for reading.
  214. */
  215. local int get_byte(s)
  216. gz_stream *s;
  217. {
  218. if (s->z_eof) return EOF;
  219. if (s->stream.avail_in == 0) {
  220. errno = 0;
  221. s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
  222. if (s->stream.avail_in == 0) {
  223. s->z_eof = 1;
  224. if (ferror(s->file)) s->z_err = Z_ERRNO;
  225. return EOF;
  226. }
  227. s->stream.next_in = s->inbuf;
  228. }
  229. s->stream.avail_in--;
  230. return *(s->stream.next_in)++;
  231. }
  232. /* ===========================================================================
  233. Check the gzip header of a gz_stream opened for reading. Set the stream
  234. mode to transparent if the gzip magic header is not present; set s->err
  235. to Z_DATA_ERROR if the magic header is present but the rest of the header
  236. is incorrect.
  237. IN assertion: the stream s has already been created sucessfully;
  238. s->stream.avail_in is zero for the first time, but may be non-zero
  239. for concatenated .gz files.
  240. */
  241. local void check_header(s)
  242. gz_stream *s;
  243. {
  244. int method; /* method byte */
  245. int flags; /* flags byte */
  246. uInt len;
  247. int c;
  248. /* Assure two bytes in the buffer so we can peek ahead -- handle case
  249. where first byte of header is at the end of the buffer after the last
  250. gzip segment */
  251. len = s->stream.avail_in;
  252. if (len < 2) {
  253. if (len) s->inbuf[0] = s->stream.next_in[0];
  254. errno = 0;
  255. len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file);
  256. if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO;
  257. s->stream.avail_in += len;
  258. s->stream.next_in = s->inbuf;
  259. if (s->stream.avail_in < 2) {
  260. s->transparent = s->stream.avail_in;
  261. return;
  262. }
  263. }
  264. /* Peek ahead to check the gzip magic header */
  265. if (s->stream.next_in[0] != gz_magic[0] ||
  266. s->stream.next_in[1] != gz_magic[1]) {
  267. s->transparent = 1;
  268. return;
  269. }
  270. s->stream.avail_in -= 2;
  271. s->stream.next_in += 2;
  272. /* Check the rest of the gzip header */
  273. method = get_byte(s);
  274. flags = get_byte(s);
  275. if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
  276. s->z_err = Z_DATA_ERROR;
  277. return;
  278. }
  279. /* Discard time, xflags and OS code: */
  280. for (len = 0; len < 6; len++) (void)get_byte(s);
  281. if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
  282. len = (uInt)get_byte(s);
  283. len += ((uInt)get_byte(s))<<8;
  284. /* len is garbage if EOF but the loop below will quit anyway */
  285. while (len-- != 0 && get_byte(s) != EOF) ;
  286. }
  287. if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
  288. while ((c = get_byte(s)) != 0 && c != EOF) ;
  289. }
  290. if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
  291. while ((c = get_byte(s)) != 0 && c != EOF) ;
  292. }
  293. if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
  294. for (len = 0; len < 2; len++) (void)get_byte(s);
  295. }
  296. s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
  297. }
  298. /* ===========================================================================
  299. * Cleanup then free the given gz_stream. Return a zlib error code.
  300. Try freeing in the reverse order of allocations.
  301. */
  302. local int destroy (s)
  303. gz_stream *s;
  304. {
  305. int err = Z_OK;
  306. if (!s) return Z_STREAM_ERROR;
  307. TRYFREE(s->msg);
  308. if (s->stream.state != NULL) {
  309. if (s->mode == 'w') {
  310. #ifdef NO_GZCOMPRESS
  311. err = Z_STREAM_ERROR;
  312. #else
  313. err = deflateEnd(&(s->stream));
  314. #endif
  315. } else if (s->mode == 'r') {
  316. err = inflateEnd(&(s->stream));
  317. }
  318. }
  319. if (s->file != NULL && fclose(s->file)) {
  320. #ifdef ESPIPE
  321. if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
  322. #endif
  323. err = Z_ERRNO;
  324. }
  325. if (s->z_err < 0) err = s->z_err;
  326. TRYFREE(s->inbuf);
  327. TRYFREE(s->outbuf);
  328. TRYFREE(s->path);
  329. TRYFREE(s);
  330. return err;
  331. }
  332. /* ===========================================================================
  333. Reads the given number of uncompressed bytes from the compressed file.
  334. gzread returns the number of bytes actually read (0 for end of file).
  335. */
  336. int ZEXPORT gzread (file, buf, len)
  337. gzFile file;
  338. voidp buf;
  339. unsigned len;
  340. {
  341. gz_stream *s = (gz_stream*)file;
  342. Bytef *start = (Bytef*)buf; /* starting point for crc computation */
  343. Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
  344. if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
  345. if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
  346. if (s->z_err == Z_STREAM_END) return 0; /* EOF */
  347. next_out = (Byte*)buf;
  348. s->stream.next_out = (Bytef*)buf;
  349. s->stream.avail_out = len;
  350. if (s->stream.avail_out && s->back != EOF) {
  351. *next_out++ = s->back;
  352. s->stream.next_out++;
  353. s->stream.avail_out--;
  354. s->back = EOF;
  355. s->out++;
  356. start++;
  357. if (s->last) {
  358. s->z_err = Z_STREAM_END;
  359. return 1;
  360. }
  361. }
  362. while (s->stream.avail_out != 0) {
  363. if (s->transparent) {
  364. /* Copy first the lookahead bytes: */
  365. uInt n = s->stream.avail_in;
  366. if (n > s->stream.avail_out) n = s->stream.avail_out;
  367. if (n > 0) {
  368. zmemcpy(s->stream.next_out, s->stream.next_in, n);
  369. next_out += n;
  370. s->stream.next_out = next_out;
  371. s->stream.next_in += n;
  372. s->stream.avail_out -= n;
  373. s->stream.avail_in -= n;
  374. }
  375. if (s->stream.avail_out > 0) {
  376. s->stream.avail_out -=
  377. (uInt)fread(next_out, 1, s->stream.avail_out, s->file);
  378. }
  379. len -= s->stream.avail_out;
  380. s->in += len;
  381. s->out += len;
  382. if (len == 0) s->z_eof = 1;
  383. return (int)len;
  384. }
  385. if (s->stream.avail_in == 0 && !s->z_eof) {
  386. errno = 0;
  387. s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
  388. if (s->stream.avail_in == 0) {
  389. s->z_eof = 1;
  390. if (ferror(s->file)) {
  391. s->z_err = Z_ERRNO;
  392. break;
  393. }
  394. }
  395. s->stream.next_in = s->inbuf;
  396. }
  397. s->in += s->stream.avail_in;
  398. s->out += s->stream.avail_out;
  399. s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
  400. s->in -= s->stream.avail_in;
  401. s->out -= s->stream.avail_out;
  402. if (s->z_err == Z_STREAM_END) {
  403. /* Check CRC and original size */
  404. s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
  405. start = s->stream.next_out;
  406. if (getLong(s) != s->crc) {
  407. s->z_err = Z_DATA_ERROR;
  408. } else {
  409. (void)getLong(s);
  410. /* The uncompressed length returned by above getlong() may be
  411. * different from s->out in case of concatenated .gz files.
  412. * Check for such files:
  413. */
  414. check_header(s);
  415. if (s->z_err == Z_OK) {
  416. inflateReset(&(s->stream));
  417. s->crc = crc32(0L, Z_NULL, 0);
  418. }
  419. }
  420. }
  421. if (s->z_err != Z_OK || s->z_eof) break;
  422. }
  423. s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
  424. if (len == s->stream.avail_out &&
  425. (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
  426. return -1;
  427. return (int)(len - s->stream.avail_out);
  428. }
  429. #ifndef NO_GZCOMPRESS
  430. /* ===========================================================================
  431. Writes the given number of uncompressed bytes into the compressed file.
  432. gzwrite returns the number of bytes actually written (0 in case of error).
  433. */
  434. int ZEXPORT gzwrite (file, buf, len)
  435. gzFile file;
  436. voidpc buf;
  437. unsigned len;
  438. {
  439. gz_stream *s = (gz_stream*)file;
  440. if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
  441. s->stream.next_in = (Bytef*)buf;
  442. s->stream.avail_in = len;
  443. while (s->stream.avail_in != 0) {
  444. if (s->stream.avail_out == 0) {
  445. s->stream.next_out = s->outbuf;
  446. if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
  447. s->z_err = Z_ERRNO;
  448. break;
  449. }
  450. s->stream.avail_out = Z_BUFSIZE;
  451. }
  452. s->in += s->stream.avail_in;
  453. s->out += s->stream.avail_out;
  454. s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
  455. s->in -= s->stream.avail_in;
  456. s->out -= s->stream.avail_out;
  457. if (s->z_err != Z_OK) break;
  458. }
  459. s->crc = crc32(s->crc, (const Bytef *)buf, len);
  460. return (int)(len - s->stream.avail_in);
  461. }
  462. /* ===========================================================================
  463. Flushes all pending output into the compressed file. The parameter
  464. flush is as in the deflate() function.
  465. */
  466. local int do_flush (file, flush)
  467. gzFile file;
  468. int flush;
  469. {
  470. uInt len;
  471. int done = 0;
  472. gz_stream *s = (gz_stream*)file;
  473. if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
  474. s->stream.avail_in = 0; /* should be zero already anyway */
  475. for (;;) {
  476. len = Z_BUFSIZE - s->stream.avail_out;
  477. if (len != 0) {
  478. if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
  479. s->z_err = Z_ERRNO;
  480. return Z_ERRNO;
  481. }
  482. s->stream.next_out = s->outbuf;
  483. s->stream.avail_out = Z_BUFSIZE;
  484. }
  485. if (done) break;
  486. s->out += s->stream.avail_out;
  487. s->z_err = deflate(&(s->stream), flush);
  488. s->out -= s->stream.avail_out;
  489. /* Ignore the second of two consecutive flushes: */
  490. if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
  491. /* deflate has finished flushing only when it hasn't used up
  492. * all the available space in the output buffer:
  493. */
  494. done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
  495. if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
  496. }
  497. return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
  498. }
  499. #endif /* NO_GZCOMPRESS */
  500. /* ===========================================================================
  501. Outputs a long in LSB order to the given file
  502. */
  503. local void putLong (file, x)
  504. FILE *file;
  505. uLong x;
  506. {
  507. int n;
  508. for (n = 0; n < 4; n++) {
  509. fputc((int)(x & 0xff), file);
  510. x >>= 8;
  511. }
  512. }
  513. /* ===========================================================================
  514. Reads a long in LSB order from the given gz_stream. Sets z_err in case
  515. of error.
  516. */
  517. local uLong getLong (s)
  518. gz_stream *s;
  519. {
  520. uLong x = (uLong)get_byte(s);
  521. int c;
  522. x += ((uLong)get_byte(s))<<8;
  523. x += ((uLong)get_byte(s))<<16;
  524. c = get_byte(s);
  525. if (c == EOF) s->z_err = Z_DATA_ERROR;
  526. x += ((uLong)c)<<24;
  527. return x;
  528. }
  529. /* ===========================================================================
  530. Flushes all pending output if necessary, closes the compressed file
  531. and deallocates all the (de)compression state.
  532. */
  533. int ZEXPORT gzclose (file)
  534. gzFile file;
  535. {
  536. gz_stream *s = (gz_stream*)file;
  537. if (s == NULL) return Z_STREAM_ERROR;
  538. if (s->mode == 'w') {
  539. #ifdef NO_GZCOMPRESS
  540. return Z_STREAM_ERROR;
  541. #else
  542. if (do_flush (file, Z_FINISH) != Z_OK)
  543. return destroy((gz_stream*)file);
  544. putLong (s->file, s->crc);
  545. putLong (s->file, (uLong)(s->in & 0xffffffff));
  546. #endif
  547. }
  548. return destroy((gz_stream*)file);
  549. }