Fixed several bugs. Use an extra argument to filter_iconv_create to decide what …
…to do if conversion fails (mu_iconv_fallback_mode).
Showing
1 changed file
with
55 additions
and
53 deletions
... | @@ -50,24 +50,24 @@ | ... | @@ -50,24 +50,24 @@ |
50 | 50 | ||
51 | enum _icvt_state | 51 | enum _icvt_state |
52 | { | 52 | { |
53 | state_closed, | 53 | state_closed, /* Filter is closed */ |
54 | state_open, | 54 | state_open, /* Filter is open and running in conversion mode */ |
55 | state_literal, | 55 | state_copy_pass, /* Filter is open and running in copy-pass mode */ |
56 | state_octal, | 56 | state_copy_octal, /* Filter is open and running in copy-octal mode */ |
57 | state_iconv_error, | 57 | state_iconv_error, /* A fatal iconv error has occurred */ |
58 | state_transport_error | 58 | state_transport_error /* A fatal transport error has occurred */ |
59 | }; | 59 | }; |
60 | 60 | ||
61 | struct icvt_stream | 61 | struct icvt_stream |
62 | { | 62 | { |
63 | stream_t stream; /* I/O stream */ | 63 | stream_t stream; /* I/O stream */ |
64 | int fallback_mode; | ||
64 | iconv_t cd; /* Conversion descriptor */ | 65 | iconv_t cd; /* Conversion descriptor */ |
65 | char *buf; /* Conversion buffer */ | 66 | char *buf; /* Conversion buffer */ |
66 | size_t bufsize; /* Size of buf */ | 67 | size_t bufsize; /* Size of buf */ |
67 | size_t bufpos; /* Current position in buf */ | 68 | size_t bufpos; /* Current position in buf */ |
68 | enum _icvt_state state; | 69 | enum _icvt_state state; |
69 | int ec; /* Error code */ | 70 | int ec; /* Error code */ |
70 | char ICONV_CONST *errp; /* Offending input if state == state_iconv_error */ | ||
71 | char errbuf[128]; /* Error message buffer */ | 71 | char errbuf[128]; /* Error message buffer */ |
72 | }; | 72 | }; |
73 | 73 | ||
... | @@ -123,8 +123,9 @@ internal_icvt_read (stream_t stream, char *optr, size_t osize, size_t *pnbytes) | ... | @@ -123,8 +123,9 @@ internal_icvt_read (stream_t stream, char *optr, size_t osize, size_t *pnbytes) |
123 | { | 123 | { |
124 | struct icvt_stream *s = stream_get_owner (stream); | 124 | struct icvt_stream *s = stream_get_owner (stream); |
125 | size_t nbytes = 0; | 125 | size_t nbytes = 0; |
126 | size_t cvtbytes = 0; | 126 | int rc, status = 0; |
127 | int rc, status; | 127 | char *ob = optr; |
128 | size_t olen = osize; | ||
128 | 129 | ||
129 | if (s->bufpos == 0) | 130 | if (s->bufpos == 0) |
130 | { | 131 | { |
... | @@ -147,21 +148,22 @@ internal_icvt_read (stream_t stream, char *optr, size_t osize, size_t *pnbytes) | ... | @@ -147,21 +148,22 @@ internal_icvt_read (stream_t stream, char *optr, size_t osize, size_t *pnbytes) |
147 | { | 148 | { |
148 | char ICONV_CONST *ib = s->buf; | 149 | char ICONV_CONST *ib = s->buf; |
149 | size_t inlen = s->bufpos + nbytes; | 150 | size_t inlen = s->bufpos + nbytes; |
150 | char *ob = optr + cvtbytes; | ||
151 | size_t olen = osize - cvtbytes; | ||
152 | 151 | ||
153 | rc = iconv (s->cd, &ib, &inlen, &ob, &olen); | 152 | rc = iconv (s->cd, &ib, &inlen, &ob, &olen); |
154 | cvtbytes += ib - s->buf; | 153 | if (ib > s->buf) |
154 | { | ||
155 | memmove (s->buf, ib, inlen); | ||
156 | s->bufpos = inlen; | ||
157 | } | ||
158 | else | ||
159 | s->bufpos += nbytes; | ||
160 | |||
155 | if (rc == -1) | 161 | if (rc == -1) |
156 | { | 162 | { |
157 | if (errno == E2BIG) | 163 | if (errno == E2BIG) |
158 | { | 164 | { |
159 | if (cvtbytes) | 165 | if (ob > optr) |
160 | { | 166 | break; |
161 | memmove (s->buf, ib, inlen); | ||
162 | s->bufpos = inlen; | ||
163 | break; | ||
164 | } | ||
165 | else | 167 | else |
166 | { | 168 | { |
167 | s->ec = MU_ERR_BUFSPACE; | 169 | s->ec = MU_ERR_BUFSPACE; |
... | @@ -172,22 +174,24 @@ internal_icvt_read (stream_t stream, char *optr, size_t osize, size_t *pnbytes) | ... | @@ -172,22 +174,24 @@ internal_icvt_read (stream_t stream, char *optr, size_t osize, size_t *pnbytes) |
172 | { | 174 | { |
173 | int flags = 0; | 175 | int flags = 0; |
174 | stream_get_flags (stream, &flags); | 176 | stream_get_flags (stream, &flags); |
175 | if (flags & MU_STREAM_STRICT) | 177 | switch (s->fallback_mode) |
176 | { | 178 | { |
179 | case mu_fallback_none: | ||
177 | s->state = state_iconv_error; | 180 | s->state = state_iconv_error; |
178 | s->ec = errno; | 181 | s->ec = errno; |
179 | s->errp = ib; | 182 | if (ob == optr) |
180 | if (cvtbytes) | ||
181 | break; | ||
182 | else | ||
183 | return MU_ERR_FAILURE; | 183 | return MU_ERR_FAILURE; |
184 | } | 184 | break; |
185 | else | 185 | |
186 | { | 186 | case mu_fallback_copy_pass: |
187 | s->state = state_octal; | 187 | s->state = state_copy_pass; |
188 | memmove (s->buf, ib, inlen); | 188 | if (ob == optr) |
189 | s->bufpos = inlen; | 189 | return _icvt_read (stream, optr, osize, 0, pnbytes); |
190 | if (cvtbytes == 0) | 190 | break; |
191 | |||
192 | case mu_fallback_copy_octal: | ||
193 | s->state = state_copy_octal; | ||
194 | if (ob == optr) | ||
191 | return _icvt_read (stream, optr, osize, 0, pnbytes); | 195 | return _icvt_read (stream, optr, osize, 0, pnbytes); |
192 | break; | 196 | break; |
193 | } | 197 | } |
... | @@ -199,16 +203,9 @@ internal_icvt_read (stream_t stream, char *optr, size_t osize, size_t *pnbytes) | ... | @@ -199,16 +203,9 @@ internal_icvt_read (stream_t stream, char *optr, size_t osize, size_t *pnbytes) |
199 | /* Try to reallocate temp buffer */ | 203 | /* Try to reallocate temp buffer */ |
200 | char *p = realloc (s->buf, s->bufsize + 128); | 204 | char *p = realloc (s->buf, s->bufsize + 128); |
201 | if (!p) | 205 | if (!p) |
202 | { | 206 | return ENOMEM; |
203 | /* Rearrange the buffer anyway */ | ||
204 | memmove (s->buf, ib, inlen); | ||
205 | s->bufpos = inlen; | ||
206 | return ENOMEM; | ||
207 | } | ||
208 | s->bufsize += 128; | 207 | s->bufsize += 128; |
209 | } | 208 | } |
210 | memmove (s->buf, ib, inlen); | ||
211 | s->bufpos = inlen; | ||
212 | continue; | 209 | continue; |
213 | } | 210 | } |
214 | else | 211 | else |
... | @@ -219,7 +216,7 @@ internal_icvt_read (stream_t stream, char *optr, size_t osize, size_t *pnbytes) | ... | @@ -219,7 +216,7 @@ internal_icvt_read (stream_t stream, char *optr, size_t osize, size_t *pnbytes) |
219 | } | 216 | } |
220 | } | 217 | } |
221 | } | 218 | } |
222 | while (cvtbytes < osize | 219 | while (olen > 0 |
223 | && (status = stream_sequential_read (s->stream, | 220 | && (status = stream_sequential_read (s->stream, |
224 | s->buf + s->bufpos, | 221 | s->buf + s->bufpos, |
225 | s->bufsize - s->bufpos, | 222 | s->bufsize - s->bufpos, |
... | @@ -229,20 +226,20 @@ internal_icvt_read (stream_t stream, char *optr, size_t osize, size_t *pnbytes) | ... | @@ -229,20 +226,20 @@ internal_icvt_read (stream_t stream, char *optr, size_t osize, size_t *pnbytes) |
229 | if (status) | 226 | if (status) |
230 | { | 227 | { |
231 | s->state = state_transport_error; | 228 | s->state = state_transport_error; |
232 | s->ec = rc; | 229 | s->ec = status; |
233 | if (!cvtbytes) | 230 | if (ob == optr) |
234 | return MU_ERR_FAILURE; | 231 | return MU_ERR_FAILURE; |
235 | } | 232 | } |
236 | 233 | ||
237 | if (*pnbytes) | 234 | if (*pnbytes) |
238 | *pnbytes = cvtbytes; | 235 | *pnbytes = ob - optr; |
239 | return 0; | 236 | return 0; |
240 | } | 237 | } |
241 | 238 | ||
242 | #define ISPRINT(c) ((c)>=' '&&(c)<127) | 239 | #define ISPRINT(c) (((c)>=' '&&(c)<127)||c=='\n') |
243 | 240 | ||
244 | static int | 241 | static int |
245 | octal_icvt_read (struct icvt_stream *s, char *optr, size_t osize, size_t *pnbytes) | 242 | copy_octal (struct icvt_stream *s, char *optr, size_t osize, size_t *pnbytes) |
246 | { | 243 | { |
247 | size_t i, j; | 244 | size_t i, j; |
248 | int status; | 245 | int status; |
... | @@ -263,7 +260,9 @@ octal_icvt_read (struct icvt_stream *s, char *optr, size_t osize, size_t *pnbyte | ... | @@ -263,7 +260,9 @@ octal_icvt_read (struct icvt_stream *s, char *optr, size_t osize, size_t *pnbyte |
263 | rdcount = s->bufsize; | 260 | rdcount = s->bufsize; |
264 | } | 261 | } |
265 | 262 | ||
266 | status = stream_sequential_read (s->stream, s->buf, rdcount - s->bufpos, | 263 | status = stream_sequential_read (s->stream, |
264 | s->buf + s->bufpos, | ||
265 | rdcount - s->bufpos, | ||
267 | &rdcount); | 266 | &rdcount); |
268 | if (status) | 267 | if (status) |
269 | { | 268 | { |
... | @@ -276,7 +275,7 @@ octal_icvt_read (struct icvt_stream *s, char *optr, size_t osize, size_t *pnbyte | ... | @@ -276,7 +275,7 @@ octal_icvt_read (struct icvt_stream *s, char *optr, size_t osize, size_t *pnbyte |
276 | s->bufpos += rdcount; | 275 | s->bufpos += rdcount; |
277 | } | 276 | } |
278 | 277 | ||
279 | for (i = j = 0; i < osize && j < s->bufpos; i++) | 278 | for (i = j = 0; j < osize && i < s->bufpos; i++) |
280 | { | 279 | { |
281 | if (ISPRINT (*(unsigned char*)(s->buf+i))) | 280 | if (ISPRINT (*(unsigned char*)(s->buf+i))) |
282 | optr[j++] = s->buf[i]; | 281 | optr[j++] = s->buf[i]; |
... | @@ -296,7 +295,7 @@ octal_icvt_read (struct icvt_stream *s, char *optr, size_t osize, size_t *pnbyte | ... | @@ -296,7 +295,7 @@ octal_icvt_read (struct icvt_stream *s, char *optr, size_t osize, size_t *pnbyte |
296 | } | 295 | } |
297 | 296 | ||
298 | static int | 297 | static int |
299 | literal_icvt_read (struct icvt_stream *s, char *optr, size_t osize, size_t *pnbytes) | 298 | copy_pass (struct icvt_stream *s, char *optr, size_t osize, size_t *pnbytes) |
300 | { | 299 | { |
301 | int status; | 300 | int status; |
302 | size_t nbytes; | 301 | size_t nbytes; |
... | @@ -340,11 +339,11 @@ _icvt_read (stream_t stream, char *optr, size_t osize, | ... | @@ -340,11 +339,11 @@ _icvt_read (stream_t stream, char *optr, size_t osize, |
340 | case state_closed: | 339 | case state_closed: |
341 | return EINVAL; | 340 | return EINVAL; |
342 | 341 | ||
343 | case state_literal: | 342 | case state_copy_pass: |
344 | return literal_icvt_read (s, optr, osize, pnbytes); | 343 | return copy_pass (s, optr, osize, pnbytes); |
345 | 344 | ||
346 | case state_octal: | 345 | case state_copy_octal: |
347 | return octal_icvt_read (s, optr, osize, pnbytes); | 346 | return copy_octal (s, optr, osize, pnbytes); |
348 | 347 | ||
349 | default: | 348 | default: |
350 | break; | 349 | break; |
... | @@ -369,7 +368,8 @@ _icvt_strerror (stream_t stream, char **pstr) | ... | @@ -369,7 +368,8 @@ _icvt_strerror (stream_t stream, char **pstr) |
369 | { | 368 | { |
370 | case EILSEQ: | 369 | case EILSEQ: |
371 | snprintf (s->errbuf, sizeof s->errbuf, | 370 | snprintf (s->errbuf, sizeof s->errbuf, |
372 | _("Illegal multibyte sequence near %s"), s->errp); | 371 | _("Illegal multibyte sequence near %*.*s"), |
372 | s->bufpos, s->bufpos, s->buf); | ||
373 | break; | 373 | break; |
374 | 374 | ||
375 | default: | 375 | default: |
... | @@ -411,7 +411,8 @@ _icvt_wait (stream_t stream, int *pflags, struct timeval *tvp) | ... | @@ -411,7 +411,8 @@ _icvt_wait (stream_t stream, int *pflags, struct timeval *tvp) |
411 | 411 | ||
412 | int | 412 | int |
413 | filter_iconv_create (stream_t *s, stream_t transport, | 413 | filter_iconv_create (stream_t *s, stream_t transport, |
414 | char *fromcode, char *tocode, int flags) | 414 | const char *fromcode, const char *tocode, int flags, |
415 | enum mu_iconv_fallback_mode fallback_mode) | ||
415 | { | 416 | { |
416 | struct icvt_stream *iptr; | 417 | struct icvt_stream *iptr; |
417 | iconv_t cd; | 418 | iconv_t cd; |
... | @@ -425,6 +426,7 @@ filter_iconv_create (stream_t *s, stream_t transport, | ... | @@ -425,6 +426,7 @@ filter_iconv_create (stream_t *s, stream_t transport, |
425 | if (!iptr) | 426 | if (!iptr) |
426 | return ENOMEM; | 427 | return ENOMEM; |
427 | iptr->stream = transport; | 428 | iptr->stream = transport; |
429 | iptr->fallback_mode = fallback_mode; | ||
428 | iptr->cd = cd; | 430 | iptr->cd = cd; |
429 | iptr->state = state_closed; | 431 | iptr->state = state_closed; |
430 | iptr->bufsize = 128; | 432 | iptr->bufsize = 128; | ... | ... |
-
Please register or sign in to post a comment