2022-09-29 16:53:11 +01:00
|
|
|
#include "base64.h"
|
2020-12-05 11:26:32 +00:00
|
|
|
|
2023-08-22 11:50:19 +01:00
|
|
|
static int mg_base64_encode_single(int c) {
|
2020-12-05 11:26:32 +00:00
|
|
|
if (c < 26) {
|
|
|
|
return c + 'A';
|
|
|
|
} else if (c < 52) {
|
|
|
|
return c - 26 + 'a';
|
|
|
|
} else if (c < 62) {
|
|
|
|
return c - 52 + '0';
|
|
|
|
} else {
|
|
|
|
return c == 62 ? '+' : '/';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-22 11:50:19 +01:00
|
|
|
static int mg_base64_decode_single(int c) {
|
2020-12-05 11:26:32 +00:00
|
|
|
if (c >= 'A' && c <= 'Z') {
|
|
|
|
return c - 'A';
|
|
|
|
} else if (c >= 'a' && c <= 'z') {
|
|
|
|
return c + 26 - 'a';
|
|
|
|
} else if (c >= '0' && c <= '9') {
|
|
|
|
return c + 52 - '0';
|
|
|
|
} else if (c == '+') {
|
|
|
|
return 62;
|
|
|
|
} else if (c == '/') {
|
|
|
|
return 63;
|
|
|
|
} else if (c == '=') {
|
|
|
|
return 64;
|
|
|
|
} else {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-22 11:50:19 +01:00
|
|
|
size_t mg_base64_update(unsigned char ch, char *to, size_t n) {
|
|
|
|
unsigned long rem = (n & 3) % 3;
|
2020-12-05 11:26:32 +00:00
|
|
|
if (rem == 0) {
|
2023-08-22 11:50:19 +01:00
|
|
|
to[n] = (char) mg_base64_encode_single(ch >> 2);
|
2021-05-28 18:30:42 +01:00
|
|
|
to[++n] = (char) ((ch & 3) << 4);
|
2020-12-05 11:26:32 +00:00
|
|
|
} else if (rem == 1) {
|
2023-08-22 11:50:19 +01:00
|
|
|
to[n] = (char) mg_base64_encode_single(to[n] | (ch >> 4));
|
2021-05-28 18:30:42 +01:00
|
|
|
to[++n] = (char) ((ch & 15) << 2);
|
2020-12-05 11:26:32 +00:00
|
|
|
} else {
|
2023-08-22 11:50:19 +01:00
|
|
|
to[n] = (char) mg_base64_encode_single(to[n] | (ch >> 6));
|
|
|
|
to[++n] = (char) mg_base64_encode_single(ch & 63);
|
2020-12-05 11:26:32 +00:00
|
|
|
n++;
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2023-08-22 11:50:19 +01:00
|
|
|
size_t mg_base64_final(char *to, size_t n) {
|
|
|
|
size_t saved = n;
|
2020-12-05 11:26:32 +00:00
|
|
|
// printf("---[%.*s]\n", n, to);
|
|
|
|
if (n & 3) n = mg_base64_update(0, to, n);
|
|
|
|
if ((saved & 3) == 2) n--;
|
|
|
|
// printf(" %d[%.*s]\n", n, n, to);
|
|
|
|
while (n & 3) to[n++] = '=';
|
|
|
|
to[n] = '\0';
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2023-08-22 11:50:19 +01:00
|
|
|
size_t mg_base64_encode(const unsigned char *p, size_t n, char *to, size_t dl) {
|
|
|
|
size_t i, len = 0;
|
|
|
|
if (dl > 0) to[0] = '\0';
|
|
|
|
if (dl < ((n / 3) + (n % 3 ? 1 : 0)) * 4 + 1) return 0;
|
2020-12-05 11:26:32 +00:00
|
|
|
for (i = 0; i < n; i++) len = mg_base64_update(p[i], to, len);
|
|
|
|
len = mg_base64_final(to, len);
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2023-08-22 11:50:19 +01:00
|
|
|
size_t mg_base64_decode(const char *src, size_t n, char *dst, size_t dl) {
|
2022-09-29 16:53:11 +01:00
|
|
|
const char *end = src == NULL ? NULL : src + n; // Cannot add to NULL
|
2023-08-22 11:50:19 +01:00
|
|
|
size_t len = 0;
|
2023-12-18 19:08:51 +00:00
|
|
|
if (dl < n / 4 * 3 + 1) goto fail;
|
2022-09-29 16:53:11 +01:00
|
|
|
while (src != NULL && src + 3 < end) {
|
2023-08-22 11:50:19 +01:00
|
|
|
int a = mg_base64_decode_single(src[0]),
|
|
|
|
b = mg_base64_decode_single(src[1]),
|
|
|
|
c = mg_base64_decode_single(src[2]),
|
|
|
|
d = mg_base64_decode_single(src[3]);
|
2023-12-18 19:08:51 +00:00
|
|
|
if (a == 64 || a < 0 || b == 64 || b < 0 || c < 0 || d < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2021-05-28 18:30:42 +01:00
|
|
|
dst[len++] = (char) ((a << 2) | (b >> 4));
|
2020-12-05 11:26:32 +00:00
|
|
|
if (src[2] != '=') {
|
2021-05-28 18:30:42 +01:00
|
|
|
dst[len++] = (char) ((b << 4) | (c >> 2));
|
|
|
|
if (src[3] != '=') dst[len++] = (char) ((c << 6) | d);
|
2020-12-05 11:26:32 +00:00
|
|
|
}
|
|
|
|
src += 4;
|
|
|
|
}
|
|
|
|
dst[len] = '\0';
|
|
|
|
return len;
|
2023-12-18 19:08:51 +00:00
|
|
|
fail:
|
|
|
|
if (dl > 0) dst[0] = '\0';
|
|
|
|
return 0;
|
2020-12-05 11:26:32 +00:00
|
|
|
}
|