/* * clavitor CLI — utility functions */ #include "util.h" #include #include 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'; }