diff options
Diffstat (limited to 'zio.c')
-rw-r--r-- | zio.c | 231 |
1 files changed, 151 insertions, 80 deletions
@@ -4,11 +4,20 @@ * Copyright 2004 Werner Fink, 2004 SuSE LINUX AG, Germany. * Copyright 2006 Werner Fink, 2006 SuSE Products GmbH, Germany. * Copyright 2009 Werner Fink, 2009 SuSE Products GmbH, Germany. + * Copyright 2013 Werner Fink, 2013 SuSE Products GmbH, Germany. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * the Free Software Foundation; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Author: Werner Fink <werner@suse.de> */ @@ -42,6 +51,7 @@ static zio_int_t zseek(void *cookie, zio_off_t *poffset, int whence) errno = EINVAL; return -1; } + off_t offset = (off_t)*poffset; return (zio_int_t)gzseek((gzFile)cookie, (z_off_t)(*poffset), whence); } @@ -74,8 +84,9 @@ static cookie_io_functions_t ioz = { # endif typedef struct bzfile_s { - size_t total_out; + size_t position; BZFILE *file; + FILE *stdio; char *mode; char *path; int fd; @@ -90,7 +101,7 @@ static ssize_t bzread(void *cookie, char *buf, size_t count) if (bzf->file) len = (ssize_t)BZ2_bzread(bzf->file, (void*)buf, count); if (len > 0) - bzf->total_out += len; + bzf->position += len; out: if (len < 0) errno = EINVAL; @@ -104,9 +115,9 @@ static ssize_t bzwrite(void *cookie, const char *buf, size_t count) if (!bzf) goto out; if (bzf->file) - len = (ssize_t)BZ2_bzread(bzf->file, (void*)buf, count); + len = (ssize_t)BZ2_bzwrite(bzf->file, (void*)buf, count); if (len > 0) - bzf->total_out += len; + bzf->position += len; out: if (len < 0) errno = EINVAL; @@ -116,24 +127,29 @@ out: static zio_int_t bzseek(void *cookie, zio_off_t *poffset, int whence) { bzfile_t *bzf = (bzfile_t*)cookie; - off_t offset = (off_t)*poffset; - off_t oldpos, newpos; + off_t offset, curpos, newpos; if (!bzf) { errno = EINVAL; return -1; } - oldpos = (off_t)bzf->total_out; + offset = (off_t)*poffset; + curpos = (off_t)bzf->position; + switch (whence) { case SEEK_SET: - if (offset < 0) + if (offset < 0) { + errno = EINVAL; return -1; + } newpos = offset; break; case SEEK_CUR: - if ((offset < 0 && (off_t)(-1 * offset) > oldpos) || (offset > 0 && (offset+oldpos) < oldpos)) + if ((offset < 0 && (off_t)(-1 * offset) > curpos) || (offset > 0 && (offset+curpos) < curpos)) { + errno = EINVAL; return -1; - newpos = (off_t)bzf->total_out + offset; + } + newpos = curpos + offset; break; case SEEK_END: newpos = -1; @@ -143,7 +159,7 @@ static zio_int_t bzseek(void *cookie, zio_off_t *poffset, int whence) return -1; } - if (whence != SEEK_END && newpos < oldpos) { + if (whence != SEEK_END && newpos < curpos) { int status = BZ2_bzflush(bzf->file); BZ2_bzclose(bzf->file); if (status < 0) { @@ -163,27 +179,36 @@ static zio_int_t bzseek(void *cookie, zio_off_t *poffset, int whence) errno = EINVAL; return -1; } - bzf->total_out = 0; + curpos = (off_t)0; + bzf->position = curpos; } - if (newpos == oldpos) - return oldpos; - else { + if (newpos == curpos) + goto out; + if (newpos == -1) { + char buf[1<<12]; + while (1) { + ssize_t got_size = BZ2_bzread(bzf->file, buf, sizeof(buf)); + if (got_size < 0) + return -1; + if (got_size == 0) + break; + curpos += got_size; + } + } else { char buf[1<<12]; - while (newpos > oldpos || newpos == -1) { - size_t req_size = MIN(sizeof(buf), newpos - oldpos); + while (newpos > curpos) { + size_t req_size = MIN(sizeof(buf), newpos - curpos); ssize_t got_size = BZ2_bzread(bzf->file, buf, req_size); - if (got_size != (ssize_t)(req_size)) { - if (got_size < 0) - return -1; - else { - newpos = oldpos + got_size; - break; - } - } - oldpos += got_size; + if (got_size < 0) + return -1; + if (got_size == 0) + break; + curpos += got_size; } - return newpos; } +out: + bzf->position = curpos; + return curpos; } static int bzclose(void *cookie) @@ -223,6 +248,7 @@ typedef struct lzfile_s { uint8_t buf[1<<12]; lzma_stream strm; FILE *file; + FILE *stdio; int encoding; int level; int what; @@ -291,9 +317,9 @@ static ssize_t lzmawrite(void *cookie, const char *buf, size_t count) lzfile_t *lzma = (lzfile_t*)cookie; lzma_stream *strm; if (!lzma || !lzma->encoding) - return -1; + return -1; if (!count) - return 0; + return 0; strm = &lzma->strm; strm->next_in = (uint8_t*)buf; @@ -318,24 +344,31 @@ static ssize_t lzmawrite(void *cookie, const char *buf, size_t count) static zio_int_t lzmaseek(void *cookie, zio_off_t *poffset, int whence) { lzfile_t *lzma = (lzfile_t*)cookie; - off_t offset = (off_t)*poffset; lzma_stream *strm; - off_t oldpos, newpos; - if (!lzma) + off_t offset, curpos, newpos; + if (!lzma) { + errno = EINVAL; return -1; + } + strm = &lzma->strm; + offset = (off_t)*poffset; + curpos = (off_t)strm->total_out; - oldpos = (off_t)strm->total_out; switch (whence) { case SEEK_SET: - if (offset < 0) + if (offset < 0) { + errno = EINVAL; return -1; + } newpos = offset; break; case SEEK_CUR: - if ((offset < 0 && (off_t)(-1 * offset) > oldpos) || (offset > 0 && (offset+oldpos) < oldpos)) + if ((offset < 0 && (off_t)(-1 * offset) > curpos) || (offset > 0 && (offset+curpos) < curpos)) { + errno = EINVAL; return -1; - newpos = (off_t)strm->total_out + offset; + } + newpos = curpos + offset; break; case SEEK_END: newpos = -1; @@ -344,37 +377,51 @@ static zio_int_t lzmaseek(void *cookie, zio_off_t *poffset, int whence) errno = EINVAL; return -1; } - - if (whence != SEEK_END && newpos < oldpos) { + if (whence != SEEK_END && newpos < curpos) { lzma_ret ret; + lzma_end(strm); + lzma->strm = (lzma_stream)LZMA_STREAM_INIT; + strm = &lzma->strm; + rewind(lzma->file); + clearerr(lzma->file); + lzma->eof = 0; + ret = lzmaopen(strm, lzma->encoding ? 'w' : 'r', lzma->what, lzma->level); if (ret != LZMA_OK || strm->total_out != 0) { fclose(lzma->file); errno = EINVAL; return -1; } + curpos = (off_t)0; } - if (newpos == oldpos) - return oldpos; - else { + if (newpos == curpos) + goto out; + if (newpos == -1) { char buf[sizeof(lzma->buf)]; - while (newpos > oldpos || newpos == -1) { - size_t req_size = MIN(sizeof(buf), newpos - oldpos); + while (1) { + ssize_t got_size = lzmaread(cookie, buf, sizeof(buf)); + if (got_size < 0) + return -1; + if (got_size == 0) + break; + curpos += got_size; + } + } else { + char buf[sizeof(lzma->buf)]; + while (newpos > curpos) { + size_t req_size = MIN(sizeof(buf), newpos - curpos); ssize_t got_size = lzmaread(cookie, buf, req_size); - if (got_size != (ssize_t)(req_size)) { - if (got_size < 0) - return -1; - else { - newpos = oldpos + got_size; - break; - } - } - oldpos += got_size; + if (got_size < 0) + return -1; + if (got_size == 0) + break; + curpos += got_size; } - return newpos; } +out: + return curpos; } static int lzmaclose(void *cookie) @@ -466,8 +513,9 @@ static cookie_io_functions_t iolzma = { #endif /* !HAS_LZMA_H */ typedef struct lzwfile_s { - size_t total_out; + size_t position; LZW_t *file; + FILE *stdio; char *mode; char *path; int fd; @@ -482,7 +530,7 @@ static ssize_t lzwread(void *cookie, char *buf, size_t count) if (lzw->file) len = readlzw(lzw->file, buf, count); if (len > 0) - lzw->total_out += len; + lzw->position += len; out: if (len < 0) errno = EINVAL; @@ -498,24 +546,29 @@ static ssize_t lzwwrite(void *cookie, const char *buf, size_t count) static zio_int_t lzwseek(void *cookie, zio_off_t *poffset, int whence) { lzwfile_t *lzw = (lzwfile_t*)cookie; - off_t offset = (off_t)*poffset; - off_t oldpos, newpos; + off_t offset, curpos, newpos; if (!lzw) { errno = EINVAL; return -1; } - oldpos = (off_t)lzw->total_out; + offset = (off_t)*poffset; + curpos = (off_t)lzw->position; + switch (whence) { case SEEK_SET: - if (offset < 0) + if (offset < 0) { + errno = EINVAL; return -1; + } newpos = offset; break; case SEEK_CUR: - if ((offset < 0 && (off_t)(-1 * offset) > oldpos) || (offset > 0 && (offset+oldpos) < oldpos)) + if ((offset < 0 && (off_t)(-1 * offset) > curpos) || (offset > 0 && (offset+curpos) < curpos)) { + errno = EINVAL; return -1; - newpos = (off_t)lzw->total_out + offset; + } + newpos = curpos + offset; break; case SEEK_END: newpos = -1; @@ -525,7 +578,7 @@ static zio_int_t lzwseek(void *cookie, zio_off_t *poffset, int whence) return -1; } - if (whence != SEEK_END && newpos < oldpos) { + if (whence != SEEK_END && newpos < curpos) { closelzw(lzw->file); if (lzw->fd >= 0) { lseek(lzw->fd, 0, SEEK_SET); @@ -540,27 +593,36 @@ static zio_int_t lzwseek(void *cookie, zio_off_t *poffset, int whence) errno = EINVAL; return -1; } - lzw->total_out = 0; + curpos = (off_t)0; + lzw->position = curpos; } - if (newpos == oldpos) - return oldpos; - else { + if (newpos == curpos) + goto out; + if (newpos == -1) { char buf[1<<12]; - while (newpos > oldpos || newpos == -1) { - size_t req_size = MIN(sizeof(buf), newpos - oldpos); + while (1) { + ssize_t got_size = readlzw(lzw->file, buf, sizeof(buf)); + if (got_size < 0) + return -1; + if (got_size == 0) + break; + curpos += got_size; + } + } else { + char buf[1<<12]; + while (newpos > curpos) { + size_t req_size = MIN(sizeof(buf), newpos - curpos); ssize_t got_size = readlzw(lzw->file, buf, req_size); - if (got_size != (ssize_t)(req_size)) { - if (got_size < 0) - return -1; - else { - newpos = oldpos + got_size; - break; - } - } - oldpos += got_size; + if (got_size < 0) + return -1; + if (got_size == 0) + break; + curpos += got_size; } - return newpos; } +out: + lzw->position = curpos; + return curpos; } static int lzwclose(void *cookie) @@ -787,6 +849,7 @@ FILE * fzopen(const char * path, const char * mode) if (ret->_fileno < 0) ret->_fileno = 0; # endif + cookie->stdio = ret; } break; case 'b': @@ -834,6 +897,7 @@ FILE * fzopen(const char * path, const char * mode) if (ret->_fileno < 0) ret->_fileno = 0; # endif + cookie->stdio = ret; } #else /* !HAS_BZLIB_H */ errno = ENOTSUP; @@ -892,6 +956,7 @@ FILE * fzopen(const char * path, const char * mode) if (ret->_fileno < 0) ret->_fileno = 0; # endif + cookie->stdio = ret; } break; #else /* !HAS_LZMA_H */ @@ -928,6 +993,7 @@ FILE * fzopen(const char * path, const char * mode) if (ret->_fileno < 0) ret->_fileno = 0; # endif + cookie->stdio = ret; } # else /* !HAS_LZMADEC_H */ errno = ENOTSUP; @@ -1048,6 +1114,7 @@ FILE * fdzopen(int fildes, const char * mode, const char *what) if (ret->_fileno < 0) ret->_fileno = 0; # endif + cookie->stdio = ret; } break; case 'b': @@ -1097,6 +1164,7 @@ FILE * fdzopen(int fildes, const char * mode, const char *what) if (ret->_fileno < 0) ret->_fileno = 0; # endif + cookie->stdio = ret; } #else /* !HAS_BZLIB_H */ errno = ENOTSUP; @@ -1137,6 +1205,7 @@ FILE * fdzopen(int fildes, const char * mode, const char *what) cookie->level = level; cookie->encoding = (check[0] == 'w') ? 1 : 0; lret = lzmaopen(&cookie->strm, check[0], *what, level); + if (lret != LZMA_OK) { fclose(cookie->file); free(cookie); @@ -1154,6 +1223,7 @@ FILE * fdzopen(int fildes, const char * mode, const char *what) if (ret->_fileno < 0) ret->_fileno = 0; # endif + cookie->stdio = ret; } break; #else /* !HAS_LZMA_H */ @@ -1190,6 +1260,7 @@ FILE * fdzopen(int fildes, const char * mode, const char *what) if (ret->_fileno < 0) ret->_fileno = 0; # endif + cookie->stdio = ret; } # else /* !HAS_LZMADEC_H */ errno = ENOTSUP; |