RESTinio
Toggle main menu visibility
Loading...
Searching...
No Matches
restinio
utils
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
#
include
<
restinio
/
expected
.
hpp
>
13
14
#
include
<
restinio
/
utils
/
impl
/
bitops
.
hpp
>
15
16
#
include
<
restinio
/
impl
/
include_fmtlib
.
hpp
>
17
18
#
include
<
string
>
19
#
include
<
array
>
20
#
include
<
exception
>
21
#
include
<
iostream
>
// std::cout, debug
22
23
namespace
restinio
24
{
25
26
namespace
utils
27
{
28
29
namespace
base64
30
{
31
32
#
include
"base64_lut.ipp"
33
34
using
uint_type_t
= std::
uint_fast32_t
;
35
36
inline
bool
37
is_base64_char
(
char
c )
noexcept
38
{
39
return
1 == is_base64_char_lut<
unsigned
char
>()[
40
static_cast
<
unsigned
char
>(c) ];
41
}
42
43
inline
bool
44
is_valid_base64_string
( string_view_t str )
noexcept
45
{
46
enum
class
expected_type { b64ch, b64ch_or_padding, padding };
47
48
if
( str.size() < 4u )
49
return
false
;
50
51
expected_type expects = expected_type::b64ch;
52
std::uint_fast8_t b64chars_found = 0u;
// Can't be greater than 2.
53
std::uint_fast8_t paddings_found = 0u;
// Can't be greater than 3.
54
for
(
const
auto
ch : str )
55
{
56
switch
( expects )
57
{
58
case
expected_type::b64ch:
59
{
60
// Because '=' is a part of base64_chars, it should be checked
61
// individually.
62
if
(
'='
== ch )
63
return
false
;
64
else
if
( is_base64_char( ch ) )
65
{
66
++b64chars_found;
67
if
( b64chars_found >= 2u )
68
expects = expected_type::b64ch_or_padding;
69
}
70
else
71
return
false
;
72
break
;
73
}
74
case
expected_type::b64ch_or_padding:
75
{
76
if
(
'='
== ch )
77
{
78
expects = expected_type::padding;
79
++paddings_found;
80
}
81
else
if
( is_base64_char( ch ) )
82
{
83
/* Nothing to do */
84
}
85
else
86
return
false
;
87
88
break
;
89
}
90
case
expected_type::padding:
91
{
92
if
(
'='
== ch )
93
{
94
++paddings_found;
95
if
( paddings_found > 2u )
96
return
false
;
97
}
98
else
99
return
false
;
100
101
break
;
102
}
103
}
104
}
105
106
return
true
;
107
}
108
109
inline
uint_type_t
110
uch
(
char
ch )
111
{
112
return
static_cast
<
uint_type_t
>(
static_cast
<
unsigned
char
>(ch));
113
}
114
115
template
<
unsigned
int
Shift>
116
char
117
sixbits_char
(
uint_type_t
bs )
118
{
119
return
::
restinio
::
utils
::
impl
::
bitops
::n_bits_from<
char
, Shift, 6 >(bs);
120
}
121
122
inline
std::string
123
encode
( string_view_t str )
124
{
125
std::string result;
126
127
const
auto
at = [&str](
auto
index) {
return
uch(str[index]); };
128
129
const
auto
alphabet_char = [](
auto
ch) {
130
return
static_cast
<
char
>(
131
base64_alphabet<
unsigned
char
>()[
132
static_cast
<
unsigned
char
>(ch) ]);
133
};
134
135
constexpr
std::size_t group_size = 3u;
136
const
auto
remaining = str.size() % group_size;
137
138
result.reserve( (str.size()/group_size + (remaining ? 1:0)) * 4 );
139
140
std::size_t i = 0;
141
for
(; i < str.size() - remaining; i += group_size )
142
{
143
uint_type_t
bs = (at(i) << 16) | (at(i+1) << 8) | at(i+2);
144
145
result.push_back( alphabet_char( sixbits_char<18>(bs) ) );
146
result.push_back( alphabet_char( sixbits_char<12>(bs) ) );
147
result.push_back( alphabet_char( sixbits_char<6>(bs) ) );
148
result.push_back( alphabet_char( sixbits_char<0>(bs) ) );
149
}
150
151
if
( remaining )
152
{
153
// Some code duplication to avoid additional IFs.
154
if
( 1u == remaining )
155
{
156
uint_type_t
bs = (at(i) << 16);
157
result.push_back( alphabet_char( sixbits_char<18>(bs) ) );
158
result.push_back( alphabet_char( sixbits_char<12>(bs) ) );
159
160
result.push_back(
'='
);
161
}
162
else
163
{
164
uint_type_t
bs = (at(i) << 16) | (at(i+1) << 8);
165
166
result.push_back( alphabet_char( sixbits_char<18>(bs) ) );
167
result.push_back( alphabet_char( sixbits_char<12>(bs) ) );
168
result.push_back( alphabet_char( sixbits_char<6>(bs) ) );
169
}
170
171
result.push_back(
'='
);
172
}
173
174
return
result;
175
}
176
177
//! Description of base64 decode error.
178
enum
class
decoding_error_t
179
{
180
invalid_base64_sequence
181
};
182
183
inline
expected_t
<
std
::
string
,
decoding_error_t
>
184
try_decode
( string_view_t str )
185
{
186
if
( !is_valid_base64_string( str ) )
187
return
make_unexpected(
decoding_error_t
::
invalid_base64_sequence
);
188
189
constexpr
std::size_t group_size = 4;
190
191
std::string result;
192
result.reserve( (str.size() / group_size) * 3 );
193
194
const
unsigned
char
*
const
decode_table = base64_decode_lut<
unsigned
char
>();
195
196
const
auto
at = [&str](
auto
index) {
197
return
static_cast
<
unsigned
char
>(str[index]);
198
};
199
200
for
( size_t i = 0 ; i < str.size(); i += group_size)
201
{
202
203
uint_type_t
bs{};
204
int
paddings_found = 0u;
205
206
bs |= decode_table[ at(i) ];
207
208
bs <<= 6;
209
bs |= decode_table[ at(i+1) ];
210
211
bs <<= 6;
212
if
(
'='
== str[i+2] )
213
{
214
++paddings_found;
215
}
216
else
217
{
218
bs |= decode_table[ at(i+2) ];
219
}
220
221
bs <<= 6;
222
if
(
'='
== str[i+3] )
223
{
224
++paddings_found;
225
}
226
else
227
{
228
bs |= decode_table[ at(i+3) ];
229
}
230
231
using
::
restinio
::
utils
::
impl
::
bitops
::n_bits_from;
232
233
result.push_back( n_bits_from<
char
, 16 >(bs) );
234
if
( paddings_found < 2 )
235
{
236
result.push_back( n_bits_from<
char
, 8 >(bs) );
237
}
238
if
( paddings_found < 1 )
239
{
240
result.push_back( n_bits_from<
char
, 0 >(bs) );
241
}
242
}
243
244
return
result;
245
}
246
247
namespace
impl
248
{
249
250
inline
void
251
throw_exception_on_invalid_base64_string
( string_view_t str )
252
{
253
constexpr
size_t max_allowed_len = 32u;
254
// If str is too long only a part of it will be included
255
// in the error message.
256
if
( str.size() > max_allowed_len )
257
throw
exception_t
{
258
fmt::format(
259
RESTINIO_FMT_FORMAT_STRING
(
260
"invalid base64 string that starts with '{}'"
),
261
fmtlib_tools
::streamed( str.substr( 0u, max_allowed_len ) ) )
262
};
263
else
264
throw
exception_t
{
265
fmt::format(
266
RESTINIO_FMT_FORMAT_STRING
(
"invalid base64 string '{}'"
),
267
fmtlib_tools
::streamed( str ) ) };
268
}
269
270
}
/* namespace impl */
271
272
inline
std::string
273
decode
( string_view_t str )
274
{
275
auto
result = try_decode( str );
276
if
( !result )
277
impl
::
throw_exception_on_invalid_base64_string
( str );
278
279
return
std::move( *result );
280
}
281
282
}
/* namespace base64 */
283
284
}
/* namespace utils */
285
286
}
/* namespace restinio */
restinio::exception_t
Exception class for all exceptions thrown by RESTinio.
Definition
exception.hpp:26
RESTINIO_FMT_FORMAT_STRING
#define RESTINIO_FMT_FORMAT_STRING(s)
Definition
include_fmtlib.hpp:92
restinio::fmtlib_tools
Definition
include_fmtlib.hpp:45
restinio::utils::base64::impl
Definition
base64.hpp:248
restinio::utils::base64::impl::throw_exception_on_invalid_base64_string
void throw_exception_on_invalid_base64_string(string_view_t str)
Definition
base64.hpp:251
restinio::utils::base64
Definition
base64.hpp:30
restinio::utils::base64::sixbits_char
char sixbits_char(uint_type_t bs)
Definition
base64.hpp:117
restinio::utils::base64::is_base64_char
bool is_base64_char(char c) noexcept
Definition
base64.hpp:37
restinio::utils::base64::decode
std::string decode(string_view_t str)
Definition
base64.hpp:273
restinio::utils::base64::is_valid_base64_string
bool is_valid_base64_string(string_view_t str) noexcept
Definition
base64.hpp:44
restinio::utils::base64::uint_type_t
std::uint_fast32_t uint_type_t
Definition
base64.hpp:34
restinio::utils::base64::try_decode
expected_t< std::string, decoding_error_t > try_decode(string_view_t str)
Definition
base64.hpp:184
restinio::utils::base64::decoding_error_t
decoding_error_t
Description of base64 decode error.
Definition
base64.hpp:179
restinio::utils::base64::decoding_error_t::invalid_base64_sequence
@ invalid_base64_sequence
Definition
base64.hpp:180
restinio::utils::base64::uch
uint_type_t uch(char ch)
Definition
base64.hpp:110
restinio::utils::base64::encode
std::string encode(string_view_t str)
Definition
base64.hpp:123
restinio::utils::impl::bitops
Definition
bitops.hpp:19
restinio::utils::impl
Definition
bitops.hpp:17
restinio::utils
Definition
from_string_details.ipp:5
restinio
Definition
sendfile_operation_default.ipp:12
Generated by
1.17.0