结构体设置
static T_EncodingOpr g_tAsciiEncodingOpr = {
.name = "ascii",
.iHeadLen = 0,
.isSupport = isAsciiCoding,
.GetCodeFrmBuf = AsciiGetCodeFrmBuf,
};
结构体注册
int AsciiEncodingInit(void)
{
AddFontOprForEncoding(&g_tAsciiEncodingOpr, GetFontOpr("freetype"));
AddFontOprForEncoding(&g_tAsciiEncodingOpr, GetFontOpr("ascii"));
AddFontOprForEncoding(&g_tAsciiEncodingOpr, GetFontOpr("gbk"));
return RegisterEncodingOpr(&g_tAsciiEncodingOpr);
}
判断是否为对应编码(判断是否是UTF-8编码)
原理是,utf-8文件的前三个字符编码固定是0XEF 0XBB 0X BF
static int isUtf8Coding(unsigned char *pucBufHead)
{
const char aStrUtf8[] = {0xEF, 0xBB, 0xBF, 0};
if (strncmp((const char*)pucBufHead, aStrUtf8, 3) == 0)
{
/* UTF-8 */
return 1;
}
else
{
return 0;
}
}
判断UTF-8字符编码字节数(从高往低判断)
/* 获得前导为1的位的个数
* 比如二进制数 11001111 的前导1有2位
* 11100001 的前导1有3位
*/
static int GetPreOneBits(unsigned char ucVal)
{
int i;
int j = 0;
for (i = 7; i >= 0; i--)
{
if (!(ucVal & (1<<i)))
break;
else
j++;
}
return j;
}
取出字符的编码值(根据pucBufStart、pucBufEnd、ucVal把字符编码值取出来放到pdwCode里)
static int Utf8GetCodeFrmBuf(unsigned char *pucBufStart, unsigned char *pucBufEnd, unsigned int *pdwCode)
{
#if 0
对于UTF-8编码中的任意字节B,如果B的第一位为0,则B为ASCII码,并且B独立的表示一个字符;
如果B的第一位为1,第二位为0,则B为一个非ASCII字符(该字符由多个字节表示)中的一个字节,并且不为字符的第一个字节编码;
如果B的前两位为1,第三位为0,则B为一个非ASCII字符(该字符由多个字节表示)中的第一个字节,并且该字符由两个字节表示;
如果B的前三位为1,第四位为0,则B为一个非ASCII字符(该字符由多个字节表示)中的第一个字节,并且该字符由三个字节表示;
如果B的前四位为1,第五位为0,则B为一个非ASCII字符(该字符由多个字节表示)中的第一个字节,并且该字符由四个字节表示;
因此,对UTF-8编码中的任意字节,根据第一位,可判断是否为ASCII字符;
根据前二位,可判断该字节是否为一个字符编码的第一个字节;
根据前四位(如果前两位均为1),可确定该字节为字符编码的第一个字节,并且可判断对应的字符由几个字节表示;
根据前五位(如果前四位为1),可判断编码是否有错误或数据传输过程中是否有错误。
#endif
int i;
int iNum;
unsigned char ucVal;
unsigned int dwSum = 0;
if (pucBufStart >= pucBufEnd)
{
/* 文件结束 */
return 0;
}
ucVal = pucBufStart[0];
iNum = GetPreOneBits(pucBufStart[0]);
if ((pucBufStart + iNum) > pucBufEnd)
{
/* 文件结束 */
return 0;
}
if (iNum == 0)
{
/* ASCII */
*pdwCode = pucBufStart[0];
return 1;
}
else
{
ucVal = ucVal << iNum;
ucVal = ucVal >> iNum;
dwSum += ucVal;
for (i = 1; i < iNum; i++)
{
ucVal = pucBufStart[i] & 0x3f;//0x3f代表每个字节去掉前两位的后6位
dwSum = dwSum << 6;//通过<<把每个字节拼接起来
dwSum += ucVal;
}
*pdwCode = dwSum;
return iNum;
}
}
扩展
1、如何判断ASCII编码(这里使用排除法)
static int isAsciiCoding(unsigned char *pucBufHead)
{
const char aStrUtf8[] = {0xEF, 0xBB, 0xBF, 0};
const char aStrUtf16le[] = {0xFF, 0xFE, 0};
const char aStrUtf16be[] = {0xFE, 0xFF, 0};
if (strncmp((const char*)pucBufHead, aStrUtf8, 3) == 0)
{
/* UTF-8 */
return 0;
}
else if (strncmp((const char*)pucBufHead, aStrUtf16le, 2) == 0)
{
/* UTF-16 little endian */
return 0;
}
else if (strncmp((const char*)pucBufHead, aStrUtf16be, 2) == 0)
{
/* UTF-16 big endian */
return 0;
}
else
{
return 1;
}
}
2、1的结果判断else可能是ascii或者gbk,则判断字符长度是否大于0x80(128)即可
static int AsciiGetCodeFrmBuf(unsigned char *pucBufStart, unsigned char *pucBufEnd, unsigned int *pdwCode)
{
unsigned char *pucBuf = pucBufStart;
unsigned char c = *pucBuf;
if ((pucBuf < pucBufEnd) && (c < (unsigned char)0x80))
{
/* 返回ASCII码 */
*pdwCode = (unsigned int)c;
return 1;
}
if (((pucBuf + 1) < pucBufEnd) && (c >= (unsigned char)0x80))
{
/* 返回GBK码 */
*pdwCode = pucBuf[0] + (((unsigned int)pucBuf[1])<<8);
return 2;
}
if (pucBuf < pucBufEnd)
{
/* 可能文件有损坏, 但是还是返回一个码, 即使它是错误的 */
*pdwCode = (unsigned int)c;
return 1;
}
else
{
/* 文件处理完毕 */
return 0;
}
}