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