diff options
Diffstat (limited to 'stream/filt_filec.c')
-rw-r--r-- | stream/filt_filec.c | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/stream/filt_filec.c b/stream/filt_filec.c new file mode 100644 index 00000000..05813185 --- /dev/null +++ b/stream/filt_filec.c @@ -0,0 +1,349 @@ +#include <fitz.h> + +fz_error * +fz_ferror(fz_file *f) +{ + fz_error *e = f->error; + f->error = nil; + return e; +} + +fz_error * +fz_openfile(fz_file **filep, char *path, int mode) +{ + fz_error *error; + fz_file *file; + int realmode; + int fd; + int n; + + assert(mode == FZ_READ || mode == FZ_WRITE || mode == FZ_APPEND); + + realmode = 0; + if (mode == FZ_READ) + realmode = O_BINARY | O_RDONLY; + if (mode == FZ_WRITE) + realmode = O_BINARY | O_WRONLY | O_CREAT | O_TRUNC; + if (mode == FZ_APPEND) + realmode = O_BINARY | O_WRONLY; + + fd = open(path, realmode, 0644); + if (fd == -1) + return fz_throw("ioerror: open '%s': %s", path, strerror(errno)); + + if (mode == FZ_APPEND) + { + mode = FZ_WRITE; + n = lseek(fd, 0, 2); + if (n == -1) { + error = fz_throw("ioerror: lseek: %s", strerror(errno)); + close(fd); + return error; + } + } + + file = *filep = fz_malloc(sizeof(fz_file)); + if (!file) + return fz_outofmem; + + file->mode = mode; + file->fd = fd; + file->depth = 0; + file->error = nil; + file->filter = nil; + file->in = nil; + file->out = nil; + + error = fz_newbuffer(&file->in, FZ_BUFSIZE); + if (error) + goto cleanup; + + error = fz_newbuffer(&file->out, FZ_BUFSIZE); + if (error) + goto cleanup; + + return nil; + +cleanup: + *filep = nil; + close(fd); + fz_dropbuffer(file->out); + fz_dropbuffer(file->in); + fz_free(file); + return error; +} + +fz_error * +fz_openbuffer(fz_file **filep, fz_buffer *buf, int mode) +{ + fz_error *error; + fz_file *file; + + assert(mode == FZ_READ || mode == FZ_WRITE); + + file = *filep = fz_malloc(sizeof(fz_file)); + if (!file) + return fz_outofmem; + + file->mode = mode; + file->fd = -1; + file->depth = 0; + file->error = nil; + file->filter = nil; + + if (mode == FZ_READ) + { + file->out = fz_keepbuffer(buf); + error = fz_newbuffer(&file->in, FZ_BUFSIZE); + if (error) + goto cleanup; + } + + else + { + error = fz_newbuffer(&file->out, FZ_BUFSIZE); + if (error) + goto cleanup; + file->in = fz_keepbuffer(buf); + } + + return nil; + +cleanup: + *filep = nil; + fz_free(file); + return error; +} + +void +fz_closefile(fz_file *file) +{ + assert(file->depth == 0); + + if (file->mode == FZ_WRITE) + fz_flush(file); + + if (file->error) + { + fz_warn("%s", file->error->msg); + fz_droperror(file->error); + file->error = nil; + } + + if (file->fd != -1) /* open to real file */ + close(file->fd); + + fz_dropbuffer(file->in); + fz_dropbuffer(file->out); + + if (file->filter) + fz_dropfilter(file->filter); + + fz_free(file); +} + +fz_error * +fz_pushfilter(fz_file *file, fz_filter *filter) +{ + fz_error *error; + + /* without a filter, one buffer is ignored: unignore. */ + if (file->depth == 0) + { + fz_buffer *buf; + + buf = file->out; + file->out = file->in; + file->in = buf; + + if (file->mode == FZ_READ) + { + file->out->rp = file->out->bp; + file->out->wp = file->out->bp; + file->out->eof = 0; + } + else + { + file->out->eof = 0; + file->in->rp = file->in->bp; + file->in->wp = file->in->bp; + file->in->eof = 0; + } + + file->filter = fz_keepfilter(filter); + } + + else + { + if (file->mode == FZ_READ) + { + error = fz_chainpipeline(&file->filter, file->filter, filter, file->out); + if (error) + return error; + + error = fz_newbuffer(&file->out, FZ_BUFSIZE); + if (error) + { + fz_unchainpipeline(file->filter, &file->filter, &file->out); + return error; + } + } + + else + { + error = fz_chainpipeline(&file->filter, filter, file->filter, file->in); + if (error) + return error; + + error = fz_newbuffer(&file->in, FZ_BUFSIZE); + if (error) + { + fz_unchainpipeline(file->filter, &file->filter, &file->in); + return error; + } + } + } + + file->depth ++; + + return nil; +} + +void +fz_popfilter(fz_file *file) +{ + fz_buffer *buf; + + assert(file->depth > 0); + + if (file->mode == FZ_WRITE) + fz_flush(file); + + if (file->error) + { + fz_warn("%s", file->error->msg); + fz_droperror(file->error); + file->error = nil; + } + + if (file->depth == 1) + { + fz_dropfilter(file->filter); + file->filter = nil; + + buf = file->out; + file->out = file->in; + file->in = buf; + } + else + { + if (file->mode == FZ_READ) + { + fz_dropbuffer(file->out); + fz_unchainpipeline(file->filter, &file->filter, &file->out); + } + else + { + fz_dropbuffer(file->in); + fz_unchainpipeline(file->filter, &file->filter, &file->in); + } + } + + file->depth --; +} + +int +fz_seek(fz_file *f, int ofs, int whence) +{ + int t; + int c; + + if (f->filter) + { + assert(f->mode == FZ_READ && whence == 0); + + if (ofs < fz_tell(f)) + { + f->error = fz_throw("ioerror: cannot seek backwards in filter"); + return -1; + } + while (fz_tell(f) < ofs) + { + c = fz_readbyte(f); + if (c == EOF) + return -1; + } + return ofs; + } + + if (whence == 1) + { + ofs = fz_tell(f) + ofs; + whence = 0; + } + + if (f->fd == -1) + { + if (whence == 0) + { + if (f->mode == FZ_READ) + f->out->rp = CLAMP(f->out->bp + ofs, f->out->bp, f->in->ep); + else + f->in->wp = CLAMP(f->in->bp + ofs, f->in->bp, f->in->ep); + } + else + { + if (f->mode == FZ_READ) + f->out->rp = CLAMP(f->out->ep + ofs, f->out->bp, f->in->ep); + else + f->in->wp = CLAMP(f->in->ep + ofs, f->in->bp, f->in->ep); + } + return fz_tell(f); + } + + t = lseek(f->fd, ofs, whence); + if (t == -1) + { + f->error = fz_throw("ioerror: lseek: %s", strerror(errno)); + return -1; + } + + f->out->rp = f->out->bp; + f->out->wp = f->out->bp; + f->out->eof = 0; + + return t; +} + +int +fz_tell(fz_file *f) +{ + int t; + + if (f->filter) + { + assert(f->mode == FZ_READ); + return f->filter->count - (f->out->wp - f->out->rp); + } + + if (f->fd == -1) + { + if (f->mode == FZ_READ) + return f->out->rp - f->out->bp; + else + return f->in->wp - f->in->bp; + } + + t = lseek(f->fd, 0, 1); + if (t == -1) + { + f->error = fz_throw("ioerror: lseek: %s", strerror(errno)); + return -1; + } + + if (f->mode == FZ_READ) + return t - (f->out->wp - f->out->rp); + else + return t + (f->in->wp - f->in->rp); +} + |