diff --git a/ChangeLog b/ChangeLog index 3d1bf4e60f..43896da428 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2013-05-29 Mike Blumenkrantz + + * Added eina_str_convert_len() to work around broken eina_str_convert() + 2013-05-28 ChunEon Park (Hermet) * Fix textblock to render pre again if it needs to relayouting. diff --git a/NEWS b/NEWS index dcf157a2bf..1e75370f40 100644 --- a/NEWS +++ b/NEWS @@ -25,6 +25,7 @@ Additions: - Add eina_log_timing() - Add eina_inlist_first - Add eina_inlist_last + - Added eina_str_convert_len() to work around broken eina_str_convert() * Add Cserve2 scalecache support * ecore_x: - Add window profile support. diff --git a/src/lib/eina/eina_str.c b/src/lib/eina/eina_str.c index b6b0d9e2c9..1b4d0dcab3 100644 --- a/src/lib/eina/eina_str.c +++ b/src/lib/eina/eina_str.c @@ -525,6 +525,77 @@ eina_str_convert(const char *enc_from EINA_UNUSED, } #endif +#ifdef HAVE_ICONV +EAPI char * +eina_str_convert_len(const char *enc_from, const char *enc_to, const char *text, size_t len, size_t *retlen) +{ + iconv_t ic; + char *new_txt, *inp, *outp; + size_t inb, outb, outlen, tob, outalloc; + + if (retlen) *retlen = 0; + if (!text) return NULL; + + ic = iconv_open(enc_to, enc_from); + if (ic == (iconv_t)(-1)) + return NULL; + + new_txt = malloc(64); + inb = len; + outb = 64; + inp = (char *)text; + outp = new_txt; + outalloc = 64; + outlen = 0; + + for (;; ) + { + size_t count; + + tob = outb; + count = iconv(ic, &inp, &inb, &outp, &outb); + outlen += tob - outb; + if (count == (size_t)(-1)) + { + if (errno == E2BIG) + { + new_txt = realloc(new_txt, outalloc + 64); + outp = new_txt + outlen; + outalloc += 64; + outb += 64; + } + else + { + if (new_txt) + free(new_txt); + + new_txt = NULL; + break; + } + } + + if (inb == 0) + { + if (outalloc == outlen) + new_txt = realloc(new_txt, outalloc + 1); + + new_txt[outlen] = 0; + break; + } + } + iconv_close(ic); + if (retlen) *retlen = outlen; + return new_txt; +} +#else +EAPI char * +eina_str_convert_len(const char *enc_from EINA_UNUSED, const char *enc_to EINA_UNUSED, const char *text EINA_UNUSED, size_t len EINA_UNUSED, size_t *retlen) +{ + if (retlen) *retlen = 0; + return NULL; +} +#endif + EAPI char * eina_str_escape(const char *str) { diff --git a/src/lib/eina/eina_str.h b/src/lib/eina/eina_str.h index f199a9a6dc..e083ec036f 100644 --- a/src/lib/eina/eina_str.h +++ b/src/lib/eina/eina_str.h @@ -260,9 +260,31 @@ EAPI size_t eina_str_join_len(char *dst, size_t size, char sep, const c * failure, @c NULL is returned. Iconv is used to convert @p text. If * Iconv is not available, @c NULL is returned. When not used anymore, * the returned value must be freed. + * + * @warning This function is guaranteed to break when '\0' characters are in @p text. + * DO NOT USE THIS FUNCTION IF YOUR TEXT CONTAINS NON-TERMINATING '\0' CHARACTERS. */ EAPI char *eina_str_convert(const char *enc_from, const char *enc_to, const char *text) EINA_WARN_UNUSED_RESULT EINA_MALLOC EINA_ARG_NONNULL(1, 2, 3); +/** + * @brief Use Iconv to convert a text string from one encoding to another. + * + * @param enc_from Encoding to convert from. + * @param enc_to Encoding to convert to. + * @param text The text to convert. + * @param text The length of the text to convert. + * @return The converted text. + * + * This function converts @p text, encoded in @p enc_from. On success, + * the converted text is returned and is encoded in @p enc_to. On + * failure, @c NULL is returned. Iconv is used to convert @p text. If + * Iconv is not available, @c NULL is returned. When not used anymore, + * the returned value must be freed. + * + * @since 1.8 + */ +EAPI char *eina_str_convert_len(const char *enc_from, const char *enc_to, const char *text, size_t len, size_t *retlen) EINA_WARN_UNUSED_RESULT EINA_MALLOC EINA_ARG_NONNULL(1, 2, 3); + /** * @brief Escape slashes, spaces and apostrophes in strings.