Commit c563f0a8 c563f0a80b6bddb7a9125f1cb7b0d7cc6a057d46 by Sergey Poznyakoff

Fixed several bugs. Use an extra argument to filter_iconv_create to decide what …

…to do if conversion fails (mu_iconv_fallback_mode).
1 parent 9696cfac
...@@ -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 {
161 memmove (s->buf, ib, inlen);
162 s->bufpos = inlen;
163 break; 166 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 {
203 /* Rearrange the buffer anyway */
204 memmove (s->buf, ib, inlen);
205 s->bufpos = inlen;
206 return ENOMEM; 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;
......