算法系列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 ...
随机推荐
- Android开发-API指南-数据存储
Storage Options 英文原文:http://developer.android.com/guide/topics/data/data-storage.html 采集日期:2015-02-0 ...
- Android开发-API指南-Content Provider
Content Providers 英文原文:http://developer.android.com/guide/topics/providers/content-providers.html 采集 ...
- 【LeetCode】21. Merge Two Sorted Lists
题目: Merge two sorted linked lists and return it as a new list. The new list should be made by splici ...
- 【程序与资源】linux程序与资源管理
程序与资源管理:ps.top.free.sar.kill.uname ①ps语法: [root @test /root ]# ps -aux 参数说明: a :选择所有的程序列出 u :所有使 ...
- vimdiff vimmerge 配置及使用
1 Set up vimdiff The vimdiff as a merge tool will display several buffers to show the yours/theirs/o ...
- webview渲染流程
文档标记说明 ################# 消息边界 +++++++++++++++++ 区域分隔 $$$$$$$$$$$$$$$$$ 线程边界 ~~~~~~~~~~~~~~~~~ 进程边界 - ...
- Java学习一
Java程序的运行机制和JVM JVM(java 虚拟机) Java Virtual Machine java语言比较特殊,由Java语言编写的程序需要经过编译步骤, JDK java SE ...
- Android书籍资源汇总
之前一直在Linux下使用C++做服务器端的开发工作,对Android关于移动方面的开发了解较少,现将android开发方面的书籍与资源整理如下,方便后续的查阅. 19本Android开发书籍 7本A ...
- Oracle笔记 十三、PL/SQL面向对象之package
--将方法和过程用包定义 create or replace package pkg_emp as --输入员工编号查询出员工信息 procedure pro_findInfo( in_empno e ...
- UITextView如何关闭键盘
UITextField可以响应键盘上的完成按钮,关闭键盘,而UITextView不一样,它的return按钮或者Done按钮执行的是换行功能,不能达到关闭键盘的目的.解决方法有两个:一个是通过捕捉to ...