1 #ifndef BOOST_NETWORK_UTILS_BASE64_STATEFUL_ITERATOR_HPP
2 #define BOOST_NETWORK_UTILS_BASE64_STATEFUL_ITERATOR_HPP
3 
4 #include <boost/archive/iterators/base64_from_binary.hpp>
5 #include "iterators/stateful_transform_width.hpp"
6 #include "iterators/iterator_with_state.hpp"
7 #include <boost/range/begin.hpp>
8 #include <boost/range/end.hpp>
9 #include <boost/array.hpp>
10 #include <algorithm>
11 #include <iterator>
12 #include <sstream>
13 #include <string>
14 
15 namespace boost {
16 namespace network {
17 namespace utils {
18 
19 // Uses base64_from_binary and stateful_transform_width to implement a
20 // BASE64
21 // converter working on an iterator range.  Based on transform_width, the
22 // stateful_transform_width relies on the end iterator and the encoding
23 // state
24 // stored in the transformed iterator; usually by using the iterator
25 // adaptor
26 // - iterator_with_state.  Storing the encoding state in the transformed
27 // iterator practically means adapting every such iterator, but the
28 // iterators
29 // which wrap the stateful_transform_width, like the base64_from_binary,
30 // do
31 // not need to be re-declared with an extra constructor to pass the end
32 // iterator and the encoding state to an extended transform_width.
33 //
34 // Summarized interface:
35 //
36 // struct state<Value>  {
37 //     bool empty () const;
38 //     void clear();
39 //     unsigned short padding_length() const;
40 // }
41 //
42 // OutputIterator encode(InputIterator begin, InputIterator end,
43 //                       OutputIterator output, State & rest)
44 // OutputIterator encode_rest(OutputIterator output, State & rest)
45 // OutputIterator encode(InputRange const & input, OutputIterator output,
46 //                       State & rest)
47 // OutputIterator encode(char const * value, OutputIterator output,
48 //                       state<char> & rest)
49 // std::basic_string<Char> encode(InputRange const & value, State & rest)
50 // std::basic_string<Char> encode(char const * value, state<char> & rest)
51 //
52 // OutputIterator encode(InputIterator begin, InputIterator end,
53 //                       OutputIterator output)
54 // OutputIterator encode(InputRange const & input, OutputIterator output)
55 // OutputIterator encode(char const * value, OutputIterator output)
56 // std::basic_string<Char> encode(InputRange const & value)
57 // std::basic_string<Char> encode(char const * value) {
58 
59 namespace base64_stateful_iterator {
60 
61 // force using the ostream_iterator from boost::archive to write wide
62 // characters reliably, althoth wchar_t may not be a native character
63 // type
64 using namespace boost::archive::iterators;
65 using namespace boost::network::utils::iterators;
66 
67 template <typename Value>
68 struct state : public state_for_transform_width<Value, 6, 8> {
69   typedef state<Value> this_t;
70   typedef state_for_transform_width<Value, 6, 8> super_t;
71 
stateboost::network::utils::base64_stateful_iterator::state72   state() {}
stateboost::network::utils::base64_stateful_iterator::state73   state(this_t const& source) : super_t(source) {}
74 
padding_lengthboost::network::utils::base64_stateful_iterator::state75   unsigned short padding_length() const {
76     // the BASE64 encoding unit consists of 6 bits; if the 8-bit
77     // input cannot be completely divided to 6-bit chunks, 2 or
78     // 4 bits can remain, which the bit_count returns as displacement
79     // of the 8-bit value (right shift length) - 6 or 4
80     unsigned short bits = super_t::bit_count();
81     return bits > 0 ? 6 / bits : 0;
82   }
83 };
84 
85 template <typename InputIterator, typename OutputIterator, typename State>
86 OutputIterator encode(InputIterator begin, InputIterator end,
87                       OutputIterator output, State& rest) {
88   typedef boost::iterator_with_state<InputIterator, State> stateful_input;
89   // declare the encoding iterator type
90   typedef base64_from_binary<stateful_transform_width<stateful_input, 6, 8> >
91       base64_input;
92   // declare the stateful transforming itarators
93   stateful_input stateful_begin(begin, end, rest), stateful_end(end);
94   // declare the iterator to transform the encoded 6-bit units to the
95   // BASE64 alphabet
96   base64_input base64_begin(stateful_begin), base64_end(stateful_end);
97   return std::copy(base64_begin, base64_end, output);
98 }
99 
100 template <typename State, typename OutputIterator>
encode_rest(OutputIterator output,State & rest)101 OutputIterator encode_rest(OutputIterator output, State& rest) {
102   unsigned short padding_length = rest.padding_length();
103   if (padding_length > 0) {
104     typedef typename State::value_type value_type;
105     // declare the input padding type and the adapted iterator including
106     // the encoding state for it - see below
107     typedef boost::array<value_type, 2> pillow_input;
108     typedef boost::iterator_with_state<typename pillow_input::const_iterator,
109                                        State> stateful_input;
110     // declare the encoding iterator type
111     typedef base64_from_binary<stateful_transform_width<stateful_input, 6, 8> >
112         base64_input;
113     // although containing encoding state to continue with the next
114     // chunk, the stateful_transform_width still reads from the input
115     // iterator and needs the complete quantum for the encoding; the
116     // zero padding will make for an artifitial input ending here
117     pillow_input pillow = {{0, 0}};
118     stateful_input stateful_begin(pillow.begin(), pillow.end(), rest);
119     base64_input base64_begin(stateful_begin);
120     *output++ = *base64_begin;
121     if (padding_length > 0) {
122       *output++ = '=';
123       if (padding_length > 1) *output++ = '=';
124     }
125   }
126   return output;
127 }
128 
129 template <typename InputIterator, typename OutputIterator>
encode(InputIterator begin,InputIterator end,OutputIterator output)130 OutputIterator encode(InputIterator begin, InputIterator end,
131                       OutputIterator output) {
132   state<typename iterator_value<InputIterator>::type> rest;
133   output = encode(begin, end, output, rest);
134   return encode_rest(output, rest);
135 }
136 
137 template <typename InputRange, typename OutputIterator>
encode(InputRange const & input,OutputIterator output)138 OutputIterator encode(InputRange const& input, OutputIterator output) {
139   return encode(boost::begin(input), boost::end(input), output);
140 }
141 
142 template <typename OutputIterator>
encode(char const * value,OutputIterator output)143 OutputIterator encode(char const* value, OutputIterator output) {
144   return encode(value, value + strlen(value), output);
145 }
146 
147 template <typename Char, typename InputRange>
encode(InputRange const & value)148 std::basic_string<Char> encode(InputRange const& value) {
149   std::basic_string<Char> result;
150   encode(value, std::back_inserter(result));
151   return result;
152 }
153 
154 template <typename Char>
encode(char const * value)155 std::basic_string<Char> encode(char const* value) {
156   std::basic_string<Char> result;
157   encode(value, std::back_inserter(result));
158   return result;
159 }
160 
161 }  // namespace base64_stateful_iterator
162 
163 }  // namespace utils
164 }  // namespace network
165 }  // namespace boost
166 
167 #endif  // BOOST_NETWORK_UTILS_BASE64_STATEFUL_ITERATOR_HPP
168