Tengo un archivo que contiene cadenas UNICODE-16 que me gustaría leer en un programa Linux. Las cadenas se escribieron sin procesar desde el formato WCHAR interno de Windows. (¿Windows siempre usa UTF-16? Por ejemplo, en versiones japonesas)¿Cómo leo cadenas Unicode-16 desde un archivo utilizando métodos POSIX en Linux?
Creo que puedo leerlos usando lecturas sin formato y la conversión con wcstombs_l. Sin embargo, no puedo imaginarme qué locale usar. Ejecutar "locale -a" en mis máquinas actualizadas Ubuntu y Mac OS X produce cero configuraciones regionales con utf-16 en sus nombres.
¿Hay una manera mejor?
Actualización: la respuesta correcta y otras a continuación me ayudaron a utilizar libiconv. Aquí hay una función que estoy usando para hacer la conversión. Actualmente lo tengo dentro de una clase que hace que las conversiones se conviertan en una sola línea de código.
// Function for converting wchar_t* to char*. (Really: UTF-16LE --> UTF-8)
// It will allocate the space needed for dest. The caller is
// responsible for freeing the memory.
static int iwcstombs_alloc(char **dest, const wchar_t *src)
{
iconv_t cd;
const char from[] = "UTF-16LE";
const char to[] = "UTF-8";
cd = iconv_open(to, from);
if (cd == (iconv_t)-1)
{
printf("iconv_open(\"%s\", \"%s\") failed: %s\n",
to, from, strerror(errno));
return(-1);
}
// How much space do we need?
// Guess that we need the same amount of space as used by src.
// TODO: There should be a while loop around this whole process
// that detects insufficient memory space and reallocates
// more space.
int len = sizeof(wchar_t) * (wcslen(src) + 1);
//printf("len = %d\n", len);
// Allocate space
int destLen = len * sizeof(char);
*dest = (char *)malloc(destLen);
if (*dest == NULL)
{
iconv_close(cd);
return -1;
}
// Convert
size_t inBufBytesLeft = len;
char *inBuf = (char *)src;
size_t outBufBytesLeft = destLen;
char *outBuf = (char *)*dest;
int rc = iconv(cd,
&inBuf,
&inBufBytesLeft,
&outBuf,
&outBufBytesLeft);
if (rc == -1)
{
printf("iconv() failed: %s\n", strerror(errno));
iconv_close(cd);
free(*dest);
*dest = NULL;
return -1;
}
iconv_close(cd);
return 0;
} // iwcstombs_alloc()
WCHAR en Windows parece tener un tamaño fijo (puede hacer sizeof() en él). ¿Eso no significa que solo implementa un subconjunto de UTF-16, que es de tamaño variable? – PolyThinker
Almacena los valores de 16 bits correspondientes a los puntos de código UTF-16; si quieres personajes fuera del BMP tienes que usar los sustitutos manualmente, Windows no te ayudará. p.ej. '' .length == 2. Esta es la misma situación que, por ejemplo. Java o Python en modo estrecho-Unicode. – bobince
Después de muchos experimentos y utilizando el conocimiento de esta respuesta, utilicé libiconv. Estoy agregando la función simple que utilicé aquí para que otros la usen. No es perfecto y animo a otros a solucionar los problemas. – Harvey