File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / xzlib.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 01:22:18 2013 UTC (10 years, 10 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_9_1p0, v2_9_1, v2_8_0p0, v2_8_0, HEAD
2.8.0

    1: /**
    2:  * xzlib.c: front end for the transparent suport of lzma compression
    3:  *          at the I/O layer, based on an example file from lzma project
    4:  *
    5:  * See Copyright for the status of this software.
    6:  *
    7:  * Anders F Bjorklund <afb@users.sourceforge.net>
    8:  */
    9: #define IN_LIBXML
   10: #include "libxml.h"
   11: #ifdef HAVE_LZMA_H
   12: 
   13: #include <string.h>
   14: #ifdef HAVE_ERRNO_H
   15: #include <errno.h>
   16: #endif
   17: 
   18: 
   19: #ifdef HAVE_SYS_TYPES_H
   20: #include <sys/types.h>
   21: #endif
   22: #ifdef HAVE_SYS_STAT_H
   23: #include <sys/stat.h>
   24: #endif
   25: #ifdef HAVE_FCNTL_H
   26: #include <fcntl.h>
   27: #endif
   28: #ifdef HAVE_UNISTD_H
   29: #include <unistd.h>
   30: #endif
   31: #ifdef HAVE_STDLIB_H
   32: #include <stdlib.h>
   33: #endif
   34: #ifdef HAVE_ZLIB_H
   35: #include <zlib.h>
   36: #endif
   37: #include <lzma.h>
   38: 
   39: #include "xzlib.h"
   40: #include <libxml/xmlmemory.h>
   41: 
   42: /* values for xz_state how */
   43: #define LOOK 0                  /* look for a gzip/lzma header */
   44: #define COPY 1                  /* copy input directly */
   45: #define GZIP 2                  /* decompress a gzip stream */
   46: #define LZMA 3                  /* decompress a lzma stream */
   47: 
   48: /* internal lzma file state data structure */
   49: typedef struct {
   50:     int mode;                   /* see lzma modes above */
   51:     int fd;                     /* file descriptor */
   52:     char *path;                 /* path or fd for error messages */
   53:     uint64_t pos;               /* current position in uncompressed data */
   54:     unsigned int size;          /* buffer size, zero if not allocated yet */
   55:     unsigned int want;          /* requested buffer size, default is BUFSIZ */
   56:     unsigned char *in;          /* input buffer */
   57:     unsigned char *out;         /* output buffer (double-sized when reading) */
   58:     unsigned char *next;        /* next output data to deliver or write */
   59:     unsigned int have;          /* amount of output data unused at next */
   60:     int eof;                    /* true if end of input file reached */
   61:     uint64_t start;             /* where the lzma data started, for rewinding */
   62:     uint64_t raw;               /* where the raw data started, for seeking */
   63:     int how;                    /* 0: get header, 1: copy, 2: decompress */
   64:     int direct;                 /* true if last read direct, false if lzma */
   65:     /* seek request */
   66:     uint64_t skip;              /* amount to skip (already rewound if backwards) */
   67:     int seek;                   /* true if seek request pending */
   68:     /* error information */
   69:     int err;                    /* error code */
   70:     char *msg;                  /* error message */
   71:     /* lzma stream */
   72:     int init;                   /* is the iniflate stream initialized */
   73:     lzma_stream strm;           /* stream structure in-place (not a pointer) */
   74:     char padding1[32];          /* padding allowing to cope with possible
   75:                                    extensions of above structure without
   76: 				   too much side effect */
   77: #ifdef HAVE_ZLIB_H
   78:     /* zlib inflate or deflate stream */
   79:     z_stream zstrm;             /* stream structure in-place (not a pointer) */
   80: #endif
   81:     char padding2[32];          /* padding allowing to cope with possible
   82:                                    extensions of above structure without
   83: 				   too much side effect */
   84: } xz_state, *xz_statep;
   85: 
   86: static void
   87: xz_error(xz_statep state, int err, const char *msg)
   88: {
   89:     /* free previously allocated message and clear */
   90:     if (state->msg != NULL) {
   91:         if (state->err != LZMA_MEM_ERROR)
   92:             xmlFree(state->msg);
   93:         state->msg = NULL;
   94:     }
   95: 
   96:     /* set error code, and if no message, then done */
   97:     state->err = err;
   98:     if (msg == NULL)
   99:         return;
  100: 
  101:     /* for an out of memory error, save as static string */
  102:     if (err == LZMA_MEM_ERROR) {
  103:         state->msg = (char *) msg;
  104:         return;
  105:     }
  106: 
  107:     /* construct error message with path */
  108:     if ((state->msg =
  109:          xmlMalloc(strlen(state->path) + strlen(msg) + 3)) == NULL) {
  110:         state->err = LZMA_MEM_ERROR;
  111:         state->msg = (char *) "out of memory";
  112:         return;
  113:     }
  114:     strcpy(state->msg, state->path);
  115:     strcat(state->msg, ": ");
  116:     strcat(state->msg, msg);
  117:     return;
  118: }
  119: 
  120: static void
  121: xz_reset(xz_statep state)
  122: {
  123:     state->have = 0;            /* no output data available */
  124:     state->eof = 0;             /* not at end of file */
  125:     state->how = LOOK;          /* look for gzip header */
  126:     state->direct = 1;          /* default for empty file */
  127:     state->seek = 0;            /* no seek request pending */
  128:     xz_error(state, LZMA_OK, NULL);     /* clear error */
  129:     state->pos = 0;             /* no uncompressed data yet */
  130:     state->strm.avail_in = 0;   /* no input data yet */
  131: #ifdef HAVE_ZLIB_H
  132:     state->zstrm.avail_in = 0;  /* no input data yet */
  133: #endif
  134: }
  135: 
  136: static xzFile
  137: xz_open(const char *path, int fd, const char *mode ATTRIBUTE_UNUSED)
  138: {
  139:     xz_statep state;
  140: 
  141:     /* allocate xzFile structure to return */
  142:     state = xmlMalloc(sizeof(xz_state));
  143:     if (state == NULL)
  144:         return NULL;
  145:     state->size = 0;            /* no buffers allocated yet */
  146:     state->want = BUFSIZ;       /* requested buffer size */
  147:     state->msg = NULL;          /* no error message yet */
  148:     state->init = 0;            /* initialization of zlib data */
  149: 
  150:     /* save the path name for error messages */
  151:     state->path = xmlMalloc(strlen(path) + 1);
  152:     if (state->path == NULL) {
  153:         xmlFree(state);
  154:         return NULL;
  155:     }
  156:     strcpy(state->path, path);
  157: 
  158:     /* open the file with the appropriate mode (or just use fd) */
  159:     state->fd = fd != -1 ? fd : open(path,
  160: #ifdef O_LARGEFILE
  161:                                      O_LARGEFILE |
  162: #endif
  163: #ifdef O_BINARY
  164:                                      O_BINARY |
  165: #endif
  166:                                      O_RDONLY, 0666);
  167:     if (state->fd == -1) {
  168:         xmlFree(state->path);
  169:         xmlFree(state);
  170:         return NULL;
  171:     }
  172: 
  173:     /* save the current position for rewinding (only if reading) */
  174:     state->start = lseek(state->fd, 0, SEEK_CUR);
  175:     if (state->start == (uint64_t) - 1)
  176:         state->start = 0;
  177: 
  178:     /* initialize stream */
  179:     xz_reset(state);
  180: 
  181:     /* return stream */
  182:     return (xzFile) state;
  183: }
  184: 
  185: xzFile
  186: __libxml2_xzopen(const char *path, const char *mode)
  187: {
  188:     return xz_open(path, -1, mode);
  189: }
  190: 
  191: xzFile
  192: __libxml2_xzdopen(int fd, const char *mode)
  193: {
  194:     char *path;                 /* identifier for error messages */
  195:     xzFile xz;
  196: 
  197:     if (fd == -1 || (path = xmlMalloc(7 + 3 * sizeof(int))) == NULL)
  198:         return NULL;
  199:     sprintf(path, "<fd:%d>", fd);       /* for debugging */
  200:     xz = xz_open(path, fd, mode);
  201:     xmlFree(path);
  202:     return xz;
  203: }
  204: 
  205: static int
  206: xz_load(xz_statep state, unsigned char *buf, unsigned int len,
  207:         unsigned int *have)
  208: {
  209:     int ret;
  210: 
  211:     *have = 0;
  212:     do {
  213:         ret = read(state->fd, buf + *have, len - *have);
  214:         if (ret <= 0)
  215:             break;
  216:         *have += ret;
  217:     } while (*have < len);
  218:     if (ret < 0) {
  219:         xz_error(state, -1, strerror(errno));
  220:         return -1;
  221:     }
  222:     if (ret == 0)
  223:         state->eof = 1;
  224:     return 0;
  225: }
  226: 
  227: static int
  228: xz_avail(xz_statep state)
  229: {
  230:     lzma_stream *strm = &(state->strm);
  231: 
  232:     if (state->err != LZMA_OK)
  233:         return -1;
  234:     if (state->eof == 0) {
  235:         /* avail_in is size_t, which is not necessary sizeof(unsigned) */
  236:         unsigned tmp = strm->avail_in;
  237: 
  238:         if (xz_load(state, state->in, state->size, &tmp) == -1) {
  239:             strm->avail_in = tmp;
  240:             return -1;
  241:         }
  242:         strm->avail_in = tmp;
  243:         strm->next_in = state->in;
  244:     }
  245:     return 0;
  246: }
  247: 
  248: static int
  249: is_format_xz(xz_statep state)
  250: {
  251:     lzma_stream *strm = &(state->strm);
  252: 
  253:     return strm->avail_in >= 6 && memcmp(state->in, "\3757zXZ", 6) == 0;
  254: }
  255: 
  256: static int
  257: is_format_lzma(xz_statep state)
  258: {
  259:     lzma_stream *strm = &(state->strm);
  260: 
  261:     lzma_filter filter;
  262:     lzma_options_lzma *opt;
  263:     uint32_t dict_size;
  264:     uint64_t uncompressed_size;
  265:     size_t i;
  266: 
  267:     if (strm->avail_in < 13)
  268:         return 0;
  269: 
  270:     filter.id = LZMA_FILTER_LZMA1;
  271:     if (lzma_properties_decode(&filter, NULL, state->in, 5) != LZMA_OK)
  272:         return 0;
  273: 
  274:     opt = filter.options;
  275:     dict_size = opt->dict_size;
  276:     free(opt); /* we can't use xmlFree on a string returned by zlib */
  277: 
  278:     /* A hack to ditch tons of false positives: We allow only dictionary
  279:      * sizes that are 2^n or 2^n + 2^(n-1) or UINT32_MAX. LZMA_Alone
  280:      * created only files with 2^n, but accepts any dictionary size.
  281:      * If someone complains, this will be reconsidered.
  282:      */
  283:     if (dict_size != UINT32_MAX) {
  284:         uint32_t d = dict_size - 1;
  285: 
  286:         d |= d >> 2;
  287:         d |= d >> 3;
  288:         d |= d >> 4;
  289:         d |= d >> 8;
  290:         d |= d >> 16;
  291:         ++d;
  292:         if (d != dict_size || dict_size == 0)
  293:             return 0;
  294:     }
  295: 
  296:     /* Another hack to ditch false positives: Assume that if the
  297:      * uncompressed size is known, it must be less than 256 GiB.
  298:      * Again, if someone complains, this will be reconsidered.
  299:      */
  300:     uncompressed_size = 0;
  301:     for (i = 0; i < 8; ++i)
  302:         uncompressed_size |= (uint64_t) (state->in[5 + i]) << (i * 8);
  303: 
  304:     if (uncompressed_size != UINT64_MAX
  305:         && uncompressed_size > (UINT64_C(1) << 38))
  306:         return 0;
  307: 
  308:     return 1;
  309: }
  310: 
  311: #ifdef HAVE_ZLIB_H
  312: 
  313: /* Get next byte from input, or -1 if end or error. */
  314: #define NEXT() ((strm->avail_in == 0 && xz_avail(state) == -1) ? -1 : \
  315:                 (strm->avail_in == 0 ? -1 : \
  316:                  (strm->avail_in--, *(strm->next_in)++)))
  317: 
  318: /* Get a four-byte little-endian integer and return 0 on success and the value
  319:    in *ret.  Otherwise -1 is returned and *ret is not modified. */
  320: static int
  321: gz_next4(xz_statep state, unsigned long *ret)
  322: {
  323:     int ch;
  324:     unsigned long val;
  325:     z_streamp strm = &(state->zstrm);
  326: 
  327:     val = NEXT();
  328:     val += (unsigned) NEXT() << 8;
  329:     val += (unsigned long) NEXT() << 16;
  330:     ch = NEXT();
  331:     if (ch == -1)
  332:         return -1;
  333:     val += (unsigned long) ch << 24;
  334:     *ret = val;
  335:     return 0;
  336: }
  337: #endif
  338: 
  339: static int
  340: xz_head(xz_statep state)
  341: {
  342:     lzma_stream *strm = &(state->strm);
  343:     lzma_stream init = LZMA_STREAM_INIT;
  344:     int flags;
  345:     unsigned len;
  346: 
  347:     /* allocate read buffers and inflate memory */
  348:     if (state->size == 0) {
  349:         /* allocate buffers */
  350:         state->in = xmlMalloc(state->want);
  351:         state->out = xmlMalloc(state->want << 1);
  352:         if (state->in == NULL || state->out == NULL) {
  353:             if (state->out != NULL)
  354:                 xmlFree(state->out);
  355:             if (state->in != NULL)
  356:                 xmlFree(state->in);
  357:             xz_error(state, LZMA_MEM_ERROR, "out of memory");
  358:             return -1;
  359:         }
  360:         state->size = state->want;
  361: 
  362:         /* allocate decoder memory */
  363:         state->strm = init;
  364:         state->strm.avail_in = 0;
  365:         state->strm.next_in = NULL;
  366:         if (lzma_auto_decoder(&state->strm, UINT64_MAX, 0) != LZMA_OK) {
  367:             xmlFree(state->out);
  368:             xmlFree(state->in);
  369:             state->size = 0;
  370:             xz_error(state, LZMA_MEM_ERROR, "out of memory");
  371:             return -1;
  372:         }
  373: #ifdef HAVE_ZLIB_H
  374:         /* allocate inflate memory */
  375:         state->zstrm.zalloc = Z_NULL;
  376:         state->zstrm.zfree = Z_NULL;
  377:         state->zstrm.opaque = Z_NULL;
  378:         state->zstrm.avail_in = 0;
  379:         state->zstrm.next_in = Z_NULL;
  380:         if (state->init == 0) {
  381:             if (inflateInit2(&(state->zstrm), -15) != Z_OK) {/* raw inflate */
  382:                 xmlFree(state->out);
  383:                 xmlFree(state->in);
  384:                 state->size = 0;
  385:                 xz_error(state, LZMA_MEM_ERROR, "out of memory");
  386:                 return -1;
  387:             }
  388:             state->init = 1;
  389:         }
  390: #endif
  391:     }
  392: 
  393:     /* get some data in the input buffer */
  394:     if (strm->avail_in == 0) {
  395:         if (xz_avail(state) == -1)
  396:             return -1;
  397:         if (strm->avail_in == 0)
  398:             return 0;
  399:     }
  400: 
  401:     /* look for the xz magic header bytes */
  402:     if (is_format_xz(state) || is_format_lzma(state)) {
  403:         state->how = LZMA;
  404:         state->direct = 0;
  405:         return 0;
  406:     }
  407: #ifdef HAVE_ZLIB_H
  408:     /* look for the gzip magic header bytes 31 and 139 */
  409:     if (strm->next_in[0] == 31) {
  410:         strm->avail_in--;
  411:         strm->next_in++;
  412:         if (strm->avail_in == 0 && xz_avail(state) == -1)
  413:             return -1;
  414:         if (strm->avail_in && strm->next_in[0] == 139) {
  415:             /* we have a gzip header, woo hoo! */
  416:             strm->avail_in--;
  417:             strm->next_in++;
  418: 
  419:             /* skip rest of header */
  420:             if (NEXT() != 8) {  /* compression method */
  421:                 xz_error(state, LZMA_DATA_ERROR,
  422:                          "unknown compression method");
  423:                 return -1;
  424:             }
  425:             flags = NEXT();
  426:             if (flags & 0xe0) { /* reserved flag bits */
  427:                 xz_error(state, LZMA_DATA_ERROR,
  428:                          "unknown header flags set");
  429:                 return -1;
  430:             }
  431:             NEXT();             /* modification time */
  432:             NEXT();
  433:             NEXT();
  434:             NEXT();
  435:             NEXT();             /* extra flags */
  436:             NEXT();             /* operating system */
  437:             if (flags & 4) {    /* extra field */
  438:                 len = (unsigned) NEXT();
  439:                 len += (unsigned) NEXT() << 8;
  440:                 while (len--)
  441:                     if (NEXT() < 0)
  442:                         break;
  443:             }
  444:             if (flags & 8)      /* file name */
  445:                 while (NEXT() > 0) ;
  446:             if (flags & 16)     /* comment */
  447:                 while (NEXT() > 0) ;
  448:             if (flags & 2) {    /* header crc */
  449:                 NEXT();
  450:                 NEXT();
  451:             }
  452:             /* an unexpected end of file is not checked for here -- it will be
  453:              * noticed on the first request for uncompressed data */
  454: 
  455:             /* set up for decompression */
  456:             inflateReset(&state->zstrm);
  457:             state->zstrm.adler = crc32(0L, Z_NULL, 0);
  458:             state->how = GZIP;
  459:             state->direct = 0;
  460:             return 0;
  461:         } else {
  462:             /* not a gzip file -- save first byte (31) and fall to raw i/o */
  463:             state->out[0] = 31;
  464:             state->have = 1;
  465:         }
  466:     }
  467: #endif
  468: 
  469:     /* doing raw i/o, save start of raw data for seeking, copy any leftover
  470:      * input to output -- this assumes that the output buffer is larger than
  471:      * the input buffer, which also assures space for gzungetc() */
  472:     state->raw = state->pos;
  473:     state->next = state->out;
  474:     if (strm->avail_in) {
  475:         memcpy(state->next + state->have, strm->next_in, strm->avail_in);
  476:         state->have += strm->avail_in;
  477:         strm->avail_in = 0;
  478:     }
  479:     state->how = COPY;
  480:     state->direct = 1;
  481:     return 0;
  482: }
  483: 
  484: static int
  485: xz_decomp(xz_statep state)
  486: {
  487:     int ret;
  488:     unsigned had;
  489:     unsigned long crc, len;
  490:     lzma_stream *strm = &(state->strm);
  491: 
  492:     lzma_action action = LZMA_RUN;
  493: 
  494:     /* fill output buffer up to end of deflate stream */
  495:     had = strm->avail_out;
  496:     do {
  497:         /* get more input for inflate() */
  498:         if (strm->avail_in == 0 && xz_avail(state) == -1)
  499:             return -1;
  500:         if (strm->avail_in == 0) {
  501:             xz_error(state, LZMA_DATA_ERROR, "unexpected end of file");
  502:             return -1;
  503:         }
  504:         if (state->eof)
  505:             action = LZMA_FINISH;
  506: 
  507:         /* decompress and handle errors */
  508: #ifdef HAVE_ZLIB_H
  509:         if (state->how == GZIP) {
  510:             state->zstrm.avail_in = (uInt) state->strm.avail_in;
  511:             state->zstrm.next_in = (Bytef *) state->strm.next_in;
  512:             state->zstrm.avail_out = (uInt) state->strm.avail_out;
  513:             state->zstrm.next_out = (Bytef *) state->strm.next_out;
  514:             ret = inflate(&state->zstrm, Z_NO_FLUSH);
  515:             if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
  516:                 xz_error(state, Z_STREAM_ERROR,
  517:                          "internal error: inflate stream corrupt");
  518:                 return -1;
  519:             }
  520:             if (ret == Z_MEM_ERROR)
  521:                 ret = LZMA_MEM_ERROR;
  522:             if (ret == Z_DATA_ERROR)
  523:                 ret = LZMA_DATA_ERROR;
  524:             if (ret == Z_STREAM_END)
  525:                 ret = LZMA_STREAM_END;
  526:             state->strm.avail_in = state->zstrm.avail_in;
  527:             state->strm.next_in = state->zstrm.next_in;
  528:             state->strm.avail_out = state->zstrm.avail_out;
  529:             state->strm.next_out = state->zstrm.next_out;
  530:         } else                  /* state->how == LZMA */
  531: #endif
  532:             ret = lzma_code(strm, action);
  533:         if (ret == LZMA_MEM_ERROR) {
  534:             xz_error(state, LZMA_MEM_ERROR, "out of memory");
  535:             return -1;
  536:         }
  537:         if (ret == LZMA_DATA_ERROR) {
  538:             xz_error(state, LZMA_DATA_ERROR, "compressed data error");
  539:             return -1;
  540:         }
  541:     } while (strm->avail_out && ret != LZMA_STREAM_END);
  542: 
  543:     /* update available output and crc check value */
  544:     state->have = had - strm->avail_out;
  545:     state->next = strm->next_out - state->have;
  546: #ifdef HAVE_ZLIB_H
  547:     state->zstrm.adler =
  548:         crc32(state->zstrm.adler, state->next, state->have);
  549: #endif
  550: 
  551:     if (ret == LZMA_STREAM_END) {
  552: #ifdef HAVE_ZLIB_H
  553:         if (state->how == GZIP) {
  554:             if (gz_next4(state, &crc) == -1 || gz_next4(state, &len) == -1) {
  555:                 xz_error(state, LZMA_DATA_ERROR, "unexpected end of file");
  556:                 return -1;
  557:             }
  558:             if (crc != state->zstrm.adler) {
  559:                 xz_error(state, LZMA_DATA_ERROR, "incorrect data check");
  560:                 return -1;
  561:             }
  562:             if (len != (state->zstrm.total_out & 0xffffffffL)) {
  563:                 xz_error(state, LZMA_DATA_ERROR, "incorrect length check");
  564:                 return -1;
  565:             }
  566:             state->strm.avail_in = 0;
  567:             state->strm.next_in = NULL;
  568:             state->strm.avail_out = 0;
  569:             state->strm.next_out = NULL;
  570:         } else
  571: #endif
  572:         if (strm->avail_in != 0 || !state->eof) {
  573:             xz_error(state, LZMA_DATA_ERROR, "trailing garbage");
  574:             return -1;
  575:         }
  576:         state->how = LOOK;      /* ready for next stream, once have is 0 (leave
  577:                                  * state->direct unchanged to remember how) */
  578:     }
  579: 
  580:     /* good decompression */
  581:     return 0;
  582: }
  583: 
  584: static int
  585: xz_make(xz_statep state)
  586: {
  587:     lzma_stream *strm = &(state->strm);
  588: 
  589:     if (state->how == LOOK) {   /* look for lzma / gzip header */
  590:         if (xz_head(state) == -1)
  591:             return -1;
  592:         if (state->have)        /* got some data from xz_head() */
  593:             return 0;
  594:     }
  595:     if (state->how == COPY) {   /* straight copy */
  596:         if (xz_load(state, state->out, state->size << 1, &(state->have)) ==
  597:             -1)
  598:             return -1;
  599:         state->next = state->out;
  600:     } else if (state->how == LZMA || state->how == GZIP) {      /* decompress */
  601:         strm->avail_out = state->size << 1;
  602:         strm->next_out = state->out;
  603:         if (xz_decomp(state) == -1)
  604:             return -1;
  605:     }
  606:     return 0;
  607: }
  608: 
  609: static int
  610: xz_skip(xz_statep state, uint64_t len)
  611: {
  612:     unsigned n;
  613: 
  614:     /* skip over len bytes or reach end-of-file, whichever comes first */
  615:     while (len)
  616:         /* skip over whatever is in output buffer */
  617:         if (state->have) {
  618:             n = (uint64_t) state->have > len ?
  619:                 (unsigned) len : state->have;
  620:             state->have -= n;
  621:             state->next += n;
  622:             state->pos += n;
  623:             len -= n;
  624:         }
  625: 
  626:     /* output buffer empty -- return if we're at the end of the input */
  627:         else if (state->eof && state->strm.avail_in == 0)
  628:             break;
  629: 
  630:     /* need more data to skip -- load up output buffer */
  631:         else {
  632:             /* get more output, looking for header if required */
  633:             if (xz_make(state) == -1)
  634:                 return -1;
  635:         }
  636:     return 0;
  637: }
  638: 
  639: int
  640: __libxml2_xzread(xzFile file, void *buf, unsigned len)
  641: {
  642:     unsigned got, n;
  643:     xz_statep state;
  644:     lzma_stream *strm;
  645: 
  646:     /* get internal structure */
  647:     if (file == NULL)
  648:         return -1;
  649:     state = (xz_statep) file;
  650:     strm = &(state->strm);
  651: 
  652:     /* check that we're reading and that there's no error */
  653:     if (state->err != LZMA_OK)
  654:         return -1;
  655: 
  656:     /* since an int is returned, make sure len fits in one, otherwise return
  657:      * with an error (this avoids the flaw in the interface) */
  658:     if ((int) len < 0) {
  659:         xz_error(state, LZMA_BUF_ERROR,
  660:                  "requested length does not fit in int");
  661:         return -1;
  662:     }
  663: 
  664:     /* if len is zero, avoid unnecessary operations */
  665:     if (len == 0)
  666:         return 0;
  667: 
  668:     /* process a skip request */
  669:     if (state->seek) {
  670:         state->seek = 0;
  671:         if (xz_skip(state, state->skip) == -1)
  672:             return -1;
  673:     }
  674: 
  675:     /* get len bytes to buf, or less than len if at the end */
  676:     got = 0;
  677:     do {
  678:         /* first just try copying data from the output buffer */
  679:         if (state->have) {
  680:             n = state->have > len ? len : state->have;
  681:             memcpy(buf, state->next, n);
  682:             state->next += n;
  683:             state->have -= n;
  684:         }
  685: 
  686:         /* output buffer empty -- return if we're at the end of the input */
  687:         else if (state->eof && strm->avail_in == 0)
  688:             break;
  689: 
  690:         /* need output data -- for small len or new stream load up our output
  691:          * buffer */
  692:         else if (state->how == LOOK || len < (state->size << 1)) {
  693:             /* get more output, looking for header if required */
  694:             if (xz_make(state) == -1)
  695:                 return -1;
  696:             continue;           /* no progress yet -- go back to memcpy() above */
  697:             /* the copy above assures that we will leave with space in the
  698:              * output buffer, allowing at least one gzungetc() to succeed */
  699:         }
  700: 
  701:         /* large len -- read directly into user buffer */
  702:         else if (state->how == COPY) {  /* read directly */
  703:             if (xz_load(state, buf, len, &n) == -1)
  704:                 return -1;
  705:         }
  706: 
  707:         /* large len -- decompress directly into user buffer */
  708:         else {                  /* state->how == LZMA */
  709:             strm->avail_out = len;
  710:             strm->next_out = buf;
  711:             if (xz_decomp(state) == -1)
  712:                 return -1;
  713:             n = state->have;
  714:             state->have = 0;
  715:         }
  716: 
  717:         /* update progress */
  718:         len -= n;
  719:         buf = (char *) buf + n;
  720:         got += n;
  721:         state->pos += n;
  722:     } while (len);
  723: 
  724:     /* return number of bytes read into user buffer (will fit in int) */
  725:     return (int) got;
  726: }
  727: 
  728: int
  729: __libxml2_xzclose(xzFile file)
  730: {
  731:     int ret;
  732:     xz_statep state;
  733: 
  734:     /* get internal structure */
  735:     if (file == NULL)
  736:         return LZMA_DATA_ERROR;
  737:     state = (xz_statep) file;
  738: 
  739:     /* free memory and close file */
  740:     if (state->size) {
  741:         lzma_end(&(state->strm));
  742: #ifdef HAVE_ZLIB_H
  743:         if (state->init == 1)
  744:             inflateEnd(&(state->zstrm));
  745:         state->init = 0;
  746: #endif
  747:         xmlFree(state->out);
  748:         xmlFree(state->in);
  749:     }
  750:     xmlFree(state->path);
  751:     ret = close(state->fd);
  752:     xmlFree(state);
  753:     return ret ? ret : LZMA_OK;
  754: }
  755: #endif /* HAVE_LZMA_H */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>