Click here to Skip to main content
15,896,278 members
Articles / Programming Languages / C++

Base64 Encoder and Boost

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
3 Apr 2012CPOL 32.2K   4   2
Base64 Encoder and Boost

Well, I was looking for a Base64 library recently, and I thought, “I know, I bet it is in Boost, I have Boost, and Boost has everything.” And it turns out that it does! Kind of. But it’s a bit odd and sadly incomplete.

So let’s fix it.

To start with, I didn’t really have a clue how to plug these Boost components together, so a quick scout on the beloved StackOverflow (a Programmer’s Guide to the Galaxy) yields the following code, which I have slightly modified:

using namespace boost::archive::iterators;

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

Disgusting, isn’t it? It also doesn’t work. It will only work when the data you use is a multiple of three, so we’ll have to pad it ourselves. Here’s the full code for that:

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

namespace Base64Utilities
{
  std::string ToBase64(std::vector<unsigned char> data)
  {
    using namespace boost::archive::iterators;

    // Pad with 0 until a multiple of 3
    unsigned int paddedCharacters = 0;
    while(data.size() % 3 != 0)
    {
      paddedCharacters++;
      data.push_back(0x00);
    }

    // Crazy typedef black magic
    typedef
      insert_linebreaks<         // insert line breaks every 76 characters
        base64_from_binary<    // convert binary values to base64 characters
          transform_width<   // retrieve 6 bit integers from a sequence of 8 bit bytes
            const unsigned char *
            ,6
            ,8
            >
          >
          ,76
        >
        base64Iterator; // compose all the above operations in to a new iterator

    // Encode the buffer and create a string
    std::string encodedString(
      base64Iterator(&data[0]),
      base64Iterator(&data[0] + (data.size() - paddedCharacters)));

    // Add '=' for each padded character used
    for(unsigned int i = 0; i < paddedCharacters; i++)
    {
      encodedString.push_back('=');
    }

    return encodedString;
  }
}

It’s not that elegant but it seems to work. Can you improve on this code? Can you write the decode function? Check your answers with this excellent Online Base64 Converter.
Leave your comments below! 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Web Biscuit
United Kingdom United Kingdom
At Web Biscuit, you can find software, articles, a good dollop of quality and an unhealthy obsession over biscuits.
Website: http://www.webbiscuit.co.uk
Twitter Watch: http://twitter.com/WebBiscuitCoUk

Comments and Discussions

 
QuestionUsing raw poiners as iterators is bad form Pin
Oded Arbel4-Nov-13 9:22
Oded Arbel4-Nov-13 9:22 
QuestionSame bug, same place Pin
net_storm3-Oct-13 2:05
net_storm3-Oct-13 2:05 
Damn, stuck on the same issue, Man!
I wonder why boost developers cannot fix it starting from 2008!
My version is following:

C++
static const std::string encode_base64(byte_sequence_t & buffer)
{
    // Warning : Boost implementation of Base64 is incomplete and missing padding '=' insertion
    // http://lists.boost.org/Archives/boost/2008/07/139814.php
    // Additionally boost have bug when processing sequence which size % 3 != 0
    // we can workaround this by adding extra bytes to the end of it
    std::size_t sequence_len = buffer.size(); // original sequence size
    buffer.resize(sequence_len + sequence_len % 3); // to make boost happy

    using namespace boost::archive::iterators;
    typedef byte_sequence_t::const_iterator itr_type;
    typedef transform_width<itr_type, 6, 8> take_6_bits; // retrieves 6 bit integers from a sequence of 8 bit bytes
    typedef base64_from_binary<take_6_bits> to_base64;   // converts binary values at base64 characters

    std::string base64_encoded(to_base64(buffer.begin()), to_base64(buffer.begin() + sequence_len));
    // here we calculating padding sequence at the end of the sequence:
    // we must add '=' if there is only 2 remaining bytes or '==' if 1
    const std::size_t padding_chars_count = ( 3 - sequence_len % 3 ) % 3;
    return base64_encoded.append(padding_chars_count, '=');
}

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.