base64的C++实现
来源:互联网 发布:李炎恢js视频教程下载 编辑:程序博客网 时间:2024/05/20 16:13
base64简介
base64网络上已经有很多人有讲述,下面摘录wiki上的简述:
Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于2的6次方等于64,所以每6个比特为一个单元,对应某个可打印字符。三个字节有24个比特,对应于4个Base64单元,即3个字节可表示4个可打印字符。它可用来作为电子邮件的传输编码。在Base64中的可打印字符包括字母A-Z、a-z、数字0-9,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。
在MIME格式的电子邮件中,base64可以用来将binary的字节序列数据编码成ASCII字符序列构成的文本。使用时,在传输编码方式中指定base64。使用的字符包括大小写字母各26个,加上10个数字,和加号“+”,斜杠“/”,一共64个字符,等号“=”用来作为后缀用途。
完整的base64定义可见RFC 1421和RFC 2045。编码后的数据比原始数据略长,为原来的4/3。在电子邮件中,根据RFC 822规定,每76个字符,还需要加上一个回车换行。可以估算编码后数据长度大约为原长的135.1%。转换的时候,将三个byte的数据,先后放入一个24bit的缓冲区中,先来的byte占高位。数据不足3byte的话,于缓冲器中剩下的bit用0补足。然后,每次取出6(因为26=64)个bit,按照其值选择ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/中的字符作为编码后的输出。不断进行,直到全部输入数据转换完成。当原数据长度不是3的整数倍时, 如果最后剩下一个输入数据,在编码结果后加2个“=”;如果最后剩下两个输入数据,编码结果后加1个“=”;如果没有剩下任何数据,就什么都不要加,这样才可以保证数据还原的正确性。
完整的base64说明可以参考wiki_base64
本文中主要陈述的是base64编码的一种C++代码实现。
base64_operation.h
先列出实现的API的声明头文件:
#ifndef _BASE64_OPERATION_H_#define _BASE64_OPERATION_H_#include <iostream>#include <stdio.h>typedef enum { E_BASH64_OK = 0, E_BASH64_ERROR_PARAM, E_BASH64_FILE_ERROR, E_BASH64_BUFFER_OVERFLOW, E_BASH64_ERROR_USUAL}BASE64_RESULT;class Base64_Operation{public: /** * [base64_GetInstance Get the object pointer] * @return [the object pointer] */ static Base64_Operation* base64_GetInstance(void); Base64_Operation(); ~Base64_Operation(); /** * [base64_file_encode Ecode a file to base64 format file] * @param pInFile [The input file pointer from fopen(), must be opened with "rb"] * @param pOutFile [The output file pointer from fopen(), must be opened with "wb+"] * @return [The error code] */ BASE64_RESULT base64_file_encode(FILE* pInFile, FILE* pOutFile); /** * [base64_file_decode decode a file from base64 format file] * @param pInFile [The input file pointer from fopen(), must be opened with "rb"] * @param pOutFile [The output file pointer from fopen(), must be opened with "wb+"] * @return [The error code] */ BASE64_RESULT base64_file_decode(FILE* pInFile, FILE* pOutFile); /** * [base64_hex_encode Encode a buffer data to base64 format] * @param pInBuffer [The normal data buffer] * @param InBufferLen [The normal data length] * @param pOutBuffer [The output buffer] * @param pOutBufferLen [The output buffer of base64 length] * @return [The error code] */ BASE64_RESULT base64_hex_encode(char* pInBuffer, unsigned int InBufferLen, char *pOutBuffer,unsigned int *pOutBufferLen); /** * [base64_hex_decode decode a buffer data from base64 format] * @param pInBuffer [The base64 format buffer] * @param InBufferLen [The base64 buffer length] * @param pOutBuffer [The output buffer pointer] * @param pOutBufferLen [The output buffer length] * @return [The error code] */ BASE64_RESULT base64_hex_decode(char* pInBuffer, unsigned int InBufferLen, char *pOutBuffer,unsigned int *pOutBufferLen); protected:private: static Base64_Operation* Instance; static void _initDecTable(void); static unsigned int _singleGroupDecode(char* inBuffer, char* outBuffer); static void _singleGroupEncode(char* inBuffer, char* outBuffer);};#endif
主要有实现基于用户buffer的base64的编码与解码(支持小于unsigned int所能表示的最大长度);实现了文件的base64的编码与解码。另外base64完整规范有要求每隔76bytes需要有换行,本实现没有考虑这种要求,鄙人认为用户自己在编码的base64上按自己的需求去增加换行符应该会更好;
base64_operation.cpp
#include "base64_operation.h"#include <stdio.h>#include <stdlib.h>#include <string.h>using std::cout;using std::cin;using std::endl;using std::hex;#define DECTABLE_LEN 123#define EQUAL_SIGN_MAGIC 0xFF#define FILE_BUFFER_LEN 0x200000#define FILE_OUTTMP_LEN 0x300000#define OPEN_DBG 0Base64_Operation* Base64_Operation::Instance = NULL;static const char base64Char[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";static unsigned char charDecTable[DECTABLE_LEN+1];void Base64_Operation::_initDecTable(){ int index = 0; memset(charDecTable, 0x0, DECTABLE_LEN); for(index = 'A'; index <= 'Z';index++) { charDecTable[index] = index - 'A'; } for(index = 'a'; index <= 'z';index++) { charDecTable[index] = index - 'a' + 26; } for(index = '0'; index <= '9';index++) { charDecTable[index] = index - '0' + 52; } charDecTable['+'] = 62; charDecTable['/'] = 63; charDecTable['='] = EQUAL_SIGN_MAGIC;}void Base64_Operation::_singleGroupEncode(char* inBuffer, char* outBuffer){ unsigned int order; order = (inBuffer[0]&0xFC)>>2; outBuffer[0] = base64Char[order];#if OPEN_DBG cout<<order<<endl; cout<<outBuffer[0]<<endl;#endif order = ((inBuffer[0]&0x3)<<4)|((inBuffer[1]&0xF0)>>4); outBuffer[1] = base64Char[order];#if OPEN_DBG cout<<order<<endl; cout<<outBuffer[1]<<endl;#endif order = ((inBuffer[1]&0xF)<<2)|((inBuffer[2]&0xC0)>>6); outBuffer[2] = base64Char[order];#if OPEN_DBG cout<<order<<endl; cout<<outBuffer[2]<<endl;#endif order = inBuffer[2]&0x3F; outBuffer[3] = base64Char[order];#if OPEN_DBG cout<<order<<endl; cout<<outBuffer[3]<<endl;#endif}unsigned int Base64_Operation::_singleGroupDecode(char* inBuffer, char* outBuffer){ unsigned int resLen = 0; unsigned char value[4]; unsigned int index = 0;#if 1 for(index = 0;index<4;index++) { if((inBuffer[index]>= 'A') && (inBuffer[index]<='Z')) { } else if((inBuffer[index] >= 'a') && (inBuffer[index]<='z')) { } else if((inBuffer[index] >= '0') && (inBuffer[index]<='9')) { } else if((inBuffer[index] == '+') || (inBuffer[index] == '/')) { } else if(inBuffer[index] == '=') { if(index<=1) return resLen; } else { return resLen; } }#endif value[0] = charDecTable[(unsigned char)inBuffer[0]]; value[1] = charDecTable[(unsigned char)inBuffer[1]]; value[2] = charDecTable[(unsigned char)inBuffer[2]]; value[3] = charDecTable[(unsigned char)inBuffer[3]]; if((value[2] == EQUAL_SIGN_MAGIC) && (value[3] == EQUAL_SIGN_MAGIC)) { resLen = 1; outBuffer[0] = ((value[0]&0x3F)<<2) | ((value[1]&0x30)>>4); } else if(value[3] == EQUAL_SIGN_MAGIC) { resLen = 2; outBuffer[0] = ((value[0]&0x3F)<<2) | ((value[1]&0x30)>>4); outBuffer[1] = ((value[1]&0x0F)<<4) | ((value[2]&0x3C)>>2); } else { resLen = 3; outBuffer[0] = ((value[0]&0x3F)<<2) | ((value[1]&0x30)>>4); outBuffer[1] = ((value[1]&0x0F)<<4) | ((value[2]&0x3C)>>2); outBuffer[2] = ((value[2]&0x03)<<6) | (value[3]&0x3F); } return resLen;}Base64_Operation *Base64_Operation::base64_GetInstance(){ if(Instance == NULL) { Instance = new Base64_Operation(); Instance->_initDecTable();#if OPEN_DBG int index = 0; for(index = 0; index<=DECTABLE_LEN; index++) { cout<<index<<": "<<charDecTable[index]<<endl; }#endif } return Instance;}Base64_Operation::Base64_Operation(){ cout<<"Create a base64 object"<<endl;}Base64_Operation::~Base64_Operation(){ cout<<"Destroy a base64 object"<<endl; Instance = NULL;}BASE64_RESULT Base64_Operation::base64_file_encode(FILE* pInFile, FILE* pOutFile){ if(pInFile == NULL || pOutFile == NULL) { cout<<__FUNCTION__<<" "<<__LINE__<<" The file pointer can't be NULL"<<endl; return E_BASH64_FILE_ERROR; } unsigned int readLen = 0; unsigned int outBufferLen = 0; //The hexadecimal digit:0x1FFFFE can be devided by 3; char *tmpBuffer = new char[0x1FFFFE]; if(tmpBuffer == NULL) { return E_BASH64_BUFFER_OVERFLOW; } char *outBuffer = new char[FILE_OUTTMP_LEN]; if(outBuffer == NULL) { delete []tmpBuffer; return E_BASH64_BUFFER_OVERFLOW; } do { memset(tmpBuffer,0x00, 0x1FFFFE); readLen = fread(tmpBuffer, 1, 0x1FFFFE, pInFile); if(E_BASH64_OK == (this->base64_hex_encode(tmpBuffer, readLen, outBuffer, &outBufferLen))) { if(fwrite(outBuffer, outBufferLen, 1, pOutFile)!=1) { cout<<__FUNCTION__<<" write file error!"<<endl; delete []tmpBuffer; delete []outBuffer; return E_BASH64_FILE_ERROR; } } else { cout<<__FUNCTION__<<" encode base64 failed!"<<endl; delete []tmpBuffer; delete []outBuffer; return E_BASH64_ERROR_USUAL; } }while(readLen==0x1FFFFE); delete []tmpBuffer; delete []outBuffer; return E_BASH64_OK;}BASE64_RESULT Base64_Operation::base64_file_decode(FILE* pInFile, FILE* pOutFile){ if(pInFile == NULL || pOutFile == NULL) { cout<<__FUNCTION__<<" "<<__LINE__<<" The file pointer can't be NULL"<<endl; return E_BASH64_FILE_ERROR; } unsigned int readLen = 0; unsigned int outBufferLen = 0; char *tmpBuffer = new char[FILE_BUFFER_LEN]; if(tmpBuffer == NULL) { return E_BASH64_BUFFER_OVERFLOW; } char *outBuffer = new char[FILE_OUTTMP_LEN]; if(outBuffer == NULL) { delete []tmpBuffer; return E_BASH64_BUFFER_OVERFLOW; } do { memset(tmpBuffer,0x00, FILE_BUFFER_LEN); readLen = fread(tmpBuffer, 1, FILE_BUFFER_LEN, pInFile); if(E_BASH64_OK == (this->base64_hex_decode(tmpBuffer, readLen, outBuffer, &outBufferLen))) { if(fwrite(outBuffer, outBufferLen, 1, pOutFile)!=1) { cout<<__FUNCTION__<<" write file error!"<<endl; delete []tmpBuffer; delete []outBuffer; return E_BASH64_FILE_ERROR; } } else { cout<<__FUNCTION__<<" decode base64 failed!"<<endl; delete []tmpBuffer; delete []outBuffer; return E_BASH64_ERROR_USUAL; } }while(readLen==FILE_BUFFER_LEN); delete []tmpBuffer; delete []outBuffer; return E_BASH64_OK;}BASE64_RESULT Base64_Operation::base64_hex_encode(char* pInBuffer,unsigned int InBufferLen, char *pOutBuffer, unsigned int *pOutBufferLen){ if(pInBuffer == NULL || pOutBuffer == NULL || pOutBufferLen == NULL) { cout<<__FUNCTION__<<" "<<"The buffer can't be NULL"<<endl; return E_BASH64_ERROR_PARAM; } char *pRunInBuffer = pInBuffer; char *pRunOutBuffer = pOutBuffer; char withoutEnc[3]; char withEnc[4]; unsigned int order = 0; *pOutBufferLen = 0; if(InBufferLen >= 3) { do { memcpy(withoutEnc, pRunInBuffer, 3); this->_singleGroupEncode(withoutEnc, withEnc); memcpy(pRunOutBuffer, withEnc, 4); pRunOutBuffer = pRunOutBuffer + 4; *pOutBufferLen = *pOutBufferLen + 4; InBufferLen = InBufferLen-3; pRunInBuffer = pRunInBuffer+3; }while(InBufferLen>=3); } if(InBufferLen == 2) { order = (pRunInBuffer[0]&0xFC)>>2; pRunOutBuffer[0] = base64Char[order]; order = ((pRunInBuffer[0]&0x3)<<4) | ((pRunInBuffer[1]&0xF0)>>4); pRunOutBuffer[1] = base64Char[order]; order = (pRunInBuffer[1]&0xF)<<2; pRunOutBuffer[2] = base64Char[order]; pRunOutBuffer[3] = '='; *pOutBufferLen = *pOutBufferLen + 4; } else if(InBufferLen == 1) { order = (pRunInBuffer[0]&0xFC)>>2; pRunOutBuffer[0] = base64Char[order]; order = (pRunInBuffer[0]&0x3)<<4; pRunOutBuffer[1] = base64Char[order]; pRunOutBuffer[2] = '='; pRunOutBuffer[3] = '='; *pOutBufferLen = *pOutBufferLen + 4; } return E_BASH64_OK; }BASE64_RESULT Base64_Operation::base64_hex_decode(char* pInBuffer, unsigned int InBufferLen, char *pOutBuffer, unsigned int *pOutBufferLen){ if(pInBuffer == NULL || pOutBuffer == NULL || pOutBufferLen == NULL) { cout<<__FUNCTION__<<" "<<"The buffer can't be NULL"<<endl; return E_BASH64_ERROR_PARAM; } if(InBufferLen%4) { cout<<__FUNCTION__<<" "<<"The inBufferLen must be devided by 4"<<endl; return E_BASH64_ERROR_PARAM; } char *pRunInBuffer = pInBuffer; char *pRunOutBuffer = pOutBuffer; char withoutEnc[3]; char withEnc[4]; unsigned int resLen = 0; *pOutBufferLen = 0;// cout<<__FUNCTION__<<" "<<__LINE__<<endl; while((InBufferLen/4)) { memcpy(withEnc, pRunInBuffer, 4); resLen = this->_singleGroupDecode(withEnc, withoutEnc); memcpy(pRunOutBuffer, withoutEnc, resLen); // cout<<__FUNCTION__<<" "<<__LINE__<<endl; if((resLen<3) && (InBufferLen>4)) { cout<<__FUNCTION__<<" wrong input string for decode!"<<endl; return E_BASH64_ERROR_USUAL; } else if(resLen == 0) { cout<<__FUNCTION__<<" error base64 string!"<<endl; return E_BASH64_ERROR_USUAL; } InBufferLen = InBufferLen-4; pRunInBuffer = pRunInBuffer+4; pRunOutBuffer = pRunOutBuffer+resLen; *pOutBufferLen = *pOutBufferLen+resLen; } return E_BASH64_OK;}
这是base64编码与解码的具体实现;
base64_main.cpp
#include <iostream>#include <stdio.h>#include <string.h>#include "base64_operation.h"using std::cin;using std::cout;using std::endl;using std::hex;#define TEST_FILEIN "./test_fileIn.bin"#define TEST_FILEOUT "./test_fileOut.bin"#define TEST_DECOUT "./test_dec.bin"int main(int argc, char* argv[]){ FILE* pInFile = NULL; FILE* pOutFile = NULL; char *pOutBuffer = new char[100]; unsigned int outBufferLen = 0; BASE64_RESULT eRet = E_BASH64_ERROR_USUAL; Base64_Operation* pBase64 = Base64_Operation::base64_GetInstance(); if(pBase64 == NULL) { cout<<__FUNCTION__<<"Get base64 instance failed!"<<endl; goto DESTROY; } //memset(pOutBuffer, '\0', 100); eRet = pBase64->base64_hex_encode((char*)"s13sdfasdf*we", 13, pOutBuffer, &outBufferLen); if(eRet == E_BASH64_OK) { cout<<"outBufferLen is: "<<outBufferLen<<endl; cout<<pOutBuffer<<endl; // delete []pOutBuffer; // goto DESTROY; } memset(pOutBuffer, '\0', 100); eRet = pBase64->base64_hex_decode((char*)"czEzc2RmYXNkZip3ZQ==",0x14, pOutBuffer, &outBufferLen); if(eRet == E_BASH64_OK) { cout<<"outBufferLen is: "<<outBufferLen<<endl; cout<<pOutBuffer<<endl; // goto DESTROY; } if((pInFile=fopen((const char*)TEST_FILEIN, "rb")) == NULL) { cout<<"source file open failed!"<<endl; return -1; } if((pOutFile=fopen((const char*)TEST_FILEOUT, "wb+")) == NULL) { cout<<"output file open failed!"<<endl; return -1; } eRet = pBase64->base64_file_encode(pInFile, pOutFile); if(eRet == E_BASH64_OK) { cout<<"file encode successfully!"<<endl; fclose(pInFile); fclose(pOutFile); pInFile = NULL; pOutFile = NULL; } if((pInFile=fopen((const char*)TEST_FILEOUT, "rb")) == NULL) { cout<<"source file open failed!"<<endl; return -1; } if((pOutFile=fopen((const char*)TEST_DECOUT, "wb+")) == NULL) { cout<<"output file open failed!"<<endl; return -1; } eRet = pBase64->base64_file_decode(pInFile, pOutFile); if(eRet == E_BASH64_OK) { cout<<"file dec successfully!"<<endl; fclose(pInFile); fclose(pOutFile); pInFile = NULL; pOutFile = NULL; }DESTROY: if(pBase64 != NULL) { delete pBase64; pBase64 = NULL; } return 0;}
这是对应的测试函数,可在linux有g++环境下如果编译测试:
g++ base64_main.cpp base64_operaion.cpp -o base64
然后运行:
./base64
正常情况下会有下面打印输出:
Create a base64 objectoutBufferLen is: 20czEzc2RmYXNkZip3ZQ==outBufferLen is: 13s13sdfasdf*wefile encode successfully!file dec successfully!Destroy a base64 object
- Base64的 c实现
- base64编码解码的实现(C语言)
- base64编码解码的实现(C语言)
- 实现base64编码的C代码
- Base64编码解码的实现(C语言)
- BASE64解码的c语言实现
- C语言实现的Base64码
- Base64编码解码的实现(C语言)
- c语言Base64算法的实现
- base64编码、解码的C语言实现
- Base64 编解码的C语言实现
- Base64编解码的C语言实现
- base64编码、解码的C语言实现
- BASE64编码and解码的C实现
- base64编码、解码的C语言实现
- Base64编码的C语言实现
- base64编码、解码的C语言实现
- BASE64编码、解码的C语言实现
- Linux基础知识
- 第三周 项目2
- Coroutines in C(by Simon Tatham)
- Python List使用的简单心得
- 第三周 项目一 顺序表的基本运算
- base64的C++实现
- p2469,[sdoi2010]星际竞速
- 小结
- 【大话数据结构】01 数据结构的绪论 笔记
- hive array、map、struct使用
- (面试题)创建子类时会调用父类的构造方法
- spring @component的作用
- bzoj 2666: [cqoi2012]组装 贪心
- Android——OnItemSelectedListener事件与二级联动