Coverage Report

Created: 2025-07-01 06:27

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