电子书---编码子模块

一、关于window下的一些编码常识
对于一个文本文件,可保存为ANSI、UTF-8、UTF-16 LE、UTF-16BE及 带有BOM的UTF-8
1)先说说啥是BOM?
BOM,是Byte Order Mark 的缩写,就是字节序标记。

2)UTF-8 的 编码规则
在前面文字提到如何解读UTF-8, 这里再回顾并补充一些。
UTF-8 是 遵从 unicode 标准的(也就是是说,UTF-8表示的字符编码在unicode编码表中)
但是,UTF-8 是变长(1~4字节)编码的,如何实现变长呢?
还是举个例子,对于“中”这个汉字,对应 unicode 编码表,其字符编码值为 0x4E 0x2D
没错,汉字是2个字节表示的,4E 2D 刚好两字节。来看看UTF-8 对“中”字的编码,如下
   E  4         B  8         A  D 
1110  0100   1011  1000     1010   1101
1110 前导三个1,表示用三个字节表示该字符, B8 AD 两个字节的高两位都是10,起标识作用,去掉这些标识后
0100 1110 0010 1101 ---> 即,4E  2D, 刚好组成16位,表示“中”的编码值

3)UTF-8 BOM是怎么回事?
明确1)2)两点后,不难发现,带BOM的UTF-8,其BOM只是作为UTF-8编码方式的标识而已。
不信看看,在window下,以记事本写一个“中”字,然后分别另存为UTF-8 和 带BOM的UTF-8,
 再通过UE以十六进制查看,如下图

带BOM的UTF-8与UTF-8

接着,按UTF-8的编码规则,对EF BB BF 解析可得到,其编码值为 FE FF(可以自己尝试下)
那FE FF在unicode编码表中对应什么字符呢?
对应ZERO WIDTH NO-BREAK SPACE"字符,表示这是一个不存在的字符。
UCS规范建议我们在传输字节流前,先传输 字符"ZERO WIDTH NO-BREAK SPACE"。这样如果接收者收到FEFF,
就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little- Endian的。因此字符
"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。
因此,UTF8 BOM 是以(EF BB BF)字节开头的文本流。

UTF-8的一些个人理解:
UTF-8 以 8 位为一个编码单元,每个字符会由 1 到 4 个单元表示。因此,一个字节根本不存在字节序问题
所以,UTF-8可以带BOM,也可不带(推荐)。个人觉得,带BOM只是更方便软件识别文件的编码方式。当然
不带BOM也可识别,没那么直观、简单判断而已。
另外,既然UTF-8是以一个字节为单位来传输,那么即使丢失了一些字节,也不会影响到后面的解码。
就如“中”字的UTF-8编码来说,假如丢失了第一个字节,那么B8 AD的二进制为 1011 1000   1010 1101
10 是个标志而已,那么就解读为 11 10,00 10, 1101  ---> 0E, 2D.其实这个字乱码了,但是后续的字节流
一点都不受影响,肯定能正确解析。而像UTF-16,如果前面字节丢失了,肯定会影响后续的解码的。
但实际,字节流都会有校验一步的,检测到字节丢失,肯定会丢弃重传。所以大可放心接收到的字节流的准确性。

4)UTF-16 LE  和 UTF-16 BE
有了前面的理解,这两个不难理解,LE: 小端  BE:大端,要区分两者,BOM标志不同
文本开头FEFF,就表明这个字节流是Big-Endian的;而如果是 FFFE,就表明这个字节流是Little- Endian的。
因此,总结来说,BOM对于UTF-16被用作字节序的标识,而对于UTF-8是标识UTF-8编码,可有可无

5)ANSI 编码
	在简体中文window环境下,当保存为ANSI编码文件时,对于字母,ANSI会以ASCII方式一个字节存储编码值,
	而对于汉字,则以GBK编码两字节大小存储一个汉字。
好了,通过对window下的编码讨论,也发现了一个问题。对于一个文本文件,自然先要判断编码方式,然后
去掉这些标志字符(BOM)以获取正确的文本数据。因此很有必要划分出一个“编码子模块”,用于解析这些文件的编码
然后才能正确提取后面的编码值,后面的获取点阵和显示点阵才能正确进行下去。
二、编码子模块介绍
遵循前面两个子模块的介绍,编码子模块的框图如下

编码子模块框图

三、源码实现与编译检查
encoding_manager.h
#ifndef _ENCODING_MANAGER_H
#define _ENCODING_MANAGER_H

#include <fonts_manager.h>
#include <disp_manager.h>

typedef struct EncodingOpr{
    char* name;
    int iHeadLen;
    PT_FontOpr ptFontOprSupportedHead;
    int (*isSupport)(unsigned char* pucBufHead);
    int (*GetCodeFrmBuf)(unsigned char* pucBufStart, unsigned char*pucBufEnd,unsigned int *pdwCode);
    struct EncodingOpr* ptNext;
}T_EncodingOpr, *PT_EncodingOpr;

int RegisterEncodingOpr(PT_EncodingOpr ptEncodingOpr);
void ShowEncodingOpr(void);
PT_DispOpr GetDispOpr(char *pcName);
PT_EncodingOpr SelectEncodingOprForFile(unsigned char *pucFileBufHead);
int AddFontOprForEncoding(PT_EncodingOpr ptEncodingOpr, PT_FontOpr ptFontOpr);
int DelFontOprFrmEncoding(PT_EncodingOpr ptEncodingOpr, PT_FontOpr ptFontOpr);
int EncodingInit(void);
int AsciiEncodingInit(void);
int  Utf16beEncodingInit(void);
int  Utf16leEncodingInit(void);
int  Utf8EncodingInit(void);

#endif /*_ENCODING_MANAGER_H */
encoding_manager.c
#include <config.h>
#include <encoding_manager.h>
#include <string.h>
#include <stdlib.h>

static PT_EncodingOpr g_ptEncodingOprHead;

int RegisterEncodingOpr(PT_EncodingOpr ptEncodingOpr)
{
    PT_EncodingOpr ptTmp;
    
    if(!g_ptEncodingOprHead)
    {
        g_ptEncodingOprHead = ptEncodingOpr;
        ptEncodingOpr->ptNext = NULL;
    }
    else
    {
        ptTmp = g_ptEncodingOprHead;
        while(ptTmp->ptNext)
        {
            ptTmp = ptTmp->ptNext;
        }
        ptTmp->ptNext = ptEncodingOpr;
        ptEncodingOpr->ptNext = NULL;
    }
    return 0;
}

void ShowEncodingOpr(void)
{
    int i = 0;
    
    PT_EncodingOpr ptTmp = g_ptEncodingOprHead;
    while(ptTmp)
    {
        printf("%02d %s\n", i++, ptTmp->name);
        ptTmp = ptTmp->ptNext;
    }
}

PT_EncodingOpr SelectEncodingOprForFile(unsigned char* pucFileBufHead)
{
    PT_EncodingOpr ptTmp = g_ptEncodingOprHead;
    
    while(ptTmp)
    {
        if(ptTmp->isSupport(pucFileBufHead))
            return ptTmp;
        else
            ptTmp = ptTmp->ptNext;
    }
    return NULL;
}

int AddFontOprForEncoding(PT_EncodingOpr ptEncodingOpr, PT_FontOpr ptFontOpr)
{
    PT_FontOpr ptFontOprCpy;
    
    if(!ptEncodingOpr || !ptFontOpr)
        return -1;
    else
    {
        ptFontOprCpy = malloc(sizeof(T_FontOpr));
        if(!ptFontOprCpy)
        {
            return -1;
        }
        else
        {
            memcpy(ptFontOprCpy, ptFontOpr, sizeof(T_FontOpr));
            ptFontOprCpy->ptNext = ptEncodingOpr->ptFontOprSupportedHead; //头插法
            ptEncodingOpr->ptFontOprSupportedHead = ptFontOprCpy;
            return 0;
        }
    }
}
int DelFontOprFrmEncoding(PT_EncodingOpr ptEncodingOpr, PT_FontOpr ptFontOpr)
{
    PT_FontOpr ptTmp;
    PT_FontOpr ptPre;
    
    if(!ptEncodingOpr || !ptFontOpr)
        return -1;
    else
    {
        ptTmp = ptEncodingOpr->ptFontOprSupportedHead;
        if(strcmp(ptTmp->name, ptFontOpr->name) == 0)
        {
            ptEncodingOpr->ptFontOprSupportedHead = ptTmp->ptNext;
            free(ptTmp);
            return 0;
        }
        ptPre = ptEncodingOpr->ptFontOprSupportedHead;
        ptTmp = ptPre->ptNext;
        while(ptTmp)
        {
            if(strcmp(ptTmp->name, ptFontOpr->name) == 0)
            {
                ptPre->ptNext = ptTmp->ptNext;
                free(ptTmp);
                return 0;
            }
            else
            {
                ptPre = ptTmp;
                ptTmp = ptTmp->ptNext;
            }
        }
        return -1;
    }
}

int EncodingInit(void)
{
    int iError;
    
    iError = AsciiEncodingInit();
    if(iError)
    {
        DBG_PRINTF("AsciiEncodingInit error!\n");
        return -1;
    }
    
    iError = Utf16leEncodingInit();
    if (iError)
    {
  	DBG_PRINTF("Utf16leEncodingInit error!\n");
  	return -1;
    }
    
    iError = Utf16beEncodingInit();
    if (iError)
    {
  	DBG_PRINTF("Utf16beEncodingInit error!\n");
  	return -1;
    }
    
    iError = Utf8EncodingInit();
    if (iError)
    {
  	DBG_PRINTF("Utf8EncodingInit error!\n");
  	return -1;
   }
   
   return 0;
}
ascii_encoding.c
#include <config.h>
#include <encoding_manager.h>
#include <string.h>
static int isAsciiCoding(unsigned char *pucBufHead);
static int AsciiGetCodeFrmBuf(unsigned char *pucBufStart, unsigned char *pucBufEnd, unsigned int *pdwCode);

static T_EncodingOpr g_tAsciiEncodingOpr = {
    .name = "ascii",
    .iHeadLen = 0,
    .isSupport = isAsciiCoding,
    .GetCodeFrmBuf = AsciiGetCodeFrmBuf,
}; 

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;
    }
}

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))
    {
        /* return ASCII code*/
        *pdwCode = (unsigned)c;
        return 1;
    }
    if(((pucBuf + 1) < pucBufEnd) && (c >= (unsigned char)0x80))
    {
        /* return GBK code*/
        *pdwCode = pucBuf[0] + (((unsigned int)pucBuf[1]) << 8);
        return 2;
    }
    if(pucBuf < pucBufEnd)
    {
        *pdwCode = (unsigned int)c;
        return 1; 
    }
    else
    {
        return 0;
    }
}

int AsciiEncodingInit(void)
{
    AddFontOprForEncoding(&g_tAsciiEncodingOpr, GetFontOpr("freetype"));
    AddFontOprForEncoding(&g_tAsciiEncodingOpr, GetFontOpr("ascii"));
    AddFontOprForEncoding(&g_tAsciiEncodingOpr, GetFontOpr("gbk"));
    return RegisterEncodingOpr(&g_tAsciiEncodingOpr);
}
utf-8_encoding.c
#include <config.h>
#include <encoding_manager.h>
#include <string.h>

static int isUtf8Coding(unsigned char *pucBufHead);
static int Utf8GetCodeFrmBuf(unsigned char *pucBufStart, unsigned char *pucBufEnd, unsigned int *pdwCode);

static T_EncodingOpr g_tUtf8EncodingOpr = {
    .name = "utf-8",
    .iHeadLen = 3,
    .isSupport = isUtf8Coding,
    .GetCodeFrmBuf = Utf8GetCodeFrmBuf,
};

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;
    }
}

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;
}
static int Utf8GetCodeFrmBuf(unsigned char * pucBufStart, unsigned char * pucBufEnd, unsigned int * pdwCode)
{
    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)
    {
        *pdwCode = pucBufStart[0];
        return 1;
    }
    else
    {
        ucVal = ucVal << iNum;
        ucVal = ucVal >> iNum;
        dwSum += ucVal;
        for(i = 1; i < iNum; i++)
        {
            ucVal = pucBufStart[i] & 0x3f;
            dwSum = dwSum << 6;
            dwSum += ucVal;
        }
        *pdwCode = dwSum;
        return iNum;
    }
}   
int Utf8EncodingInit(void)
{
    AddFontOprForEncoding(&g_tUtf8EncodingOpr, GetFontOpr("freetype"));
    AddFontOprForEncoding(&g_tUtf8EncodingOpr, GetFontOpr("ascii"));
    return RegisterEncodingOpr(&g_tUtf8EncodingOpr);
}
utf-16le_encoding.c
#include <config.h>
#include <encoding_manager.h>
#include <string.h>

static int isUtf16leCoding(unsigned char*pucBufHead);
static int Utf16leGetCodeFrmBuf(unsigned char *pucBufStart, unsigned char *pucBufEnd, unsigned int *pdwCode);

static T_EncodingOpr g_tUtf16leEncodingOpr = {
    .name = "utf-16le",
    .iHeadLen = 2,
    .isSupport = isUtf16leCoding,
    .GetCodeFrmBuf = Utf16leGetCodeFrmBuf,
};

static int isUtf16leCoding(unsigned char * pucBufHead)
{
    const char aStrUtf16le[] = {0xFF, 0xFE, 0};
    
    if(strncmp((const char*)pucBufHead, aStrUtf16le, 2) == 0)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}
static int Utf16leGetCodeFrmBuf(unsigned char * pucBufStart, unsigned char * pucBufEnd, unsigned int * pdwCode)
{
    if(pucBufStart + 1 < pucBufEnd)
    {
        *pdwCode = (((unsigned int)pucBufStart[1])<<8) + pucBufStart[0];
        return 2;
    }
    else
    {
        return 0;
    }
}
int Utf16leEncodingInit(void)
{
	AddFontOprForEncoding(&g_tUtf16leEncodingOpr, GetFontOpr("freetype"));
 	AddFontOprForEncoding(&g_tUtf16leEncodingOpr, GetFontOpr("ascii"));
 	return RegisterEncodingOpr(&g_tUtf16leEncodingOpr);
}
utf16-be_encoding.c
#include <config.h>
#include <encoding_manager.h>
#include <string.h>

static int isUtf16beCoding(unsigned char*pucBufHead);
static int Utf16beGetCodeFrmBuf(unsigned char *pucBufStart, unsigned char *pucBufEnd, unsigned int *pdwCode);

static T_EncodingOpr g_tUtf16beEncodingOpr = {
    .name = "utf-16be",
    .iHeadLen = 2,
    .isSupport = isUtf16beCoding,
    .GetCodeFrmBuf = Utf16beGetCodeFrmBuf,
};

static int isUtf16beCoding(unsigned char * pucBufHead)
{
    const char aStrUtf16be[] = {0xFE, 0xFF,  0};
    
    if(strncmp((const char*)pucBufHead, aStrUtf16be, 2) == 0)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}
static int Utf16beGetCodeFrmBuf(unsigned char * pucBufStart, unsigned char * pucBufEnd, unsigned int * pdwCode)
{
    if(pucBufStart + 1 < pucBufEnd)
    {
        *pdwCode = (((unsigned int)pucBufStart[0])<<8) + pucBufStart[1];
        return 2;
    }
    else
    {
        return 0;
    }
}
int Utf16beEncodingInit(void)
{
    	AddFontOprForEncoding(&g_tUtf16beEncodingOpr, GetFontOpr("freetype"));
 	AddFontOprForEncoding(&g_tUtf16beEncodingOpr, GetFontOpr("ascii"));
 	return RegisterEncodingOpr(&g_tUtf16beEncodingOpr);
}
编译检测语法/书写有无错误

编码子模块的编译检查

注意:编译时,也要编译点阵子模块,因为两者是是有关联的,如EncodingOpr结构体有PT_FontOpr 指针,指向该编码
支持的字体文件。比如说,对于ASCII,不仅支持ascii字体文件,还有gbk和freetype两种字体文件,即对应于UTF-16le、
UTF-16be、UTF-8这三者编码方式。这三者都能表达ascii字符,只是编码方式不同,需分别识别再提取有效的文本数据。

OK,三大子模块讲解完了,也是电子书框架最基本的组件。实际,这三个子模块框架都是一样的。编码并不难,套路都一样。
难点或者电子书的核心点在于下一篇文章的“draw.c”的实现,不仅要综合这三个字模块,还要向上提供换页显示功能。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值