#include "bee2/core/b64.h"
#include "bee2/core/mem.h"
#include "bee2/core/str.h"
#include "bee2/core/util.h"
static const char b64_alphabet[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static const octet b64_dec_table[256] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3E,0xFF,0xFF,0xFF,0x3F,
0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,
0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,
0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
};
bool_t b64IsValid(const char* b64)
{
size_t len;
if (!strIsValid(b64))
return FALSE;
len = strLen(b64);
if (len % 4)
return FALSE;
if (len && b64[len - 1] == '=' && b64[--len - 1] == '=')
--len;
if (len % 4 == 3)
{
if (b64_dec_table[(octet)b64[len - 1]] & 3)
return FALSE;
--len;
}
else if (len % 4 == 2)
{
if (b64_dec_table[(octet)b64[len - 1]] & 15)
return FALSE;
--len;
}
for (; len--; ++b64)
if (b64_dec_table[(octet)*b64] == 0xFF)
return FALSE;
return TRUE;
}
void b64From(char* dest, const void* src, size_t count)
{
register u32 block;
ASSERT(memIsDisjoint2(src, count, dest, 4 * ((count + 2) / 3) + 1));
for (; count >= 3; count -= 3)
{
block = ((const octet*)src)[0], block <<= 8;
block |= ((const octet*)src)[1], block <<= 8;
block |= ((const octet*)src)[2];
dest[3] = b64_alphabet[block & 63], block >>= 6;
dest[2] = b64_alphabet[block & 63], block >>= 6;
dest[1] = b64_alphabet[block & 63], block >>= 6;
dest[0] = b64_alphabet[block];
src = (const octet*)src + 3;
dest += 4;
}
if (count == 2)
{
block = ((const octet*)src)[0], block <<= 8;
block |= ((const octet*)src)[1], block <<= 2;
dest[3] = '=';
dest[2] = b64_alphabet[block & 63], block >>= 6;
dest[1] = b64_alphabet[block & 63], block >>= 6;
dest[0] = b64_alphabet[block];
dest += 4;
}
else if (count == 1)
{
block = ((const octet*)src)[0], block <<= 4;
dest[3] = dest[2] = '=';
dest[1] = b64_alphabet[block & 63], block >>= 6;
dest[0] = b64_alphabet[block];
dest += 4;
}
*dest = '\0';
CLEAN(block);
}
void b64To(void* dest, size_t* count, const char* src)
{
register u32 block;
size_t len;
ASSERT(b64IsValid(src));
ASSERT(memIsValid(count, sizeof(size_t)));
ASSERT(memIsNullOrValid(dest, *count));
len = strLen(src);
if (len && src[len - 1] == '=' && src[--len - 1] == '=')
--len;
ASSERT(dest ? *count >= 3 * (len / 4) + (len & 1) + (len >> 1 & 1) : TRUE);
*count = 3 * (len / 4) + (len & 1) + (len >> 1 & 1);
if (dest == 0)
return;
ASSERT(memIsDisjoint2(src, strLen(src) + 1, dest, *count));
for (; len >= 4; len -= 4)
{
block = b64_dec_table[(octet)src[0]], block <<= 6;
block |= b64_dec_table[(octet)src[1]], block <<= 6;
block |= b64_dec_table[(octet)src[2]], block <<= 6;
block |= b64_dec_table[(octet)src[3]];
((octet*)dest)[2] = block & 255, block >>= 8;
((octet*)dest)[1] = block & 255, block >>= 8;
((octet*)dest)[0] = block;
src += 4;
dest = (octet*)dest + 3;
}
if (len == 3)
{
block = b64_dec_table[(octet)src[0]], block <<= 6;
block |= b64_dec_table[(octet)src[1]], block <<= 6;
block |= b64_dec_table[(octet)src[2]], block >>= 2;
((octet*)dest)[1] = block & 255, block >>= 8;
((octet*)dest)[0] = block;
}
else if (len == 2)
{
block = b64_dec_table[(octet)src[0]], block <<= 6;
block |= b64_dec_table[(octet)src[1]], block >>= 4;
((octet*)dest)[0] = block;
}
CLEAN(block);
}