首先了解了下Base64的實(shí)現(xiàn)原理:https://baijiahao.baidu.com/s?id=1644892102150918183&wfr=spider&for=pc
大概內(nèi)容就是嫡纠,base64基于一個(gè)含有64個(gè)字符的編碼表(A-Z,a-z,0-9,+忘朝,/)违孝,將原文進(jìn)行轉(zhuǎn)碼,其步驟就是將原文按每三個(gè)字節(jié)一組分割毛嫉,每三個(gè)字節(jié)又按六位一組分為四組,然后高位補(bǔ)零妇菱,所以輸出結(jié)果里每個(gè)字節(jié)最大值也就63承粤,也就是對(duì)應(yīng)了base64的編碼表。
接下來(lái)直接看base64.c文件的代碼
int base64_encode(unsigned char *dst, int *dlen, const unsigned char *src, int slen) {
int i, n;
int C1, C2, C3;
unsigned char *p;
if (slen == 0)
return (0);
/**
* 首先計(jì)算傳入進(jìn)來(lái)的原文按六位一組闯团,可以分成多少組
* 所以將slen * 8辛臊,然后再除6 (由于8是2的3次方,用乘法算太耗時(shí)房交,所以直接左移3位)
*/
n = (slen << 3) / 6;
/**
* 由于原文長(zhǎng)度并不一定是3的倍數(shù)彻舰,可能多1或2個(gè)字節(jié),所以還需要計(jì)算是否多出字節(jié)
* 由于是將3字節(jié)按4個(gè)6位分割候味,需要以24位一組的規(guī)則計(jì)算新數(shù)組空間
* 按照8:6 和 16:12的比例淹遵,那么多出1個(gè)字節(jié),原文總位數(shù)除以6负溪,余2透揣;多出2個(gè)字節(jié),余4
* 再結(jié)合每組24位的原則川抡,原文多1個(gè)字節(jié)辐真,在n的基礎(chǔ)上须尚,新數(shù)組還差18位即3字節(jié)空間,原文多2字節(jié)侍咱,新數(shù)組還差12位即2字節(jié)空間
* 所以當(dāng)余2耐床,n需要自加3,當(dāng)余4楔脯,n需要自加2
*/
switch ((slen << 3) - (n * 6)) {
case 2:
n += 3;
break;
case 4:
n += 2;
break;
default:
break;
}
/**
* 按理說(shuō)按照以上計(jì)算撩轰,最終n的值就是新數(shù)組的長(zhǎng)度,所以dlen只要不小于n即可
* 但我不明白為什么這里的判斷是dlen要大于n昧廷,不知道是不是為了字符串結(jié)尾\0留位置堪嫂,但也沒看代碼里結(jié)尾添加字符串的結(jié)尾標(biāo)識(shí)啊,啊木柬,不懂c啊
*/
if (*dlen < n + 1) {
*dlen = n + 1;
return (POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL);
}
/**
* 這里是將原文按3字節(jié)分組皆串,得到組數(shù),多余的1眉枕、2字節(jié)后面單獨(dú)計(jì)算
*/
n = (slen / 3) * 3;
/**
* 按組數(shù)循環(huán)取原文里的字節(jié)恶复,每次取3個(gè),這里用了新指針p速挑,指向地址與傳參的dst一樣谤牡,聯(lián)系上下文针余,我個(gè)人理解是為了計(jì)算新數(shù)組實(shí)際長(zhǎng)度
* 但是用strlen不也可以計(jì)算dst的長(zhǎng)度么葫男,不明白為什么這樣做
* em....好像直接用dst運(yùn)算,最后指針已經(jīng)指向字符串末尾了河泳,不過也不是沒有辦法回到開頭伶授,這個(gè)p還是讓我很糾結(jié)
*/
for (i = 0, p = dst; i < n; i += 3) {
C1 = *src++;
C2 = *src++;
C3 = *src++;
/**
* 首先將第一字節(jié)右移2位,得到左6位流纹,與上0x3F糜烹,高2位置0,得到第一個(gè)6位
* 然后在編碼表里進(jìn)行轉(zhuǎn)碼漱凝,得到新組的第一字節(jié)
*/
*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
/**
* 接著將第一字節(jié)與3疮蹦,即00000011,得到低2位茸炒,然后左移4位愕乎,
* 然后將第二字節(jié)右移4位,做加法運(yùn)算壁公,得到第二個(gè)6位感论,轉(zhuǎn)碼得到新組的第二字節(jié)
*/
*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
/**
* 將第二字節(jié)與15,即00001111紊册,得到低4位比肄,然后左移2位,
* 然后將第三字節(jié)右移6位,得到高2位芳绩,做加法運(yùn)算掀亥,得到第三個(gè)6位,轉(zhuǎn)碼得到新組的第三字節(jié)
*/
*p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
/**
* 最后將第三字節(jié)與上0x3F妥色,清除高2位搪花,得到低6位,即第四個(gè)6位嘹害,轉(zhuǎn)碼得到新組的第四字節(jié)
*/
*p++ = base64_enc_map[C3 & 0x3F];
}
//以上將正好可以按3字節(jié)一組分割的內(nèi)容全部轉(zhuǎn)碼完畢
/**
* 接下來(lái)判斷原文按3字節(jié)分組后撮竿,是否還多出不夠一組的內(nèi)容
*/
if (i < slen) {
/**
* 既然多出內(nèi)容,那么至少多一個(gè)吼拥,所以第一字節(jié)直接取
* 對(duì)第二字節(jié)需要判斷
*/
C1 = *src++;
C2 = ((i + 1) < slen) ? *src++ : 0;
/**
* 新組第一二字節(jié)可直接取6位然后轉(zhuǎn)碼
*/
*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
/**
* 如果原文只多出1字節(jié)倚聚,那么新組第三字節(jié)肯定為0,那么按照規(guī)則凿可,空字符用 '=' 代替
* 如果多出2字節(jié)惑折,則還繼續(xù)進(jìn)行取6位,轉(zhuǎn)碼的運(yùn)算
*/
if ((i + 1) < slen)
*p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
else *p++ = '=';
/**
* 由于最多多出2字節(jié)枯跑,所以新組第四字節(jié)肯定沒有值可以取惨驶,也就是空字符,所以直接轉(zhuǎn)換為 '='
*/
*p++ = '=';
}
/**
* 這里我的理解是計(jì)算字符數(shù)組dst(p)的長(zhǎng)度敛助,但還是那句話粗卜,為啥不用strlen(dst)計(jì)算
*/
*dlen = p - dst;
*p = 0;
return (0);
}