use actual mmap implementation on windows
[picodrive.git] / zlib / gzio_symb.c
CommitLineData
cc68a136 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
49static 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
59typedef 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
79local gzFile gz_open OF((const char *path, const char *mode, int fd));
80local int do_flush OF((gzFile file, int flush));
81local int get_byte OF((gz_stream *s));
82local void check_header OF((gz_stream *s));
83local int destroy OF((gz_stream *s));
84local void putLong OF((FILE *file, uLong x));
85local 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*/
96local 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*/
211gzFile 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 */
221int 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*/
248local 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*/
275local 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 */
342local 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*/
381int 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*/
491int 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*/
531local 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*/
578local 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*/
593local 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*/
611int 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}