|
| 1 | +#ifndef BOOST_NETWORK_UTILS_BASE64_ENCODE_IO_HPP |
| 2 | +#defineBOOST_NETWORK_UTILS_BASE64_ENCODE_IO_HPP |
| 3 | + |
| 4 | +#include<boost/network/utils/base64/encode.hpp> |
| 5 | +#include<boost/archive/iterators/ostream_iterator.hpp> |
| 6 | +#include<boost/range/begin.hpp> |
| 7 | +#include<boost/range/end.hpp> |
| 8 | +#include<iterator> |
| 9 | + |
| 10 | +namespaceboost { |
| 11 | +namespacenetwork { |
| 12 | +namespaceutils { |
| 13 | + |
| 14 | +// Offers an interface to the BASE64 converter from encode.hpp, which is |
| 15 | +// based on stream manipulators to be friendly to the usage with output |
| 16 | +// streams combining heterogenous output by using the output operators. |
| 17 | +// The encoding state is serialized to long and maintained in te extensible |
| 18 | +// internal array of the output stream. |
| 19 | +// |
| 20 | +// Summarized interface - ostream manipulators and one function: |
| 21 | +// |
| 22 | +// encode(InputIterator begin, InputIterator end) |
| 23 | +// encode(InputRange const & value) |
| 24 | +// encode(char const * value) |
| 25 | +// encode_rest |
| 26 | +// clear_state |
| 27 | +// bool empty_state(std::basic_ostream<Char> & output) |
| 28 | + |
| 29 | +namespacebase64 { |
| 30 | +namespaceio { |
| 31 | + |
| 32 | +// force using the ostream_iterator from boost::archive to write wide |
| 33 | +// characters reliably, althoth wchar_t may not be a native character type |
| 34 | +usingnamespaceboost::archive::iterators; |
| 35 | + |
| 36 | +namespacedetail { |
| 37 | + |
| 38 | +// Enables transferring of the input sequence for the BASE64 encoding into |
| 39 | +// the ostream operator defined for it, which performs the operation. It |
| 40 | +// is to be used from ostream manipulators. |
| 41 | +// |
| 42 | +// std::basic_ostream<Char> & output = ...; |
| 43 | +// output << input_wrapper<InputIterator>(value.begin(), value.end()); |
| 44 | +template<typename InputIterator> |
| 45 | +structinput_wrapper { |
| 46 | +input_wrapper(InputIterator begin, InputIterator end) |
| 47 | + : begin(begin), end(end) {} |
| 48 | + |
| 49 | +private: |
| 50 | + InputIterator begin, end; |
| 51 | + |
| 52 | +// only encoding of an input sequence needs access to it |
| 53 | +template< |
| 54 | +typename Char, |
| 55 | +typename InputIterator2 |
| 56 | + > |
| 57 | +friend std::basic_ostream<Char> & |
| 58 | +operator <<(std::basic_ostream<Char> & output, |
| 59 | + input_wrapper<InputIterator2> input_wrapper); |
| 60 | +}; |
| 61 | + |
| 62 | +// The output stream state should be used only in a single scope around |
| 63 | +// encoding operations. Constructor performs initialization from the |
| 64 | +// output stream internal extensible array and destructor updates it |
| 65 | +// according to the encoding result. It inherits from the base64::state |
| 66 | +// to gain access to its protected members and allow easy value passing |
| 67 | +// to base64::encode. |
| 68 | +// |
| 69 | +// |
| 70 | +// std::basic_ostream<Char> & output = ...; |
| 71 | +// { |
| 72 | +// state<Char, Value> rest(output); |
| 73 | +// base64::encode(..., ostream_iterator<Char>(output), rest); |
| 74 | +// } |
| 75 | +template<typename Char,typename Value> |
| 76 | +structstate :publicboost::network::utils::base64::state<Value> { |
| 77 | +typedef boost::network::utils::base64::state<Value>super_t; |
| 78 | + |
| 79 | +// initialize the (inherited) contents of the base64::state<> from the |
| 80 | +// output stream internal extensible array |
| 81 | +state(std::basic_ostream<Char> & output) :super_t(), output(output) { |
| 82 | +constunsigned triplet_index_size =sizeof(super_t::triplet_index) *8; |
| 83 | +unsignedlong data =static_cast<unsignedlong>(storage()); |
| 84 | +// mask the long value with the bit-size of the triplet_index member |
| 85 | +super_t::triplet_index = data & ((1 << triplet_index_size) -1); |
| 86 | +// shift the long value right to remove the the triplet_index value; |
| 87 | +// masking is not necessary because the last_encoded_value it is the |
| 88 | +// last record stored in the data value |
| 89 | +super_t::last_encoded_value = data >> triplet_index_size; |
| 90 | + } |
| 91 | + |
| 92 | +// update the value in the output stream internal extensible array by |
| 93 | +// the last (inherited) contents of the base64::state<> |
| 94 | +~state() { |
| 95 | +constunsigned triplet_index_size =sizeof(super_t::triplet_index) *8; |
| 96 | +// store the last_encoded_value in the data value first |
| 97 | +unsignedlong data = |
| 98 | +static_cast<unsignedlong>(super_t::last_encoded_value); |
| 99 | +// shift the long data value left to make place for storing the |
| 100 | +// full triplet_index value there |
| 101 | + data <<= triplet_index_size; |
| 102 | + data |=static_cast<unsignedlong>(super_t::triplet_index); |
| 103 | +storage() =static_cast<long>(data); |
| 104 | + } |
| 105 | + |
| 106 | +private: |
| 107 | +// all data of the base64::state<> must be serializable into a long |
| 108 | +// value allocated in the output stream internal extensible array |
| 109 | +BOOST_STATIC_ASSERT(sizeof(super_t) <=sizeof(long)); |
| 110 | + |
| 111 | +// allow only the construction with an output stream (strict RAII) |
| 112 | +state(); |
| 113 | +state(state<Char, Value>const & source); |
| 114 | + |
| 115 | + std::basic_ostream<Char> & output; |
| 116 | + |
| 117 | +long &storage() { |
| 118 | +staticint index =std::ios_base::xalloc(); |
| 119 | +return output.iword(index); |
| 120 | + } |
| 121 | +}; |
| 122 | + |
| 123 | +// Output operator implementing the BASE64 encoding for an input sequence |
| 124 | +// which was wrapped by the ostream manipulator; the state must be preserved |
| 125 | +// because multiple sequences can be sent in the ouptut by this operator. |
| 126 | +template< |
| 127 | +typename Char, |
| 128 | +typename InputIterator |
| 129 | + > |
| 130 | +std::basic_ostream<Char> & |
| 131 | +operator <<(std::basic_ostream<Char> & output, |
| 132 | + input_wrapper<InputIterator> input) { |
| 133 | +typedeftypename iterator_value<InputIterator>::type value_type; |
| 134 | + state<Char, value_type>rest(output); |
| 135 | +base64::encode(input.begin, input.end, ostream_iterator<Char>(output), rest); |
| 136 | +return output; |
| 137 | +} |
| 138 | + |
| 139 | +}// namespace detail |
| 140 | + |
| 141 | +// Encoding ostream manipulator for sequences specified by the pair of begin |
| 142 | +// and end iterators. |
| 143 | +// |
| 144 | +// std::vector<unsigned char> buffer = ...; |
| 145 | +// std::basic_ostream<Char> & output = ...; |
| 146 | +// output << base64::io::encode(buffer.begin(), buffer.end()) << ... << |
| 147 | +// base64::io::encode_rest<unsigned char>; |
| 148 | +template<typename InputIterator> |
| 149 | +detail::input_wrapper<InputIterator>encode(InputIterator begin, |
| 150 | + InputIterator end) { |
| 151 | +return detail::input_wrapper<InputIterator>(begin, end); |
| 152 | +} |
| 153 | + |
| 154 | +// Encoding ostream manipulator processing whole sequences which either |
| 155 | +// support begin() and end() methods returning boundaries of the sequence |
| 156 | +// or the boundaries can be computed by the Boost::Range. |
| 157 | +// |
| 158 | +// Warning: Buffers identified by C-pointers are processed including their |
| 159 | +// termination character, if they have any. This is unexpected at least |
| 160 | +// for the storing literals, which have a specialization here to avoid it. |
| 161 | +// |
| 162 | +// std::vector<unsigned char> buffer = ...; |
| 163 | +// std::basic_ostream<Char> & output = ...; |
| 164 | +// output << base64::io::encode(buffer) << ... << |
| 165 | +// base64::io::encode_rest<unsigned char>; |
| 166 | +template<typename InputRange> |
| 167 | +detail::input_wrapper<typename boost::range_const_iterator<InputRange>::type> |
| 168 | +encode(InputRangeconst & value) { |
| 169 | +typedeftypename boost::range_const_iterator<InputRange>::type InputIterator; |
| 170 | +return detail::input_wrapper<InputIterator>(boost::begin(value), |
| 171 | +boost::end(value)); |
| 172 | +} |
| 173 | + |
| 174 | +// Encoding ostream manipulator processing string literals; the usual |
| 175 | +// expectation from their encoding is processing only the string content |
| 176 | +// without the terminating zero character. |
| 177 | +// |
| 178 | +// std::basic_ostream<Char> & output = ...; |
| 179 | +// output << base64::io::encode("ab") << ... << base64::io::encode_rest<char>; |
| 180 | +inline detail::input_wrapper<charconst *>encode(charconst * value) { |
| 181 | +return detail::input_wrapper<charconst *>(value, value +strlen(value)); |
| 182 | +} |
| 183 | + |
| 184 | +// Encoding ostream manipulator which finishes encoding of the previously |
| 185 | +// processed chunks. If their total byte-length was divisible by three, |
| 186 | +// nothing is needed, if not, the last quantum will be encoded as if padded |
| 187 | +// with zeroes, which will be indicated by appending '=' characters to the |
| 188 | +// output. This manipulator must be always used at the end of encoding, |
| 189 | +// after previous usages of the encode manipulator. |
| 190 | +// |
| 191 | +// std::basic_ostream<Char> & output = ...; |
| 192 | +// output << base64::io::encode("ab") << ... << base64::io::encode_rest<char>; |
| 193 | +template<typename Value,typename Char> |
| 194 | +std::basic_ostream<Char> &encode_rest(std::basic_ostream<Char> & output) { |
| 195 | + detail::state<Char, Value>rest(output); |
| 196 | +base64::encode_rest(ostream_iterator<Char>(output), rest); |
| 197 | +return output; |
| 198 | +} |
| 199 | + |
| 200 | +// Clears the encoding state in the internal array of the output stream. |
| 201 | +// Use it to re-use a state object in an unknown state only; Encoding of |
| 202 | +// the last chunk must be followed by encode_rest otherwise the end of the |
| 203 | +// input sequence may be missing in the encoded output. The encode_rest |
| 204 | +// ensures that the rest of the input sequence will be encoded corectly and |
| 205 | +// the '=' padding applied as necessary. The encode rest clears the state |
| 206 | +// when finished. |
| 207 | +// |
| 208 | +// std::basic_ostream<Char> & output = ...; |
| 209 | +// output << base64::io::encode("ab") << ...; |
| 210 | +// output << clear_state<char>; |
| 211 | +template<typename Value,typename Char> |
| 212 | +std::basic_ostream<Char> &clear_state(std::basic_ostream<Char> & output) { |
| 213 | + detail::state<Char, Value>rest(output); |
| 214 | + rest.clear(); |
| 215 | +return output; |
| 216 | +} |
| 217 | + |
| 218 | +// Checks if the encoding state in the internal array of the output stream |
| 219 | +// is empty. |
| 220 | +// |
| 221 | +// std::basic_ostream<Char> & output = ...; |
| 222 | +// output << base64::io::encode("ab") << ...; |
| 223 | +// bool is_complete = base64::io::empty_state<char>(output); |
| 224 | +template<typename Value,typename Char> |
| 225 | +boolempty_state(std::basic_ostream<Char> & output) { |
| 226 | + detail::state<Char, Value>rest(output); |
| 227 | +return rest.empty(); |
| 228 | +} |
| 229 | + |
| 230 | +}// namespace io |
| 231 | +}// namespace base64 |
| 232 | + |
| 233 | +}// namespace utils |
| 234 | +}// namespace network |
| 235 | +}// namespace boost |
| 236 | + |
| 237 | +#endif// BOOST_NETWORK_UTILS_BASE64_ENCODE_IO_HPP |