경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

[JNI] 안드로이드 JNI 환경에서 C++과 Java 간의 한글 데이터 전송 문제

[출처] http://snowbora.tistory.com/371



지금은 잠깐 쉬고 있지만, 예전에 안드로이드 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] = '

[JNI] 안드로이드 JNI 환경에서 C++과 Java 간의 한글 데이터 전송 문제

[출처] http://snowbora.tistory.com/371



지금은 잠깐 쉬고 있지만, 예전에 안드로이드 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.}

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

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
18 [java 인공지능] Spring AI 로 ChatGPT API 만들기 졸리운_곰 2024.12.30 215
17 [java 인공지능] 오라클, 자바 머신러닝 라이브러리 ‘트리뷰오’ 오픈소스로 공개 졸리운_곰 2023.08.27 296
16 [java 인공지능] 자바를 위한 머신 러닝 라이브러리 졸리운_곰 2023.08.27 361
15 [Java 인공지능] 오라클, 자바 머신러닝 라이브러리 ‘트리뷰오’ 오픈소스로 공개 file 졸리운_곰 2023.08.13 358
14 [java 인공지능] [java] 라이프 게임 (life game) file 졸리운_곰 2021.10.19 341
13 How to use Weka in your Java code 졸리운_곰 2020.02.01 307
12 weka and java eclipse example : A Simple Machine Learning Example in Java file 졸리운_곰 2020.01.31 365
11 머신러닝? weka file 졸리운_곰 2020.01.31 358
10 [Weka] Weka를 이용한 Iris 데이터 머신러닝 file 졸리운_곰 2020.01.30 365
9 [강좌] WEKA 사용법 (간단한 분류, 의사결정트리 분석 설명) file 졸리운_곰 2020.01.30 344
8 [JESS] Jess , 이클립스 연동 file 졸리운_곰 2019.12.22 217
7 Jess 간단한 문법 요약 졸리운_곰 2019.12.22 278
6 Jess 6.1 다운로드 friedman-hill_src_1_jess_se file 졸리운_곰 2019.12.22 187
5 java artificial intelligence Rule Engine Jess Working Memory 졸리운_곰 2019.12.22 301
4 Defining Functions in Jess 졸리운_곰 2019.12.22 389
3 Jess Language Basics 졸리운_곰 2019.12.22 274
2 Embedding Jess in a Java Application 졸리운_곰 2019.12.22 300
1 다섯개의 탑 자바로 머신러닝 라이브러리 Top 5 machine learning libraries for Java file 졸리운_곰 2017.08.22 389
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED