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>