]> git.saurik.com Git - wxWidgets.git/blame - src/zlib/gzio.c
Added chapter on collection and container classes to contents
[wxWidgets.git] / src / zlib / gzio.c
CommitLineData
c801d85f
KB
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
14struct 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
30static 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
40typedef 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
56local gzFile gz_open OF((const char *path, const char *mode, int fd));
57local int do_flush OF((gzFile file, int flush));
58local int get_byte OF((gz_stream *s));
59local void check_header OF((gz_stream *s));
60local int destroy OF((gz_stream *s));
61local void putLong OF((FILE *file, uLong x));
62local 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*/
75bce3ad 73#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
74local gzFile gz_open (const char* path, const char* mode, int fd)
75#else
c801d85f
KB
76local gzFile gz_open (path, mode, fd)
77 const char *path;
78 const char *mode;
79 int fd;
e6ebb514 80#endif
c801d85f
KB
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;
e6ebb514 129
c801d85f
KB
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 }
e6ebb514 180
c801d85f
KB
181 return (gzFile)s;
182}
183
184/* ===========================================================================
185 Opens a gzip (.gz) file for reading or writing.
186*/
75bce3ad 187#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
188gzFile ZEXPORT gzopen (const char* path, const char* mode)
189#else
c801d85f
KB
190gzFile ZEXPORT gzopen (path, mode)
191 const char *path;
192 const char *mode;
e6ebb514 193#endif
c801d85f
KB
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*/
75bce3ad 202#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
203gzFile ZEXPORT gzdopen (int fd, const char* mode)
204#else
c801d85f
KB
205gzFile ZEXPORT gzdopen (fd, mode)
206 int fd;
207 const char *mode;
e6ebb514 208#endif
c801d85f
KB
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 */
75bce3ad 221#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
222int ZEXPORT gzsetparams (gzFile file, int level, int strategy)
223#else
c801d85f
KB
224int ZEXPORT gzsetparams (file, level, strategy)
225 gzFile file;
226 int level;
227 int strategy;
e6ebb514 228#endif
c801d85f
KB
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*/
75bce3ad 252#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
253local int get_byte(gz_stream* s)
254#else
c801d85f
KB
255local int get_byte(s)
256 gz_stream *s;
e6ebb514 257#endif
c801d85f
KB
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*/
75bce3ad 283#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
284local void check_header(gz_stream* s)
285#else
c801d85f
KB
286local void check_header(s)
287 gz_stream *s;
e6ebb514 288#endif
c801d85f
KB
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 */
75bce3ad 340#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
341local int destroy (gz_stream* s)
342#else
c801d85f
KB
343local int destroy (s)
344 gz_stream *s;
e6ebb514 345#endif
c801d85f
KB
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*/
75bce3ad 383#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
384int ZEXPORT gzread (gzFile file, voidp buf, unsigned len)
385#else
c801d85f
KB
386int ZEXPORT gzread (file, buf, len)
387 gzFile file;
388 voidp buf;
389 unsigned len;
e6ebb514 390#endif
c801d85f
KB
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*/
75bce3ad 477#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
478int ZEXPORT gzgetc(gzFile file)
479#else
c801d85f
KB
480int ZEXPORT gzgetc(file)
481 gzFile file;
e6ebb514 482#endif
c801d85f
KB
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*/
75bce3ad 499#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
500char* ZEXPORT gzgets(gzFile file, char* buf, int len)
501#else
c801d85f
KB
502char * ZEXPORT gzgets(file, buf, len)
503 gzFile file;
504 char *buf;
505 int len;
e6ebb514 506#endif
c801d85f
KB
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*/
75bce3ad 522#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
523int ZEXPORT gzwrite (gzFile file, const voidp buf, unsigned len)
524#else
c801d85f
KB
525int ZEXPORT gzwrite (file, buf, len)
526 gzFile file;
527 const voidp buf;
528 unsigned len;
e6ebb514 529#endif
c801d85f
KB
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
565int 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
75bce3ad 585#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
586int 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
c801d85f
KB
590int 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;
e6ebb514 596#endif
c801d85f
KB
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*/
75bce3ad 619#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
620int ZEXPORT gzputc(gzFile file, int c)
621#else
c801d85f
KB
622int ZEXPORT gzputc(file, c)
623 gzFile file;
624 int c;
e6ebb514 625#endif
c801d85f
KB
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*/
75bce3ad 638#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
639int ZEXPORT gzputs(gzFile file, const char* s)
640#else
c801d85f
KB
641int ZEXPORT gzputs(file, s)
642 gzFile file;
643 const char *s;
e6ebb514 644#endif
c801d85f
KB
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*/
75bce3ad 654#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
655local int do_flush (gzFile file, int flush)
656#else
c801d85f
KB
657local int do_flush (file, flush)
658 gzFile file;
659 int flush;
e6ebb514 660#endif
c801d85f
KB
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
e6ebb514 688 * all the available space in the output buffer:
c801d85f
KB
689 */
690 done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
e6ebb514 691
c801d85f
KB
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
75bce3ad 697#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
698int ZEXPORT gzflush (gzFile file, int flush)
699#else
c801d85f
KB
700int ZEXPORT gzflush (file, flush)
701 gzFile file;
702 int flush;
e6ebb514 703#endif
c801d85f
KB
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*/
75bce3ad 722#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
723z_off_t ZEXPORT gzseek (gzFile file, z_off_t offset, int whence)
724#else
c801d85f
KB
725z_off_t ZEXPORT gzseek (file, offset, whence)
726 gzFile file;
727 z_off_t offset;
728 int whence;
e6ebb514 729#endif
c801d85f
KB
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 }
e6ebb514 737
c801d85f
KB
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/* ===========================================================================
e6ebb514 805 Rewinds input file.
c801d85f 806*/
75bce3ad 807#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
808int ZEXPORT gzrewind (gzFile file)
809#else
c801d85f
KB
810int ZEXPORT gzrewind (file)
811 gzFile file;
e6ebb514 812#endif
c801d85f
KB
813{
814 gz_stream *s = (gz_stream*)file;
e6ebb514 815
c801d85f
KB
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*/
75bce3ad 837#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
838z_off_t ZEXPORT gztell (gzFile file)
839#else
c801d85f
KB
840z_off_t ZEXPORT gztell (file)
841 gzFile file;
e6ebb514 842#endif
c801d85f
KB
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*/
75bce3ad 851#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
852int ZEXPORT gzeof (gzFile file)
853#else
c801d85f
KB
854int ZEXPORT gzeof (file)
855 gzFile file;
e6ebb514 856#endif
c801d85f
KB
857{
858 gz_stream *s = (gz_stream*)file;
e6ebb514 859
c801d85f
KB
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*/
75bce3ad 866#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
867local void putLong (FILE* file, uLong x)
868#else
c801d85f
KB
869local void putLong (file, x)
870 FILE *file;
871 uLong x;
e6ebb514 872#endif
c801d85f
KB
873{
874 int n;
875 for (n = 0; n < 4; n++) {
876 fputc((int)(x & 0xff), file);
877 x >>= 8;
878 }
879}
880
881/* ===========================================================================
e6ebb514 882 Reads a long in LSB order from the given gz_stream. Sets
c801d85f 883*/
75bce3ad 884#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
885local uLong getLong (gz_stream* s)
886#else
c801d85f
KB
887local uLong getLong (s)
888 gz_stream *s;
e6ebb514 889#endif
c801d85f
KB
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*/
75bce3ad 906#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
907int ZEXPORT gzclose (gzFile file)
908#else
c801d85f
KB
909int ZEXPORT gzclose (file)
910 gzFile file;
e6ebb514 911#endif
c801d85f
KB
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*/
75bce3ad 939#if defined(__VISAGECPP__) /* Visualage can't handle this antiquated interface */
e6ebb514
DW
940const char* ZEXPORT gzerror (gzFile file, int* errnum)
941#else
c801d85f
KB
942const char* ZEXPORT gzerror (file, errnum)
943 gzFile file;
944 int *errnum;
e6ebb514 945#endif
c801d85f
KB
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}