大端小端,ascii,unicode,utf8,utf16,utf32,gb2312,gbk,gb18030等字符編碼問題 (轉)
字符編碼的問題讓我困惑了好久的一段時間,其實簡單的想,字符編碼沒有什么東西的,可是想真弄明白還是花去了我一點時間,前端時間寫了一個簡單的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個比特無論如何也是滿足不了的。一般的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 externchar cUTF8Hdr[];
19 externbool UTF8_Unicode_Possible;
20
21 int UTF8CharLen(charin);
22 int IsUTF8(constchar* src, size_t max_source_len);
23 void utf8_EnableRealUnicode(bool bEnabled);
24 bool utf8_IsUnicodeEnabled();
25
26 int _stdcall UTF82WStr(constchar* source, char* dest, int max_len = MAX_LENGTH_VAUTF8);
27 int _stdcall UTF82WStr(constchar* source, char** dest);
28
29 int _stdcall UTF82Str(constchar* source, char* dest, int max_len = MAX_LENGTH_VAUTF8);
30 int _stdcall UTF82Str(constchar* source, char** dest);
31
32 int _stdcall WStr2UTF8(constchar* 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(constchar* source, char** dest);
35 int _stdcall WStr2UTF8(const wchar_t* source, char** dest);
36
37 int _stdcall Str2UTF8(constchar* source, char* dest, int max_len = MAX_LENGTH_VAUTF8);
38 int _stdcall Str2UTF8(constchar* source, char** dest);
39
40 int _stdcall Str2WStr(constchar* source, char* dest, int max_len = MAX_LENGTH_VAUTF8);
41 int _stdcall Str2WStr(constchar* source, char** dest);
42
43 int _stdcall WStr2Str(constchar* source, char* dest, int max_len = MAX_LENGTH_VAUTF8);
44 int _stdcall WStr2Str(constchar* source, char** dest);
45
46 int StringConvert(constchar* source, nsVAUTF8::eCharacterEncodingMode source_format,
47 char** dest, nsVAUTF8::eCharacterEncodingMode dest_format);
48
49 int FromUTF8(constchar* source, wchar_t** dest);
50 int FromUTF8(constchar* source, char** dest);
51
52 int ToUTF8(constchar* 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(constchar* pSrc);
70 VAUTF8(const wchar_t* pSrc);
71 VAUTF8(constchar* 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 constchar* UTF8() const { return m_sUTF8.c_str();}
82 const size_t Size() const { return m_sUTF8.size();}
83 constchar* 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(charin)
8 {
9 unsigned char uin = (unsigned char)in;
10
11 if (uin <128)
12 return1;
13
14 if (uin <192)
15 return-1;
16
17 if (uin <0xE0)
18 return2;
19
20 if (uin <0xF0)
21 return3;
22
23 if (uin <0xF8)
24 return4;
25
26 if (uin <0xFC)
27 return5;
28
29 if (uin <0xFE)
30 return6;
31
32 if (uin <0xFF)
33 return7;
34
35 return8;
36 }
37 int IsUTF8(constchar* src, size_t max_source_len)
38 {
39 if (max_source_len <0)
40 return0;
41
42 if (max_source_len ==0)
43 return1;
44
45 while (*src && max_source_len--)
46 {
47 int bytes = UTF8CharLen(*src++);
48 if (bytes <0)
49 return0;
50 if (static_cast<int>(max_source_len) <--bytes)
51 return0;
52 while (bytes--) {
53 if ((*src++&0xC0) !=0x80)
54 return0;
55 }
56 }
57
58 return1;
59 }
60
61 //===================================================================================================
62 // 寬字節字符串轉化為UTF8
63 int _stdcall WStr2UTF8(constchar* 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 return1;
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(constchar* 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 return0;
107 }
108 //===================================================================================================
109
110 //===================================================================================================
111 // 短字節字符串轉化為寬字節字符串
112 int _stdcall Str2WStr(constchar* source, char* dest, int max_len)
113 {
114 if (!source)
115 {
116 memset(dest, 0, 2);
117 return2;
118 }
119 size_t source_len =1+ strlen(source);
120
121 if (source!=dest)
122 {
123 if (!dest)
124 return2* MultiByteToWideChar(CP_THREAD_ACP, 0, source, -1, NULL, 0);
125
126
127 return2*MultiByteToWideChar(CP_THREAD_ACP,0,source,-1,(LPWSTR)dest,max_len/2);
128 }
129 else
130 {
131 char* cTemp =newchar[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(constchar* source, char** dest)
140 {
141 if (!source)
142 {
143 *dest =newchar[2];
144 memset(*dest, 0, 2);
145 return2;
146 }
147 int dest_len = Str2WStr(source, NULL, 0);
148 *dest = (char*)calloc(1, dest_len);
149 return2*MultiByteToWideChar(CP_THREAD_ACP,0,source,-1,(LPWSTR)*dest,dest_len/2);
150 }
151 //===================================================================================================
152
153
154 //===================================================================================================
155 // 寬字節字符串轉化為短字節字符串
156 int _stdcall WStr2Str(constchar* 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(constchar* 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(constchar* source, char* dest, int max_len)
178 {
179 if (!source)
180 {
181 *dest =0;
182 return1;
183 }
184
185 if (max_len <0)
186 return0;
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 return1+(int)strlen(source);
225 }
226
227 }
228
229 int _stdcall Str2UTF8(constchar* source, char** dest)
230 {
231 if (!dest)
232 return-1;
233
234 if (!source) {
235 *dest = (char*)calloc(1, 1);
236 return1;
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(constchar* source, char** dest)
257 {
258 if (!dest) {
259 return-1;
260 }
261
262 if (!source) {
263 *dest = (char*)calloc(1, 1);
264 return1;
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(constchar* source, char* dest, int max_len)
290 {
291 int i;
292
293 if (!source) {
294 if (dest)
295 *dest =0;
296 return1;
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(constchar* 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 returnsizeof(wchar_t)*MultiByteToWideChar(CP_UTF8, 0, source, -1,
335 (LPWSTR)*dest, dest_len /sizeof(wchar_t));
336 } else {
337 returnsizeof(wchar_t)*MultiByteToWideChar(CP_UTF8, 0, source, -1, 0, 0);
338 }
339 }
340
341
342 int _stdcall UTF82WStr(constchar* source, char* dest, int max_len)
343 {
344 int i;
345
346 if (!source)
347 return0;
348
349 size_t source_len = strlen(source) +1;
350
351 if (dest) {
352 if (source!=dest) {
353 returnsizeof(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 return2*MultiByteToWideChar(CP_UTF8,0,source,-1,0,0);
365 }
366 }
367
368 //===================================================================================================
369
370
371 int StringConvert( constchar* 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 return1;
405 }
406
407 int FromUTF8(constchar* source, wchar_t** dest)
408 {
409 return StringConvert(source, nsVAUTF8::UTF8,
410 (char**)dest, nsVAUTF8::UTF16LE);
411 }
412
413 int FromUTF8(constchar* source, char** dest)
414 {
415 return StringConvert(source, nsVAUTF8::UTF8,
416 (char**)dest, nsVAUTF8::ANSI);
417 }
418
419 int ToUTF8(constchar* 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( constchar* 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( constchar* 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
posted on 2013-04-05 17:05 coreBugZJ 閱讀(2047) 評論(0) 編輯 收藏 引用 所屬分類: 技術視野