⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 base64.cpp

📁 C++ patterns设计模式
💻 CPP
字号:
////////////////////////////////////////////////////////////////////////////////
// Base64 编/解码
////////////////////////////////////////////////////////////////////////////////
// Author      : 黎达文
// Description : Base64编码解码模块
//
// Version     : 1.0
//
// Standard include files : std_inc.hpp(in precompile header)
//
// Start Date  : 2003年5月9日
//
// Change Log  : 
// 2003年5月9日 by Darkay Li 
// -- explant from xerces
// 2003年6月18日 by 黎达文
// -- 修改名字空间从stk改称util
////////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "charset.h"
#include "janitor.h"
#include "base64.h"

namespace stk
{
    static const int BASELENGTH = 255;
    static const int FOURBYTE   = 4;

    const unsigned char Base64::base64Alphabet[] = {
        chLatin_A, chLatin_B, chLatin_C, chLatin_D, chLatin_E,
            chLatin_F, chLatin_G, chLatin_H, chLatin_I, chLatin_J,
            chLatin_K, chLatin_L, chLatin_M, chLatin_N, chLatin_O,
            chLatin_P, chLatin_Q, chLatin_R, chLatin_S, chLatin_T,
            chLatin_U, chLatin_V, chLatin_W, chLatin_X, chLatin_Y, chLatin_Z,
            chLatin_a, chLatin_b, chLatin_c, chLatin_d, chLatin_e,
            chLatin_f, chLatin_g, chLatin_h, chLatin_i, chLatin_j,
            chLatin_k, chLatin_l, chLatin_m, chLatin_n, chLatin_o,
            chLatin_p, chLatin_q, chLatin_r, chLatin_s, chLatin_t,
            chLatin_u, chLatin_v, chLatin_w, chLatin_x, chLatin_y, chLatin_z,
            chDigit_0, chDigit_1, chDigit_2, chDigit_3, chDigit_4,
            chDigit_5, chDigit_6, chDigit_7, chDigit_8, chDigit_9,
            chPlus, chForwardSlash, chNull
    };

    unsigned char Base64::base64Inverse[BASELENGTH];

    const unsigned char Base64::base64Padding = chEqual;

    bool Base64::isInitialized = false;

    /**
    *     E2-9
    *
    *     Canonical-base64Binary ::= (B64line* B64lastline)?
    *
    *      B64line ::= B64x15 B64x15 B64x15 B64x15 B64x15 B64 #xA
    *                  76 Base64 characters followed by newline
    *
    *      B64x15  ::= B64 B64 B64 B64 B64
    *                  B64 B64 B64 B64 B64
    *                  B64 B64 B64 B64 B64
    *
    *      B64lastline ::= B64x4? B64x4? B64x4? B64x4?
    *                      B64x4? B64x4? B64x4? B64x4?
    *                      B64x4? B64x4? B64x4? B64x4?
    *                      B64x4? B64x4? B64x4? B64x4?
    *                      B64x4? B64x4?
    *                      (B64x4 | (B64 B64 B16 '=') | (B64 B04 '=='))
    *                      #xA
    *
    *      B64x4   ::= B64 B64 B64 B64
    *      B04     ::= [AQgw]
    *      B16     ::= [AEIMQUYcgkosw048]
    */

    // number of quadruplets per one line ( must be >1 and <19 )
    const unsigned int Base64::quadsPerLine = 15;

    unsigned char* Base64::encode(const unsigned char* const inputData,
                                  const unsigned int   inputLength,
                                  unsigned int*        outputLength)
    {
        if (!isInitialized)
            init();

        if (!inputData)
            return 0;

        int quadrupletCount = ( inputLength + 2 ) / 3;
        if (quadrupletCount == 0)
            return 0;

        // number of rows in encoded stream ( including the last one )
        int lineCount = ( quadrupletCount + quadsPerLine-1 ) / quadsPerLine;

        //
        // convert the triplet(s) to quadruplet(s)
        //
        unsigned char  b1, b2, b3, b4;  // base64 binary codes ( 0..63 )

        unsigned int inputIndex = 0;
        unsigned int outputIndex = 0;
        unsigned char *encodedData = new unsigned char[ quadrupletCount*FOURBYTE + lineCount + 1 ];

        //
        // Process all quadruplet(s) except the last
        //
        int quad = 1;
        for (; quad <= quadrupletCount-1; quad++ )
        {
            // read triplet from the input stream
            split1stOctet( inputData[ inputIndex++ ], b1, b2 );
            split2ndOctet( inputData[ inputIndex++ ], b2, b3 );
            split3rdOctet( inputData[ inputIndex++ ], b3, b4 );

            // write quadruplet to the output stream
            encodedData[ outputIndex++ ] = base64Alphabet[ b1 ];
            encodedData[ outputIndex++ ] = base64Alphabet[ b2 ];
            encodedData[ outputIndex++ ] = base64Alphabet[ b3 ];
            encodedData[ outputIndex++ ] = base64Alphabet[ b4 ];

            if (( quad % quadsPerLine ) == 0 )
                encodedData[ outputIndex++ ] = chLF;
        }

        //
        // process the last Quadruplet
        //
        // first octet is present always, process it
        split1stOctet( inputData[ inputIndex++ ], b1, b2 );
        encodedData[ outputIndex++ ] = base64Alphabet[ b1 ];

        if( inputIndex < inputLength )
        {
            // second octet is present, process it
            split2ndOctet( inputData[ inputIndex++ ], b2, b3 );
            encodedData[ outputIndex++ ] = base64Alphabet[ b2 ];

            if( inputIndex < inputLength )
            {
                // third octet present, process it
                // no PAD e.g. 3cQl
                split3rdOctet( inputData[ inputIndex++ ], b3, b4 );
                encodedData[ outputIndex++ ] = base64Alphabet[ b3 ];
                encodedData[ outputIndex++ ] = base64Alphabet[ b4 ];
            }
            else
            {
                // third octet not present
                // one PAD e.g. 3cQ=
                encodedData[ outputIndex++ ] = base64Alphabet[ b3 ];
                encodedData[ outputIndex++ ] = base64Padding;
            }
        }
        else
        {
            // second octet not present
            // two PADs e.g. 3c==
            encodedData[ outputIndex++ ] = base64Alphabet[ b2 ];
            encodedData[ outputIndex++ ] = base64Padding;
            encodedData[ outputIndex++ ] = base64Padding;
        }

        // write out end of the last line
        encodedData[ outputIndex++ ] = chLF;
        // write out end of string
        encodedData[ outputIndex ] = 0;

        if( outputLength != 0 )
            (*outputLength) = outputIndex;

        return encodedData;
    }

    //
    // return 0(null) if invalid data found.
    // return the buffer containning decoded data otherwise
    // the caller is responsible for the de-allocation of the
    // buffer returned.
    //
    // temporary data, rawInputData, is ALWAYS released by this function.
    //

    /***
    *     E2-9
    *
    *     Base64Binary ::= S? B64quartet* B64final?
    *
    *     B64quartet   ::= B64 S? B64 S? B64 S? B64 S?
    *
    *     B64final     ::= B64 S? B04 S? '=' S? '=' S?
    *                    | B64 S? B64 S? B16 S? '=' S?
    *
    *     B04          ::= [AQgw]
    *     B16          ::= [AEIMQUYcgkosw048]
    *     B64          ::= [A-Za-z0-9+/]
    */

    unsigned char* Base64::decode(const unsigned char* const inputData,
        unsigned int*        outputLength)
    {
        if (!isInitialized)
            init();

        if ((!inputData) || (!*inputData))
            return 0;

        //
        // remove all XML whitespaces from the base64Data
        //
        int inputLength = (int)strlen((const char *)inputData);
        unsigned char* rawInputData = new unsigned char[ inputLength + 1 ];
		ArrayJanitor<unsigned char> janInputData(rawInputData);

        int inputIndex = 0;
        int rawInputLength = 0;
        bool inWhiteSpace = false;

        while ( inputIndex < inputLength )
        {
            //if (!XMLChar1_0::isWhitespace(inputData[inputIndex]))
			if(!isspace(inputData[inputIndex]))
            {
                rawInputData[ rawInputLength++ ] = inputData[ inputIndex ];
                inWhiteSpace = false;
            }
            else
            {
                if (inWhiteSpace)
                    return 0; // more than 1 whitespaces encountered
                else
                    inWhiteSpace = true;
            }

            inputIndex++;
        }
        rawInputData[ rawInputLength ] = 0;

        // the length of raw data should be divisible by four
        if (( rawInputLength % FOURBYTE ) != 0 )
            return 0;

        int quadrupletCount = rawInputLength / FOURBYTE;
        if ( quadrupletCount == 0 )
            return 0;

        //
        // convert the quadruplet(s) to triplet(s)
        //
        unsigned char  d1, d2, d3, d4;  // base64 characters
        unsigned char  b1, b2, b3, b4;  // base64 binary codes ( 0..64 )

        int rawInputIndex  = 0;
        int outputIndex    = 0;
        unsigned char *decodedData = new unsigned char[ quadrupletCount*3 + 1 ];
		ArrayJanitor<unsigned char> janDecodeData(decodedData);

        //
        // Process all quadruplet(s) except the last
        //
        int quad = 1;
        for (; quad <= quadrupletCount-1; quad++ )
        {
            // read quadruplet from the input stream
            if (!isData( (d1 = rawInputData[ rawInputIndex++ ]) ) ||
                !isData( (d2 = rawInputData[ rawInputIndex++ ]) ) ||
                !isData( (d3 = rawInputData[ rawInputIndex++ ]) ) ||
                !isData( (d4 = rawInputData[ rawInputIndex++ ]) ))
            {
                return 0;
            }

            b1 = base64Inverse[ d1 ];
            b2 = base64Inverse[ d2 ];
            b3 = base64Inverse[ d3 ];
            b4 = base64Inverse[ d4 ];

            // write triplet to the output stream
            decodedData[ outputIndex++ ] = set1stOctet(b1, b2);
            decodedData[ outputIndex++ ] = set2ndOctet(b2, b3);
            decodedData[ outputIndex++ ] = set3rdOctet(b3, b4);
        }

        //
        // process the last Quadruplet
        //
        // first two octets are present always, process them
        if (!isData( (d1 = rawInputData[ rawInputIndex++ ]) ) ||
            !isData( (d2 = rawInputData[ rawInputIndex++ ]) ))
        {
            return 0;
        }

        b1 = base64Inverse[ d1 ];
        b2 = base64Inverse[ d2 ];

        // try to process last two octets
        d3 = rawInputData[ rawInputIndex++ ];
        d4 = rawInputData[ rawInputIndex++ ];

        if (!isData( d3 ) || !isData( d4 ))
        {
            // check if last two are PAD characters
            if (isPad( d3 ) && isPad( d4 ))
            {
                // two PAD e.g. 3c==
                if ((b2 & 0xf) != 0) // last 4 bits should be zero
                {
                    return 0;
                }

                decodedData[ outputIndex++ ] = set1stOctet(b1, b2);
            }
            else if (!isPad( d3 ) && isPad( d4 ))
            {
                // one PAD e.g. 3cQ=
                b3 = base64Inverse[ d3 ];
                if (( b3 & 0x3 ) != 0 ) // last 2 bits should be zero
                {
//                    delete[] decodedData;
                    return 0;
                }

                decodedData[ outputIndex++ ] = set1stOctet( b1, b2 );
                decodedData[ outputIndex++ ] = set2ndOctet( b2, b3 );
            }
            else
            {
                // an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data
                return 0;
            }
        }
        else
        {
            // no PAD e.g 3cQl
            b3 = base64Inverse[ d3 ];
            b4 = base64Inverse[ d4 ];
            decodedData[ outputIndex++ ] = set1stOctet( b1, b2 );
            decodedData[ outputIndex++ ] = set2ndOctet( b2, b3 );
            decodedData[ outputIndex++ ] = set3rdOctet( b3, b4 );
        }

        // write out the end of string
        decodedData[ outputIndex ] = 0;
        *outputLength = outputIndex;

		//don't guard anymore because it will return to the user
		janDecodeData.orphan();

        return decodedData;
    }

    // -----------------------------------------------------------------------
    //  Helper methods
    // -----------------------------------------------------------------------
    void Base64::init()
    {
        if (isInitialized)
            return;

        isInitialized = true;

        // create inverse table for base64 decoding
        // if base64Alphabet[ 17 ] = 'R', then base64Inverse[ 'R' ] = 17
        // for characters not in base64Alphabet the base64Inverse[] = -1

        int i;
        // set all fields to -1
        for ( i = 0; i < BASELENGTH; i++ )
            base64Inverse[i] = (unsigned char)-1;

        // compute inverse table
        for ( i = 0; i < 64; i++ )
            base64Inverse[ base64Alphabet[i] ] = (unsigned char)i;
    }

    bool Base64::isData(const unsigned char& octet)
    {
        return (base64Inverse[octet]!=(unsigned char)-1);
    }

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -