clavitor/clavis/clavis-cli/src/util.c

117 lines
3.6 KiB
C

/*
* clavitor CLI — utility functions
*/
#include "util.h"
#include <string.h>
#include <ctype.h>
static const char b64_table[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int base64_encode(const unsigned char *src, size_t src_len, char *dst, size_t dst_len) {
size_t needed = ((src_len + 2) / 3) * 4 + 1;
if (dst_len < needed) return -1;
size_t i = 0, j = 0;
while (i + 2 < src_len) {
unsigned int triple = ((unsigned int)src[i] << 16) |
((unsigned int)src[i+1] << 8) |
(unsigned int)src[i+2];
dst[j++] = b64_table[(triple >> 18) & 0x3F];
dst[j++] = b64_table[(triple >> 12) & 0x3F];
dst[j++] = b64_table[(triple >> 6) & 0x3F];
dst[j++] = b64_table[triple & 0x3F];
i += 3;
}
/* Handle remaining 1 or 2 bytes */
size_t remaining = src_len - i;
if (remaining == 1) {
unsigned int a = src[i];
dst[j++] = b64_table[(a >> 2) & 0x3F];
dst[j++] = b64_table[(a << 4) & 0x3F];
dst[j++] = '=';
dst[j++] = '=';
} else if (remaining == 2) {
unsigned int a = src[i];
unsigned int b = src[i + 1];
dst[j++] = b64_table[(a >> 2) & 0x3F];
dst[j++] = b64_table[((a << 4) | (b >> 4)) & 0x3F];
dst[j++] = b64_table[(b << 2) & 0x3F];
dst[j++] = '=';
}
dst[j] = '\0';
return 0;
}
static int b64_val(char c) {
if (c >= 'A' && c <= 'Z') return c - 'A';
if (c >= 'a' && c <= 'z') return c - 'a' + 26;
if (c >= '0' && c <= '9') return c - '0' + 52;
if (c == '+' || c == '-') return 62; /* - is url-safe variant */
if (c == '/' || c == '_') return 63; /* _ is url-safe variant */
return -1;
}
int base64_decode(const char *src, unsigned char *dst, size_t dst_len, size_t *out_len) {
size_t slen = strlen(src);
/* count padding */
int pad = 0;
while (slen > 0 && src[slen - 1] == '=') { slen--; pad++; }
/* strip whitespace */
while (slen > 0 && (src[slen - 1] == '\n' || src[slen - 1] == '\r')) slen--;
size_t needed = (slen * 3) / 4;
if (dst_len < needed) return -1;
size_t i = 0, j = 0;
while (i + 3 < slen) {
int a = b64_val(src[i++]);
int b = b64_val(src[i++]);
int c = b64_val(src[i++]);
int d = b64_val(src[i++]);
if (a < 0 || b < 0 || c < 0 || d < 0) return -1;
dst[j++] = (unsigned char)((a << 2) | (b >> 4));
dst[j++] = (unsigned char)(((b & 0x0F) << 4) | (c >> 2));
dst[j++] = (unsigned char)(((c & 0x03) << 6) | d);
}
/* Handle remaining chars based on padding count */
size_t rem = slen - i;
if (rem >= 2) {
int a = b64_val(src[i++]);
int b = b64_val(src[i++]);
if (a < 0 || b < 0) return -1;
dst[j++] = (unsigned char)((a << 2) | (b >> 4));
if (rem >= 3 && pad < 2) {
int c = b64_val(src[i++]);
if (c < 0) return -1;
dst[j++] = (unsigned char)(((b & 0x0F) << 4) | (c >> 2));
}
}
if (out_len) *out_len = j;
return 0;
}
void url_encode(const char *src, char *dst, size_t dst_len) {
static const char hex[] = "0123456789ABCDEF";
size_t j = 0;
for (size_t i = 0; src[i] && j + 3 < dst_len; i++) {
unsigned char c = (unsigned char)src[i];
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
dst[j++] = (char)c;
} else {
dst[j++] = '%';
dst[j++] = hex[c >> 4];
dst[j++] = hex[c & 0x0F];
}
}
dst[j] = '\0';
}