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. 1.Java 加解密技术系列之 BASE64

    Java 加解密技术系列之 BASE64 序号 背景 正文 总结 序 这段时间,工作中 用到了 Java 的加解密技术,本着学习的态度,打算从这篇文章开始,详细的研究一番 Java 在加解密技术上有什 ...

  2. JAVA算法系列 冒泡排序

    java算法系列之排序 手写冒泡 冒泡算是最基础的一个排序算法,简单的可以理解为,每一趟都拿i与i+1进行比较,两个for循环,时间复杂度为 O(n^2),同时本例与选择排序进行了比较,选择排序又叫直 ...

  3. JAVA算法系列 快速排序

    java算法系列之排序 手写快排 首先说一下什么是快排,比冒泡效率要高,快排的基本思路是首先找到一个基准元素,比如数组中最左边的那个位置,作为基准元素key,之后在最左边和最右边设立两个哨兵,i 和 ...

  4. javascript实现数据结构与算法系列:栈 -- 顺序存储表示和链式表示及示例

    栈(Stack)是限定仅在表尾进行插入或删除操作的线性表.表尾为栈顶(top),表头为栈底(bottom),不含元素的空表为空栈. 栈又称为后进先出(last in first out)的线性表. 堆 ...

  5. 三白话经典算法系列 Shell排序实现

    山是包插入的精髓排序排序,这种方法,也被称为窄增量排序.因为DL.Shell至1959提出命名. 该方法的基本思想是:先将整个待排元素序列切割成若干个子序列(由相隔某个"增量"的元 ...

  6. 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 ...

  7. 【C#实现漫画算法系列】-判断 2 的乘方

    微信上关注了算法爱好者这个公众号,有一个漫画算法系列的文章生动形象,感觉特别好,给大家推荐一下(没收过广告费哦),原文链接:漫画算法系列.也看到了许多同学用不同的语言来实现算法,作为一枚C#资深爱好的 ...

  8. 玩转算法系列--图论精讲 面试升职必备(Java版)

    第1章 和bobo老师一起,玩转图论算法欢迎大家来到我的新课程:<玩转图论算法>.在这个课程中,我们将一起完整学习图论领域的经典算法,培养大家的图论建模能力.通过这个课程的学习,你将能够真 ...

  9. 数据结构与算法系列——排序(4)_Shell希尔排序

    1. 工作原理(定义) 希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本.但希尔排序是非稳定排序算法. 希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入 ...

  10. 编程作业1.1——sklearn机器学习算法系列之LinearRegression线性回归

    知识点 scikit-learn 对于线性回归提供了比较多的类库,这些类库都可以用来做线性回归分析. 我们也可以使用scikit-learn的线性回归函数,而不是从头开始实现这些算法. 我们将scik ...

随机推荐

  1. 2016阿里巴巴校招offer面经

    前段时间参加阿里巴巴校招,非常荣幸,很快就拿到了offer,经历了三轮技术面试和一轮hr面,面试官们都非常nice,在此感谢一下各位面试官,你们辛苦了,百忙之中抽时间面试!为了帮助更多人想进阿里巴巴的 ...

  2. 挣值管理(EVT)

    如果你对项目管理.系统架构有兴趣,请加微信订阅号"softjg",加入这个PM.架构师的大家庭 第二个大计算,根据PV.EV.AC计算出CV.SV.SPI.CPI.ETC.EAC. ...

  3. ionic ngcordova camera

    拍照是經常用到的,所以記錄一下 拍照的代碼... 1. ionic start camera blankcd camera ionic platform add ios 2. 添加插件,這裏很熟悉.. ...

  4. postgresql安装配置

    一,什么是postgresql PostgreSQL是以加州大学伯克利分校计算机系开发的 POSTGRES 版本 4.2 为基础的对象关系型数据库管理系统(ORDBMS),简称pgsql,它支持大部分 ...

  5. pxecfg&kickstart生成脚本

    em tm 00:00:00:00:00:12 10.180.1.12 255.255.255.0 173.45.34.25 255.255.255.225 173.45.34.1 em tm 00: ...

  6. gulp.spritesmith修改px为rem单位

    移动端开发中,使用gulp.spritesmith进行小图sprite并生成样式,但由于spritesmith默认是以px为单位,所以就把插件的内容修改了下让生成rem单位并且能把background ...

  7. solr5.5教程-solrconfig.xml,加载schema.xml

    布署完成后,接下来要更深入的研究solr的原理和使用. 首先进入testcore这个文件夹下面,发现这个core的conf里并没有schema.xml.那么数据格式是在哪里定义的呢? 打开 solr_ ...

  8. ASP.NET-----Repeater数据控件的用法总结(转)

    一.Repeater控件的用法流程及实例: 1.首先建立一个网站,新建一个网页index.aspx. 2.添加或者建立APP_Data数据文件,然后将用到的数据库文件放到APP_Data文件夹中. 3 ...

  9. JavaScript中的Get和Set访问器

    今天要和大家分享的是JavaScript中的Get和Set访问器,和C#中的访问器非常相似. 标准的Get和Set访问器的实现   function Field(val){       this.va ...

  10. Solaris的vi

    进入输入模式i: 在光标之前插入a: 在光标之后插入o: 在下面新建一行输入I: 光标移动到本行首插入A: 光标移动到本行末尾插入O: 在上面新建一行输入 移动光标M:移到屏幕中间一行的行首L:移到屏 ...