From f3af019c415bd28353f21bc37c413891419ff0a9 Mon Sep 17 00:00:00 2001 From: Adam Murdoch Date: Mon, 25 Feb 2013 19:30:16 +1100 Subject: [PATCH] Changed method for converting between java and c strings, to convert using an intermediate wchar_t string. Should be more reliable than trying to probe the character encoding. --- src/main/cpp/generic_posix.cpp | 65 ++++++++++++++++------------------ 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/src/main/cpp/generic_posix.cpp b/src/main/cpp/generic_posix.cpp index f05c8a9..a70a967 100644 --- a/src/main/cpp/generic_posix.cpp +++ b/src/main/cpp/generic_posix.cpp @@ -23,10 +23,8 @@ #include "generic.h" #include #include -#include -#include -#include #include +#include void mark_failed_with_errno(JNIEnv *env, const char* message, jobject result) { const char * errno_message = NULL; @@ -40,47 +38,46 @@ void mark_failed_with_errno(JNIEnv *env, const char* message, jobject result) { } char* java_to_char(JNIEnv *env, jstring string, jobject result) { - // TODO - share this code with nnn_getSystemInfo() below - // Empty string means load locale from environment. - locale_t locale = newlocale(LC_CTYPE_MASK, "", NULL); - if (locale == NULL) { - mark_failed_with_message(env, "could not create locale", result); + size_t stringLen = env->GetStringLength(string); + wchar_t* wideString = (wchar_t*)malloc(sizeof(wchar_t) * (stringLen+1)); + const jchar* javaString = env->GetStringChars(string, NULL); + for (size_t i = 0; i < stringLen; i++) { + wideString[i] = javaString[i]; + } + wideString[stringLen] = L'\0'; + env->ReleaseStringChars(string, javaString); + + size_t bytes = wcstombs(NULL, wideString, 0); + if (bytes < 0) { + mark_failed_with_message(env, "could not convert string to current locale", result); + free(wideString); return NULL; } - jstring encoding = env->NewStringUTF(nl_langinfo_l(CODESET, locale)); - freelocale(locale); - - jclass strClass = env->FindClass("java/lang/String"); - jmethodID method = env->GetMethodID(strClass, "getBytes", "(Ljava/lang/String;)[B"); - jbyteArray byteArray = (jbyteArray)env->CallObjectMethod(string, method, encoding); - size_t len = env->GetArrayLength(byteArray); - char* chars = (char*)malloc(len + 1); - env->GetByteArrayRegion(byteArray, 0, len, (jbyte*)chars); - chars[len] = 0; + char* chars = (char*)malloc(bytes + 1); + wcstombs(chars, wideString, bytes+1); + free(wideString); return chars; } jstring char_to_java(JNIEnv* env, const char* chars, jobject result) { - // TODO - share this code with nnn_getSystemInfo() below - // Empty string means load locale from environment. - locale_t locale = newlocale(LC_CTYPE_MASK, "", NULL); - if (locale == NULL) { - mark_failed_with_message(env, "could not create locale", result); + size_t bytes = strlen(chars); + wchar_t* wideString = (wchar_t*)malloc(sizeof(wchar_t) * (bytes+1)); + if (mbstowcs(wideString, chars, bytes+1) < 0) { + mark_failed_with_message(env, "could not convert string from current locale", result); + free(wideString); return NULL; } - jstring encoding = env->NewStringUTF(nl_langinfo_l(CODESET, locale)); - freelocale(locale); - - size_t len = strlen(chars); - jbyteArray byteArray = env->NewByteArray(len); - jbyte* bytes = env->GetByteArrayElements(byteArray, NULL); - memcpy(bytes, chars, len); - env->ReleaseByteArrayElements(byteArray, bytes, JNI_COMMIT); - jclass strClass = env->FindClass("java/lang/String"); - jmethodID method = env->GetMethodID(strClass, "", "([BLjava/lang/String;)V"); - return (jstring)env->NewObject(strClass, method, byteArray, encoding); + size_t stringLen = wcslen(wideString); + jchar* javaString = (jchar*)malloc(sizeof(jchar) * stringLen); + for (int i =0; i < stringLen; i++) { + javaString[i] = (jchar)wideString[i]; + } + jstring string = env->NewString(javaString, stringLen); + free(wideString); + free(javaString); + return string; } #endif