linux 宽字符与多字节字符之间的转换
- 格式:doc
- 大小:25.00 KB
- 文档页数:3
字符集之:短信中文编码的问题收藏SMS是由Esti 所制定的一个规范(GSM 03.40 和GSM 03.38)。
有两种方式来发送和接收SMS消息:文本模式或者PDU(protocol description unit)模式。
文本模式只能发送普通的ASCII字符,而要发送图片、铃声、其它编码的字符(如中文)就必须采用PDU模式。
PDU模式中,可以采用三种编码方式来编码要发送的内容,分别是7-bit编码、8-bit编码、16-bit编码。
7-bit编码用于发送普通的ASCII字符;8-bit编码通常用于发送数据消息,比如图片和铃声等;而16-bit编码用于发送Unicode字符。
在这三种编码方式下,可以发送的最大字符数分别是160、140、70。
若要发送中文(或日文等),必须采用PDU模式的Unicode编码方式。
我最近参与了一个在linux下收发短信的项目。
其中,需要实现中文的发送和接收。
由于原来没有中文编码、Unicode编码的经验,所以查了一些资料,也在一些论坛上提了一些问题。
现在把它整理出来,希望对以后再做类似项目的朋友有个帮助。
我写的比较简单,关于PDU 的规范,可以看这里:/sustain/SMS_PDU-mode.p df ,或者去wavecom的网站上找找看。
1、GB2312 编码到Unicode 编码的转换在Redhat 7.3系统上,默认是用GB2312编码保存中文字符的(对于中英文混合的文本也是如此)。
所以首先需要把GB2312 编码的字符串转换到Unicode编码的字符串。
G B2312编码是一种多字节编码方式,对于中文,用2个字节表示,对于英文,用1个字节表示,就是英文的ascii码。
(注:我没有仔细看过GB2312编码的规范,以上理解是实际开发中得出来的,不能保证正确性)。
Unicode编码是双字节编码方式,对所有字符,都采用2个字节编码。
在linux平台上,GB2312编码到Unicode编码的转换,可以有三种实现方式(或者更多):1)、用mbstowcs () 函数。
测试报告题目:超星阅读器pdg2.dll ActiveX栈溢出0day漏洞报告报告类型:漏洞分析报告提交人:张东辉[shineast]报告人背景:西安交通大学智能网络与网络安全教育部重点实验室,看雪软件安全评测中心联系方式:/shineastdh报告创建日期:2008年8月4日最后修改日期:2008年8月4日测试目标名称:超星阅读器测试目标信息:从超星的网站(/downland_index.asp)下载最新版的超星阅读器,版本4.0,更新日期是2007年5月11日,文件大小为6.8MB。
测试环境和配置:INTEL CPU,内存1G,Windows XP安全评测类别得分:(最大值2)项目:漏洞的利用:危险等级2 (漏洞会被攻击者利用威胁软件使用者个人信息安全)分析和测试工具:OLLYDBG 1.10测试周期:1天主要存在的安全性问题:该软件注册的pdg2.dll控件存在多处缓冲区溢出漏洞。
简短摘要:本报告详细分析存在于pdg2.dll ActiveX中的多处安全漏洞,并给出了对应的技术解决方案,希望能够引超星公司的重视,并尽快修复。
报告正文内容:尊敬的超星公司:您好!我是西安交通大学智能网络与网络安全教育部重点实验室的研究员,经过我们的对贵公司产品——超星阅读器的安全测试,发现该软件注册的pdg2.dll控件存在多处缓冲区溢出漏洞。
这给使用超星的广大用户带来极大的安全隐患。
本报告将详细分析存在于pdg2.dll ActiveX中的多处安全漏洞,希望能够引起贵公司的重视,并尽快修复。
漏洞分析从超星的网站(/downland_index.asp)下载最新版的超星阅读器,版本4.0,更新日期是2007年5月11日,文件大小为6.8MB。
下载后安装之,用COM Explorer 可以看到超星在你的系统上注册的几个ActiveX控件。
其中有一个是,pdg2.dll:该控件CLSID是{7F5E27CE-4A5C-11D3-9232-0000B48A05B2};文件路径在C:\WINDOWS\system32\pdg2.dll;并且可以看出这个dll确实是最新4.0版的。
linux宽字符与多字节字符之间的转换linux 宽字符与多字节字符之间的转换2008-07-17 09:411237人阅读评论(0)收藏举报最近再调linux下证书验证问题,由于要对客户端发送过来的证书在服务器上与根证书进行认证,所以在读取证书、验证证书时设计到了编码转换问题。
在windows下,使用MultiByteT oWideChar和WideCharT oMultiByte没有问题,但在linux下,不存在这两个函数,于是我们想到了用wcstombs和mbstowcs两个函数,但经试验,不能得到正确的结果,后来,经分析,得到,在windows下wchar_t为2字节,而在linux wchar_t为4字节,我们提取的证书编码为2字节的宽字符,所以不能正确地进行转换。
不得不,只能使用libiconv 进行转换。
iconv函数族的头文件是iconv.h。
#includeiconv函数族有三个函数,原型如下:(1) iconv_t iconv_open(const char *tocode, const char *fromcode);此函数说明将要进行哪两种编码的转换,tocode是目标编码,fromcode是原编码,该函数返回一个转换句柄,供以下两个函数使用。
(2) size_t iconv(iconv_t cd,char **inbuf,size_t *inbytesleft,char **outbuf,size_t*outbytesleft);此函数从inbuf中读取字符,转换后输出到outbuf中,inbytesleft 用以记录还未转换的字符数,outbytesleft用以记录输出缓冲的剩余空间。
(3) int iconv_close(iconv_t cd);此函数用于关闭转换句柄,释放资源。
经过测试,使用这转换函数需要注意的有以下几点:1、宽字节存在big-endian和little-endian之分,那使用宽字符编码时使用的编码名字也不一样,例如我们用的UCS-2编码,那有“UCS-2”和“UCS-2-INTERNAL”之分;2、iconv中的两个长度在运行完函数后,分别为分配缓存剩余字节的大小;3、而两个指针分别指向转换后字符串的尾部,所以在进行转换之前,应该保留缓存的原始指针,在转换后,用这两个指针减去原始指针,那就是已转换的字节长度和转换后的字节长度。
MultiByteToWideChar和WideCharToMultiByte用法详解注意:这两个函数是由Windows提供的转换函数,不具有通用性C语言提供的转换函数为mbstowcs()/wcstombs()一、函数简单介绍涉及到的头文件:函数所在头文件:windows.h#include <windows.h>wchar_t类型所需头文件:wchar.h#include <wchar.h>( 1 ) MultiByteToWideChar()函数功能:该函数映射一个字符串到一个宽字符(unicode)的字符串。
由该函数映射的字符串没必要是多字节字符组。
函数原型:int MultiByteToWideChar(UINT CodePage,DWORD dwFlags,LPCSTR lpMultiByteStr,int cchMultiByte,LPWSTR lpWideCharStr,int cchWideChar);参数:1> CodePage:指定执行转换的多字节字符所使用的字符集这个参数可以为系统已安装或有效的任何字符集所给定的值。
你也可以指定其为下面的任意一值:2> dwFlags:一组位标记,用以指出是否未转换成预作或宽字符(若组合形式存在),是否使用象形文字替代控制字符,以及如何处理无效字符。
你可以指定下面是标记常量的组合,含义如下:MB_PRECOMPOSED:通常使用预作字符——就是说,由一个基本字符和一个非空字符组成的字符只有一个单一的字符值。
这是缺省的转换选择。
不能与MB_COMPOSITE值一起使用。
MB_COMPOSITE:通常使用组合字符——就是说,由一个基本字符和一个非空字符组成的字符分别有不同的字符值。
不能与MB_PRECOMPOSED值一起使用。
MB_ERR_INVALID_CHARS:如果函数遇到无效的输入字符,它将运行失败,且GetLastErro返回ERROR_NO_UNICODE_TRANSLATION 值。
浅析Solaris移植到linux的大小字节序问题市场部/林铮一. 前言随着 Linux 操作系统的逐渐普及,很多公司都在考虑如何将已有的Solaris应用程序和开发环境移植到 Linux上。
本文对C/C++语言从solaris(32bit)移植到linux(32bit)环境上的过程中,可能遇到的大小字节序的问题和解决方案进行说明。
当有2个字节以上的数值存入计算机内存或是文档的时候,又或是进行数据转送的时候,我们要考虑先把哪个位置的字节存入内存地址的高位?或是要先转送哪个位置的数据?像这样的次序考虑,就称为endian或者是byte order(字节序)。
Little endian(小端):按照最低字节在地址最低位,最高字节在地址最高位的顺序排列。
Big endian(大端):按照最高字节在地址最低位,最低字节在地址最高位的顺序排列。
字节序是根据CPU的构造来来决定的。
一般来说,Solaris 是大端,而Linux则是小端。
比如,要将这个为0x12345678的32bit(4字节)的16进制常量,其按照不同的字节序存入内存时,其排列如下:Big endian(Solaris):内容 12345678地址 0 1 2 3 Little endian(Linux):内容 78563412地址 0 1 2 3 二. 大小字节序对移植的影响字节序的移植性问题的话,只对short, int, long, float, double, pointer等多字节的类型有影响,而对单字节(char 型等),或是字符串是没有影响的。
例如:int size;char data[7];把十进制数10,和字符串"012345"分别赋值到size和data,在字节序不同的机器中,对size和data进行二进制转送,结果如下:像这样的字节序的不同,当在字节序不同的机器(OS)间进行二进制数据文档共享的时候,或是通过网络进行通信的时候,就会产生问题。
char*与wchar_t*之间的转换1.问题描述char字符与wchar_t字符由于编码不同,所以在char*和wchar_t之间使用强制类型转换达不到正确转换字符串的目的。
考察如下程序。
#include<iostream>usingnamespace std;int main(){wchar_t* str=L"ABC我们";char* s=(char*)str;cout<<s<<endl;}输出结果出错:只输出A。
经过强制类型转换,s指向了宽字符编码字符串,字符串数据没有发生任何变化,只是用多字节字符字符编码重新对它进行解释,自然输出的结果是错误的。
2.char*与wchar_t*之间相互转换要想将宽字符编码字符串转换成多字节编码字符串(或者反过来),必须先读懂原来的字符串,然后再重新对它进行编码。
只有这样才能到达转换的目的。
由于宽字符可以表示多国语言的文字,因此,下文的讨论限于中文的宽字符串与多字节字符串之间的相互转换。
在不同的才做系统上,有一些特殊的库函数可以用来进行字符编码之间的转换。
在VC++中,其中关键的几个函数是setlocale()、wcstombs_s()和mbstowcs_s()。
2.1关键函数简介(1)setlocale()功能:配置地域化信息头文件:#include <locale.h>函数原型:char *setlocale (int category, const char * locale);函数参数:category表示对本地化的某项内容进行设置,可取如下值:LC_ALL 包括下面的全部选项都要;LC_COLLATE 配置字符串比较;C_CTYPE 配置字符类别及转换,例如全变大写strtoupper();LC_MONETARY 配置金融货币;LC_NUMERIC 配置小数点后的位数;LC_TIME 配置时间日期格式,与strftime() 合用。
多字节与宽字节stringwstring互转多字节字符集(MBCS,Multi-Byte Chactacter Set):指⽤多个字节来表⽰⼀个字符的字符编码集合。
⼀般英⽂字母⽤1Byte,汉语等⽤2Byte来表⽰。
兼容ASCII 127。
在最初的时候,Internet上只有⼀种字符集——ANSI的ASCII字符集,它使⽤7 bits来表⽰⼀个字符,总共表⽰128个字符,其中包括了英⽂字母、数字、标点符号等常⽤字符。
为了扩充,以⽤于显⽰本国的语⾔,不同的国家和地区制定了不同的标准,由此产⽣了 GB2312, BIG5, JIS 等各⾃的编码标准。
这些使⽤ 2个来代表⼀个字符的各种汉字延伸编码⽅式,称为 ANSI 编码,⼜称为"MBCS(Muilti-Bytes Charecter Set,多字节字符集)"。
不同 ANSI 编码之间互不兼容,当信息在国际间交流时,⽆法将属于两种语⾔的⽂字,存储在同⼀段 ANSI 编码的⽂本中。
⼀个很⼤的缺点是,同⼀个编码值,在不同的编码体系⾥代表着不同的字。
这样就容易造成混乱。
导致了unicode码的诞⽣。
宽字节字符集:⼀般指Unicode编码的字符集,Unicode称为统⼀码或万国码,统⼀了不同国家的字符编码。
Unicode通常⽤两个字节表⽰⼀个字符,原有的英⽂编码从单字节变成双字节,只需要把⾼字节全部填为0就可以。
为了统⼀所有⽂字的编码,Unicode应运⽽⽣。
Unicode把所有语⾔都统⼀到⼀套编码⾥,这样就不会再有乱码问题了。
Unicode固然统⼀了编码⽅式,但是它的效率不⾼,⽐如UCS-4(Unicode的标准之⼀)规定⽤4个字节存储⼀个符号,那么每个英⽂字母前都必然有三个字节是0,这对存储和传输来说都很耗资源。
为了提⾼Unicode的编码效率,于是就出现了UTF-8编码。
UTF-8可以根据不同的符号⾃动选择编码的长短。
⽐如英⽂字母可以只⽤1个字节就够了。
linux中将字符串转换为数组的方法-概述说明以及解释1.引言1.1 概述概述部分应该对文章主题进行简要的介绍和概括。
对于这篇文章,我们可以概述如下:在Linux系统中,经常会遇到需要将字符串转换为数组的情况。
无论是在Shell脚本编程还是在命令行操作中,对字符串进行拆分并存储到数组中是一项常见的任务。
本文将介绍三种常用的方法来实现这一目标。
方法一是使用split函数进行字符串分割,该函数能够根据指定的分隔符将字符串拆分成多个子字符串,并将其存储到数组中。
这种方法简单直接,适合处理简单的字符串拆分需求。
方法二是使用正则表达式进行字符串匹配,通过正则表达式的特性,我们可以定义更复杂的拆分规则。
这种方法更加灵活,适用于处理表达式较为复杂的字符串拆分情况。
方法三是使用循环遍历字符串进行字符拆分,通过遍历字符串中的每个字符并判断其是否为分隔符,将字符串按照指定规则进行拆分并存储到数组中。
这种方法相对较为繁琐,但在某些情况下可以提供更高的灵活性。
本文将详细介绍上述三种方法的具体实现步骤,并对它们的优缺点进行分析。
最后,我们将讨论这些方法的应用场景,以帮助读者根据实际需求选择合适的方法。
通过本文的学习,读者将能够掌握在Linux中将字符串转换为数组的方法,为其后续的开发和操作提供更多的可能性。
1.2 文章结构文章将分为以下几个部分:1. 引言:对Linux中将字符串转换为数组的方法进行概述,并介绍本文的目的和总结。
2. 正文:详细介绍了三种方法将字符串转换为数组的步骤和具体实现。
2.1 方法一:使用split函数进行字符串分割。
这一部分将介绍split 函数的使用方法,并提供示例代码演示如何将字符串根据指定的分隔符进行分割,并将结果存储到数组中。
2.2 方法二:使用正则表达式进行字符串匹配。
这一部分将解释如何使用正则表达式来匹配字符串,并提取其中的内容,并通过示例代码展示如何将匹配到的结果存储到数组中。
2.3 方法三:使用循环遍历字符串进行字符拆分。
高低字节序转换(htonl、ntohl、htons、ntohs函数)Part 1: htons函数具体解释在Linux和Windows网络编程时需要用到htons和htonl函数,用来将主机字节顺序转换为网络字节顺序。
在Intel机器下,执行以下程序int main()...{printf("%d /n",htons(16));return 0;}得到的结果是4096,初一看感觉很怪。
解释如下,数字16的16进制表示为0x0010,数字4096的16进制表示为0x1000。
由于Intel机器是小尾端,存储数字16时实际顺序为1000,存储4096时实际顺序为0010。
因此在发送网络包时为了报文中数据为0010,需要经过htons进行字节转换。
如果用IBM 等大尾端机器,则没有这种字节顺序转换,但为了程序的可移植性,也最好用这个函数。
另外用注意,数字所占位数小于或等于一个字节(8 bits)时,不要用htons转换。
这是因为对于主机来说,大小尾端的最小单位为字节(byte)。
Part 2: 大小端模式不同的CPU有不同的字节序类型这些字节序是指整数在内存中保存的顺序这个叫做主机序最常见的有两种1. Little endian:将低序字节存储在起始地址2. Big endian:将高序字节存储在起始地址LE little-endian最符合人的思维的字节序地址低位存储值的低位地址高位存储值的高位怎么讲是最符合人的思维的字节序,是因为从人的第一观感来说低位值小,就应该放在内存地址小的地方,也即内存地址低位反之,高位值就应该放在内存地址大的地方,也即内存地址高位BE big-endian最直观的字节序地址低位存储值的高位地址高位存储值的低位为什么说直观,不要考虑对应关系只需要把内存地址从左到右按照由低到高的顺序写出把值按照通常的高位到低位的顺序写出两者对照,一个字节一个字节的填充进去例子:在内存中双字0x01020304(DWORD)的存储方式内存地址4000 4001 4002 4003LE 04 03 02 01BE 01 02 03 04例子:如果我们将0x1234abcd写入到以0x0000开始的内存中,则结果为big-endian little-endian0x0000 0x12 0xcd0x0001 0x23 0xab0x0002 0xab 0x340x0003 0xcd 0x12x86系列CPU都是little-endian的字节序.网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。
linux 宽字符与多字节字符之间的转换
2008-07-17 09:411237人阅读评论(0)收藏举报最近再调linux下证书验证问题,由于要对客户端发送过来的证书在服务器上与根证书进行认证,所以在读取证书、验证证书时设计到了编码转换问题。
在windows下,使用MultiByteToWideChar和WideCharT oMultiByte没有问题,但在linux下,不存在这两个函数,于是我们想到了用wcstombs和mbstowcs两个函数,但经试验,不能得到正确的结果,后来,经分析,得到,在windows下wchar_t为2字节,而在linux wchar_t为4字节,我们提取的证书编码为2字节的宽字符,所以不能正确地进行转换。
不得不,只能使用libiconv 进行转换。
iconv函数族的头文件是iconv.h。
#include <iconv.h>
iconv函数族有三个函数,原型如下:
(1) iconv_t iconv_open(const char *tocode, const char *fromcode);
此函数说明将要进行哪两种编码的转换,tocode是目标编码,fromcode是原编码,该函数返回一个转换句柄,供以下两个函数使用。
(2) size_t iconv(iconv_t cd,char **inbuf,size_t *inbytesleft,char **outbuf,size_t
*outbytesleft);
此函数从inbuf中读取字符,转换后输出到outbuf中,inbytesleft用以记录还未转换的字符数,outbytesleft用以记录输出缓冲的剩余空间。
(3) int iconv_close(iconv_t cd);
此函数用于关闭转换句柄,释放资源。
经过测试,使用这转换函数需要注意的有以下几点:
1、宽字节存在big-endian和little-endian之分,那使用宽字符编码时使用的编码名字也不一样,例如我们用的UCS-2编码,那有“UCS-2”和“UCS-2-INTERNAL”之分;
2、iconv中的两个长度在运行完函数后,分别为分配缓存剩余字节的大小;
3、而两个指针分别指向转换后字符串的尾部,所以在进行转换之前,应该保留缓存的原始指针,在转换后,用这两个指针减去原始指针,那就是已转换的字节长度和转换后的字节长度。
下面是我测试的代码,程序写的不怎么考究,呵呵!
#include <iconv.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <locale.h>
#define BUFLEN 200
char outBuf[BUFLEN];
//char inBuf[BUFLEN]="CN";
char inBuf[BUFLEN]="/x43/x00/x4e/x00/x00/x00";
//char inBuf[BUFLEN]="/x7a/x7a/x51/x9b/x00/x00";
int main(){
char *pIn = inBuf;
char *pOut = outBuf;
iconv_t cd;
int inLen = 4, outLen = BUFLEN;
int retSize = 0;
cd = iconv_open("UTF-8","UCS-2-INTERNAL");
// cd = iconv_open("UCS-2-INTERNAL","UTF-8");
if ((iconv_t)-1 == cd){
printf("Donot support this convert../n");
return -1;
}
if ((size_t)-1 == (retSize= iconv(cd, &pIn, (size_t *)&inLen, &pOut,(size_t
*)&outLen))){
if (E2BIG == errno)
printf(" E2BIG errno %d/n", errno);
if (EILSEQ == errno)
printf("EILSEQ errno %d/n", errno);
if (EINVAL == errno)
printf("EINVAL errno %d/n", errno);
printf("convert WCHAR to multi error/n");
return -1;
}
if (outLen > 0){
printf("/n/n outBuf:");
int i = 0;
for (i = 0; i < 200; i++){
printf("%02x ", outBuf[i]);
}
printf("/n/n inBuf:");
for (i = 0; i < 200; i++){
printf("%02x ", inBuf[i]);
}
printf("/n/n");
}
printf("out buf: %s outLen: %d retSize: %d inLen: %d/n", pOut, outLen, retSize, inLen);
printf("pInbuf: %s/n", pIn);
iconv_close(cd);
return 0;
}。