지금은 잠깐 쉬고 있지만, 예전에 안드로이드 ndk 환경에서 프로그래밍을 하던 때가 있었습니다.
그 때, JNI 인터페이스를 통해 Native단의 C++과 Application단의 Java와의 데이터를 주고 받아야 하는 API들을
만들었었는데, 그 중 문자열 전송과 관련해서 한글이 죄다 깨져서 전송되는 현상이 있었습니다.
Java 단에서는 UTF-8 방식을 이용하고, C++에서는 KSC5601 방식의 문자열이었기 때문에 발생하는 문제였습니다.
그래서 구글링을 통해 C++과 Java간의 한글 변환 관련 코드를 확보 및 컨버팅을 했습니다.
C++과 Java간의 한글 변환 코드는 다음과 같습니다. 다음은 헤더 파일입니다.
01.#ifndef _STRING_CONVERTER_FOR_JNI_02.#define _STRING_CONVERTER_FOR_JNI_03. 04.#include <jni.h>05.#include <stdio.h>06.#include <string.h>07. 08.#ifdef __cplusplus09.extern "C"10.{11.#endif12. 13.char *jbyteArray2cstr( JNIEnv *env, jbyteArray javaBytes );14.jbyteArray cstr2jbyteArray( JNIEnv *env, const char *nativeStr);15.jbyteArray javaGetBytes( JNIEnv *env, jstring str );16.jbyteArray javaGetBytesEncoding( JNIEnv *env, jstring str, const char *encoding );17.jstring javaNewString( JNIEnv *env, jbyteArray javaBytes );18.jstring javaNewStringEncoding(JNIEnv *env, jbyteArray javaBytes, const char *encoding );19. 20.jstring javaNewStringChar(JNIEnv* env, const char* nativeStr);21. 22.#ifdef __cplusplus23.}24.#endif25. 26.#endif //_STRING_CONVERTER_FOR_JNI_27.</string.h></stdio.h></jni.h>그리고 다음은 C++ 소스 코드입니다.
001.#include "StringConverter_For_JNI.h"002. 003.static jclass class_String;004.static jmethodID mid_getBytes, mid_getBytesEncoding;005.static jmethodID mid_newString, mid_newStringEncoding;006. 007.char *jbyteArray2cstr( JNIEnv *env, jbyteArray javaBytes )008.{009.size_t len = env->GetArrayLength(javaBytes);010.jbyte *nativeBytes = env->GetByteArrayElements(javaBytes, 0);011.char *nativeStr = (char *)malloc(len+1);012.strncpy( nativeStr, (const char*)nativeBytes, len );013.nativeStr[len] = '\0';014.env->ReleaseByteArrayElements(javaBytes, nativeBytes, JNI_ABORT);015. 016.return nativeStr;017.}018. 019.jbyteArray cstr2jbyteArray( JNIEnv *env, const char *nativeStr)020.{021.jbyteArray javaBytes;022.int len = strlen( nativeStr );023.javaBytes = env->NewByteArray(len);024.env->SetByteArrayRegion(javaBytes, 0, len, (jbyte *) nativeStr );025. 026.return javaBytes;027.}028. 029.jbyteArray javaGetBytes( JNIEnv *env, jstring str )030.{031.if ( mid_getBytes == 0 )032.{033.if ( class_String == 0 )034.{035.jclass cls = env->FindClass("java/lang/String");036.if ( cls == 0 )037.{038.return 0;039.}040. 041.class_String = (jclass)env->NewGlobalRef(cls);042.env->DeleteLocalRef(cls);043.if ( class_String == 0 )044.{045.return 0;046.}047.}048. 049.mid_getBytes = env->GetMethodID(class_String, "getBytes", "()[B");050.if (mid_getBytes == 0)051.{052.return 0;053.}054.}055. 056.return (jbyteArray)env->CallObjectMethod(str, mid_getBytes );057.}058. 059.jbyteArray javaGetBytesEncoding( JNIEnv *env, jstring str, const char *encoding )060.{061.if ( mid_getBytesEncoding == 0 )062.{063.if ( class_String == 0 )064.{065.jclass cls = env->FindClass("java/lang/String");066.if ( cls == 0 )067.{068.return 0;069.}070. 071.class_String = (jclass)env->NewGlobalRef(cls);072.env->DeleteLocalRef(cls);073.if ( class_String == 0 )074.{075.return 0;076.}077.}078. 079.mid_getBytesEncoding = env->GetMethodID(class_String, "getBytes", "(Ljava/lang/String;)[B");080.if (mid_getBytesEncoding == 0)081.{082.return 0;083.}084.}085. 086.jstring jstr = env->NewStringUTF(encoding);087.jbyteArray retArray = (jbyteArray)env->CallObjectMethod(str, mid_getBytesEncoding, jstr);088.env->DeleteLocalRef(jstr);089. 090.return retArray;091.}092. 093.jstring javaNewString( JNIEnv *env, jbyteArray javaBytes )094.{095.if ( mid_newString == 0 )096.{097.if ( class_String == 0 )098.{099.jclass cls = env->FindClass("java/lang/String");100.if ( cls == 0 )101.{102.return 0;103.}104. 105.class_String = (jclass)env->NewGlobalRef(cls);106.env->DeleteLocalRef(cls);107.if ( class_String == 0 )108.{109.return 0;110.}111.}112. 113.mid_newString = env->GetMethodID(class_String, "<init>", "([B)V");114.if ( mid_newString == 0 )115.{116.return 0;117.}118.}119. 120.return (jstring)env->NewObject(class_String, mid_newString, javaBytes );121.}122. 123.jstring javaNewStringEncoding(JNIEnv *env, jbyteArray javaBytes, const char *encoding )124.{125.int len;126.jstring str;127.if ( mid_newString == 0 )128.{129.if ( class_String == 0 )130.{131.jclass cls = env->FindClass("java/lang/String");132.if ( cls == 0 )133.{134.return 0;135.}136. 137.class_String = (jclass)env->NewGlobalRef(cls);138.env->DeleteLocalRef(cls);139.if ( class_String == 0 )140.{141.return 0;142.}143. 144.}145. 146.mid_newString = env->GetMethodID(class_String, "<init>", "([BLjava/lang/String;)V");147.if ( mid_newString == 0 )148.{149.return 0;150.}151.}152. 153.jstring jstr = env->NewStringUTF(encoding);154.str = (jstring)env->NewObject(class_String, mid_newString, javaBytes, jstr);155.env->DeleteLocalRef(jstr);156. 157.return str;158.}159. 160.jstring javaNewStringChar(JNIEnv* env, const char* nativeStr)161.{162.jbyteArray byteArray = cstr2jbyteArray(env, nativeStr);163.jstring jstr = javaNewString(env, byteArray);164.env->DeleteLocalRef(byteArray);165. 166.return jstr;167.}168.</init></init>이 함수들을 이용해서 실제로 사용한 예제는 다음과 같습니다.
C++의 string을 Java용 jstring으로 변환하는 부분
1.jstring jstrValue;2.jfieldID fieldID;3.jmethodID methodID;4. 5.methodID = env->GetMethodID( cProgramInfo, "ProgramName","(Ljava/lang/String;)V");6.jstrValue = javaNewStringChar(env, strProgramName);7.env->CallVoidMethod( jElement, methodID, jstrValue);8.env->DeleteLocalRef(jstrValue);Java용 jstring를 C++의 string으로 변환하는 함수
01.string title_;02.jmethodID methodID;03. 04.methodID = env->GetMethodID( cProgramInfo, "ProgramTitle","()Ljava/lang/String;");05.jstring jstrTitle = (jstring)env->CallObjectMethod(jElement, methodID);06.if(jstrTitle)07.{08.pszTitle = (char*)env->GetStringUTFChars(jstrTitle, &iscopy);09.title_ = pszTitle;10.env->ReleaseStringUTFChars(jstrTitle, pszTitle);11.env->DeleteLocalRef(jstrTitle); 12.}
댓글 없음:
댓글 쓰기