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 /* Evil hack for Haiku: fopencookie() is implemented internally, but not
21 exported by a header. */
25 ssize_t (*read)(void*, char*, size_t);
26 ssize_t (*write)(void*, const char*, size_t);
27 int (*seek)(off_t*, int);
29 } cookie_io_functions_t;
32 FILE *fopencookie(void*, const char*, cookie_io_functions_t);
34 #endif /* __HAIKU__ */
37 static FILE *cookieopen(void *cookie, const char *mode,
38 ssize_t (*cread)(void *, char *, size_t),
39 ssize_t (*cwrite)(void *, const char *, size_t),
40 int (*cclose)(void *))
45 return funopen(cookie,
46 (int (*)(void *, char *, int))(*mode == 'r' ? cread : NULL), /* readfn */
47 (int (*)(void *, const char *, int))(*mode == 'w' ? cwrite : NULL), /* writefn */
48 (fpos_t (*)(void *, fpos_t, int))NULL, /* seekfn */
51 #elif defined(HAVE_FOPENCOOKIE)
52 cookie_io_functions_t cio;
56 memset(&cio, 0, sizeof(cio));
59 else if (*mode == 'w')
62 return fopencookie(cookie, *mode == 'w' ? "w" : "r", cio);
64 # error Need to implement custom I/O
69 /* gzip compression */
71 static ssize_t cookie_gzread(void *cookie, char *buf, size_t nbytes)
73 return gzread((gzFile)cookie, buf, nbytes);
76 static ssize_t cookie_gzwrite(void *cookie, const char *buf, size_t nbytes)
78 return gzwrite((gzFile)cookie, buf, nbytes);
81 static int cookie_gzclose(void *cookie)
83 return gzclose((gzFile)cookie);
86 static inline FILE *mygzfopen(const char *fn, const char *mode)
88 gzFile gzf = gzopen(fn, mode);
89 return cookieopen(gzf, mode, cookie_gzread, cookie_gzwrite, cookie_gzclose);
92 static inline FILE *mygzfdopen(int fd, const char *mode)
94 gzFile gzf = gzdopen(fd, mode);
95 return cookieopen(gzf, mode, cookie_gzread, cookie_gzwrite, cookie_gzclose);
98 #ifdef ENABLE_BZIP2_COMPRESSION
102 /* bzip2 compression */
104 static ssize_t cookie_bzread(void *cookie, char *buf, size_t nbytes)
106 return BZ2_bzread((BZFILE *)cookie, buf, nbytes);
109 static ssize_t cookie_bzwrite(void *cookie, const char *buf, size_t nbytes)
111 return BZ2_bzwrite((BZFILE *)cookie, (char *)buf, nbytes);
114 static int cookie_bzclose(void *cookie)
116 BZ2_bzclose((BZFILE *)cookie);
120 static inline FILE *mybzfopen(const char *fn, const char *mode)
122 BZFILE *bzf = BZ2_bzopen(fn, mode);
123 return cookieopen(bzf, mode, cookie_bzread, cookie_bzwrite, cookie_bzclose);
126 static inline FILE *mybzfdopen(int fd, const char *mode)
128 BZFILE *bzf = BZ2_bzdopen(fd, mode);
129 return cookieopen(bzf, mode, cookie_bzread, cookie_bzwrite, cookie_bzclose);
135 #ifdef ENABLE_LZMA_COMPRESSION
139 /* lzma code written by me in 2008 for rpm's rpmio.c */
141 typedef struct lzfile {
142 unsigned char buf[1 << 15];
149 static inline lzma_ret setup_alone_encoder(lzma_stream *strm, int level)
151 lzma_options_lzma options;
152 lzma_lzma_preset(&options, level);
153 return lzma_alone_encoder(strm, &options);
156 static lzma_stream stream_init = LZMA_STREAM_INIT;
158 static LZFILE *lzopen(const char *path, const char *mode, int fd, int isxz)
168 for (; *mode; mode++)
172 else if (*mode == 'r')
174 else if (*mode >= '1' && *mode <= '9')
178 fp = fdopen(fd, encoding ? "w" : "r");
180 fp = fopen(path, encoding ? "w" : "r");
183 lzfile = calloc(1, sizeof(*lzfile));
190 lzfile->encoding = encoding;
192 lzfile->strm = stream_init;
196 ret = lzma_easy_encoder(&lzfile->strm, level, LZMA_CHECK_SHA256);
198 ret = setup_alone_encoder(&lzfile->strm, level);
201 ret = lzma_auto_decoder(&lzfile->strm, 100 << 20, 0);
211 static int lzclose(void *cookie)
213 LZFILE *lzfile = cookie;
220 if (lzfile->encoding)
224 lzfile->strm.avail_out = sizeof(lzfile->buf);
225 lzfile->strm.next_out = lzfile->buf;
226 ret = lzma_code(&lzfile->strm, LZMA_FINISH);
227 if (ret != LZMA_OK && ret != LZMA_STREAM_END)
229 n = sizeof(lzfile->buf) - lzfile->strm.avail_out;
230 if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
232 if (ret == LZMA_STREAM_END)
236 lzma_end(&lzfile->strm);
237 rc = fclose(lzfile->file);
242 static ssize_t lzread(void *cookie, char *buf, size_t len)
244 LZFILE *lzfile = cookie;
248 if (!lzfile || lzfile->encoding)
252 lzfile->strm.next_out = (unsigned char *)buf;
253 lzfile->strm.avail_out = len;
256 if (!lzfile->strm.avail_in)
258 lzfile->strm.next_in = lzfile->buf;
259 lzfile->strm.avail_in = fread(lzfile->buf, 1, sizeof(lzfile->buf), lzfile->file);
260 if (!lzfile->strm.avail_in)
263 ret = lzma_code(&lzfile->strm, LZMA_RUN);
264 if (ret == LZMA_STREAM_END)
267 return len - lzfile->strm.avail_out;
271 if (!lzfile->strm.avail_out)
278 static ssize_t lzwrite(void *cookie, const char *buf, size_t len)
280 LZFILE *lzfile = cookie;
283 if (!lzfile || !lzfile->encoding)
287 lzfile->strm.next_in = (unsigned char *)buf;
288 lzfile->strm.avail_in = len;
291 lzfile->strm.next_out = lzfile->buf;
292 lzfile->strm.avail_out = sizeof(lzfile->buf);
293 ret = lzma_code(&lzfile->strm, LZMA_RUN);
296 n = sizeof(lzfile->buf) - lzfile->strm.avail_out;
297 if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
299 if (!lzfile->strm.avail_in)
304 static inline FILE *myxzfopen(const char *fn, const char *mode)
306 LZFILE *lzf = lzopen(fn, mode, -1, 1);
307 return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
310 static inline FILE *myxzfdopen(int fd, const char *mode)
312 LZFILE *lzf = lzopen(0, mode, fd, 1);
313 return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
316 static inline FILE *mylzfopen(const char *fn, const char *mode)
318 LZFILE *lzf = lzopen(fn, mode, -1, 0);
319 return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
322 static inline FILE *mylzfdopen(int fd, const char *mode)
324 LZFILE *lzf = lzopen(0, mode, fd, 0);
325 return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
328 #endif /* ENABLE_LZMA_COMPRESSION */
332 solv_xfopen(const char *fn, const char *mode)
340 suf = strrchr(fn, '.');
341 if (suf && !strcmp(suf, ".gz"))
342 return mygzfopen(fn, mode);
343 #ifdef ENABLE_LZMA_COMPRESSION
344 if (suf && !strcmp(suf, ".xz"))
345 return myxzfopen(fn, mode);
346 if (suf && !strcmp(suf, ".lzma"))
347 return mylzfopen(fn, mode);
349 if (suf && !strcmp(suf, ".xz"))
351 if (suf && !strcmp(suf, ".lzma"))
354 #ifdef ENABLE_BZIP2_COMPRESSION
355 if (suf && !strcmp(suf, ".bz2"))
356 return mybzfopen(fn, mode);
358 if (suf && !strcmp(suf, ".bz2"))
361 return fopen(fn, mode);
365 solv_xfopen_fd(const char *fn, int fd, const char *mode)
367 const char *simplemode = mode;
370 suf = fn ? strrchr(fn, '.') : 0;
373 int fl = fcntl(fd, F_GETFL, 0);
376 fl &= O_RDONLY|O_WRONLY|O_RDWR;
378 mode = simplemode = "w";
379 else if (fl == O_RDWR)
385 mode = simplemode = "r";
387 if (suf && !strcmp(suf, ".gz"))
388 return mygzfdopen(fd, simplemode);
389 #ifdef ENABLE_LZMA_COMPRESSION
390 if (suf && !strcmp(suf, ".xz"))
391 return myxzfdopen(fd, simplemode);
392 if (suf && !strcmp(suf, ".lzma"))
393 return mylzfdopen(fd, simplemode);
395 if (suf && !strcmp(suf, ".xz"))
397 if (suf && !strcmp(suf, ".lzma"))
400 #ifdef ENABLE_BZIP2_COMPRESSION
401 if (suf && !strcmp(suf, ".bz2"))
402 return mybzfdopen(fd, simplemode);
404 if (suf && !strcmp(suf, ".bz2"))
407 return fdopen(fd, mode);
411 solv_xfopen_iscompressed(const char *fn)
413 const char *suf = fn ? strrchr(fn, '.') : 0;
416 if (!strcmp(suf, ".gz"))
418 if (!strcmp(suf, ".xz") || !strcmp(suf, ".lzma"))
419 #ifdef ENABLE_LZMA_COMPRESSION
424 if (!strcmp(suf, ".bz2"))
425 #ifdef ENABLE_BZIP2_COMPRESSION
440 static ssize_t cookie_bufread(void *cookie, char *buf, size_t nbytes)
442 struct bufcookie *bc = cookie;
443 size_t n = *bc->buflp > nbytes ? nbytes : *bc->buflp;
446 memcpy(buf, *bc->bufp, n);
453 static ssize_t cookie_bufwrite(void *cookie, const char *buf, size_t nbytes)
455 struct bufcookie *bc = cookie;
456 int n = nbytes > 0x40000000 ? 0x40000000 : nbytes;
459 *bc->bufp = solv_extend(*bc->bufp, *bc->buflp, n + 1, 1, 4095);
460 memcpy(*bc->bufp, buf, n);
461 (*bc->bufp)[n] = 0; /* zero-terminate */
467 static int cookie_bufclose(void *cookie)
469 struct bufcookie *bc = cookie;
471 solv_free(bc->freemem);
477 solv_xfopen_buf(const char *fn, char **bufp, size_t *buflp, const char *mode)
479 struct bufcookie *bc;
481 if (*mode != 'r' && *mode != 'w')
483 bc = solv_calloc(1, sizeof(*bc));
488 bc->bufl_int = *mode == 'w' ? 0 : strlen(*bufp);
489 buflp = &bc->bufl_int;
494 *bc->bufp = solv_extend(0, 0, 1, 1, 4095); /* always zero-terminate */
498 fp = cookieopen(bc, mode, cookie_bufread, cookie_bufwrite, cookie_bufclose);
499 if (!strcmp(mode, "rf")) /* auto-free */
504 *bc->bufp = solv_free(*bc->bufp);