Annotation of embedaddon/libpdel/io/filter.c, revision 1.1

1.1     ! misho       1: 
        !             2: /*
        !             3:  * Copyright (c) 2001-2002 Packet Design, LLC.
        !             4:  * All rights reserved.
        !             5:  * 
        !             6:  * Subject to the following obligations and disclaimer of warranty,
        !             7:  * use and redistribution of this software, in source or object code
        !             8:  * forms, with or without modifications are expressly permitted by
        !             9:  * Packet Design; provided, however, that:
        !            10:  * 
        !            11:  *    (i)  Any and all reproductions of the source or object code
        !            12:  *         must include the copyright notice above and the following
        !            13:  *         disclaimer of warranties; and
        !            14:  *    (ii) No rights are granted, in any manner or form, to use
        !            15:  *         Packet Design trademarks, including the mark "PACKET DESIGN"
        !            16:  *         on advertising, endorsements, or otherwise except as such
        !            17:  *         appears in the above copyright notice or in the software.
        !            18:  * 
        !            19:  * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
        !            20:  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
        !            21:  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
        !            22:  * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
        !            23:  * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
        !            24:  * OR NON-INFRINGEMENT.  PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
        !            25:  * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
        !            26:  * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
        !            27:  * RELIABILITY OR OTHERWISE.  IN NO EVENT SHALL PACKET DESIGN BE
        !            28:  * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
        !            29:  * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
        !            30:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
        !            31:  * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
        !            32:  * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
        !            33:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            34:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
        !            35:  * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
        !            36:  * THE POSSIBILITY OF SUCH DAMAGE.
        !            37:  *
        !            38:  * Author: Archie Cobbs <archie@freebsd.org>
        !            39:  */
        !            40: 
        !            41: #include <sys/types.h>
        !            42: #include <sys/param.h>
        !            43: 
        !            44: #include <assert.h>
        !            45: #include <stdio.h>
        !            46: #include <stdarg.h>
        !            47: #include <string.h>
        !            48: #include <errno.h>
        !            49: #include <stdlib.h>
        !            50: 
        !            51: #include "structs/structs.h"
        !            52: #include "structs/type/array.h"
        !            53: 
        !            54: #include "io/filter.h"
        !            55: #include "util/typed_mem.h"
        !            56: 
        !            57: /************************************************************************
        !            58:                        FILTER STREAMS
        !            59: ************************************************************************/
        !            60: 
        !            61: /* funopen(3) methods used by filter_fopen() */
        !            62: static int     filter_stream_read(void *cookie, char *buf, int len);
        !            63: static int     filter_stream_write(void *cookie, const char *buf, int len);
        !            64: static int     filter_stream_close(void *cookie);
        !            65: 
        !            66: /* State used by filter_fopen() */
        !            67: struct filter_stream {
        !            68:        FILE            *fp;                    /* underlying stream */
        !            69:        struct filter   *filter;                /* filter object */
        !            70:        int             output;                 /* input or output? */
        !            71:        int             eof;                    /* eof has been reached */
        !            72:        int             flags;                  /* flags */
        !            73: };
        !            74: 
        !            75: /*
        !            76:  * Create a new filter stream using the supplied filter.
        !            77:  */
        !            78: FILE *
        !            79: filter_fopen(struct filter *filter, int flags, FILE *fp, const char *mode)
        !            80: {
        !            81:        struct filter_stream *fs;
        !            82:        int output;
        !            83: 
        !            84:        if (strcmp(mode, "r") == 0)
        !            85:                output = 0;
        !            86:        else if (strcmp(mode, "w") == 0)
        !            87:                output = 1;
        !            88:        else {
        !            89:                errno = EINVAL;
        !            90:                return (NULL);
        !            91:        }
        !            92:        if ((fs = MALLOC("filter_stream", sizeof(*fs))) == NULL)
        !            93:                return (NULL);
        !            94:        memset(fs, 0, sizeof(*fs));
        !            95:        fs->filter = filter;
        !            96:        fs->fp = fp;
        !            97:        fs->output = output;
        !            98:        fs->flags = flags;
        !            99:        if ((fp = funopen(fs,
        !           100:            !fs->output ? filter_stream_read : NULL,
        !           101:            fs->output ? filter_stream_write : NULL,
        !           102:            NULL, filter_stream_close)) == NULL) {
        !           103:                FREE("filter_stream", fs);
        !           104:                return (NULL);
        !           105:        }
        !           106:        return (fp);
        !           107: }
        !           108: 
        !           109: static int
        !           110: filter_stream_read(void *cookie, char *buf, int len)
        !           111: {
        !           112:        struct filter_stream *const fs = cookie;
        !           113:        u_char fbuf[1024];
        !           114:        int total = 0;
        !           115:        int flen;
        !           116:        int num;
        !           117:        int i;
        !           118: 
        !           119:        /*
        !           120:         * Read from underlying stream until we've read "len" bytes
        !           121:         * from the filter or the underlying stream returns EOF.
        !           122:         */
        !           123:        for (total = 0; len > 0; ) {
        !           124: 
        !           125:                /* Read any remaining output from the filter */
        !           126:                if ((num = filter_read(fs->filter, buf, len)) == -1)
        !           127:                        return (-1);
        !           128:                buf += num;
        !           129:                len -= num;
        !           130:                total += num;
        !           131: 
        !           132:                /* No more data to be read from underlying stream? */
        !           133:                if (fs->eof || len == 0)
        !           134:                        break;
        !           135: 
        !           136:                /*
        !           137:                 * Read more data from the underlying stream,
        !           138:                 * but not any more than necessary.
        !           139:                 */
        !           140:                flen = filter_convert(fs->filter, len, 0);
        !           141:                flen = MIN(flen, sizeof(fbuf));
        !           142:                clearerr(fs->fp);
        !           143:                if ((num = fread(fbuf, 1, flen, fs->fp)) == 0) {
        !           144:                        if (ferror(fs->fp))
        !           145:                                return (total > 0 ? total : -1);
        !           146:                        fs->eof = 1;
        !           147:                        if (filter_end(fs->filter) == -1)
        !           148:                                return (total > 0 ? total : -1);
        !           149:                }
        !           150: 
        !           151:                /* Send the data we just read through the filter */
        !           152:                for (i = 0; i < num; i += flen) {
        !           153:                        if ((flen = filter_write(fs->filter,
        !           154:                            fbuf + i, num - i)) == -1)
        !           155:                                return (total > 0 ? total : -1);
        !           156:                }
        !           157:        }
        !           158:        return (total);
        !           159: }
        !           160: 
        !           161: static int
        !           162: filter_stream_write(void *cookie, const char *buf, int len)
        !           163: {
        !           164:        struct filter_stream *const fs = cookie;
        !           165:        u_char fbuf[1024];
        !           166:        int flen;
        !           167: 
        !           168:        if ((len = filter_write(fs->filter, buf, len)) == -1)
        !           169:                return (-1);
        !           170:        while ((flen = filter_read(fs->filter, fbuf, sizeof(fbuf))) > 0) {
        !           171:                if (fwrite(fbuf, 1, flen, fs->fp) != flen)
        !           172:                        return (-1);
        !           173:        }
        !           174:        return (len);
        !           175: }
        !           176: 
        !           177: static int
        !           178: filter_stream_close(void *cookie)
        !           179: {
        !           180:        struct filter_stream *const fs = cookie;
        !           181:        u_char buf[1024];
        !           182:        int len;
        !           183: 
        !           184:        if (fs->output) {
        !           185:                (void)filter_end(fs->filter);                   /* XXX */
        !           186:                while ((len = filter_read(fs->filter, buf, sizeof(buf))) > 0) {
        !           187:                        if (fwrite(buf, 1, len, fs->fp) != len)
        !           188:                                break;
        !           189:                }
        !           190:                fflush(fs->fp);
        !           191:        }
        !           192:        if ((fs->flags & FILTER_NO_CLOSE_STREAM) == 0)
        !           193:                fclose(fs->fp);
        !           194:        if ((fs->flags & FILTER_NO_DESTROY_FILTER) == 0)
        !           195:                filter_destroy(&fs->filter);
        !           196: 
        !           197:        /* Done */
        !           198:        FREE("filter_stream", fs);
        !           199:        return (0);
        !           200: }
        !           201: 
        !           202: /************************************************************************
        !           203:                        FILTER PROCESSING
        !           204: ************************************************************************/
        !           205: 
        !           206: /*
        !           207:  * Filter data in memory using a filter.
        !           208:  */
        !           209: int
        !           210: filter_process(struct filter *filter, const void *input, int ilen,
        !           211:        int final, u_char **outputp, const char *mtype)
        !           212: {
        !           213:        int nw, w;
        !           214:        int nr, r;
        !           215:        int olen;
        !           216: 
        !           217:        /* Allocate buffer big enough to hold filter output */
        !           218:        olen = filter_convert(filter, ilen, 1) + 10;
        !           219:        if ((*outputp = MALLOC(mtype, olen)) == NULL)
        !           220:                return (-1);
        !           221: 
        !           222:        /* Filter data */
        !           223:        for (w = r = 0; w < ilen; w += nw, r += nr) {
        !           224:                if ((nw = filter_write(filter,
        !           225:                    (char *)input + w, MIN(ilen - w, 1024))) == -1)
        !           226:                        goto fail;
        !           227:                if ((nr = filter_read(filter, *outputp + r, olen - r)) == -1)
        !           228:                        goto fail;
        !           229:        }
        !           230:        if (final) {
        !           231:                if (filter_end(filter) == -1)
        !           232:                        goto fail;
        !           233:                do {
        !           234:                        if ((nr = filter_read(filter,
        !           235:                            *outputp + r, olen - r)) == -1)
        !           236:                                goto fail;
        !           237:                        r += nr;
        !           238:                } while (nr != 0);
        !           239:        }
        !           240:        assert(r < olen);
        !           241: 
        !           242:        /* Done */
        !           243:        (*outputp)[r] = 0;
        !           244:        return (r);
        !           245: 
        !           246: fail:
        !           247:        FREE(mtype, *outputp);
        !           248:        *outputp = NULL;
        !           249:        return (-1);
        !           250: }
        !           251: 
        !           252: /************************************************************************
        !           253:                        FILTER METHOD WRAPPERS
        !           254: ************************************************************************/
        !           255: 
        !           256: int
        !           257: filter_read(struct filter *filter, void *data, int len)
        !           258: {
        !           259:        return (*filter->read)(filter, data, len);
        !           260: }
        !           261: 
        !           262: int
        !           263: filter_write(struct filter *filter, const void *data, int len)
        !           264: {
        !           265:        return (*filter->write)(filter, data, len);
        !           266: }
        !           267: 
        !           268: int
        !           269: filter_end(struct filter *filter)
        !           270: {
        !           271:        return (*filter->end)(filter);
        !           272: }
        !           273: 
        !           274: int
        !           275: filter_convert(struct filter *filter, int num, int forward)
        !           276: {
        !           277:        return (*filter->convert)(filter, num, forward);
        !           278: }
        !           279: 
        !           280: void
        !           281: filter_destroy(struct filter **filterp)
        !           282: {
        !           283:        struct filter *const filter = *filterp;
        !           284: 
        !           285:        if (filter != NULL)
        !           286:                (*filter->destroy)(filterp);
        !           287: }
        !           288: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>