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"
20 static FILE *cookieopen(void *cookie, const char *mode,
21 ssize_t (*cread)(void *, char *, size_t),
22 ssize_t (*cwrite)(void *, const char *, size_t),
23 int (*cclose)(void *))
28 return funopen(cookie,
29 (int (*)(void *, char *, int))(*mode == 'r' ? cread : NULL), /* readfn */
30 (int (*)(void *, const char *, int))(*mode == 'w' ? cwrite : NULL), /* writefn */
31 (fpos_t (*)(void *, fpos_t, int))NULL, /* seekfn */
34 #elif defined(HAVE_FOPENCOOKIE)
35 cookie_io_functions_t cio;
39 memset(&cio, 0, sizeof(cio));
42 else if (*mode == 'w')
45 return fopencookie(cookie, *mode == 'w' ? "w" : "r", cio);
47 # error Need to implement custom I/O
52 /* gzip compression */
54 static ssize_t cookie_gzread(void *cookie, char *buf, size_t nbytes)
56 return gzread((gzFile)cookie, buf, nbytes);
59 static ssize_t cookie_gzwrite(void *cookie, const char *buf, size_t nbytes)
61 return gzwrite((gzFile)cookie, buf, nbytes);
64 static int cookie_gzclose(void *cookie)
66 return gzclose((gzFile)cookie);
69 static inline FILE *mygzfopen(const char *fn, const char *mode)
71 gzFile gzf = gzopen(fn, mode);
72 return cookieopen(gzf, mode, cookie_gzread, cookie_gzwrite, cookie_gzclose);
75 static inline FILE *mygzfdopen(int fd, const char *mode)
77 gzFile gzf = gzdopen(fd, mode);
78 return cookieopen(gzf, mode, cookie_gzread, cookie_gzwrite, cookie_gzclose);
81 #ifdef ENABLE_BZIP2_COMPRESSION
85 /* bzip2 compression */
87 static ssize_t cookie_bzread(void *cookie, char *buf, size_t nbytes)
89 return BZ2_bzread((BZFILE *)cookie, buf, nbytes);
92 static ssize_t cookie_bzwrite(void *cookie, const char *buf, size_t nbytes)
94 return BZ2_bzwrite((BZFILE *)cookie, (char *)buf, nbytes);
97 static int cookie_bzclose(void *cookie)
99 BZ2_bzclose((BZFILE *)cookie);
103 static inline FILE *mybzfopen(const char *fn, const char *mode)
105 BZFILE *bzf = BZ2_bzopen(fn, mode);
106 return cookieopen(bzf, mode, cookie_bzread, cookie_bzwrite, cookie_bzclose);
109 static inline FILE *mybzfdopen(int fd, const char *mode)
111 BZFILE *bzf = BZ2_bzdopen(fd, mode);
112 return cookieopen(bzf, mode, cookie_bzread, cookie_bzwrite, cookie_bzclose);
118 #ifdef ENABLE_LZMA_COMPRESSION
122 /* lzma code written by me in 2008 for rpm's rpmio.c */
124 typedef struct lzfile {
125 unsigned char buf[1 << 15];
132 static inline lzma_ret setup_alone_encoder(lzma_stream *strm, int level)
134 lzma_options_lzma options;
135 lzma_lzma_preset(&options, level);
136 return lzma_alone_encoder(strm, &options);
139 static lzma_stream stream_init = LZMA_STREAM_INIT;
141 static LZFILE *lzopen(const char *path, const char *mode, int fd, int isxz)
151 for (; *mode; mode++)
155 else if (*mode == 'r')
157 else if (*mode >= '1' && *mode <= '9')
161 fp = fdopen(fd, encoding ? "w" : "r");
163 fp = fopen(path, encoding ? "w" : "r");
166 lzfile = calloc(1, sizeof(*lzfile));
173 lzfile->encoding = encoding;
175 lzfile->strm = stream_init;
179 ret = lzma_easy_encoder(&lzfile->strm, level, LZMA_CHECK_SHA256);
181 ret = setup_alone_encoder(&lzfile->strm, level);
184 ret = lzma_auto_decoder(&lzfile->strm, 100 << 20, 0);
194 static int lzclose(void *cookie)
196 LZFILE *lzfile = cookie;
203 if (lzfile->encoding)
207 lzfile->strm.avail_out = sizeof(lzfile->buf);
208 lzfile->strm.next_out = lzfile->buf;
209 ret = lzma_code(&lzfile->strm, LZMA_FINISH);
210 if (ret != LZMA_OK && ret != LZMA_STREAM_END)
212 n = sizeof(lzfile->buf) - lzfile->strm.avail_out;
213 if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
215 if (ret == LZMA_STREAM_END)
219 lzma_end(&lzfile->strm);
220 rc = fclose(lzfile->file);
225 static ssize_t lzread(void *cookie, char *buf, size_t len)
227 LZFILE *lzfile = cookie;
231 if (!lzfile || lzfile->encoding)
235 lzfile->strm.next_out = (unsigned char *)buf;
236 lzfile->strm.avail_out = len;
239 if (!lzfile->strm.avail_in)
241 lzfile->strm.next_in = lzfile->buf;
242 lzfile->strm.avail_in = fread(lzfile->buf, 1, sizeof(lzfile->buf), lzfile->file);
243 if (!lzfile->strm.avail_in)
246 ret = lzma_code(&lzfile->strm, LZMA_RUN);
247 if (ret == LZMA_STREAM_END)
250 return len - lzfile->strm.avail_out;
254 if (!lzfile->strm.avail_out)
261 static ssize_t lzwrite(void *cookie, const char *buf, size_t len)
263 LZFILE *lzfile = cookie;
266 if (!lzfile || !lzfile->encoding)
270 lzfile->strm.next_in = (unsigned char *)buf;
271 lzfile->strm.avail_in = len;
274 lzfile->strm.next_out = lzfile->buf;
275 lzfile->strm.avail_out = sizeof(lzfile->buf);
276 ret = lzma_code(&lzfile->strm, LZMA_RUN);
279 n = sizeof(lzfile->buf) - lzfile->strm.avail_out;
280 if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
282 if (!lzfile->strm.avail_in)
287 static inline FILE *myxzfopen(const char *fn, const char *mode)
289 LZFILE *lzf = lzopen(fn, mode, -1, 1);
290 return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
293 static inline FILE *myxzfdopen(int fd, const char *mode)
295 LZFILE *lzf = lzopen(0, mode, fd, 1);
296 return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
299 static inline FILE *mylzfopen(const char *fn, const char *mode)
301 LZFILE *lzf = lzopen(fn, mode, -1, 0);
302 return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
305 static inline FILE *mylzfdopen(int fd, const char *mode)
307 LZFILE *lzf = lzopen(0, mode, fd, 0);
308 return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
311 #endif /* ENABLE_LZMA_COMPRESSION */
315 solv_xfopen(const char *fn, const char *mode)
323 suf = strrchr(fn, '.');
324 if (suf && !strcmp(suf, ".gz"))
325 return mygzfopen(fn, mode);
326 #ifdef ENABLE_LZMA_COMPRESSION
327 if (suf && !strcmp(suf, ".xz"))
328 return myxzfopen(fn, mode);
329 if (suf && !strcmp(suf, ".lzma"))
330 return mylzfopen(fn, mode);
332 if (suf && !strcmp(suf, ".xz"))
334 if (suf && !strcmp(suf, ".lzma"))
337 #ifdef ENABLE_BZIP2_COMPRESSION
338 if (suf && !strcmp(suf, ".bz2"))
339 return mybzfopen(fn, mode);
341 if (suf && !strcmp(suf, ".bz2"))
344 return fopen(fn, mode);
348 solv_xfopen_fd(const char *fn, int fd, const char *mode)
350 const char *simplemode = mode;
353 suf = fn ? strrchr(fn, '.') : 0;
356 int fl = fcntl(fd, F_GETFL, 0);
359 fl &= O_RDONLY|O_WRONLY|O_RDWR;
361 mode = simplemode = "w";
362 else if (fl == O_RDWR)
368 mode = simplemode = "r";
370 if (suf && !strcmp(suf, ".gz"))
371 return mygzfdopen(fd, simplemode);
372 #ifdef ENABLE_LZMA_COMPRESSION
373 if (suf && !strcmp(suf, ".xz"))
374 return myxzfdopen(fd, simplemode);
375 if (suf && !strcmp(suf, ".lzma"))
376 return mylzfdopen(fd, simplemode);
378 if (suf && !strcmp(suf, ".xz"))
380 if (suf && !strcmp(suf, ".lzma"))
383 #ifdef ENABLE_BZIP2_COMPRESSION
384 if (suf && !strcmp(suf, ".bz2"))
385 return mybzfdopen(fd, simplemode);
387 if (suf && !strcmp(suf, ".bz2"))
390 return fdopen(fd, mode);
394 solv_xfopen_iscompressed(const char *fn)
396 const char *suf = fn ? strrchr(fn, '.') : 0;
399 if (!strcmp(suf, ".gz"))
401 if (!strcmp(suf, ".xz") || !strcmp(suf, ".lzma"))
402 #ifdef ENABLE_LZMA_COMPRESSION
407 if (!strcmp(suf, ".bz2"))
408 #ifdef ENABLE_BZIP2_COMPRESSION
423 static ssize_t cookie_bufread(void *cookie, char *buf, size_t nbytes)
425 struct bufcookie *bc = cookie;
426 size_t n = *bc->buflp > nbytes ? nbytes : *bc->buflp;
429 memcpy(buf, *bc->bufp, n);
436 static ssize_t cookie_bufwrite(void *cookie, const char *buf, size_t nbytes)
438 struct bufcookie *bc = cookie;
439 int n = nbytes > 0x40000000 ? 0x40000000 : nbytes;
442 *bc->bufp = solv_extend(*bc->bufp, *bc->buflp, n + 1, 1, 4095);
443 memcpy(*bc->bufp, buf, n);
444 (*bc->bufp)[n] = 0; /* zero-terminate */
450 static int cookie_bufclose(void *cookie)
452 struct bufcookie *bc = cookie;
454 solv_free(bc->freemem);
460 solv_xfopen_buf(const char *fn, char **bufp, size_t *buflp, const char *mode)
462 struct bufcookie *bc;
464 if (*mode != 'r' && *mode != 'w')
466 bc = solv_calloc(1, sizeof(*bc));
471 bc->bufl_int = *mode == 'w' ? 0 : strlen(*bufp);
472 buflp = &bc->bufl_int;
477 *bc->bufp = solv_extend(0, 0, 1, 1, 4095); /* always zero-terminate */
481 fp = cookieopen(bc, mode, cookie_bufread, cookie_bufwrite, cookie_bufclose);
482 if (!strcmp(mode, "rf")) /* auto-free */
487 *bc->bufp = solv_free(*bc->bufp);