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