diff --git a/include/tlibc/base64.h b/include/tlibc/base64.h new file mode 100644 index 0000000..e71cc88 --- /dev/null +++ b/include/tlibc/base64.h @@ -0,0 +1,23 @@ +#pragma once +#include "tlibc/std.h" + +/// @param src_size size of data to encode +/// @return number of encoded characters. Is a multiple of 4. +u32 base64_encodedSize(u32 src_size); + +/// @param src data to encode +/// @param src_size size of data to encode +/// @param dst buffer of size base64_encodedSize(src_size) +/// @return number of encoded characters. Is a multiple of 4. +u32 base64_encode(const u8* src, u32 src_size, char* dst); + +/// @param src data to decode +/// @param src_size size of data to decode. Must be a multiple of 4 for valid base64 data. +/// @return number of decoded characters or 0 on error +u32 base64_decodedSize(const char* src, u32 src_size); + +/// @param src data to decode +/// @param src_size size of data to decode. Must be a multiple of 4 for valid base64 data. +/// @param dst buffer of size base64_decodedSize(src, src_size) +/// @return number of decoded characters or 0 on error +u32 base64_decode(const u8* src, u32 src_size, u8* dst); diff --git a/src/base64.c b/src/base64.c new file mode 100644 index 0000000..bac1765 --- /dev/null +++ b/src/base64.c @@ -0,0 +1,86 @@ +#include "tlibc/base64.h" + +// based on https://nachtimwald.com/2017/11/18/base64-encode-and-decode-in-c + +u32 base64_encodedSize(u32 src_size){ + u32 ret = src_size; + if (src_size % 3 != 0) + ret += 3 - (src_size % 3); + ret /= 3; + ret *= 4; + return ret; +} + +static const char b64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +u32 base64_encode(const u8* src, u32 src_size, char* dst){ + u32 i = 0, j = 0, v = 0; + for (; i < src_size; i += 3) { + v = src[i]; + v = i + 1 < src_size ? v << 8 | src[i + 1] : v << 8; + v = i + 2 < src_size ? v << 8 | src[i + 2] : v << 8; + + dst[j++] = b64chars[(v >> 18) & 0x3F]; + dst[j++] = b64chars[(v >> 12) & 0x3F]; + dst[j++] = i + 1 < src_size ? b64chars[(v >> 6) & 0x3F] : '='; + dst[j++] = i + 2 < src_size ? b64chars[v & 0x3F] : '='; + } + + return j; +} + +u32 base64_decodedSize(const char* src, u32 src_size){ + // incomplete src + if(src_size % 4 != 0) + return 0; + + u32 ret = src_size / 4 * 3; + u32 i = src_size; + while(i > 0 && src[--i] == '=') { + ret--; + } + return ret; +} + +/* +void base64_generateDecodeTable(){ + int inv[80]; + memset(inv, -1, sizeof(inv)); + for (u32 i = 0; i < 64; i + +) { + inv[b64chars[i] - 43] = i; + } +} +*/ + +static int b64inverse[] = { + 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51 +}; + +u32 base64_decode(const u8* src, u32 src_size, u8* dst){ + // incomplete src + if(src_size % 4 != 0) + return 0; + + u32 i = 0, j = 0, v = 0; + for (; i < src_size; i += 4) { + v = b64inverse[src[i] - 43]; + v = (v << 6) | b64inverse[src[i + 1] - 43]; + v = src[i + 2]=='=' ? v << 6 : (v << 6) | b64inverse[src[i + 2] - 43]; + v = src[i + 3]=='=' ? v << 6 : (v << 6) | b64inverse[src[i + 3] - 43]; + + dst[j++] = (v >> 16) & 0xFF; + if (src[i + 2] != '='){ + dst[j++] = (v >> 8) & 0xFF; + } + if (src[i + 3] != '='){ + dst[j++] = v & 0xFF; + } + } + + return j; +}