1275793eaSopenharmony_ci/* gzread.c -- zlib functions for reading gzip files 2275793eaSopenharmony_ci * Copyright (C) 2004-2017 Mark Adler 3275793eaSopenharmony_ci * For conditions of distribution and use, see copyright notice in zlib.h 4275793eaSopenharmony_ci */ 5275793eaSopenharmony_ci 6275793eaSopenharmony_ci#include "gzguts.h" 7275793eaSopenharmony_ci#include <fcntl.h> 8275793eaSopenharmony_ci#include <unistd.h> 9275793eaSopenharmony_ci 10275793eaSopenharmony_ci/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from 11275793eaSopenharmony_ci state->fd, and update state->eof, state->err, and state->msg as appropriate. 12275793eaSopenharmony_ci This function needs to loop on read(), since read() is not guaranteed to 13275793eaSopenharmony_ci read the number of bytes requested, depending on the type of descriptor. */ 14275793eaSopenharmony_cilocal int gz_load(gz_statep state, unsigned char *buf, unsigned len, 15275793eaSopenharmony_ci unsigned *have) 16275793eaSopenharmony_ci{ 17275793eaSopenharmony_ci int ret; 18275793eaSopenharmony_ci unsigned get, max = ((unsigned)-1 >> 2) + 1; 19275793eaSopenharmony_ci 20275793eaSopenharmony_ci *have = 0; 21275793eaSopenharmony_ci do { 22275793eaSopenharmony_ci get = len - *have; 23275793eaSopenharmony_ci if (get > max) 24275793eaSopenharmony_ci { 25275793eaSopenharmony_ci get = max; 26275793eaSopenharmony_ci } 27275793eaSopenharmony_ci ret = read(state->fd, buf + *have, get); 28275793eaSopenharmony_ci if (ret <= 0) 29275793eaSopenharmony_ci { 30275793eaSopenharmony_ci break; 31275793eaSopenharmony_ci } 32275793eaSopenharmony_ci *have += (unsigned)ret; 33275793eaSopenharmony_ci } while (*have < len); 34275793eaSopenharmony_ci if (ret < 0) { 35275793eaSopenharmony_ci gz_error(state, Z_ERRNO, zstrerror()); 36275793eaSopenharmony_ci return -1; 37275793eaSopenharmony_ci } 38275793eaSopenharmony_ci if (ret == 0) 39275793eaSopenharmony_ci { 40275793eaSopenharmony_ci state->eof = 1; 41275793eaSopenharmony_ci } 42275793eaSopenharmony_ci return 0; 43275793eaSopenharmony_ci} 44275793eaSopenharmony_ci 45275793eaSopenharmony_ci/* Load up input buffer and set eof flag if last data loaded -- return -1 on 46275793eaSopenharmony_ci error, 0 otherwise. Note that the eof flag is set when the end of the input 47275793eaSopenharmony_ci file is reached, even though there may be unused data in the buffer. Once 48275793eaSopenharmony_ci that data has been used, no more attempts will be made to read the file. 49275793eaSopenharmony_ci If strm->avail_in != 0, then the current data is moved to the beginning of 50275793eaSopenharmony_ci the input buffer, and then the remainder of the buffer is loaded with the 51275793eaSopenharmony_ci available data from the input file. */ 52275793eaSopenharmony_cilocal int gz_avail(gz_statep state) 53275793eaSopenharmony_ci{ 54275793eaSopenharmony_ci unsigned got; 55275793eaSopenharmony_ci z_streamp strm = &(state->strm); 56275793eaSopenharmony_ci 57275793eaSopenharmony_ci if (state->err != Z_OK && state->err != Z_BUF_ERROR) 58275793eaSopenharmony_ci { 59275793eaSopenharmony_ci return -1; 60275793eaSopenharmony_ci } 61275793eaSopenharmony_ci if (state->eof == 0) { 62275793eaSopenharmony_ci if (strm->avail_in) { /* copy what's there to the start */ 63275793eaSopenharmony_ci unsigned char *p = state->in; 64275793eaSopenharmony_ci unsigned const char *q = strm->next_in; 65275793eaSopenharmony_ci unsigned n = strm->avail_in; 66275793eaSopenharmony_ci do { 67275793eaSopenharmony_ci *p++ = *q++; 68275793eaSopenharmony_ci } while (--n); 69275793eaSopenharmony_ci } 70275793eaSopenharmony_ci if (gz_load(state, state->in + strm->avail_in, 71275793eaSopenharmony_ci state->size - strm->avail_in, &got) == -1) 72275793eaSopenharmony_ci { 73275793eaSopenharmony_ci return -1; 74275793eaSopenharmony_ci } 75275793eaSopenharmony_ci strm->avail_in += got; 76275793eaSopenharmony_ci strm->next_in = state->in; 77275793eaSopenharmony_ci } 78275793eaSopenharmony_ci return 0; 79275793eaSopenharmony_ci} 80275793eaSopenharmony_ci 81275793eaSopenharmony_ci/* Look for gzip header, set up for inflate or copy. state->x.have must be 0. 82275793eaSopenharmony_ci If this is the first time in, allocate required memory. state->how will be 83275793eaSopenharmony_ci left unchanged if there is no more input data available, will be set to COPY 84275793eaSopenharmony_ci if there is no gzip header and direct copying will be performed, or it will 85275793eaSopenharmony_ci be set to GZIP for decompression. If direct copying, then leftover input 86275793eaSopenharmony_ci data from the input buffer will be copied to the output buffer. In that 87275793eaSopenharmony_ci case, all further file reads will be directly to either the output buffer or 88275793eaSopenharmony_ci a user buffer. If decompressing, the inflate state will be initialized. 89275793eaSopenharmony_ci gz_look() will return 0 on success or -1 on failure. */ 90275793eaSopenharmony_cilocal int gz_look(gz_statep state) 91275793eaSopenharmony_ci{ 92275793eaSopenharmony_ci z_streamp strm = &(state->strm); 93275793eaSopenharmony_ci 94275793eaSopenharmony_ci /* allocate read buffers and inflate memory */ 95275793eaSopenharmony_ci if (state->size == 0) { 96275793eaSopenharmony_ci /* allocate buffers */ 97275793eaSopenharmony_ci state->in = (unsigned char *)malloc(state->want); 98275793eaSopenharmony_ci state->out = (unsigned char *)malloc(state->want << 1); 99275793eaSopenharmony_ci if (state->in == NULL || state->out == NULL) { 100275793eaSopenharmony_ci free(state->out); 101275793eaSopenharmony_ci free(state->in); 102275793eaSopenharmony_ci gz_error(state, Z_MEM_ERROR, "out of memory"); 103275793eaSopenharmony_ci return -1; 104275793eaSopenharmony_ci } 105275793eaSopenharmony_ci state->size = state->want; 106275793eaSopenharmony_ci 107275793eaSopenharmony_ci /* allocate inflate memory */ 108275793eaSopenharmony_ci state->strm.zalloc = Z_NULL; 109275793eaSopenharmony_ci state->strm.zfree = Z_NULL; 110275793eaSopenharmony_ci state->strm.opaque = Z_NULL; 111275793eaSopenharmony_ci state->strm.avail_in = 0; 112275793eaSopenharmony_ci state->strm.next_in = Z_NULL; 113275793eaSopenharmony_ci if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) { /* gunzip */ 114275793eaSopenharmony_ci free(state->out); 115275793eaSopenharmony_ci free(state->in); 116275793eaSopenharmony_ci state->size = 0; 117275793eaSopenharmony_ci gz_error(state, Z_MEM_ERROR, "out of memory"); 118275793eaSopenharmony_ci return -1; 119275793eaSopenharmony_ci } 120275793eaSopenharmony_ci } 121275793eaSopenharmony_ci 122275793eaSopenharmony_ci /* get at least the magic bytes in the input buffer */ 123275793eaSopenharmony_ci if (strm->avail_in < 2) { 124275793eaSopenharmony_ci if (gz_avail(state) == -1) 125275793eaSopenharmony_ci { 126275793eaSopenharmony_ci return -1; 127275793eaSopenharmony_ci } 128275793eaSopenharmony_ci if (strm->avail_in == 0) 129275793eaSopenharmony_ci { 130275793eaSopenharmony_ci return 0; 131275793eaSopenharmony_ci } 132275793eaSopenharmony_ci } 133275793eaSopenharmony_ci 134275793eaSopenharmony_ci /* look for gzip magic bytes -- if there, do gzip decoding (note: there is 135275793eaSopenharmony_ci a logical dilemma here when considering the case of a partially written 136275793eaSopenharmony_ci gzip file, to wit, if a single 31 byte is written, then we cannot tell 137275793eaSopenharmony_ci whether this is a single-byte file, or just a partially written gzip 138275793eaSopenharmony_ci file -- for here we assume that if a gzip file is being written, then 139275793eaSopenharmony_ci the header will be written in a single operation, so that reading a 140275793eaSopenharmony_ci single byte is sufficient indication that it is not a gzip file) */ 141275793eaSopenharmony_ci if (strm->avail_in > 1 && 142275793eaSopenharmony_ci strm->next_in[0] == 31 && strm->next_in[1] == 139) { 143275793eaSopenharmony_ci inflateReset(strm); 144275793eaSopenharmony_ci state->how = GZIP; 145275793eaSopenharmony_ci state->direct = 0; 146275793eaSopenharmony_ci return 0; 147275793eaSopenharmony_ci } 148275793eaSopenharmony_ci 149275793eaSopenharmony_ci /* no gzip header -- if we were decoding gzip before, then this is trailing 150275793eaSopenharmony_ci garbage. Ignore the trailing garbage and finish. */ 151275793eaSopenharmony_ci if (state->direct == 0) { 152275793eaSopenharmony_ci strm->avail_in = 0; 153275793eaSopenharmony_ci state->eof = 1; 154275793eaSopenharmony_ci state->x.have = 0; 155275793eaSopenharmony_ci return 0; 156275793eaSopenharmony_ci } 157275793eaSopenharmony_ci 158275793eaSopenharmony_ci /* doing raw i/o, copy any leftover input to output -- this assumes that 159275793eaSopenharmony_ci the output buffer is larger than the input buffer, which also assures 160275793eaSopenharmony_ci space for gzungetc() */ 161275793eaSopenharmony_ci state->x.next = state->out; 162275793eaSopenharmony_ci memcpy(state->x.next, strm->next_in, strm->avail_in); 163275793eaSopenharmony_ci state->x.have = strm->avail_in; 164275793eaSopenharmony_ci strm->avail_in = 0; 165275793eaSopenharmony_ci state->how = COPY; 166275793eaSopenharmony_ci state->direct = 1; 167275793eaSopenharmony_ci return 0; 168275793eaSopenharmony_ci} 169275793eaSopenharmony_ci 170275793eaSopenharmony_ci/* Decompress from input to the provided next_out and avail_out in the state. 171275793eaSopenharmony_ci On return, state->x.have and state->x.next point to the just decompressed 172275793eaSopenharmony_ci data. If the gzip stream completes, state->how is reset to LOOK to look for 173275793eaSopenharmony_ci the next gzip stream or raw data, once state->x.have is depleted. Returns 0 174275793eaSopenharmony_ci on success, -1 on failure. */ 175275793eaSopenharmony_cilocal int gz_decomp(gz_statep state) 176275793eaSopenharmony_ci{ 177275793eaSopenharmony_ci int ret = Z_OK; 178275793eaSopenharmony_ci unsigned had; 179275793eaSopenharmony_ci z_streamp strm = &(state->strm); 180275793eaSopenharmony_ci 181275793eaSopenharmony_ci /* fill output buffer up to end of deflate stream */ 182275793eaSopenharmony_ci had = strm->avail_out; 183275793eaSopenharmony_ci do { 184275793eaSopenharmony_ci /* get more input for inflate() */ 185275793eaSopenharmony_ci if (strm->avail_in == 0 && gz_avail(state) == -1) 186275793eaSopenharmony_ci { 187275793eaSopenharmony_ci return -1; 188275793eaSopenharmony_ci } 189275793eaSopenharmony_ci if (strm->avail_in == 0) { 190275793eaSopenharmony_ci gz_error(state, Z_BUF_ERROR, "unexpected end of file"); 191275793eaSopenharmony_ci break; 192275793eaSopenharmony_ci } 193275793eaSopenharmony_ci 194275793eaSopenharmony_ci /* decompress and handle errors */ 195275793eaSopenharmony_ci ret = inflate(strm, Z_NO_FLUSH); 196275793eaSopenharmony_ci if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { 197275793eaSopenharmony_ci gz_error(state, Z_STREAM_ERROR, 198275793eaSopenharmony_ci "internal error: inflate stream corrupt"); 199275793eaSopenharmony_ci return -1; 200275793eaSopenharmony_ci } 201275793eaSopenharmony_ci if (ret == Z_MEM_ERROR) { 202275793eaSopenharmony_ci gz_error(state, Z_MEM_ERROR, "out of memory"); 203275793eaSopenharmony_ci return -1; 204275793eaSopenharmony_ci } 205275793eaSopenharmony_ci if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ 206275793eaSopenharmony_ci gz_error(state, Z_DATA_ERROR, 207275793eaSopenharmony_ci strm->msg == NULL ? "compressed data error" : strm->msg); 208275793eaSopenharmony_ci return -1; 209275793eaSopenharmony_ci } 210275793eaSopenharmony_ci } while (strm->avail_out && ret != Z_STREAM_END); 211275793eaSopenharmony_ci 212275793eaSopenharmony_ci /* update available output */ 213275793eaSopenharmony_ci state->x.have = had - strm->avail_out; 214275793eaSopenharmony_ci state->x.next = strm->next_out - state->x.have; 215275793eaSopenharmony_ci 216275793eaSopenharmony_ci /* if the gzip stream completed successfully, look for another */ 217275793eaSopenharmony_ci if (ret == Z_STREAM_END) 218275793eaSopenharmony_ci state->how = LOOK; 219275793eaSopenharmony_ci 220275793eaSopenharmony_ci /* good decompression */ 221275793eaSopenharmony_ci return 0; 222275793eaSopenharmony_ci} 223275793eaSopenharmony_ci 224275793eaSopenharmony_ci/* Fetch data and put it in the output buffer. Assumes state->x.have is 0. 225275793eaSopenharmony_ci Data is either copied from the input file or decompressed from the input 226275793eaSopenharmony_ci file depending on state->how. If state->how is LOOK, then a gzip header is 227275793eaSopenharmony_ci looked for to determine whether to copy or decompress. Returns -1 on error, 228275793eaSopenharmony_ci otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the 229275793eaSopenharmony_ci end of the input file has been reached and all data has been processed. */ 230275793eaSopenharmony_cilocal int gz_fetch(gz_statep state) 231275793eaSopenharmony_ci{ 232275793eaSopenharmony_ci z_streamp strm = &(state->strm); 233275793eaSopenharmony_ci 234275793eaSopenharmony_ci do { 235275793eaSopenharmony_ci switch(state->how) { 236275793eaSopenharmony_ci case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */ 237275793eaSopenharmony_ci if (gz_look(state) == -1) 238275793eaSopenharmony_ci { 239275793eaSopenharmony_ci return -1; 240275793eaSopenharmony_ci } 241275793eaSopenharmony_ci if (state->how == LOOK) 242275793eaSopenharmony_ci { 243275793eaSopenharmony_ci return 0; 244275793eaSopenharmony_ci } 245275793eaSopenharmony_ci break; 246275793eaSopenharmony_ci case COPY: /* -> COPY */ 247275793eaSopenharmony_ci if (gz_load(state, state->out, state->size << 1, &(state->x.have)) 248275793eaSopenharmony_ci == -1) 249275793eaSopenharmony_ci { 250275793eaSopenharmony_ci return -1; 251275793eaSopenharmony_ci } 252275793eaSopenharmony_ci state->x.next = state->out; 253275793eaSopenharmony_ci return 0; 254275793eaSopenharmony_ci case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */ 255275793eaSopenharmony_ci strm->avail_out = state->size << 1; 256275793eaSopenharmony_ci strm->next_out = state->out; 257275793eaSopenharmony_ci if (gz_decomp(state) == -1) 258275793eaSopenharmony_ci { 259275793eaSopenharmony_ci return -1; 260275793eaSopenharmony_ci } 261275793eaSopenharmony_ci } 262275793eaSopenharmony_ci } while (state->x.have == 0 && (!state->eof || strm->avail_in)); 263275793eaSopenharmony_ci return 0; 264275793eaSopenharmony_ci} 265275793eaSopenharmony_ci 266275793eaSopenharmony_ci/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ 267275793eaSopenharmony_cilocal int gz_skip(gz_statep state, z_off64_t len) 268275793eaSopenharmony_ci{ 269275793eaSopenharmony_ci unsigned n; 270275793eaSopenharmony_ci 271275793eaSopenharmony_ci /* skip over len bytes or reach end-of-file, whichever comes first */ 272275793eaSopenharmony_ci while (len) 273275793eaSopenharmony_ci /* skip over whatever is in output buffer */ 274275793eaSopenharmony_ci if (state->x.have) { 275275793eaSopenharmony_ci n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ? 276275793eaSopenharmony_ci (unsigned)len : state->x.have; 277275793eaSopenharmony_ci state->x.have -= n; 278275793eaSopenharmony_ci state->x.next += n; 279275793eaSopenharmony_ci state->x.pos += n; 280275793eaSopenharmony_ci len -= n; 281275793eaSopenharmony_ci } 282275793eaSopenharmony_ci 283275793eaSopenharmony_ci /* output buffer empty -- return if we're at the end of the input */ 284275793eaSopenharmony_ci else if (state->eof && state->strm.avail_in == 0) 285275793eaSopenharmony_ci { 286275793eaSopenharmony_ci break; 287275793eaSopenharmony_ci } 288275793eaSopenharmony_ci 289275793eaSopenharmony_ci /* need more data to skip -- load up output buffer */ 290275793eaSopenharmony_ci else { 291275793eaSopenharmony_ci /* get more output, looking for header if required */ 292275793eaSopenharmony_ci if (gz_fetch(state) == -1) 293275793eaSopenharmony_ci { 294275793eaSopenharmony_ci return -1; 295275793eaSopenharmony_ci } 296275793eaSopenharmony_ci } 297275793eaSopenharmony_ci return 0; 298275793eaSopenharmony_ci} 299275793eaSopenharmony_ci 300275793eaSopenharmony_ci/* Read len bytes into buf from file, or less than len up to the end of the 301275793eaSopenharmony_ci input. Return the number of bytes read. If zero is returned, either the 302275793eaSopenharmony_ci end of file was reached, or there was an error. state->err must be 303275793eaSopenharmony_ci consulted in that case to determine which. */ 304275793eaSopenharmony_cilocal z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) 305275793eaSopenharmony_ci{ 306275793eaSopenharmony_ci z_size_t got; 307275793eaSopenharmony_ci unsigned n; 308275793eaSopenharmony_ci 309275793eaSopenharmony_ci /* if len is zero, avoid unnecessary operations */ 310275793eaSopenharmony_ci if (len == 0) 311275793eaSopenharmony_ci { 312275793eaSopenharmony_ci return 0; 313275793eaSopenharmony_ci } 314275793eaSopenharmony_ci 315275793eaSopenharmony_ci /* process a skip request */ 316275793eaSopenharmony_ci if (state->seek) { 317275793eaSopenharmony_ci state->seek = 0; 318275793eaSopenharmony_ci if (gz_skip(state, state->skip) == -1) 319275793eaSopenharmony_ci { 320275793eaSopenharmony_ci return 0; 321275793eaSopenharmony_ci } 322275793eaSopenharmony_ci } 323275793eaSopenharmony_ci 324275793eaSopenharmony_ci /* get len bytes to buf, or less than len if at the end */ 325275793eaSopenharmony_ci got = 0; 326275793eaSopenharmony_ci do { 327275793eaSopenharmony_ci /* set n to the maximum amount of len that fits in an unsigned int */ 328275793eaSopenharmony_ci n = (unsigned)-1; 329275793eaSopenharmony_ci if (n > len) 330275793eaSopenharmony_ci { 331275793eaSopenharmony_ci n = (unsigned)len; 332275793eaSopenharmony_ci } 333275793eaSopenharmony_ci 334275793eaSopenharmony_ci /* first just try copying data from the output buffer */ 335275793eaSopenharmony_ci if (state->x.have) { 336275793eaSopenharmony_ci if (state->x.have < n) 337275793eaSopenharmony_ci { 338275793eaSopenharmony_ci n = state->x.have; 339275793eaSopenharmony_ci } 340275793eaSopenharmony_ci memcpy(buf, state->x.next, n); 341275793eaSopenharmony_ci state->x.next += n; 342275793eaSopenharmony_ci state->x.have -= n; 343275793eaSopenharmony_ci } 344275793eaSopenharmony_ci 345275793eaSopenharmony_ci /* output buffer empty -- return if we're at the end of the input */ 346275793eaSopenharmony_ci else if (state->eof && state->strm.avail_in == 0) { 347275793eaSopenharmony_ci state->past = 1; /* tried to read past end */ 348275793eaSopenharmony_ci break; 349275793eaSopenharmony_ci } 350275793eaSopenharmony_ci 351275793eaSopenharmony_ci /* need output data -- for small len or new stream load up our output 352275793eaSopenharmony_ci buffer */ 353275793eaSopenharmony_ci else if (state->how == LOOK || n < (state->size << 1)) { 354275793eaSopenharmony_ci /* get more output, looking for header if required */ 355275793eaSopenharmony_ci if (gz_fetch(state) == -1) 356275793eaSopenharmony_ci { 357275793eaSopenharmony_ci return 0; 358275793eaSopenharmony_ci } 359275793eaSopenharmony_ci continue; /* no progress yet -- go back to copy above */ 360275793eaSopenharmony_ci /* the copy above assures that we will leave with space in the 361275793eaSopenharmony_ci output buffer, allowing at least one gzungetc() to succeed */ 362275793eaSopenharmony_ci } 363275793eaSopenharmony_ci 364275793eaSopenharmony_ci /* large len -- read directly into user buffer */ 365275793eaSopenharmony_ci else if (state->how == COPY) { /* read directly */ 366275793eaSopenharmony_ci if (gz_load(state, (unsigned char *)buf, n, &n) == -1) 367275793eaSopenharmony_ci { 368275793eaSopenharmony_ci return 0; 369275793eaSopenharmony_ci } 370275793eaSopenharmony_ci } 371275793eaSopenharmony_ci 372275793eaSopenharmony_ci /* large len -- decompress directly into user buffer */ 373275793eaSopenharmony_ci else { /* state->how == GZIP */ 374275793eaSopenharmony_ci state->strm.avail_out = n; 375275793eaSopenharmony_ci state->strm.next_out = (unsigned char *)buf; 376275793eaSopenharmony_ci if (gz_decomp(state) == -1) 377275793eaSopenharmony_ci { 378275793eaSopenharmony_ci return 0; 379275793eaSopenharmony_ci } 380275793eaSopenharmony_ci n = state->x.have; 381275793eaSopenharmony_ci state->x.have = 0; 382275793eaSopenharmony_ci } 383275793eaSopenharmony_ci 384275793eaSopenharmony_ci /* update progress */ 385275793eaSopenharmony_ci len -= n; 386275793eaSopenharmony_ci buf = (char *)buf + n; 387275793eaSopenharmony_ci got += n; 388275793eaSopenharmony_ci state->x.pos += n; 389275793eaSopenharmony_ci } while (len); 390275793eaSopenharmony_ci 391275793eaSopenharmony_ci /* return number of bytes read into user buffer */ 392275793eaSopenharmony_ci return got; 393275793eaSopenharmony_ci} 394275793eaSopenharmony_ci 395275793eaSopenharmony_ci/* -- see zlib.h -- */ 396275793eaSopenharmony_ciint ZEXPORT gzread(gzFile file, voidp buf, unsigned len) 397275793eaSopenharmony_ci{ 398275793eaSopenharmony_ci gz_statep state; 399275793eaSopenharmony_ci 400275793eaSopenharmony_ci /* get internal structure */ 401275793eaSopenharmony_ci if (file == NULL) 402275793eaSopenharmony_ci { 403275793eaSopenharmony_ci return -1; 404275793eaSopenharmony_ci } 405275793eaSopenharmony_ci state = (gz_statep)file; 406275793eaSopenharmony_ci 407275793eaSopenharmony_ci /* check that we're reading and that there's no (serious) error */ 408275793eaSopenharmony_ci if (state->mode != GZ_READ || 409275793eaSopenharmony_ci (state->err != Z_OK && state->err != Z_BUF_ERROR)) 410275793eaSopenharmony_ci { 411275793eaSopenharmony_ci return -1; 412275793eaSopenharmony_ci } 413275793eaSopenharmony_ci 414275793eaSopenharmony_ci /* since an int is returned, make sure len fits in one, otherwise return 415275793eaSopenharmony_ci with an error (this avoids a flaw in the interface) */ 416275793eaSopenharmony_ci if ((int)len < 0) { 417275793eaSopenharmony_ci gz_error(state, Z_STREAM_ERROR, "request does not fit in an int"); 418275793eaSopenharmony_ci return -1; 419275793eaSopenharmony_ci } 420275793eaSopenharmony_ci 421275793eaSopenharmony_ci /* read len or fewer bytes to buf */ 422275793eaSopenharmony_ci len = (unsigned)gz_read(state, buf, len); 423275793eaSopenharmony_ci 424275793eaSopenharmony_ci /* check for an error */ 425275793eaSopenharmony_ci if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR) 426275793eaSopenharmony_ci { 427275793eaSopenharmony_ci return -1; 428275793eaSopenharmony_ci } 429275793eaSopenharmony_ci 430275793eaSopenharmony_ci /* return the number of bytes read (this is assured to fit in an int) */ 431275793eaSopenharmony_ci return (int)len; 432275793eaSopenharmony_ci} 433275793eaSopenharmony_ci 434275793eaSopenharmony_ci/* -- see zlib.h -- */ 435275793eaSopenharmony_ciz_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, gzFile file) 436275793eaSopenharmony_ci{ 437275793eaSopenharmony_ci z_size_t len; 438275793eaSopenharmony_ci gz_statep state; 439275793eaSopenharmony_ci 440275793eaSopenharmony_ci /* get internal structure */ 441275793eaSopenharmony_ci if (file == NULL) 442275793eaSopenharmony_ci { 443275793eaSopenharmony_ci return 0; 444275793eaSopenharmony_ci } 445275793eaSopenharmony_ci state = (gz_statep)file; 446275793eaSopenharmony_ci 447275793eaSopenharmony_ci /* check that we're reading and that there's no (serious) error */ 448275793eaSopenharmony_ci if (state->mode != GZ_READ || 449275793eaSopenharmony_ci (state->err != Z_OK && state->err != Z_BUF_ERROR)) 450275793eaSopenharmony_ci { 451275793eaSopenharmony_ci return 0; 452275793eaSopenharmony_ci } 453275793eaSopenharmony_ci 454275793eaSopenharmony_ci /* compute bytes to read -- error on overflow */ 455275793eaSopenharmony_ci len = nitems * size; 456275793eaSopenharmony_ci if (size && len / size != nitems) { 457275793eaSopenharmony_ci gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); 458275793eaSopenharmony_ci return 0; 459275793eaSopenharmony_ci } 460275793eaSopenharmony_ci 461275793eaSopenharmony_ci /* read len or fewer bytes to buf, return the number of full items read */ 462275793eaSopenharmony_ci return len ? gz_read(state, buf, len) / size : 0; 463275793eaSopenharmony_ci} 464275793eaSopenharmony_ci 465275793eaSopenharmony_ci/* -- see zlib.h -- */ 466275793eaSopenharmony_ci#ifdef Z_PREFIX_SET 467275793eaSopenharmony_ci# undef z_gzgetc 468275793eaSopenharmony_ci#else 469275793eaSopenharmony_ci# undef gzgetc 470275793eaSopenharmony_ci#endif 471275793eaSopenharmony_ciint ZEXPORT gzgetc(gzFile file) 472275793eaSopenharmony_ci{ 473275793eaSopenharmony_ci unsigned char buf[1]; 474275793eaSopenharmony_ci gz_statep state; 475275793eaSopenharmony_ci 476275793eaSopenharmony_ci /* get internal structure */ 477275793eaSopenharmony_ci if (file == NULL) 478275793eaSopenharmony_ci { 479275793eaSopenharmony_ci return -1; 480275793eaSopenharmony_ci } 481275793eaSopenharmony_ci state = (gz_statep)file; 482275793eaSopenharmony_ci 483275793eaSopenharmony_ci /* check that we're reading and that there's no (serious) error */ 484275793eaSopenharmony_ci if (state->mode != GZ_READ || 485275793eaSopenharmony_ci (state->err != Z_OK && state->err != Z_BUF_ERROR)) 486275793eaSopenharmony_ci { 487275793eaSopenharmony_ci return -1; 488275793eaSopenharmony_ci } 489275793eaSopenharmony_ci 490275793eaSopenharmony_ci /* try output buffer (no need to check for skip request) */ 491275793eaSopenharmony_ci if (state->x.have) { 492275793eaSopenharmony_ci state->x.have--; 493275793eaSopenharmony_ci state->x.pos++; 494275793eaSopenharmony_ci return *(state->x.next)++; 495275793eaSopenharmony_ci } 496275793eaSopenharmony_ci 497275793eaSopenharmony_ci /* nothing there -- try gz_read() */ 498275793eaSopenharmony_ci return gz_read(state, buf, 1) < 1 ? -1 : buf[0]; 499275793eaSopenharmony_ci} 500275793eaSopenharmony_ci 501275793eaSopenharmony_ciint ZEXPORT gzgetc_(gzFile file) 502275793eaSopenharmony_ci{ 503275793eaSopenharmony_ci return gzgetc(file); 504275793eaSopenharmony_ci} 505275793eaSopenharmony_ci 506275793eaSopenharmony_ci/* -- see zlib.h -- */ 507275793eaSopenharmony_ciint ZEXPORT gzungetc(int c, gzFile file) 508275793eaSopenharmony_ci{ 509275793eaSopenharmony_ci gz_statep state; 510275793eaSopenharmony_ci 511275793eaSopenharmony_ci /* get internal structure */ 512275793eaSopenharmony_ci if (file == NULL) 513275793eaSopenharmony_ci { 514275793eaSopenharmony_ci return -1; 515275793eaSopenharmony_ci } 516275793eaSopenharmony_ci state = (gz_statep)file; 517275793eaSopenharmony_ci 518275793eaSopenharmony_ci /* in case this was just opened, set up the input buffer */ 519275793eaSopenharmony_ci if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) 520275793eaSopenharmony_ci { 521275793eaSopenharmony_ci (void)gz_look(state); 522275793eaSopenharmony_ci } 523275793eaSopenharmony_ci 524275793eaSopenharmony_ci /* check that we're reading and that there's no (serious) error */ 525275793eaSopenharmony_ci if (state->mode != GZ_READ || 526275793eaSopenharmony_ci (state->err != Z_OK && state->err != Z_BUF_ERROR)) 527275793eaSopenharmony_ci { 528275793eaSopenharmony_ci return -1; 529275793eaSopenharmony_ci } 530275793eaSopenharmony_ci 531275793eaSopenharmony_ci /* process a skip request */ 532275793eaSopenharmony_ci if (state->seek) { 533275793eaSopenharmony_ci state->seek = 0; 534275793eaSopenharmony_ci if (gz_skip(state, state->skip) == -1) 535275793eaSopenharmony_ci { 536275793eaSopenharmony_ci return -1; 537275793eaSopenharmony_ci } 538275793eaSopenharmony_ci } 539275793eaSopenharmony_ci 540275793eaSopenharmony_ci /* can't push EOF */ 541275793eaSopenharmony_ci if (c < 0) 542275793eaSopenharmony_ci { 543275793eaSopenharmony_ci return -1; 544275793eaSopenharmony_ci } 545275793eaSopenharmony_ci 546275793eaSopenharmony_ci /* if output buffer empty, put byte at end (allows more pushing) */ 547275793eaSopenharmony_ci if (state->x.have == 0) { 548275793eaSopenharmony_ci state->x.have = 1; 549275793eaSopenharmony_ci state->x.next = state->out + (state->size << 1) - 1; 550275793eaSopenharmony_ci state->x.next[0] = (unsigned char)c; 551275793eaSopenharmony_ci state->x.pos--; 552275793eaSopenharmony_ci state->past = 0; 553275793eaSopenharmony_ci return c; 554275793eaSopenharmony_ci } 555275793eaSopenharmony_ci 556275793eaSopenharmony_ci /* if no room, give up (must have already done a gzungetc()) */ 557275793eaSopenharmony_ci if (state->x.have == (state->size << 1)) { 558275793eaSopenharmony_ci gz_error(state, Z_DATA_ERROR, "out of room to push characters"); 559275793eaSopenharmony_ci return -1; 560275793eaSopenharmony_ci } 561275793eaSopenharmony_ci 562275793eaSopenharmony_ci /* slide output data if needed and insert byte before existing data */ 563275793eaSopenharmony_ci if (state->x.next == state->out) { 564275793eaSopenharmony_ci unsigned char *src = state->out + state->x.have; 565275793eaSopenharmony_ci unsigned char *dest = state->out + (state->size << 1); 566275793eaSopenharmony_ci while (src > state->out){ 567275793eaSopenharmony_ci *--dest = *--src; 568275793eaSopenharmony_ci } 569275793eaSopenharmony_ci state->x.next = dest; 570275793eaSopenharmony_ci } 571275793eaSopenharmony_ci state->x.have++; 572275793eaSopenharmony_ci state->x.next--; 573275793eaSopenharmony_ci state->x.next[0] = (unsigned char)c; 574275793eaSopenharmony_ci state->x.pos--; 575275793eaSopenharmony_ci state->past = 0; 576275793eaSopenharmony_ci return c; 577275793eaSopenharmony_ci} 578275793eaSopenharmony_ci 579275793eaSopenharmony_ci/* -- see zlib.h -- */ 580275793eaSopenharmony_cichar * ZEXPORT gzgets(gzFile file, char *buf, int len) 581275793eaSopenharmony_ci{ 582275793eaSopenharmony_ci unsigned left, n; 583275793eaSopenharmony_ci char *str; 584275793eaSopenharmony_ci unsigned char *eol; 585275793eaSopenharmony_ci gz_statep state; 586275793eaSopenharmony_ci 587275793eaSopenharmony_ci /* check parameters and get internal structure */ 588275793eaSopenharmony_ci if (file == NULL || buf == NULL || len < 1) 589275793eaSopenharmony_ci { 590275793eaSopenharmony_ci return NULL; 591275793eaSopenharmony_ci } 592275793eaSopenharmony_ci state = (gz_statep)file; 593275793eaSopenharmony_ci 594275793eaSopenharmony_ci /* check that we're reading and that there's no (serious) error */ 595275793eaSopenharmony_ci if (state->mode != GZ_READ || 596275793eaSopenharmony_ci (state->err != Z_OK && state->err != Z_BUF_ERROR)) 597275793eaSopenharmony_ci { 598275793eaSopenharmony_ci return NULL; 599275793eaSopenharmony_ci } 600275793eaSopenharmony_ci 601275793eaSopenharmony_ci /* process a skip request */ 602275793eaSopenharmony_ci if (state->seek) { 603275793eaSopenharmony_ci state->seek = 0; 604275793eaSopenharmony_ci if (gz_skip(state, state->skip) == -1) 605275793eaSopenharmony_ci { 606275793eaSopenharmony_ci return NULL; 607275793eaSopenharmony_ci } 608275793eaSopenharmony_ci } 609275793eaSopenharmony_ci 610275793eaSopenharmony_ci /* copy output bytes up to new line or len - 1, whichever comes first -- 611275793eaSopenharmony_ci append a terminating zero to the string (we don't check for a zero in 612275793eaSopenharmony_ci the contents, let the user worry about that) */ 613275793eaSopenharmony_ci str = buf; 614275793eaSopenharmony_ci left = (unsigned)len - 1; 615275793eaSopenharmony_ci if (left) do { 616275793eaSopenharmony_ci /* assure that something is in the output buffer */ 617275793eaSopenharmony_ci if (state->x.have == 0 && gz_fetch(state) == -1) 618275793eaSopenharmony_ci { 619275793eaSopenharmony_ci return NULL; /* error */ 620275793eaSopenharmony_ci } 621275793eaSopenharmony_ci if (state->x.have == 0) { /* end of file */ 622275793eaSopenharmony_ci state->past = 1; /* read past end */ 623275793eaSopenharmony_ci break; /* return what we have */ 624275793eaSopenharmony_ci } 625275793eaSopenharmony_ci 626275793eaSopenharmony_ci /* look for end-of-line in current output buffer */ 627275793eaSopenharmony_ci n = state->x.have > left ? left : state->x.have; 628275793eaSopenharmony_ci eol = (unsigned char *)memchr(state->x.next, '\n', n); 629275793eaSopenharmony_ci if (eol != NULL) 630275793eaSopenharmony_ci { 631275793eaSopenharmony_ci n = (unsigned)(eol - state->x.next) + 1; 632275793eaSopenharmony_ci } 633275793eaSopenharmony_ci 634275793eaSopenharmony_ci /* copy through end-of-line, or remainder if not found */ 635275793eaSopenharmony_ci memcpy(buf, state->x.next, n); 636275793eaSopenharmony_ci state->x.have -= n; 637275793eaSopenharmony_ci state->x.next += n; 638275793eaSopenharmony_ci state->x.pos += n; 639275793eaSopenharmony_ci left -= n; 640275793eaSopenharmony_ci buf += n; 641275793eaSopenharmony_ci } while (left && eol == NULL); 642275793eaSopenharmony_ci 643275793eaSopenharmony_ci /* return terminated string, or if nothing, end of file */ 644275793eaSopenharmony_ci if (buf == str) 645275793eaSopenharmony_ci { 646275793eaSopenharmony_ci return NULL; 647275793eaSopenharmony_ci } 648275793eaSopenharmony_ci buf[0] = 0; 649275793eaSopenharmony_ci return str; 650275793eaSopenharmony_ci} 651275793eaSopenharmony_ci 652275793eaSopenharmony_ci/* -- see zlib.h -- */ 653275793eaSopenharmony_ciint ZEXPORT gzdirect(gzFile file) 654275793eaSopenharmony_ci{ 655275793eaSopenharmony_ci gz_statep state; 656275793eaSopenharmony_ci 657275793eaSopenharmony_ci /* get internal structure */ 658275793eaSopenharmony_ci if (file == NULL) 659275793eaSopenharmony_ci { 660275793eaSopenharmony_ci return 0; 661275793eaSopenharmony_ci } 662275793eaSopenharmony_ci state = (gz_statep)file; 663275793eaSopenharmony_ci 664275793eaSopenharmony_ci /* if the state is not known, but we can find out, then do so (this is 665275793eaSopenharmony_ci mainly for right after a gzopen() or gzdopen()) */ 666275793eaSopenharmony_ci if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) 667275793eaSopenharmony_ci { 668275793eaSopenharmony_ci (void)gz_look(state); 669275793eaSopenharmony_ci } 670275793eaSopenharmony_ci 671275793eaSopenharmony_ci /* return 1 if transparent, 0 if processing a gzip stream */ 672275793eaSopenharmony_ci return state->direct; 673275793eaSopenharmony_ci} 674275793eaSopenharmony_ci 675275793eaSopenharmony_ci/* -- see zlib.h -- */ 676275793eaSopenharmony_ciint ZEXPORT gzclose_r(gzFile file) 677275793eaSopenharmony_ci{ 678275793eaSopenharmony_ci int ret, err; 679275793eaSopenharmony_ci gz_statep state; 680275793eaSopenharmony_ci 681275793eaSopenharmony_ci /* get internal structure */ 682275793eaSopenharmony_ci if (file == NULL) 683275793eaSopenharmony_ci { 684275793eaSopenharmony_ci return Z_STREAM_ERROR; 685275793eaSopenharmony_ci } 686275793eaSopenharmony_ci state = (gz_statep)file; 687275793eaSopenharmony_ci 688275793eaSopenharmony_ci /* check that we're reading */ 689275793eaSopenharmony_ci if (state->mode != GZ_READ) 690275793eaSopenharmony_ci { 691275793eaSopenharmony_ci return Z_STREAM_ERROR; 692275793eaSopenharmony_ci } 693275793eaSopenharmony_ci 694275793eaSopenharmony_ci /* free memory and close file */ 695275793eaSopenharmony_ci if (state->size) { 696275793eaSopenharmony_ci inflateEnd(&(state->strm)); 697275793eaSopenharmony_ci free(state->out); 698275793eaSopenharmony_ci free(state->in); 699275793eaSopenharmony_ci } 700275793eaSopenharmony_ci err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK; 701275793eaSopenharmony_ci gz_error(state, Z_OK, NULL); 702275793eaSopenharmony_ci free(state->path); 703275793eaSopenharmony_ci ret = close(state->fd); 704275793eaSopenharmony_ci free(state); 705275793eaSopenharmony_ci return ret ? Z_ERRNO : err; 706275793eaSopenharmony_ci} 707