Annotation of embedaddon/libpdel/io/filter.c, revision 1.1.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>