前言
base64是一种编码方案,将二进制字节流编码成可显示字符,其中可显示字符有64种,如下表所示。
在http头,JSON等格式中,要求必须为可显示字符,如果想将二进制字节流加入http头或JSON中可将其用base64转换成字符后加入到协议中。
一、编码表
值 | 对应base64字符 | 值 | 对应base64字符 | 值 | 对应base64字符 |
---|---|---|---|---|---|
0x0 | A | 26 | a | 52 | 0 |
0x1 | B | 27 | b | 53 | 1 |
… | C | c | 2 | ||
D | d | 3 | |||
E | e | 4 | |||
F | f | 5 | |||
G | g | 6 | |||
H | h | 7 | |||
I | i | 8 | |||
J | j | 9 | |||
K | k | + | |||
L | l | 63 | / | ||
M | m | ||||
N | n | ||||
O | o | ||||
P | p | ||||
Q | q | ||||
R | r | ||||
S | s | ||||
T | t | ||||
U | u | ||||
V | v | ||||
W | w | ||||
X | x | ||||
Y | y | ||||
25 | Z | z |
不足的用’='代替
二、实现
欢迎指出程序中的bug
#include <stdio.h>
#include <stdbool.h>
bool encode_base64(const char* src, int s_len, char* dest, int* d_len)
{
static unsigned char table[] = {
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
97, 98, 99, 100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,
'0', 49, 50, 51, 52, 53, 54, 55, 56, 57, '+', '/',
};
if ( *d_len < ((s_len + 2) / 3 * 4) + 1 ) return false;
int round_len = s_len / 3 * 3;
*d_len = 0;
for (int i = 0; i+2 < round_len; i += 3)
{
dest[(*d_len)++] = table[src[i] >> 2];
dest[(*d_len)++] = table[ ((src[i]&0x03) << 4) | ((src[i+1]&0xF0) >> 4) ];
dest[(*d_len)++] = table[ ((src[i+1]&0x0F) << 2) | ((src[i+2]&0xC0) >> 6) ];
dest[(*d_len)++] = table[ src[i+2]&0x3F ];
}
if (s_len - round_len == 2) {
dest[(*d_len)++] = table[src[round_len] >> 2];
dest[(*d_len)++] = table[ ((src[round_len]&0x03) << 4) | ((src[round_len+1]&0xF0) >> 4) ];
dest[(*d_len)++] = table[ ((src[round_len+1]&0x0F) << 2) ];
dest[(*d_len)++] = '=';
} else if (s_len - round_len == 1) {
dest[(*d_len)++] = table[src[round_len] >> 2];
dest[(*d_len)++] = table[ ((src[round_len]&0x03) << 4) ];
dest[(*d_len)++] = '=';
dest[(*d_len)++] = '=';
}
dest[*d_len] = '\0';
return true;
}
static inline bool not_in_base64(unsigned char ch)
{
if (ch == '=' || ch == 43 || (ch >= 47 && ch <= 57) || (ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122)) return false;
return true;
}
bool decode_base64(const char* src, int s_len, char* dest, int* d_len)
{
static unsigned char 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/* 43 '+' */, 0,0,0, 63/* 47 '/' */, 52/* 48 '0' */, 53, 54, 55, 56, 57, 58, 59, 60, 61,
0,0,0,0,0,0,0/* 64 */,
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/* 90 */,
0, 0, 0, 0, 0, 0/* 96 */,
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/* 122 */,
};
if (s_len % 4 != 0) return false;
*d_len = 0;
for (int i = 0; i + 4 <= s_len; i += 4)
{
if (not_in_base64(src[i ])) return false;
if (not_in_base64(src[i+1])) return false;
if (not_in_base64(src[i+2])) return false;
if (not_in_base64(src[i+3])) return false;
dest[(*d_len)++] = (table[src[i]] << 2) | (table[src[i+1]] >> 4);
dest[(*d_len)++] = (table[src[i+1]] << 4) | (table[src[i+2]] >> 2);
dest[(*d_len)++] = (table[src[i+2]] << 6) | (table[src[i+3]]);
}
if ('=' == src[s_len-1]) --(*d_len);
if ('=' == src[s_len-2]) --(*d_len);
return true;
}