Notice
Recent Posts
Recent Comments
Link
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
Archives
Today
Total
02-05 00:07
관리 메뉴

zyint's blog

한글 문자열 깨짐 문제 본문

예전글들

한글 문자열 깨짐 문제

진트­ 2008. 2. 3. 16:26

요약

자바 JNI를 통해서 문자열을 jstring 타입으로 넘길 경우 2 바이트를 사용하는 유니코드 등의 한글과 같은 문자는 깨짐 현상이 발생하게 된다. 여기에서는 이러한 글자 깨짐 현상을 해결하고자 한다.

 

소스코드 다운로드

JNINativeStringUtil.zip

 

주의할 점

Java쪽에서 넘겨 받은 문자열을 "jstring string" 변수에 저장하였을 때 C언어에서 사용할 수 있는 문자열로 가공하려면,

 

  1. char * cString;
    /* 최종 C 문자열을 가리킬 포인터 */
    jbyteArray jba;
    jba = javaGetBytes(env, string);
    cString = jbyteArray2cstr(env, jba);
    /* cString 이 C어언에서 사용할 수 있는 문자열이다. 이것을 사용한 후에 필히 메모리를 free해줘야만 한다.
    그렇지 않으면 메모리 누수로 어플리케이션이 죽는다. */
    free(cString); 

 

보시다시피 Java 문자열에서 C 문자열로 변환한 뒤에 필히 메모리를 free해야만 한다.

 

소스코드

NativeStringUtil.h

  1. #ifndef _Included_NativeStringUtil
    #define _Included_NativeStringUtil
    #ifdef __cplusplus
    extern "C" {
    #endif
    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 );
    #ifdef __cplusplus
    }
    #endif
    #endif 

 

NativeStringUtil.c

  1. /*
     * @(#)NativeStringUtil.c 1.0 98/01/02 Deogtae Kim (dtkim@calab.kaist.ac.kr)
     */
    #include <stdlib.h>
    #include <string.h>
    #include <jni.h>
    #include "NativeStringUtil.h"
    /* 효율성을 높이기 위한 캐슁 변수 */
    static jclass class_String;
    static jmethodID mid_getBytes, mid_getBytesEncoding;
    static jmethodID mid_newString, mid_newStringEncoding;
  2. /* 자바 바이트 배열로부터 C 문자열을 생성하여 반환
     */
    char *jbyteArray2cstr( JNIEnv *env, jbyteArray javaBytes )
    {
        size_t len = (*env)->GetArrayLength(env, javaBytes);
        jbyte *nativeBytes = (*env)->GetByteArrayElements(env, javaBytes, 0);
        char *nativeStr = malloc(len+1);
        strncpy( nativeStr, nativeBytes, len );
        nativeStr[len] = '\0';
        (*env)->ReleaseByteArrayElements(
            env, javaBytes, nativeBytes, JNI_ABORT);
        return nativeStr; /* ML(Memory Loss 발생 */
    }
    /* 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;
    }
  3. /* 자바 스트링을 디폴트 인코딩의 자바 바이트 배열로 변환.
     * 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 );
    }
  4. /* 자바 스트링을 지정된 인코딩 `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));
    }
  5. /* 디폴트 인코딩의 자바 바이트 배열을 자바 스트링으로 변환.
     * 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 );
    }
  6. /* 지정된 인코딩 `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;
    }

 

 

출처

http://blog.naver.com/mismir?Redirect=Log&logNo=40011464831

 

 

이 글은 스프링노트에서 작성되었습니다.

Comments