代码改变世界

C++ Base64 编码 解码

2013-10-25 22:51  wid  阅读(8862)  评论(4编辑  收藏  举报

C++实现 base64 字符串编码解码(GCC编译)。

  1 /**
  2 * @brief C++ base64 编解码
  3 * @author wid
  4 * @date 2013-20-25
  5 *
  6 * @note 若代码存在 bug 或程序缺陷, 请留言反馈, 谢谢!
  7 */
  8 
  9 #include <iostream>
 10 #include <string>
 11 #include <ctime>
 12 
 13 //base64 编解码函数声明
 14 std::string b64encodestring(const std::string &strString);      //对 ASCII 字符串进行 base64 编码
 15 std::string b64decodestring(const std::string &strString);      //对 base64 编码后的字符串进行解码
 16 
 17 //base64 编解码函数实现
 18 /**
 19 * @brief 对 ASCII 字符串进行 base64 编码
 20 *
 21 * @param strString 待编码的字符串
 22 *
 23 * @return srs::string 返回编码后的字符串
 24 *
 25 * @note 对于字符串中含有非 ASCII 字符串型的字符, 代码将抛出 std::string 型异常, 请捕获
 26 */
 27 std::string b64encodestring(const std::string &strString)
 28 {
 29     int nByteSrc = strString.length();
 30     std::string pszSource = strString;
 31 
 32     int i = 0;
 33     for(i; i < nByteSrc; i++)
 34         if( pszSource[i] < 0 || pszSource[i] > 127 )
 35             throw "can not encode Non-ASCII characters";
 36 
 37     const char *enkey = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 38     std::string pszEncode(nByteSrc*4/3 + 4, '\0');
 39     int nLoop = nByteSrc %3 == 0 ? nByteSrc : nByteSrc - 3;
 40     int n = 0;
 41     for(i=0; i < nLoop; i+=3 )
 42     {
 43         pszEncode[n] = enkey[pszSource[i]>>2];
 44         pszEncode[n+1] = enkey[((pszSource[i]&3)<<4) | ((pszSource[i+1] & 0xF0)>>4)];
 45         pszEncode[n+2] = enkey[((pszSource[i+1] & 0x0f)<<2) | ((pszSource[i+2] & 0xc0 )>>6)];
 46         pszEncode[n+3] = enkey[pszSource[i+2] & 0x3F];
 47         n += 4;
 48     }
 49 
 50     switch(nByteSrc%3)
 51     {
 52     case 0:
 53         pszEncode[n] = '\0';
 54         break;
 55 
 56     case 1:
 57         pszEncode[n] = enkey[pszSource[i]>>2];
 58         pszEncode[n+1] = enkey[((pszSource[i]&3)<<4) | ((0&0xf0)>>4)];
 59         pszEncode[n+2] = '=';
 60         pszEncode[n+3] = '=';
 61         pszEncode[n+4] = '\0';
 62         break;
 63 
 64     case 2:
 65         pszEncode[n] = enkey[pszSource[i]>>2];
 66         pszEncode[n+1] = enkey[((pszSource[i]&3)<<4) | ((pszSource[i+1]&0xf0)>>4)];
 67         pszEncode[n+2] = enkey[(( pszSource[i+1]&0xf)<<2 ) | ((0&0xc0)>>6)];
 68         pszEncode[n+3] = '=';
 69         pszEncode[n+4] = '\0';
 70         break;
 71     }
 72 
 73     return pszEncode.c_str();
 74 }
 75 
 76 /**
 77 * @brief 对 base64 编码后的字符串进行解码
 78 *
 79 * @param strString 待解码的字符串
 80 *
 81 * @return std::string 返回解码后的字符串
 82 *
 83 * @note 对于非base64编码的字符串或已损坏的base64字符串进行解码会抛出 std::string 型异常, 请捕获
 84 */
 85 std::string b64decodestring(const std::string &strString)
 86 {
 87     int nByteSrc = strString.length();
 88     std::string pszSource = strString;
 89 
 90     const int dekey[] = {
 91         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 92         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 93         62, // '+'
 94         -1, -1, -1,
 95         63, // '/'
 96         52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0'-'9'
 97         -1, -1, -1, -1, -1, -1, -1,
 98         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
 99         13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 'A'-'Z'
100         -1, -1, -1, -1, -1, -1,
101         26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
102         39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 'a'-'z'
103     };
104 
105     if(nByteSrc%4 != 0)
106         throw "bad base64 string";
107 
108     std::string pszDecode(nByteSrc*3/4+4, '\0');
109     int nLoop = pszSource[nByteSrc-1]  == '=' ? nByteSrc - 4 : nByteSrc;
110     int b[4];
111     int i = 0, n = 0;
112     for(i = 0; i < nLoop; i += 4 )
113     {
114         b[0] = dekey[pszSource[i]];        b[1] = dekey[pszSource[i+1]];
115         b[2] = dekey[pszSource[i+2]];    b[3] = dekey[pszSource[i+3]];
116         if(b[0] == -1 || b[1] == -1 || b[2] == -1 || b[3] == -1)
117             throw "bad base64 string";
118 
119         pszDecode[n] = (b[0] << 2) | ((b[1] & 0x30) >> 4);
120         pszDecode[n+1] = ((b[1] & 0xf) << 4) | ((b[2] & 0x3c) >> 2);
121         pszDecode[n+2] =  ((b[2] & 0x3) << 6) | b[3];
122 
123         n+=3;
124     }
125 
126     if( pszSource[nByteSrc-1] == '=' && pszSource[nByteSrc-2] == '=' )
127     {
128         b[0] = dekey[pszSource[i]];        b[1] = dekey[pszSource[i+1]];
129         if(b[0] == -1 || b[1] == -1)
130             throw "bad base64 string";
131 
132         pszDecode[n] = (b[0] << 2) | ((b[1] & 0x30) >> 4);
133         pszDecode[n+1] = '\0';
134     }
135 
136     if( pszSource[nByteSrc-1] == '=' && pszSource[nByteSrc-2] != '=' )
137     {
138         b[0] = dekey[pszSource[i]];        b[1] = dekey[pszSource[i+1]];
139         b[2] = dekey[pszSource[i+2]];
140         if(b[0] == -1 || b[1] == -1 || b[2] == -1)
141             throw "bad base64 string";
142 
143         pszDecode[n] = (b[0] << 2) | ((b[1] & 0x30) >> 4);
144         pszDecode[n+1] = ((b[1] & 0xf) << 4) | ((b[2] & 0x3c) >> 2);
145         pszDecode[n+2] = '\0';
146     }
147 
148     if( pszSource[nByteSrc-1] != '=' && pszSource[nByteSrc-2] != '=' )
149         pszDecode[n] = '\0';
150 
151     return pszDecode;
152 }
153 
154 //测试
155 int main()
156 {
157     ///编码测试
158     std::string str1 = "Hello, world!";
159     std::cout << "对Hello, world!进行base64编码: " << b64encodestring(str1) << std::endl;
160 
161     ///解码测试
162     std::string str2 = "SGVsbG8sIHdvcmxkIQ==";
163     std::cout << "对SGVsbG8sIHdvcmxkIQ==进行base64解码: " << b64decodestring(str2) << std::endl;
164 
165     ///编码耗时测试
166     std::string str3(10000000, 'A');    //生成 10000000 长的字符串
167     std::cout << std::endl << "对 10000000 长的字符串进行编码耗时测试.." << std::endl;
168     size_t t0 = clock();        //编码计时开始
169     b64encodestring(str3);
170     std::cout << "测试结束, 耗时 " << clock() - t0 << "ms" << std::endl;
171 
172     ///解码耗时测试
173     std::string str4 = b64encodestring(str3);        //得到长度为 10000000 的字符串base64编码后的字符串
174     std::cout << std::endl << "" << str4.length() << " 长的base64字符串进行解码耗时测试.." << std::endl;
175     size_t t1 = clock();        //解码计时开始
176     b64decodestring(str3);
177     std::cout << "测试结束, 耗时 " << clock() - t1 << "ms" << std::endl;
178 
179     return 0;
180 }

 

运行测试结果:

 

若代码存在 bug 或程序缺陷, 请留言反馈, 谢谢。