rapidyaml 0.15.2
parse and emit YAML, and do it fast
Loading...
Searching...
No Matches
format_base64.hpp
Go to the documentation of this file.
1#ifndef C4_FORMAT_BASE64_HPP_
2#define C4_FORMAT_BASE64_HPP_
3
4/** @file format_base64.hpp Utilities for formatting data as base64 */
5
6#ifndef C4_SUBSTR_HPP_
7#include "c4/substr.hpp"
8#endif
9#ifndef C4_BLOB_HPP_
10#include "c4/blob.hpp"
11#endif
12#ifndef C4_BASE64_HPP_
13#include "c4/base64.hpp"
14#endif
15
16
17namespace c4 {
18namespace fmt {
19
20/** @defgroup doc_base64_fmt Base64 format specifiers
21 *
22 * ```c++
23 * // given these variables:
24 * T var = {};
25 * T &ref = var;
26 * std::vector<T> vec = ...;
27 * substr buf = ...;
28 *
29 * // there are different approaches to encode/decode base64:
30 * size_t numchars = to_chars(buf, base64(var)); // encode var as base64
31 * size_t numchars = to_chars(buf, base64(ref)); // same as above
32 * size_t numchars = to_chars(buf, base64(&var, 1)); // same as above
33 * size_t numchars = to_chars(buf, base64(vec.data(), vec.size())); // for the container, but same call form as above
34 * size_t numchars = to_chars(buf, base64(vec)); // same effect as prev call
35 *
36 * // using cbase64() (the `c` prefix is for const) is equivalent
37 * // for encoding, but quicker to compile:
38 * size_t numchars = to_chars(buf, cbase64(var)); // encode var as base64
39 * size_t numchars = to_chars(buf, cbase64(ref)); // same as above
40 * size_t numchars = to_chars(buf, cbase64(&var, 1)); // same as above
41 * size_t numchars = to_chars(buf, cbase64(vec.data(), vec.size())); // for the container, but same call as above
42 * size_t numchars = to_chars(buf, cbase64(vec)); // same effect as prev call
43 *
44 * // to decode:
45 * csubstr buf = ...;
46 * size_t reqbytes = 0; // number of bytes of decoded data
47 * bool ok = from_chars(buf, base64(var)); // decode base64 to var
48 * bool ok = from_chars(buf, base64(var, &reqbytes)); // same. reqbytes will be sizeof(var)
49 * bool ok = from_chars(buf, base64(ref)); // same as above
50 * bool ok = from_chars(buf, base64(ref, &reqbytes)); // same. reqbytes will be sizeof(var)
51 * bool ok = from_chars(buf, base64(&var, 1, &reqbytes)); // same
52 * bool ok = from_chars(buf, base64(vec.data(), vec.size(), &reqbytes)); // for the container, but same call as above
53 * bool ok = from_chars(buf, base64(vec, &reqbytes)); // same effect as prev call
54 * ```
55 * @ingroup doc_format_specifiers
56 * @ingroup doc_base64
57 * @{ */
58
59/** @cond dev */
60namespace detail {
61template<class> struct sfinae_true : std::true_type{};
62template<class T, class A0> static auto test_resize(int) -> sfinae_true<decltype(std::declval<T>().resize(std::declval<A0>()))>;
63template<class, class A0> static auto test_resize(int64_t) -> std::false_type;
64/// a traits class to report when a type as a member method named resize
65/// @see https://stackoverflow.com/a/9154394
66template<class T, class Arg=size_t>
67struct has_resize : decltype(detail::test_resize<typename std::remove_cv<typename std::remove_reference<typename std::remove_pointer<T>::type>::type>::type, Arg>(0)){};
68
69template<typename CharOrConstChar>
70struct base64_wrapper_
71{
72 blob_<CharOrConstChar> data;
73 size_t *required_size;
74 base64_wrapper_(blob_<CharOrConstChar> blob, size_t *len_=nullptr) noexcept
75 : data(blob)
76 , required_size(len_)
77 {}
78};
79
80template<class Container, typename CharOrConstChar>
81struct base64_container_wrapper_
82{
83 using value_type = typename Container::value_type;
84 Container *container;
85 size_t *required_size;
86 base64_container_wrapper_(Container *c, size_t *len_=nullptr) noexcept
87 : container(c)
88 , required_size(len_)
89 {}
90 blob_<CharOrConstChar> data() const noexcept
91 {
92 size_t sz = container->size();
93 CharOrConstChar *first = sz ? reinterpret_cast<CharOrConstChar*>(&(*container)[0]) : nullptr; // NOLINT
94 return blob_<CharOrConstChar>(first, sizeof(value_type) * sz);
95 }
96};
97} // namespace detail
98/** @endcond */
99
100
101
102/** a tag type to mark a payload to be encoded as base64 */
103using const_base64_wrapper = detail::base64_wrapper_<cbyte>;
104/** a tag type to mark a payload to be decoded as base64 */
105using base64_wrapper = detail::base64_wrapper_<byte>;
106
107
108/** a tag type to mark a payload as base64-encoded */
109template<class Container>
110using const_base64_container_wrapper = detail::base64_container_wrapper_<const Container, cbyte>;
111/** a tag type to mark a payload to be encoded as base64 */
112template<class Container>
113using base64_container_wrapper = detail::base64_container_wrapper_<Container, byte>;
114
115
116/** a tag function to mark a csubstr payload to be encoded in base64 format */
117C4_ALWAYS_INLINE const_base64_wrapper cbase64(csubstr s, size_t *reqsize=nullptr)
118{
119 return const_base64_wrapper(cblob(s.str, s.len), reqsize);
120}
121/** a tag function to mark a csubstr payload to be encoded in base64 format */
122C4_ALWAYS_INLINE const_base64_wrapper base64(csubstr s, size_t *reqsize=nullptr)
123{
124 return const_base64_wrapper(cblob(s.str, s.len), reqsize);
125}
126/** a tag function to mark a variable to be decoded from base64 */
127C4_ALWAYS_INLINE base64_wrapper base64(substr s, size_t *reqsize=nullptr)
128{
129 return base64_wrapper(blob(s.str, s.len), reqsize);
130}
131
132
133/** a tag function to mark a payload to be encoded in base64 format */
134template<class T>
135C4_ALWAYS_INLINE const_base64_wrapper cbase64(T const* arg, size_t sz, size_t *reqsize=nullptr) // NOLINT
136{
137 return const_base64_wrapper(cblob(arg, sz), reqsize);
138}
139/** a tag function to mark a payload to be encoded in base64 format */
140template<class T>
141C4_ALWAYS_INLINE auto base64(T * arg, size_t sz, size_t *reqsize=nullptr) // NOLINT
142 -> typename std::conditional<std::is_const<typename std::remove_reference<typename std::remove_pointer<T>::type>::type>::value,
144 base64_wrapper>::type
145{
146 using U = typename std::remove_reference<typename std::remove_pointer<T>::type>::type;
147 using ret_type = typename std::conditional<std::is_const<U>::value,
149 base64_wrapper>::type;
150 using blob_type = typename std::conditional<std::is_const<U>::value,
151 cblob,
152 blob>::type;
153 return ret_type(blob_type(arg, sz), reqsize);
154}
155
156
157/** a tag function to mark a payload to be encoded in base64 format */
158template<class T>
159C4_ALWAYS_INLINE auto cbase64(T const& arg, size_t *reqsize=nullptr) // NOLINT
160 -> typename std::enable_if< ! detail::has_resize<T>::value, const_base64_wrapper>::type
161{
162 return const_base64_wrapper(cblob(arg), reqsize);
163}
164/** a tag function to mark a payload to be encoded or decoded in base64 format */
165template<class T>
166C4_ALWAYS_INLINE auto base64(T & arg, size_t *reqsize=nullptr) // NOLINT
167 -> typename std::enable_if< ! detail::has_resize<T>::value,
168 typename std::conditional<std::is_const<typename std::remove_reference<typename std::remove_pointer<T>::type>::type>::value,
170 base64_wrapper>::type>::type
171{
172 using U = typename std::remove_reference<typename std::remove_pointer<T>::type>::type;
173 using ret_type = typename std::conditional<std::is_const<U>::value,
175 base64_wrapper>::type;
176 using blob_type = typename std::conditional<std::is_const<U>::value,
177 cblob,
178 blob>::type;
179 return ret_type(blob_type(arg), reqsize);
180}
181
182/** a tag function to mark a container (payload with a .resize()
183 * method) to be encoded in base64 format. */
184template<class T>
185C4_ALWAYS_INLINE auto cbase64(T const& arg, size_t *reqsize=nullptr) // NOLINT
186 -> typename std::enable_if<detail::has_resize<T>::value, const_base64_container_wrapper<T>>::type
187{
188 return const_base64_container_wrapper<T>(&arg, reqsize);
189}
190/** a tag function to mark a container (payload with a .resize()
191 * method) to be encoded or decoded in base64 format. Subsequently
192 * when decoding, from_chars() will resize the container to fit the
193 * decoded data. */
194template<class T>
195C4_ALWAYS_INLINE auto base64(T & arg, size_t *reqsize=nullptr) // NOLINT
196 -> typename std::enable_if<detail::has_resize<T>::value,
197 typename std::conditional<std::is_const<typename std::remove_reference<typename std::remove_pointer<T>::type>::type>::value,
199 base64_container_wrapper<T>>::type>::type
200{
201 using ret_type = typename std::conditional<std::is_const<typename std::remove_reference<typename std::remove_pointer<T>::type>::type>::value,
204 return ret_type(&arg, reqsize);
205}
206
207/** @} */ // base64_fmt
208
209} // namespace fmt
210
211
212//-----------------------------------------------------------------------------
213
214/** @addtogroup doc_base64
215 * @{ */
216
217/** (1) read a variable in base64 format
218 * @ingroup doc_from_chars */
219inline bool from_chars(csubstr buf, fmt::base64_wrapper const& b)
220{
221 size_t reqsize = 0;
222 bool ok = base64_decode(buf.str, buf.len, b.data.buf, b.data.len, &reqsize);
223 if(b.required_size)
224 *b.required_size = reqsize;
225 return ok;
226}
227/** (2) read a variable in base64 format
228 * @ingroup doc_from_chars */
230{
231 return from_chars(buf, *b);
232}
233
234
235/** write a variable or buffer in base64 format
236 * @ingroup doc_to_chars */
237template<typename CharOrConstChar>
238inline size_t to_chars(substr buf, fmt::detail::base64_wrapper_<CharOrConstChar> const& b)
239{
240 size_t reqsize = base64_encode(buf.str, buf.len, b.data.buf, b.data.len);
241 if(b.required_size)
242 *b.required_size = reqsize;
243 return reqsize;
244}
245/** write a container in base64 format
246 * @ingroup doc_to_chars */
247template<class Container, typename CharOrConstChar>
248size_t to_chars(substr buf, fmt::detail::base64_container_wrapper_<Container, CharOrConstChar> const& b)
249{
250 cblob data = b.data();
251 size_t reqsize = base64_encode(buf.str, buf.len, data.buf, data.len);
252 if(b.required_size)
253 *b.required_size = reqsize;
254 return reqsize;
255}
256
257/** read a container in base64 format, resizing it as needed to
258 * accomodate the result
259 * @ingroup doc_from_chars */
260template<class T>
262{
263 enum : size_t { elm_sz = sizeof(typename fmt::base64_container_wrapper<T>::value_type) }; // NOLINT
264 blob data = b.data();
265 size_t required_size = 0;
266 bool ok = base64_decode(buf.str, buf.len, data.buf, data.len, &required_size);
267 if(b.required_size)
268 *b.required_size = required_size;
269 if(!required_size)
270 return ok;
271 else if(!ok && ((required_size < data.len) || (required_size % elm_sz)))
272 return false;
273 size_t num_elms = required_size / elm_sz;
274 b.container->resize(num_elms);
275 if(required_size > data.len)
276 {
277 data = b.data();
278 ok = base64_decode(buf.str, buf.len, data.buf, data.len, &required_size);
279 if(b.required_size)
280 *b.required_size = required_size;
281 }
282 return ok;
283}
284/** read a container in base64 format, resizing it as needed to
285 * accomodate the result
286 * @ingroup doc_from_chars */
287template<class T>
289{
290 return from_chars(buf, *b);
291}
292
293/** @} */ // base64
294
295} // namespace c4
296
297#endif /* C4_FORMAT_BASE64_HPP_ */
encoding/decoding for base64.
detail::base64_container_wrapper_< const Container, cbyte > const_base64_container_wrapper
a tag type to mark a payload as base64-encoded
detail::base64_wrapper_< cbyte > const_base64_wrapper
a tag type to mark a payload to be encoded as base64
detail::base64_container_wrapper_< Container, byte > base64_container_wrapper
a tag type to mark a payload to be encoded as base64
detail::base64_wrapper_< byte > base64_wrapper
a tag type to mark a payload to be decoded as base64
const_base64_wrapper base64(csubstr s, size_t *reqsize=nullptr)
a tag function to mark a csubstr payload to be encoded in base64 format
const_base64_wrapper cbase64(csubstr s, size_t *reqsize=nullptr)
a tag function to mark a csubstr payload to be encoded in base64 format
bool base64_decode(char const *encoded, size_t encoded_sz, void *data, size_t data_sz, size_t *data_sz_required)
decode the base64 encoding in the given buffer.
Definition base64.cpp:412
size_t base64_encode(char *encoded, size_t encoded_sz, void const *data, size_t data_sz)
base64-encode binary data.
Definition base64.cpp:361
bool from_chars(csubstr buf, uint8_t *v) noexcept
basic_substring< char > substr
a mutable string view
Definition substr.hpp:2355
basic_substring< const char > csubstr
an immutable string view
Definition substr.hpp:2356
size_t to_chars(substr buf, uint8_t v) noexcept
size_t len
the length of the substring
Definition substr.hpp:218
C * str
a restricted pointer to the first character of the substring
Definition substr.hpp:216
read+write string views