2010-09-24 17 views
5

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?

Respuesta

5

Debe agregar 0x10000 al descodificar el par suplente; citar rfc 2781, el paso que se está perdiendo es el número 5:

 
    1) If W1 < 0xD800 or W1 > 0xDFFF, the character value U is the value 
     of W1. Terminate. 

    2) Determine if W1 is between 0xD800 and 0xDBFF. If not, the sequence 
     is in error and no valid character can be obtained using W1. 
     Terminate. 

    3) If there is no W2 (that is, the sequence ends with W1), or if W2 
     is not between 0xDC00 and 0xDFFF, the sequence is in error. 
     Terminate. 

    4) Construct a 20-bit unsigned integer U', taking the 10 low-order 
     bits of W1 as its 10 high-order bits and the 10 low-order bits of 
     W2 as its 10 low-order bits. 

    5) Add 0x10000 to U' to obtain the character value U. Terminate. 

decir. Una solución sería añadir una línea adicional después de la primera lectura:

cur = (old.data[i] & 0x3ff) << 10; 
cur += 0x10000; 
+0

¡Guau, gracias! ¡Se agregó un simple paso que falta, y mi decodificador UTF-16 funciona! –

+0

No hay problema, me alegra saber que funciona ahora. Gracias por arreglar mi error tipográfico :) – JosephH

0

Usted parece que faltan un desplazamiento de 0x10000.

Según this WIKI page, UTF-16 pares suplentes están construidos de esta manera:

UTF-16 representa los caracteres no BMP (U + 10.000 a U + 10FFFF) utilizando dos unidades de código, conocido como un par suplente Primero 10000 se resta del punto de código para dar un valor de 20 bits. Esto se divide en dos valores de 10 bits , cada uno de los cuales se representa como , un sustituto con el más significativo medio colocado en el primer suplente.

Cuestiones relacionadas