본문 바로가기

J N I/jbyteArray2cstr

JNI, jbyteArray2cstr

JNI에서 한글처리 문제와 그 해결방법

Java, C언어간 한글처리 문제
한글과 같은 2바이트 문자를 다루는 방식이 Java언어와 C언어가 차이를 보이기 때문에 양 언어 사이에 한글이 전달된다면 각자의 처리기준으로 처리하여 한글이 제대로 표현될 수가 없다. Java나 C 언어가 모두 한글을 표현할 때 2바이트 공간에 한개의 문자를 저장하지만 각 바이트에 저장하는 방식은 서로 다르다는 것이다.

Java언어에서 한글은 유니코드로 표현되고, C언어에서 한글은 KSC5601 Character set 형식으로 표현하기 때문에 문자열을 전달하여 제대로 표현되기를 바라는 것은 무리일 것이다.

JNI 한글처리 해결
다행스러운 것은 Java 언어에서도 KSC5601형식의 바이트 단위 문자열로 표현해 주는 방법이 존재한다는 것이다.
그것이 바로 유니코드 문자열을 각국 문자집합으로 변환해 주는 String.getBytes("KSC5601") 메소드이다.
String.getBytes()처럼 아규먼트를 전달하지 않으면 시스템의 디폴트 문자집합이 사용된다.

또한, 그 반대로 각국 문자집합으로 표현된 바이트배열을 유니코드 문자열로 변환하는 방법도 제공하고 있는데,
String 클래스의 생성자가 그 역할을 한다.
String unicodeStr = new String(byte[] data, "KSC5601");
여기서도 마찬가지로 "KSC5601"을 사용하지 않으면 시스템의 디폴트 문자집합이 사용된다.

JNI에서 한글처리 적용
그러므로 이 원리를 JNI 프로그래밍에 적용해 보면 다음과 같은 결론이 나온다.

Java -- 한글 --> C 의 경우
Java에서 String을 getByte("KSC5601")을 사용하여 각국 문자집합의 바이트배열로 변환하여 C언어로 전달한다. JNI의 경우 Java에서 byte[]을 전달하면 C측에서는 jbyteArray형으로 받게 된다.
C언어에서는 배열을 받아서 각각의 원소를 char 배열의 원소에 복사하여 사용하면 된다.

C -- 한글 -->  Java 의 경우
C언어에서는 char 배열에 저장된 데이터를 그대로 자바로 전달한다. JNI의 경우 자바측으로 전달할 때는 jbyteArray형을 사용하고 Java에서는 byte[]배열을 받아서 다시 유니코드 문자열로 변환해서 사용하면 된다.


다음은 위에서 언급한 내용을 실제 JNI프로그램에서 적용한 예이다.
JNI Functions References : http://download.oracle.com/javase/1.4.2/docs/guide/jni/spec/functions.html#wp17314
HelloJNI.java

public class HelloJNI {

 static{
  System.loadLibrary("my_dll");  
 }

 /* 한글 문자열을 byte[] 형태로 전달하고 리턴받음 */
 public native byte[] sayHello(byte [] name);

 public static void main(String[] args) throws Exception{
      HelloJNI test = new HelloJNI();
   String name = "홍길동"; // Unicode 문자열
   /* 한글문자열을 전달하고 C함수가 추가한 문자열을 리턴받는다 */
   byte[] msg = test.sayHello(name.getBytes("KSC5601")); // C언어에서 사용하는 문자표현
   System.out.println("Java측에서 수신한 메시지:"+new String(msg)); // Unicode문자열로 변환
 }
}


HelloJNI.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloJNI */

#ifndef _Included_HelloJNI
#define _Included_HelloJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloJNI
 * Method:    sayHello
 * Signature: ([B)[B
 */

JNIEXPORT jbyteArray JNICALL Java_HelloJNI_sayHello
  (JNIEnv *, jobject, jbyteArray);

#ifdef __cplusplus
}
#endif
#endif


my_dll.c

#include "HelloJNI.h"
#include <stdio.h>

char * jbyteArray2cstr(JNIEnv *env, jbyteArray javaBytes);
jbyteArray cstr2jbyteArray( JNIEnv *env, const char *nativeStr);

JNIEXPORT jbyteArray JNICALL Java_HelloJNI_sayHello
(JNIEnv * env, jobject jobj, jbyteArray jname) {
 char * cname = jbyteArray2cstr(env, jname);
 char msg[60] = "안녕하세요? ";
 jbyteArray result;
 
 printf("C함수에서 수신한 한글문자열:%s \n", cname);

 strcat(msg, cname);
 result = cstr2jbyteArray(env, msg);
   return result;
}

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;
}

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;
}


실행결과

C함수에서 수신한 한글문자열:홍길동
Java측에서 수신한 메시지:안녕하세요? 홍길동