지금은 잠깐 쉬고 있지만, 예전에 안드로이드 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 __cplusplus
09.
extern
"C"
10.
{
11.
#endif
12.
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 __cplusplus
23.
}
24.
#endif
25.
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.
}
댓글 없음:
댓글 쓰기