zoukankan      html  css  js  c++  java
  • 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);
    
        /** 解析为一个字符串(由调用者确定解出的字符中不包含''才能能调用此函数,否则返回的结果可能不是期望的值) */
        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("
    ");}
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        unsigned char pBuffer[] = "~!@#$%^&*(	)_+{}:"?></.,;'[]\";
        
        int nCount = sizeof(pBuffer);
        printf("count=%d
    ", nCount);
        for (int i = 1; i <= nCount; i++)
        {
            string str(&pBuffer[0], &pBuffer[i]);
            printf("----------  input %d ------------
    ", i);
            printf("%s
    ", str.c_str());
            string strBase64My = Base64Utils::Encode(pBuffer, i);
            printf("%s
    ", strBase64My.c_str());
    
            int nOutSize = Base64Utils::Decode(strBase64My, NULL, 0);
            printf("need buffer : %d
    ", nOutSize);
    
            //printf("decode:%s
    ", Base64Utils::DecodeToString(strBase64My).c_str());
    
            //if (strBase64My.length() > 2)
            //{
            //    strBase64My.replace(strBase64My.begin() + 2, strBase64My.begin() + 3, 1, ',');
            //    printf("%s
    ", 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
    ", j, pOutBuffer);
                PRINT_BYTE(pOutBuffer, j);
                delete[] pOutBuffer;
                pOutBuffer = NULL;
            }
        }
        system("pause");
        return 0;
    }
  • 相关阅读:
    使用数据(二)
    lambda表达式
    方法引用::
    开发 Web 应用(一)
    Spring基础(三)
    Spring基础(二)
    Spring 基础(一)
    项目实践之Ajax 技术使用教程
    项目实践之前后端分离详解
    考研计算机基础:构造算法与自上而下逐步完善:实例研究3(嵌套控制结构)
  • 原文地址:https://www.cnblogs.com/diysoul/p/5816240.html
Copyright © 2011-2022 走看看