编程技术记录

世界你好!

#pragma once

//从ATL的base64库整理而来
//整理的目的是提供一个仅基于标准c++的base64库,提高代码的可移植性
#include <string>

namespace Crypt
{

class Base64
{
public:
    enum Base64_Flag
    {
        ATL_BASE64_FLAG_NONE = 0, // 0000 0000  标准的编码方式(RFC2045)
        ATL_BASE64_FLAG_NOPAD = 1 , // 0000 0001  没有补全( = )
        ATL_BASE64_FLAG_NOCRLF = 2 // 0000 0010   没有换行 ( crlf )
    } ;

    //计算编码后的长度
    static int EncodeGetRequiredLength(int nSrcLen, Base64_Flag dwFlags = ATL_BASE64_FLAG_NONE)
    {
        int nRet = static_cast<int>( (nSrcLen<<2) /3);

        if ((dwFlags & ATL_BASE64_FLAG_NOPAD) == 0)// 需要补全 =
            nRet += nSrcLen % 3;

        int nOnLastLine = nRet % 76;
        if (nOnLastLine)
        {
            if (  (nOnLastLine & 0x03)  ) //nOnLastLine % 4
                nRet += 4-(nOnLastLine & 0x03 );
        }

        if ((dwFlags & ATL_BASE64_FLAG_NOCRLF) == 0) //需要换行符
        {
            nRet += ((nRet / 76 + 1) << 1) ;//(nRet / 76 + 1) * 2, 回车换行个数(+1是为了取最多值),根据rfc2045,编码后一行最多76个字符(不含换行)
        }

        return nRet;
    }

    inline static int DecodeGetRequiredLength(int nSrcLen)
    {
        return ((nSrcLen*3)>>2)+2; //(nSrcLen*3)/4+2
    }

    //pbSrcData  要编码的原始数据
    //nSrcLen  原始数据长度
    //szDest    编码后的输出
    //pnEncodeRealLen       编码后的实际长度
    static bool Encode(const unsigned char *pbSrcData,int nSrcLen,char* szDest,int *pnEncodeRealLen,Base64_Flag dwFlags = ATL_BASE64_FLAG_NONE)
    {
        static const char *s_chBase64EncodingTable="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

        if (!pbSrcData || !szDest || !pnEncodeRealLen)
        {
            return false;
        }

        int nWritten = 0 ; //编码后的长度,EncodeGetRequiredLength获得的长度通常大于实际长度

        int nLen1 = (nSrcLen/3) << 2; // (nSrcLen/3)*4
        int nLen2 = nLen1/76 ;  //RFC2045 base64编码后,每行最多76个字符
        int nLen3 = 19 ;

        for (int i=0; i<=nLen2; i++)
        {
            if (i==nLen2)
                nLen3 = (nLen1%76)/4;

            for (int j=0; j<nLen3; j++)
            {
                unsigned long dwCurr = 0;
                for (int n=0; n<3; n++)
                {
                    dwCurr |= *pbSrcData++;
                    dwCurr <<= 8;
                }
                for (int k=0; k<4; k++)
                {
                    unsigned char b = (unsigned char)(dwCurr>>26);
                    *szDest++ = s_chBase64EncodingTable[b];
                    dwCurr <<= 6;
                }
            }
            nWritten+= nLen3*4;

            if ((dwFlags & ATL_BASE64_FLAG_NOCRLF)==0)
            {
                *szDest++ = '\r';
                *szDest++ = '\n';
                nWritten+= 2;
            }
        }

        if (nWritten && (dwFlags & ATL_BASE64_FLAG_NOCRLF)==0)
        {
            szDest-= 2;
            nWritten -= 2;
        }

        nLen2 = (nSrcLen%3) ? (nSrcLen%3 + 1) : 0;
        if (nLen2)
        {
            unsigned long dwCurr = 0;
            for (int n=0; n<3; n++)
            {
                if (n<(nSrcLen%3))
                    dwCurr |= *pbSrcData++;
                dwCurr <<= 8;
            }
            for (int k=0; k<nLen2; k++)
            {
                unsigned char b = (unsigned char)(dwCurr>>26);
                *szDest++ = s_chBase64EncodingTable[b];
                dwCurr <<= 6;
            }
            nWritten+= nLen2;
            if ((dwFlags & ATL_BASE64_FLAG_NOPAD)==0)
            {
                nLen3 = nLen2 ? 4-nLen2 : 0;
                for (int j=0; j<nLen3; j++)
                {
                    *szDest++ = '=';
                }
                nWritten+= nLen3;
            }
        }

        *pnEncodeRealLen = nWritten;
        return true;
    }

    //szSrc  要解码的数据
    //nSrcLen  要解码数据的长度
    //pbDest   解码后的输出
    //pnDecodeRealLen  解码后的字节长度
    static bool Decode(const char* szSrc, int nSrcLen, unsigned char *pbDest, int *pnDecodeRealLen)
    {
        // walk the source buffer
        // each four character sequence is converted to 3 bytes
        // CRLFs and =, and any characters not in the encoding table
        // are skiped

        // returns -1 if the character is invalid
        // or should be skipped
        // otherwise, returns the 6-bit code for the character
        // from the encoding table
        static const int base64_decode_table[] =
        {
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1,
            -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
            15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
            29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
            49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
        };

        if (szSrc == 0 || pnDecodeRealLen == 0)
        {
            return false;
        }

        const char* szSrcEnd = szSrc + nSrcLen;
        int nWritten = 0;

        while (szSrc < szSrcEnd &&(*szSrc) != 0)
        {
            unsigned long dwCurr = 0;
            int i;
            int nBits = 0;
            for (i=0; i<4; i++)
            {
                if (szSrc >= szSrcEnd)
                    break;
                int nCh = base64_decode_table[(unsigned char)(*szSrc)]; //强转为unsigned char,防止运行时抛出异常
                szSrc++;
                if (nCh == -1)
                {
                    // skip this char
                    i--;
                    continue;
                }
                dwCurr <<= 6;
                dwCurr |= nCh;
                nBits += 6;
            }

            // dwCurr has the 3 bytes to write to the output buffer
            // left to right
            dwCurr <<= 24-nBits;
            for (i=0; i<nBits/8; i++)
            {
                *pbDest = (unsigned char) ((dwCurr & 0x00ff0000) >> 16);
                pbDest++;

                dwCurr <<= 8;
                nWritten++;
            }

        }

        *pnDecodeRealLen = nWritten;

        return true;
    }

    static bool Encode(const std::string & in , std::string & out,Base64_Flag dwFlags = ATL_BASE64_FLAG_NONE)
    {
        int len = EncodeGetRequiredLength(static_cast<int>(in.size()),dwFlags);
        out.assign(len,0);
        bool ret=Encode((const unsigned char*)in.c_str(),static_cast<int>(in.size()),(char*)out.c_str(),&len,dwFlags);
        out.resize(static_cast<size_t>(len));
        return ret;
    }
    static bool Encode( const unsigned char * in ,int in_len,std::string & out ,Base64_Flag dwFlags = ATL_BASE64_FLAG_NONE)
    {
        int len = EncodeGetRequiredLength(in_len,dwFlags);
        out.assign(len,0);
        bool ret=Encode(in ,in_len,(char*)out.c_str(),&len,dwFlags);
        out.resize(static_cast<size_t>(len));
        return ret;
    }
    static bool Decode(const std::string & in, std::string & out )
    {
        out.assign(in.size(),0);
        int len=static_cast<int>(out.size());
        bool ret = Decode(in.c_str(),static_cast<int>(in.size()), (unsigned char*) out.c_str() , &len);
        out.resize(static_cast<size_t>(len));
        return ret;
    }
    static bool Decode(const char * in ,int in_len , std::string & out )
    {
        out.assign( static_cast<size_t>(in_len),0);
        int outlen=static_cast<int>(out.size());
        bool ret = Decode(in ,in_len, (unsigned char*) out.c_str() , &outlen);
        out.resize(static_cast<size_t>(outlen));
        return ret;
    }
};

}

发表回复

© Beli. All Rights Reserved.