220 lines
5.3 KiB
C++
220 lines
5.3 KiB
C++
#include "ehs/Base64.h"
|
|
|
|
namespace ehs
|
|
{
|
|
Str_8 Base64::EncodeURL(const Str_8 &input)
|
|
{
|
|
UInt_64 input_length = input.Size();
|
|
|
|
// Calculate the output length
|
|
UInt_64 output_length = (input_length * 4 + 2) / 3;
|
|
|
|
// Allocate memory for the output
|
|
Str_8 result(output_length);
|
|
|
|
// Loop through the input and fill the output
|
|
for (int i = 0, j = 0; i < input_length;) {
|
|
|
|
// Take first byte and shift right by 2 bits
|
|
UInt_32 octet_a = (UInt_8)input[i++];
|
|
UInt_32 octet_b = i < input_length ? (UInt_8)input[i++] : 0;
|
|
UInt_32 octet_c = i < input_length ? (UInt_8)input[i++] : 0;
|
|
|
|
UInt_32 triple = (octet_a << 16) + (octet_b << 8) + octet_c;
|
|
|
|
// Encode the 24-bits into four 6-bits integers
|
|
result[j++] = asciiUrl[(triple >> 3 * 6) & 0x3F];
|
|
result[j++] = asciiUrl[(triple >> 2 * 6) & 0x3F];
|
|
result[j++] = asciiUrl[(triple >> 1 * 6) & 0x3F];
|
|
result[j++] = asciiUrl[(triple >> 0 * 6) & 0x3F];
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
Str_8 Base64::Encode(const Str_8 &input)
|
|
{
|
|
UInt_64 input_length = input.Size();
|
|
|
|
// Calculate the output length
|
|
UInt_64 output_length = 4 * ((input_length + 2) / 3);
|
|
|
|
// Allocate memory for the output
|
|
Str_8 result(output_length);
|
|
|
|
// Loop through the input and fill the output
|
|
for (int i = 0, j = 0; i < input_length;) {
|
|
|
|
// Take first byte and shift right by 2 bits
|
|
UInt_32 octet_a = i < input_length ? (UInt_8)input[i++] : 0;
|
|
UInt_32 octet_b = i < input_length ? (UInt_8)input[i++] : 0;
|
|
UInt_32 octet_c = i < input_length ? (UInt_8)input[i++] : 0;
|
|
|
|
UInt_32 triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
|
|
|
|
// Encode the 24-bits into four 6-bits integers
|
|
result[j++] = ascii[(triple >> 3 * 6) & 0x3F];
|
|
result[j++] = ascii[(triple >> 2 * 6) & 0x3F];
|
|
result[j++] = ascii[(triple >> 1 * 6) & 0x3F];
|
|
result[j++] = ascii[(triple >> 0 * 6) & 0x3F];
|
|
}
|
|
|
|
// Add padding '='
|
|
if (input_length % 3 == 1) {
|
|
result[output_length - 1] = '=';
|
|
result[output_length - 2] = '=';
|
|
} else if (input_length % 3 == 2) {
|
|
result[output_length - 1] = '=';
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
Str_8 Base64::DecodeURL(const Str_8 &input)
|
|
{
|
|
Str_8 result(input.Size() * 3 / 4);
|
|
|
|
UInt_64 remaining = input.Size();
|
|
UInt_64 offsetIn = 0;
|
|
UInt_64 offsetOut = 0;
|
|
UInt_8 quartet[4];
|
|
|
|
while (remaining)
|
|
{
|
|
if (remaining >= 4)
|
|
{
|
|
for (UInt_8 i = 0; i < 4; ++i)
|
|
{
|
|
if (!IsBase64URL(input[offsetIn + i]))
|
|
return {};
|
|
|
|
quartet[i] = FindURL(input[offsetIn + i]);
|
|
if (quartet[i] == EHS_UINT_8_MAX)
|
|
return {};
|
|
}
|
|
|
|
result[offsetOut++] = (Char_8)((((UInt_8*)&quartet)[0] << 2) | (((UInt_8*)&quartet)[1] >> 4));
|
|
result[offsetOut++] = (Char_8)((((UInt_8*)&quartet)[1] << 4) | (((UInt_8*)&quartet)[2] >> 2));
|
|
result[offsetOut++] = (Char_8)((((UInt_8*)&quartet)[2] << 6) | ((UInt_8*)&quartet)[3]);
|
|
|
|
offsetIn += 4;
|
|
remaining -= 4;
|
|
}
|
|
else
|
|
{
|
|
for (UInt_8 i = 0; i < 4; ++i)
|
|
{
|
|
if (i < remaining)
|
|
{
|
|
if (!IsBase64URL(input[offsetIn + i]))
|
|
return {};
|
|
|
|
quartet[i] = FindURL(input[offsetIn + i]);
|
|
if (quartet[i] == EHS_UINT_8_MAX)
|
|
return {};
|
|
}
|
|
else
|
|
quartet[i] = 0;
|
|
}
|
|
|
|
result[offsetOut++] = (Char_8)((quartet[0] << 2) | (quartet[1] >> 4));
|
|
|
|
if (remaining == 3)
|
|
result[offsetOut++] = (Char_8)((quartet[1] << 4) | (quartet[2] >> 2));
|
|
|
|
offsetIn += remaining;
|
|
remaining = 0;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
Str_8 Base64::Decode(const Str_8 &input)
|
|
{
|
|
Str_8 result(input.Size() * 3 / 4);
|
|
|
|
UInt_64 remaining = input.Size();
|
|
UInt_64 offsetIn = 0;
|
|
UInt_64 offsetOut = 0;
|
|
UInt_8 quartet[4];
|
|
|
|
while (remaining)
|
|
{
|
|
if (remaining >= 4)
|
|
{
|
|
for (UInt_8 i = 0; i < 4; ++i)
|
|
{
|
|
if (!IsBase64(input[offsetIn + i]))
|
|
return {};
|
|
|
|
quartet[i] = Find(input[offsetIn + i]);
|
|
if (quartet[i] == EHS_UINT_8_MAX)
|
|
return {};
|
|
}
|
|
|
|
result[offsetOut++] = (Char_8)((((UInt_8*)&quartet)[0] << 2) | (((UInt_8*)&quartet)[1] >> 4));
|
|
result[offsetOut++] = (Char_8)((((UInt_8*)&quartet)[1] << 4) | (((UInt_8*)&quartet)[2] >> 2));
|
|
result[offsetOut++] = (Char_8)((((UInt_8*)&quartet)[2] << 6) | ((UInt_8*)&quartet)[3]);
|
|
|
|
offsetIn += 4;
|
|
remaining -= 4;
|
|
}
|
|
else
|
|
{
|
|
for (UInt_8 i = 0; i < 4; ++i)
|
|
{
|
|
if (i < remaining)
|
|
{
|
|
if (!IsBase64(input[offsetIn + i]))
|
|
return {};
|
|
|
|
quartet[i] = Find(input[offsetIn + i]);
|
|
if (quartet[i] == EHS_UINT_8_MAX)
|
|
return {};
|
|
}
|
|
else
|
|
quartet[i] = 0;
|
|
}
|
|
|
|
result[offsetOut++] = (Char_8)((quartet[0] << 2) | (quartet[1] >> 4));
|
|
|
|
if (remaining == 3)
|
|
result[offsetOut++] = (Char_8)((quartet[1] << 4) | (quartet[2] >> 2));
|
|
|
|
offsetIn += remaining;
|
|
remaining = 0;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
UInt_8 Base64::FindURL(const UInt_8 &c)
|
|
{
|
|
for (UInt_8 i = 0; i < (UInt_8)sizeof(asciiUrl) - 1; ++i)
|
|
if (asciiUrl[i] == c)
|
|
return i;
|
|
|
|
return EHS_UINT_8_MAX;;
|
|
}
|
|
|
|
UInt_8 Base64::Find(const UInt_8 &c)
|
|
{
|
|
for (UInt_8 i = 0; i < (UInt_8)sizeof(ascii) - 1; ++i)
|
|
if (ascii[i] == c)
|
|
return i;
|
|
|
|
return EHS_SINT_8_MAX;
|
|
}
|
|
|
|
bool Base64::IsBase64URL(const UInt_8 &c)
|
|
{
|
|
return (c > 47 && c < 58) || (c > 64 && c < 91) || (c > 96 && c < 123) || c == '-' || c == '_';
|
|
}
|
|
|
|
bool Base64::IsBase64(const UInt_8 &c)
|
|
{
|
|
return (c > 47 && c < 58) || (c > 64 && c < 91) || (c > 96 && c < 123) || c == '+' || c == '/';
|
|
}
|
|
} |