Android NDK 字符编码转换及icu库ucnv_convert函数不同版本的统一使用方法
一、ICU4C及ucnv_convert概述
如果是在java层,有String类可以很好的转换各种编码,在ndk下面就没有现成的公开的工具,不过可以用icu4c。
ICU4C 是IBM的国际化开发组件ICU的C语言实现版本。在android系统里也有实现。ndk里面并没有公开可用的api,需要自己加载动态库来调用转换函数。
android下icu库路径为"/system/lib/libicuuc.so",主要用到的转换函数为ucnv_convert_*。这里的星号是根据版本的不同函数名也不一样,通常关联如下。函数名不同,导致程序的跨平台出现了问题,本文主要介绍如何在不同版本下统一使用ucnv_convert函数。
android版本号 | ucnv_convert函数名 |
android2.1 | ucnv_convert_3_8 |
android2.2 | ucnv_convert_4_2 |
android2.3 | ucnv_convert_44 |
android4.0 | ucnv_convert_46 |
android4.1 | ucnv_convert_47 |
android4.2 | ucnv_convert_48 |
android4.3 | ucnv_convert_50 |
android4.4 | ucnv_convert_51 |
android7.0 | ucnv_convert_56 |
二、函数原型及参数定义
int32_t ucnv_convert(const char *outEcd, const char *inEcd,char *outBuf, int32_t outLen,const char *inBuf, int32_t inLen,int32_t *errCode);
outEcd:目标编码格式,是输出的字符编码格式;
inEcd:原字符编码格式,是输入的字符编码格式;
outBuf:存放转换出来的字符的输出缓冲区;
outLen:outBuf输出缓冲区的大小;
inBuf:要转换的字符串指针;
inBuf:输入字符串的大小;
errCode:错误编码,该值不能为空;
返回值:整个源串inBuf转换后的字节数,该值不含'\0'结尾的长度,不受outBuf、outLen影响。
outLen与转换所需空间的关系
1.如果outLen小于转换所需空间:
1. outBuf 中会填充 outLen 所指定的转换的字节数,并且不会有 0 填充 outBuf 的结尾
2. errCode 会被置为 U_BUFFER_OVERFLOW_ERROR
2.如果outLen等于转换所需空间:
1. outBuf 中会填充 outLen 所指定的转换的字节数,并且不会有 0 填充 outBuf 的结尾
2. errCode 会被置为 U_STRING_NOT_TERMINATED_WARNING
3.如果outLen大于转换所需空间:
1. outBuf 中会填充返回值的字节数,outBuf[返回值] 处被填为 0 表示 outBuf 字符串结束
2. errCode会被置为 U_ZERO_ERROR
4.其他:
outBuf 可被置为 NULL (当然此时outLen应该为0),此时:
1. errCode 会被置为 U_BUFFER_OVERFLOW_ERROR
2. 可以使用这种方法来计算转换所需空间,但感觉不是太值
三、使用例程
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <android/log.h>#define LOG_TAG "LOG"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define SourceFile "jni/xxx.cpp"
typedef int32_t (*TUCNVCONVERT) (const char *outEcd, const char *inEcd,char *outBuf, int32_t outLen,const char *inBuf, int32_t inLen,int32_t *errCode);void *handle = NULL;
TUCNVCONVERT ucnv_convert = NULL;void init() {const char *path = "/system/lib/libicuuc.so";int libFile = open(path, O_RDONLY);if (libFile < 0) {LOGE("%s(%d): ", SourceFile, 73);LOGE("open(%s): %s\n", path, strerror(errno));return;}struct stat libBuf;if (fstat(libFile, &libBuf) < 0) {LOGE("%s(%d): ", SourceFile, 80);LOGE("fstat(%mProgress): %s\n", libFile, strerror(errno));return;}void *lib = mmap(NULL, (size_t) libBuf.st_size, PROT_READ, MAP_PRIVATE, libFile, 0);if (lib == MAP_FAILED) {LOGE("%s(%d): ", SourceFile, 85);LOGE("mmap(): %s\n", strerror(errno));return;}handle = dlopen(path, RTLD_LAZY);char *libName = (char*) memmem(lib, (size_t) libBuf.st_size, "ucnv_convert_", 13);if (libName == NULL) {LOGE("%s(%d): ", SourceFile, 93);LOGE("ucnv_convert() not find\n");return;}ucnv_convert = (TUCNVCONVERT) dlsym(handle, libName);if (ucnv_convert == NULL) {LOGE("%s(%d): ", SourceFile, 99);LOGE("dlsym(%s) return null\n", libName);return;}munmap(lib, (size_t) libBuf.st_size);
}//utf-8,gb2312,ucs4
//utf-8: 一个英文字母或者是数字占用一个字节,汉字占3个字节
//gb2312: 一个英文字母或者是数字占用一个字节,汉字占2个字节
int32_t dl_icuuc_gbk2utf8(char *outbuf, int32_t buflen, const char *instring, int32_t inlen)
{int32_t iret = 0;if (outbuf != 0 && instring != 0){if (ucnv_convert != 0){int32_t err_code = 0;iret = ucnv_convert("utf-8", "gb2312",outbuf, buflen,instring, inlen,&err_code);}}return iret;
}
int32_t dl_icuuc_utf82gbk(char *outbuf, int32_t buflen, const char *instring, int32_t inlen)
{int32_t iret;iret = 0;if (outbuf != 0 && instring != 0){if (ucnv_convert != 0){int32_t err_code = 0;iret = ucnv_convert("gb2312", "utf-8",outbuf, buflen,instring, inlen,&err_code);}}return iret;
}
int32_t dl_icuuc_unicode2utf8(char *outbuf, int32_t buflen, const unsigned short *instring, int32_t inlen)
{int32_t iret;iret = 0;if (outbuf != 0 && instring != 0){if (ucnv_convert != 0){int32_t err_code = 0;iret = ucnv_convert("utf-8", "ucs4",outbuf, buflen,(const char *)instring, inlen*sizeof(unsigned short)/sizeof(char),&err_code);}}return iret;
}
int32_t dl_icuuc_utf82unicode(unsigned short *outbuf, int32_t buflen, const char *instring, int32_t inlen)
{int32_t iret;iret = 0;if (outbuf != 0 && instring != 0){if (ucnv_convert != 0){int32_t err_code = 0;iret = ucnv_convert("ucs4", "utf-8",(char *)outbuf, buflen*sizeof(unsigned short)/sizeof(char),instring, inlen,&err_code);}}return iret;
}
Android NDK 字符编码转换及icu库ucnv_convert函数不同版本的统一使用方法相关推荐
- android 使用icon进行字符编码转换
在使用ndk开发应用程序时,有时需要字符编码转换,这里使用开源库icon进行字符编码转换,代码如下 char * convertString(const char * fromCode, const ...
- Android字符编码转换,GBK转UTF-8
Android字符编码转换,GBK转UTF-8 网上看了很多都不能用,最后看到这个方法,很靠谱,分享给大家! String str; str = new String(str.getBytes(&qu ...
- 字符编码转换类(支持多国语言)
头文件StrConvertor.h /* * 字符编码转换库,支持多国语言. */ #pragma once #include <string>class CStrConvertor { ...
- iconv 判断字符编码_iconv字符编码转换全攻略
iconv(http://www.gnu.org/software/libiconv/)是一个开源的字符编码转换库,可以"方便"的完成几乎所有的编码转换工作.说简单是因为,它常用的 ...
- c语言使用iconv函数实现字符编码转换
c语言使用iconv函数实现字符编码转换 linux下提供了iconv库来实现字符编码转换,先介绍下命令行: iconv [-f encoding] [-t encoding] [inputfile ...
- 《MySQL tips:隐式类型转换与隐式字符编码转换对查询效率的影响》
维护一个交易系统,交易记录表tradelog包含交易流水号(tradeid).交易员id(operator).交易时间(t_modified)等字段. create table 'tradelog' ...
- Qt中的字符编码转换:UTF8、Unicode、GBK、ASCII、16进制字符、16进制数值
文章目录 前言 简述 ASCII GBK Unicode UTF-8 应用场景 开发环境 编码转换 16进制数值转换为16进制字符 16进制数值转化为字符串 16进制字符串转换为Unicode字符串 ...
- iconv()和mb_conver_encoding()字符编码转换函数
2019独角兽企业重金招聘Python工程师标准>>> 一. `string iconv ( string $in_charset , string $out_charset , s ...
- 【转】Vim 字符编码转换
如果只是要简单的转换文件编码,打开后 :set fileencodings=utf-8 ,然后 w (存盘)一下即可转化为 utf8 格式, :set fileencod ...
最新文章
- 鸟哥的Linux私房菜(基础篇)-第三章、主机规划与磁盘分区(三.4. 重点回顾)
- Python学习系列day5-python基础
- 【渝粤题库】广东开放大学 会展概论 形成性考核
- mysql——decimal类型与decimal长度
- 收藏 | 使用Pytorch从头实现Canny边缘检测
- GDI+中发生一般性错误的解决办法(转帖)
- 应用开发专家一席谈:开发低代码,上手低门槛,AppCube使能Citizen Developer,人人都是开发者
- 解密flash播放器
- Windows驱动开发技术详解——经典书评
- struts2拦截器interceptor的三种配置方法
- 10分钟掌握运输问题(一)
- 【终终极版】linux(Ubuntu)下wineQQ的安装办法
- 工业机器人技术基础及其应用总结
- 单维度量表验证性因子分析_探索性因子分析(EFA)和验证性因子分析(CFA)
- 简简单单几行Python代码就能暴力破解网站登录密码,真有这么强吗?
- 微信刷票python代码_微信刷票漏洞详解, Python脚本实现一秒破万!
- 设置手机最小宽度为1000,无限重启怎么办
- QGIS进行坐标转换
- 我的 Chrome 插件集
- 九点标定和旋转中心标定后旋转点的计算