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