Home | History | Annotate | Line # | Download | only in zlib
      1      1.1  christos /* gzread.c -- zlib functions for reading gzip files
      2  1.1.1.4  christos  * Copyright (C) 2004-2017 Mark Adler
      3      1.1  christos  * For conditions of distribution and use, see copyright notice in zlib.h
      4      1.1  christos  */
      5      1.1  christos 
      6      1.1  christos #include "gzguts.h"
      7      1.1  christos 
      8      1.1  christos /* Use read() to load a buffer -- return -1 on error, otherwise 0.  Read from
      9      1.1  christos    state->fd, and update state->eof, state->err, and state->msg as appropriate.
     10      1.1  christos    This function needs to loop on read(), since read() is not guaranteed to
     11      1.1  christos    read the number of bytes requested, depending on the type of descriptor. */
     12  1.1.1.5  christos local int gz_load(gz_statep state, unsigned char *buf, unsigned len,
     13  1.1.1.5  christos                   unsigned *have) {
     14      1.1  christos     int ret;
     15  1.1.1.3  christos     unsigned get, max = ((unsigned)-1 >> 2) + 1;
     16      1.1  christos 
     17      1.1  christos     *have = 0;
     18      1.1  christos     do {
     19  1.1.1.3  christos         get = len - *have;
     20  1.1.1.3  christos         if (get > max)
     21  1.1.1.3  christos             get = max;
     22  1.1.1.3  christos         ret = read(state->fd, buf + *have, get);
     23      1.1  christos         if (ret <= 0)
     24      1.1  christos             break;
     25  1.1.1.3  christos         *have += (unsigned)ret;
     26      1.1  christos     } while (*have < len);
     27      1.1  christos     if (ret < 0) {
     28      1.1  christos         gz_error(state, Z_ERRNO, zstrerror());
     29      1.1  christos         return -1;
     30      1.1  christos     }
     31      1.1  christos     if (ret == 0)
     32      1.1  christos         state->eof = 1;
     33      1.1  christos     return 0;
     34      1.1  christos }
     35      1.1  christos 
     36      1.1  christos /* Load up input buffer and set eof flag if last data loaded -- return -1 on
     37      1.1  christos    error, 0 otherwise.  Note that the eof flag is set when the end of the input
     38      1.1  christos    file is reached, even though there may be unused data in the buffer.  Once
     39      1.1  christos    that data has been used, no more attempts will be made to read the file.
     40      1.1  christos    If strm->avail_in != 0, then the current data is moved to the beginning of
     41      1.1  christos    the input buffer, and then the remainder of the buffer is loaded with the
     42      1.1  christos    available data from the input file. */
     43  1.1.1.5  christos local int gz_avail(gz_statep state) {
     44      1.1  christos     unsigned got;
     45      1.1  christos     z_streamp strm = &(state->strm);
     46      1.1  christos 
     47      1.1  christos     if (state->err != Z_OK && state->err != Z_BUF_ERROR)
     48      1.1  christos         return -1;
     49      1.1  christos     if (state->eof == 0) {
     50      1.1  christos         if (strm->avail_in) {       /* copy what's there to the start */
     51  1.1.1.2  christos             unsigned char *p = state->in;
     52  1.1.1.2  christos             unsigned const char *q = strm->next_in;
     53      1.1  christos             unsigned n = strm->avail_in;
     54      1.1  christos             do {
     55      1.1  christos                 *p++ = *q++;
     56      1.1  christos             } while (--n);
     57      1.1  christos         }
     58      1.1  christos         if (gz_load(state, state->in + strm->avail_in,
     59      1.1  christos                     state->size - strm->avail_in, &got) == -1)
     60      1.1  christos             return -1;
     61      1.1  christos         strm->avail_in += got;
     62      1.1  christos         strm->next_in = state->in;
     63      1.1  christos     }
     64      1.1  christos     return 0;
     65      1.1  christos }
     66      1.1  christos 
     67      1.1  christos /* Look for gzip header, set up for inflate or copy.  state->x.have must be 0.
     68      1.1  christos    If this is the first time in, allocate required memory.  state->how will be
     69      1.1  christos    left unchanged if there is no more input data available, will be set to COPY
     70      1.1  christos    if there is no gzip header and direct copying will be performed, or it will
     71      1.1  christos    be set to GZIP for decompression.  If direct copying, then leftover input
     72      1.1  christos    data from the input buffer will be copied to the output buffer.  In that
     73      1.1  christos    case, all further file reads will be directly to either the output buffer or
     74      1.1  christos    a user buffer.  If decompressing, the inflate state will be initialized.
     75      1.1  christos    gz_look() will return 0 on success or -1 on failure. */
     76  1.1.1.5  christos local int gz_look(gz_statep state) {
     77      1.1  christos     z_streamp strm = &(state->strm);
     78      1.1  christos 
     79      1.1  christos     /* allocate read buffers and inflate memory */
     80      1.1  christos     if (state->size == 0) {
     81      1.1  christos         /* allocate buffers */
     82  1.1.1.2  christos         state->in = (unsigned char *)malloc(state->want);
     83  1.1.1.2  christos         state->out = (unsigned char *)malloc(state->want << 1);
     84      1.1  christos         if (state->in == NULL || state->out == NULL) {
     85  1.1.1.3  christos             free(state->out);
     86  1.1.1.3  christos             free(state->in);
     87      1.1  christos             gz_error(state, Z_MEM_ERROR, "out of memory");
     88      1.1  christos             return -1;
     89      1.1  christos         }
     90      1.1  christos         state->size = state->want;
     91      1.1  christos 
     92      1.1  christos         /* allocate inflate memory */
     93      1.1  christos         state->strm.zalloc = Z_NULL;
     94      1.1  christos         state->strm.zfree = Z_NULL;
     95      1.1  christos         state->strm.opaque = Z_NULL;
     96      1.1  christos         state->strm.avail_in = 0;
     97      1.1  christos         state->strm.next_in = Z_NULL;
     98      1.1  christos         if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) {    /* gunzip */
     99      1.1  christos             free(state->out);
    100      1.1  christos             free(state->in);
    101      1.1  christos             state->size = 0;
    102      1.1  christos             gz_error(state, Z_MEM_ERROR, "out of memory");
    103      1.1  christos             return -1;
    104      1.1  christos         }
    105      1.1  christos     }
    106      1.1  christos 
    107      1.1  christos     /* get at least the magic bytes in the input buffer */
    108      1.1  christos     if (strm->avail_in < 2) {
    109      1.1  christos         if (gz_avail(state) == -1)
    110      1.1  christos             return -1;
    111      1.1  christos         if (strm->avail_in == 0)
    112      1.1  christos             return 0;
    113      1.1  christos     }
    114      1.1  christos 
    115      1.1  christos     /* look for gzip magic bytes -- if there, do gzip decoding (note: there is
    116      1.1  christos        a logical dilemma here when considering the case of a partially written
    117      1.1  christos        gzip file, to wit, if a single 31 byte is written, then we cannot tell
    118      1.1  christos        whether this is a single-byte file, or just a partially written gzip
    119      1.1  christos        file -- for here we assume that if a gzip file is being written, then
    120      1.1  christos        the header will be written in a single operation, so that reading a
    121      1.1  christos        single byte is sufficient indication that it is not a gzip file) */
    122      1.1  christos     if (strm->avail_in > 1 &&
    123      1.1  christos             strm->next_in[0] == 31 && strm->next_in[1] == 139) {
    124      1.1  christos         inflateReset(strm);
    125      1.1  christos         state->how = GZIP;
    126      1.1  christos         state->direct = 0;
    127      1.1  christos         return 0;
    128      1.1  christos     }
    129      1.1  christos 
    130      1.1  christos     /* no gzip header -- if we were decoding gzip before, then this is trailing
    131      1.1  christos        garbage.  Ignore the trailing garbage and finish. */
    132      1.1  christos     if (state->direct == 0) {
    133      1.1  christos         strm->avail_in = 0;
    134      1.1  christos         state->eof = 1;
    135      1.1  christos         state->x.have = 0;
    136      1.1  christos         return 0;
    137      1.1  christos     }
    138      1.1  christos 
    139      1.1  christos     /* doing raw i/o, copy any leftover input to output -- this assumes that
    140      1.1  christos        the output buffer is larger than the input buffer, which also assures
    141      1.1  christos        space for gzungetc() */
    142      1.1  christos     state->x.next = state->out;
    143  1.1.1.5  christos     memcpy(state->x.next, strm->next_in, strm->avail_in);
    144  1.1.1.5  christos     state->x.have = strm->avail_in;
    145  1.1.1.5  christos     strm->avail_in = 0;
    146      1.1  christos     state->how = COPY;
    147      1.1  christos     state->direct = 1;
    148      1.1  christos     return 0;
    149      1.1  christos }
    150      1.1  christos 
    151      1.1  christos /* Decompress from input to the provided next_out and avail_out in the state.
    152      1.1  christos    On return, state->x.have and state->x.next point to the just decompressed
    153      1.1  christos    data.  If the gzip stream completes, state->how is reset to LOOK to look for
    154      1.1  christos    the next gzip stream or raw data, once state->x.have is depleted.  Returns 0
    155      1.1  christos    on success, -1 on failure. */
    156  1.1.1.5  christos local int gz_decomp(gz_statep state) {
    157      1.1  christos     int ret = Z_OK;
    158      1.1  christos     unsigned had;
    159      1.1  christos     z_streamp strm = &(state->strm);
    160      1.1  christos 
    161      1.1  christos     /* fill output buffer up to end of deflate stream */
    162      1.1  christos     had = strm->avail_out;
    163      1.1  christos     do {
    164      1.1  christos         /* get more input for inflate() */
    165      1.1  christos         if (strm->avail_in == 0 && gz_avail(state) == -1)
    166      1.1  christos             return -1;
    167      1.1  christos         if (strm->avail_in == 0) {
    168      1.1  christos             gz_error(state, Z_BUF_ERROR, "unexpected end of file");
    169      1.1  christos             break;
    170      1.1  christos         }
    171      1.1  christos 
    172      1.1  christos         /* decompress and handle errors */
    173      1.1  christos         ret = inflate(strm, Z_NO_FLUSH);
    174      1.1  christos         if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
    175      1.1  christos             gz_error(state, Z_STREAM_ERROR,
    176      1.1  christos                      "internal error: inflate stream corrupt");
    177      1.1  christos             return -1;
    178      1.1  christos         }
    179      1.1  christos         if (ret == Z_MEM_ERROR) {
    180      1.1  christos             gz_error(state, Z_MEM_ERROR, "out of memory");
    181      1.1  christos             return -1;
    182      1.1  christos         }
    183      1.1  christos         if (ret == Z_DATA_ERROR) {              /* deflate stream invalid */
    184      1.1  christos             gz_error(state, Z_DATA_ERROR,
    185      1.1  christos                      strm->msg == NULL ? "compressed data error" : strm->msg);
    186      1.1  christos             return -1;
    187      1.1  christos         }
    188      1.1  christos     } while (strm->avail_out && ret != Z_STREAM_END);
    189      1.1  christos 
    190      1.1  christos     /* update available output */
    191      1.1  christos     state->x.have = had - strm->avail_out;
    192      1.1  christos     state->x.next = strm->next_out - state->x.have;
    193      1.1  christos 
    194      1.1  christos     /* if the gzip stream completed successfully, look for another */
    195      1.1  christos     if (ret == Z_STREAM_END)
    196      1.1  christos         state->how = LOOK;
    197      1.1  christos 
    198      1.1  christos     /* good decompression */
    199      1.1  christos     return 0;
    200      1.1  christos }
    201      1.1  christos 
    202      1.1  christos /* Fetch data and put it in the output buffer.  Assumes state->x.have is 0.
    203      1.1  christos    Data is either copied from the input file or decompressed from the input
    204      1.1  christos    file depending on state->how.  If state->how is LOOK, then a gzip header is
    205      1.1  christos    looked for to determine whether to copy or decompress.  Returns -1 on error,
    206      1.1  christos    otherwise 0.  gz_fetch() will leave state->how as COPY or GZIP unless the
    207      1.1  christos    end of the input file has been reached and all data has been processed.  */
    208  1.1.1.5  christos local int gz_fetch(gz_statep state) {
    209      1.1  christos     z_streamp strm = &(state->strm);
    210      1.1  christos 
    211      1.1  christos     do {
    212      1.1  christos         switch(state->how) {
    213      1.1  christos         case LOOK:      /* -> LOOK, COPY (only if never GZIP), or GZIP */
    214      1.1  christos             if (gz_look(state) == -1)
    215      1.1  christos                 return -1;
    216      1.1  christos             if (state->how == LOOK)
    217      1.1  christos                 return 0;
    218      1.1  christos             break;
    219      1.1  christos         case COPY:      /* -> COPY */
    220      1.1  christos             if (gz_load(state, state->out, state->size << 1, &(state->x.have))
    221      1.1  christos                     == -1)
    222      1.1  christos                 return -1;
    223      1.1  christos             state->x.next = state->out;
    224      1.1  christos             return 0;
    225      1.1  christos         case GZIP:      /* -> GZIP or LOOK (if end of gzip stream) */
    226      1.1  christos             strm->avail_out = state->size << 1;
    227      1.1  christos             strm->next_out = state->out;
    228      1.1  christos             if (gz_decomp(state) == -1)
    229      1.1  christos                 return -1;
    230      1.1  christos         }
    231      1.1  christos     } while (state->x.have == 0 && (!state->eof || strm->avail_in));
    232      1.1  christos     return 0;
    233      1.1  christos }
    234      1.1  christos 
    235      1.1  christos /* Skip len uncompressed bytes of output.  Return -1 on error, 0 on success. */
    236  1.1.1.5  christos local int gz_skip(gz_statep state, z_off64_t len) {
    237      1.1  christos     unsigned n;
    238      1.1  christos 
    239      1.1  christos     /* skip over len bytes or reach end-of-file, whichever comes first */
    240      1.1  christos     while (len)
    241      1.1  christos         /* skip over whatever is in output buffer */
    242      1.1  christos         if (state->x.have) {
    243      1.1  christos             n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ?
    244      1.1  christos                 (unsigned)len : state->x.have;
    245      1.1  christos             state->x.have -= n;
    246      1.1  christos             state->x.next += n;
    247      1.1  christos             state->x.pos += n;
    248      1.1  christos             len -= n;
    249      1.1  christos         }
    250      1.1  christos 
    251      1.1  christos         /* output buffer empty -- return if we're at the end of the input */
    252      1.1  christos         else if (state->eof && state->strm.avail_in == 0)
    253      1.1  christos             break;
    254      1.1  christos 
    255      1.1  christos         /* need more data to skip -- load up output buffer */
    256      1.1  christos         else {
    257      1.1  christos             /* get more output, looking for header if required */
    258      1.1  christos             if (gz_fetch(state) == -1)
    259      1.1  christos                 return -1;
    260      1.1  christos         }
    261      1.1  christos     return 0;
    262      1.1  christos }
    263      1.1  christos 
    264  1.1.1.3  christos /* Read len bytes into buf from file, or less than len up to the end of the
    265  1.1.1.3  christos    input.  Return the number of bytes read.  If zero is returned, either the
    266  1.1.1.3  christos    end of file was reached, or there was an error.  state->err must be
    267  1.1.1.3  christos    consulted in that case to determine which. */
    268  1.1.1.5  christos local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) {
    269  1.1.1.3  christos     z_size_t got;
    270  1.1.1.3  christos     unsigned n;
    271      1.1  christos 
    272      1.1  christos     /* if len is zero, avoid unnecessary operations */
    273      1.1  christos     if (len == 0)
    274      1.1  christos         return 0;
    275      1.1  christos 
    276      1.1  christos     /* process a skip request */
    277      1.1  christos     if (state->seek) {
    278      1.1  christos         state->seek = 0;
    279      1.1  christos         if (gz_skip(state, state->skip) == -1)
    280  1.1.1.3  christos             return 0;
    281      1.1  christos     }
    282      1.1  christos 
    283      1.1  christos     /* get len bytes to buf, or less than len if at the end */
    284      1.1  christos     got = 0;
    285      1.1  christos     do {
    286  1.1.1.3  christos         /* set n to the maximum amount of len that fits in an unsigned int */
    287  1.1.1.4  christos         n = (unsigned)-1;
    288  1.1.1.3  christos         if (n > len)
    289  1.1.1.4  christos             n = (unsigned)len;
    290  1.1.1.3  christos 
    291      1.1  christos         /* first just try copying data from the output buffer */
    292      1.1  christos         if (state->x.have) {
    293  1.1.1.3  christos             if (state->x.have < n)
    294  1.1.1.3  christos                 n = state->x.have;
    295      1.1  christos             memcpy(buf, state->x.next, n);
    296      1.1  christos             state->x.next += n;
    297      1.1  christos             state->x.have -= n;
    298      1.1  christos         }
    299      1.1  christos 
    300      1.1  christos         /* output buffer empty -- return if we're at the end of the input */
    301  1.1.1.3  christos         else if (state->eof && state->strm.avail_in == 0) {
    302      1.1  christos             state->past = 1;        /* tried to read past end */
    303      1.1  christos             break;
    304      1.1  christos         }
    305      1.1  christos 
    306      1.1  christos         /* need output data -- for small len or new stream load up our output
    307      1.1  christos            buffer */
    308  1.1.1.3  christos         else if (state->how == LOOK || n < (state->size << 1)) {
    309      1.1  christos             /* get more output, looking for header if required */
    310      1.1  christos             if (gz_fetch(state) == -1)
    311  1.1.1.3  christos                 return 0;
    312      1.1  christos             continue;       /* no progress yet -- go back to copy above */
    313      1.1  christos             /* the copy above assures that we will leave with space in the
    314      1.1  christos                output buffer, allowing at least one gzungetc() to succeed */
    315      1.1  christos         }
    316      1.1  christos 
    317      1.1  christos         /* large len -- read directly into user buffer */
    318      1.1  christos         else if (state->how == COPY) {      /* read directly */
    319  1.1.1.3  christos             if (gz_load(state, (unsigned char *)buf, n, &n) == -1)
    320  1.1.1.3  christos                 return 0;
    321      1.1  christos         }
    322      1.1  christos 
    323      1.1  christos         /* large len -- decompress directly into user buffer */
    324      1.1  christos         else {  /* state->how == GZIP */
    325  1.1.1.3  christos             state->strm.avail_out = n;
    326  1.1.1.3  christos             state->strm.next_out = (unsigned char *)buf;
    327      1.1  christos             if (gz_decomp(state) == -1)
    328  1.1.1.3  christos                 return 0;
    329      1.1  christos             n = state->x.have;
    330      1.1  christos             state->x.have = 0;
    331      1.1  christos         }
    332      1.1  christos 
    333      1.1  christos         /* update progress */
    334      1.1  christos         len -= n;
    335      1.1  christos         buf = (char *)buf + n;
    336      1.1  christos         got += n;
    337      1.1  christos         state->x.pos += n;
    338      1.1  christos     } while (len);
    339      1.1  christos 
    340  1.1.1.3  christos     /* return number of bytes read into user buffer */
    341  1.1.1.3  christos     return got;
    342  1.1.1.3  christos }
    343  1.1.1.3  christos 
    344  1.1.1.3  christos /* -- see zlib.h -- */
    345  1.1.1.5  christos int ZEXPORT gzread(gzFile file, voidp buf, unsigned len) {
    346  1.1.1.3  christos     gz_statep state;
    347  1.1.1.3  christos 
    348  1.1.1.3  christos     /* get internal structure */
    349  1.1.1.3  christos     if (file == NULL)
    350  1.1.1.3  christos         return -1;
    351  1.1.1.3  christos     state = (gz_statep)file;
    352  1.1.1.3  christos 
    353  1.1.1.3  christos     /* check that we're reading and that there's no (serious) error */
    354  1.1.1.3  christos     if (state->mode != GZ_READ ||
    355  1.1.1.3  christos             (state->err != Z_OK && state->err != Z_BUF_ERROR))
    356  1.1.1.3  christos         return -1;
    357  1.1.1.3  christos 
    358  1.1.1.3  christos     /* since an int is returned, make sure len fits in one, otherwise return
    359  1.1.1.3  christos        with an error (this avoids a flaw in the interface) */
    360  1.1.1.3  christos     if ((int)len < 0) {
    361  1.1.1.3  christos         gz_error(state, Z_STREAM_ERROR, "request does not fit in an int");
    362  1.1.1.3  christos         return -1;
    363  1.1.1.3  christos     }
    364  1.1.1.3  christos 
    365  1.1.1.3  christos     /* read len or fewer bytes to buf */
    366  1.1.1.4  christos     len = (unsigned)gz_read(state, buf, len);
    367  1.1.1.3  christos 
    368  1.1.1.3  christos     /* check for an error */
    369  1.1.1.3  christos     if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR)
    370  1.1.1.3  christos         return -1;
    371  1.1.1.3  christos 
    372  1.1.1.3  christos     /* return the number of bytes read (this is assured to fit in an int) */
    373  1.1.1.3  christos     return (int)len;
    374  1.1.1.3  christos }
    375  1.1.1.3  christos 
    376  1.1.1.3  christos /* -- see zlib.h -- */
    377  1.1.1.5  christos z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, gzFile file) {
    378  1.1.1.3  christos     z_size_t len;
    379  1.1.1.3  christos     gz_statep state;
    380  1.1.1.3  christos 
    381  1.1.1.3  christos     /* get internal structure */
    382  1.1.1.3  christos     if (file == NULL)
    383  1.1.1.3  christos         return 0;
    384  1.1.1.3  christos     state = (gz_statep)file;
    385  1.1.1.3  christos 
    386  1.1.1.3  christos     /* check that we're reading and that there's no (serious) error */
    387  1.1.1.3  christos     if (state->mode != GZ_READ ||
    388  1.1.1.3  christos             (state->err != Z_OK && state->err != Z_BUF_ERROR))
    389  1.1.1.3  christos         return 0;
    390  1.1.1.3  christos 
    391  1.1.1.3  christos     /* compute bytes to read -- error on overflow */
    392  1.1.1.3  christos     len = nitems * size;
    393  1.1.1.3  christos     if (size && len / size != nitems) {
    394  1.1.1.3  christos         gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
    395  1.1.1.3  christos         return 0;
    396  1.1.1.3  christos     }
    397  1.1.1.3  christos 
    398  1.1.1.3  christos     /* read len or fewer bytes to buf, return the number of full items read */
    399  1.1.1.3  christos     return len ? gz_read(state, buf, len) / size : 0;
    400      1.1  christos }
    401      1.1  christos 
    402      1.1  christos /* -- see zlib.h -- */
    403  1.1.1.2  christos #ifdef Z_PREFIX_SET
    404  1.1.1.2  christos #  undef z_gzgetc
    405  1.1.1.2  christos #else
    406  1.1.1.2  christos #  undef gzgetc
    407  1.1.1.2  christos #endif
    408  1.1.1.5  christos int ZEXPORT gzgetc(gzFile file) {
    409      1.1  christos     unsigned char buf[1];
    410      1.1  christos     gz_statep state;
    411      1.1  christos 
    412      1.1  christos     /* get internal structure */
    413      1.1  christos     if (file == NULL)
    414      1.1  christos         return -1;
    415      1.1  christos     state = (gz_statep)file;
    416      1.1  christos 
    417      1.1  christos     /* check that we're reading and that there's no (serious) error */
    418      1.1  christos     if (state->mode != GZ_READ ||
    419      1.1  christos         (state->err != Z_OK && state->err != Z_BUF_ERROR))
    420      1.1  christos         return -1;
    421      1.1  christos 
    422      1.1  christos     /* try output buffer (no need to check for skip request) */
    423      1.1  christos     if (state->x.have) {
    424      1.1  christos         state->x.have--;
    425      1.1  christos         state->x.pos++;
    426      1.1  christos         return *(state->x.next)++;
    427      1.1  christos     }
    428      1.1  christos 
    429  1.1.1.3  christos     /* nothing there -- try gz_read() */
    430  1.1.1.4  christos     return gz_read(state, buf, 1) < 1 ? -1 : buf[0];
    431      1.1  christos }
    432      1.1  christos 
    433  1.1.1.5  christos int ZEXPORT gzgetc_(gzFile file) {
    434      1.1  christos     return gzgetc(file);
    435      1.1  christos }
    436      1.1  christos 
    437      1.1  christos /* -- see zlib.h -- */
    438  1.1.1.5  christos int ZEXPORT gzungetc(int c, gzFile file) {
    439      1.1  christos     gz_statep state;
    440      1.1  christos 
    441      1.1  christos     /* get internal structure */
    442      1.1  christos     if (file == NULL)
    443      1.1  christos         return -1;
    444      1.1  christos     state = (gz_statep)file;
    445      1.1  christos 
    446  1.1.1.5  christos     /* in case this was just opened, set up the input buffer */
    447  1.1.1.5  christos     if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
    448  1.1.1.5  christos         (void)gz_look(state);
    449  1.1.1.5  christos 
    450      1.1  christos     /* check that we're reading and that there's no (serious) error */
    451      1.1  christos     if (state->mode != GZ_READ ||
    452      1.1  christos         (state->err != Z_OK && state->err != Z_BUF_ERROR))
    453      1.1  christos         return -1;
    454      1.1  christos 
    455      1.1  christos     /* process a skip request */
    456      1.1  christos     if (state->seek) {
    457      1.1  christos         state->seek = 0;
    458      1.1  christos         if (gz_skip(state, state->skip) == -1)
    459      1.1  christos             return -1;
    460      1.1  christos     }
    461      1.1  christos 
    462      1.1  christos     /* can't push EOF */
    463      1.1  christos     if (c < 0)
    464      1.1  christos         return -1;
    465      1.1  christos 
    466      1.1  christos     /* if output buffer empty, put byte at end (allows more pushing) */
    467      1.1  christos     if (state->x.have == 0) {
    468      1.1  christos         state->x.have = 1;
    469      1.1  christos         state->x.next = state->out + (state->size << 1) - 1;
    470  1.1.1.3  christos         state->x.next[0] = (unsigned char)c;
    471      1.1  christos         state->x.pos--;
    472      1.1  christos         state->past = 0;
    473      1.1  christos         return c;
    474      1.1  christos     }
    475      1.1  christos 
    476      1.1  christos     /* if no room, give up (must have already done a gzungetc()) */
    477      1.1  christos     if (state->x.have == (state->size << 1)) {
    478      1.1  christos         gz_error(state, Z_DATA_ERROR, "out of room to push characters");
    479      1.1  christos         return -1;
    480      1.1  christos     }
    481      1.1  christos 
    482      1.1  christos     /* slide output data if needed and insert byte before existing data */
    483      1.1  christos     if (state->x.next == state->out) {
    484      1.1  christos         unsigned char *src = state->out + state->x.have;
    485      1.1  christos         unsigned char *dest = state->out + (state->size << 1);
    486      1.1  christos         while (src > state->out)
    487      1.1  christos             *--dest = *--src;
    488      1.1  christos         state->x.next = dest;
    489      1.1  christos     }
    490      1.1  christos     state->x.have++;
    491      1.1  christos     state->x.next--;
    492  1.1.1.3  christos     state->x.next[0] = (unsigned char)c;
    493      1.1  christos     state->x.pos--;
    494      1.1  christos     state->past = 0;
    495      1.1  christos     return c;
    496      1.1  christos }
    497      1.1  christos 
    498      1.1  christos /* -- see zlib.h -- */
    499  1.1.1.5  christos char * ZEXPORT gzgets(gzFile file, char *buf, int len) {
    500      1.1  christos     unsigned left, n;
    501      1.1  christos     char *str;
    502      1.1  christos     unsigned char *eol;
    503      1.1  christos     gz_statep state;
    504      1.1  christos 
    505      1.1  christos     /* check parameters and get internal structure */
    506      1.1  christos     if (file == NULL || buf == NULL || len < 1)
    507      1.1  christos         return NULL;
    508      1.1  christos     state = (gz_statep)file;
    509      1.1  christos 
    510      1.1  christos     /* check that we're reading and that there's no (serious) error */
    511      1.1  christos     if (state->mode != GZ_READ ||
    512      1.1  christos         (state->err != Z_OK && state->err != Z_BUF_ERROR))
    513      1.1  christos         return NULL;
    514      1.1  christos 
    515      1.1  christos     /* process a skip request */
    516      1.1  christos     if (state->seek) {
    517      1.1  christos         state->seek = 0;
    518      1.1  christos         if (gz_skip(state, state->skip) == -1)
    519      1.1  christos             return NULL;
    520      1.1  christos     }
    521      1.1  christos 
    522      1.1  christos     /* copy output bytes up to new line or len - 1, whichever comes first --
    523      1.1  christos        append a terminating zero to the string (we don't check for a zero in
    524      1.1  christos        the contents, let the user worry about that) */
    525      1.1  christos     str = buf;
    526      1.1  christos     left = (unsigned)len - 1;
    527      1.1  christos     if (left) do {
    528      1.1  christos         /* assure that something is in the output buffer */
    529      1.1  christos         if (state->x.have == 0 && gz_fetch(state) == -1)
    530      1.1  christos             return NULL;                /* error */
    531      1.1  christos         if (state->x.have == 0) {       /* end of file */
    532      1.1  christos             state->past = 1;            /* read past end */
    533      1.1  christos             break;                      /* return what we have */
    534      1.1  christos         }
    535      1.1  christos 
    536      1.1  christos         /* look for end-of-line in current output buffer */
    537      1.1  christos         n = state->x.have > left ? left : state->x.have;
    538  1.1.1.2  christos         eol = (unsigned char *)memchr(state->x.next, '\n', n);
    539      1.1  christos         if (eol != NULL)
    540      1.1  christos             n = (unsigned)(eol - state->x.next) + 1;
    541      1.1  christos 
    542      1.1  christos         /* copy through end-of-line, or remainder if not found */
    543      1.1  christos         memcpy(buf, state->x.next, n);
    544      1.1  christos         state->x.have -= n;
    545      1.1  christos         state->x.next += n;
    546      1.1  christos         state->x.pos += n;
    547      1.1  christos         left -= n;
    548      1.1  christos         buf += n;
    549      1.1  christos     } while (left && eol == NULL);
    550      1.1  christos 
    551      1.1  christos     /* return terminated string, or if nothing, end of file */
    552      1.1  christos     if (buf == str)
    553      1.1  christos         return NULL;
    554      1.1  christos     buf[0] = 0;
    555      1.1  christos     return str;
    556      1.1  christos }
    557      1.1  christos 
    558      1.1  christos /* -- see zlib.h -- */
    559  1.1.1.5  christos int ZEXPORT gzdirect(gzFile file) {
    560      1.1  christos     gz_statep state;
    561      1.1  christos 
    562      1.1  christos     /* get internal structure */
    563      1.1  christos     if (file == NULL)
    564      1.1  christos         return 0;
    565      1.1  christos     state = (gz_statep)file;
    566      1.1  christos 
    567      1.1  christos     /* if the state is not known, but we can find out, then do so (this is
    568      1.1  christos        mainly for right after a gzopen() or gzdopen()) */
    569      1.1  christos     if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
    570      1.1  christos         (void)gz_look(state);
    571      1.1  christos 
    572      1.1  christos     /* return 1 if transparent, 0 if processing a gzip stream */
    573      1.1  christos     return state->direct;
    574      1.1  christos }
    575      1.1  christos 
    576      1.1  christos /* -- see zlib.h -- */
    577  1.1.1.5  christos int ZEXPORT gzclose_r(gzFile file) {
    578      1.1  christos     int ret, err;
    579      1.1  christos     gz_statep state;
    580      1.1  christos 
    581      1.1  christos     /* get internal structure */
    582      1.1  christos     if (file == NULL)
    583      1.1  christos         return Z_STREAM_ERROR;
    584      1.1  christos     state = (gz_statep)file;
    585      1.1  christos 
    586      1.1  christos     /* check that we're reading */
    587      1.1  christos     if (state->mode != GZ_READ)
    588      1.1  christos         return Z_STREAM_ERROR;
    589      1.1  christos 
    590      1.1  christos     /* free memory and close file */
    591      1.1  christos     if (state->size) {
    592      1.1  christos         inflateEnd(&(state->strm));
    593      1.1  christos         free(state->out);
    594      1.1  christos         free(state->in);
    595      1.1  christos     }
    596      1.1  christos     err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK;
    597      1.1  christos     gz_error(state, Z_OK, NULL);
    598      1.1  christos     free(state->path);
    599      1.1  christos     ret = close(state->fd);
    600      1.1  christos     free(state);
    601      1.1  christos     return ret ? Z_ERRNO : err;
    602      1.1  christos }
    603