Annotation of embedaddon/libxml2/xzlib.c, revision 1.1.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>