Вот короткая программа, которая преобразует UTF-16 в массив широких символов и затем распечатывает его.
#include <endian.h>
#include <errno.h>
#include <iconv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define FROMCODE "UTF-16"
#if (BYTE_ORDER == LITTLE_ENDIAN)
#define TOCODE "UTF-32LE"
#elif (BYTE_ORDER == BIG_ENDIAN)
#define TOCODE "UTF-32BE"
#else
#error Unsupported byte order
#endif
int main(void)
{
void *tmp;
char *outbuf;
const char *inbuf;
long converted = 0;
wchar_t *out = NULL;
int status = EXIT_SUCCESS, n;
size_t inbytesleft, outbytesleft, size;
const char in[] = {
0xff, 0xfe,
'H', 0x0,
'e', 0x0,
'l', 0x0,
'l', 0x0,
'o', 0x0,
',', 0x0,
' ', 0x0,
'W', 0x0,
'o', 0x0,
'r', 0x0,
'l', 0x0,
'd', 0x0,
'!', 0x0
};
iconv_t cd = iconv_open(TOCODE, FROMCODE);
if ((iconv_t)-1 == cd) {
if (EINVAL == errno) {
fprintf(stderr, "iconv: cannot convert from %s to %s\n",
FROMCODE, TOCODE);
} else {
fprintf(stderr, "iconv: %s\n", strerror(errno));
}
goto error;
}
size = sizeof(in) * sizeof(wchar_t);
inbuf = in;
inbytesleft = sizeof(in);
while (1) {
tmp = realloc(out, size + sizeof(wchar_t));
if (!tmp) {
fprintf(stderr, "realloc: %s\n", strerror(errno));
goto error;
}
out = tmp;
outbuf = (char *)out + converted;
outbytesleft = size - converted;
n = iconv(cd, (char **)&inbuf, &inbytesleft, &outbuf, &outbytesleft);
if (-1 == n) {
if (EINVAL == errno) {
/* junk at the end of the buffer, ignore it */
break;
} else if (E2BIG != errno) {
/* unrecoverable error */
fprintf(stderr, "iconv: %s\n", strerror(errno));
goto error;
}
/* increase the size of the output buffer */
converted = size - outbytesleft;
size <<= 1;
} else {
/* done */
break;
}
}
converted = (size - outbytesleft) / sizeof(wchar_t);
out[converted] = L'\0';
fprintf(stdout, "%ls\n", out);
/* flush the iconv buffer */
iconv(cd, NULL, NULL, &outbuf, &outbytesleft);
exit:
if (out) {
free(out);
}
if (cd) {
iconv_close(cd);
}
exit(status);
error:
status = EXIT_FAILURE;
goto exit;
}
Поскольку UTF-16 является кодировкой переменной длины, вы угадываете, насколько велика вашавыходной буфер должен быть.Правильная программа должна обрабатывать случай, когда выходной буфер недостаточно велик для хранения преобразованных данных.
Вы также должны заметить, что iconv
не NULL
определяет ваш выходной буфер для вас.
Iconv является потоково-ориентированным процессором, поэтому вам нужно сбросить iconv_t
, если вы хотите использовать его для другого преобразования (пример кода делает это ближе к концу).Если вы хотите выполнить потоковую обработку, вы бы обработали ошибку EINVAL
, скопировав все байты, оставшиеся во входном буфере, в начало нового входного буфера перед повторным вызовом iconv
.