加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

JNI 实现 Java String 与 char 数组互相转换函数

(2012-12-10 19:19:15)
标签:

杂谈

分类: 开源项目之Android
#include <stdio.h>
#include <string.h>

#include <android/log.h>

#ifndef LOGV
    #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "https2auth", __VA_ARGS__)
#endif

#ifndef LOGD
    #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG  , "https2auth", __VA_ARGS__)
#endif

#ifndef LOGI
    #define LOGI(...) __android_log_print(ANDROID_LOG_INFO   , "https2auth", __VA_ARGS__)
#endif

#ifndef LOGW
    #define LOGW(...) __android_log_print(ANDROID_LOG_WARN   , "https2auth", __VA_ARGS__)
#endif

#ifndef LOGE
    #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR  , "https2auth", __VA_ARGS__)
#endif

#include <jni.h>

#ifndef IN
    #define IN
#endif

#ifndef OUT
    #define OUT
#endif

// 由 Java String 转为指定编码的 char 数组
// 注:调用者再传入 puiOutputStringLen 参数指针值时,一定要是 unsigned int 类型的变量指针,
//   如果将 unsigned char 类型的变量地址强制转换后传入,会在传出值时覆盖四个字节,就会出现内存越界的问题!!!
int
jstring2pchar( IN     JNIEnv*             env,                 // JNI 本地接口指针
               IN     jstring             jniInputString,      // Java层传下来的字符串
               IN     const char*         pcEncoding,          // 可以指定转换为的编码
               OUT    char* const         pcOutputString,      // 返回转换后的字符串,若为 NULL 仅是取所需字节个数
               IN OUT unsigned int* const puiOutputStringLen ) // 返回转换后的字节个数(不含‘\0’)
{
    // 返回值
    int iResult = 0; // 零为成功

    // Java 字符串的类和获取字节的方法ID
    jclass    jniStringClass = NULL;
    jmethodID jniGetBytesMethodID = NULL;

    // 指定转换字符串时用的编码格式
    jstring jniEncoding = NULL;

    // 取得 字符串 转换成 字节数组
    jbyteArray jniByteArray = NULL;
    // 取得 字符串 转换成 字节数组 的字节个数
    jsize jniByteArraySize = 0;
    // 基本类型 - 字节数组
    jbyte* jniPrimitiveByteArray = NULL;

    do // 非循环,只是为了减少分支缩进
    {
        // 要转换的字符串或要传出字节个数的变量指针为 NULL 时
        if ( ( NULL == env )              ||
             ( NULL == jniInputString )   ||
             ( NULL == pcOutputString )   ||
             ( NULL == puiOutputStringLen ) )
        {
            __android_log_print( ANDROID_LOG_INFO,
                                 "jstring2pchar",
                                 "Parameter is invalid!" );
            iResult = -1;
            break;
        }


        // 指定字符串编码格式
        if ( NULL  == pcEncoding )
        {
            jniEncoding = (*env)->NewStringUTF( env, "utf-8" );
        }
        else
        {
            jniEncoding =(*env)->NewStringUTF( env, pcEncoding );
        }

        if ( NULL == jniEncoding )
        {
            __android_log_print( ANDROID_LOG_INFO,
                                 "jstring2pchar",
                                 "Call NewStringUTF to get specific encoding failed!" );
            iResult = -2;
            break;
        }

        // 获取 Java String 类和回调方法 I D信息,
        // 也可以用全局变量记下来,免得浪费时间重复执行。
        jniStringClass = (*env)->FindClass( env,
                                            "java/lang/String" );

        if ( NULL == jniStringClass )
        {
            __android_log_print( ANDROID_LOG_INFO,
                                 "jstring2pchar",
                                 "Call FindClass to get java/lang/String failed!" );
            iResult = -3;
            break;
        }

        // 得到 String 类的 getBytes 方法
        jniGetBytesMethodID = (*env)->GetMethodID( env,
                                                   jniStringClass,
                                                   "getBytes",
                                                   "(Ljava/lang/String;)[B" );

        if ( NULL == jniGetBytesMethodID )
        {
            __android_log_print( ANDROID_LOG_INFO,
                                 "jstring2pchar",
                                 "Call GetMethodID to get getBytes method failed!" );
            iResult = -4;
            break;
        }

        // 从 字符串 中得到指定编码的 字节数组
        jniByteArray = (jbyteArray)(*env)->CallObjectMethod( env,
                                                             jniInputString,
                                                             jniGetBytesMethodID,
                                                             jniEncoding );

        if ( NULL == jniByteArray )
        {
            __android_log_print( ANDROID_LOG_INFO,
                                 "jstring2pchar",
                                 "Call NewStringUTF to get specific encoding failed!" );
            iResult = -5;
            break;
        }

        // 取得 字符串 转换成 字节数组 的字节个数
        jniByteArraySize = (*env)->GetArrayLength( env, jniByteArray );

        if ( 0 >= jniByteArraySize )
        {
            __android_log_print( ANDROID_LOG_INFO,
                                 "jstring2pchar",
                                 "Call GetArrayLength to get array length failed!" );
            iResult = -6;
            break;
        }

        // 返回原始数组的实体,需要对应调用 ReleaseByteArrayElements 来释放返回值
        jniPrimitiveByteArray = (*env)->GetByteArrayElements( env,
                                                              jniByteArray,
                                                              NULL ); // 不关心是否产生拷贝

        if ( NULL == jniPrimitiveByteArray )
        {
            __android_log_print( ANDROID_LOG_INFO,
                                 "jstring2pchar",
                                 "Call GetByteArrayElements to get array pointer failed!" );
            iResult = -7;
            break;
        }

        if ( ( NULL != pcOutputString ) &&
             ( jniByteArraySize > *puiOutputStringLen ) )
        {
            __android_log_print( ANDROID_LOG_INFO,
                                 "jstring2pchar",
                                 "pcOutputString is less than need!" );
            iResult = -8;
            break;
        }

        if ( NULL != pcOutputString )
        {
            memset( pcOutputString, 0, *puiOutputStringLen );
            memcpy( pcOutputString, jniPrimitiveByteArray, jniByteArraySize );
        }

        // 返回转换后的字节个数(不含‘\0’) - 四字节内容覆盖
        *puiOutputStringLen = jniByteArraySize;

        break; // 正常流程到此结束
    } while ( 0 );

    if ( NULL != jniPrimitiveByteArray )
    {
        // 与 GetByteArrayElements 函数对应,释放其返回值指向的数组
        (*env)->ReleaseByteArrayElements( env,
                                          jniByteArray,
                                          jniPrimitiveByteArray,
                                          0 ); // 复制回内容并释放 参数三 的缓冲区
        jniPrimitiveByteArray = NULL;
    }

    return iResult;
}

// 指定编码且以零('\0')结束的 char 数组转为 Java String
jstring
pchar2jstring( IN  JNIEnv*     env,
               IN  const char* pcInputString,
               OUT const char* pcEncoding )
{
    // 待返回的 Java String
    jstring jniReturnString = NULL;

    // Java 字符串的类和获取字节的方法ID
    jclass    jniStringClass = NULL;
    jmethodID jniInitMethodID = NULL;

    // 指定转换字符串时用的编码格式
    jstring jniEncoding = NULL;

    // 取得 字符串 转换成 字节数组
    jbyteArray jniByteArray = NULL;

    do // 非循环,只是为了减少分支缩进
    {
        // 要转换的字符串或要传出字节个数的变量指针为 NULL 时
        if ( ( NULL == env )           || 
             ( NULL == pcInputString ) ||
             ( '\0' == *pcInputString ) )
        {
            __android_log_print( ANDROID_LOG_INFO,
                                 "pchar2jstring",
                                 "Parameter is invalid!" );
            break;
        }

        // 指定字符串编码格式
        if ( NULL  == pcEncoding )
        {
            jniEncoding = (*env)->NewStringUTF( env, "utf-8" );
        }
        else
        {
            jniEncoding =(*env)->NewStringUTF( env, pcEncoding );
        }

        if ( NULL == jniEncoding )
        {
            __android_log_print( ANDROID_LOG_INFO,
                                 "jstring2pchar",
                                 "Call NewStringUTF to get specific encoding failed!" );
            break;
        }

        // 获取 Java String 类和回调方法 I D信息,
        // 也可以用全局变量记下来,免得浪费时间重复执行。
        jniStringClass = (*env)->FindClass( env,
                                            "java/lang/String" );

        if ( NULL == jniStringClass )
        {
            __android_log_print( ANDROID_LOG_INFO,
                                 "jstring2pchar",
                                 "Call FindClass to get java/lang/String failed!" );
            break;
        }

        jniInitMethodID = (*env)->GetMethodID( env,
                                               jniStringClass,
                                               "",
                                               "([BLjava/lang/String;)V" );

        if ( NULL == jniInitMethodID )
        {
            __android_log_print( ANDROID_LOG_INFO,
                                 "jstring2pchar",
                                 "Call GetMethodID to get failed!" );
            break;
        }

        // 新建一个字节数组
        jniByteArray = (*env)->NewByteArray( env, strlen( pcInputString ) );

        // 将基本类型数组中的某一区域从缓冲区中复制过来
        (*env)->SetByteArrayRegion( env,
                                    jniByteArray,            // Java 数组
                                    0,                       // 起始下标
                                    strlen( pcInputString ), // 要复制的元素个数
                                    (jbyte*)pcInputString ); // 来源缓冲区

        // 用新建的字节数组来构建 Java String
        jniReturnString = (jstring)(*env)->NewObject( env,
                                                      jniStringClass,
                                                      jniInitMethodID,
                                                      jniByteArray,
                                                      jniEncoding );
    } while ( 0 );

    return jniReturnString;
}

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有