Re: [Boost-bugs] [Boost C++ Libraries] #5629: base64 encode/decode for std::istreambuf_iterator/std::ostreambuf_iterator

Subject: Re: [Boost-bugs] [Boost C++ Libraries] #5629: base64 encode/decode for std::istreambuf_iterator/std::ostreambuf_iterator
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2012-12-14 14:51:08


#5629: base64 encode/decode for std::istreambuf_iterator/std::ostreambuf_iterator
--------------------------------+-------------------------------------------
  Reporter: nen777w@… | Owner: ramey
      Type: Bugs | Status: assigned
 Milestone: To Be Determined | Component: serialization
   Version: Boost 1.45.0 | Severity: Problem
Resolution: | Keywords:
--------------------------------+-------------------------------------------

Comment (by iGene):

 The root cause is that sequences whose size doesn't divide by four get a
 buffer overrun.
 Here is my workaround.


 {{{

 #include <sstream>
 #include <cassert>

 struct to_base64 : public std::stringstream {
         to_base64(const std::string& str);
         to_base64(const char* begin, const char* end);
 };

 struct from_base64 : public std::stringstream {
         from_base64(const std::string& str);
         from_base64(const char* begin, const char* end);
 };

 #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/archive/iterators/ostream_iterator.hpp>

 // slightly generalized version of the example here:
 // http://stackoverflow.com/questions/7053538/how-do-i-encode-a-string-to-
 base64-using-only-boost

 template <typename TransformIterator>
 static void apply(const char* begin, const char* end, std::stringstream&
 target) {
         std::copy(TransformIterator(begin), TransformIterator(end),
 std::ostreambuf_iterator<char>(target));
 }
 template <typename TransformIterator>
 static void applyTwice(const char* begin, const char* end,
 std::stringstream& target) {
         long size = end - begin;
         int remainder = size % 4;
         const char* truncated = end - remainder;
         apply<TransformIterator>(begin, truncated, target);
         if (remainder) {
                 assert(remainder != 1); /* it can never be =1 if this
 whole thing about dividing by four is correct */
                 char padded[4] = { 'A', 'A', 'A', 'A' };
                 const char* src = truncated;
                 char* dest = &padded[0];
                 while (src != end)
                         *(dest++) = *(src++);
                 apply<TransformIterator>(&padded[0],
 &padded[sizeof(padded)], target);
                 std::ios::streampos pos = target.tellp();
                 pos -= (4 - remainder);
                 target.seekp(pos);
         }
 }

 using namespace boost::archive::iterators;

 typedef base64_from_binary<transform_width<const char*, 6, 8> > to;
 to_base64::to_base64(const char* begin, const char* end) {
 apply<to>(begin, end, *this); }
 to_base64::to_base64(const std::string& str) { apply<to>(str.c_str(),
 str.c_str() + str.length(), *this); }

 typedef transform_width<binary_from_base64<const char*>, 8, 6> from;
 from_base64::from_base64(const char* begin, const char* end) {
 applyTwice<from>(begin, end, *this); }
 from_base64::from_base64(const std::string& str) {
 applyTwice<from>(str.c_str(), str.c_str() + str.length(), *this); }

 int main()
 {
         size_t length = 0;
         do {
                 // generate source bytes
                 char source[RAND_MAX + 1];
                 for (size_t pos = 0; pos < length; ++pos)
                         source[pos] = '0' + char(rand() % 32);
                 source[length] = '\0';
                 // convert them to base64
                 to_base64 b(&source[0], &source[length]);
                 std::string b64 = b.str();
                 // and convert them back
                 from_base64 result(b64.c_str(), b64.c_str() + b64.size());
                 // compare as binary
                 size_t size = (size_t)result.tellp();
                 assert(size == length);
                 char dest[RAND_MAX];
                 result.read(&dest[0], size);
                 for (size_t pos = 0; pos < length; ++pos)
                         assert(source[pos] == dest[pos]);
                 // compare as text
                 std::string asString = result.str();
                 assert(!strcmp(asString.c_str(), &source[0]));
         } while (++length < 100);

         return 0;
 }

 }}}

-- 
Ticket URL: <https://svn.boost.org/trac/boost/ticket/5629#comment:7>
Boost C++ Libraries <http://www.boost.org/>
Boost provides free peer-reviewed portable C++ source libraries.

This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:11 UTC