]> 4ch.mooo.com Git - 16.git/blob - src/lib/doslib/ext/zlib/gzread.c
4cf8877f00423eaf0e6ff3fcc12f51bca7bba3e0
[16.git] / src / lib / doslib / ext / zlib / gzread.c
1 /* gzread.c -- zlib functions for reading gzip files
2  * Copyright (C) 2004, 2005, 2010 Mark Adler
3  * For conditions of distribution and use, see copyright notice in zlib.h
4  */
5
6 #include "gzguts.h"
7 #include "zutil.h"
8
9 #if TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__MEDIUM__))
10 #include <dos.h>
11 #include <i86.h>
12 #endif
13
14 /* Local functions */
15 local int gz_load OF((gz_statep, voidpf, unsigned, unsigned *));
16 local int gz_avail OF((gz_statep));
17 local int gz_next4 OF((gz_statep, unsigned long *));
18 local int gz_head OF((gz_statep));
19 local int gz_decomp OF((gz_statep));
20 local int gz_make OF((gz_statep));
21 local int gz_skip OF((gz_statep, z_off64_t));
22
23 /* Use read() to load a buffer -- return -1 on error, otherwise 0.  Read from
24    state->fd, and update state->eof, state->err, and state->msg as appropriate.
25    This function needs to loop on read(), since read() is not guaranteed to
26    read the number of bytes requested, depending on the type of descriptor. */
27 local int gz_load(state, buf, len, have)
28     gz_statep state;
29     voidpf buf;
30     unsigned len;
31     unsigned *have;
32 {
33     int ret;
34
35     *have = 0;
36     do {
37 #if TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__MEDIUM__))
38         ret = -1;
39         if (_dos_read(state->fd, (unsigned char FAR*)buf + *have, len - *have, (unsigned*)(&ret)) != 0 || ret == 0)
40             break;
41 #else
42         ret = read(state->fd, (unsigned char*)buf + *have, len - *have);
43 #endif
44         if (ret <= 0)
45             break;
46         *have += ret;
47     } while (*have < len);
48     if (ret < 0) {
49         gz_error(state, Z_ERRNO, zstrerror());
50         return -1;
51     }
52     if (ret == 0)
53         state->eof = 1;
54
55     return 0;
56 }
57
58 /* Load up input buffer and set eof flag if last data loaded -- return -1 on
59    error, 0 otherwise.  Note that the eof flag is set when the end of the input
60    file is reached, even though there may be unused data in the buffer.  Once
61    that data has been used, no more attempts will be made to read the file.
62    gz_avail() assumes that strm->avail_in == 0. */
63 local int gz_avail(state)
64     gz_statep state;
65 {
66     z_streamp strm = &(state->strm);
67
68     if (state->err != Z_OK)
69         return -1;
70     if (state->eof == 0) {
71         if (gz_load(state, state->in, state->size,
72                 (unsigned *)&(strm->avail_in)) == -1)
73             return -1;
74         strm->next_in = state->in;
75     }
76     return 0;
77 }
78
79 /* Get next byte from input, or -1 if end or error. */
80 #define NEXT() ((strm->avail_in == 0 && gz_avail(state) == -1) ? -1 : \
81                 (strm->avail_in == 0 ? -1 : \
82                  (strm->avail_in--, *(strm->next_in)++)))
83
84 /* Get a four-byte little-endian integer and return 0 on success and the value
85    in *ret.  Otherwise -1 is returned and *ret is not modified. */
86 local int gz_next4(state, ret)
87     gz_statep state;
88     unsigned long *ret;
89 {
90     int ch;
91     unsigned long val;
92     z_streamp strm = &(state->strm);
93
94     val = NEXT();
95     val += (unsigned)NEXT() << 8;
96     val += (unsigned long)NEXT() << 16;
97     ch = NEXT();
98     if (ch == -1)
99         return -1;
100     val += (unsigned long)ch << 24;
101     *ret = val;
102     return 0;
103 }
104
105 /* Look for gzip header, set up for inflate or copy.  state->have must be zero.
106    If this is the first time in, allocate required memory.  state->how will be
107    left unchanged if there is no more input data available, will be set to COPY
108    if there is no gzip header and direct copying will be performed, or it will
109    be set to GZIP for decompression, and the gzip header will be skipped so
110    that the next available input data is the raw deflate stream.  If direct
111    copying, then leftover input data from the input buffer will be copied to
112    the output buffer.  In that case, all further file reads will be directly to
113    either the output buffer or a user buffer.  If decompressing, the inflate
114    state and the check value will be initialized.  gz_head() will return 0 on
115    success or -1 on failure.  Failures may include read errors or gzip header
116    errors.  */
117 local int gz_head(state)
118     gz_statep state;
119 {
120     z_streamp strm = &(state->strm);
121     int flags;
122     unsigned len;
123
124     /* allocate read buffers and inflate memory */
125     if (state->size == 0) {
126         /* allocate buffers */
127 #if TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__MEDIUM__))
128         state->in = _fmalloc(state->want);
129         state->out = _fmalloc(state->want << 1);
130 #else
131         state->in = malloc(state->want);
132         state->out = malloc(state->want << 1);
133 #endif
134         if (state->in == NULL || state->out == NULL) {
135 #if TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__MEDIUM__))
136             if (state->out != NULL)
137                 _ffree(state->out);
138             if (state->in != NULL)
139                 _ffree(state->in);
140 #else
141             if (state->out != NULL)
142                 free(state->out);
143             if (state->in != NULL)
144                 free(state->in);
145 #endif
146             gz_error(state, Z_MEM_ERROR, "out of memory");
147             return -1;
148         }
149         state->size = state->want;
150
151         /* allocate inflate memory */
152         state->strm.zalloc = Z_NULL;
153         state->strm.zfree = Z_NULL;
154         state->strm.opaque = Z_NULL;
155         state->strm.avail_in = 0;
156         state->strm.next_in = Z_NULL;
157         if (inflateInit2(&(state->strm), -15) != Z_OK) {    /* raw inflate */
158 #if TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__MEDIUM__))
159             _ffree(state->out);
160             _ffree(state->in);
161 #else
162             free(state->out);
163             free(state->in);
164 #endif
165             state->size = 0;
166             gz_error(state, Z_MEM_ERROR, "out of memory");
167             return -1;
168         }
169     }
170
171     /* get some data in the input buffer */
172     if (strm->avail_in == 0) {
173         if (gz_avail(state) == -1)
174             return -1;
175         if (strm->avail_in == 0)
176             return 0;
177     }
178
179     /* look for the gzip magic header bytes 31 and 139 */
180     if (strm->next_in[0] == 31) {
181         strm->avail_in--;
182         strm->next_in++;
183         if (strm->avail_in == 0 && gz_avail(state) == -1)
184             return -1;
185         if (strm->avail_in && strm->next_in[0] == 139) {
186             /* we have a gzip header, woo hoo! */
187             strm->avail_in--;
188             strm->next_in++;
189
190             /* skip rest of header */
191             if (NEXT() != 8) {      /* compression method */
192                 gz_error(state, Z_DATA_ERROR, "unknown compression method");
193                 return -1;
194             }
195             flags = NEXT();
196             if (flags & 0xe0) {     /* reserved flag bits */
197                 gz_error(state, Z_DATA_ERROR, "unknown header flags set");
198                 return -1;
199             }
200             NEXT();                 /* modification time */
201             NEXT();
202             NEXT();
203             NEXT();
204             NEXT();                 /* extra flags */
205             NEXT();                 /* operating system */
206             if (flags & 4) {        /* extra field */
207                 len = (unsigned)NEXT();
208                 len += (unsigned)NEXT() << 8;
209                 while (len--)
210                     if (NEXT() < 0)
211                         break;
212             }
213             if (flags & 8)          /* file name */
214                 while (NEXT() > 0)
215                     ;
216             if (flags & 16)         /* comment */
217                 while (NEXT() > 0)
218                     ;
219             if (flags & 2) {        /* header crc */
220                 NEXT();
221                 NEXT();
222             }
223             /* an unexpected end of file is not checked for here -- it will be
224                noticed on the first request for uncompressed data */
225
226             /* set up for decompression */
227             inflateReset(strm);
228             strm->adler = crc32(0L, Z_NULL, 0);
229             state->how = GZIP;
230             state->direct = 0;
231             return 0;
232         }
233         else {
234             /* not a gzip file -- save first byte (31) and fall to raw i/o */
235             state->out[0] = 31;
236             state->have = 1;
237         }
238     }
239
240     /* doing raw i/o, save start of raw data for seeking, copy any leftover
241        input to output -- this assumes that the output buffer is larger than
242        the input buffer, which also assures space for gzungetc() */
243     state->raw = state->pos;
244     state->next = state->out;
245     if (strm->avail_in) {
246         zmemcpy(state->next + state->have, strm->next_in, strm->avail_in);
247         state->have += strm->avail_in;
248         strm->avail_in = 0;
249     }
250     state->how = COPY;
251     state->direct = 1;
252     return 0;
253 }
254
255 /* Decompress from input to the provided next_out and avail_out in the state.
256    If the end of the compressed data is reached, then verify the gzip trailer
257    check value and length (modulo 2^32).  state->have and state->next are set
258    to point to the just decompressed data, and the crc is updated.  If the
259    trailer is verified, state->how is reset to LOOK to look for the next gzip
260    stream or raw data, once state->have is depleted.  Returns 0 on success, -1
261    on failure.  Failures may include invalid compressed data or a failed gzip
262    trailer verification. */
263 local int gz_decomp(state)
264     gz_statep state;
265 {
266     int ret;
267     unsigned had;
268     unsigned long crc, len;
269     z_streamp strm = &(state->strm);
270
271     /* fill output buffer up to end of deflate stream */
272     had = strm->avail_out;
273     do {
274         /* get more input for inflate() */
275         if (strm->avail_in == 0 && gz_avail(state) == -1)
276             return -1;
277         if (strm->avail_in == 0) {
278             gz_error(state, Z_DATA_ERROR, "unexpected end of file");
279             return -1;
280         }
281
282         /* decompress and handle errors */
283         ret = inflate(strm, Z_NO_FLUSH);
284         if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
285             gz_error(state, Z_STREAM_ERROR,
286                       "internal error: inflate stream corrupt");
287             return -1;
288         }
289         if (ret == Z_MEM_ERROR) {
290             gz_error(state, Z_MEM_ERROR, "out of memory");
291             return -1;
292         }
293         if (ret == Z_DATA_ERROR) {              /* deflate stream invalid */
294             gz_error(state, Z_DATA_ERROR,
295                       strm->msg == NULL ? "compressed data error" : strm->msg);
296             return -1;
297         }
298     } while (strm->avail_out && ret != Z_STREAM_END);
299
300     /* update available output and crc check value */
301     state->have = had - strm->avail_out;
302     state->next = strm->next_out - state->have;
303     strm->adler = crc32(strm->adler, state->next, state->have);
304
305     /* check gzip trailer if at end of deflate stream */
306     if (ret == Z_STREAM_END) {
307         if (gz_next4(state, &crc) == -1 || gz_next4(state, &len) == -1) {
308             gz_error(state, Z_DATA_ERROR, "unexpected end of file");
309             return -1;
310         }
311         if (crc != strm->adler) {
312             gz_error(state, Z_DATA_ERROR, "incorrect data check");
313             return -1;
314         }
315         if (len != (strm->total_out & 0xffffffffL)) {
316             gz_error(state, Z_DATA_ERROR, "incorrect length check");
317             return -1;
318         }
319         state->how = LOOK;      /* ready for next stream, once have is 0 (leave
320                                    state->direct unchanged to remember how) */
321     }
322
323     /* good decompression */
324     return 0;
325 }
326
327 /* Make data and put in the output buffer.  Assumes that state->have == 0.
328    Data is either copied from the input file or decompressed from the input
329    file depending on state->how.  If state->how is LOOK, then a gzip header is
330    looked for (and skipped if found) to determine wither to copy or decompress.
331    Returns -1 on error, otherwise 0.  gz_make() will leave state->have as COPY
332    or GZIP unless the end of the input file has been reached and all data has
333    been processed.  */
334 local int gz_make(state)
335     gz_statep state;
336 {
337     z_streamp strm = &(state->strm);
338
339     if (state->how == LOOK) {           /* look for gzip header */
340         if (gz_head(state) == -1)
341             return -1;
342         if (state->have)                /* got some data from gz_head() */
343             return 0;
344     }
345     if (state->how == COPY) {           /* straight copy */
346         if (gz_load(state, state->out, state->size << 1, &(state->have)) == -1)
347             return -1;
348         state->next = state->out;
349     }
350     else if (state->how == GZIP) {      /* decompress */
351         strm->avail_out = state->size << 1;
352         strm->next_out = state->out;
353         if (gz_decomp(state) == -1)
354             return -1;
355     }
356     return 0;
357 }
358
359 /* Skip len uncompressed bytes of output.  Return -1 on error, 0 on success. */
360 local int gz_skip(state, len)
361     gz_statep state;
362     z_off64_t len;
363 {
364     unsigned n;
365
366     /* skip over len bytes or reach end-of-file, whichever comes first */
367     while (len)
368         /* skip over whatever is in output buffer */
369         if (state->have) {
370             n = GT_OFF(state->have) || (z_off64_t)state->have > len ?
371                 (unsigned)len : state->have;
372             state->have -= n;
373             state->next += n;
374             state->pos += n;
375             len -= n;
376         }
377
378         /* output buffer empty -- return if we're at the end of the input */
379         else if (state->eof && state->strm.avail_in == 0)
380             break;
381
382         /* need more data to skip -- load up output buffer */
383         else {
384             /* get more output, looking for header if required */
385             if (gz_make(state) == -1)
386                 return -1;
387         }
388     return 0;
389 }
390
391 /* -- see zlib.h -- */
392 int ZEXPORT gzread(file, buf, len)
393     gzFile file;
394     voidpf buf;
395     unsigned len;
396 {
397     unsigned got, n;
398     gz_statep state;
399     z_streamp strm;
400
401     /* get internal structure */
402     if (file == NULL)
403         return -1;
404     state = (gz_statep)file;
405     strm = &(state->strm);
406
407     /* check that we're reading and that there's no error */
408     if (state->mode != GZ_READ || state->err != Z_OK)
409         return -1;
410
411     /* since an int is returned, make sure len fits in one, otherwise return
412        with an error (this avoids the flaw in the interface) */
413     if ((int)len < 0) {
414         gz_error(state, Z_BUF_ERROR, "requested length does not fit in int");
415         return -1;
416     }
417
418     /* if len is zero, avoid unnecessary operations */
419     if (len == 0)
420         return 0;
421
422     /* process a skip request */
423     if (state->seek) {
424         state->seek = 0;
425         if (gz_skip(state, state->skip) == -1)
426             return -1;
427     }
428
429     /* get len bytes to buf, or less than len if at the end */
430     got = 0;
431     do {
432         /* first just try copying data from the output buffer */
433         if (state->have) {
434             n = state->have > len ? len : state->have;
435             zmemcpy(buf, state->next, n);
436             state->next += n;
437             state->have -= n;
438         }
439
440         /* output buffer empty -- return if we're at the end of the input */
441         else if (state->eof && strm->avail_in == 0)
442             break;
443
444         /* need output data -- for small len or new stream load up our output
445            buffer */
446         else if (state->how == LOOK || len < (state->size << 1)) {
447             /* get more output, looking for header if required */
448             if (gz_make(state) == -1)
449                 return -1;
450             continue;       /* no progress yet -- go back to memcpy() above */
451             /* the copy above assures that we will leave with space in the
452                output buffer, allowing at least one gzungetc() to succeed */
453         }
454
455         /* large len -- read directly into user buffer */
456         else if (state->how == COPY) {      /* read directly */
457             if (gz_load(state, buf, len, &n) == -1)
458                 return -1;
459         }
460
461         /* large len -- decompress directly into user buffer */
462         else {  /* state->how == GZIP */
463             strm->avail_out = len;
464             strm->next_out = buf;
465             if (gz_decomp(state) == -1)
466                 return -1;
467             n = state->have;
468             state->have = 0;
469         }
470
471         /* update progress */
472         len -= n;
473         buf = (char FAR *)buf + n;
474         got += n;
475         state->pos += n;
476     } while (len);
477
478     /* return number of bytes read into user buffer (will fit in int) */
479     return (int)got;
480 }
481
482 /* -- see zlib.h -- */
483 int ZEXPORT gzgetc(file)
484     gzFile file;
485 {
486     int ret;
487     unsigned char buf[1];
488     gz_statep state;
489
490     /* get internal structure */
491     if (file == NULL)
492         return -1;
493     state = (gz_statep)file;
494
495     /* check that we're reading and that there's no error */
496     if (state->mode != GZ_READ || state->err != Z_OK)
497         return -1;
498
499     /* try output buffer (no need to check for skip request) */
500     if (state->have) {
501         state->have--;
502         state->pos++;
503         return *(state->next)++;
504     }
505
506     /* nothing there -- try gzread() */
507     ret = gzread(file, buf, 1);
508     return ret < 1 ? -1 : buf[0];
509 }
510
511 /* -- see zlib.h -- */
512 int ZEXPORT gzungetc(c, file)
513     int c;
514     gzFile file;
515 {
516     gz_statep state;
517
518     /* get internal structure */
519     if (file == NULL)
520         return -1;
521     state = (gz_statep)file;
522
523     /* check that we're reading and that there's no error */
524     if (state->mode != GZ_READ || state->err != Z_OK)
525         return -1;
526
527     /* process a skip request */
528     if (state->seek) {
529         state->seek = 0;
530         if (gz_skip(state, state->skip) == -1)
531             return -1;
532     }
533
534     /* can't push EOF */
535     if (c < 0)
536         return -1;
537
538     /* if output buffer empty, put byte at end (allows more pushing) */
539     if (state->have == 0) {
540         state->have = 1;
541         state->next = state->out + (state->size << 1) - 1;
542         state->next[0] = c;
543         state->pos--;
544         return c;
545     }
546
547     /* if no room, give up (must have already done a gzungetc()) */
548     if (state->have == (state->size << 1)) {
549         gz_error(state, Z_BUF_ERROR, "out of room to push characters");
550         return -1;
551     }
552
553     /* slide output data if needed and insert byte before existing data */
554     if (state->next == state->out) {
555         unsigned char FAR *src = state->out + state->have;
556         unsigned char FAR *dest = state->out + (state->size << 1);
557         while (src > state->out)
558             *--dest = *--src;
559         state->next = dest;
560     }
561     state->have++;
562     state->next--;
563     state->next[0] = c;
564     state->pos--;
565     return c;
566 }
567
568 /* -- see zlib.h -- */
569 char * ZEXPORT gzgets(file, buf, len)
570     gzFile file;
571     char *buf;
572     int len;
573 {
574     unsigned left, n;
575     char *str;
576     unsigned char FAR *eol;
577     gz_statep state;
578
579     /* check parameters and get internal structure */
580     if (file == NULL || buf == NULL || len < 1)
581         return NULL;
582     state = (gz_statep)file;
583
584     /* check that we're reading and that there's no error */
585     if (state->mode != GZ_READ || state->err != Z_OK)
586         return NULL;
587
588     /* process a skip request */
589     if (state->seek) {
590         state->seek = 0;
591         if (gz_skip(state, state->skip) == -1)
592             return NULL;
593     }
594
595     /* copy output bytes up to new line or len - 1, whichever comes first --
596        append a terminating zero to the string (we don't check for a zero in
597        the contents, let the user worry about that) */
598     str = buf;
599     left = (unsigned)len - 1;
600     if (left) do {
601         /* assure that something is in the output buffer */
602         if (state->have == 0) {
603             if (gz_make(state) == -1)
604                 return NULL;            /* error */
605             if (state->have == 0) {     /* end of file */
606                 if (buf == str)         /* got bupkus */
607                     return NULL;
608                 break;                  /* got something -- return it */
609             }
610         }
611
612         /* look for end-of-line in current output buffer */
613         n = state->have > left ? left : state->have;
614         eol = zmemchr(state->next, '\n', n);
615         if (eol != NULL)
616             n = (unsigned)(eol - state->next) + 1;
617
618         /* copy through end-of-line, or remainder if not found */
619         zmemcpy(buf, state->next, n);
620         state->have -= n;
621         state->next += n;
622         state->pos += n;
623         left -= n;
624         buf += n;
625     } while (left && eol == NULL);
626
627     /* found end-of-line or out of space -- terminate string and return it */
628     buf[0] = 0;
629     return str;
630 }
631
632 /* -- see zlib.h -- */
633 int ZEXPORT gzdirect(file)
634     gzFile file;
635 {
636     gz_statep state;
637
638     /* get internal structure */
639     if (file == NULL)
640         return 0;
641     state = (gz_statep)file;
642
643     /* check that we're reading */
644     if (state->mode != GZ_READ)
645         return 0;
646
647     /* if the state is not known, but we can find out, then do so (this is
648        mainly for right after a gzopen() or gzdopen()) */
649     if (state->how == LOOK && state->have == 0)
650         (void)gz_head(state);
651
652     /* return 1 if reading direct, 0 if decompressing a gzip stream */
653     return state->direct;
654 }
655
656 /* -- see zlib.h -- */
657 int ZEXPORT gzclose_r(file)
658     gzFile file;
659 {
660     int ret;
661     gz_statep state;
662
663     /* get internal structure */
664     if (file == NULL)
665         return Z_STREAM_ERROR;
666     state = (gz_statep)file;
667
668     /* check that we're reading */
669     if (state->mode != GZ_READ)
670         return Z_STREAM_ERROR;
671
672     /* free memory and close file */
673     if (state->size) {
674         inflateEnd(&(state->strm));
675 #if TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__MEDIUM__))
676         _ffree(state->out);
677         _ffree(state->in);
678 #else
679         free(state->out);
680         free(state->in);
681 #endif
682     }
683     gz_error(state, Z_OK, NULL);
684     free(state->path);
685     ret = close(state->fd);
686     free(state);
687     return ret ? Z_ERRNO : Z_OK;
688 }