﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-网络服务器软件开发-随笔分类-编码知识</title><link>http://www.cppblog.com/true/category/3966.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 25 Sep 2009 13:58:55 GMT</lastBuildDate><pubDate>Fri, 25 Sep 2009 13:58:55 GMT</pubDate><ttl>60</ttl><item><title>C++结构体序列化的一点思考</title><link>http://www.cppblog.com/true/archive/2009/09/24/97087.html</link><dc:creator>true</dc:creator><author>true</author><pubDate>Wed, 23 Sep 2009 19:03:00 GMT</pubDate><guid>http://www.cppblog.com/true/archive/2009/09/24/97087.html</guid><wfw:comment>http://www.cppblog.com/true/comments/97087.html</wfw:comment><comments>http://www.cppblog.com/true/archive/2009/09/24/97087.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/true/comments/commentRss/97087.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/true/services/trackbacks/97087.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: C++结构体序列化  libprotobuf&nbsp;&nbsp;<a href='http://www.cppblog.com/true/archive/2009/09/24/97087.html'>阅读全文</a><img src ="http://www.cppblog.com/true/aggbug/97087.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/true/" target="_blank">true</a> 2009-09-24 03:03 <a href="http://www.cppblog.com/true/archive/2009/09/24/97087.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>协议设计之二  结构体类型的编码</title><link>http://www.cppblog.com/true/archive/2009/09/11/95949.html</link><dc:creator>true</dc:creator><author>true</author><pubDate>Fri, 11 Sep 2009 11:35:00 GMT</pubDate><guid>http://www.cppblog.com/true/archive/2009/09/11/95949.html</guid><wfw:comment>http://www.cppblog.com/true/comments/95949.html</wfw:comment><comments>http://www.cppblog.com/true/archive/2009/09/11/95949.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/true/comments/commentRss/95949.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/true/services/trackbacks/95949.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 结构体类型的序列化&nbsp;&nbsp;<a href='http://www.cppblog.com/true/archive/2009/09/11/95949.html'>阅读全文</a><img src ="http://www.cppblog.com/true/aggbug/95949.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/true/" target="_blank">true</a> 2009-09-11 19:35 <a href="http://www.cppblog.com/true/archive/2009/09/11/95949.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>协议设计之一  基本类型的编码</title><link>http://www.cppblog.com/true/archive/2009/09/11/95873.html</link><dc:creator>true</dc:creator><author>true</author><pubDate>Thu, 10 Sep 2009 20:12:00 GMT</pubDate><guid>http://www.cppblog.com/true/archive/2009/09/11/95873.html</guid><wfw:comment>http://www.cppblog.com/true/comments/95873.html</wfw:comment><comments>http://www.cppblog.com/true/archive/2009/09/11/95873.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/true/comments/commentRss/95873.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/true/services/trackbacks/95873.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 协议设计的基础部分，基本类型的编码，参考了libprotobuf&nbsp;&nbsp;<a href='http://www.cppblog.com/true/archive/2009/09/11/95873.html'>阅读全文</a><img src ="http://www.cppblog.com/true/aggbug/95873.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/true/" target="_blank">true</a> 2009-09-11 04:12 <a href="http://www.cppblog.com/true/archive/2009/09/11/95873.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>字符转换（转载）</title><link>http://www.cppblog.com/true/archive/2007/11/18/36895.html</link><dc:creator>true</dc:creator><author>true</author><pubDate>Sun, 18 Nov 2007 11:48:00 GMT</pubDate><guid>http://www.cppblog.com/true/archive/2007/11/18/36895.html</guid><wfw:comment>http://www.cppblog.com/true/comments/36895.html</wfw:comment><comments>http://www.cppblog.com/true/archive/2007/11/18/36895.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/true/comments/commentRss/36895.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/true/services/trackbacks/36895.html</trackback:ping><description><![CDATA[<div class=postTitle twffan="done">&nbsp;</div>
<p>一 C++ 中 string与wstring互转</p>
<p>方法一：</p>
<p>string WideToMutilByte(const wstring&amp; _src)<br>{<br>int nBufSize = WideCharToMultiByte(GetACP(), 0, _src.c_str(),-1, NULL, 0, 0, FALSE);</p>
<p>char *szBuf = new char[nBufSize];</p>
<p>WideCharToMultiByte(GetACP(), 0, _src.c_str(),-1, szBuf, nBufSize, 0, FALSE);</p>
<p>string strRet(szBuf);</p>
<p>delete []szBuf;<br>szBuf = NULL;</p>
<p>return strRet;<br>}</p>
<p>wstring MutilByteToWide(const string&amp; _src)<br>{<br>//计算字符串 string 转成 wchar_t 之后占用的内存字节数<br>int nBufSize = MultiByteToWideChar(GetACP(),0,_src.c_str(),-1,NULL,0); </p>
<p>//为 wsbuf 分配内存 BufSize 个字节<br>wchar_t *wsBuf = new wchar_t[nBufSize];</p>
<p>//转化为 unicode 的 WideString<br>MultiByteToWideChar(GetACP(),0,_src.c_str(),-1,wsBuf,nBufSize); </p>
<p>wstring wstrRet(wsBuf);</p>
<p>delete []wsBuf;<br>wsBuf = NULL;</p>
<p>return wstrRet;<br>}</p>
<p>&nbsp;</p>
<p><br>转载：csdn</p>
<p>这篇文章里，我将给出几种C++ std::string和std::wstring相互转换的转换方法。<br>&nbsp;<br>第一种方法：调用WideCharToMultiByte()和MultiByteToWideChar()，代码如下（关于详细的解释，可以参考《windows核心编程》）：<br>&nbsp;</p>
<p>#include &lt;string&gt;<br>#include &lt;windows.h&gt;<br>using namespace std;<br>//Converting a WChar string to a Ansi string<br>std::string WChar2Ansi(LPCWSTR pwszSrc)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int nLen = WideCharToMultiByte(CP_ACP, 0, pwszSrc, -1, NULL, 0, NULL, NULL);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (nLen&lt;= 0) return std::string("");<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char* pszDst = new char[nLen];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (NULL == pszDst) return std::string("");<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WideCharToMultiByte(CP_ACP, 0, pwszSrc, -1, pszDst, nLen, NULL, NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pszDst[nLen -1] = 0;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::string strTemp(pszDst);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delete [] pszDst;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return strTemp;<br>}</p>
<p>&nbsp;<br>string ws2s(wstring&amp; inputws)<br>{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return WChar2Ansi(inputws.c_str()); <br>}</p>
<p>&nbsp;</p>
<p>&nbsp;<br>//Converting a Ansi string to WChar string </p>
<p><br>std::wstring Ansi2WChar(LPCSTR pszSrc, int nLen)<br>&nbsp;<br>{<br>&nbsp;&nbsp;&nbsp; int nSize = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pszSrc, nLen, 0, 0);<br>&nbsp;&nbsp;&nbsp; if(nSize &lt;= 0) return NULL;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WCHAR *pwszDst = new WCHAR[nSize+1];<br>&nbsp;&nbsp;&nbsp; if( NULL == pwszDst) return NULL;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; MultiByteToWideChar(CP_ACP, 0,(LPCSTR)pszSrc, nLen, pwszDst, nSize);<br>&nbsp;&nbsp;&nbsp; pwszDst[nSize] = 0;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; if( pwszDst[0] == 0xFEFF)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // skip Oxfeff<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i = 0; i &lt; nSize; i ++) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pwszDst[i] = pwszDst[i+1]; <br>&nbsp;<br>&nbsp;&nbsp;&nbsp; wstring wcharString(pwszDst);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delete pwszDst;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; return wcharString;<br>}</p>
<p>&nbsp;<br>std::wstring s2ws(const string&amp; s)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp; return Ansi2WChar(s.c_str(),s.size());<br>}</p>
<p><br>&nbsp; <br>&nbsp;<br>第二种方法：采用ATL封装_bstr_t的过渡：（注，_bstr_是Microsoft Specific的，所以下面代码可以在VS2005通过，无移植性）；</p>
<p><br>#include &lt;string&gt;<br>#include &lt;comutil.h&gt;<br>using namespace std;<br>#pragma comment(lib, "comsuppw.lib") <br>&nbsp;<br>string ws2s(const wstring&amp; ws);<br>wstring s2ws(const string&amp; s);<br>&nbsp;<br>string ws2s(const wstring&amp; ws)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _bstr_t t = ws.c_str();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char* pchar = (char*)t;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string result = pchar;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return result;<br>}</p>
<p>&nbsp;<br>wstring s2ws(const string&amp; s)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _bstr_t t = s.c_str();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wchar_t* pwchar = (wchar_t*)t;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wstring result = pwchar;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return result;<br>}</p>
<p><br>&nbsp;<br>第三种方法：使用CRT库的mbstowcs()函数和wcstombs()函数，平台无关，需设定locale。</p>
<p><br>#include &lt;string&gt;<br>#include &lt;locale.h&gt;<br>using namespace std;<br>string ws2s(const wstring&amp; ws)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string curLocale = setlocale(LC_ALL, NULL);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // curLocale = "C";<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setlocale(LC_ALL, "chs"); <br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const wchar_t* _Source = ws.c_str();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size_t _Dsize = 2 * ws.size() + 1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char *_Dest = new char[_Dsize];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memset(_Dest,0,_Dsize);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wcstombs(_Dest,_Source,_Dsize);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string result = _Dest;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delete []_Dest;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setlocale(LC_ALL, curLocale.c_str());<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return result;<br>}</p>
<p>&nbsp;<br>wstring s2ws(const string&amp; s)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setlocale(LC_ALL, "chs"); <br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const char* _Source = s.c_str();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size_t _Dsize = s.size() + 1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wchar_t *_Dest = new wchar_t[_Dsize];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wmemset(_Dest, 0, _Dsize);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mbstowcs(_Dest,_Source,_Dsize);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wstring result = _Dest;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delete []_Dest;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setlocale(LC_ALL, "C");<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return result;<br>}</p>
<p><br>二 utf8.utf16.utf32的相互转化</p>
<p>可以参考Unicode.org 上有ConvertUTF.c和ConvertUTF.h （下载地址：<a href="http://www.unicode.org/Public/PROGRAMS/CVTUTF/"><u><font color=#6fbc4c>http://www.unicode.org/Public/PROGRAMS/CVTUTF/</font></u></a>）</p>
<p>实现文件ConvertUTF.c：（.h省）<br>/**//*<br>&nbsp;* Copyright 2001-2004 Unicode, Inc.<br>&nbsp;* <br>&nbsp;* Disclaimer<br>&nbsp;* <br>&nbsp;* This source code is provided as is by Unicode, Inc. No claims are<br>&nbsp;* made as to fitness for any particular purpose. No warranties of any<br>&nbsp;* kind are expressed or implied. The recipient agrees to determine<br>&nbsp;* applicability of information provided. If this file has been<br>&nbsp;* purchased on magnetic or optical media from Unicode, Inc., the<br>&nbsp;* sole remedy for any claim will be exchange of defective media<br>&nbsp;* within 90 days of receipt.<br>&nbsp;* <br>&nbsp;* Limitations on Rights to Redistribute This Code<br>&nbsp;* <br>&nbsp;* Unicode, Inc. hereby grants the right to freely use the information<br>&nbsp;* supplied in this file in the creation of products supporting the<br>&nbsp;* Unicode Standard, and to make copies of this file in any form<br>&nbsp;* for internal or external distribution as long as this notice<br>&nbsp;* remains attached.<br>&nbsp;*/</p>
<p>/**//* ---------------------------------------------------------------------</p>
<p>&nbsp;&nbsp;&nbsp; Conversions between UTF32, UTF-16, and UTF-8. Source code file.<br>&nbsp;&nbsp;&nbsp; Author: Mark E. Davis, 1994.<br>&nbsp;&nbsp;&nbsp; Rev History: Rick McGowan, fixes &amp; updates May 2001.<br>&nbsp;&nbsp;&nbsp; Sept 2001: fixed const &amp; error conditions per<br>&nbsp;&nbsp;&nbsp; mods suggested by S. Parent &amp; A. Lillich.<br>&nbsp;&nbsp;&nbsp; June 2002: Tim Dodd added detection and handling of incomplete<br>&nbsp;&nbsp;&nbsp; source sequences, enhanced error detection, added casts<br>&nbsp;&nbsp;&nbsp; to eliminate compiler warnings.<br>&nbsp;&nbsp;&nbsp; July 2003: slight mods to back out aggressive FFFE detection.<br>&nbsp;&nbsp;&nbsp; Jan 2004: updated switches in from-UTF8 conversions.<br>&nbsp;&nbsp;&nbsp; Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.</p>
<p>&nbsp;&nbsp;&nbsp; See the header file "ConvertUTF.h" for complete documentation.</p>
<p>------------------------------------------------------------------------ */</p>
<p><br>#include "ConvertUTF.h"<br>#ifdef CVTUTF_DEBUG<br>#include &lt;stdio.h&gt;<br>#endif</p>
<p>static const int halfShift&nbsp; = 10; /**//* used for shifting by 10 bits */</p>
<p>static const UTF32 halfBase = 0x0010000UL;<br>static const UTF32 halfMask = 0x3FFUL;</p>
<p>#define UNI_SUR_HIGH_START&nbsp; (UTF32)0xD800<br>#define UNI_SUR_HIGH_END&nbsp;&nbsp;&nbsp; (UTF32)0xDBFF<br>#define UNI_SUR_LOW_START&nbsp;&nbsp; (UTF32)0xDC00<br>#define UNI_SUR_LOW_END&nbsp;&nbsp;&nbsp;&nbsp; (UTF32)0xDFFF<br>#define false&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0<br>#define true&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1</p>
<p>/**//* --------------------------------------------------------------------- */</p>
<p>ConversionResult ConvertUTF32toUTF16 (<br>&nbsp;&nbsp;&nbsp; const UTF32** sourceStart, const UTF32* sourceEnd, <br>&nbsp;&nbsp;&nbsp; UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {<br>&nbsp;&nbsp;&nbsp; ConversionResult result = conversionOK;<br>&nbsp;&nbsp;&nbsp; const UTF32* source = *sourceStart;<br>&nbsp;&nbsp;&nbsp; UTF16* target = *targetStart;<br>&nbsp;&nbsp;&nbsp; while (source &lt; sourceEnd) {<br>&nbsp;&nbsp;&nbsp; UTF32 ch;<br>&nbsp;&nbsp;&nbsp; if (target &gt;= targetEnd) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = targetExhausted; break;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; ch = *source++;<br>&nbsp;&nbsp;&nbsp; if (ch &lt;= UNI_MAX_BMP) { /**//* Target is a character &lt;= 0xFFFF */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**//* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ch &gt;= UNI_SUR_HIGH_START &amp;&amp; ch &lt;= UNI_SUR_LOW_END) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (flags == strictConversion) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --source; /**//* return to the illegal value itself */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = sourceIllegal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *target++ = UNI_REPLACEMENT_CHAR;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *target++ = (UTF16)ch; /**//* normal case */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; } else if (ch &gt; UNI_MAX_LEGAL_UTF32) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (flags == strictConversion) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = sourceIllegal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *target++ = UNI_REPLACEMENT_CHAR;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; } else {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**//* target is a character in range 0xFFFF - 0x10FFFF. */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (target + 1 &gt;= targetEnd) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --source; /**//* Back up source pointer! */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = targetExhausted; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ch -= halfBase;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *target++ = (UTF16)((ch &gt;&gt; halfShift) + UNI_SUR_HIGH_START);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *target++ = (UTF16)((ch &amp; halfMask) + UNI_SUR_LOW_START);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; *sourceStart = source;<br>&nbsp;&nbsp;&nbsp; *targetStart = target;<br>&nbsp;&nbsp;&nbsp; return result;<br>}</p>
<p>/**//* --------------------------------------------------------------------- */</p>
<p>ConversionResult ConvertUTF16toUTF32 (<br>&nbsp;&nbsp;&nbsp; const UTF16** sourceStart, const UTF16* sourceEnd, <br>&nbsp;&nbsp;&nbsp; UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {<br>&nbsp;&nbsp;&nbsp; ConversionResult result = conversionOK;<br>&nbsp;&nbsp;&nbsp; const UTF16* source = *sourceStart;<br>&nbsp;&nbsp;&nbsp; UTF32* target = *targetStart;<br>&nbsp;&nbsp;&nbsp; UTF32 ch, ch2;<br>&nbsp;&nbsp;&nbsp; while (source &lt; sourceEnd) {<br>&nbsp;&nbsp;&nbsp; const UTF16* oldSource = source; /**//*&nbsp; In case we have to back up because of target overflow. */<br>&nbsp;&nbsp;&nbsp; ch = *source++;<br>&nbsp;&nbsp;&nbsp; /**//* If we have a surrogate pair, convert to UTF32 first. */<br>&nbsp;&nbsp;&nbsp; if (ch &gt;= UNI_SUR_HIGH_START &amp;&amp; ch &lt;= UNI_SUR_HIGH_END) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**//* If the 16 bits following the high surrogate are in the source buffer */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (source &lt; sourceEnd) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ch2 = *source;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**//* If it's a low surrogate, convert to UTF32. */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ch2 &gt;= UNI_SUR_LOW_START &amp;&amp; ch2 &lt;= UNI_SUR_LOW_END) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ch = ((ch - UNI_SUR_HIGH_START) &lt;&lt; halfShift)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + (ch2 - UNI_SUR_LOW_START) + halfBase;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ++source;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (flags == strictConversion) { /**//* it's an unpaired high surrogate */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --source; /**//* return to the illegal value itself */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = sourceIllegal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else { /**//* We don't have the 16 bits following the high surrogate. */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --source; /**//* return to the high surrogate */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = sourceExhausted;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; } else if (flags == strictConversion) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**//* UTF-16 surrogate values are illegal in UTF-32 */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ch &gt;= UNI_SUR_LOW_START &amp;&amp; ch &lt;= UNI_SUR_LOW_END) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --source; /**//* return to the illegal value itself */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = sourceIllegal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; if (target &gt;= targetEnd) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; source = oldSource; /**//* Back up source pointer! */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = targetExhausted; break;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; *target++ = ch;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; *sourceStart = source;<br>&nbsp;&nbsp;&nbsp; *targetStart = target;<br>#ifdef CVTUTF_DEBUG<br>if (result == sourceIllegal) {<br>&nbsp;&nbsp;&nbsp; fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);<br>&nbsp;&nbsp;&nbsp; fflush(stderr);<br>}<br>#endif<br>&nbsp;&nbsp;&nbsp; return result;<br>}</p>
<p>/**//* --------------------------------------------------------------------- */</p>
<p>/**//*<br>&nbsp;* Index into the table below with the first byte of a UTF-8 sequence to<br>&nbsp;* get the number of trailing bytes that are supposed to follow it.<br>&nbsp;* Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is<br>&nbsp;* left as-is for anyone who may want to do such conversion, which was<br>&nbsp;* allowed in earlier algorithms.<br>&nbsp;*/<br>static const char trailingBytesForUTF8[256] = {<br>&nbsp;&nbsp;&nbsp; 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,<br>&nbsp;&nbsp;&nbsp; 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,<br>&nbsp;&nbsp;&nbsp; 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,<br>&nbsp;&nbsp;&nbsp; 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,<br>&nbsp;&nbsp;&nbsp; 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,<br>&nbsp;&nbsp;&nbsp; 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,<br>&nbsp;&nbsp;&nbsp; 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,<br>&nbsp;&nbsp;&nbsp; 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5<br>};</p>
<p>/**//*<br>&nbsp;* Magic values subtracted from a buffer value during UTF8 conversion.<br>&nbsp;* This table contains as many values as there might be trailing bytes<br>&nbsp;* in a UTF-8 sequence.<br>&nbsp;*/<br>static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x03C82080UL, 0xFA082080UL, 0x82082080UL };</p>
<p>/**//*<br>&nbsp;* Once the bits are split out into bytes of UTF-8, this is a mask OR-ed<br>&nbsp;* into the first byte, depending on how many bytes follow.&nbsp; There are<br>&nbsp;* as many entries in this table as there are UTF-8 sequence types.<br>&nbsp;* (I.e., one byte sequence, two byte etc.). Remember that sequencs<br>&nbsp;* for *legal* UTF-8 will be 4 or fewer bytes total.<br>&nbsp;*/<br>static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };</p>
<p>/**//* --------------------------------------------------------------------- */</p>
<p>/**//* The interface converts a whole buffer to avoid function-call overhead.<br>&nbsp;* Constants have been gathered. Loops &amp; conditionals have been removed as<br>&nbsp;* much as possible for efficiency, in favor of drop-through switches.<br>&nbsp;* (See "Note A" at the bottom of the file for equivalent code.)<br>&nbsp;* If your compiler supports it, the "isLegalUTF8" call can be turned<br>&nbsp;* into an inline function.<br>&nbsp;*/</p>
<p>/**//* --------------------------------------------------------------------- */</p>
<p>ConversionResult ConvertUTF16toUTF8 (<br>&nbsp;&nbsp;&nbsp; const UTF16** sourceStart, const UTF16* sourceEnd, <br>&nbsp;&nbsp;&nbsp; UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {<br>&nbsp;&nbsp;&nbsp; ConversionResult result = conversionOK;<br>&nbsp;&nbsp;&nbsp; const UTF16* source = *sourceStart;<br>&nbsp;&nbsp;&nbsp; UTF8* target = *targetStart;<br>&nbsp;&nbsp;&nbsp; while (source &lt; sourceEnd) {<br>&nbsp;&nbsp;&nbsp; UTF32 ch;<br>&nbsp;&nbsp;&nbsp; unsigned short bytesToWrite = 0;<br>&nbsp;&nbsp;&nbsp; const UTF32 byteMask = 0xBF;<br>&nbsp;&nbsp;&nbsp; const UTF32 byteMark = 0x80; <br>&nbsp;&nbsp;&nbsp; const UTF16* oldSource = source; /**//* In case we have to back up because of target overflow. */<br>&nbsp;&nbsp;&nbsp; ch = *source++;<br>&nbsp;&nbsp;&nbsp; /**//* If we have a surrogate pair, convert to UTF32 first. */<br>&nbsp;&nbsp;&nbsp; if (ch &gt;= UNI_SUR_HIGH_START &amp;&amp; ch &lt;= UNI_SUR_HIGH_END) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**//* If the 16 bits following the high surrogate are in the source buffer */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (source &lt; sourceEnd) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UTF32 ch2 = *source;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**//* If it's a low surrogate, convert to UTF32. */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ch2 &gt;= UNI_SUR_LOW_START &amp;&amp; ch2 &lt;= UNI_SUR_LOW_END) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ch = ((ch - UNI_SUR_HIGH_START) &lt;&lt; halfShift)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + (ch2 - UNI_SUR_LOW_START) + halfBase;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ++source;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (flags == strictConversion) { /**//* it's an unpaired high surrogate */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --source; /**//* return to the illegal value itself */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = sourceIllegal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else { /**//* We don't have the 16 bits following the high surrogate. */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --source; /**//* return to the high surrogate */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = sourceExhausted;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; } else if (flags == strictConversion) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**//* UTF-16 surrogate values are illegal in UTF-32 */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ch &gt;= UNI_SUR_LOW_START &amp;&amp; ch &lt;= UNI_SUR_LOW_END) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --source; /**//* return to the illegal value itself */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = sourceIllegal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; /**//* Figure out how many bytes the result will require */<br>&nbsp;&nbsp;&nbsp; if (ch &lt; (UTF32)0x80) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bytesToWrite = 1;<br>&nbsp;&nbsp;&nbsp; } else if (ch &lt; (UTF32)0x800) {&nbsp;&nbsp;&nbsp;&nbsp; bytesToWrite = 2;<br>&nbsp;&nbsp;&nbsp; } else if (ch &lt; (UTF32)0x10000) {&nbsp;&nbsp; bytesToWrite = 3;<br>&nbsp;&nbsp;&nbsp; } else if (ch &lt; (UTF32)0x110000) {&nbsp; bytesToWrite = 4;<br>&nbsp;&nbsp;&nbsp; } else {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bytesToWrite = 3;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ch = UNI_REPLACEMENT_CHAR;<br>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; target += bytesToWrite;<br>&nbsp;&nbsp;&nbsp; if (target &gt; targetEnd) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; source = oldSource; /**//* Back up source pointer! */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; target -= bytesToWrite; result = targetExhausted; break;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; switch (bytesToWrite) { /**//* note: everything falls through. */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 4: *--target = (UTF8)((ch | byteMark) &amp; byteMask); ch &gt;&gt;= 6;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 3: *--target = (UTF8)((ch | byteMark) &amp; byteMask); ch &gt;&gt;= 6;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 2: *--target = (UTF8)((ch | byteMark) &amp; byteMask); ch &gt;&gt;= 6;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 1: *--target =&nbsp; (UTF8)(ch | firstByteMark[bytesToWrite]);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; target += bytesToWrite;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; *sourceStart = source;<br>&nbsp;&nbsp;&nbsp; *targetStart = target;<br>&nbsp;&nbsp;&nbsp; return result;<br>}</p>
<p>/**//* --------------------------------------------------------------------- */</p>
<p>/**//*<br>&nbsp;* Utility routine to tell whether a sequence of bytes is legal UTF-8.<br>&nbsp;* This must be called with the length pre-determined by the first byte.<br>&nbsp;* If not calling this from ConvertUTF8to*, then the length can be set by:<br>&nbsp;*&nbsp; length = trailingBytesForUTF8[*source]+1;<br>&nbsp;* and the sequence is illegal right away if there aren't that many bytes<br>&nbsp;* available.<br>&nbsp;* If presented with a length &gt; 4, this returns false.&nbsp; The Unicode<br>&nbsp;* definition of UTF-8 goes up to 4-byte sequences.<br>&nbsp;*/</p>
<p>static Boolean isLegalUTF8(const UTF8 *source, int length) {<br>&nbsp;&nbsp;&nbsp; UTF8 a;<br>&nbsp;&nbsp;&nbsp; const UTF8 *srcptr = source+length;<br>&nbsp;&nbsp;&nbsp; switch (length) {<br>&nbsp;&nbsp;&nbsp; default: return false;<br>&nbsp;&nbsp;&nbsp; /**//* Everything else falls through when "true" */<br>&nbsp;&nbsp;&nbsp; case 4: if ((a = (*--srcptr)) &lt; 0x80 || a &gt; 0xBF) return false;<br>&nbsp;&nbsp;&nbsp; case 3: if ((a = (*--srcptr)) &lt; 0x80 || a &gt; 0xBF) return false;<br>&nbsp;&nbsp;&nbsp; case 2: if ((a = (*--srcptr)) &gt; 0xBF) return false;</p>
<p>&nbsp;&nbsp;&nbsp; switch (*source) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**//* no fall-through in this inner switch */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 0xE0: if (a &lt; 0xA0) return false; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 0xED: if (a &gt; 0x9F) return false; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 0xF0: if (a &lt; 0x90) return false; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 0xF4: if (a &gt; 0x8F) return false; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; default:&nbsp;&nbsp; if (a &lt; 0x80) return false;<br>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; case 1: if (*source &gt;= 0x80 &amp;&amp; *source &lt; 0xC2) return false;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; if (*source &gt; 0xF4) return false;<br>&nbsp;&nbsp;&nbsp; return true;<br>}</p>
<p>/**//* --------------------------------------------------------------------- */</p>
<p>/**//*<br>&nbsp;* Exported function to return whether a UTF-8 sequence is legal or not.<br>&nbsp;* This is not used here; it's just exported.<br>&nbsp;*/<br>Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {<br>&nbsp;&nbsp;&nbsp; int length = trailingBytesForUTF8[*source]+1;<br>&nbsp;&nbsp;&nbsp; if (source+length &gt; sourceEnd) {<br>&nbsp;&nbsp;&nbsp; return false;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; return isLegalUTF8(source, length);<br>}</p>
<p>/**//* --------------------------------------------------------------------- */</p>
<p>ConversionResult ConvertUTF8toUTF16 (<br>&nbsp;&nbsp;&nbsp; const UTF8** sourceStart, const UTF8* sourceEnd, <br>&nbsp;&nbsp;&nbsp; UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {<br>&nbsp;&nbsp;&nbsp; ConversionResult result = conversionOK;<br>&nbsp;&nbsp;&nbsp; const UTF8* source = *sourceStart;<br>&nbsp;&nbsp;&nbsp; UTF16* target = *targetStart;<br>&nbsp;&nbsp;&nbsp; while (source &lt; sourceEnd) {<br>&nbsp;&nbsp;&nbsp; UTF32 ch = 0;<br>&nbsp;&nbsp;&nbsp; unsigned short extraBytesToRead = trailingBytesForUTF8[*source];<br>&nbsp;&nbsp;&nbsp; if (source + extraBytesToRead &gt;= sourceEnd) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = sourceExhausted; break;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; /**//* Do this check whether lenient or strict */<br>&nbsp;&nbsp;&nbsp; if (! isLegalUTF8(source, extraBytesToRead+1)) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = sourceIllegal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; /**//*<br>&nbsp;&nbsp;&nbsp;&nbsp; * The cases all fall through. See "Note A" below.<br>&nbsp;&nbsp;&nbsp;&nbsp; */<br>&nbsp;&nbsp;&nbsp; switch (extraBytesToRead) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 5: ch += *source++; ch &lt;&lt;= 6; /**//* remember, illegal UTF-8 */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 4: ch += *source++; ch &lt;&lt;= 6; /**//* remember, illegal UTF-8 */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 3: ch += *source++; ch &lt;&lt;= 6;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 2: ch += *source++; ch &lt;&lt;= 6;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 1: ch += *source++; ch &lt;&lt;= 6;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 0: ch += *source++;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; ch -= offsetsFromUTF8[extraBytesToRead];</p>
<p>&nbsp;&nbsp;&nbsp; if (target &gt;= targetEnd) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; source -= (extraBytesToRead+1); /**//* Back up source pointer! */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = targetExhausted; break;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; if (ch &lt;= UNI_MAX_BMP) { /**//* Target is a character &lt;= 0xFFFF */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**//* UTF-16 surrogate values are illegal in UTF-32 */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ch &gt;= UNI_SUR_HIGH_START &amp;&amp; ch &lt;= UNI_SUR_LOW_END) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (flags == strictConversion) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; source -= (extraBytesToRead+1); /**//* return to the illegal value itself */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = sourceIllegal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *target++ = UNI_REPLACEMENT_CHAR;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *target++ = (UTF16)ch; /**//* normal case */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; } else if (ch &gt; UNI_MAX_UTF16) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (flags == strictConversion) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = sourceIllegal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; source -= (extraBytesToRead+1); /**//* return to the start */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break; /**//* Bail out; shouldn't continue */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *target++ = UNI_REPLACEMENT_CHAR;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; } else {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**//* target is a character in range 0xFFFF - 0x10FFFF. */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (target + 1 &gt;= targetEnd) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; source -= (extraBytesToRead+1); /**//* Back up source pointer! */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = targetExhausted; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ch -= halfBase;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *target++ = (UTF16)((ch &gt;&gt; halfShift) + UNI_SUR_HIGH_START);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *target++ = (UTF16)((ch &amp; halfMask) + UNI_SUR_LOW_START);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; *sourceStart = source;<br>&nbsp;&nbsp;&nbsp; *targetStart = target;<br>&nbsp;&nbsp;&nbsp; return result;<br>}</p>
<p>/**//* --------------------------------------------------------------------- */</p>
<p>ConversionResult ConvertUTF32toUTF8 (<br>&nbsp;&nbsp;&nbsp; const UTF32** sourceStart, const UTF32* sourceEnd, <br>&nbsp;&nbsp;&nbsp; UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {<br>&nbsp;&nbsp;&nbsp; ConversionResult result = conversionOK;<br>&nbsp;&nbsp;&nbsp; const UTF32* source = *sourceStart;<br>&nbsp;&nbsp;&nbsp; UTF8* target = *targetStart;<br>&nbsp;&nbsp;&nbsp; while (source &lt; sourceEnd) {<br>&nbsp;&nbsp;&nbsp; UTF32 ch;<br>&nbsp;&nbsp;&nbsp; unsigned short bytesToWrite = 0;<br>&nbsp;&nbsp;&nbsp; const UTF32 byteMask = 0xBF;<br>&nbsp;&nbsp;&nbsp; const UTF32 byteMark = 0x80; <br>&nbsp;&nbsp;&nbsp; ch = *source++;<br>&nbsp;&nbsp;&nbsp; if (flags == strictConversion ) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**//* UTF-16 surrogate values are illegal in UTF-32 */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ch &gt;= UNI_SUR_HIGH_START &amp;&amp; ch &lt;= UNI_SUR_LOW_END) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --source; /**//* return to the illegal value itself */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = sourceIllegal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; /**//*<br>&nbsp;&nbsp;&nbsp;&nbsp; * Figure out how many bytes the result will require. Turn any<br>&nbsp;&nbsp;&nbsp;&nbsp; * illegally large UTF32 things (&gt; Plane 17) into replacement chars.<br>&nbsp;&nbsp;&nbsp;&nbsp; */<br>&nbsp;&nbsp;&nbsp; if (ch &lt; (UTF32)0x80) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bytesToWrite = 1;<br>&nbsp;&nbsp;&nbsp; } else if (ch &lt; (UTF32)0x800) {&nbsp;&nbsp;&nbsp;&nbsp; bytesToWrite = 2;<br>&nbsp;&nbsp;&nbsp; } else if (ch &lt; (UTF32)0x10000) {&nbsp;&nbsp; bytesToWrite = 3;<br>&nbsp;&nbsp;&nbsp; } else if (ch &lt;= UNI_MAX_LEGAL_UTF32) {&nbsp; bytesToWrite = 4;<br>&nbsp;&nbsp;&nbsp; } else {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bytesToWrite = 3;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ch = UNI_REPLACEMENT_CHAR;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = sourceIllegal;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; target += bytesToWrite;<br>&nbsp;&nbsp;&nbsp; if (target &gt; targetEnd) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --source; /**//* Back up source pointer! */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; target -= bytesToWrite; result = targetExhausted; break;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; switch (bytesToWrite) { /**//* note: everything falls through. */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 4: *--target = (UTF8)((ch | byteMark) &amp; byteMask); ch &gt;&gt;= 6;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 3: *--target = (UTF8)((ch | byteMark) &amp; byteMask); ch &gt;&gt;= 6;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 2: *--target = (UTF8)((ch | byteMark) &amp; byteMask); ch &gt;&gt;= 6;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; target += bytesToWrite;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; *sourceStart = source;<br>&nbsp;&nbsp;&nbsp; *targetStart = target;<br>&nbsp;&nbsp;&nbsp; return result;<br>}</p>
<p>/**//* --------------------------------------------------------------------- */</p>
<p>ConversionResult ConvertUTF8toUTF32 (<br>&nbsp;&nbsp;&nbsp; const UTF8** sourceStart, const UTF8* sourceEnd, <br>&nbsp;&nbsp;&nbsp; UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {<br>&nbsp;&nbsp;&nbsp; ConversionResult result = conversionOK;<br>&nbsp;&nbsp;&nbsp; const UTF8* source = *sourceStart;<br>&nbsp;&nbsp;&nbsp; UTF32* target = *targetStart;<br>&nbsp;&nbsp;&nbsp; while (source &lt; sourceEnd) {<br>&nbsp;&nbsp;&nbsp; UTF32 ch = 0;<br>&nbsp;&nbsp;&nbsp; unsigned short extraBytesToRead = trailingBytesForUTF8[*source];<br>&nbsp;&nbsp;&nbsp; if (source + extraBytesToRead &gt;= sourceEnd) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = sourceExhausted; break;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; /**//* Do this check whether lenient or strict */<br>&nbsp;&nbsp;&nbsp; if (! isLegalUTF8(source, extraBytesToRead+1)) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = sourceIllegal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; /**//*<br>&nbsp;&nbsp;&nbsp;&nbsp; * The cases all fall through. See "Note A" below.<br>&nbsp;&nbsp;&nbsp;&nbsp; */<br>&nbsp;&nbsp;&nbsp; switch (extraBytesToRead) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 5: ch += *source++; ch &lt;&lt;= 6;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 4: ch += *source++; ch &lt;&lt;= 6;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 3: ch += *source++; ch &lt;&lt;= 6;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 2: ch += *source++; ch &lt;&lt;= 6;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 1: ch += *source++; ch &lt;&lt;= 6;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 0: ch += *source++;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; ch -= offsetsFromUTF8[extraBytesToRead];</p>
<p>&nbsp;&nbsp;&nbsp; if (target &gt;= targetEnd) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; source -= (extraBytesToRead+1); /**//* Back up the source pointer! */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = targetExhausted; break;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; if (ch &lt;= UNI_MAX_LEGAL_UTF32) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**//*<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * UTF-16 surrogate values are illegal in UTF-32, and anything<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * over Plane 17 (&gt; 0x10FFFF) is illegal.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ch &gt;= UNI_SUR_HIGH_START &amp;&amp; ch &lt;= UNI_SUR_LOW_END) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (flags == strictConversion) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; source -= (extraBytesToRead+1); /**//* return to the illegal value itself */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = sourceIllegal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *target++ = UNI_REPLACEMENT_CHAR;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *target++ = ch;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; } else { /**//* i.e., ch &gt; UNI_MAX_LEGAL_UTF32 */<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = sourceIllegal;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *target++ = UNI_REPLACEMENT_CHAR;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; *sourceStart = source;<br>&nbsp;&nbsp;&nbsp; *targetStart = target;<br>&nbsp;&nbsp;&nbsp; return result;<br>}</p>
<p>/**//* ---------------------------------------------------------------------</p>
<p>&nbsp;&nbsp;&nbsp; Note A.<br>&nbsp;&nbsp;&nbsp; The fall-through switches in UTF-8 reading code save a<br>&nbsp;&nbsp;&nbsp; temp variable, some decrements &amp; conditionals.&nbsp; The switches<br>&nbsp;&nbsp;&nbsp; are equivalent to the following loop:<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int tmpBytesToRead = extraBytesToRead+1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ch += *source++;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --tmpBytesToRead;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (tmpBytesToRead) ch &lt;&lt;= 6;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (tmpBytesToRead &gt; 0);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; In UTF-8 writing code, the switches on "bytesToWrite" are<br>&nbsp;&nbsp;&nbsp; similarly unrolled loops.</p>
<p>&nbsp;&nbsp; --------------------------------------------------------------------- */</p>
<p>&nbsp;</p>
<p>三 C++ 的字符串与C#的转化</p>
<p>1）将system::String 转化为C++的string：<br>// convert_system_string.cpp<br>// compile with: /clr<br>#include &lt;string&gt;<br>#include &lt;iostream&gt;<br>using namespace std;<br>using namespace System;</p>
<p>void MarshalString ( String ^ s, string&amp; os ) {<br>&nbsp;&nbsp; using namespace Runtime::InteropServices;<br>&nbsp;&nbsp; const char* chars = <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (const char*)(Marshal::StringToHGlobalAnsi(s)).ToPointer();<br>&nbsp;&nbsp; os = chars;<br>&nbsp;&nbsp; Marshal::FreeHGlobal(IntPtr((void*)chars));<br>}</p>
<p>void MarshalString ( String ^ s, wstring&amp; os ) {<br>&nbsp;&nbsp; using namespace Runtime::InteropServices;<br>&nbsp;&nbsp; const wchar_t* chars = <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (const wchar_t*)(Marshal::StringToHGlobalUni(s)).ToPointer();<br>&nbsp;&nbsp; os = chars;<br>&nbsp;&nbsp; Marshal::FreeHGlobal(IntPtr((void*)chars));<br>}</p>
<p>int main() {<br>&nbsp;&nbsp; string a = "test";<br>&nbsp;&nbsp; wstring b = L"test2";<br>&nbsp;&nbsp; String ^ c = gcnew String("abcd");</p>
<p>&nbsp;&nbsp; cout &lt;&lt; a &lt;&lt; endl;<br>&nbsp;&nbsp; MarshalString(c, a);<br>&nbsp;&nbsp; c = "efgh";<br>&nbsp;&nbsp; MarshalString(c, b);<br>&nbsp;&nbsp; cout &lt;&lt; a &lt;&lt; endl;<br>&nbsp;&nbsp; wcout &lt;&lt; b &lt;&lt; endl;<br>}</p>
<p><br>2）将System::String转化为char*或w_char*<br>// convert_string_to_wchar.cpp<br>// compile with: /clr<br>#include &lt; stdio.h &gt;<br>#include &lt; stdlib.h &gt;<br>#include &lt; vcclr.h &gt;</p>
<p>using namespace System;</p>
<p>int main() {<br>&nbsp;&nbsp; String ^str = "Hello";</p>
<p>&nbsp;&nbsp; // Pin memory so GC can't move it while native function is called<br>&nbsp;&nbsp; pin_ptr&lt;const wchar_t&gt; wch = PtrToStringChars(str);<br>&nbsp;&nbsp; printf_s("%S\n", wch);</p>
<p>&nbsp;&nbsp; // Conversion to char* :<br>&nbsp;&nbsp; // Can just convert wchar_t* to char* using one of the <br>&nbsp;&nbsp; // conversion functions such as: <br>&nbsp;&nbsp; // WideCharToMultiByte()<br>&nbsp;&nbsp; // wcstombs_s()<br>&nbsp;&nbsp; //&nbsp; etc<br>&nbsp;&nbsp; size_t convertedChars = 0;<br>&nbsp;&nbsp; size_t&nbsp; sizeInBytes = ((str-&gt;Length + 1) * 2);<br>&nbsp;&nbsp; errno_t err = 0;<br>&nbsp;&nbsp; char&nbsp;&nbsp;&nbsp; *ch = (char *)malloc(sizeInBytes);</p>
<p>&nbsp;&nbsp; err = wcstombs_s(&amp;convertedChars, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ch, sizeInBytes,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wch, sizeInBytes);<br>&nbsp;&nbsp; if (err != 0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf_s("wcstombs_s&nbsp; failed!\n");</p>
<p>&nbsp;&nbsp;&nbsp; printf_s("%s\n", ch);<br>}<br></p>
<img src ="http://www.cppblog.com/true/aggbug/36895.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/true/" target="_blank">true</a> 2007-11-18 19:48 <a href="http://www.cppblog.com/true/archive/2007/11/18/36895.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>utf8编码简介</title><link>http://www.cppblog.com/true/archive/2007/04/05/21335.html</link><dc:creator>true</dc:creator><author>true</author><pubDate>Thu, 05 Apr 2007 09:23:00 GMT</pubDate><guid>http://www.cppblog.com/true/archive/2007/04/05/21335.html</guid><wfw:comment>http://www.cppblog.com/true/comments/21335.html</wfw:comment><comments>http://www.cppblog.com/true/archive/2007/04/05/21335.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/true/comments/commentRss/21335.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/true/services/trackbacks/21335.html</trackback:ping><description><![CDATA[<p align=center><font size=5>utf8的编码算法</font><br>作者：转载&nbsp;&nbsp;&nbsp;&nbsp;转贴自：转载&nbsp;&nbsp;&nbsp;&nbsp;点击数：827&nbsp;&nbsp;&nbsp;&nbsp;文章录入： zhaizl </p>
<p>
<blockquote></blockquote><br><br>
<p dir=ltr style="MARGIN-RIGHT: 0px"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>例如字符"汉"的unicode是6C49，把这个unicode字符表示为一个大整数，然后转变成多字节编码110110001001001：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>观察这个整数的二进制码序列（110，110001，001001）<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 从后往前取<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>如果这个二进制序列只有后7位（小于128,也就是ascii字符）则直接取后7位二进制数形成一个utf8字符。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>上面的字符&#8220;汉&#8221;二进制序列大于7位，所以取后6位(1001001)，加10形成一个utf8字节（10 001001 ,16进制89）。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>剩下的二进制序列（110，110001）从后向前取6位，加10形成一个utf8字节（10 110001，16进制B1）。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>剩下的二进制序列（110）从后向前取6位，由于不足6位，将这个数和1110000相或，得到字符11100110，16进制E6<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>最后，就得到了utf8编码，16进制表示为E6B189</p>
<br>
<div class=tit twffan="done">解读UTF8编码</div>
<div class=date twffan="done">2007-01-19 10:40</div>
<table style="TABLE-LAYOUT: fixed">
    <tbody>
        <tr>
            <td>
            <div class=cnt twffan="done">
            <p>在网络中有很多地方都有采用UTF8编码，由于要编写与邮件服务端有关的程序，而邮件服务端有些地方用到了UTF8编码，所以对它有了初步的认识！<br><br>它其实和Unicode是同类，就是在编码方式上不同！<br>首先UTF8编码后的大小是不一定，不像Unicode编码后的大小是一样的！&nbsp;<br>我们先来看Unicode的编码：一个英文字母&nbsp;&#8220;a&#8221;&nbsp;和　一个汉字&nbsp;&#8220;好&#8221;，编码后都是占用的空间大小是一样的，都是两个字节！<br><br>而UTF8编码：一个英文字母&#8220;a&#8221;&nbsp;和　一个汉字&nbsp;&#8220;好&#8221;，编码后占用的空间大小就不样了，前者是一个字节，后者是三个字节！<br><br>现在就让我们来看看UTF8编码的原理吧：<br>　　因为一个字母还有一些键盘上的符号加起来只用二进制七位就可以表示出来，而一个字节就是八位，所以UTF8就用一个字节来表式字母和一些键盘上的符号。然而当我们拿到被编码后的一个字节后怎么知道它的组成？它有可能是英文字母的一个字节，也有可能是汉字的三个字节中的一个字节！所以，UTF8是有标志位的！<br><br>　　当要表示的内容是　7位　的时候就用一个字节：0******* 　第一个0为标志位，剩下的空间正好可以表示ASCII　0－127　的内容。<br><br>　　当要表示的内容在　8　到　11　位的时候就用两个字节：110*****&nbsp;10****** 　第一个字节的110和第二个字节的10为标志位。<br><br>　　当要表示的内容在　12　到　16　位的时候就用三个字节：1110*****&nbsp;10******&nbsp;10******&nbsp;　　　和上面一样，第一个字节的1110和第二、三个字节的10都是标志位，剩下的空间正好可以表示汉字。<br><br>　　以此类推：<br>四个字节：11110****&nbsp;10******&nbsp;10******&nbsp;10******&nbsp;<br>　　五个字节：111110***&nbsp;10******&nbsp;10******&nbsp;10******&nbsp;10******&nbsp;<br>　　六个字节：1111110**&nbsp;10******&nbsp;10******&nbsp;10******&nbsp;10******&nbsp;10******&nbsp;<br>　　.............................................<br>&nbsp;..............................................<br><br>明白了没有？<br>编码的方法是从低位到高位<br><br>现在就让我们来看看实例吧！<br><br>红色为标志位<br>其它着色为了显示其，编码后的位置&nbsp;<br></p>
            <p>
            <table height=138 cellSpacing=0 cellPadding=0 width=765 border=1>
                <tbody>
                    <tr>
                        <td>
                        <p align=center>Unicode十六进制</p>
                        </td>
                        <td><br>
                        <p align=center>Unicode二进制</p>
                        </td>
                        <td><br>
                        <p align=center>UTF8二进制</p>
                        </td>
                        <td><br>
                        <p align=center>UTF8十六进制</p>
                        </td>
                        <td><br>
                        <p align=center>UTF8字节数</p>
                        </td>
                    </tr>
                    <tr>
                        <td><br>
                        <p align=center>B</p>
                        </td>
                        <td><br>
                        <p align=center><font style="BACKGROUND-COLOR: #ffc0cb">00001011</font></p>
                        </td>
                        <td><br>
                        <p align=center><font style="BACKGROUND-COLOR: #ffff00">0</font><font style="BACKGROUND-COLOR: #ffc0cb">0001010</font></p>
                        </td>
                        <td><br>
                        <p align=center>B</p>
                        </td>
                        <td><br>
                        <p align=center>1</p>
                        </td>
                    </tr>
                    <tr>
                        <td><br>
                        <p align=center>9D</p>
                        </td>
                        <td><br>
                        <p align=center><font style="BACKGROUND-COLOR: #ffc0cb">00010</font><font style="BACKGROUND-COLOR: #808080">011101</font></p>
                        </td>
                        <td><br>
                        <p align=center><font style="BACKGROUND-COLOR: #ffff00">110</font><font style="BACKGROUND-COLOR: #ffc0cb">00010</font>&nbsp;<font style="BACKGROUND-COLOR: #ffff00">10</font><font style="BACKGROUND-COLOR: #808080">011101&nbsp;</font></p>
                        </td>
                        <td><br>
                        <p align=center>C2&nbsp;9D</p>
                        </td>
                        <td><br>
                        <p align=center>2</p>
                        </td>
                    </tr>
                    <tr>
                        <td><br>
                        <p align=center>A89E</p>
                        </td>
                        <td><br>
                        <p align=center><font style="BACKGROUND-COLOR: #ffc0cb">1010</font><font style="BACKGROUND-COLOR: #808080">1000&nbsp;</font><font style="BACKGROUND-COLOR: #808080">10</font><font style="BACKGROUND-COLOR: #7fffd4">011110</font></p>
                        </td>
                        <td><br>
                        <p align=center><font style="BACKGROUND-COLOR: #ffff00">1110</font><font style="BACKGROUND-COLOR: #ffc0cb">1010</font>&nbsp;<font style="BACKGROUND-COLOR: #ffff00">10</font><font style="BACKGROUND-COLOR: #808080">100010</font>&nbsp;<font style="BACKGROUND-COLOR: #ffff00">10</font><font style="BACKGROUND-COLOR: #7fffd4">011110</font></p>
                        </td>
                        <td><br>
                        <p align=center>EA&nbsp;A2&nbsp;9E</p>
                        </td>
                        <td><br>
                        <p align=center>3</p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </p>
            </div>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/true/aggbug/21335.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/true/" target="_blank">true</a> 2007-04-05 17:23 <a href="http://www.cppblog.com/true/archive/2007/04/05/21335.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>字符，编码的基本知识</title><link>http://www.cppblog.com/true/archive/2007/04/05/21334.html</link><dc:creator>true</dc:creator><author>true</author><pubDate>Thu, 05 Apr 2007 09:14:00 GMT</pubDate><guid>http://www.cppblog.com/true/archive/2007/04/05/21334.html</guid><wfw:comment>http://www.cppblog.com/true/comments/21334.html</wfw:comment><comments>http://www.cppblog.com/true/archive/2007/04/05/21334.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/true/comments/commentRss/21334.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/true/services/trackbacks/21334.html</trackback:ping><description><![CDATA[<h2><a name=main></a>字符，字节和编码</h2>
<p><font size=1>[原创文章，转载请保留或注明出处：<a href="http://www.regexlab.com/zh/encoding.htm"><u><font color=#800080>http://www.regexlab.com/zh/encoding.htm</font></u></a>]</font></p>
<p>级别：中级</p>
<blockquote>
<p>摘要：本文介绍了字符与编码的发展过程，相关概念的正确理解。举例说明了一些实际应用中，编码的实现方法。然后，本文讲述了通常对字符与编码的几种误解，由于这些误解而导致乱码产生的原因，以及消除乱码的办法。本文的内容涵盖了&#8220;中文问题&#8221;，&#8220;乱码问题&#8221;。</p>
<p>掌握编码问题的关键是正确地理解相关概念，编码所涉及的技术其实是很简单的。因此，阅读本文时需要慢读多想，多思考。</p>
</blockquote>
<h4><a name=intro></a>引言</h4>
<p>&#8220;字符与编码&#8221;是一个被经常讨论的话题。即使这样，时常出现的乱码仍然困扰着大家。虽然我们有很多的办法可以用来消除乱码，但我们并不一定理解这些办法的内在原理。而有的乱码产生的原因，实际上由于底层代码本身有问题所导致的。因此，不仅是初学者会对字符编码感到模糊，有的底层开发人员同样对字符编码缺乏准确的理解。</p>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr vAlign=top>
            <td align=right width="100%"><img height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></td>
        </tr>
        <tr vAlign=top>
            <td align=right width="100%">
            <table cellSpacing=0 cellPadding=0>
                <tbody>
                    <tr align=right>
                        <td>
                        <table cellSpacing=0 cellPadding=0 border=0>
                            <tbody>
                                <tr>
                                    <td vAlign=center><img height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></td>
                                    <td vAlign=top align=right>
                                    <p><a href="http://www.regexlab.com/zh/encoding.htm#main"><u><font color=#800080>回页首</font></u></a></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<h4><a name=develop></a>1. 编码问题的由来，相关概念的理解</h4>
<h5>1.1 字符与编码的发展</h5>
<p>从计算机对多国语言的支持角度看，大致可以分为三个阶段：</p>
<table cellSpacing=0 cellPadding=3 border=0>
    <tbody>
        <tr>
            <td class=top_1>　</td>
            <td class=top_2 noWrap align=middle><strong>系统内码</strong></td>
            <td class=top_2 align=middle><strong>说明</strong></td>
            <td class=top_2 align=middle><strong>系统</strong></td>
        </tr>
        <tr>
            <td class=con_1 noWrap>阶段一</td>
            <td class=con_2 noWrap align=middle>ASCII</td>
            <td class=con_2>计算机刚开始只支持英语，其它语言不能够在计算机上存储和显示。</td>
            <td class=con_2>英文 DOS</td>
        </tr>
        <tr>
            <td class=con_1 noWrap>阶段二</td>
            <td class=con_2 noWrap align=middle>ANSI编码<br>（本地化）</td>
            <td class=con_2>为使计算机支持更多语言，通常使用 0x80~0xFF 范围的 2 个字节来表示 1 个字符。比如：汉字 '中' 在中文操作系统中，使用 [0xD6,0xD0] 这两个字节存储。<br><br>不同的国家和地区制定了不同的标准，由此产生了 GB2312, BIG5, JIS 等各自的编码标准。这些使用 2 个字节来代表一个字符的各种汉字延伸编码方式，称为<strong> ANSI 编码</strong>。在简体中文系统下，ANSI 编码代表 GB2312 编码，在日文操作系统下，ANSI 编码代表 JIS 编码。<br><br>不同 ANSI 编码之间互不兼容，当信息在国际间交流时，无法将属于两种语言的文字，存储在同一段<strong> ANSI 编码</strong>的文本中。</td>
            <td class=con_2>中文 DOS，中文 Windows 95/98，日文 Windows 95/98</td>
        </tr>
        <tr>
            <td class=bot_1 noWrap>阶段三</td>
            <td class=bot_2 noWrap align=middle>UNICODE<br>（国际化）</td>
            <td class=bot_2>为了使国际间信息交流更加方便，国际组织制定了 <strong>UNICODE 字符集</strong>，为各种语言中的每一个字符设定了统一并且唯一的数字编号，以满足跨语言、跨平台进行文本转换、处理的要求。</td>
            <td class=bot_2>Windows NT/2000/XP，Linux，Java</td>
        </tr>
    </tbody>
</table>
<p>字符串在内存中的存放方法：</p>
<p>在 ASCII 阶段，<strong>单字节字符串</strong>使用一个字节存放一个字符（SBCS）。比如，"Bob123" 在内存中为：</p>
<table style="FONT-SIZE: 80%; COLOR: #000080" cellSpacing=5 cellPadding=0 border=0>
    <tbody>
        <tr>
            <td>42</td>
            <td>6F</td>
            <td>62</td>
            <td>31</td>
            <td>32</td>
            <td>33</td>
            <td>00</td>
        </tr>
        <tr>
            <td bgColor=#000080><img height=1 src="http://www.regexlab.com/images/spacer.gif" width=1 border=0 twffan="done"></td>
            <td bgColor=#000080><img height=1 src="http://www.regexlab.com/images/spacer.gif" width=1 border=0 twffan="done"></td>
            <td bgColor=#000080><img height=1 src="http://www.regexlab.com/images/spacer.gif" width=1 border=0 twffan="done"></td>
            <td bgColor=#000080><img height=1 src="http://www.regexlab.com/images/spacer.gif" width=1 border=0 twffan="done"></td>
            <td bgColor=#000080><img height=1 src="http://www.regexlab.com/images/spacer.gif" width=1 border=0 twffan="done"></td>
            <td bgColor=#000080><img height=1 src="http://www.regexlab.com/images/spacer.gif" width=1 border=0 twffan="done"></td>
            <td bgColor=#000080><img height=1 src="http://www.regexlab.com/images/spacer.gif" width=1 border=0 twffan="done"></td>
        </tr>
        <tr>
            <td align=middle>B</td>
            <td align=middle>o</td>
            <td align=middle>b</td>
            <td align=middle>1</td>
            <td align=middle>2</td>
            <td align=middle>3</td>
            <td align=middle>\0</td>
        </tr>
    </tbody>
</table>
<p>在使用 ANSI 编码支持多种语言阶段，每个字符使用一个字节或多个字节来表示（MBCS），因此，这种方式存放的字符也被称作<strong>多字节字符</strong>。比如，"中文123" 在中文 Windows 95 内存中为7个字节，每个汉字占2个字节，每个英文和数字字符占1个字节：</p>
<table style="FONT-SIZE: 80%; COLOR: #000080" cellSpacing=5 cellPadding=0 border=0>
    <tbody>
        <tr>
            <td>D6</td>
            <td>D0</td>
            <td>CE</td>
            <td>C4</td>
            <td>31</td>
            <td>32</td>
            <td>33</td>
            <td>00</td>
        </tr>
        <tr>
            <td bgColor=#ff0000 colSpan=2><img height=1 src="http://www.regexlab.com/images/spacer.gif" width=1 border=0 twffan="done"></td>
            <td bgColor=#ff0000 colSpan=2><img height=1 src="http://www.regexlab.com/images/spacer.gif" width=1 border=0 twffan="done"></td>
            <td bgColor=#000080><img height=1 src="http://www.regexlab.com/images/spacer.gif" width=1 border=0 twffan="done"></td>
            <td bgColor=#000080><img height=1 src="http://www.regexlab.com/images/spacer.gif" width=1 border=0 twffan="done"></td>
            <td bgColor=#000080><img height=1 src="http://www.regexlab.com/images/spacer.gif" width=1 border=0 twffan="done"></td>
            <td bgColor=#000080><img height=1 src="http://www.regexlab.com/images/spacer.gif" width=1 border=0 twffan="done"></td>
        </tr>
        <tr>
            <td align=middle colSpan=2>中</td>
            <td align=middle colSpan=2>文</td>
            <td align=middle>1</td>
            <td align=middle>2</td>
            <td align=middle>3</td>
            <td align=middle>\0</td>
        </tr>
    </tbody>
</table>
<p>在 UNICODE 被采用之后，计算机存放字符串时，改为存放每个字符在 UNICODE 字符集中的序号。目前计算机一般使用 2 个字节（16 位）来存放一个序号（DBCS），因此，这种方式存放的字符也被称作<strong>宽字节字符</strong>。比如，字符串 "中文123" 在 Windows 2000 下，内存中实际存放的是 5 个序号：</p>
<table style="FONT-SIZE: 80%; COLOR: #000080" cellSpacing=5 cellPadding=0 border=0>
    <tbody>
        <tr>
            <td vAlign=bottom>2D</td>
            <td vAlign=bottom>4E</td>
            <td vAlign=bottom>87</td>
            <td vAlign=bottom>65</td>
            <td vAlign=bottom>31</td>
            <td vAlign=bottom>00</td>
            <td vAlign=bottom>32</td>
            <td vAlign=bottom>00</td>
            <td vAlign=bottom>33</td>
            <td vAlign=bottom>00</td>
            <td vAlign=bottom>00</td>
            <td vAlign=bottom>00</td>
            <td><font color=#808080>&nbsp;&nbsp;&nbsp;&nbsp; &#8592; 在 x86 CPU 中，低字节在前</font></td>
        </tr>
        <tr>
            <td bgColor=#ff0000 colSpan=2><img height=1 src="http://www.regexlab.com/images/spacer.gif" width=1 border=0 twffan="done"></td>
            <td bgColor=#ff0000 colSpan=2><img height=1 src="http://www.regexlab.com/images/spacer.gif" width=1 border=0 twffan="done"></td>
            <td bgColor=#ff0000 colSpan=2><img height=1 src="http://www.regexlab.com/images/spacer.gif" width=1 border=0 twffan="done"></td>
            <td bgColor=#ff0000 colSpan=2><img height=1 src="http://www.regexlab.com/images/spacer.gif" width=1 border=0 twffan="done"></td>
            <td bgColor=#ff0000 colSpan=2><img height=1 src="http://www.regexlab.com/images/spacer.gif" width=1 border=0 twffan="done"></td>
            <td bgColor=#ff0000 colSpan=2><img height=1 src="http://www.regexlab.com/images/spacer.gif" width=1 border=0 twffan="done"></td>
            <td><img height=1 src="http://www.regexlab.com/images/spacer.gif" width=1 border=0 twffan="done"></td>
        </tr>
        <tr>
            <td align=middle colSpan=2>中</td>
            <td align=middle colSpan=2>文</td>
            <td align=middle colSpan=2>1</td>
            <td align=middle colSpan=2>2</td>
            <td align=middle colSpan=2>3</td>
            <td align=middle colSpan=2>\0</td>
            <td align=middle>　</td>
        </tr>
    </tbody>
</table>
<p>一共占 10 个字节。</p>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr vAlign=top>
            <td align=right width="100%"><img height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></td>
        </tr>
        <tr vAlign=top>
            <td align=right width="100%">
            <table cellSpacing=0 cellPadding=0>
                <tbody>
                    <tr align=right>
                        <td>
                        <table cellSpacing=0 cellPadding=0 border=0>
                            <tbody>
                                <tr>
                                    <td vAlign=center><img height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></td>
                                    <td vAlign=top align=right>
                                    <p><a href="http://www.regexlab.com/zh/encoding.htm#main"><u><font color=#800080>回页首</font></u></a></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<h5><a name=concept></a>1.2 字符，字节，字符串</h5>
<p>理解编码的关键，是要把字符的概念和字节的概念理解准确。这两个概念容易混淆，我们在此做一下区分：</p>
<table cellSpacing=0 cellPadding=3 border=0>
    <tbody>
        <tr>
            <td class=top_1>　</td>
            <td class=top_2 align=middle><strong>概念描述</strong></td>
            <td class=top_2 align=middle><strong>举例</strong></td>
        </tr>
        <tr>
            <td class=con_1 noWrap align=middle>字符</td>
            <td class=con_2>人们使用的记号，抽象意义上的一个符号。</td>
            <td class=con_2>'1', '中', 'a', '$', '￥', &#8230;&#8230;</td>
        </tr>
        <tr>
            <td class=con_1 noWrap align=middle>字节</td>
            <td class=con_2>计算机中存储数据的单元，一个8位的二进制数，是一个很具体的存储空间。</td>
            <td class=con_2>0x01, 0x45, 0xFA, &#8230;&#8230;</td>
        </tr>
        <tr>
            <td class=con_1 noWrap align=middle>ANSI<br>字符串</td>
            <td class=con_2>在内存中，如果&#8220;字符&#8221;是以 <strong>ANSI 编码</strong>形式存在的，一个字符可能使用一个字节或多个字节来表示，那么我们称这种字符串为 <strong>ANSI 字符串</strong>或者<strong>多字节字符串</strong>。</td>
            <td class=con_2>"中文123"<br><span class=rem twffan="done"><font color=#339933>（占7字节）</font></span></td>
        </tr>
        <tr>
            <td class=bot_1 noWrap align=middle>UNICODE<br>字符串</td>
            <td class=bot_2>在内存中，如果&#8220;字符&#8221;是以在 UNICODE 中的序号存在的，那么我们称这种字符串为 <strong>UNICODE 字符串</strong>或者<strong>宽字节字符串</strong>。</td>
            <td class=bot_2>L"中文123"<br><span class=rem twffan="done"><font color=#339933>（占10字节）</font></span></td>
        </tr>
    </tbody>
</table>
<p>由于不同 ANSI 编码所规定的标准是不相同的，因此，对于一个给定的<strong>多字节字符串</strong>，我们必须知道它采用的是哪一种编码规则，才能够知道它包含了哪些&#8220;字符&#8221;。而对于 <strong>UNICODE 字符串</strong>来说，不管在什么环境下，它所代表的&#8220;字符&#8221;内容总是不变的。</p>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr vAlign=top>
            <td align=right width="100%"><img height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></td>
        </tr>
        <tr vAlign=top>
            <td align=right width="100%">
            <table cellSpacing=0 cellPadding=0>
                <tbody>
                    <tr align=right>
                        <td>
                        <table cellSpacing=0 cellPadding=0 border=0>
                            <tbody>
                                <tr>
                                    <td vAlign=center><img height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></td>
                                    <td vAlign=top align=right>
                                    <p><a href="http://www.regexlab.com/zh/encoding.htm#main"><u><font color=#800080>回页首</font></u></a></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<h5>1.3 字符集与编码</h5>
<p>各个国家和地区所制定的不同 ANSI 编码标准中，都只规定了各自语言所需的&#8220;字符&#8221;。比如：汉字标准（GB2312）中没有规定韩国语字符怎样存储。这些 ANSI 编码标准所规定的内容包含两层含义：</p>
<ol>
    <li>使用哪些字符。也就是说哪些汉字，字母和符号会被收入标准中。所包含&#8220;字符&#8221;的集合就叫做&#8220;<strong>字符集</strong>&#8221;。
    <li>规定每个&#8220;字符&#8221;分别用一个字节还是多个字节存储，用哪些字节来存储，这个规定就叫做&#8220;<strong>编码</strong>&#8221;。 </li>
</ol>
<p>各个国家和地区在制定编码标准的时候，&#8220;字符的集合&#8221;和&#8220;编码&#8221;一般都是同时制定的。因此，平常我们所说的&#8220;字符集&#8221;，比如：GB2312, GBK, JIS 等，除了有&#8220;字符的集合&#8221;这层含义外，同时也包含了&#8220;编码&#8221;的含义。</p>
<p>&#8220;<strong>UNICODE 字符集</strong>&#8221;包含了各种语言中使用到的所有&#8220;字符&#8221;。用来给 UNICODE 字符集编码的标准有很多种，比如：UTF-8, UTF-7, UTF-16, UnicodeLittle, UnicodeBig 等。</p>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr vAlign=top>
            <td align=right width="100%"><img height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></td>
        </tr>
        <tr vAlign=top>
            <td align=right width="100%">
            <table cellSpacing=0 cellPadding=0>
                <tbody>
                    <tr align=right>
                        <td>
                        <table cellSpacing=0 cellPadding=0 border=0>
                            <tbody>
                                <tr>
                                    <td vAlign=center><img height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></td>
                                    <td vAlign=top align=right>
                                    <p><a href="http://www.regexlab.com/zh/encoding.htm#main"><u><font color=#800080>回页首</font></u></a></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<h5>1.4 常用的编码简介</h5>
<p>简单介绍一下常用的编码规则，为后边的章节做一个准备。在这里，我们根据编码规则的特点，把所有的编码分成三类：</p>
<table cellSpacing=0 cellPadding=3 border=0>
    <tbody>
        <tr>
            <td class=top_1 align=middle><strong>分类</strong></td>
            <td class=top_2 align=middle><strong>编码标准</strong></td>
            <td class=top_2 align=middle><strong>说明</strong></td>
        </tr>
        <tr>
            <td class=con_1 noWrap align=middle>单字节字符编码</td>
            <td class=con_2>ISO-8859-1</td>
            <td class=con_2>最简单的编码规则，每一个字节直接作为一个 UNICODE 字符。比如，[0xD6, 0xD0] 这两个字节，通过 iso-8859-1 转化为字符串时，将直接得到 [0x00D6, 0x00D0] 两个 UNICODE 字符，即 "&#214;&#208;"。<br><br>反之，将 UNICODE 字符串通过 iso-8859-1 转化为字节串时，只能正常转化 0~255 范围的字符。</td>
        </tr>
        <tr>
            <td class=con_1 noWrap align=middle>ANSI 编码</td>
            <td class=con_2>GB2312,<br>BIG5,<br>Shift_JIS,<br>ISO-8859-2 &#8230;&#8230;</td>
            <td class=con_2>把 UNICODE 字符串通过 ANSI 编码转化为&#8220;字节串&#8221;时，根据各自编码的规定，一个 UNICODE 字符可能转化成一个字节或多个字节。<br><br>反之，将字节串转化成字符串时，也可能多个字节转化成一个字符。比如，[0xD6, 0xD0] 这两个字节，通过 GB2312 转化为字符串时，将得到 [0x4E2D] 一个字符，即 '中' 字。<br><br>&#8220;ANSI 编码&#8221;的特点：<br>1. 这些&#8220;ANSI 编码标准&#8221;都只能处理各自语言范围之内的 UNICODE 字符。<br>2. &#8220;UNICODE 字符&#8221;与&#8220;转换出来的字节&#8221;之间的关系是人为规定的。</td>
        </tr>
        <tr>
            <td class=bot_1 noWrap align=middle>UNICODE 编码</td>
            <td class=bot_2>UTF-8,<br>UTF-16, UnicodeBig &#8230;&#8230;</td>
            <td class=bot_2>与&#8220;ANSI 编码&#8221;类似的，把字符串通过 UNICODE 编码转化成&#8220;字节串&#8221;时，一个 UNICODE 字符可能转化成一个字节或多个字节。<br><br>与&#8220;ANSI 编码&#8221;不同的是：<br>1. 这些&#8220;UNICODE 编码&#8221;能够处理所有的 UNICODE 字符。<br>2. &#8220;UNICODE 字符&#8221;与&#8220;转换出来的字节&#8221;之间是可以通过计算得到的。</td>
        </tr>
    </tbody>
</table>
<p>我们实际上没有必要去深究每一种编码具体把某一个字符编码成了哪几个字节，我们只需要知道&#8220;编码&#8221;的概念就是把&#8220;字符&#8221;转化成&#8220;字节&#8221;就可以了。对于&#8220;UNICODE 编码&#8221;，由于它们是可以通过计算得到的，因此，在特殊的场合，我们可以去了解某一种&#8220;UNICODE 编码&#8221;是怎样的规则。</p>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr vAlign=top>
            <td align=right width="100%"><img height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></td>
        </tr>
        <tr vAlign=top>
            <td align=right width="100%">
            <table cellSpacing=0 cellPadding=0>
                <tbody>
                    <tr align=right>
                        <td>
                        <table cellSpacing=0 cellPadding=0 border=0>
                            <tbody>
                                <tr>
                                    <td vAlign=center><img height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></td>
                                    <td vAlign=top align=right>
                                    <p><a href="http://www.regexlab.com/zh/encoding.htm#main"><u><font color=#800080>回页首</font></u></a></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<h4><a name=implement></a>2. 字符与编码在程序中的实现</h4>
<h5>2.1 程序中的字符与字节</h5>
<p>在 C++ 和 Java 中，用来代表&#8220;字符&#8221;和&#8220;字节&#8221;的数据类型，以及进行编码的方法：</p>
<table cellSpacing=0 cellPadding=3 border=0>
    <tbody>
        <tr>
            <td class=top_1 align=middle><strong>类型或操作</strong></td>
            <td class=top_2 align=middle><strong>C++</strong></td>
            <td class=top_2 align=middle><strong>Java</strong></td>
        </tr>
        <tr>
            <td class=con_1 noWrap align=middle>字符</td>
            <td class=con_2>wchar_t</td>
            <td class=con_2>char</td>
        </tr>
        <tr>
            <td class=con_1 noWrap align=middle>字节</td>
            <td class=con_2>char</td>
            <td class=con_2>byte</td>
        </tr>
        <tr>
            <td class=con_1 noWrap align=middle>ANSI 字符串</td>
            <td class=con_2>char[]</td>
            <td class=con_2>byte[]</td>
        </tr>
        <tr>
            <td class=con_1 noWrap align=middle>UNICODE 字符串</td>
            <td class=con_2>wchar_t[]</td>
            <td class=con_2>String</td>
        </tr>
        <tr>
            <td class=con_1 noWrap align=middle>字节串&#8594;字符串</td>
            <td class=con_2>mbstowcs(), MultiByteToWideChar()</td>
            <td class=con_2>string = new String(bytes, "encoding")</td>
        </tr>
        <tr>
            <td class=bot_1 noWrap align=middle>字符串&#8594;字节串</td>
            <td class=bot_2>wcstombs(), WideCharToMultiByte()</td>
            <td class=bot_2>bytes = string.getBytes("encoding")</td>
        </tr>
    </tbody>
</table>
<p>以上需要注意几点：</p>
<ol>
    <li>Java 中的 char 代表一个&#8220;UNICODE 字符（宽字节字符）&#8221;，而 C++ 中的 char 代表一个字节。
    <li>MultiByteToWideChar() 和 WideCharToMultiByte() 是 Windows API 函数。 </li>
</ol>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr vAlign=top>
            <td align=right width="100%"><img height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></td>
        </tr>
        <tr vAlign=top>
            <td align=right width="100%">
            <table cellSpacing=0 cellPadding=0>
                <tbody>
                    <tr align=right>
                        <td>
                        <table cellSpacing=0 cellPadding=0 border=0>
                            <tbody>
                                <tr>
                                    <td vAlign=center><img height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></td>
                                    <td vAlign=top align=right>
                                    <p><a href="http://www.regexlab.com/zh/encoding.htm#main"><u><font color=#800080>回页首</font></u></a></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<h5>2.2 C++ 中相关实现方法</h5>
<p>声明一段字符串常量：</p>
<table cellSpacing=0 cellPadding=6 bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td class=code><span class=rem twffan="done"><font color=#339933>// ANSI 字符串，内容长度 7 字节</font></span><span class=key twffan="done"><br><font color=#0000ff>char</font></span>&nbsp;&nbsp;&nbsp;&nbsp; sz[<span class=number twffan="done"><font color=#6d66a5>20</font></span>] = <span class=string twffan="done"><font color=#ff00ff>"中文123"</font></span>;<br><br><font color=#339933><span class=rem twffan="done">// UNICODE 字符串，内容长度 5 个 wchar_t（10 字节）</span><br></font>wchar_t wsz[<span class=number twffan="done"><font color=#6d66a5>20</font></span>] = L<span class=string twffan="done"><font color=#ff00ff>"\x4E2D\x6587\x0031\x0032\x0033"</font></span>;</td>
        </tr>
    </tbody>
</table>
<p>UNICODE 字符串的 I/O 操作，字符与字节的转换操作：</p>
<table cellSpacing=0 cellPadding=6 bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td class=code><span class=rem twffan="done"><font color=#339933>// 运行时设定当前 ANSI 编码，VC 格式<br></font></span>setlocale(LC_ALL, <span class=string twffan="done"><font color=#ff00ff>".936"</font></span>);<br><br><font color=#339933><span class=rem twffan="done">// GCC 中格式</span><br></font>setlocale(LC_ALL, <span class=string twffan="done"><font color=#ff00ff>"zh_CN.GBK"</font></span>);<br><br><font color=#339933><span class=rem twffan="done">// Visual C++ 中使用小写 %s，按照 setlocale 指定编码输出到文件<br>// GCC 中使用大写 %S</span><br></font>fwprintf(fp, L<span class=string twffan="done"><font color=#ff00ff>"%s\n"</font></span>, wsz);<br><br><font color=#339933><span class=rem twffan="done">// 把 UNICODE 字符串按照 setlocale 指定的编码转换成字节</span><br></font>wcstombs(sz, wsz, <span class=number twffan="done"><font color=#6d66a5>20</font></span>);<span class=rem twffan="done"><br><font color=#339933>// 把字节串按照 setlocale 指定的编码转换成 UNICODE 字符串<br></font></span>mbstowcs(wsz, sz, <span class=number twffan="done"><font color=#6d66a5>20</font></span>);</td>
        </tr>
    </tbody>
</table>
<p>在 Visual C++ 中，UNICODE 字符串常量有更简单的表示方法。如果源程序的编码与当前默认 ANSI 编码不符，则需要使用 #pragma setlocale，告诉编译器源程序使用的编码：</p>
<table cellSpacing=0 cellPadding=6 bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td class=code><span class=rem twffan="done"><font color=#339933>// 如果源程序的编码与当前默认 ANSI 编码不一致，<br>// 则需要此行，编译时用来指明当前源程序使用的编码</font></span><span class=key twffan="done"><br><font color=#0000ff>#pragma setlocale</font></span>(<span class=string twffan="done"><font color=#ff00ff>".936"</font></span>)<br><br><font color=#339933><span class=rem twffan="done">// UNICODE 字符串常量，内容长度 10 字节</span><br></font>wchar_t wsz[<span class=number twffan="done"><font color=#6d66a5>20</font></span>] = L<span class=string twffan="done"><font color=#ff00ff>"中文123"</font></span>;</td>
        </tr>
    </tbody>
</table>
<p>以上需要注意 #pragma setlocale 与 setlocale(LC_ALL, "") 的作用是不同的，#pragma setlocale 在编译时起作用，setlocale() 在运行时起作用。</p>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr vAlign=top>
            <td align=right width="100%"><img height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></td>
        </tr>
        <tr vAlign=top>
            <td align=right width="100%">
            <table cellSpacing=0 cellPadding=0>
                <tbody>
                    <tr align=right>
                        <td>
                        <table cellSpacing=0 cellPadding=0 border=0>
                            <tbody>
                                <tr>
                                    <td vAlign=center><img height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></td>
                                    <td vAlign=top align=right>
                                    <p><a href="http://www.regexlab.com/zh/encoding.htm#main"><u><font color=#800080>回页首</font></u></a></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<h5>2.3 Java 中相关实现方法</h5>
<p>字符串类 String 中的内容是 UNICODE 字符串：</p>
<table cellSpacing=0 cellPadding=6 bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td class=code><span class=rem twffan="done"><font color=#339933>// Java 代码，直接写中文</font></span><span class=pw twffan="done"><br><font color=#ff0000>String</font></span> string = <span class=string twffan="done"><font color=#ff00ff>"中文123"</font></span>;<br><br><font color=#339933><span class=rem twffan="done">// 得到长度为 5，因为是 5 个字符</span><br></font><span class=pw twffan="done"><font color=#ff0000>System</font></span>.out.println(string.length());</td>
        </tr>
    </tbody>
</table>
<p>字符串 I/O 操作，字符与字节转换操作。在 Java 包 java.io.* 中，以&#8220;Stream&#8221;结尾的类一般是用来操作&#8220;字节串&#8221;的类，以&#8220;Reader&#8221;，&#8220;Writer&#8221;结尾的类一般是用来操作&#8220;字符串&#8221;的类。</p>
<table cellSpacing=0 cellPadding=6 bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td class=code><span class=rem twffan="done"><font color=#339933>// 字符串与字节串间相互转化<br><br>// 按照 GB2312 得到字节（得到多字节字符串）</font></span><span class=key twffan="done"><br><font color=#0000ff>byte</font></span> [] bytes = string.getBytes(<span class=string twffan="done"><font color=#ff00ff>"GB2312"</font></span>);<br><br><font color=#339933><span class=rem twffan="done">// 从字节按照 GB2312 得到 UNICODE 字符串</span><br></font>string = <span class=key twffan="done"><font color=#0000ff>new</font></span> <span class=pw twffan="done"><font color=#ff0000>String</font></span>(bytes, <span class=string twffan="done"><font color=#ff00ff>"GB2312"</font></span>);<br><br><font color=#339933><span class=rem twffan="done">// 要将 String 按照某种编码写入文本文件，有两种方法：<br><br>// 第一种办法：用 Stream 类写入已经按照指定编码转化好的字节串</span><br></font>OutputStream os = <span class=key twffan="done"><font color=#0000ff>new</font></span> FileOutputStream(<span class=string twffan="done"><font color=#ff00ff>"1.txt"</font></span>);<br>os.write(bytes);<br>os.close();<br><br><font color=#339933><span class=rem twffan="done">// 第二种办法：构造指定编码的 Writer 来写入字符串</span><br></font>Writer ow = <span class=key twffan="done"><font color=#0000ff>new</font></span> OutputStreamWriter(<span class=key twffan="done"><font color=#0000ff>new</font></span> FileOutputStream(<span class=string twffan="done"><font color=#ff00ff>"2.txt"</font></span>), <span class=string twffan="done"><font color=#ff00ff>"GB2312"</font></span>);<br>ow.write(string);<br>ow.close();<br><br><span class=rem twffan="done"><font color=#339933>/* 最后得到的 1.txt 和 2.txt 都是 7 个字节 */</font></span></td>
        </tr>
    </tbody>
</table>
<p>如果 java 的源程序编码与当前默认 ANSI 编码不符，则在编译的时候，需要指明一下源程序的编码。比如：</p>
<table cellSpacing=0 cellPadding=6 bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td class=code>E:\&gt;javac <font color=#ff0000>-encoding BIG5</font> Hello.java</td>
        </tr>
    </tbody>
</table>
<p>以上需要注意区分源程序的编码与 I/O 操作的编码，前者是在编译时起作用，后者是在运行时起作用。</p>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr vAlign=top>
            <td align=right width="100%"><img height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></td>
        </tr>
        <tr vAlign=top>
            <td align=right width="100%">
            <table cellSpacing=0 cellPadding=0>
                <tbody>
                    <tr align=right>
                        <td>
                        <table cellSpacing=0 cellPadding=0 border=0>
                            <tbody>
                                <tr>
                                    <td vAlign=center><img height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></td>
                                    <td vAlign=top align=right>
                                    <p><a href="http://www.regexlab.com/zh/encoding.htm#main"><u><font color=#800080>回页首</font></u></a></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<h4><a name=misunderstand></a>3. 几种误解，以及乱码产生的原因和解决办法</h4>
<h5>3.1 容易产生的误解</h5>
<table cellSpacing=0 cellPadding=3 border=0>
    <tbody>
        <tr>
            <td class=top_1>　</td>
            <td class=top_2 align=middle><strong>对编码的误解</strong></td>
        </tr>
        <tr>
            <td class=con_1 noWrap align=middle>误解一</td>
            <td class=con_2>在将&#8220;字节串&#8221;转化成&#8220;UNICODE 字符串&#8221;时，比如在读取文本文件时，或者通过网络传输文本时，容易将&#8220;字节串&#8221;简单地作为<strong>单字节字符串</strong>，采用每&#8220;一个字节&#8221;就是&#8220;一个字符&#8221;的方法进行转化。<br><br>而实际上，在非英文的环境中，应该将&#8220;字节串&#8221;作为 ANSI 字符串，采用适当的编码来得到 UNICODE 字符串，有可能&#8220;多个字节&#8221;才能得到&#8220;一个字符&#8221;。<br><br>通常，一直在英文环境下做开发的程序员们，容易有这种误解。</td>
        </tr>
        <tr>
            <td class=bot_1 noWrap align=middle>误解二</td>
            <td class=bot_2>在 DOS，Windows 98 等非 UNICODE 环境下，字符串都是以 ANSI 编码的字节形式存在的。这种以字节形式存在的字符串，必须知道是哪种编码才能被正确地使用。这使我们形成了一个惯性思维：&#8220;字符串的编码&#8221;。<br><br>当 UNICODE 被支持后，Java 中的 String 是以字符的&#8220;序号&#8221;来存储的，不是以&#8220;某种编码的字节&#8221;来存储的，因此已经不存在&#8220;字符串的编码&#8221;这个概念了。只有在&#8220;字符串&#8221;与&#8220;字节串&#8221;转化时，或者，将一个&#8220;字节串&#8221;当成一个 ANSI 字符串时，才有编码的概念。<br><br>不少的人都有这个误解。</td>
        </tr>
    </tbody>
</table>
<p>第一种误解，往往是导致乱码产生的原因。第二种误解，往往导致本来容易纠正的乱码问题变得更复杂。</p>
<p>在这里，我们可以看到，其中所讲的&#8220;误解一&#8221;，即采用每&#8220;一个字节&#8221;就是&#8220;一个字符&#8221;的转化方法，实际上也就等同于采用 iso-8859-1 进行转化。因此，我们常常使用 bytes = string.getBytes("iso-8859-1") 来进行逆向操作，得到原始的&#8220;字节串&#8221;。然后再使用正确的 ANSI 编码，比如 string = new String(bytes, "GB2312")，来得到正确的&#8220;UNICODE 字符串&#8221;。</p>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr vAlign=top>
            <td align=right width="100%"><img height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></td>
        </tr>
        <tr vAlign=top>
            <td align=right width="100%">
            <table cellSpacing=0 cellPadding=0>
                <tbody>
                    <tr align=right>
                        <td>
                        <table cellSpacing=0 cellPadding=0 border=0>
                            <tbody>
                                <tr>
                                    <td vAlign=center><img height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></td>
                                    <td vAlign=top align=right>
                                    <p><a href="http://www.regexlab.com/zh/encoding.htm#main"><u><font color=#800080>回页首</font></u></a></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<h5><a name=instances></a>3.2 非 UNICODE 程序在不同语言环境间移植时的乱码</h5>
<p>非 UNICODE 程序中的字符串，都是以某种 ANSI 编码形式存在的。如果程序运行时的语言环境与开发时的语言环境不同，将会导致 ANSI 字符串的显示失败。</p>
<p>比如，在日文环境下开发的非 UNICODE 的日文程序界面，拿到中文环境下运行时，界面上将显示乱码。如果这个日文程序界面改为采用 UNICODE 来记录字符串，那么当在中文环境下运行时，界面上将可以显示正常的日文。</p>
<p>由于客观原因，有时候我们必须在中文操作系统下运行非 UNICODE 的日文软件，这时我们可以采用一些工具，比如，南极星，AppLocale 等，暂时的模拟不同的语言环境。</p>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr vAlign=top>
            <td align=right width="100%"><img height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></td>
        </tr>
        <tr vAlign=top>
            <td align=right width="100%">
            <table cellSpacing=0 cellPadding=0>
                <tbody>
                    <tr align=right>
                        <td>
                        <table cellSpacing=0 cellPadding=0 border=0>
                            <tbody>
                                <tr>
                                    <td vAlign=center><img height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></td>
                                    <td vAlign=top align=right>
                                    <p><a href="http://www.regexlab.com/zh/encoding.htm#main"><u><font color=#800080>回页首</font></u></a></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<h5>3.3 网页提交字符串</h5>
<p>当页面中的表单提交字符串时，首先把字符串按照当前页面的编码，转化成字节串。然后再将每个字节转化成 "%XX" 的格式提交到 Web 服务器。比如，一个编码为 GB2312 的页面，提交 "中" 这个字符串时，提交给服务器的内容为 "%D6%D0"。</p>
<p>在服务器端，Web 服务器把收到的 "%D6%D0" 转化成 [0xD6, 0xD0] 两个字节，然后再根据 GB2312 编码规则得到 "中" 字。</p>
<p>在 Tomcat 服务器中，request.getParameter() 得到乱码时，常常是因为前面提到的&#8220;误解一&#8221;造成的。默认情况下，当提交 "%D6%D0" 给 Tomcat 服务器时，request.getParameter() 将返回 [0x00D6, 0x00D0] 两个 UNICODE 字符，而不是返回一个 "中" 字符。因此，我们需要使用 bytes = string.getBytes("iso-8859-1") 得到原始的字节串，再用 string = new String(bytes, "GB2312") 重新得到正确的字符串 "中"。</p>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr vAlign=top>
            <td align=right width="100%"><img height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></td>
        </tr>
        <tr vAlign=top>
            <td align=right width="100%">
            <table cellSpacing=0 cellPadding=0>
                <tbody>
                    <tr align=right>
                        <td>
                        <table cellSpacing=0 cellPadding=0 border=0>
                            <tbody>
                                <tr>
                                    <td vAlign=center><img height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></td>
                                    <td vAlign=top align=right>
                                    <p><a href="http://www.regexlab.com/zh/encoding.htm#main"><u><font color=#800080>回页首</font></u></a></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<h5>3.4 从数据库读取字符串</h5>
<p>通过数据库客户端（比如 ODBC 或 JDBC）从数据库服务器中读取字符串时，客户端需要从服务器获知所使用的 ANSI 编码。当数据库服务器发送字节流给客户端时，客户端负责将字节流按照正确的编码转化成 UNICODE 字符串。</p>
<p>如果从数据库读取字符串时得到乱码，而数据库中存放的数据又是正确的，那么往往还是因为前面提到的&#8220;误解一&#8221;造成的。解决的办法还是通过 string = new String( string.getBytes("iso-8859-1"), "GB2312") 的方法，重新得到原始的字节串，再重新使用正确的编码转化成字符串。</p>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr vAlign=top>
            <td align=right width="100%"><img height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></td>
        </tr>
        <tr vAlign=top>
            <td align=right width="100%">
            <table cellSpacing=0 cellPadding=0>
                <tbody>
                    <tr align=right>
                        <td>
                        <table cellSpacing=0 cellPadding=0 border=0>
                            <tbody>
                                <tr>
                                    <td vAlign=center><img height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></td>
                                    <td vAlign=top align=right>
                                    <p><a href="http://www.regexlab.com/zh/encoding.htm#main"><u><font color=#800080>回页首</font></u></a></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<h5>3.5 电子邮件中的字符串</h5>
<p>当一段 Text 或者 HTML 通过电子邮件传送时，发送的内容首先通过一种指定的<strong>字符编码</strong>转化成&#8220;字节串&#8221;，然后再把&#8220;字节串&#8221;通过一种指定的<strong>传输编码</strong>（Content-Transfer-Encoding）进行转化得到另一串&#8220;字节串&#8221;。比如，打开一封电子邮件源代码，可以看到类似的内容：</p>
<table cellSpacing=0 cellPadding=6 width="100%" bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td class=code>Content-Type: text/plain;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color=#ff0000>charset="gb2312"</font><br><font color=#ff0000>Content-Transfer-Encoding: base64</font><br><br>sbG+qcrQuqO17cf4yee74bGjz9W7+b3wudzA7dbQ0MQNCg0KvPKzxqO6uqO17cnnsaPW0NDEDQoNCg==</td>
        </tr>
    </tbody>
</table>
<p>最常用的 Content-Transfer-Encoding 有 Base64 和 Quoted-Printable 两种。在对二进制文件或者中文文本进行转化时，Base64 得到的&#8220;字节串&#8221;比 Quoted-Printable 更短。在对英文文本进行转化时，Quoted-Printable 得到的&#8220;字节串&#8221;比 Base64 更短。</p>
<p>邮件的标题，用了一种更简短的格式来标注&#8220;字符编码&#8221;和&#8220;传输编码&#8221;。比如，标题内容为 "中"，则在邮件源代码中表示为：</p>
<table cellSpacing=0 cellPadding=6 width="100%" bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td class=code><font color=#339933><span class=rem twffan="done">// 正确的标题格式</span><br></font>Subject: <span style="BACKGROUND-COLOR: #ffff00" twffan="done">=?</span>GB2312<span style="BACKGROUND-COLOR: #ffff00" twffan="done">?B?</span>1tA=<span style="BACKGROUND-COLOR: #ffff00" twffan="done">?=</span></td>
        </tr>
    </tbody>
</table>
<p>其中，</p>
<ul>
    <li>第一个&#8220;=?&#8221;与&#8220;?&#8221;中间的部分指定了字符编码，在这个例子中指定的是 GB2312。
    <li>&#8220;?&#8221;与&#8220;?&#8221;中间的&#8220;B&#8221;代表 Base64。如果是&#8220;Q&#8221;则代表 Quoted-Printable。
    <li>最后&#8220;?&#8221;与&#8220;?=&#8221;之间的部分，就是经过 GB2312 转化成字节串，再经过 Base64 转化后的标题内容。 </li>
</ul>
<p>如果&#8220;传输编码&#8221;改为 Quoted-Printable，同样，如果标题内容为 "中"：</p>
<table cellSpacing=0 cellPadding=6 width="100%" bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td class=code><font color=#339933><span class=rem twffan="done">// 正确的标题格式</span><br></font>Subject: <span style="BACKGROUND-COLOR: #ffff00" twffan="done">=?</span>GB2312<span style="BACKGROUND-COLOR: #ffff00" twffan="done">?Q?</span>=D6=D0<span style="BACKGROUND-COLOR: #ffff00" twffan="done">?=</span></td>
        </tr>
    </tbody>
</table>
<p>如果阅读邮件时出现乱码，一般是因为&#8220;字符编码&#8221;或&#8220;传输编码&#8221;指定有误，或者是没有指定。比如，有的发邮件组件在发送邮件时，标题 "中"：</p>
<table cellSpacing=0 cellPadding=6 width="100%" bgColor=#eeeeee border=1>
    <tbody>
        <tr>
            <td class=code><font color=#339933><span class=rem twffan="done">// 错误的标题格式</span><br></font>Subject: <span style="BACKGROUND-COLOR: #ffff00" twffan="done">=?</span><font color=#ff0000>ISO-8859-1</font><span style="BACKGROUND-COLOR: #ffff00" twffan="done">?Q?</span>=D6=D0<span style="BACKGROUND-COLOR: #ffff00" twffan="done">?=</span></td>
        </tr>
    </tbody>
</table>
<p>这样的表示，实际上是明确指明了标题为 [0x00D6, 0x00D0]，即 "&#214;&#208;"，而不是 "中"。</p>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr vAlign=top>
            <td align=right width="100%"><img height=1 alt="" src="http://www.regexlab.com/images/blue_rule.gif" width="100%" border=0 twffan="done"></td>
        </tr>
        <tr vAlign=top>
            <td align=right width="100%">
            <table cellSpacing=0 cellPadding=0>
                <tbody>
                    <tr align=right>
                        <td>
                        <table cellSpacing=0 cellPadding=0 border=0>
                            <tbody>
                                <tr>
                                    <td vAlign=center><img height=16 alt="" src="http://www.regexlab.com/images/u_bold.gif" width=16 border=0 twffan="done"></td>
                                    <td vAlign=top align=right>
                                    <p><a href="http://www.regexlab.com/zh/encoding.htm#main"><u><font color=#800080>回页首</font></u></a></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<h4><a name=correct></a>4. 几种错误理解的纠正</h4>
<h5>误解：&#8220;ISO-8859-1 是国际编码？&#8221;</h5>
<p>非也。iso-8859-1 只是单字节字符集中最简单的一种，也就是&#8220;字节编号&#8221;与&#8220;UNICODE 字符编号&#8221;一致的那种编码规则。当我们要把一个&#8220;字节串&#8221;转化成&#8220;字符串&#8221;，而又不知道它是哪一种 ANSI 编码时，先暂时地把&#8220;每一个字节&#8221;作为&#8220;一个字符&#8221;进行转化，不会造成信息丢失。然后再使用 bytes = string.getBytes("iso-8859-1") 的方法可恢复到原始的字节串。</p>
<h5>误解：&#8220;Java 中，怎样知道某个字符串的内码？&#8221;</h5>
<p>Java 中，字符串类 java.lang.String 处理的是 UNICODE 字符串，不是 ANSI 字符串。我们只需要把字符串作为&#8220;抽象的符号的串&#8221;来看待。因此不存在字符串的内码的问题。</p>
<img src ="http://www.cppblog.com/true/aggbug/21334.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/true/" target="_blank">true</a> 2007-04-05 17:14 <a href="http://www.cppblog.com/true/archive/2007/04/05/21334.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>base64编码</title><link>http://www.cppblog.com/true/archive/2007/04/05/21330.html</link><dc:creator>true</dc:creator><author>true</author><pubDate>Thu, 05 Apr 2007 08:43:00 GMT</pubDate><guid>http://www.cppblog.com/true/archive/2007/04/05/21330.html</guid><wfw:comment>http://www.cppblog.com/true/comments/21330.html</wfw:comment><comments>http://www.cppblog.com/true/archive/2007/04/05/21330.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/true/comments/commentRss/21330.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/true/services/trackbacks/21330.html</trackback:ping><description><![CDATA[<p>Base64编码其实是将3个8位字节转换为4个6位字节,( 3*8 = 4*6 = 24 ) 这4个六位字节 <br>其实仍然是8位,只不过高两位被设置为0. 当一个字节只有6位有效时,它的取值空间为0 <br>到 2的6次方减1 即63,也就是说被转换的Base64编码的每一个编码的取值空间为(0~63) <br>。 <br>事实上，0~63之间的ASCII码有许多不可见字符，所以应该再做一个映射，映射表为 <br>&#8216;A&#8216; ~ &#8216;Z&#8216; ? ASCII（0 ~ 25） <br>&#8216;a&#8217; ~ &#8216;z&#8216; ? ASCII（26 ~ 51） <br>&#8216;0&#8217; ~ &#8216;9&#8216; ? ASCII（52 ~ 61） <br>&#8216;+&#8216; ? ASCII（62） <br>&#8216;/&#8216; ? ASCII（63） <br>这样就可以将3个8位字节，转换为4个可见字符。 <br>具体的字节拆分方法为：(图（画得不好，领会精神 :-)) <br>aaaaaabb ccccdddd eeffffff <br>~~~~~~~~ ~~~~~~~~ ~~~~~~~~ <br>字节 1 字节 2 字节 3 <br>|| <br>\/ <br>00aaaaaa 00bbcccc 00ddddee 00ffffff </p>
<p>注：上面的三个字节位原文，下面四个字节为Base64编码，其前两位均为0。 <br>这样拆分的时候，原文的字节数量应该是3的倍数，当这个条件不能满足时，用全零字节 <br>补足，转化时Base64编码用=号代替，这就是为什么有些Base64编码以一个或两个等号结 <br>束的原因，但等号最多有两个，因为：如果F(origin)代表原文的字节数，F(remain)代 <br>表余数，则 <br>F(remain) = F(origin) MOD 3 成立。 <br>所以F(remain)的可能取值为0,1,2. <br>如果设 n = [F(origin) &#8211; F(remain)] / 3 <br>当F(remain) = 0 时，恰好转换为4*n个字节的Base64编码。 <br>当F(remain) = 1 时，由于一个原文字节可以拆分为属于两个Base64编码的字节，为了 <br>让Base64编码是4的倍数，所以应该为补2个等号。 <br>当F(remain) = 2 时，由于两个原文字节可以拆分为属于3个Base64编码的字节，同理， <br>应该补上一个等号&nbsp;</p>
<br>
<img src ="http://www.cppblog.com/true/aggbug/21330.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/true/" target="_blank">true</a> 2007-04-05 16:43 <a href="http://www.cppblog.com/true/archive/2007/04/05/21330.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>