117 lines
3.6 KiB
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';
|
|
}
|