C/C++ Base64解碼器

    Base64被普遍用於xml類型的文檔中,經過實現編碼和譯碼,能夠練習一下c++c++

    首先,咱們要知道什麼是Base64編碼。它是把二進制文件存儲成爲文本文件後的文件的編碼,它是64位進制的編碼,因此對於0至63的數字咱們都須要一個字符來表示。Base64的字符集很簡單,0-25 這26位是[A-Z] 26-51這26位是[a-z],52-61這十位是[0-9] 62位是+ 63位是/ 這裏咱們添加一個64號位=。 =號做用很大,一會再說。數據結構

    Base64的編碼過程是這樣的,首先讀取一個二進制文件,而後,把每三個byte取出來,對於這三個byte如何處理呢?3個byte即3*8=24 bit 咱們把每6個bits拿出來,共4*6 = 24,因此有4個6位的二進制數,咱們在這4個數的首位均補上兩個0,這樣能夠獲得4個byte,咱們把文件的長度增長了三分之一左右,可是讓全部的byte所表示的數字均不超過63,咱們這時使用Base64的字符集把數字映射成字符,而後就成爲了文本。若是它的字節數不是3的倍數呢,咱們能夠在它們佔位的地方使用=函數

    這裏咱們說編碼過程是爲了解碼,若是解碼作出來了其實編碼很簡單。編碼

    由於c++中cout很好用,因此用的是c++語言,可是裏面除去cout部分都是使用c的庫和函數,因此能夠說這個是c/c++通用的。code

    咱們要解碼,首先,咱們要把每4個字符拿出來,變成4個6bit的值。由於源文件爲文本文件,目標文件是二進制文件,因此在讀取的時候使用fgetc,寫入時使用fwritexml

    

const int map_length = 65;

struct bits {
    unsigned a:6;
    unsigned b:6;
    unsigned c:6;
    unsigned d:6;
};

const char map[map_length] = {
    'A','B','C','D','E',
    'F','G','H','I','J',
    'K','L','M','N','O',
    'P','Q','R','S','T',
    'U','V','W','X','Y',
    'Z','a','b','c','d',
    'e','f','g','h','i',
    'j','k','l','m','n',
    'o','p','q','r','s',
    't','u','v','w','x',
    'y','z','0','1','2',
    '3','4','5','6','7',
    '8','9','+','/','=',
};

 這個是映射表,以及存儲4個6bit的數據結構。索引

int getIndex(char c){
    for(int i=0; i<map_length; i++){
        if(map[i] == c) {
            return i;
        }
    }
    cout << "invalid char!!" << endl;
    exit(1);
}

經過字符查找索引數字。

 

int main()
{
    cout << "Hello world!" << endl;
/*  下行代碼結果爲 1,因此char是1byte的
    cout << sizeof(char) << endl;*/

    FILE * file = 0, * wfile = 0;
    /* 把從mht文件中找到的base64編碼複製到一個文本文件中
     * 是一個png文件,取名爲a.png.base64,只讀打開
     * 再打開一個輸出文件result.png 二進制寫入方式
     * i是在循環中計數用的
     * block用來一次性表示3個byte塊
     * buf用來存儲拿到的四個整數
     * tmp是當前拿到的字符
     */
    file = fopen("a.png.base64","r");
    wfile = fopen("result.png", "wb");
    int i=0;
    bits block;
    int buf[4];
    char tmp;

    if(file == 0 || wfile == 0) {
        cout << "Error opening file!" << endl;
        exit(1);
    }


    // 獲取字符,輸出到屏幕,忽略掉\n並寫入文件中
    
    // 這裏要注意,實際中block內部存儲的順序:dcba
    // 這裏要倒置兩次
    while(!feof(file)) {
        tmp = fgetc(file);
        if(tmp != '\n') {
            buf[i % 4] = getIndex(tmp);
            i++;
            if(i % 4 == 0) {
                block.a = buf[3];
                block.b = buf[2];
                block.c = buf[1];
                block.d = buf[0];

                char *tmp;
                char chs[3];
                tmp = (char *)&block;
                chs[0] = tmp[2];
                chs[1] = tmp[1];
                chs[2] = tmp[0];
                fwrite(chs, 1, 3, wfile);
            }
            cout << tmp;
            //fputc(tmp, wfile);
        }
    }

    fclose(file);
    fclose(wfile);

    cout << endl;

    //沒什麼做用,表示結束了,打印下好看
    for(int i=0; i<65; i++) {
        cout << "=";
    }

    return 0;
}
有一點不足,文件最後會出現一次invalid char,多是文件結束符eof吧,沒管它,由於在那以前已經寫入文件了。
相關文章
相關標籤/搜索