【C++】base64でバイナリデータをascii文字列に変換する



タイトルの通り。以下コード

ヘッダーファイル

//mybase64.hpp

#include<string>

//binary -> ascii
std::string base64encode(const std::string &str){
    static const char cvt[65]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    std::string res;
    uint8_t phase=0;
    uint8_t b;
    for(char ch : str){
        switch(phase){
            case 0:
            {
                b = ch>>2 & 0b111111;
                res+=cvt[b];
                b = (ch&0b11)<<4;
            } break;
            case 1:
            {
                b += ch>>4 & 0b1111;
                res+=cvt[b];
                b = (ch&0b1111)<<2;
            } break;
            case 2:
            {
                b += ch>>6 & 0b11;
                res+=cvt[b];
                b = ch&0b111111;
                res+=cvt[b];
                b = 0;
            } break;
        }
        phase=(phase+1)%3;
    }
    if(phase>0){
        res+=cvt[b];
    }
    if(res.length()%4>0){
        for(int i=res.length()%4; i<4; i++){
            res+='=';
        }
    }
    return res;
}

//ascii -> binary
std::string base64decode(const std::string &str){
    std::string res;
    uint8_t phase=0;
    char b;
    uint8_t tmp;
    for(char ch : str){
        uint8_t tmp=0;
        if(ch>='A' && ch<='Z'){
            tmp=ch-'A';
        }else if(ch>='a' && ch<='z'){
            tmp=ch-'a'+26;
        }else if(ch>='0' && ch<='9'){
            tmp=ch-'0'+52;
        }else if(ch=='+'){
            tmp=62;
        }else if(ch=='/'){
            tmp=63;
        }else if(ch=='='){
            if(phase==1) res += b;
            break;
        }else{
            res="";
            phase=0;
            break;
        }
        switch(phase){
            case 0:
            {
                b = tmp<<2;
            }break;
            case 1:
            {
                b += tmp>>4 & 0b11;
                res += b;
                b = (tmp&0b1111)<<4;
            }break;
            case 2:
            {
                b += tmp>>2 & 0b1111;
                res += b;
                b = (tmp&0b11)<<6;
            }break;
            case 3:
            {
                b += tmp & 0b111111;
                res += b;
            }break;
        }
        phase=(phase+1)%4;
    }
    return res;
}


バイナリデータの入出力もstd::stringでやってるけど、 1byteずつデータ処理できるならvector<char> とかvector<uint8_t>とかなんでもいいと思う。 8bitずつ区切られたデータの並びから6bitずつ取り出していくので、ちょっと面倒くさい。

プログラム


文字列

//sample1.cpp
#includ<iostream>
#include<string>
#include"mybase64.hpp"
int main(){
    std::string a="Hello, World!";
    std::string b=base64encode(s);
    std::string c=base64decode(e);
    std::cout << a << std::endl;
    std::cout << b << std::endl;
    std::cout << c << std::endl;

    return 0;
}
//出力
//Hello, World!
//SGVsbG8sIFdvcmxkIQ==
//Hello, World!


ファイル読み書き

//sample2.cpp
#include&lt;fstream&gt;
#include&lt;string&gt;
#include"mybase64.hpp"
int main(){
    std::ifstream ifs;
    std::ofstream ofs;

    ifs.open("sample.hoge",std::ios::binary);
    //std::ios::binaryでバイナリモード指定

    if(!ifs.is_open()){
        std::cout << "file not exist\n";
        exit(1);
    }
    std::string in;
    while(true){
        char ch=ifs.get();
        //ifs >> ch; だと正しく読み込めなかった

        if(ifs.eof()){
            break;
        }else{
            in+=ch;
        }
    }
    ifs.close();
    std::string en=base64encode(in);
    std::string de=base64decode(en);

    ofs.open("sample_base64encode.txt");
    ofs << en;
    ofs.close();

    ofs.open("sample_base64decode.hoge",std::ios::binary);
    ofs.write(de.c_str(),de.length());
    //ここも ofs << de; では正しく出力できない
    ofs.close();

    return 0;
}


参考

base64ってなんぞ??理解のために実装してみた


#C++ 

投稿日時 : 2022/01/20 19:51