字符编码的问题让我困惑了好久的一段时间,其实简单的想,字符编码没有什么东西的,可是想真弄明白还是花去了我一点时间,前端时间写了一个简单的log程序,主要的工作就是支持系统运行时输出日志信息,同时允许定制不同级别的日志输出,刚开始的时候只是写入到文件中,可用过之后发现,只是写入到文件中,在进行系统调试的时候不是很方便,还要打开文件,浏览,再返回源代码,如果能够有一个界面展示岂不是更好,列表显示日志,可以选择显示的日志级别,实现日志输出位置的定位,类似下图中展示的一样:
感觉还是能方便一点的,而显示窗口的实现可以通过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”这三个字符用各种方式编码后的结果如下:
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'举例:
但是,仔细分析可以发现,其实绝大部分字符只使用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字符(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中我们可以看到这样一个选项
这里的Unicode一般就是指的UTF16,双字节宽字符,也就是wchar_t
而多字节字符集就是不确定使用的字节数的那种情况了……
一般在编写应用程序的时候,应该使用unicode字符编码方案,而在写文件的时候应该使用多字节字符编码方案,比较节省空间。
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 };
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 i = 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 i = 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 i = WideCharToMultiByte(CP_THREAD_ACP, 0 ,(LPCWSTR)temp, - 1 ,dest,max_len, 0 , 0 );
305 delete[] temp;
306 return i;
307 } else {
308 i = 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 i = 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