출처: http://www.manghon.com/blog/400
Strings in JNI
자바에서의 String 은 JNI 코드에서 jstring 타입으로 사용할 수 있다. 이 jstring 타입은 C, C++ 코드에서 바로 사용할 수는 없다. C언어의 출력 함수인 printf 함수에서 jstring 타입을 출력하려 할때 JVM에서 충돌이 일어날 수 있다. jstring 을 사용하기 위해서는 먼저 JNI 에서 제공하는 string 변환 함수들을 이용하여 C-string 타입으로 변환해야 한다.
Java 프로그램에서 native 환경으로 string 이 전달될때 UTF-8 형식으로 변경된다.
다음 그림은 UTF-8 인코딩이 메모리에서 구조화되는 모습을 보여준다.
만약 바이트의 high bit 가 1이라면 그 바이트는 멀티바이트 캐릭터의 부분이다. 이것이 의미하는 것은
ASCII 에서 사용하는 1~127까지의 값은 그대로 사용된다는 의미이고, jstring 의 모든 character 가
이 범위에 속한다면 변환없이 C/C++ 코드에서 바로 사용할 수 있음을 의미한다. 자바에서는 3바이트 보다
큰 멀티바이트 UTF-8 인코딩은 사용하지 않으며, NULL character ( ASCII 0 )은 2바이트로 표현한다.
이 의것의 의미는 모든 비트가 0인 케릭터를 가질수 없음을 의미한다.
스트링을 다루는 루틴이 하나 더 있는데, 2바이트로 인코딩된 유니코드를 사용하는 것이다. 만약 프로그램에서 지역화된 스트링(??)을 사용했을 경우, 항상 유니코드 스트링으로 처리해야 한다. 왜냐하면 UTF-8은 국제화를 지원하지 않기 때문이다.
UTF-8 을 다루는 5가지 함수가 있는데 이 함수들은 2바이트 유니코드 인코딩을 카운트할 수 있는 부분을
가진다. 또 스트링을 해제(아마 음... free 또는 delete 개념인듯) 하는 2개의 함수가 있다. 그리고 자바에서
사용되는 synchronized 기능을 위해 스트링의 lock 과 release 를 담당하는 메소드 2개가 있다.
각 함수들은 첫번째 인자로 Java environment 의 pointer 를 받는다. 이것은 자바에서 native 메소드를
호출할 때 자동으로 전달하는 인자이므로 쉽게 사용할 수 있다.
jstring NewString(const jchar *unicodeChars, jsize len);
jstring NewStringUTF(const char *bytes);
위 첫번째 NewString 함수는 jchar 의 시퀀스 (즉, 2바이트를 사용하는 jchar 타입 캐릭터의 연속)를 받고, 캐릭터의 길이를 인자로 받는다. 두번째 UTF 버전은 단순히 char (즉, byte) 의 연속을 받는다. 각 바이트들은 1, 2, 3 바이트인 멀티바이트 캐릭터일 것이다. 그리고 스트링의 끝은 2바이트 NULL 캐릭터로 나타낸다.
jsize GetStringLength(jstring string);
jsize GetStringUTFLength(jstring string);
위 두 메소드는 jstring을 인자로 받아서 유니코드와 UTF 형식일때의 캐릭터 숫자를 반환한다.
const jchar *GetStringChars(jstring string, jboolean *isCopy);
const char *GetStringUTFChars(jstring string, jboolean *isCopy);
위 두 메소드는 주어진 jstring 의 포인터를 반환한다. 이 두 메소드는 jstring 을 native 환경에서 사용하기
쉬운 string 으로 변환하기 위해 자주 사용하는 함수들이다. 이 함수가 반환한 포인터는 대응되는 버전의 ReleaseStringChars 함수가 호출되기 전까지 유효하다. 첫번째 버전은 jchar 타입의 포인터를, 두번째 버전인 UTF 버전은 jbyte(1바이트..함수의 리턴타입은 char *이다) 타입의 포인터를 리턴한다. isCopy 인자에 JNI_TRUE 를 주면 string의 복사본을 만들고 그 포인터를 리턴하고, NULL 이나 JNI_FALSE 를 주면,
복사하지 않고 원본의 포인터를 리턴한다.
다음 ReleaseStringChars 함수들은 VM 에게 native 환경에서 더 이상 스트링을 사용하지 않는다고 말한다.(free 개념인듯 가비지 콜렉팅 대상으로..ㅋ)
void ReleaseStringChars(jstring string, const jchar *chars);
void ReleaseStringUTFChars(jstring string, const char *utf);
위 함수가 호출되고 나면 더 이상 jstring 으로 들어간 인자가 가리키는 스트링은 유효하지 않게 된다.
다음 두 함수는 jstring 인자에서 start에서 시작하여 len-1 까지의 substring 을 buf 에 넣어주는 함수들이다.
void GetStringRegion(jstring str, jsize start, jsize len, jchar *buf);
void GetStringUTFRegion(jstring str, jsize start, jsize len, char *buf);
위 두 함수는 StringIndexOutOfBoundsException 을 발생시킬 수 있다.
다음 GetStringCritical 함수는 주어진 jstring 타입의 jchar * 타입 포인터를 반환한다.
이 함수는 다중 스레드 환경에서 사용되는 스트링의 잠금 역할을 한다.
const jchar *GetStringCritical(jstring string, jboolean *isCopy);
필요하다면, isCopy 인자로 스트링을 복사할 수도 있다.
이 스트링의 사용이 끝나면 ReleaseStringCritical 함수를 호출하여 잠금을 해제할 수 있다.
void ReleaseStringCritical(jstring string, const jchar *carray);
ReleaseStringCritical 함수는 GetStringCritical 함수를 호출하여 얻은 포인터를 릴리즈 한다.
=========================== 스트링을 사용하는 예제 프로그램을 첨부한다. ===========================
JNIStringFunctions.java
public class JNIStringFunctions
{
public native String replaceString(String srcStr, String strToReplce, String replaceStr);
static
{
System.loadLibrary("JNIStringFunctions");
}
public static void main(String[] args)
{
JNIStringFunctions test = new JNIStringFunctions();
String one = "manghon";
String temp = test.replaceString(one, "n", "Abc");
System.out.println( temp );
}
}
JNIStringFunctions.cpp 중에서 일부분...
JNIEXPORT jstring JNICALL Java_JNIStringFunctions_replaceString(JNIEnv *env, jobject obj, jstring _srcString, jstring _strToReplace, jstring _replString)
{
const char *searchStr, *findStr, *replStr, *found;
jstring newString = NULL;
int index;
searchStr = env->GetStringChars(_srcString, NULL);
findStr = env->GetStringChars(_strToReplace, NULL);
replStr = env->GetStringChars(_replString, NULL);
found = strstr(searchStr, findStr);
if( found != NULL )
{
char *newStringTemp;
index = found - searchStr;
newStringTemp = new char[strlen(searchStr) + strlen(replStr) + 1];
strcpy(newStringTemp, searchStr);
newStringTemp[index] = 0;
strcat(newStringTemp, replStr);
strcat(newStringTemp, &searchStr[index+strlen(findStr)]);
newString = env->NewStringUTF( (const char*)newStringTemp);
delete[] newStringTemp;
}
env->ReleaseStringUTFChars(_srcString, searchStr);
env->ReleaseStringUTFChars(_strToReplace, findStr);
env->ReleaseStringUTFChars(_replString, replStr);
return (newString);
}
아래는 완전한 이클립스 프로젝트와 비주얼 스튜디오 프로젝트를 각각 압축하여 놓았다.
'IT_Programming > Java' 카테고리의 다른 글
[펌] Jar 파일 사용 - Jar 파일에 포함된 image, 파일 로드하기 (0) | 2009.04.13 |
---|---|
[펌] Arrays in JNI (0) | 2009.04.13 |
[JDBC] Procedure Call 샘플 코드 (0) | 2009.04.13 |
[JNI] 키보드 후킹 소스 (0) | 2009.04.13 |
[펌] HTML내 본문 추출 구현.. (0) | 2009.04.12 |