1205194Sdelphij/* gzread.c -- zlib functions for reading gzip files 2311285Sdelphij * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler 3205194Sdelphij * For conditions of distribution and use, see copyright notice in zlib.h 4205194Sdelphij */ 5205194Sdelphij 6311275Sdelphij/* $FreeBSD: stable/11/sys/contrib/zlib/gzread.c 311285 2017-01-04 16:09:08Z delphij $ */ 7311275Sdelphij 8205194Sdelphij#include "gzguts.h" 9311275Sdelphij#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)); 14230837Sdelphijlocal int gz_look OF((gz_statep)); 15205194Sdelphijlocal int gz_decomp OF((gz_statep)); 16230837Sdelphijlocal int gz_fetch OF((gz_statep)); 17205194Sdelphijlocal int gz_skip OF((gz_statep, z_off64_t)); 18311285Sdelphijlocal z_size_t gz_read OF((gz_statep, voidp, z_size_t)); 19205194Sdelphij 20205194Sdelphij/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from 21205194Sdelphij state->fd, and update state->eof, state->err, and state->msg as appropriate. 22205194Sdelphij This function needs to loop on read(), since read() is not guaranteed to 23205194Sdelphij read the number of bytes requested, depending on the type of descriptor. */ 24205194Sdelphijlocal int gz_load(state, buf, len, have) 25205194Sdelphij gz_statep state; 26205194Sdelphij unsigned char *buf; 27205194Sdelphij unsigned len; 28205194Sdelphij unsigned *have; 29205194Sdelphij{ 30205194Sdelphij int ret; 31311285Sdelphij unsigned get, max = ((unsigned)-1 >> 2) + 1; 32205194Sdelphij 33205194Sdelphij *have = 0; 34205194Sdelphij do { 35311285Sdelphij get = len - *have; 36311285Sdelphij if (get > max) 37311285Sdelphij get = max; 38311285Sdelphij ret = read(state->fd, buf + *have, get); 39205194Sdelphij if (ret <= 0) 40205194Sdelphij break; 41311285Sdelphij *have += (unsigned)ret; 42205194Sdelphij } while (*have < len); 43205194Sdelphij if (ret < 0) { 44205194Sdelphij gz_error(state, Z_ERRNO, zstrerror()); 45205194Sdelphij return -1; 46205194Sdelphij } 47205194Sdelphij if (ret == 0) 48205194Sdelphij state->eof = 1; 49205194Sdelphij return 0; 50205194Sdelphij} 51205194Sdelphij 52205194Sdelphij/* Load up input buffer and set eof flag if last data loaded -- return -1 on 53205194Sdelphij error, 0 otherwise. Note that the eof flag is set when the end of the input 54205194Sdelphij file is reached, even though there may be unused data in the buffer. Once 55205194Sdelphij that data has been used, no more attempts will be made to read the file. 56230837Sdelphij If strm->avail_in != 0, then the current data is moved to the beginning of 57230837Sdelphij the input buffer, and then the remainder of the buffer is loaded with the 58230837Sdelphij available data from the input file. */ 59205194Sdelphijlocal int gz_avail(state) 60205194Sdelphij gz_statep state; 61205194Sdelphij{ 62230837Sdelphij unsigned got; 63205194Sdelphij z_streamp strm = &(state->strm); 64205194Sdelphij 65230837Sdelphij if (state->err != Z_OK && state->err != Z_BUF_ERROR) 66205194Sdelphij return -1; 67205194Sdelphij if (state->eof == 0) { 68237248Sdelphij if (strm->avail_in) { /* copy what's there to the start */ 69250224Sdelphij unsigned char *p = state->in; 70250224Sdelphij unsigned const char *q = strm->next_in; 71237248Sdelphij unsigned n = strm->avail_in; 72237248Sdelphij do { 73237248Sdelphij *p++ = *q++; 74237248Sdelphij } while (--n); 75237248Sdelphij } 76230837Sdelphij if (gz_load(state, state->in + strm->avail_in, 77230837Sdelphij state->size - strm->avail_in, &got) == -1) 78205194Sdelphij return -1; 79230837Sdelphij strm->avail_in += got; 80205194Sdelphij strm->next_in = state->in; 81205194Sdelphij } 82205194Sdelphij return 0; 83205194Sdelphij} 84205194Sdelphij 85230837Sdelphij/* Look for gzip header, set up for inflate or copy. state->x.have must be 0. 86205194Sdelphij If this is the first time in, allocate required memory. state->how will be 87205194Sdelphij left unchanged if there is no more input data available, will be set to COPY 88205194Sdelphij if there is no gzip header and direct copying will be performed, or it will 89230837Sdelphij be set to GZIP for decompression. If direct copying, then leftover input 90230837Sdelphij data from the input buffer will be copied to the output buffer. In that 91230837Sdelphij case, all further file reads will be directly to either the output buffer or 92230837Sdelphij a user buffer. If decompressing, the inflate state will be initialized. 93230837Sdelphij gz_look() will return 0 on success or -1 on failure. */ 94230837Sdelphijlocal int gz_look(state) 95205194Sdelphij gz_statep state; 96205194Sdelphij{ 97205194Sdelphij z_streamp strm = &(state->strm); 98205194Sdelphij 99205194Sdelphij /* allocate read buffers and inflate memory */ 100205194Sdelphij if (state->size == 0) { 101205194Sdelphij /* allocate buffers */ 102250224Sdelphij state->in = (unsigned char *)malloc(state->want); 103250224Sdelphij state->out = (unsigned char *)malloc(state->want << 1); 104205194Sdelphij if (state->in == NULL || state->out == NULL) { 105311285Sdelphij free(state->out); 106311285Sdelphij free(state->in); 107205194Sdelphij gz_error(state, Z_MEM_ERROR, "out of memory"); 108205194Sdelphij return -1; 109205194Sdelphij } 110205194Sdelphij state->size = state->want; 111205194Sdelphij 112205194Sdelphij /* allocate inflate memory */ 113205194Sdelphij state->strm.zalloc = Z_NULL; 114205194Sdelphij state->strm.zfree = Z_NULL; 115205194Sdelphij state->strm.opaque = Z_NULL; 116205194Sdelphij state->strm.avail_in = 0; 117205194Sdelphij state->strm.next_in = Z_NULL; 118230837Sdelphij if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) { /* gunzip */ 119205194Sdelphij free(state->out); 120205194Sdelphij free(state->in); 121205194Sdelphij state->size = 0; 122205194Sdelphij gz_error(state, Z_MEM_ERROR, "out of memory"); 123205194Sdelphij return -1; 124205194Sdelphij } 125205194Sdelphij } 126205194Sdelphij 127230837Sdelphij /* get at least the magic bytes in the input buffer */ 128230837Sdelphij if (strm->avail_in < 2) { 129205194Sdelphij if (gz_avail(state) == -1) 130205194Sdelphij return -1; 131205194Sdelphij if (strm->avail_in == 0) 132205194Sdelphij return 0; 133205194Sdelphij } 134205194Sdelphij 135230837Sdelphij /* look for gzip magic bytes -- if there, do gzip decoding (note: there is 136230837Sdelphij a logical dilemma here when considering the case of a partially written 137230837Sdelphij gzip file, to wit, if a single 31 byte is written, then we cannot tell 138230837Sdelphij whether this is a single-byte file, or just a partially written gzip 139230837Sdelphij file -- for here we assume that if a gzip file is being written, then 140230837Sdelphij the header will be written in a single operation, so that reading a 141230837Sdelphij single byte is sufficient indication that it is not a gzip file) */ 142230837Sdelphij if (strm->avail_in > 1 && 143230837Sdelphij strm->next_in[0] == 31 && strm->next_in[1] == 139) { 144230837Sdelphij inflateReset(strm); 145230837Sdelphij state->how = GZIP; 146230837Sdelphij state->direct = 0; 147230837Sdelphij return 0; 148230837Sdelphij } 149205194Sdelphij 150230837Sdelphij /* no gzip header -- if we were decoding gzip before, then this is trailing 151230837Sdelphij garbage. Ignore the trailing garbage and finish. */ 152230837Sdelphij if (state->direct == 0) { 153230837Sdelphij strm->avail_in = 0; 154230837Sdelphij state->eof = 1; 155230837Sdelphij state->x.have = 0; 156230837Sdelphij return 0; 157205194Sdelphij } 158205194Sdelphij 159230837Sdelphij /* doing raw i/o, copy any leftover input to output -- this assumes that 160230837Sdelphij the output buffer is larger than the input buffer, which also assures 161230837Sdelphij space for gzungetc() */ 162230837Sdelphij state->x.next = state->out; 163205194Sdelphij if (strm->avail_in) { 164230837Sdelphij memcpy(state->x.next, strm->next_in, strm->avail_in); 165230837Sdelphij state->x.have = strm->avail_in; 166205194Sdelphij strm->avail_in = 0; 167205194Sdelphij } 168205194Sdelphij state->how = COPY; 169205194Sdelphij state->direct = 1; 170205194Sdelphij return 0; 171205194Sdelphij} 172205194Sdelphij 173205194Sdelphij/* Decompress from input to the provided next_out and avail_out in the state. 174230837Sdelphij On return, state->x.have and state->x.next point to the just decompressed 175230837Sdelphij data. If the gzip stream completes, state->how is reset to LOOK to look for 176230837Sdelphij the next gzip stream or raw data, once state->x.have is depleted. Returns 0 177230837Sdelphij on success, -1 on failure. */ 178205194Sdelphijlocal int gz_decomp(state) 179205194Sdelphij gz_statep state; 180205194Sdelphij{ 181230837Sdelphij int ret = Z_OK; 182205194Sdelphij unsigned had; 183205194Sdelphij z_streamp strm = &(state->strm); 184205194Sdelphij 185205194Sdelphij /* fill output buffer up to end of deflate stream */ 186205194Sdelphij had = strm->avail_out; 187205194Sdelphij do { 188205194Sdelphij /* get more input for inflate() */ 189205194Sdelphij if (strm->avail_in == 0 && gz_avail(state) == -1) 190205194Sdelphij return -1; 191205194Sdelphij if (strm->avail_in == 0) { 192230837Sdelphij gz_error(state, Z_BUF_ERROR, "unexpected end of file"); 193230837Sdelphij break; 194205194Sdelphij } 195205194Sdelphij 196205194Sdelphij /* decompress and handle errors */ 197205194Sdelphij ret = inflate(strm, Z_NO_FLUSH); 198205194Sdelphij if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { 199205194Sdelphij gz_error(state, Z_STREAM_ERROR, 200230837Sdelphij "internal error: inflate stream corrupt"); 201205194Sdelphij return -1; 202205194Sdelphij } 203205194Sdelphij if (ret == Z_MEM_ERROR) { 204205194Sdelphij gz_error(state, Z_MEM_ERROR, "out of memory"); 205205194Sdelphij return -1; 206205194Sdelphij } 207205194Sdelphij if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ 208205194Sdelphij gz_error(state, Z_DATA_ERROR, 209230837Sdelphij strm->msg == NULL ? "compressed data error" : strm->msg); 210205194Sdelphij return -1; 211205194Sdelphij } 212205194Sdelphij } while (strm->avail_out && ret != Z_STREAM_END); 213205194Sdelphij 214230837Sdelphij /* update available output */ 215230837Sdelphij state->x.have = had - strm->avail_out; 216230837Sdelphij state->x.next = strm->next_out - state->x.have; 217205194Sdelphij 218230837Sdelphij /* if the gzip stream completed successfully, look for another */ 219230837Sdelphij if (ret == Z_STREAM_END) 220230837Sdelphij state->how = LOOK; 221205194Sdelphij 222205194Sdelphij /* good decompression */ 223205194Sdelphij return 0; 224205194Sdelphij} 225205194Sdelphij 226230837Sdelphij/* Fetch data and put it in the output buffer. Assumes state->x.have is 0. 227205194Sdelphij Data is either copied from the input file or decompressed from the input 228205194Sdelphij file depending on state->how. If state->how is LOOK, then a gzip header is 229230837Sdelphij looked for to determine whether to copy or decompress. Returns -1 on error, 230230837Sdelphij otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the 231230837Sdelphij end of the input file has been reached and all data has been processed. */ 232230837Sdelphijlocal int gz_fetch(state) 233205194Sdelphij gz_statep state; 234205194Sdelphij{ 235205194Sdelphij z_streamp strm = &(state->strm); 236205194Sdelphij 237230837Sdelphij do { 238230837Sdelphij switch(state->how) { 239230837Sdelphij case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */ 240230837Sdelphij if (gz_look(state) == -1) 241230837Sdelphij return -1; 242230837Sdelphij if (state->how == LOOK) 243230837Sdelphij return 0; 244230837Sdelphij break; 245230837Sdelphij case COPY: /* -> COPY */ 246230837Sdelphij if (gz_load(state, state->out, state->size << 1, &(state->x.have)) 247230837Sdelphij == -1) 248230837Sdelphij return -1; 249230837Sdelphij state->x.next = state->out; 250205194Sdelphij return 0; 251230837Sdelphij case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */ 252230837Sdelphij strm->avail_out = state->size << 1; 253230837Sdelphij strm->next_out = state->out; 254230837Sdelphij if (gz_decomp(state) == -1) 255230837Sdelphij return -1; 256230837Sdelphij } 257230837Sdelphij } while (state->x.have == 0 && (!state->eof || strm->avail_in)); 258205194Sdelphij return 0; 259205194Sdelphij} 260205194Sdelphij 261205194Sdelphij/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ 262205194Sdelphijlocal int gz_skip(state, len) 263205194Sdelphij gz_statep state; 264205194Sdelphij z_off64_t len; 265205194Sdelphij{ 266205194Sdelphij unsigned n; 267205194Sdelphij 268205194Sdelphij /* skip over len bytes or reach end-of-file, whichever comes first */ 269205194Sdelphij while (len) 270205194Sdelphij /* skip over whatever is in output buffer */ 271230837Sdelphij if (state->x.have) { 272230837Sdelphij n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ? 273230837Sdelphij (unsigned)len : state->x.have; 274230837Sdelphij state->x.have -= n; 275230837Sdelphij state->x.next += n; 276230837Sdelphij state->x.pos += n; 277205194Sdelphij len -= n; 278205194Sdelphij } 279205194Sdelphij 280205194Sdelphij /* output buffer empty -- return if we're at the end of the input */ 281205194Sdelphij else if (state->eof && state->strm.avail_in == 0) 282205194Sdelphij break; 283205194Sdelphij 284205194Sdelphij /* need more data to skip -- load up output buffer */ 285205194Sdelphij else { 286205194Sdelphij /* get more output, looking for header if required */ 287230837Sdelphij if (gz_fetch(state) == -1) 288205194Sdelphij return -1; 289205194Sdelphij } 290205194Sdelphij return 0; 291205194Sdelphij} 292205194Sdelphij 293311285Sdelphij/* Read len bytes into buf from file, or less than len up to the end of the 294311285Sdelphij input. Return the number of bytes read. If zero is returned, either the 295311285Sdelphij end of file was reached, or there was an error. state->err must be 296311285Sdelphij consulted in that case to determine which. */ 297311285Sdelphijlocal z_size_t gz_read(state, buf, len) 298311285Sdelphij gz_statep state; 299205194Sdelphij voidp buf; 300311285Sdelphij z_size_t len; 301205194Sdelphij{ 302311285Sdelphij z_size_t got; 303311285Sdelphij unsigned n; 304205194Sdelphij 305205194Sdelphij /* if len is zero, avoid unnecessary operations */ 306205194Sdelphij if (len == 0) 307205194Sdelphij return 0; 308205194Sdelphij 309205194Sdelphij /* process a skip request */ 310205194Sdelphij if (state->seek) { 311205194Sdelphij state->seek = 0; 312205194Sdelphij if (gz_skip(state, state->skip) == -1) 313311285Sdelphij return 0; 314205194Sdelphij } 315205194Sdelphij 316205194Sdelphij /* get len bytes to buf, or less than len if at the end */ 317205194Sdelphij got = 0; 318205194Sdelphij do { 319311285Sdelphij /* set n to the maximum amount of len that fits in an unsigned int */ 320311285Sdelphij n = -1; 321311285Sdelphij if (n > len) 322311285Sdelphij n = len; 323311285Sdelphij 324205194Sdelphij /* first just try copying data from the output buffer */ 325230837Sdelphij if (state->x.have) { 326311285Sdelphij if (state->x.have < n) 327311285Sdelphij n = state->x.have; 328230837Sdelphij memcpy(buf, state->x.next, n); 329230837Sdelphij state->x.next += n; 330230837Sdelphij state->x.have -= n; 331205194Sdelphij } 332205194Sdelphij 333205194Sdelphij /* output buffer empty -- return if we're at the end of the input */ 334311285Sdelphij else if (state->eof && state->strm.avail_in == 0) { 335230837Sdelphij state->past = 1; /* tried to read past end */ 336205194Sdelphij break; 337230837Sdelphij } 338205194Sdelphij 339205194Sdelphij /* need output data -- for small len or new stream load up our output 340205194Sdelphij buffer */ 341311285Sdelphij else if (state->how == LOOK || n < (state->size << 1)) { 342205194Sdelphij /* get more output, looking for header if required */ 343230837Sdelphij if (gz_fetch(state) == -1) 344311285Sdelphij return 0; 345237248Sdelphij continue; /* no progress yet -- go back to copy above */ 346205194Sdelphij /* the copy above assures that we will leave with space in the 347205194Sdelphij output buffer, allowing at least one gzungetc() to succeed */ 348205194Sdelphij } 349205194Sdelphij 350205194Sdelphij /* large len -- read directly into user buffer */ 351205194Sdelphij else if (state->how == COPY) { /* read directly */ 352311285Sdelphij if (gz_load(state, (unsigned char *)buf, n, &n) == -1) 353311285Sdelphij return 0; 354205194Sdelphij } 355205194Sdelphij 356205194Sdelphij /* large len -- decompress directly into user buffer */ 357205194Sdelphij else { /* state->how == GZIP */ 358311285Sdelphij state->strm.avail_out = n; 359311285Sdelphij state->strm.next_out = (unsigned char *)buf; 360205194Sdelphij if (gz_decomp(state) == -1) 361311285Sdelphij return 0; 362230837Sdelphij n = state->x.have; 363230837Sdelphij state->x.have = 0; 364205194Sdelphij } 365205194Sdelphij 366205194Sdelphij /* update progress */ 367205194Sdelphij len -= n; 368205194Sdelphij buf = (char *)buf + n; 369205194Sdelphij got += n; 370230837Sdelphij state->x.pos += n; 371205194Sdelphij } while (len); 372205194Sdelphij 373311285Sdelphij /* return number of bytes read into user buffer */ 374311285Sdelphij return got; 375205194Sdelphij} 376205194Sdelphij 377205194Sdelphij/* -- see zlib.h -- */ 378311285Sdelphijint ZEXPORT gzread(file, buf, len) 379311285Sdelphij gzFile file; 380311285Sdelphij voidp buf; 381311285Sdelphij unsigned len; 382311285Sdelphij{ 383311285Sdelphij gz_statep state; 384311285Sdelphij 385311285Sdelphij /* get internal structure */ 386311285Sdelphij if (file == NULL) 387311285Sdelphij return -1; 388311285Sdelphij state = (gz_statep)file; 389311285Sdelphij 390311285Sdelphij /* check that we're reading and that there's no (serious) error */ 391311285Sdelphij if (state->mode != GZ_READ || 392311285Sdelphij (state->err != Z_OK && state->err != Z_BUF_ERROR)) 393311285Sdelphij return -1; 394311285Sdelphij 395311285Sdelphij /* since an int is returned, make sure len fits in one, otherwise return 396311285Sdelphij with an error (this avoids a flaw in the interface) */ 397311285Sdelphij if ((int)len < 0) { 398311285Sdelphij gz_error(state, Z_STREAM_ERROR, "request does not fit in an int"); 399311285Sdelphij return -1; 400311285Sdelphij } 401311285Sdelphij 402311285Sdelphij /* read len or fewer bytes to buf */ 403311285Sdelphij len = gz_read(state, buf, len); 404311285Sdelphij 405311285Sdelphij /* check for an error */ 406311285Sdelphij if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR) 407311285Sdelphij return -1; 408311285Sdelphij 409311285Sdelphij /* return the number of bytes read (this is assured to fit in an int) */ 410311285Sdelphij return (int)len; 411311285Sdelphij} 412311285Sdelphij 413311285Sdelphij/* -- see zlib.h -- */ 414311285Sdelphijz_size_t ZEXPORT gzfread(buf, size, nitems, file) 415311285Sdelphij voidp buf; 416311285Sdelphij z_size_t size; 417311285Sdelphij z_size_t nitems; 418311285Sdelphij gzFile file; 419311285Sdelphij{ 420311285Sdelphij z_size_t len; 421311285Sdelphij gz_statep state; 422311285Sdelphij 423311285Sdelphij /* get internal structure */ 424311285Sdelphij if (file == NULL) 425311285Sdelphij return 0; 426311285Sdelphij state = (gz_statep)file; 427311285Sdelphij 428311285Sdelphij /* check that we're reading and that there's no (serious) error */ 429311285Sdelphij if (state->mode != GZ_READ || 430311285Sdelphij (state->err != Z_OK && state->err != Z_BUF_ERROR)) 431311285Sdelphij return 0; 432311285Sdelphij 433311285Sdelphij /* compute bytes to read -- error on overflow */ 434311285Sdelphij len = nitems * size; 435311285Sdelphij if (size && len / size != nitems) { 436311285Sdelphij gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); 437311285Sdelphij return 0; 438311285Sdelphij } 439311285Sdelphij 440311285Sdelphij /* read len or fewer bytes to buf, return the number of full items read */ 441311285Sdelphij return len ? gz_read(state, buf, len) / size : 0; 442311285Sdelphij} 443311285Sdelphij 444311285Sdelphij/* -- see zlib.h -- */ 445250224Sdelphij#ifdef Z_PREFIX_SET 446250224Sdelphij# undef z_gzgetc 447250224Sdelphij#else 448250224Sdelphij# undef gzgetc 449250224Sdelphij#endif 450237248Sdelphijint ZEXPORT gzgetc(file) 451205194Sdelphij gzFile file; 452205194Sdelphij{ 453205194Sdelphij int ret; 454205194Sdelphij unsigned char buf[1]; 455205194Sdelphij gz_statep state; 456205194Sdelphij 457205194Sdelphij /* get internal structure */ 458205194Sdelphij if (file == NULL) 459205194Sdelphij return -1; 460205194Sdelphij state = (gz_statep)file; 461205194Sdelphij 462230837Sdelphij /* check that we're reading and that there's no (serious) error */ 463230837Sdelphij if (state->mode != GZ_READ || 464230837Sdelphij (state->err != Z_OK && state->err != Z_BUF_ERROR)) 465205194Sdelphij return -1; 466205194Sdelphij 467205194Sdelphij /* try output buffer (no need to check for skip request) */ 468230837Sdelphij if (state->x.have) { 469230837Sdelphij state->x.have--; 470230837Sdelphij state->x.pos++; 471230837Sdelphij return *(state->x.next)++; 472205194Sdelphij } 473205194Sdelphij 474311285Sdelphij /* nothing there -- try gz_read() */ 475311285Sdelphij ret = gz_read(state, buf, 1); 476205194Sdelphij return ret < 1 ? -1 : buf[0]; 477205194Sdelphij} 478205194Sdelphij 479237248Sdelphijint ZEXPORT gzgetc_(file) 480230837SdelphijgzFile file; 481230837Sdelphij{ 482237248Sdelphij return gzgetc(file); 483237248Sdelphij} 484230837Sdelphij 485205194Sdelphij/* -- see zlib.h -- */ 486205194Sdelphijint ZEXPORT gzungetc(c, file) 487205194Sdelphij int c; 488205194Sdelphij gzFile file; 489205194Sdelphij{ 490205194Sdelphij gz_statep state; 491205194Sdelphij 492205194Sdelphij /* get internal structure */ 493205194Sdelphij if (file == NULL) 494205194Sdelphij return -1; 495205194Sdelphij state = (gz_statep)file; 496205194Sdelphij 497230837Sdelphij /* check that we're reading and that there's no (serious) error */ 498230837Sdelphij if (state->mode != GZ_READ || 499230837Sdelphij (state->err != Z_OK && state->err != Z_BUF_ERROR)) 500205194Sdelphij return -1; 501205194Sdelphij 502205194Sdelphij /* process a skip request */ 503205194Sdelphij if (state->seek) { 504205194Sdelphij state->seek = 0; 505205194Sdelphij if (gz_skip(state, state->skip) == -1) 506205194Sdelphij return -1; 507205194Sdelphij } 508205194Sdelphij 509205194Sdelphij /* can't push EOF */ 510205194Sdelphij if (c < 0) 511205194Sdelphij return -1; 512205194Sdelphij 513205194Sdelphij /* if output buffer empty, put byte at end (allows more pushing) */ 514230837Sdelphij if (state->x.have == 0) { 515230837Sdelphij state->x.have = 1; 516230837Sdelphij state->x.next = state->out + (state->size << 1) - 1; 517311285Sdelphij state->x.next[0] = (unsigned char)c; 518230837Sdelphij state->x.pos--; 519230837Sdelphij state->past = 0; 520205194Sdelphij return c; 521205194Sdelphij } 522205194Sdelphij 523205194Sdelphij /* if no room, give up (must have already done a gzungetc()) */ 524230837Sdelphij if (state->x.have == (state->size << 1)) { 525230837Sdelphij gz_error(state, Z_DATA_ERROR, "out of room to push characters"); 526205194Sdelphij return -1; 527205194Sdelphij } 528205194Sdelphij 529205194Sdelphij /* slide output data if needed and insert byte before existing data */ 530230837Sdelphij if (state->x.next == state->out) { 531230837Sdelphij unsigned char *src = state->out + state->x.have; 532205194Sdelphij unsigned char *dest = state->out + (state->size << 1); 533205194Sdelphij while (src > state->out) 534205194Sdelphij *--dest = *--src; 535230837Sdelphij state->x.next = dest; 536205194Sdelphij } 537230837Sdelphij state->x.have++; 538230837Sdelphij state->x.next--; 539311285Sdelphij state->x.next[0] = (unsigned char)c; 540230837Sdelphij state->x.pos--; 541230837Sdelphij state->past = 0; 542205194Sdelphij return c; 543205194Sdelphij} 544205194Sdelphij 545205194Sdelphij/* -- see zlib.h -- */ 546205194Sdelphijchar * ZEXPORT gzgets(file, buf, len) 547205194Sdelphij gzFile file; 548205194Sdelphij char *buf; 549205194Sdelphij int len; 550205194Sdelphij{ 551205194Sdelphij unsigned left, n; 552205194Sdelphij char *str; 553205194Sdelphij unsigned char *eol; 554205194Sdelphij gz_statep state; 555205194Sdelphij 556205194Sdelphij /* check parameters and get internal structure */ 557205194Sdelphij if (file == NULL || buf == NULL || len < 1) 558205194Sdelphij return NULL; 559205194Sdelphij state = (gz_statep)file; 560205194Sdelphij 561230837Sdelphij /* check that we're reading and that there's no (serious) error */ 562230837Sdelphij if (state->mode != GZ_READ || 563230837Sdelphij (state->err != Z_OK && state->err != Z_BUF_ERROR)) 564205194Sdelphij return NULL; 565205194Sdelphij 566205194Sdelphij /* process a skip request */ 567205194Sdelphij if (state->seek) { 568205194Sdelphij state->seek = 0; 569205194Sdelphij if (gz_skip(state, state->skip) == -1) 570205194Sdelphij return NULL; 571205194Sdelphij } 572205194Sdelphij 573205194Sdelphij /* copy output bytes up to new line or len - 1, whichever comes first -- 574205194Sdelphij append a terminating zero to the string (we don't check for a zero in 575205194Sdelphij the contents, let the user worry about that) */ 576205194Sdelphij str = buf; 577205194Sdelphij left = (unsigned)len - 1; 578205194Sdelphij if (left) do { 579205194Sdelphij /* assure that something is in the output buffer */ 580230837Sdelphij if (state->x.have == 0 && gz_fetch(state) == -1) 581230837Sdelphij return NULL; /* error */ 582230837Sdelphij if (state->x.have == 0) { /* end of file */ 583230837Sdelphij state->past = 1; /* read past end */ 584230837Sdelphij break; /* return what we have */ 585205194Sdelphij } 586205194Sdelphij 587205194Sdelphij /* look for end-of-line in current output buffer */ 588230837Sdelphij n = state->x.have > left ? left : state->x.have; 589250224Sdelphij eol = (unsigned char *)memchr(state->x.next, '\n', n); 590205194Sdelphij if (eol != NULL) 591230837Sdelphij n = (unsigned)(eol - state->x.next) + 1; 592205194Sdelphij 593205194Sdelphij /* copy through end-of-line, or remainder if not found */ 594230837Sdelphij memcpy(buf, state->x.next, n); 595230837Sdelphij state->x.have -= n; 596230837Sdelphij state->x.next += n; 597230837Sdelphij state->x.pos += n; 598205194Sdelphij left -= n; 599205194Sdelphij buf += n; 600205194Sdelphij } while (left && eol == NULL); 601205194Sdelphij 602230837Sdelphij /* return terminated string, or if nothing, end of file */ 603230837Sdelphij if (buf == str) 604230837Sdelphij return NULL; 605205194Sdelphij buf[0] = 0; 606205194Sdelphij return str; 607205194Sdelphij} 608205194Sdelphij 609205194Sdelphij/* -- see zlib.h -- */ 610205194Sdelphijint ZEXPORT gzdirect(file) 611205194Sdelphij gzFile file; 612205194Sdelphij{ 613205194Sdelphij gz_statep state; 614205194Sdelphij 615205194Sdelphij /* get internal structure */ 616205194Sdelphij if (file == NULL) 617205194Sdelphij return 0; 618205194Sdelphij state = (gz_statep)file; 619205194Sdelphij 620205194Sdelphij /* if the state is not known, but we can find out, then do so (this is 621205194Sdelphij mainly for right after a gzopen() or gzdopen()) */ 622230837Sdelphij if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) 623230837Sdelphij (void)gz_look(state); 624205194Sdelphij 625230837Sdelphij /* return 1 if transparent, 0 if processing a gzip stream */ 626205194Sdelphij return state->direct; 627205194Sdelphij} 628205194Sdelphij 629205194Sdelphij/* -- see zlib.h -- */ 630205194Sdelphijint ZEXPORT gzclose_r(file) 631205194Sdelphij gzFile file; 632205194Sdelphij{ 633230837Sdelphij int ret, err; 634205194Sdelphij gz_statep state; 635205194Sdelphij 636205194Sdelphij /* get internal structure */ 637205194Sdelphij if (file == NULL) 638205194Sdelphij return Z_STREAM_ERROR; 639205194Sdelphij state = (gz_statep)file; 640205194Sdelphij 641205194Sdelphij /* check that we're reading */ 642205194Sdelphij if (state->mode != GZ_READ) 643205194Sdelphij return Z_STREAM_ERROR; 644205194Sdelphij 645205194Sdelphij /* free memory and close file */ 646205194Sdelphij if (state->size) { 647205194Sdelphij inflateEnd(&(state->strm)); 648205194Sdelphij free(state->out); 649205194Sdelphij free(state->in); 650205194Sdelphij } 651230837Sdelphij err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK; 652205194Sdelphij gz_error(state, Z_OK, NULL); 653205194Sdelphij free(state->path); 654205194Sdelphij ret = close(state->fd); 655205194Sdelphij free(state); 656230837Sdelphij return ret ? Z_ERRNO : err; 657205194Sdelphij} 658