算法系列8《Base64》
Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,Base64编码可用于在HTTP环境下传递较长的标识信息。在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式。此时,采用Base64编码具有不可读性,即所编码的数据不会被人用肉眼所直接看到。金融数据也常以base64编码格式提供。
Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于2的6次方等于64,所以每6个比特为一个单元,对应某个可打印字符。三个字节有24个比特,对应于4个Base64单元,即3个字节需要用4个可打印字符来表示。它可用来作为电子邮件的传输编码。在Base64中的可打印字符包括字母A-Z、a-z、数字0-9,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。一些如uuencode的其他编码方法,和之后binhex的版本使用不同的64字符集来代表6个二进制数字,但是它们不叫Base64。
Base64索引表
C++实现代码
1. 《Base64.h》
// Base64.h
#pragma once
#include <windows.h> class CBase64
{
// Internal bucket class.
class TempBucket
{
public:
BYTE nData[4];
BYTE nSize;
void Clear() { ::ZeroMemory(nData, 4); nSize = 0; };
}; PBYTE m_pDBuffer;
PBYTE m_pEBuffer;
DWORD m_nDBufLen;
DWORD m_nEBufLen;
DWORD m_nDDataLen;
DWORD m_nEDataLen; public:
CBase64();
virtual ~CBase64(); public:
virtual PBYTE Encode(const PBYTE, DWORD);
virtual PBYTE Decode(const PBYTE, DWORD);
virtual CString Encode(LPCSTR sMessage);
virtual CString Decode(LPCSTR sMessage); virtual LPCSTR DecodedMessage() const;
virtual LPCSTR EncodedMessage() const; virtual void AlloCEncodeDlg(DWORD);
virtual void AllocDecode(DWORD);
virtual void SetEncodeBuffer(const PBYTE pBuffer, DWORD nBufLen);
virtual void SetDecodeBuffer(const PBYTE pBuffer, DWORD nBufLen); protected:
virtual void _EncodeToBuffer(const TempBucket &Decode, PBYTE pBuffer);
virtual ULONG _DecodeToBuffer(const TempBucket &Decode, PBYTE pBuffer);
virtual void _EncodeRaw(TempBucket &, const TempBucket &);
virtual void _DecodeRaw(TempBucket &, const TempBucket &);
virtual BOOL _IsBadMimeChar(BYTE); static char m_DecodeTable[256];
static BOOL m_Init;
void _Init();
};
2. 《CBase64.cpp》
// CBase64.cpp
// CBase64.cpp: implementation of the CBase64 class. //////////////////////////////////////////////////////////////////////
#include "stdAfx.h"
#include "Base64.h"
#include "DataX.h" using namespace DataX; // Digits...
static char Base64Digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; BOOL CBase64::m_Init = FALSE;
char CBase64::m_DecodeTable[256]; #ifndef PAGESIZE
#define PAGESIZE 4096
#endif #ifndef ROUNDTOPAGE
#define ROUNDTOPAGE(a) ((((a) / 4096) + 1) * 4096)
#endif //////////////////////////////////////////////////////////////////////
// Construction/Destruction
////////////////////////////////////////////////////////////////////// CBase64::CBase64()
: m_pDBuffer(NULL),
m_pEBuffer(NULL),
m_nDBufLen(0),
m_nEBufLen(0)
{ } CBase64::~CBase64()
{
if (m_pDBuffer != NULL)
{
delete [] m_pDBuffer;
} if (m_pEBuffer != NULL)
{
delete [] m_pEBuffer;
}
} LPCSTR CBase64::DecodedMessage() const
{
return (LPCSTR) m_pDBuffer;
} LPCSTR CBase64::EncodedMessage() const
{
return (LPCSTR) m_pEBuffer;
} void CBase64::AlloCEncodeDlg(DWORD nSize)
{
if (m_nEBufLen < nSize)
{
if (m_pEBuffer != NULL)
delete [] m_pEBuffer; m_nEBufLen = ROUNDTOPAGE(nSize);
m_pEBuffer = new BYTE[m_nEBufLen];
} ::ZeroMemory(m_pEBuffer, m_nEBufLen);
m_nEDataLen = 0;
} void CBase64::AllocDecode(DWORD nSize)
{
if (m_nDBufLen < nSize)
{
if (m_pDBuffer != NULL)
{
delete [] m_pDBuffer;
} m_nDBufLen = ROUNDTOPAGE(nSize);
m_pDBuffer = new BYTE[m_nDBufLen];
} ::ZeroMemory(m_pDBuffer, m_nDBufLen);
m_nDDataLen = 0;
} void CBase64::SetEncodeBuffer(const PBYTE pBuffer, DWORD nBufLen)
{
DWORD ii = 0; AlloCEncodeDlg(nBufLen);
while(ii < nBufLen)
{
if (!_IsBadMimeChar(pBuffer[ii]))
{
m_pEBuffer[m_nEDataLen] = pBuffer[ii];
m_nEDataLen ++ ;
} ii ++ ;
}
} void CBase64::SetDecodeBuffer(const PBYTE pBuffer, DWORD nBufLen)
{
AllocDecode(nBufLen);
::CopyMemory(m_pDBuffer, pBuffer, nBufLen);
m_nDDataLen = nBufLen;
} PBYTE CBase64::Encode(const PBYTE pBuffer, DWORD nBufLen)
{
SetDecodeBuffer(pBuffer, nBufLen);
AlloCEncodeDlg(nBufLen * 2); TempBucket Raw;
DWORD nIndex = 0; while((nIndex + 3) <= nBufLen)
{
Raw.Clear();
::CopyMemory(&Raw, m_pDBuffer + nIndex, 3);
Raw.nSize = 3;
_EncodeToBuffer(Raw, m_pEBuffer + m_nEDataLen);
nIndex += 3; m_nEDataLen += 4;
} if (nBufLen > nIndex)
{
Raw.Clear();
Raw.nSize = (BYTE) (nBufLen - nIndex);
::CopyMemory(&Raw, m_pDBuffer + nIndex, nBufLen - nIndex);
_EncodeToBuffer(Raw, m_pEBuffer + m_nEDataLen);
m_nEDataLen += 4;
} return m_pEBuffer;
} CString CBase64::Encode(LPCSTR szMessage)
{
CString strHex = _T("");
if (szMessage != NULL)
{
CBase64::Encode((const PBYTE)szMessage, lstrlenA(szMessage));
if (m_nEDataLen > 0)
{
AscToHex(m_pEBuffer, m_nEDataLen, strHex);
}
} return strHex;
} PBYTE CBase64::Decode(const PBYTE pBuffer, DWORD dwBufLen)
{
if (!CBase64::m_Init)
_Init(); SetEncodeBuffer(pBuffer, dwBufLen); AllocDecode(dwBufLen); TempBucket Raw; DWORD nIndex = 0; while((nIndex + 4) <= m_nEDataLen)
{
Raw.Clear();
Raw.nData[0] = CBase64::m_DecodeTable[m_pEBuffer[nIndex]];
Raw.nData[1] = CBase64::m_DecodeTable[m_pEBuffer[nIndex + 1]];
Raw.nData[2] = CBase64::m_DecodeTable[m_pEBuffer[nIndex + 2]]; Raw.nData[3] = CBase64::m_DecodeTable[m_pEBuffer[nIndex + 3]]; if (Raw.nData[2] == 255)
Raw.nData[2] = 0;
if (Raw.nData[3] == 255)
Raw.nData[3] = 0; Raw.nSize = 4;
_DecodeToBuffer(Raw, m_pDBuffer + m_nDDataLen);
nIndex += 4;
m_nDDataLen += 3;
} // If nIndex < m_nEDataLen, then we got a decode message without padding.
// We may want to throw some kind of warning here, but we are still required
// to handle the decoding as if it was properly padded.
if (nIndex < m_nEDataLen)
{
Raw.Clear();
for(DWORD ii = nIndex; ii < m_nEDataLen; ii ++ )
{
Raw.nData[ii - nIndex] = CBase64::m_DecodeTable[m_pEBuffer[ii]];
Raw.nSize ++ ;
if (Raw.nData[ii - nIndex] == 255)
Raw.nData[ii - nIndex] = 0;
} _DecodeToBuffer(Raw, m_pDBuffer + m_nDDataLen);
m_nDDataLen += (m_nEDataLen - nIndex);
} return m_pDBuffer;
} CString CBase64::Decode(LPCSTR pszMessage)
{
if (!pszMessage)
{
return _T("");
} CBase64::Decode((const PBYTE)pszMessage, lstrlenA(pszMessage));
CString strHex = _T("");
if (m_nDDataLen > 0)
{
AscToHex(m_pDBuffer, m_nDDataLen, strHex);
} return strHex; } DWORD CBase64::_DecodeToBuffer(const TempBucket &Decode, PBYTE pBuffer)
{
TempBucket Data;
DWORD nCount = 0; _DecodeRaw(Data, Decode); for(int ii = 0; ii < 3; ii ++ )
{
pBuffer[ii] = Data.nData[ii];
if (pBuffer[ii] != 255)
nCount ++ ;
} return nCount;
} void CBase64::_EncodeToBuffer(const TempBucket &Decode, PBYTE pBuffer)
{
TempBucket Data; _EncodeRaw(Data, Decode); for(int ii = 0; ii < 4; ii ++ )
pBuffer[ii] = Base64Digits[Data.nData[ii]]; switch(Decode.nSize)
{
case 1:
pBuffer[2] = '='; case 2:
pBuffer[3] = '=';
}
} void CBase64::_DecodeRaw(TempBucket &Data, const TempBucket &Decode)
{
BYTE nTemp; Data.nData[0] = Decode.nData[0];
Data.nData[0] <<= 2; nTemp = Decode.nData[1];
nTemp >>= 4;
nTemp &= 0x03;
Data.nData[0] |= nTemp; Data.nData[1] = Decode.nData[1];
Data.nData[1] <<= 4; nTemp = Decode.nData[2];
nTemp >>= 2;
nTemp &= 0x0F;
Data.nData[1] |= nTemp; Data.nData[2] = Decode.nData[2];
Data.nData[2] <<= 6;
nTemp = Decode.nData[3];
nTemp &= 0x3F;
Data.nData[2] |= nTemp;
} void CBase64::_EncodeRaw(TempBucket &Data, const TempBucket &Decode)
{
BYTE nTemp; Data.nData[0] = Decode.nData[0];
Data.nData[0] >>= 2; Data.nData[1] = Decode.nData[0];
Data.nData[1] <<= 4;
nTemp = Decode.nData[1];
nTemp >>= 4;
Data.nData[1] |= nTemp;
Data.nData[1] &= 0x3F; Data.nData[2] = Decode.nData[1];
Data.nData[2] <<= 2; nTemp = Decode.nData[2];
nTemp >>= 6; Data.nData[2] |= nTemp;
Data.nData[2] &= 0x3F; Data.nData[3] = Decode.nData[2];
Data.nData[3] &= 0x3F;
} BOOL CBase64::_IsBadMimeChar(BYTE nData)
{
switch(nData)
{
case '\r': case '\n': case '\t': case ' ' :
case '\b': case '\a': case '\f': case '\v':
return TRUE; default:
return FALSE;
}
} void CBase64::_Init()
{
// Initialize Decoding table.
int ii; for(ii = 0; ii < 256; ii ++ )
CBase64::m_DecodeTable[ii] = -2; for(ii = 0; ii < 64; ii ++ )
{
CBase64::m_DecodeTable[Base64Digits[ii]] = (CHAR)ii;
CBase64::m_DecodeTable[Base64Digits[ii]|0x80] = (CHAR)ii;
} CBase64::m_DecodeTable['='] = -1; CBase64::m_DecodeTable['='|0x80] = -1; CBase64::m_Init = TRUE;
}
文/yanxin8原创,获取更多信息请访问http://yanxin8.com/277.html
算法系列8《Base64》的更多相关文章
- 1.Java 加解密技术系列之 BASE64
Java 加解密技术系列之 BASE64 序号 背景 正文 总结 序 这段时间,工作中 用到了 Java 的加解密技术,本着学习的态度,打算从这篇文章开始,详细的研究一番 Java 在加解密技术上有什 ...
- JAVA算法系列 冒泡排序
java算法系列之排序 手写冒泡 冒泡算是最基础的一个排序算法,简单的可以理解为,每一趟都拿i与i+1进行比较,两个for循环,时间复杂度为 O(n^2),同时本例与选择排序进行了比较,选择排序又叫直 ...
- JAVA算法系列 快速排序
java算法系列之排序 手写快排 首先说一下什么是快排,比冒泡效率要高,快排的基本思路是首先找到一个基准元素,比如数组中最左边的那个位置,作为基准元素key,之后在最左边和最右边设立两个哨兵,i 和 ...
- javascript实现数据结构与算法系列:栈 -- 顺序存储表示和链式表示及示例
栈(Stack)是限定仅在表尾进行插入或删除操作的线性表.表尾为栈顶(top),表头为栈底(bottom),不含元素的空表为空栈. 栈又称为后进先出(last in first out)的线性表. 堆 ...
- 三白话经典算法系列 Shell排序实现
山是包插入的精髓排序排序,这种方法,也被称为窄增量排序.因为DL.Shell至1959提出命名. 该方法的基本思想是:先将整个待排元素序列切割成若干个子序列(由相隔某个"增量"的元 ...
- Atitit s2018.6 s6 doc list on com pc.docx Atitit s2018.6 s6 doc list on com pc.docx Aitit algo fix 算法系列补充.docx Atiitt 兼容性提示的艺术 attilax总结.docx Atitit 应用程序容器化总结 v2 s66.docx Atitit file cms api
Atitit s2018.6 s6 doc list on com pc.docx Atitit s2018.6 s6 doc list on com pc.docx Aitit algo fi ...
- 【C#实现漫画算法系列】-判断 2 的乘方
微信上关注了算法爱好者这个公众号,有一个漫画算法系列的文章生动形象,感觉特别好,给大家推荐一下(没收过广告费哦),原文链接:漫画算法系列.也看到了许多同学用不同的语言来实现算法,作为一枚C#资深爱好的 ...
- 玩转算法系列--图论精讲 面试升职必备(Java版)
第1章 和bobo老师一起,玩转图论算法欢迎大家来到我的新课程:<玩转图论算法>.在这个课程中,我们将一起完整学习图论领域的经典算法,培养大家的图论建模能力.通过这个课程的学习,你将能够真 ...
- 数据结构与算法系列——排序(4)_Shell希尔排序
1. 工作原理(定义) 希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本.但希尔排序是非稳定排序算法. 希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入 ...
- 编程作业1.1——sklearn机器学习算法系列之LinearRegression线性回归
知识点 scikit-learn 对于线性回归提供了比较多的类库,这些类库都可以用来做线性回归分析. 我们也可以使用scikit-learn的线性回归函数,而不是从头开始实现这些算法. 我们将scik ...
随机推荐
- BZOJ1407_NOI2002_荒岛野人_Savage_C++
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1407 题解:http://www.cnblogs.com/hadilo/p/5951091.h ...
- Orchard官方文档翻译(十) 管理Widgets
原文地址:http://docs.orchardproject.net/Documentation/Managing-widgets 想要查看文档目录请用力点击这里 最近想要学习了解orchard,但 ...
- Flex4 DataGrid实现可复制单元格,同时解决自定义GridItemRenderer出现1009错误的方法
原创内容,如需转载,请注明出处,谢谢 最近在项目中发现Flex的DataGrid不支持内容复制,在涉及到保护敏感数据时倒是很有用处,但大部分情况下,我们还是希望客户能够直接复制DataGrid单元格中 ...
- 【练习】手工生成awr报告
①首先进入$ORACLE_HOME/rdbms/admin目录 [oracle@host02 ~]$ cd $ORACLE_HOME/rdbms/admin 该目录下 [oracle@host02 a ...
- matlab读取txt文档中的数据
ps:文件中只有数字! format long fp=fopen('文件路径','打开方式(r)') [num,count]=fscnaf(fp,'%f')
- 洛谷P1828 香甜的黄油 Sweet Butter
P1828 香甜的黄油 Sweet Butter 241通过 724提交 题目提供者JOHNKRAM 标签USACO 难度普及+/提高 提交 讨论 题解 最新讨论 我的SPFA为什么TLE.. 为 ...
- DNS协议 实践
根据DNS协议发送UDP请求,然后获取IP地址 头文件: #ifndef __DNS__ #define __DNS__ #include <stdio.h> #include <s ...
- meta基础知识
H5页面窗口自动调整到设备宽度,并禁止用户缩放页面 <meta name="viewport" content="width=device-width,initia ...
- WP_从独立存储区读取缓存的图片
///<summary> /// 独立存储缓存的图片源 /// 用法:item.img = new StorageCachedImage(newUri(http://www.baidu ...
- Linux:一台apache服务器上部署多个项目的apache配置
第一步: 将代码取到/var/www/html目录下(此为默认目录,具体看apache的设置):该目录下可以放多个项目,如: [root@www html]# pwd/var/www/html[roo ...