Improve filter framework. Implement a CRLFDOT filter.
* include/mailutils/filter.h (mu_filter_command) <mu_filter_flush> New command. (mu_filter_result) <mu_filter_again>: New result code. (MU_FILTER_MAX_AGAIN): New constant. (mu_crlfdot_filter): New filter. * include/mailutils/sys/stream.h (_MU_STR_DIRTY, _MU_STR_WRT) (_MU_STR_ERR, _MU_STR_EOF, _MU_STR_INTERN_MASK): Avoid conflicts with MU_STREAM_ constants from mailutils/stream.h * mailbox/crlfdot.c: New source. * mailbox/Makefile.am (libmailutils_la_SOURCES): Add crlfdot.c. * mailbox/filter.c (mu_filter_get_list): Register mu_crlfdot_filter. * mailbox/fltstream.c (init_iobuf): Fix initialization of isize and input. (filter_read): Redo the loop, allowing xcode to request a new iteration by returning mu_filter_again. (filter_write_internal): Likewise. (filter_wr_flush): Call filter_write_internal with mu_filter_flush, reserving mu_filter_lastbuf for really last buffers. (filter_close): Call filter_write_internal with mu_filter_lastbuf. * mailbox/stream.c (mu_stream_skip_input_bytes): Clear MU_STREAM_SEEK bit before actually doing anything. * include/mailutils/sys/pop3.h [DMALLOC]: Remove unneeded cond.
Showing
8 changed files
with
431 additions
and
50 deletions
... | @@ -50,7 +50,8 @@ enum mu_filter_command | ... | @@ -50,7 +50,8 @@ enum mu_filter_command |
50 | mu_filter_init, | 50 | mu_filter_init, |
51 | mu_filter_done, | 51 | mu_filter_done, |
52 | mu_filter_xcode, | 52 | mu_filter_xcode, |
53 | mu_filter_lastbuf | 53 | mu_filter_lastbuf, |
54 | mu_filter_flush | ||
54 | }; | 55 | }; |
55 | 56 | ||
56 | enum mu_filter_result | 57 | enum mu_filter_result |
... | @@ -58,9 +59,12 @@ enum mu_filter_result | ... | @@ -58,9 +59,12 @@ enum mu_filter_result |
58 | mu_filter_ok, | 59 | mu_filter_ok, |
59 | mu_filter_falure, | 60 | mu_filter_falure, |
60 | mu_filter_moreinput, | 61 | mu_filter_moreinput, |
61 | mu_filter_moreoutput | 62 | mu_filter_moreoutput, |
63 | mu_filter_again | ||
62 | }; | 64 | }; |
63 | 65 | ||
66 | #define MU_FILTER_MAX_AGAIN 5 | ||
67 | |||
64 | typedef int (*mu_filter_new_data_t) (void **, int, void *); | 68 | typedef int (*mu_filter_new_data_t) (void **, int, void *); |
65 | typedef enum mu_filter_result (*mu_filter_xcode_t) (void *data, | 69 | typedef enum mu_filter_result (*mu_filter_xcode_t) (void *data, |
66 | enum mu_filter_command cmd, | 70 | enum mu_filter_command cmd, |
... | @@ -88,8 +92,9 @@ extern int mu_filter_create (mu_stream_t *, mu_stream_t, const char*, | ... | @@ -88,8 +92,9 @@ extern int mu_filter_create (mu_stream_t *, mu_stream_t, const char*, |
88 | extern int mu_filter_get_list (mu_list_t *); | 92 | extern int mu_filter_get_list (mu_list_t *); |
89 | 93 | ||
90 | /* List of defaults. */ | 94 | /* List of defaults. */ |
91 | extern mu_filter_record_t mu_crlf_filter; | 95 | extern mu_filter_record_t mu_crlf_filter; |
92 | extern mu_filter_record_t mu_rfc822_filter; | 96 | extern mu_filter_record_t mu_rfc822_filter; |
97 | extern mu_filter_record_t mu_crlfdot_filter; | ||
93 | extern mu_filter_record_t mu_qp_filter; /* quoted-printable. */ | 98 | extern mu_filter_record_t mu_qp_filter; /* quoted-printable. */ |
94 | extern mu_filter_record_t mu_base64_filter; | 99 | extern mu_filter_record_t mu_base64_filter; |
95 | extern mu_filter_record_t mu_binary_filter; | 100 | extern mu_filter_record_t mu_binary_filter; | ... | ... |
... | @@ -25,10 +25,6 @@ | ... | @@ -25,10 +25,6 @@ |
25 | #include <mailutils/errno.h> | 25 | #include <mailutils/errno.h> |
26 | #include <mailutils/cstr.h> | 26 | #include <mailutils/cstr.h> |
27 | 27 | ||
28 | #ifdef DMALLOC | ||
29 | # include <dmalloc.h> | ||
30 | #endif | ||
31 | |||
32 | #ifdef __cplusplus | 28 | #ifdef __cplusplus |
33 | extern "C" { | 29 | extern "C" { |
34 | #endif | 30 | #endif | ... | ... |
... | @@ -17,12 +17,12 @@ | ... | @@ -17,12 +17,12 @@ |
17 | #ifndef _MAILUTILS_SYS_STREAM_H | 17 | #ifndef _MAILUTILS_SYS_STREAM_H |
18 | #define _MAILUTILS_SYS_STREAM_H | 18 | #define _MAILUTILS_SYS_STREAM_H |
19 | 19 | ||
20 | #define _MU_STR_DIRTY 0x1000 /* Buffer dirty */ | 20 | #define _MU_STR_DIRTY 0x10000000 /* Buffer dirty */ |
21 | #define _MU_STR_WRT 0x2000 /* Unflushed write pending */ | 21 | #define _MU_STR_WRT 0x20000000 /* Unflushed write pending */ |
22 | #define _MU_STR_ERR 0x4000 /* Permanent error state */ | 22 | #define _MU_STR_ERR 0x40000000 /* Permanent error state */ |
23 | #define _MU_STR_EOF 0x8000 /* EOF encountered */ | 23 | #define _MU_STR_EOF 0x80000000 /* EOF encountered */ |
24 | 24 | ||
25 | #define _MU_STR_INTERN_MASK 0xf000 | 25 | #define _MU_STR_INTERN_MASK 0xf0000000 |
26 | 26 | ||
27 | #define _MU_STR_EVENT_SET 1 | 27 | #define _MU_STR_EVENT_SET 1 |
28 | #define _MU_STR_EVENT_CLR 2 | 28 | #define _MU_STR_EVENT_CLR 2 | ... | ... |
... | @@ -63,6 +63,7 @@ libmailutils_la_SOURCES = \ | ... | @@ -63,6 +63,7 @@ libmailutils_la_SOURCES = \ |
63 | cfg_format.c\ | 63 | cfg_format.c\ |
64 | cfg_lexer.c\ | 64 | cfg_lexer.c\ |
65 | cfg_parser.c\ | 65 | cfg_parser.c\ |
66 | crlfdot.c\ | ||
66 | crlfflt.c\ | 67 | crlfflt.c\ |
67 | cstrlower.c\ | 68 | cstrlower.c\ |
68 | cstrupper.c\ | 69 | cstrupper.c\ | ... | ... |
mailbox/crlfdot.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2003, 2007, 2010 Free Software Foundation, Inc. | ||
3 | |||
4 | This library is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU Lesser General Public | ||
6 | License as published by the Free Software Foundation; either | ||
7 | version 3 of the License, or (at your option) any later version. | ||
8 | |||
9 | This library is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | Lesser General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Lesser General | ||
15 | Public License along with this library; if not, write to the | ||
16 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
17 | Boston, MA 02110-1301 USA */ | ||
18 | |||
19 | /* This source implements a CRLFDOT filter, useful for data I/O in | ||
20 | such protocols as POP3 and SMTP. When encoding, this filter | ||
21 | replaces each '\n' not following '\r' by "\r\n" and "byte-stuffs" | ||
22 | the input by outputting an additional '.' in front of any '.' appearing | ||
23 | at the beginning of a line. Upon closing the filter in this mode, it | ||
24 | outputs additional ".\r\n". | ||
25 | |||
26 | When decoding, the reverse is performed: each "\r\n" is replaced by a | ||
27 | '\n', and additional '.' are removed from beginning of lines. A single | ||
28 | dot on a line by itself marks end of the stream. | ||
29 | */ | ||
30 | |||
31 | #ifdef HAVE_CONFIG_H | ||
32 | # include <config.h> | ||
33 | #endif | ||
34 | |||
35 | #include <stdlib.h> | ||
36 | #include <string.h> | ||
37 | #include <mailutils/errno.h> | ||
38 | #include <mailutils/filter.h> | ||
39 | #include <mailutils/stream.h> | ||
40 | |||
41 | enum crlfdot_decode_state | ||
42 | { | ||
43 | crlfdot_decode_init, /* initial state */ | ||
44 | crlfdot_decode_char, /* Any character excepting [\r\n.] */ | ||
45 | crlfdot_decode_cr, /* prev. char was \r */ | ||
46 | crlfdot_decode_crlf, /* 2 prev. char were \r\n */ | ||
47 | crlfdot_decode_dot, /* 3 prev. chars were \r\n. */ | ||
48 | crlfdot_decode_dotcr, /* 4 prev. chars were \r\n.\r */ | ||
49 | crlfdot_decode_end /* final state, a \r\n.\r\n seen. */ | ||
50 | }; | ||
51 | |||
52 | static enum crlfdot_decode_state | ||
53 | new_decode_state (enum crlfdot_decode_state state, int c) | ||
54 | { | ||
55 | switch (state) | ||
56 | { | ||
57 | case crlfdot_decode_init: | ||
58 | switch (c) | ||
59 | { | ||
60 | case '\r': | ||
61 | return crlfdot_decode_cr; | ||
62 | case '.': | ||
63 | return crlfdot_decode_dot; | ||
64 | } | ||
65 | break; | ||
66 | |||
67 | case crlfdot_decode_char: | ||
68 | switch (c) | ||
69 | { | ||
70 | case '\r': | ||
71 | return crlfdot_decode_cr; | ||
72 | } | ||
73 | break; | ||
74 | |||
75 | case crlfdot_decode_cr: | ||
76 | switch (c) | ||
77 | { | ||
78 | case '\r': | ||
79 | return crlfdot_decode_cr; | ||
80 | case '\n': | ||
81 | return crlfdot_decode_crlf; | ||
82 | } | ||
83 | break; | ||
84 | |||
85 | case crlfdot_decode_crlf: | ||
86 | switch (c) | ||
87 | { | ||
88 | case '\r': | ||
89 | return crlfdot_decode_cr; | ||
90 | case '.': | ||
91 | return crlfdot_decode_dot; | ||
92 | } | ||
93 | |||
94 | case crlfdot_decode_dot: | ||
95 | switch (c) | ||
96 | { | ||
97 | case '\r': | ||
98 | return crlfdot_decode_dotcr; | ||
99 | } | ||
100 | break; | ||
101 | |||
102 | case crlfdot_decode_dotcr: | ||
103 | switch (c) | ||
104 | { | ||
105 | case '\n': | ||
106 | return crlfdot_decode_end; | ||
107 | } | ||
108 | |||
109 | case crlfdot_decode_end: | ||
110 | break; | ||
111 | } | ||
112 | return crlfdot_decode_char; | ||
113 | } | ||
114 | |||
115 | /* Move min(isize,osize) bytes from iptr to optr, replacing each \r\n | ||
116 | with \n. */ | ||
117 | static enum mu_filter_result | ||
118 | _crlfdot_decoder (void *xd, | ||
119 | enum mu_filter_command cmd, | ||
120 | struct mu_filter_io *iobuf) | ||
121 | { | ||
122 | int *pstate = xd; | ||
123 | size_t i, j; | ||
124 | const unsigned char *iptr; | ||
125 | size_t isize; | ||
126 | char *optr; | ||
127 | size_t osize; | ||
128 | |||
129 | switch (cmd) | ||
130 | { | ||
131 | case mu_filter_init: | ||
132 | *pstate = crlfdot_decode_init; | ||
133 | return mu_filter_ok; | ||
134 | |||
135 | case mu_filter_done: | ||
136 | return mu_filter_ok; | ||
137 | |||
138 | default: | ||
139 | break; | ||
140 | } | ||
141 | |||
142 | iptr = (const unsigned char *) iobuf->input; | ||
143 | isize = iobuf->isize; | ||
144 | optr = iobuf->output; | ||
145 | osize = iobuf->osize; | ||
146 | |||
147 | for (i = j = 0; *pstate != crlfdot_decode_end && i < isize && j < osize; i++) | ||
148 | { | ||
149 | unsigned char c = *iptr++; | ||
150 | |||
151 | if (c == '\r') | ||
152 | { | ||
153 | if (i + 1 == isize) | ||
154 | break; | ||
155 | *pstate = new_decode_state (*pstate, c); | ||
156 | if (*iptr == '\n') | ||
157 | continue; | ||
158 | } | ||
159 | else if (c == '.' && | ||
160 | (*pstate == crlfdot_decode_init || | ||
161 | *pstate == crlfdot_decode_crlf)) | ||
162 | { | ||
163 | /* Make sure we have two more characters in the buffer */ | ||
164 | if (i + 2 == isize) | ||
165 | break; | ||
166 | *pstate = new_decode_state (*pstate, c); | ||
167 | if (*iptr != '\r') | ||
168 | continue; | ||
169 | } | ||
170 | else | ||
171 | *pstate = new_decode_state (*pstate, c); | ||
172 | optr[j++] = c; | ||
173 | } | ||
174 | |||
175 | if (*pstate == crlfdot_decode_end) | ||
176 | { | ||
177 | j -= 2; /* remove the trailing .\n */ | ||
178 | iobuf->eof = 1; | ||
179 | } | ||
180 | iobuf->isize = i; | ||
181 | iobuf->osize = j; | ||
182 | return mu_filter_ok; | ||
183 | } | ||
184 | |||
185 | enum crlfdot_encode_state | ||
186 | { | ||
187 | crlfdot_encode_init, /* initial state */ | ||
188 | crlfdot_encode_char, /* Any character excepting [\r\n] */ | ||
189 | crlfdot_encode_cr, /* prev. char was \r */ | ||
190 | crlfdot_encode_lf, /* prev. char was \n */ | ||
191 | }; | ||
192 | |||
193 | static enum crlfdot_encode_state | ||
194 | new_encode_state (enum crlfdot_encode_state state, int c) | ||
195 | { | ||
196 | switch (c) | ||
197 | { | ||
198 | case '\r': | ||
199 | return crlfdot_encode_cr; | ||
200 | |||
201 | case '\n': | ||
202 | return crlfdot_encode_lf; | ||
203 | } | ||
204 | return crlfdot_encode_char; | ||
205 | } | ||
206 | |||
207 | /* Move min(isize,osize) bytes from iptr to optr, replacing each \n | ||
208 | with \r\n. Any input \r\n sequences remain untouched. */ | ||
209 | static enum mu_filter_result | ||
210 | _crlfdot_encoder (void *xd, | ||
211 | enum mu_filter_command cmd, | ||
212 | struct mu_filter_io *iobuf) | ||
213 | { | ||
214 | enum mu_filter_result result; | ||
215 | size_t i, j; | ||
216 | const unsigned char *iptr; | ||
217 | size_t isize; | ||
218 | char *optr; | ||
219 | size_t osize; | ||
220 | int *state = xd; | ||
221 | |||
222 | iptr = (const unsigned char *) iobuf->input; | ||
223 | isize = iobuf->isize; | ||
224 | optr = iobuf->output; | ||
225 | osize = iobuf->osize; | ||
226 | |||
227 | switch (cmd) | ||
228 | { | ||
229 | case mu_filter_init: | ||
230 | *state = crlfdot_encode_init; | ||
231 | return mu_filter_ok; | ||
232 | |||
233 | case mu_filter_done: | ||
234 | return mu_filter_ok; | ||
235 | |||
236 | default: | ||
237 | break; | ||
238 | } | ||
239 | |||
240 | for (i = j = 0; i < isize && j < osize; i++, iptr++) | ||
241 | { | ||
242 | unsigned char c = *iptr; | ||
243 | int curstate = *state; | ||
244 | |||
245 | if (c == '\n') | ||
246 | { | ||
247 | if (curstate == crlfdot_encode_cr) | ||
248 | optr[j++] = c; | ||
249 | else if (j + 1 == osize) | ||
250 | { | ||
251 | if (i == 0) | ||
252 | { | ||
253 | iobuf->osize = 2; | ||
254 | return mu_filter_moreoutput; | ||
255 | } | ||
256 | break; | ||
257 | } | ||
258 | else | ||
259 | { | ||
260 | optr[j++] = '\r'; | ||
261 | optr[j++] = '\n'; | ||
262 | } | ||
263 | } | ||
264 | else if (c == '.' && | ||
265 | (curstate == crlfdot_encode_init || | ||
266 | curstate == crlfdot_encode_lf)) | ||
267 | { | ||
268 | if (j + 2 > osize) | ||
269 | { | ||
270 | if (i == 0) | ||
271 | { | ||
272 | iobuf->osize = 2; | ||
273 | return mu_filter_moreoutput; | ||
274 | } | ||
275 | break; | ||
276 | } | ||
277 | optr[j++] = '.'; | ||
278 | optr[j++] = '.'; | ||
279 | } | ||
280 | else | ||
281 | optr[j++] = c; | ||
282 | |||
283 | *state = new_encode_state (curstate, c); | ||
284 | } | ||
285 | |||
286 | result = mu_filter_ok; | ||
287 | if (cmd == mu_filter_lastbuf) | ||
288 | { | ||
289 | switch (*state) | ||
290 | { | ||
291 | case crlfdot_encode_lf: | ||
292 | if (j + 3 > osize) | ||
293 | result = mu_filter_again; | ||
294 | break; | ||
295 | |||
296 | default: | ||
297 | if (j + 5 > osize) | ||
298 | result = mu_filter_again; | ||
299 | else | ||
300 | { | ||
301 | optr[j++] = '\r'; | ||
302 | optr[j++] = '\n'; | ||
303 | } | ||
304 | } | ||
305 | |||
306 | if (result == mu_filter_ok) | ||
307 | { | ||
308 | optr[j++] = '.'; | ||
309 | optr[j++] = '\r'; | ||
310 | optr[j++] = '\n'; | ||
311 | } | ||
312 | } | ||
313 | |||
314 | iobuf->isize = i; | ||
315 | iobuf->osize = j; | ||
316 | return result; | ||
317 | } | ||
318 | |||
319 | static int | ||
320 | alloc_state (void **pret, int mode MU_ARG_UNUSED, void *data MU_ARG_UNUSED) | ||
321 | { | ||
322 | *pret = malloc (sizeof (int)); | ||
323 | if (!*pret) | ||
324 | return ENOMEM; | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static struct _mu_filter_record _crlfdot_filter = { | ||
329 | "CRLFDOT", | ||
330 | 0, | ||
331 | alloc_state, | ||
332 | _crlfdot_encoder, | ||
333 | _crlfdot_decoder | ||
334 | }; | ||
335 | |||
336 | mu_filter_record_t mu_crlfdot_filter = &_crlfdot_filter; |
... | @@ -74,6 +74,7 @@ mu_filter_get_list (mu_list_t *plist) | ... | @@ -74,6 +74,7 @@ mu_filter_get_list (mu_list_t *plist) |
74 | mu_list_append (filter_list, mu_bit7_filter); | 74 | mu_list_append (filter_list, mu_bit7_filter); |
75 | mu_list_append (filter_list, mu_rfc822_filter); | 75 | mu_list_append (filter_list, mu_rfc822_filter); |
76 | mu_list_append (filter_list, mu_crlf_filter); | 76 | mu_list_append (filter_list, mu_crlf_filter); |
77 | mu_list_append (filter_list, mu_crlfdot_filter); | ||
77 | mu_list_append (filter_list, mu_rfc_2047_Q_filter); | 78 | mu_list_append (filter_list, mu_rfc_2047_Q_filter); |
78 | mu_list_append (filter_list, mu_rfc_2047_B_filter); | 79 | mu_list_append (filter_list, mu_rfc_2047_B_filter); |
79 | /* FIXME: add the default encodings? */ | 80 | /* FIXME: add the default encodings? */ | ... | ... |
... | @@ -45,8 +45,8 @@ | ... | @@ -45,8 +45,8 @@ |
45 | static void | 45 | static void |
46 | init_iobuf (struct mu_filter_io *io, struct _mu_filter_stream *fs) | 46 | init_iobuf (struct mu_filter_io *io, struct _mu_filter_stream *fs) |
47 | { | 47 | { |
48 | io->input = MFB_BASE (fs->inbuf); | 48 | io->input = MFB_CURPTR (fs->inbuf); |
49 | io->isize = MFB_LEVEL (fs->inbuf); | 49 | io->isize = MFB_RDBYTES (fs->inbuf); |
50 | io->output = MFB_ENDPTR (fs->outbuf); | 50 | io->output = MFB_ENDPTR (fs->outbuf); |
51 | io->osize = MFB_FREESIZE (fs->outbuf); | 51 | io->osize = MFB_FREESIZE (fs->outbuf); |
52 | io->errcode = 0; | 52 | io->errcode = 0; |
... | @@ -111,14 +111,15 @@ static int | ... | @@ -111,14 +111,15 @@ static int |
111 | filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) | 111 | filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) |
112 | { | 112 | { |
113 | struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream; | 113 | struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream; |
114 | enum mu_filter_command cmd = mu_filter_xcode; | ||
115 | struct mu_filter_io iobuf; | 114 | struct mu_filter_io iobuf; |
116 | size_t min_input_level = MU_FILTER_BUF_SIZE; | 115 | size_t min_input_level = MU_FILTER_BUF_SIZE; |
117 | size_t min_output_size = MU_FILTER_BUF_SIZE; | 116 | size_t min_output_size = MU_FILTER_BUF_SIZE; |
117 | enum mu_filter_command cmd = mu_filter_xcode; | ||
118 | size_t total = 0; | 118 | size_t total = 0; |
119 | int stop = 0; | 119 | int stop = 0; |
120 | int again = 0; | ||
120 | 121 | ||
121 | while (!stop && total < size && cmd != mu_filter_lastbuf) | 122 | do |
122 | { | 123 | { |
123 | size_t rdsize; | 124 | size_t rdsize; |
124 | 125 | ||
... | @@ -127,7 +128,7 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) | ... | @@ -127,7 +128,7 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) |
127 | enum mu_filter_result res; | 128 | enum mu_filter_result res; |
128 | int rc; | 129 | int rc; |
129 | 130 | ||
130 | if (MFB_RDBYTES (fs->inbuf) < min_input_level) | 131 | if (MFB_RDBYTES (fs->inbuf) < min_input_level && !again) |
131 | { | 132 | { |
132 | rc = MFB_require (&fs->inbuf, min_input_level); | 133 | rc = MFB_require (&fs->inbuf, min_input_level); |
133 | if (rc) | 134 | if (rc) |
... | @@ -139,9 +140,10 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) | ... | @@ -139,9 +140,10 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) |
139 | if (rc) | 140 | if (rc) |
140 | return rc; | 141 | return rc; |
141 | if (rdsize == 0 && | 142 | if (rdsize == 0 && |
142 | MFB_RDBYTES (fs->outbuf) == 0 | 143 | MFB_RDBYTES (fs->outbuf) == 0 && |
143 | && MFB_RDBYTES (fs->inbuf) == 0) | 144 | MFB_RDBYTES (fs->inbuf) == 0) |
144 | break; | 145 | cmd = mu_filter_lastbuf; |
146 | |||
145 | MFB_advance_level (&fs->inbuf, rdsize); | 147 | MFB_advance_level (&fs->inbuf, rdsize); |
146 | } | 148 | } |
147 | 149 | ||
... | @@ -153,16 +155,24 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) | ... | @@ -153,16 +155,24 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) |
153 | 155 | ||
154 | init_iobuf (&iobuf, fs); | 156 | init_iobuf (&iobuf, fs); |
155 | 157 | ||
156 | cmd = mu_stream_eof (fs->transport) ? | 158 | if (cmd != mu_filter_lastbuf) |
157 | mu_filter_lastbuf : mu_filter_xcode; | 159 | cmd = mu_stream_eof (fs->transport) ? |
160 | mu_filter_lastbuf : mu_filter_xcode; | ||
158 | res = fs->xcode (fs->xdata, cmd, &iobuf); | 161 | res = fs->xcode (fs->xdata, cmd, &iobuf); |
159 | switch (res) | 162 | switch (res) |
160 | { | 163 | { |
164 | case mu_filter_again: | ||
165 | if (++again > MU_FILTER_MAX_AGAIN) | ||
166 | { | ||
167 | /* FIXME: What filter? Need some id. */ | ||
168 | mu_error (_("filter returned `again' too many times")); | ||
169 | again = 0; | ||
170 | } | ||
171 | break; | ||
172 | |||
161 | case mu_filter_ok: | 173 | case mu_filter_ok: |
162 | if (iobuf.isize > MFB_RDBYTES (fs->inbuf) | 174 | again = 0; |
163 | || iobuf.osize > MFB_FREESIZE (fs->outbuf)) | 175 | if (cmd == mu_filter_lastbuf || iobuf.eof) |
164 | return MU_ERR_FAILURE; /* FIXME: special error code? */ | ||
165 | if (iobuf.eof) | ||
166 | { | 176 | { |
167 | _mu_stream_seteof (stream); | 177 | _mu_stream_seteof (stream); |
168 | stop = 1; | 178 | stop = 1; |
... | @@ -181,6 +191,10 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) | ... | @@ -181,6 +191,10 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) |
181 | continue; | 191 | continue; |
182 | } | 192 | } |
183 | 193 | ||
194 | if (iobuf.isize > MFB_RDBYTES (fs->inbuf) | ||
195 | || iobuf.osize > MFB_FREESIZE (fs->outbuf)) | ||
196 | return MU_ERR_FAILURE; /* FIXME: special error code? */ | ||
197 | |||
184 | /* iobuf.osize contains number of bytes written to output */ | 198 | /* iobuf.osize contains number of bytes written to output */ |
185 | MFB_advance_level (&fs->outbuf, iobuf.osize); | 199 | MFB_advance_level (&fs->outbuf, iobuf.osize); |
186 | 200 | ||
... | @@ -194,8 +208,10 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) | ... | @@ -194,8 +208,10 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) |
194 | memcpy (buf + total, MFB_CURPTR (fs->outbuf), rdsize); | 208 | memcpy (buf + total, MFB_CURPTR (fs->outbuf), rdsize); |
195 | MFB_advance_pos (&fs->outbuf, rdsize); | 209 | MFB_advance_pos (&fs->outbuf, rdsize); |
196 | total += rdsize; | 210 | total += rdsize; |
197 | } | ||
198 | 211 | ||
212 | } | ||
213 | while (!stop && (total < size || again)); | ||
214 | |||
199 | *pret = total; | 215 | *pret = total; |
200 | return 0; | 216 | return 0; |
201 | } | 217 | } |
... | @@ -217,6 +233,8 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd, | ... | @@ -217,6 +233,8 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd, |
217 | size_t min_output_size = MU_FILTER_BUF_SIZE; | 233 | size_t min_output_size = MU_FILTER_BUF_SIZE; |
218 | size_t total = 0; | 234 | size_t total = 0; |
219 | int rc = 0; | 235 | int rc = 0; |
236 | int again; | ||
237 | int stop = 0; | ||
220 | 238 | ||
221 | do | 239 | do |
222 | { | 240 | { |
... | @@ -249,19 +267,22 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd, | ... | @@ -249,19 +267,22 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd, |
249 | res = fs->xcode (fs->xdata, cmd, &iobuf); | 267 | res = fs->xcode (fs->xdata, cmd, &iobuf); |
250 | switch (res) | 268 | switch (res) |
251 | { | 269 | { |
270 | case mu_filter_again: | ||
271 | if (++again > MU_FILTER_MAX_AGAIN) | ||
272 | { | ||
273 | /* FIXME: What filter? Need some id. */ | ||
274 | mu_error (_("filter returned `again' too many times")); | ||
275 | again = 0; | ||
276 | } | ||
277 | break; | ||
278 | |||
252 | case mu_filter_ok: | 279 | case mu_filter_ok: |
253 | if (iobuf.isize == 0 || iobuf.osize == 0) | 280 | again = 0; |
281 | if (cmd == mu_filter_lastbuf || iobuf.eof) | ||
254 | { | 282 | { |
255 | /* FIXME: Hack to handle eventual buggy filters */ | 283 | _mu_stream_seteof (stream); |
256 | if (iobuf.isize == 0) | 284 | stop = 1; |
257 | min_input_level++; | ||
258 | if (iobuf.osize == 0) | ||
259 | min_output_size++; | ||
260 | continue; | ||
261 | } | 285 | } |
262 | if (iobuf.isize > MFB_RDBYTES (fs->inbuf) | ||
263 | || iobuf.osize > MFB_FREESIZE (fs->outbuf)) | ||
264 | return MU_ERR_FAILURE; /* FIXME: special error code? */ | ||
265 | break; | 286 | break; |
266 | 287 | ||
267 | case mu_filter_falure: | 288 | case mu_filter_falure: |
... | @@ -276,24 +297,26 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd, | ... | @@ -276,24 +297,26 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd, |
276 | continue; | 297 | continue; |
277 | } | 298 | } |
278 | 299 | ||
300 | if (iobuf.isize > MFB_RDBYTES (fs->inbuf) | ||
301 | || iobuf.osize > MFB_FREESIZE (fs->outbuf)) | ||
302 | return MU_ERR_FAILURE; /* FIXME: special error code? */ | ||
303 | |||
279 | /* iobuf.osize contains number of bytes written to output */ | 304 | /* iobuf.osize contains number of bytes written to output */ |
280 | MFB_advance_level (&fs->outbuf, iobuf.osize); | 305 | MFB_advance_level (&fs->outbuf, iobuf.osize); |
281 | 306 | ||
282 | /* iobuf.isize contains number of bytes read from input */ | 307 | /* iobuf.isize contains number of bytes read from input */ |
283 | MFB_advance_pos (&fs->inbuf, iobuf.isize); | 308 | MFB_advance_pos (&fs->inbuf, iobuf.isize); |
284 | 309 | ||
285 | rdsize = size - total; | ||
286 | if (rdsize > MFB_RDBYTES (fs->outbuf)) | ||
287 | rdsize = MFB_RDBYTES (fs->outbuf); | ||
288 | |||
289 | rc = mu_stream_write (fs->transport, | 310 | rc = mu_stream_write (fs->transport, |
290 | MFB_CURPTR (fs->outbuf), MFB_RDBYTES (fs->outbuf), | 311 | MFB_CURPTR (fs->outbuf), |
312 | MFB_RDBYTES (fs->outbuf), | ||
291 | &rdsize); | 313 | &rdsize); |
292 | MFB_advance_pos (&fs->outbuf, rdsize); | 314 | if (rc == 0) |
293 | if (rc) | 315 | MFB_advance_pos (&fs->outbuf, rdsize); |
316 | else | ||
294 | break; | 317 | break; |
295 | } | 318 | } |
296 | while (MFB_RDBYTES (fs->outbuf)); | 319 | while (!stop && (MFB_RDBYTES (fs->outbuf) || again)); |
297 | if (pret) | 320 | if (pret) |
298 | *pret = total; | 321 | *pret = total; |
299 | else if (total < size && rc == 0) | 322 | else if (total < size && rc == 0) |
... | @@ -311,7 +334,8 @@ static int | ... | @@ -311,7 +334,8 @@ static int |
311 | filter_wr_flush (mu_stream_t stream) | 334 | filter_wr_flush (mu_stream_t stream) |
312 | { | 335 | { |
313 | struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream; | 336 | struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream; |
314 | int rc = filter_write_internal (stream, mu_filter_lastbuf, NULL, 0, NULL); | 337 | size_t dummy; |
338 | int rc = filter_write_internal (stream, mu_filter_flush, NULL, 0, &dummy); | ||
315 | if (rc == 0) | 339 | if (rc == 0) |
316 | rc = mu_stream_flush (fs->transport); | 340 | rc = mu_stream_flush (fs->transport); |
317 | return rc; | 341 | return rc; |
... | @@ -380,6 +404,8 @@ static int | ... | @@ -380,6 +404,8 @@ static int |
380 | filter_close (mu_stream_t stream) | 404 | filter_close (mu_stream_t stream) |
381 | { | 405 | { |
382 | struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream; | 406 | struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream; |
407 | size_t dummy; | ||
408 | int rc = filter_write_internal (stream, mu_filter_lastbuf, NULL, 0, &dummy); | ||
383 | MBF_CLEAR (fs->inbuf); | 409 | MBF_CLEAR (fs->inbuf); |
384 | MBF_CLEAR (fs->outbuf); | 410 | MBF_CLEAR (fs->outbuf); |
385 | return mu_stream_close (fs->transport); | 411 | return mu_stream_close (fs->transport); | ... | ... |
... | @@ -380,10 +380,10 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence, | ... | @@ -380,10 +380,10 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence, |
380 | input operations. | 380 | input operations. |
381 | 381 | ||
382 | This function is designed to help implement seek method in otherwise | 382 | This function is designed to help implement seek method in otherwise |
383 | unseekable streams (such as filters). Do not use it if you absolutely | 383 | unseekable streams (such as filters). Do not use it unless you absolutely |
384 | have to. Using it on an unbuffered stream is a terrible waste of CPU. */ | 384 | have to. Using it on an unbuffered stream is a terrible waste of CPU. */ |
385 | int | 385 | static int |
386 | mu_stream_skip_input_bytes (mu_stream_t stream, mu_off_t count, mu_off_t *pres) | 386 | _stream_skip_input_bytes (mu_stream_t stream, mu_off_t count, mu_off_t *pres) |
387 | { | 387 | { |
388 | mu_off_t pos; | 388 | mu_off_t pos; |
389 | int rc; | 389 | int rc; |
... | @@ -439,6 +439,22 @@ mu_stream_skip_input_bytes (mu_stream_t stream, mu_off_t count, mu_off_t *pres) | ... | @@ -439,6 +439,22 @@ mu_stream_skip_input_bytes (mu_stream_t stream, mu_off_t count, mu_off_t *pres) |
439 | return rc; | 439 | return rc; |
440 | } | 440 | } |
441 | 441 | ||
442 | /* A wrapper for the above function. It is normally called from a | ||
443 | seek method implementation, so it makes sure the MU_STREAM_SEEK | ||
444 | is cleared while in _stream_skip_input_bytes, to avoid infitite | ||
445 | recursion that may be triggered by _stream_flush_buffer invoking | ||
446 | stream->seek. */ | ||
447 | int | ||
448 | mu_stream_skip_input_bytes (mu_stream_t stream, mu_off_t count, mu_off_t *pres) | ||
449 | { | ||
450 | int rc; | ||
451 | int seek_flag = stream->flags & MU_STREAM_SEEK; | ||
452 | stream->flags &= ~MU_STREAM_SEEK; | ||
453 | rc = _stream_skip_input_bytes (stream, count, pres); | ||
454 | stream->flags |= seek_flag; | ||
455 | return rc; | ||
456 | } | ||
457 | |||
442 | int | 458 | int |
443 | mu_stream_set_buffer (mu_stream_t stream, enum mu_buffer_type type, | 459 | mu_stream_set_buffer (mu_stream_t stream, enum mu_buffer_type type, |
444 | size_t size) | 460 | size_t size) | ... | ... |
-
Please register or sign in to post a comment