diff options
-rw-r--r-- | camel/ChangeLog | 7 | ||||
-rw-r--r-- | camel/camel-mime-part-utils.c | 107 |
2 files changed, 68 insertions, 46 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog index 7d334da54a..de92871e4d 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,10 @@ +2002-04-10 Jeffrey Stedfast <fejj@ximian.com> + + * camel-mime-part-utils.c (convert_buffer): Fixed a bug that would + miscalculate how much data to copy into the GByteArray (negative + value) thus causing a segfault. Also optimized it while I was at + it. + 2002-04-09 Jeffrey Stedfast <fejj@ximian.com> * camel-store.c (camel_store_init): Make the folder_lock diff --git a/camel/camel-mime-part-utils.c b/camel/camel-mime-part-utils.c index 024eec091e..19f58bf1d2 100644 --- a/camel/camel-mime-part-utils.c +++ b/camel/camel-mime-part-utils.c @@ -102,59 +102,74 @@ check_html_charset(char *buffer, int length) static GByteArray * convert_buffer (GByteArray *in, const char *to, const char *from) { - iconv_t ic; - size_t inlen, outlen; - char *inbuf, *outbuf; - char *buffer; + size_t inleft, outleft, outlen, converted = 0; GByteArray *out = NULL; - int i = 2; - + const char *inbuf; + char *outbuf; + iconv_t cd; + d(printf("converting buffer from %s to %s: '%.*s'\n", from, to, (int)in->len, in->data)); - - ic = e_iconv_open(to, from); - if (ic == (iconv_t) -1) { - g_warning("Cannot convert from '%s' to '%s': %s", from, to, strerror(errno)); + + cd = e_iconv_open(to, from); + if (cd == (iconv_t) -1) { + g_warning ("Cannot convert from '%s' to '%s': %s", from, to, g_strerror (errno)); return NULL; } - + + outlen = in->len * 2 + 16; + out = g_byte_array_new (); + g_byte_array_set_size (out, outlen); + + inbuf = in->data; + inleft = in->len; + do { - /* make plenty of space? */ - outlen = in->len * i + 16; - buffer = g_malloc(outlen); - - inbuf = in->data; - inlen = in->len; - outbuf = buffer; - - if (e_iconv(ic, (const char **)&inbuf, &inlen, &outbuf, &outlen) == (size_t) -1) { - g_free(buffer); - g_warning("conversion failed: %s", strerror(errno)); - /* we didn't have enough space */ - if (errno == E2BIG && i<6) { - i++; - continue; - } - break; + outbuf = out->data + converted; + outleft = outlen - converted; + + converted = e_iconv (cd, &inbuf, &inleft, &outbuf, &outleft); + if (converted == (size_t) -1) { + if (errno != E2BIG && errno != EINVAL) + goto fail; } - - out = g_byte_array_new(); - g_byte_array_append(out, buffer, (in->len*i+16) - outlen); - - /* close off the conversion */ - outbuf = buffer; - outlen = in->len * i + 16; - if (e_iconv(ic, NULL, 0, &outbuf, &outlen) != (size_t) -1) - g_byte_array_append(out, buffer, (in->len*i+16) - outlen); - g_free(buffer); - - d(printf("converted: '%.*s'\n", (int)out->len, out->data)); - - break; - } while (1); - - e_iconv_close(ic); - + + /* + * E2BIG There is not sufficient room at *outbuf. + * + * We just need to grow our outbuffer and try again. + */ + + converted = outlen - outleft; + if (errno == E2BIG) { + outlen += inleft * 2 + 16; + out = g_byte_array_set_size (out, outlen); + outbuf = out->data + converted; + } + + } while (errno == E2BIG && inleft > 0); + + /* + * EINVAL An incomplete multibyte sequence has been encoun + * tered in the input. + * + * We'll just have to ignore it... + */ + + /* flush the iconv conversion */ + e_iconv (cd, NULL, NULL, &outbuf, &outleft); + + e_iconv_close (cd); + return out; + + fail: + g_warning ("Cannot convert from '%s' to '%s': %s", from, to, g_strerror (errno)); + + g_byte_array_free (out, TRUE); + + e_iconv_close (cd); + + return NULL; } /* We don't really use the charset argument except for debugging... */ |