📄 gsmencode.hpp
字号:
#ifndef _CAESAR_GSMENCODE_H__DEF
#define _CAESAR_GSMENCODE_H__DEF
#include <windows.h>
/*
在PDU Mode中,可以采用三种编码方式来对发送的内容进行编码,
它们是7-bit、8-bit和UCS2编码。7-bit编码用于发送普通的ASCII字符,
它将一串7-bit的字符(最高位为0)编码成8-bit的数据,每8个字符可
“压缩”成7个;8-bit编码通常用于发送数据消息,比如图片和铃声等;
而UCS2编码用于发送Unicode字符。PDU串的用户信息(TP-UD)段最大容量
是140字节,所以在这三种编码方式下,可以发送的短消息的最大字符数
分别是160、140和70。这里,将一个英文字母、一个汉字和一个数据字节
都视为一个字符。需要注意的是,PDU串的用户信息长度(TP-UDL),在各
种编码方式下意义有所不同。7-bit编码时,指原始短消息的字符个数,
而不是编码后的字节数。8-bit编码时,就是字节数。UCS2编码时,也是
字节数,等于原始短消息的字符数的两倍。如果用户信息(TP-UD)中存在
一个头(基本参数的TP-UDHI为1),在所有编码方式下,用户信息长度(TP
-UDL)都等于头长度与编码后字节数之和。如果采用GSM 03.42所建议的压
缩算法(TP-DCS的高3位为001),则该长度也是压缩编码后字节数或头长度
与压缩编码后字节数之和。
7byte编码原理:
将源串每8个字符分为一组(最后一组可以不满8个)进行编码,在组内字符间压缩,
但每组之间是没有什么联系的。
压缩的方式是从下一个ASCII从低位取值错位,把8个7位的ASCII码压缩成7个8位的BYTE.
UNICODE编码原理:
国际化编码方式。没两个字节表示一个字,对于原ACSII字符高位填充0
UCS2编码原理:
将双字节的UNICODE以高位在前,低位在后的方式输出为BYTE流。
UTF-8原理:
UCS 字符 U+0000 到 U+007F (ASCII) 被编码为字节 0x00 到 0x7F (ASCII 兼容). 这意味着只包含 7 位 ASCII 字符的文件在 ASCII 和 UTF-8 两种编码方式下是一样的.
所有 >U+007F 的 UCS 字符被编码为一个多个字节的串, 每个字节都有标记位集. 因此, ASCII 字节 (0x00-0x7F) 不可能作为任何其他字符的一部分.
表示非 ASCII 字符的多字节串的第一个字节总是在 0xC0 到 0xFD 的范围里, 并指出这个字符包含多少个字节. 多字节串的其余字节都在 0x80 到 0xBF 范围里. 这使得重新同步非常容易, 并使编码无国界, 且很少受丢失字节的影响.
可以编入所有可能的 231个 UCS 代码
UTF-8 编码字符理论上可以最多到 6 个字节长, 然而 16 位 BMP 字符最多只用到 3 字节长.
Bigendian UCS-4 字节串的排列顺序是预定的.
字节 0xFE 和 0xFF 在 UTF-8 编码中从未用到.
下列字节串用来表示一个字符. 用到哪个串取决于该字符在 Unicode 中的序号.
U-00000000 - U-0000007F: 0xxxxxxx
U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
xxx 的位置由字符编码数的二进制表示的位填入. 越靠右的 x 具有越少的特殊意义. 只用最短的那个足够表达一个字符编码数的多字节串. 注意在多字节串中, 第一个字节的开头"1"的数目就是整个串中字节的数目.
例如: Unicode 字符 U+00A9 = 1010 1001 (版权符号) 在 UTF-8 里的编码为:
11000010 10101001 = 0xC2 0xA9
而字符 U+2260 = 0010 0010 0110 0000 (不等于) 编码为:
11100010 10001001 10100000 = 0xE2 0x89 0xA0
这种编码的官方名字拼写为 UTF-8, 其中 UTF 代表 UCS Transformation Format. 请勿在任何文档中用其他名字 (比如 utf8 或 UTF_8) 来表示 UTF-8, 当然除非你指的是一个变量名而不是这种编码本身.
*/
/*
GSMEncode:用以实现在GSM应用中常见的字符串处理,与编码转化的问题。会根据情况继续扩充
作者:邹德强。
江西捷德智能卡有限公司。
name_caesar@msn.com
*/
class CGSMEnCode
{
public:
/*******************************************************************
函 数 名 称: GSMString2Bytes(const char* pSrc, BYTE* pDst, int nSrcLength)
功 能 描 述: 把可打印字符串转化为字节数据。
参 数 说 明: pSrc: 字符串指针。pDst:字节数据指针。nSrcLength:源字符串长度。
返回值 说明: -1: 数据错误
>=0: 字节数据长度
作 者: 邹德强
更 新 日 期: 2004.2.26
*******************************************************************/
static int GSMString2Bytes(const CHAR* pSrc, BYTE* pDst, int nSrcLength)
{
try
{
for(int i=0;i<nSrcLength;i+=2)
{
//输出高4位
if(*pSrc>='0' && *pSrc<='9')
{
*pDst = (*pSrc - '0')<<4;
}
else
if(*pSrc>='a' && *pSrc<='f')
{
*pDst = (*pSrc - 'a' + 0x0A)<<4;
}
else
if(*pSrc>='A' && *pSrc<='F')
{
*pDst = (*pSrc - 'A' + 0x0A)<<4;
}
else
{
return -1;
}
pSrc++;
//输出低四位
if(*pSrc>='0' && *pSrc<='9')
{
*pDst |= (*pSrc - '0');
}
else
if(*pSrc>='a' && *pSrc<='f')
{
*pDst |= (*pSrc - 'a' + 0x0A);
}
else
if(*pSrc>='A' && *pSrc<='F')
{
*pDst |= (*pSrc - 'A' + 0x0A);
}
else
{
return -1;
}
pSrc++;
pDst++;
}
}
catch (...)
{
return -1;
}
return nSrcLength>>1;
}
/*******************************************************************
函 数 名 称: GSMBytes2String(const BYTE* pSrc, CHAR* pDst, int nSrcLength)
功 能 描 述: 把可打印字符串转化为字节数据。
参 数 说 明: pSrc: 字节数据指针。pDst:字符串指针。nSrcLength:源字符串长度。
返回值 说明: -1: 数据错误
>=0: 字节数据长度
作 者: 邹德强
更 新 日 期: 2004.2.26
*******************************************************************/
static int GSMBytes2String(const BYTE* pSrc, CHAR* pDst, int nSrcLength)
{
try
{
for(int i=0;i<nSrcLength;i++)
{
::wsprintf(pDst+i*2,"%02X",pSrc[i]);
}
}
catch (...)
{
return -1;
}
return nSrcLength<<1;
}
/*******************************************************************
函 数 名 称: GSMEncodeUCS2(const CHAR* pSrc, BYTE* pDst, int nSrcLength)
功 能 描 述: 把Ascii串转化为UCS2字符串
参 数 说 明: pSrc: 字节数据指针。pDst:UCS2指针。nSrcLength:源字符串长度。
返回值 说明: -1: 数据错误
>=0: 字节数据长度
作 者: 邹德强
更 新 日 期: 2004.2.26
*******************************************************************/
static int GSMEncodeUCS2(const CHAR* pSrc, BYTE* pDst, int nSrcLength)
{
int nDstLen = 0;
int nOffset = nSrcLength;
int nTotal = 0;
WCHAR wchr[8];
try
{
//以8 WCHAR 为段。避免开启过大的Buffer
while(nOffset>0)
{
if(nOffset>8)
{
nDstLen = ::MultiByteToWideChar(CP_ACP, 0, pSrc, 8, wchr, 8);
if(nDstLen>0)
{
for(int i=0;i<nDstLen;i++)
{
//取高位放在第一个BYTE
*pDst++ = HIBYTE(wchr[i]);
//取低位放在下一个BYTE
*(pDst++) = LOBYTE(wchr[i]);
}
}
else
{
return -1;
}
nOffset -= 8;
nTotal += nDstLen<<1;
pSrc += 8;
}
else
{
nDstLen = ::MultiByteToWideChar(CP_ACP, 0, pSrc, nOffset, wchr, 8);
if(nDstLen>0)
{
for(int i=0;i<nDstLen;i++)
{
//取高位放在第一个BYTE
*(pDst++) = HIBYTE(wchr[i]);
//取低位放在下一个BYTE
*(pDst++) = LOBYTE(wchr[i]);
}
}
else
{
return -1;
}
nTotal += nDstLen<<1;
break;
}
}
}
catch(...)
{
return -1;
}
return nTotal;
}
/*******************************************************************
函 数 名 称: GSMUncodeUCS2(const BYTE* pSrc, CHAR* pDst, int nSrcLength)
功 能 描 述: 把UCS2流转化为ASCII流
参 数 说 明: pSrc: UCS2指针。pDst:字节数据指针。nSrcLength:源字符串长度。
返回值 说明: -1: 数据错误
>=0: 字节数据长度
作 者: 邹德强
更 新 日 期: 2004.2.26
*******************************************************************/
static int GSMDecodeUCS2(const BYTE* pSrc, CHAR* pDst, int nSrcLength)
{
int nDstLen = 0;
int nOffset = nSrcLength;
int nTotal = 0;
WCHAR wchr[8];
try
{
while(nOffset>0)
{
if(nOffset>16)
{
for(int i=0;i<8;i++)
{
//由BYTE组成UNICODE
wchr[i] = *(pSrc++)<<8;
wchr[i] |= *(pSrc++);
}
//把UNICODE分散成字符串
nDstLen = ::WideCharToMultiByte(CP_ACP,0,wchr,8,pDst,16,NULL,NULL);
pDst += nDstLen;
nOffset -= 16;
nTotal += nDstLen;
}
else
{
for(int i=0;i<nOffset>>1;i++)
{
//由BYTE组成UNICODE
wchr[i] = *(pSrc++)<<8;
wchr[i] |= *(pSrc++);
}
//把UNICODE分散成字符串
nDstLen = ::WideCharToMultiByte(CP_ACP,0,wchr,nOffset>>1,pDst,nOffset,NULL,NULL);
nTotal += nDstLen;
pDst += nDstLen;
*pDst = 0;
break;
}
}
}
catch (...)
{
return -1;
}
return nTotal;
}
/*******************************************************************
函 数 名 称: GSMEncode7bit(const char* pSrc, unsigned char* pDst, int nSrcLength)
功 能 描 述: 把ACSII流转化为7byteASCII流
参 数 说 明: pSrc: 源指针。pDst:目标指针。nSrcLength:源字符串长度。
返回值 说明: -1: 数据错误
>=0: 目标数据长度
作 者: 邹德强
更 新 日 期: 2004.2.26
*******************************************************************/
static int GSMEncode7bit(const char* pSrc, unsigned char* pDst, int nSrcLength)
{
int nbyt = 0x00;
int ntotal = 0x00;
for(int nlen=1;nlen<=nSrcLength;nlen++,pSrc++)
{
//每8个byte一组的下标
nbyt = nlen%0x08;
//第8个byte不处理
if(nbyt == 0x00)
{
continue;
}
else
{
//把7bit数据转化为8bit数据
*(pDst++) = (*pSrc>>(nbyt-1)) | ((nlen==nSrcLength) ? 0x00 : (*(pSrc+1)<<(8-nbyt)));
//总处理数加1
ntotal ++;
}
}
return ntotal;
}
/*******************************************************************
函 数 名 称: GSMDecode7bit(const unsigned char* pSrc, char* pDst, int nSrcLength)
功 能 描 述: 把7byteASCII流转化为ACSII流
参 数 说 明: pSrc: 源指针。pDst:目标指针。nSrcLength:源字符串长度。
返回值 说明: -1: 数据错误
>=0: 目标数据长度
作 者: 邹德强
更 新 日 期: 2004.2.26
*******************************************************************/
static int GSMDecode7bit(const unsigned char* pSrc, char* pDst, int nSrcLength)
{
int nbyt = 0x00;
int ntotal = 0x00;
for(int nlen=1;nlen<=nSrcLength;nlen++,pSrc++)
{
ntotal ++;
//每7个byte一组的下标
nbyt = nlen%0x07;
if(nbyt == 0x01)
{
//每组第一个
*(pDst++) = *pSrc & 0x7F;
}
else
if(nbyt == 0x00)
{
//每组最后一个
*(pDst++) = *pSrc<<6 & 0x7F | *(pSrc-1)>>2;
//每组第7个bit完毕后增加一个输出
*(pDst++) = *pSrc>>1;
//总处理数加1
ntotal++;
}
else
{
*(pDst++) = (*pSrc<<(nbyt-1) & 0x7F) | (*(pSrc-1)>>(9-nbyt));
}
}
//串尾标识
*(pDst) = 0x00;
return ntotal;
}
/*******************************************************************
函 数 名 称: GSMUCS2ToUTF8(const CHAR* pSrc, BYTE* pDst, int nSrcLength)
功 能 描 述: 把UCS2的串转化为UTF-8
参 数 说 明: pSrc: UCS2指针。pDst:UTF-8指针。nSrcLength:源字符串长度。
返回值 说明: -1: 数据错误
>=0: UTF8数据长度
作 者: 邹德强
更 新 日 期: 2004.2.26
*******************************************************************/
static int GSMEncodeUTF8(const BYTE* pSrc, BYTE* pDst, int nSrcLength)
{
int nTotal = 0;
WCHAR wchr;
for(int nLen=0;nLen<nSrcLength;nLen+=2)
{
//取一个Unicode字符
wchr = *(pSrc++)<<8;
wchr |= *(pSrc++);
if(wchr<=0x007F)
{
//第一种编码模式
*(pDst++) = LOBYTE(wchr);
nTotal ++;
}
else
if(wchr<=0x07FF)
{
//第二种编码模式
*(pDst++) = 0xc0 | HIBYTE(wchr<<2);
*(pDst++) = 0x80 | (LOBYTE(wchr) & 0x3f);
nTotal += 2;
}
else
{
//第三种编码模式
*(pDst++) = 0xe0 | HIBYTE(wchr>>4);
*(pDst++) = 0x80 | (HIBYTE(wchr<<2) & 0x3f);
*(pDst++) = 0x80 | (LOBYTE(wchr) & 0x3f);
nTotal += 3;
}
}
return nTotal;
}
/*******************************************************************
函 数 名 称: GSMUtf8ToUcs2(const CHAR* pSrc, BYTE* pDst, int nSrcLength)
功 能 描 述: 把UTF-8的串转化为UCS2
参 数 说 明: pSrc: UTF-8数据指针。pDst:UCS2指针。nSrcLength:源字符串长度。
返回值 说明: -1: 数据错误
>=0: UCS2数据长度
作 者: 邹德强
更 新 日 期: 2004.2.26
*******************************************************************/
static int GSMDecodeUTF8(const BYTE* pSrc, BYTE* pDst, int nSrcLength)
{
int nTotal = 0;
BYTE bychr;
for(int nLen=0;nLen<nSrcLength;nTotal+=2)
{
//判断首字符
bychr = *(pSrc++);
if(bychr <= 0x7f)
{
//第一种模式
*(pDst++) = 0x00;
*(pDst++) = bychr;
nLen ++;
}
else
if(bychr>=0xc0 && bychr<=0xdf)
{
//第二种模式
*(pDst++) = (bychr>>2) & 0x07;
*(pDst++) = (bychr<<6) | (*(pSrc++) & 0x3F);
nLen += 2;
}
else
{
//第三种模式
*(pDst++) = (bychr<<4) | ((*pSrc>>2) & 0x0F);
bychr = *(pSrc++);
*(pDst++) = (bychr<<6) | (*(pSrc++) & 0x3F);
nLen += 3;
}
}
return nTotal;
}
};
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -