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