Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
xzlib.c
00001 /** 00002 * xzlib.c: front end for the transparent suport of lzma compression 00003 * at the I/O layer, based on an example file from lzma project 00004 * 00005 * See Copyright for the status of this software. 00006 * 00007 * Anders F Bjorklund <afb@users.sourceforge.net> 00008 */ 00009 #define IN_LIBXML 00010 #include "libxml.h" 00011 #ifdef LIBXML_LZMA_ENABLED 00012 00013 #include <string.h> 00014 #ifdef HAVE_ERRNO_H 00015 #include <errno.h> 00016 #endif 00017 00018 00019 #ifdef HAVE_SYS_TYPES_H 00020 #include <sys/types.h> 00021 #endif 00022 #ifdef HAVE_SYS_STAT_H 00023 #include <sys/stat.h> 00024 #endif 00025 #ifdef HAVE_FCNTL_H 00026 #include <fcntl.h> 00027 #endif 00028 #ifdef HAVE_UNISTD_H 00029 #include <unistd.h> 00030 #endif 00031 #ifdef HAVE_STDLIB_H 00032 #include <stdlib.h> 00033 #endif 00034 #ifdef HAVE_ZLIB_H 00035 #include <zlib.h> 00036 #endif 00037 #ifdef HAVE_LZMA_H 00038 #include <lzma.h> 00039 #endif 00040 00041 #include "xzlib.h" 00042 #include <libxml/xmlmemory.h> 00043 00044 /* values for xz_state how */ 00045 #define LOOK 0 /* look for a gzip/lzma header */ 00046 #define COPY 1 /* copy input directly */ 00047 #define GZIP 2 /* decompress a gzip stream */ 00048 #define LZMA 3 /* decompress a lzma stream */ 00049 00050 /* internal lzma file state data structure */ 00051 typedef struct { 00052 int mode; /* see lzma modes above */ 00053 int fd; /* file descriptor */ 00054 char *path; /* path or fd for error messages */ 00055 uint64_t pos; /* current position in uncompressed data */ 00056 unsigned int size; /* buffer size, zero if not allocated yet */ 00057 unsigned int want; /* requested buffer size, default is BUFSIZ */ 00058 unsigned char *in; /* input buffer */ 00059 unsigned char *out; /* output buffer (double-sized when reading) */ 00060 unsigned char *next; /* next output data to deliver or write */ 00061 unsigned int have; /* amount of output data unused at next */ 00062 int eof; /* true if end of input file reached */ 00063 uint64_t start; /* where the lzma data started, for rewinding */ 00064 uint64_t raw; /* where the raw data started, for seeking */ 00065 int how; /* 0: get header, 1: copy, 2: decompress */ 00066 int direct; /* true if last read direct, false if lzma */ 00067 /* seek request */ 00068 uint64_t skip; /* amount to skip (already rewound if backwards) */ 00069 int seek; /* true if seek request pending */ 00070 /* error information */ 00071 int err; /* error code */ 00072 char *msg; /* error message */ 00073 /* lzma stream */ 00074 int init; /* is the iniflate stream initialized */ 00075 lzma_stream strm; /* stream structure in-place (not a pointer) */ 00076 char padding1[32]; /* padding allowing to cope with possible 00077 extensions of above structure without 00078 too much side effect */ 00079 #ifdef HAVE_ZLIB_H 00080 /* zlib inflate or deflate stream */ 00081 z_stream zstrm; /* stream structure in-place (not a pointer) */ 00082 #endif 00083 char padding2[32]; /* padding allowing to cope with possible 00084 extensions of above structure without 00085 too much side effect */ 00086 } xz_state, *xz_statep; 00087 00088 static void 00089 xz_error(xz_statep state, int err, const char *msg) 00090 { 00091 /* free previously allocated message and clear */ 00092 if (state->msg != NULL) { 00093 if (state->err != LZMA_MEM_ERROR) 00094 xmlFree(state->msg); 00095 state->msg = NULL; 00096 } 00097 00098 /* set error code, and if no message, then done */ 00099 state->err = err; 00100 if (msg == NULL) 00101 return; 00102 00103 /* for an out of memory error, save as static string */ 00104 if (err == LZMA_MEM_ERROR) { 00105 state->msg = (char *) msg; 00106 return; 00107 } 00108 00109 /* construct error message with path */ 00110 if ((state->msg = 00111 xmlMalloc(strlen(state->path) + strlen(msg) + 3)) == NULL) { 00112 state->err = LZMA_MEM_ERROR; 00113 state->msg = (char *) "out of memory"; 00114 return; 00115 } 00116 strcpy(state->msg, state->path); 00117 strcat(state->msg, ": "); 00118 strcat(state->msg, msg); 00119 return; 00120 } 00121 00122 static void 00123 xz_reset(xz_statep state) 00124 { 00125 state->have = 0; /* no output data available */ 00126 state->eof = 0; /* not at end of file */ 00127 state->how = LOOK; /* look for gzip header */ 00128 state->direct = 1; /* default for empty file */ 00129 state->seek = 0; /* no seek request pending */ 00130 xz_error(state, LZMA_OK, NULL); /* clear error */ 00131 state->pos = 0; /* no uncompressed data yet */ 00132 state->strm.avail_in = 0; /* no input data yet */ 00133 #ifdef HAVE_ZLIB_H 00134 state->zstrm.avail_in = 0; /* no input data yet */ 00135 #endif 00136 } 00137 00138 static xzFile 00139 xz_open(const char *path, int fd, const char *mode ATTRIBUTE_UNUSED) 00140 { 00141 xz_statep state; 00142 00143 /* allocate xzFile structure to return */ 00144 state = xmlMalloc(sizeof(xz_state)); 00145 if (state == NULL) 00146 return NULL; 00147 state->size = 0; /* no buffers allocated yet */ 00148 state->want = BUFSIZ; /* requested buffer size */ 00149 state->msg = NULL; /* no error message yet */ 00150 state->init = 0; /* initialization of zlib data */ 00151 00152 /* save the path name for error messages */ 00153 state->path = xmlMalloc(strlen(path) + 1); 00154 if (state->path == NULL) { 00155 xmlFree(state); 00156 return NULL; 00157 } 00158 strcpy(state->path, path); 00159 00160 /* open the file with the appropriate mode (or just use fd) */ 00161 state->fd = fd != -1 ? fd : open(path, 00162 #ifdef O_LARGEFILE 00163 O_LARGEFILE | 00164 #endif 00165 #ifdef O_BINARY 00166 O_BINARY | 00167 #endif 00168 O_RDONLY, 0666); 00169 if (state->fd == -1) { 00170 xmlFree(state->path); 00171 xmlFree(state); 00172 return NULL; 00173 } 00174 00175 /* save the current position for rewinding (only if reading) */ 00176 state->start = lseek(state->fd, 0, SEEK_CUR); 00177 if (state->start == (uint64_t) - 1) 00178 state->start = 0; 00179 00180 /* initialize stream */ 00181 xz_reset(state); 00182 00183 /* return stream */ 00184 return (xzFile) state; 00185 } 00186 00187 static int 00188 xz_compressed(xzFile f) { 00189 xz_statep state; 00190 00191 if (f == NULL) 00192 return(-1); 00193 state = (xz_statep) f; 00194 if (state->init <= 0) 00195 return(-1); 00196 00197 switch (state->how) { 00198 case COPY: 00199 return(0); 00200 case GZIP: 00201 case LZMA: 00202 return(1); 00203 } 00204 return(-1); 00205 } 00206 00207 xzFile 00208 __libxml2_xzopen(const char *path, const char *mode) 00209 { 00210 return xz_open(path, -1, mode); 00211 } 00212 00213 int 00214 __libxml2_xzcompressed(xzFile f) { 00215 return xz_compressed(f); 00216 } 00217 00218 xzFile 00219 __libxml2_xzdopen(int fd, const char *mode) 00220 { 00221 char *path; /* identifier for error messages */ 00222 xzFile xz; 00223 00224 if (fd == -1 || (path = xmlMalloc(7 + 3 * sizeof(int))) == NULL) 00225 return NULL; 00226 sprintf(path, "<fd:%d>", fd); /* for debugging */ 00227 xz = xz_open(path, fd, mode); 00228 xmlFree(path); 00229 return xz; 00230 } 00231 00232 static int 00233 xz_load(xz_statep state, unsigned char *buf, unsigned int len, 00234 unsigned int *have) 00235 { 00236 int ret; 00237 00238 *have = 0; 00239 do { 00240 ret = read(state->fd, buf + *have, len - *have); 00241 if (ret <= 0) 00242 break; 00243 *have += ret; 00244 } while (*have < len); 00245 if (ret < 0) { 00246 xz_error(state, -1, strerror(errno)); 00247 return -1; 00248 } 00249 if (ret == 0) 00250 state->eof = 1; 00251 return 0; 00252 } 00253 00254 static int 00255 xz_avail(xz_statep state) 00256 { 00257 lzma_stream *strm = &(state->strm); 00258 00259 if (state->err != LZMA_OK) 00260 return -1; 00261 if (state->eof == 0) { 00262 /* avail_in is size_t, which is not necessary sizeof(unsigned) */ 00263 unsigned tmp = strm->avail_in; 00264 00265 if (xz_load(state, state->in, state->size, &tmp) == -1) { 00266 strm->avail_in = tmp; 00267 return -1; 00268 } 00269 strm->avail_in = tmp; 00270 strm->next_in = state->in; 00271 } 00272 return 0; 00273 } 00274 00275 #ifdef HAVE_ZLIB_H 00276 static int 00277 xz_avail_zstrm(xz_statep state) 00278 { 00279 int ret; 00280 state->strm.avail_in = state->zstrm.avail_in; 00281 state->strm.next_in = state->zstrm.next_in; 00282 ret = xz_avail(state); 00283 state->zstrm.avail_in = (uInt) state->strm.avail_in; 00284 state->zstrm.next_in = (Bytef *) state->strm.next_in; 00285 return ret; 00286 } 00287 #endif 00288 00289 static int 00290 is_format_xz(xz_statep state) 00291 { 00292 lzma_stream *strm = &(state->strm); 00293 00294 return strm->avail_in >= 6 && memcmp(state->in, "\3757zXZ", 6) == 0; 00295 } 00296 00297 static int 00298 is_format_lzma(xz_statep state) 00299 { 00300 lzma_stream *strm = &(state->strm); 00301 00302 lzma_filter filter; 00303 lzma_options_lzma *opt; 00304 uint32_t dict_size; 00305 uint64_t uncompressed_size; 00306 size_t i; 00307 00308 if (strm->avail_in < 13) 00309 return 0; 00310 00311 filter.id = LZMA_FILTER_LZMA1; 00312 if (lzma_properties_decode(&filter, NULL, state->in, 5) != LZMA_OK) 00313 return 0; 00314 00315 opt = filter.options; 00316 dict_size = opt->dict_size; 00317 free(opt); /* we can't use xmlFree on a string returned by zlib */ 00318 00319 /* A hack to ditch tons of false positives: We allow only dictionary 00320 * sizes that are 2^n or 2^n + 2^(n-1) or UINT32_MAX. LZMA_Alone 00321 * created only files with 2^n, but accepts any dictionary size. 00322 * If someone complains, this will be reconsidered. 00323 */ 00324 if (dict_size != UINT32_MAX) { 00325 uint32_t d = dict_size - 1; 00326 00327 d |= d >> 2; 00328 d |= d >> 3; 00329 d |= d >> 4; 00330 d |= d >> 8; 00331 d |= d >> 16; 00332 ++d; 00333 if (d != dict_size || dict_size == 0) 00334 return 0; 00335 } 00336 00337 /* Another hack to ditch false positives: Assume that if the 00338 * uncompressed size is known, it must be less than 256 GiB. 00339 * Again, if someone complains, this will be reconsidered. 00340 */ 00341 uncompressed_size = 0; 00342 for (i = 0; i < 8; ++i) 00343 uncompressed_size |= (uint64_t) (state->in[5 + i]) << (i * 8); 00344 00345 if (uncompressed_size != UINT64_MAX 00346 && uncompressed_size > (UINT64_C(1) << 38)) 00347 return 0; 00348 00349 return 1; 00350 } 00351 00352 #ifdef HAVE_ZLIB_H 00353 00354 /* Get next byte from input, or -1 if end or error. */ 00355 #define NEXT() ((strm->avail_in == 0 && xz_avail(state) == -1) ? -1 : \ 00356 (strm->avail_in == 0 ? -1 : \ 00357 (strm->avail_in--, *(strm->next_in)++))) 00358 /* Same thing, but from zstrm */ 00359 #define NEXTZ() ((strm->avail_in == 0 && xz_avail_zstrm(state) == -1) ? -1 : \ 00360 (strm->avail_in == 0 ? -1 : \ 00361 (strm->avail_in--, *(strm->next_in)++))) 00362 00363 /* Get a four-byte little-endian integer and return 0 on success and the value 00364 in *ret. Otherwise -1 is returned and *ret is not modified. */ 00365 static int 00366 gz_next4(xz_statep state, unsigned long *ret) 00367 { 00368 int ch; 00369 unsigned long val; 00370 z_streamp strm = &(state->zstrm); 00371 00372 val = NEXTZ(); 00373 val += (unsigned) NEXTZ() << 8; 00374 val += (unsigned long) NEXTZ() << 16; 00375 ch = NEXTZ(); 00376 if (ch == -1) 00377 return -1; 00378 val += (unsigned long) ch << 24; 00379 *ret = val; 00380 return 0; 00381 } 00382 #endif 00383 00384 static int 00385 xz_head(xz_statep state) 00386 { 00387 lzma_stream *strm = &(state->strm); 00388 lzma_stream init = LZMA_STREAM_INIT; 00389 int flags; 00390 unsigned len; 00391 00392 /* allocate read buffers and inflate memory */ 00393 if (state->size == 0) { 00394 /* allocate buffers */ 00395 state->in = xmlMalloc(state->want); 00396 state->out = xmlMalloc(state->want << 1); 00397 if (state->in == NULL || state->out == NULL) { 00398 if (state->out != NULL) 00399 xmlFree(state->out); 00400 if (state->in != NULL) 00401 xmlFree(state->in); 00402 xz_error(state, LZMA_MEM_ERROR, "out of memory"); 00403 return -1; 00404 } 00405 state->size = state->want; 00406 00407 /* allocate decoder memory */ 00408 state->strm = init; 00409 state->strm.avail_in = 0; 00410 state->strm.next_in = NULL; 00411 if (lzma_auto_decoder(&state->strm, UINT64_MAX, 0) != LZMA_OK) { 00412 xmlFree(state->out); 00413 xmlFree(state->in); 00414 state->size = 0; 00415 xz_error(state, LZMA_MEM_ERROR, "out of memory"); 00416 return -1; 00417 } 00418 #ifdef HAVE_ZLIB_H 00419 /* allocate inflate memory */ 00420 state->zstrm.zalloc = Z_NULL; 00421 state->zstrm.zfree = Z_NULL; 00422 state->zstrm.opaque = Z_NULL; 00423 state->zstrm.avail_in = 0; 00424 state->zstrm.next_in = Z_NULL; 00425 if (state->init == 0) { 00426 if (inflateInit2(&(state->zstrm), -15) != Z_OK) {/* raw inflate */ 00427 xmlFree(state->out); 00428 xmlFree(state->in); 00429 state->size = 0; 00430 xz_error(state, LZMA_MEM_ERROR, "out of memory"); 00431 return -1; 00432 } 00433 state->init = 1; 00434 } 00435 #endif 00436 } 00437 00438 /* get some data in the input buffer */ 00439 if (strm->avail_in == 0) { 00440 if (xz_avail(state) == -1) 00441 return -1; 00442 if (strm->avail_in == 0) 00443 return 0; 00444 } 00445 00446 /* look for the xz magic header bytes */ 00447 if (is_format_xz(state) || is_format_lzma(state)) { 00448 state->how = LZMA; 00449 state->direct = 0; 00450 return 0; 00451 } 00452 #ifdef HAVE_ZLIB_H 00453 /* look for the gzip magic header bytes 31 and 139 */ 00454 if (strm->next_in[0] == 31) { 00455 strm->avail_in--; 00456 strm->next_in++; 00457 if (strm->avail_in == 0 && xz_avail(state) == -1) 00458 return -1; 00459 if (strm->avail_in && strm->next_in[0] == 139) { 00460 /* we have a gzip header, woo hoo! */ 00461 strm->avail_in--; 00462 strm->next_in++; 00463 00464 /* skip rest of header */ 00465 if (NEXT() != 8) { /* compression method */ 00466 xz_error(state, LZMA_DATA_ERROR, 00467 "unknown compression method"); 00468 return -1; 00469 } 00470 flags = NEXT(); 00471 if (flags & 0xe0) { /* reserved flag bits */ 00472 xz_error(state, LZMA_DATA_ERROR, 00473 "unknown header flags set"); 00474 return -1; 00475 } 00476 NEXT(); /* modification time */ 00477 NEXT(); 00478 NEXT(); 00479 NEXT(); 00480 NEXT(); /* extra flags */ 00481 NEXT(); /* operating system */ 00482 if (flags & 4) { /* extra field */ 00483 len = (unsigned) NEXT(); 00484 len += (unsigned) NEXT() << 8; 00485 while (len--) 00486 if (NEXT() < 0) 00487 break; 00488 } 00489 if (flags & 8) /* file name */ 00490 while (NEXT() > 0) ; 00491 if (flags & 16) /* comment */ 00492 while (NEXT() > 0) ; 00493 if (flags & 2) { /* header crc */ 00494 NEXT(); 00495 NEXT(); 00496 } 00497 /* an unexpected end of file is not checked for here -- it will be 00498 * noticed on the first request for uncompressed data */ 00499 00500 /* set up for decompression */ 00501 inflateReset(&state->zstrm); 00502 state->zstrm.adler = crc32(0L, Z_NULL, 0); 00503 state->how = GZIP; 00504 state->direct = 0; 00505 return 0; 00506 } else { 00507 /* not a gzip file -- save first byte (31) and fall to raw i/o */ 00508 state->out[0] = 31; 00509 state->have = 1; 00510 } 00511 } 00512 #endif 00513 00514 /* doing raw i/o, save start of raw data for seeking, copy any leftover 00515 * input to output -- this assumes that the output buffer is larger than 00516 * the input buffer, which also assures space for gzungetc() */ 00517 state->raw = state->pos; 00518 state->next = state->out; 00519 if (strm->avail_in) { 00520 memcpy(state->next + state->have, strm->next_in, strm->avail_in); 00521 state->have += strm->avail_in; 00522 strm->avail_in = 0; 00523 } 00524 state->how = COPY; 00525 state->direct = 1; 00526 return 0; 00527 } 00528 00529 static int 00530 xz_decomp(xz_statep state) 00531 { 00532 int ret; 00533 unsigned had; 00534 unsigned long crc, len; 00535 lzma_stream *strm = &(state->strm); 00536 00537 lzma_action action = LZMA_RUN; 00538 00539 /* fill output buffer up to end of deflate stream */ 00540 had = strm->avail_out; 00541 do { 00542 /* get more input for inflate() */ 00543 if (strm->avail_in == 0 && xz_avail(state) == -1) 00544 return -1; 00545 if (strm->avail_in == 0) { 00546 xz_error(state, LZMA_DATA_ERROR, "unexpected end of file"); 00547 return -1; 00548 } 00549 if (state->eof) 00550 action = LZMA_FINISH; 00551 00552 /* decompress and handle errors */ 00553 #ifdef HAVE_ZLIB_H 00554 if (state->how == GZIP) { 00555 state->zstrm.avail_in = (uInt) state->strm.avail_in; 00556 state->zstrm.next_in = (Bytef *) state->strm.next_in; 00557 state->zstrm.avail_out = (uInt) state->strm.avail_out; 00558 state->zstrm.next_out = (Bytef *) state->strm.next_out; 00559 ret = inflate(&state->zstrm, Z_NO_FLUSH); 00560 if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { 00561 xz_error(state, Z_STREAM_ERROR, 00562 "internal error: inflate stream corrupt"); 00563 return -1; 00564 } 00565 if (ret == Z_MEM_ERROR) 00566 ret = LZMA_MEM_ERROR; 00567 if (ret == Z_DATA_ERROR) 00568 ret = LZMA_DATA_ERROR; 00569 if (ret == Z_STREAM_END) 00570 ret = LZMA_STREAM_END; 00571 state->strm.avail_in = state->zstrm.avail_in; 00572 state->strm.next_in = state->zstrm.next_in; 00573 state->strm.avail_out = state->zstrm.avail_out; 00574 state->strm.next_out = state->zstrm.next_out; 00575 } else /* state->how == LZMA */ 00576 #endif 00577 ret = lzma_code(strm, action); 00578 if (ret == LZMA_MEM_ERROR) { 00579 xz_error(state, LZMA_MEM_ERROR, "out of memory"); 00580 return -1; 00581 } 00582 if (ret == LZMA_DATA_ERROR) { 00583 xz_error(state, LZMA_DATA_ERROR, "compressed data error"); 00584 return -1; 00585 } 00586 if (ret == LZMA_PROG_ERROR) { 00587 xz_error(state, LZMA_PROG_ERROR, "compression error"); 00588 return -1; 00589 } 00590 } while (strm->avail_out && ret != LZMA_STREAM_END); 00591 00592 /* update available output and crc check value */ 00593 state->have = had - strm->avail_out; 00594 state->next = strm->next_out - state->have; 00595 #ifdef HAVE_ZLIB_H 00596 state->zstrm.adler = 00597 crc32(state->zstrm.adler, state->next, state->have); 00598 #endif 00599 00600 if (ret == LZMA_STREAM_END) { 00601 #ifdef HAVE_ZLIB_H 00602 if (state->how == GZIP) { 00603 if (gz_next4(state, &crc) == -1 || gz_next4(state, &len) == -1) { 00604 xz_error(state, LZMA_DATA_ERROR, "unexpected end of file"); 00605 return -1; 00606 } 00607 if (crc != state->zstrm.adler) { 00608 xz_error(state, LZMA_DATA_ERROR, "incorrect data check"); 00609 return -1; 00610 } 00611 if (len != (state->zstrm.total_out & 0xffffffffL)) { 00612 xz_error(state, LZMA_DATA_ERROR, "incorrect length check"); 00613 return -1; 00614 } 00615 state->strm.avail_in = 0; 00616 state->strm.next_in = NULL; 00617 state->strm.avail_out = 0; 00618 state->strm.next_out = NULL; 00619 } else 00620 #endif 00621 if (strm->avail_in != 0 || !state->eof) { 00622 xz_error(state, LZMA_DATA_ERROR, "trailing garbage"); 00623 return -1; 00624 } 00625 state->how = LOOK; /* ready for next stream, once have is 0 (leave 00626 * state->direct unchanged to remember how) */ 00627 } 00628 00629 /* good decompression */ 00630 return 0; 00631 } 00632 00633 static int 00634 xz_make(xz_statep state) 00635 { 00636 lzma_stream *strm = &(state->strm); 00637 00638 if (state->how == LOOK) { /* look for lzma / gzip header */ 00639 if (xz_head(state) == -1) 00640 return -1; 00641 if (state->have) /* got some data from xz_head() */ 00642 return 0; 00643 } 00644 if (state->how == COPY) { /* straight copy */ 00645 if (xz_load(state, state->out, state->size << 1, &(state->have)) == 00646 -1) 00647 return -1; 00648 state->next = state->out; 00649 } else if (state->how == LZMA || state->how == GZIP) { /* decompress */ 00650 strm->avail_out = state->size << 1; 00651 strm->next_out = state->out; 00652 if (xz_decomp(state) == -1) 00653 return -1; 00654 } 00655 return 0; 00656 } 00657 00658 static int 00659 xz_skip(xz_statep state, uint64_t len) 00660 { 00661 unsigned n; 00662 00663 /* skip over len bytes or reach end-of-file, whichever comes first */ 00664 while (len) 00665 /* skip over whatever is in output buffer */ 00666 if (state->have) { 00667 n = (uint64_t) state->have > len ? 00668 (unsigned) len : state->have; 00669 state->have -= n; 00670 state->next += n; 00671 state->pos += n; 00672 len -= n; 00673 } 00674 00675 /* output buffer empty -- return if we're at the end of the input */ 00676 else if (state->eof && state->strm.avail_in == 0) 00677 break; 00678 00679 /* need more data to skip -- load up output buffer */ 00680 else { 00681 /* get more output, looking for header if required */ 00682 if (xz_make(state) == -1) 00683 return -1; 00684 } 00685 return 0; 00686 } 00687 00688 int 00689 __libxml2_xzread(xzFile file, void *buf, unsigned len) 00690 { 00691 unsigned got, n; 00692 xz_statep state; 00693 lzma_stream *strm; 00694 00695 /* get internal structure */ 00696 if (file == NULL) 00697 return -1; 00698 state = (xz_statep) file; 00699 strm = &(state->strm); 00700 00701 /* check that we're reading and that there's no error */ 00702 if (state->err != LZMA_OK) 00703 return -1; 00704 00705 /* since an int is returned, make sure len fits in one, otherwise return 00706 * with an error (this avoids the flaw in the interface) */ 00707 if ((int) len < 0) { 00708 xz_error(state, LZMA_BUF_ERROR, 00709 "requested length does not fit in int"); 00710 return -1; 00711 } 00712 00713 /* if len is zero, avoid unnecessary operations */ 00714 if (len == 0) 00715 return 0; 00716 00717 /* process a skip request */ 00718 if (state->seek) { 00719 state->seek = 0; 00720 if (xz_skip(state, state->skip) == -1) 00721 return -1; 00722 } 00723 00724 /* get len bytes to buf, or less than len if at the end */ 00725 got = 0; 00726 do { 00727 /* first just try copying data from the output buffer */ 00728 if (state->have) { 00729 n = state->have > len ? len : state->have; 00730 memcpy(buf, state->next, n); 00731 state->next += n; 00732 state->have -= n; 00733 } 00734 00735 /* output buffer empty -- return if we're at the end of the input */ 00736 else if (state->eof && strm->avail_in == 0) 00737 break; 00738 00739 /* need output data -- for small len or new stream load up our output 00740 * buffer */ 00741 else if (state->how == LOOK || len < (state->size << 1)) { 00742 /* get more output, looking for header if required */ 00743 if (xz_make(state) == -1) 00744 return -1; 00745 continue; /* no progress yet -- go back to memcpy() above */ 00746 /* the copy above assures that we will leave with space in the 00747 * output buffer, allowing at least one gzungetc() to succeed */ 00748 } 00749 00750 /* large len -- read directly into user buffer */ 00751 else if (state->how == COPY) { /* read directly */ 00752 if (xz_load(state, buf, len, &n) == -1) 00753 return -1; 00754 } 00755 00756 /* large len -- decompress directly into user buffer */ 00757 else { /* state->how == LZMA */ 00758 strm->avail_out = len; 00759 strm->next_out = buf; 00760 if (xz_decomp(state) == -1) 00761 return -1; 00762 n = state->have; 00763 state->have = 0; 00764 } 00765 00766 /* update progress */ 00767 len -= n; 00768 buf = (char *) buf + n; 00769 got += n; 00770 state->pos += n; 00771 } while (len); 00772 00773 /* return number of bytes read into user buffer (will fit in int) */ 00774 return (int) got; 00775 } 00776 00777 int 00778 __libxml2_xzclose(xzFile file) 00779 { 00780 int ret; 00781 xz_statep state; 00782 00783 /* get internal structure */ 00784 if (file == NULL) 00785 return LZMA_DATA_ERROR; 00786 state = (xz_statep) file; 00787 00788 /* free memory and close file */ 00789 if (state->size) { 00790 lzma_end(&(state->strm)); 00791 #ifdef HAVE_ZLIB_H 00792 if (state->init == 1) 00793 inflateEnd(&(state->zstrm)); 00794 state->init = 0; 00795 #endif 00796 xmlFree(state->out); 00797 xmlFree(state->in); 00798 } 00799 xmlFree(state->path); 00800 ret = close(state->fd); 00801 xmlFree(state); 00802 return ret ? ret : LZMA_OK; 00803 } 00804 #endif /* LIBXML_LZMA_ENABLED */ 00805
Generated on Thu Jul 14 2022 13:59:20 by
