Index: src/af/util/xp/ut_iconv.cpp =================================================================== RCS file: /cvsroot/abi/src/af/util/xp/ut_iconv.cpp,v retrieving revision 1.18 diff -u -r1.18 ut_iconv.cpp --- src/af/util/xp/ut_iconv.cpp 2001/12/11 18:47:47 1.18 +++ src/af/util/xp/ut_iconv.cpp 2002/02/04 22:34:54 @@ -156,7 +156,7 @@ // while some (newer, conformant ones) do if ( !UT_iconv_isValid ( cd ) ) - return -1; + return (size_t)-1; ICONV_CONST char ** buf = (ICONV_CONST char**)(inbuf); return iconv( cd, buf, inbytesleft, outbuf, outbytesleft ); @@ -210,6 +210,34 @@ return NULL; } + UT_iconv_t cd = INVALID_ICONV_HANDLE; + UT_TRY + { + auto_iconv converter(from_codeset, to_codeset); + cd = converter.getHandle(); + return UT_convert(str, len, cd, bytes_read_arg, bytes_written_arg); + } + UT_CATCH(UT_CATCH_ANY) + { + if (bytes_read_arg) + *bytes_read_arg = 0; + if (bytes_written_arg) + *bytes_written_arg = 0; + return NULL; + } + UT_END_CATCH +} + +/*! This function is almost the same as the other UT_convert function, + * only that it takes an UT_iconv_t instead of a from and to codeset. + * This is useful if you need to do a conversion multiple times + */ +char * UT_convert(const char *str, + UT_sint32 len, + UT_iconv_t cd, + UT_uint32 *bytes_read_arg, + UT_uint32 *bytes_written_arg) +{ // The following two variables are used to be used in absence of given arguments // (to not have to check for NULL pointers upon assignment). UT_uint32 bytes_read_local; @@ -218,114 +246,99 @@ UT_uint32& bytes_read = bytes_read_arg ? *bytes_read_arg : bytes_read_local; UT_uint32& bytes_written = bytes_written_arg ? *bytes_written_arg : bytes_written_local; - UT_iconv_t cd = INVALID_ICONV_HANDLE; - - UT_TRY + if (len < 0) { - auto_iconv converter(from_codeset, to_codeset); - cd = converter.getHandle(); + len = strlen(str); + } - if (len < 0) - { - len = strlen(str); - } + const char* p = str; + size_t inbytes_remaining = len; - const char* p = str; - size_t inbytes_remaining = len; + /* Due to a GLIBC bug, round outbuf_size up to a multiple of 4 */ + /* + 1 for nul in case len == 1 */ + size_t outbuf_size = ((len + 3) & ~3) + 15; + size_t outbytes_remaining = outbuf_size - 1; /* -1 for nul */ - /* Due to a GLIBC bug, round outbuf_size up to a multiple of 4 */ - /* + 1 for nul in case len == 1 */ - size_t outbuf_size = ((len + 3) & ~3) + 15; - size_t outbytes_remaining = outbuf_size - 1; /* -1 for nul */ + char* pDest = (char*)malloc(outbuf_size); + char* outp = pDest; - char* pDest = (char*)malloc(outbuf_size); - char* outp = pDest; + bool have_error = false; + bool bAgain = true; - bool have_error = false; - bool bAgain = true; + while (bAgain) + { + size_t err = UT_iconv(cd, + &p, + &inbytes_remaining, + &outp, &outbytes_remaining); - while (bAgain) + if (err == (size_t) -1) { - size_t err = UT_iconv(cd, - &p, - &inbytes_remaining, - &outp, &outbytes_remaining); - - if (err == (size_t) -1) - { - switch (errno) - { - case EINVAL: - /* Incomplete text, do not report an error */ - bAgain = false; - break; - case E2BIG: - { - size_t used = outp - pDest; - - /* glibc's iconv can return E2BIG even if there is space - * remaining if an internal buffer is exhausted. The - * folllowing is a heuristic to catch this. The 16 is - * pretty arbitrary. - */ - if (used + 16 > outbuf_size) - { - outbuf_size = outbuf_size + 15; - pDest = (char*)realloc(pDest, outbuf_size); - - outp = pDest + used; - outbytes_remaining = outbuf_size - used - 1; /* -1 for nul */ - } - - bAgain = true; - break; - } - default: - have_error = true; - bAgain = false; - break; - } - } - else + switch (errno) { + case EINVAL: + /* Incomplete text, do not report an error */ + bAgain = false; + break; + case E2BIG: + { + size_t used = outp - pDest; + + /* glibc's iconv can return E2BIG even if there is space + * remaining if an internal buffer is exhausted. The + * folllowing is a heuristic to catch this. The 16 is + * pretty arbitrary. + */ + if (used + 16 > outbuf_size) + { + outbuf_size = outbuf_size + 15; + pDest = (char*)realloc(pDest, outbuf_size); + + outp = pDest + used; + outbytes_remaining = outbuf_size - used - 1; /* -1 for nul */ + } + + bAgain = true; + break; + } + default: + have_error = true; bAgain = false; + break; } } - - *outp = '\0'; - - const size_t nNewLen = p - str; - - if (bytes_read_arg) - { - bytes_read = nNewLen; - } - else + else { - if (nNewLen != len) - { - have_error = true; - } + bAgain = false; } + } + + *outp = '\0'; - bytes_written = outp - pDest; /* Doesn't include '\0' */ + const size_t nNewLen = p - str; - if (have_error && pDest) + if (bytes_read_arg) + { + bytes_read = nNewLen; + } + else + { + if (nNewLen != len) { - free(pDest); + have_error = true; } + } - if (have_error) - return NULL; + bytes_written = outp - pDest; /* Doesn't include '\0' */ - return pDest; - } - UT_CATCH(UT_CATCH_ANY) + if (have_error && pDest) { - bytes_read = 0; - bytes_written = 0; - return NULL; + free(pDest); } - UT_END_CATCH + + if (have_error) + return NULL; + + return pDest; } Index: src/af/util/xp/ut_iconv.h =================================================================== RCS file: /cvsroot/abi/src/af/util/xp/ut_iconv.h,v retrieving revision 1.10 diff -u -r1.10 ut_iconv.h --- src/af/util/xp/ut_iconv.h 2001/09/28 15:29:44 1.10 +++ src/af/util/xp/ut_iconv.h 2002/02/04 22:34:54 @@ -81,6 +81,16 @@ UT_END_EXTERN_C +#ifdef __cplusplus + +char * UT_convert (const char *str, + UT_sint32 len, + UT_iconv_t cd, + UT_uint32 *bytes_read, + UT_uint32 *bytes_written); + +#endif + #endif /* UT_ICONV_H */