Tengo una parte de mi biblioteca Unicode que decodifica UTF-16 en puntos de código Unicode en bruto. Sin embargo, no está funcionando como se esperaba.El decodificador UTF-16 no funciona como se esperaba
Aquí está la parte pertinente del código (omitiendo cosas UTF-8 y la manipulación de cadenas):
typedef struct string {
unsigned long length;
unsigned *data;
} string;
string *upush(string *s, unsigned c) {
if (!s->length) s->data = (unsigned *) malloc((s->length = 1) * sizeof(unsigned));
else s->data = (unsigned *) realloc(s->data, ++s->length * sizeof(unsigned));
s->data[s->length - 1] = c;
return s;
}
typedef struct string16 {
unsigned long length;
unsigned short *data;
} string16;
string u16tou(string16 old) {
unsigned long i, cur = 0, need = 0;
string new;
new.length = 0;
for (i = 0; i < old.length; i++)
if (old.data[i] < 0xd800 || old.data[i] > 0xdfff) upush(&new, old.data[i]);
else
if (old.data[i] > 0xdbff && !need) {
cur = 0; continue;
} else if (old.data[i] < 0xdc00) {
need = 1;
cur = (old.data[i] & 0x3ff) << 10;
printf("cur 1: %lx\n", cur);
} else if (old.data[i] > 0xdbff) {
cur |= old.data[i] & 0x3ff;
upush(&new, cur);
printf("cur 2: %lx\n", cur);
cur = need = 0;
}
return new;
}
¿Cómo funciona?
string
es una estructura que contiene valores de 32 bits, y string16
es para valores de 16 bits como UTF-16. Todo upush
es agregar un punto de código Unicode completo a string
, reasignando memoria según sea necesario.
u16tou
es la parte en la que me estoy enfocando. Pasa por el string16
, pasando valores no sustitutivos a través de lo normal y convirtiendo pares sustitutos en puntos de código completo. Los sustitutos mal ubicados son ignorados.
La primera sustituta en un par tiene sus 10 bits más bajos desplazados 10 bits hacia la izquierda, lo que hace que forme los 10 bits más altos del punto de código final. El otro suplente tiene sus 10 bits más bajos agregados a la final, y luego se agrega a la cadena.
¿El problema?
Probemos el punto de código más alto, ¿o sí?
U+10FFFD
, el último punto de código Unicode válido, está codificado como 0xDBFF 0xDFFD
en UTF-16. Probemos decodificando eso.
string16 b;
b.length = 2;
b.data = (unsigned short *) malloc(2 * sizeof(unsigned short));
b.data[0] = 0xdbff;
b.data[1] = 0xdffd;
string a = u16tou(b);
puts(utoc(a));
Utilizando el utoc
(que no se muestra, sé que está funcionando (véase más adelante)) función para convertir de nuevo a un UTF-8 char *
para la impresión, que puedo ver en mi terminal que estoy recibiendo U+0FFFFD
, no U+10FFFD
como resultado.
En la calculadora
Hacer todas las conversiones de forma manual en gcalctool resultados en la misma respuesta, mal. Entonces mi sintaxis en sí no está mal, pero el algoritmo sí lo está. Sin embargo, el algoritmo me parece correcto y, sin embargo, termina en una respuesta incorrecta.
¿Qué estoy haciendo mal?
¡Guau, gracias! ¡Se agregó un simple paso que falta, y mi decodificador UTF-16 funciona! –
No hay problema, me alegra saber que funciona ahora. Gracias por arreglar mi error tipográfico :) – JosephH