add eina_str_convert_len() for converting from encodings which contain '\0' characters

eina_str_convert() is GUARANTEED to break when doing any such encoding (eg. UTF16->UTF8). I don't know who added the original function, but this is very bad, and we should almost certainly deprecate eina_str_convert() so people are not surprised when they are unable to convert strings as expected.
This commit is contained in:
Mike Blumenkrantz 2013-05-29 12:42:37 +01:00
parent 6a4cdea904
commit 37aa26b977
4 changed files with 98 additions and 0 deletions

View File

@ -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.

1
NEWS
View File

@ -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.

View File

@ -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)
{

View File

@ -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.