stdex
Additional custom or not Standard C++ covered algorithms
base64.h
1/*
2 SPDX-License-Identifier: MIT
3 Copyright © 2016-2022 Amebis
4*/
5
6#pragma once
7
8#include <string>
9#include <vector>
10
11
12namespace stdex
13{
18 {
19 public:
23 base64_enc() noexcept : num(0)
24 {
25 buf[0] = 0;
26 buf[1] = 0;
27 buf[2] = 0;
28 }
29
30
39 template<class _Elem, class _Traits, class _Ax>
40 void encode(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &out, _In_bytecount_(size) const void *data, _In_ size_t size, _In_opt_ bool is_last = true)
41 {
42 assert(data || !size);
43
44 // Preallocate output
45 out.reserve(out.size() + enc_size(size));
46
47 // Convert data character by character.
48 for (size_t i = 0;; i++) {
49 if (num >= 3) {
50 encode(out);
51 num = 0;
52 }
53
54 if (i >= size)
55 break;
56
57 buf[num++] = reinterpret_cast<const unsigned char*>(data)[i];
58 }
59
60 // If this is the last block, flush the buffer.
61 if (is_last && num) {
62 encode(out, num);
63 num = 0;
64 }
65 }
66
67
71 void clear() noexcept
72 {
73 num = 0;
74 }
75
76
84 size_t enc_size(size_t size) const noexcept
85 {
86 return ((num + size + 2)/3)*4;
87 }
88
89
90 protected:
94 template<class _Elem, class _Traits, class _Ax>
95 void encode(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &out)
96 {
97 out += base64_enc_lookup[ buf[0] >> 2 ];
98 out += base64_enc_lookup[((buf[0] << 4) | (buf[1] >> 4)) & 0x3f];
99 out += base64_enc_lookup[((buf[1] << 2) | (buf[2] >> 6)) & 0x3f];
100 out += base64_enc_lookup[ buf[2] & 0x3f];
101 }
102
103
107 template<class _Elem, class _Traits, class _Ax>
108 void encode(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &out, _In_ size_t size)
109 {
110 if (size > 0) {
111 out += base64_enc_lookup[buf[0] >> 2];
112 if (size > 1) {
113 out += base64_enc_lookup[((buf[0] << 4) | (buf[1] >> 4)) & 0x3f];
114 if (size > 2) {
115 out += base64_enc_lookup[((buf[1] << 2) | (buf[2] >> 6)) & 0x3f];
116 out += base64_enc_lookup[buf[2] & 0x3f];
117 } else {
118 out += base64_enc_lookup[(buf[1] << 2) & 0x3f];
119 out += '=';
120 }
121 } else {
122 out += base64_enc_lookup[(buf[0] << 4) & 0x3f];
123 out += '=';
124 out += '=';
125 }
126 } else {
127 out += '=';
128 out += '=';
129 out += '=';
130 out += '=';
131 }
132 }
133
134
135 protected:
136 unsigned char buf[3];
137 size_t num;
138 };
139
140
142 static const char base64_enc_lookup[64] = {
143 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
144 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
145 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
146 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
147 };
149
150
155 {
156 public:
160 base64_dec() noexcept : num(0)
161 {
162 buf[0] = 0;
163 buf[1] = 0;
164 buf[2] = 0;
165 buf[3] = 0;
166 }
167
168
177 template<class _Ty, class _Ax, class _Tchr>
178 void decode(_Inout_ std::vector<_Ty, _Ax> &out, _Out_ bool &is_last, _In_z_count_(size) const _Tchr *data, _In_ size_t size)
179 {
180 is_last = false;
181
182 // Trim data size to first terminator.
183 for (size_t k = 0; k < size; k++)
184 if (!data[k]) { size = k; break; }
185
186 // Preallocate output
187 out.reserve(out.size() + dec_size(size));
188
189 for (size_t i = 0;; i++) {
190 if (num >= 4) {
191 // Buffer full; decode it.
192 size_t nibbles = decode(out);
193 num = 0;
194 if (nibbles < 3) {
195 is_last = true;
196 break;
197 }
198 }
199
200 if (i >= size)
201 break;
202
203 int x = data[i];
204 if ((buf[num] = x < _countof(base64_dec_lookup) ? base64_dec_lookup[x] : 255) != 255)
205 num++;
206 }
207 }
208
209
213 void clear() noexcept
214 {
215 num = 0;
216 }
217
218
226 size_t dec_size(size_t size) const noexcept
227 {
228 return ((num + size + 3)/4)*3;
229 }
230
231
232 protected:
236 template<class _Ty, class _Ax>
237 size_t decode(_Inout_ std::vector<_Ty, _Ax> &out)
238 {
239 out.push_back((_Ty)(((buf[0] << 2) | (buf[1] >> 4)) & 0xff));
240 if (buf[2] < 64) {
241 out.push_back((_Ty)(((buf[1] << 4) | (buf[2] >> 2)) & 0xff));
242 if (buf[3] < 64) {
243 out.push_back((_Ty)(((buf[2] << 6) | buf[3]) & 0xff));
244 return 3;
245 } else
246 return 2;
247 } else
248 return 1;
249 }
250
251
252 protected:
253 unsigned char buf[4];
254 size_t num;
255 };
256
257
259 static const unsigned char base64_dec_lookup[256] = {
260 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
261 /* 0 */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
262 /* 1 */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
263 /* 2 */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
264 /* 3 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 64, 255, 255,
265 /* 4 */ 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
266 /* 5 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
267 /* 6 */ 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
268 /* 7 */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255,
269 /* 8 */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
270 /* 9 */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
271 /* A */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
272 /* B */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
273 /* C */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
274 /* D */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
275 /* E */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
276 /* F */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
277 };
279}
Base64 decoding session.
Definition: base64.h:155
size_t num
Number of bytes used in buf
Definition: base64.h:254
base64_dec() noexcept
Constructs blank decoding session.
Definition: base64.h:160
void decode(std::vector< _Ty, _Ax > &out, bool &is_last, const _Tchr *data, size_t size)
Decodes one block of information, and appends it to the output.
Definition: base64.h:178
size_t dec_size(size_t size) const noexcept
Returns maximum decoded size.
Definition: base64.h:226
size_t decode(std::vector< _Ty, _Ax > &out)
Decodes one complete internal buffer of data.
Definition: base64.h:237
void clear() noexcept
Resets decoding session.
Definition: base64.h:213
unsigned char buf[4]
Internal buffer.
Definition: base64.h:253
Base64 encoding session.
Definition: base64.h:18
void encode(std::basic_string< _Elem, _Traits, _Ax > &out, const void *data, size_t size, bool is_last=true)
Encodes one block of information, and appends it to the output.
Definition: base64.h:40
unsigned char buf[3]
Internal buffer.
Definition: base64.h:136
void encode(std::basic_string< _Elem, _Traits, _Ax > &out)
Encodes one complete internal buffer of data.
Definition: base64.h:95
size_t num
Number of bytes used in buf
Definition: base64.h:137
void encode(std::basic_string< _Elem, _Traits, _Ax > &out, size_t size)
Encodes partial internal buffer of data.
Definition: base64.h:108
base64_enc() noexcept
Constructs blank encoding session.
Definition: base64.h:23
void clear() noexcept
Resets encoding session.
Definition: base64.h:71
size_t enc_size(size_t size) const noexcept
Returns maximum encoded size.
Definition: base64.h:84