emule中的字符串转换主要在stringconversion.h和stringconversion.cpp中实现,其实掌握了utf-8和utf-16的编码方式,这些代码自己来写也很简单,下面给出stringconversion.cpp中的函数utf8towc的注释版。如果代码中有细节不清楚的,可以查看 rfc2781和rfc3629,这两个文档相当清晰的描述了utf-8和utf-16,比在网上荡的其它资料清晰多了。
一、utf-8编码方式
首先要清楚下面的关系:Unicode字符集给每个字符分类了一个整数(code point)来代表它(可以想象成这个整数和字符是一个映射关系),而具体在计算机中用什么样的编码来表示这个整数就是编码方式。Unicode字符集所使用的编码方式有如下几种:UTF-8、UTF-16、UTF-32等。其中前两种编码方式是边长编码方式,最后一种是定长的。变长编码方式就是说在该编码中所使用的表示一个字符的字节数是不固定的。下面介绍utf-8中的一些概念:
- code unit:编码单元,编码方式所使用的最小数据单元,如utf-8的code unit是1字节,utf-16是2字节,utf-32是4字节。
- singletons:在utf-8中使用一个code unit编码的编码形式。这些字符的code point在0x00~0x7F之间。
- lead unit:当需要多个字节合起来表示一个字符时,第一个字节叫lead unit。Lead unit的范围是0xC0~0xFD,该字节同样指示了他后面跟多少字节是来表示同一个字符的。后面的字节(trail unit)的值的范围是0x80~0xBF。这样的编码方式自同步的,即从串的中间也能决定哪个字节是一个字符编码的开始字节。
下面是code point 和utf-8编码的对应表,其中x表示有效编码位。这张表非常重要,下面代码中的判断有效字符的方法均是根据这个表得出的。
Bits | Last code point | Byte 1 | Byte 2 | Byte 3 | Byte 4 | |
---|---|---|---|---|---|---|
7 | U+007F | 0xxxxxxx | ||||
11 | U+07FF | 110xxxxx | 10xxxxxx | |||
16 | U+FFFF | 1110xxxx | 10xxxxxx | 10xxxxxx | ||
21 | U+1FFFFF | 11110xxx | 10xxxxxx | 10xxxxxx | 10xxxxxx |
解释:
下划线部分:这个部分只存在于使用2个或多个字节编码字符时。下划线中1的个数表示该字符使用了多少个字节来编码。
重叠编码问题:utf-8中不允许重叠编码。如utf-8编码C080解码后为0,但是0可以用7位表示,所以c080不是合法的编码,也就是在编码是要按最小的字节来编码。
获得code point:将上表中的xxxx和到一起组成的二进制数就是该字符的code point。
二、utf-16编码
这样编码方式比较简单,它使用双字节为一个code unit。在0x10000一下的code point对应的字符使用一个code point编码,超过的用两个code point。转换规则见 rfc2781。
下面的是代码了:
参考资料:
rfc2781:http://www.rfc-editor.org/info/rfc2781
rfc3629:http://www.rfc-editor.org/info/rfc3629