Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygengzread.c
Go to the documentation of this file.
00001 /* gzread.c -- zlib functions for reading gzip files 00002 * Copyright (C) 2004, 2005, 2010 Mark Adler 00003 * For conditions of distribution and use, see copyright notice in zlib.h 00004 */ 00005 00006 #include "gzguts.h" 00007 00008 /* Local functions */ 00009 local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *)); 00010 local int gz_avail OF((gz_statep)); 00011 local int gz_next4 OF((gz_statep, unsigned long *)); 00012 local int gz_head OF((gz_statep)); 00013 local int gz_decomp OF((gz_statep)); 00014 local int gz_make OF((gz_statep)); 00015 local int gz_skip OF((gz_statep, z_off64_t)); 00016 00017 /* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from 00018 state->fd, and update state->eof, state->err, and state->msg as appropriate. 00019 This function needs to loop on read(), since read() is not guaranteed to 00020 read the number of bytes requested, depending on the type of descriptor. */ 00021 local int gz_load(state, buf, len, have) 00022 gz_statep state; 00023 unsigned char *buf; 00024 unsigned len; 00025 unsigned *have; 00026 { 00027 int ret; 00028 00029 *have = 0; 00030 do { 00031 ret = read(state->fd, buf + *have, len - *have); 00032 if (ret <= 0) 00033 break; 00034 *have += ret; 00035 } while (*have < len); 00036 if (ret < 0) { 00037 gz_error(state, Z_ERRNO, zstrerror()); 00038 return -1; 00039 } 00040 if (ret == 0) 00041 state->eof = 1; 00042 return 0; 00043 } 00044 00045 /* Load up input buffer and set eof flag if last data loaded -- return -1 on 00046 error, 0 otherwise. Note that the eof flag is set when the end of the input 00047 file is reached, even though there may be unused data in the buffer. Once 00048 that data has been used, no more attempts will be made to read the file. 00049 gz_avail() assumes that strm->avail_in == 0. */ 00050 local int gz_avail(state) 00051 gz_statep state; 00052 { 00053 z_streamp strm = &(state->strm); 00054 00055 if (state->err != Z_OK) 00056 return -1; 00057 if (state->eof == 0) { 00058 if (gz_load(state, state->in, state->size, 00059 (unsigned *)&(strm->avail_in)) == -1) 00060 return -1; 00061 strm->next_in = state->in; 00062 } 00063 return 0; 00064 } 00065 00066 /* Get next byte from input, or -1 if end or error. */ 00067 #define NEXT() ((strm->avail_in == 0 && gz_avail(state) == -1) ? -1 : \ 00068 (strm->avail_in == 0 ? -1 : \ 00069 (strm->avail_in--, *(strm->next_in)++))) 00070 00071 /* Get a four-byte little-endian integer and return 0 on success and the value 00072 in *ret. Otherwise -1 is returned and *ret is not modified. */ 00073 local int gz_next4(state, ret) 00074 gz_statep state; 00075 unsigned long *ret; 00076 { 00077 int ch; 00078 unsigned long val; 00079 z_streamp strm = &(state->strm); 00080 00081 val = NEXT(); 00082 val += (unsigned)NEXT() << 8; 00083 val += (unsigned long)NEXT() << 16; 00084 ch = NEXT(); 00085 if (ch == -1) 00086 return -1; 00087 val += (unsigned long)ch << 24; 00088 *ret = val; 00089 return 0; 00090 } 00091 00092 /* Look for gzip header, set up for inflate or copy. state->have must be zero. 00093 If this is the first time in, allocate required memory. state->how will be 00094 left unchanged if there is no more input data available, will be set to COPY 00095 if there is no gzip header and direct copying will be performed, or it will 00096 be set to GZIP for decompression, and the gzip header will be skipped so 00097 that the next available input data is the raw deflate stream. If direct 00098 copying, then leftover input data from the input buffer will be copied to 00099 the output buffer. In that case, all further file reads will be directly to 00100 either the output buffer or a user buffer. If decompressing, the inflate 00101 state and the check value will be initialized. gz_head() will return 0 on 00102 success or -1 on failure. Failures may include read errors or gzip header 00103 errors. */ 00104 local int gz_head(state) 00105 gz_statep state; 00106 { 00107 z_streamp strm = &(state->strm); 00108 int flags; 00109 unsigned len; 00110 00111 /* allocate read buffers and inflate memory */ 00112 if (state->size == 0) { 00113 /* allocate buffers */ 00114 state->in = malloc(state->want); 00115 state->out = malloc(state->want << 1); 00116 if (state->in == NULL || state->out == NULL) { 00117 if (state->out != NULL) 00118 free(state->out); 00119 if (state->in != NULL) 00120 free(state->in); 00121 gz_error(state, Z_MEM_ERROR, "out of memory"); 00122 return -1; 00123 } 00124 state->size = state->want; 00125 00126 /* allocate inflate memory */ 00127 state->strm.zalloc = Z_NULL; 00128 state->strm.zfree = Z_NULL; 00129 state->strm.opaque = Z_NULL; 00130 state->strm.avail_in = 0; 00131 state->strm.next_in = Z_NULL; 00132 if (inflateInit2(&(state->strm), -15) != Z_OK) { /* raw inflate */ 00133 free(state->out); 00134 free(state->in); 00135 state->size = 0; 00136 gz_error(state, Z_MEM_ERROR, "out of memory"); 00137 return -1; 00138 } 00139 } 00140 00141 /* get some data in the input buffer */ 00142 if (strm->avail_in == 0) { 00143 if (gz_avail(state) == -1) 00144 return -1; 00145 if (strm->avail_in == 0) 00146 return 0; 00147 } 00148 00149 /* look for the gzip magic header bytes 31 and 139 */ 00150 if (strm->next_in[0] == 31) { 00151 strm->avail_in--; 00152 strm->next_in++; 00153 if (strm->avail_in == 0 && gz_avail(state) == -1) 00154 return -1; 00155 if (strm->avail_in && strm->next_in[0] == 139) { 00156 /* we have a gzip header, woo hoo! */ 00157 strm->avail_in--; 00158 strm->next_in++; 00159 00160 /* skip rest of header */ 00161 if (NEXT() != 8) { /* compression method */ 00162 gz_error(state, Z_DATA_ERROR, "unknown compression method"); 00163 return -1; 00164 } 00165 flags = NEXT(); 00166 if (flags & 0xe0) { /* reserved flag bits */ 00167 gz_error(state, Z_DATA_ERROR, "unknown header flags set"); 00168 return -1; 00169 } 00170 NEXT(); /* modification time */ 00171 NEXT(); 00172 NEXT(); 00173 NEXT(); 00174 NEXT(); /* extra flags */ 00175 NEXT(); /* operating system */ 00176 if (flags & 4) { /* extra field */ 00177 len = (unsigned)NEXT(); 00178 len += (unsigned)NEXT() << 8; 00179 while (len--) 00180 if (NEXT() < 0) 00181 break; 00182 } 00183 if (flags & 8) /* file name */ 00184 while (NEXT() > 0) 00185 ; 00186 if (flags & 16) /* comment */ 00187 while (NEXT() > 0) 00188 ; 00189 if (flags & 2) { /* header crc */ 00190 NEXT(); 00191 NEXT(); 00192 } 00193 /* an unexpected end of file is not checked for here -- it will be 00194 noticed on the first request for uncompressed data */ 00195 00196 /* set up for decompression */ 00197 inflateReset(strm); 00198 strm->adler = crc32(0L, Z_NULL, 0); 00199 state->how = GZIP; 00200 state->direct = 0; 00201 return 0; 00202 } 00203 else { 00204 /* not a gzip file -- save first byte (31) and fall to raw i/o */ 00205 state->out[0] = 31; 00206 state->have = 1; 00207 } 00208 } 00209 00210 /* doing raw i/o, save start of raw data for seeking, copy any leftover 00211 input to output -- this assumes that the output buffer is larger than 00212 the input buffer, which also assures space for gzungetc() */ 00213 state->raw = state->pos; 00214 state->next = state->out; 00215 if (strm->avail_in) { 00216 memcpy(state->next + state->have, strm->next_in, strm->avail_in); 00217 state->have += strm->avail_in; 00218 strm->avail_in = 0; 00219 } 00220 state->how = COPY; 00221 state->direct = 1; 00222 return 0; 00223 } 00224 00225 /* Decompress from input to the provided next_out and avail_out in the state. 00226 If the end of the compressed data is reached, then verify the gzip trailer 00227 check value and length (modulo 2^32). state->have and state->next are set 00228 to point to the just decompressed data, and the crc is updated. If the 00229 trailer is verified, state->how is reset to LOOK to look for the next gzip 00230 stream or raw data, once state->have is depleted. Returns 0 on success, -1 00231 on failure. Failures may include invalid compressed data or a failed gzip 00232 trailer verification. */ 00233 local int gz_decomp(state) 00234 gz_statep state; 00235 { 00236 int ret; 00237 unsigned had; 00238 unsigned long crc, len; 00239 z_streamp strm = &(state->strm); 00240 00241 /* fill output buffer up to end of deflate stream */ 00242 had = strm->avail_out; 00243 do { 00244 /* get more input for inflate() */ 00245 if (strm->avail_in == 0 && gz_avail(state) == -1) 00246 return -1; 00247 if (strm->avail_in == 0) { 00248 gz_error(state, Z_DATA_ERROR, "unexpected end of file"); 00249 return -1; 00250 } 00251 00252 /* decompress and handle errors */ 00253 ret = inflate(strm, Z_NO_FLUSH); 00254 if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { 00255 gz_error(state, Z_STREAM_ERROR, 00256 "internal error: inflate stream corrupt"); 00257 return -1; 00258 } 00259 if (ret == Z_MEM_ERROR) { 00260 gz_error(state, Z_MEM_ERROR, "out of memory"); 00261 return -1; 00262 } 00263 if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ 00264 gz_error(state, Z_DATA_ERROR, 00265 strm->msg == NULL ? "compressed data error" : strm->msg); 00266 return -1; 00267 } 00268 } while (strm->avail_out && ret != Z_STREAM_END); 00269 00270 /* update available output and crc check value */ 00271 state->have = had - strm->avail_out; 00272 state->next = strm->next_out - state->have; 00273 strm->adler = crc32(strm->adler, state->next, state->have); 00274 00275 /* check gzip trailer if at end of deflate stream */ 00276 if (ret == Z_STREAM_END) { 00277 if (gz_next4(state, &crc) == -1 || gz_next4(state, &len) == -1) { 00278 gz_error(state, Z_DATA_ERROR, "unexpected end of file"); 00279 return -1; 00280 } 00281 if (crc != strm->adler) { 00282 gz_error(state, Z_DATA_ERROR, "incorrect data check"); 00283 return -1; 00284 } 00285 if (len != (strm->total_out & 0xffffffffL)) { 00286 gz_error(state, Z_DATA_ERROR, "incorrect length check"); 00287 return -1; 00288 } 00289 state->how = LOOK; /* ready for next stream, once have is 0 (leave 00290 state->direct unchanged to remember how) */ 00291 } 00292 00293 /* good decompression */ 00294 return 0; 00295 } 00296 00297 /* Make data and put in the output buffer. Assumes that state->have == 0. 00298 Data is either copied from the input file or decompressed from the input 00299 file depending on state->how. If state->how is LOOK, then a gzip header is 00300 looked for (and skipped if found) to determine wither to copy or decompress. 00301 Returns -1 on error, otherwise 0. gz_make() will leave state->have as COPY 00302 or GZIP unless the end of the input file has been reached and all data has 00303 been processed. */ 00304 local int gz_make(state) 00305 gz_statep state; 00306 { 00307 z_streamp strm = &(state->strm); 00308 00309 if (state->how == LOOK) { /* look for gzip header */ 00310 if (gz_head(state) == -1) 00311 return -1; 00312 if (state->have) /* got some data from gz_head() */ 00313 return 0; 00314 } 00315 if (state->how == COPY) { /* straight copy */ 00316 if (gz_load(state, state->out, state->size << 1, &(state->have)) == -1) 00317 return -1; 00318 state->next = state->out; 00319 } 00320 else if (state->how == GZIP) { /* decompress */ 00321 strm->avail_out = state->size << 1; 00322 strm->next_out = state->out; 00323 if (gz_decomp(state) == -1) 00324 return -1; 00325 } 00326 return 0; 00327 } 00328 00329 /* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ 00330 local int gz_skip(state, len) 00331 gz_statep state; 00332 z_off64_t len; 00333 { 00334 unsigned n; 00335 00336 /* skip over len bytes or reach end-of-file, whichever comes first */ 00337 while (len) 00338 /* skip over whatever is in output buffer */ 00339 if (state->have) { 00340 n = GT_OFF(state->have) || (z_off64_t)state->have > len ? 00341 (unsigned)len : state->have; 00342 state->have -= n; 00343 state->next += n; 00344 state->pos += n; 00345 len -= n; 00346 } 00347 00348 /* output buffer empty -- return if we're at the end of the input */ 00349 else if (state->eof && state->strm.avail_in == 0) 00350 break; 00351 00352 /* need more data to skip -- load up output buffer */ 00353 else { 00354 /* get more output, looking for header if required */ 00355 if (gz_make(state) == -1) 00356 return -1; 00357 } 00358 return 0; 00359 } 00360 00361 /* -- see zlib.h -- */ 00362 int ZEXPORT gzread(file, buf, len) 00363 gzFile file; 00364 voidp buf; 00365 unsigned len; 00366 { 00367 unsigned got, n; 00368 gz_statep state; 00369 z_streamp strm; 00370 00371 /* get internal structure */ 00372 if (file == NULL) 00373 return -1; 00374 state = (gz_statep)file; 00375 strm = &(state->strm); 00376 00377 /* check that we're reading and that there's no error */ 00378 if (state->mode != GZ_READ || state->err != Z_OK) 00379 return -1; 00380 00381 /* since an int is returned, make sure len fits in one, otherwise return 00382 with an error (this avoids the flaw in the interface) */ 00383 if ((int)len < 0) { 00384 gz_error(state, Z_BUF_ERROR, "requested length does not fit in int"); 00385 return -1; 00386 } 00387 00388 /* if len is zero, avoid unnecessary operations */ 00389 if (len == 0) 00390 return 0; 00391 00392 /* process a skip request */ 00393 if (state->seek) { 00394 state->seek = 0; 00395 if (gz_skip(state, state->skip) == -1) 00396 return -1; 00397 } 00398 00399 /* get len bytes to buf, or less than len if at the end */ 00400 got = 0; 00401 do { 00402 /* first just try copying data from the output buffer */ 00403 if (state->have) { 00404 n = state->have > len ? len : state->have; 00405 memcpy(buf, state->next, n); 00406 state->next += n; 00407 state->have -= n; 00408 } 00409 00410 /* output buffer empty -- return if we're at the end of the input */ 00411 else if (state->eof && strm->avail_in == 0) 00412 break; 00413 00414 /* need output data -- for small len or new stream load up our output 00415 buffer */ 00416 else if (state->how == LOOK || len < (state->size << 1)) { 00417 /* get more output, looking for header if required */ 00418 if (gz_make(state) == -1) 00419 return -1; 00420 continue; /* no progress yet -- go back to memcpy() above */ 00421 /* the copy above assures that we will leave with space in the 00422 output buffer, allowing at least one gzungetc() to succeed */ 00423 } 00424 00425 /* large len -- read directly into user buffer */ 00426 else if (state->how == COPY) { /* read directly */ 00427 if (gz_load(state, buf, len, &n) == -1) 00428 return -1; 00429 } 00430 00431 /* large len -- decompress directly into user buffer */ 00432 else { /* state->how == GZIP */ 00433 strm->avail_out = len; 00434 strm->next_out = buf; 00435 if (gz_decomp(state) == -1) 00436 return -1; 00437 n = state->have; 00438 state->have = 0; 00439 } 00440 00441 /* update progress */ 00442 len -= n; 00443 buf = (char *)buf + n; 00444 got += n; 00445 state->pos += n; 00446 } while (len); 00447 00448 /* return number of bytes read into user buffer (will fit in int) */ 00449 return (int)got; 00450 } 00451 00452 /* -- see zlib.h -- */ 00453 int ZEXPORT gzgetc(file) 00454 gzFile file; 00455 { 00456 int ret; 00457 unsigned char buf[1]; 00458 gz_statep state; 00459 00460 /* get internal structure */ 00461 if (file == NULL) 00462 return -1; 00463 state = (gz_statep)file; 00464 00465 /* check that we're reading and that there's no error */ 00466 if (state->mode != GZ_READ || state->err != Z_OK) 00467 return -1; 00468 00469 /* try output buffer (no need to check for skip request) */ 00470 if (state->have) { 00471 state->have--; 00472 state->pos++; 00473 return *(state->next)++; 00474 } 00475 00476 /* nothing there -- try gzread() */ 00477 ret = gzread(file, buf, 1); 00478 return ret < 1 ? -1 : buf[0]; 00479 } 00480 00481 /* -- see zlib.h -- */ 00482 int ZEXPORT gzungetc(c, file) 00483 int c; 00484 gzFile file; 00485 { 00486 gz_statep state; 00487 00488 /* get internal structure */ 00489 if (file == NULL) 00490 return -1; 00491 state = (gz_statep)file; 00492 00493 /* check that we're reading and that there's no error */ 00494 if (state->mode != GZ_READ || state->err != Z_OK) 00495 return -1; 00496 00497 /* process a skip request */ 00498 if (state->seek) { 00499 state->seek = 0; 00500 if (gz_skip(state, state->skip) == -1) 00501 return -1; 00502 } 00503 00504 /* can't push EOF */ 00505 if (c < 0) 00506 return -1; 00507 00508 /* if output buffer empty, put byte at end (allows more pushing) */ 00509 if (state->have == 0) { 00510 state->have = 1; 00511 state->next = state->out + (state->size << 1) - 1; 00512 state->next[0] = c; 00513 state->pos--; 00514 return c; 00515 } 00516 00517 /* if no room, give up (must have already done a gzungetc()) */ 00518 if (state->have == (state->size << 1)) { 00519 gz_error(state, Z_BUF_ERROR, "out of room to push characters"); 00520 return -1; 00521 } 00522 00523 /* slide output data if needed and insert byte before existing data */ 00524 if (state->next == state->out) { 00525 unsigned char *src = state->out + state->have; 00526 unsigned char *dest = state->out + (state->size << 1); 00527 while (src > state->out) 00528 *--dest = *--src; 00529 state->next = dest; 00530 } 00531 state->have++; 00532 state->next--; 00533 state->next[0] = c; 00534 state->pos--; 00535 return c; 00536 } 00537 00538 /* -- see zlib.h -- */ 00539 char * ZEXPORT gzgets(file, buf, len) 00540 gzFile file; 00541 char *buf; 00542 int len; 00543 { 00544 unsigned left, n; 00545 char *str; 00546 unsigned char *eol; 00547 gz_statep state; 00548 00549 /* check parameters and get internal structure */ 00550 if (file == NULL || buf == NULL || len < 1) 00551 return NULL; 00552 state = (gz_statep)file; 00553 00554 /* check that we're reading and that there's no error */ 00555 if (state->mode != GZ_READ || state->err != Z_OK) 00556 return NULL; 00557 00558 /* process a skip request */ 00559 if (state->seek) { 00560 state->seek = 0; 00561 if (gz_skip(state, state->skip) == -1) 00562 return NULL; 00563 } 00564 00565 /* copy output bytes up to new line or len - 1, whichever comes first -- 00566 append a terminating zero to the string (we don't check for a zero in 00567 the contents, let the user worry about that) */ 00568 str = buf; 00569 left = (unsigned)len - 1; 00570 if (left) do { 00571 /* assure that something is in the output buffer */ 00572 if (state->have == 0) { 00573 if (gz_make(state) == -1) 00574 return NULL; /* error */ 00575 if (state->have == 0) { /* end of file */ 00576 if (buf == str) /* got bupkus */ 00577 return NULL; 00578 break; /* got something -- return it */ 00579 } 00580 } 00581 00582 /* look for end-of-line in current output buffer */ 00583 n = state->have > left ? left : state->have; 00584 eol = memchr(state->next, '\n', n); 00585 if (eol != NULL) 00586 n = (unsigned)(eol - state->next) + 1; 00587 00588 /* copy through end-of-line, or remainder if not found */ 00589 memcpy(buf, state->next, n); 00590 state->have -= n; 00591 state->next += n; 00592 state->pos += n; 00593 left -= n; 00594 buf += n; 00595 } while (left && eol == NULL); 00596 00597 /* found end-of-line or out of space -- terminate string and return it */ 00598 buf[0] = 0; 00599 return str; 00600 } 00601 00602 /* -- see zlib.h -- */ 00603 int ZEXPORT gzdirect(file) 00604 gzFile file; 00605 { 00606 gz_statep state; 00607 00608 /* get internal structure */ 00609 if (file == NULL) 00610 return 0; 00611 state = (gz_statep)file; 00612 00613 /* check that we're reading */ 00614 if (state->mode != GZ_READ) 00615 return 0; 00616 00617 /* if the state is not known, but we can find out, then do so (this is 00618 mainly for right after a gzopen() or gzdopen()) */ 00619 if (state->how == LOOK && state->have == 0) 00620 (void)gz_head(state); 00621 00622 /* return 1 if reading direct, 0 if decompressing a gzip stream */ 00623 return state->direct; 00624 } 00625 00626 /* -- see zlib.h -- */ 00627 int ZEXPORT gzclose_r(file) 00628 gzFile file; 00629 { 00630 int ret; 00631 gz_statep state; 00632 00633 /* get internal structure */ 00634 if (file == NULL) 00635 return Z_STREAM_ERROR; 00636 state = (gz_statep)file; 00637 00638 /* check that we're reading */ 00639 if (state->mode != GZ_READ) 00640 return Z_STREAM_ERROR; 00641 00642 /* free memory and close file */ 00643 if (state->size) { 00644 inflateEnd(&(state->strm)); 00645 free(state->out); 00646 free(state->in); 00647 } 00648 gz_error(state, Z_OK, NULL); 00649 free(state->path); 00650 ret = close(state->fd); 00651 free(state); 00652 return ret ? Z_ERRNO : Z_OK; 00653 } Generated on Thu May 24 2012 04:36:22 for ReactOS by
1.7.6.1
|