JNI 할때 한글이 문제가 될것 같았다. -_-
그래서 테스트를 해 보니 역시 문제가 되었다. -_-
) 에서.. JNI 검색하다가 자료를 찾았다.
으흐~ 우선.. 저 소스들을 분석해 보아야 겠다~ ^_^
역시나 ! byte 배열이다. -_-b 어떤형태로도 변환가능 !! ㅋㅋ
박용운 2004-04-21 18:39:28.0
sialnuri@yahoo.co.kr
JNI(JAVA <-> C)에서 한글 사용
전 자바는 완전초보인데, 사정상 급히 JNI를 구현했어야 했습니다.
자바도 모르는데 JNI를 하라니...정말 죽을맛이더군요.
인터넷은 죄다 뒤져 겨우 문자열을 주고받는데까지 했는데 이제는 한글이 문제를 일으키더군요.
자바는 유니코드를 쓰고, JNI는 UTF-8을 쓰구, C/C++환경에서는 KSC5601 바이트문자열을 쓰더군요. 황당 그자체였습니다.
하지만, 여기도 그렇고 다른곳에서도 한글해결을 위한 명확한 방법을 제시한곳이 없더군요.
그래서, 3일동안 끙끙되며 찾은 방법을 JNI를 공부하거나 구현하고자 하는분을 위해서 설명드리고자 합니다.
참고URL : http://www.grine.co.kr/computer/lang6101.htm => JNI에서 한글처리하는 코어를 가져온 사이트임다. 겨우 찾아냈죠. ^^*
컴파일 환경은 WinXP, JDK1.4.2.04로 했으며, C컴파일을 위해서 VisualC++을 이용했습니다.
간단히 설명하면(파일명을 Test.java과 Test.c)
javac Test.java
javah Test
cl -IC:\j2sdk1.4.2_04\include -IC:\j2sdk1.4.2_04\include\win32 -LD Test.c
java Test
입니다.
이제 소스설명입니다. 설명은 자바->C만 하겠습니다. C->자바도 소스는 같이 첨부할테니 보시면 금방 아실수 있습니다.
public class JavaToC
{
public native void sendtoc(String ar[]);
static
{
System.loadLibrary("JavaToC"); // 클래스명과 동일하게
}
public static void main(String[] args)
{
String ar[] = {"노무현","대통령","짱!!"}; // C로 넘길 String 객체
JavaToC a = new JavaToC();
a.sendtoc(ar); // C호출
}
}
간단하죠? 만약, 이 부분이 어려웠다면 자바도 모르는 제가 했을리 없겠죠.
이제는 C부분입니다. 자바보다는 쬐금 깁니다. 하지만, 직접 코딩하는 부분은 얼마없으니 걱정마시길...
#include
#include "JavaToC.h"
#include
#include
// ==> 여기부터 쭈~~~~욱 내려가서
char *jbyteArray2cstr( JNIEnv *env, jbyteArray javaBytes );
jbyteArray cstr2jbyteArray( JNIEnv *env, const char *nativeStr);
jbyteArray javaGetBytes( JNIEnv *env, jstring str );
jbyteArray javaGetBytesEncoding( JNIEnv *env, jstring str, const char *encoding );
jstring javaNewString( JNIEnv *env, jbyteArray javaBytes );
jstring javaNewStringEncoding(JNIEnv *env, jbyteArray javaBytes, const char *encoding );
static jclass class_String;
static jmethodID mid_getBytes, mid_getBytesEncoding;
static jmethodID mid_newString, mid_newStringEncoding;
char *jbyteArray2cstr( JNIEnv *env, jbyteArray javaBytes )
{
size_t len = (*env)->GetArrayLength(env, javaBytes);
jbyte *nativeBytes = (*env)->GetByteArrayElements(env, javaBytes, 0);
char *nativeStr = (char *)malloc(len+1);
strncpy( nativeStr, nativeBytes, len );
nativeStr[len] = '\0';
(*env)->ReleaseByteArrayElements(env, javaBytes, nativeBytes, JNI_ABORT);
return nativeStr;
}
/* C 문자열로부터 자바 바이트 배열을 생성하여 반환 */
jbyteArray cstr2jbyteArray( JNIEnv *env, const char *nativeStr)
{
jbyteArray javaBytes;
int len = strlen( nativeStr );
javaBytes = (*env)->NewByteArray(env, len);
(*env)->SetByteArrayRegion(env, javaBytes, 0, len, (jbyte *) nativeStr );
return javaBytes;
}
/* 자바 스트링을 디폴트 인코딩의 자바 바이트 배열로 변환.
* String 클래스의 getBytes() 메쏘드를 호출한다. */
jbyteArray javaGetBytes( JNIEnv *env, jstring str )
{
if ( mid_getBytes == 0 )
{
if ( class_String == 0 )
{
jclass cls = (*env)->FindClass(env, "java/lang/String");
if ( cls == 0 ) return 0; /* 오류 */
class_String = (*env)->NewGlobalRef(env, cls);
if ( class_String == 0 ) return 0; /* 오류 */
}
mid_getBytes = (*env)->GetMethodID(env, class_String, "getBytes", "()[B");
if (mid_getBytes == 0) return 0;
}
/* str.getBytes(); */
return (*env)->CallObjectMethod( env, str, mid_getBytes );
}
/* 자바 스트링을 지정된 인코딩 `encoding'의 자바 바이트 배열로 변환.
* String 클래스의 getBytes(String encoding) 메쏘드를 호출한다. */
jbyteArray javaGetBytesEncoding( JNIEnv *env, jstring str, const char *encoding )
{
if ( mid_getBytesEncoding == 0 )
{
if ( class_String == 0 )
{
jclass cls = (*env)->FindClass(env, "java/lang/String");
if ( cls == 0 ) return 0; /* 오류 */
class_String = (*env)->NewGlobalRef(env, cls);
if ( class_String == 0 ) return 0; /* 오류 */
}
mid_getBytesEncoding = (*env)->GetMethodID(env, class_String, "getBytes", "(Ljava/lang/String;)[B");
if (mid_getBytesEncoding == 0) return 0;
}
/* str.getBytes( encoding ); */
return (*env)->CallObjectMethod(env, str, mid_getBytesEncoding, (*env)->NewStringUTF(env, encoding));
}
/* 디폴트 인코딩의 자바 바이트 배열을 자바 스트링으로 변환.
* String 클래스의 new String(byte[] bytes) 메쏘드를 호출한다. */
jstring javaNewString( JNIEnv *env, jbyteArray javaBytes )
{
if ( mid_newString == 0 )
{
if ( class_String == 0 )
{
jclass cls = (*env)->FindClass(env, "java/lang/String");
if ( cls == 0 ) return 0; /* 오류 */
class_String = (*env)->NewGlobalRef(env, cls);
if ( class_String == 0 ) return 0; /* 오류 */
}
mid_newString = (*env)->GetMethodID(env, class_String, "", "([B)V");
if ( mid_newString == 0 ) return 0;
}
/* new String( javaBytes ); */
return (*env)->NewObject(env, class_String, mid_newString, javaBytes );
}
/* 지정된 인코딩 `encoding'의 자바 바이트 배열을 자바 스트링으로 변환.
* String 클래스의 new String(byte[] bytes, String encoding)
* 메쏘드를 호출한다. */
jstring javaNewStringEncoding(JNIEnv *env, jbyteArray javaBytes, const char *encoding )
{
int len;
jstring str;
if ( mid_newString == 0 )
{
if ( class_String == 0 )
{
jclass cls = (*env)->FindClass(env, "java/lang/String");
if ( cls == 0 ) return 0; /* 오류 */
class_String = (*env)->NewGlobalRef(env, cls);
if ( class_String == 0 ) return 0; /* 오류 */
}
mid_newString = (*env)->GetMethodID(env, class_String, "", "([BLjava/lang/String;)V");
if ( mid_newString == 0 ) return 0;
}
/* new String( javaBytes, encoding ); */
str = (*env)->NewObject(env, class_String, mid_newString, javaBytes, (*env)->NewStringUTF(env, encoding) );
return str;
}
//<-- 이부분까지는 한글변환 함수들을 정의한것으로 그냥 붙여넣기한사용하시면 됩니다.
JNIEXPORT void JNICALL Java_JavaToC_sendtoc(JNIEnv *env, jobject obj, jobjectArray ar)
{
// 자바에서 넘긴 String객체는 jobjectArray ar가 받습니다.
int i;
char str[100];
jstring iArray
jint i1;
i1 = (*env)->GetArrayLength(env, ar); // 갯수 세기
for(i = 0; i < i1; i++) // 반복문
{
iArray = (jstring)(*env)->GetObjectArrayElement(env, ar, i); // 배열객체를 참조하기 위해서
str[0] = '\0';
strcpy(str, jbyteArray2cstr(env, javaGetBytes(env, iArray))); // i번째 배열객체를 읽어온 iArray를 문자열변환하여 str에 저장합니다.
printf("ar[%d] = %s\n", i, str); // 출력
}
return;
}
핫...간단하죠?
뭐...저도 찾는데 오래걸려서 그렇지 막상해보니 제가 직접 코딩한것은 거의 없군요.
JNI로 한글처리로 고민하는분들께 조금이나마 도움이 되었으면 좋겠습니다.
당연한 문제점이 발견되었다.
한다.
그러므로.. Unicode 에는 있으나 네이티브 문자셋에는 없는 글자를 사용하면
한다.
"가 출력되게 된다.
문자열 처리를 해야 한다면. 네이티브에 종속된 문자열 처리를 하여야 할것이다. ( 물론 네이티브에서 자바 보다 더 많은 문자셋을 지원한다면.. 자바에 종속적인 코드를 짜야 할것 같다. )