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