UTF8文字列をUTF16(リトルエンディアン)に変換する関数を記述したいと思います。問題は、iconv
関数が出力文字列を格納するために必要なバイト数を事前に通知していないように見えることです。
私の解決策は、を割り当てることから始めて、ループで2*strlen(utf8)
実行し、必要iconv
に応じてそのバッファのサイズを増やすことです。realloc
static int utf8_to_utf16le(char *utf8, char **utf16, int *utf16_len)
{
iconv_t cd;
char *inbuf, *outbuf;
size_t inbytesleft, outbytesleft, nchars, utf16_buf_len;
cd = iconv_open("UTF16LE", "UTF8");
if (cd == (iconv_t)-1) {
printf("!%s: iconv_open failed: %d\n", __func__, errno);
return -1;
}
inbytesleft = strlen(utf8);
if (inbytesleft == 0) {
printf("!%s: empty string\n", __func__);
iconv_close(cd);
return -1;
}
inbuf = utf8;
utf16_buf_len = 2 * inbytesleft; // sufficient in many cases, i.e. if the input string is ASCII
*utf16 = malloc(utf16_buf_len);
if (!*utf16) {
printf("!%s: malloc failed\n", __func__);
iconv_close(cd);
return -1;
}
outbytesleft = utf16_buf_len;
outbuf = *utf16;
nchars = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
while (nchars == (size_t)-1 && errno == E2BIG) {
char *ptr;
size_t increase = 10; // increase length a bit
size_t len;
utf16_buf_len += increase;
outbytesleft += increase;
ptr = realloc(*utf16, utf16_buf_len);
if (!ptr) {
printf("!%s: realloc failed\n", __func__);
free(*utf16);
iconv_close(cd);
return -1;
}
len = outbuf - *utf16;
*utf16 = ptr;
outbuf = *utf16 + len;
nchars = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
}
if (nchars == (size_t)-1) {
printf("!%s: iconv failed: %d\n", __func__, errno);
free(*utf16);
iconv_close(cd);
return -1;
}
iconv_close(cd);
*utf16_len = utf16_buf_len - outbytesleft;
return 0;
}
これは本当にそれを行うための最良の方法ですか?sを繰り返すrealloc
のは無駄に思えますが、utf8に含まれる可能性のある文字シーケンスと、それらがutf16にどのような結果になるかを知らなければ、初期バッファーサイズをより適切に推測できるかどうかわかりません2*strlen(utf8)
。