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