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