8#include "Stroika/Foundation/StroikaPreComp.h"
13#include "Stroika/Foundation/Containers/Common.h"
14#include "Stroika/Foundation/DataExchange/BadFormatException.h"
23using namespace Stroika::Foundation::Cryptography;
24using namespace Stroika::Foundation::Cryptography::Encoding;
25using namespace Stroika::Foundation::Cryptography::Encoding::Algorithm;
26using namespace Stroika::Foundation::Memory;
49 enum base64_decodestep_ {
55 struct base64_decodestate_ {
56 base64_decodestep_ step{step_a};
59 int base64_decode_value_ (
signed char value_in)
61 static constexpr signed char kDecoding[] = {62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1,
62 -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
63 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31,
64 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51};
66 if (value_in < 0 ||
static_cast<unsigned char> (value_in) >= NEltsOf (kDecoding)) {
69 Assert (0 <= value_in and
static_cast<unsigned char> (value_in) < NEltsOf (kDecoding));
70 return kDecoding[(int)value_in];
72 size_t base64_decode_block_ (
const signed char* code_in,
size_t length_in,
byte* plaintext_out, base64_decodestate_* state)
77 const signed char* codechar = code_in;
78 byte* plainchar = plaintext_out;
79 signed char fragment =
'\0';
81 *plainchar = state->plainchar;
83 switch (state->step) {
87 if (codechar == code_in + length_in) {
89 state->plainchar = *plainchar;
90 return plainchar - plaintext_out;
92 fragment = (
signed char)base64_decode_value_ (*codechar++);
93 }
while (fragment < 0);
94 *plainchar = byte ((fragment & 0x03f) << 2);
97 if (codechar == code_in + length_in) {
99 state->plainchar = *plainchar;
100 return plainchar - plaintext_out;
102 fragment = (
signed char)base64_decode_value_ (*codechar++);
103 }
while (fragment < 0);
104 *plainchar++ |= byte ((fragment & 0x030) >> 4);
105 *plainchar = byte ((fragment & 0x00f) << 4);
108 if (codechar == code_in + length_in) {
109 state->step = step_c;
110 state->plainchar = *plainchar;
111 return plainchar - plaintext_out;
113 fragment = (
signed char)base64_decode_value_ (*codechar++);
114 }
while (fragment < 0);
115 *plainchar++ |= byte ((fragment & 0x03c) >> 2);
116 *plainchar = byte ((fragment & 0x003) << 6);
119 if (codechar == code_in + length_in) {
120 state->step = step_d;
121 state->plainchar = *plainchar;
122 return plainchar - plaintext_out;
124 fragment = (
signed char)base64_decode_value_ (*codechar++);
125 }
while (fragment < 0);
126 *plainchar++ |= byte (fragment & 0x03f);
129 return plainchar - plaintext_out;
136 return Decode (s.
AsUTF8<
string> ());
139Memory::BLOB Algorithm::Base64::Decode (span<const char> s)
144 size_t dataSize1 = s.
size ();
146 base64_decodestate_ state{};
147 size_t r = base64_decode_block_ (
reinterpret_cast<const signed char*
> (s.data ()), s.size (), buf1.begin (), &state);
148 Assert (r <= dataSize1);
158 size_t dataSize1 = s.
length ();
160 base64_decodestate_ state{};
161 size_t r = base64_decode_block_ (
reinterpret_cast<const signed char*
> (
Containers::Start (s)), s.length (), buf1.begin (), &state);
162 Assert (r <= dataSize1);
167Memory::BLOB Algorithm::Base64::Decode (
const u8string& s)
172 size_t dataSize1 = s.
length ();
174 base64_decodestate_ state{};
175 size_t r = base64_decode_block_ (
reinterpret_cast<const signed char*
> (
Containers::Start (s)), s.length (), buf1.begin (), &state);
176 Assert (r <= dataSize1);
184 out.
Write (Decode (s));
193 enum base64_encodestep {
198 struct base64_encodestate {
199 base64_encodestep step{step_A};
200 signed char result{0};
202 LineBreak fLineBreak;
204 base64_encodestate (LineBreak lb)
210 signed char base64_encode_value_ (
signed char value_in)
212 const signed char BASE64_CHARS_[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
213 Assert (NEltsOf (BASE64_CHARS_) == (2 * 26 + 10 + 2 + 1));
217 return BASE64_CHARS_[(int)value_in];
220 size_t base64_encode_block_ (
const byte* plaintext_in,
size_t length_in,
signed char* code_out, base64_encodestate* state)
222 const int CHARS_PER_LINE = 76;
224 const byte* plainchar = plaintext_in;
225 const byte*
const plaintextend = plaintext_in + length_in;
226 signed char* codechar = code_out;
227 signed char result = state->result;
229 signed char fragment =
'\0';
230 switch (state->step) {
233 if (plainchar == plaintextend) {
234 state->result = result;
235 state->step = step_A;
236 return codechar - code_out;
238 fragment = to_integer<signed char> (*plainchar++);
239 result = (fragment & 0x0fc) >> 2;
240 *codechar++ = base64_encode_value_ (result);
241 result = (fragment & 0x003) << 4;
243 if (plainchar == plaintextend) {
244 state->result = result;
245 state->step = step_B;
246 return codechar - code_out;
248 fragment = to_integer<signed char> (*plainchar++);
249 result |= (fragment & 0x0f0) >> 4;
250 *codechar++ = base64_encode_value_ (result);
251 result = (fragment & 0x00f) << 2;
253 if (plainchar == plaintextend) {
254 state->result = result;
255 state->step = step_C;
256 return codechar - code_out;
258 fragment = to_integer<signed char> (*plainchar++);
259 result |= (fragment & 0x0c0) >> 6;
260 *codechar++ = base64_encode_value_ (result);
261 result = (fragment & 0x03f) >> 0;
262 *codechar++ = base64_encode_value_ (result);
264 ++(state->stepcount);
265 if (state->stepcount == CHARS_PER_LINE / 4) {
266 switch (state->fLineBreak) {
267 case LineBreak::eLF_LB:
270 case LineBreak::eCRLF_LB:
275 state->stepcount = 0;
279 return codechar - code_out;
281 inline size_t base64_encode_blockend_ (
signed char* code_out, base64_encodestate* state)
283 signed char* codechar = code_out;
284 switch (state->step) {
286 *codechar++ = base64_encode_value_ (state->result);
291 *codechar++ = base64_encode_value_ (state->result);
297 return static_cast<size_t> (codechar - code_out);
308 const byte* start = bytes.
begin ();
309 const byte* end = bytes.
end ();
310 Require (start == end or start !=
nullptr);
311 Require (start == end or end !=
nullptr);
312 base64_encodestate state{options.fLineBreak};
313 size_t srcLen = end - start;
314 size_t bufSize = 4 * srcLen;
315 Assert (bufSize >= srcLen);
317 size_t mostBytesCopied = base64_encode_block_ (start, srcLen, data.begin (), &state);
318 size_t extraBytes = base64_encode_blockend_ (data.begin () + mostBytesCopied, &state);
319 size_t totalBytes = mostBytesCopied + extraBytes;
320 Assert (totalBytes <= bufSize);
321 return string{data.begin (), data.begin () + totalBytes};
323 Require (start == end or start !=
nullptr);
324 Require (start == end or end !=
nullptr);
326 base64_encodestate state{lb};
327 size_t srcLen = end - start;
328 size_t bufSize = 4 * srcLen;
329 Assert (bufSize >= srcLen);
331 size_t mostBytesCopied = base64_encode_block_ (start, srcLen, data.begin (), &state);
332 size_t extraBytes = base64_encode_blockend_ (data.begin () + mostBytesCopied, &state);
333 size_t totalBytes = mostBytesCopied + extraBytes;
334 Assert (totalBytes <= bufSize);
335 return string{data.begin (), data.begin () + totalBytes};
339string Algorithm::Base64::Encode (
const Memory::BLOB& from,
const Options& options)
341 const byte* start = from.
begin ();
342 const byte* end = from.
end ();
343 Require (start == end or start !=
nullptr);
344 Require (start == end or end !=
nullptr);
345 base64_encodestate state{options.fLineBreak};
346 size_t srcLen = end - start;
347 size_t bufSize = 4 * srcLen;
348 Assert (bufSize >= srcLen);
350 size_t mostBytesCopied = base64_encode_block_ (start, srcLen, data.begin (), &state);
351 size_t extraBytes = base64_encode_blockend_ (data.begin () + mostBytesCopied, &state);
352 size_t totalBytes = mostBytesCopied + extraBytes;
353 Assert (totalBytes <= bufSize);
354 return string{data.begin (), data.begin () + totalBytes};
#define RequireNotNull(p)
String is like std::u32string, except it is much easier to use, often much more space efficient,...
nonvirtual T AsUTF8() const
nonvirtual size_t length() const
nonvirtual const byte * end() const
nonvirtual const byte * begin() const
nonvirtual size_t size() const
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
OutputStream<>::Ptr is Smart pointer to a stream-based sink of data.
nonvirtual void Write(span< ELEMENT_TYPE2, EXTENT_2 > elts) const
CONTAINER::value_type * Start(CONTAINER &c)
For a contiguous container (such as a vector or basic_string) - find the pointer to the start of the ...