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