관리 메뉴

드럼치는 프로그래머

[JNI/NDK] JNI(JAVA <-> C)에서 한글 사용 본문

★─Programing/☆─JNI | NDK

[JNI/NDK] JNI(JAVA <-> C)에서 한글 사용

드럼치는한동이 2013. 4. 17. 10:34

자바는 유니코드를 쓰고, 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

입니다.

 

ctojava-khahahat.c

ctojava-khahahat.java

javatoc-khahahat.c

javatoc-khahahat.java

 

이제 소스설명입니다. 설명은 자바->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 <jni.h>
#include "JavaToC.h"
#include <stdio.h>
#include <string.h>

 

// ==> 여기부터 쭈~~~~욱 내려가서
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, "<init>", "([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, "<init>", "([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로 한글처리로 고민하는분들께 조금이나마 도움이 되었으면 좋겠습니다.

 

[출처] http://blog.naver.com/PostView.nhn?blogId=khahahat&logNo=90029108655&redirect=Dlog&widgetTypeCall=true

Comments