2 * Copyright (c) 2011, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
16 #include "solv_xfopen.h"
19 static FILE *cookieopen(void *cookie, const char *mode,
20 ssize_t (*cread)(void *, char *, size_t),
21 ssize_t (*cwrite)(void *, const char *, size_t),
22 int (*cclose)(void *))
27 return funopen(cookie,
28 (int (*)(void *, char *, int))(*mode == 'r' ? cread: NULL),/* readfn */
29 (int (*)(void *, const char *, int))(*mode == 'w' ? cwrite : NULL), /* writefn */
30 (fpos_t (*)(void *, fpos_t, int))NULL, /* seekfn */
33 #elif defined(HAVE_FOPENCOOKIE)
34 cookie_io_functions_t cio;
35 memset(&cio, 0, sizeof(cio));
38 else if (*mode == 'w')
41 return fopencookie(cookie, *mode == 'w' ? "w" : "r", cio);
43 # error Need to implement custom I/O
48 /* gzip compression */
50 static ssize_t cookie_gzread(void *cookie, char *buf, size_t nbytes)
52 return gzread((gzFile *)cookie, buf, nbytes);
55 static ssize_t cookie_gzwrite(void *cookie, const char *buf, size_t nbytes)
57 return gzwrite((gzFile *)cookie, buf, nbytes);
60 static int cookie_gzclose(void *cookie)
62 return gzclose((gzFile *)cookie);
65 static inline FILE *mygzfopen(const char *fn, const char *mode)
67 gzFile *gzf = gzopen(fn, mode);
68 return cookieopen(gzf, mode, cookie_gzread, cookie_gzwrite, cookie_gzclose);
71 static inline FILE *mygzfdopen(int fd, const char *mode)
73 gzFile *gzf = gzdopen(fd, mode);
74 return cookieopen(gzf, mode, cookie_gzread, cookie_gzwrite, cookie_gzclose);
78 #ifdef ENABLE_LZMA_COMPRESSION
82 /* lzma code written by me in 2008 for rpm's rpmio.c */
84 typedef struct lzfile {
85 unsigned char buf[1 << 15];
92 static inline lzma_ret setup_alone_encoder(lzma_stream *strm, int level)
94 lzma_options_lzma options;
95 lzma_lzma_preset(&options, level);
96 return lzma_alone_encoder(strm, &options);
99 static lzma_stream stream_init = LZMA_STREAM_INIT;
101 static LZFILE *lzopen(const char *path, const char *mode, int fd, int isxz)
111 for (; *mode; mode++)
115 else if (*mode == 'r')
117 else if (*mode >= '1' && *mode <= '9')
121 fp = fdopen(fd, encoding ? "w" : "r");
123 fp = fopen(path, encoding ? "w" : "r");
126 lzfile = calloc(1, sizeof(*lzfile));
133 lzfile->encoding = encoding;
135 lzfile->strm = stream_init;
139 ret = lzma_easy_encoder(&lzfile->strm, level, LZMA_CHECK_SHA256);
141 ret = setup_alone_encoder(&lzfile->strm, level);
144 ret = lzma_auto_decoder(&lzfile->strm, 100 << 20, 0);
154 static int lzclose(void *cookie)
156 LZFILE *lzfile = cookie;
163 if (lzfile->encoding)
167 lzfile->strm.avail_out = sizeof(lzfile->buf);
168 lzfile->strm.next_out = lzfile->buf;
169 ret = lzma_code(&lzfile->strm, LZMA_FINISH);
170 if (ret != LZMA_OK && ret != LZMA_STREAM_END)
172 n = sizeof(lzfile->buf) - lzfile->strm.avail_out;
173 if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
175 if (ret == LZMA_STREAM_END)
179 lzma_end(&lzfile->strm);
180 rc = fclose(lzfile->file);
185 static ssize_t lzread(void *cookie, char *buf, size_t len)
187 LZFILE *lzfile = cookie;
191 if (!lzfile || lzfile->encoding)
195 lzfile->strm.next_out = (unsigned char *)buf;
196 lzfile->strm.avail_out = len;
199 if (!lzfile->strm.avail_in)
201 lzfile->strm.next_in = lzfile->buf;
202 lzfile->strm.avail_in = fread(lzfile->buf, 1, sizeof(lzfile->buf), lzfile->file);
203 if (!lzfile->strm.avail_in)
206 ret = lzma_code(&lzfile->strm, LZMA_RUN);
207 if (ret == LZMA_STREAM_END)
210 return len - lzfile->strm.avail_out;
214 if (!lzfile->strm.avail_out)
221 static ssize_t lzwrite(void *cookie, const char *buf, size_t len)
223 LZFILE *lzfile = cookie;
226 if (!lzfile || !lzfile->encoding)
230 lzfile->strm.next_in = (unsigned char *)buf;
231 lzfile->strm.avail_in = len;
234 lzfile->strm.next_out = lzfile->buf;
235 lzfile->strm.avail_out = sizeof(lzfile->buf);
236 ret = lzma_code(&lzfile->strm, LZMA_RUN);
239 n = sizeof(lzfile->buf) - lzfile->strm.avail_out;
240 if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
242 if (!lzfile->strm.avail_in)
247 static inline FILE *myxzfopen(const char *fn, const char *mode)
249 LZFILE *lzf = lzopen(fn, mode, -1, 1);
250 return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
253 static inline FILE *myxzfdopen(int fd, const char *mode)
255 LZFILE *lzf = lzopen(0, mode, fd, 1);
256 return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
259 static inline FILE *mylzfopen(const char *fn, const char *mode)
261 LZFILE *lzf = lzopen(fn, mode, -1, 0);
262 return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
265 static inline FILE *mylzfdopen(int fd, const char *mode)
267 LZFILE *lzf = lzopen(0, mode, fd, 0);
268 return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
271 #endif /* ENABLE_LZMA_COMPRESSION */
275 solv_xfopen(const char *fn, const char *mode)
283 suf = strrchr(fn, '.');
284 if (suf && !strcmp(suf, ".gz"))
285 return mygzfopen(fn, mode);
286 #ifdef ENABLE_LZMA_COMPRESSION
287 if (suf && !strcmp(suf, ".xz"))
288 return myxzfopen(fn, mode);
289 if (suf && !strcmp(suf, ".lzma"))
290 return mylzfopen(fn, mode);
292 return fopen(fn, mode);
296 solv_xfopen_fd(const char *fn, int fd, const char *mode)
298 const char *simplemode = mode;
301 suf = fn ? strrchr(fn, '.') : 0;
304 int fl = fcntl(fd, F_GETFL, 0);
307 fl &= O_RDONLY|O_WRONLY|O_RDWR;
309 mode = simplemode = "w";
310 else if (fl == O_RDWR)
316 mode = simplemode = "r";
318 if (suf && !strcmp(suf, ".gz"))
319 return mygzfdopen(fd, simplemode);
320 #ifdef ENABLE_LZMA_COMPRESSION
321 if (suf && !strcmp(suf, ".xz"))
322 return myxzfdopen(fd, simplemode);
323 if (suf && !strcmp(suf, ".lzma"))
324 return mylzfdopen(fd, simplemode);
326 return fdopen(fd, mode);