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