前段时间在做邮件解码的时候碰到MIME的Base64编码和QP编码
1.Base64编码
Base64要求把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之后在6位的前面补两个0,形成8位一个字节的形式.
解码算法大概可以分为如下几步几步:
读取数据3字节用AND取前6位,放入新的变量中右移两位,高两位清0AND取第一个字节的后2位和第二个字节的前4位移位放入新变量中右移两位,清0……依此类推。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![ExpandedBlockStart.gif](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
//
解码后的长度一般比原文少用占1/4的存储空间,请保证buf有足够的空间
inline int Base64Decode( char * buf, const char * base64code, int src_len)
{
if (src_len == 0 )
src_len = strlen(base64code);
int len = 0 ;
unsigned char * psrc = (unsigned char * )base64code;
char * pbuf = buf;
int i ;
for ( i = 0 ; i < src_len - 4 ; i += 4 )
{
unsigned long ulTmp = * (unsigned long * )psrc;
register int b0 = (GetB64Index(( char )B0(ulTmp)) << 2 | GetB64Index(( char )B1(ulTmp)) << 2 >> 6 ) & 0xFF ;
register int b1 = (GetB64Index(( char )B1(ulTmp)) << 4 | GetB64Index(( char )B2(ulTmp)) << 2 >> 4 ) & 0xFF ;
register int b2 = (GetB64Index(( char )B2(ulTmp)) << 6 | GetB64Index(( char )B3(ulTmp)) << 2 >> 2 ) & 0xFF ;
// *((unsigned long*)pbuf) = b0 | b1 << 8 | b2 << 16;
* pbuf ++ = b0;
* pbuf ++ = b1;
* pbuf ++ = b2;
psrc += 4 ;
// pbuf += 4;
len += 3 ;
}
// 处理最后余下的不足4字节的数据
if (i < src_len)
{
int rest = src_len - i;
unsigned long ulTmp = 0 ;
for ( int j = 0 ; j < rest; ++ j)
{
* (((unsigned char * ) & ulTmp) + j) = * psrc ++ ;
}
register int b0 = (GetB64Index(( char )B0(ulTmp)) << 2 | GetB64Index(( char )B1(ulTmp)) << 2 >> 6 ) & 0xFF ;
* pbuf ++ = b0;
len ++ ;
if ( ' = ' != B1(ulTmp) && ' = ' != B2(ulTmp))
{
register int b1 = (GetB64Index(( char )B1(ulTmp)) << 4 | GetB64Index(( char )B2(ulTmp)) << 2 >> 4 ) & 0xFF ;
* pbuf ++ = b1;
len ++ ;
}
if ( ' = ' != B2(ulTmp) && ' = ' != B3(ulTmp))
{
register int b2 = (GetB64Index(( char )B2(ulTmp)) << 6 | GetB64Index(( char )B3(ulTmp)) << 2 >> 2 ) & 0xFF ;
* pbuf ++ = b2;
len ++ ;
}
}
* pbuf = ' \0 ' ;
return len;
}
inline int Base64Decode( char * buf, const char * base64code, int src_len)
{
if (src_len == 0 )
src_len = strlen(base64code);
int len = 0 ;
unsigned char * psrc = (unsigned char * )base64code;
char * pbuf = buf;
int i ;
for ( i = 0 ; i < src_len - 4 ; i += 4 )
{
unsigned long ulTmp = * (unsigned long * )psrc;
register int b0 = (GetB64Index(( char )B0(ulTmp)) << 2 | GetB64Index(( char )B1(ulTmp)) << 2 >> 6 ) & 0xFF ;
register int b1 = (GetB64Index(( char )B1(ulTmp)) << 4 | GetB64Index(( char )B2(ulTmp)) << 2 >> 4 ) & 0xFF ;
register int b2 = (GetB64Index(( char )B2(ulTmp)) << 6 | GetB64Index(( char )B3(ulTmp)) << 2 >> 2 ) & 0xFF ;
// *((unsigned long*)pbuf) = b0 | b1 << 8 | b2 << 16;
* pbuf ++ = b0;
* pbuf ++ = b1;
* pbuf ++ = b2;
psrc += 4 ;
// pbuf += 4;
len += 3 ;
}
// 处理最后余下的不足4字节的数据
if (i < src_len)
{
int rest = src_len - i;
unsigned long ulTmp = 0 ;
for ( int j = 0 ; j < rest; ++ j)
{
* (((unsigned char * ) & ulTmp) + j) = * psrc ++ ;
}
register int b0 = (GetB64Index(( char )B0(ulTmp)) << 2 | GetB64Index(( char )B1(ulTmp)) << 2 >> 6 ) & 0xFF ;
* pbuf ++ = b0;
len ++ ;
if ( ' = ' != B1(ulTmp) && ' = ' != B2(ulTmp))
{
register int b1 = (GetB64Index(( char )B1(ulTmp)) << 4 | GetB64Index(( char )B2(ulTmp)) << 2 >> 4 ) & 0xFF ;
* pbuf ++ = b1;
len ++ ;
}
if ( ' = ' != B2(ulTmp) && ' = ' != B3(ulTmp))
{
register int b2 = (GetB64Index(( char )B2(ulTmp)) << 6 | GetB64Index(( char )B3(ulTmp)) << 2 >> 2 ) & 0xFF ;
* pbuf ++ = b2;
len ++ ;
}
}
* pbuf = ' \0 ' ;
return len;
}
2.QP(Quote-Printable)编码
Quoted-Printable编码的基本方法是:输入数据在33-60、62-126范围内的,直接输出;其它的需编码为“=”加两个字节的HEX码(大写)。为保证输出行不超过规定长度,可在行尾加“=\r\n”序列作为软回车。
QP的解码算法:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![ExpandedBlockStart.gif](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
inline
int
DecodeQuoted(
char
*
pDst,
const
char
*
pSrc,
int
nSrcLen)
{
if (nSrcLen == 0 )
nSrcLen = strlen(pSrc);
int nDstLen; // 输出的字符计数
int i;
i = 0 ;
nDstLen = 0 ;
while (i < nSrcLen)
{
if (strncmp(pSrc, " =\r\n " , 3 ) == 0 ) // 软回车,跳过
{
pSrc += 3 ;
i += 3 ;
}
else
{
if ( * pSrc == ' = ' ) // 是编码字节
{
sscanf(pSrc, " =%02X " , pDst);
pDst ++ ;
pSrc += 3 ;
i += 3 ;
}
else // 非编码字节
{
* pDst ++ = (unsigned char ) * pSrc ++ ;
i ++ ;
}
nDstLen ++ ;
}
}
// 输出加个结束符
* pDst = ' \0 ' ;
return nDstLen;
}
{
if (nSrcLen == 0 )
nSrcLen = strlen(pSrc);
int nDstLen; // 输出的字符计数
int i;
i = 0 ;
nDstLen = 0 ;
while (i < nSrcLen)
{
if (strncmp(pSrc, " =\r\n " , 3 ) == 0 ) // 软回车,跳过
{
pSrc += 3 ;
i += 3 ;
}
else
{
if ( * pSrc == ' = ' ) // 是编码字节
{
sscanf(pSrc, " =%02X " , pDst);
pDst ++ ;
pSrc += 3 ;
i += 3 ;
}
else // 非编码字节
{
* pDst ++ = (unsigned char ) * pSrc ++ ;
i ++ ;
}
nDstLen ++ ;
}
}
// 输出加个结束符
* pDst = ' \0 ' ;
return nDstLen;
}