zoukankan      html  css  js  c++  java
  • Base64编码解码

    Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。
    可用于网络传输二进制数据(图片,文件...),将二进制转为Base64编码后,可以写入XML,将XML传输到Server端,再进行Base64解码,得到二进制数据。(二进制不能直接写入XML,Base64字符才可以。)
    Base64适用于小段内容的编码,比如数字证书签名、Cookie的内容等。
    标准的Base64并不适合直接放在URL里传输,因为URL编码器会把标准Base64中的“/”和“+”字符变为形如“%XX”的形式,而这些“%”号在存入数据库时还需要再进行转换,因为ANSI SQL中已将“%”号用作通配符。为解决此问题,可采用一种用于URL的改进Base64编码,它在末尾填充'='号,并将标准Base64中的“+”和“/”分别改成了“-”和“_”。

    Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节,也就是说,转换后的字符串理论上将要比原来的长1/3。
    关于编码的规则:
    ①.把3个字节变成4个字节。
    ② 每76个字符加一个换行符。(可选,编码解码一致即可)
    ③.最后的结束符也要处理。(若字节数是3的倍数正好,若字节数 n%3=1, 在结尾补“==”,n%3=2时,在结尾补“=”)

    例子1

    转换前 11111111, 11111111, 11111111 (二进制)
    转换后 00111111, 00111111, 00111111, 00111111 (二进制)
    上面的三个字节是原文,下面的四个字节是转换后的Base64编码,其前两位均为0。
    转换后,我们用一个码表来得到我们想要的字符串(也就是最终的Base64编码),这个表是这样的:(十进制  <-->  字符)
    索引
    对应字符
    索引
    对应字符
    索引
    对应字符
    索引
    对应字符
    0
    A
    17
    R
    34
    i
    51
    z
    1
    B
    18
    S
    35
    j
    52
    0
    2
    C
    19
    T
    36
    k
    53
    1
    3
    D
    20
    U
    37
    l
    54
    2
    4
    E
    21
    V
    38
    m
    55
    3
    5
    F
    22
    W
    39
    n
    56
    4
    6
    G
    23
    X
    40
    o
    57
    5
    7
    H
    24
    Y
    41
    p
    58
    6
    8
    I
    25
    Z
    42
    q
    59
    7
    9
    J
    26
    a
    43
    r
    60
    8
    10
    K
    27
    b
    44
    s
    61
    9
    11
    L
    28
    c
    45
    t
    62
    +
    12
    M
    29
    d
    46
    u
    63
    /
    13
    N
    30
    e
    47
    v
       
    14
    O
    31
    f
    48
    w
       
    15
    P
    32
    g
    49
    x
       
    16
    Q
    33
    h
    50
    y
       
     

    例子2

    转换前                         10101101,10111010,01110110
    转换后                         00101011, 00011011 ,00101001 ,00110110
    十进制                               43            27             41               54
    对应码表中的值                   r              b                p                 2
    所以上面的24位编码,编码后的Base64值为 rbp2
    解码同理,把 rbq2 的二进制位连接上再重组得到三个8位值,得出原码。
     
    //用更接近于编程的思维来说,编码的过程是这样的:
    //第一个字符通过右移2位获得第一个目标字符的Base64表位置,根据这个数值取到表上相应的字符,就是第一个目标字符。
    //然后将第一个字符与0x03(00000011)进行与(&)操作并左移4位,接着第二个字符右移4位,两者相或(|),或者相加,即获得第二个目标字符。
    //再将第二个字符与0x0f(00001111)进行与(&)操作并左移2位,接着第三个字符右移6位,两者相或(|),或者相加,即获得第三个目标字符。
    //最后将第三个字符与0x3f(00111111)进行与(&)操作,即获得第四个目标字符。
    
    //在以上的每一个步骤之后,再把结果与 0x3F 进行 AND 位操作,就可以得到编码后的字符了。
    

    C++代码实现

    特别注意,按位左移和右移,必须是 unsigned char 。可以定义   typedef unsigned char BYTE;

    const char* Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxwz0123456789+/";
    std::string Base64encode(const unsigned char* buf, unsigned int size)
    {
        std::string sBase64;
        unsigned int i;
        for (i = 0; i < size/3*3; i += 3)
        {
            sBase64 += Base64[buf[i] >> 2];
            sBase64 += Base64[(buf[i]<<4 | buf[i+1]>>4) & 0x3f];
            sBase64 += Base64[(buf[i+1]<<2 | buf[i+2]>>6) & 0x3f];
            sBase64 += Base64[buf[i+2] & 0x3f];
        }
        if (size % 3 == 1)
        {
            sBase64 += Base64[buf[i] >> 2];
            sBase64 += Base64[buf[i]<<4 & 0x3f];
            sBase64 += '=';
            sBase64 += '=';
        }
        else if (size % 3 == 2)
        {
            sBase64 += Base64[buf[i] >> 2];
            sBase64 += Base64[(buf[i]<<4 | buf[i+1]>>4) & 0x3f];
            sBase64 += Base64[buf[i+1]<<2 & 0x3f];
            sBase64 += '=';
        }
        return sBase64;
    }
    std::string Base64decode(std::string sBase64)
    {
        std::string sRet;
        unsigned int nLen = sBase64.size();//nLen一定是4的倍数
        unsigned char* a = new unsigned char[nLen];
        int count = 0; // the number of '='.
        for (unsigned i = 0; i < nLen; ++i)
        {
            if (sBase64[i] >= 'A' && sBase64[i] <= 'Z')
                a[i] = sBase64[i] - 'A';
            else if (sBase64[i] >= 'a' && sBase64[i] <= 'z')
                a[i] = sBase64[i] - 'a' + 26;
            else if (sBase64[i] >= '0' && sBase64[i] <= '9')
                a[i] = sBase64[i] - '0' + 52;
            else if ('+' == sBase64[i])
                a[i] = 62;
            else if ('/' == sBase64[i])
                a[i] = 63;
            else if ('=' == sBase64[i])
            {
                a[i] = 0;
                count++;
            }
        }
        sRet.resize(nLen/4*3);
        unsigned j = 0;
        for (unsigned i = 0; i < nLen; i += 4)
        {
            sRet[j++] = a[i]<<2 | a[i+1]>>4;
            sRet[j++] = a[i+1]<<4 | a[i+2]>>2;
            sRet[j++] = a[i+2]<<6 | a[i+3];
        }
        delete[] a;
        assert(j == nLen / 4 * 3);
        if (count)
            sRet.resize(sRet.size() - count);
        return sRet;
    }
    
    int main() {
        //std::string s("ixb7x1dxfbxefxffi");//-> abcd++//aQ==
        //std::string s("x00x3fxbfxd7m",5);//-> AD+/120=
        std::string s("abcde"); // -> YWJjZGU=
        std::string r = Base64encode((const unsigned char*)s.c_str(), s.size());
        std::string sRet = Base64decode(r);
        return 0;
    }

     方法2:

    std::string Base64encode(const unsigned char* buf, unsigned int size)
    {
        //方法二
        typedef   unsigned char       BYTE;
        std::string sBase64;
        std::basic_string<BYTE> s(buf, buf+size);
        unsigned count = 0;//不足3的倍数,补  的个数,即编码后“=”个数。
        if (size % 3 == 1)
        {
            s.push_back('');
            s.push_back('');
            count = 2;
        }
        else if (size % 3 == 2)
        {
            s.push_back('');
            count = 1;
        }
            
        sBase64.resize((size+count)/3*4);//sBase64的大小一定是4的倍数。
        unsigned j = 0;
        for (unsigned i = 0; i < s.size(); i += 3)
        {
            sBase64[j++] = Base64[s[i] >> 2];
            sBase64[j++] = Base64[(s[i]<<4 | s[i+1]>>4) & 0x3f];
            sBase64[j++] = Base64[(s[i+1]<<2 | s[i+2]>>6) & 0x3f];
            sBase64[j++] = Base64[s[i+2] & 0x3f];
        }
        while (count--)//此时 j = (size+count)/3*4
            sBase64[--j] = '=';
        
        return sBase64;
    }
     

    常记溪亭日暮,沉醉不知归路。兴尽晚回舟,误入藕花深处。争渡,争渡,惊起一滩鸥鹭。

    昨夜雨疏风骤,浓睡不消残酒。试问卷帘人,却道海棠依旧。知否?知否?应是绿肥红瘦。
  • 相关阅读:
    数据库面试题
    网络编程_TCP协议_客户端与服务端
    29-街道最短路径问题(哈曼顿距离)
    60-安慰奶牛(最小生成树)
    20-集合问题(并查集)
    59-算法训练 操作格子 (线段树)
    58-最小乘积(基本型)
    11-vector的使用
    20-取石子动态规则(hdu2516 斐波那契博弈)
    19-格子游戏(hdu2147博弈)
  • 原文地址:https://www.cnblogs.com/htj10/p/11508381.html
Copyright © 2011-2022 走看看