1205194Sdelphij/* gzread.c -- zlib functions for reading gzip files 2250261Sdelphij * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler 3205194Sdelphij * For conditions of distribution and use, see copyright notice in zlib.h 4205194Sdelphij */ 5205194Sdelphij 6206002Sdelphij/* $FreeBSD$ */ 7206002Sdelphij 8205194Sdelphij#include "gzguts.h" 9205305Sdelphij#include <unistd.h> 10205194Sdelphij 11205194Sdelphij/* Local functions */ 12205194Sdelphijlocal int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *)); 13205194Sdelphijlocal int gz_avail OF((gz_statep)); 14237410Sdelphijlocal int gz_look OF((gz_statep)); 15205194Sdelphijlocal int gz_decomp OF((gz_statep)); 16237410Sdelphijlocal int gz_fetch OF((gz_statep)); 17205194Sdelphijlocal int gz_skip OF((gz_statep, z_off64_t)); 18205194Sdelphij 19205194Sdelphij/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from 20205194Sdelphij state->fd, and update state->eof, state->err, and state->msg as appropriate. 21205194Sdelphij This function needs to loop on read(), since read() is not guaranteed to 22205194Sdelphij read the number of bytes requested, depending on the type of descriptor. */ 23205194Sdelphijlocal int gz_load(state, buf, len, have) 24205194Sdelphij gz_statep state; 25205194Sdelphij unsigned char *buf; 26205194Sdelphij unsigned len; 27205194Sdelphij unsigned *have; 28205194Sdelphij{ 29205194Sdelphij int ret; 30205194Sdelphij 31205194Sdelphij *have = 0; 32205194Sdelphij do { 33205194Sdelphij ret = read(state->fd, buf + *have, len - *have); 34205194Sdelphij if (ret <= 0) 35205194Sdelphij break; 36205194Sdelphij *have += ret; 37205194Sdelphij } while (*have < len); 38205194Sdelphij if (ret < 0) { 39205194Sdelphij gz_error(state, Z_ERRNO, zstrerror()); 40205194Sdelphij return -1; 41205194Sdelphij } 42205194Sdelphij if (ret == 0) 43205194Sdelphij state->eof = 1; 44205194Sdelphij return 0; 45205194Sdelphij} 46205194Sdelphij 47205194Sdelphij/* Load up input buffer and set eof flag if last data loaded -- return -1 on 48205194Sdelphij error, 0 otherwise. Note that the eof flag is set when the end of the input 49205194Sdelphij file is reached, even though there may be unused data in the buffer. Once 50205194Sdelphij that data has been used, no more attempts will be made to read the file. 51237410Sdelphij If strm->avail_in != 0, then the current data is moved to the beginning of 52237410Sdelphij the input buffer, and then the remainder of the buffer is loaded with the 53237410Sdelphij available data from the input file. */ 54205194Sdelphijlocal int gz_avail(state) 55205194Sdelphij gz_statep state; 56205194Sdelphij{ 57237410Sdelphij unsigned got; 58205194Sdelphij z_streamp strm = &(state->strm); 59205194Sdelphij 60237410Sdelphij if (state->err != Z_OK && state->err != Z_BUF_ERROR) 61205194Sdelphij return -1; 62205194Sdelphij if (state->eof == 0) { 63237410Sdelphij if (strm->avail_in) { /* copy what's there to the start */ 64250261Sdelphij unsigned char *p = state->in; 65250261Sdelphij unsigned const char *q = strm->next_in; 66237410Sdelphij unsigned n = strm->avail_in; 67237410Sdelphij do { 68237410Sdelphij *p++ = *q++; 69237410Sdelphij } while (--n); 70237410Sdelphij } 71237410Sdelphij if (gz_load(state, state->in + strm->avail_in, 72237410Sdelphij state->size - strm->avail_in, &got) == -1) 73205194Sdelphij return -1; 74237410Sdelphij strm->avail_in += got; 75205194Sdelphij strm->next_in = state->in; 76205194Sdelphij } 77205194Sdelphij return 0; 78205194Sdelphij} 79205194Sdelphij 80237410Sdelphij/* Look for gzip header, set up for inflate or copy. state->x.have must be 0. 81205194Sdelphij If this is the first time in, allocate required memory. state->how will be 82205194Sdelphij left unchanged if there is no more input data available, will be set to COPY 83205194Sdelphij if there is no gzip header and direct copying will be performed, or it will 84237410Sdelphij be set to GZIP for decompression. If direct copying, then leftover input 85237410Sdelphij data from the input buffer will be copied to the output buffer. In that 86237410Sdelphij case, all further file reads will be directly to either the output buffer or 87237410Sdelphij a user buffer. If decompressing, the inflate state will be initialized. 88237410Sdelphij gz_look() will return 0 on success or -1 on failure. */ 89237410Sdelphijlocal int gz_look(state) 90205194Sdelphij gz_statep state; 91205194Sdelphij{ 92205194Sdelphij z_streamp strm = &(state->strm); 93205194Sdelphij 94205194Sdelphij /* allocate read buffers and inflate memory */ 95205194Sdelphij if (state->size == 0) { 96205194Sdelphij /* allocate buffers */ 97250261Sdelphij state->in = (unsigned char *)malloc(state->want); 98250261Sdelphij state->out = (unsigned char *)malloc(state->want << 1); 99205194Sdelphij if (state->in == NULL || state->out == NULL) { 100205194Sdelphij if (state->out != NULL) 101205194Sdelphij free(state->out); 102205194Sdelphij if (state->in != NULL) 103205194Sdelphij free(state->in); 104205194Sdelphij gz_error(state, Z_MEM_ERROR, "out of memory"); 105205194Sdelphij return -1; 106205194Sdelphij } 107205194Sdelphij state->size = state->want; 108205194Sdelphij 109205194Sdelphij /* allocate inflate memory */ 110205194Sdelphij state->strm.zalloc = Z_NULL; 111205194Sdelphij state->strm.zfree = Z_NULL; 112205194Sdelphij state->strm.opaque = Z_NULL; 113205194Sdelphij state->strm.avail_in = 0; 114205194Sdelphij state->strm.next_in = Z_NULL; 115237410Sdelphij if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) { /* gunzip */ 116205194Sdelphij free(state->out); 117205194Sdelphij free(state->in); 118205194Sdelphij state->size = 0; 119205194Sdelphij gz_error(state, Z_MEM_ERROR, "out of memory"); 120205194Sdelphij return -1; 121205194Sdelphij } 122205194Sdelphij } 123205194Sdelphij 124237410Sdelphij /* get at least the magic bytes in the input buffer */ 125237410Sdelphij if (strm->avail_in < 2) { 126205194Sdelphij if (gz_avail(state) == -1) 127205194Sdelphij return -1; 128205194Sdelphij if (strm->avail_in == 0) 129205194Sdelphij return 0; 130205194Sdelphij } 131205194Sdelphij 132237410Sdelphij /* look for gzip magic bytes -- if there, do gzip decoding (note: there is 133237410Sdelphij a logical dilemma here when considering the case of a partially written 134237410Sdelphij gzip file, to wit, if a single 31 byte is written, then we cannot tell 135237410Sdelphij whether this is a single-byte file, or just a partially written gzip 136237410Sdelphij file -- for here we assume that if a gzip file is being written, then 137237410Sdelphij the header will be written in a single operation, so that reading a 138237410Sdelphij single byte is sufficient indication that it is not a gzip file) */ 139237410Sdelphij if (strm->avail_in > 1 && 140237410Sdelphij strm->next_in[0] == 31 && strm->next_in[1] == 139) { 141237410Sdelphij inflateReset(strm); 142237410Sdelphij state->how = GZIP; 143237410Sdelphij state->direct = 0; 144237410Sdelphij return 0; 145237410Sdelphij } 146205194Sdelphij 147237410Sdelphij /* no gzip header -- if we were decoding gzip before, then this is trailing 148237410Sdelphij garbage. Ignore the trailing garbage and finish. */ 149237410Sdelphij if (state->direct == 0) { 150237410Sdelphij strm->avail_in = 0; 151237410Sdelphij state->eof = 1; 152237410Sdelphij state->x.have = 0; 153237410Sdelphij return 0; 154205194Sdelphij } 155205194Sdelphij 156237410Sdelphij /* doing raw i/o, copy any leftover input to output -- this assumes that 157237410Sdelphij the output buffer is larger than the input buffer, which also assures 158237410Sdelphij space for gzungetc() */ 159237410Sdelphij state->x.next = state->out; 160205194Sdelphij if (strm->avail_in) { 161237410Sdelphij memcpy(state->x.next, strm->next_in, strm->avail_in); 162237410Sdelphij state->x.have = strm->avail_in; 163205194Sdelphij strm->avail_in = 0; 164205194Sdelphij } 165205194Sdelphij state->how = COPY; 166205194Sdelphij state->direct = 1; 167205194Sdelphij return 0; 168205194Sdelphij} 169205194Sdelphij 170205194Sdelphij/* Decompress from input to the provided next_out and avail_out in the state. 171237410Sdelphij On return, state->x.have and state->x.next point to the just decompressed 172237410Sdelphij data. If the gzip stream completes, state->how is reset to LOOK to look for 173237410Sdelphij the next gzip stream or raw data, once state->x.have is depleted. Returns 0 174237410Sdelphij on success, -1 on failure. */ 175205194Sdelphijlocal int gz_decomp(state) 176205194Sdelphij gz_statep state; 177205194Sdelphij{ 178237410Sdelphij int ret = Z_OK; 179205194Sdelphij unsigned had; 180205194Sdelphij z_streamp strm = &(state->strm); 181205194Sdelphij 182205194Sdelphij /* fill output buffer up to end of deflate stream */ 183205194Sdelphij had = strm->avail_out; 184205194Sdelphij do { 185205194Sdelphij /* get more input for inflate() */ 186205194Sdelphij if (strm->avail_in == 0 && gz_avail(state) == -1) 187205194Sdelphij return -1; 188205194Sdelphij if (strm->avail_in == 0) { 189237410Sdelphij gz_error(state, Z_BUF_ERROR, "unexpected end of file"); 190237410Sdelphij break; 191205194Sdelphij } 192205194Sdelphij 193205194Sdelphij /* decompress and handle errors */ 194205194Sdelphij ret = inflate(strm, Z_NO_FLUSH); 195205194Sdelphij if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { 196205194Sdelphij gz_error(state, Z_STREAM_ERROR, 197237410Sdelphij "internal error: inflate stream corrupt"); 198205194Sdelphij return -1; 199205194Sdelphij } 200205194Sdelphij if (ret == Z_MEM_ERROR) { 201205194Sdelphij gz_error(state, Z_MEM_ERROR, "out of memory"); 202205194Sdelphij return -1; 203205194Sdelphij } 204205194Sdelphij if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ 205205194Sdelphij gz_error(state, Z_DATA_ERROR, 206237410Sdelphij strm->msg == NULL ? "compressed data error" : strm->msg); 207205194Sdelphij return -1; 208205194Sdelphij } 209205194Sdelphij } while (strm->avail_out && ret != Z_STREAM_END); 210205194Sdelphij 211237410Sdelphij /* update available output */ 212237410Sdelphij state->x.have = had - strm->avail_out; 213237410Sdelphij state->x.next = strm->next_out - state->x.have; 214205194Sdelphij 215237410Sdelphij /* if the gzip stream completed successfully, look for another */ 216237410Sdelphij if (ret == Z_STREAM_END) 217237410Sdelphij state->how = LOOK; 218205194Sdelphij 219205194Sdelphij /* good decompression */ 220205194Sdelphij return 0; 221205194Sdelphij} 222205194Sdelphij 223237410Sdelphij/* Fetch data and put it in the output buffer. Assumes state->x.have is 0. 224205194Sdelphij Data is either copied from the input file or decompressed from the input 225205194Sdelphij file depending on state->how. If state->how is LOOK, then a gzip header is 226237410Sdelphij looked for to determine whether to copy or decompress. Returns -1 on error, 227237410Sdelphij otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the 228237410Sdelphij end of the input file has been reached and all data has been processed. */ 229237410Sdelphijlocal int gz_fetch(state) 230205194Sdelphij gz_statep state; 231205194Sdelphij{ 232205194Sdelphij z_streamp strm = &(state->strm); 233205194Sdelphij 234237410Sdelphij do { 235237410Sdelphij switch(state->how) { 236237410Sdelphij case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */ 237237410Sdelphij if (gz_look(state) == -1) 238237410Sdelphij return -1; 239237410Sdelphij if (state->how == LOOK) 240237410Sdelphij return 0; 241237410Sdelphij break; 242237410Sdelphij case COPY: /* -> COPY */ 243237410Sdelphij if (gz_load(state, state->out, state->size << 1, &(state->x.have)) 244237410Sdelphij == -1) 245237410Sdelphij return -1; 246237410Sdelphij state->x.next = state->out; 247205194Sdelphij return 0; 248237410Sdelphij case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */ 249237410Sdelphij strm->avail_out = state->size << 1; 250237410Sdelphij strm->next_out = state->out; 251237410Sdelphij if (gz_decomp(state) == -1) 252237410Sdelphij return -1; 253237410Sdelphij } 254237410Sdelphij } while (state->x.have == 0 && (!state->eof || strm->avail_in)); 255205194Sdelphij return 0; 256205194Sdelphij} 257205194Sdelphij 258205194Sdelphij/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ 259205194Sdelphijlocal int gz_skip(state, len) 260205194Sdelphij gz_statep state; 261205194Sdelphij z_off64_t len; 262205194Sdelphij{ 263205194Sdelphij unsigned n; 264205194Sdelphij 265205194Sdelphij /* skip over len bytes or reach end-of-file, whichever comes first */ 266205194Sdelphij while (len) 267205194Sdelphij /* skip over whatever is in output buffer */ 268237410Sdelphij if (state->x.have) { 269237410Sdelphij n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ? 270237410Sdelphij (unsigned)len : state->x.have; 271237410Sdelphij state->x.have -= n; 272237410Sdelphij state->x.next += n; 273237410Sdelphij state->x.pos += n; 274205194Sdelphij len -= n; 275205194Sdelphij } 276205194Sdelphij 277205194Sdelphij /* output buffer empty -- return if we're at the end of the input */ 278205194Sdelphij else if (state->eof && state->strm.avail_in == 0) 279205194Sdelphij break; 280205194Sdelphij 281205194Sdelphij /* need more data to skip -- load up output buffer */ 282205194Sdelphij else { 283205194Sdelphij /* get more output, looking for header if required */ 284237410Sdelphij if (gz_fetch(state) == -1) 285205194Sdelphij return -1; 286205194Sdelphij } 287205194Sdelphij return 0; 288205194Sdelphij} 289205194Sdelphij 290205194Sdelphij/* -- see zlib.h -- */ 291205194Sdelphijint ZEXPORT gzread(file, buf, len) 292205194Sdelphij gzFile file; 293205194Sdelphij voidp buf; 294205194Sdelphij unsigned len; 295205194Sdelphij{ 296205194Sdelphij unsigned got, n; 297205194Sdelphij gz_statep state; 298205194Sdelphij z_streamp strm; 299205194Sdelphij 300205194Sdelphij /* get internal structure */ 301205194Sdelphij if (file == NULL) 302205194Sdelphij return -1; 303205194Sdelphij state = (gz_statep)file; 304205194Sdelphij strm = &(state->strm); 305205194Sdelphij 306237410Sdelphij /* check that we're reading and that there's no (serious) error */ 307237410Sdelphij if (state->mode != GZ_READ || 308237410Sdelphij (state->err != Z_OK && state->err != Z_BUF_ERROR)) 309205194Sdelphij return -1; 310205194Sdelphij 311205194Sdelphij /* since an int is returned, make sure len fits in one, otherwise return 312205194Sdelphij with an error (this avoids the flaw in the interface) */ 313205194Sdelphij if ((int)len < 0) { 314237410Sdelphij gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); 315205194Sdelphij return -1; 316205194Sdelphij } 317205194Sdelphij 318205194Sdelphij /* if len is zero, avoid unnecessary operations */ 319205194Sdelphij if (len == 0) 320205194Sdelphij return 0; 321205194Sdelphij 322205194Sdelphij /* process a skip request */ 323205194Sdelphij if (state->seek) { 324205194Sdelphij state->seek = 0; 325205194Sdelphij if (gz_skip(state, state->skip) == -1) 326205194Sdelphij return -1; 327205194Sdelphij } 328205194Sdelphij 329205194Sdelphij /* get len bytes to buf, or less than len if at the end */ 330205194Sdelphij got = 0; 331205194Sdelphij do { 332205194Sdelphij /* first just try copying data from the output buffer */ 333237410Sdelphij if (state->x.have) { 334237410Sdelphij n = state->x.have > len ? len : state->x.have; 335237410Sdelphij memcpy(buf, state->x.next, n); 336237410Sdelphij state->x.next += n; 337237410Sdelphij state->x.have -= n; 338205194Sdelphij } 339205194Sdelphij 340205194Sdelphij /* output buffer empty -- return if we're at the end of the input */ 341237410Sdelphij else if (state->eof && strm->avail_in == 0) { 342237410Sdelphij state->past = 1; /* tried to read past end */ 343205194Sdelphij break; 344237410Sdelphij } 345205194Sdelphij 346205194Sdelphij /* need output data -- for small len or new stream load up our output 347205194Sdelphij buffer */ 348205194Sdelphij else if (state->how == LOOK || len < (state->size << 1)) { 349205194Sdelphij /* get more output, looking for header if required */ 350237410Sdelphij if (gz_fetch(state) == -1) 351205194Sdelphij return -1; 352237410Sdelphij continue; /* no progress yet -- go back to copy above */ 353205194Sdelphij /* the copy above assures that we will leave with space in the 354205194Sdelphij output buffer, allowing at least one gzungetc() to succeed */ 355205194Sdelphij } 356205194Sdelphij 357205194Sdelphij /* large len -- read directly into user buffer */ 358205194Sdelphij else if (state->how == COPY) { /* read directly */ 359250261Sdelphij if (gz_load(state, (unsigned char *)buf, len, &n) == -1) 360205194Sdelphij return -1; 361205194Sdelphij } 362205194Sdelphij 363205194Sdelphij /* large len -- decompress directly into user buffer */ 364205194Sdelphij else { /* state->how == GZIP */ 365205194Sdelphij strm->avail_out = len; 366250261Sdelphij strm->next_out = (unsigned char *)buf; 367205194Sdelphij if (gz_decomp(state) == -1) 368205194Sdelphij return -1; 369237410Sdelphij n = state->x.have; 370237410Sdelphij state->x.have = 0; 371205194Sdelphij } 372205194Sdelphij 373205194Sdelphij /* update progress */ 374205194Sdelphij len -= n; 375205194Sdelphij buf = (char *)buf + n; 376205194Sdelphij got += n; 377237410Sdelphij state->x.pos += n; 378205194Sdelphij } while (len); 379205194Sdelphij 380205194Sdelphij /* return number of bytes read into user buffer (will fit in int) */ 381205194Sdelphij return (int)got; 382205194Sdelphij} 383205194Sdelphij 384205194Sdelphij/* -- see zlib.h -- */ 385250261Sdelphij#ifdef Z_PREFIX_SET 386250261Sdelphij# undef z_gzgetc 387250261Sdelphij#else 388250261Sdelphij# undef gzgetc 389250261Sdelphij#endif 390205194Sdelphijint ZEXPORT gzgetc(file) 391205194Sdelphij gzFile file; 392205194Sdelphij{ 393205194Sdelphij int ret; 394205194Sdelphij unsigned char buf[1]; 395205194Sdelphij gz_statep state; 396205194Sdelphij 397205194Sdelphij /* get internal structure */ 398205194Sdelphij if (file == NULL) 399205194Sdelphij return -1; 400205194Sdelphij state = (gz_statep)file; 401205194Sdelphij 402237410Sdelphij /* check that we're reading and that there's no (serious) error */ 403237410Sdelphij if (state->mode != GZ_READ || 404237410Sdelphij (state->err != Z_OK && state->err != Z_BUF_ERROR)) 405205194Sdelphij return -1; 406205194Sdelphij 407205194Sdelphij /* try output buffer (no need to check for skip request) */ 408237410Sdelphij if (state->x.have) { 409237410Sdelphij state->x.have--; 410237410Sdelphij state->x.pos++; 411237410Sdelphij return *(state->x.next)++; 412205194Sdelphij } 413205194Sdelphij 414205194Sdelphij /* nothing there -- try gzread() */ 415205194Sdelphij ret = gzread(file, buf, 1); 416205194Sdelphij return ret < 1 ? -1 : buf[0]; 417205194Sdelphij} 418205194Sdelphij 419237410Sdelphijint ZEXPORT gzgetc_(file) 420237410SdelphijgzFile file; 421237410Sdelphij{ 422237410Sdelphij return gzgetc(file); 423237410Sdelphij} 424237410Sdelphij 425205194Sdelphij/* -- see zlib.h -- */ 426205194Sdelphijint ZEXPORT gzungetc(c, file) 427205194Sdelphij int c; 428205194Sdelphij gzFile file; 429205194Sdelphij{ 430205194Sdelphij gz_statep state; 431205194Sdelphij 432205194Sdelphij /* get internal structure */ 433205194Sdelphij if (file == NULL) 434205194Sdelphij return -1; 435205194Sdelphij state = (gz_statep)file; 436205194Sdelphij 437237410Sdelphij /* check that we're reading and that there's no (serious) error */ 438237410Sdelphij if (state->mode != GZ_READ || 439237410Sdelphij (state->err != Z_OK && state->err != Z_BUF_ERROR)) 440205194Sdelphij return -1; 441205194Sdelphij 442205194Sdelphij /* process a skip request */ 443205194Sdelphij if (state->seek) { 444205194Sdelphij state->seek = 0; 445205194Sdelphij if (gz_skip(state, state->skip) == -1) 446205194Sdelphij return -1; 447205194Sdelphij } 448205194Sdelphij 449205194Sdelphij /* can't push EOF */ 450205194Sdelphij if (c < 0) 451205194Sdelphij return -1; 452205194Sdelphij 453205194Sdelphij /* if output buffer empty, put byte at end (allows more pushing) */ 454237410Sdelphij if (state->x.have == 0) { 455237410Sdelphij state->x.have = 1; 456237410Sdelphij state->x.next = state->out + (state->size << 1) - 1; 457237410Sdelphij state->x.next[0] = c; 458237410Sdelphij state->x.pos--; 459237410Sdelphij state->past = 0; 460205194Sdelphij return c; 461205194Sdelphij } 462205194Sdelphij 463205194Sdelphij /* if no room, give up (must have already done a gzungetc()) */ 464237410Sdelphij if (state->x.have == (state->size << 1)) { 465237410Sdelphij gz_error(state, Z_DATA_ERROR, "out of room to push characters"); 466205194Sdelphij return -1; 467205194Sdelphij } 468205194Sdelphij 469205194Sdelphij /* slide output data if needed and insert byte before existing data */ 470237410Sdelphij if (state->x.next == state->out) { 471237410Sdelphij unsigned char *src = state->out + state->x.have; 472205194Sdelphij unsigned char *dest = state->out + (state->size << 1); 473205194Sdelphij while (src > state->out) 474205194Sdelphij *--dest = *--src; 475237410Sdelphij state->x.next = dest; 476205194Sdelphij } 477237410Sdelphij state->x.have++; 478237410Sdelphij state->x.next--; 479237410Sdelphij state->x.next[0] = c; 480237410Sdelphij state->x.pos--; 481237410Sdelphij state->past = 0; 482205194Sdelphij return c; 483205194Sdelphij} 484205194Sdelphij 485205194Sdelphij/* -- see zlib.h -- */ 486205194Sdelphijchar * ZEXPORT gzgets(file, buf, len) 487205194Sdelphij gzFile file; 488205194Sdelphij char *buf; 489205194Sdelphij int len; 490205194Sdelphij{ 491205194Sdelphij unsigned left, n; 492205194Sdelphij char *str; 493205194Sdelphij unsigned char *eol; 494205194Sdelphij gz_statep state; 495205194Sdelphij 496205194Sdelphij /* check parameters and get internal structure */ 497205194Sdelphij if (file == NULL || buf == NULL || len < 1) 498205194Sdelphij return NULL; 499205194Sdelphij state = (gz_statep)file; 500205194Sdelphij 501237410Sdelphij /* check that we're reading and that there's no (serious) error */ 502237410Sdelphij if (state->mode != GZ_READ || 503237410Sdelphij (state->err != Z_OK && state->err != Z_BUF_ERROR)) 504205194Sdelphij return NULL; 505205194Sdelphij 506205194Sdelphij /* process a skip request */ 507205194Sdelphij if (state->seek) { 508205194Sdelphij state->seek = 0; 509205194Sdelphij if (gz_skip(state, state->skip) == -1) 510205194Sdelphij return NULL; 511205194Sdelphij } 512205194Sdelphij 513205194Sdelphij /* copy output bytes up to new line or len - 1, whichever comes first -- 514205194Sdelphij append a terminating zero to the string (we don't check for a zero in 515205194Sdelphij the contents, let the user worry about that) */ 516205194Sdelphij str = buf; 517205194Sdelphij left = (unsigned)len - 1; 518205194Sdelphij if (left) do { 519205194Sdelphij /* assure that something is in the output buffer */ 520237410Sdelphij if (state->x.have == 0 && gz_fetch(state) == -1) 521237410Sdelphij return NULL; /* error */ 522237410Sdelphij if (state->x.have == 0) { /* end of file */ 523237410Sdelphij state->past = 1; /* read past end */ 524237410Sdelphij break; /* return what we have */ 525205194Sdelphij } 526205194Sdelphij 527205194Sdelphij /* look for end-of-line in current output buffer */ 528237410Sdelphij n = state->x.have > left ? left : state->x.have; 529250261Sdelphij eol = (unsigned char *)memchr(state->x.next, '\n', n); 530205194Sdelphij if (eol != NULL) 531237410Sdelphij n = (unsigned)(eol - state->x.next) + 1; 532205194Sdelphij 533205194Sdelphij /* copy through end-of-line, or remainder if not found */ 534237410Sdelphij memcpy(buf, state->x.next, n); 535237410Sdelphij state->x.have -= n; 536237410Sdelphij state->x.next += n; 537237410Sdelphij state->x.pos += n; 538205194Sdelphij left -= n; 539205194Sdelphij buf += n; 540205194Sdelphij } while (left && eol == NULL); 541205194Sdelphij 542237410Sdelphij /* return terminated string, or if nothing, end of file */ 543237410Sdelphij if (buf == str) 544237410Sdelphij return NULL; 545205194Sdelphij buf[0] = 0; 546205194Sdelphij return str; 547205194Sdelphij} 548205194Sdelphij 549205194Sdelphij/* -- see zlib.h -- */ 550205194Sdelphijint ZEXPORT gzdirect(file) 551205194Sdelphij gzFile file; 552205194Sdelphij{ 553205194Sdelphij gz_statep state; 554205194Sdelphij 555205194Sdelphij /* get internal structure */ 556205194Sdelphij if (file == NULL) 557205194Sdelphij return 0; 558205194Sdelphij state = (gz_statep)file; 559205194Sdelphij 560205194Sdelphij /* if the state is not known, but we can find out, then do so (this is 561205194Sdelphij mainly for right after a gzopen() or gzdopen()) */ 562237410Sdelphij if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) 563237410Sdelphij (void)gz_look(state); 564205194Sdelphij 565237410Sdelphij /* return 1 if transparent, 0 if processing a gzip stream */ 566205194Sdelphij return state->direct; 567205194Sdelphij} 568205194Sdelphij 569205194Sdelphij/* -- see zlib.h -- */ 570205194Sdelphijint ZEXPORT gzclose_r(file) 571205194Sdelphij gzFile file; 572205194Sdelphij{ 573237410Sdelphij int ret, err; 574205194Sdelphij gz_statep state; 575205194Sdelphij 576205194Sdelphij /* get internal structure */ 577205194Sdelphij if (file == NULL) 578205194Sdelphij return Z_STREAM_ERROR; 579205194Sdelphij state = (gz_statep)file; 580205194Sdelphij 581205194Sdelphij /* check that we're reading */ 582205194Sdelphij if (state->mode != GZ_READ) 583205194Sdelphij return Z_STREAM_ERROR; 584205194Sdelphij 585205194Sdelphij /* free memory and close file */ 586205194Sdelphij if (state->size) { 587205194Sdelphij inflateEnd(&(state->strm)); 588205194Sdelphij free(state->out); 589205194Sdelphij free(state->in); 590205194Sdelphij } 591237410Sdelphij err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK; 592205194Sdelphij gz_error(state, Z_OK, NULL); 593205194Sdelphij free(state->path); 594205194Sdelphij ret = close(state->fd); 595205194Sdelphij free(state); 596237410Sdelphij return ret ? Z_ERRNO : err; 597205194Sdelphij} 598