RESTinio
base64.hpp
Go to the documentation of this file.
1 /*
2  restinio
3 */
4 
5 /*!
6  Base64 implementation.
7 */
8 
9 #pragma once
10 
11 #include <restinio/exception.hpp>
12 
13 #include <restinio/utils/impl/bitops.hpp>
14 
15 #include <fmt/format.h>
16 #include <fmt/ostream.h>
17 
18 #include <string>
19 #include <bitset>
20 #include <array>
21 #include <exception>
22 #include <iostream> // std::cout, debug
23 
24 namespace restinio
25 {
26 
27 namespace utils
28 {
29 
30 namespace base64
31 {
32 
33 #include "base64_lut.ipp"
34 
36 
37 using bitset24_t = std::bitset<24>;
38 
39 inline bool
40 is_base64_char( char c )
41 {
42  return 1 == is_base64_char_lut< unsigned char >()[
43  static_cast<unsigned char>(c) ];
44 }
45 
46 inline void
47 check_string_is_base64( string_view_t str )
48 {
49  auto throw_invalid_string = [&]{
50  throw exception_t{
51  fmt::format( "invalid base64 string '{}'", str ) };
52  };
53 
54  // TODO: Handle long strings.
55 
56  if( str.size() < 4 )
57  throw_invalid_string();
58 
59  for( const auto & ch : str )
60  {
61  if( !is_base64_char( ch ) && ch != '=' )
62  throw_invalid_string();
63  }
64 }
65 
66 inline uint_type_t
67 uch( char ch )
68 {
69  return static_cast<uint_type_t>(static_cast<unsigned char>(ch));
70 }
71 
72 template<unsigned int Shift>
73 char
74 sixbits_char( uint_type_t bs )
75 {
76  return ::restinio::utils::impl::bitops::n_bits_from< char, Shift, 6 >(bs);
77 }
78 
79 inline std::string
81 {
82  std::string result;
83 
84  const auto at = [&str](auto index) { return uch(str[index]); };
85 
86  const auto alphabet_char = [](auto ch) {
87  return static_cast<char>(
88  base64_alphabet< unsigned char >()[
89  static_cast<unsigned char>(ch) ]);
90  };
91 
92  constexpr std::size_t group_size = 3u;
93  const auto remaining = str.size() % group_size;
94 
95  result.reserve( (str.size()/group_size + (remaining ? 1:0)) * 4 );
96 
97  std::size_t i = 0;
98  for(; i < str.size() - remaining; i += group_size )
99  {
100  uint_type_t bs = (at(i) << 16) | (at(i+1) << 8) | at(i+2);
101 
102  result.push_back( alphabet_char( sixbits_char<18>(bs) ) );
103  result.push_back( alphabet_char( sixbits_char<12>(bs) ) );
104  result.push_back( alphabet_char( sixbits_char<6>(bs) ) );
105  result.push_back( alphabet_char( sixbits_char<0>(bs) ) );
106  }
107 
108  if( remaining )
109  {
110  uint_type_t bs =
111  1u == remaining ?
112  // only one char left.
113  (at(i) << 16) :
114  // two chars left.
115  ((at(i) << 16) | (at(i+1) << 8));
116 
117  result.push_back( alphabet_char( sixbits_char<18>(bs) ) );
118  result.push_back( alphabet_char( sixbits_char<12>(bs) ) );
119 
120  if( (bs >> 8) & 0xFFu )
121  result.push_back( alphabet_char( sixbits_char<6>(bs) ) );
122  else
123  result.push_back('=');
124 
125  if( bs & 0xFFu )
126  result.push_back( alphabet_char( sixbits_char<0>(bs) ) );
127  else
128  result.push_back('=');
129  }
130 
131  return result;
132 }
133 
134 inline std::string
136 {
137  constexpr std::size_t group_size = 4;
138 
139  std::string result;
140 
141  check_string_is_base64( str );
142  result.reserve( (str.size() / group_size) * 3 );
143 
144  const unsigned char * const decode_table = base64_decode_lut< unsigned char >();
145 
146  const auto at = [&str](auto index) {
147  return static_cast<unsigned char>(str[index]);
148  };
149 
150  for( size_t i = 0 ; i < str.size(); i += group_size)
151  {
152 
153  uint_type_t bs{};
154 
155  bs |= decode_table[ at(i) ];
156  bs <<= 6;
157  bs |= decode_table[ at(i+1) ];
158  bs <<= 6;
159  bs |= str[i+2] != '=' ? decode_table[ at(i+2) ] : 0;
160  bs <<= 6;
161  bs |= str[i+3] != '=' ? decode_table[ at(i+3) ] : 0;
162 
163 
164  using ::restinio::utils::impl::bitops::n_bits_from;
165 
166  result.push_back( n_bits_from< char, 16 >(bs) );
167  const auto c2 = n_bits_from< char, 8 >(bs);
168  if( c2 )
169  result.push_back( c2 );
170  const auto c3 = n_bits_from< char, 0 >(bs);
171  if( c3 )
172  result.push_back( c3 );
173  }
174 
175  return result;
176 }
177 
178 } /* namespace base64 */
179 
180 } /* namespace utils */
181 
182 } /* namespace restinio */
char sixbits_char(uint_type_t bs)
Definition: base64.hpp:74
string_view_t from_string< string_view_t >(string_view_t s)
Get a value from string_view.
std::string decode(string_view_t str)
Definition: base64.hpp:135
void check_string_is_base64(string_view_t str)
Definition: base64.hpp:47
bool is_base64_char(char c)
Definition: base64.hpp:40
std::string encode(string_view_t str)
Definition: base64.hpp:80
uint_type_t uch(char ch)
Definition: base64.hpp:67
std::enable_if< std::is_same< Parameter_Container, query_string_params_t >::value||std::is_same< Parameter_Container, router::route_params_t >::value, optional_t< Value_Type > >::type opt_value(const Parameter_Container &params, string_view_t key)
Gets the value of a parameter specified by key wrapped in optional_t<Value_Type> if parameter exists ...
Definition: value_or.hpp:64