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

元サイト
http://yano.hatenadiary.jp/entry/20100908/1283945820


消えたら困るのでメモ

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;
    }
}

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;
}