Test on using JNI callback in C/C ++ code of Android ndk to implement character encoding conversion (Chinese utf8 and GBK)

Source: Internet
Author: User

During network transmission under the ndk, an encoding conversion problem occurs, that is, the file name uploaded by the other party is GBK encoded in Chinese and needs to be converted to utf8 for processing.

 

When programming in C/C ++, the system provides the character encoding conversion API. For example, functions such as multibytetowidechar and iconv library are available in windows, and wcstombs and mbstowcs can be used in pure C. However, I did not find the iconv library under the android ndk directory on my machine, and I could not compile the iconv function by writing it directly. However, the local library required by mbstowcs does not seem to exist, even if it can be compiled, it will fail to run. As a result, it seems that there is no way to manually write the code table library for conversion.

 

Later, I came up with a method: Because ndk in Android is called by Java JNI, and the character encoding conversion function of Java itself is ready-made, a new string is directly used to pass in bytes and encoding, you can get the character of another encoding.

 

Through online data query and testing, the compilation and operation are finally passed and the problem is solved. The JNI code is not pasted in Java. The content and description of the C program are as follows:

 

 

// First include the header file and define the global variable # include <string. h> # include <JNI. h> # include <pthread. h> // The initial jni vm environment and thread JavaVM * gjavavm; jnienv * gjnienv; pthread_t gjvmthread; // Java string class and the method for obtaining bytes idjclass gstringclass; jmethodid gmidstringinit; jmethodid gmidstringgetbytes; // initialize the JNI environment. JNI calls jstring evaluate (jnienv * ENV, jobject OBJ) {(* env)-> getjavavm (ENV, & gjavavm ); gjnienv = env; gjvmthread = pthread_self (); // remember the thread of the current JNI environment // obtain the Java string class and callback method ID information, because every conversion is required, therefore, use global variables to write them down, so that you do not waste time executing gstringclass = (* env)-> findclass (ENV, "Java/lang/string"); gmidstringgetbytes = (* env) -> getmethodid (ENV, gstringclass, "getbytes", "(ljava/lang/string;) [B"); gmidstringinit = (* env)-> getmethodid (ENV, gstringclass, "<init>", "([bljava/lang/string;) V ");... return (* env)-> newstringutf (ENV, "OK");} // convert from Java string to charint jstringtopchar (jnienv * ENV, jstring jstr, const char * encoding, char * outbuf, int outlen) {char * RTN = NULL; jstring jencoding; If (encoding = hnull) jencoding = (* env) -> newstringutf (ENV, "UTF-8"); else jencoding = (* env)-> newstringutf (ENV, encoding); jbytearray Barr = (jbytearray) (* env) -> callobjectmethod (ENV, jstr, gmidstringgetbytes, jencoding); jsize Alen = (* env)-> getarraylength (ENV, Barr); jbyte * Ba = (* env) -> getbytearrayelements (ENV, Barr, jni_false); If (Alen> 0) {If (outlen = 0) return Alen; If (outlen <= Alen) Return-1; RTN = outbuf; memcpy (RTN, Ba, Alen); RTN [Alen] = 0;} (* env)-> releasebytearrayelements (ENV, Barr, Ba, 0 ); return Alen;} // convert the specified zero-end Char to Java stringjstring pchartojstring (jnienv * ENV, const char * Pat, const char * encoding) {jstring jencoding; jbytearray bytes = (* env)-> newbytearray (ENV, strlen (PAT); (* env)-> setbytearrayregion (ENV, bytes, 0, strlen (PAT ), (jbyte *) Pat); If (encoding = hnull) jencoding = (* env)-> newstringutf (ENV, "UTF-8"); else jencoding = (* env) -> newstringutf (ENV, encoding); Return (jstring) (* env)-> newobject (ENV, gstringclass, gmidstringinit, bytes, jencoding );} // perform string encoding conversion in C code // The parameters are: original character, original encoding, target character buffer, target encoding, and target buffer size, return the length of the Conversion Result int changecharset (char * src_buf, char * src_encoding, char * dst_buf, char * dst_encoding, int dst_size) {jnienv * env; jstring jtemp; int res; // because the initialization is only executed once, this function and the initial JNI call may not be in the same thread, so you need to determine the current thread if (gjvmthread = pthread_self ()) {// if it is the same thread, directly convert it to Env = gjnienv; jtemp = pchartojstring (ENV, src_buf, src_encoding); Res = jstringtopchar (ENV, jtemp, dst_encoding, dst_size);} else {// if it is not the same thread, attach it first and then Env = gjnienv; (* gjavavm)-> attachcurrentthread (gjavavm, & ENV, null ); jtemp = pchartojstring (ENV, src_buf, src_encoding); Res = jstringtopchar (ENV, jtemp, temperature, distance, dst_size); (* gjavavm)-> detachcurrentthread (gjavavm );} return res ;}

 

Although JNI callback can solve this problem, it is difficult to use and the speed is estimated to be slow. It is suitable for a small amount of data processing. It is estimated that the new Android ndk version will solve this problem in the future.

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.