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 "compat.hpp"
9#include <assert.h>
10#include <cstdint>
11#include <string>
12#include <vector>
13
14
15namespace stdex
16{
18 static const char base64_enc_lookup[64] = {
19 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
20 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
21 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
22 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
23 };
24
25 static const uint8_t base64_dec_lookup[256] = {
26 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
27 /* 0 */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
28 /* 1 */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
29 /* 2 */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
30 /* 3 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 64, 255, 255,
31 /* 4 */ 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
32 /* 5 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
33 /* 6 */ 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
34 /* 7 */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255,
35 /* 8 */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
36 /* 9 */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
37 /* A */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
38 /* B */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
39 /* C */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
40 /* D */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
41 /* E */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
42 /* F */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
43 };
45
50 {
51 public:
55 base64_enc() noexcept : num(0)
56 {
57 buf[0] = 0;
58 buf[1] = 0;
59 buf[2] = 0;
60 }
61
62
71 template<class _Elem, class _Traits, class _Ax>
72 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)
73 {
74 assert(data || !size);
75
76 // Preallocate output
77 out.reserve(out.size() + enc_size(size));
78
79 // Convert data character by character.
80 for (size_t i = 0;; i++) {
81 if (num >= 3) {
82 encode(out);
83 num = 0;
84 }
85
86 if (i >= size)
87 break;
88
89 buf[num++] = reinterpret_cast<const uint8_t*>(data)[i];
90 }
91
92 // If this is the last block, flush the buffer.
93 if (is_last && num) {
94 encode(out, num);
95 num = 0;
96 }
97 }
98
99
103 void clear() noexcept
104 {
105 num = 0;
106 }
107
108
116 size_t enc_size(_In_ size_t size) const noexcept
117 {
118 return ((num + size + 2)/3)*4;
119 }
120
121
122 protected:
126 template<class _Elem, class _Traits, class _Ax>
127 void encode(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &out)
128 {
129 out += base64_enc_lookup[ buf[0] >> 2 ];
130 out += base64_enc_lookup[((buf[0] << 4) | (buf[1] >> 4)) & 0x3f];
131 out += base64_enc_lookup[((buf[1] << 2) | (buf[2] >> 6)) & 0x3f];
132 out += base64_enc_lookup[ buf[2] & 0x3f];
133 }
134
135
139 template<class _Elem, class _Traits, class _Ax>
140 void encode(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &out, _In_ size_t size)
141 {
142 if (size > 0) {
143 out += base64_enc_lookup[buf[0] >> 2];
144 if (size > 1) {
145 out += base64_enc_lookup[((buf[0] << 4) | (buf[1] >> 4)) & 0x3f];
146 if (size > 2) {
147 out += base64_enc_lookup[((buf[1] << 2) | (buf[2] >> 6)) & 0x3f];
148 out += base64_enc_lookup[buf[2] & 0x3f];
149 } else {
150 out += base64_enc_lookup[(buf[1] << 2) & 0x3f];
151 out += '=';
152 }
153 } else {
154 out += base64_enc_lookup[(buf[0] << 4) & 0x3f];
155 out += '=';
156 out += '=';
157 }
158 } else {
159 out += '=';
160 out += '=';
161 out += '=';
162 out += '=';
163 }
164 }
165
166
167 protected:
168 uint8_t buf[3];
169 size_t num;
170 };
171
176 {
177 public:
181 base64_dec() noexcept : num(0)
182 {
183 buf[0] = 0;
184 buf[1] = 0;
185 buf[2] = 0;
186 buf[3] = 0;
187 }
188
189
198 template<class _Ty, class _Ax, class _Tchr>
199 void decode(_Inout_ std::vector<_Ty, _Ax> &out, _Out_ bool &is_last, _In_z_count_(size) const _Tchr *data, _In_ size_t size)
200 {
201 is_last = false;
202
203 // Trim data size to first terminator.
204 for (size_t k = 0; k < size; k++)
205 if (!data[k]) { size = k; break; }
206
207 // Preallocate output
208 out.reserve(out.size() + dec_size(size));
209
210 for (size_t i = 0;; i++) {
211 if (num >= 4) {
212 // Buffer full; decode it.
213 size_t nibbles = decode(out);
214 num = 0;
215 if (nibbles < 3) {
216 is_last = true;
217 break;
218 }
219 }
220
221 if (i >= size)
222 break;
223
224 int x = data[i];
225 if ((buf[num] = x < _countof(base64_dec_lookup) ? base64_dec_lookup[x] : 255) != 255)
226 num++;
227 }
228 }
229
230
234 void clear() noexcept
235 {
236 num = 0;
237 }
238
239
247 size_t dec_size(_In_ size_t size) const noexcept
248 {
249 return ((num + size + 3)/4)*3;
250 }
251
252
253 protected:
257 template<class _Ty, class _Ax>
258 size_t decode(_Inout_ std::vector<_Ty, _Ax> &out)
259 {
260 out.push_back((_Ty)(((buf[0] << 2) | (buf[1] >> 4)) & 0xff));
261 if (buf[2] < 64) {
262 out.push_back((_Ty)(((buf[1] << 4) | (buf[2] >> 2)) & 0xff));
263 if (buf[3] < 64) {
264 out.push_back((_Ty)(((buf[2] << 6) | buf[3]) & 0xff));
265 return 3;
266 } else
267 return 2;
268 } else
269 return 1;
270 }
271
272
273 protected:
274 uint8_t buf[4];
275 size_t num;
276 };
277}
Base64 decoding session.
Definition base64.hpp:176
size_t num
Number of bytes used in buf
Definition base64.hpp:275
base64_dec() noexcept
Constructs blank decoding session.
Definition base64.hpp:181
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:199
size_t dec_size(size_t size) const noexcept
Returns maximum decoded size.
Definition base64.hpp:247
uint8_t buf[4]
Internal buffer.
Definition base64.hpp:274
size_t decode(std::vector< _Ty, _Ax > &out)
Decodes one complete internal buffer of data.
Definition base64.hpp:258
void clear() noexcept
Resets decoding session.
Definition base64.hpp:234
Base64 encoding session.
Definition base64.hpp:50
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:72
void encode(std::basic_string< _Elem, _Traits, _Ax > &out)
Encodes one complete internal buffer of data.
Definition base64.hpp:127
size_t num
Number of bytes used in buf
Definition base64.hpp:169
void encode(std::basic_string< _Elem, _Traits, _Ax > &out, size_t size)
Encodes partial internal buffer of data.
Definition base64.hpp:140
base64_enc() noexcept
Constructs blank encoding session.
Definition base64.hpp:55
uint8_t buf[3]
Internal buffer.
Definition base64.hpp:168
void clear() noexcept
Resets encoding session.
Definition base64.hpp:103
size_t enc_size(size_t size) const noexcept
Returns maximum encoded size.
Definition base64.hpp:116