2008-09-15 30 views
12

Digamos que en el lado C++ mi función toma una variable de tipo jstring llamada myString. Puedo convertirlo en una cadena ANSI de la siguiente manera:Cómo convierto jstring a wchar_t *

const char* ansiString = env->GetStringUTFChars(myString, 0); 

hay una manera de conseguir

const wchar_t* unicodeString = ...

Respuesta

3

Una solución portátil y robusto es utilizar iconv, con el entendimiento de que debe saber qué codificación usa su sistema wchar_t (UTF-16 en Windows, UTF-32 en muchos sistemas Unix, por ejemplo).

Si desea minimizar su dependencia del código de un tercero, también puede transferir manualmente su propio convertidor UTF-8. Esto es fácil si se convierte a UTF-32, algo más difícil con UTF-16 porque también tiene que manejar pares sustitutos. :-P Además, debe tener cuidado de rechazar los formularios non-shortest, o puede abrir fallas de seguridad en algunos casos.

+0

¿Está sugiriendo convertir el jstring a UTF-8 y luego de vuelta a UTF-16? ¿Es eso realmente necesario? – Rup

+0

@Rup jstrings ya son UTF-8: "El JNI usa cadenas UTF-8 modificadas para representar varios tipos de cadenas. Las cadenas UTF-8 modificadas son las mismas que las utilizadas por la máquina virtual Java. Las cadenas UTF-8 modificadas están codificadas para que las secuencias de caracteres que contienen solo caracteres ASCII no nulos se pueden representar utilizando solo un byte por carácter, pero todos los caracteres Unicode se pueden representar ... La máquina virtual Java no reconoce el formato de cuatro bytes del UTF-8 estándar; utiliza su propio formato de dos veces tres bytes en su lugar ". –

+0

@ b1naryatr0phy ¿De verdad? jni.h en mi sistema (ambos 1.6 y 1.7) tiene 'typedef unsigned short jchar;' que se parece más a UTF-16 para mí. – Rup

0

Si no estamos interesados ​​en la capacidad de plataforma cruzada, en Windows puede usar la función MultiByteToWideChar, o las útiles macros A2W (ref. example).

3

JNI también tiene una función GetStringChars(). El tipo de retorno es const jchar *, jchar es de 16 bits en win32, de modo que sea compatible con wchar_t. No estoy seguro si es UTF-16 real o algo más ...

+0

¿Sabes por casualidad si el ordenamiento de bytes de jchar es compatible con el wchar_t de Win32? Debería serlo, pero probablemente sea bueno estar seguro. :-) –

+0

jchar es typedef'ed para unsigned short. No lo he probado yo mismo, pero supongo que sería "sí". –

+0

char == jchar == unsigned 16 bits –

0

Simplemente use env-> GetStringChars (myString, 0); Java pasar Unicode por su naturaleza

2

Sé que esto fue preguntado hace un año, pero no me gustan las otras respuestas, así que voy a responder de todos modos. Así es como lo hacemos en nuestra fuente:

wchar_t * JavaToWSZ(JNIEnv* env, jstring string) 
{ 
    if (string == NULL) 
     return NULL; 
    int len = env->GetStringLength(string); 
    const jchar* raw = env->GetStringChars(string, NULL); 
    if (raw == NULL) 
     return NULL; 

    wchar_t* wsz = new wchar_t[len+1]; 
    memcpy(wsz, raw, len*2); 
    wsz[len] = 0; 

    env->ReleaseStringChars(string, raw); 

    return wsz; 
} 

EDITAR: Esta solución funciona bien en las plataformas que wchar_t es de 2 bytes, algunas plataformas tienen un wchar_t 4 bytes en cuyo caso esta solución no funcionará.

+2

Esta solución es incorrecta. He chupado 12 horas por eso. wchar_t y jchar no son necesariamente lo mismo. La prueba para eso es la salida de mi programa de prueba: '01-26 20: 28: 43.675: E/[LMI-NATIVE] (9280): len: 7, jchar: 2, wchar: 4' – Kobor42

+2

@ Kobor42 - ¿Qué hace tu programa de prueba? ¿Estás diciendo que encontraste una instancia donde wchar_t tenía 4 bytes? En realidad no me di cuenta, pero esta función fue diseñada para ejecutarse (principalmente) en Windows donde wchar_t siempre es 2. Ahora me doy cuenta de que wchar_t es específico del compilador y puede ser diferente en su plataforma. – Benj

+0

Exactamente. En Android anterior 2.1 wchar_t es de 1 byte. 2.1 y después es 4 bytes. – Kobor42

4

¿Y quién libera a wsz? ¡Recomendaría STL!

std::wstring JavaToWSZ(JNIEnv* env, jstring string) 
{ 
    std::wstring value; 
    if (string == NULL) { 
     return value; // empty string 
    } 
    const jchar* raw = env->GetStringChars(string, NULL); 
    if (raw != NULL) { 
     jsize len = env->GetStringLength(string); 
     value.assign(raw, len); 
     env->ReleaseStringChars(string, raw); 
    } 
    return value; 
} 
+0

No es una gran solución, a menos que se use C++ 11, ya que el valor de wstring será devuelto por valor. (Obviamente publicar C++ 11 será un movimiento construido que sería eficiente) – Benj

+4

value.assign (raw, len); no es válido. Creo que debería ser value.assign (raw, raw + len); pero aún no lo he probado – mjaggard

+0

Genial, funcionó perfectamente para mí en C# -> C++/CLI -> JNI -> ¡Aplicación Java! – bbqchickenrobot

0

Rather simple. Pero no se olvide de liberar la memoria por ReleaseStringChars

JNIEXPORT jboolean JNICALL Java_TestClass_test(JNIEnv * env, jobject, jstring string) 
{ 
    const wchar_t * utf16 = (wchar_t *)env->GetStringChars(string, NULL); 
    ... 
    env->ReleaseStringChars(string, utf16); 
} 
13

Si esto ayuda a alguien ... He usado esta función para un proyecto Android:

std::wstring Java_To_WStr(JNIEnv *env, jstring string) 
{ 
    std::wstring value; 

    const jchar *raw = env->GetStringChars(string, 0); 
    jsize len = env->GetStringLength(string); 
    const jchar *temp = raw; 
    while (len > 0) 
    { 
     value += *(temp++); 
     len--; 
    } 
    env->ReleaseStringChars(string, raw); 

    return value; 
} 

Una solución podría ser mejorada (Gracias por los comentarios):

std::wstring Java_To_WStr(JNIEnv *env, jstring string) 
{ 
    std::wstring value; 

    const jchar *raw = env->GetStringChars(string, 0); 
    jsize len = env->GetStringLength(string); 

    value.assign(raw, raw + len); 

    env->ReleaseStringChars(string, raw); 

    return value; 
} 
+0

Limpio, aunque sospecho que cargar el wstring con un buffer de una vez sería más eficiente que un carácter a la vez. – Rup

+0

Sí, también creo que sí. Acabo de actualizar mi respuesta :) – gergonzalez

+0

¿El compilador de C++ se da cuenta de que está devolviendo una automática y la asigna al montón y no a la pila? –