大端小端,ascii,unicode,utf8,utf16,utf32,gb2312,gbk,gb18030等字符编码问题

字符编码的问题让我困惑了好久的一段时间,其实简单的想,字符编码没有什么东西的,可是想真弄明白还是花去了我一点时间,前端时间写了一个简单的log程序,主要的工作就是支持系统运行时输出日志信息,同时允许定制不同级别的日志输出,刚开始的时候只是写入到文件中,可用过之后发现,只是写入到文件中,在进行系统调试的时候不是很方便,还要打开文件,浏览,再返回源代码,如果能够有一个界面展示岂不是更好,列表显示日志,可以选择显示的日志级别,实现日志输出位置的定位,类似下图中展示的一样:

大端小端,ascii,unicode,utf8,utf16,utf32,gb2312,gbk,gb18030等字符编码问题_第1张图片

感觉还是能方便一点的,而显示窗口的实现可以通过exe或者dll的方式,这就需要进行两个独立进程之间的通信,为了支持多个日志显示窗口,我要枚举现在打开的窗口比较窗口名,还要创建命名管道,比较管道名,不幸的是,log显示窗口系统用的是unicode编码,而在写日志主系统程序的时候用的却是多字节编码,在进行通信的时候总是出现这样那样的问题,同时为了使得log主系统可以在服务的主程序选用不同的字符编码方案的时候可以正常工作,费了点事情,因为当时对字符编码不了解,然后就去网上查了下,总结一下子,同时,为了使用方便,写了一个VAUTF8类实现UTF8编码方案,同时实现不同编码方案的转化。

    这篇文章里主要阐述下面几个问题

    1: 字符和字节的区别

    2: Big Endian和Little Endian

    3: ASCII

    4: Unicode的定义

    5: Unicode的编码方案

    6: Unicode的实现方式

    7: 一些名词解释

字符和字节的区别

字节(octet):是一个八位的存储单元,取值范围一定是0~255。

字符(character):为语言意义上的符号,范围不一定。例如在UCS-2中定义的字符范围为0~65535,一个字符占用两个字节。

Big Endian和Little Endian

上面提到了一个字符可能占用多个字节,那么这多个字节在计算机中如何存储呢?比如字符0xABCD,它的存储格式到底是 AB CD,还是 CD AB 呢?

实际上两者都有可能,并分别有不同的名字。如果存储为 AB CD,则称为Big Endian;如果存储为 CD AB,则称为Little Endian

Big Endian:高字节在前,低字节在后

Little Endian:低字节在前,高字节在后

X86系统都是Little Endian的,也就是低字节在前,高字节在后.也就是低地址存储低位字节,高地址存储高位字节.

ASCII

ASCII使用数字32到 127来表示所有的英文字母,比如空格是32,字母"A"是65等等。使用7个比特就可以存储所有这样字符。那个时代的大多数计算机使用8个比特来,所以你不但可以存储全部的ASCII,而且还有一个比特可以多出来用作其他。如果你想,你可以把它用作你不可告人的目的。32以下的码字是不可打印的,它们属于控制字符,像7表示响铃,12表示打印机换纸。

标准中,对于低128个码字大家都无异议,差不多就是ASCII了,但对于高128个码字,根据你所在地的不同,会有不同的处理方式。我们称这样相异的编码系统为码页(code pages)。举个例子,比如在以色列发布的DOS中使用的码页是862,而在希腊使用的是737。它们的低128个完全相同,但从128往上,就有了很大差别。MS-DOS的国际版有很多这样的码页,涵盖了从英语到冰岛语各种语言,甚至还有一些"多语言"码页。但是还得说,如果想让希伯来语和希腊语在同一台计算机上和平共处,基本上没有可能。除非你自己写程序,程序中的显示部分直接使用位图。因为希伯来语对高128个码字的解释与希腊语压根不同。

在亚洲,更疯狂的事情正在上演。因为亚洲的字母系统中要上千个字母,8个比特无论如何也是满足不了的。一般的解决方案就是使用DBCS- "双字节字符集",即有的字母使用一个字节来表示,有的使用两个字节。所以处理字符串时,指针移动到下一个字符比较容易,但移动到上一个字符就变得非常危险了。于是s++或s—不再被鼓励使用,相应的比如Windows下的AnsiNext和AnsiPrev被用来处理这种情况。

不少人依然坚信一个字节就是一个字符,一个字符就是8个比特。当然,如果你从来都没有试着把一个字符串从一台计算机移到另一台计算机,或者你不用说除英文以外的另一种语言,那么你的坚信不会出问题。但是互联网出现让字符串在计算机间移动变得非常普遍,于是所有的混乱都爆发了。非常幸运,Unicode适时而生。

Unicode的定义

Unicode是为整合全世界的所有语言文字而诞生的。任何文字在Unicode中都对应一个值,这个值称为代码点(code point)。代码点的值通常写成 U+ABCD 的格式。

一些人误以为Unicode只是简单的使用16比特的码字,也就是说每一个字符对应 16比特,总共可以表示65536个字符。这是完全不正确的。

在Unicode中,一个字母被映射到一个叫做码点(code point)的东西,这个码点可以看作一个纯粹的逻辑概念。至于码点(code point)如何在内存或磁盘中存储是另外的一个故事了。

码点(code point)的形式:U+0639

U+的意思就是"Unicode",后面跟的数字是十六进制的。

事实上Unicode可以定义的字符数并没有上限,而且现在已经超过65536了。显然,并不是任何Unicode字符都可以用2个字节来表示了。

例如:Hello

在Unicode中,对应的码点(code point)如下:

U+0048 U+0065 U+006C U+006C U+006F

仅仅是一堆码点而已,或者说数字。不过到现在为止,我们还没有说这些码点究竟是如何存储到内存或如何表示在email信息中的

Unicode最早的编码想法,就是把每一个码点(code point)都存储在两个字节中,这也就导致了大多数人的误解。于是Hello就变成了:

00 48 00 65 00 6C 00 6C 00 6F

这样对吗?如下如何?

48 00 65 00 6C 00 6C 00 6F 00

技术上说,我相信这样是可以的。事实上,早期的实现者们的确想把Unicode的码点(code point)按照大端或小端两种方式存储,这样至少已经有两种存储Unicode的方法了。于是人们就必须使用FE FF作为每一个Unicode字符串的开头,我们称这个为Unicode Byte Order Mark。如果你互换了你的高位与低位,就变成了FF FE,这样读取这个字符串的程序就知道后面字节也需要互换了。可惜,不是每一个Unicode字符串都有字节序标记。

现在,看起来好像问题已经解决了,可是这帮程序员仍在抱怨。"看看这些零!"他们会这样说,因为他们是美国人,他们只看不会码点不会超过U+00FF的英文字母。同时他们也是California的嬉皮士,他们想节省一点。如果他们是得克萨斯人,可能他们就不会介意两倍的字节数。但是这样California节俭的人却无法忍受字符串所占空间翻倍。而且现在大堆的文档使用的是ANSI和DBCS字符集,谁去转换它们?于是这帮人选择忽略Unicode,继续自己的路,这显然让事情变得更糟。

Unicode的编码方式

Unicode的编码方式与ISO 10646的通用字符集(Universal Character Set,UCS)概念相对应,目前实际应用的Unicode版本对应于UCS-2,使用16位的编码空间。也就是每个字符占用2个字节。这样理论上一共最多可以表示216即65536个字符。基本满足各种语言的使用。实际上目前版本的Unicode尚未填充满这16 位编码,保留了大量空间作为特殊使用或将来扩展。

上述16位Unicode字符构成基本多文种平面(Basic Multilingual Plane,简称BMP)。最新(但未实际广泛使用)的Unicode版本定义了16个辅助平面,两者合起来至少需要占据21位的编码空间,比3字节略少。但事实上辅助平面字符仍然占用4字节编码空间,与UCS-4保持一致。未来版本会扩充到ISO 10646-1实现级别3,即涵盖UCS-4的所有字符。UCS-4是一个更大的尚未填充完全的31位字符集,加上恒为0的首位,共需占据32位,即4字节。理论上最多能表示231个字符,完全可以涵盖一切语言所用的符号。

BMP字符的Unicode编码表示为U+hhhh,其中每个h 代表一个十六进制数位。与UCS-2编码完全相同。对应的4字节UCS-4编码后两个字节一致,前两个字节的所有位均为0。

Unicode的实现方式: Unicode Translation Format(UTF)

Unicode的实现方式不同于编码方式。一个字符的Unicode编码是确定的。但是在实际传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对Unicode编码的实现方式有所不同。Unicode的实现方式称为Unicode转换格式(Unicode Translation Format,简称为UTF)。

Unicode.org定义了百万个以上的字符,如果将所有的字符用统一的格式表示,需要的是4个字节。“a“的Unicode表示就会变成0x00000061,而“一“的Unicode值是0x00004E00。实际上,这就是UTF32,Linux操作系统上所使用的Unicode方案。而Windows平台下默认的Unicode编码方式为Little Endian的UTF-16。

UTF16

UTF-16由RFC2781规定,它使用两个字节来表示一个代码点。

不难猜到,UTF-16是完全对应于UCS-2的,即把UCS-2规定的代码点通过Big Endian或Little Endian方式直接保存下来。UTF-16包括三种:UTF-16,UTF-16BE(Big Endian),UTF-16LE(Little Endian)。

UTF-16BE和UTF-16LE不难理解,而UTF-16就需要通过在文件开头以名为BOM(Byte Order Mark)的字符来表明文件是Big Endian还是Little Endian。BOM为U+FEFF这个字符。

其实BOM是个小聪明的想法。由于UCS-2没有定义U+FFFE,因此只要出现 FF FE 或者 FE FF 这样的字节序列,就可以认为它是U+FEFF,并且可以判断出是Big Endian还是Little Endian。

举个例子。“ABC”这三个字符用各种方式编码后的结果如下:

大端小端,ascii,unicode,utf8,utf16,utf32,gb2312,gbk,gb18030等字符编码问题_第2张图片

Windows平台下默认的Unicode编码为Little Endian的UTF-16(即上述的 FF FE 41 00 42 00 43 00)。你可以打开记事本,写上ABC,然后保存,再用二进制编辑器看看它的编码结果。

UTF32

UTF-32用四个字节表示代码点,这样就可以完全表示UCS-4的所有代码点,而无需像UTF-16那样使用复杂的算法。与UTF-16类似,UTF-32也包括UTF-32、UTF-32BE、UTF-32LE三种编码,UTF-32也同样需要BOM字符。仅用'ABC'举例:

大端小端,ascii,unicode,utf8,utf16,utf32,gb2312,gbk,gb18030等字符编码问题_第3张图片

但是,仔细分析可以发现,其实绝大部分字符只使用2个字节就可以表示了。英文的Unicode范围是0x0000-0x007F,中文的Unicode范围是0x4E00-0x9F**,真正需要扩展到4个字节来表示的字符少之又少,所以有些系统直接使用2个字节来表示Unicode。比如Windows系统上,Unicode就是两个字节的。对于那些需要4个字节才能表示的字符,使用一种代理的手法来扩展(其实就是在低两个字节上做一个标记,表示这是一个代理,需要连接上随后的两个字节,才能组成一个字符)。这样的好处是大量的节约了存取空间,也提高了处理的速度。这种Unicode表示方法就是UTF16。一般在Windows平台上,提到Unicode,那就是指UTF16了。

UTF8

UTF-16和UTF-32的一个缺点就是它们固定使用两个或四个字节,这样在表示纯ASCII文件时会有很多00字节,造成浪费。而RFC3629定义的 UTF-8则解决了这个问题。UTF-8用1~4个字节来表示代码点。表示方式如下:

大端小端,ascii,unicode,utf8,utf16,utf32,gb2312,gbk,gb18030等字符编码问题_第4张图片

可见,ASCII字符(U+0000~U+007F)部分完全使用一个字节,避免了存储空间的浪费。而且UTF-8不再需要BOM字节。

另外,从上表中可以看出,单字节编码的第一字节为[00-7F],双字节编码的第一字节为[C2-DF],三字节编码的第一字节为[E0-EF]。这样只要看到第一个字节的范围就可以知道编码的字节数。这样也可以大大简化算法。

GB2312,GBK,GB18030

从ASCII、GB2312、GBK到GB18030,这些编码方法是向下兼容的,即同一个字符在这些方案中总是有相同的编码,后面的标准支持更多的字符。在这些编码中,英文和中文可以统一地处理。区分中文编码的方法是高字节的最高位不为0。按照程序员的称呼,GB2312、GBK到GB18030都属于双字节字符集 (DBCS)。

在MS的IDE中我们可以看到这样一个选项

5 

这里的Unicode一般就是指的UTF16,双字节宽字符,也就是wchar_t

而多字节字符集就是不确定使用的字节数的那种情况了……

一般在编写应用程序的时候,应该使用unicode字符编码方案,而在写文件的时候应该使用多字节字符编码方案,比较节省空间。

VAUTF8.h
复制代码
1  #include  < string >
2    #define  MAX_LENGTH_VAUTF8 16384
3    namespace  nsVAUTF8
4  {
5  ///  字符编码模式
6    enum  eCharacterEncodingMode
7  {
8  UNDEFINED,
9  ANSI,
10  UTF8,
11  UTF16LE,
12  UTF16BE,
13  UTF32LE,
14  UTF32BE
15  };
16  }
17 
18    extern char  cUTF8Hdr[];
19  extern bool  UTF8_Unicode_Possible;
20 
21  int  UTF8CharLen( char in );
22  int  IsUTF8( const char *  src, size_t max_source_len);
23  void  utf8_EnableRealUnicode( bool  bEnabled);
24  bool  utf8_IsUnicodeEnabled();
25 
26  int  _stdcall UTF82WStr( const char *  source,  char *  dest,  int  max_len  =  MAX_LENGTH_VAUTF8);
27  int  _stdcall UTF82WStr( const char *  source,  char **  dest);
28 
29  int  _stdcall UTF82Str( const char *  source,  char *  dest,  int  max_len  =  MAX_LENGTH_VAUTF8);
30  int  _stdcall UTF82Str( const char *  source,  char **  dest);
31 
32  int  _stdcall WStr2UTF8( const char *  source,  char *  dest,  int  max_len  =  MAX_LENGTH_VAUTF8);
33  int  _stdcall WStr2UTF8( const  wchar_t *  source,  char *  dest,  int  max_len  =  MAX_LENGTH_VAUTF8);
34  int  _stdcall WStr2UTF8( const char *  source,  char **  dest);
35  int  _stdcall WStr2UTF8( const  wchar_t *  source,  char **  dest);
36 
37  int  _stdcall Str2UTF8( const char *  source,  char *  dest,  int  max_len  =  MAX_LENGTH_VAUTF8);
38  int  _stdcall Str2UTF8( const char *  source,  char **  dest);
39 
40  int  _stdcall Str2WStr( const char *  source,  char *  dest,  int  max_len  =  MAX_LENGTH_VAUTF8);
41  int  _stdcall Str2WStr( const char *  source,  char **  dest);
42 
43  int  _stdcall WStr2Str( const char *  source,  char *  dest,  int  max_len  =  MAX_LENGTH_VAUTF8); 
44  int  _stdcall WStr2Str( const char *  source,  char **  dest);
45 
46  int  StringConvert( const char *  source, nsVAUTF8::eCharacterEncodingMode source_format,
47  char **  dest, nsVAUTF8::eCharacterEncodingMode dest_format);
48 
49  int  FromUTF8( const char *  source, wchar_t **  dest);
50  int  FromUTF8( const char *  source,  char **  dest);
51 
52  int  ToUTF8( const char *  source,  char **  dest);
53  int  ToUTF8( const  wchar_t *  source,  char **  dest);
54 
55  typedef std:: string  EncodingStirngA;
56  typedef std::wstring EncodingStirngW;
57  class  VAUTF8
58  {
59  private :
60  EncodingStirngA m_sANSI;
61  EncodingStirngA m_sUTF8;
62  EncodingStirngW m_sUNICODE;
63  private :
64  void  Complete();
65  public :
66  ///  构造函数
67  VAUTF8() {};
68  virtual ~ VAUTF8(){}
69  VAUTF8( const char *  pSrc);
70  VAUTF8( const  wchar_t *  pSrc);
71  VAUTF8( const char *  pSrc,  int  Encoding);
72  VAUTF8( const  EncodingStirngA &  src);
73  VAUTF8( const  EncodingStirngW &  src);
74 
75  //  拷贝构造函数
76  VAUTF8( const  VAUTF8 &  other);
77  VAUTF8 & operator = ( const  VAUTF8 &  rhs);
78 
79  operator  EncodingStirngA()  const  {  return  m_sANSI;}
80  operator  EncodingStirngW()  const  {  return  m_sUNICODE;}
81  const char *  UTF8()  const  {  return  m_sUTF8.c_str();}
82  const  size_t Size()  const  {  return  m_sUTF8.size();}
83  const char *  Str()  const  {  return  m_sANSI.c_str();}
84  const  wchar_t *  WStr()  const  {  return  m_sUNICODE.c_str();}
85 
86  //  如果定义了TCHAR,则可调用该方法
87  #ifdef _TCHAR_DEFINED
88  const  TCHAR *  TStr()  const  {
89  #ifdef _UNICODE
90  return  WStr();
91  #else
92  return  Str();
93  #endif
94  }
95  #endif
96  };
复制代码
VAUTF8.cpp
复制代码
1  #include  " VAUTF8.h "
2  #include  < windows.h >  
3 
4  bool  UTF8_Unicode_Possible  = true ;
5  char  cUTF8Hdr[]  =  {( char ) 0xEF ,( char ) 0xBB ,( char ) 0xBF , 0 };
6 
7  int  UTF8CharLen( char in )
8  {
9  unsigned  char  uin  =  (unsigned  char ) in ;
10 
11  if  (uin  < 128 )
12  return 1 ;
13 
14  if  (uin  < 192 )
15  return - 1 ;
16 
17  if  (uin  < 0xE0 )
18  return 2 ;
19 
20  if  (uin  < 0xF0 )
21  return 3 ;
22 
23  if  (uin  < 0xF8 )
24  return 4 ;
25 
26  if  (uin  < 0xFC )
27  return 5 ;
28 
29  if  (uin  < 0xFE )
30  return 6 ;
31 
32  if  (uin  < 0xFF )
33  return 7 ;
34 
35  return 8 ;
36  }
37  int  IsUTF8( const char *  src, size_t max_source_len)
38  {
39  if  (max_source_len  < 0 )
40  return 0 ;
41 
42  if  (max_source_len  == 0 )
43  return 1 ;
44 
45  while  ( * src  &&  max_source_len -- )
46  {
47  int  bytes  =  UTF8CharLen( * src ++ );
48  if  (bytes  < 0 )
49  return 0 ;
50  if  (static_cast < int > (max_source_len)  < -- bytes)
51  return 0 ;
52  while  (bytes -- ) {
53  if  (( * src ++ & 0xC0 != 0x80 )
54  return 0 ;
55  }
56  }
57 
58  return 1 ;
59  }
60 
61  // ===================================================================================================
62  //  宽字节字符串转化为UTF8
63  int  _stdcall WStr2UTF8( const char *  source,  char **  dest)
64  {
65  int  len  = 1 ;
66 
67  if  (source) 
68  len  =  WStr2UTF8(source, NULL,  0 );
69 
70  * dest  =  ( char * )malloc(len);
71 
72  if  ( ! source) {
73  * dest  = 0 ;
74  return 1 ;
75  }
76 
77  return  WideCharToMultiByte(CP_UTF8,  0 , (LPCWSTR)source,  - 1 ,
78  * dest, len, NULL, NULL);
79  }
80 
81  int  _stdcall WStr2UTF8( const  wchar_t *  source,  char **  dest)
82  {
83  return  WStr2UTF8(( char * )source, dest);
84  }
85 
86  int  _stdcall WStr2UTF8( const char *  source,  char *  dest,  int  max_len)
87  {
88  if  (dest) {
89  if  (source != dest) {
90  return  WideCharToMultiByte(CP_UTF8,  0
91  (LPCWSTR)source,  - 1 , dest, max_len, NULL, NULL);
92  else  {
93  int  dest_size  =  WStr2UTF8(source, NULL,  0 );
94 
95  char *  cTemp  =  NULL;
96  WStr2UTF8(source,  & cTemp);
97  strcpy_s(dest, max_len, cTemp);
98  free(cTemp); 
99 
100  return  dest_size;
101  }
102  else  {
103  return  WideCharToMultiByte(CP_UTF8, 0 ,(LPCWSTR)source, - 1 ,NULL, 0 ,NULL,NULL);
104  }
105 
106  return 0 ;
107  }
108  // ===================================================================================================
109 
110  // ===================================================================================================
111  //  短字节字符串转化为宽字节字符串
112  int  _stdcall Str2WStr( const char *  source,  char *  dest,  int  max_len)
113  {
114  if  ( ! source) 
115  {
116  memset(dest,  0 2 );
117  return 2 ;
118  }
119  size_t source_len  = 1 +  strlen(source);
120 
121  if  (source != dest) 
122  {
123  if  ( ! dest) 
124  return 2 *  MultiByteToWideChar(CP_THREAD_ACP,  0 , source,  - 1 , NULL,  0 ); 
125 
126 
127  return 2 * MultiByteToWideChar(CP_THREAD_ACP, 0 ,source, - 1 ,(LPWSTR)dest,max_len / 2 );
128 
129  else  
130  {
131  char *  cTemp  = new char [ 2 *  source_len];
132  int  i  = 2 * MultiByteToWideChar(CP_THREAD_ACP, 0 ,source, - 1 ,(LPWSTR)cTemp,max_len / 2 );
133  memcpy(dest, cTemp, i);
134  delete[] cTemp;
135  return  i;
136  }
137  }
138 
139  int  _stdcall Str2WStr( const char *  source,  char **  dest)
140  {
141  if  ( ! source) 
142  {
143  * dest  = new char [ 2 ];
144  memset( * dest,  0 2 );
145  return 2 ;
146  }
147  int  dest_len  =  Str2WStr(source, NULL,  0 );
148  * dest  =  ( char * )calloc( 1 , dest_len);
149  return 2 * MultiByteToWideChar(CP_THREAD_ACP, 0 ,source, - 1 ,(LPWSTR) * dest,dest_len / 2 );
150  }
151  // ===================================================================================================
152 
153 
154  // ===================================================================================================
155  //  宽字节字符串转化为短字节字符串
156  int  _stdcall WStr2Str( const char *  source,  char *  dest,  int  max_len)
157  {
158  int  len  =  WideCharToMultiByte(CP_THREAD_ACP,  0 , (LPCWSTR)source,  - 1 ,
159  (LPSTR)dest, max_len, NULL, NULL);
160  return  len;
161  }
162 
163  int  _stdcall WStr2Str( const char *  source,  char **  dest)
164  {
165  int  len  = 1 ;
166  if  (source)
167  len  =  WideCharToMultiByte(CP_THREAD_ACP, 0 ,(LPCWSTR)source, - 1 ,NULL, 0 , 0 , 0 );
168  * dest  =  ( char * )malloc(len);
169  return  WideCharToMultiByte(CP_THREAD_ACP,  0 , (LPCWSTR)source,
170  - 1 * dest, len,  0 0 );
171  }
172  // ===================================================================================================
173 
174 
175  // ===================================================================================================
176  //  短字节字符串转化到UTF8字符串
177  int  _stdcall Str2UTF8( const char *  source,  char *  dest,  int  max_len)
178  {
179  if  ( ! source) 
180  {
181  * dest  = 0 ;
182  return 1 ;
183  }
184 
185  if  (max_len  < 0 )
186  return 0 ;
187 
188  int  temp_size;
189  size_t source_len  =  strlen(source)  + 1 ;
190  if  (UTF8_Unicode_Possible) 
191  {
192  temp_size  =  Str2WStr(source, ( char * )NULL);
193  else  {
194  temp_size  = 1 + ( int )strlen(source);
195  }
196  int  i;
197 
198  unsigned  short *  temp  = new  unsigned  short [temp_size];
199 
200  if  (UTF8_Unicode_Possible) {
201  ZeroMemory(temp, sizeof (unsigned  short *  temp_size);
202 
203  if  (dest) {
204  MultiByteToWideChar(CP_THREAD_ACP, 0 ,source, - 1 ,(LPWSTR)temp,temp_size);
205  =  WideCharToMultiByte(CP_UTF8, 0 ,(LPCWSTR)temp, - 1 ,dest,max_len, 0 , 0 );
206  delete[] temp;
207  return  i;
208  else  {
209  MultiByteToWideChar(CP_THREAD_ACP, 0 ,source, - 1 ,(LPWSTR)temp,temp_size);
210  =  WideCharToMultiByte(CP_UTF8, 0 ,(LPCWSTR)temp, - 1 , 0 , 0 , 0 , 0 );
211  delete[] temp;
212  return  i;
213  }
214  else  {
215  delete[] temp;
216  if  (dest) {
217  if  (( int )source_len  <  max_len) 
218  strcpy_s(dest, max_len, source);
219  else  {
220  strncpy_s(dest, max_len, source, max_len);
221  dest[( int )max_len - 1 = 0 ;
222  }
223  }
224  return 1 + ( int )strlen(source);
225  }
226 
227  }
228 
229  int  _stdcall Str2UTF8( const char *  source,  char **  dest)
230  {
231  if  ( ! dest)
232  return - 1 ;
233 
234  if  ( ! source) {
235  * dest  =  ( char * )calloc( 1 1 );
236  return 1 ;
237  }
238 
239  if  (UTF8_Unicode_Possible) {
240  unsigned  short *  temp  =  NULL;
241  Str2WStr(source, ( char ** ) & temp);
242  int  result  =  WStr2UTF8(( char * )temp, dest);
243  free(temp);
244  return  result;
245  else  {
246  * dest  =  _strdup(source);
247  return  ( int )( 1 + strlen(source));
248  }
249  }
250  // ===================================================================================================
251 
252 
253 
254  // ===================================================================================================
255  //  UTF8串转化到短字节字符串
256  int  _stdcall UTF82Str( const char *  source,  char **  dest)
257  {
258  if  ( ! dest) {
259  return - 1 ;
260  }
261 
262  if  ( ! source) {
263  * dest  =  ( char * )calloc( 1 1 ); 
264  return 1 ;
265  }
266 
267  unsigned  short *  temp  =  NULL;
268 
269  if  (UTF8_Unicode_Possible) {
270  UTF82WStr(source,( char ** ) & temp);
271  int  dest_len  =  WideCharToMultiByte(CP_THREAD_ACP, 0 ,(LPCWSTR)temp, - 1 , 0 , 0 , 0 , 0 );
272 
273  if  (dest) {
274  * dest  =  ( char * )calloc( 1 , dest_len);
275  int  r  =  WideCharToMultiByte(CP_THREAD_ACP, 0 ,(LPCWSTR)temp, - 1 , * dest,dest_len, 0 , 0 );
276  free(temp);
277  return  r;
278  else  {
279  int  r  =  WideCharToMultiByte(CP_THREAD_ACP, 0 ,(LPCWSTR)temp, - 1 , 0 , 0 , 0 , 0 );
280  free(temp);
281  return  r;
282  }
283  else  {
284  * dest  =  _strdup(source);
285  return  ( int )strlen( * dest) + 1 ;
286  }
287  }
288 
289  int  _stdcall UTF82Str( const char *  source,  char *  dest,  int  max_len)
290  {
291  int  i;
292 
293  if  ( ! source) {
294  if  (dest)
295  * dest  = 0 ;
296  return 1 ;
297  }
298 
299  unsigned  short *  temp  =  NULL;
300 
301  if  (UTF8_Unicode_Possible) {
302  UTF82WStr(source, ( char ** ) & temp);
303  if  (dest) {
304  =  WideCharToMultiByte(CP_THREAD_ACP, 0 ,(LPCWSTR)temp, - 1 ,dest,max_len, 0 , 0 );
305  delete[] temp;
306  return  i;
307  else  {
308  =  WideCharToMultiByte(CP_THREAD_ACP, 0 ,(LPCWSTR)temp, - 1 , 0 , 0 , 0 , 0 );
309  delete[] temp;
310  return  i;
311  }
312  else  {
313  delete[] temp;
314  if  (dest) 
315  strcpy_s(dest, max_len, source);
316 
317  return  ( int )strlen(source);
318  }
319  }
320  // ===================================================================================================
321 
322  // ===================================================================================================
323  //  UTF8串转化到宽字节字符串
324  int  _stdcall UTF82WStr( const char *  source,  char **  dest)
325  {
326  size_t source_len  =  strlen(source)  + 1 ;
327  int  dest_len  = 2 ;
328 
329  if  (source)
330  dest_len  = 2 *  MultiByteToWideChar(CP_UTF8,  0 , source,  - 1 0 0 );
331 
332  if  (dest) {
333  * dest  =  ( char * )malloc(dest_len);
334  return sizeof (wchar_t) * MultiByteToWideChar(CP_UTF8,  0 , source,  - 1 ,
335  (LPWSTR) * dest, dest_len  / sizeof (wchar_t));
336  else  {
337  return sizeof (wchar_t) * MultiByteToWideChar(CP_UTF8,  0 , source,  - 1 0 0 );
338  }
339  }
340 
341 
342  int  _stdcall UTF82WStr( const char *  source,  char *  dest,  int  max_len)
343  {
344  int  i;
345 
346  if  ( ! source)
347  return 0 ;
348 
349  size_t source_len  =  strlen(source)  + 1 ;
350 
351  if  (dest) {
352  if  (source != dest) {
353  return sizeof (wchar_t)  *  MultiByteToWideChar(CP_UTF8,  0 , source,  - 1 ,
354  (LPWSTR)dest, max_len  / sizeof (wchar_t));
355  else  {
356  char *  cTemp  =  ( char * )malloc(UTF82WStr(source, NULL,  0 ));
357  = sizeof (wchar_t)  *  MultiByteToWideChar(CP_UTF8,  0 , source, 
358  - 1 , (LPWSTR)cTemp, max_len  / sizeof (wchar_t));
359  memcpy(dest, cTemp, i);
360  free(cTemp);
361  return  i;
362  }
363  else  {
364  return 2 * MultiByteToWideChar(CP_UTF8, 0 ,source, - 1 , 0 , 0 );
365  }
366  }
367 
368  // ===================================================================================================
369 
370 
371  int  StringConvert(  const char *  source, nsVAUTF8::eCharacterEncodingMode source_format, /*  int max_source_len, */ char **  dest, nsVAUTF8::eCharacterEncodingMode dest_format )
372  {
373  char *  _source  =  ( char * )source;
374  switch  (source_format)
375  {
376  case  nsVAUTF8::ANSI:
377  switch  (dest_format) {
378  case  nsVAUTF8::ANSI:  * dest  =  _strdup(_source);  break ;
379  case  nsVAUTF8::UTF8: Str2UTF8(_source, dest);  break ;
380  case  nsVAUTF8::UTF16LE: Str2WStr(_source, dest);  break ;
381  }
382  break ;
383  case  nsVAUTF8::UTF8:
384  switch  (dest_format) {
385  case  nsVAUTF8::ANSI: UTF82Str(_source, dest);  break ;
386  case  nsVAUTF8::UTF8:  * dest  =  _strdup(_source);  break ;
387  case  nsVAUTF8::UTF16LE: UTF82WStr(_source, dest);  break ;
388  }
389  break ;
390  case  nsVAUTF8::UTF16LE:
391  switch  (dest_format) {
392  case  nsVAUTF8::ANSI: 
393  WStr2Str(_source, dest); 
394  break ;
395  case  nsVAUTF8::UTF8: 
396  WStr2UTF8(_source, dest); 
397  break ;
398  case  nsVAUTF8::UTF16LE: 
399  * dest  =  ( char * )_wcsdup((wchar_t * )_source); 
400  break ;
401  }
402  break ;
403  }
404  return 1 ;
405  }
406 
407  int  FromUTF8( const char *  source, wchar_t **  dest)
408  {
409  return  StringConvert(source, nsVAUTF8::UTF8,
410  ( char ** )dest, nsVAUTF8::UTF16LE);
411  }
412 
413  int  FromUTF8( const char *  source,  char **  dest)
414  {
415  return  StringConvert(source, nsVAUTF8::UTF8,
416  ( char ** )dest, nsVAUTF8::ANSI);
417  }
418 
419  int  ToUTF8( const char *  source,  char **  dest)
420  {
421  return  StringConvert(source, nsVAUTF8::ANSI,
422  ( char ** )dest, nsVAUTF8::UTF8);
423  }
424 
425  int  ToUTF8( const  wchar_t *  source,  char **  dest)
426  {
427  return  StringConvert(( char * )source, nsVAUTF8::UTF16LE,
428  ( char ** )dest, nsVAUTF8::UTF8);
429  }
430 
431  void  utf8_EnableRealUnicode(  bool  bEnabled )
432  {
433  UTF8_Unicode_Possible  =  bEnabled;
434  }
435 
436  bool  utf8_IsUnicodeEnabled()
437  {
438  return  UTF8_Unicode_Possible;
439  }
440  VAUTF8::VAUTF8(  const char *  pSrc,  int  Encoding )
441  {
442  if  (pSrc)
443  {
444  if  (Encoding  ==  nsVAUTF8::UTF8)
445  {
446  m_sUTF8  =  pSrc;
447  }
448  else
449  {
450  m_sANSI  =  pSrc;
451  }
452 
453  Complete();
454  }
455 
456  }
457 
458 
459  VAUTF8::VAUTF8(  const char *  pSrc )
460  {
461  if  (pSrc)
462  {
463  if  (IsUTF8(pSrc, strlen(pSrc)))
464  {
465  m_sUTF8  =  pSrc;
466  }
467  else
468  {
469  m_sANSI  =  pSrc;
470  }
471 
472  Complete();
473  }
474  }
475 
476  VAUTF8::VAUTF8(  const  wchar_t *  pSrc )
477  {
478  if  (pSrc)
479  {
480  m_sUNICODE  =  pSrc;
481  Complete();
482  }
483  }
484 
485  VAUTF8::VAUTF8(  const  EncodingStirngA &  src )
486  {
487  if  (IsUTF8(src.c_str(), src.size()))
488  {
489  m_sUTF8  =  src;
490  }
491  else
492  {
493  m_sANSI  =  src;
494  }
495 
496  Complete();
497  }
498 
499 
500  VAUTF8::VAUTF8(  const  EncodingStirngW &  src )
501  {
502  m_sUNICODE  =  src;
503  Complete();
504  }
505 
506  VAUTF8::VAUTF8(  const  VAUTF8 &  other )
507  {
508  * this =  other;
509  }
510 
511 
512  VAUTF8 &  VAUTF8:: operator = ( const  VAUTF8 &  rhs )
513  {
514  m_sUTF8  =  rhs.m_sUTF8;
515  Complete();
516  return * this ;
517  }
518 
519  void  VAUTF8::Complete()
520  {
521  char *  p  =  NULL;
522 
523  if  ( ! m_sANSI.empty())
524  {
525  Str2UTF8(m_sANSI.c_str(),  & p);
526  m_sUTF8  =  p;
527  free(p);
528 
529  Str2WStr(m_sANSI.c_str(),  & p);
530  m_sUNICODE  =  (wchar_t * )p;
531  free(p);
532  }
533  else
534  {
535  if  ( ! m_sUTF8.empty())
536  {
537  UTF82Str(( char * )m_sUTF8.c_str(),  & p);
538  m_sANSI  =  p;
539  free(p);
540 
541  UTF82WStr(( char * )m_sUTF8.c_str(),  & p);
542  m_sUNICODE  =  (wchar_t * )p;
543  free(p);
544  }
545  else
546  {
547  if  ( ! m_sUNICODE.empty())
548  {
549  WStr2Str(( char * )m_sUNICODE.c_str(),  & p);
550  m_sANSI  =  p;
551  free(p);
552 
553  WStr2UTF8(( char * )m_sUNICODE.c_str(),  & p);
554  m_sUTF8  =  p;
555  free(p);
556  }
557  }
558  }
559  }
560
复制代码

你可能感兴趣的:(大端小端,ascii,unicode,utf8,utf16,utf32,gb2312,gbk,gb18030等字符编码问题)