Bsee64算法,編碼實現

 

  

  代碼是阿帕奇開源代碼,C語言實現。使用位運算,能夠更快地實現算法,下面會詳細介紹如何使用位運算進行編碼。算法

  由於有些網絡傳送渠道並不支持全部的字節,例如傳統的郵件只支持可見字符的傳送,像ASCII碼的控制字符就 不能經過郵件傳送。這樣用途就受到了很大的限制,好比圖片二進制流的每一個字節不可能所有是可見字符,因此就傳送不了。最好的方法就是在不改變傳統協議的情 況下,作一種擴展方案來支持二進制文件的傳送。把不可打印的字符也能用可打印字符來表示,問題就解決了。Base64編碼應運而生,Base64就是一種 基於64個可打印字符來表示二進制數據的表示方法。網絡

  看一下Base64的索引表,字符選用了"A-Z、a-z、0-九、+、/" 64個可打印字符。數值表明字符的索引,這個是標準Base64協議規定的,不能更改。64個字符用6個bit位就能夠所有表示,一個字節有8個bit 位,剩下兩個bit就浪費掉了,這樣就不得不犧牲一部分空間了。這裏須要弄明白的就是一個Base64字符是8個bit,可是有效部分只有右邊的6個 bit,左邊兩個永遠是0。編碼

  那麼怎麼用6個有效bit來表示傳統字符的8個bit呢?8和6的最小公倍數 是24,也就是說3個傳統字節能夠由4個Base64字符來表示,保證有效位數是同樣的,這樣就多了1/3的字節數來彌補Base64只有6個有效bit 的不足。你也能夠說用兩個Base64字符也能表示一個傳統字符,可是採用最小公倍數的方案實際上是最減小浪費的。結合下邊的圖比較容易理解。Man是三個 字符,一共24個有效bit,只好用4個Base64字符來湊齊24個有效位。紅框表示的是對應的Base64,6個有效位轉化成相應的索引值再對應 Base64字符表,查出"Man"對應的Base64字符是"TWFU"。說到這裏有個原則不知道你發現了沒有,要轉換成Base64的最小單位就是三個字節,對一個字符串來講每次都是三個字節三個字節的轉換,對應的是Base64的四個字節。這個搞清楚了其實就差很少了。spa

  可是轉換到最後你發現不夠三個字節了怎麼辦呢?願望終於實現了,咱們能夠用兩 個Base64來表示一個字符或用三個Base64表示兩個字符,像下圖的A對應的第二個Base64的二進制位只有兩個,把後邊的四個補0就是了。因此 A對應的Base64字符就是QQ。上邊已經說過了,原則是Base64字符的最小單位是四個字符一組,那這才兩個字 符,後邊補兩個"="吧。其實不用"="也不耽誤解碼,之因此用"=",多是考慮到多段編碼後的Base64字符串拼起來也不會引發混淆。因而可知 Base64字符串只可能最後出現一個或兩個"=",中間是不可能出現"="的。下圖中字符"BC"的編碼過程也是同樣的。指針

 

 

static const char basis_64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
APU_DECLARE(int) apr_base64_encode_binary(char *encoded, const unsigned char *string, int len)
{
    int i;
    char *p;

    p = encoded;
    for (i = 0; i < len - 2; i += 3) {
	*p++ = basis_64[(string[i] >> 2) & 0x3F];
	*p++ = basis_64[((string[i] & 0x3) << 4) |
	                ((int) (string[i + 1] & 0xF0) >> 4)];
	*p++ = basis_64[((string[i + 1] & 0xF) << 2) |
	                ((int) (string[i + 2] & 0xC0) >> 6)];
	*p++ = basis_64[string[i + 2] & 0x3F];
    }
    if (i < len) {
	*p++ = basis_64[(string[i] >> 2) & 0x3F];
	if (i == (len - 1)) {
	    *p++ = basis_64[((string[i] & 0x3) << 4)];
	    *p++ = '=';
	}
	else {
	    *p++ = basis_64[((string[i] & 0x3) << 4) |
	                    ((int) (string[i + 1] & 0xF0) >> 4)];
	    *p++ = basis_64[((string[i + 1] & 0xF) << 2)];
	}
	*p++ = '=';
    }

    *p++ = '\0';
    return (int)(p - encoded);
}

  for循環以3個字符爲單位,由於三個字符一共24bit,正好是4個base64編碼字符的長度。for循環裏的4行代碼,是針對24bit長度的三個字符,轉化爲24bit長度的4個base64編碼的字符。code

  第一行:string[i]前6位blog

  第二行,string[i]後兩位和string[i+1]前4位索引

  第三行:string[i+1]後四位和string[i+2]前兩位圖片

  第四行:string[i+2]後6位字符串

 

  最後的if(i < len)是給編碼後的字符串末尾加上「=」的,若是最後只有一個字符,加兩個=,若是有兩個只加一個=

 

  返回值是指針走過的距離,即編碼後的base64串的長度。

相關文章
相關標籤/搜索