+
+/* gzip compression */
+
+static ssize_t cookie_gzread(void *cookie, char *buf, size_t nbytes)
+{
+ return gzread((gzFile)cookie, buf, nbytes);
+}
+
+static ssize_t cookie_gzwrite(void *cookie, const char *buf, size_t nbytes)
+{
+ return gzwrite((gzFile)cookie, buf, nbytes);
+}
+
+static int cookie_gzclose(void *cookie)
+{
+ return gzclose((gzFile)cookie);
+}
+
+static inline FILE *mygzfopen(const char *fn, const char *mode)
+{
+ gzFile gzf = gzopen(fn, mode);
+ return cookieopen(gzf, mode, cookie_gzread, cookie_gzwrite, cookie_gzclose);
+}
+
+static inline FILE *mygzfdopen(int fd, const char *mode)
+{
+ gzFile gzf = gzdopen(fd, mode);
+ return cookieopen(gzf, mode, cookie_gzread, cookie_gzwrite, cookie_gzclose);
+}
+
+#ifdef ENABLE_BZIP2_COMPRESSION
+
+#include <bzlib.h>
+
+/* bzip2 compression */
+
+static ssize_t cookie_bzread(void *cookie, char *buf, size_t nbytes)
+{
+ return BZ2_bzread((BZFILE *)cookie, buf, nbytes);
+}
+
+static ssize_t cookie_bzwrite(void *cookie, const char *buf, size_t nbytes)
+{
+ return BZ2_bzwrite((BZFILE *)cookie, (char *)buf, nbytes);
+}
+
+static int cookie_bzclose(void *cookie)
+{
+ BZ2_bzclose((BZFILE *)cookie);
+ return 0;
+}
+
+static inline FILE *mybzfopen(const char *fn, const char *mode)
+{
+ BZFILE *bzf = BZ2_bzopen(fn, mode);
+ return cookieopen(bzf, mode, cookie_bzread, cookie_bzwrite, cookie_bzclose);
+}
+
+static inline FILE *mybzfdopen(int fd, const char *mode)
+{
+ BZFILE *bzf = BZ2_bzdopen(fd, mode);
+ return cookieopen(bzf, mode, cookie_bzread, cookie_bzwrite, cookie_bzclose);
+}
+
+#endif
+
+
+#ifdef ENABLE_LZMA_COMPRESSION
+
+#include <lzma.h>
+
+/* lzma code written by me in 2008 for rpm's rpmio.c */
+
+typedef struct lzfile {
+ unsigned char buf[1 << 15];
+ lzma_stream strm;
+ FILE *file;
+ int encoding;
+ int eof;
+} LZFILE;
+
+static inline lzma_ret setup_alone_encoder(lzma_stream *strm, int level)
+{
+ lzma_options_lzma options;
+ lzma_lzma_preset(&options, level);
+ return lzma_alone_encoder(strm, &options);
+}
+
+static lzma_stream stream_init = LZMA_STREAM_INIT;
+
+static LZFILE *lzopen(const char *path, const char *mode, int fd, int isxz)
+{
+ int level = 7;
+ int encoding = 0;
+ FILE *fp;
+ LZFILE *lzfile;
+ lzma_ret ret;
+
+ if (!path && fd < 0)
+ return 0;
+ for (; *mode; mode++)
+ {
+ if (*mode == 'w')
+ encoding = 1;
+ else if (*mode == 'r')
+ encoding = 0;
+ else if (*mode >= '1' && *mode <= '9')
+ level = *mode - '0';
+ }
+ if (fd != -1)
+ fp = fdopen(fd, encoding ? "w" : "r");
+ else
+ fp = fopen(path, encoding ? "w" : "r");
+ if (!fp)
+ return 0;
+ lzfile = calloc(1, sizeof(*lzfile));
+ if (!lzfile)
+ {
+ fclose(fp);
+ return 0;
+ }
+ lzfile->file = fp;
+ lzfile->encoding = encoding;
+ lzfile->eof = 0;
+ lzfile->strm = stream_init;
+ if (encoding)
+ {
+ if (isxz)
+ ret = lzma_easy_encoder(&lzfile->strm, level, LZMA_CHECK_SHA256);
+ else
+ ret = setup_alone_encoder(&lzfile->strm, level);
+ }
+ else
+ ret = lzma_auto_decoder(&lzfile->strm, 100 << 20, 0);
+ if (ret != LZMA_OK)
+ {
+ fclose(fp);
+ free(lzfile);
+ return 0;
+ }
+ return lzfile;
+}
+
+static int lzclose(void *cookie)
+{
+ LZFILE *lzfile = cookie;
+ lzma_ret ret;
+ size_t n;
+ int rc;
+
+ if (!lzfile)
+ return -1;
+ if (lzfile->encoding)
+ {
+ for (;;)
+ {
+ lzfile->strm.avail_out = sizeof(lzfile->buf);
+ lzfile->strm.next_out = lzfile->buf;
+ ret = lzma_code(&lzfile->strm, LZMA_FINISH);
+ if (ret != LZMA_OK && ret != LZMA_STREAM_END)
+ return -1;
+ n = sizeof(lzfile->buf) - lzfile->strm.avail_out;
+ if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
+ return -1;
+ if (ret == LZMA_STREAM_END)
+ break;
+ }
+ }
+ lzma_end(&lzfile->strm);
+ rc = fclose(lzfile->file);
+ free(lzfile);
+ return rc;
+}
+
+static ssize_t lzread(void *cookie, char *buf, size_t len)
+{
+ LZFILE *lzfile = cookie;
+ lzma_ret ret;
+ int eof = 0;
+
+ if (!lzfile || lzfile->encoding)
+ return -1;
+ if (lzfile->eof)
+ return 0;
+ lzfile->strm.next_out = (unsigned char *)buf;
+ lzfile->strm.avail_out = len;
+ for (;;)
+ {
+ if (!lzfile->strm.avail_in)
+ {
+ lzfile->strm.next_in = lzfile->buf;
+ lzfile->strm.avail_in = fread(lzfile->buf, 1, sizeof(lzfile->buf), lzfile->file);
+ if (!lzfile->strm.avail_in)
+ eof = 1;
+ }
+ ret = lzma_code(&lzfile->strm, LZMA_RUN);
+ if (ret == LZMA_STREAM_END)
+ {
+ lzfile->eof = 1;
+ return len - lzfile->strm.avail_out;
+ }
+ if (ret != LZMA_OK)
+ return -1;
+ if (!lzfile->strm.avail_out)
+ return len;
+ if (eof)
+ return -1;
+ }
+}
+
+static ssize_t lzwrite(void *cookie, const char *buf, size_t len)
+{
+ LZFILE *lzfile = cookie;
+ lzma_ret ret;
+ size_t n;
+ if (!lzfile || !lzfile->encoding)
+ return -1;
+ if (!len)
+ return 0;
+ lzfile->strm.next_in = (unsigned char *)buf;
+ lzfile->strm.avail_in = len;
+ for (;;)
+ {
+ lzfile->strm.next_out = lzfile->buf;
+ lzfile->strm.avail_out = sizeof(lzfile->buf);
+ ret = lzma_code(&lzfile->strm, LZMA_RUN);
+ if (ret != LZMA_OK)
+ return -1;
+ n = sizeof(lzfile->buf) - lzfile->strm.avail_out;
+ if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
+ return -1;
+ if (!lzfile->strm.avail_in)
+ return len;
+ }
+}
+
+static inline FILE *myxzfopen(const char *fn, const char *mode)
+{
+ LZFILE *lzf = lzopen(fn, mode, -1, 1);
+ return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
+}
+
+static inline FILE *myxzfdopen(int fd, const char *mode)
+{
+ LZFILE *lzf = lzopen(0, mode, fd, 1);
+ return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
+}
+
+static inline FILE *mylzfopen(const char *fn, const char *mode)
+{
+ LZFILE *lzf = lzopen(fn, mode, -1, 0);
+ return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
+}
+
+static inline FILE *mylzfdopen(int fd, const char *mode)
+{
+ LZFILE *lzf = lzopen(0, mode, fd, 0);
+ return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
+}
+
+#endif /* ENABLE_LZMA_COMPRESSION */
+
+