Annotation of embedaddon/libxml2/xzlib.c, revision 1.1

1.1     ! misho       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>