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