Files
fastfetch/src/common/impl/base64.c
T

111 lines
2.9 KiB
C
Raw Normal View History

2026-01-06 09:48:38 +08:00
#include "common/base64.h"
// https://github.com/kostya/benchmarks/blob/master/base64/test-nolib.c#L145
2026-03-29 09:28:49 +08:00
void ffBase64EncodeRaw(uint32_t size, const char* str, uint32_t* out_size, char* output) {
static const char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2026-03-29 09:28:49 +08:00
char* out = output;
const char* ends = str + (size - size % 3);
while (str != ends) {
uint32_t n = __builtin_bswap32(*(uint32_t*) str);
*out++ = chars[(n >> 26) & 63];
*out++ = chars[(n >> 20) & 63];
*out++ = chars[(n >> 14) & 63];
*out++ = chars[(n >> 8) & 63];
str += 3;
}
2026-03-29 09:28:49 +08:00
if (size % 3 == 1) {
uint64_t n = (uint64_t) *str << 16;
*out++ = chars[(n >> 18) & 63];
*out++ = chars[(n >> 12) & 63];
*out++ = '=';
*out++ = '=';
2026-03-29 09:28:49 +08:00
} else if (size % 3 == 2) {
uint64_t n = (uint64_t) *str++ << 16;
n |= (uint64_t) *str << 8;
*out++ = chars[(n >> 18) & 63];
*out++ = chars[(n >> 12) & 63];
*out++ = chars[(n >> 6) & 63];
*out++ = '=';
}
*out = '\0';
2026-03-29 09:28:49 +08:00
*out_size = (uint32_t) (out - output);
}
2024-07-06 12:11:36 +08:00
static uint8_t decode_table[256];
2026-03-29 09:28:49 +08:00
void init_decode_table() {
uint8_t ch = 0;
2026-03-29 09:28:49 +08:00
do {
int32_t code = -1;
2026-03-29 09:28:49 +08:00
if (ch >= 'A' && ch <= 'Z') {
code = ch - 0x41;
2026-03-29 09:28:49 +08:00
}
if (ch >= 'a' && ch <= 'z') {
code = ch - 0x47;
2026-03-29 09:28:49 +08:00
}
if (ch >= '0' && ch <= '9') {
code = ch + 0x04;
2026-03-29 09:28:49 +08:00
}
if (ch == '+' || ch == '-') {
code = 0x3E;
2026-03-29 09:28:49 +08:00
}
if (ch == '/' || ch == '_') {
code = 0x3F;
2026-03-29 09:28:49 +08:00
}
2024-07-08 14:20:57 +08:00
decode_table[ch] = (uint8_t) code;
} while (ch++ < 0xFF);
}
2024-07-06 12:11:36 +08:00
#define next_char(x) uint8_t x = decode_table[(uint8_t) *str++];
2026-03-29 09:28:49 +08:00
bool ffBase64DecodeRaw(uint32_t size, const char* str, uint32_t* out_size, char* output) {
if (*(uint64_t*) decode_table == 0) {
init_decode_table();
2026-03-29 09:28:49 +08:00
}
2026-03-29 09:28:49 +08:00
char* out = output;
while (size > 0 && (str[size - 1] == '\n' || str[size - 1] == '\r' || str[size - 1] == '=')) {
size--;
2026-03-29 09:28:49 +08:00
}
2026-03-29 09:28:49 +08:00
const char* ends = str + size - 4;
while (true) {
if (str > ends) {
break;
2026-03-29 09:28:49 +08:00
}
while (*str == '\n' || *str == '\r') {
str++;
2026-03-29 09:28:49 +08:00
}
2026-03-29 09:28:49 +08:00
if (str > ends) {
break;
2026-03-29 09:28:49 +08:00
}
next_char(a);
next_char(b);
next_char(c);
next_char(d);
2026-03-29 09:28:49 +08:00
*out++ = (char) (a << 2 | b >> 4);
*out++ = (char) (b << 4 | c >> 2);
*out++ = (char) (c << 6 | d >> 0);
}
uint8_t mod = (uint8_t) (ends - str + 4) % 4;
2026-03-29 09:28:49 +08:00
if (mod == 2) {
next_char(a);
next_char(b);
2026-03-29 09:28:49 +08:00
*out++ = (char) (a << 2 | b >> 4);
} else if (mod == 3) {
next_char(a);
next_char(b);
next_char(c);
2026-03-29 09:28:49 +08:00
*out++ = (char) (a << 2 | b >> 4);
*out++ = (char) (b << 4 | c >> 2);
}
*out = '\0';
*out_size = (uint32_t) (out - output);
return true;
}