1 #ifndef BOOST_NETWORK_UTILS_BASE64_STATELESS_HPP
2 #define BOOST_NETWORK_UTILS_BASE64_STATELESS_HPP
3 
4 #include <boost/archive/iterators/base64_from_binary.hpp>
5 #include <boost/archive/iterators/transform_width.hpp>
6 #include <boost/range/begin.hpp>
7 #include <boost/range/end.hpp>
8 #include <algorithm>
9 #include <iterator>
10 #include <string>
11 
12 namespace boost {
13 namespace network {
14 namespace utils {
15 
16 // Uses base64_from_binary and transform_width to implement a BASE64
17 // converter working on an iterator range.  While it is a nice example
18 // of code reuse, the input sequence must either end at the three-byte
19 // boundary or be padded with a zero, otherwise the transforming
20 // iterator tries to read behind the end iterator.
21 //
22 // Summarized interface:
23 //
24 // OutputIterator encode(InputIterator begin, InputIterator end,
25 //                       OutputIterator output)
26 // OutputIterator encode(InputRange const & input, OutputIterator output)
27 // OutputIterator encode(char const * value, OutputIterator output)
28 // std::basic_string<Char> encode(InputRange const & value)
29 // std::basic_string<Char> encode(char const * value)
30 
31 namespace base64_stateless {
32 
33 // force using the ostream_iterator from boost::archive to write wide
34 // characters reliably, although wchar_t may not be a native character
35 // type
36 using namespace boost::archive::iterators;
37 
38 template <typename InputIterator, typename OutputIterator>
encode(InputIterator begin,InputIterator end,OutputIterator output)39 OutputIterator encode(InputIterator begin, InputIterator end,
40                       OutputIterator output) {
41   // declare the encoding iterator type
42   typedef base64_from_binary<transform_width<InputIterator, 6, 8> > base64_text;
43   base64_text base64_begin(begin), base64_end(end);
44   // iterate through the input by the encoding iterator one encoded
45   // unit at a time to learn how many units were encoded without
46   // requiring neither the input iterators nor the output ones to be
47   // random access iterators (supporting subtraction end - begin)
48   std::size_t encoded_count = 0;
49   while (base64_begin != base64_end) {
50     *output++ = *base64_begin++;
51     ++encoded_count;
52   }
53   // the encoding iterator advanced so many times as is the encoded
54   // output
55   // size, but the padding is determined by the number of bytes in the
56   // last
57   // (incomplete) input byte-triplet; first compute the input length and
58   // then how many trailing bytes followed the last complete quantum
59   std::size_t incomplete_length = encoded_count * 6 / 8 % 3;
60   if (incomplete_length > 0) {
61     *output++ = '=';
62     if (incomplete_length < 2) *output++ = '=';
63   }
64   return output;
65 }
66 
67 template <typename InputRange, typename OutputIterator>
encode(InputRange const & input,OutputIterator output)68 OutputIterator encode(InputRange const& input, OutputIterator output) {
69   return encode(boost::begin(input), boost::end(input), output);
70 }
71 
72 template <typename OutputIterator>
encode(char const * value,OutputIterator output)73 OutputIterator encode(char const* value, OutputIterator output) {
74   return encode(value, value + strlen(value), output);
75 }
76 
77 template <typename Char, typename InputRange>
encode(InputRange const & value)78 std::basic_string<Char> encode(InputRange const& value) {
79   std::basic_string<Char> result;
80   encode(value, std::back_inserter(result));
81   return result;
82 }
83 
84 template <typename Char>
encode(char const * value)85 std::basic_string<Char> encode(char const* value) {
86   std::basic_string<Char> result;
87   encode(value, std::back_inserter(result));
88   return result;
89 }
90 
91 }  // namespace base64_stateless
92 
93 }  // namespace utils
94 }  // namespace network
95 }  // namespace boost
96 
97 #endif  // BOOST_NETWORK_UTILS_BASE64_STATELESS_HPP
98