/* * Copyright (c) 2001-2002 Packet Design, LLC. * All rights reserved. * * Subject to the following obligations and disclaimer of warranty, * use and redistribution of this software, in source or object code * forms, with or without modifications are expressly permitted by * Packet Design; provided, however, that: * * (i) Any and all reproductions of the source or object code * must include the copyright notice above and the following * disclaimer of warranties; and * (ii) No rights are granted, in any manner or form, to use * Packet Design trademarks, including the mark "PACKET DESIGN" * on advertising, endorsements, or otherwise except as such * appears in the above copyright notice or in the software. * * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE, * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Author: Archie Cobbs */ #include #include #include #include #include #include #include #include #include "structs/structs.h" #include "structs/type/array.h" #include "io/filter.h" #include "util/typed_mem.h" /************************************************************************ FILTER STREAMS ************************************************************************/ /* funopen(3) methods used by filter_fopen() */ static int filter_stream_read(void *cookie, char *buf, int len); static int filter_stream_write(void *cookie, const char *buf, int len); static int filter_stream_close(void *cookie); /* State used by filter_fopen() */ struct filter_stream { FILE *fp; /* underlying stream */ struct filter *filter; /* filter object */ int output; /* input or output? */ int eof; /* eof has been reached */ int flags; /* flags */ }; /* * Create a new filter stream using the supplied filter. */ FILE * filter_fopen(struct filter *filter, int flags, FILE *fp, const char *mode) { struct filter_stream *fs; int output; if (strcmp(mode, "r") == 0) output = 0; else if (strcmp(mode, "w") == 0) output = 1; else { errno = EINVAL; return (NULL); } if ((fs = MALLOC("filter_stream", sizeof(*fs))) == NULL) return (NULL); memset(fs, 0, sizeof(*fs)); fs->filter = filter; fs->fp = fp; fs->output = output; fs->flags = flags; if ((fp = funopen(fs, !fs->output ? filter_stream_read : NULL, fs->output ? filter_stream_write : NULL, NULL, filter_stream_close)) == NULL) { FREE("filter_stream", fs); return (NULL); } return (fp); } static int filter_stream_read(void *cookie, char *buf, int len) { struct filter_stream *const fs = cookie; u_char fbuf[1024]; int total = 0; int flen; int num; int i; /* * Read from underlying stream until we've read "len" bytes * from the filter or the underlying stream returns EOF. */ for (total = 0; len > 0; ) { /* Read any remaining output from the filter */ if ((num = filter_read(fs->filter, buf, len)) == -1) return (-1); buf += num; len -= num; total += num; /* No more data to be read from underlying stream? */ if (fs->eof || len == 0) break; /* * Read more data from the underlying stream, * but not any more than necessary. */ flen = filter_convert(fs->filter, len, 0); flen = MIN(flen, sizeof(fbuf)); clearerr(fs->fp); if ((num = fread(fbuf, 1, flen, fs->fp)) == 0) { if (ferror(fs->fp)) return (total > 0 ? total : -1); fs->eof = 1; if (filter_end(fs->filter) == -1) return (total > 0 ? total : -1); } /* Send the data we just read through the filter */ for (i = 0; i < num; i += flen) { if ((flen = filter_write(fs->filter, fbuf + i, num - i)) == -1) return (total > 0 ? total : -1); } } return (total); } static int filter_stream_write(void *cookie, const char *buf, int len) { struct filter_stream *const fs = cookie; u_char fbuf[1024]; int flen; if ((len = filter_write(fs->filter, buf, len)) == -1) return (-1); while ((flen = filter_read(fs->filter, fbuf, sizeof(fbuf))) > 0) { if (fwrite(fbuf, 1, flen, fs->fp) != flen) return (-1); } return (len); } static int filter_stream_close(void *cookie) { struct filter_stream *const fs = cookie; u_char buf[1024]; int len; if (fs->output) { (void)filter_end(fs->filter); /* XXX */ while ((len = filter_read(fs->filter, buf, sizeof(buf))) > 0) { if (fwrite(buf, 1, len, fs->fp) != len) break; } fflush(fs->fp); } if ((fs->flags & FILTER_NO_CLOSE_STREAM) == 0) fclose(fs->fp); if ((fs->flags & FILTER_NO_DESTROY_FILTER) == 0) filter_destroy(&fs->filter); /* Done */ FREE("filter_stream", fs); return (0); } /************************************************************************ FILTER PROCESSING ************************************************************************/ /* * Filter data in memory using a filter. */ int filter_process(struct filter *filter, const void *input, int ilen, int final, u_char **outputp, const char *mtype) { int nw, w; int nr, r; int olen; /* Allocate buffer big enough to hold filter output */ olen = filter_convert(filter, ilen, 1) + 10; if ((*outputp = MALLOC(mtype, olen)) == NULL) return (-1); /* Filter data */ for (w = r = 0; w < ilen; w += nw, r += nr) { if ((nw = filter_write(filter, (char *)input + w, MIN(ilen - w, 1024))) == -1) goto fail; if ((nr = filter_read(filter, *outputp + r, olen - r)) == -1) goto fail; } if (final) { if (filter_end(filter) == -1) goto fail; do { if ((nr = filter_read(filter, *outputp + r, olen - r)) == -1) goto fail; r += nr; } while (nr != 0); } assert(r < olen); /* Done */ (*outputp)[r] = 0; return (r); fail: FREE(mtype, *outputp); *outputp = NULL; return (-1); } /************************************************************************ FILTER METHOD WRAPPERS ************************************************************************/ int filter_read(struct filter *filter, void *data, int len) { return (*filter->read)(filter, data, len); } int filter_write(struct filter *filter, const void *data, int len) { return (*filter->write)(filter, data, len); } int filter_end(struct filter *filter) { return (*filter->end)(filter); } int filter_convert(struct filter *filter, int num, int forward) { return (*filter->convert)(filter, num, forward); } void filter_destroy(struct filter **filterp) { struct filter *const filter = *filterp; if (filter != NULL) (*filter->destroy)(filterp); }