読者です 読者をやめる 読者になる 読者になる

C++ による base64 エンコード/デコード

C++

C++base64エンコード/デコードするプログラムを作成したので紹介します.以下に実装する関数 encode_base64/decode_base64 を用いればバイト列(std::vector),プレインテキスト(std::string) 間でデータを変換できます.
base64 については「Base64」に分かりやすくまとめられているので,内部の動きについて知りたい方は是非ご覧下さい.
それでは以下に私の実装を示します.

base64.hpp

#ifndef BASE64_HPP_20100908_
#define BASE64_HPP_20100908_

#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif


#include <string>
#include <vector>


namespace algorithm {
    bool encode_base64(const std::vector<unsigned char>& src, std::string& dst);
    bool decode_base64(const std::string& src, std::vector<unsigned char>& dst);
}


#endif

base64.cpp

#include "base64.hpp"


// base64 エンコード
bool algorithm::encode_base64(const std::vector<unsigned char>& src, std::string& dst)
{
    const std::string table("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
    std::string       cdst;

    for (std::size_t i = 0; i < src.size(); ++i) {
        switch (i % 3) {
        case 0:
            cdst.push_back(table[(src[i] & 0xFC) >> 2]);
            if (i + 1 == src.size()) {
                cdst.push_back(table[(src[i] & 0x03) << 4]);
                cdst.push_back('=');
                cdst.push_back('=');
            }

            break;
        case 1:
            cdst.push_back(table[((src[i - 1] & 0x03) << 4) | ((src[i + 0] & 0xF0) >> 4)]);
            if (i + 1 == src.size()) {
                cdst.push_back(table[(src[i] & 0x0F) << 2]);
                cdst.push_back('=');
            }

            break;
        case 2:
            cdst.push_back(table[((src[i - 1] & 0x0F) << 2) | ((src[i + 0] & 0xC0) >> 6)]);
            cdst.push_back(table[src[i] & 0x3F]);

            break;
        }
    }

    dst.swap(cdst);

    return true;
}


// base64 デコード
bool algorithm::decode_base64(const std::string& src, std::vector<unsigned char>& dst)
{
    if (src.size() & 0x00000003) {
        return false;
    }
    else {
        const std::string          table("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
        std::vector<unsigned char> cdst;

        for (std::size_t i = 0; i < src.size(); i += 4) {
            if (src[i + 0] == '=') {
                return false;
            }
            else if (src[i + 1] == '=') {
                return false;
            }
            else if (src[i + 2] == '=') {
                const std::string::size_type s1 = table.find(src[i + 0]);
                const std::string::size_type s2 = table.find(src[i + 1]);

                if (s1 == std::string::npos || s2 == std::string::npos) {
                    return false;
                }

                cdst.push_back(static_cast<unsigned char>(((s1 & 0x3F) << 2) | ((s2 & 0x30) >> 4)));

                break;
            }
            else if (src[i + 3] == '=') {
                const std::string::size_type s1 = table.find(src[i + 0]);
                const std::string::size_type s2 = table.find(src[i + 1]);
                const std::string::size_type s3 = table.find(src[i + 2]);

                if (s1 == std::string::npos || s2 == std::string::npos || s3 == std::string::npos) {
                    return false;
                }

                cdst.push_back(static_cast<unsigned char>(((s1 & 0x3F) << 2) | ((s2 & 0x30) >> 4)));
                cdst.push_back(static_cast<unsigned char>(((s2 & 0x0F) << 4) | ((s3 & 0x3C) >> 2)));

                break;
            }
            else {
                const std::string::size_type s1 = table.find(src[i + 0]);
                const std::string::size_type s2 = table.find(src[i + 1]);
                const std::string::size_type s3 = table.find(src[i + 2]);
                const std::string::size_type s4 = table.find(src[i + 3]);

                if (s1 == std::string::npos || s2 == std::string::npos || s3 == std::string::npos || s4 == std::string::npos) {
                    return false;
                }

                cdst.push_back(static_cast<unsigned char>(((s1 & 0x3F) << 2) | ((s2 & 0x30) >> 4)));
                cdst.push_back(static_cast<unsigned char>(((s2 & 0x0F) << 4) | ((s3 & 0x3C) >> 2)));
                cdst.push_back(static_cast<unsigned char>(((s3 & 0x03) << 6) | ((s4 & 0x3F) >> 0)));
            }
        }

        dst.swap(cdst);

        return true;
    }
}

base64.cpp に base64 エンコード/デコードをする関数 encode_base64/decode_base64 を実装しました.base64.cpp をプロジェクトに加え(他のソースコードと一緒にコンパイル),base64.hpp を include することにより encode_base64/decode_base64 が使用可能になります.
以下のテストコードで encode_base64/decode_base64 の動作を確認できます.

test.cpp

#include <iostream>
#include <iomanip>
#include <vector>
#include "base64.hpp"


int main()
{
    std::vector<unsigned char> v1, v2;

    v1.push_back(0xde);
    v1.push_back(0xad);
    v1.push_back(0xbe);
    v1.push_back(0xef);

    std::string s;

    algorithm::encode_base64(v1, s); // base64 エンコード
    std::cout << s << std::endl; // 3q2+7w==

    algorithm::decode_base64(s, v2); // base64 デコード
    for (std::vector<unsigned char>::const_iterator it = v2.begin(); it != v2.end(); ++it) {
        std::cout << std::hex << static_cast<int>(*it);
    } // deadbeef

    return 0;
}

以上です.
非常に単純な記事ですが,少しでもお役に立てると幸いです.