84 lines
2.6 KiB
C
84 lines
2.6 KiB
C
#include "base64.h"
|
|
|
|
// Thanks, ryyst https://stackoverflow.com/questions/342409/how-do-i-base64-encode-decode-in-c
|
|
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
/*
|
|
* Data
|
|
*/
|
|
static const int mod_table[] = {0, 2, 1};
|
|
static const char *encoding_table =
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
static char decoding_table[256] = {};
|
|
|
|
/*
|
|
* Private API
|
|
*/
|
|
static void build_decoding_table() {
|
|
for (int i = 0; i < 64; ++i) {
|
|
decoding_table[(uint8_t)encoding_table[i]] = i;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Public API
|
|
*/
|
|
char *base64_encode(const void *_data, uint32_t size) {
|
|
uint32_t out_size = 4 * ((size + 2) / 3) + 1;
|
|
char *out_data = malloc(out_size);
|
|
if (!out_size) {
|
|
return NULL;
|
|
}
|
|
const char *data = _data;
|
|
for (int i = 0, j = 0; i < size;) {
|
|
uint32_t octet_a = i < size ? (uint8_t)data[i++] : 0;
|
|
uint32_t octet_b = i < size ? (uint8_t)data[i++] : 0;
|
|
uint32_t octet_c = i < size ? (uint8_t)data[i++] : 0;
|
|
|
|
uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
|
|
|
|
out_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F];
|
|
out_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F];
|
|
out_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F];
|
|
out_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];
|
|
}
|
|
for (int i = 0; i < mod_table[size % 3]; i++)
|
|
out_data[out_size - 2 - i] = '=';
|
|
out_data[out_size - 1] = '\0';
|
|
return out_data;
|
|
}
|
|
|
|
void *base64_decode(const char *data, uint32_t *out_size) {
|
|
if (decoding_table[0] == 0)
|
|
build_decoding_table();
|
|
uint32_t size = strlen(data);
|
|
if (size % 4 != 0) return NULL;
|
|
|
|
*out_size = size / 4 * 3;
|
|
if (data[size - 1] == '=') (*out_size)--;
|
|
if (data[size - 2] == '=') (*out_size)--;
|
|
|
|
uint8_t *decoded_data = malloc(*out_size);
|
|
if (decoded_data == NULL) return NULL;
|
|
|
|
for (int i = 0, j = 0; i < size;) {
|
|
uint32_t sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
|
|
uint32_t sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
|
|
uint32_t sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
|
|
uint32_t sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
|
|
|
|
uint32_t triple = (sextet_a << 3 * 6)
|
|
+ (sextet_b << 2 * 6)
|
|
+ (sextet_c << 1 * 6)
|
|
+ (sextet_d << 0 * 6);
|
|
|
|
if (j < *out_size) decoded_data[j++] = (triple >> 2 * 8) & 0xFF;
|
|
if (j < *out_size) decoded_data[j++] = (triple >> 1 * 8) & 0xFF;
|
|
if (j < *out_size) decoded_data[j++] = (triple >> 0 * 8) & 0xFF;
|
|
}
|
|
return decoded_data;
|
|
}
|