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