Base64 編解碼

Base64編碼簡介

  Base64用來將binary的字節序列數據編碼成ASCII字符序列構成的文本。其使用的字符包括大小寫字母各26個,加上10個數字,和加號「+」,斜槓「/」,一共64個字符。另外還使用等號「=」用來做爲後綴。
  Base64編碼要求把3個8位字節(3*8=24)轉化爲4個6位的字節(4*6=24),以後在6位的前面補兩個0,造成8位一個字節的形式。若是剩下的字符不足3個字節,則用0填充,最後的輸出字符時使用'='做爲結尾,所以編碼後輸出的文本末尾可能會出現1或2個'='。
  爲了保證所輸出的編碼字符都是可讀的,Base64制定了一個編碼表,以便進行統一轉換。編碼表的大小爲2^6=64。ios

Base64編碼表                            
碼值    字符    碼值    字符    碼值    字符    碼值    字符
0    A    16    Q    32    g    48    w
1    B    17    R    33    h    49    x
2    C    18    S    34    i    50    y
3    D    19    T    35    j    51    z
4    E    20    U    36    k    52    0
5    F    21    V    37    l    53    1
6    G    22    W    38    m    54    2
7    H    23    X    39    n    55    3
8    I    24    Y    40    o    56    4
9    J    25    Z    41    p    57    5
10    K    26    a    42    q    58    6
11    L    27    b    43    r    59    7
12    M    28    c    44    s    60    8
13    N    29    d    45    t    61    9
14    O    30    e    46    u    62    +
15    P    31    f    47    v    63    /

 

C++實現

#ifndef __BASE64_UTILS__
#define __BASE64_UTILS__

#include <string>

using std::string;

class Base64Utils
{
public:
    Base64Utils(void);
    ~Base64Utils(void);

    /** 
        將一個字節數組中的數據轉爲一個 base64 格式的數組
    */
    static string Encode(const unsigned char* pEncodeData, int nLength);

    /** 
        nLength 爲 0 時返回須要 pOutBuffer 須要分配的大小; 不然解碼數據, 並存入 pOutBuffer 指向的內存中. 
        返回值: 失敗時返回0. 不然返回反解碼後的字符的個數
    */
    static int Decode(const string& strBase64, unsigned char* pOutBuffer, int nLength);

    /** 解析爲一個字符串(由調用者肯定解出的字符中不包含'\0'才能能調用此函數,不然返回的結果可能不是指望的值) */
    static string DecodeToString(const string& strBase64);

    /** 檢查一個字符是不是 base64 編碼的字符 */
    static bool CheckBase64(unsigned char bas64Char);

protected:
    template <class T> static T min(T left, T right);
};

#endif __BASE64_UTILS__

 

#include "Base64Utils.h"

// Base64 編碼所用的字符, 其順序由 base64 協議規定
static const string BASE64_ENCODE_TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

// 將 ascii 碼錶中, 對應的 Base64 字符的改爲 Base64 字符表中的索引值, 以便解碼時進行轉行轉換
static const unsigned char BASE64_DECODE_TABLE[] =
{
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    62, // '+'
    0, 0, 0,
    63, // '/'
    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0'-'9'
    0, 0, 0, 0, 0, 0, 0,
    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, // 'A'-'Z'
    0, 0, 0, 0, 0, 0,
    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, // 'a'-'z'
};

static const unsigned char BASE64_END_CHARACTER = '=';

Base64Utils::Base64Utils(void)
{
}

Base64Utils::~Base64Utils(void)
{
}

template <class T> T Base64Utils::min(T left, T right)
{
    return (left < right) ? left : right;
}

bool Base64Utils::CheckBase64(unsigned char bas64Char)
{
    return (BASE64_ENCODE_TABLE.find(bas64Char) != -1) ? true : false;
}

string Base64Utils::Encode(const unsigned char* pEncodeData, int nLength)
{
    string strBase64;

    int i = 0;
    for (; i + 2 < nLength; i += 3)
    {
        strBase64.push_back(BASE64_ENCODE_TABLE.at((pEncodeData[i] >> 2) & 0x3f));
        strBase64.push_back(BASE64_ENCODE_TABLE.at(((pEncodeData[i] & 0x03) << 4) | ((pEncodeData[i + 1] >> 4) & 0x0f)));
        strBase64.push_back(BASE64_ENCODE_TABLE.at(((pEncodeData[i + 1] & 0x0f) << 2) | ((pEncodeData[i + 2] >> 6) & 0x03)));
        strBase64.push_back(BASE64_ENCODE_TABLE.at(pEncodeData[i + 2] & 0x3f));
    }

    if (i < nLength)
    {
        strBase64.push_back(BASE64_ENCODE_TABLE.at((pEncodeData[i] >> 2) & 0x3f));
        if (i + 1 < nLength)
        {
            strBase64.push_back(BASE64_ENCODE_TABLE.at(((pEncodeData[i] & 0x03) << 4) | ((pEncodeData[i + 1] >> 4) & 0x0f)));
            strBase64.push_back(BASE64_ENCODE_TABLE.at(((pEncodeData[i + 1] & 0x0f) << 2)));
        }
        else
        {
            strBase64.push_back(BASE64_ENCODE_TABLE.at(((pEncodeData[i] & 0x03) << 4)));
            strBase64.push_back(BASE64_END_CHARACTER);
        }
        strBase64.push_back(BASE64_END_CHARACTER);
    }

    return strBase64;
}

int Base64Utils::Decode(const string& strBase64, unsigned char* pOutBuffer, int nLength)
{
    nLength = abs(nLength);
    int nBase64 = strBase64.length();
    /** 不符合 base64 字符串長度要求的字符串, 不是 base64 編碼格式的字符串, 返回 0 */
    if ((nBase64 == 0) || ((nBase64 % 4) != 0)) 
    {
        return 0;
    }

    int nNeedSize = nBase64 * 3 / 4;
    if (strBase64.at(nBase64 - 1) == BASE64_END_CHARACTER)
        nNeedSize--;
    if (strBase64.at(nBase64 - 2) == BASE64_END_CHARACTER)
        nNeedSize--;

    if (0 == nLength)
    {
        return nNeedSize;
    }

    nNeedSize = min(nNeedSize, nLength);

    const int nSizeOfDecode = sizeof(BASE64_DECODE_TABLE);
    int index = 0;
    int k = 0;
    unsigned char byteValue;
    unsigned char base64Char;
    unsigned char base64Arr[4] = {0};
    for (int i = 0; i < nBase64; i++)
    {
        base64Char = strBase64.at(i);
        if (base64Char == BASE64_END_CHARACTER) // 遇到結速符
        {
            break;
        }

        /**
            若是 base64字符爲編碼表中只有一個字符, 其解碼後值必定爲 0
            不然, 到解碼錶中查找對應的值, 若是找到, 而且值不爲 0, 纔是符合的 base64 編碼的字符.
            若是不是 base64 編碼表中的字符, 則解碼失敗, 設置返回值爲 0
        */
        if (base64Char == BASE64_ENCODE_TABLE.at(0))
        {
            byteValue = 0;
        }
        else
        {
            if (base64Char < nSizeOfDecode)
            {
                byteValue = BASE64_DECODE_TABLE[base64Char];
            }
            if (byteValue == 0)
            {
                nNeedSize = 0;
                break;
            }
        }

        base64Arr[k++] = byteValue;

        if (k == 4)
        {
            if (index >= nNeedSize)
                break;
            pOutBuffer[index++] = ((base64Arr[0] & 0x3f) << 2) | ((base64Arr[1] & 0x30) >> 4);
            if (index >= nNeedSize)
                break;
            pOutBuffer[index++] = ((base64Arr[1] & 0x0f) << 4) | ((base64Arr[2] & 0x3c) >> 2);
            if (index >= nNeedSize)
                break;
            pOutBuffer[index++] = ((base64Arr[2] & 0x03) << 6) | ((base64Arr[3] & 0x3f));
            k = 0;
        }
    }

    if ((k != 0) && (index < nNeedSize))
    {
        for (; k < 4; k++)
        {
            base64Arr[k] = 0;
        }
        if (index < nNeedSize)
            pOutBuffer[index++] = ((base64Arr[0] & 0x3f) << 2) | ((base64Arr[1] & 0x30) >> 4);
        if (index < nNeedSize)
            pOutBuffer[index++] = ((base64Arr[1] & 0x0f) << 4) | ((base64Arr[2] & 0x3c) >> 2);
        if (index < nNeedSize)
            pOutBuffer[index++] = ((base64Arr[2] & 0x03) << 6) | ((base64Arr[3] & 0x3f));
    }

    return nNeedSize;
}

string Base64Utils::DecodeToString(const string& strBase64)
{
    string strResult;
    int nSize = Decode(strBase64, NULL, 0);
    if (nSize == 0)
    {
        return strResult;
    }
    unsigned char* pOutBuffer = new unsigned char[nSize + 1];
    if (!pOutBuffer)
    {
        return strResult;
    }
    pOutBuffer[nSize] = 0;
    nSize = Decode(strBase64, pOutBuffer, nSize);
    if (nSize != 0)
    {
        strResult = reinterpret_cast<char*>(pOutBuffer);
    }
    delete[] pOutBuffer;
    pOutBuffer = NULL;
    return strResult;
}

 

測試代碼

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include "Base64Utils.h"

#define PRINT_BYTE(str, len) {printf("[%03d]", len); for(int t = 0; t < len; t++) printf("%c", str[t]); printf("\n");}

int _tmain(int argc, _TCHAR* argv[])
{
    unsigned char pBuffer[] = "~!@#$%^&\0*(\t)_+{}:\"?></.,;'[]\\";
    
    int nCount = sizeof(pBuffer);
    printf("count=%d\n", nCount);
    for (int i = 1; i <= nCount; i++)
    {
        string str(&pBuffer[0], &pBuffer[i]);
        printf("----------  input %d ------------\n", i);
        printf("%s\n", str.c_str());
        string strBase64My = Base64Utils::Encode(pBuffer, i);
        printf("%s\n", strBase64My.c_str());

        int nOutSize = Base64Utils::Decode(strBase64My, NULL, 0);
        printf("need buffer : %d\n", nOutSize);

        //printf("decode:%s\n", Base64Utils::DecodeToString(strBase64My).c_str());

        //if (strBase64My.length() > 2)
        //{
        //    strBase64My.replace(strBase64My.begin() + 2, strBase64My.begin() + 3, 1, ',');
        //    printf("%s\n", strBase64My.c_str());
        //}

        int j = nOutSize;
        for (; j > 0; j--)
        {
            unsigned char* pOutBuffer = new unsigned char[j + 1];
            memset(pOutBuffer, 0, j + 1);
            //pOutBuffer[j] = 0;
            j = Base64Utils::Decode(strBase64My, pOutBuffer, j);
            // printf("[%03d]%s\n", j, pOutBuffer);
            PRINT_BYTE(pOutBuffer, j);
            delete[] pOutBuffer;
            pOutBuffer = NULL;
        }
    }
    system("pause");
    return 0;
}
相關文章
相關標籤/搜索