Base64 编解码

Posted 阿Hai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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。

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"

int _tmain(int argc, _TCHAR* argv[])
{
    unsigned char pBuffer[] = "[email protected]#$%^&*()_+{}:\"?></.,;‘[]\\";

    //unsigned char pBuffer[] = {‘a‘, ‘b‘, 0, ‘c‘};
    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("[%d]%s\n", j, pOutBuffer);
            delete[] pOutBuffer;
            pOutBuffer = NULL;
        }
    }
    system("pause");
    return 0;
}

 

以上是关于Base64 编解码的主要内容,如果未能解决你的问题,请参考以下文章

Lua Base64自定义编解码

VC++详解Base64编解码原理以及Base64编解码接口实现(附源码)

python3的base64编解码

Base64编解码是什么?

Base64编解码 ---- 支持64编码

[NodeJs] 如何使用nodejs对base64进行编解码?