web-dev-qa-db-ja.com

ブーストのみを使用して文字列をbase64にエンコードするにはどうすればよいですか?

簡単なASCII stringをbase64(boost :: asioを使用した基本HTTP認証)にすばやくエンコードし、新しいコードコードを貼り付けたり、boostを超えるライブラリを使用したりしないようにしています。

単純な署名は次のようになります:string Base64Encode(const string&text);

繰り返しますが、アルゴリズムは簡単であり、これを行うライブラリ/サンプルが多数あることを認識していますが、クリーンブーストのサンプルを探しています。ブーストシリアル化は見つかりましたが、GoogleやGoogleからの明確な例はありません。 http://www.boost.org/doc/libs/1_46_1/libs/serialization/doc/dataflow.html

実際のbase64アルゴリズムをコードに明示的に追加しなくてもこれは可能ですか?

43
MattiasF

あなたが少し提供したリンクの例を改善しました:

#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/insert_linebreaks.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/archive/iterators/ostream_iterator.hpp>
#include <sstream>
#include <string>


int main()
{
    using namespace boost::archive::iterators;

    std::string test = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce ornare ullamcorper ipsum ac gravida.";

    std::stringstream os;
    typedef 
        insert_linebreaks<         // insert line breaks every 72 characters
            base64_from_binary<    // convert binary values to base64 characters
                transform_width<   // retrieve 6 bit integers from a sequence of 8 bit bytes
                    const char *,
                    6,
                    8
                >
            > 
            ,72
        > 
        base64_text; // compose all the above operations in to a new iterator

    std::copy(
        base64_text(test.c_str()),
        base64_text(test.c_str() + test.size()),
        ostream_iterator<char>(os)
    );

    std::cout << os.str();
}

これにより、72文字ごとに改行でエンコードされたbase64でエンコードされた文字列がコンソールに出力され、電子メールに入れる準備が整います。改行が気に入らない場合は、このままにしてください:

    typedef 
        base64_from_binary<
           transform_width<
                const char *,
                6,
                8
            >
        > 
        base64_text;
38
Tobias Schlegel

これが私の解決策です。このページの他のソリューションと同じ基本的な手法を使用しますが、パディングの問題をよりエレガントな方法で解決します。このソリューションでは、C++ 11も利用しています。

ほとんどのコードは自明だと思います。エンコード関数の数学のビットは、追加する必要がある「=」文字の数を計算します。 val.size()の3を法とする剰余ですが、本当に必要なのは、val.size()と3で割り切れる次の数値との差です。剰余があるため、3から剰余を差し引くことができますが、0が必要な場合は3が残るため、もう一度3をモジュロする必要があります。

#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/algorithm/string.hpp>

std::string decode64(const std::string &val) {
    using namespace boost::archive::iterators;
    using It = transform_width<binary_from_base64<std::string::const_iterator>, 8, 6>;
    return boost::algorithm::trim_right_copy_if(std::string(It(std::begin(val)), It(std::end(val))), [](char c) {
        return c == '\0';
    });
}

std::string encode64(const std::string &val) {
    using namespace boost::archive::iterators;
    using It = base64_from_binary<transform_width<std::string::const_iterator, 6, 8>>;
    auto tmp = std::string(It(std::begin(val)), It(std::end(val)));
    return tmp.append((3 - val.size() % 3) % 3, '=');
}
41
ltc

ブーストbase64エンコードデコードを使用する別のソリューション:

const std::string base64_padding[] = {"", "==","="};
std::string base64_encode(const std::string& s) {
  namespace bai = boost::archive::iterators;

  std::stringstream os;

  // convert binary values to base64 characters
  typedef bai::base64_from_binary
  // retrieve 6 bit integers from a sequence of 8 bit bytes
  <bai::transform_width<const char *, 6, 8> > base64_enc; // compose all the above operations in to a new iterator

  std::copy(base64_enc(s.c_str()), base64_enc(s.c_str() + s.size()),
            std::ostream_iterator<char>(os));

  os << base64_padding[s.size() % 3];
  return os.str();
}

std::string base64_decode(const std::string& s) {
  namespace bai = boost::archive::iterators;

  std::stringstream os;

  typedef bai::transform_width<bai::binary_from_base64<const char *>, 8, 6> base64_dec;

  unsigned int size = s.size();

  // Remove the padding characters, cf. https://svn.boost.org/trac/boost/ticket/5629
  if (size && s[size - 1] == '=') {
    --size;
    if (size && s[size - 1] == '=') --size;
  }
  if (size == 0) return std::string();

  std::copy(base64_dec(s.data()), base64_dec(s.data() + size),
            std::ostream_iterator<char>(os));

  return os.str();
}

次に、テストケースを示します。

    std::string t_e[TESTSET_SIZE] = {
        ""
      , "M"
      , "Ma"
      , "Man"
      , "pleasure."
      , "leasure."
      , "easure."
      , "asure."
      , "sure."
};
std::string t_d[TESTSET_SIZE] = {
        ""
      , "TQ=="
      , "TWE="
      , "TWFu"
      , "cGxlYXN1cmUu"
      , "bGVhc3VyZS4="
      , "ZWFzdXJlLg=="
      , "YXN1cmUu"
      , "c3VyZS4="
};

お役に立てれば

15
flare

ブーストが1.66に達し、ビーストが含まれているので、ビーストの実装を使用できます。

必要な主な関数は次のとおりです。boost::beast::detail::base64_encode() boost::beast::detail::base64_decode()

#include < boost/beast/core/detail/base64.hpp >から

13
Ben

Googleからここに来る人のために、boostに基づくbase64エンコード/デコード機能を紹介します。上記のDanDanのコメントに従って、パディングを正しく処理します。デコード関数は、不正な文字に遭遇すると停止し、その文字へのポインターを返します。これは、jsonまたはxmlでbase64を解析している場合に便利です。

///
/// Convert up to len bytes of binary data in src to base64 and store it in dest
///
/// \param dest Destination buffer to hold the base64 data.
/// \param src Source binary data.
/// \param len The number of bytes of src to convert.
///
/// \return The number of characters written to dest.
/// \remarks Does not store a terminating null in dest.
///
uint base64_encode(char* dest, const char* src, uint len)
{
    char tail[3] = {0,0,0};
    typedef base64_from_binary<transform_width<const char *, 6, 8> > base64_enc;

    uint one_third_len = len/3;
    uint len_rounded_down = one_third_len*3;
    uint j = len_rounded_down + one_third_len;

    std::copy(base64_enc(src), base64_enc(src + len_rounded_down), dest);

    if (len_rounded_down != len)
    {
        uint i=0;
        for(; i < len - len_rounded_down; ++i)
        {
            tail[i] = src[len_rounded_down+i];
        }

        std::copy(base64_enc(tail), base64_enc(tail + 3), dest + j);

        for(i=len + one_third_len + 1; i < j+4; ++i)
        {
            dest[i] = '=';
        }

        return i;
    }

    return j;
}

///
/// Convert null-terminated string src from base64 to binary and store it in dest.
///
/// \param dest Destination buffer
/// \param src Source base64 string
/// \param len Pointer to unsigned int representing size of dest buffer. After function returns this is set to the number of character written to dest.
///
/// \return Pointer to first character in source that could not be converted (the terminating null on success)
///
const char* base64_decode(char* dest, const char* src, uint* len)
{
    uint output_len = *len;

    typedef transform_width<binary_from_base64<const char*>, 8, 6> base64_dec;

    uint i=0;
    try
    {
        base64_dec src_it(src);
        for(; i < output_len; ++i)
        {
            *dest++ = *src_it;
            ++src_it;
        }
    }
    catch(dataflow_exception&)
    {
    }

    *len = i;
    return src + (i+2)/3*4; // bytes in = bytes out / 3 rounded up * 4
}
6
Eloff

エンコードは機能しますが、デコーダーは確かに壊れています。また、バグが開いています: https://svn.boost.org/trac/boost/ticket/5629 。私はその修正を見つけていません。

3
user434345

私のプラットフォームでは機能しないため、Answer 8を変更しました。

const std::string base64_padding[] = {"", "==","="};
std::string *m_ArchiveData;

/// \brief  To Base64 string
bool Base64Encode(string* output) 
{  
    try
    {
        UInt32 iPadding_Mask = 0;
        typedef boost::archive::iterators::base64_from_binary
            <boost::archive::iterators::transform_width<const char *, 6, 8> > Base64EncodeIterator;  
        UInt32 len = m_ArchiveData->size();
        std::stringstream os;

        std::copy(Base64EncodeIterator(m_ArchiveData->c_str()), 
            Base64EncodeIterator(m_ArchiveData->c_str()+len), 
            std::ostream_iterator<char>(os));

        iPadding_Mask = m_ArchiveData->size() % 3;
        os << base64_padding[iPadding_Pask];

        *output = os.str();
        return output->empty() == false;  
    }
    catch (...)
    {
        PLOG_ERROR_DEV("unknown error happens");
        return false;
    }
}  

/// \brief  From Base64 string
bool mcsf_data_header_byte_stream_archive::Base64Decode(const std::string *input) 
{  
    try
    {
        std::stringstream os;
        bool bPaded = false;
        typedef boost::archive::iterators::transform_width<boost::archive::iterators::
            binary_from_base64<const char *>, 8, 6> Base64DecodeIterator;  

        UInt32 iLength = input->length();
        // Remove the padding characters, cf. https://svn.boost.org/trac/boost/ticket/5629
        if (iLength && (*input)[iLength-1] == '=') {
            bPaded = true;
            --iLength;
            if (iLength && (*input)[iLength - 1] == '=') 
            {
                --iLength;
            }
        }
        if (iLength == 0)
        {
            return false;
        }

        if(bPaded)
        {
            iLength --;
        }

        copy(Base64DecodeIterator(input->c_str()) ,
            Base64DecodeIterator(input->c_str()+iLength), 
            ostream_iterator<char>(os)); 

        *m_ArchiveData = os.str();
        return m_ArchiveData->empty() == false;
    }
    catch (...)
    {
        PLOG_ERROR_DEV("unknown error happens");
        return false;
    }
}  
0
Richardicy

Base64エンコードテキストとデータ

const std::string base64_padding[] = {"", "==","="};

std::string base64EncodeText(std::string text) {
    using namespace boost::archive::iterators;
    typedef std::string::const_iterator iterator_type;
    typedef base64_from_binary<transform_width<iterator_type, 6, 8> > base64_enc;
    std::stringstream ss;
    std::copy(base64_enc(text.begin()), base64_enc(text.end()), ostream_iterator<char>(ss));
    ss << base64_padding[text.size() % 3];
    return ss.str();
}

std::string base64EncodeData(std::vector<uint8_t> data) {
    using namespace boost::archive::iterators;
    typedef std::vector<uint8_t>::const_iterator iterator_type;
    typedef base64_from_binary<transform_width<iterator_type, 6, 8> > base64_enc;
    std::stringstream ss;
    std::copy(base64_enc(data.begin()), base64_enc(data.end()), ostream_iterator<char>(ss));
    ss << base64_padding[data.size() % 3];
    return ss.str();
}
0
neoneye