more input layer tweaks
[picodrive.git] / zlib / gzio_symb.c
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 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <errno.h>
14
15 //#include "zutil.h"
16 #include <EZlib.h>
17 #include "gzio_symb.h"
18
19 #ifndef Z_BUFSIZE
20 #  ifdef MAXSEG_64K
21 #    define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
22 #  else
23 #    define Z_BUFSIZE 16384
24 #  endif
25 #endif
26
27 #ifndef local
28 #  define local static
29 #endif
30
31 #ifndef OS_CODE
32 #  define OS_CODE  0x03  /* assume Unix */
33 #endif
34
35 #ifndef F_OPEN
36 #  define F_OPEN(name, mode) fopen((name), (mode))
37 #endif
38
39 #if MAX_MEM_LEVEL >= 8
40 #  define DEF_MEM_LEVEL 8
41 #else
42 #  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
43 #endif
44
45 #define ALLOC(size) malloc(size)
46 #define TRYFREE(p) {if (p) free(p);}
47 #define zmemcpy memcpy
48
49 static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
50
51 /* gzip flag byte */
52 #define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
53 #define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
54 #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
55 #define ORIG_NAME    0x08 /* bit 3 set: original file name present */
56 #define COMMENT      0x10 /* bit 4 set: file comment present */
57 #define RESERVED     0xE0 /* bits 5..7: reserved */
58
59 typedef struct gz_stream {
60     z_stream stream;
61     int      z_err;   /* error code for last stream operation */
62     int      z_eof;   /* set if end of input file */
63     FILE     *file;   /* .gz file */
64     Byte     *inbuf;  /* input buffer */
65     Byte     *outbuf; /* output buffer */
66     uLong    crc;     /* crc32 of uncompressed data */
67     char     *msg;    /* error message */
68     char     *path;   /* path name for debugging only */
69     int      transparent; /* 1 if input file is not a .gz file */
70     char     mode;    /* 'w' or 'r' */
71     z_off_t  start;   /* start of compressed data in file (header skipped) */
72     z_off_t  in;      /* bytes into deflate or inflate */
73     z_off_t  out;     /* bytes out of deflate or inflate */
74     int      back;    /* one character push-back */
75     int      last;    /* true if push-back is last character */
76 } gz_stream;
77
78
79 local gzFile gz_open      OF((const char *path, const char *mode, int  fd));
80 local int do_flush        OF((gzFile file, int flush));
81 local int    get_byte     OF((gz_stream *s));
82 local void   check_header OF((gz_stream *s));
83 local int    destroy      OF((gz_stream *s));
84 local void   putLong      OF((FILE *file, uLong x));
85 local uLong  getLong      OF((gz_stream *s));
86
87 /* ===========================================================================
88      Opens a gzip (.gz) file for reading or writing. The mode parameter
89    is as in fopen ("rb" or "wb"). The file is given either by file descriptor
90    or path name (if fd == -1).
91      gz_open returns NULL if the file could not be opened or if there was
92    insufficient memory to allocate the (de)compression state; errno
93    can be checked to distinguish the two cases (if errno is zero, the
94    zlib error is Z_MEM_ERROR).
95 */
96 local gzFile gz_open (path, mode, fd)
97     const char *path;
98     const char *mode;
99     int  fd;
100 {
101     int err;
102     int level = Z_DEFAULT_COMPRESSION; /* compression level */
103     int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
104     char *p = (char*)mode;
105     gz_stream *s;
106     char fmode[80]; /* copy of mode, without the compression level */
107     char *m = fmode;
108
109     if (!path || !mode) return Z_NULL;
110
111     s = (gz_stream *)ALLOC(sizeof(gz_stream));
112     if (!s) return Z_NULL;
113
114     s->stream.zalloc = (alloc_func)0;
115     s->stream.zfree = (free_func)0;
116     s->stream.opaque = (voidpf)0;
117     s->stream.next_in = s->inbuf = Z_NULL;
118     s->stream.next_out = s->outbuf = Z_NULL;
119     s->stream.avail_in = s->stream.avail_out = 0;
120     s->file = NULL;
121     s->z_err = Z_OK;
122     s->z_eof = 0;
123     s->in = 0;
124     s->out = 0;
125     s->back = EOF;
126     s->crc = crc32(0L, Z_NULL, 0);
127     s->msg = NULL;
128     s->transparent = 0;
129
130     s->path = (char*)ALLOC(strlen(path)+1);
131     if (s->path == NULL) {
132         return destroy(s), (gzFile)Z_NULL;
133     }
134     strcpy(s->path, path); /* do this early for debugging */
135
136     s->mode = '\0';
137     do {
138         if (*p == 'r') s->mode = 'r';
139         if (*p == 'w' || *p == 'a') s->mode = 'w';
140         if (*p >= '0' && *p <= '9') {
141             level = *p - '0';
142         } else if (*p == 'f') {
143           strategy = Z_FILTERED;
144         } else if (*p == 'h') {
145           strategy = Z_HUFFMAN_ONLY;
146         } else if (*p == 'R') {
147           strategy = Z_RLE;
148         } else {
149             *m++ = *p; /* copy the mode */
150         }
151     } while (*p++ && m != fmode + sizeof(fmode));
152     if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
153
154     if (s->mode == 'w') {
155 #ifdef NO_GZCOMPRESS
156         err = Z_STREAM_ERROR;
157 #else
158         err = deflateInit2(&(s->stream), level,
159                            Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
160         /* windowBits is passed < 0 to suppress zlib header */
161
162         s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
163 #endif
164         if (err != Z_OK || s->outbuf == Z_NULL) {
165             return destroy(s), (gzFile)Z_NULL;
166         }
167     } else {
168         s->stream.next_in  = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
169
170         err = inflateInit2(&(s->stream), -MAX_WBITS);
171         /* windowBits is passed < 0 to tell that there is no zlib header.
172          * Note that in this case inflate *requires* an extra "dummy" byte
173          * after the compressed stream in order to complete decompression and
174          * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
175          * present after the compressed stream.
176          */
177         if (err != Z_OK || s->inbuf == Z_NULL) {
178             return destroy(s), (gzFile)Z_NULL;
179         }
180     }
181     s->stream.avail_out = Z_BUFSIZE;
182
183     errno = 0;
184     s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
185
186     if (s->file == NULL) {
187         return destroy(s), (gzFile)Z_NULL;
188     }
189     if (s->mode == 'w') {
190         /* Write a very simple .gz header:
191          */
192         fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
193              Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
194         s->start = 10L;
195         /* We use 10L instead of ftell(s->file) to because ftell causes an
196          * fflush on some systems. This version of the library doesn't use
197          * start anyway in write mode, so this initialization is not
198          * necessary.
199          */
200     } else {
201         check_header(s); /* skip the .gz header */
202         s->start = ftell(s->file) - s->stream.avail_in;
203     }
204
205     return (gzFile)s;
206 }
207
208 /* ===========================================================================
209      Opens a gzip (.gz) file for reading or writing.
210 */
211 gzFile ZEXPORT gzopen (path, mode)
212     const char *path;
213     const char *mode;
214 {
215     return gz_open (path, mode, -1);
216 }
217
218 /* ===========================================================================
219  * Update the compression level and strategy
220  */
221 int ZEXPORT gzsetparams (file, level, strategy)
222     gzFile file;
223     int level;
224     int strategy;
225 {
226     gz_stream *s = (gz_stream*)file;
227
228     if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
229
230     /* Make room to allow flushing */
231     if (s->stream.avail_out == 0) {
232
233         s->stream.next_out = s->outbuf;
234         if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
235             s->z_err = Z_ERRNO;
236         }
237         s->stream.avail_out = Z_BUFSIZE;
238     }
239
240     return deflateParams (&(s->stream), level, strategy);
241 }
242
243 /* ===========================================================================
244      Read a byte from a gz_stream; update next_in and avail_in. Return EOF
245    for end of file.
246    IN assertion: the stream s has been sucessfully opened for reading.
247 */
248 local int get_byte(s)
249     gz_stream *s;
250 {
251     if (s->z_eof) return EOF;
252     if (s->stream.avail_in == 0) {
253         errno = 0;
254         s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
255         if (s->stream.avail_in == 0) {
256             s->z_eof = 1;
257             if (ferror(s->file)) s->z_err = Z_ERRNO;
258             return EOF;
259         }
260         s->stream.next_in = s->inbuf;
261     }
262     s->stream.avail_in--;
263     return *(s->stream.next_in)++;
264 }
265
266 /* ===========================================================================
267       Check the gzip header of a gz_stream opened for reading. Set the stream
268     mode to transparent if the gzip magic header is not present; set s->err
269     to Z_DATA_ERROR if the magic header is present but the rest of the header
270     is incorrect.
271     IN assertion: the stream s has already been created sucessfully;
272        s->stream.avail_in is zero for the first time, but may be non-zero
273        for concatenated .gz files.
274 */
275 local void check_header(s)
276     gz_stream *s;
277 {
278     int method; /* method byte */
279     int flags;  /* flags byte */
280     uInt len;
281     int c;
282
283     /* Assure two bytes in the buffer so we can peek ahead -- handle case
284        where first byte of header is at the end of the buffer after the last
285        gzip segment */
286     len = s->stream.avail_in;
287     if (len < 2) {
288         if (len) s->inbuf[0] = s->stream.next_in[0];
289         errno = 0;
290         len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file);
291         if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO;
292         s->stream.avail_in += len;
293         s->stream.next_in = s->inbuf;
294         if (s->stream.avail_in < 2) {
295             s->transparent = s->stream.avail_in;
296             return;
297         }
298     }
299
300     /* Peek ahead to check the gzip magic header */
301     if (s->stream.next_in[0] != gz_magic[0] ||
302         s->stream.next_in[1] != gz_magic[1]) {
303         s->transparent = 1;
304         return;
305     }
306     s->stream.avail_in -= 2;
307     s->stream.next_in += 2;
308
309     /* Check the rest of the gzip header */
310     method = get_byte(s);
311     flags = get_byte(s);
312     if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
313         s->z_err = Z_DATA_ERROR;
314         return;
315     }
316
317     /* Discard time, xflags and OS code: */
318     for (len = 0; len < 6; len++) (void)get_byte(s);
319
320     if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
321         len  =  (uInt)get_byte(s);
322         len += ((uInt)get_byte(s))<<8;
323         /* len is garbage if EOF but the loop below will quit anyway */
324         while (len-- != 0 && get_byte(s) != EOF) ;
325     }
326     if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
327         while ((c = get_byte(s)) != 0 && c != EOF) ;
328     }
329     if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */
330         while ((c = get_byte(s)) != 0 && c != EOF) ;
331     }
332     if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
333         for (len = 0; len < 2; len++) (void)get_byte(s);
334     }
335     s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
336 }
337
338  /* ===========================================================================
339  * Cleanup then free the given gz_stream. Return a zlib error code.
340    Try freeing in the reverse order of allocations.
341  */
342 local int destroy (s)
343     gz_stream *s;
344 {
345     int err = Z_OK;
346
347     if (!s) return Z_STREAM_ERROR;
348
349     TRYFREE(s->msg);
350
351     if (s->stream.state != NULL) {
352         if (s->mode == 'w') {
353 #ifdef NO_GZCOMPRESS
354             err = Z_STREAM_ERROR;
355 #else
356             err = deflateEnd(&(s->stream));
357 #endif
358         } else if (s->mode == 'r') {
359             err = inflateEnd(&(s->stream));
360         }
361     }
362     if (s->file != NULL && fclose(s->file)) {
363 #ifdef ESPIPE
364         if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
365 #endif
366             err = Z_ERRNO;
367     }
368     if (s->z_err < 0) err = s->z_err;
369
370     TRYFREE(s->inbuf);
371     TRYFREE(s->outbuf);
372     TRYFREE(s->path);
373     TRYFREE(s);
374     return err;
375 }
376
377 /* ===========================================================================
378      Reads the given number of uncompressed bytes from the compressed file.
379    gzread returns the number of bytes actually read (0 for end of file).
380 */
381 int ZEXPORT gzread (file, buf, len)
382     gzFile file;
383     voidp buf;
384     unsigned len;
385 {
386     gz_stream *s = (gz_stream*)file;
387     Bytef *start = (Bytef*)buf; /* starting point for crc computation */
388     Byte  *next_out; /* == stream.next_out but not forced far (for MSDOS) */
389
390     if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
391
392     if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
393     if (s->z_err == Z_STREAM_END) return 0;  /* EOF */
394
395     next_out = (Byte*)buf;
396     s->stream.next_out = (Bytef*)buf;
397     s->stream.avail_out = len;
398
399     if (s->stream.avail_out && s->back != EOF) {
400         *next_out++ = s->back;
401         s->stream.next_out++;
402         s->stream.avail_out--;
403         s->back = EOF;
404         s->out++;
405         start++;
406         if (s->last) {
407             s->z_err = Z_STREAM_END;
408             return 1;
409         }
410     }
411
412     while (s->stream.avail_out != 0) {
413
414         if (s->transparent) {
415             /* Copy first the lookahead bytes: */
416             uInt n = s->stream.avail_in;
417             if (n > s->stream.avail_out) n = s->stream.avail_out;
418             if (n > 0) {
419                 zmemcpy(s->stream.next_out, s->stream.next_in, n);
420                 next_out += n;
421                 s->stream.next_out = next_out;
422                 s->stream.next_in   += n;
423                 s->stream.avail_out -= n;
424                 s->stream.avail_in  -= n;
425             }
426             if (s->stream.avail_out > 0) {
427                 s->stream.avail_out -=
428                     (uInt)fread(next_out, 1, s->stream.avail_out, s->file);
429             }
430             len -= s->stream.avail_out;
431             s->in  += len;
432             s->out += len;
433             if (len == 0) s->z_eof = 1;
434             return (int)len;
435         }
436         if (s->stream.avail_in == 0 && !s->z_eof) {
437
438             errno = 0;
439             s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
440             if (s->stream.avail_in == 0) {
441                 s->z_eof = 1;
442                 if (ferror(s->file)) {
443                     s->z_err = Z_ERRNO;
444                     break;
445                 }
446             }
447             s->stream.next_in = s->inbuf;
448         }
449         s->in += s->stream.avail_in;
450         s->out += s->stream.avail_out;
451         s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
452         s->in -= s->stream.avail_in;
453         s->out -= s->stream.avail_out;
454
455         if (s->z_err == Z_STREAM_END) {
456             /* Check CRC and original size */
457             s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
458             start = s->stream.next_out;
459
460             if (getLong(s) != s->crc) {
461                 s->z_err = Z_DATA_ERROR;
462             } else {
463                 (void)getLong(s);
464                 /* The uncompressed length returned by above getlong() may be
465                  * different from s->out in case of concatenated .gz files.
466                  * Check for such files:
467                  */
468                 check_header(s);
469                 if (s->z_err == Z_OK) {
470                     inflateReset(&(s->stream));
471                     s->crc = crc32(0L, Z_NULL, 0);
472                 }
473             }
474         }
475         if (s->z_err != Z_OK || s->z_eof) break;
476     }
477     s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
478
479     if (len == s->stream.avail_out &&
480         (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
481         return -1;
482     return (int)(len - s->stream.avail_out);
483 }
484
485
486 #ifndef NO_GZCOMPRESS
487 /* ===========================================================================
488      Writes the given number of uncompressed bytes into the compressed file.
489    gzwrite returns the number of bytes actually written (0 in case of error).
490 */
491 int ZEXPORT gzwrite (file, buf, len)
492     gzFile file;
493     voidpc buf;
494     unsigned len;
495 {
496     gz_stream *s = (gz_stream*)file;
497
498     if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
499
500     s->stream.next_in = (Bytef*)buf;
501     s->stream.avail_in = len;
502
503     while (s->stream.avail_in != 0) {
504
505         if (s->stream.avail_out == 0) {
506
507             s->stream.next_out = s->outbuf;
508             if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
509                 s->z_err = Z_ERRNO;
510                 break;
511             }
512             s->stream.avail_out = Z_BUFSIZE;
513         }
514         s->in += s->stream.avail_in;
515         s->out += s->stream.avail_out;
516         s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
517         s->in -= s->stream.avail_in;
518         s->out -= s->stream.avail_out;
519         if (s->z_err != Z_OK) break;
520     }
521     s->crc = crc32(s->crc, (const Bytef *)buf, len);
522
523     return (int)(len - s->stream.avail_in);
524 }
525
526
527 /* ===========================================================================
528      Flushes all pending output into the compressed file. The parameter
529    flush is as in the deflate() function.
530 */
531 local int do_flush (file, flush)
532     gzFile file;
533     int flush;
534 {
535     uInt len;
536     int done = 0;
537     gz_stream *s = (gz_stream*)file;
538
539     if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
540
541     s->stream.avail_in = 0; /* should be zero already anyway */
542
543     for (;;) {
544         len = Z_BUFSIZE - s->stream.avail_out;
545
546         if (len != 0) {
547             if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
548                 s->z_err = Z_ERRNO;
549                 return Z_ERRNO;
550             }
551             s->stream.next_out = s->outbuf;
552             s->stream.avail_out = Z_BUFSIZE;
553         }
554         if (done) break;
555         s->out += s->stream.avail_out;
556         s->z_err = deflate(&(s->stream), flush);
557         s->out -= s->stream.avail_out;
558
559         /* Ignore the second of two consecutive flushes: */
560         if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
561
562         /* deflate has finished flushing only when it hasn't used up
563          * all the available space in the output buffer:
564          */
565         done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
566
567         if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
568     }
569     return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
570 }
571
572 #endif /* NO_GZCOMPRESS */
573
574
575 /* ===========================================================================
576    Outputs a long in LSB order to the given file
577 */
578 local void putLong (file, x)
579     FILE *file;
580     uLong x;
581 {
582     int n;
583     for (n = 0; n < 4; n++) {
584         fputc((int)(x & 0xff), file);
585         x >>= 8;
586     }
587 }
588
589 /* ===========================================================================
590    Reads a long in LSB order from the given gz_stream. Sets z_err in case
591    of error.
592 */
593 local uLong getLong (s)
594     gz_stream *s;
595 {
596     uLong x = (uLong)get_byte(s);
597     int c;
598
599     x += ((uLong)get_byte(s))<<8;
600     x += ((uLong)get_byte(s))<<16;
601     c = get_byte(s);
602     if (c == EOF) s->z_err = Z_DATA_ERROR;
603     x += ((uLong)c)<<24;
604     return x;
605 }
606
607 /* ===========================================================================
608      Flushes all pending output if necessary, closes the compressed file
609    and deallocates all the (de)compression state.
610 */
611 int ZEXPORT gzclose (file)
612     gzFile file;
613 {
614     gz_stream *s = (gz_stream*)file;
615
616     if (s == NULL) return Z_STREAM_ERROR;
617
618     if (s->mode == 'w') {
619 #ifdef NO_GZCOMPRESS
620         return Z_STREAM_ERROR;
621 #else
622         if (do_flush (file, Z_FINISH) != Z_OK)
623             return destroy((gz_stream*)file);
624
625         putLong (s->file, s->crc);
626         putLong (s->file, (uLong)(s->in & 0xffffffff));
627 #endif
628     }
629     return destroy((gz_stream*)file);
630 }