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