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